|
1 /* |
|
2 * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu> |
|
3 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions |
|
7 * are met: |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. The name of the author may not be used to endorse or promote products |
|
14 * derived from this software without specific prior written permission. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
26 */ |
|
27 |
|
28 #include "event2/event-config.h" |
|
29 |
|
30 #ifdef _EVENT_HAVE_SYS_PARAM_H |
|
31 #include <sys/param.h> |
|
32 #endif |
|
33 #ifdef _EVENT_HAVE_SYS_TYPES_H |
|
34 #include <sys/types.h> |
|
35 #endif |
|
36 |
|
37 #ifdef _EVENT_HAVE_SYS_TIME_H |
|
38 #include <sys/time.h> |
|
39 #endif |
|
40 #ifdef HAVE_SYS_IOCCOM_H |
|
41 #include <sys/ioccom.h> |
|
42 #endif |
|
43 |
|
44 #ifndef WIN32 |
|
45 #include <sys/resource.h> |
|
46 #include <sys/socket.h> |
|
47 #include <sys/stat.h> |
|
48 #include <sys/wait.h> |
|
49 #else |
|
50 #include <winsock2.h> |
|
51 #include <ws2tcpip.h> |
|
52 #endif |
|
53 |
|
54 #include <sys/queue.h> |
|
55 |
|
56 #ifdef _EVENT_HAVE_NETINET_IN_H |
|
57 #include <netinet/in.h> |
|
58 #endif |
|
59 #ifdef _EVENT_HAVE_ARPA_INET_H |
|
60 #include <arpa/inet.h> |
|
61 #endif |
|
62 #ifdef _EVENT_HAVE_NETDB_H |
|
63 #include <netdb.h> |
|
64 #endif |
|
65 |
|
66 #ifdef WIN32 |
|
67 #include <winsock2.h> |
|
68 #endif |
|
69 |
|
70 #include <errno.h> |
|
71 #include <stdio.h> |
|
72 #include <stdlib.h> |
|
73 #include <string.h> |
|
74 #ifndef WIN32 |
|
75 #include <syslog.h> |
|
76 #endif |
|
77 #include <signal.h> |
|
78 #include <time.h> |
|
79 #ifdef _EVENT_HAVE_UNISTD_H |
|
80 #include <unistd.h> |
|
81 #endif |
|
82 #ifdef _EVENT_HAVE_FCNTL_H |
|
83 #include <fcntl.h> |
|
84 #endif |
|
85 |
|
86 #undef timeout_pending |
|
87 #undef timeout_initialized |
|
88 |
|
89 #include "strlcpy-internal.h" |
|
90 #include "event2/http.h" |
|
91 #include "event2/event.h" |
|
92 #include "event2/buffer.h" |
|
93 #include "event2/bufferevent.h" |
|
94 #include "event2/bufferevent_compat.h" |
|
95 #include "event2/http_struct.h" |
|
96 #include "event2/http_compat.h" |
|
97 #include "event2/util.h" |
|
98 #include "event2/listener.h" |
|
99 #include "log-internal.h" |
|
100 #include "util-internal.h" |
|
101 #include "http-internal.h" |
|
102 #include "mm-internal.h" |
|
103 #include "bufferevent-internal.h" |
|
104 |
|
105 #ifndef _EVENT_HAVE_GETNAMEINFO |
|
106 #define NI_MAXSERV 32 |
|
107 #define NI_MAXHOST 1025 |
|
108 |
|
109 #ifndef NI_NUMERICHOST |
|
110 #define NI_NUMERICHOST 1 |
|
111 #endif |
|
112 |
|
113 #ifndef NI_NUMERICSERV |
|
114 #define NI_NUMERICSERV 2 |
|
115 #endif |
|
116 |
|
117 static int |
|
118 fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, |
|
119 size_t hostlen, char *serv, size_t servlen, int flags) |
|
120 { |
|
121 struct sockaddr_in *sin = (struct sockaddr_in *)sa; |
|
122 |
|
123 if (serv != NULL) { |
|
124 char tmpserv[16]; |
|
125 evutil_snprintf(tmpserv, sizeof(tmpserv), |
|
126 "%d", ntohs(sin->sin_port)); |
|
127 if (strlcpy(serv, tmpserv, servlen) >= servlen) |
|
128 return (-1); |
|
129 } |
|
130 |
|
131 if (host != NULL) { |
|
132 if (flags & NI_NUMERICHOST) { |
|
133 if (strlcpy(host, inet_ntoa(sin->sin_addr), |
|
134 hostlen) >= hostlen) |
|
135 return (-1); |
|
136 else |
|
137 return (0); |
|
138 } else { |
|
139 struct hostent *hp; |
|
140 hp = gethostbyaddr((char *)&sin->sin_addr, |
|
141 sizeof(struct in_addr), AF_INET); |
|
142 if (hp == NULL) |
|
143 return (-2); |
|
144 |
|
145 if (strlcpy(host, hp->h_name, hostlen) >= hostlen) |
|
146 return (-1); |
|
147 else |
|
148 return (0); |
|
149 } |
|
150 } |
|
151 return (0); |
|
152 } |
|
153 |
|
154 #endif |
|
155 |
|
156 #define REQ_VERSION_BEFORE(req, major_v, minor_v) \ |
|
157 ((req)->major < (major_v) || \ |
|
158 ((req)->major == (major_v) && (req)->minor < (minor_v))) |
|
159 |
|
160 #define REQ_VERSION_ATLEAST(req, major_v, minor_v) \ |
|
161 ((req)->major > (major_v) || \ |
|
162 ((req)->major == (major_v) && (req)->minor >= (minor_v))) |
|
163 |
|
164 #ifndef MIN |
|
165 #define MIN(a,b) (((a)<(b))?(a):(b)) |
|
166 #endif |
|
167 |
|
168 extern int debug; |
|
169 |
|
170 static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse); |
|
171 static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse); |
|
172 static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **); |
|
173 static int evhttp_associate_new_request_with_connection( |
|
174 struct evhttp_connection *evcon); |
|
175 static void evhttp_connection_start_detectclose( |
|
176 struct evhttp_connection *evcon); |
|
177 static void evhttp_connection_stop_detectclose( |
|
178 struct evhttp_connection *evcon); |
|
179 static void evhttp_request_dispatch(struct evhttp_connection* evcon); |
|
180 static void evhttp_read_firstline(struct evhttp_connection *evcon, |
|
181 struct evhttp_request *req); |
|
182 static void evhttp_read_header(struct evhttp_connection *evcon, |
|
183 struct evhttp_request *req); |
|
184 static int evhttp_add_header_internal(struct evkeyvalq *headers, |
|
185 const char *key, const char *value); |
|
186 static const char *evhttp_response_phrase_internal(int code); |
|
187 static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t); |
|
188 static void evhttp_write_buffer(struct evhttp_connection *, |
|
189 void (*)(struct evhttp_connection *, void *), void *); |
|
190 static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *); |
|
191 |
|
192 /* callbacks for bufferevent */ |
|
193 static void evhttp_read_cb(struct bufferevent *, void *); |
|
194 static void evhttp_write_cb(struct bufferevent *, void *); |
|
195 static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg); |
|
196 static int evhttp_decode_uri_internal(const char *uri, size_t length, |
|
197 char *ret, int decode_plus); |
|
198 static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, |
|
199 const char *hostname); |
|
200 |
|
201 #ifndef _EVENT_HAVE_STRSEP |
|
202 /* strsep replacement for platforms that lack it. Only works if |
|
203 * del is one character long. */ |
|
204 static char * |
|
205 strsep(char **s, const char *del) |
|
206 { |
|
207 char *d, *tok; |
|
208 EVUTIL_ASSERT(strlen(del) == 1); |
|
209 if (!s || !*s) |
|
210 return NULL; |
|
211 tok = *s; |
|
212 d = strstr(tok, del); |
|
213 if (d) { |
|
214 *d = '\0'; |
|
215 *s = d + 1; |
|
216 } else |
|
217 *s = NULL; |
|
218 return tok; |
|
219 } |
|
220 #endif |
|
221 |
|
222 static size_t |
|
223 html_replace(const char ch, const char **escaped) |
|
224 { |
|
225 switch (ch) { |
|
226 case '<': |
|
227 *escaped = "<"; |
|
228 return 4; |
|
229 case '>': |
|
230 *escaped = ">"; |
|
231 return 4; |
|
232 case '"': |
|
233 *escaped = """; |
|
234 return 6; |
|
235 case '\'': |
|
236 *escaped = "'"; |
|
237 return 6; |
|
238 case '&': |
|
239 *escaped = "&"; |
|
240 return 5; |
|
241 default: |
|
242 break; |
|
243 } |
|
244 |
|
245 return 1; |
|
246 } |
|
247 |
|
248 /* |
|
249 * Replaces <, >, ", ' and & with <, >, ", |
|
250 * ' and & correspondingly. |
|
251 * |
|
252 * The returned string needs to be freed by the caller. |
|
253 */ |
|
254 |
|
255 char * |
|
256 evhttp_htmlescape(const char *html) |
|
257 { |
|
258 size_t i; |
|
259 size_t new_size = 0, old_size = 0; |
|
260 char *escaped_html, *p; |
|
261 |
|
262 if (html == NULL) |
|
263 return (NULL); |
|
264 |
|
265 old_size = strlen(html); |
|
266 for (i = 0; i < old_size; ++i) { |
|
267 const char *replaced = NULL; |
|
268 const size_t replace_size = html_replace(html[i], &replaced); |
|
269 if (replace_size > EV_SIZE_MAX - new_size) { |
|
270 event_warn("%s: html_replace overflow", __func__); |
|
271 return (NULL); |
|
272 } |
|
273 new_size += replace_size; |
|
274 } |
|
275 |
|
276 if (new_size == EV_SIZE_MAX) |
|
277 return (NULL); |
|
278 p = escaped_html = mm_malloc(new_size + 1); |
|
279 if (escaped_html == NULL) { |
|
280 event_warn("%s: malloc(%lu)", __func__, |
|
281 (unsigned long)(new_size + 1)); |
|
282 return (NULL); |
|
283 } |
|
284 for (i = 0; i < old_size; ++i) { |
|
285 const char *replaced = &html[i]; |
|
286 const size_t len = html_replace(html[i], &replaced); |
|
287 memcpy(p, replaced, len); |
|
288 p += len; |
|
289 } |
|
290 |
|
291 *p = '\0'; |
|
292 |
|
293 return (escaped_html); |
|
294 } |
|
295 |
|
296 /** Given an evhttp_cmd_type, returns a constant string containing the |
|
297 * equivalent HTTP command, or NULL if the evhttp_command_type is |
|
298 * unrecognized. */ |
|
299 static const char * |
|
300 evhttp_method(enum evhttp_cmd_type type) |
|
301 { |
|
302 const char *method; |
|
303 |
|
304 switch (type) { |
|
305 case EVHTTP_REQ_GET: |
|
306 method = "GET"; |
|
307 break; |
|
308 case EVHTTP_REQ_POST: |
|
309 method = "POST"; |
|
310 break; |
|
311 case EVHTTP_REQ_HEAD: |
|
312 method = "HEAD"; |
|
313 break; |
|
314 case EVHTTP_REQ_PUT: |
|
315 method = "PUT"; |
|
316 break; |
|
317 case EVHTTP_REQ_DELETE: |
|
318 method = "DELETE"; |
|
319 break; |
|
320 case EVHTTP_REQ_OPTIONS: |
|
321 method = "OPTIONS"; |
|
322 break; |
|
323 case EVHTTP_REQ_TRACE: |
|
324 method = "TRACE"; |
|
325 break; |
|
326 case EVHTTP_REQ_CONNECT: |
|
327 method = "CONNECT"; |
|
328 break; |
|
329 case EVHTTP_REQ_PATCH: |
|
330 method = "PATCH"; |
|
331 break; |
|
332 default: |
|
333 method = NULL; |
|
334 break; |
|
335 } |
|
336 |
|
337 return (method); |
|
338 } |
|
339 |
|
340 /** |
|
341 * Determines if a response should have a body. |
|
342 * Follows the rules in RFC 2616 section 4.3. |
|
343 * @return 1 if the response MUST have a body; 0 if the response MUST NOT have |
|
344 * a body. |
|
345 */ |
|
346 static int |
|
347 evhttp_response_needs_body(struct evhttp_request *req) |
|
348 { |
|
349 return (req->response_code != HTTP_NOCONTENT && |
|
350 req->response_code != HTTP_NOTMODIFIED && |
|
351 (req->response_code < 100 || req->response_code >= 200) && |
|
352 req->type != EVHTTP_REQ_HEAD); |
|
353 } |
|
354 |
|
355 /** Helper: adds the event 'ev' with the timeout 'timeout', or with |
|
356 * default_timeout if timeout is -1. |
|
357 */ |
|
358 static int |
|
359 evhttp_add_event(struct event *ev, int timeout, int default_timeout) |
|
360 { |
|
361 if (timeout != 0) { |
|
362 struct timeval tv; |
|
363 |
|
364 evutil_timerclear(&tv); |
|
365 tv.tv_sec = timeout != -1 ? timeout : default_timeout; |
|
366 return event_add(ev, &tv); |
|
367 } else { |
|
368 return event_add(ev, NULL); |
|
369 } |
|
370 } |
|
371 |
|
372 /** Helper: called after we've added some data to an evcon's bufferevent's |
|
373 * output buffer. Sets the evconn's writing-is-done callback, and puts |
|
374 * the bufferevent into writing mode. |
|
375 */ |
|
376 static void |
|
377 evhttp_write_buffer(struct evhttp_connection *evcon, |
|
378 void (*cb)(struct evhttp_connection *, void *), void *arg) |
|
379 { |
|
380 event_debug(("%s: preparing to write buffer\n", __func__)); |
|
381 |
|
382 /* Set call back */ |
|
383 evcon->cb = cb; |
|
384 evcon->cb_arg = arg; |
|
385 |
|
386 bufferevent_enable(evcon->bufev, EV_WRITE); |
|
387 |
|
388 /* Disable the read callback: we don't actually care about data; |
|
389 * we only care about close detection. (We don't disable reading, |
|
390 * since we *do* want to learn about any close events.) */ |
|
391 bufferevent_setcb(evcon->bufev, |
|
392 NULL, /*read*/ |
|
393 evhttp_write_cb, |
|
394 evhttp_error_cb, |
|
395 evcon); |
|
396 } |
|
397 |
|
398 static void |
|
399 evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg) |
|
400 { |
|
401 bufferevent_disable(evcon->bufev, EV_WRITE); |
|
402 } |
|
403 |
|
404 static void |
|
405 evhttp_send_continue(struct evhttp_connection *evcon, |
|
406 struct evhttp_request *req) |
|
407 { |
|
408 bufferevent_enable(evcon->bufev, EV_WRITE); |
|
409 evbuffer_add_printf(bufferevent_get_output(evcon->bufev), |
|
410 "HTTP/%d.%d 100 Continue\r\n\r\n", |
|
411 req->major, req->minor); |
|
412 evcon->cb = evhttp_send_continue_done; |
|
413 evcon->cb_arg = NULL; |
|
414 bufferevent_setcb(evcon->bufev, |
|
415 evhttp_read_cb, |
|
416 evhttp_write_cb, |
|
417 evhttp_error_cb, |
|
418 evcon); |
|
419 } |
|
420 |
|
421 /** Helper: returns true iff evconn is in any connected state. */ |
|
422 static int |
|
423 evhttp_connected(struct evhttp_connection *evcon) |
|
424 { |
|
425 switch (evcon->state) { |
|
426 case EVCON_DISCONNECTED: |
|
427 case EVCON_CONNECTING: |
|
428 return (0); |
|
429 case EVCON_IDLE: |
|
430 case EVCON_READING_FIRSTLINE: |
|
431 case EVCON_READING_HEADERS: |
|
432 case EVCON_READING_BODY: |
|
433 case EVCON_READING_TRAILER: |
|
434 case EVCON_WRITING: |
|
435 default: |
|
436 return (1); |
|
437 } |
|
438 } |
|
439 |
|
440 /* Create the headers needed for an outgoing HTTP request, adds them to |
|
441 * the request's header list, and writes the request line to the |
|
442 * connection's output buffer. |
|
443 */ |
|
444 static void |
|
445 evhttp_make_header_request(struct evhttp_connection *evcon, |
|
446 struct evhttp_request *req) |
|
447 { |
|
448 const char *method; |
|
449 |
|
450 evhttp_remove_header(req->output_headers, "Proxy-Connection"); |
|
451 |
|
452 /* Generate request line */ |
|
453 method = evhttp_method(req->type); |
|
454 evbuffer_add_printf(bufferevent_get_output(evcon->bufev), |
|
455 "%s %s HTTP/%d.%d\r\n", |
|
456 method, req->uri, req->major, req->minor); |
|
457 |
|
458 /* Add the content length on a post or put request if missing */ |
|
459 if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) && |
|
460 evhttp_find_header(req->output_headers, "Content-Length") == NULL){ |
|
461 char size[22]; |
|
462 evutil_snprintf(size, sizeof(size), EV_SIZE_FMT, |
|
463 EV_SIZE_ARG(evbuffer_get_length(req->output_buffer))); |
|
464 evhttp_add_header(req->output_headers, "Content-Length", size); |
|
465 } |
|
466 } |
|
467 |
|
468 /** Return true if the list of headers in 'headers', intepreted with respect |
|
469 * to flags, means that we should send a "connection: close" when the request |
|
470 * is done. */ |
|
471 static int |
|
472 evhttp_is_connection_close(int flags, struct evkeyvalq* headers) |
|
473 { |
|
474 if (flags & EVHTTP_PROXY_REQUEST) { |
|
475 /* proxy connection */ |
|
476 const char *connection = evhttp_find_header(headers, "Proxy-Connection"); |
|
477 return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0); |
|
478 } else { |
|
479 const char *connection = evhttp_find_header(headers, "Connection"); |
|
480 return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0); |
|
481 } |
|
482 } |
|
483 |
|
484 /* Return true iff 'headers' contains 'Connection: keep-alive' */ |
|
485 static int |
|
486 evhttp_is_connection_keepalive(struct evkeyvalq* headers) |
|
487 { |
|
488 const char *connection = evhttp_find_header(headers, "Connection"); |
|
489 return (connection != NULL |
|
490 && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0); |
|
491 } |
|
492 |
|
493 /* Add a correct "Date" header to headers, unless it already has one. */ |
|
494 static void |
|
495 evhttp_maybe_add_date_header(struct evkeyvalq *headers) |
|
496 { |
|
497 if (evhttp_find_header(headers, "Date") == NULL) { |
|
498 char date[50]; |
|
499 #ifndef WIN32 |
|
500 struct tm cur; |
|
501 #endif |
|
502 struct tm *cur_p; |
|
503 time_t t = time(NULL); |
|
504 #ifdef WIN32 |
|
505 cur_p = gmtime(&t); |
|
506 #else |
|
507 gmtime_r(&t, &cur); |
|
508 cur_p = &cur; |
|
509 #endif |
|
510 if (strftime(date, sizeof(date), |
|
511 "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) { |
|
512 evhttp_add_header(headers, "Date", date); |
|
513 } |
|
514 } |
|
515 } |
|
516 |
|
517 /* Add a "Content-Length" header with value 'content_length' to headers, |
|
518 * unless it already has a content-length or transfer-encoding header. */ |
|
519 static void |
|
520 evhttp_maybe_add_content_length_header(struct evkeyvalq *headers, |
|
521 size_t content_length) |
|
522 { |
|
523 if (evhttp_find_header(headers, "Transfer-Encoding") == NULL && |
|
524 evhttp_find_header(headers, "Content-Length") == NULL) { |
|
525 char len[22]; |
|
526 evutil_snprintf(len, sizeof(len), EV_SIZE_FMT, |
|
527 EV_SIZE_ARG(content_length)); |
|
528 evhttp_add_header(headers, "Content-Length", len); |
|
529 } |
|
530 } |
|
531 |
|
532 /* |
|
533 * Create the headers needed for an HTTP reply in req->output_headers, |
|
534 * and write the first HTTP response for req line to evcon. |
|
535 */ |
|
536 static void |
|
537 evhttp_make_header_response(struct evhttp_connection *evcon, |
|
538 struct evhttp_request *req) |
|
539 { |
|
540 int is_keepalive = evhttp_is_connection_keepalive(req->input_headers); |
|
541 evbuffer_add_printf(bufferevent_get_output(evcon->bufev), |
|
542 "HTTP/%d.%d %d %s\r\n", |
|
543 req->major, req->minor, req->response_code, |
|
544 req->response_code_line); |
|
545 |
|
546 if (req->major == 1) { |
|
547 if (req->minor >= 1) |
|
548 evhttp_maybe_add_date_header(req->output_headers); |
|
549 |
|
550 /* |
|
551 * if the protocol is 1.0; and the connection was keep-alive |
|
552 * we need to add a keep-alive header, too. |
|
553 */ |
|
554 if (req->minor == 0 && is_keepalive) |
|
555 evhttp_add_header(req->output_headers, |
|
556 "Connection", "keep-alive"); |
|
557 |
|
558 if ((req->minor >= 1 || is_keepalive) && |
|
559 evhttp_response_needs_body(req)) { |
|
560 /* |
|
561 * we need to add the content length if the |
|
562 * user did not give it, this is required for |
|
563 * persistent connections to work. |
|
564 */ |
|
565 evhttp_maybe_add_content_length_header( |
|
566 req->output_headers, |
|
567 evbuffer_get_length(req->output_buffer)); |
|
568 } |
|
569 } |
|
570 |
|
571 /* Potentially add headers for unidentified content. */ |
|
572 if (evhttp_response_needs_body(req)) { |
|
573 if (evhttp_find_header(req->output_headers, |
|
574 "Content-Type") == NULL) { |
|
575 evhttp_add_header(req->output_headers, |
|
576 "Content-Type", "text/html; charset=ISO-8859-1"); |
|
577 } |
|
578 } |
|
579 |
|
580 /* if the request asked for a close, we send a close, too */ |
|
581 if (evhttp_is_connection_close(req->flags, req->input_headers)) { |
|
582 evhttp_remove_header(req->output_headers, "Connection"); |
|
583 if (!(req->flags & EVHTTP_PROXY_REQUEST)) |
|
584 evhttp_add_header(req->output_headers, "Connection", "close"); |
|
585 evhttp_remove_header(req->output_headers, "Proxy-Connection"); |
|
586 } |
|
587 } |
|
588 |
|
589 /** Generate all headers appropriate for sending the http request in req (or |
|
590 * the response, if we're sending a response), and write them to evcon's |
|
591 * bufferevent. Also writes all data from req->output_buffer */ |
|
592 static void |
|
593 evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req) |
|
594 { |
|
595 struct evkeyval *header; |
|
596 struct evbuffer *output = bufferevent_get_output(evcon->bufev); |
|
597 |
|
598 /* |
|
599 * Depending if this is a HTTP request or response, we might need to |
|
600 * add some new headers or remove existing headers. |
|
601 */ |
|
602 if (req->kind == EVHTTP_REQUEST) { |
|
603 evhttp_make_header_request(evcon, req); |
|
604 } else { |
|
605 evhttp_make_header_response(evcon, req); |
|
606 } |
|
607 |
|
608 TAILQ_FOREACH(header, req->output_headers, next) { |
|
609 evbuffer_add_printf(output, "%s: %s\r\n", |
|
610 header->key, header->value); |
|
611 } |
|
612 evbuffer_add(output, "\r\n", 2); |
|
613 |
|
614 if (evbuffer_get_length(req->output_buffer) > 0) { |
|
615 /* |
|
616 * For a request, we add the POST data, for a reply, this |
|
617 * is the regular data. |
|
618 */ |
|
619 /* XXX We might want to support waiting (a limited amount of |
|
620 time) for a continue status line from the server before |
|
621 sending POST/PUT message bodies. */ |
|
622 evbuffer_add_buffer(output, req->output_buffer); |
|
623 } |
|
624 } |
|
625 |
|
626 void |
|
627 evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, |
|
628 ev_ssize_t new_max_headers_size) |
|
629 { |
|
630 if (new_max_headers_size<0) |
|
631 evcon->max_headers_size = EV_SIZE_MAX; |
|
632 else |
|
633 evcon->max_headers_size = new_max_headers_size; |
|
634 } |
|
635 void |
|
636 evhttp_connection_set_max_body_size(struct evhttp_connection* evcon, |
|
637 ev_ssize_t new_max_body_size) |
|
638 { |
|
639 if (new_max_body_size<0) |
|
640 evcon->max_body_size = EV_UINT64_MAX; |
|
641 else |
|
642 evcon->max_body_size = new_max_body_size; |
|
643 } |
|
644 |
|
645 static int |
|
646 evhttp_connection_incoming_fail(struct evhttp_request *req, |
|
647 enum evhttp_connection_error error) |
|
648 { |
|
649 switch (error) { |
|
650 case EVCON_HTTP_TIMEOUT: |
|
651 case EVCON_HTTP_EOF: |
|
652 /* |
|
653 * these are cases in which we probably should just |
|
654 * close the connection and not send a reply. this |
|
655 * case may happen when a browser keeps a persistent |
|
656 * connection open and we timeout on the read. when |
|
657 * the request is still being used for sending, we |
|
658 * need to disassociated it from the connection here. |
|
659 */ |
|
660 if (!req->userdone) { |
|
661 /* remove it so that it will not be freed */ |
|
662 TAILQ_REMOVE(&req->evcon->requests, req, next); |
|
663 /* indicate that this request no longer has a |
|
664 * connection object |
|
665 */ |
|
666 req->evcon = NULL; |
|
667 } |
|
668 return (-1); |
|
669 case EVCON_HTTP_INVALID_HEADER: |
|
670 case EVCON_HTTP_BUFFER_ERROR: |
|
671 case EVCON_HTTP_REQUEST_CANCEL: |
|
672 default: /* xxx: probably should just error on default */ |
|
673 /* the callback looks at the uri to determine errors */ |
|
674 if (req->uri) { |
|
675 mm_free(req->uri); |
|
676 req->uri = NULL; |
|
677 } |
|
678 if (req->uri_elems) { |
|
679 evhttp_uri_free(req->uri_elems); |
|
680 req->uri_elems = NULL; |
|
681 } |
|
682 |
|
683 /* |
|
684 * the callback needs to send a reply, once the reply has |
|
685 * been send, the connection should get freed. |
|
686 */ |
|
687 (*req->cb)(req, req->cb_arg); |
|
688 } |
|
689 |
|
690 return (0); |
|
691 } |
|
692 |
|
693 /* Called when evcon has experienced a (non-recoverable? -NM) error, as |
|
694 * given in error. If it's an outgoing connection, reset the connection, |
|
695 * retry any pending requests, and inform the user. If it's incoming, |
|
696 * delegates to evhttp_connection_incoming_fail(). */ |
|
697 void |
|
698 evhttp_connection_fail(struct evhttp_connection *evcon, |
|
699 enum evhttp_connection_error error) |
|
700 { |
|
701 struct evhttp_request* req = TAILQ_FIRST(&evcon->requests); |
|
702 void (*cb)(struct evhttp_request *, void *); |
|
703 void *cb_arg; |
|
704 EVUTIL_ASSERT(req != NULL); |
|
705 |
|
706 bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE); |
|
707 |
|
708 if (evcon->flags & EVHTTP_CON_INCOMING) { |
|
709 /* |
|
710 * for incoming requests, there are two different |
|
711 * failure cases. it's either a network level error |
|
712 * or an http layer error. for problems on the network |
|
713 * layer like timeouts we just drop the connections. |
|
714 * For HTTP problems, we might have to send back a |
|
715 * reply before the connection can be freed. |
|
716 */ |
|
717 if (evhttp_connection_incoming_fail(req, error) == -1) |
|
718 evhttp_connection_free(evcon); |
|
719 return; |
|
720 } |
|
721 |
|
722 /* when the request was canceled, the callback is not executed */ |
|
723 if (error != EVCON_HTTP_REQUEST_CANCEL) { |
|
724 /* save the callback for later; the cb might free our object */ |
|
725 cb = req->cb; |
|
726 cb_arg = req->cb_arg; |
|
727 } else { |
|
728 cb = NULL; |
|
729 cb_arg = NULL; |
|
730 } |
|
731 |
|
732 /* do not fail all requests; the next request is going to get |
|
733 * send over a new connection. when a user cancels a request, |
|
734 * all other pending requests should be processed as normal |
|
735 */ |
|
736 TAILQ_REMOVE(&evcon->requests, req, next); |
|
737 evhttp_request_free(req); |
|
738 |
|
739 /* reset the connection */ |
|
740 evhttp_connection_reset(evcon); |
|
741 |
|
742 /* We are trying the next request that was queued on us */ |
|
743 if (TAILQ_FIRST(&evcon->requests) != NULL) |
|
744 evhttp_connection_connect(evcon); |
|
745 |
|
746 /* inform the user */ |
|
747 if (cb != NULL) |
|
748 (*cb)(NULL, cb_arg); |
|
749 } |
|
750 |
|
751 /* Bufferevent callback: invoked when any data has been written from an |
|
752 * http connection's bufferevent */ |
|
753 static void |
|
754 evhttp_write_cb(struct bufferevent *bufev, void *arg) |
|
755 { |
|
756 struct evhttp_connection *evcon = arg; |
|
757 |
|
758 /* Activate our call back */ |
|
759 if (evcon->cb != NULL) |
|
760 (*evcon->cb)(evcon, evcon->cb_arg); |
|
761 } |
|
762 |
|
763 /** |
|
764 * Advance the connection state. |
|
765 * - If this is an outgoing connection, we've just processed the response; |
|
766 * idle or close the connection. |
|
767 * - If this is an incoming connection, we've just processed the request; |
|
768 * respond. |
|
769 */ |
|
770 static void |
|
771 evhttp_connection_done(struct evhttp_connection *evcon) |
|
772 { |
|
773 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); |
|
774 int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING; |
|
775 |
|
776 if (con_outgoing) { |
|
777 /* idle or close the connection */ |
|
778 int need_close; |
|
779 TAILQ_REMOVE(&evcon->requests, req, next); |
|
780 req->evcon = NULL; |
|
781 |
|
782 evcon->state = EVCON_IDLE; |
|
783 |
|
784 need_close = |
|
785 evhttp_is_connection_close(req->flags, req->input_headers)|| |
|
786 evhttp_is_connection_close(req->flags, req->output_headers); |
|
787 |
|
788 /* check if we got asked to close the connection */ |
|
789 if (need_close) |
|
790 evhttp_connection_reset(evcon); |
|
791 |
|
792 if (TAILQ_FIRST(&evcon->requests) != NULL) { |
|
793 /* |
|
794 * We have more requests; reset the connection |
|
795 * and deal with the next request. |
|
796 */ |
|
797 if (!evhttp_connected(evcon)) |
|
798 evhttp_connection_connect(evcon); |
|
799 else |
|
800 evhttp_request_dispatch(evcon); |
|
801 } else if (!need_close) { |
|
802 /* |
|
803 * The connection is going to be persistent, but we |
|
804 * need to detect if the other side closes it. |
|
805 */ |
|
806 evhttp_connection_start_detectclose(evcon); |
|
807 } |
|
808 } else { |
|
809 /* |
|
810 * incoming connection - we need to leave the request on the |
|
811 * connection so that we can reply to it. |
|
812 */ |
|
813 evcon->state = EVCON_WRITING; |
|
814 } |
|
815 |
|
816 /* notify the user of the request */ |
|
817 (*req->cb)(req, req->cb_arg); |
|
818 |
|
819 /* if this was an outgoing request, we own and it's done. so free it. |
|
820 * unless the callback specifically requested to own the request. |
|
821 */ |
|
822 if (con_outgoing && ((req->flags & EVHTTP_USER_OWNED) == 0)) { |
|
823 evhttp_request_free(req); |
|
824 } |
|
825 } |
|
826 |
|
827 /* |
|
828 * Handles reading from a chunked request. |
|
829 * return ALL_DATA_READ: |
|
830 * all data has been read |
|
831 * return MORE_DATA_EXPECTED: |
|
832 * more data is expected |
|
833 * return DATA_CORRUPTED: |
|
834 * data is corrupted |
|
835 * return REQUEST_CANCELED: |
|
836 * request was canceled by the user calling evhttp_cancel_request |
|
837 * return DATA_TOO_LONG: |
|
838 * ran over the maximum limit |
|
839 */ |
|
840 |
|
841 static enum message_read_status |
|
842 evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) |
|
843 { |
|
844 if (req == NULL || buf == NULL) { |
|
845 return DATA_CORRUPTED; |
|
846 } |
|
847 |
|
848 while (1) { |
|
849 size_t buflen; |
|
850 |
|
851 if ((buflen = evbuffer_get_length(buf)) == 0) { |
|
852 break; |
|
853 } |
|
854 |
|
855 /* evbuffer_get_length returns size_t, but len variable is ssize_t, |
|
856 * check for overflow conditions */ |
|
857 if (buflen > EV_SSIZE_MAX) { |
|
858 return DATA_CORRUPTED; |
|
859 } |
|
860 |
|
861 if (req->ntoread < 0) { |
|
862 /* Read chunk size */ |
|
863 ev_int64_t ntoread; |
|
864 char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF); |
|
865 char *endp; |
|
866 int error; |
|
867 if (p == NULL) |
|
868 break; |
|
869 /* the last chunk is on a new line? */ |
|
870 if (strlen(p) == 0) { |
|
871 mm_free(p); |
|
872 continue; |
|
873 } |
|
874 ntoread = evutil_strtoll(p, &endp, 16); |
|
875 error = (*p == '\0' || |
|
876 (*endp != '\0' && *endp != ' ') || |
|
877 ntoread < 0); |
|
878 mm_free(p); |
|
879 if (error) { |
|
880 /* could not get chunk size */ |
|
881 return (DATA_CORRUPTED); |
|
882 } |
|
883 |
|
884 /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */ |
|
885 if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) { |
|
886 return DATA_CORRUPTED; |
|
887 } |
|
888 |
|
889 if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) { |
|
890 /* failed body length test */ |
|
891 event_debug(("Request body is too long")); |
|
892 return (DATA_TOO_LONG); |
|
893 } |
|
894 |
|
895 req->body_size += (size_t)ntoread; |
|
896 req->ntoread = ntoread; |
|
897 if (req->ntoread == 0) { |
|
898 /* Last chunk */ |
|
899 return (ALL_DATA_READ); |
|
900 } |
|
901 continue; |
|
902 } |
|
903 |
|
904 /* req->ntoread is signed int64, len is ssize_t, based on arch, |
|
905 * ssize_t could only be 32b, check for these conditions */ |
|
906 if (req->ntoread > EV_SSIZE_MAX) { |
|
907 return DATA_CORRUPTED; |
|
908 } |
|
909 |
|
910 /* don't have enough to complete a chunk; wait for more */ |
|
911 if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread) |
|
912 return (MORE_DATA_EXPECTED); |
|
913 |
|
914 /* Completed chunk */ |
|
915 evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread); |
|
916 req->ntoread = -1; |
|
917 if (req->chunk_cb != NULL) { |
|
918 req->flags |= EVHTTP_REQ_DEFER_FREE; |
|
919 (*req->chunk_cb)(req, req->cb_arg); |
|
920 evbuffer_drain(req->input_buffer, |
|
921 evbuffer_get_length(req->input_buffer)); |
|
922 req->flags &= ~EVHTTP_REQ_DEFER_FREE; |
|
923 if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { |
|
924 return (REQUEST_CANCELED); |
|
925 } |
|
926 } |
|
927 } |
|
928 |
|
929 return (MORE_DATA_EXPECTED); |
|
930 } |
|
931 |
|
932 static void |
|
933 evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req) |
|
934 { |
|
935 struct evbuffer *buf = bufferevent_get_input(evcon->bufev); |
|
936 |
|
937 switch (evhttp_parse_headers(req, buf)) { |
|
938 case DATA_CORRUPTED: |
|
939 case DATA_TOO_LONG: |
|
940 evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); |
|
941 break; |
|
942 case ALL_DATA_READ: |
|
943 bufferevent_disable(evcon->bufev, EV_READ); |
|
944 evhttp_connection_done(evcon); |
|
945 break; |
|
946 case MORE_DATA_EXPECTED: |
|
947 case REQUEST_CANCELED: /* ??? */ |
|
948 default: |
|
949 bufferevent_enable(evcon->bufev, EV_READ); |
|
950 break; |
|
951 } |
|
952 } |
|
953 |
|
954 static void |
|
955 evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) |
|
956 { |
|
957 struct evbuffer *buf = bufferevent_get_input(evcon->bufev); |
|
958 |
|
959 if (req->chunked) { |
|
960 switch (evhttp_handle_chunked_read(req, buf)) { |
|
961 case ALL_DATA_READ: |
|
962 /* finished last chunk */ |
|
963 evcon->state = EVCON_READING_TRAILER; |
|
964 evhttp_read_trailer(evcon, req); |
|
965 return; |
|
966 case DATA_CORRUPTED: |
|
967 case DATA_TOO_LONG:/*separate error for this? XXX */ |
|
968 /* corrupted data */ |
|
969 evhttp_connection_fail(evcon, |
|
970 EVCON_HTTP_INVALID_HEADER); |
|
971 return; |
|
972 case REQUEST_CANCELED: |
|
973 /* request canceled */ |
|
974 evhttp_request_free(req); |
|
975 return; |
|
976 case MORE_DATA_EXPECTED: |
|
977 default: |
|
978 break; |
|
979 } |
|
980 } else if (req->ntoread < 0) { |
|
981 /* Read until connection close. */ |
|
982 if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) { |
|
983 evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); |
|
984 return; |
|
985 } |
|
986 |
|
987 req->body_size += evbuffer_get_length(buf); |
|
988 evbuffer_add_buffer(req->input_buffer, buf); |
|
989 } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) { |
|
990 /* XXX: the above get_length comparison has to be fixed for overflow conditions! */ |
|
991 /* We've postponed moving the data until now, but we're |
|
992 * about to use it. */ |
|
993 size_t n = evbuffer_get_length(buf); |
|
994 |
|
995 if (n > (size_t) req->ntoread) |
|
996 n = (size_t) req->ntoread; |
|
997 req->ntoread -= n; |
|
998 req->body_size += n; |
|
999 evbuffer_remove_buffer(buf, req->input_buffer, n); |
|
1000 } |
|
1001 |
|
1002 if (req->body_size > req->evcon->max_body_size || |
|
1003 (!req->chunked && req->ntoread >= 0 && |
|
1004 (size_t)req->ntoread > req->evcon->max_body_size)) { |
|
1005 /* XXX: The above casted comparison must checked for overflow */ |
|
1006 /* failed body length test */ |
|
1007 event_debug(("Request body is too long")); |
|
1008 evhttp_connection_fail(evcon, |
|
1009 EVCON_HTTP_INVALID_HEADER); |
|
1010 return; |
|
1011 } |
|
1012 |
|
1013 if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) { |
|
1014 req->flags |= EVHTTP_REQ_DEFER_FREE; |
|
1015 (*req->chunk_cb)(req, req->cb_arg); |
|
1016 req->flags &= ~EVHTTP_REQ_DEFER_FREE; |
|
1017 evbuffer_drain(req->input_buffer, |
|
1018 evbuffer_get_length(req->input_buffer)); |
|
1019 if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { |
|
1020 evhttp_request_free(req); |
|
1021 return; |
|
1022 } |
|
1023 } |
|
1024 |
|
1025 if (req->ntoread == 0) { |
|
1026 bufferevent_disable(evcon->bufev, EV_READ); |
|
1027 /* Completed content length */ |
|
1028 evhttp_connection_done(evcon); |
|
1029 return; |
|
1030 } |
|
1031 |
|
1032 /* Read more! */ |
|
1033 bufferevent_enable(evcon->bufev, EV_READ); |
|
1034 } |
|
1035 |
|
1036 #define get_deferred_queue(evcon) \ |
|
1037 (event_base_get_deferred_cb_queue((evcon)->base)) |
|
1038 |
|
1039 /* |
|
1040 * Gets called when more data becomes available |
|
1041 */ |
|
1042 |
|
1043 static void |
|
1044 evhttp_read_cb(struct bufferevent *bufev, void *arg) |
|
1045 { |
|
1046 struct evhttp_connection *evcon = arg; |
|
1047 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); |
|
1048 |
|
1049 /* Cancel if it's pending. */ |
|
1050 event_deferred_cb_cancel(get_deferred_queue(evcon), |
|
1051 &evcon->read_more_deferred_cb); |
|
1052 |
|
1053 switch (evcon->state) { |
|
1054 case EVCON_READING_FIRSTLINE: |
|
1055 evhttp_read_firstline(evcon, req); |
|
1056 /* note the request may have been freed in |
|
1057 * evhttp_read_body */ |
|
1058 break; |
|
1059 case EVCON_READING_HEADERS: |
|
1060 evhttp_read_header(evcon, req); |
|
1061 /* note the request may have been freed in |
|
1062 * evhttp_read_body */ |
|
1063 break; |
|
1064 case EVCON_READING_BODY: |
|
1065 evhttp_read_body(evcon, req); |
|
1066 /* note the request may have been freed in |
|
1067 * evhttp_read_body */ |
|
1068 break; |
|
1069 case EVCON_READING_TRAILER: |
|
1070 evhttp_read_trailer(evcon, req); |
|
1071 break; |
|
1072 case EVCON_IDLE: |
|
1073 { |
|
1074 #ifdef USE_DEBUG |
|
1075 struct evbuffer *input; |
|
1076 size_t total_len; |
|
1077 |
|
1078 input = bufferevent_get_input(evcon->bufev); |
|
1079 total_len = evbuffer_get_length(input); |
|
1080 event_debug(("%s: read "EV_SIZE_FMT |
|
1081 " bytes in EVCON_IDLE state," |
|
1082 " resetting connection", |
|
1083 __func__, EV_SIZE_ARG(total_len))); |
|
1084 #endif |
|
1085 |
|
1086 evhttp_connection_reset(evcon); |
|
1087 } |
|
1088 break; |
|
1089 case EVCON_DISCONNECTED: |
|
1090 case EVCON_CONNECTING: |
|
1091 case EVCON_WRITING: |
|
1092 default: |
|
1093 event_errx(1, "%s: illegal connection state %d", |
|
1094 __func__, evcon->state); |
|
1095 } |
|
1096 } |
|
1097 |
|
1098 static void |
|
1099 evhttp_deferred_read_cb(struct deferred_cb *cb, void *data) |
|
1100 { |
|
1101 struct evhttp_connection *evcon = data; |
|
1102 evhttp_read_cb(evcon->bufev, evcon); |
|
1103 } |
|
1104 |
|
1105 static void |
|
1106 evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg) |
|
1107 { |
|
1108 /* This is after writing the request to the server */ |
|
1109 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); |
|
1110 EVUTIL_ASSERT(req != NULL); |
|
1111 |
|
1112 EVUTIL_ASSERT(evcon->state == EVCON_WRITING); |
|
1113 |
|
1114 /* We are done writing our header and are now expecting the response */ |
|
1115 req->kind = EVHTTP_RESPONSE; |
|
1116 |
|
1117 evhttp_start_read(evcon); |
|
1118 } |
|
1119 |
|
1120 /* |
|
1121 * Clean up a connection object |
|
1122 */ |
|
1123 |
|
1124 void |
|
1125 evhttp_connection_free(struct evhttp_connection *evcon) |
|
1126 { |
|
1127 struct evhttp_request *req; |
|
1128 |
|
1129 /* notify interested parties that this connection is going down */ |
|
1130 if (evcon->fd != -1) { |
|
1131 if (evhttp_connected(evcon) && evcon->closecb != NULL) |
|
1132 (*evcon->closecb)(evcon, evcon->closecb_arg); |
|
1133 } |
|
1134 |
|
1135 /* remove all requests that might be queued on this |
|
1136 * connection. for server connections, this should be empty. |
|
1137 * because it gets dequeued either in evhttp_connection_done or |
|
1138 * evhttp_connection_fail. |
|
1139 */ |
|
1140 while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) { |
|
1141 TAILQ_REMOVE(&evcon->requests, req, next); |
|
1142 evhttp_request_free(req); |
|
1143 } |
|
1144 |
|
1145 if (evcon->http_server != NULL) { |
|
1146 struct evhttp *http = evcon->http_server; |
|
1147 TAILQ_REMOVE(&http->connections, evcon, next); |
|
1148 } |
|
1149 |
|
1150 if (event_initialized(&evcon->retry_ev)) { |
|
1151 event_del(&evcon->retry_ev); |
|
1152 event_debug_unassign(&evcon->retry_ev); |
|
1153 } |
|
1154 |
|
1155 if (evcon->bufev != NULL) |
|
1156 bufferevent_free(evcon->bufev); |
|
1157 |
|
1158 event_deferred_cb_cancel(get_deferred_queue(evcon), |
|
1159 &evcon->read_more_deferred_cb); |
|
1160 |
|
1161 if (evcon->fd != -1) { |
|
1162 shutdown(evcon->fd, EVUTIL_SHUT_WR); |
|
1163 evutil_closesocket(evcon->fd); |
|
1164 } |
|
1165 |
|
1166 if (evcon->bind_address != NULL) |
|
1167 mm_free(evcon->bind_address); |
|
1168 |
|
1169 if (evcon->address != NULL) |
|
1170 mm_free(evcon->address); |
|
1171 |
|
1172 mm_free(evcon); |
|
1173 } |
|
1174 |
|
1175 void |
|
1176 evhttp_connection_set_local_address(struct evhttp_connection *evcon, |
|
1177 const char *address) |
|
1178 { |
|
1179 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); |
|
1180 if (evcon->bind_address) |
|
1181 mm_free(evcon->bind_address); |
|
1182 if ((evcon->bind_address = mm_strdup(address)) == NULL) |
|
1183 event_warn("%s: strdup", __func__); |
|
1184 } |
|
1185 |
|
1186 void |
|
1187 evhttp_connection_set_local_port(struct evhttp_connection *evcon, |
|
1188 ev_uint16_t port) |
|
1189 { |
|
1190 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); |
|
1191 evcon->bind_port = port; |
|
1192 } |
|
1193 |
|
1194 static void |
|
1195 evhttp_request_dispatch(struct evhttp_connection* evcon) |
|
1196 { |
|
1197 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); |
|
1198 |
|
1199 /* this should not usually happy but it's possible */ |
|
1200 if (req == NULL) |
|
1201 return; |
|
1202 |
|
1203 /* delete possible close detection events */ |
|
1204 evhttp_connection_stop_detectclose(evcon); |
|
1205 |
|
1206 /* we assume that the connection is connected already */ |
|
1207 EVUTIL_ASSERT(evcon->state == EVCON_IDLE); |
|
1208 |
|
1209 evcon->state = EVCON_WRITING; |
|
1210 |
|
1211 /* Create the header from the store arguments */ |
|
1212 evhttp_make_header(evcon, req); |
|
1213 |
|
1214 evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); |
|
1215 } |
|
1216 |
|
1217 /* Reset our connection state: disables reading/writing, closes our fd (if |
|
1218 * any), clears out buffers, and puts us in state DISCONNECTED. */ |
|
1219 void |
|
1220 evhttp_connection_reset(struct evhttp_connection *evcon) |
|
1221 { |
|
1222 struct evbuffer *tmp; |
|
1223 |
|
1224 /* XXXX This is not actually an optimal fix. Instead we ought to have |
|
1225 an API for "stop connecting", or use bufferevent_setfd to turn off |
|
1226 connecting. But for Libevent 2.0, this seems like a minimal change |
|
1227 least likely to disrupt the rest of the bufferevent and http code. |
|
1228 |
|
1229 Why is this here? If the fd is set in the bufferevent, and the |
|
1230 bufferevent is connecting, then you can't actually stop the |
|
1231 bufferevent from trying to connect with bufferevent_disable(). The |
|
1232 connect will never trigger, since we close the fd, but the timeout |
|
1233 might. That caused an assertion failure in evhttp_connection_fail. |
|
1234 */ |
|
1235 bufferevent_disable_hard(evcon->bufev, EV_READ|EV_WRITE); |
|
1236 |
|
1237 if (evcon->fd != -1) { |
|
1238 /* inform interested parties about connection close */ |
|
1239 if (evhttp_connected(evcon) && evcon->closecb != NULL) |
|
1240 (*evcon->closecb)(evcon, evcon->closecb_arg); |
|
1241 |
|
1242 shutdown(evcon->fd, EVUTIL_SHUT_WR); |
|
1243 evutil_closesocket(evcon->fd); |
|
1244 evcon->fd = -1; |
|
1245 } |
|
1246 |
|
1247 /* we need to clean up any buffered data */ |
|
1248 tmp = bufferevent_get_output(evcon->bufev); |
|
1249 evbuffer_drain(tmp, evbuffer_get_length(tmp)); |
|
1250 tmp = bufferevent_get_input(evcon->bufev); |
|
1251 evbuffer_drain(tmp, evbuffer_get_length(tmp)); |
|
1252 |
|
1253 evcon->state = EVCON_DISCONNECTED; |
|
1254 } |
|
1255 |
|
1256 static void |
|
1257 evhttp_connection_start_detectclose(struct evhttp_connection *evcon) |
|
1258 { |
|
1259 evcon->flags |= EVHTTP_CON_CLOSEDETECT; |
|
1260 |
|
1261 bufferevent_enable(evcon->bufev, EV_READ); |
|
1262 } |
|
1263 |
|
1264 static void |
|
1265 evhttp_connection_stop_detectclose(struct evhttp_connection *evcon) |
|
1266 { |
|
1267 evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; |
|
1268 |
|
1269 bufferevent_disable(evcon->bufev, EV_READ); |
|
1270 } |
|
1271 |
|
1272 static void |
|
1273 evhttp_connection_retry(evutil_socket_t fd, short what, void *arg) |
|
1274 { |
|
1275 struct evhttp_connection *evcon = arg; |
|
1276 |
|
1277 evcon->state = EVCON_DISCONNECTED; |
|
1278 evhttp_connection_connect(evcon); |
|
1279 } |
|
1280 |
|
1281 static void |
|
1282 evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) |
|
1283 { |
|
1284 struct evcon_requestq requests; |
|
1285 |
|
1286 if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { |
|
1287 evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon); |
|
1288 /* XXXX handle failure from evhttp_add_event */ |
|
1289 evhttp_add_event(&evcon->retry_ev, |
|
1290 MIN(3600, 2 << evcon->retry_cnt), |
|
1291 HTTP_CONNECT_TIMEOUT); |
|
1292 evcon->retry_cnt++; |
|
1293 return; |
|
1294 } |
|
1295 evhttp_connection_reset(evcon); |
|
1296 |
|
1297 /* |
|
1298 * User callback can do evhttp_make_request() on the same |
|
1299 * evcon so new request will be added to evcon->requests. To |
|
1300 * avoid freeing it prematurely we iterate over the copy of |
|
1301 * the queue. |
|
1302 */ |
|
1303 TAILQ_INIT(&requests); |
|
1304 while (TAILQ_FIRST(&evcon->requests) != NULL) { |
|
1305 struct evhttp_request *request = TAILQ_FIRST(&evcon->requests); |
|
1306 TAILQ_REMOVE(&evcon->requests, request, next); |
|
1307 TAILQ_INSERT_TAIL(&requests, request, next); |
|
1308 } |
|
1309 |
|
1310 /* for now, we just signal all requests by executing their callbacks */ |
|
1311 while (TAILQ_FIRST(&requests) != NULL) { |
|
1312 struct evhttp_request *request = TAILQ_FIRST(&requests); |
|
1313 TAILQ_REMOVE(&requests, request, next); |
|
1314 request->evcon = NULL; |
|
1315 |
|
1316 /* we might want to set an error here */ |
|
1317 request->cb(request, request->cb_arg); |
|
1318 evhttp_request_free(request); |
|
1319 } |
|
1320 } |
|
1321 |
|
1322 static void |
|
1323 evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) |
|
1324 { |
|
1325 struct evhttp_connection *evcon = arg; |
|
1326 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); |
|
1327 |
|
1328 switch (evcon->state) { |
|
1329 case EVCON_CONNECTING: |
|
1330 if (what & BEV_EVENT_TIMEOUT) { |
|
1331 event_debug(("%s: connection timeout for \"%s:%d\" on " |
|
1332 EV_SOCK_FMT, |
|
1333 __func__, evcon->address, evcon->port, |
|
1334 EV_SOCK_ARG(evcon->fd))); |
|
1335 evhttp_connection_cb_cleanup(evcon); |
|
1336 return; |
|
1337 } |
|
1338 break; |
|
1339 |
|
1340 case EVCON_READING_BODY: |
|
1341 if (!req->chunked && req->ntoread < 0 |
|
1342 && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) { |
|
1343 /* EOF on read can be benign */ |
|
1344 evhttp_connection_done(evcon); |
|
1345 return; |
|
1346 } |
|
1347 break; |
|
1348 |
|
1349 case EVCON_DISCONNECTED: |
|
1350 case EVCON_IDLE: |
|
1351 case EVCON_READING_FIRSTLINE: |
|
1352 case EVCON_READING_HEADERS: |
|
1353 case EVCON_READING_TRAILER: |
|
1354 case EVCON_WRITING: |
|
1355 default: |
|
1356 break; |
|
1357 } |
|
1358 |
|
1359 /* when we are in close detect mode, a read error means that |
|
1360 * the other side closed their connection. |
|
1361 */ |
|
1362 if (evcon->flags & EVHTTP_CON_CLOSEDETECT) { |
|
1363 evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; |
|
1364 EVUTIL_ASSERT(evcon->http_server == NULL); |
|
1365 /* For connections from the client, we just |
|
1366 * reset the connection so that it becomes |
|
1367 * disconnected. |
|
1368 */ |
|
1369 EVUTIL_ASSERT(evcon->state == EVCON_IDLE); |
|
1370 evhttp_connection_reset(evcon); |
|
1371 return; |
|
1372 } |
|
1373 |
|
1374 if (what & BEV_EVENT_TIMEOUT) { |
|
1375 evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); |
|
1376 } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { |
|
1377 evhttp_connection_fail(evcon, EVCON_HTTP_EOF); |
|
1378 } else { |
|
1379 evhttp_connection_fail(evcon, EVCON_HTTP_BUFFER_ERROR); |
|
1380 } |
|
1381 } |
|
1382 |
|
1383 /* |
|
1384 * Event callback for asynchronous connection attempt. |
|
1385 */ |
|
1386 static void |
|
1387 evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) |
|
1388 { |
|
1389 struct evhttp_connection *evcon = arg; |
|
1390 int error; |
|
1391 ev_socklen_t errsz = sizeof(error); |
|
1392 |
|
1393 if (!(what & BEV_EVENT_CONNECTED)) { |
|
1394 /* some operating systems return ECONNREFUSED immediately |
|
1395 * when connecting to a local address. the cleanup is going |
|
1396 * to reschedule this function call. |
|
1397 */ |
|
1398 #ifndef WIN32 |
|
1399 if (errno == ECONNREFUSED) |
|
1400 goto cleanup; |
|
1401 #endif |
|
1402 evhttp_error_cb(bufev, what, arg); |
|
1403 return; |
|
1404 } |
|
1405 |
|
1406 /* Check if the connection completed */ |
|
1407 if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error, |
|
1408 &errsz) == -1) { |
|
1409 event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT, |
|
1410 __func__, evcon->address, evcon->port, |
|
1411 EV_SOCK_ARG(evcon->fd))); |
|
1412 goto cleanup; |
|
1413 } |
|
1414 |
|
1415 if (error) { |
|
1416 event_debug(("%s: connect failed for \"%s:%d\" on " |
|
1417 EV_SOCK_FMT": %s", |
|
1418 __func__, evcon->address, evcon->port, |
|
1419 EV_SOCK_ARG(evcon->fd), |
|
1420 evutil_socket_error_to_string(error))); |
|
1421 goto cleanup; |
|
1422 } |
|
1423 |
|
1424 /* We are connected to the server now */ |
|
1425 event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n", |
|
1426 __func__, evcon->address, evcon->port, |
|
1427 EV_SOCK_ARG(evcon->fd))); |
|
1428 |
|
1429 /* Reset the retry count as we were successful in connecting */ |
|
1430 evcon->retry_cnt = 0; |
|
1431 evcon->state = EVCON_IDLE; |
|
1432 |
|
1433 /* reset the bufferevent cbs */ |
|
1434 bufferevent_setcb(evcon->bufev, |
|
1435 evhttp_read_cb, |
|
1436 evhttp_write_cb, |
|
1437 evhttp_error_cb, |
|
1438 evcon); |
|
1439 |
|
1440 if (evcon->timeout == -1) |
|
1441 bufferevent_settimeout(evcon->bufev, |
|
1442 HTTP_READ_TIMEOUT, HTTP_WRITE_TIMEOUT); |
|
1443 else { |
|
1444 struct timeval tv; |
|
1445 tv.tv_sec = evcon->timeout; |
|
1446 tv.tv_usec = 0; |
|
1447 bufferevent_set_timeouts(evcon->bufev, &tv, &tv); |
|
1448 } |
|
1449 |
|
1450 /* try to start requests that have queued up on this connection */ |
|
1451 evhttp_request_dispatch(evcon); |
|
1452 return; |
|
1453 |
|
1454 cleanup: |
|
1455 evhttp_connection_cb_cleanup(evcon); |
|
1456 } |
|
1457 |
|
1458 /* |
|
1459 * Check if we got a valid response code. |
|
1460 */ |
|
1461 |
|
1462 static int |
|
1463 evhttp_valid_response_code(int code) |
|
1464 { |
|
1465 if (code == 0) |
|
1466 return (0); |
|
1467 |
|
1468 return (1); |
|
1469 } |
|
1470 |
|
1471 static int |
|
1472 evhttp_parse_http_version(const char *version, struct evhttp_request *req) |
|
1473 { |
|
1474 int major, minor; |
|
1475 char ch; |
|
1476 int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch); |
|
1477 if (n != 2 || major > 1) { |
|
1478 event_debug(("%s: bad version %s on message %p from %s", |
|
1479 __func__, version, req, req->remote_host)); |
|
1480 return (-1); |
|
1481 } |
|
1482 req->major = major; |
|
1483 req->minor = minor; |
|
1484 return (0); |
|
1485 } |
|
1486 |
|
1487 /* Parses the status line of a web server */ |
|
1488 |
|
1489 static int |
|
1490 evhttp_parse_response_line(struct evhttp_request *req, char *line) |
|
1491 { |
|
1492 char *protocol; |
|
1493 char *number; |
|
1494 const char *readable = ""; |
|
1495 |
|
1496 protocol = strsep(&line, " "); |
|
1497 if (line == NULL) |
|
1498 return (-1); |
|
1499 number = strsep(&line, " "); |
|
1500 if (line != NULL) |
|
1501 readable = line; |
|
1502 |
|
1503 if (evhttp_parse_http_version(protocol, req) < 0) |
|
1504 return (-1); |
|
1505 |
|
1506 req->response_code = atoi(number); |
|
1507 if (!evhttp_valid_response_code(req->response_code)) { |
|
1508 event_debug(("%s: bad response code \"%s\"", |
|
1509 __func__, number)); |
|
1510 return (-1); |
|
1511 } |
|
1512 |
|
1513 if ((req->response_code_line = mm_strdup(readable)) == NULL) { |
|
1514 event_warn("%s: strdup", __func__); |
|
1515 return (-1); |
|
1516 } |
|
1517 |
|
1518 return (0); |
|
1519 } |
|
1520 |
|
1521 /* Parse the first line of a HTTP request */ |
|
1522 |
|
1523 static int |
|
1524 evhttp_parse_request_line(struct evhttp_request *req, char *line) |
|
1525 { |
|
1526 char *method; |
|
1527 char *uri; |
|
1528 char *version; |
|
1529 const char *hostname; |
|
1530 const char *scheme; |
|
1531 |
|
1532 /* Parse the request line */ |
|
1533 method = strsep(&line, " "); |
|
1534 if (line == NULL) |
|
1535 return (-1); |
|
1536 uri = strsep(&line, " "); |
|
1537 if (line == NULL) |
|
1538 return (-1); |
|
1539 version = strsep(&line, " "); |
|
1540 if (line != NULL) |
|
1541 return (-1); |
|
1542 |
|
1543 /* First line */ |
|
1544 if (strcmp(method, "GET") == 0) { |
|
1545 req->type = EVHTTP_REQ_GET; |
|
1546 } else if (strcmp(method, "POST") == 0) { |
|
1547 req->type = EVHTTP_REQ_POST; |
|
1548 } else if (strcmp(method, "HEAD") == 0) { |
|
1549 req->type = EVHTTP_REQ_HEAD; |
|
1550 } else if (strcmp(method, "PUT") == 0) { |
|
1551 req->type = EVHTTP_REQ_PUT; |
|
1552 } else if (strcmp(method, "DELETE") == 0) { |
|
1553 req->type = EVHTTP_REQ_DELETE; |
|
1554 } else if (strcmp(method, "OPTIONS") == 0) { |
|
1555 req->type = EVHTTP_REQ_OPTIONS; |
|
1556 } else if (strcmp(method, "TRACE") == 0) { |
|
1557 req->type = EVHTTP_REQ_TRACE; |
|
1558 } else if (strcmp(method, "PATCH") == 0) { |
|
1559 req->type = EVHTTP_REQ_PATCH; |
|
1560 } else { |
|
1561 req->type = _EVHTTP_REQ_UNKNOWN; |
|
1562 event_debug(("%s: bad method %s on request %p from %s", |
|
1563 __func__, method, req, req->remote_host)); |
|
1564 /* No error yet; we'll give a better error later when |
|
1565 * we see that req->type is unsupported. */ |
|
1566 } |
|
1567 |
|
1568 if (evhttp_parse_http_version(version, req) < 0) |
|
1569 return (-1); |
|
1570 |
|
1571 if ((req->uri = mm_strdup(uri)) == NULL) { |
|
1572 event_debug(("%s: mm_strdup", __func__)); |
|
1573 return (-1); |
|
1574 } |
|
1575 |
|
1576 if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri, |
|
1577 EVHTTP_URI_NONCONFORMANT)) == NULL) { |
|
1578 return -1; |
|
1579 } |
|
1580 |
|
1581 /* If we have an absolute-URI, check to see if it is an http request |
|
1582 for a known vhost or server alias. If we don't know about this |
|
1583 host, we consider it a proxy request. */ |
|
1584 scheme = evhttp_uri_get_scheme(req->uri_elems); |
|
1585 hostname = evhttp_uri_get_host(req->uri_elems); |
|
1586 if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") || |
|
1587 !evutil_ascii_strcasecmp(scheme, "https")) && |
|
1588 hostname && |
|
1589 !evhttp_find_vhost(req->evcon->http_server, NULL, hostname)) |
|
1590 req->flags |= EVHTTP_PROXY_REQUEST; |
|
1591 |
|
1592 return (0); |
|
1593 } |
|
1594 |
|
1595 const char * |
|
1596 evhttp_find_header(const struct evkeyvalq *headers, const char *key) |
|
1597 { |
|
1598 struct evkeyval *header; |
|
1599 |
|
1600 TAILQ_FOREACH(header, headers, next) { |
|
1601 if (evutil_ascii_strcasecmp(header->key, key) == 0) |
|
1602 return (header->value); |
|
1603 } |
|
1604 |
|
1605 return (NULL); |
|
1606 } |
|
1607 |
|
1608 void |
|
1609 evhttp_clear_headers(struct evkeyvalq *headers) |
|
1610 { |
|
1611 struct evkeyval *header; |
|
1612 |
|
1613 for (header = TAILQ_FIRST(headers); |
|
1614 header != NULL; |
|
1615 header = TAILQ_FIRST(headers)) { |
|
1616 TAILQ_REMOVE(headers, header, next); |
|
1617 mm_free(header->key); |
|
1618 mm_free(header->value); |
|
1619 mm_free(header); |
|
1620 } |
|
1621 } |
|
1622 |
|
1623 /* |
|
1624 * Returns 0, if the header was successfully removed. |
|
1625 * Returns -1, if the header could not be found. |
|
1626 */ |
|
1627 |
|
1628 int |
|
1629 evhttp_remove_header(struct evkeyvalq *headers, const char *key) |
|
1630 { |
|
1631 struct evkeyval *header; |
|
1632 |
|
1633 TAILQ_FOREACH(header, headers, next) { |
|
1634 if (evutil_ascii_strcasecmp(header->key, key) == 0) |
|
1635 break; |
|
1636 } |
|
1637 |
|
1638 if (header == NULL) |
|
1639 return (-1); |
|
1640 |
|
1641 /* Free and remove the header that we found */ |
|
1642 TAILQ_REMOVE(headers, header, next); |
|
1643 mm_free(header->key); |
|
1644 mm_free(header->value); |
|
1645 mm_free(header); |
|
1646 |
|
1647 return (0); |
|
1648 } |
|
1649 |
|
1650 static int |
|
1651 evhttp_header_is_valid_value(const char *value) |
|
1652 { |
|
1653 const char *p = value; |
|
1654 |
|
1655 while ((p = strpbrk(p, "\r\n")) != NULL) { |
|
1656 /* we really expect only one new line */ |
|
1657 p += strspn(p, "\r\n"); |
|
1658 /* we expect a space or tab for continuation */ |
|
1659 if (*p != ' ' && *p != '\t') |
|
1660 return (0); |
|
1661 } |
|
1662 return (1); |
|
1663 } |
|
1664 |
|
1665 int |
|
1666 evhttp_add_header(struct evkeyvalq *headers, |
|
1667 const char *key, const char *value) |
|
1668 { |
|
1669 event_debug(("%s: key: %s val: %s\n", __func__, key, value)); |
|
1670 |
|
1671 if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) { |
|
1672 /* drop illegal headers */ |
|
1673 event_debug(("%s: dropping illegal header key\n", __func__)); |
|
1674 return (-1); |
|
1675 } |
|
1676 |
|
1677 if (!evhttp_header_is_valid_value(value)) { |
|
1678 event_debug(("%s: dropping illegal header value\n", __func__)); |
|
1679 return (-1); |
|
1680 } |
|
1681 |
|
1682 return (evhttp_add_header_internal(headers, key, value)); |
|
1683 } |
|
1684 |
|
1685 static int |
|
1686 evhttp_add_header_internal(struct evkeyvalq *headers, |
|
1687 const char *key, const char *value) |
|
1688 { |
|
1689 struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval)); |
|
1690 if (header == NULL) { |
|
1691 event_warn("%s: calloc", __func__); |
|
1692 return (-1); |
|
1693 } |
|
1694 if ((header->key = mm_strdup(key)) == NULL) { |
|
1695 mm_free(header); |
|
1696 event_warn("%s: strdup", __func__); |
|
1697 return (-1); |
|
1698 } |
|
1699 if ((header->value = mm_strdup(value)) == NULL) { |
|
1700 mm_free(header->key); |
|
1701 mm_free(header); |
|
1702 event_warn("%s: strdup", __func__); |
|
1703 return (-1); |
|
1704 } |
|
1705 |
|
1706 TAILQ_INSERT_TAIL(headers, header, next); |
|
1707 |
|
1708 return (0); |
|
1709 } |
|
1710 |
|
1711 /* |
|
1712 * Parses header lines from a request or a response into the specified |
|
1713 * request object given an event buffer. |
|
1714 * |
|
1715 * Returns |
|
1716 * DATA_CORRUPTED on error |
|
1717 * MORE_DATA_EXPECTED when we need to read more headers |
|
1718 * ALL_DATA_READ when all headers have been read. |
|
1719 */ |
|
1720 |
|
1721 enum message_read_status |
|
1722 evhttp_parse_firstline(struct evhttp_request *req, struct evbuffer *buffer) |
|
1723 { |
|
1724 char *line; |
|
1725 enum message_read_status status = ALL_DATA_READ; |
|
1726 |
|
1727 size_t line_length; |
|
1728 /* XXX try */ |
|
1729 line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF); |
|
1730 if (line == NULL) { |
|
1731 if (req->evcon != NULL && |
|
1732 evbuffer_get_length(buffer) > req->evcon->max_headers_size) |
|
1733 return (DATA_TOO_LONG); |
|
1734 else |
|
1735 return (MORE_DATA_EXPECTED); |
|
1736 } |
|
1737 |
|
1738 if (req->evcon != NULL && |
|
1739 line_length > req->evcon->max_headers_size) { |
|
1740 mm_free(line); |
|
1741 return (DATA_TOO_LONG); |
|
1742 } |
|
1743 |
|
1744 req->headers_size = line_length; |
|
1745 |
|
1746 switch (req->kind) { |
|
1747 case EVHTTP_REQUEST: |
|
1748 if (evhttp_parse_request_line(req, line) == -1) |
|
1749 status = DATA_CORRUPTED; |
|
1750 break; |
|
1751 case EVHTTP_RESPONSE: |
|
1752 if (evhttp_parse_response_line(req, line) == -1) |
|
1753 status = DATA_CORRUPTED; |
|
1754 break; |
|
1755 default: |
|
1756 status = DATA_CORRUPTED; |
|
1757 } |
|
1758 |
|
1759 mm_free(line); |
|
1760 return (status); |
|
1761 } |
|
1762 |
|
1763 static int |
|
1764 evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line) |
|
1765 { |
|
1766 struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq); |
|
1767 char *newval; |
|
1768 size_t old_len, line_len; |
|
1769 |
|
1770 if (header == NULL) |
|
1771 return (-1); |
|
1772 |
|
1773 old_len = strlen(header->value); |
|
1774 line_len = strlen(line); |
|
1775 |
|
1776 newval = mm_realloc(header->value, old_len + line_len + 1); |
|
1777 if (newval == NULL) |
|
1778 return (-1); |
|
1779 |
|
1780 memcpy(newval + old_len, line, line_len + 1); |
|
1781 header->value = newval; |
|
1782 |
|
1783 return (0); |
|
1784 } |
|
1785 |
|
1786 enum message_read_status |
|
1787 evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer) |
|
1788 { |
|
1789 enum message_read_status errcode = DATA_CORRUPTED; |
|
1790 char *line; |
|
1791 enum message_read_status status = MORE_DATA_EXPECTED; |
|
1792 |
|
1793 struct evkeyvalq* headers = req->input_headers; |
|
1794 size_t line_length; |
|
1795 while ((line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF)) |
|
1796 != NULL) { |
|
1797 char *skey, *svalue; |
|
1798 |
|
1799 req->headers_size += line_length; |
|
1800 |
|
1801 if (req->evcon != NULL && |
|
1802 req->headers_size > req->evcon->max_headers_size) { |
|
1803 errcode = DATA_TOO_LONG; |
|
1804 goto error; |
|
1805 } |
|
1806 |
|
1807 if (*line == '\0') { /* Last header - Done */ |
|
1808 status = ALL_DATA_READ; |
|
1809 mm_free(line); |
|
1810 break; |
|
1811 } |
|
1812 |
|
1813 /* Check if this is a continuation line */ |
|
1814 if (*line == ' ' || *line == '\t') { |
|
1815 if (evhttp_append_to_last_header(headers, line) == -1) |
|
1816 goto error; |
|
1817 mm_free(line); |
|
1818 continue; |
|
1819 } |
|
1820 |
|
1821 /* Processing of header lines */ |
|
1822 svalue = line; |
|
1823 skey = strsep(&svalue, ":"); |
|
1824 if (svalue == NULL) |
|
1825 goto error; |
|
1826 |
|
1827 svalue += strspn(svalue, " "); |
|
1828 |
|
1829 if (evhttp_add_header(headers, skey, svalue) == -1) |
|
1830 goto error; |
|
1831 |
|
1832 mm_free(line); |
|
1833 } |
|
1834 |
|
1835 if (status == MORE_DATA_EXPECTED) { |
|
1836 if (req->evcon != NULL && |
|
1837 req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size) |
|
1838 return (DATA_TOO_LONG); |
|
1839 } |
|
1840 |
|
1841 return (status); |
|
1842 |
|
1843 error: |
|
1844 mm_free(line); |
|
1845 return (errcode); |
|
1846 } |
|
1847 |
|
1848 static int |
|
1849 evhttp_get_body_length(struct evhttp_request *req) |
|
1850 { |
|
1851 struct evkeyvalq *headers = req->input_headers; |
|
1852 const char *content_length; |
|
1853 const char *connection; |
|
1854 |
|
1855 content_length = evhttp_find_header(headers, "Content-Length"); |
|
1856 connection = evhttp_find_header(headers, "Connection"); |
|
1857 |
|
1858 if (content_length == NULL && connection == NULL) |
|
1859 req->ntoread = -1; |
|
1860 else if (content_length == NULL && |
|
1861 evutil_ascii_strcasecmp(connection, "Close") != 0) { |
|
1862 /* Bad combination, we don't know when it will end */ |
|
1863 event_warnx("%s: we got no content length, but the " |
|
1864 "server wants to keep the connection open: %s.", |
|
1865 __func__, connection); |
|
1866 return (-1); |
|
1867 } else if (content_length == NULL) { |
|
1868 req->ntoread = -1; |
|
1869 } else { |
|
1870 char *endp; |
|
1871 ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10); |
|
1872 if (*content_length == '\0' || *endp != '\0' || ntoread < 0) { |
|
1873 event_debug(("%s: illegal content length: %s", |
|
1874 __func__, content_length)); |
|
1875 return (-1); |
|
1876 } |
|
1877 req->ntoread = ntoread; |
|
1878 } |
|
1879 |
|
1880 event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n", |
|
1881 __func__, EV_I64_ARG(req->ntoread), |
|
1882 EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev))))); |
|
1883 |
|
1884 return (0); |
|
1885 } |
|
1886 |
|
1887 static int |
|
1888 evhttp_method_may_have_body(enum evhttp_cmd_type type) |
|
1889 { |
|
1890 switch (type) { |
|
1891 case EVHTTP_REQ_POST: |
|
1892 case EVHTTP_REQ_PUT: |
|
1893 case EVHTTP_REQ_PATCH: |
|
1894 return 1; |
|
1895 case EVHTTP_REQ_TRACE: |
|
1896 return 0; |
|
1897 /* XXX May any of the below methods have a body? */ |
|
1898 case EVHTTP_REQ_GET: |
|
1899 case EVHTTP_REQ_HEAD: |
|
1900 case EVHTTP_REQ_DELETE: |
|
1901 case EVHTTP_REQ_OPTIONS: |
|
1902 case EVHTTP_REQ_CONNECT: |
|
1903 return 0; |
|
1904 default: |
|
1905 return 0; |
|
1906 } |
|
1907 } |
|
1908 |
|
1909 static void |
|
1910 evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) |
|
1911 { |
|
1912 const char *xfer_enc; |
|
1913 |
|
1914 /* If this is a request without a body, then we are done */ |
|
1915 if (req->kind == EVHTTP_REQUEST && |
|
1916 !evhttp_method_may_have_body(req->type)) { |
|
1917 evhttp_connection_done(evcon); |
|
1918 return; |
|
1919 } |
|
1920 evcon->state = EVCON_READING_BODY; |
|
1921 xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding"); |
|
1922 if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) { |
|
1923 req->chunked = 1; |
|
1924 req->ntoread = -1; |
|
1925 } else { |
|
1926 if (evhttp_get_body_length(req) == -1) { |
|
1927 evhttp_connection_fail(evcon, |
|
1928 EVCON_HTTP_INVALID_HEADER); |
|
1929 return; |
|
1930 } |
|
1931 if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) { |
|
1932 /* An incoming request with no content-length and no |
|
1933 * transfer-encoding has no body. */ |
|
1934 evhttp_connection_done(evcon); |
|
1935 return; |
|
1936 } |
|
1937 } |
|
1938 |
|
1939 /* Should we send a 100 Continue status line? */ |
|
1940 if (req->kind == EVHTTP_REQUEST && REQ_VERSION_ATLEAST(req, 1, 1)) { |
|
1941 const char *expect; |
|
1942 |
|
1943 expect = evhttp_find_header(req->input_headers, "Expect"); |
|
1944 if (expect) { |
|
1945 if (!evutil_ascii_strcasecmp(expect, "100-continue")) { |
|
1946 /* XXX It would be nice to do some sanity |
|
1947 checking here. Does the resource exist? |
|
1948 Should the resource accept post requests? If |
|
1949 no, we should respond with an error. For |
|
1950 now, just optimistically tell the client to |
|
1951 send their message body. */ |
|
1952 if (req->ntoread > 0) { |
|
1953 /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */ |
|
1954 if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) { |
|
1955 evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL); |
|
1956 return; |
|
1957 } |
|
1958 } |
|
1959 if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev))) |
|
1960 evhttp_send_continue(evcon, req); |
|
1961 } else { |
|
1962 evhttp_send_error(req, HTTP_EXPECTATIONFAILED, |
|
1963 NULL); |
|
1964 return; |
|
1965 } |
|
1966 } |
|
1967 } |
|
1968 |
|
1969 evhttp_read_body(evcon, req); |
|
1970 /* note the request may have been freed in evhttp_read_body */ |
|
1971 } |
|
1972 |
|
1973 static void |
|
1974 evhttp_read_firstline(struct evhttp_connection *evcon, |
|
1975 struct evhttp_request *req) |
|
1976 { |
|
1977 enum message_read_status res; |
|
1978 |
|
1979 res = evhttp_parse_firstline(req, bufferevent_get_input(evcon->bufev)); |
|
1980 if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { |
|
1981 /* Error while reading, terminate */ |
|
1982 event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", |
|
1983 __func__, EV_SOCK_ARG(evcon->fd))); |
|
1984 evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); |
|
1985 return; |
|
1986 } else if (res == MORE_DATA_EXPECTED) { |
|
1987 /* Need more header lines */ |
|
1988 return; |
|
1989 } |
|
1990 |
|
1991 evcon->state = EVCON_READING_HEADERS; |
|
1992 evhttp_read_header(evcon, req); |
|
1993 } |
|
1994 |
|
1995 static void |
|
1996 evhttp_read_header(struct evhttp_connection *evcon, |
|
1997 struct evhttp_request *req) |
|
1998 { |
|
1999 enum message_read_status res; |
|
2000 evutil_socket_t fd = evcon->fd; |
|
2001 |
|
2002 res = evhttp_parse_headers(req, bufferevent_get_input(evcon->bufev)); |
|
2003 if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { |
|
2004 /* Error while reading, terminate */ |
|
2005 event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", |
|
2006 __func__, EV_SOCK_ARG(fd))); |
|
2007 evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); |
|
2008 return; |
|
2009 } else if (res == MORE_DATA_EXPECTED) { |
|
2010 /* Need more header lines */ |
|
2011 return; |
|
2012 } |
|
2013 |
|
2014 /* Disable reading for now */ |
|
2015 bufferevent_disable(evcon->bufev, EV_READ); |
|
2016 |
|
2017 /* Done reading headers, do the real work */ |
|
2018 switch (req->kind) { |
|
2019 case EVHTTP_REQUEST: |
|
2020 event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n", |
|
2021 __func__, EV_SOCK_ARG(fd))); |
|
2022 evhttp_get_body(evcon, req); |
|
2023 /* note the request may have been freed in evhttp_get_body */ |
|
2024 break; |
|
2025 |
|
2026 case EVHTTP_RESPONSE: |
|
2027 /* Start over if we got a 100 Continue response. */ |
|
2028 if (req->response_code == 100) { |
|
2029 evhttp_start_read(evcon); |
|
2030 return; |
|
2031 } |
|
2032 if (!evhttp_response_needs_body(req)) { |
|
2033 event_debug(("%s: skipping body for code %d\n", |
|
2034 __func__, req->response_code)); |
|
2035 evhttp_connection_done(evcon); |
|
2036 } else { |
|
2037 event_debug(("%s: start of read body for %s on " |
|
2038 EV_SOCK_FMT"\n", |
|
2039 __func__, req->remote_host, EV_SOCK_ARG(fd))); |
|
2040 evhttp_get_body(evcon, req); |
|
2041 /* note the request may have been freed in |
|
2042 * evhttp_get_body */ |
|
2043 } |
|
2044 break; |
|
2045 |
|
2046 default: |
|
2047 event_warnx("%s: bad header on "EV_SOCK_FMT, __func__, |
|
2048 EV_SOCK_ARG(fd)); |
|
2049 evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); |
|
2050 break; |
|
2051 } |
|
2052 /* request may have been freed above */ |
|
2053 } |
|
2054 |
|
2055 /* |
|
2056 * Creates a TCP connection to the specified port and executes a callback |
|
2057 * when finished. Failure or success is indicate by the passed connection |
|
2058 * object. |
|
2059 * |
|
2060 * Although this interface accepts a hostname, it is intended to take |
|
2061 * only numeric hostnames so that non-blocking DNS resolution can |
|
2062 * happen elsewhere. |
|
2063 */ |
|
2064 |
|
2065 struct evhttp_connection * |
|
2066 evhttp_connection_new(const char *address, unsigned short port) |
|
2067 { |
|
2068 return (evhttp_connection_base_new(NULL, NULL, address, port)); |
|
2069 } |
|
2070 |
|
2071 struct evhttp_connection * |
|
2072 evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, |
|
2073 const char *address, unsigned short port) |
|
2074 { |
|
2075 struct evhttp_connection *evcon = NULL; |
|
2076 |
|
2077 event_debug(("Attempting connection to %s:%d\n", address, port)); |
|
2078 |
|
2079 if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) { |
|
2080 event_warn("%s: calloc failed", __func__); |
|
2081 goto error; |
|
2082 } |
|
2083 |
|
2084 evcon->fd = -1; |
|
2085 evcon->port = port; |
|
2086 |
|
2087 evcon->max_headers_size = EV_SIZE_MAX; |
|
2088 evcon->max_body_size = EV_SIZE_MAX; |
|
2089 |
|
2090 evcon->timeout = -1; |
|
2091 evcon->retry_cnt = evcon->retry_max = 0; |
|
2092 |
|
2093 if ((evcon->address = mm_strdup(address)) == NULL) { |
|
2094 event_warn("%s: strdup failed", __func__); |
|
2095 goto error; |
|
2096 } |
|
2097 |
|
2098 if ((evcon->bufev = bufferevent_new(-1, |
|
2099 evhttp_read_cb, |
|
2100 evhttp_write_cb, |
|
2101 evhttp_error_cb, evcon)) == NULL) { |
|
2102 event_warn("%s: bufferevent_new failed", __func__); |
|
2103 goto error; |
|
2104 } |
|
2105 |
|
2106 evcon->state = EVCON_DISCONNECTED; |
|
2107 TAILQ_INIT(&evcon->requests); |
|
2108 |
|
2109 if (base != NULL) { |
|
2110 evcon->base = base; |
|
2111 bufferevent_base_set(base, evcon->bufev); |
|
2112 } |
|
2113 |
|
2114 |
|
2115 event_deferred_cb_init(&evcon->read_more_deferred_cb, |
|
2116 evhttp_deferred_read_cb, evcon); |
|
2117 |
|
2118 evcon->dns_base = dnsbase; |
|
2119 |
|
2120 return (evcon); |
|
2121 |
|
2122 error: |
|
2123 if (evcon != NULL) |
|
2124 evhttp_connection_free(evcon); |
|
2125 return (NULL); |
|
2126 } |
|
2127 |
|
2128 struct bufferevent * |
|
2129 evhttp_connection_get_bufferevent(struct evhttp_connection *evcon) |
|
2130 { |
|
2131 return evcon->bufev; |
|
2132 } |
|
2133 |
|
2134 void |
|
2135 evhttp_connection_set_base(struct evhttp_connection *evcon, |
|
2136 struct event_base *base) |
|
2137 { |
|
2138 EVUTIL_ASSERT(evcon->base == NULL); |
|
2139 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); |
|
2140 evcon->base = base; |
|
2141 bufferevent_base_set(base, evcon->bufev); |
|
2142 } |
|
2143 |
|
2144 void |
|
2145 evhttp_connection_set_timeout(struct evhttp_connection *evcon, |
|
2146 int timeout_in_secs) |
|
2147 { |
|
2148 evcon->timeout = timeout_in_secs; |
|
2149 |
|
2150 if (evcon->timeout == -1) |
|
2151 bufferevent_settimeout(evcon->bufev, |
|
2152 HTTP_READ_TIMEOUT, HTTP_WRITE_TIMEOUT); |
|
2153 else |
|
2154 bufferevent_settimeout(evcon->bufev, |
|
2155 evcon->timeout, evcon->timeout); |
|
2156 } |
|
2157 |
|
2158 void |
|
2159 evhttp_connection_set_retries(struct evhttp_connection *evcon, |
|
2160 int retry_max) |
|
2161 { |
|
2162 evcon->retry_max = retry_max; |
|
2163 } |
|
2164 |
|
2165 void |
|
2166 evhttp_connection_set_closecb(struct evhttp_connection *evcon, |
|
2167 void (*cb)(struct evhttp_connection *, void *), void *cbarg) |
|
2168 { |
|
2169 evcon->closecb = cb; |
|
2170 evcon->closecb_arg = cbarg; |
|
2171 } |
|
2172 |
|
2173 void |
|
2174 evhttp_connection_get_peer(struct evhttp_connection *evcon, |
|
2175 char **address, ev_uint16_t *port) |
|
2176 { |
|
2177 *address = evcon->address; |
|
2178 *port = evcon->port; |
|
2179 } |
|
2180 |
|
2181 int |
|
2182 evhttp_connection_connect(struct evhttp_connection *evcon) |
|
2183 { |
|
2184 if (evcon->state == EVCON_CONNECTING) |
|
2185 return (0); |
|
2186 |
|
2187 evhttp_connection_reset(evcon); |
|
2188 |
|
2189 EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING)); |
|
2190 evcon->flags |= EVHTTP_CON_OUTGOING; |
|
2191 |
|
2192 evcon->fd = bind_socket( |
|
2193 evcon->bind_address, evcon->bind_port, 0 /*reuse*/); |
|
2194 if (evcon->fd == -1) { |
|
2195 event_debug(("%s: failed to bind to \"%s\"", |
|
2196 __func__, evcon->bind_address)); |
|
2197 return (-1); |
|
2198 } |
|
2199 |
|
2200 /* Set up a callback for successful connection setup */ |
|
2201 bufferevent_setfd(evcon->bufev, evcon->fd); |
|
2202 bufferevent_setcb(evcon->bufev, |
|
2203 NULL /* evhttp_read_cb */, |
|
2204 NULL /* evhttp_write_cb */, |
|
2205 evhttp_connection_cb, |
|
2206 evcon); |
|
2207 bufferevent_settimeout(evcon->bufev, 0, |
|
2208 evcon->timeout != -1 ? evcon->timeout : HTTP_CONNECT_TIMEOUT); |
|
2209 /* make sure that we get a write callback */ |
|
2210 bufferevent_enable(evcon->bufev, EV_WRITE); |
|
2211 |
|
2212 if (bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base, |
|
2213 AF_UNSPEC, evcon->address, evcon->port) < 0) { |
|
2214 event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed", |
|
2215 __func__, evcon->address); |
|
2216 /* some operating systems return ECONNREFUSED immediately |
|
2217 * when connecting to a local address. the cleanup is going |
|
2218 * to reschedule this function call. |
|
2219 */ |
|
2220 evhttp_connection_cb_cleanup(evcon); |
|
2221 return (0); |
|
2222 } |
|
2223 |
|
2224 evcon->state = EVCON_CONNECTING; |
|
2225 |
|
2226 return (0); |
|
2227 } |
|
2228 |
|
2229 /* |
|
2230 * Starts an HTTP request on the provided evhttp_connection object. |
|
2231 * If the connection object is not connected to the web server already, |
|
2232 * this will start the connection. |
|
2233 */ |
|
2234 |
|
2235 int |
|
2236 evhttp_make_request(struct evhttp_connection *evcon, |
|
2237 struct evhttp_request *req, |
|
2238 enum evhttp_cmd_type type, const char *uri) |
|
2239 { |
|
2240 /* We are making a request */ |
|
2241 req->kind = EVHTTP_REQUEST; |
|
2242 req->type = type; |
|
2243 if (req->uri != NULL) |
|
2244 mm_free(req->uri); |
|
2245 if ((req->uri = mm_strdup(uri)) == NULL) { |
|
2246 event_warn("%s: strdup", __func__); |
|
2247 evhttp_request_free(req); |
|
2248 return (-1); |
|
2249 } |
|
2250 |
|
2251 /* Set the protocol version if it is not supplied */ |
|
2252 if (!req->major && !req->minor) { |
|
2253 req->major = 1; |
|
2254 req->minor = 1; |
|
2255 } |
|
2256 |
|
2257 EVUTIL_ASSERT(req->evcon == NULL); |
|
2258 req->evcon = evcon; |
|
2259 EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION)); |
|
2260 |
|
2261 TAILQ_INSERT_TAIL(&evcon->requests, req, next); |
|
2262 |
|
2263 /* If the connection object is not connected; make it so */ |
|
2264 if (!evhttp_connected(evcon)) { |
|
2265 int res = evhttp_connection_connect(evcon); |
|
2266 /* evhttp_connection_fail(), which is called through |
|
2267 * evhttp_connection_connect(), assumes that req lies in |
|
2268 * evcon->requests. Thus, enqueue the request in advance and r |
|
2269 * it in the error case. */ |
|
2270 if (res != 0) |
|
2271 TAILQ_REMOVE(&evcon->requests, req, next); |
|
2272 |
|
2273 return res; |
|
2274 } |
|
2275 |
|
2276 /* |
|
2277 * If it's connected already and we are the first in the queue, |
|
2278 * then we can dispatch this request immediately. Otherwise, it |
|
2279 * will be dispatched once the pending requests are completed. |
|
2280 */ |
|
2281 if (TAILQ_FIRST(&evcon->requests) == req) |
|
2282 evhttp_request_dispatch(evcon); |
|
2283 |
|
2284 return (0); |
|
2285 } |
|
2286 |
|
2287 void |
|
2288 evhttp_cancel_request(struct evhttp_request *req) |
|
2289 { |
|
2290 struct evhttp_connection *evcon = req->evcon; |
|
2291 if (evcon != NULL) { |
|
2292 /* We need to remove it from the connection */ |
|
2293 if (TAILQ_FIRST(&evcon->requests) == req) { |
|
2294 /* it's currently being worked on, so reset |
|
2295 * the connection. |
|
2296 */ |
|
2297 evhttp_connection_fail(evcon, |
|
2298 EVCON_HTTP_REQUEST_CANCEL); |
|
2299 |
|
2300 /* connection fail freed the request */ |
|
2301 return; |
|
2302 } else { |
|
2303 /* otherwise, we can just remove it from the |
|
2304 * queue |
|
2305 */ |
|
2306 TAILQ_REMOVE(&evcon->requests, req, next); |
|
2307 } |
|
2308 } |
|
2309 |
|
2310 evhttp_request_free(req); |
|
2311 } |
|
2312 |
|
2313 /* |
|
2314 * Reads data from file descriptor into request structure |
|
2315 * Request structure needs to be set up correctly. |
|
2316 */ |
|
2317 |
|
2318 void |
|
2319 evhttp_start_read(struct evhttp_connection *evcon) |
|
2320 { |
|
2321 /* Set up an event to read the headers */ |
|
2322 bufferevent_disable(evcon->bufev, EV_WRITE); |
|
2323 bufferevent_enable(evcon->bufev, EV_READ); |
|
2324 evcon->state = EVCON_READING_FIRSTLINE; |
|
2325 /* Reset the bufferevent callbacks */ |
|
2326 bufferevent_setcb(evcon->bufev, |
|
2327 evhttp_read_cb, |
|
2328 evhttp_write_cb, |
|
2329 evhttp_error_cb, |
|
2330 evcon); |
|
2331 |
|
2332 /* If there's still data pending, process it next time through the |
|
2333 * loop. Don't do it now; that could get recusive. */ |
|
2334 if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) { |
|
2335 event_deferred_cb_schedule(get_deferred_queue(evcon), |
|
2336 &evcon->read_more_deferred_cb); |
|
2337 } |
|
2338 } |
|
2339 |
|
2340 static void |
|
2341 evhttp_send_done(struct evhttp_connection *evcon, void *arg) |
|
2342 { |
|
2343 int need_close; |
|
2344 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); |
|
2345 TAILQ_REMOVE(&evcon->requests, req, next); |
|
2346 |
|
2347 need_close = |
|
2348 (REQ_VERSION_BEFORE(req, 1, 1) && |
|
2349 !evhttp_is_connection_keepalive(req->input_headers))|| |
|
2350 evhttp_is_connection_close(req->flags, req->input_headers) || |
|
2351 evhttp_is_connection_close(req->flags, req->output_headers); |
|
2352 |
|
2353 EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION); |
|
2354 evhttp_request_free(req); |
|
2355 |
|
2356 if (need_close) { |
|
2357 evhttp_connection_free(evcon); |
|
2358 return; |
|
2359 } |
|
2360 |
|
2361 /* we have a persistent connection; try to accept another request. */ |
|
2362 if (evhttp_associate_new_request_with_connection(evcon) == -1) { |
|
2363 evhttp_connection_free(evcon); |
|
2364 } |
|
2365 } |
|
2366 |
|
2367 /* |
|
2368 * Returns an error page. |
|
2369 */ |
|
2370 |
|
2371 void |
|
2372 evhttp_send_error(struct evhttp_request *req, int error, const char *reason) |
|
2373 { |
|
2374 |
|
2375 #define ERR_FORMAT "<HTML><HEAD>\n" \ |
|
2376 "<TITLE>%d %s</TITLE>\n" \ |
|
2377 "</HEAD><BODY>\n" \ |
|
2378 "<H1>%s</H1>\n" \ |
|
2379 "</BODY></HTML>\n" |
|
2380 |
|
2381 struct evbuffer *buf = evbuffer_new(); |
|
2382 if (buf == NULL) { |
|
2383 /* if we cannot allocate memory; we just drop the connection */ |
|
2384 evhttp_connection_free(req->evcon); |
|
2385 return; |
|
2386 } |
|
2387 if (reason == NULL) { |
|
2388 reason = evhttp_response_phrase_internal(error); |
|
2389 } |
|
2390 |
|
2391 evhttp_response_code(req, error, reason); |
|
2392 |
|
2393 evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason); |
|
2394 |
|
2395 evhttp_send_page(req, buf); |
|
2396 |
|
2397 evbuffer_free(buf); |
|
2398 #undef ERR_FORMAT |
|
2399 } |
|
2400 |
|
2401 /* Requires that headers and response code are already set up */ |
|
2402 |
|
2403 static inline void |
|
2404 evhttp_send(struct evhttp_request *req, struct evbuffer *databuf) |
|
2405 { |
|
2406 struct evhttp_connection *evcon = req->evcon; |
|
2407 |
|
2408 if (evcon == NULL) { |
|
2409 evhttp_request_free(req); |
|
2410 return; |
|
2411 } |
|
2412 |
|
2413 EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req); |
|
2414 |
|
2415 /* we expect no more calls form the user on this request */ |
|
2416 req->userdone = 1; |
|
2417 |
|
2418 /* xxx: not sure if we really should expose the data buffer this way */ |
|
2419 if (databuf != NULL) |
|
2420 evbuffer_add_buffer(req->output_buffer, databuf); |
|
2421 |
|
2422 /* Adds headers to the response */ |
|
2423 evhttp_make_header(evcon, req); |
|
2424 |
|
2425 evhttp_write_buffer(evcon, evhttp_send_done, NULL); |
|
2426 } |
|
2427 |
|
2428 void |
|
2429 evhttp_send_reply(struct evhttp_request *req, int code, const char *reason, |
|
2430 struct evbuffer *databuf) |
|
2431 { |
|
2432 evhttp_response_code(req, code, reason); |
|
2433 |
|
2434 evhttp_send(req, databuf); |
|
2435 } |
|
2436 |
|
2437 void |
|
2438 evhttp_send_reply_start(struct evhttp_request *req, int code, |
|
2439 const char *reason) |
|
2440 { |
|
2441 evhttp_response_code(req, code, reason); |
|
2442 if (evhttp_find_header(req->output_headers, "Content-Length") == NULL && |
|
2443 REQ_VERSION_ATLEAST(req, 1, 1) && |
|
2444 evhttp_response_needs_body(req)) { |
|
2445 /* |
|
2446 * prefer HTTP/1.1 chunked encoding to closing the connection; |
|
2447 * note RFC 2616 section 4.4 forbids it with Content-Length: |
|
2448 * and it's not necessary then anyway. |
|
2449 */ |
|
2450 evhttp_add_header(req->output_headers, "Transfer-Encoding", |
|
2451 "chunked"); |
|
2452 req->chunked = 1; |
|
2453 } else { |
|
2454 req->chunked = 0; |
|
2455 } |
|
2456 evhttp_make_header(req->evcon, req); |
|
2457 evhttp_write_buffer(req->evcon, NULL, NULL); |
|
2458 } |
|
2459 |
|
2460 void |
|
2461 evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf) |
|
2462 { |
|
2463 struct evhttp_connection *evcon = req->evcon; |
|
2464 struct evbuffer *output; |
|
2465 |
|
2466 if (evcon == NULL) |
|
2467 return; |
|
2468 |
|
2469 output = bufferevent_get_output(evcon->bufev); |
|
2470 |
|
2471 if (evbuffer_get_length(databuf) == 0) |
|
2472 return; |
|
2473 if (!evhttp_response_needs_body(req)) |
|
2474 return; |
|
2475 if (req->chunked) { |
|
2476 evbuffer_add_printf(output, "%x\r\n", |
|
2477 (unsigned)evbuffer_get_length(databuf)); |
|
2478 } |
|
2479 evbuffer_add_buffer(output, databuf); |
|
2480 if (req->chunked) { |
|
2481 evbuffer_add(output, "\r\n", 2); |
|
2482 } |
|
2483 evhttp_write_buffer(evcon, NULL, NULL); |
|
2484 } |
|
2485 |
|
2486 void |
|
2487 evhttp_send_reply_end(struct evhttp_request *req) |
|
2488 { |
|
2489 struct evhttp_connection *evcon = req->evcon; |
|
2490 struct evbuffer *output; |
|
2491 |
|
2492 if (evcon == NULL) { |
|
2493 evhttp_request_free(req); |
|
2494 return; |
|
2495 } |
|
2496 |
|
2497 output = bufferevent_get_output(evcon->bufev); |
|
2498 |
|
2499 /* we expect no more calls form the user on this request */ |
|
2500 req->userdone = 1; |
|
2501 |
|
2502 if (req->chunked) { |
|
2503 evbuffer_add(output, "0\r\n\r\n", 5); |
|
2504 evhttp_write_buffer(req->evcon, evhttp_send_done, NULL); |
|
2505 req->chunked = 0; |
|
2506 } else if (evbuffer_get_length(output) == 0) { |
|
2507 /* let the connection know that we are done with the request */ |
|
2508 evhttp_send_done(evcon, NULL); |
|
2509 } else { |
|
2510 /* make the callback execute after all data has been written */ |
|
2511 evcon->cb = evhttp_send_done; |
|
2512 evcon->cb_arg = NULL; |
|
2513 } |
|
2514 } |
|
2515 |
|
2516 static const char *informational_phrases[] = { |
|
2517 /* 100 */ "Continue", |
|
2518 /* 101 */ "Switching Protocols" |
|
2519 }; |
|
2520 |
|
2521 static const char *success_phrases[] = { |
|
2522 /* 200 */ "OK", |
|
2523 /* 201 */ "Created", |
|
2524 /* 202 */ "Accepted", |
|
2525 /* 203 */ "Non-Authoritative Information", |
|
2526 /* 204 */ "No Content", |
|
2527 /* 205 */ "Reset Content", |
|
2528 /* 206 */ "Partial Content" |
|
2529 }; |
|
2530 |
|
2531 static const char *redirection_phrases[] = { |
|
2532 /* 300 */ "Multiple Choices", |
|
2533 /* 301 */ "Moved Permanently", |
|
2534 /* 302 */ "Found", |
|
2535 /* 303 */ "See Other", |
|
2536 /* 304 */ "Not Modified", |
|
2537 /* 305 */ "Use Proxy", |
|
2538 /* 307 */ "Temporary Redirect" |
|
2539 }; |
|
2540 |
|
2541 static const char *client_error_phrases[] = { |
|
2542 /* 400 */ "Bad Request", |
|
2543 /* 401 */ "Unauthorized", |
|
2544 /* 402 */ "Payment Required", |
|
2545 /* 403 */ "Forbidden", |
|
2546 /* 404 */ "Not Found", |
|
2547 /* 405 */ "Method Not Allowed", |
|
2548 /* 406 */ "Not Acceptable", |
|
2549 /* 407 */ "Proxy Authentication Required", |
|
2550 /* 408 */ "Request Time-out", |
|
2551 /* 409 */ "Conflict", |
|
2552 /* 410 */ "Gone", |
|
2553 /* 411 */ "Length Required", |
|
2554 /* 412 */ "Precondition Failed", |
|
2555 /* 413 */ "Request Entity Too Large", |
|
2556 /* 414 */ "Request-URI Too Large", |
|
2557 /* 415 */ "Unsupported Media Type", |
|
2558 /* 416 */ "Requested range not satisfiable", |
|
2559 /* 417 */ "Expectation Failed" |
|
2560 }; |
|
2561 |
|
2562 static const char *server_error_phrases[] = { |
|
2563 /* 500 */ "Internal Server Error", |
|
2564 /* 501 */ "Not Implemented", |
|
2565 /* 502 */ "Bad Gateway", |
|
2566 /* 503 */ "Service Unavailable", |
|
2567 /* 504 */ "Gateway Time-out", |
|
2568 /* 505 */ "HTTP Version not supported" |
|
2569 }; |
|
2570 |
|
2571 struct response_class { |
|
2572 const char *name; |
|
2573 size_t num_responses; |
|
2574 const char **responses; |
|
2575 }; |
|
2576 |
|
2577 #ifndef MEMBERSOF |
|
2578 #define MEMBERSOF(x) (sizeof(x)/sizeof(x[0])) |
|
2579 #endif |
|
2580 |
|
2581 static const struct response_class response_classes[] = { |
|
2582 /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases }, |
|
2583 /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases }, |
|
2584 /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases }, |
|
2585 /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases }, |
|
2586 /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases } |
|
2587 }; |
|
2588 |
|
2589 static const char * |
|
2590 evhttp_response_phrase_internal(int code) |
|
2591 { |
|
2592 int klass = code / 100 - 1; |
|
2593 int subcode = code % 100; |
|
2594 |
|
2595 /* Unknown class - can't do any better here */ |
|
2596 if (klass < 0 || klass >= (int) MEMBERSOF(response_classes)) |
|
2597 return "Unknown Status Class"; |
|
2598 |
|
2599 /* Unknown sub-code, return class name at least */ |
|
2600 if (subcode >= (int) response_classes[klass].num_responses) |
|
2601 return response_classes[klass].name; |
|
2602 |
|
2603 return response_classes[klass].responses[subcode]; |
|
2604 } |
|
2605 |
|
2606 void |
|
2607 evhttp_response_code(struct evhttp_request *req, int code, const char *reason) |
|
2608 { |
|
2609 req->kind = EVHTTP_RESPONSE; |
|
2610 req->response_code = code; |
|
2611 if (req->response_code_line != NULL) |
|
2612 mm_free(req->response_code_line); |
|
2613 if (reason == NULL) |
|
2614 reason = evhttp_response_phrase_internal(code); |
|
2615 req->response_code_line = mm_strdup(reason); |
|
2616 if (req->response_code_line == NULL) { |
|
2617 event_warn("%s: strdup", __func__); |
|
2618 /* XXX what else can we do? */ |
|
2619 } |
|
2620 } |
|
2621 |
|
2622 void |
|
2623 evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf) |
|
2624 { |
|
2625 if (!req->major || !req->minor) { |
|
2626 req->major = 1; |
|
2627 req->minor = 1; |
|
2628 } |
|
2629 |
|
2630 if (req->kind != EVHTTP_RESPONSE) |
|
2631 evhttp_response_code(req, 200, "OK"); |
|
2632 |
|
2633 evhttp_clear_headers(req->output_headers); |
|
2634 evhttp_add_header(req->output_headers, "Content-Type", "text/html"); |
|
2635 evhttp_add_header(req->output_headers, "Connection", "close"); |
|
2636 |
|
2637 evhttp_send(req, databuf); |
|
2638 } |
|
2639 |
|
2640 static const char uri_chars[256] = { |
|
2641 /* 0 */ |
|
2642 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2643 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
|
2645 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, |
|
2646 /* 64 */ |
|
2647 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
|
2648 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, |
|
2649 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
|
2650 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, |
|
2651 /* 128 */ |
|
2652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2653 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2654 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2655 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2656 /* 192 */ |
|
2657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2659 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2660 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
2661 }; |
|
2662 |
|
2663 #define CHAR_IS_UNRESERVED(c) \ |
|
2664 (uri_chars[(unsigned char)(c)]) |
|
2665 |
|
2666 /* |
|
2667 * Helper functions to encode/decode a string for inclusion in a URI. |
|
2668 * The returned string must be freed by the caller. |
|
2669 */ |
|
2670 char * |
|
2671 evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus) |
|
2672 { |
|
2673 struct evbuffer *buf = evbuffer_new(); |
|
2674 const char *p, *end; |
|
2675 char *result; |
|
2676 |
|
2677 if (buf == NULL) |
|
2678 return (NULL); |
|
2679 |
|
2680 if (len >= 0) |
|
2681 end = uri+len; |
|
2682 else |
|
2683 end = uri+strlen(uri); |
|
2684 |
|
2685 for (p = uri; p < end; p++) { |
|
2686 if (CHAR_IS_UNRESERVED(*p)) { |
|
2687 evbuffer_add(buf, p, 1); |
|
2688 } else if (*p == ' ' && space_as_plus) { |
|
2689 evbuffer_add(buf, "+", 1); |
|
2690 } else { |
|
2691 evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p)); |
|
2692 } |
|
2693 } |
|
2694 evbuffer_add(buf, "", 1); /* NUL-terminator. */ |
|
2695 result = mm_malloc(evbuffer_get_length(buf)); |
|
2696 if (result) |
|
2697 evbuffer_remove(buf, result, evbuffer_get_length(buf)); |
|
2698 evbuffer_free(buf); |
|
2699 |
|
2700 return (result); |
|
2701 } |
|
2702 |
|
2703 char * |
|
2704 evhttp_encode_uri(const char *str) |
|
2705 { |
|
2706 return evhttp_uriencode(str, -1, 0); |
|
2707 } |
|
2708 |
|
2709 /* |
|
2710 * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't. |
|
2711 * If -1, when true we transform plus to space only after we've seen |
|
2712 * a ?. -1 is deprecated. |
|
2713 * @return the number of bytes written to 'ret'. |
|
2714 */ |
|
2715 static int |
|
2716 evhttp_decode_uri_internal( |
|
2717 const char *uri, size_t length, char *ret, int decode_plus_ctl) |
|
2718 { |
|
2719 char c; |
|
2720 int j; |
|
2721 int decode_plus = (decode_plus_ctl == 1) ? 1: 0; |
|
2722 unsigned i; |
|
2723 |
|
2724 for (i = j = 0; i < length; i++) { |
|
2725 c = uri[i]; |
|
2726 if (c == '?') { |
|
2727 if (decode_plus_ctl < 0) |
|
2728 decode_plus = 1; |
|
2729 } else if (c == '+' && decode_plus) { |
|
2730 c = ' '; |
|
2731 } else if (c == '%' && EVUTIL_ISXDIGIT(uri[i+1]) && |
|
2732 EVUTIL_ISXDIGIT(uri[i+2])) { |
|
2733 char tmp[3]; |
|
2734 tmp[0] = uri[i+1]; |
|
2735 tmp[1] = uri[i+2]; |
|
2736 tmp[2] = '\0'; |
|
2737 c = (char)strtol(tmp, NULL, 16); |
|
2738 i += 2; |
|
2739 } |
|
2740 ret[j++] = c; |
|
2741 } |
|
2742 ret[j] = '\0'; |
|
2743 |
|
2744 return (j); |
|
2745 } |
|
2746 |
|
2747 /* deprecated */ |
|
2748 char * |
|
2749 evhttp_decode_uri(const char *uri) |
|
2750 { |
|
2751 char *ret; |
|
2752 |
|
2753 if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { |
|
2754 event_warn("%s: malloc(%lu)", __func__, |
|
2755 (unsigned long)(strlen(uri) + 1)); |
|
2756 return (NULL); |
|
2757 } |
|
2758 |
|
2759 evhttp_decode_uri_internal(uri, strlen(uri), |
|
2760 ret, -1 /*always_decode_plus*/); |
|
2761 |
|
2762 return (ret); |
|
2763 } |
|
2764 |
|
2765 char * |
|
2766 evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out) |
|
2767 { |
|
2768 char *ret; |
|
2769 int n; |
|
2770 |
|
2771 if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { |
|
2772 event_warn("%s: malloc(%lu)", __func__, |
|
2773 (unsigned long)(strlen(uri) + 1)); |
|
2774 return (NULL); |
|
2775 } |
|
2776 |
|
2777 n = evhttp_decode_uri_internal(uri, strlen(uri), |
|
2778 ret, !!decode_plus/*always_decode_plus*/); |
|
2779 |
|
2780 if (size_out) { |
|
2781 EVUTIL_ASSERT(n >= 0); |
|
2782 *size_out = (size_t)n; |
|
2783 } |
|
2784 |
|
2785 return (ret); |
|
2786 } |
|
2787 |
|
2788 /* |
|
2789 * Helper function to parse out arguments in a query. |
|
2790 * The arguments are separated by key and value. |
|
2791 */ |
|
2792 |
|
2793 static int |
|
2794 evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers, |
|
2795 int is_whole_uri) |
|
2796 { |
|
2797 char *line=NULL; |
|
2798 char *argument; |
|
2799 char *p; |
|
2800 const char *query_part; |
|
2801 int result = -1; |
|
2802 struct evhttp_uri *uri=NULL; |
|
2803 |
|
2804 TAILQ_INIT(headers); |
|
2805 |
|
2806 if (is_whole_uri) { |
|
2807 uri = evhttp_uri_parse(str); |
|
2808 if (!uri) |
|
2809 goto error; |
|
2810 query_part = evhttp_uri_get_query(uri); |
|
2811 } else { |
|
2812 query_part = str; |
|
2813 } |
|
2814 |
|
2815 /* No arguments - we are done */ |
|
2816 if (!query_part || !strlen(query_part)) { |
|
2817 result = 0; |
|
2818 goto done; |
|
2819 } |
|
2820 |
|
2821 if ((line = mm_strdup(query_part)) == NULL) { |
|
2822 event_warn("%s: strdup", __func__); |
|
2823 goto error; |
|
2824 } |
|
2825 |
|
2826 p = argument = line; |
|
2827 while (p != NULL && *p != '\0') { |
|
2828 char *key, *value, *decoded_value; |
|
2829 argument = strsep(&p, "&"); |
|
2830 |
|
2831 value = argument; |
|
2832 key = strsep(&value, "="); |
|
2833 if (value == NULL || *key == '\0') { |
|
2834 goto error; |
|
2835 } |
|
2836 |
|
2837 if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) { |
|
2838 event_warn("%s: mm_malloc", __func__); |
|
2839 goto error; |
|
2840 } |
|
2841 evhttp_decode_uri_internal(value, strlen(value), |
|
2842 decoded_value, 1 /*always_decode_plus*/); |
|
2843 event_debug(("Query Param: %s -> %s\n", key, decoded_value)); |
|
2844 evhttp_add_header_internal(headers, key, decoded_value); |
|
2845 mm_free(decoded_value); |
|
2846 } |
|
2847 |
|
2848 result = 0; |
|
2849 goto done; |
|
2850 error: |
|
2851 evhttp_clear_headers(headers); |
|
2852 done: |
|
2853 if (line) |
|
2854 mm_free(line); |
|
2855 if (uri) |
|
2856 evhttp_uri_free(uri); |
|
2857 return result; |
|
2858 } |
|
2859 |
|
2860 int |
|
2861 evhttp_parse_query(const char *uri, struct evkeyvalq *headers) |
|
2862 { |
|
2863 return evhttp_parse_query_impl(uri, headers, 1); |
|
2864 } |
|
2865 int |
|
2866 evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers) |
|
2867 { |
|
2868 return evhttp_parse_query_impl(uri, headers, 0); |
|
2869 } |
|
2870 |
|
2871 static struct evhttp_cb * |
|
2872 evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req) |
|
2873 { |
|
2874 struct evhttp_cb *cb; |
|
2875 size_t offset = 0; |
|
2876 char *translated; |
|
2877 const char *path; |
|
2878 |
|
2879 /* Test for different URLs */ |
|
2880 path = evhttp_uri_get_path(req->uri_elems); |
|
2881 offset = strlen(path); |
|
2882 if ((translated = mm_malloc(offset + 1)) == NULL) |
|
2883 return (NULL); |
|
2884 evhttp_decode_uri_internal(path, offset, translated, |
|
2885 0 /* decode_plus */); |
|
2886 |
|
2887 TAILQ_FOREACH(cb, callbacks, next) { |
|
2888 if (!strcmp(cb->what, translated)) { |
|
2889 mm_free(translated); |
|
2890 return (cb); |
|
2891 } |
|
2892 } |
|
2893 |
|
2894 mm_free(translated); |
|
2895 return (NULL); |
|
2896 } |
|
2897 |
|
2898 |
|
2899 static int |
|
2900 prefix_suffix_match(const char *pattern, const char *name, int ignorecase) |
|
2901 { |
|
2902 char c; |
|
2903 |
|
2904 while (1) { |
|
2905 switch (c = *pattern++) { |
|
2906 case '\0': |
|
2907 return *name == '\0'; |
|
2908 |
|
2909 case '*': |
|
2910 while (*name != '\0') { |
|
2911 if (prefix_suffix_match(pattern, name, |
|
2912 ignorecase)) |
|
2913 return (1); |
|
2914 ++name; |
|
2915 } |
|
2916 return (0); |
|
2917 default: |
|
2918 if (c != *name) { |
|
2919 if (!ignorecase || |
|
2920 EVUTIL_TOLOWER(c) != EVUTIL_TOLOWER(*name)) |
|
2921 return (0); |
|
2922 } |
|
2923 ++name; |
|
2924 } |
|
2925 } |
|
2926 /* NOTREACHED */ |
|
2927 } |
|
2928 |
|
2929 /* |
|
2930 Search the vhost hierarchy beginning with http for a server alias |
|
2931 matching hostname. If a match is found, and outhttp is non-null, |
|
2932 outhttp is set to the matching http object and 1 is returned. |
|
2933 */ |
|
2934 |
|
2935 static int |
|
2936 evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp, |
|
2937 const char *hostname) |
|
2938 { |
|
2939 struct evhttp_server_alias *alias; |
|
2940 struct evhttp *vhost; |
|
2941 |
|
2942 TAILQ_FOREACH(alias, &http->aliases, next) { |
|
2943 /* XXX Do we need to handle IP addresses? */ |
|
2944 if (!evutil_ascii_strcasecmp(alias->alias, hostname)) { |
|
2945 if (outhttp) |
|
2946 *outhttp = http; |
|
2947 return 1; |
|
2948 } |
|
2949 } |
|
2950 |
|
2951 /* XXX It might be good to avoid recursion here, but I don't |
|
2952 see a way to do that w/o a list. */ |
|
2953 TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { |
|
2954 if (evhttp_find_alias(vhost, outhttp, hostname)) |
|
2955 return 1; |
|
2956 } |
|
2957 |
|
2958 return 0; |
|
2959 } |
|
2960 |
|
2961 /* |
|
2962 Attempts to find the best http object to handle a request for a hostname. |
|
2963 All aliases for the root http object and vhosts are searched for an exact |
|
2964 match. Then, the vhost hierarchy is traversed again for a matching |
|
2965 pattern. |
|
2966 |
|
2967 If an alias or vhost is matched, 1 is returned, and outhttp, if non-null, |
|
2968 is set with the best matching http object. If there are no matches, the |
|
2969 root http object is stored in outhttp and 0 is returned. |
|
2970 */ |
|
2971 |
|
2972 static int |
|
2973 evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, |
|
2974 const char *hostname) |
|
2975 { |
|
2976 struct evhttp *vhost; |
|
2977 struct evhttp *oldhttp; |
|
2978 int match_found = 0; |
|
2979 |
|
2980 if (evhttp_find_alias(http, outhttp, hostname)) |
|
2981 return 1; |
|
2982 |
|
2983 do { |
|
2984 oldhttp = http; |
|
2985 TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { |
|
2986 if (prefix_suffix_match(vhost->vhost_pattern, |
|
2987 hostname, 1 /* ignorecase */)) { |
|
2988 http = vhost; |
|
2989 match_found = 1; |
|
2990 break; |
|
2991 } |
|
2992 } |
|
2993 } while (oldhttp != http); |
|
2994 |
|
2995 if (outhttp) |
|
2996 *outhttp = http; |
|
2997 |
|
2998 return match_found; |
|
2999 } |
|
3000 |
|
3001 static void |
|
3002 evhttp_handle_request(struct evhttp_request *req, void *arg) |
|
3003 { |
|
3004 struct evhttp *http = arg; |
|
3005 struct evhttp_cb *cb = NULL; |
|
3006 const char *hostname; |
|
3007 |
|
3008 /* we have a new request on which the user needs to take action */ |
|
3009 req->userdone = 0; |
|
3010 |
|
3011 if (req->type == 0 || req->uri == NULL) { |
|
3012 evhttp_send_error(req, HTTP_BADREQUEST, NULL); |
|
3013 return; |
|
3014 } |
|
3015 |
|
3016 if ((http->allowed_methods & req->type) == 0) { |
|
3017 event_debug(("Rejecting disallowed method %x (allowed: %x)\n", |
|
3018 (unsigned)req->type, (unsigned)http->allowed_methods)); |
|
3019 evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL); |
|
3020 return; |
|
3021 } |
|
3022 |
|
3023 /* handle potential virtual hosts */ |
|
3024 hostname = evhttp_request_get_host(req); |
|
3025 if (hostname != NULL) { |
|
3026 evhttp_find_vhost(http, &http, hostname); |
|
3027 } |
|
3028 |
|
3029 if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) { |
|
3030 (*cb->cb)(req, cb->cbarg); |
|
3031 return; |
|
3032 } |
|
3033 |
|
3034 /* Generic call back */ |
|
3035 if (http->gencb) { |
|
3036 (*http->gencb)(req, http->gencbarg); |
|
3037 return; |
|
3038 } else { |
|
3039 /* We need to send a 404 here */ |
|
3040 #define ERR_FORMAT "<html><head>" \ |
|
3041 "<title>404 Not Found</title>" \ |
|
3042 "</head><body>" \ |
|
3043 "<h1>Not Found</h1>" \ |
|
3044 "<p>The requested URL %s was not found on this server.</p>"\ |
|
3045 "</body></html>\n" |
|
3046 |
|
3047 char *escaped_html; |
|
3048 struct evbuffer *buf; |
|
3049 |
|
3050 if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) { |
|
3051 evhttp_connection_free(req->evcon); |
|
3052 return; |
|
3053 } |
|
3054 |
|
3055 if ((buf = evbuffer_new()) == NULL) { |
|
3056 mm_free(escaped_html); |
|
3057 evhttp_connection_free(req->evcon); |
|
3058 return; |
|
3059 } |
|
3060 |
|
3061 evhttp_response_code(req, HTTP_NOTFOUND, "Not Found"); |
|
3062 |
|
3063 evbuffer_add_printf(buf, ERR_FORMAT, escaped_html); |
|
3064 |
|
3065 mm_free(escaped_html); |
|
3066 |
|
3067 evhttp_send_page(req, buf); |
|
3068 |
|
3069 evbuffer_free(buf); |
|
3070 #undef ERR_FORMAT |
|
3071 } |
|
3072 } |
|
3073 |
|
3074 /* Listener callback when a connection arrives at a server. */ |
|
3075 static void |
|
3076 accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg) |
|
3077 { |
|
3078 struct evhttp *http = arg; |
|
3079 |
|
3080 evhttp_get_request(http, nfd, peer_sa, peer_socklen); |
|
3081 } |
|
3082 |
|
3083 int |
|
3084 evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port) |
|
3085 { |
|
3086 struct evhttp_bound_socket *bound = |
|
3087 evhttp_bind_socket_with_handle(http, address, port); |
|
3088 if (bound == NULL) |
|
3089 return (-1); |
|
3090 return (0); |
|
3091 } |
|
3092 |
|
3093 struct evhttp_bound_socket * |
|
3094 evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port) |
|
3095 { |
|
3096 evutil_socket_t fd; |
|
3097 struct evhttp_bound_socket *bound; |
|
3098 |
|
3099 if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1) |
|
3100 return (NULL); |
|
3101 |
|
3102 if (listen(fd, 128) == -1) { |
|
3103 event_sock_warn(fd, "%s: listen", __func__); |
|
3104 evutil_closesocket(fd); |
|
3105 return (NULL); |
|
3106 } |
|
3107 |
|
3108 bound = evhttp_accept_socket_with_handle(http, fd); |
|
3109 |
|
3110 if (bound != NULL) { |
|
3111 event_debug(("Bound to port %d - Awaiting connections ... ", |
|
3112 port)); |
|
3113 return (bound); |
|
3114 } |
|
3115 |
|
3116 return (NULL); |
|
3117 } |
|
3118 |
|
3119 int |
|
3120 evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd) |
|
3121 { |
|
3122 struct evhttp_bound_socket *bound = |
|
3123 evhttp_accept_socket_with_handle(http, fd); |
|
3124 if (bound == NULL) |
|
3125 return (-1); |
|
3126 return (0); |
|
3127 } |
|
3128 |
|
3129 |
|
3130 struct evhttp_bound_socket * |
|
3131 evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd) |
|
3132 { |
|
3133 struct evhttp_bound_socket *bound; |
|
3134 struct evconnlistener *listener; |
|
3135 const int flags = |
|
3136 LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE; |
|
3137 |
|
3138 listener = evconnlistener_new(http->base, NULL, NULL, |
|
3139 flags, |
|
3140 0, /* Backlog is '0' because we already said 'listen' */ |
|
3141 fd); |
|
3142 if (!listener) |
|
3143 return (NULL); |
|
3144 |
|
3145 bound = evhttp_bind_listener(http, listener); |
|
3146 if (!bound) { |
|
3147 evconnlistener_free(listener); |
|
3148 return (NULL); |
|
3149 } |
|
3150 return (bound); |
|
3151 } |
|
3152 |
|
3153 struct evhttp_bound_socket * |
|
3154 evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener) |
|
3155 { |
|
3156 struct evhttp_bound_socket *bound; |
|
3157 |
|
3158 bound = mm_malloc(sizeof(struct evhttp_bound_socket)); |
|
3159 if (bound == NULL) |
|
3160 return (NULL); |
|
3161 |
|
3162 bound->listener = listener; |
|
3163 TAILQ_INSERT_TAIL(&http->sockets, bound, next); |
|
3164 |
|
3165 evconnlistener_set_cb(listener, accept_socket_cb, http); |
|
3166 return bound; |
|
3167 } |
|
3168 |
|
3169 evutil_socket_t |
|
3170 evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound) |
|
3171 { |
|
3172 return evconnlistener_get_fd(bound->listener); |
|
3173 } |
|
3174 |
|
3175 struct evconnlistener * |
|
3176 evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound) |
|
3177 { |
|
3178 return bound->listener; |
|
3179 } |
|
3180 |
|
3181 void |
|
3182 evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound) |
|
3183 { |
|
3184 TAILQ_REMOVE(&http->sockets, bound, next); |
|
3185 evconnlistener_free(bound->listener); |
|
3186 mm_free(bound); |
|
3187 } |
|
3188 |
|
3189 static struct evhttp* |
|
3190 evhttp_new_object(void) |
|
3191 { |
|
3192 struct evhttp *http = NULL; |
|
3193 |
|
3194 if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) { |
|
3195 event_warn("%s: calloc", __func__); |
|
3196 return (NULL); |
|
3197 } |
|
3198 |
|
3199 http->timeout = -1; |
|
3200 evhttp_set_max_headers_size(http, EV_SIZE_MAX); |
|
3201 evhttp_set_max_body_size(http, EV_SIZE_MAX); |
|
3202 evhttp_set_allowed_methods(http, |
|
3203 EVHTTP_REQ_GET | |
|
3204 EVHTTP_REQ_POST | |
|
3205 EVHTTP_REQ_HEAD | |
|
3206 EVHTTP_REQ_PUT | |
|
3207 EVHTTP_REQ_DELETE); |
|
3208 |
|
3209 TAILQ_INIT(&http->sockets); |
|
3210 TAILQ_INIT(&http->callbacks); |
|
3211 TAILQ_INIT(&http->connections); |
|
3212 TAILQ_INIT(&http->virtualhosts); |
|
3213 TAILQ_INIT(&http->aliases); |
|
3214 |
|
3215 return (http); |
|
3216 } |
|
3217 |
|
3218 struct evhttp * |
|
3219 evhttp_new(struct event_base *base) |
|
3220 { |
|
3221 struct evhttp *http = NULL; |
|
3222 |
|
3223 http = evhttp_new_object(); |
|
3224 if (http == NULL) |
|
3225 return (NULL); |
|
3226 http->base = base; |
|
3227 |
|
3228 return (http); |
|
3229 } |
|
3230 |
|
3231 /* |
|
3232 * Start a web server on the specified address and port. |
|
3233 */ |
|
3234 |
|
3235 struct evhttp * |
|
3236 evhttp_start(const char *address, unsigned short port) |
|
3237 { |
|
3238 struct evhttp *http = NULL; |
|
3239 |
|
3240 http = evhttp_new_object(); |
|
3241 if (http == NULL) |
|
3242 return (NULL); |
|
3243 if (evhttp_bind_socket(http, address, port) == -1) { |
|
3244 mm_free(http); |
|
3245 return (NULL); |
|
3246 } |
|
3247 |
|
3248 return (http); |
|
3249 } |
|
3250 |
|
3251 void |
|
3252 evhttp_free(struct evhttp* http) |
|
3253 { |
|
3254 struct evhttp_cb *http_cb; |
|
3255 struct evhttp_connection *evcon; |
|
3256 struct evhttp_bound_socket *bound; |
|
3257 struct evhttp* vhost; |
|
3258 struct evhttp_server_alias *alias; |
|
3259 |
|
3260 /* Remove the accepting part */ |
|
3261 while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) { |
|
3262 TAILQ_REMOVE(&http->sockets, bound, next); |
|
3263 |
|
3264 evconnlistener_free(bound->listener); |
|
3265 |
|
3266 mm_free(bound); |
|
3267 } |
|
3268 |
|
3269 while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) { |
|
3270 /* evhttp_connection_free removes the connection */ |
|
3271 evhttp_connection_free(evcon); |
|
3272 } |
|
3273 |
|
3274 while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) { |
|
3275 TAILQ_REMOVE(&http->callbacks, http_cb, next); |
|
3276 mm_free(http_cb->what); |
|
3277 mm_free(http_cb); |
|
3278 } |
|
3279 |
|
3280 while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) { |
|
3281 TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); |
|
3282 |
|
3283 evhttp_free(vhost); |
|
3284 } |
|
3285 |
|
3286 if (http->vhost_pattern != NULL) |
|
3287 mm_free(http->vhost_pattern); |
|
3288 |
|
3289 while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) { |
|
3290 TAILQ_REMOVE(&http->aliases, alias, next); |
|
3291 mm_free(alias->alias); |
|
3292 mm_free(alias); |
|
3293 } |
|
3294 |
|
3295 mm_free(http); |
|
3296 } |
|
3297 |
|
3298 int |
|
3299 evhttp_add_virtual_host(struct evhttp* http, const char *pattern, |
|
3300 struct evhttp* vhost) |
|
3301 { |
|
3302 /* a vhost can only be a vhost once and should not have bound sockets */ |
|
3303 if (vhost->vhost_pattern != NULL || |
|
3304 TAILQ_FIRST(&vhost->sockets) != NULL) |
|
3305 return (-1); |
|
3306 |
|
3307 vhost->vhost_pattern = mm_strdup(pattern); |
|
3308 if (vhost->vhost_pattern == NULL) |
|
3309 return (-1); |
|
3310 |
|
3311 TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost); |
|
3312 |
|
3313 return (0); |
|
3314 } |
|
3315 |
|
3316 int |
|
3317 evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost) |
|
3318 { |
|
3319 if (vhost->vhost_pattern == NULL) |
|
3320 return (-1); |
|
3321 |
|
3322 TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); |
|
3323 |
|
3324 mm_free(vhost->vhost_pattern); |
|
3325 vhost->vhost_pattern = NULL; |
|
3326 |
|
3327 return (0); |
|
3328 } |
|
3329 |
|
3330 int |
|
3331 evhttp_add_server_alias(struct evhttp *http, const char *alias) |
|
3332 { |
|
3333 struct evhttp_server_alias *evalias; |
|
3334 |
|
3335 evalias = mm_calloc(1, sizeof(*evalias)); |
|
3336 if (!evalias) |
|
3337 return -1; |
|
3338 |
|
3339 evalias->alias = mm_strdup(alias); |
|
3340 if (!evalias->alias) { |
|
3341 mm_free(evalias); |
|
3342 return -1; |
|
3343 } |
|
3344 |
|
3345 TAILQ_INSERT_TAIL(&http->aliases, evalias, next); |
|
3346 |
|
3347 return 0; |
|
3348 } |
|
3349 |
|
3350 int |
|
3351 evhttp_remove_server_alias(struct evhttp *http, const char *alias) |
|
3352 { |
|
3353 struct evhttp_server_alias *evalias; |
|
3354 |
|
3355 TAILQ_FOREACH(evalias, &http->aliases, next) { |
|
3356 if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) { |
|
3357 TAILQ_REMOVE(&http->aliases, evalias, next); |
|
3358 mm_free(evalias->alias); |
|
3359 mm_free(evalias); |
|
3360 return 0; |
|
3361 } |
|
3362 } |
|
3363 |
|
3364 return -1; |
|
3365 } |
|
3366 |
|
3367 void |
|
3368 evhttp_set_timeout(struct evhttp* http, int timeout_in_secs) |
|
3369 { |
|
3370 http->timeout = timeout_in_secs; |
|
3371 } |
|
3372 |
|
3373 void |
|
3374 evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size) |
|
3375 { |
|
3376 if (max_headers_size < 0) |
|
3377 http->default_max_headers_size = EV_SIZE_MAX; |
|
3378 else |
|
3379 http->default_max_headers_size = max_headers_size; |
|
3380 } |
|
3381 |
|
3382 void |
|
3383 evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size) |
|
3384 { |
|
3385 if (max_body_size < 0) |
|
3386 http->default_max_body_size = EV_UINT64_MAX; |
|
3387 else |
|
3388 http->default_max_body_size = max_body_size; |
|
3389 } |
|
3390 |
|
3391 void |
|
3392 evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods) |
|
3393 { |
|
3394 http->allowed_methods = methods; |
|
3395 } |
|
3396 |
|
3397 int |
|
3398 evhttp_set_cb(struct evhttp *http, const char *uri, |
|
3399 void (*cb)(struct evhttp_request *, void *), void *cbarg) |
|
3400 { |
|
3401 struct evhttp_cb *http_cb; |
|
3402 |
|
3403 TAILQ_FOREACH(http_cb, &http->callbacks, next) { |
|
3404 if (strcmp(http_cb->what, uri) == 0) |
|
3405 return (-1); |
|
3406 } |
|
3407 |
|
3408 if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) { |
|
3409 event_warn("%s: calloc", __func__); |
|
3410 return (-2); |
|
3411 } |
|
3412 |
|
3413 http_cb->what = mm_strdup(uri); |
|
3414 if (http_cb->what == NULL) { |
|
3415 event_warn("%s: strdup", __func__); |
|
3416 mm_free(http_cb); |
|
3417 return (-3); |
|
3418 } |
|
3419 http_cb->cb = cb; |
|
3420 http_cb->cbarg = cbarg; |
|
3421 |
|
3422 TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next); |
|
3423 |
|
3424 return (0); |
|
3425 } |
|
3426 |
|
3427 int |
|
3428 evhttp_del_cb(struct evhttp *http, const char *uri) |
|
3429 { |
|
3430 struct evhttp_cb *http_cb; |
|
3431 |
|
3432 TAILQ_FOREACH(http_cb, &http->callbacks, next) { |
|
3433 if (strcmp(http_cb->what, uri) == 0) |
|
3434 break; |
|
3435 } |
|
3436 if (http_cb == NULL) |
|
3437 return (-1); |
|
3438 |
|
3439 TAILQ_REMOVE(&http->callbacks, http_cb, next); |
|
3440 mm_free(http_cb->what); |
|
3441 mm_free(http_cb); |
|
3442 |
|
3443 return (0); |
|
3444 } |
|
3445 |
|
3446 void |
|
3447 evhttp_set_gencb(struct evhttp *http, |
|
3448 void (*cb)(struct evhttp_request *, void *), void *cbarg) |
|
3449 { |
|
3450 http->gencb = cb; |
|
3451 http->gencbarg = cbarg; |
|
3452 } |
|
3453 |
|
3454 /* |
|
3455 * Request related functions |
|
3456 */ |
|
3457 |
|
3458 struct evhttp_request * |
|
3459 evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg) |
|
3460 { |
|
3461 struct evhttp_request *req = NULL; |
|
3462 |
|
3463 /* Allocate request structure */ |
|
3464 if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) { |
|
3465 event_warn("%s: calloc", __func__); |
|
3466 goto error; |
|
3467 } |
|
3468 |
|
3469 req->headers_size = 0; |
|
3470 req->body_size = 0; |
|
3471 |
|
3472 req->kind = EVHTTP_RESPONSE; |
|
3473 req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq)); |
|
3474 if (req->input_headers == NULL) { |
|
3475 event_warn("%s: calloc", __func__); |
|
3476 goto error; |
|
3477 } |
|
3478 TAILQ_INIT(req->input_headers); |
|
3479 |
|
3480 req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq)); |
|
3481 if (req->output_headers == NULL) { |
|
3482 event_warn("%s: calloc", __func__); |
|
3483 goto error; |
|
3484 } |
|
3485 TAILQ_INIT(req->output_headers); |
|
3486 |
|
3487 if ((req->input_buffer = evbuffer_new()) == NULL) { |
|
3488 event_warn("%s: evbuffer_new", __func__); |
|
3489 goto error; |
|
3490 } |
|
3491 |
|
3492 if ((req->output_buffer = evbuffer_new()) == NULL) { |
|
3493 event_warn("%s: evbuffer_new", __func__); |
|
3494 goto error; |
|
3495 } |
|
3496 |
|
3497 req->cb = cb; |
|
3498 req->cb_arg = arg; |
|
3499 |
|
3500 return (req); |
|
3501 |
|
3502 error: |
|
3503 if (req != NULL) |
|
3504 evhttp_request_free(req); |
|
3505 return (NULL); |
|
3506 } |
|
3507 |
|
3508 void |
|
3509 evhttp_request_free(struct evhttp_request *req) |
|
3510 { |
|
3511 if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) { |
|
3512 req->flags |= EVHTTP_REQ_NEEDS_FREE; |
|
3513 return; |
|
3514 } |
|
3515 |
|
3516 if (req->remote_host != NULL) |
|
3517 mm_free(req->remote_host); |
|
3518 if (req->uri != NULL) |
|
3519 mm_free(req->uri); |
|
3520 if (req->uri_elems != NULL) |
|
3521 evhttp_uri_free(req->uri_elems); |
|
3522 if (req->response_code_line != NULL) |
|
3523 mm_free(req->response_code_line); |
|
3524 if (req->host_cache != NULL) |
|
3525 mm_free(req->host_cache); |
|
3526 |
|
3527 evhttp_clear_headers(req->input_headers); |
|
3528 mm_free(req->input_headers); |
|
3529 |
|
3530 evhttp_clear_headers(req->output_headers); |
|
3531 mm_free(req->output_headers); |
|
3532 |
|
3533 if (req->input_buffer != NULL) |
|
3534 evbuffer_free(req->input_buffer); |
|
3535 |
|
3536 if (req->output_buffer != NULL) |
|
3537 evbuffer_free(req->output_buffer); |
|
3538 |
|
3539 mm_free(req); |
|
3540 } |
|
3541 |
|
3542 void |
|
3543 evhttp_request_own(struct evhttp_request *req) |
|
3544 { |
|
3545 req->flags |= EVHTTP_USER_OWNED; |
|
3546 } |
|
3547 |
|
3548 int |
|
3549 evhttp_request_is_owned(struct evhttp_request *req) |
|
3550 { |
|
3551 return (req->flags & EVHTTP_USER_OWNED) != 0; |
|
3552 } |
|
3553 |
|
3554 struct evhttp_connection * |
|
3555 evhttp_request_get_connection(struct evhttp_request *req) |
|
3556 { |
|
3557 return req->evcon; |
|
3558 } |
|
3559 |
|
3560 struct event_base * |
|
3561 evhttp_connection_get_base(struct evhttp_connection *conn) |
|
3562 { |
|
3563 return conn->base; |
|
3564 } |
|
3565 |
|
3566 void |
|
3567 evhttp_request_set_chunked_cb(struct evhttp_request *req, |
|
3568 void (*cb)(struct evhttp_request *, void *)) |
|
3569 { |
|
3570 req->chunk_cb = cb; |
|
3571 } |
|
3572 |
|
3573 /* |
|
3574 * Allows for inspection of the request URI |
|
3575 */ |
|
3576 |
|
3577 const char * |
|
3578 evhttp_request_get_uri(const struct evhttp_request *req) { |
|
3579 if (req->uri == NULL) |
|
3580 event_debug(("%s: request %p has no uri\n", __func__, req)); |
|
3581 return (req->uri); |
|
3582 } |
|
3583 |
|
3584 const struct evhttp_uri * |
|
3585 evhttp_request_get_evhttp_uri(const struct evhttp_request *req) { |
|
3586 if (req->uri_elems == NULL) |
|
3587 event_debug(("%s: request %p has no uri elems\n", |
|
3588 __func__, req)); |
|
3589 return (req->uri_elems); |
|
3590 } |
|
3591 |
|
3592 const char * |
|
3593 evhttp_request_get_host(struct evhttp_request *req) |
|
3594 { |
|
3595 const char *host = NULL; |
|
3596 |
|
3597 if (req->host_cache) |
|
3598 return req->host_cache; |
|
3599 |
|
3600 if (req->uri_elems) |
|
3601 host = evhttp_uri_get_host(req->uri_elems); |
|
3602 if (!host && req->input_headers) { |
|
3603 const char *p; |
|
3604 size_t len; |
|
3605 |
|
3606 host = evhttp_find_header(req->input_headers, "Host"); |
|
3607 /* The Host: header may include a port. Remove it here |
|
3608 to be consistent with uri_elems case above. */ |
|
3609 if (host) { |
|
3610 p = host + strlen(host) - 1; |
|
3611 while (p > host && EVUTIL_ISDIGIT(*p)) |
|
3612 --p; |
|
3613 if (p > host && *p == ':') { |
|
3614 len = p - host; |
|
3615 req->host_cache = mm_malloc(len + 1); |
|
3616 if (!req->host_cache) { |
|
3617 event_warn("%s: malloc", __func__); |
|
3618 return NULL; |
|
3619 } |
|
3620 memcpy(req->host_cache, host, len); |
|
3621 req->host_cache[len] = '\0'; |
|
3622 host = req->host_cache; |
|
3623 } |
|
3624 } |
|
3625 } |
|
3626 |
|
3627 return host; |
|
3628 } |
|
3629 |
|
3630 enum evhttp_cmd_type |
|
3631 evhttp_request_get_command(const struct evhttp_request *req) { |
|
3632 return (req->type); |
|
3633 } |
|
3634 |
|
3635 int |
|
3636 evhttp_request_get_response_code(const struct evhttp_request *req) |
|
3637 { |
|
3638 return req->response_code; |
|
3639 } |
|
3640 |
|
3641 /** Returns the input headers */ |
|
3642 struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req) |
|
3643 { |
|
3644 return (req->input_headers); |
|
3645 } |
|
3646 |
|
3647 /** Returns the output headers */ |
|
3648 struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req) |
|
3649 { |
|
3650 return (req->output_headers); |
|
3651 } |
|
3652 |
|
3653 /** Returns the input buffer */ |
|
3654 struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req) |
|
3655 { |
|
3656 return (req->input_buffer); |
|
3657 } |
|
3658 |
|
3659 /** Returns the output buffer */ |
|
3660 struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req) |
|
3661 { |
|
3662 return (req->output_buffer); |
|
3663 } |
|
3664 |
|
3665 |
|
3666 /* |
|
3667 * Takes a file descriptor to read a request from. |
|
3668 * The callback is executed once the whole request has been read. |
|
3669 */ |
|
3670 |
|
3671 static struct evhttp_connection* |
|
3672 evhttp_get_request_connection( |
|
3673 struct evhttp* http, |
|
3674 evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen) |
|
3675 { |
|
3676 struct evhttp_connection *evcon; |
|
3677 char *hostname = NULL, *portname = NULL; |
|
3678 |
|
3679 name_from_addr(sa, salen, &hostname, &portname); |
|
3680 if (hostname == NULL || portname == NULL) { |
|
3681 if (hostname) mm_free(hostname); |
|
3682 if (portname) mm_free(portname); |
|
3683 return (NULL); |
|
3684 } |
|
3685 |
|
3686 event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n", |
|
3687 __func__, hostname, portname, EV_SOCK_ARG(fd))); |
|
3688 |
|
3689 /* we need a connection object to put the http request on */ |
|
3690 evcon = evhttp_connection_base_new( |
|
3691 http->base, NULL, hostname, atoi(portname)); |
|
3692 mm_free(hostname); |
|
3693 mm_free(portname); |
|
3694 if (evcon == NULL) |
|
3695 return (NULL); |
|
3696 |
|
3697 evcon->max_headers_size = http->default_max_headers_size; |
|
3698 evcon->max_body_size = http->default_max_body_size; |
|
3699 |
|
3700 evcon->flags |= EVHTTP_CON_INCOMING; |
|
3701 evcon->state = EVCON_READING_FIRSTLINE; |
|
3702 |
|
3703 evcon->fd = fd; |
|
3704 |
|
3705 bufferevent_setfd(evcon->bufev, fd); |
|
3706 |
|
3707 return (evcon); |
|
3708 } |
|
3709 |
|
3710 static int |
|
3711 evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon) |
|
3712 { |
|
3713 struct evhttp *http = evcon->http_server; |
|
3714 struct evhttp_request *req; |
|
3715 if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL) |
|
3716 return (-1); |
|
3717 |
|
3718 if ((req->remote_host = mm_strdup(evcon->address)) == NULL) { |
|
3719 event_warn("%s: strdup", __func__); |
|
3720 evhttp_request_free(req); |
|
3721 return (-1); |
|
3722 } |
|
3723 req->remote_port = evcon->port; |
|
3724 |
|
3725 req->evcon = evcon; /* the request ends up owning the connection */ |
|
3726 req->flags |= EVHTTP_REQ_OWN_CONNECTION; |
|
3727 |
|
3728 /* We did not present the request to the user user yet, so treat it as |
|
3729 * if the user was done with the request. This allows us to free the |
|
3730 * request on a persistent connection if the client drops it without |
|
3731 * sending a request. |
|
3732 */ |
|
3733 req->userdone = 1; |
|
3734 |
|
3735 TAILQ_INSERT_TAIL(&evcon->requests, req, next); |
|
3736 |
|
3737 req->kind = EVHTTP_REQUEST; |
|
3738 |
|
3739 |
|
3740 evhttp_start_read(evcon); |
|
3741 |
|
3742 return (0); |
|
3743 } |
|
3744 |
|
3745 static void |
|
3746 evhttp_get_request(struct evhttp *http, evutil_socket_t fd, |
|
3747 struct sockaddr *sa, ev_socklen_t salen) |
|
3748 { |
|
3749 struct evhttp_connection *evcon; |
|
3750 |
|
3751 evcon = evhttp_get_request_connection(http, fd, sa, salen); |
|
3752 if (evcon == NULL) { |
|
3753 event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT, |
|
3754 __func__, EV_SOCK_ARG(fd)); |
|
3755 evutil_closesocket(fd); |
|
3756 return; |
|
3757 } |
|
3758 |
|
3759 /* the timeout can be used by the server to close idle connections */ |
|
3760 if (http->timeout != -1) |
|
3761 evhttp_connection_set_timeout(evcon, http->timeout); |
|
3762 |
|
3763 /* |
|
3764 * if we want to accept more than one request on a connection, |
|
3765 * we need to know which http server it belongs to. |
|
3766 */ |
|
3767 evcon->http_server = http; |
|
3768 TAILQ_INSERT_TAIL(&http->connections, evcon, next); |
|
3769 |
|
3770 if (evhttp_associate_new_request_with_connection(evcon) == -1) |
|
3771 evhttp_connection_free(evcon); |
|
3772 } |
|
3773 |
|
3774 |
|
3775 /* |
|
3776 * Network helper functions that we do not want to export to the rest of |
|
3777 * the world. |
|
3778 */ |
|
3779 |
|
3780 static void |
|
3781 name_from_addr(struct sockaddr *sa, ev_socklen_t salen, |
|
3782 char **phost, char **pport) |
|
3783 { |
|
3784 char ntop[NI_MAXHOST]; |
|
3785 char strport[NI_MAXSERV]; |
|
3786 int ni_result; |
|
3787 |
|
3788 #ifdef _EVENT_HAVE_GETNAMEINFO |
|
3789 ni_result = getnameinfo(sa, salen, |
|
3790 ntop, sizeof(ntop), strport, sizeof(strport), |
|
3791 NI_NUMERICHOST|NI_NUMERICSERV); |
|
3792 |
|
3793 if (ni_result != 0) { |
|
3794 #ifdef EAI_SYSTEM |
|
3795 /* Windows doesn't have an EAI_SYSTEM. */ |
|
3796 if (ni_result == EAI_SYSTEM) |
|
3797 event_err(1, "getnameinfo failed"); |
|
3798 else |
|
3799 #endif |
|
3800 event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result)); |
|
3801 return; |
|
3802 } |
|
3803 #else |
|
3804 ni_result = fake_getnameinfo(sa, salen, |
|
3805 ntop, sizeof(ntop), strport, sizeof(strport), |
|
3806 NI_NUMERICHOST|NI_NUMERICSERV); |
|
3807 if (ni_result != 0) |
|
3808 return; |
|
3809 #endif |
|
3810 |
|
3811 *phost = mm_strdup(ntop); |
|
3812 *pport = mm_strdup(strport); |
|
3813 } |
|
3814 |
|
3815 /* Create a non-blocking socket and bind it */ |
|
3816 /* todo: rename this function */ |
|
3817 static evutil_socket_t |
|
3818 bind_socket_ai(struct evutil_addrinfo *ai, int reuse) |
|
3819 { |
|
3820 evutil_socket_t fd; |
|
3821 |
|
3822 int on = 1, r; |
|
3823 int serrno; |
|
3824 |
|
3825 /* Create listen socket */ |
|
3826 fd = socket(ai ? ai->ai_family : AF_INET, SOCK_STREAM, 0); |
|
3827 if (fd == -1) { |
|
3828 event_sock_warn(-1, "socket"); |
|
3829 return (-1); |
|
3830 } |
|
3831 |
|
3832 if (evutil_make_socket_nonblocking(fd) < 0) |
|
3833 goto out; |
|
3834 if (evutil_make_socket_closeonexec(fd) < 0) |
|
3835 goto out; |
|
3836 |
|
3837 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0) |
|
3838 goto out; |
|
3839 if (reuse) { |
|
3840 if (evutil_make_listen_socket_reuseable(fd) < 0) |
|
3841 goto out; |
|
3842 } |
|
3843 |
|
3844 if (ai != NULL) { |
|
3845 r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen); |
|
3846 if (r == -1) |
|
3847 goto out; |
|
3848 } |
|
3849 |
|
3850 return (fd); |
|
3851 |
|
3852 out: |
|
3853 serrno = EVUTIL_SOCKET_ERROR(); |
|
3854 evutil_closesocket(fd); |
|
3855 EVUTIL_SET_SOCKET_ERROR(serrno); |
|
3856 return (-1); |
|
3857 } |
|
3858 |
|
3859 static struct evutil_addrinfo * |
|
3860 make_addrinfo(const char *address, ev_uint16_t port) |
|
3861 { |
|
3862 struct evutil_addrinfo *ai = NULL; |
|
3863 |
|
3864 struct evutil_addrinfo hints; |
|
3865 char strport[NI_MAXSERV]; |
|
3866 int ai_result; |
|
3867 |
|
3868 memset(&hints, 0, sizeof(hints)); |
|
3869 hints.ai_family = AF_UNSPEC; |
|
3870 hints.ai_socktype = SOCK_STREAM; |
|
3871 /* turn NULL hostname into INADDR_ANY, and skip looking up any address |
|
3872 * types we don't have an interface to connect to. */ |
|
3873 hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG; |
|
3874 evutil_snprintf(strport, sizeof(strport), "%d", port); |
|
3875 if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai)) |
|
3876 != 0) { |
|
3877 if (ai_result == EVUTIL_EAI_SYSTEM) |
|
3878 event_warn("getaddrinfo"); |
|
3879 else |
|
3880 event_warnx("getaddrinfo: %s", |
|
3881 evutil_gai_strerror(ai_result)); |
|
3882 return (NULL); |
|
3883 } |
|
3884 |
|
3885 return (ai); |
|
3886 } |
|
3887 |
|
3888 static evutil_socket_t |
|
3889 bind_socket(const char *address, ev_uint16_t port, int reuse) |
|
3890 { |
|
3891 evutil_socket_t fd; |
|
3892 struct evutil_addrinfo *aitop = NULL; |
|
3893 |
|
3894 /* just create an unbound socket */ |
|
3895 if (address == NULL && port == 0) |
|
3896 return bind_socket_ai(NULL, 0); |
|
3897 |
|
3898 aitop = make_addrinfo(address, port); |
|
3899 |
|
3900 if (aitop == NULL) |
|
3901 return (-1); |
|
3902 |
|
3903 fd = bind_socket_ai(aitop, reuse); |
|
3904 |
|
3905 evutil_freeaddrinfo(aitop); |
|
3906 |
|
3907 return (fd); |
|
3908 } |
|
3909 |
|
3910 struct evhttp_uri { |
|
3911 unsigned flags; |
|
3912 char *scheme; /* scheme; e.g http, ftp etc */ |
|
3913 char *userinfo; /* userinfo (typically username:pass), or NULL */ |
|
3914 char *host; /* hostname, IP address, or NULL */ |
|
3915 int port; /* port, or zero */ |
|
3916 char *path; /* path, or "". */ |
|
3917 char *query; /* query, or NULL */ |
|
3918 char *fragment; /* fragment or NULL */ |
|
3919 }; |
|
3920 |
|
3921 struct evhttp_uri * |
|
3922 evhttp_uri_new(void) |
|
3923 { |
|
3924 struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1); |
|
3925 if (uri) |
|
3926 uri->port = -1; |
|
3927 return uri; |
|
3928 } |
|
3929 |
|
3930 void |
|
3931 evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags) |
|
3932 { |
|
3933 uri->flags = flags; |
|
3934 } |
|
3935 |
|
3936 /* Return true if the string starting at s and ending immediately before eos |
|
3937 * is a valid URI scheme according to RFC3986 |
|
3938 */ |
|
3939 static int |
|
3940 scheme_ok(const char *s, const char *eos) |
|
3941 { |
|
3942 /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ |
|
3943 EVUTIL_ASSERT(eos >= s); |
|
3944 if (s == eos) |
|
3945 return 0; |
|
3946 if (!EVUTIL_ISALPHA(*s)) |
|
3947 return 0; |
|
3948 while (++s < eos) { |
|
3949 if (! EVUTIL_ISALNUM(*s) && |
|
3950 *s != '+' && *s != '-' && *s != '.') |
|
3951 return 0; |
|
3952 } |
|
3953 return 1; |
|
3954 } |
|
3955 |
|
3956 #define SUBDELIMS "!$&'()*+,;=" |
|
3957 |
|
3958 /* Return true iff [s..eos) is a valid userinfo */ |
|
3959 static int |
|
3960 userinfo_ok(const char *s, const char *eos) |
|
3961 { |
|
3962 while (s < eos) { |
|
3963 if (CHAR_IS_UNRESERVED(*s) || |
|
3964 strchr(SUBDELIMS, *s) || |
|
3965 *s == ':') |
|
3966 ++s; |
|
3967 else if (*s == '%' && s+2 < eos && |
|
3968 EVUTIL_ISXDIGIT(s[1]) && |
|
3969 EVUTIL_ISXDIGIT(s[2])) |
|
3970 s += 3; |
|
3971 else |
|
3972 return 0; |
|
3973 } |
|
3974 return 1; |
|
3975 } |
|
3976 |
|
3977 static int |
|
3978 regname_ok(const char *s, const char *eos) |
|
3979 { |
|
3980 while (s && s<eos) { |
|
3981 if (CHAR_IS_UNRESERVED(*s) || |
|
3982 strchr(SUBDELIMS, *s)) |
|
3983 ++s; |
|
3984 else if (*s == '%' && |
|
3985 EVUTIL_ISXDIGIT(s[1]) && |
|
3986 EVUTIL_ISXDIGIT(s[2])) |
|
3987 s += 3; |
|
3988 else |
|
3989 return 0; |
|
3990 } |
|
3991 return 1; |
|
3992 } |
|
3993 |
|
3994 static int |
|
3995 parse_port(const char *s, const char *eos) |
|
3996 { |
|
3997 int portnum = 0; |
|
3998 while (s < eos) { |
|
3999 if (! EVUTIL_ISDIGIT(*s)) |
|
4000 return -1; |
|
4001 portnum = (portnum * 10) + (*s - '0'); |
|
4002 if (portnum < 0) |
|
4003 return -1; |
|
4004 ++s; |
|
4005 } |
|
4006 return portnum; |
|
4007 } |
|
4008 |
|
4009 /* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */ |
|
4010 static int |
|
4011 bracket_addr_ok(const char *s, const char *eos) |
|
4012 { |
|
4013 if (s + 3 > eos || *s != '[' || *(eos-1) != ']') |
|
4014 return 0; |
|
4015 if (s[1] == 'v') { |
|
4016 /* IPvFuture, or junk. |
|
4017 "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) |
|
4018 */ |
|
4019 s += 2; /* skip [v */ |
|
4020 --eos; |
|
4021 if (!EVUTIL_ISXDIGIT(*s)) /*require at least one*/ |
|
4022 return 0; |
|
4023 while (s < eos && *s != '.') { |
|
4024 if (EVUTIL_ISXDIGIT(*s)) |
|
4025 ++s; |
|
4026 else |
|
4027 return 0; |
|
4028 } |
|
4029 if (*s != '.') |
|
4030 return 0; |
|
4031 ++s; |
|
4032 while (s < eos) { |
|
4033 if (CHAR_IS_UNRESERVED(*s) || |
|
4034 strchr(SUBDELIMS, *s) || |
|
4035 *s == ':') |
|
4036 ++s; |
|
4037 else |
|
4038 return 0; |
|
4039 } |
|
4040 return 2; |
|
4041 } else { |
|
4042 /* IPv6, or junk */ |
|
4043 char buf[64]; |
|
4044 ev_ssize_t n_chars = eos-s-2; |
|
4045 struct in6_addr in6; |
|
4046 if (n_chars >= 64) /* way too long */ |
|
4047 return 0; |
|
4048 memcpy(buf, s+1, n_chars); |
|
4049 buf[n_chars]='\0'; |
|
4050 return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0; |
|
4051 } |
|
4052 } |
|
4053 |
|
4054 static int |
|
4055 parse_authority(struct evhttp_uri *uri, char *s, char *eos) |
|
4056 { |
|
4057 char *cp, *port; |
|
4058 EVUTIL_ASSERT(eos); |
|
4059 if (eos == s) { |
|
4060 uri->host = mm_strdup(""); |
|
4061 if (uri->host == NULL) { |
|
4062 event_warn("%s: strdup", __func__); |
|
4063 return -1; |
|
4064 } |
|
4065 return 0; |
|
4066 } |
|
4067 |
|
4068 /* Optionally, we start with "userinfo@" */ |
|
4069 |
|
4070 cp = strchr(s, '@'); |
|
4071 if (cp && cp < eos) { |
|
4072 if (! userinfo_ok(s,cp)) |
|
4073 return -1; |
|
4074 *cp++ = '\0'; |
|
4075 uri->userinfo = mm_strdup(s); |
|
4076 if (uri->userinfo == NULL) { |
|
4077 event_warn("%s: strdup", __func__); |
|
4078 return -1; |
|
4079 } |
|
4080 } else { |
|
4081 cp = s; |
|
4082 } |
|
4083 /* Optionally, we end with ":port" */ |
|
4084 for (port=eos-1; port >= cp && EVUTIL_ISDIGIT(*port); --port) |
|
4085 ; |
|
4086 if (port >= cp && *port == ':') { |
|
4087 if (port+1 == eos) /* Leave port unspecified; the RFC allows a |
|
4088 * nil port */ |
|
4089 uri->port = -1; |
|
4090 else if ((uri->port = parse_port(port+1, eos))<0) |
|
4091 return -1; |
|
4092 eos = port; |
|
4093 } |
|
4094 /* Now, cp..eos holds the "host" port, which can be an IPv4Address, |
|
4095 * an IP-Literal, or a reg-name */ |
|
4096 EVUTIL_ASSERT(eos >= cp); |
|
4097 if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') { |
|
4098 /* IPv6address, IP-Literal, or junk. */ |
|
4099 if (! bracket_addr_ok(cp, eos)) |
|
4100 return -1; |
|
4101 } else { |
|
4102 /* Make sure the host part is ok. */ |
|
4103 if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */ |
|
4104 return -1; |
|
4105 } |
|
4106 uri->host = mm_malloc(eos-cp+1); |
|
4107 if (uri->host == NULL) { |
|
4108 event_warn("%s: malloc", __func__); |
|
4109 return -1; |
|
4110 } |
|
4111 memcpy(uri->host, cp, eos-cp); |
|
4112 uri->host[eos-cp] = '\0'; |
|
4113 return 0; |
|
4114 |
|
4115 } |
|
4116 |
|
4117 static char * |
|
4118 end_of_authority(char *cp) |
|
4119 { |
|
4120 while (*cp) { |
|
4121 if (*cp == '?' || *cp == '#' || *cp == '/') |
|
4122 return cp; |
|
4123 ++cp; |
|
4124 } |
|
4125 return cp; |
|
4126 } |
|
4127 |
|
4128 enum uri_part { |
|
4129 PART_PATH, |
|
4130 PART_QUERY, |
|
4131 PART_FRAGMENT |
|
4132 }; |
|
4133 |
|
4134 /* Return the character after the longest prefix of 'cp' that matches... |
|
4135 * *pchar / "/" if allow_qchars is false, or |
|
4136 * *(pchar / "/" / "?") if allow_qchars is true. |
|
4137 */ |
|
4138 static char * |
|
4139 end_of_path(char *cp, enum uri_part part, unsigned flags) |
|
4140 { |
|
4141 if (flags & EVHTTP_URI_NONCONFORMANT) { |
|
4142 /* If NONCONFORMANT: |
|
4143 * Path is everything up to a # or ? or nul. |
|
4144 * Query is everything up a # or nul |
|
4145 * Fragment is everything up to a nul. |
|
4146 */ |
|
4147 switch (part) { |
|
4148 case PART_PATH: |
|
4149 while (*cp && *cp != '#' && *cp != '?') |
|
4150 ++cp; |
|
4151 break; |
|
4152 case PART_QUERY: |
|
4153 while (*cp && *cp != '#') |
|
4154 ++cp; |
|
4155 break; |
|
4156 case PART_FRAGMENT: |
|
4157 cp += strlen(cp); |
|
4158 break; |
|
4159 }; |
|
4160 return cp; |
|
4161 } |
|
4162 |
|
4163 while (*cp) { |
|
4164 if (CHAR_IS_UNRESERVED(*cp) || |
|
4165 strchr(SUBDELIMS, *cp) || |
|
4166 *cp == ':' || *cp == '@' || *cp == '/') |
|
4167 ++cp; |
|
4168 else if (*cp == '%' && EVUTIL_ISXDIGIT(cp[1]) && |
|
4169 EVUTIL_ISXDIGIT(cp[2])) |
|
4170 cp += 3; |
|
4171 else if (*cp == '?' && part != PART_PATH) |
|
4172 ++cp; |
|
4173 else |
|
4174 return cp; |
|
4175 } |
|
4176 return cp; |
|
4177 } |
|
4178 |
|
4179 static int |
|
4180 path_matches_noscheme(const char *cp) |
|
4181 { |
|
4182 while (*cp) { |
|
4183 if (*cp == ':') |
|
4184 return 0; |
|
4185 else if (*cp == '/') |
|
4186 return 1; |
|
4187 ++cp; |
|
4188 } |
|
4189 return 1; |
|
4190 } |
|
4191 |
|
4192 struct evhttp_uri * |
|
4193 evhttp_uri_parse(const char *source_uri) |
|
4194 { |
|
4195 return evhttp_uri_parse_with_flags(source_uri, 0); |
|
4196 } |
|
4197 |
|
4198 struct evhttp_uri * |
|
4199 evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags) |
|
4200 { |
|
4201 char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL; |
|
4202 char *path = NULL, *fragment = NULL; |
|
4203 int got_authority = 0; |
|
4204 |
|
4205 struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri)); |
|
4206 if (uri == NULL) { |
|
4207 event_warn("%s: calloc", __func__); |
|
4208 goto err; |
|
4209 } |
|
4210 uri->port = -1; |
|
4211 uri->flags = flags; |
|
4212 |
|
4213 readbuf = mm_strdup(source_uri); |
|
4214 if (readbuf == NULL) { |
|
4215 event_warn("%s: strdup", __func__); |
|
4216 goto err; |
|
4217 } |
|
4218 |
|
4219 readp = readbuf; |
|
4220 token = NULL; |
|
4221 |
|
4222 /* We try to follow RFC3986 here as much as we can, and match |
|
4223 the productions |
|
4224 |
|
4225 URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] |
|
4226 |
|
4227 relative-ref = relative-part [ "?" query ] [ "#" fragment ] |
|
4228 */ |
|
4229 |
|
4230 /* 1. scheme: */ |
|
4231 token = strchr(readp, ':'); |
|
4232 if (token && scheme_ok(readp,token)) { |
|
4233 *token = '\0'; |
|
4234 uri->scheme = mm_strdup(readp); |
|
4235 if (uri->scheme == NULL) { |
|
4236 event_warn("%s: strdup", __func__); |
|
4237 goto err; |
|
4238 } |
|
4239 readp = token+1; /* eat : */ |
|
4240 } |
|
4241 |
|
4242 /* 2. Optionally, "//" then an 'authority' part. */ |
|
4243 if (readp[0]=='/' && readp[1] == '/') { |
|
4244 char *authority; |
|
4245 readp += 2; |
|
4246 authority = readp; |
|
4247 path = end_of_authority(readp); |
|
4248 if (parse_authority(uri, authority, path) < 0) |
|
4249 goto err; |
|
4250 readp = path; |
|
4251 got_authority = 1; |
|
4252 } |
|
4253 |
|
4254 /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty |
|
4255 */ |
|
4256 path = readp; |
|
4257 readp = end_of_path(path, PART_PATH, flags); |
|
4258 |
|
4259 /* Query */ |
|
4260 if (*readp == '?') { |
|
4261 *readp = '\0'; |
|
4262 ++readp; |
|
4263 query = readp; |
|
4264 readp = end_of_path(readp, PART_QUERY, flags); |
|
4265 } |
|
4266 /* fragment */ |
|
4267 if (*readp == '#') { |
|
4268 *readp = '\0'; |
|
4269 ++readp; |
|
4270 fragment = readp; |
|
4271 readp = end_of_path(readp, PART_FRAGMENT, flags); |
|
4272 } |
|
4273 if (*readp != '\0') { |
|
4274 goto err; |
|
4275 } |
|
4276 |
|
4277 /* These next two cases may be unreachable; I'm leaving them |
|
4278 * in to be defensive. */ |
|
4279 /* If you didn't get an authority, the path can't begin with "//" */ |
|
4280 if (!got_authority && path[0]=='/' && path[1]=='/') |
|
4281 goto err; |
|
4282 /* If you did get an authority, the path must begin with "/" or be |
|
4283 * empty. */ |
|
4284 if (got_authority && path[0] != '/' && path[0] != '\0') |
|
4285 goto err; |
|
4286 /* (End of maybe-unreachable cases) */ |
|
4287 |
|
4288 /* If there was no scheme, the first part of the path (if any) must |
|
4289 * have no colon in it. */ |
|
4290 if (! uri->scheme && !path_matches_noscheme(path)) |
|
4291 goto err; |
|
4292 |
|
4293 EVUTIL_ASSERT(path); |
|
4294 uri->path = mm_strdup(path); |
|
4295 if (uri->path == NULL) { |
|
4296 event_warn("%s: strdup", __func__); |
|
4297 goto err; |
|
4298 } |
|
4299 |
|
4300 if (query) { |
|
4301 uri->query = mm_strdup(query); |
|
4302 if (uri->query == NULL) { |
|
4303 event_warn("%s: strdup", __func__); |
|
4304 goto err; |
|
4305 } |
|
4306 } |
|
4307 if (fragment) { |
|
4308 uri->fragment = mm_strdup(fragment); |
|
4309 if (uri->fragment == NULL) { |
|
4310 event_warn("%s: strdup", __func__); |
|
4311 goto err; |
|
4312 } |
|
4313 } |
|
4314 |
|
4315 mm_free(readbuf); |
|
4316 |
|
4317 return uri; |
|
4318 err: |
|
4319 if (uri) |
|
4320 evhttp_uri_free(uri); |
|
4321 if (readbuf) |
|
4322 mm_free(readbuf); |
|
4323 return NULL; |
|
4324 } |
|
4325 |
|
4326 void |
|
4327 evhttp_uri_free(struct evhttp_uri *uri) |
|
4328 { |
|
4329 #define _URI_FREE_STR(f) \ |
|
4330 if (uri->f) { \ |
|
4331 mm_free(uri->f); \ |
|
4332 } |
|
4333 |
|
4334 _URI_FREE_STR(scheme); |
|
4335 _URI_FREE_STR(userinfo); |
|
4336 _URI_FREE_STR(host); |
|
4337 _URI_FREE_STR(path); |
|
4338 _URI_FREE_STR(query); |
|
4339 _URI_FREE_STR(fragment); |
|
4340 |
|
4341 mm_free(uri); |
|
4342 #undef _URI_FREE_STR |
|
4343 } |
|
4344 |
|
4345 char * |
|
4346 evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit) |
|
4347 { |
|
4348 struct evbuffer *tmp = 0; |
|
4349 size_t joined_size = 0; |
|
4350 char *output = NULL; |
|
4351 |
|
4352 #define _URI_ADD(f) evbuffer_add(tmp, uri->f, strlen(uri->f)) |
|
4353 |
|
4354 if (!uri || !buf || !limit) |
|
4355 return NULL; |
|
4356 |
|
4357 tmp = evbuffer_new(); |
|
4358 if (!tmp) |
|
4359 return NULL; |
|
4360 |
|
4361 if (uri->scheme) { |
|
4362 _URI_ADD(scheme); |
|
4363 evbuffer_add(tmp, ":", 1); |
|
4364 } |
|
4365 if (uri->host) { |
|
4366 evbuffer_add(tmp, "//", 2); |
|
4367 if (uri->userinfo) |
|
4368 evbuffer_add_printf(tmp,"%s@", uri->userinfo); |
|
4369 _URI_ADD(host); |
|
4370 if (uri->port >= 0) |
|
4371 evbuffer_add_printf(tmp,":%d", uri->port); |
|
4372 |
|
4373 if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0') |
|
4374 goto err; |
|
4375 } |
|
4376 |
|
4377 if (uri->path) |
|
4378 _URI_ADD(path); |
|
4379 |
|
4380 if (uri->query) { |
|
4381 evbuffer_add(tmp, "?", 1); |
|
4382 _URI_ADD(query); |
|
4383 } |
|
4384 |
|
4385 if (uri->fragment) { |
|
4386 evbuffer_add(tmp, "#", 1); |
|
4387 _URI_ADD(fragment); |
|
4388 } |
|
4389 |
|
4390 evbuffer_add(tmp, "\0", 1); /* NUL */ |
|
4391 |
|
4392 joined_size = evbuffer_get_length(tmp); |
|
4393 |
|
4394 if (joined_size > limit) { |
|
4395 /* It doesn't fit. */ |
|
4396 evbuffer_free(tmp); |
|
4397 return NULL; |
|
4398 } |
|
4399 evbuffer_remove(tmp, buf, joined_size); |
|
4400 |
|
4401 output = buf; |
|
4402 err: |
|
4403 evbuffer_free(tmp); |
|
4404 |
|
4405 return output; |
|
4406 #undef _URI_ADD |
|
4407 } |
|
4408 |
|
4409 const char * |
|
4410 evhttp_uri_get_scheme(const struct evhttp_uri *uri) |
|
4411 { |
|
4412 return uri->scheme; |
|
4413 } |
|
4414 const char * |
|
4415 evhttp_uri_get_userinfo(const struct evhttp_uri *uri) |
|
4416 { |
|
4417 return uri->userinfo; |
|
4418 } |
|
4419 const char * |
|
4420 evhttp_uri_get_host(const struct evhttp_uri *uri) |
|
4421 { |
|
4422 return uri->host; |
|
4423 } |
|
4424 int |
|
4425 evhttp_uri_get_port(const struct evhttp_uri *uri) |
|
4426 { |
|
4427 return uri->port; |
|
4428 } |
|
4429 const char * |
|
4430 evhttp_uri_get_path(const struct evhttp_uri *uri) |
|
4431 { |
|
4432 return uri->path; |
|
4433 } |
|
4434 const char * |
|
4435 evhttp_uri_get_query(const struct evhttp_uri *uri) |
|
4436 { |
|
4437 return uri->query; |
|
4438 } |
|
4439 const char * |
|
4440 evhttp_uri_get_fragment(const struct evhttp_uri *uri) |
|
4441 { |
|
4442 return uri->fragment; |
|
4443 } |
|
4444 |
|
4445 #define _URI_SET_STR(f) do { \ |
|
4446 if (uri->f) \ |
|
4447 mm_free(uri->f); \ |
|
4448 if (f) { \ |
|
4449 if ((uri->f = mm_strdup(f)) == NULL) { \ |
|
4450 event_warn("%s: strdup()", __func__); \ |
|
4451 return -1; \ |
|
4452 } \ |
|
4453 } else { \ |
|
4454 uri->f = NULL; \ |
|
4455 } \ |
|
4456 } while(0) |
|
4457 |
|
4458 int |
|
4459 evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme) |
|
4460 { |
|
4461 if (scheme && !scheme_ok(scheme, scheme+strlen(scheme))) |
|
4462 return -1; |
|
4463 |
|
4464 _URI_SET_STR(scheme); |
|
4465 return 0; |
|
4466 } |
|
4467 int |
|
4468 evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo) |
|
4469 { |
|
4470 if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo))) |
|
4471 return -1; |
|
4472 _URI_SET_STR(userinfo); |
|
4473 return 0; |
|
4474 } |
|
4475 int |
|
4476 evhttp_uri_set_host(struct evhttp_uri *uri, const char *host) |
|
4477 { |
|
4478 if (host) { |
|
4479 if (host[0] == '[') { |
|
4480 if (! bracket_addr_ok(host, host+strlen(host))) |
|
4481 return -1; |
|
4482 } else { |
|
4483 if (! regname_ok(host, host+strlen(host))) |
|
4484 return -1; |
|
4485 } |
|
4486 } |
|
4487 |
|
4488 _URI_SET_STR(host); |
|
4489 return 0; |
|
4490 } |
|
4491 int |
|
4492 evhttp_uri_set_port(struct evhttp_uri *uri, int port) |
|
4493 { |
|
4494 if (port < -1) |
|
4495 return -1; |
|
4496 uri->port = port; |
|
4497 return 0; |
|
4498 } |
|
4499 #define end_of_cpath(cp,p,f) \ |
|
4500 ((const char*)(end_of_path(((char*)(cp)), (p), (f)))) |
|
4501 |
|
4502 int |
|
4503 evhttp_uri_set_path(struct evhttp_uri *uri, const char *path) |
|
4504 { |
|
4505 if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path)) |
|
4506 return -1; |
|
4507 |
|
4508 _URI_SET_STR(path); |
|
4509 return 0; |
|
4510 } |
|
4511 int |
|
4512 evhttp_uri_set_query(struct evhttp_uri *uri, const char *query) |
|
4513 { |
|
4514 if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query)) |
|
4515 return -1; |
|
4516 _URI_SET_STR(query); |
|
4517 return 0; |
|
4518 } |
|
4519 int |
|
4520 evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment) |
|
4521 { |
|
4522 if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment)) |
|
4523 return -1; |
|
4524 _URI_SET_STR(fragment); |
|
4525 return 0; |
|
4526 } |