blob: 5331602a7a7d0601cacb991ed9d9fb4a686b9cfa [file] [log] [blame]
Christopher Wileye8679812015-07-01 13:36:18 -07001/*
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"
Narayan Kamathfc74cb42017-09-13 12:53:52 +010029#include "evconfig-private.h"
Christopher Wileye8679812015-07-01 13:36:18 -070030
Narayan Kamathfc74cb42017-09-13 12:53:52 +010031#ifdef EVENT__HAVE_SYS_PARAM_H
Christopher Wileye8679812015-07-01 13:36:18 -070032#include <sys/param.h>
33#endif
Narayan Kamathfc74cb42017-09-13 12:53:52 +010034#ifdef EVENT__HAVE_SYS_TYPES_H
Christopher Wileye8679812015-07-01 13:36:18 -070035#include <sys/types.h>
36#endif
37
Christopher Wileye8679812015-07-01 13:36:18 -070038#ifdef HAVE_SYS_IOCCOM_H
39#include <sys/ioccom.h>
40#endif
Narayan Kamathfc74cb42017-09-13 12:53:52 +010041#ifdef EVENT__HAVE_SYS_RESOURCE_H
Josh Gao83a0c9c2017-08-10 12:30:25 -070042#include <sys/resource.h>
Narayan Kamathfc74cb42017-09-13 12:53:52 +010043#endif
44#ifdef EVENT__HAVE_SYS_TIME_H
45#include <sys/time.h>
46#endif
47#ifdef EVENT__HAVE_SYS_WAIT_H
48#include <sys/wait.h>
49#endif
50
51#ifndef _WIN32
Christopher Wileye8679812015-07-01 13:36:18 -070052#include <sys/socket.h>
53#include <sys/stat.h>
Haibo Huangb2279672019-05-31 16:12:39 -070054#else /* _WIN32 */
Christopher Wileye8679812015-07-01 13:36:18 -070055#include <winsock2.h>
56#include <ws2tcpip.h>
Haibo Huangb2279672019-05-31 16:12:39 -070057#endif /* _WIN32 */
58
59#ifdef EVENT__HAVE_SYS_UN_H
60#include <sys/un.h>
61#endif
62#ifdef EVENT__HAVE_AFUNIX_H
63#include <afunix.h>
Christopher Wileye8679812015-07-01 13:36:18 -070064#endif
65
66#include <sys/queue.h>
67
Narayan Kamathfc74cb42017-09-13 12:53:52 +010068#ifdef EVENT__HAVE_NETINET_IN_H
Christopher Wileye8679812015-07-01 13:36:18 -070069#include <netinet/in.h>
70#endif
Narayan Kamathfc74cb42017-09-13 12:53:52 +010071#ifdef EVENT__HAVE_ARPA_INET_H
Christopher Wileye8679812015-07-01 13:36:18 -070072#include <arpa/inet.h>
73#endif
Narayan Kamathfc74cb42017-09-13 12:53:52 +010074#ifdef EVENT__HAVE_NETDB_H
Christopher Wileye8679812015-07-01 13:36:18 -070075#include <netdb.h>
76#endif
77
Narayan Kamathfc74cb42017-09-13 12:53:52 +010078#ifdef _WIN32
Christopher Wileye8679812015-07-01 13:36:18 -070079#include <winsock2.h>
80#endif
81
82#include <errno.h>
83#include <stdio.h>
84#include <stdlib.h>
85#include <string.h>
Narayan Kamathfc74cb42017-09-13 12:53:52 +010086#ifndef _WIN32
Christopher Wileye8679812015-07-01 13:36:18 -070087#include <syslog.h>
Haibo Huangb2279672019-05-31 16:12:39 -070088#endif /* !_WIN32 */
Christopher Wileye8679812015-07-01 13:36:18 -070089#include <signal.h>
Narayan Kamathfc74cb42017-09-13 12:53:52 +010090#ifdef EVENT__HAVE_UNISTD_H
Christopher Wileye8679812015-07-01 13:36:18 -070091#include <unistd.h>
92#endif
Narayan Kamathfc74cb42017-09-13 12:53:52 +010093#ifdef EVENT__HAVE_FCNTL_H
Christopher Wileye8679812015-07-01 13:36:18 -070094#include <fcntl.h>
95#endif
96
97#undef timeout_pending
98#undef timeout_initialized
99
100#include "strlcpy-internal.h"
101#include "event2/http.h"
102#include "event2/event.h"
103#include "event2/buffer.h"
104#include "event2/bufferevent.h"
Christopher Wileye8679812015-07-01 13:36:18 -0700105#include "event2/http_struct.h"
106#include "event2/http_compat.h"
107#include "event2/util.h"
108#include "event2/listener.h"
109#include "log-internal.h"
110#include "util-internal.h"
111#include "http-internal.h"
112#include "mm-internal.h"
113#include "bufferevent-internal.h"
114
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100115#ifndef EVENT__HAVE_GETNAMEINFO
Christopher Wileye8679812015-07-01 13:36:18 -0700116#define NI_MAXSERV 32
117#define NI_MAXHOST 1025
118
119#ifndef NI_NUMERICHOST
120#define NI_NUMERICHOST 1
121#endif
122
123#ifndef NI_NUMERICSERV
124#define NI_NUMERICSERV 2
125#endif
126
127static int
128fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
129 size_t hostlen, char *serv, size_t servlen, int flags)
130{
131 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
132
133 if (serv != NULL) {
134 char tmpserv[16];
135 evutil_snprintf(tmpserv, sizeof(tmpserv),
136 "%d", ntohs(sin->sin_port));
137 if (strlcpy(serv, tmpserv, servlen) >= servlen)
138 return (-1);
139 }
140
141 if (host != NULL) {
142 if (flags & NI_NUMERICHOST) {
143 if (strlcpy(host, inet_ntoa(sin->sin_addr),
144 hostlen) >= hostlen)
145 return (-1);
146 else
147 return (0);
148 } else {
149 struct hostent *hp;
150 hp = gethostbyaddr((char *)&sin->sin_addr,
151 sizeof(struct in_addr), AF_INET);
152 if (hp == NULL)
153 return (-2);
154
155 if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
156 return (-1);
157 else
158 return (0);
159 }
160 }
161 return (0);
162}
163
164#endif
165
166#define REQ_VERSION_BEFORE(req, major_v, minor_v) \
167 ((req)->major < (major_v) || \
168 ((req)->major == (major_v) && (req)->minor < (minor_v)))
169
170#define REQ_VERSION_ATLEAST(req, major_v, minor_v) \
171 ((req)->major > (major_v) || \
172 ((req)->major == (major_v) && (req)->minor >= (minor_v)))
173
174#ifndef MIN
175#define MIN(a,b) (((a)<(b))?(a):(b))
176#endif
177
178extern int debug;
179
180static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse);
181static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
182static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
Haibo Huangb2279672019-05-31 16:12:39 -0700183static struct evhttp_uri *evhttp_uri_parse_authority(char *source_uri);
Christopher Wileye8679812015-07-01 13:36:18 -0700184static int evhttp_associate_new_request_with_connection(
185 struct evhttp_connection *evcon);
186static void evhttp_connection_start_detectclose(
187 struct evhttp_connection *evcon);
188static void evhttp_connection_stop_detectclose(
189 struct evhttp_connection *evcon);
190static void evhttp_request_dispatch(struct evhttp_connection* evcon);
191static void evhttp_read_firstline(struct evhttp_connection *evcon,
192 struct evhttp_request *req);
193static void evhttp_read_header(struct evhttp_connection *evcon,
194 struct evhttp_request *req);
195static int evhttp_add_header_internal(struct evkeyvalq *headers,
196 const char *key, const char *value);
197static const char *evhttp_response_phrase_internal(int code);
198static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t);
199static void evhttp_write_buffer(struct evhttp_connection *,
200 void (*)(struct evhttp_connection *, void *), void *);
201static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
202
203/* callbacks for bufferevent */
204static void evhttp_read_cb(struct bufferevent *, void *);
205static void evhttp_write_cb(struct bufferevent *, void *);
206static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg);
Christopher Wileye8679812015-07-01 13:36:18 -0700207static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
208 const char *hostname);
209
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100210#ifndef EVENT__HAVE_STRSEP
Christopher Wileye8679812015-07-01 13:36:18 -0700211/* strsep replacement for platforms that lack it. Only works if
212 * del is one character long. */
213static char *
214strsep(char **s, const char *del)
215{
216 char *d, *tok;
217 EVUTIL_ASSERT(strlen(del) == 1);
218 if (!s || !*s)
219 return NULL;
220 tok = *s;
221 d = strstr(tok, del);
222 if (d) {
223 *d = '\0';
224 *s = d + 1;
225 } else
226 *s = NULL;
227 return tok;
228}
229#endif
230
231static size_t
232html_replace(const char ch, const char **escaped)
233{
234 switch (ch) {
235 case '<':
236 *escaped = "&lt;";
237 return 4;
238 case '>':
239 *escaped = "&gt;";
240 return 4;
241 case '"':
242 *escaped = "&quot;";
243 return 6;
244 case '\'':
245 *escaped = "&#039;";
246 return 6;
247 case '&':
248 *escaped = "&amp;";
249 return 5;
250 default:
251 break;
252 }
253
254 return 1;
255}
256
257/*
258 * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
259 * &#039; and &amp; correspondingly.
260 *
261 * The returned string needs to be freed by the caller.
262 */
263
264char *
265evhttp_htmlescape(const char *html)
266{
267 size_t i;
268 size_t new_size = 0, old_size = 0;
269 char *escaped_html, *p;
270
271 if (html == NULL)
272 return (NULL);
273
274 old_size = strlen(html);
275 for (i = 0; i < old_size; ++i) {
276 const char *replaced = NULL;
277 const size_t replace_size = html_replace(html[i], &replaced);
278 if (replace_size > EV_SIZE_MAX - new_size) {
279 event_warn("%s: html_replace overflow", __func__);
280 return (NULL);
281 }
282 new_size += replace_size;
283 }
284
285 if (new_size == EV_SIZE_MAX)
286 return (NULL);
287 p = escaped_html = mm_malloc(new_size + 1);
288 if (escaped_html == NULL) {
289 event_warn("%s: malloc(%lu)", __func__,
290 (unsigned long)(new_size + 1));
291 return (NULL);
292 }
293 for (i = 0; i < old_size; ++i) {
294 const char *replaced = &html[i];
295 const size_t len = html_replace(html[i], &replaced);
296 memcpy(p, replaced, len);
297 p += len;
298 }
299
300 *p = '\0';
301
302 return (escaped_html);
303}
304
305/** Given an evhttp_cmd_type, returns a constant string containing the
306 * equivalent HTTP command, or NULL if the evhttp_command_type is
307 * unrecognized. */
308static const char *
309evhttp_method(enum evhttp_cmd_type type)
310{
311 const char *method;
312
313 switch (type) {
314 case EVHTTP_REQ_GET:
315 method = "GET";
316 break;
317 case EVHTTP_REQ_POST:
318 method = "POST";
319 break;
320 case EVHTTP_REQ_HEAD:
321 method = "HEAD";
322 break;
323 case EVHTTP_REQ_PUT:
324 method = "PUT";
325 break;
326 case EVHTTP_REQ_DELETE:
327 method = "DELETE";
328 break;
329 case EVHTTP_REQ_OPTIONS:
330 method = "OPTIONS";
331 break;
332 case EVHTTP_REQ_TRACE:
333 method = "TRACE";
334 break;
335 case EVHTTP_REQ_CONNECT:
336 method = "CONNECT";
337 break;
338 case EVHTTP_REQ_PATCH:
339 method = "PATCH";
340 break;
341 default:
342 method = NULL;
343 break;
344 }
345
346 return (method);
347}
348
349/**
350 * Determines if a response should have a body.
351 * Follows the rules in RFC 2616 section 4.3.
352 * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
353 * a body.
354 */
355static int
356evhttp_response_needs_body(struct evhttp_request *req)
357{
358 return (req->response_code != HTTP_NOCONTENT &&
359 req->response_code != HTTP_NOTMODIFIED &&
360 (req->response_code < 100 || req->response_code >= 200) &&
361 req->type != EVHTTP_REQ_HEAD);
362}
363
Christopher Wileye8679812015-07-01 13:36:18 -0700364/** Helper: called after we've added some data to an evcon's bufferevent's
365 * output buffer. Sets the evconn's writing-is-done callback, and puts
366 * the bufferevent into writing mode.
367 */
368static void
369evhttp_write_buffer(struct evhttp_connection *evcon,
370 void (*cb)(struct evhttp_connection *, void *), void *arg)
371{
372 event_debug(("%s: preparing to write buffer\n", __func__));
373
374 /* Set call back */
375 evcon->cb = cb;
376 evcon->cb_arg = arg;
377
378 /* Disable the read callback: we don't actually care about data;
Haibo Huangb2279672019-05-31 16:12:39 -0700379 * we only care about close detection. (We don't disable reading --
380 * EV_READ, since we *do* want to learn about any close events.) */
Christopher Wileye8679812015-07-01 13:36:18 -0700381 bufferevent_setcb(evcon->bufev,
382 NULL, /*read*/
383 evhttp_write_cb,
384 evhttp_error_cb,
385 evcon);
386
Haibo Huangb2279672019-05-31 16:12:39 -0700387 bufferevent_enable(evcon->bufev, EV_READ|EV_WRITE);
Christopher Wileye8679812015-07-01 13:36:18 -0700388}
389
390static void
391evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg)
392{
393 bufferevent_disable(evcon->bufev, EV_WRITE);
394}
395
396static void
397evhttp_send_continue(struct evhttp_connection *evcon,
398 struct evhttp_request *req)
399{
400 bufferevent_enable(evcon->bufev, EV_WRITE);
401 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
402 "HTTP/%d.%d 100 Continue\r\n\r\n",
403 req->major, req->minor);
404 evcon->cb = evhttp_send_continue_done;
405 evcon->cb_arg = NULL;
406 bufferevent_setcb(evcon->bufev,
407 evhttp_read_cb,
408 evhttp_write_cb,
409 evhttp_error_cb,
410 evcon);
411}
412
413/** Helper: returns true iff evconn is in any connected state. */
414static int
415evhttp_connected(struct evhttp_connection *evcon)
416{
417 switch (evcon->state) {
418 case EVCON_DISCONNECTED:
419 case EVCON_CONNECTING:
420 return (0);
421 case EVCON_IDLE:
422 case EVCON_READING_FIRSTLINE:
423 case EVCON_READING_HEADERS:
424 case EVCON_READING_BODY:
425 case EVCON_READING_TRAILER:
426 case EVCON_WRITING:
427 default:
428 return (1);
429 }
430}
431
432/* Create the headers needed for an outgoing HTTP request, adds them to
433 * the request's header list, and writes the request line to the
434 * connection's output buffer.
435 */
436static void
437evhttp_make_header_request(struct evhttp_connection *evcon,
438 struct evhttp_request *req)
439{
440 const char *method;
441
442 evhttp_remove_header(req->output_headers, "Proxy-Connection");
443
444 /* Generate request line */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100445 if (!(method = evhttp_method(req->type))) {
446 method = "NULL";
447 }
448
Christopher Wileye8679812015-07-01 13:36:18 -0700449 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
450 "%s %s HTTP/%d.%d\r\n",
451 method, req->uri, req->major, req->minor);
452
453 /* Add the content length on a post or put request if missing */
454 if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
455 evhttp_find_header(req->output_headers, "Content-Length") == NULL){
456 char size[22];
457 evutil_snprintf(size, sizeof(size), EV_SIZE_FMT,
458 EV_SIZE_ARG(evbuffer_get_length(req->output_buffer)));
459 evhttp_add_header(req->output_headers, "Content-Length", size);
460 }
461}
462
463/** Return true if the list of headers in 'headers', intepreted with respect
464 * to flags, means that we should send a "connection: close" when the request
465 * is done. */
466static int
467evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
468{
469 if (flags & EVHTTP_PROXY_REQUEST) {
470 /* proxy connection */
471 const char *connection = evhttp_find_header(headers, "Proxy-Connection");
472 return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0);
473 } else {
474 const char *connection = evhttp_find_header(headers, "Connection");
475 return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0);
476 }
477}
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100478static int
479evhttp_is_request_connection_close(struct evhttp_request *req)
480{
481 return
482 evhttp_is_connection_close(req->flags, req->input_headers) ||
483 evhttp_is_connection_close(req->flags, req->output_headers);
484}
Christopher Wileye8679812015-07-01 13:36:18 -0700485
486/* Return true iff 'headers' contains 'Connection: keep-alive' */
487static int
488evhttp_is_connection_keepalive(struct evkeyvalq* headers)
489{
490 const char *connection = evhttp_find_header(headers, "Connection");
491 return (connection != NULL
492 && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0);
493}
494
495/* Add a correct "Date" header to headers, unless it already has one. */
496static void
497evhttp_maybe_add_date_header(struct evkeyvalq *headers)
498{
499 if (evhttp_find_header(headers, "Date") == NULL) {
500 char date[50];
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100501 if (sizeof(date) - evutil_date_rfc1123(date, sizeof(date), NULL) > 0) {
Christopher Wileye8679812015-07-01 13:36:18 -0700502 evhttp_add_header(headers, "Date", date);
503 }
504 }
505}
506
507/* Add a "Content-Length" header with value 'content_length' to headers,
508 * unless it already has a content-length or transfer-encoding header. */
509static void
510evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
511 size_t content_length)
512{
513 if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
514 evhttp_find_header(headers, "Content-Length") == NULL) {
515 char len[22];
516 evutil_snprintf(len, sizeof(len), EV_SIZE_FMT,
517 EV_SIZE_ARG(content_length));
518 evhttp_add_header(headers, "Content-Length", len);
519 }
520}
521
522/*
523 * Create the headers needed for an HTTP reply in req->output_headers,
524 * and write the first HTTP response for req line to evcon.
525 */
526static void
527evhttp_make_header_response(struct evhttp_connection *evcon,
528 struct evhttp_request *req)
529{
530 int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
531 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
532 "HTTP/%d.%d %d %s\r\n",
533 req->major, req->minor, req->response_code,
534 req->response_code_line);
535
536 if (req->major == 1) {
537 if (req->minor >= 1)
538 evhttp_maybe_add_date_header(req->output_headers);
539
540 /*
541 * if the protocol is 1.0; and the connection was keep-alive
542 * we need to add a keep-alive header, too.
543 */
544 if (req->minor == 0 && is_keepalive)
545 evhttp_add_header(req->output_headers,
546 "Connection", "keep-alive");
547
548 if ((req->minor >= 1 || is_keepalive) &&
549 evhttp_response_needs_body(req)) {
550 /*
551 * we need to add the content length if the
552 * user did not give it, this is required for
553 * persistent connections to work.
554 */
555 evhttp_maybe_add_content_length_header(
556 req->output_headers,
557 evbuffer_get_length(req->output_buffer));
558 }
559 }
560
561 /* Potentially add headers for unidentified content. */
562 if (evhttp_response_needs_body(req)) {
563 if (evhttp_find_header(req->output_headers,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100564 "Content-Type") == NULL
565 && evcon->http_server->default_content_type) {
Christopher Wileye8679812015-07-01 13:36:18 -0700566 evhttp_add_header(req->output_headers,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100567 "Content-Type",
568 evcon->http_server->default_content_type);
Christopher Wileye8679812015-07-01 13:36:18 -0700569 }
570 }
571
572 /* if the request asked for a close, we send a close, too */
573 if (evhttp_is_connection_close(req->flags, req->input_headers)) {
574 evhttp_remove_header(req->output_headers, "Connection");
575 if (!(req->flags & EVHTTP_PROXY_REQUEST))
576 evhttp_add_header(req->output_headers, "Connection", "close");
577 evhttp_remove_header(req->output_headers, "Proxy-Connection");
578 }
579}
580
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100581enum expect { NO, CONTINUE, OTHER };
582static enum expect evhttp_have_expect(struct evhttp_request *req, int input)
583{
584 const char *expect;
585 struct evkeyvalq *h = input ? req->input_headers : req->output_headers;
586
587 if (!(req->kind == EVHTTP_REQUEST) || !REQ_VERSION_ATLEAST(req, 1, 1))
588 return NO;
589
590 expect = evhttp_find_header(h, "Expect");
591 if (!expect)
592 return NO;
593
594 return !evutil_ascii_strcasecmp(expect, "100-continue") ? CONTINUE : OTHER;
595}
596
597
Christopher Wileye8679812015-07-01 13:36:18 -0700598/** Generate all headers appropriate for sending the http request in req (or
599 * the response, if we're sending a response), and write them to evcon's
600 * bufferevent. Also writes all data from req->output_buffer */
601static void
602evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
603{
604 struct evkeyval *header;
605 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
606
607 /*
608 * Depending if this is a HTTP request or response, we might need to
609 * add some new headers or remove existing headers.
610 */
611 if (req->kind == EVHTTP_REQUEST) {
612 evhttp_make_header_request(evcon, req);
613 } else {
614 evhttp_make_header_response(evcon, req);
615 }
616
617 TAILQ_FOREACH(header, req->output_headers, next) {
618 evbuffer_add_printf(output, "%s: %s\r\n",
619 header->key, header->value);
620 }
621 evbuffer_add(output, "\r\n", 2);
622
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100623 if (evhttp_have_expect(req, 0) != CONTINUE &&
624 evbuffer_get_length(req->output_buffer)) {
Christopher Wileye8679812015-07-01 13:36:18 -0700625 /*
626 * For a request, we add the POST data, for a reply, this
627 * is the regular data.
628 */
Christopher Wileye8679812015-07-01 13:36:18 -0700629 evbuffer_add_buffer(output, req->output_buffer);
630 }
631}
632
633void
634evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon,
635 ev_ssize_t new_max_headers_size)
636{
637 if (new_max_headers_size<0)
638 evcon->max_headers_size = EV_SIZE_MAX;
639 else
640 evcon->max_headers_size = new_max_headers_size;
641}
642void
643evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
644 ev_ssize_t new_max_body_size)
645{
646 if (new_max_body_size<0)
647 evcon->max_body_size = EV_UINT64_MAX;
648 else
649 evcon->max_body_size = new_max_body_size;
650}
651
652static int
653evhttp_connection_incoming_fail(struct evhttp_request *req,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100654 enum evhttp_request_error error)
Christopher Wileye8679812015-07-01 13:36:18 -0700655{
656 switch (error) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100657 case EVREQ_HTTP_DATA_TOO_LONG:
658 req->response_code = HTTP_ENTITYTOOLARGE;
659 break;
660 default:
661 req->response_code = HTTP_BADREQUEST;
662 }
663
664 switch (error) {
665 case EVREQ_HTTP_TIMEOUT:
666 case EVREQ_HTTP_EOF:
Christopher Wileye8679812015-07-01 13:36:18 -0700667 /*
668 * these are cases in which we probably should just
669 * close the connection and not send a reply. this
670 * case may happen when a browser keeps a persistent
671 * connection open and we timeout on the read. when
672 * the request is still being used for sending, we
673 * need to disassociated it from the connection here.
674 */
675 if (!req->userdone) {
676 /* remove it so that it will not be freed */
677 TAILQ_REMOVE(&req->evcon->requests, req, next);
678 /* indicate that this request no longer has a
679 * connection object
680 */
681 req->evcon = NULL;
682 }
683 return (-1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100684 case EVREQ_HTTP_INVALID_HEADER:
685 case EVREQ_HTTP_BUFFER_ERROR:
686 case EVREQ_HTTP_REQUEST_CANCEL:
687 case EVREQ_HTTP_DATA_TOO_LONG:
Christopher Wileye8679812015-07-01 13:36:18 -0700688 default: /* xxx: probably should just error on default */
689 /* the callback looks at the uri to determine errors */
690 if (req->uri) {
691 mm_free(req->uri);
692 req->uri = NULL;
693 }
694 if (req->uri_elems) {
695 evhttp_uri_free(req->uri_elems);
696 req->uri_elems = NULL;
697 }
698
699 /*
700 * the callback needs to send a reply, once the reply has
701 * been send, the connection should get freed.
702 */
703 (*req->cb)(req, req->cb_arg);
704 }
705
706 return (0);
707}
708
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100709/* Free connection ownership of which can be acquired by user using
710 * evhttp_request_own(). */
711static inline void
712evhttp_request_free_auto(struct evhttp_request *req)
713{
714 if (!(req->flags & EVHTTP_USER_OWNED))
715 evhttp_request_free(req);
716}
717
718static void
719evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req)
720{
721 TAILQ_REMOVE(&evcon->requests, req, next);
722 evhttp_request_free_auto(req);
723}
724
Christopher Wileye8679812015-07-01 13:36:18 -0700725/* Called when evcon has experienced a (non-recoverable? -NM) error, as
726 * given in error. If it's an outgoing connection, reset the connection,
727 * retry any pending requests, and inform the user. If it's incoming,
728 * delegates to evhttp_connection_incoming_fail(). */
729void
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100730evhttp_connection_fail_(struct evhttp_connection *evcon,
731 enum evhttp_request_error error)
Christopher Wileye8679812015-07-01 13:36:18 -0700732{
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100733 const int errsave = EVUTIL_SOCKET_ERROR();
Christopher Wileye8679812015-07-01 13:36:18 -0700734 struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
735 void (*cb)(struct evhttp_request *, void *);
736 void *cb_arg;
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100737 void (*error_cb)(enum evhttp_request_error, void *);
738 void *error_cb_arg;
Christopher Wileye8679812015-07-01 13:36:18 -0700739 EVUTIL_ASSERT(req != NULL);
740
741 bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
742
743 if (evcon->flags & EVHTTP_CON_INCOMING) {
744 /*
745 * for incoming requests, there are two different
746 * failure cases. it's either a network level error
747 * or an http layer error. for problems on the network
748 * layer like timeouts we just drop the connections.
749 * For HTTP problems, we might have to send back a
750 * reply before the connection can be freed.
751 */
752 if (evhttp_connection_incoming_fail(req, error) == -1)
753 evhttp_connection_free(evcon);
754 return;
755 }
756
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100757 error_cb = req->error_cb;
758 error_cb_arg = req->cb_arg;
Christopher Wileye8679812015-07-01 13:36:18 -0700759 /* when the request was canceled, the callback is not executed */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100760 if (error != EVREQ_HTTP_REQUEST_CANCEL) {
Christopher Wileye8679812015-07-01 13:36:18 -0700761 /* save the callback for later; the cb might free our object */
762 cb = req->cb;
763 cb_arg = req->cb_arg;
764 } else {
765 cb = NULL;
766 cb_arg = NULL;
767 }
768
769 /* do not fail all requests; the next request is going to get
770 * send over a new connection. when a user cancels a request,
771 * all other pending requests should be processed as normal
772 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100773 evhttp_request_free_(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -0700774
775 /* reset the connection */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100776 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700777
778 /* We are trying the next request that was queued on us */
779 if (TAILQ_FIRST(&evcon->requests) != NULL)
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100780 evhttp_connection_connect_(evcon);
781
782 /* The call to evhttp_connection_reset_ overwrote errno.
783 * Let's restore the original errno, so that the user's
784 * callback can have a better idea of what the error was.
785 */
786 EVUTIL_SET_SOCKET_ERROR(errsave);
Christopher Wileye8679812015-07-01 13:36:18 -0700787
788 /* inform the user */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100789 if (error_cb != NULL)
790 error_cb(error, error_cb_arg);
Christopher Wileye8679812015-07-01 13:36:18 -0700791 if (cb != NULL)
792 (*cb)(NULL, cb_arg);
793}
794
795/* Bufferevent callback: invoked when any data has been written from an
796 * http connection's bufferevent */
797static void
798evhttp_write_cb(struct bufferevent *bufev, void *arg)
799{
800 struct evhttp_connection *evcon = arg;
801
802 /* Activate our call back */
803 if (evcon->cb != NULL)
804 (*evcon->cb)(evcon, evcon->cb_arg);
805}
806
807/**
808 * Advance the connection state.
809 * - If this is an outgoing connection, we've just processed the response;
810 * idle or close the connection.
811 * - If this is an incoming connection, we've just processed the request;
812 * respond.
813 */
814static void
815evhttp_connection_done(struct evhttp_connection *evcon)
816{
817 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
818 int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100819 int free_evcon = 0;
Christopher Wileye8679812015-07-01 13:36:18 -0700820
821 if (con_outgoing) {
822 /* idle or close the connection */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100823 int need_close = evhttp_is_request_connection_close(req);
Christopher Wileye8679812015-07-01 13:36:18 -0700824 TAILQ_REMOVE(&evcon->requests, req, next);
825 req->evcon = NULL;
826
827 evcon->state = EVCON_IDLE;
828
Christopher Wileye8679812015-07-01 13:36:18 -0700829 /* check if we got asked to close the connection */
830 if (need_close)
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100831 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700832
833 if (TAILQ_FIRST(&evcon->requests) != NULL) {
834 /*
835 * We have more requests; reset the connection
836 * and deal with the next request.
837 */
838 if (!evhttp_connected(evcon))
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100839 evhttp_connection_connect_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700840 else
841 evhttp_request_dispatch(evcon);
842 } else if (!need_close) {
843 /*
844 * The connection is going to be persistent, but we
845 * need to detect if the other side closes it.
846 */
847 evhttp_connection_start_detectclose(evcon);
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100848 } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) {
849 /*
850 * If we have no more requests that need completion
851 * and we're not waiting for the connection to close
852 */
853 free_evcon = 1;
Christopher Wileye8679812015-07-01 13:36:18 -0700854 }
855 } else {
856 /*
857 * incoming connection - we need to leave the request on the
858 * connection so that we can reply to it.
859 */
860 evcon->state = EVCON_WRITING;
861 }
862
863 /* notify the user of the request */
864 (*req->cb)(req, req->cb_arg);
865
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100866 /* if this was an outgoing request, we own and it's done. so free it. */
867 if (con_outgoing) {
868 evhttp_request_free_auto(req);
869 }
870
871 /* If this was the last request of an outgoing connection and we're
872 * not waiting to receive a connection close event and we want to
873 * automatically free the connection. We check to ensure our request
874 * list is empty one last time just in case our callback added a
875 * new request.
Christopher Wileye8679812015-07-01 13:36:18 -0700876 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100877 if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) {
878 evhttp_connection_free(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700879 }
880}
881
882/*
883 * Handles reading from a chunked request.
884 * return ALL_DATA_READ:
885 * all data has been read
886 * return MORE_DATA_EXPECTED:
887 * more data is expected
888 * return DATA_CORRUPTED:
889 * data is corrupted
890 * return REQUEST_CANCELED:
891 * request was canceled by the user calling evhttp_cancel_request
892 * return DATA_TOO_LONG:
893 * ran over the maximum limit
894 */
895
896static enum message_read_status
897evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
898{
899 if (req == NULL || buf == NULL) {
900 return DATA_CORRUPTED;
901 }
902
903 while (1) {
904 size_t buflen;
905
906 if ((buflen = evbuffer_get_length(buf)) == 0) {
907 break;
908 }
909
910 /* evbuffer_get_length returns size_t, but len variable is ssize_t,
911 * check for overflow conditions */
912 if (buflen > EV_SSIZE_MAX) {
913 return DATA_CORRUPTED;
914 }
915
916 if (req->ntoread < 0) {
917 /* Read chunk size */
918 ev_int64_t ntoread;
919 char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF);
920 char *endp;
921 int error;
922 if (p == NULL)
923 break;
924 /* the last chunk is on a new line? */
925 if (strlen(p) == 0) {
926 mm_free(p);
927 continue;
928 }
929 ntoread = evutil_strtoll(p, &endp, 16);
930 error = (*p == '\0' ||
931 (*endp != '\0' && *endp != ' ') ||
932 ntoread < 0);
933 mm_free(p);
934 if (error) {
935 /* could not get chunk size */
936 return (DATA_CORRUPTED);
937 }
938
939 /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */
940 if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) {
941 return DATA_CORRUPTED;
942 }
943
944 if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) {
945 /* failed body length test */
946 event_debug(("Request body is too long"));
947 return (DATA_TOO_LONG);
948 }
949
950 req->body_size += (size_t)ntoread;
951 req->ntoread = ntoread;
952 if (req->ntoread == 0) {
953 /* Last chunk */
954 return (ALL_DATA_READ);
955 }
956 continue;
957 }
958
959 /* req->ntoread is signed int64, len is ssize_t, based on arch,
960 * ssize_t could only be 32b, check for these conditions */
961 if (req->ntoread > EV_SSIZE_MAX) {
962 return DATA_CORRUPTED;
963 }
964
965 /* don't have enough to complete a chunk; wait for more */
966 if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread)
967 return (MORE_DATA_EXPECTED);
968
969 /* Completed chunk */
970 evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread);
971 req->ntoread = -1;
972 if (req->chunk_cb != NULL) {
973 req->flags |= EVHTTP_REQ_DEFER_FREE;
974 (*req->chunk_cb)(req, req->cb_arg);
975 evbuffer_drain(req->input_buffer,
976 evbuffer_get_length(req->input_buffer));
977 req->flags &= ~EVHTTP_REQ_DEFER_FREE;
978 if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
979 return (REQUEST_CANCELED);
980 }
981 }
982 }
983
984 return (MORE_DATA_EXPECTED);
985}
986
987static void
988evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
989{
990 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
991
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100992 switch (evhttp_parse_headers_(req, buf)) {
Christopher Wileye8679812015-07-01 13:36:18 -0700993 case DATA_CORRUPTED:
994 case DATA_TOO_LONG:
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100995 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
Christopher Wileye8679812015-07-01 13:36:18 -0700996 break;
997 case ALL_DATA_READ:
998 bufferevent_disable(evcon->bufev, EV_READ);
999 evhttp_connection_done(evcon);
1000 break;
1001 case MORE_DATA_EXPECTED:
1002 case REQUEST_CANCELED: /* ??? */
1003 default:
Christopher Wileye8679812015-07-01 13:36:18 -07001004 break;
1005 }
1006}
1007
1008static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001009evhttp_lingering_close(struct evhttp_connection *evcon,
1010 struct evhttp_request *req)
1011{
1012 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
1013
1014 size_t n = evbuffer_get_length(buf);
1015 if (n > (size_t) req->ntoread)
1016 n = (size_t) req->ntoread;
1017 req->ntoread -= n;
1018 req->body_size += n;
1019
1020 event_debug(("Request body is too long, left " EV_I64_FMT,
1021 EV_I64_ARG(req->ntoread)));
1022
1023 evbuffer_drain(buf, n);
1024 if (!req->ntoread)
1025 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
1026}
1027static void
1028evhttp_lingering_fail(struct evhttp_connection *evcon,
1029 struct evhttp_request *req)
1030{
1031 if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE)
1032 evhttp_lingering_close(evcon, req);
1033 else
1034 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
1035}
1036
1037static void
Christopher Wileye8679812015-07-01 13:36:18 -07001038evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
1039{
1040 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
1041
1042 if (req->chunked) {
1043 switch (evhttp_handle_chunked_read(req, buf)) {
1044 case ALL_DATA_READ:
1045 /* finished last chunk */
1046 evcon->state = EVCON_READING_TRAILER;
1047 evhttp_read_trailer(evcon, req);
1048 return;
1049 case DATA_CORRUPTED:
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001050 case DATA_TOO_LONG:
Christopher Wileye8679812015-07-01 13:36:18 -07001051 /* corrupted data */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001052 evhttp_connection_fail_(evcon,
1053 EVREQ_HTTP_DATA_TOO_LONG);
Christopher Wileye8679812015-07-01 13:36:18 -07001054 return;
1055 case REQUEST_CANCELED:
1056 /* request canceled */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001057 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07001058 return;
1059 case MORE_DATA_EXPECTED:
1060 default:
1061 break;
1062 }
1063 } else if (req->ntoread < 0) {
1064 /* Read until connection close. */
1065 if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001066 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07001067 return;
1068 }
1069
1070 req->body_size += evbuffer_get_length(buf);
1071 evbuffer_add_buffer(req->input_buffer, buf);
1072 } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) {
1073 /* XXX: the above get_length comparison has to be fixed for overflow conditions! */
1074 /* We've postponed moving the data until now, but we're
1075 * about to use it. */
1076 size_t n = evbuffer_get_length(buf);
1077
1078 if (n > (size_t) req->ntoread)
1079 n = (size_t) req->ntoread;
1080 req->ntoread -= n;
1081 req->body_size += n;
1082 evbuffer_remove_buffer(buf, req->input_buffer, n);
1083 }
1084
1085 if (req->body_size > req->evcon->max_body_size ||
1086 (!req->chunked && req->ntoread >= 0 &&
1087 (size_t)req->ntoread > req->evcon->max_body_size)) {
1088 /* XXX: The above casted comparison must checked for overflow */
1089 /* failed body length test */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001090
1091 evhttp_lingering_fail(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07001092 return;
1093 }
1094
1095 if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) {
1096 req->flags |= EVHTTP_REQ_DEFER_FREE;
1097 (*req->chunk_cb)(req, req->cb_arg);
1098 req->flags &= ~EVHTTP_REQ_DEFER_FREE;
1099 evbuffer_drain(req->input_buffer,
1100 evbuffer_get_length(req->input_buffer));
1101 if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001102 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07001103 return;
1104 }
1105 }
1106
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001107 if (!req->ntoread) {
Christopher Wileye8679812015-07-01 13:36:18 -07001108 bufferevent_disable(evcon->bufev, EV_READ);
1109 /* Completed content length */
1110 evhttp_connection_done(evcon);
1111 return;
1112 }
Christopher Wileye8679812015-07-01 13:36:18 -07001113}
1114
1115#define get_deferred_queue(evcon) \
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001116 ((evcon)->base)
Christopher Wileye8679812015-07-01 13:36:18 -07001117
1118/*
1119 * Gets called when more data becomes available
1120 */
1121
1122static void
1123evhttp_read_cb(struct bufferevent *bufev, void *arg)
1124{
1125 struct evhttp_connection *evcon = arg;
1126 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1127
1128 /* Cancel if it's pending. */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001129 event_deferred_cb_cancel_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07001130 &evcon->read_more_deferred_cb);
1131
1132 switch (evcon->state) {
1133 case EVCON_READING_FIRSTLINE:
1134 evhttp_read_firstline(evcon, req);
1135 /* note the request may have been freed in
1136 * evhttp_read_body */
1137 break;
1138 case EVCON_READING_HEADERS:
1139 evhttp_read_header(evcon, req);
1140 /* note the request may have been freed in
1141 * evhttp_read_body */
1142 break;
1143 case EVCON_READING_BODY:
1144 evhttp_read_body(evcon, req);
1145 /* note the request may have been freed in
1146 * evhttp_read_body */
1147 break;
1148 case EVCON_READING_TRAILER:
1149 evhttp_read_trailer(evcon, req);
1150 break;
1151 case EVCON_IDLE:
1152 {
1153#ifdef USE_DEBUG
1154 struct evbuffer *input;
1155 size_t total_len;
1156
1157 input = bufferevent_get_input(evcon->bufev);
1158 total_len = evbuffer_get_length(input);
1159 event_debug(("%s: read "EV_SIZE_FMT
1160 " bytes in EVCON_IDLE state,"
1161 " resetting connection",
1162 __func__, EV_SIZE_ARG(total_len)));
1163#endif
1164
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001165 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001166 }
1167 break;
1168 case EVCON_DISCONNECTED:
1169 case EVCON_CONNECTING:
1170 case EVCON_WRITING:
1171 default:
1172 event_errx(1, "%s: illegal connection state %d",
1173 __func__, evcon->state);
1174 }
1175}
1176
1177static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001178evhttp_deferred_read_cb(struct event_callback *cb, void *data)
Christopher Wileye8679812015-07-01 13:36:18 -07001179{
1180 struct evhttp_connection *evcon = data;
Haibo Huangb2279672019-05-31 16:12:39 -07001181 struct bufferevent *bev = evcon->bufev;
1182 if (bev->readcb)
1183 (bev->readcb)(evcon->bufev, evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001184}
1185
1186static void
1187evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
1188{
1189 /* This is after writing the request to the server */
1190 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001191 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07001192 EVUTIL_ASSERT(req != NULL);
1193
1194 EVUTIL_ASSERT(evcon->state == EVCON_WRITING);
1195
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001196 /* We need to wait until we've written all of our output data before we can
1197 * continue */
1198 if (evbuffer_get_length(output) > 0)
1199 return;
1200
Christopher Wileye8679812015-07-01 13:36:18 -07001201 /* We are done writing our header and are now expecting the response */
1202 req->kind = EVHTTP_RESPONSE;
1203
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001204 evhttp_start_read_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001205}
1206
1207/*
1208 * Clean up a connection object
1209 */
1210
1211void
1212evhttp_connection_free(struct evhttp_connection *evcon)
1213{
1214 struct evhttp_request *req;
Haibo Huangb2279672019-05-31 16:12:39 -07001215 int need_close = 0;
Christopher Wileye8679812015-07-01 13:36:18 -07001216
1217 /* notify interested parties that this connection is going down */
1218 if (evcon->fd != -1) {
1219 if (evhttp_connected(evcon) && evcon->closecb != NULL)
1220 (*evcon->closecb)(evcon, evcon->closecb_arg);
1221 }
1222
1223 /* remove all requests that might be queued on this
1224 * connection. for server connections, this should be empty.
1225 * because it gets dequeued either in evhttp_connection_done or
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001226 * evhttp_connection_fail_.
Christopher Wileye8679812015-07-01 13:36:18 -07001227 */
1228 while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001229 evhttp_request_free_(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07001230 }
1231
1232 if (evcon->http_server != NULL) {
1233 struct evhttp *http = evcon->http_server;
1234 TAILQ_REMOVE(&http->connections, evcon, next);
1235 }
1236
1237 if (event_initialized(&evcon->retry_ev)) {
1238 event_del(&evcon->retry_ev);
1239 event_debug_unassign(&evcon->retry_ev);
1240 }
1241
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001242 event_deferred_cb_cancel_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07001243 &evcon->read_more_deferred_cb);
1244
Haibo Huangb2279672019-05-31 16:12:39 -07001245 if (evcon->bufev != NULL) {
1246 need_close =
1247 !(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE);
1248 if (evcon->fd == -1)
1249 evcon->fd = bufferevent_getfd(evcon->bufev);
1250
1251 bufferevent_free(evcon->bufev);
1252 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001253
Christopher Wileye8679812015-07-01 13:36:18 -07001254 if (evcon->fd != -1) {
1255 shutdown(evcon->fd, EVUTIL_SHUT_WR);
Haibo Huangb2279672019-05-31 16:12:39 -07001256 if (need_close)
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001257 evutil_closesocket(evcon->fd);
Christopher Wileye8679812015-07-01 13:36:18 -07001258 }
1259
1260 if (evcon->bind_address != NULL)
1261 mm_free(evcon->bind_address);
1262
1263 if (evcon->address != NULL)
1264 mm_free(evcon->address);
1265
1266 mm_free(evcon);
1267}
1268
1269void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001270evhttp_connection_free_on_completion(struct evhttp_connection *evcon) {
1271 evcon->flags |= EVHTTP_CON_AUTOFREE;
1272}
1273
1274void
Christopher Wileye8679812015-07-01 13:36:18 -07001275evhttp_connection_set_local_address(struct evhttp_connection *evcon,
1276 const char *address)
1277{
1278 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
1279 if (evcon->bind_address)
1280 mm_free(evcon->bind_address);
1281 if ((evcon->bind_address = mm_strdup(address)) == NULL)
1282 event_warn("%s: strdup", __func__);
1283}
1284
1285void
1286evhttp_connection_set_local_port(struct evhttp_connection *evcon,
1287 ev_uint16_t port)
1288{
1289 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
1290 evcon->bind_port = port;
1291}
1292
1293static void
1294evhttp_request_dispatch(struct evhttp_connection* evcon)
1295{
1296 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1297
1298 /* this should not usually happy but it's possible */
1299 if (req == NULL)
1300 return;
1301
Haibo Huangb2279672019-05-31 16:12:39 -07001302 EVUTIL_ASSERT(req->kind == EVHTTP_REQUEST);
1303
Christopher Wileye8679812015-07-01 13:36:18 -07001304 /* delete possible close detection events */
1305 evhttp_connection_stop_detectclose(evcon);
1306
1307 /* we assume that the connection is connected already */
1308 EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
1309
1310 evcon->state = EVCON_WRITING;
1311
1312 /* Create the header from the store arguments */
1313 evhttp_make_header(evcon, req);
1314
1315 evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
1316}
1317
1318/* Reset our connection state: disables reading/writing, closes our fd (if
1319* any), clears out buffers, and puts us in state DISCONNECTED. */
1320void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001321evhttp_connection_reset_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07001322{
1323 struct evbuffer *tmp;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001324 int err;
Christopher Wileye8679812015-07-01 13:36:18 -07001325
Haibo Huangb2279672019-05-31 16:12:39 -07001326 bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL);
1327
Christopher Wileye8679812015-07-01 13:36:18 -07001328 /* XXXX This is not actually an optimal fix. Instead we ought to have
1329 an API for "stop connecting", or use bufferevent_setfd to turn off
1330 connecting. But for Libevent 2.0, this seems like a minimal change
1331 least likely to disrupt the rest of the bufferevent and http code.
1332
1333 Why is this here? If the fd is set in the bufferevent, and the
1334 bufferevent is connecting, then you can't actually stop the
1335 bufferevent from trying to connect with bufferevent_disable(). The
1336 connect will never trigger, since we close the fd, but the timeout
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001337 might. That caused an assertion failure in evhttp_connection_fail_.
Christopher Wileye8679812015-07-01 13:36:18 -07001338 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001339 bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE);
1340
1341 if (evcon->fd == -1)
1342 evcon->fd = bufferevent_getfd(evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07001343
1344 if (evcon->fd != -1) {
1345 /* inform interested parties about connection close */
1346 if (evhttp_connected(evcon) && evcon->closecb != NULL)
1347 (*evcon->closecb)(evcon, evcon->closecb_arg);
1348
1349 shutdown(evcon->fd, EVUTIL_SHUT_WR);
1350 evutil_closesocket(evcon->fd);
1351 evcon->fd = -1;
1352 }
Haibo Huangb2279672019-05-31 16:12:39 -07001353 err = bufferevent_setfd(evcon->bufev, -1);
1354 EVUTIL_ASSERT(!err && "setfd");
Christopher Wileye8679812015-07-01 13:36:18 -07001355
1356 /* we need to clean up any buffered data */
1357 tmp = bufferevent_get_output(evcon->bufev);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001358 err = evbuffer_drain(tmp, -1);
1359 EVUTIL_ASSERT(!err && "drain output");
Christopher Wileye8679812015-07-01 13:36:18 -07001360 tmp = bufferevent_get_input(evcon->bufev);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001361 err = evbuffer_drain(tmp, -1);
1362 EVUTIL_ASSERT(!err && "drain input");
1363
1364 evcon->flags &= ~EVHTTP_CON_READING_ERROR;
Christopher Wileye8679812015-07-01 13:36:18 -07001365
1366 evcon->state = EVCON_DISCONNECTED;
1367}
1368
1369static void
1370evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
1371{
1372 evcon->flags |= EVHTTP_CON_CLOSEDETECT;
Christopher Wileye8679812015-07-01 13:36:18 -07001373 bufferevent_enable(evcon->bufev, EV_READ);
1374}
1375
1376static void
1377evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
1378{
1379 evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
Christopher Wileye8679812015-07-01 13:36:18 -07001380 bufferevent_disable(evcon->bufev, EV_READ);
1381}
1382
1383static void
1384evhttp_connection_retry(evutil_socket_t fd, short what, void *arg)
1385{
1386 struct evhttp_connection *evcon = arg;
1387
1388 evcon->state = EVCON_DISCONNECTED;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001389 evhttp_connection_connect_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001390}
1391
1392static void
1393evhttp_connection_cb_cleanup(struct evhttp_connection *evcon)
1394{
1395 struct evcon_requestq requests;
1396
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001397 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001398 if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001399 struct timeval tv_retry = evcon->initial_retry_timeout;
1400 int i;
Christopher Wileye8679812015-07-01 13:36:18 -07001401 evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon);
1402 /* XXXX handle failure from evhttp_add_event */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001403 for (i=0; i < evcon->retry_cnt; ++i) {
1404 tv_retry.tv_usec *= 2;
1405 if (tv_retry.tv_usec > 1000000) {
1406 tv_retry.tv_usec -= 1000000;
1407 tv_retry.tv_sec += 1;
1408 }
1409 tv_retry.tv_sec *= 2;
1410 if (tv_retry.tv_sec > 3600) {
1411 tv_retry.tv_sec = 3600;
1412 tv_retry.tv_usec = 0;
1413 }
1414 }
1415 event_add(&evcon->retry_ev, &tv_retry);
Christopher Wileye8679812015-07-01 13:36:18 -07001416 evcon->retry_cnt++;
1417 return;
1418 }
Christopher Wileye8679812015-07-01 13:36:18 -07001419
1420 /*
1421 * User callback can do evhttp_make_request() on the same
1422 * evcon so new request will be added to evcon->requests. To
1423 * avoid freeing it prematurely we iterate over the copy of
1424 * the queue.
1425 */
1426 TAILQ_INIT(&requests);
1427 while (TAILQ_FIRST(&evcon->requests) != NULL) {
1428 struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
1429 TAILQ_REMOVE(&evcon->requests, request, next);
1430 TAILQ_INSERT_TAIL(&requests, request, next);
1431 }
1432
1433 /* for now, we just signal all requests by executing their callbacks */
1434 while (TAILQ_FIRST(&requests) != NULL) {
1435 struct evhttp_request *request = TAILQ_FIRST(&requests);
1436 TAILQ_REMOVE(&requests, request, next);
1437 request->evcon = NULL;
1438
1439 /* we might want to set an error here */
1440 request->cb(request, request->cb_arg);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001441 evhttp_request_free_auto(request);
Christopher Wileye8679812015-07-01 13:36:18 -07001442 }
1443}
1444
1445static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001446evhttp_connection_read_on_write_error(struct evhttp_connection *evcon,
1447 struct evhttp_request *req)
1448{
1449 struct evbuffer *buf;
1450
1451 /** Second time, we can't read anything */
1452 if (evcon->flags & EVHTTP_CON_READING_ERROR) {
1453 evcon->flags &= ~EVHTTP_CON_READING_ERROR;
1454 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
1455 return;
1456 }
1457
1458 req->kind = EVHTTP_RESPONSE;
1459
1460 buf = bufferevent_get_output(evcon->bufev);
1461 evbuffer_unfreeze(buf, 1);
1462 evbuffer_drain(buf, evbuffer_get_length(buf));
1463 evbuffer_freeze(buf, 1);
1464
1465 evhttp_start_read_(evcon);
1466 evcon->flags |= EVHTTP_CON_READING_ERROR;
1467}
1468
1469static void
Christopher Wileye8679812015-07-01 13:36:18 -07001470evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
1471{
1472 struct evhttp_connection *evcon = arg;
1473 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1474
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001475 if (evcon->fd == -1)
1476 evcon->fd = bufferevent_getfd(bufev);
1477
Christopher Wileye8679812015-07-01 13:36:18 -07001478 switch (evcon->state) {
1479 case EVCON_CONNECTING:
1480 if (what & BEV_EVENT_TIMEOUT) {
1481 event_debug(("%s: connection timeout for \"%s:%d\" on "
1482 EV_SOCK_FMT,
1483 __func__, evcon->address, evcon->port,
1484 EV_SOCK_ARG(evcon->fd)));
1485 evhttp_connection_cb_cleanup(evcon);
1486 return;
1487 }
1488 break;
1489
1490 case EVCON_READING_BODY:
1491 if (!req->chunked && req->ntoread < 0
1492 && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) {
1493 /* EOF on read can be benign */
1494 evhttp_connection_done(evcon);
1495 return;
1496 }
1497 break;
1498
1499 case EVCON_DISCONNECTED:
1500 case EVCON_IDLE:
1501 case EVCON_READING_FIRSTLINE:
1502 case EVCON_READING_HEADERS:
1503 case EVCON_READING_TRAILER:
1504 case EVCON_WRITING:
1505 default:
1506 break;
1507 }
1508
1509 /* when we are in close detect mode, a read error means that
1510 * the other side closed their connection.
1511 */
1512 if (evcon->flags & EVHTTP_CON_CLOSEDETECT) {
1513 evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
1514 EVUTIL_ASSERT(evcon->http_server == NULL);
1515 /* For connections from the client, we just
1516 * reset the connection so that it becomes
1517 * disconnected.
1518 */
1519 EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001520 evhttp_connection_reset_(evcon);
1521
1522 /*
1523 * If we have no more requests that need completion
1524 * and we want to auto-free the connection when all
1525 * requests have been completed.
1526 */
1527 if (TAILQ_FIRST(&evcon->requests) == NULL
1528 && (evcon->flags & EVHTTP_CON_OUTGOING)
1529 && (evcon->flags & EVHTTP_CON_AUTOFREE)) {
1530 evhttp_connection_free(evcon);
1531 }
Christopher Wileye8679812015-07-01 13:36:18 -07001532 return;
1533 }
1534
1535 if (what & BEV_EVENT_TIMEOUT) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001536 evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
Christopher Wileye8679812015-07-01 13:36:18 -07001537 } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001538 if (what & BEV_EVENT_WRITING &&
1539 evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) {
1540 evhttp_connection_read_on_write_error(evcon, req);
1541 return;
1542 }
1543
Haibo Huangb2279672019-05-31 16:12:39 -07001544 if (what & BEV_EVENT_READING &&
1545 evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR &&
1546 evbuffer_get_length(bufferevent_get_input(bufev))) {
1547 event_deferred_cb_schedule_(get_deferred_queue(evcon),
1548 &evcon->read_more_deferred_cb);
1549 return;
1550 }
1551
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001552 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
1553 } else if (what == BEV_EVENT_CONNECTED) {
Christopher Wileye8679812015-07-01 13:36:18 -07001554 } else {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001555 evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR);
Christopher Wileye8679812015-07-01 13:36:18 -07001556 }
1557}
1558
1559/*
1560 * Event callback for asynchronous connection attempt.
1561 */
1562static void
1563evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
1564{
1565 struct evhttp_connection *evcon = arg;
1566 int error;
1567 ev_socklen_t errsz = sizeof(error);
1568
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001569 if (evcon->fd == -1)
1570 evcon->fd = bufferevent_getfd(bufev);
1571
Christopher Wileye8679812015-07-01 13:36:18 -07001572 if (!(what & BEV_EVENT_CONNECTED)) {
1573 /* some operating systems return ECONNREFUSED immediately
1574 * when connecting to a local address. the cleanup is going
1575 * to reschedule this function call.
1576 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001577#ifndef _WIN32
Christopher Wileye8679812015-07-01 13:36:18 -07001578 if (errno == ECONNREFUSED)
1579 goto cleanup;
1580#endif
1581 evhttp_error_cb(bufev, what, arg);
1582 return;
1583 }
1584
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001585 if (evcon->fd == -1) {
1586 event_debug(("%s: bufferevent_getfd returned -1",
1587 __func__));
1588 goto cleanup;
1589 }
1590
Christopher Wileye8679812015-07-01 13:36:18 -07001591 /* Check if the connection completed */
1592 if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
1593 &errsz) == -1) {
1594 event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT,
1595 __func__, evcon->address, evcon->port,
1596 EV_SOCK_ARG(evcon->fd)));
1597 goto cleanup;
1598 }
1599
1600 if (error) {
1601 event_debug(("%s: connect failed for \"%s:%d\" on "
1602 EV_SOCK_FMT": %s",
1603 __func__, evcon->address, evcon->port,
1604 EV_SOCK_ARG(evcon->fd),
1605 evutil_socket_error_to_string(error)));
1606 goto cleanup;
1607 }
1608
1609 /* We are connected to the server now */
1610 event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n",
1611 __func__, evcon->address, evcon->port,
1612 EV_SOCK_ARG(evcon->fd)));
1613
1614 /* Reset the retry count as we were successful in connecting */
1615 evcon->retry_cnt = 0;
1616 evcon->state = EVCON_IDLE;
1617
1618 /* reset the bufferevent cbs */
1619 bufferevent_setcb(evcon->bufev,
1620 evhttp_read_cb,
1621 evhttp_write_cb,
1622 evhttp_error_cb,
1623 evcon);
1624
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001625 if (!evutil_timerisset(&evcon->timeout)) {
1626 const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
1627 const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
1628 bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
1629 } else {
1630 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07001631 }
1632
1633 /* try to start requests that have queued up on this connection */
1634 evhttp_request_dispatch(evcon);
1635 return;
1636
1637 cleanup:
1638 evhttp_connection_cb_cleanup(evcon);
1639}
1640
1641/*
1642 * Check if we got a valid response code.
1643 */
1644
1645static int
1646evhttp_valid_response_code(int code)
1647{
1648 if (code == 0)
1649 return (0);
1650
1651 return (1);
1652}
1653
1654static int
1655evhttp_parse_http_version(const char *version, struct evhttp_request *req)
1656{
1657 int major, minor;
1658 char ch;
1659 int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch);
1660 if (n != 2 || major > 1) {
1661 event_debug(("%s: bad version %s on message %p from %s",
1662 __func__, version, req, req->remote_host));
1663 return (-1);
1664 }
1665 req->major = major;
1666 req->minor = minor;
1667 return (0);
1668}
1669
1670/* Parses the status line of a web server */
1671
1672static int
1673evhttp_parse_response_line(struct evhttp_request *req, char *line)
1674{
1675 char *protocol;
1676 char *number;
1677 const char *readable = "";
1678
1679 protocol = strsep(&line, " ");
1680 if (line == NULL)
1681 return (-1);
1682 number = strsep(&line, " ");
1683 if (line != NULL)
1684 readable = line;
1685
1686 if (evhttp_parse_http_version(protocol, req) < 0)
1687 return (-1);
1688
1689 req->response_code = atoi(number);
1690 if (!evhttp_valid_response_code(req->response_code)) {
1691 event_debug(("%s: bad response code \"%s\"",
1692 __func__, number));
1693 return (-1);
1694 }
1695
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001696 if (req->response_code_line != NULL)
1697 mm_free(req->response_code_line);
Christopher Wileye8679812015-07-01 13:36:18 -07001698 if ((req->response_code_line = mm_strdup(readable)) == NULL) {
1699 event_warn("%s: strdup", __func__);
1700 return (-1);
1701 }
1702
1703 return (0);
1704}
1705
1706/* Parse the first line of a HTTP request */
1707
1708static int
Haibo Huangb2279672019-05-31 16:12:39 -07001709evhttp_parse_request_line(struct evhttp_request *req, char *line, size_t len)
Christopher Wileye8679812015-07-01 13:36:18 -07001710{
Haibo Huangb2279672019-05-31 16:12:39 -07001711 char *eos = line + len;
Christopher Wileye8679812015-07-01 13:36:18 -07001712 char *method;
1713 char *uri;
1714 char *version;
1715 const char *hostname;
1716 const char *scheme;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001717 size_t method_len;
1718 enum evhttp_cmd_type type;
Christopher Wileye8679812015-07-01 13:36:18 -07001719
Haibo Huangb2279672019-05-31 16:12:39 -07001720 while (eos > line && *(eos-1) == ' ') {
1721 *(eos-1) = '\0';
1722 --eos;
1723 --len;
1724 }
1725 if (len < strlen("GET / HTTP/1.0"))
1726 return -1;
1727
Christopher Wileye8679812015-07-01 13:36:18 -07001728 /* Parse the request line */
1729 method = strsep(&line, " ");
Haibo Huangb2279672019-05-31 16:12:39 -07001730 if (!line)
1731 return -1;
1732 uri = line;
1733 version = strrchr(uri, ' ');
1734 if (!version || uri == version)
1735 return -1;
1736 *version = '\0';
1737 version++;
Christopher Wileye8679812015-07-01 13:36:18 -07001738
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001739 method_len = (uri - method) - 1;
1740 type = EVHTTP_REQ_UNKNOWN_;
1741
Christopher Wileye8679812015-07-01 13:36:18 -07001742 /* First line */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001743 switch (method_len) {
1744 case 3:
1745 /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */
1746
1747 /* Since both GET and PUT share the same character 'T' at the end,
1748 * if the string doesn't have 'T', we can immediately determine this
1749 * is an invalid HTTP method */
1750
1751 if (method[2] != 'T') {
1752 break;
1753 }
1754
1755 switch (*method) {
1756 case 'G':
1757 /* This first byte is 'G', so make sure the next byte is
1758 * 'E', if it isn't then this isn't a valid method */
1759
1760 if (method[1] == 'E') {
1761 type = EVHTTP_REQ_GET;
1762 }
1763
1764 break;
1765 case 'P':
1766 /* First byte is P, check second byte for 'U', if not,
1767 * we know it's an invalid method */
1768 if (method[1] == 'U') {
1769 type = EVHTTP_REQ_PUT;
1770 }
1771 break;
1772 default:
1773 break;
1774 }
1775 break;
1776 case 4:
1777 /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */
1778 switch (*method) {
1779 case 'P':
1780 if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') {
1781 type = EVHTTP_REQ_POST;
1782 }
1783 break;
1784 case 'H':
1785 if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') {
1786 type = EVHTTP_REQ_HEAD;
1787 }
1788 break;
1789 default:
1790 break;
1791 }
1792 break;
1793 case 5:
1794 /* Method length is 5 bytes, which can only encompass PATCH and TRACE */
1795 switch (*method) {
1796 case 'P':
1797 if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') {
1798 type = EVHTTP_REQ_PATCH;
1799 }
1800 break;
1801 case 'T':
1802 if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') {
1803 type = EVHTTP_REQ_TRACE;
1804 }
1805
1806 break;
1807 default:
1808 break;
1809 }
1810 break;
1811 case 6:
1812 /* Method length is 6, only valid method 6 bytes in length is DELEte */
1813
1814 /* If the first byte isn't 'D' then it's invalid */
1815 if (*method != 'D') {
1816 break;
1817 }
1818
1819 if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') {
1820 type = EVHTTP_REQ_DELETE;
1821 }
1822
1823 break;
1824 case 7:
1825 /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */
1826 switch (*method) {
1827 case 'O':
1828 if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' &&
1829 method[3] == 'I' && method[2] == 'T' && method[1] == 'P') {
1830 type = EVHTTP_REQ_OPTIONS;
1831 }
1832
1833 break;
1834 case 'C':
1835 if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' &&
1836 method[3] == 'N' && method[2] == 'N' && method[1] == 'O') {
1837 type = EVHTTP_REQ_CONNECT;
1838 }
1839
1840 break;
1841 default:
1842 break;
1843 }
1844 break;
1845 } /* switch */
1846
1847 if ((int)type == EVHTTP_REQ_UNKNOWN_) {
1848 event_debug(("%s: bad method %s on request %p from %s",
Christopher Wileye8679812015-07-01 13:36:18 -07001849 __func__, method, req, req->remote_host));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001850 /* No error yet; we'll give a better error later when
1851 * we see that req->type is unsupported. */
Christopher Wileye8679812015-07-01 13:36:18 -07001852 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001853
1854 req->type = type;
Christopher Wileye8679812015-07-01 13:36:18 -07001855
1856 if (evhttp_parse_http_version(version, req) < 0)
Haibo Huangb2279672019-05-31 16:12:39 -07001857 return -1;
Christopher Wileye8679812015-07-01 13:36:18 -07001858
1859 if ((req->uri = mm_strdup(uri)) == NULL) {
1860 event_debug(("%s: mm_strdup", __func__));
Haibo Huangb2279672019-05-31 16:12:39 -07001861 return -1;
Christopher Wileye8679812015-07-01 13:36:18 -07001862 }
1863
Haibo Huangb2279672019-05-31 16:12:39 -07001864 if (type == EVHTTP_REQ_CONNECT) {
1865 if ((req->uri_elems = evhttp_uri_parse_authority(req->uri)) == NULL) {
1866 return -1;
1867 }
1868 } else {
1869 if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri,
1870 EVHTTP_URI_NONCONFORMANT)) == NULL) {
1871 return -1;
1872 }
Christopher Wileye8679812015-07-01 13:36:18 -07001873 }
1874
1875 /* If we have an absolute-URI, check to see if it is an http request
1876 for a known vhost or server alias. If we don't know about this
1877 host, we consider it a proxy request. */
1878 scheme = evhttp_uri_get_scheme(req->uri_elems);
1879 hostname = evhttp_uri_get_host(req->uri_elems);
1880 if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") ||
1881 !evutil_ascii_strcasecmp(scheme, "https")) &&
1882 hostname &&
1883 !evhttp_find_vhost(req->evcon->http_server, NULL, hostname))
1884 req->flags |= EVHTTP_PROXY_REQUEST;
1885
Haibo Huangb2279672019-05-31 16:12:39 -07001886 return 0;
Christopher Wileye8679812015-07-01 13:36:18 -07001887}
1888
1889const char *
1890evhttp_find_header(const struct evkeyvalq *headers, const char *key)
1891{
1892 struct evkeyval *header;
1893
1894 TAILQ_FOREACH(header, headers, next) {
1895 if (evutil_ascii_strcasecmp(header->key, key) == 0)
1896 return (header->value);
1897 }
1898
1899 return (NULL);
1900}
1901
1902void
1903evhttp_clear_headers(struct evkeyvalq *headers)
1904{
1905 struct evkeyval *header;
1906
1907 for (header = TAILQ_FIRST(headers);
1908 header != NULL;
1909 header = TAILQ_FIRST(headers)) {
1910 TAILQ_REMOVE(headers, header, next);
1911 mm_free(header->key);
1912 mm_free(header->value);
1913 mm_free(header);
1914 }
1915}
1916
1917/*
1918 * Returns 0, if the header was successfully removed.
1919 * Returns -1, if the header could not be found.
1920 */
1921
1922int
1923evhttp_remove_header(struct evkeyvalq *headers, const char *key)
1924{
1925 struct evkeyval *header;
1926
1927 TAILQ_FOREACH(header, headers, next) {
1928 if (evutil_ascii_strcasecmp(header->key, key) == 0)
1929 break;
1930 }
1931
1932 if (header == NULL)
1933 return (-1);
1934
1935 /* Free and remove the header that we found */
1936 TAILQ_REMOVE(headers, header, next);
1937 mm_free(header->key);
1938 mm_free(header->value);
1939 mm_free(header);
1940
1941 return (0);
1942}
1943
1944static int
1945evhttp_header_is_valid_value(const char *value)
1946{
1947 const char *p = value;
1948
1949 while ((p = strpbrk(p, "\r\n")) != NULL) {
1950 /* we really expect only one new line */
1951 p += strspn(p, "\r\n");
1952 /* we expect a space or tab for continuation */
1953 if (*p != ' ' && *p != '\t')
1954 return (0);
1955 }
1956 return (1);
1957}
1958
1959int
1960evhttp_add_header(struct evkeyvalq *headers,
1961 const char *key, const char *value)
1962{
1963 event_debug(("%s: key: %s val: %s\n", __func__, key, value));
1964
1965 if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
1966 /* drop illegal headers */
1967 event_debug(("%s: dropping illegal header key\n", __func__));
1968 return (-1);
1969 }
1970
1971 if (!evhttp_header_is_valid_value(value)) {
1972 event_debug(("%s: dropping illegal header value\n", __func__));
1973 return (-1);
1974 }
1975
1976 return (evhttp_add_header_internal(headers, key, value));
1977}
1978
1979static int
1980evhttp_add_header_internal(struct evkeyvalq *headers,
1981 const char *key, const char *value)
1982{
1983 struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval));
1984 if (header == NULL) {
1985 event_warn("%s: calloc", __func__);
1986 return (-1);
1987 }
1988 if ((header->key = mm_strdup(key)) == NULL) {
1989 mm_free(header);
1990 event_warn("%s: strdup", __func__);
1991 return (-1);
1992 }
1993 if ((header->value = mm_strdup(value)) == NULL) {
1994 mm_free(header->key);
1995 mm_free(header);
1996 event_warn("%s: strdup", __func__);
1997 return (-1);
1998 }
1999
2000 TAILQ_INSERT_TAIL(headers, header, next);
2001
2002 return (0);
2003}
2004
2005/*
2006 * Parses header lines from a request or a response into the specified
2007 * request object given an event buffer.
2008 *
2009 * Returns
2010 * DATA_CORRUPTED on error
2011 * MORE_DATA_EXPECTED when we need to read more headers
2012 * ALL_DATA_READ when all headers have been read.
2013 */
2014
2015enum message_read_status
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002016evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer)
Christopher Wileye8679812015-07-01 13:36:18 -07002017{
2018 char *line;
2019 enum message_read_status status = ALL_DATA_READ;
2020
Haibo Huangb2279672019-05-31 16:12:39 -07002021 size_t len;
Christopher Wileye8679812015-07-01 13:36:18 -07002022 /* XXX try */
Haibo Huangb2279672019-05-31 16:12:39 -07002023 line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF);
Christopher Wileye8679812015-07-01 13:36:18 -07002024 if (line == NULL) {
2025 if (req->evcon != NULL &&
2026 evbuffer_get_length(buffer) > req->evcon->max_headers_size)
2027 return (DATA_TOO_LONG);
2028 else
2029 return (MORE_DATA_EXPECTED);
2030 }
2031
Haibo Huangb2279672019-05-31 16:12:39 -07002032 if (req->evcon != NULL && len > req->evcon->max_headers_size) {
Christopher Wileye8679812015-07-01 13:36:18 -07002033 mm_free(line);
2034 return (DATA_TOO_LONG);
2035 }
2036
Haibo Huangb2279672019-05-31 16:12:39 -07002037 req->headers_size = len;
Christopher Wileye8679812015-07-01 13:36:18 -07002038
2039 switch (req->kind) {
2040 case EVHTTP_REQUEST:
Haibo Huangb2279672019-05-31 16:12:39 -07002041 if (evhttp_parse_request_line(req, line, len) == -1)
Christopher Wileye8679812015-07-01 13:36:18 -07002042 status = DATA_CORRUPTED;
2043 break;
2044 case EVHTTP_RESPONSE:
2045 if (evhttp_parse_response_line(req, line) == -1)
2046 status = DATA_CORRUPTED;
2047 break;
2048 default:
2049 status = DATA_CORRUPTED;
2050 }
2051
2052 mm_free(line);
2053 return (status);
2054}
2055
2056static int
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002057evhttp_append_to_last_header(struct evkeyvalq *headers, char *line)
Christopher Wileye8679812015-07-01 13:36:18 -07002058{
2059 struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
2060 char *newval;
2061 size_t old_len, line_len;
2062
2063 if (header == NULL)
2064 return (-1);
2065
2066 old_len = strlen(header->value);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002067
2068 /* Strip space from start and end of line. */
2069 while (*line == ' ' || *line == '\t')
2070 ++line;
2071 evutil_rtrim_lws_(line);
2072
Christopher Wileye8679812015-07-01 13:36:18 -07002073 line_len = strlen(line);
2074
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002075 newval = mm_realloc(header->value, old_len + line_len + 2);
Christopher Wileye8679812015-07-01 13:36:18 -07002076 if (newval == NULL)
2077 return (-1);
2078
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002079 newval[old_len] = ' ';
2080 memcpy(newval + old_len + 1, line, line_len + 1);
Christopher Wileye8679812015-07-01 13:36:18 -07002081 header->value = newval;
2082
2083 return (0);
2084}
2085
2086enum message_read_status
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002087evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
Christopher Wileye8679812015-07-01 13:36:18 -07002088{
2089 enum message_read_status errcode = DATA_CORRUPTED;
2090 char *line;
2091 enum message_read_status status = MORE_DATA_EXPECTED;
2092
2093 struct evkeyvalq* headers = req->input_headers;
Haibo Huangb2279672019-05-31 16:12:39 -07002094 size_t len;
2095 while ((line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF))
Christopher Wileye8679812015-07-01 13:36:18 -07002096 != NULL) {
2097 char *skey, *svalue;
2098
Haibo Huangb2279672019-05-31 16:12:39 -07002099 req->headers_size += len;
Christopher Wileye8679812015-07-01 13:36:18 -07002100
2101 if (req->evcon != NULL &&
2102 req->headers_size > req->evcon->max_headers_size) {
2103 errcode = DATA_TOO_LONG;
2104 goto error;
2105 }
2106
2107 if (*line == '\0') { /* Last header - Done */
2108 status = ALL_DATA_READ;
2109 mm_free(line);
2110 break;
2111 }
2112
2113 /* Check if this is a continuation line */
2114 if (*line == ' ' || *line == '\t') {
2115 if (evhttp_append_to_last_header(headers, line) == -1)
2116 goto error;
2117 mm_free(line);
2118 continue;
2119 }
2120
2121 /* Processing of header lines */
2122 svalue = line;
2123 skey = strsep(&svalue, ":");
2124 if (svalue == NULL)
2125 goto error;
2126
2127 svalue += strspn(svalue, " ");
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002128 evutil_rtrim_lws_(svalue);
Christopher Wileye8679812015-07-01 13:36:18 -07002129
2130 if (evhttp_add_header(headers, skey, svalue) == -1)
2131 goto error;
2132
2133 mm_free(line);
2134 }
2135
2136 if (status == MORE_DATA_EXPECTED) {
2137 if (req->evcon != NULL &&
2138 req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size)
2139 return (DATA_TOO_LONG);
2140 }
2141
2142 return (status);
2143
2144 error:
2145 mm_free(line);
2146 return (errcode);
2147}
2148
2149static int
2150evhttp_get_body_length(struct evhttp_request *req)
2151{
2152 struct evkeyvalq *headers = req->input_headers;
2153 const char *content_length;
2154 const char *connection;
2155
2156 content_length = evhttp_find_header(headers, "Content-Length");
2157 connection = evhttp_find_header(headers, "Connection");
2158
2159 if (content_length == NULL && connection == NULL)
2160 req->ntoread = -1;
2161 else if (content_length == NULL &&
2162 evutil_ascii_strcasecmp(connection, "Close") != 0) {
Haibo Huangb2279672019-05-31 16:12:39 -07002163 req->ntoread = 0;
Christopher Wileye8679812015-07-01 13:36:18 -07002164 } else if (content_length == NULL) {
2165 req->ntoread = -1;
2166 } else {
2167 char *endp;
2168 ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
2169 if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
2170 event_debug(("%s: illegal content length: %s",
2171 __func__, content_length));
2172 return (-1);
2173 }
2174 req->ntoread = ntoread;
2175 }
2176
2177 event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n",
2178 __func__, EV_I64_ARG(req->ntoread),
2179 EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev)))));
2180
2181 return (0);
2182}
2183
2184static int
2185evhttp_method_may_have_body(enum evhttp_cmd_type type)
2186{
2187 switch (type) {
2188 case EVHTTP_REQ_POST:
2189 case EVHTTP_REQ_PUT:
2190 case EVHTTP_REQ_PATCH:
Haibo Huangb2279672019-05-31 16:12:39 -07002191
Christopher Wileye8679812015-07-01 13:36:18 -07002192 case EVHTTP_REQ_GET:
Christopher Wileye8679812015-07-01 13:36:18 -07002193 case EVHTTP_REQ_DELETE:
2194 case EVHTTP_REQ_OPTIONS:
2195 case EVHTTP_REQ_CONNECT:
Haibo Huangb2279672019-05-31 16:12:39 -07002196 return 1;
2197
2198 case EVHTTP_REQ_TRACE:
2199 case EVHTTP_REQ_HEAD:
Christopher Wileye8679812015-07-01 13:36:18 -07002200 default:
2201 return 0;
2202 }
2203}
2204
2205static void
2206evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
2207{
2208 const char *xfer_enc;
2209
2210 /* If this is a request without a body, then we are done */
2211 if (req->kind == EVHTTP_REQUEST &&
2212 !evhttp_method_may_have_body(req->type)) {
2213 evhttp_connection_done(evcon);
2214 return;
2215 }
2216 evcon->state = EVCON_READING_BODY;
2217 xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
2218 if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) {
2219 req->chunked = 1;
2220 req->ntoread = -1;
2221 } else {
2222 if (evhttp_get_body_length(req) == -1) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002223 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002224 return;
2225 }
2226 if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
2227 /* An incoming request with no content-length and no
2228 * transfer-encoding has no body. */
2229 evhttp_connection_done(evcon);
2230 return;
2231 }
2232 }
2233
2234 /* Should we send a 100 Continue status line? */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002235 switch (evhttp_have_expect(req, 1)) {
2236 case CONTINUE:
Christopher Wileye8679812015-07-01 13:36:18 -07002237 /* XXX It would be nice to do some sanity
2238 checking here. Does the resource exist?
2239 Should the resource accept post requests? If
2240 no, we should respond with an error. For
2241 now, just optimistically tell the client to
2242 send their message body. */
2243 if (req->ntoread > 0) {
2244 /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002245 if ((req->evcon->max_body_size <= EV_INT64_MAX) &&
2246 (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
2247 evhttp_lingering_fail(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07002248 return;
2249 }
2250 }
2251 if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
2252 evhttp_send_continue(evcon, req);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002253 break;
2254 case OTHER:
2255 evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL);
2256 return;
2257 case NO: break;
Christopher Wileye8679812015-07-01 13:36:18 -07002258 }
2259
2260 evhttp_read_body(evcon, req);
2261 /* note the request may have been freed in evhttp_read_body */
2262}
2263
2264static void
2265evhttp_read_firstline(struct evhttp_connection *evcon,
2266 struct evhttp_request *req)
2267{
2268 enum message_read_status res;
2269
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002270 res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev));
Christopher Wileye8679812015-07-01 13:36:18 -07002271 if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
2272 /* Error while reading, terminate */
2273 event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
2274 __func__, EV_SOCK_ARG(evcon->fd)));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002275 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002276 return;
2277 } else if (res == MORE_DATA_EXPECTED) {
2278 /* Need more header lines */
2279 return;
2280 }
2281
2282 evcon->state = EVCON_READING_HEADERS;
2283 evhttp_read_header(evcon, req);
2284}
2285
2286static void
2287evhttp_read_header(struct evhttp_connection *evcon,
2288 struct evhttp_request *req)
2289{
2290 enum message_read_status res;
2291 evutil_socket_t fd = evcon->fd;
2292
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002293 res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev));
Christopher Wileye8679812015-07-01 13:36:18 -07002294 if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
2295 /* Error while reading, terminate */
2296 event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
2297 __func__, EV_SOCK_ARG(fd)));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002298 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002299 return;
2300 } else if (res == MORE_DATA_EXPECTED) {
2301 /* Need more header lines */
2302 return;
2303 }
2304
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002305 /* Callback can shut down connection with negative return value */
2306 if (req->header_cb != NULL) {
2307 if ((*req->header_cb)(req, req->cb_arg) < 0) {
2308 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
2309 return;
2310 }
2311 }
Christopher Wileye8679812015-07-01 13:36:18 -07002312
2313 /* Done reading headers, do the real work */
2314 switch (req->kind) {
2315 case EVHTTP_REQUEST:
2316 event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n",
2317 __func__, EV_SOCK_ARG(fd)));
2318 evhttp_get_body(evcon, req);
2319 /* note the request may have been freed in evhttp_get_body */
2320 break;
2321
2322 case EVHTTP_RESPONSE:
2323 /* Start over if we got a 100 Continue response. */
2324 if (req->response_code == 100) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002325 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
2326 evbuffer_add_buffer(output, req->output_buffer);
2327 evhttp_start_write_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07002328 return;
2329 }
2330 if (!evhttp_response_needs_body(req)) {
2331 event_debug(("%s: skipping body for code %d\n",
2332 __func__, req->response_code));
2333 evhttp_connection_done(evcon);
2334 } else {
2335 event_debug(("%s: start of read body for %s on "
2336 EV_SOCK_FMT"\n",
2337 __func__, req->remote_host, EV_SOCK_ARG(fd)));
2338 evhttp_get_body(evcon, req);
2339 /* note the request may have been freed in
2340 * evhttp_get_body */
2341 }
2342 break;
2343
2344 default:
2345 event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
2346 EV_SOCK_ARG(fd));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002347 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002348 break;
2349 }
2350 /* request may have been freed above */
2351}
2352
2353/*
2354 * Creates a TCP connection to the specified port and executes a callback
2355 * when finished. Failure or success is indicate by the passed connection
2356 * object.
2357 *
2358 * Although this interface accepts a hostname, it is intended to take
2359 * only numeric hostnames so that non-blocking DNS resolution can
2360 * happen elsewhere.
2361 */
2362
2363struct evhttp_connection *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002364evhttp_connection_new(const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07002365{
2366 return (evhttp_connection_base_new(NULL, NULL, address, port));
2367}
2368
2369struct evhttp_connection *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002370evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
2371 const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07002372{
2373 struct evhttp_connection *evcon = NULL;
2374
2375 event_debug(("Attempting connection to %s:%d\n", address, port));
2376
2377 if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) {
2378 event_warn("%s: calloc failed", __func__);
2379 goto error;
2380 }
2381
2382 evcon->fd = -1;
2383 evcon->port = port;
2384
2385 evcon->max_headers_size = EV_SIZE_MAX;
2386 evcon->max_body_size = EV_SIZE_MAX;
2387
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002388 evutil_timerclear(&evcon->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07002389 evcon->retry_cnt = evcon->retry_max = 0;
2390
2391 if ((evcon->address = mm_strdup(address)) == NULL) {
2392 event_warn("%s: strdup failed", __func__);
2393 goto error;
2394 }
2395
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002396 if (bev == NULL) {
2397 if (!(bev = bufferevent_socket_new(base, -1, 0))) {
2398 event_warn("%s: bufferevent_socket_new failed", __func__);
2399 goto error;
2400 }
Christopher Wileye8679812015-07-01 13:36:18 -07002401 }
2402
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002403 bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon);
2404 evcon->bufev = bev;
2405
Christopher Wileye8679812015-07-01 13:36:18 -07002406 evcon->state = EVCON_DISCONNECTED;
2407 TAILQ_INIT(&evcon->requests);
2408
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002409 evcon->initial_retry_timeout.tv_sec = 2;
2410 evcon->initial_retry_timeout.tv_usec = 0;
2411
Christopher Wileye8679812015-07-01 13:36:18 -07002412 if (base != NULL) {
2413 evcon->base = base;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002414 if (bufferevent_get_base(bev) != base)
2415 bufferevent_base_set(base, evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07002416 }
2417
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002418 event_deferred_cb_init_(
2419 &evcon->read_more_deferred_cb,
2420 bufferevent_get_priority(bev),
Christopher Wileye8679812015-07-01 13:36:18 -07002421 evhttp_deferred_read_cb, evcon);
2422
2423 evcon->dns_base = dnsbase;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002424 evcon->ai_family = AF_UNSPEC;
Christopher Wileye8679812015-07-01 13:36:18 -07002425
2426 return (evcon);
2427
2428 error:
2429 if (evcon != NULL)
2430 evhttp_connection_free(evcon);
2431 return (NULL);
2432}
2433
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002434struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002435{
2436 return evcon->bufev;
2437}
2438
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002439struct evhttp *
2440evhttp_connection_get_server(struct evhttp_connection *evcon)
2441{
2442 return evcon->http_server;
2443}
2444
2445struct evhttp_connection *
2446evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
2447 const char *address, ev_uint16_t port)
2448{
2449 return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port);
2450}
2451
2452void evhttp_connection_set_family(struct evhttp_connection *evcon,
2453 int family)
2454{
2455 evcon->ai_family = family;
2456}
2457
2458int evhttp_connection_set_flags(struct evhttp_connection *evcon,
2459 int flags)
2460{
2461 int avail_flags = 0;
2462 avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR;
2463 avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR;
2464
2465 if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END)
2466 return 1;
2467 evcon->flags &= ~avail_flags;
2468
2469 evcon->flags |= flags;
2470
2471 return 0;
2472}
2473
Christopher Wileye8679812015-07-01 13:36:18 -07002474void
2475evhttp_connection_set_base(struct evhttp_connection *evcon,
2476 struct event_base *base)
2477{
2478 EVUTIL_ASSERT(evcon->base == NULL);
2479 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
2480 evcon->base = base;
2481 bufferevent_base_set(base, evcon->bufev);
2482}
2483
2484void
2485evhttp_connection_set_timeout(struct evhttp_connection *evcon,
2486 int timeout_in_secs)
2487{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002488 if (timeout_in_secs == -1)
2489 evhttp_connection_set_timeout_tv(evcon, NULL);
2490 else {
2491 struct timeval tv;
2492 tv.tv_sec = timeout_in_secs;
2493 tv.tv_usec = 0;
2494 evhttp_connection_set_timeout_tv(evcon, &tv);
2495 }
2496}
Christopher Wileye8679812015-07-01 13:36:18 -07002497
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002498void
2499evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
2500 const struct timeval* tv)
2501{
2502 if (tv) {
2503 evcon->timeout = *tv;
2504 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
2505 } else {
2506 const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
2507 const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
2508 evutil_timerclear(&evcon->timeout);
2509 bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
2510 }
2511}
2512
2513void
2514evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon,
2515 const struct timeval *tv)
2516{
2517 if (tv) {
2518 evcon->initial_retry_timeout = *tv;
2519 } else {
2520 evutil_timerclear(&evcon->initial_retry_timeout);
2521 evcon->initial_retry_timeout.tv_sec = 2;
2522 }
Christopher Wileye8679812015-07-01 13:36:18 -07002523}
2524
2525void
2526evhttp_connection_set_retries(struct evhttp_connection *evcon,
2527 int retry_max)
2528{
2529 evcon->retry_max = retry_max;
2530}
2531
2532void
2533evhttp_connection_set_closecb(struct evhttp_connection *evcon,
2534 void (*cb)(struct evhttp_connection *, void *), void *cbarg)
2535{
2536 evcon->closecb = cb;
2537 evcon->closecb_arg = cbarg;
2538}
2539
2540void
2541evhttp_connection_get_peer(struct evhttp_connection *evcon,
2542 char **address, ev_uint16_t *port)
2543{
2544 *address = evcon->address;
2545 *port = evcon->port;
2546}
2547
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002548const struct sockaddr*
2549evhttp_connection_get_addr(struct evhttp_connection *evcon)
2550{
2551 return bufferevent_socket_get_conn_address_(evcon->bufev);
2552}
2553
Christopher Wileye8679812015-07-01 13:36:18 -07002554int
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002555evhttp_connection_connect_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002556{
2557 int old_state = evcon->state;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002558 const char *address = evcon->address;
2559 const struct sockaddr *sa = evhttp_connection_get_addr(evcon);
2560 int ret;
Christopher Wileye8679812015-07-01 13:36:18 -07002561
2562 if (evcon->state == EVCON_CONNECTING)
2563 return (0);
2564
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002565 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07002566
2567 EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING));
2568 evcon->flags |= EVHTTP_CON_OUTGOING;
2569
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002570 if (evcon->bind_address || evcon->bind_port) {
2571 evcon->fd = bind_socket(
2572 evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
2573 if (evcon->fd == -1) {
2574 event_debug(("%s: failed to bind to \"%s\"",
2575 __func__, evcon->bind_address));
2576 return (-1);
2577 }
2578
Haibo Huangb2279672019-05-31 16:12:39 -07002579 if (bufferevent_setfd(evcon->bufev, evcon->fd))
2580 return (-1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002581 } else {
Haibo Huangb2279672019-05-31 16:12:39 -07002582 if (bufferevent_setfd(evcon->bufev, -1))
2583 return (-1);
Christopher Wileye8679812015-07-01 13:36:18 -07002584 }
2585
2586 /* Set up a callback for successful connection setup */
Christopher Wileye8679812015-07-01 13:36:18 -07002587 bufferevent_setcb(evcon->bufev,
2588 NULL /* evhttp_read_cb */,
2589 NULL /* evhttp_write_cb */,
2590 evhttp_connection_cb,
2591 evcon);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002592 if (!evutil_timerisset(&evcon->timeout)) {
2593 const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 };
2594 bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv);
2595 } else {
2596 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
2597 }
Christopher Wileye8679812015-07-01 13:36:18 -07002598 /* make sure that we get a write callback */
Haibo Huangb2279672019-05-31 16:12:39 -07002599 if (bufferevent_enable(evcon->bufev, EV_WRITE))
2600 return (-1);
Christopher Wileye8679812015-07-01 13:36:18 -07002601
2602 evcon->state = EVCON_CONNECTING;
2603
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002604 if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR &&
2605 sa &&
2606 (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) {
2607 int socklen = sizeof(struct sockaddr_in);
2608 if (sa->sa_family == AF_INET6) {
2609 socklen = sizeof(struct sockaddr_in6);
2610 }
2611 ret = bufferevent_socket_connect(evcon->bufev, sa, socklen);
2612 } else {
2613 ret = bufferevent_socket_connect_hostname(evcon->bufev,
2614 evcon->dns_base, evcon->ai_family, address, evcon->port);
2615 }
2616
2617 if (ret < 0) {
Christopher Wileye8679812015-07-01 13:36:18 -07002618 evcon->state = old_state;
2619 event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
2620 __func__, evcon->address);
2621 /* some operating systems return ECONNREFUSED immediately
2622 * when connecting to a local address. the cleanup is going
2623 * to reschedule this function call.
2624 */
2625 evhttp_connection_cb_cleanup(evcon);
2626 return (0);
2627 }
2628
2629 return (0);
2630}
2631
2632/*
2633 * Starts an HTTP request on the provided evhttp_connection object.
2634 * If the connection object is not connected to the web server already,
2635 * this will start the connection.
2636 */
2637
2638int
2639evhttp_make_request(struct evhttp_connection *evcon,
2640 struct evhttp_request *req,
2641 enum evhttp_cmd_type type, const char *uri)
2642{
2643 /* We are making a request */
2644 req->kind = EVHTTP_REQUEST;
2645 req->type = type;
2646 if (req->uri != NULL)
2647 mm_free(req->uri);
2648 if ((req->uri = mm_strdup(uri)) == NULL) {
2649 event_warn("%s: strdup", __func__);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002650 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002651 return (-1);
2652 }
2653
2654 /* Set the protocol version if it is not supplied */
2655 if (!req->major && !req->minor) {
2656 req->major = 1;
2657 req->minor = 1;
2658 }
2659
2660 EVUTIL_ASSERT(req->evcon == NULL);
2661 req->evcon = evcon;
2662 EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
2663
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002664 TAILQ_INSERT_TAIL(&evcon->requests, req, next);
Christopher Wileye8679812015-07-01 13:36:18 -07002665
Haibo Huangb2279672019-05-31 16:12:39 -07002666 /* We do not want to conflict with retry_ev */
2667 if (evcon->retry_cnt)
2668 return (0);
2669
Christopher Wileye8679812015-07-01 13:36:18 -07002670 /* If the connection object is not connected; make it so */
2671 if (!evhttp_connected(evcon)) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002672 int res = evhttp_connection_connect_(evcon);
2673 /* evhttp_connection_fail_(), which is called through
2674 * evhttp_connection_connect_(), assumes that req lies in
2675 * evcon->requests. Thus, enqueue the request in advance and
2676 * remove it in the error case. */
2677 if (res != 0)
2678 TAILQ_REMOVE(&evcon->requests, req, next);
Christopher Wileye8679812015-07-01 13:36:18 -07002679
Haibo Huangb2279672019-05-31 16:12:39 -07002680 return (res);
Christopher Wileye8679812015-07-01 13:36:18 -07002681 }
2682
2683 /*
2684 * If it's connected already and we are the first in the queue,
2685 * then we can dispatch this request immediately. Otherwise, it
2686 * will be dispatched once the pending requests are completed.
2687 */
2688 if (TAILQ_FIRST(&evcon->requests) == req)
2689 evhttp_request_dispatch(evcon);
2690
2691 return (0);
2692}
2693
2694void
2695evhttp_cancel_request(struct evhttp_request *req)
2696{
2697 struct evhttp_connection *evcon = req->evcon;
2698 if (evcon != NULL) {
2699 /* We need to remove it from the connection */
2700 if (TAILQ_FIRST(&evcon->requests) == req) {
2701 /* it's currently being worked on, so reset
2702 * the connection.
2703 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002704 evhttp_connection_fail_(evcon,
2705 EVREQ_HTTP_REQUEST_CANCEL);
Christopher Wileye8679812015-07-01 13:36:18 -07002706
2707 /* connection fail freed the request */
2708 return;
2709 } else {
2710 /* otherwise, we can just remove it from the
2711 * queue
2712 */
2713 TAILQ_REMOVE(&evcon->requests, req, next);
2714 }
2715 }
2716
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002717 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002718}
2719
2720/*
2721 * Reads data from file descriptor into request structure
2722 * Request structure needs to be set up correctly.
2723 */
2724
2725void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002726evhttp_start_read_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002727{
Christopher Wileye8679812015-07-01 13:36:18 -07002728 bufferevent_disable(evcon->bufev, EV_WRITE);
2729 bufferevent_enable(evcon->bufev, EV_READ);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002730
Christopher Wileye8679812015-07-01 13:36:18 -07002731 evcon->state = EVCON_READING_FIRSTLINE;
2732 /* Reset the bufferevent callbacks */
2733 bufferevent_setcb(evcon->bufev,
2734 evhttp_read_cb,
2735 evhttp_write_cb,
2736 evhttp_error_cb,
2737 evcon);
2738
2739 /* If there's still data pending, process it next time through the
2740 * loop. Don't do it now; that could get recusive. */
2741 if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002742 event_deferred_cb_schedule_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07002743 &evcon->read_more_deferred_cb);
2744 }
2745}
2746
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002747void
2748evhttp_start_write_(struct evhttp_connection *evcon)
2749{
2750 bufferevent_disable(evcon->bufev, EV_WRITE);
2751 bufferevent_enable(evcon->bufev, EV_READ);
2752
2753 evcon->state = EVCON_WRITING;
2754 evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
2755}
2756
Christopher Wileye8679812015-07-01 13:36:18 -07002757static void
2758evhttp_send_done(struct evhttp_connection *evcon, void *arg)
2759{
2760 int need_close;
2761 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
2762 TAILQ_REMOVE(&evcon->requests, req, next);
2763
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002764 if (req->on_complete_cb != NULL) {
2765 req->on_complete_cb(req, req->on_complete_cb_arg);
2766 }
2767
Christopher Wileye8679812015-07-01 13:36:18 -07002768 need_close =
2769 (REQ_VERSION_BEFORE(req, 1, 1) &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002770 !evhttp_is_connection_keepalive(req->input_headers)) ||
2771 evhttp_is_request_connection_close(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002772
2773 EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION);
2774 evhttp_request_free(req);
2775
2776 if (need_close) {
2777 evhttp_connection_free(evcon);
2778 return;
2779 }
2780
2781 /* we have a persistent connection; try to accept another request. */
2782 if (evhttp_associate_new_request_with_connection(evcon) == -1) {
2783 evhttp_connection_free(evcon);
2784 }
2785}
2786
2787/*
2788 * Returns an error page.
2789 */
2790
2791void
2792evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
2793{
2794
2795#define ERR_FORMAT "<HTML><HEAD>\n" \
2796 "<TITLE>%d %s</TITLE>\n" \
2797 "</HEAD><BODY>\n" \
2798 "<H1>%s</H1>\n" \
2799 "</BODY></HTML>\n"
2800
2801 struct evbuffer *buf = evbuffer_new();
2802 if (buf == NULL) {
2803 /* if we cannot allocate memory; we just drop the connection */
2804 evhttp_connection_free(req->evcon);
2805 return;
2806 }
2807 if (reason == NULL) {
2808 reason = evhttp_response_phrase_internal(error);
2809 }
2810
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002811 evhttp_response_code_(req, error, reason);
Christopher Wileye8679812015-07-01 13:36:18 -07002812
2813 evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason);
2814
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002815 evhttp_send_page_(req, buf);
Christopher Wileye8679812015-07-01 13:36:18 -07002816
2817 evbuffer_free(buf);
2818#undef ERR_FORMAT
2819}
2820
2821/* Requires that headers and response code are already set up */
2822
2823static inline void
2824evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
2825{
2826 struct evhttp_connection *evcon = req->evcon;
2827
2828 if (evcon == NULL) {
2829 evhttp_request_free(req);
2830 return;
2831 }
2832
2833 EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req);
2834
2835 /* we expect no more calls form the user on this request */
2836 req->userdone = 1;
2837
2838 /* xxx: not sure if we really should expose the data buffer this way */
2839 if (databuf != NULL)
2840 evbuffer_add_buffer(req->output_buffer, databuf);
2841
2842 /* Adds headers to the response */
2843 evhttp_make_header(evcon, req);
2844
2845 evhttp_write_buffer(evcon, evhttp_send_done, NULL);
2846}
2847
2848void
2849evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
2850 struct evbuffer *databuf)
2851{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002852 evhttp_response_code_(req, code, reason);
Christopher Wileye8679812015-07-01 13:36:18 -07002853
2854 evhttp_send(req, databuf);
2855}
2856
2857void
2858evhttp_send_reply_start(struct evhttp_request *req, int code,
2859 const char *reason)
2860{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002861 evhttp_response_code_(req, code, reason);
Haibo Huangb2279672019-05-31 16:12:39 -07002862
2863 if (req->evcon == NULL)
2864 return;
2865
Christopher Wileye8679812015-07-01 13:36:18 -07002866 if (evhttp_find_header(req->output_headers, "Content-Length") == NULL &&
2867 REQ_VERSION_ATLEAST(req, 1, 1) &&
2868 evhttp_response_needs_body(req)) {
2869 /*
2870 * prefer HTTP/1.1 chunked encoding to closing the connection;
2871 * note RFC 2616 section 4.4 forbids it with Content-Length:
2872 * and it's not necessary then anyway.
2873 */
2874 evhttp_add_header(req->output_headers, "Transfer-Encoding",
2875 "chunked");
2876 req->chunked = 1;
2877 } else {
2878 req->chunked = 0;
2879 }
2880 evhttp_make_header(req->evcon, req);
2881 evhttp_write_buffer(req->evcon, NULL, NULL);
2882}
2883
2884void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002885evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf,
2886 void (*cb)(struct evhttp_connection *, void *), void *arg)
Christopher Wileye8679812015-07-01 13:36:18 -07002887{
2888 struct evhttp_connection *evcon = req->evcon;
2889 struct evbuffer *output;
2890
2891 if (evcon == NULL)
2892 return;
2893
2894 output = bufferevent_get_output(evcon->bufev);
2895
2896 if (evbuffer_get_length(databuf) == 0)
2897 return;
2898 if (!evhttp_response_needs_body(req))
2899 return;
2900 if (req->chunked) {
2901 evbuffer_add_printf(output, "%x\r\n",
2902 (unsigned)evbuffer_get_length(databuf));
2903 }
2904 evbuffer_add_buffer(output, databuf);
2905 if (req->chunked) {
2906 evbuffer_add(output, "\r\n", 2);
2907 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002908 evhttp_write_buffer(evcon, cb, arg);
Christopher Wileye8679812015-07-01 13:36:18 -07002909}
2910
2911void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002912evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
2913{
2914 evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL);
2915}
2916void
Christopher Wileye8679812015-07-01 13:36:18 -07002917evhttp_send_reply_end(struct evhttp_request *req)
2918{
2919 struct evhttp_connection *evcon = req->evcon;
2920 struct evbuffer *output;
2921
2922 if (evcon == NULL) {
2923 evhttp_request_free(req);
2924 return;
2925 }
2926
2927 output = bufferevent_get_output(evcon->bufev);
2928
2929 /* we expect no more calls form the user on this request */
2930 req->userdone = 1;
2931
2932 if (req->chunked) {
2933 evbuffer_add(output, "0\r\n\r\n", 5);
2934 evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
2935 req->chunked = 0;
2936 } else if (evbuffer_get_length(output) == 0) {
2937 /* let the connection know that we are done with the request */
2938 evhttp_send_done(evcon, NULL);
2939 } else {
2940 /* make the callback execute after all data has been written */
2941 evcon->cb = evhttp_send_done;
2942 evcon->cb_arg = NULL;
2943 }
2944}
2945
2946static const char *informational_phrases[] = {
2947 /* 100 */ "Continue",
2948 /* 101 */ "Switching Protocols"
2949};
2950
2951static const char *success_phrases[] = {
2952 /* 200 */ "OK",
2953 /* 201 */ "Created",
2954 /* 202 */ "Accepted",
2955 /* 203 */ "Non-Authoritative Information",
2956 /* 204 */ "No Content",
2957 /* 205 */ "Reset Content",
2958 /* 206 */ "Partial Content"
2959};
2960
2961static const char *redirection_phrases[] = {
2962 /* 300 */ "Multiple Choices",
2963 /* 301 */ "Moved Permanently",
2964 /* 302 */ "Found",
2965 /* 303 */ "See Other",
2966 /* 304 */ "Not Modified",
2967 /* 305 */ "Use Proxy",
2968 /* 307 */ "Temporary Redirect"
2969};
2970
2971static const char *client_error_phrases[] = {
2972 /* 400 */ "Bad Request",
2973 /* 401 */ "Unauthorized",
2974 /* 402 */ "Payment Required",
2975 /* 403 */ "Forbidden",
2976 /* 404 */ "Not Found",
2977 /* 405 */ "Method Not Allowed",
2978 /* 406 */ "Not Acceptable",
2979 /* 407 */ "Proxy Authentication Required",
2980 /* 408 */ "Request Time-out",
2981 /* 409 */ "Conflict",
2982 /* 410 */ "Gone",
2983 /* 411 */ "Length Required",
2984 /* 412 */ "Precondition Failed",
2985 /* 413 */ "Request Entity Too Large",
2986 /* 414 */ "Request-URI Too Large",
2987 /* 415 */ "Unsupported Media Type",
2988 /* 416 */ "Requested range not satisfiable",
2989 /* 417 */ "Expectation Failed"
2990};
2991
2992static const char *server_error_phrases[] = {
2993 /* 500 */ "Internal Server Error",
2994 /* 501 */ "Not Implemented",
2995 /* 502 */ "Bad Gateway",
2996 /* 503 */ "Service Unavailable",
2997 /* 504 */ "Gateway Time-out",
2998 /* 505 */ "HTTP Version not supported"
2999};
3000
3001struct response_class {
3002 const char *name;
3003 size_t num_responses;
3004 const char **responses;
3005};
3006
3007#ifndef MEMBERSOF
3008#define MEMBERSOF(x) (sizeof(x)/sizeof(x[0]))
3009#endif
3010
3011static const struct response_class response_classes[] = {
3012 /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases },
3013 /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases },
3014 /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases },
3015 /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases },
3016 /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases }
3017};
3018
3019static const char *
3020evhttp_response_phrase_internal(int code)
3021{
3022 int klass = code / 100 - 1;
3023 int subcode = code % 100;
3024
3025 /* Unknown class - can't do any better here */
3026 if (klass < 0 || klass >= (int) MEMBERSOF(response_classes))
3027 return "Unknown Status Class";
3028
3029 /* Unknown sub-code, return class name at least */
3030 if (subcode >= (int) response_classes[klass].num_responses)
3031 return response_classes[klass].name;
3032
3033 return response_classes[klass].responses[subcode];
3034}
3035
3036void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003037evhttp_response_code_(struct evhttp_request *req, int code, const char *reason)
Christopher Wileye8679812015-07-01 13:36:18 -07003038{
3039 req->kind = EVHTTP_RESPONSE;
3040 req->response_code = code;
3041 if (req->response_code_line != NULL)
3042 mm_free(req->response_code_line);
3043 if (reason == NULL)
3044 reason = evhttp_response_phrase_internal(code);
3045 req->response_code_line = mm_strdup(reason);
3046 if (req->response_code_line == NULL) {
3047 event_warn("%s: strdup", __func__);
3048 /* XXX what else can we do? */
3049 }
3050}
3051
3052void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003053evhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf)
Christopher Wileye8679812015-07-01 13:36:18 -07003054{
3055 if (!req->major || !req->minor) {
3056 req->major = 1;
3057 req->minor = 1;
3058 }
3059
3060 if (req->kind != EVHTTP_RESPONSE)
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003061 evhttp_response_code_(req, 200, "OK");
Christopher Wileye8679812015-07-01 13:36:18 -07003062
3063 evhttp_clear_headers(req->output_headers);
3064 evhttp_add_header(req->output_headers, "Content-Type", "text/html");
3065 evhttp_add_header(req->output_headers, "Connection", "close");
3066
3067 evhttp_send(req, databuf);
3068}
3069
3070static const char uri_chars[256] = {
3071 /* 0 */
3072 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3073 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3074 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
3075 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
3076 /* 64 */
3077 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3078 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
3079 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3080 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
3081 /* 128 */
3082 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3083 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3084 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3085 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3086 /* 192 */
3087 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3088 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3089 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3090 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3091};
3092
3093#define CHAR_IS_UNRESERVED(c) \
3094 (uri_chars[(unsigned char)(c)])
3095
3096/*
3097 * Helper functions to encode/decode a string for inclusion in a URI.
3098 * The returned string must be freed by the caller.
3099 */
3100char *
3101evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus)
3102{
3103 struct evbuffer *buf = evbuffer_new();
3104 const char *p, *end;
Haibo Huangb2279672019-05-31 16:12:39 -07003105 char *result = NULL;
Christopher Wileye8679812015-07-01 13:36:18 -07003106
Haibo Huangb2279672019-05-31 16:12:39 -07003107 if (!buf) {
3108 goto out;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003109 }
Christopher Wileye8679812015-07-01 13:36:18 -07003110
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003111 if (len >= 0) {
3112 if (uri + len < uri) {
Haibo Huangb2279672019-05-31 16:12:39 -07003113 goto out;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003114 }
3115
3116 end = uri + len;
3117 } else {
3118 size_t slen = strlen(uri);
3119
3120 if (slen >= EV_SSIZE_MAX) {
3121 /* we don't want to mix signed and unsigned */
Haibo Huangb2279672019-05-31 16:12:39 -07003122 goto out;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003123 }
3124
3125 if (uri + slen < uri) {
Haibo Huangb2279672019-05-31 16:12:39 -07003126 goto out;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003127 }
3128
3129 end = uri + slen;
3130 }
Christopher Wileye8679812015-07-01 13:36:18 -07003131
3132 for (p = uri; p < end; p++) {
3133 if (CHAR_IS_UNRESERVED(*p)) {
3134 evbuffer_add(buf, p, 1);
3135 } else if (*p == ' ' && space_as_plus) {
3136 evbuffer_add(buf, "+", 1);
3137 } else {
3138 evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p));
3139 }
3140 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003141
Christopher Wileye8679812015-07-01 13:36:18 -07003142 evbuffer_add(buf, "", 1); /* NUL-terminator. */
3143 result = mm_malloc(evbuffer_get_length(buf));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003144
Christopher Wileye8679812015-07-01 13:36:18 -07003145 if (result)
3146 evbuffer_remove(buf, result, evbuffer_get_length(buf));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003147
Haibo Huangb2279672019-05-31 16:12:39 -07003148out:
3149 if (buf)
3150 evbuffer_free(buf);
3151 return result;
Christopher Wileye8679812015-07-01 13:36:18 -07003152}
3153
3154char *
3155evhttp_encode_uri(const char *str)
3156{
3157 return evhttp_uriencode(str, -1, 0);
3158}
3159
3160/*
3161 * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't.
3162 * If -1, when true we transform plus to space only after we've seen
3163 * a ?. -1 is deprecated.
3164 * @return the number of bytes written to 'ret'.
3165 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003166int
Christopher Wileye8679812015-07-01 13:36:18 -07003167evhttp_decode_uri_internal(
3168 const char *uri, size_t length, char *ret, int decode_plus_ctl)
3169{
3170 char c;
3171 int j;
3172 int decode_plus = (decode_plus_ctl == 1) ? 1: 0;
3173 unsigned i;
3174
3175 for (i = j = 0; i < length; i++) {
3176 c = uri[i];
3177 if (c == '?') {
3178 if (decode_plus_ctl < 0)
3179 decode_plus = 1;
3180 } else if (c == '+' && decode_plus) {
3181 c = ' ';
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003182 } else if ((i + 2) < length && c == '%' &&
3183 EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) {
Christopher Wileye8679812015-07-01 13:36:18 -07003184 char tmp[3];
3185 tmp[0] = uri[i+1];
3186 tmp[1] = uri[i+2];
3187 tmp[2] = '\0';
3188 c = (char)strtol(tmp, NULL, 16);
3189 i += 2;
3190 }
3191 ret[j++] = c;
3192 }
3193 ret[j] = '\0';
3194
3195 return (j);
3196}
3197
3198/* deprecated */
3199char *
3200evhttp_decode_uri(const char *uri)
3201{
3202 char *ret;
3203
3204 if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
3205 event_warn("%s: malloc(%lu)", __func__,
3206 (unsigned long)(strlen(uri) + 1));
3207 return (NULL);
3208 }
3209
3210 evhttp_decode_uri_internal(uri, strlen(uri),
3211 ret, -1 /*always_decode_plus*/);
3212
3213 return (ret);
3214}
3215
3216char *
3217evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out)
3218{
3219 char *ret;
3220 int n;
3221
3222 if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
3223 event_warn("%s: malloc(%lu)", __func__,
3224 (unsigned long)(strlen(uri) + 1));
3225 return (NULL);
3226 }
3227
3228 n = evhttp_decode_uri_internal(uri, strlen(uri),
3229 ret, !!decode_plus/*always_decode_plus*/);
3230
3231 if (size_out) {
3232 EVUTIL_ASSERT(n >= 0);
3233 *size_out = (size_t)n;
3234 }
3235
3236 return (ret);
3237}
3238
3239/*
3240 * Helper function to parse out arguments in a query.
3241 * The arguments are separated by key and value.
3242 */
3243
3244static int
3245evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
3246 int is_whole_uri)
3247{
3248 char *line=NULL;
3249 char *argument;
3250 char *p;
3251 const char *query_part;
3252 int result = -1;
3253 struct evhttp_uri *uri=NULL;
3254
3255 TAILQ_INIT(headers);
3256
3257 if (is_whole_uri) {
3258 uri = evhttp_uri_parse(str);
3259 if (!uri)
3260 goto error;
3261 query_part = evhttp_uri_get_query(uri);
3262 } else {
3263 query_part = str;
3264 }
3265
3266 /* No arguments - we are done */
3267 if (!query_part || !strlen(query_part)) {
3268 result = 0;
3269 goto done;
3270 }
3271
3272 if ((line = mm_strdup(query_part)) == NULL) {
3273 event_warn("%s: strdup", __func__);
3274 goto error;
3275 }
3276
3277 p = argument = line;
3278 while (p != NULL && *p != '\0') {
3279 char *key, *value, *decoded_value;
3280 argument = strsep(&p, "&");
3281
3282 value = argument;
3283 key = strsep(&value, "=");
3284 if (value == NULL || *key == '\0') {
3285 goto error;
3286 }
3287
3288 if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) {
3289 event_warn("%s: mm_malloc", __func__);
3290 goto error;
3291 }
3292 evhttp_decode_uri_internal(value, strlen(value),
3293 decoded_value, 1 /*always_decode_plus*/);
3294 event_debug(("Query Param: %s -> %s\n", key, decoded_value));
3295 evhttp_add_header_internal(headers, key, decoded_value);
3296 mm_free(decoded_value);
3297 }
3298
3299 result = 0;
3300 goto done;
3301error:
3302 evhttp_clear_headers(headers);
3303done:
3304 if (line)
3305 mm_free(line);
3306 if (uri)
3307 evhttp_uri_free(uri);
3308 return result;
3309}
3310
3311int
3312evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
3313{
3314 return evhttp_parse_query_impl(uri, headers, 1);
3315}
3316int
3317evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers)
3318{
3319 return evhttp_parse_query_impl(uri, headers, 0);
3320}
3321
3322static struct evhttp_cb *
3323evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
3324{
3325 struct evhttp_cb *cb;
3326 size_t offset = 0;
3327 char *translated;
3328 const char *path;
3329
3330 /* Test for different URLs */
3331 path = evhttp_uri_get_path(req->uri_elems);
3332 offset = strlen(path);
3333 if ((translated = mm_malloc(offset + 1)) == NULL)
3334 return (NULL);
3335 evhttp_decode_uri_internal(path, offset, translated,
3336 0 /* decode_plus */);
3337
3338 TAILQ_FOREACH(cb, callbacks, next) {
3339 if (!strcmp(cb->what, translated)) {
3340 mm_free(translated);
3341 return (cb);
3342 }
3343 }
3344
3345 mm_free(translated);
3346 return (NULL);
3347}
3348
3349
3350static int
3351prefix_suffix_match(const char *pattern, const char *name, int ignorecase)
3352{
3353 char c;
3354
3355 while (1) {
3356 switch (c = *pattern++) {
3357 case '\0':
3358 return *name == '\0';
3359
3360 case '*':
3361 while (*name != '\0') {
3362 if (prefix_suffix_match(pattern, name,
3363 ignorecase))
3364 return (1);
3365 ++name;
3366 }
3367 return (0);
3368 default:
3369 if (c != *name) {
3370 if (!ignorecase ||
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003371 EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name))
Christopher Wileye8679812015-07-01 13:36:18 -07003372 return (0);
3373 }
3374 ++name;
3375 }
3376 }
3377 /* NOTREACHED */
3378}
3379
3380/*
3381 Search the vhost hierarchy beginning with http for a server alias
3382 matching hostname. If a match is found, and outhttp is non-null,
3383 outhttp is set to the matching http object and 1 is returned.
3384*/
3385
3386static int
3387evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp,
3388 const char *hostname)
3389{
3390 struct evhttp_server_alias *alias;
3391 struct evhttp *vhost;
3392
3393 TAILQ_FOREACH(alias, &http->aliases, next) {
3394 /* XXX Do we need to handle IP addresses? */
3395 if (!evutil_ascii_strcasecmp(alias->alias, hostname)) {
3396 if (outhttp)
3397 *outhttp = http;
3398 return 1;
3399 }
3400 }
3401
3402 /* XXX It might be good to avoid recursion here, but I don't
3403 see a way to do that w/o a list. */
3404 TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
3405 if (evhttp_find_alias(vhost, outhttp, hostname))
3406 return 1;
3407 }
3408
3409 return 0;
3410}
3411
3412/*
3413 Attempts to find the best http object to handle a request for a hostname.
3414 All aliases for the root http object and vhosts are searched for an exact
3415 match. Then, the vhost hierarchy is traversed again for a matching
3416 pattern.
3417
3418 If an alias or vhost is matched, 1 is returned, and outhttp, if non-null,
3419 is set with the best matching http object. If there are no matches, the
3420 root http object is stored in outhttp and 0 is returned.
3421*/
3422
3423static int
3424evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
3425 const char *hostname)
3426{
3427 struct evhttp *vhost;
3428 struct evhttp *oldhttp;
3429 int match_found = 0;
3430
3431 if (evhttp_find_alias(http, outhttp, hostname))
3432 return 1;
3433
3434 do {
3435 oldhttp = http;
3436 TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
3437 if (prefix_suffix_match(vhost->vhost_pattern,
3438 hostname, 1 /* ignorecase */)) {
3439 http = vhost;
3440 match_found = 1;
3441 break;
3442 }
3443 }
3444 } while (oldhttp != http);
3445
3446 if (outhttp)
3447 *outhttp = http;
3448
3449 return match_found;
3450}
3451
3452static void
3453evhttp_handle_request(struct evhttp_request *req, void *arg)
3454{
3455 struct evhttp *http = arg;
3456 struct evhttp_cb *cb = NULL;
3457 const char *hostname;
3458
3459 /* we have a new request on which the user needs to take action */
3460 req->userdone = 0;
3461
Haibo Huangb2279672019-05-31 16:12:39 -07003462 bufferevent_disable(req->evcon->bufev, EV_READ);
3463
Christopher Wileye8679812015-07-01 13:36:18 -07003464 if (req->type == 0 || req->uri == NULL) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003465 evhttp_send_error(req, req->response_code, NULL);
Christopher Wileye8679812015-07-01 13:36:18 -07003466 return;
3467 }
3468
3469 if ((http->allowed_methods & req->type) == 0) {
3470 event_debug(("Rejecting disallowed method %x (allowed: %x)\n",
3471 (unsigned)req->type, (unsigned)http->allowed_methods));
3472 evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL);
3473 return;
3474 }
3475
3476 /* handle potential virtual hosts */
3477 hostname = evhttp_request_get_host(req);
3478 if (hostname != NULL) {
3479 evhttp_find_vhost(http, &http, hostname);
3480 }
3481
3482 if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
3483 (*cb->cb)(req, cb->cbarg);
3484 return;
3485 }
3486
3487 /* Generic call back */
3488 if (http->gencb) {
3489 (*http->gencb)(req, http->gencbarg);
3490 return;
3491 } else {
3492 /* We need to send a 404 here */
3493#define ERR_FORMAT "<html><head>" \
3494 "<title>404 Not Found</title>" \
3495 "</head><body>" \
3496 "<h1>Not Found</h1>" \
3497 "<p>The requested URL %s was not found on this server.</p>"\
3498 "</body></html>\n"
3499
3500 char *escaped_html;
3501 struct evbuffer *buf;
3502
3503 if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) {
3504 evhttp_connection_free(req->evcon);
3505 return;
3506 }
3507
3508 if ((buf = evbuffer_new()) == NULL) {
3509 mm_free(escaped_html);
3510 evhttp_connection_free(req->evcon);
3511 return;
3512 }
3513
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003514 evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found");
Christopher Wileye8679812015-07-01 13:36:18 -07003515
3516 evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
3517
3518 mm_free(escaped_html);
3519
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003520 evhttp_send_page_(req, buf);
Christopher Wileye8679812015-07-01 13:36:18 -07003521
3522 evbuffer_free(buf);
3523#undef ERR_FORMAT
3524 }
3525}
3526
3527/* Listener callback when a connection arrives at a server. */
3528static void
3529accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg)
3530{
3531 struct evhttp *http = arg;
3532
3533 evhttp_get_request(http, nfd, peer_sa, peer_socklen);
3534}
3535
3536int
3537evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port)
3538{
3539 struct evhttp_bound_socket *bound =
3540 evhttp_bind_socket_with_handle(http, address, port);
3541 if (bound == NULL)
3542 return (-1);
3543 return (0);
3544}
3545
3546struct evhttp_bound_socket *
3547evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port)
3548{
3549 evutil_socket_t fd;
3550 struct evhttp_bound_socket *bound;
Haibo Huangb2279672019-05-31 16:12:39 -07003551 int serrno;
Christopher Wileye8679812015-07-01 13:36:18 -07003552
3553 if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
3554 return (NULL);
3555
3556 if (listen(fd, 128) == -1) {
Haibo Huangb2279672019-05-31 16:12:39 -07003557 serrno = EVUTIL_SOCKET_ERROR();
Christopher Wileye8679812015-07-01 13:36:18 -07003558 event_sock_warn(fd, "%s: listen", __func__);
3559 evutil_closesocket(fd);
Haibo Huangb2279672019-05-31 16:12:39 -07003560 EVUTIL_SET_SOCKET_ERROR(serrno);
Christopher Wileye8679812015-07-01 13:36:18 -07003561 return (NULL);
3562 }
3563
3564 bound = evhttp_accept_socket_with_handle(http, fd);
3565
3566 if (bound != NULL) {
3567 event_debug(("Bound to port %d - Awaiting connections ... ",
3568 port));
3569 return (bound);
3570 }
3571
3572 return (NULL);
3573}
3574
3575int
3576evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)
3577{
3578 struct evhttp_bound_socket *bound =
3579 evhttp_accept_socket_with_handle(http, fd);
3580 if (bound == NULL)
3581 return (-1);
3582 return (0);
3583}
3584
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003585void
3586evhttp_foreach_bound_socket(struct evhttp *http,
3587 evhttp_bound_socket_foreach_fn *function,
3588 void *argument)
3589{
3590 struct evhttp_bound_socket *bound;
3591
3592 TAILQ_FOREACH(bound, &http->sockets, next)
3593 function(bound, argument);
3594}
Christopher Wileye8679812015-07-01 13:36:18 -07003595
3596struct evhttp_bound_socket *
3597evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd)
3598{
3599 struct evhttp_bound_socket *bound;
3600 struct evconnlistener *listener;
3601 const int flags =
3602 LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE;
3603
3604 listener = evconnlistener_new(http->base, NULL, NULL,
3605 flags,
3606 0, /* Backlog is '0' because we already said 'listen' */
3607 fd);
3608 if (!listener)
3609 return (NULL);
3610
3611 bound = evhttp_bind_listener(http, listener);
3612 if (!bound) {
3613 evconnlistener_free(listener);
3614 return (NULL);
3615 }
3616 return (bound);
3617}
3618
3619struct evhttp_bound_socket *
3620evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener)
3621{
3622 struct evhttp_bound_socket *bound;
3623
3624 bound = mm_malloc(sizeof(struct evhttp_bound_socket));
3625 if (bound == NULL)
3626 return (NULL);
3627
3628 bound->listener = listener;
3629 TAILQ_INSERT_TAIL(&http->sockets, bound, next);
3630
3631 evconnlistener_set_cb(listener, accept_socket_cb, http);
3632 return bound;
3633}
3634
3635evutil_socket_t
3636evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound)
3637{
3638 return evconnlistener_get_fd(bound->listener);
3639}
3640
3641struct evconnlistener *
3642evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
3643{
3644 return bound->listener;
3645}
3646
3647void
3648evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound)
3649{
3650 TAILQ_REMOVE(&http->sockets, bound, next);
3651 evconnlistener_free(bound->listener);
3652 mm_free(bound);
3653}
3654
3655static struct evhttp*
3656evhttp_new_object(void)
3657{
3658 struct evhttp *http = NULL;
3659
3660 if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) {
3661 event_warn("%s: calloc", __func__);
3662 return (NULL);
3663 }
3664
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003665 evutil_timerclear(&http->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07003666 evhttp_set_max_headers_size(http, EV_SIZE_MAX);
3667 evhttp_set_max_body_size(http, EV_SIZE_MAX);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003668 evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1");
Christopher Wileye8679812015-07-01 13:36:18 -07003669 evhttp_set_allowed_methods(http,
3670 EVHTTP_REQ_GET |
3671 EVHTTP_REQ_POST |
3672 EVHTTP_REQ_HEAD |
3673 EVHTTP_REQ_PUT |
3674 EVHTTP_REQ_DELETE);
3675
3676 TAILQ_INIT(&http->sockets);
3677 TAILQ_INIT(&http->callbacks);
3678 TAILQ_INIT(&http->connections);
3679 TAILQ_INIT(&http->virtualhosts);
3680 TAILQ_INIT(&http->aliases);
3681
3682 return (http);
3683}
3684
3685struct evhttp *
3686evhttp_new(struct event_base *base)
3687{
3688 struct evhttp *http = NULL;
3689
3690 http = evhttp_new_object();
3691 if (http == NULL)
3692 return (NULL);
3693 http->base = base;
3694
3695 return (http);
3696}
3697
3698/*
3699 * Start a web server on the specified address and port.
3700 */
3701
3702struct evhttp *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003703evhttp_start(const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07003704{
3705 struct evhttp *http = NULL;
3706
3707 http = evhttp_new_object();
3708 if (http == NULL)
3709 return (NULL);
3710 if (evhttp_bind_socket(http, address, port) == -1) {
3711 mm_free(http);
3712 return (NULL);
3713 }
3714
3715 return (http);
3716}
3717
3718void
3719evhttp_free(struct evhttp* http)
3720{
3721 struct evhttp_cb *http_cb;
3722 struct evhttp_connection *evcon;
3723 struct evhttp_bound_socket *bound;
3724 struct evhttp* vhost;
3725 struct evhttp_server_alias *alias;
3726
3727 /* Remove the accepting part */
3728 while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
3729 TAILQ_REMOVE(&http->sockets, bound, next);
3730
3731 evconnlistener_free(bound->listener);
3732
3733 mm_free(bound);
3734 }
3735
3736 while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
3737 /* evhttp_connection_free removes the connection */
3738 evhttp_connection_free(evcon);
3739 }
3740
3741 while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
3742 TAILQ_REMOVE(&http->callbacks, http_cb, next);
3743 mm_free(http_cb->what);
3744 mm_free(http_cb);
3745 }
3746
3747 while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) {
3748 TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
3749
3750 evhttp_free(vhost);
3751 }
3752
3753 if (http->vhost_pattern != NULL)
3754 mm_free(http->vhost_pattern);
3755
3756 while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) {
3757 TAILQ_REMOVE(&http->aliases, alias, next);
3758 mm_free(alias->alias);
3759 mm_free(alias);
3760 }
3761
3762 mm_free(http);
3763}
3764
3765int
3766evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
3767 struct evhttp* vhost)
3768{
3769 /* a vhost can only be a vhost once and should not have bound sockets */
3770 if (vhost->vhost_pattern != NULL ||
3771 TAILQ_FIRST(&vhost->sockets) != NULL)
3772 return (-1);
3773
3774 vhost->vhost_pattern = mm_strdup(pattern);
3775 if (vhost->vhost_pattern == NULL)
3776 return (-1);
3777
3778 TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost);
3779
3780 return (0);
3781}
3782
3783int
3784evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost)
3785{
3786 if (vhost->vhost_pattern == NULL)
3787 return (-1);
3788
3789 TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
3790
3791 mm_free(vhost->vhost_pattern);
3792 vhost->vhost_pattern = NULL;
3793
3794 return (0);
3795}
3796
3797int
3798evhttp_add_server_alias(struct evhttp *http, const char *alias)
3799{
3800 struct evhttp_server_alias *evalias;
3801
3802 evalias = mm_calloc(1, sizeof(*evalias));
3803 if (!evalias)
3804 return -1;
3805
3806 evalias->alias = mm_strdup(alias);
3807 if (!evalias->alias) {
3808 mm_free(evalias);
3809 return -1;
3810 }
3811
3812 TAILQ_INSERT_TAIL(&http->aliases, evalias, next);
3813
3814 return 0;
3815}
3816
3817int
3818evhttp_remove_server_alias(struct evhttp *http, const char *alias)
3819{
3820 struct evhttp_server_alias *evalias;
3821
3822 TAILQ_FOREACH(evalias, &http->aliases, next) {
3823 if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) {
3824 TAILQ_REMOVE(&http->aliases, evalias, next);
3825 mm_free(evalias->alias);
3826 mm_free(evalias);
3827 return 0;
3828 }
3829 }
3830
3831 return -1;
3832}
3833
3834void
3835evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
3836{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003837 if (timeout_in_secs == -1) {
3838 evhttp_set_timeout_tv(http, NULL);
3839 } else {
3840 struct timeval tv;
3841 tv.tv_sec = timeout_in_secs;
3842 tv.tv_usec = 0;
3843 evhttp_set_timeout_tv(http, &tv);
3844 }
3845}
3846
3847void
3848evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
3849{
3850 if (tv) {
3851 http->timeout = *tv;
3852 } else {
3853 evutil_timerclear(&http->timeout);
3854 }
3855}
3856
3857int evhttp_set_flags(struct evhttp *http, int flags)
3858{
3859 int avail_flags = 0;
3860 avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE;
3861
3862 if (flags & ~avail_flags)
3863 return 1;
3864 http->flags &= ~avail_flags;
3865
3866 http->flags |= flags;
3867
3868 return 0;
Christopher Wileye8679812015-07-01 13:36:18 -07003869}
3870
3871void
3872evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size)
3873{
3874 if (max_headers_size < 0)
3875 http->default_max_headers_size = EV_SIZE_MAX;
3876 else
3877 http->default_max_headers_size = max_headers_size;
3878}
3879
3880void
3881evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size)
3882{
3883 if (max_body_size < 0)
3884 http->default_max_body_size = EV_UINT64_MAX;
3885 else
3886 http->default_max_body_size = max_body_size;
3887}
3888
3889void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003890evhttp_set_default_content_type(struct evhttp *http,
3891 const char *content_type) {
3892 http->default_content_type = content_type;
3893}
3894
3895void
Christopher Wileye8679812015-07-01 13:36:18 -07003896evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods)
3897{
3898 http->allowed_methods = methods;
3899}
3900
3901int
3902evhttp_set_cb(struct evhttp *http, const char *uri,
3903 void (*cb)(struct evhttp_request *, void *), void *cbarg)
3904{
3905 struct evhttp_cb *http_cb;
3906
3907 TAILQ_FOREACH(http_cb, &http->callbacks, next) {
3908 if (strcmp(http_cb->what, uri) == 0)
3909 return (-1);
3910 }
3911
3912 if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) {
3913 event_warn("%s: calloc", __func__);
3914 return (-2);
3915 }
3916
3917 http_cb->what = mm_strdup(uri);
3918 if (http_cb->what == NULL) {
3919 event_warn("%s: strdup", __func__);
3920 mm_free(http_cb);
3921 return (-3);
3922 }
3923 http_cb->cb = cb;
3924 http_cb->cbarg = cbarg;
3925
3926 TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
3927
3928 return (0);
3929}
3930
3931int
3932evhttp_del_cb(struct evhttp *http, const char *uri)
3933{
3934 struct evhttp_cb *http_cb;
3935
3936 TAILQ_FOREACH(http_cb, &http->callbacks, next) {
3937 if (strcmp(http_cb->what, uri) == 0)
3938 break;
3939 }
3940 if (http_cb == NULL)
3941 return (-1);
3942
3943 TAILQ_REMOVE(&http->callbacks, http_cb, next);
3944 mm_free(http_cb->what);
3945 mm_free(http_cb);
3946
3947 return (0);
3948}
3949
3950void
3951evhttp_set_gencb(struct evhttp *http,
3952 void (*cb)(struct evhttp_request *, void *), void *cbarg)
3953{
3954 http->gencb = cb;
3955 http->gencbarg = cbarg;
3956}
3957
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003958void
3959evhttp_set_bevcb(struct evhttp *http,
3960 struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg)
3961{
3962 http->bevcb = cb;
3963 http->bevcbarg = cbarg;
3964}
3965
Christopher Wileye8679812015-07-01 13:36:18 -07003966/*
3967 * Request related functions
3968 */
3969
3970struct evhttp_request *
3971evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
3972{
3973 struct evhttp_request *req = NULL;
3974
3975 /* Allocate request structure */
3976 if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) {
3977 event_warn("%s: calloc", __func__);
3978 goto error;
3979 }
3980
3981 req->headers_size = 0;
3982 req->body_size = 0;
3983
3984 req->kind = EVHTTP_RESPONSE;
3985 req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq));
3986 if (req->input_headers == NULL) {
3987 event_warn("%s: calloc", __func__);
3988 goto error;
3989 }
3990 TAILQ_INIT(req->input_headers);
3991
3992 req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq));
3993 if (req->output_headers == NULL) {
3994 event_warn("%s: calloc", __func__);
3995 goto error;
3996 }
3997 TAILQ_INIT(req->output_headers);
3998
3999 if ((req->input_buffer = evbuffer_new()) == NULL) {
4000 event_warn("%s: evbuffer_new", __func__);
4001 goto error;
4002 }
4003
4004 if ((req->output_buffer = evbuffer_new()) == NULL) {
4005 event_warn("%s: evbuffer_new", __func__);
4006 goto error;
4007 }
4008
4009 req->cb = cb;
4010 req->cb_arg = arg;
4011
4012 return (req);
4013
4014 error:
4015 if (req != NULL)
4016 evhttp_request_free(req);
4017 return (NULL);
4018}
4019
4020void
4021evhttp_request_free(struct evhttp_request *req)
4022{
4023 if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) {
4024 req->flags |= EVHTTP_REQ_NEEDS_FREE;
4025 return;
4026 }
4027
4028 if (req->remote_host != NULL)
4029 mm_free(req->remote_host);
4030 if (req->uri != NULL)
4031 mm_free(req->uri);
4032 if (req->uri_elems != NULL)
4033 evhttp_uri_free(req->uri_elems);
4034 if (req->response_code_line != NULL)
4035 mm_free(req->response_code_line);
4036 if (req->host_cache != NULL)
4037 mm_free(req->host_cache);
4038
4039 evhttp_clear_headers(req->input_headers);
4040 mm_free(req->input_headers);
4041
4042 evhttp_clear_headers(req->output_headers);
4043 mm_free(req->output_headers);
4044
4045 if (req->input_buffer != NULL)
4046 evbuffer_free(req->input_buffer);
4047
4048 if (req->output_buffer != NULL)
4049 evbuffer_free(req->output_buffer);
4050
4051 mm_free(req);
4052}
4053
4054void
4055evhttp_request_own(struct evhttp_request *req)
4056{
4057 req->flags |= EVHTTP_USER_OWNED;
4058}
4059
4060int
4061evhttp_request_is_owned(struct evhttp_request *req)
4062{
4063 return (req->flags & EVHTTP_USER_OWNED) != 0;
4064}
4065
4066struct evhttp_connection *
4067evhttp_request_get_connection(struct evhttp_request *req)
4068{
4069 return req->evcon;
4070}
4071
4072struct event_base *
4073evhttp_connection_get_base(struct evhttp_connection *conn)
4074{
4075 return conn->base;
4076}
4077
4078void
4079evhttp_request_set_chunked_cb(struct evhttp_request *req,
4080 void (*cb)(struct evhttp_request *, void *))
4081{
4082 req->chunk_cb = cb;
4083}
4084
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004085void
4086evhttp_request_set_header_cb(struct evhttp_request *req,
4087 int (*cb)(struct evhttp_request *, void *))
4088{
4089 req->header_cb = cb;
4090}
4091
4092void
4093evhttp_request_set_error_cb(struct evhttp_request *req,
4094 void (*cb)(enum evhttp_request_error, void *))
4095{
4096 req->error_cb = cb;
4097}
4098
4099void
4100evhttp_request_set_on_complete_cb(struct evhttp_request *req,
4101 void (*cb)(struct evhttp_request *, void *), void *cb_arg)
4102{
4103 req->on_complete_cb = cb;
4104 req->on_complete_cb_arg = cb_arg;
4105}
4106
Christopher Wileye8679812015-07-01 13:36:18 -07004107/*
4108 * Allows for inspection of the request URI
4109 */
4110
4111const char *
4112evhttp_request_get_uri(const struct evhttp_request *req) {
4113 if (req->uri == NULL)
4114 event_debug(("%s: request %p has no uri\n", __func__, req));
4115 return (req->uri);
4116}
4117
4118const struct evhttp_uri *
4119evhttp_request_get_evhttp_uri(const struct evhttp_request *req) {
4120 if (req->uri_elems == NULL)
4121 event_debug(("%s: request %p has no uri elems\n",
4122 __func__, req));
4123 return (req->uri_elems);
4124}
4125
4126const char *
4127evhttp_request_get_host(struct evhttp_request *req)
4128{
4129 const char *host = NULL;
4130
4131 if (req->host_cache)
4132 return req->host_cache;
4133
4134 if (req->uri_elems)
4135 host = evhttp_uri_get_host(req->uri_elems);
4136 if (!host && req->input_headers) {
4137 const char *p;
4138 size_t len;
4139
4140 host = evhttp_find_header(req->input_headers, "Host");
4141 /* The Host: header may include a port. Remove it here
4142 to be consistent with uri_elems case above. */
4143 if (host) {
4144 p = host + strlen(host) - 1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004145 while (p > host && EVUTIL_ISDIGIT_(*p))
Christopher Wileye8679812015-07-01 13:36:18 -07004146 --p;
4147 if (p > host && *p == ':') {
4148 len = p - host;
4149 req->host_cache = mm_malloc(len + 1);
4150 if (!req->host_cache) {
4151 event_warn("%s: malloc", __func__);
4152 return NULL;
4153 }
4154 memcpy(req->host_cache, host, len);
4155 req->host_cache[len] = '\0';
4156 host = req->host_cache;
4157 }
4158 }
4159 }
4160
4161 return host;
4162}
4163
4164enum evhttp_cmd_type
4165evhttp_request_get_command(const struct evhttp_request *req) {
4166 return (req->type);
4167}
4168
4169int
4170evhttp_request_get_response_code(const struct evhttp_request *req)
4171{
4172 return req->response_code;
4173}
4174
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004175const char *
4176evhttp_request_get_response_code_line(const struct evhttp_request *req)
4177{
4178 return req->response_code_line;
4179}
4180
Christopher Wileye8679812015-07-01 13:36:18 -07004181/** Returns the input headers */
4182struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req)
4183{
4184 return (req->input_headers);
4185}
4186
4187/** Returns the output headers */
4188struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req)
4189{
4190 return (req->output_headers);
4191}
4192
4193/** Returns the input buffer */
4194struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req)
4195{
4196 return (req->input_buffer);
4197}
4198
4199/** Returns the output buffer */
4200struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req)
4201{
4202 return (req->output_buffer);
4203}
4204
4205
4206/*
4207 * Takes a file descriptor to read a request from.
4208 * The callback is executed once the whole request has been read.
4209 */
4210
4211static struct evhttp_connection*
4212evhttp_get_request_connection(
4213 struct evhttp* http,
4214 evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen)
4215{
4216 struct evhttp_connection *evcon;
4217 char *hostname = NULL, *portname = NULL;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004218 struct bufferevent* bev = NULL;
Christopher Wileye8679812015-07-01 13:36:18 -07004219
Haibo Huangb2279672019-05-31 16:12:39 -07004220#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
4221 if (sa->sa_family == AF_UNIX) {
4222 struct sockaddr_un *sa_un = (struct sockaddr_un *)sa;
4223 sa_un->sun_path[0] = '\0';
4224 }
4225#endif
4226
Christopher Wileye8679812015-07-01 13:36:18 -07004227 name_from_addr(sa, salen, &hostname, &portname);
4228 if (hostname == NULL || portname == NULL) {
4229 if (hostname) mm_free(hostname);
4230 if (portname) mm_free(portname);
4231 return (NULL);
4232 }
4233
4234 event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
4235 __func__, hostname, portname, EV_SOCK_ARG(fd)));
4236
4237 /* we need a connection object to put the http request on */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004238 if (http->bevcb != NULL) {
4239 bev = (*http->bevcb)(http->base, http->bevcbarg);
4240 }
4241 evcon = evhttp_connection_base_bufferevent_new(
4242 http->base, NULL, bev, hostname, atoi(portname));
Christopher Wileye8679812015-07-01 13:36:18 -07004243 mm_free(hostname);
4244 mm_free(portname);
4245 if (evcon == NULL)
4246 return (NULL);
4247
4248 evcon->max_headers_size = http->default_max_headers_size;
4249 evcon->max_body_size = http->default_max_body_size;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004250 if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE)
4251 evcon->flags |= EVHTTP_CON_LINGERING_CLOSE;
Christopher Wileye8679812015-07-01 13:36:18 -07004252
4253 evcon->flags |= EVHTTP_CON_INCOMING;
4254 evcon->state = EVCON_READING_FIRSTLINE;
4255
4256 evcon->fd = fd;
4257
Haibo Huangb2279672019-05-31 16:12:39 -07004258 if (bufferevent_setfd(evcon->bufev, fd))
4259 goto err;
4260 if (bufferevent_enable(evcon->bufev, EV_READ))
4261 goto err;
4262 if (bufferevent_disable(evcon->bufev, EV_WRITE))
4263 goto err;
4264 bufferevent_socket_set_conn_address_(evcon->bufev, sa, salen);
Christopher Wileye8679812015-07-01 13:36:18 -07004265
4266 return (evcon);
Haibo Huangb2279672019-05-31 16:12:39 -07004267
4268err:
4269 evhttp_connection_free(evcon);
4270 return (NULL);
Christopher Wileye8679812015-07-01 13:36:18 -07004271}
4272
4273static int
4274evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
4275{
4276 struct evhttp *http = evcon->http_server;
4277 struct evhttp_request *req;
4278 if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
4279 return (-1);
4280
4281 if ((req->remote_host = mm_strdup(evcon->address)) == NULL) {
4282 event_warn("%s: strdup", __func__);
4283 evhttp_request_free(req);
4284 return (-1);
4285 }
4286 req->remote_port = evcon->port;
4287
4288 req->evcon = evcon; /* the request ends up owning the connection */
4289 req->flags |= EVHTTP_REQ_OWN_CONNECTION;
4290
4291 /* We did not present the request to the user user yet, so treat it as
4292 * if the user was done with the request. This allows us to free the
4293 * request on a persistent connection if the client drops it without
4294 * sending a request.
4295 */
4296 req->userdone = 1;
4297
4298 TAILQ_INSERT_TAIL(&evcon->requests, req, next);
4299
4300 req->kind = EVHTTP_REQUEST;
4301
4302
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004303 evhttp_start_read_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07004304
4305 return (0);
4306}
4307
4308static void
4309evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
4310 struct sockaddr *sa, ev_socklen_t salen)
4311{
4312 struct evhttp_connection *evcon;
4313
4314 evcon = evhttp_get_request_connection(http, fd, sa, salen);
4315 if (evcon == NULL) {
4316 event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT,
4317 __func__, EV_SOCK_ARG(fd));
4318 evutil_closesocket(fd);
4319 return;
4320 }
4321
4322 /* the timeout can be used by the server to close idle connections */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004323 if (evutil_timerisset(&http->timeout))
4324 evhttp_connection_set_timeout_tv(evcon, &http->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07004325
4326 /*
4327 * if we want to accept more than one request on a connection,
4328 * we need to know which http server it belongs to.
4329 */
4330 evcon->http_server = http;
4331 TAILQ_INSERT_TAIL(&http->connections, evcon, next);
4332
4333 if (evhttp_associate_new_request_with_connection(evcon) == -1)
4334 evhttp_connection_free(evcon);
4335}
4336
4337
4338/*
4339 * Network helper functions that we do not want to export to the rest of
4340 * the world.
4341 */
4342
4343static void
4344name_from_addr(struct sockaddr *sa, ev_socklen_t salen,
4345 char **phost, char **pport)
4346{
4347 char ntop[NI_MAXHOST];
4348 char strport[NI_MAXSERV];
4349 int ni_result;
4350
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004351#ifdef EVENT__HAVE_GETNAMEINFO
Christopher Wileye8679812015-07-01 13:36:18 -07004352 ni_result = getnameinfo(sa, salen,
4353 ntop, sizeof(ntop), strport, sizeof(strport),
4354 NI_NUMERICHOST|NI_NUMERICSERV);
4355
4356 if (ni_result != 0) {
4357#ifdef EAI_SYSTEM
4358 /* Windows doesn't have an EAI_SYSTEM. */
4359 if (ni_result == EAI_SYSTEM)
4360 event_err(1, "getnameinfo failed");
4361 else
4362#endif
4363 event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
4364 return;
4365 }
4366#else
4367 ni_result = fake_getnameinfo(sa, salen,
4368 ntop, sizeof(ntop), strport, sizeof(strport),
4369 NI_NUMERICHOST|NI_NUMERICSERV);
4370 if (ni_result != 0)
4371 return;
4372#endif
4373
4374 *phost = mm_strdup(ntop);
4375 *pport = mm_strdup(strport);
4376}
4377
4378/* Create a non-blocking socket and bind it */
4379/* todo: rename this function */
4380static evutil_socket_t
4381bind_socket_ai(struct evutil_addrinfo *ai, int reuse)
4382{
4383 evutil_socket_t fd;
4384
4385 int on = 1, r;
4386 int serrno;
4387
4388 /* Create listen socket */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004389 fd = evutil_socket_(ai ? ai->ai_family : AF_INET,
4390 SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
Christopher Wileye8679812015-07-01 13:36:18 -07004391 if (fd == -1) {
4392 event_sock_warn(-1, "socket");
4393 return (-1);
4394 }
4395
Christopher Wileye8679812015-07-01 13:36:18 -07004396 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0)
4397 goto out;
4398 if (reuse) {
4399 if (evutil_make_listen_socket_reuseable(fd) < 0)
4400 goto out;
4401 }
4402
4403 if (ai != NULL) {
4404 r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen);
4405 if (r == -1)
4406 goto out;
4407 }
4408
4409 return (fd);
4410
4411 out:
4412 serrno = EVUTIL_SOCKET_ERROR();
4413 evutil_closesocket(fd);
4414 EVUTIL_SET_SOCKET_ERROR(serrno);
4415 return (-1);
4416}
4417
4418static struct evutil_addrinfo *
4419make_addrinfo(const char *address, ev_uint16_t port)
4420{
4421 struct evutil_addrinfo *ai = NULL;
4422
4423 struct evutil_addrinfo hints;
4424 char strport[NI_MAXSERV];
4425 int ai_result;
4426
4427 memset(&hints, 0, sizeof(hints));
4428 hints.ai_family = AF_UNSPEC;
4429 hints.ai_socktype = SOCK_STREAM;
4430 /* turn NULL hostname into INADDR_ANY, and skip looking up any address
4431 * types we don't have an interface to connect to. */
4432 hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG;
4433 evutil_snprintf(strport, sizeof(strport), "%d", port);
4434 if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai))
4435 != 0) {
4436 if (ai_result == EVUTIL_EAI_SYSTEM)
4437 event_warn("getaddrinfo");
4438 else
4439 event_warnx("getaddrinfo: %s",
4440 evutil_gai_strerror(ai_result));
4441 return (NULL);
4442 }
4443
4444 return (ai);
4445}
4446
4447static evutil_socket_t
4448bind_socket(const char *address, ev_uint16_t port, int reuse)
4449{
4450 evutil_socket_t fd;
4451 struct evutil_addrinfo *aitop = NULL;
4452
4453 /* just create an unbound socket */
4454 if (address == NULL && port == 0)
4455 return bind_socket_ai(NULL, 0);
4456
4457 aitop = make_addrinfo(address, port);
4458
4459 if (aitop == NULL)
4460 return (-1);
4461
4462 fd = bind_socket_ai(aitop, reuse);
4463
4464 evutil_freeaddrinfo(aitop);
4465
4466 return (fd);
4467}
4468
4469struct evhttp_uri {
4470 unsigned flags;
4471 char *scheme; /* scheme; e.g http, ftp etc */
4472 char *userinfo; /* userinfo (typically username:pass), or NULL */
4473 char *host; /* hostname, IP address, or NULL */
4474 int port; /* port, or zero */
4475 char *path; /* path, or "". */
4476 char *query; /* query, or NULL */
4477 char *fragment; /* fragment or NULL */
4478};
4479
4480struct evhttp_uri *
4481evhttp_uri_new(void)
4482{
4483 struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1);
4484 if (uri)
4485 uri->port = -1;
4486 return uri;
4487}
4488
4489void
4490evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags)
4491{
4492 uri->flags = flags;
4493}
4494
4495/* Return true if the string starting at s and ending immediately before eos
4496 * is a valid URI scheme according to RFC3986
4497 */
4498static int
4499scheme_ok(const char *s, const char *eos)
4500{
4501 /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
4502 EVUTIL_ASSERT(eos >= s);
4503 if (s == eos)
4504 return 0;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004505 if (!EVUTIL_ISALPHA_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004506 return 0;
4507 while (++s < eos) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004508 if (! EVUTIL_ISALNUM_(*s) &&
Christopher Wileye8679812015-07-01 13:36:18 -07004509 *s != '+' && *s != '-' && *s != '.')
4510 return 0;
4511 }
4512 return 1;
4513}
4514
4515#define SUBDELIMS "!$&'()*+,;="
4516
4517/* Return true iff [s..eos) is a valid userinfo */
4518static int
4519userinfo_ok(const char *s, const char *eos)
4520{
4521 while (s < eos) {
4522 if (CHAR_IS_UNRESERVED(*s) ||
4523 strchr(SUBDELIMS, *s) ||
4524 *s == ':')
4525 ++s;
4526 else if (*s == '%' && s+2 < eos &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004527 EVUTIL_ISXDIGIT_(s[1]) &&
4528 EVUTIL_ISXDIGIT_(s[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004529 s += 3;
4530 else
4531 return 0;
4532 }
4533 return 1;
4534}
4535
4536static int
4537regname_ok(const char *s, const char *eos)
4538{
4539 while (s && s<eos) {
4540 if (CHAR_IS_UNRESERVED(*s) ||
4541 strchr(SUBDELIMS, *s))
4542 ++s;
4543 else if (*s == '%' &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004544 EVUTIL_ISXDIGIT_(s[1]) &&
4545 EVUTIL_ISXDIGIT_(s[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004546 s += 3;
4547 else
4548 return 0;
4549 }
4550 return 1;
4551}
4552
4553static int
4554parse_port(const char *s, const char *eos)
4555{
4556 int portnum = 0;
4557 while (s < eos) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004558 if (! EVUTIL_ISDIGIT_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004559 return -1;
4560 portnum = (portnum * 10) + (*s - '0');
4561 if (portnum < 0)
4562 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004563 if (portnum > 65535)
4564 return -1;
Christopher Wileye8679812015-07-01 13:36:18 -07004565 ++s;
4566 }
4567 return portnum;
4568}
4569
4570/* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */
4571static int
4572bracket_addr_ok(const char *s, const char *eos)
4573{
4574 if (s + 3 > eos || *s != '[' || *(eos-1) != ']')
4575 return 0;
4576 if (s[1] == 'v') {
4577 /* IPvFuture, or junk.
4578 "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
4579 */
4580 s += 2; /* skip [v */
4581 --eos;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004582 if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/
Christopher Wileye8679812015-07-01 13:36:18 -07004583 return 0;
4584 while (s < eos && *s != '.') {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004585 if (EVUTIL_ISXDIGIT_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004586 ++s;
4587 else
4588 return 0;
4589 }
4590 if (*s != '.')
4591 return 0;
4592 ++s;
4593 while (s < eos) {
4594 if (CHAR_IS_UNRESERVED(*s) ||
4595 strchr(SUBDELIMS, *s) ||
4596 *s == ':')
4597 ++s;
4598 else
4599 return 0;
4600 }
4601 return 2;
4602 } else {
4603 /* IPv6, or junk */
4604 char buf[64];
4605 ev_ssize_t n_chars = eos-s-2;
4606 struct in6_addr in6;
4607 if (n_chars >= 64) /* way too long */
4608 return 0;
4609 memcpy(buf, s+1, n_chars);
4610 buf[n_chars]='\0';
4611 return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0;
4612 }
4613}
4614
4615static int
4616parse_authority(struct evhttp_uri *uri, char *s, char *eos)
4617{
4618 char *cp, *port;
4619 EVUTIL_ASSERT(eos);
4620 if (eos == s) {
4621 uri->host = mm_strdup("");
4622 if (uri->host == NULL) {
4623 event_warn("%s: strdup", __func__);
4624 return -1;
4625 }
4626 return 0;
4627 }
4628
4629 /* Optionally, we start with "userinfo@" */
4630
4631 cp = strchr(s, '@');
4632 if (cp && cp < eos) {
4633 if (! userinfo_ok(s,cp))
4634 return -1;
4635 *cp++ = '\0';
4636 uri->userinfo = mm_strdup(s);
4637 if (uri->userinfo == NULL) {
4638 event_warn("%s: strdup", __func__);
4639 return -1;
4640 }
4641 } else {
4642 cp = s;
4643 }
4644 /* Optionally, we end with ":port" */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004645 for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port)
Christopher Wileye8679812015-07-01 13:36:18 -07004646 ;
4647 if (port >= cp && *port == ':') {
4648 if (port+1 == eos) /* Leave port unspecified; the RFC allows a
4649 * nil port */
4650 uri->port = -1;
4651 else if ((uri->port = parse_port(port+1, eos))<0)
4652 return -1;
4653 eos = port;
4654 }
4655 /* Now, cp..eos holds the "host" port, which can be an IPv4Address,
4656 * an IP-Literal, or a reg-name */
4657 EVUTIL_ASSERT(eos >= cp);
4658 if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') {
4659 /* IPv6address, IP-Literal, or junk. */
4660 if (! bracket_addr_ok(cp, eos))
4661 return -1;
4662 } else {
4663 /* Make sure the host part is ok. */
4664 if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */
4665 return -1;
4666 }
4667 uri->host = mm_malloc(eos-cp+1);
4668 if (uri->host == NULL) {
4669 event_warn("%s: malloc", __func__);
4670 return -1;
4671 }
4672 memcpy(uri->host, cp, eos-cp);
4673 uri->host[eos-cp] = '\0';
4674 return 0;
4675
4676}
4677
4678static char *
4679end_of_authority(char *cp)
4680{
4681 while (*cp) {
4682 if (*cp == '?' || *cp == '#' || *cp == '/')
4683 return cp;
4684 ++cp;
4685 }
4686 return cp;
4687}
4688
4689enum uri_part {
4690 PART_PATH,
4691 PART_QUERY,
4692 PART_FRAGMENT
4693};
4694
4695/* Return the character after the longest prefix of 'cp' that matches...
4696 * *pchar / "/" if allow_qchars is false, or
4697 * *(pchar / "/" / "?") if allow_qchars is true.
4698 */
4699static char *
4700end_of_path(char *cp, enum uri_part part, unsigned flags)
4701{
4702 if (flags & EVHTTP_URI_NONCONFORMANT) {
4703 /* If NONCONFORMANT:
4704 * Path is everything up to a # or ? or nul.
4705 * Query is everything up a # or nul
4706 * Fragment is everything up to a nul.
4707 */
4708 switch (part) {
4709 case PART_PATH:
4710 while (*cp && *cp != '#' && *cp != '?')
4711 ++cp;
4712 break;
4713 case PART_QUERY:
4714 while (*cp && *cp != '#')
4715 ++cp;
4716 break;
4717 case PART_FRAGMENT:
4718 cp += strlen(cp);
4719 break;
4720 };
4721 return cp;
4722 }
4723
4724 while (*cp) {
4725 if (CHAR_IS_UNRESERVED(*cp) ||
4726 strchr(SUBDELIMS, *cp) ||
4727 *cp == ':' || *cp == '@' || *cp == '/')
4728 ++cp;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004729 else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) &&
4730 EVUTIL_ISXDIGIT_(cp[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004731 cp += 3;
4732 else if (*cp == '?' && part != PART_PATH)
4733 ++cp;
4734 else
4735 return cp;
4736 }
4737 return cp;
4738}
4739
4740static int
4741path_matches_noscheme(const char *cp)
4742{
4743 while (*cp) {
4744 if (*cp == ':')
4745 return 0;
4746 else if (*cp == '/')
4747 return 1;
4748 ++cp;
4749 }
4750 return 1;
4751}
4752
4753struct evhttp_uri *
4754evhttp_uri_parse(const char *source_uri)
4755{
4756 return evhttp_uri_parse_with_flags(source_uri, 0);
4757}
4758
4759struct evhttp_uri *
4760evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags)
4761{
4762 char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL;
4763 char *path = NULL, *fragment = NULL;
4764 int got_authority = 0;
4765
4766 struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
4767 if (uri == NULL) {
4768 event_warn("%s: calloc", __func__);
4769 goto err;
4770 }
4771 uri->port = -1;
4772 uri->flags = flags;
4773
4774 readbuf = mm_strdup(source_uri);
4775 if (readbuf == NULL) {
4776 event_warn("%s: strdup", __func__);
4777 goto err;
4778 }
4779
4780 readp = readbuf;
4781 token = NULL;
4782
4783 /* We try to follow RFC3986 here as much as we can, and match
4784 the productions
4785
4786 URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
4787
4788 relative-ref = relative-part [ "?" query ] [ "#" fragment ]
4789 */
4790
4791 /* 1. scheme: */
4792 token = strchr(readp, ':');
4793 if (token && scheme_ok(readp,token)) {
4794 *token = '\0';
4795 uri->scheme = mm_strdup(readp);
4796 if (uri->scheme == NULL) {
4797 event_warn("%s: strdup", __func__);
4798 goto err;
4799 }
4800 readp = token+1; /* eat : */
4801 }
4802
4803 /* 2. Optionally, "//" then an 'authority' part. */
4804 if (readp[0]=='/' && readp[1] == '/') {
4805 char *authority;
4806 readp += 2;
4807 authority = readp;
4808 path = end_of_authority(readp);
4809 if (parse_authority(uri, authority, path) < 0)
4810 goto err;
4811 readp = path;
4812 got_authority = 1;
4813 }
4814
4815 /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty
4816 */
4817 path = readp;
4818 readp = end_of_path(path, PART_PATH, flags);
4819
4820 /* Query */
4821 if (*readp == '?') {
4822 *readp = '\0';
4823 ++readp;
4824 query = readp;
4825 readp = end_of_path(readp, PART_QUERY, flags);
4826 }
4827 /* fragment */
4828 if (*readp == '#') {
4829 *readp = '\0';
4830 ++readp;
4831 fragment = readp;
4832 readp = end_of_path(readp, PART_FRAGMENT, flags);
4833 }
4834 if (*readp != '\0') {
4835 goto err;
4836 }
4837
4838 /* These next two cases may be unreachable; I'm leaving them
4839 * in to be defensive. */
4840 /* If you didn't get an authority, the path can't begin with "//" */
4841 if (!got_authority && path[0]=='/' && path[1]=='/')
4842 goto err;
4843 /* If you did get an authority, the path must begin with "/" or be
4844 * empty. */
4845 if (got_authority && path[0] != '/' && path[0] != '\0')
4846 goto err;
4847 /* (End of maybe-unreachable cases) */
4848
4849 /* If there was no scheme, the first part of the path (if any) must
4850 * have no colon in it. */
4851 if (! uri->scheme && !path_matches_noscheme(path))
4852 goto err;
4853
4854 EVUTIL_ASSERT(path);
4855 uri->path = mm_strdup(path);
4856 if (uri->path == NULL) {
4857 event_warn("%s: strdup", __func__);
4858 goto err;
4859 }
4860
4861 if (query) {
4862 uri->query = mm_strdup(query);
4863 if (uri->query == NULL) {
4864 event_warn("%s: strdup", __func__);
4865 goto err;
4866 }
4867 }
4868 if (fragment) {
4869 uri->fragment = mm_strdup(fragment);
4870 if (uri->fragment == NULL) {
4871 event_warn("%s: strdup", __func__);
4872 goto err;
4873 }
4874 }
4875
4876 mm_free(readbuf);
4877
4878 return uri;
4879err:
4880 if (uri)
4881 evhttp_uri_free(uri);
4882 if (readbuf)
4883 mm_free(readbuf);
4884 return NULL;
4885}
4886
Haibo Huangb2279672019-05-31 16:12:39 -07004887static struct evhttp_uri *
4888evhttp_uri_parse_authority(char *source_uri)
4889{
4890 struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
4891 char *end;
4892
4893 if (uri == NULL) {
4894 event_warn("%s: calloc", __func__);
4895 goto err;
4896 }
4897 uri->port = -1;
4898 uri->flags = 0;
4899
4900 end = end_of_authority(source_uri);
4901 if (parse_authority(uri, source_uri, end) < 0)
4902 goto err;
4903
4904 uri->path = mm_strdup("");
4905 if (uri->path == NULL) {
4906 event_warn("%s: strdup", __func__);
4907 goto err;
4908 }
4909
4910 return uri;
4911err:
4912 if (uri)
4913 evhttp_uri_free(uri);
4914 return NULL;
4915}
4916
Christopher Wileye8679812015-07-01 13:36:18 -07004917void
4918evhttp_uri_free(struct evhttp_uri *uri)
4919{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004920#define URI_FREE_STR_(f) \
Christopher Wileye8679812015-07-01 13:36:18 -07004921 if (uri->f) { \
4922 mm_free(uri->f); \
4923 }
4924
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004925 URI_FREE_STR_(scheme);
4926 URI_FREE_STR_(userinfo);
4927 URI_FREE_STR_(host);
4928 URI_FREE_STR_(path);
4929 URI_FREE_STR_(query);
4930 URI_FREE_STR_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07004931
4932 mm_free(uri);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004933#undef URI_FREE_STR_
Christopher Wileye8679812015-07-01 13:36:18 -07004934}
4935
4936char *
4937evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
4938{
4939 struct evbuffer *tmp = 0;
4940 size_t joined_size = 0;
4941 char *output = NULL;
4942
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004943#define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f))
Christopher Wileye8679812015-07-01 13:36:18 -07004944
4945 if (!uri || !buf || !limit)
4946 return NULL;
4947
4948 tmp = evbuffer_new();
4949 if (!tmp)
4950 return NULL;
4951
4952 if (uri->scheme) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004953 URI_ADD_(scheme);
Christopher Wileye8679812015-07-01 13:36:18 -07004954 evbuffer_add(tmp, ":", 1);
4955 }
4956 if (uri->host) {
4957 evbuffer_add(tmp, "//", 2);
4958 if (uri->userinfo)
4959 evbuffer_add_printf(tmp,"%s@", uri->userinfo);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004960 URI_ADD_(host);
Christopher Wileye8679812015-07-01 13:36:18 -07004961 if (uri->port >= 0)
4962 evbuffer_add_printf(tmp,":%d", uri->port);
4963
4964 if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0')
4965 goto err;
4966 }
4967
4968 if (uri->path)
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004969 URI_ADD_(path);
Christopher Wileye8679812015-07-01 13:36:18 -07004970
4971 if (uri->query) {
4972 evbuffer_add(tmp, "?", 1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004973 URI_ADD_(query);
Christopher Wileye8679812015-07-01 13:36:18 -07004974 }
4975
4976 if (uri->fragment) {
4977 evbuffer_add(tmp, "#", 1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004978 URI_ADD_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07004979 }
4980
4981 evbuffer_add(tmp, "\0", 1); /* NUL */
4982
4983 joined_size = evbuffer_get_length(tmp);
4984
4985 if (joined_size > limit) {
4986 /* It doesn't fit. */
4987 evbuffer_free(tmp);
4988 return NULL;
4989 }
4990 evbuffer_remove(tmp, buf, joined_size);
4991
4992 output = buf;
4993err:
4994 evbuffer_free(tmp);
4995
4996 return output;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004997#undef URI_ADD_
Christopher Wileye8679812015-07-01 13:36:18 -07004998}
4999
5000const char *
5001evhttp_uri_get_scheme(const struct evhttp_uri *uri)
5002{
5003 return uri->scheme;
5004}
5005const char *
5006evhttp_uri_get_userinfo(const struct evhttp_uri *uri)
5007{
5008 return uri->userinfo;
5009}
5010const char *
5011evhttp_uri_get_host(const struct evhttp_uri *uri)
5012{
5013 return uri->host;
5014}
5015int
5016evhttp_uri_get_port(const struct evhttp_uri *uri)
5017{
5018 return uri->port;
5019}
5020const char *
5021evhttp_uri_get_path(const struct evhttp_uri *uri)
5022{
5023 return uri->path;
5024}
5025const char *
5026evhttp_uri_get_query(const struct evhttp_uri *uri)
5027{
5028 return uri->query;
5029}
5030const char *
5031evhttp_uri_get_fragment(const struct evhttp_uri *uri)
5032{
5033 return uri->fragment;
5034}
5035
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005036#define URI_SET_STR_(f) do { \
Christopher Wileye8679812015-07-01 13:36:18 -07005037 if (uri->f) \
5038 mm_free(uri->f); \
5039 if (f) { \
5040 if ((uri->f = mm_strdup(f)) == NULL) { \
5041 event_warn("%s: strdup()", __func__); \
5042 return -1; \
5043 } \
5044 } else { \
5045 uri->f = NULL; \
5046 } \
5047 } while(0)
5048
5049int
5050evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme)
5051{
5052 if (scheme && !scheme_ok(scheme, scheme+strlen(scheme)))
5053 return -1;
5054
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005055 URI_SET_STR_(scheme);
Christopher Wileye8679812015-07-01 13:36:18 -07005056 return 0;
5057}
5058int
5059evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo)
5060{
5061 if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo)))
5062 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005063 URI_SET_STR_(userinfo);
Christopher Wileye8679812015-07-01 13:36:18 -07005064 return 0;
5065}
5066int
5067evhttp_uri_set_host(struct evhttp_uri *uri, const char *host)
5068{
5069 if (host) {
5070 if (host[0] == '[') {
5071 if (! bracket_addr_ok(host, host+strlen(host)))
5072 return -1;
5073 } else {
5074 if (! regname_ok(host, host+strlen(host)))
5075 return -1;
5076 }
5077 }
5078
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005079 URI_SET_STR_(host);
Christopher Wileye8679812015-07-01 13:36:18 -07005080 return 0;
5081}
5082int
5083evhttp_uri_set_port(struct evhttp_uri *uri, int port)
5084{
5085 if (port < -1)
5086 return -1;
5087 uri->port = port;
5088 return 0;
5089}
5090#define end_of_cpath(cp,p,f) \
5091 ((const char*)(end_of_path(((char*)(cp)), (p), (f))))
5092
5093int
5094evhttp_uri_set_path(struct evhttp_uri *uri, const char *path)
5095{
5096 if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path))
5097 return -1;
5098
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005099 URI_SET_STR_(path);
Christopher Wileye8679812015-07-01 13:36:18 -07005100 return 0;
5101}
5102int
5103evhttp_uri_set_query(struct evhttp_uri *uri, const char *query)
5104{
5105 if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query))
5106 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005107 URI_SET_STR_(query);
Christopher Wileye8679812015-07-01 13:36:18 -07005108 return 0;
5109}
5110int
5111evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment)
5112{
5113 if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment))
5114 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005115 URI_SET_STR_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07005116 return 0;
5117}