Yet Another HTTP Library: /home/cmouse/projects/libyahttp/yahttp/reqresp.hpp Source File

Yet Another HTTP Library yahttp

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
reqresp.hpp
Go to the documentation of this file.
1 #ifdef HAVE_CXX11
2 #include <functional>
3 #define HAVE_CPP_FUNC_PTR
4 namespace funcptr = std;
5 #else
6 #ifdef HAVE_BOOST
7 #include <boost/function.hpp>
8 namespace funcptr = boost;
9 #define HAVE_CPP_FUNC_PTR
10 #endif
11 #endif
12
13 #include <fstream>
14 #include <cctype>
15
16 #ifndef WIN32
17 #include <cstdio>
18 #include <unistd.h>
19 #endif
20
21 #include <algorithm>
22
23 #ifndef YAHTTP_MAX_REQUEST_SIZE
24 #define YAHTTP_MAX_REQUEST_SIZE 2097152
25 #endif
26
27 #ifndef YAHTTP_MAX_RESPONSE_SIZE
28 #define YAHTTP_MAX_RESPONSE_SIZE 2097152
29 #endif
30
31 #define YAHTTP_TYPE_REQUEST 1
32 #define YAHTTP_TYPE_RESPONSE 2
33
34 namespace YaHTTP {
35 typedef std::map<std::string,Cookie,ASCIICINullSafeComparator> strcookie_map_t; //<! String to Cookie map
36
37 typedef enum {
38 urlencoded,
39 multipart
40 } postformat_t; //<! Enumeration of possible post encodings, url encoding or multipart
41
43 class HTTPBase {
44 public:
46 class SendBodyRender {
47 public:
48 SendBodyRender() {};
49
50 size_t operator()(const HTTPBase *doc, std::ostream& os, bool chunked) const {
51 if (chunked) {
52 std::string::size_type i,cl;
53 for(i=0;i<doc->body.length();i+=1024) {
54 cl = std::min(static_cast<std::string::size_type>(1024), doc->body.length()-i); // for less than 1k blocks
55 os << std::hex << cl << std::dec << "\r\n";
56 os << doc->body.substr(i, cl) << "\r\n";
57 }
58 os << 0 << "\r\n\r\n"; // last chunk
59 } else {
60 os << doc->body;
61 }
62 return doc->body.length();
63 }; //<! writes body to ostream and returns length
64 };
65 /* Simple sendfile renderer which streams file to ostream */
66 class SendFileRender {
67 public:
68 SendFileRender(const std::string& path) {
69 this->path = path;
70 };
71
72 size_t operator()(const HTTPBase *doc __attribute__((unused)), std::ostream& os, bool chunked) const {
73 char buf[4096];
74 size_t n,k;
75 #ifdef HAVE_CXX11
76 std::ifstream ifs(path, std::ifstream::binary);
77 #else
78 std::ifstream ifs(path.c_str(), std::ifstream::binary);
79 #endif
80 n = 0;
81
82 std::cerr << "Sending file " << path << std::endl;
83 while(ifs && ifs.good()) {
84 ifs.read(buf, sizeof buf);
85 n += (k = ifs.gcount());
86 if (k) {
87 if (chunked) os << std::hex << k << std::dec << "\r\n";
88 os.write(buf, k);
89 if (chunked) os << "\r\n";
90 }
91 }
92 if (chunked) os << 0 << "\r\n\r\n";
93 return n;
94 }; //<! writes file to ostream and returns length
95
96 std::string path; //<! File to send
97 };
98
99 HTTPBase() {
100 initialize();
101 };
102
103 virtual void initialize() {
104 kind = 0;
105 status = 0;
106 #ifdef HAVE_CPP_FUNC_PTR
107 renderer = SendBodyRender();
108 #endif
109 max_request_size = YAHTTP_MAX_REQUEST_SIZE;
110 max_response_size = YAHTTP_MAX_RESPONSE_SIZE;
111 url = "";
112 method = "";
113 statusText = "";
114 jar.clear();
115 headers.clear();
116 parameters.clear();
117 getvars.clear();
118 postvars.clear();
119 body = "";
120 routeName = "";
121 version = 11; // default to version 1.1
122 }
123 protected:
124 HTTPBase(const HTTPBase& rhs) {
125 this->url = rhs.url; this->kind = rhs.kind;
126 this->status = rhs.status; this->statusText = rhs.statusText;
127 this->method = rhs.method; this->headers = rhs.headers;
128 this->jar = rhs.jar; this->postvars = rhs.postvars;
129 this->parameters = rhs.parameters; this->getvars = rhs.getvars;
130 this->body = rhs.body; this->max_request_size = rhs.max_request_size;
131 this->max_response_size = rhs.max_response_size; this->version = rhs.version;
132 #ifdef HAVE_CPP_FUNC_PTR
133 this->renderer = rhs.renderer;
134 #endif
135 };
136 HTTPBase& operator=(const HTTPBase& rhs) {
137 this->url = rhs.url; this->kind = rhs.kind;
138 this->status = rhs.status; this->statusText = rhs.statusText;
139 this->method = rhs.method; this->headers = rhs.headers;
140 this->jar = rhs.jar; this->postvars = rhs.postvars;
141 this->parameters = rhs.parameters; this->getvars = rhs.getvars;
142 this->body = rhs.body; this->max_request_size = rhs.max_request_size;
143 this->max_response_size = rhs.max_response_size; this->version = rhs.version;
144 #ifdef HAVE_CPP_FUNC_PTR
145 this->renderer = rhs.renderer;
146 #endif
147 return *this;
148 };
149 public:
150 URL url; //<! URL of this request/response
151 int kind; //<! Type of object (1 = request, 2 = response)
152 int status; //<! status code
153 int version; //<! http version 9 = 0.9, 10 = 1.0, 11 = 1.1
154 std::string statusText; //<! textual representation of status code
155 std::string method; //<! http verb
156 strstr_map_t headers; //<! map of header(s)
157 CookieJar jar; //<! cookies
158 strstr_map_t postvars; //<! map of POST variables (from POST body)
159 strstr_map_t getvars; //<! map of GET variables (from URL)
160 // these two are for Router
161 strstr_map_t parameters; //<! map of route parameters (only if you use YaHTTP::Router)
162 std::string routeName; //<! name of the current route (only if you use YaHTTP::Router)
163
164 std::string body; //<! the actual content
165
166 ssize_t max_request_size; //<! maximum size of request
167 ssize_t max_response_size; //<! maximum size of response
168
169 #ifdef HAVE_CPP_FUNC_PTR
170 funcptr::function<size_t(const HTTPBase*,std::ostream&,bool)> renderer; //<! rendering function
171 #endif
172 void write(std::ostream& os) const; //<! writes request to the given output stream
173
174 strstr_map_t& GET() { return getvars; }; //<! acccessor for getvars
175 strstr_map_t& POST() { return postvars; }; //<! accessor for postvars
176 strcookie_map_t& COOKIES() { return jar.cookies; }; //<! accessor for cookies
177
178 std::string versionStr(int version) const {
179 switch(version) {
180 case 9: return "0.9";
181 case 10: return "1.0";
182 case 11: return "1.1";
183 default: throw YaHTTP::Error("Unsupported version");
184 }
185 };
186
187 std::string str() const {
188 std::ostringstream oss;
189 write(oss);
190 return oss.str();
191 }; //<! return string representation of this object
192 };
193
195 class Response: public HTTPBase {
196 public:
197 Response() { initialize(); };
198 Response(const HTTPBase& rhs): HTTPBase(rhs) {
199 this->kind = YAHTTP_TYPE_RESPONSE;
200 };
201 Response& operator=(const HTTPBase& rhs) {
202 HTTPBase::operator=(rhs);
203 this->kind = YAHTTP_TYPE_RESPONSE;
204 return *this;
205 };
206 void initialize() {
207 HTTPBase::initialize();
208 this->kind = YAHTTP_TYPE_RESPONSE;
209 }
210 friend std::ostream& operator<<(std::ostream& os, const Response &resp);
211 friend std::istream& operator>>(std::istream& is, Response &resp);
212 };
213
214 /* Request class, represents a HTTP Request document */
215 class Request: public HTTPBase {
216 public:
217 Request() { initialize(); };
218 Request(const HTTPBase& rhs): HTTPBase(rhs) {
219 this->kind = YAHTTP_TYPE_REQUEST;
220 };
221 Request& operator=(const HTTPBase& rhs) {
222 HTTPBase::operator=(rhs);
223 this->kind = YAHTTP_TYPE_REQUEST;
224 return *this;
225 };
226 void initialize() {
227 HTTPBase::initialize();
228 this->kind = YAHTTP_TYPE_REQUEST;
229 }
230 void setup(const std::string& method, const std::string& url) {
231 this->url.parse(url);
232 this->headers["host"] = this->url.host;
233 this->method = method;
234 std::transform(this->method.begin(), this->method.end(), this->method.begin(), ::toupper);
235 this->headers["user-agent"] = "YaHTTP v1.0";
236 }; //<! Set some initial things for a request
237
238 void preparePost(postformat_t format = urlencoded) {
239 std::ostringstream postbuf;
240 if (format == urlencoded) {
241 for(strstr_map_t::const_iterator i = POST().begin(); i != POST().end(); i++) {
242 postbuf << Utility::encodeURL(i->first, false) << "=" << Utility::encodeURL(i->second, false) << "&";
243 }
244 // remove last bit
245 if (postbuf.str().length()>0)
246 body = postbuf.str().substr(0, postbuf.str().length()-1);
247 else
248 body = "";
249 headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
250 } else if (format == multipart) {
251 headers["content-type"] = "multipart/form-data; boundary=YaHTTP-12ca543";
252 for(strstr_map_t::const_iterator i = POST().begin(); i != POST().end(); i++) {
253 postbuf << "--YaHTTP-12ca543\r\nContent-Disposition: form-data; name=\"" << Utility::encodeURL(i->first, false) << "; charset=UTF-8\r\n\r\n"
254 << Utility::encodeURL(i->second, false) << "\r\n";
255 }
256 }
257
258 postbuf.str("");
259 postbuf << body.length();
260 // set method and change headers
261 method = "POST";
262 headers["content-length"] = postbuf.str();
263 }; //<! convert all postvars into string and stuff it into body
264
265 friend std::ostream& operator<<(std::ostream& os, const Request &resp);
266 friend std::istream& operator>>(std::istream& is, Request &resp);
267 };
268
270 template <class T>
271 class AsyncLoader {
272 public:
273 T* target; //<! target to populate
274 int state; //<! reader state
275 size_t pos; //<! reader position
276
277 std::string buffer; //<! read buffer
278 bool chunked; //<! whether we are parsing chunked data
279 int chunk_size; //<! expected size of next chunk
280 std::ostringstream bodybuf; //<! buffer for body
281 size_t maxbody; //<! maximum size of body
282 size_t minbody; //<! minimum size of body
283 bool hasBody; //<! are we expecting body
284
285 void keyValuePair(const std::string &keyvalue, std::string &key, std::string &value); //<! key value pair parser helper
286
287 void initialize(T* target) {
288 chunked = false; chunk_size = 0;
289 bodybuf.str(""); maxbody = 0;
290 pos = 0; state = 0; this->target = target;
291 hasBody = false;
292 buffer = "";
293 this->target->initialize();
294 }; //<! Initialize the parser for target and clear state
295 int feed(const std::string& somedata); //<! Feed data to the parser
296 bool ready() {
297 return (chunked == true && state == 3) || // if it's chunked we get end of data indication
298 (chunked == false && state > 1 &&
299 (!hasBody ||
300 (bodybuf.str().size() <= maxbody &&
301 bodybuf.str().size() >= minbody)
302 )
303 );
304 }; //<! whether we have received enough data
305 void finalize() {
306 bodybuf.flush();
307 if (ready()) {
308 strstr_map_t::iterator pos = target->headers.find("content-type");
309 if (pos != target->headers.end() && Utility::iequals(pos->second, "application/x-www-form-urlencoded", 32)) {
310 target->postvars = Utility::parseUrlParameters(bodybuf.str());
311 }
312 target->body = bodybuf.str();
313 }
314 bodybuf.str("");
315 this->target = NULL;
316 }; //<! finalize and release target
317 };
318
320 class AsyncResponseLoader: public AsyncLoader<Response> {
321 };
322
324 class AsyncRequestLoader: public AsyncLoader<Request> {
325 };
326
327 };
YAHTTP_MAX_REQUEST_SIZE
#define YAHTTP_MAX_REQUEST_SIZE
Definition: reqresp.hpp:24
YaHTTP::HTTPBase::SendFileRender::path
std::string path
Definition: reqresp.hpp:94
YaHTTP::HTTPBase::url
URL url
Definition: reqresp.hpp:148
YaHTTP::CookieJar::cookies
std::map< std::string, Cookie, ASCIICINullSafeComparator > cookies
Definition: cookie.hpp:49
YaHTTP::HTTPBase::write
void write(std::ostream &os) const
Definition: reqresp.cpp:167
YaHTTP::Response::Response
Response(const HTTPBase &rhs)
Definition: reqresp.hpp:198
YaHTTP::strstr_map_t
std::map< std::string, std::string, ASCIICINullSafeComparator > strstr_map_t
Definition: utility.hpp:22
YaHTTP::AsyncLoader
Definition: reqresp.hpp:271
YaHTTP::HTTPBase::headers
strstr_map_t headers
Definition: reqresp.hpp:156
YaHTTP::HTTPBase::versionStr
std::string versionStr(int version) const
Definition: reqresp.hpp:178
YaHTTP::HTTPBase::SendBodyRender::SendBodyRender
SendBodyRender()
Definition: reqresp.hpp:48
YaHTTP::HTTPBase::kind
int kind
Definition: reqresp.hpp:151
YaHTTP::HTTPBase::str
std::string str() const
Definition: reqresp.hpp:187
YaHTTP::Response::initialize
void initialize()
Definition: reqresp.hpp:206
YaHTTP::Error
Definition: exception.hpp:8
YaHTTP::Utility::encodeURL
static std::string encodeURL(const std::string &component, bool asUrl=true)
Definition: utility.hpp:233
YaHTTP::HTTPBase::SendFileRender
Definition: reqresp.hpp:66
YaHTTP::AsyncResponseLoader
Definition: reqresp.hpp:320
YaHTTP::HTTPBase::max_response_size
ssize_t max_response_size
Definition: reqresp.hpp:167
YAHTTP_MAX_RESPONSE_SIZE
#define YAHTTP_MAX_RESPONSE_SIZE
Definition: reqresp.hpp:28
YaHTTP::HTTPBase::postvars
strstr_map_t postvars
Definition: reqresp.hpp:158
YAHTTP_TYPE_RESPONSE
#define YAHTTP_TYPE_RESPONSE
Definition: reqresp.hpp:32
YaHTTP::AsyncRequestLoader
Definition: reqresp.hpp:324
YaHTTP::Response::operator>>
friend std::istream & operator>>(std::istream &is, Response &resp)
Definition: reqresp.cpp:248
YaHTTP::Response
Definition: reqresp.hpp:195
YaHTTP::Request::Request
Request()
Definition: reqresp.hpp:217
YaHTTP::CookieJar::clear
void clear()
Definition: cookie.hpp:56
YaHTTP::HTTPBase::SendFileRender::SendFileRender
SendFileRender(const std::string &path)
Definition: reqresp.hpp:68
YaHTTP::AsyncLoader::target
T * target
Definition: reqresp.hpp:273
YaHTTP::HTTPBase::parameters
strstr_map_t parameters
Definition: reqresp.hpp:161
YaHTTP::AsyncLoader::bodybuf
std::ostringstream bodybuf
Definition: reqresp.hpp:280
YaHTTP::HTTPBase::body
std::string body
Definition: reqresp.hpp:164
YaHTTP::HTTPBase::COOKIES
strcookie_map_t & COOKIES()
Definition: reqresp.hpp:176
YaHTTP::HTTPBase::GET
strstr_map_t & GET()
Definition: reqresp.hpp:174
YaHTTP::Request::operator<<
friend std::ostream & operator<<(std::ostream &os, const Request &resp)
Definition: reqresp.cpp:266
YaHTTP::AsyncLoader::state
int state
Definition: reqresp.hpp:274
YaHTTP::AsyncLoader::feed
int feed(const std::string &somedata)
Definition: reqresp.cpp:5
YaHTTP::Response::Response
Response()
Definition: reqresp.hpp:197
YaHTTP::Request::initialize
void initialize()
Definition: reqresp.hpp:226
YaHTTP::CookieJar
Definition: cookie.hpp:47
YaHTTP::AsyncLoader::ready
bool ready()
Definition: reqresp.hpp:296
YaHTTP::HTTPBase::status
int status
Definition: reqresp.hpp:152
YaHTTP::HTTPBase::POST
strstr_map_t & POST()
Definition: reqresp.hpp:175
YaHTTP::AsyncLoader::initialize
void initialize(T *target)
Definition: reqresp.hpp:287
YaHTTP::AsyncLoader::chunk_size
int chunk_size
Definition: reqresp.hpp:279
YaHTTP::AsyncLoader::minbody
size_t minbody
Definition: reqresp.hpp:282
YaHTTP::HTTPBase::getvars
strstr_map_t getvars
Definition: reqresp.hpp:159
YaHTTP::HTTPBase::statusText
std::string statusText
Definition: reqresp.hpp:154
YaHTTP::HTTPBase::SendFileRender::operator()
size_t operator()(const HTTPBase *doc __attribute__((unused)), std::ostream &os, bool chunked) const
Definition: reqresp.hpp:72
YaHTTP::HTTPBase
Definition: reqresp.hpp:43
YaHTTP::Response::operator=
Response & operator=(const HTTPBase &rhs)
Definition: reqresp.hpp:201
YaHTTP::Request
Definition: reqresp.hpp:215
YaHTTP::postformat_t
postformat_t
Definition: reqresp.hpp:37
YAHTTP_TYPE_REQUEST
#define YAHTTP_TYPE_REQUEST
Definition: reqresp.hpp:31
YaHTTP::strcookie_map_t
std::map< std::string, Cookie, ASCIICINullSafeComparator > strcookie_map_t
Definition: reqresp.hpp:35
YaHTTP::AsyncLoader::maxbody
size_t maxbody
Definition: reqresp.hpp:281
YaHTTP::HTTPBase::HTTPBase
HTTPBase(const HTTPBase &rhs)
Definition: reqresp.hpp:124
YaHTTP::AsyncLoader::finalize
void finalize()
Definition: reqresp.hpp:305
YaHTTP::Request::setup
void setup(const std::string &method, const std::string &url)
Definition: reqresp.hpp:230
YaHTTP::Request::preparePost
void preparePost(postformat_t format=urlencoded)
Definition: reqresp.hpp:238
YaHTTP::HTTPBase::HTTPBase
HTTPBase()
Definition: reqresp.hpp:99
YaHTTP::Request::operator>>
friend std::istream & operator>>(std::istream &is, Request &resp)
Definition: reqresp.cpp:271
YaHTTP::HTTPBase::SendBodyRender::operator()
size_t operator()(const HTTPBase *doc, std::ostream &os, bool chunked) const
Definition: reqresp.hpp:50
YaHTTP::multipart
Definition: reqresp.hpp:39
YaHTTP::HTTPBase::initialize
virtual void initialize()
Definition: reqresp.hpp:103
YaHTTP::Response::operator<<
friend std::ostream & operator<<(std::ostream &os, const Response &resp)
Definition: reqresp.cpp:243
YaHTTP::AsyncLoader::buffer
std::string buffer
Definition: reqresp.hpp:277
YaHTTP::urlencoded
Definition: reqresp.hpp:38
YaHTTP::AsyncLoader::keyValuePair
void keyValuePair(const std::string &keyvalue, std::string &key, std::string &value)
YaHTTP::HTTPBase::renderer
funcptr::function< size_t(const HTTPBase *, std::ostream &, bool)> renderer
Definition: reqresp.hpp:170
YaHTTP::HTTPBase::operator=
HTTPBase & operator=(const HTTPBase &rhs)
Definition: reqresp.hpp:136
YaHTTP::Utility::parseUrlParameters
static strstr_map_t parseUrlParameters(std::string parameters)
Definition: utility.hpp:349
YaHTTP::AsyncLoader::chunked
bool chunked
Definition: reqresp.hpp:278
YaHTTP::AsyncLoader::hasBody
bool hasBody
Definition: reqresp.hpp:283
YaHTTP::HTTPBase::SendBodyRender
Definition: reqresp.hpp:46
YaHTTP::HTTPBase::method
std::string method
Definition: reqresp.hpp:155
YaHTTP::Request::Request
Request(const HTTPBase &rhs)
Definition: reqresp.hpp:218
YaHTTP::HTTPBase::jar
CookieJar jar
Definition: reqresp.hpp:157
YaHTTP::HTTPBase::max_request_size
ssize_t max_request_size
Definition: reqresp.hpp:166
YaHTTP::AsyncLoader::pos
size_t pos
Definition: reqresp.hpp:275
YaHTTP::Utility::iequals
static bool iequals(const std::string &a, const std::string &b, size_t length)
Definition: utility.hpp:388
YaHTTP::HTTPBase::routeName
std::string routeName
Definition: reqresp.hpp:162
YaHTTP::HTTPBase::version
int version
Definition: reqresp.hpp:153
YaHTTP::Request::operator=
Request & operator=(const HTTPBase &rhs)
Definition: reqresp.hpp:221
YaHTTP::URL
Definition: url.hpp:14