void Client::use_event_dispatcher(IO::EventDispatcher *ed)
{
+ if(event_disp && sock)
+ event_disp->remove(*sock);
event_disp=ed;
- if(sock)
+ if(event_disp && sock)
event_disp->add(*sock);
}
in_buf.clear();
}
-void Client::get_url(const std::string &url)
+const Response *Client::get_url(const std::string &url)
{
start_request(Request::from_url(url));
wait_response();
+ return response;
}
void Client::tick()
if(in_buf.find("\r\n\r\n")!=string::npos || in_buf.find("\n\n")!=string::npos)
{
response=new Response(Response::parse(in_buf));
+ response->set_user_data(request->get_user_data());
in_buf=string();
}
}
else
{
- len=response->parse_data(in_buf);
+ len=response->parse_content(in_buf);
in_buf.erase(0, len);
}
class Client
{
+public:
+ sigc::signal<void, const Response &> signal_response_complete;
+ sigc::signal<void, int> signal_socket_error;
+
private:
Net::StreamSocket *sock;
IO::EventDispatcher *event_disp;
Response *response;
std::string in_buf;
-public:
- sigc::signal<void, const Response &> signal_response_complete;
- sigc::signal<void, int> signal_socket_error;
-
-private:
Client(const Client &);
Client &operator=(const Client &);
public:
void use_event_dispatcher(IO::EventDispatcher *);
void start_request(const Request &);
- void get_url(const std::string &);
+ const Response *get_url(const std::string &);
void tick();
void wait_response();
void abort();
return i->second;
}
-void Message::add_data(const string &d)
+void Message::add_content(const string &d)
{
- data+=d;
+ content+=d;
if(headers.count("content-type")==0)
set_header("content-type", "text/plain");
- set_header("content-length", lexical_cast(data.size()));
+ set_header("content-length", lexical_cast(content.size()));
}
-unsigned Message::parse_data(const string &d)
+void Message::set_user_data(const Variant &d)
+{
+ user_data=d;
+}
+
+unsigned Message::parse_content(const string &d)
{
if(complete)
return 0;
HeaderMap::const_iterator i=headers.find("content-length");
if(i!=headers.end())
{
- unsigned needed=lexical_cast<unsigned>(i->second)-data.size();
+ unsigned needed=lexical_cast<unsigned>(i->second)-content.size();
unsigned len=min(needed, d.size());
- data.append(d, 0, len);
+ content.append(d, 0, len);
if(len==needed)
complete=true;
unsigned lf=d.find('\n', pos);
if(lf==string::npos)
return pos;
- // XXX strtoul
- chunk_length=strtoul(strip(d.substr(pos, lf-pos)).c_str(), 0, 16);
+ chunk_length=lexical_cast<unsigned>(strip(d.substr(pos, lf-pos)), "x");
if(chunk_length==0)
complete=true;
pos=lf+1;
else
{
unsigned len=min(chunk_length, d.size()-pos);
- data.append(d, pos, len);
+ content.append(d, pos, len);
chunk_length-=len;
if((pos=d.find('\n', pos+len))!=string::npos)
++pos;
for(HeaderMap::const_iterator i=headers.begin(); i!=headers.end(); ++i)
result+=format("%s: %s\r\n", i->first, i->second);
result+="\r\n";
- result+=data;
+ result+=content;
return result;
}
#ifndef MSP_HTTP_MESSAGE_H_
#define MSP_HTTP_MESSAGE_H_
+#include <map>
#include <string>
-#include "misc.h"
+#include <msp/core/variant.h>
+#include "version.h"
namespace Msp {
namespace Http {
class Message
{
+protected:
+ typedef std::map<std::string, std::string> HeaderMap;
+
+ Version http_version;
+ HeaderMap headers;
+ std::string content;
+ unsigned chunk_length;
+ bool complete;
+ Variant user_data;
+
+ Message();
public:
virtual ~Message() { }
void set_header(const std::string &, const std::string &);
const std::string &get_header(const std::string &) const;
- const std::string &get_data() const { return data; }
+ void add_content(const std::string &);
+ const std::string &get_content() const { return content; }
+ void set_user_data(const Variant &);
+ const Variant &get_user_data() const { return user_data; }
bool get_complete() const { return complete; }
- void add_data(const std::string &);
- unsigned parse_data(const std::string &);
+ unsigned parse_content(const std::string &);
virtual std::string str() const =0;
protected:
- Version http_version;
- HeaderMap headers;
- std::string data;
- unsigned chunk_length;
- bool complete;
-
- Message();
std::string str_common() const;
};
+++ /dev/null
-/* $Id$
-
-This file is part of libmsphttp
-Copyright © 2008 Mikkosoft Productions, Mikko Rasa
-Distributed under the LGPL
-*/
-
-#include <msp/strings/formatter.h>
-#include <msp/strings/lexicalcast.h>
-#include <msp/strings/regex.h>
-#include "misc.h"
-
-using namespace std;
-
-namespace Msp {
-namespace Http {
-
-Version parse_version(const std::string &ver)
-{
- if(RegMatch match=Regex("^HTTP/([0-9]+).([0-9]+)$").match(ver))
- return lexical_cast<unsigned>(match[1].str)<<4 | lexical_cast<unsigned>(match[2].str);
- else
- throw InvalidParameterValue("Invalid HTTP version");
-}
-
-string version_str(Version ver)
-{
- return format("HTTP/%u.%u", (ver>>4)&0xF, ver&0xF);
-}
-
-} // namespace Http
-} // namespace Msp
+++ /dev/null
-/* $Id$
-
-This file is part of libmsphttp
-Copyright © 2008 Mikkosoft Productions, Mikko Rasa
-Distributed under the LGPL
-*/
-
-#ifndef MSP_HTTP_MISC_H_
-#define MSP_HTTP_MISC_H_
-
-#include <map>
-#include <string>
-
-namespace Msp {
-namespace Http {
-
-typedef std::map<std::string, std::string> HeaderMap;
-typedef unsigned Version;
-
-Version parse_version(const std::string &);
-std::string version_str(Version);
-
-} // namespace Http
-} // namespace Msp
-
-#endif
class Request: public Message
{
+private:
+ std::string method;
+ std::string path;
+
public:
Request(const std::string &, const std::string &);
virtual std::string str() const;
static Request parse(const std::string &);
static Request from_url(const std::string &);
-private:
- std::string method;
- std::string path;
};
} // namespace Http
start=lf+1;
}
- result.parse_data(str.substr(lf+1));
+ result.parse_content(str.substr(lf+1));
return result;
}
class Response: public Message
{
+private:
+ Status status;
+
+ Response() { }
public:
Response(Status);
Status get_status() const { return status; }
virtual std::string str() const;
static Response parse(const std::string &);
-private:
- Status status;
-
- Response() { }
};
} // namespace Http
{
switch(status)
{
- case None: out<<"None"; break;
+ case NONE: out<<"None"; break;
case OK: out<<"OK"; break;
- case BadRequest: out<<"Bad Request"; break;
- case Forbidden: out<<"Forbidden"; break;
- case NotFound: out<<"Not Found"; break;
- case InternalError: out<<"Internal Error"; break;
- case NotImplemented: out<<"Not Implemented"; break;
+ case BAD_REQUEST: out<<"Bad Request"; break;
+ case FORBIDDEN: out<<"Forbidden"; break;
+ case NOT_FOUND: out<<"Not Found"; break;
+ case INTERNAL_ERROR: out<<"Internal Error"; break;
+ case NOT_IMPLEMENTED: out<<"Not Implemented"; break;
default: out<<"Unknown Status"; break;
}
enum Status
{
- None=0,
+ NONE=0,
OK=200,
- BadRequest=400,
- Forbidden=403,
- NotFound=404,
- InternalError=500,
- NotImplemented=501
+ BAD_REQUEST=400,
+ FORBIDDEN=403,
+ NOT_FOUND=404,
+ INTERNAL_ERROR=500,
+ NOT_IMPLEMENTED=501
};
extern std::ostream &operator<<(std::ostream &, Status);
--- /dev/null
+/* $Id$
+
+This file is part of libmsphttp
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#include <msp/strings/formatter.h>
+#include <msp/strings/lexicalcast.h>
+#include <msp/strings/regex.h>
+#include "version.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Http {
+
+Version parse_version(const std::string &ver)
+{
+ if(RegMatch match=Regex("^HTTP/([0-9]+).([0-9]+)$").match(ver))
+ return lexical_cast<unsigned>(match[1].str)<<4 | lexical_cast<unsigned>(match[2].str);
+ else
+ throw InvalidParameterValue("Invalid HTTP version");
+}
+
+string version_str(Version ver)
+{
+ return format("HTTP/%u.%u", (ver>>4)&0xF, ver&0xF);
+}
+
+} // namespace Http
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmsphttp
+Copyright © 2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the LGPL
+*/
+
+#ifndef MSP_HTTP_MISC_H_
+#define MSP_HTTP_MISC_H_
+
+#include <string>
+
+namespace Msp {
+namespace Http {
+
+typedef unsigned Version;
+
+Version parse_version(const std::string &);
+std::string version_str(Version);
+
+} // namespace Http
+} // namespace Msp
+
+#endif