blob: 04f089bc01825135ee6d09e7bff87142176407cd [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
Haibo Huangf0077b82020-07-10 20:21:19 -0700180static evutil_socket_t create_bind_socket_nonblock(struct evutil_addrinfo *, int reuse);
Christopher Wileye8679812015-07-01 13:36:18 -0700181static 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) &&
Haibo Huangf0077b82020-07-10 20:21:19 -0700361 req->type != EVHTTP_REQ_CONNECT &&
Christopher Wileye8679812015-07-01 13:36:18 -0700362 req->type != EVHTTP_REQ_HEAD);
363}
364
Christopher Wileye8679812015-07-01 13:36:18 -0700365/** Helper: called after we've added some data to an evcon's bufferevent's
366 * output buffer. Sets the evconn's writing-is-done callback, and puts
367 * the bufferevent into writing mode.
368 */
369static void
370evhttp_write_buffer(struct evhttp_connection *evcon,
371 void (*cb)(struct evhttp_connection *, void *), void *arg)
372{
373 event_debug(("%s: preparing to write buffer\n", __func__));
374
375 /* Set call back */
376 evcon->cb = cb;
377 evcon->cb_arg = arg;
378
379 /* Disable the read callback: we don't actually care about data;
Haibo Huangb2279672019-05-31 16:12:39 -0700380 * we only care about close detection. (We don't disable reading --
381 * EV_READ, since we *do* want to learn about any close events.) */
Christopher Wileye8679812015-07-01 13:36:18 -0700382 bufferevent_setcb(evcon->bufev,
383 NULL, /*read*/
384 evhttp_write_cb,
385 evhttp_error_cb,
386 evcon);
387
Haibo Huangb2279672019-05-31 16:12:39 -0700388 bufferevent_enable(evcon->bufev, EV_READ|EV_WRITE);
Christopher Wileye8679812015-07-01 13:36:18 -0700389}
390
391static void
392evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg)
393{
394 bufferevent_disable(evcon->bufev, EV_WRITE);
395}
396
397static void
398evhttp_send_continue(struct evhttp_connection *evcon,
399 struct evhttp_request *req)
400{
401 bufferevent_enable(evcon->bufev, EV_WRITE);
402 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
403 "HTTP/%d.%d 100 Continue\r\n\r\n",
404 req->major, req->minor);
405 evcon->cb = evhttp_send_continue_done;
406 evcon->cb_arg = NULL;
407 bufferevent_setcb(evcon->bufev,
408 evhttp_read_cb,
409 evhttp_write_cb,
410 evhttp_error_cb,
411 evcon);
412}
413
414/** Helper: returns true iff evconn is in any connected state. */
415static int
416evhttp_connected(struct evhttp_connection *evcon)
417{
418 switch (evcon->state) {
419 case EVCON_DISCONNECTED:
420 case EVCON_CONNECTING:
421 return (0);
422 case EVCON_IDLE:
423 case EVCON_READING_FIRSTLINE:
424 case EVCON_READING_HEADERS:
425 case EVCON_READING_BODY:
426 case EVCON_READING_TRAILER:
427 case EVCON_WRITING:
428 default:
429 return (1);
430 }
431}
432
433/* Create the headers needed for an outgoing HTTP request, adds them to
434 * the request's header list, and writes the request line to the
435 * connection's output buffer.
436 */
437static void
438evhttp_make_header_request(struct evhttp_connection *evcon,
439 struct evhttp_request *req)
440{
441 const char *method;
442
443 evhttp_remove_header(req->output_headers, "Proxy-Connection");
444
445 /* Generate request line */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100446 if (!(method = evhttp_method(req->type))) {
447 method = "NULL";
448 }
449
Christopher Wileye8679812015-07-01 13:36:18 -0700450 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
451 "%s %s HTTP/%d.%d\r\n",
452 method, req->uri, req->major, req->minor);
453
454 /* Add the content length on a post or put request if missing */
455 if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
456 evhttp_find_header(req->output_headers, "Content-Length") == NULL){
457 char size[22];
458 evutil_snprintf(size, sizeof(size), EV_SIZE_FMT,
459 EV_SIZE_ARG(evbuffer_get_length(req->output_buffer)));
460 evhttp_add_header(req->output_headers, "Content-Length", size);
461 }
462}
463
464/** Return true if the list of headers in 'headers', intepreted with respect
465 * to flags, means that we should send a "connection: close" when the request
466 * is done. */
467static int
468evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
469{
470 if (flags & EVHTTP_PROXY_REQUEST) {
471 /* proxy connection */
472 const char *connection = evhttp_find_header(headers, "Proxy-Connection");
473 return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0);
474 } else {
475 const char *connection = evhttp_find_header(headers, "Connection");
476 return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0);
477 }
478}
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100479static int
480evhttp_is_request_connection_close(struct evhttp_request *req)
481{
Haibo Huangf0077b82020-07-10 20:21:19 -0700482 if (req->type == EVHTTP_REQ_CONNECT)
483 return 0;
484
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100485 return
486 evhttp_is_connection_close(req->flags, req->input_headers) ||
487 evhttp_is_connection_close(req->flags, req->output_headers);
488}
Christopher Wileye8679812015-07-01 13:36:18 -0700489
490/* Return true iff 'headers' contains 'Connection: keep-alive' */
491static int
492evhttp_is_connection_keepalive(struct evkeyvalq* headers)
493{
494 const char *connection = evhttp_find_header(headers, "Connection");
495 return (connection != NULL
496 && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0);
497}
498
499/* Add a correct "Date" header to headers, unless it already has one. */
500static void
501evhttp_maybe_add_date_header(struct evkeyvalq *headers)
502{
503 if (evhttp_find_header(headers, "Date") == NULL) {
504 char date[50];
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100505 if (sizeof(date) - evutil_date_rfc1123(date, sizeof(date), NULL) > 0) {
Christopher Wileye8679812015-07-01 13:36:18 -0700506 evhttp_add_header(headers, "Date", date);
507 }
508 }
509}
510
511/* Add a "Content-Length" header with value 'content_length' to headers,
512 * unless it already has a content-length or transfer-encoding header. */
513static void
514evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
515 size_t content_length)
516{
517 if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
518 evhttp_find_header(headers, "Content-Length") == NULL) {
519 char len[22];
520 evutil_snprintf(len, sizeof(len), EV_SIZE_FMT,
521 EV_SIZE_ARG(content_length));
522 evhttp_add_header(headers, "Content-Length", len);
523 }
524}
525
526/*
527 * Create the headers needed for an HTTP reply in req->output_headers,
528 * and write the first HTTP response for req line to evcon.
529 */
530static void
531evhttp_make_header_response(struct evhttp_connection *evcon,
532 struct evhttp_request *req)
533{
534 int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
535 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
536 "HTTP/%d.%d %d %s\r\n",
537 req->major, req->minor, req->response_code,
538 req->response_code_line);
539
540 if (req->major == 1) {
541 if (req->minor >= 1)
542 evhttp_maybe_add_date_header(req->output_headers);
543
544 /*
545 * if the protocol is 1.0; and the connection was keep-alive
546 * we need to add a keep-alive header, too.
547 */
548 if (req->minor == 0 && is_keepalive)
549 evhttp_add_header(req->output_headers,
550 "Connection", "keep-alive");
551
552 if ((req->minor >= 1 || is_keepalive) &&
553 evhttp_response_needs_body(req)) {
554 /*
555 * we need to add the content length if the
556 * user did not give it, this is required for
557 * persistent connections to work.
558 */
559 evhttp_maybe_add_content_length_header(
560 req->output_headers,
561 evbuffer_get_length(req->output_buffer));
562 }
563 }
564
565 /* Potentially add headers for unidentified content. */
566 if (evhttp_response_needs_body(req)) {
567 if (evhttp_find_header(req->output_headers,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100568 "Content-Type") == NULL
569 && evcon->http_server->default_content_type) {
Christopher Wileye8679812015-07-01 13:36:18 -0700570 evhttp_add_header(req->output_headers,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100571 "Content-Type",
572 evcon->http_server->default_content_type);
Christopher Wileye8679812015-07-01 13:36:18 -0700573 }
574 }
575
576 /* if the request asked for a close, we send a close, too */
577 if (evhttp_is_connection_close(req->flags, req->input_headers)) {
578 evhttp_remove_header(req->output_headers, "Connection");
579 if (!(req->flags & EVHTTP_PROXY_REQUEST))
580 evhttp_add_header(req->output_headers, "Connection", "close");
581 evhttp_remove_header(req->output_headers, "Proxy-Connection");
582 }
583}
584
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100585enum expect { NO, CONTINUE, OTHER };
586static enum expect evhttp_have_expect(struct evhttp_request *req, int input)
587{
588 const char *expect;
589 struct evkeyvalq *h = input ? req->input_headers : req->output_headers;
590
591 if (!(req->kind == EVHTTP_REQUEST) || !REQ_VERSION_ATLEAST(req, 1, 1))
592 return NO;
593
594 expect = evhttp_find_header(h, "Expect");
595 if (!expect)
596 return NO;
597
598 return !evutil_ascii_strcasecmp(expect, "100-continue") ? CONTINUE : OTHER;
599}
600
601
Christopher Wileye8679812015-07-01 13:36:18 -0700602/** Generate all headers appropriate for sending the http request in req (or
603 * the response, if we're sending a response), and write them to evcon's
604 * bufferevent. Also writes all data from req->output_buffer */
605static void
606evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
607{
608 struct evkeyval *header;
609 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
610
611 /*
612 * Depending if this is a HTTP request or response, we might need to
613 * add some new headers or remove existing headers.
614 */
615 if (req->kind == EVHTTP_REQUEST) {
616 evhttp_make_header_request(evcon, req);
617 } else {
618 evhttp_make_header_response(evcon, req);
619 }
620
621 TAILQ_FOREACH(header, req->output_headers, next) {
622 evbuffer_add_printf(output, "%s: %s\r\n",
623 header->key, header->value);
624 }
625 evbuffer_add(output, "\r\n", 2);
626
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100627 if (evhttp_have_expect(req, 0) != CONTINUE &&
628 evbuffer_get_length(req->output_buffer)) {
Christopher Wileye8679812015-07-01 13:36:18 -0700629 /*
630 * For a request, we add the POST data, for a reply, this
631 * is the regular data.
632 */
Christopher Wileye8679812015-07-01 13:36:18 -0700633 evbuffer_add_buffer(output, req->output_buffer);
634 }
635}
636
637void
638evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon,
639 ev_ssize_t new_max_headers_size)
640{
641 if (new_max_headers_size<0)
642 evcon->max_headers_size = EV_SIZE_MAX;
643 else
644 evcon->max_headers_size = new_max_headers_size;
645}
646void
647evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
648 ev_ssize_t new_max_body_size)
649{
650 if (new_max_body_size<0)
651 evcon->max_body_size = EV_UINT64_MAX;
652 else
653 evcon->max_body_size = new_max_body_size;
654}
655
656static int
657evhttp_connection_incoming_fail(struct evhttp_request *req,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100658 enum evhttp_request_error error)
Christopher Wileye8679812015-07-01 13:36:18 -0700659{
660 switch (error) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100661 case EVREQ_HTTP_DATA_TOO_LONG:
662 req->response_code = HTTP_ENTITYTOOLARGE;
663 break;
664 default:
665 req->response_code = HTTP_BADREQUEST;
666 }
667
668 switch (error) {
669 case EVREQ_HTTP_TIMEOUT:
670 case EVREQ_HTTP_EOF:
Christopher Wileye8679812015-07-01 13:36:18 -0700671 /*
672 * these are cases in which we probably should just
673 * close the connection and not send a reply. this
674 * case may happen when a browser keeps a persistent
675 * connection open and we timeout on the read. when
676 * the request is still being used for sending, we
677 * need to disassociated it from the connection here.
678 */
679 if (!req->userdone) {
680 /* remove it so that it will not be freed */
681 TAILQ_REMOVE(&req->evcon->requests, req, next);
682 /* indicate that this request no longer has a
683 * connection object
684 */
685 req->evcon = NULL;
686 }
687 return (-1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100688 case EVREQ_HTTP_INVALID_HEADER:
689 case EVREQ_HTTP_BUFFER_ERROR:
690 case EVREQ_HTTP_REQUEST_CANCEL:
691 case EVREQ_HTTP_DATA_TOO_LONG:
Christopher Wileye8679812015-07-01 13:36:18 -0700692 default: /* xxx: probably should just error on default */
693 /* the callback looks at the uri to determine errors */
694 if (req->uri) {
695 mm_free(req->uri);
696 req->uri = NULL;
697 }
698 if (req->uri_elems) {
699 evhttp_uri_free(req->uri_elems);
700 req->uri_elems = NULL;
701 }
702
703 /*
704 * the callback needs to send a reply, once the reply has
705 * been send, the connection should get freed.
706 */
707 (*req->cb)(req, req->cb_arg);
708 }
709
710 return (0);
711}
712
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100713/* Free connection ownership of which can be acquired by user using
714 * evhttp_request_own(). */
715static inline void
716evhttp_request_free_auto(struct evhttp_request *req)
717{
718 if (!(req->flags & EVHTTP_USER_OWNED))
719 evhttp_request_free(req);
720}
721
722static void
723evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req)
724{
725 TAILQ_REMOVE(&evcon->requests, req, next);
726 evhttp_request_free_auto(req);
727}
728
Christopher Wileye8679812015-07-01 13:36:18 -0700729/* Called when evcon has experienced a (non-recoverable? -NM) error, as
730 * given in error. If it's an outgoing connection, reset the connection,
731 * retry any pending requests, and inform the user. If it's incoming,
732 * delegates to evhttp_connection_incoming_fail(). */
733void
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100734evhttp_connection_fail_(struct evhttp_connection *evcon,
735 enum evhttp_request_error error)
Christopher Wileye8679812015-07-01 13:36:18 -0700736{
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100737 const int errsave = EVUTIL_SOCKET_ERROR();
Christopher Wileye8679812015-07-01 13:36:18 -0700738 struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
739 void (*cb)(struct evhttp_request *, void *);
740 void *cb_arg;
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100741 void (*error_cb)(enum evhttp_request_error, void *);
742 void *error_cb_arg;
Christopher Wileye8679812015-07-01 13:36:18 -0700743 EVUTIL_ASSERT(req != NULL);
744
745 bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
746
747 if (evcon->flags & EVHTTP_CON_INCOMING) {
748 /*
749 * for incoming requests, there are two different
750 * failure cases. it's either a network level error
751 * or an http layer error. for problems on the network
752 * layer like timeouts we just drop the connections.
753 * For HTTP problems, we might have to send back a
754 * reply before the connection can be freed.
755 */
756 if (evhttp_connection_incoming_fail(req, error) == -1)
757 evhttp_connection_free(evcon);
758 return;
759 }
760
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100761 error_cb = req->error_cb;
762 error_cb_arg = req->cb_arg;
Christopher Wileye8679812015-07-01 13:36:18 -0700763 /* when the request was canceled, the callback is not executed */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100764 if (error != EVREQ_HTTP_REQUEST_CANCEL) {
Christopher Wileye8679812015-07-01 13:36:18 -0700765 /* save the callback for later; the cb might free our object */
766 cb = req->cb;
767 cb_arg = req->cb_arg;
768 } else {
769 cb = NULL;
770 cb_arg = NULL;
771 }
772
773 /* do not fail all requests; the next request is going to get
774 * send over a new connection. when a user cancels a request,
775 * all other pending requests should be processed as normal
776 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100777 evhttp_request_free_(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -0700778
779 /* reset the connection */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100780 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700781
782 /* We are trying the next request that was queued on us */
783 if (TAILQ_FIRST(&evcon->requests) != NULL)
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100784 evhttp_connection_connect_(evcon);
Haibo Huangf0077b82020-07-10 20:21:19 -0700785 else
786 if ((evcon->flags & EVHTTP_CON_OUTGOING) &&
787 (evcon->flags & EVHTTP_CON_AUTOFREE)) {
788 evhttp_connection_free(evcon);
789 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100790
791 /* The call to evhttp_connection_reset_ overwrote errno.
792 * Let's restore the original errno, so that the user's
793 * callback can have a better idea of what the error was.
794 */
795 EVUTIL_SET_SOCKET_ERROR(errsave);
Christopher Wileye8679812015-07-01 13:36:18 -0700796
797 /* inform the user */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100798 if (error_cb != NULL)
799 error_cb(error, error_cb_arg);
Christopher Wileye8679812015-07-01 13:36:18 -0700800 if (cb != NULL)
801 (*cb)(NULL, cb_arg);
802}
803
804/* Bufferevent callback: invoked when any data has been written from an
805 * http connection's bufferevent */
806static void
807evhttp_write_cb(struct bufferevent *bufev, void *arg)
808{
809 struct evhttp_connection *evcon = arg;
810
811 /* Activate our call back */
812 if (evcon->cb != NULL)
813 (*evcon->cb)(evcon, evcon->cb_arg);
814}
815
816/**
817 * Advance the connection state.
818 * - If this is an outgoing connection, we've just processed the response;
819 * idle or close the connection.
820 * - If this is an incoming connection, we've just processed the request;
821 * respond.
822 */
823static void
824evhttp_connection_done(struct evhttp_connection *evcon)
825{
826 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
827 int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100828 int free_evcon = 0;
Christopher Wileye8679812015-07-01 13:36:18 -0700829
830 if (con_outgoing) {
831 /* idle or close the connection */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100832 int need_close = evhttp_is_request_connection_close(req);
Christopher Wileye8679812015-07-01 13:36:18 -0700833 TAILQ_REMOVE(&evcon->requests, req, next);
834 req->evcon = NULL;
835
836 evcon->state = EVCON_IDLE;
837
Christopher Wileye8679812015-07-01 13:36:18 -0700838 /* check if we got asked to close the connection */
839 if (need_close)
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100840 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700841
842 if (TAILQ_FIRST(&evcon->requests) != NULL) {
843 /*
844 * We have more requests; reset the connection
845 * and deal with the next request.
846 */
847 if (!evhttp_connected(evcon))
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100848 evhttp_connection_connect_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700849 else
850 evhttp_request_dispatch(evcon);
851 } else if (!need_close) {
852 /*
853 * The connection is going to be persistent, but we
854 * need to detect if the other side closes it.
855 */
856 evhttp_connection_start_detectclose(evcon);
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100857 } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) {
858 /*
859 * If we have no more requests that need completion
860 * and we're not waiting for the connection to close
861 */
862 free_evcon = 1;
Christopher Wileye8679812015-07-01 13:36:18 -0700863 }
864 } else {
865 /*
866 * incoming connection - we need to leave the request on the
867 * connection so that we can reply to it.
868 */
869 evcon->state = EVCON_WRITING;
870 }
871
872 /* notify the user of the request */
873 (*req->cb)(req, req->cb_arg);
874
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100875 /* if this was an outgoing request, we own and it's done. so free it. */
876 if (con_outgoing) {
877 evhttp_request_free_auto(req);
878 }
879
880 /* If this was the last request of an outgoing connection and we're
881 * not waiting to receive a connection close event and we want to
882 * automatically free the connection. We check to ensure our request
883 * list is empty one last time just in case our callback added a
884 * new request.
Christopher Wileye8679812015-07-01 13:36:18 -0700885 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100886 if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) {
887 evhttp_connection_free(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700888 }
889}
890
891/*
892 * Handles reading from a chunked request.
893 * return ALL_DATA_READ:
894 * all data has been read
895 * return MORE_DATA_EXPECTED:
896 * more data is expected
897 * return DATA_CORRUPTED:
898 * data is corrupted
899 * return REQUEST_CANCELED:
900 * request was canceled by the user calling evhttp_cancel_request
901 * return DATA_TOO_LONG:
902 * ran over the maximum limit
903 */
904
905static enum message_read_status
906evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
907{
908 if (req == NULL || buf == NULL) {
909 return DATA_CORRUPTED;
910 }
911
912 while (1) {
913 size_t buflen;
914
915 if ((buflen = evbuffer_get_length(buf)) == 0) {
916 break;
917 }
918
919 /* evbuffer_get_length returns size_t, but len variable is ssize_t,
920 * check for overflow conditions */
921 if (buflen > EV_SSIZE_MAX) {
922 return DATA_CORRUPTED;
923 }
924
925 if (req->ntoread < 0) {
926 /* Read chunk size */
927 ev_int64_t ntoread;
928 char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF);
929 char *endp;
930 int error;
931 if (p == NULL)
932 break;
933 /* the last chunk is on a new line? */
934 if (strlen(p) == 0) {
935 mm_free(p);
936 continue;
937 }
938 ntoread = evutil_strtoll(p, &endp, 16);
939 error = (*p == '\0' ||
940 (*endp != '\0' && *endp != ' ') ||
941 ntoread < 0);
942 mm_free(p);
943 if (error) {
944 /* could not get chunk size */
945 return (DATA_CORRUPTED);
946 }
947
948 /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */
949 if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) {
950 return DATA_CORRUPTED;
951 }
952
953 if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) {
954 /* failed body length test */
955 event_debug(("Request body is too long"));
956 return (DATA_TOO_LONG);
957 }
958
959 req->body_size += (size_t)ntoread;
960 req->ntoread = ntoread;
961 if (req->ntoread == 0) {
962 /* Last chunk */
963 return (ALL_DATA_READ);
964 }
965 continue;
966 }
967
968 /* req->ntoread is signed int64, len is ssize_t, based on arch,
969 * ssize_t could only be 32b, check for these conditions */
970 if (req->ntoread > EV_SSIZE_MAX) {
971 return DATA_CORRUPTED;
972 }
973
974 /* don't have enough to complete a chunk; wait for more */
975 if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread)
976 return (MORE_DATA_EXPECTED);
977
978 /* Completed chunk */
979 evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread);
980 req->ntoread = -1;
981 if (req->chunk_cb != NULL) {
982 req->flags |= EVHTTP_REQ_DEFER_FREE;
983 (*req->chunk_cb)(req, req->cb_arg);
984 evbuffer_drain(req->input_buffer,
985 evbuffer_get_length(req->input_buffer));
986 req->flags &= ~EVHTTP_REQ_DEFER_FREE;
987 if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
988 return (REQUEST_CANCELED);
989 }
990 }
991 }
992
993 return (MORE_DATA_EXPECTED);
994}
995
996static void
997evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
998{
999 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
1000
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001001 switch (evhttp_parse_headers_(req, buf)) {
Christopher Wileye8679812015-07-01 13:36:18 -07001002 case DATA_CORRUPTED:
1003 case DATA_TOO_LONG:
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001004 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
Christopher Wileye8679812015-07-01 13:36:18 -07001005 break;
1006 case ALL_DATA_READ:
1007 bufferevent_disable(evcon->bufev, EV_READ);
1008 evhttp_connection_done(evcon);
1009 break;
1010 case MORE_DATA_EXPECTED:
1011 case REQUEST_CANCELED: /* ??? */
1012 default:
Christopher Wileye8679812015-07-01 13:36:18 -07001013 break;
1014 }
1015}
1016
1017static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001018evhttp_lingering_close(struct evhttp_connection *evcon,
1019 struct evhttp_request *req)
1020{
1021 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
1022
1023 size_t n = evbuffer_get_length(buf);
1024 if (n > (size_t) req->ntoread)
1025 n = (size_t) req->ntoread;
1026 req->ntoread -= n;
1027 req->body_size += n;
1028
1029 event_debug(("Request body is too long, left " EV_I64_FMT,
1030 EV_I64_ARG(req->ntoread)));
1031
1032 evbuffer_drain(buf, n);
1033 if (!req->ntoread)
1034 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
1035}
1036static void
1037evhttp_lingering_fail(struct evhttp_connection *evcon,
1038 struct evhttp_request *req)
1039{
1040 if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE)
1041 evhttp_lingering_close(evcon, req);
1042 else
1043 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
1044}
1045
1046static void
Christopher Wileye8679812015-07-01 13:36:18 -07001047evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
1048{
1049 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
1050
1051 if (req->chunked) {
1052 switch (evhttp_handle_chunked_read(req, buf)) {
1053 case ALL_DATA_READ:
1054 /* finished last chunk */
1055 evcon->state = EVCON_READING_TRAILER;
1056 evhttp_read_trailer(evcon, req);
1057 return;
1058 case DATA_CORRUPTED:
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001059 case DATA_TOO_LONG:
Christopher Wileye8679812015-07-01 13:36:18 -07001060 /* corrupted data */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001061 evhttp_connection_fail_(evcon,
1062 EVREQ_HTTP_DATA_TOO_LONG);
Christopher Wileye8679812015-07-01 13:36:18 -07001063 return;
1064 case REQUEST_CANCELED:
1065 /* request canceled */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001066 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07001067 return;
1068 case MORE_DATA_EXPECTED:
1069 default:
1070 break;
1071 }
1072 } else if (req->ntoread < 0) {
1073 /* Read until connection close. */
1074 if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001075 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07001076 return;
1077 }
1078
1079 req->body_size += evbuffer_get_length(buf);
1080 evbuffer_add_buffer(req->input_buffer, buf);
1081 } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) {
1082 /* XXX: the above get_length comparison has to be fixed for overflow conditions! */
1083 /* We've postponed moving the data until now, but we're
1084 * about to use it. */
1085 size_t n = evbuffer_get_length(buf);
1086
1087 if (n > (size_t) req->ntoread)
1088 n = (size_t) req->ntoread;
1089 req->ntoread -= n;
1090 req->body_size += n;
1091 evbuffer_remove_buffer(buf, req->input_buffer, n);
1092 }
1093
1094 if (req->body_size > req->evcon->max_body_size ||
1095 (!req->chunked && req->ntoread >= 0 &&
1096 (size_t)req->ntoread > req->evcon->max_body_size)) {
1097 /* XXX: The above casted comparison must checked for overflow */
1098 /* failed body length test */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001099
1100 evhttp_lingering_fail(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07001101 return;
1102 }
1103
1104 if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) {
1105 req->flags |= EVHTTP_REQ_DEFER_FREE;
1106 (*req->chunk_cb)(req, req->cb_arg);
1107 req->flags &= ~EVHTTP_REQ_DEFER_FREE;
1108 evbuffer_drain(req->input_buffer,
1109 evbuffer_get_length(req->input_buffer));
1110 if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001111 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07001112 return;
1113 }
1114 }
1115
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001116 if (!req->ntoread) {
Christopher Wileye8679812015-07-01 13:36:18 -07001117 bufferevent_disable(evcon->bufev, EV_READ);
1118 /* Completed content length */
1119 evhttp_connection_done(evcon);
1120 return;
1121 }
Christopher Wileye8679812015-07-01 13:36:18 -07001122}
1123
1124#define get_deferred_queue(evcon) \
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001125 ((evcon)->base)
Christopher Wileye8679812015-07-01 13:36:18 -07001126
1127/*
1128 * Gets called when more data becomes available
1129 */
1130
1131static void
1132evhttp_read_cb(struct bufferevent *bufev, void *arg)
1133{
1134 struct evhttp_connection *evcon = arg;
1135 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1136
1137 /* Cancel if it's pending. */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001138 event_deferred_cb_cancel_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07001139 &evcon->read_more_deferred_cb);
1140
1141 switch (evcon->state) {
1142 case EVCON_READING_FIRSTLINE:
1143 evhttp_read_firstline(evcon, req);
1144 /* note the request may have been freed in
1145 * evhttp_read_body */
1146 break;
1147 case EVCON_READING_HEADERS:
1148 evhttp_read_header(evcon, req);
1149 /* note the request may have been freed in
1150 * evhttp_read_body */
1151 break;
1152 case EVCON_READING_BODY:
1153 evhttp_read_body(evcon, req);
1154 /* note the request may have been freed in
1155 * evhttp_read_body */
1156 break;
1157 case EVCON_READING_TRAILER:
1158 evhttp_read_trailer(evcon, req);
1159 break;
1160 case EVCON_IDLE:
1161 {
1162#ifdef USE_DEBUG
1163 struct evbuffer *input;
1164 size_t total_len;
1165
1166 input = bufferevent_get_input(evcon->bufev);
1167 total_len = evbuffer_get_length(input);
1168 event_debug(("%s: read "EV_SIZE_FMT
1169 " bytes in EVCON_IDLE state,"
1170 " resetting connection",
1171 __func__, EV_SIZE_ARG(total_len)));
1172#endif
1173
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001174 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001175 }
1176 break;
1177 case EVCON_DISCONNECTED:
1178 case EVCON_CONNECTING:
1179 case EVCON_WRITING:
1180 default:
1181 event_errx(1, "%s: illegal connection state %d",
1182 __func__, evcon->state);
1183 }
1184}
1185
1186static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001187evhttp_deferred_read_cb(struct event_callback *cb, void *data)
Christopher Wileye8679812015-07-01 13:36:18 -07001188{
1189 struct evhttp_connection *evcon = data;
Haibo Huangb2279672019-05-31 16:12:39 -07001190 struct bufferevent *bev = evcon->bufev;
1191 if (bev->readcb)
1192 (bev->readcb)(evcon->bufev, evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001193}
1194
1195static void
1196evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
1197{
1198 /* This is after writing the request to the server */
1199 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001200 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07001201 EVUTIL_ASSERT(req != NULL);
1202
1203 EVUTIL_ASSERT(evcon->state == EVCON_WRITING);
1204
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001205 /* We need to wait until we've written all of our output data before we can
1206 * continue */
1207 if (evbuffer_get_length(output) > 0)
1208 return;
1209
Christopher Wileye8679812015-07-01 13:36:18 -07001210 /* We are done writing our header and are now expecting the response */
1211 req->kind = EVHTTP_RESPONSE;
1212
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001213 evhttp_start_read_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001214}
1215
1216/*
1217 * Clean up a connection object
1218 */
1219
1220void
1221evhttp_connection_free(struct evhttp_connection *evcon)
1222{
1223 struct evhttp_request *req;
Haibo Huangb2279672019-05-31 16:12:39 -07001224 int need_close = 0;
Christopher Wileye8679812015-07-01 13:36:18 -07001225
1226 /* notify interested parties that this connection is going down */
1227 if (evcon->fd != -1) {
1228 if (evhttp_connected(evcon) && evcon->closecb != NULL)
1229 (*evcon->closecb)(evcon, evcon->closecb_arg);
1230 }
1231
1232 /* remove all requests that might be queued on this
1233 * connection. for server connections, this should be empty.
1234 * because it gets dequeued either in evhttp_connection_done or
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001235 * evhttp_connection_fail_.
Christopher Wileye8679812015-07-01 13:36:18 -07001236 */
1237 while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001238 evhttp_request_free_(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07001239 }
1240
1241 if (evcon->http_server != NULL) {
1242 struct evhttp *http = evcon->http_server;
1243 TAILQ_REMOVE(&http->connections, evcon, next);
1244 }
1245
1246 if (event_initialized(&evcon->retry_ev)) {
1247 event_del(&evcon->retry_ev);
1248 event_debug_unassign(&evcon->retry_ev);
1249 }
1250
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001251 event_deferred_cb_cancel_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07001252 &evcon->read_more_deferred_cb);
1253
Haibo Huangb2279672019-05-31 16:12:39 -07001254 if (evcon->bufev != NULL) {
1255 need_close =
1256 !(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE);
1257 if (evcon->fd == -1)
1258 evcon->fd = bufferevent_getfd(evcon->bufev);
1259
1260 bufferevent_free(evcon->bufev);
1261 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001262
Christopher Wileye8679812015-07-01 13:36:18 -07001263 if (evcon->fd != -1) {
1264 shutdown(evcon->fd, EVUTIL_SHUT_WR);
Haibo Huangb2279672019-05-31 16:12:39 -07001265 if (need_close)
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001266 evutil_closesocket(evcon->fd);
Christopher Wileye8679812015-07-01 13:36:18 -07001267 }
1268
1269 if (evcon->bind_address != NULL)
1270 mm_free(evcon->bind_address);
1271
1272 if (evcon->address != NULL)
1273 mm_free(evcon->address);
1274
1275 mm_free(evcon);
1276}
1277
1278void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001279evhttp_connection_free_on_completion(struct evhttp_connection *evcon) {
1280 evcon->flags |= EVHTTP_CON_AUTOFREE;
1281}
1282
1283void
Christopher Wileye8679812015-07-01 13:36:18 -07001284evhttp_connection_set_local_address(struct evhttp_connection *evcon,
1285 const char *address)
1286{
1287 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
1288 if (evcon->bind_address)
1289 mm_free(evcon->bind_address);
1290 if ((evcon->bind_address = mm_strdup(address)) == NULL)
1291 event_warn("%s: strdup", __func__);
1292}
1293
1294void
1295evhttp_connection_set_local_port(struct evhttp_connection *evcon,
1296 ev_uint16_t port)
1297{
1298 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
1299 evcon->bind_port = port;
1300}
1301
1302static void
1303evhttp_request_dispatch(struct evhttp_connection* evcon)
1304{
1305 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1306
1307 /* this should not usually happy but it's possible */
1308 if (req == NULL)
1309 return;
1310
Haibo Huangb2279672019-05-31 16:12:39 -07001311 EVUTIL_ASSERT(req->kind == EVHTTP_REQUEST);
1312
Christopher Wileye8679812015-07-01 13:36:18 -07001313 /* delete possible close detection events */
1314 evhttp_connection_stop_detectclose(evcon);
1315
1316 /* we assume that the connection is connected already */
1317 EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
1318
1319 evcon->state = EVCON_WRITING;
1320
1321 /* Create the header from the store arguments */
1322 evhttp_make_header(evcon, req);
1323
1324 evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
1325}
1326
1327/* Reset our connection state: disables reading/writing, closes our fd (if
1328* any), clears out buffers, and puts us in state DISCONNECTED. */
1329void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001330evhttp_connection_reset_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07001331{
1332 struct evbuffer *tmp;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001333 int err;
Christopher Wileye8679812015-07-01 13:36:18 -07001334
Haibo Huangb2279672019-05-31 16:12:39 -07001335 bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL);
1336
Christopher Wileye8679812015-07-01 13:36:18 -07001337 /* XXXX This is not actually an optimal fix. Instead we ought to have
1338 an API for "stop connecting", or use bufferevent_setfd to turn off
1339 connecting. But for Libevent 2.0, this seems like a minimal change
1340 least likely to disrupt the rest of the bufferevent and http code.
1341
1342 Why is this here? If the fd is set in the bufferevent, and the
1343 bufferevent is connecting, then you can't actually stop the
1344 bufferevent from trying to connect with bufferevent_disable(). The
1345 connect will never trigger, since we close the fd, but the timeout
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001346 might. That caused an assertion failure in evhttp_connection_fail_.
Christopher Wileye8679812015-07-01 13:36:18 -07001347 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001348 bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE);
1349
1350 if (evcon->fd == -1)
1351 evcon->fd = bufferevent_getfd(evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07001352
1353 if (evcon->fd != -1) {
1354 /* inform interested parties about connection close */
1355 if (evhttp_connected(evcon) && evcon->closecb != NULL)
1356 (*evcon->closecb)(evcon, evcon->closecb_arg);
1357
1358 shutdown(evcon->fd, EVUTIL_SHUT_WR);
1359 evutil_closesocket(evcon->fd);
1360 evcon->fd = -1;
1361 }
Haibo Huangb2279672019-05-31 16:12:39 -07001362 err = bufferevent_setfd(evcon->bufev, -1);
1363 EVUTIL_ASSERT(!err && "setfd");
Christopher Wileye8679812015-07-01 13:36:18 -07001364
1365 /* we need to clean up any buffered data */
1366 tmp = bufferevent_get_output(evcon->bufev);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001367 err = evbuffer_drain(tmp, -1);
1368 EVUTIL_ASSERT(!err && "drain output");
Christopher Wileye8679812015-07-01 13:36:18 -07001369 tmp = bufferevent_get_input(evcon->bufev);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001370 err = evbuffer_drain(tmp, -1);
1371 EVUTIL_ASSERT(!err && "drain input");
1372
1373 evcon->flags &= ~EVHTTP_CON_READING_ERROR;
Christopher Wileye8679812015-07-01 13:36:18 -07001374
1375 evcon->state = EVCON_DISCONNECTED;
1376}
1377
1378static void
1379evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
1380{
1381 evcon->flags |= EVHTTP_CON_CLOSEDETECT;
Christopher Wileye8679812015-07-01 13:36:18 -07001382 bufferevent_enable(evcon->bufev, EV_READ);
1383}
1384
1385static void
1386evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
1387{
1388 evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
Christopher Wileye8679812015-07-01 13:36:18 -07001389 bufferevent_disable(evcon->bufev, EV_READ);
1390}
1391
1392static void
1393evhttp_connection_retry(evutil_socket_t fd, short what, void *arg)
1394{
1395 struct evhttp_connection *evcon = arg;
1396
1397 evcon->state = EVCON_DISCONNECTED;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001398 evhttp_connection_connect_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001399}
1400
1401static void
1402evhttp_connection_cb_cleanup(struct evhttp_connection *evcon)
1403{
1404 struct evcon_requestq requests;
1405
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001406 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001407 if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001408 struct timeval tv_retry = evcon->initial_retry_timeout;
1409 int i;
Christopher Wileye8679812015-07-01 13:36:18 -07001410 evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon);
1411 /* XXXX handle failure from evhttp_add_event */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001412 for (i=0; i < evcon->retry_cnt; ++i) {
1413 tv_retry.tv_usec *= 2;
1414 if (tv_retry.tv_usec > 1000000) {
1415 tv_retry.tv_usec -= 1000000;
1416 tv_retry.tv_sec += 1;
1417 }
1418 tv_retry.tv_sec *= 2;
1419 if (tv_retry.tv_sec > 3600) {
1420 tv_retry.tv_sec = 3600;
1421 tv_retry.tv_usec = 0;
1422 }
1423 }
1424 event_add(&evcon->retry_ev, &tv_retry);
Christopher Wileye8679812015-07-01 13:36:18 -07001425 evcon->retry_cnt++;
1426 return;
1427 }
Christopher Wileye8679812015-07-01 13:36:18 -07001428
1429 /*
1430 * User callback can do evhttp_make_request() on the same
1431 * evcon so new request will be added to evcon->requests. To
1432 * avoid freeing it prematurely we iterate over the copy of
1433 * the queue.
1434 */
1435 TAILQ_INIT(&requests);
1436 while (TAILQ_FIRST(&evcon->requests) != NULL) {
1437 struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
1438 TAILQ_REMOVE(&evcon->requests, request, next);
1439 TAILQ_INSERT_TAIL(&requests, request, next);
1440 }
1441
1442 /* for now, we just signal all requests by executing their callbacks */
1443 while (TAILQ_FIRST(&requests) != NULL) {
1444 struct evhttp_request *request = TAILQ_FIRST(&requests);
1445 TAILQ_REMOVE(&requests, request, next);
1446 request->evcon = NULL;
1447
1448 /* we might want to set an error here */
1449 request->cb(request, request->cb_arg);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001450 evhttp_request_free_auto(request);
Christopher Wileye8679812015-07-01 13:36:18 -07001451 }
1452}
1453
1454static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001455evhttp_connection_read_on_write_error(struct evhttp_connection *evcon,
1456 struct evhttp_request *req)
1457{
1458 struct evbuffer *buf;
1459
1460 /** Second time, we can't read anything */
1461 if (evcon->flags & EVHTTP_CON_READING_ERROR) {
1462 evcon->flags &= ~EVHTTP_CON_READING_ERROR;
1463 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
1464 return;
1465 }
1466
1467 req->kind = EVHTTP_RESPONSE;
1468
1469 buf = bufferevent_get_output(evcon->bufev);
1470 evbuffer_unfreeze(buf, 1);
1471 evbuffer_drain(buf, evbuffer_get_length(buf));
1472 evbuffer_freeze(buf, 1);
1473
1474 evhttp_start_read_(evcon);
1475 evcon->flags |= EVHTTP_CON_READING_ERROR;
1476}
1477
1478static void
Christopher Wileye8679812015-07-01 13:36:18 -07001479evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
1480{
1481 struct evhttp_connection *evcon = arg;
1482 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1483
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001484 if (evcon->fd == -1)
1485 evcon->fd = bufferevent_getfd(bufev);
1486
Christopher Wileye8679812015-07-01 13:36:18 -07001487 switch (evcon->state) {
1488 case EVCON_CONNECTING:
1489 if (what & BEV_EVENT_TIMEOUT) {
1490 event_debug(("%s: connection timeout for \"%s:%d\" on "
1491 EV_SOCK_FMT,
1492 __func__, evcon->address, evcon->port,
1493 EV_SOCK_ARG(evcon->fd)));
1494 evhttp_connection_cb_cleanup(evcon);
1495 return;
1496 }
1497 break;
1498
1499 case EVCON_READING_BODY:
1500 if (!req->chunked && req->ntoread < 0
1501 && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) {
1502 /* EOF on read can be benign */
1503 evhttp_connection_done(evcon);
1504 return;
1505 }
1506 break;
1507
1508 case EVCON_DISCONNECTED:
1509 case EVCON_IDLE:
1510 case EVCON_READING_FIRSTLINE:
1511 case EVCON_READING_HEADERS:
1512 case EVCON_READING_TRAILER:
1513 case EVCON_WRITING:
1514 default:
1515 break;
1516 }
1517
1518 /* when we are in close detect mode, a read error means that
1519 * the other side closed their connection.
1520 */
1521 if (evcon->flags & EVHTTP_CON_CLOSEDETECT) {
1522 evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
1523 EVUTIL_ASSERT(evcon->http_server == NULL);
1524 /* For connections from the client, we just
1525 * reset the connection so that it becomes
1526 * disconnected.
1527 */
1528 EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001529 evhttp_connection_reset_(evcon);
1530
1531 /*
1532 * If we have no more requests that need completion
1533 * and we want to auto-free the connection when all
1534 * requests have been completed.
1535 */
1536 if (TAILQ_FIRST(&evcon->requests) == NULL
1537 && (evcon->flags & EVHTTP_CON_OUTGOING)
1538 && (evcon->flags & EVHTTP_CON_AUTOFREE)) {
1539 evhttp_connection_free(evcon);
1540 }
Christopher Wileye8679812015-07-01 13:36:18 -07001541 return;
1542 }
1543
1544 if (what & BEV_EVENT_TIMEOUT) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001545 evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
Christopher Wileye8679812015-07-01 13:36:18 -07001546 } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001547 if (what & BEV_EVENT_WRITING &&
1548 evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) {
1549 evhttp_connection_read_on_write_error(evcon, req);
1550 return;
1551 }
1552
Haibo Huangb2279672019-05-31 16:12:39 -07001553 if (what & BEV_EVENT_READING &&
1554 evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR &&
1555 evbuffer_get_length(bufferevent_get_input(bufev))) {
1556 event_deferred_cb_schedule_(get_deferred_queue(evcon),
1557 &evcon->read_more_deferred_cb);
1558 return;
1559 }
1560
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001561 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
1562 } else if (what == BEV_EVENT_CONNECTED) {
Christopher Wileye8679812015-07-01 13:36:18 -07001563 } else {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001564 evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR);
Christopher Wileye8679812015-07-01 13:36:18 -07001565 }
1566}
1567
1568/*
1569 * Event callback for asynchronous connection attempt.
1570 */
1571static void
1572evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
1573{
1574 struct evhttp_connection *evcon = arg;
1575 int error;
1576 ev_socklen_t errsz = sizeof(error);
1577
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001578 if (evcon->fd == -1)
1579 evcon->fd = bufferevent_getfd(bufev);
1580
Christopher Wileye8679812015-07-01 13:36:18 -07001581 if (!(what & BEV_EVENT_CONNECTED)) {
1582 /* some operating systems return ECONNREFUSED immediately
1583 * when connecting to a local address. the cleanup is going
1584 * to reschedule this function call.
1585 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001586#ifndef _WIN32
Christopher Wileye8679812015-07-01 13:36:18 -07001587 if (errno == ECONNREFUSED)
1588 goto cleanup;
1589#endif
1590 evhttp_error_cb(bufev, what, arg);
1591 return;
1592 }
1593
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001594 if (evcon->fd == -1) {
1595 event_debug(("%s: bufferevent_getfd returned -1",
1596 __func__));
1597 goto cleanup;
1598 }
1599
Christopher Wileye8679812015-07-01 13:36:18 -07001600 /* Check if the connection completed */
1601 if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
1602 &errsz) == -1) {
1603 event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT,
1604 __func__, evcon->address, evcon->port,
1605 EV_SOCK_ARG(evcon->fd)));
1606 goto cleanup;
1607 }
1608
1609 if (error) {
1610 event_debug(("%s: connect failed for \"%s:%d\" on "
1611 EV_SOCK_FMT": %s",
1612 __func__, evcon->address, evcon->port,
1613 EV_SOCK_ARG(evcon->fd),
1614 evutil_socket_error_to_string(error)));
1615 goto cleanup;
1616 }
1617
1618 /* We are connected to the server now */
1619 event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n",
1620 __func__, evcon->address, evcon->port,
1621 EV_SOCK_ARG(evcon->fd)));
1622
1623 /* Reset the retry count as we were successful in connecting */
1624 evcon->retry_cnt = 0;
1625 evcon->state = EVCON_IDLE;
1626
1627 /* reset the bufferevent cbs */
1628 bufferevent_setcb(evcon->bufev,
1629 evhttp_read_cb,
1630 evhttp_write_cb,
1631 evhttp_error_cb,
1632 evcon);
1633
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001634 if (!evutil_timerisset(&evcon->timeout)) {
1635 const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
1636 const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
1637 bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
1638 } else {
1639 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07001640 }
1641
1642 /* try to start requests that have queued up on this connection */
1643 evhttp_request_dispatch(evcon);
1644 return;
1645
1646 cleanup:
1647 evhttp_connection_cb_cleanup(evcon);
1648}
1649
1650/*
1651 * Check if we got a valid response code.
1652 */
1653
1654static int
1655evhttp_valid_response_code(int code)
1656{
1657 if (code == 0)
1658 return (0);
1659
1660 return (1);
1661}
1662
1663static int
1664evhttp_parse_http_version(const char *version, struct evhttp_request *req)
1665{
1666 int major, minor;
1667 char ch;
1668 int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch);
1669 if (n != 2 || major > 1) {
1670 event_debug(("%s: bad version %s on message %p from %s",
1671 __func__, version, req, req->remote_host));
1672 return (-1);
1673 }
1674 req->major = major;
1675 req->minor = minor;
1676 return (0);
1677}
1678
1679/* Parses the status line of a web server */
1680
1681static int
1682evhttp_parse_response_line(struct evhttp_request *req, char *line)
1683{
1684 char *protocol;
1685 char *number;
1686 const char *readable = "";
1687
1688 protocol = strsep(&line, " ");
1689 if (line == NULL)
1690 return (-1);
1691 number = strsep(&line, " ");
1692 if (line != NULL)
1693 readable = line;
1694
1695 if (evhttp_parse_http_version(protocol, req) < 0)
1696 return (-1);
1697
1698 req->response_code = atoi(number);
1699 if (!evhttp_valid_response_code(req->response_code)) {
1700 event_debug(("%s: bad response code \"%s\"",
1701 __func__, number));
1702 return (-1);
1703 }
1704
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001705 if (req->response_code_line != NULL)
1706 mm_free(req->response_code_line);
Christopher Wileye8679812015-07-01 13:36:18 -07001707 if ((req->response_code_line = mm_strdup(readable)) == NULL) {
1708 event_warn("%s: strdup", __func__);
1709 return (-1);
1710 }
1711
1712 return (0);
1713}
1714
1715/* Parse the first line of a HTTP request */
1716
1717static int
Haibo Huangb2279672019-05-31 16:12:39 -07001718evhttp_parse_request_line(struct evhttp_request *req, char *line, size_t len)
Christopher Wileye8679812015-07-01 13:36:18 -07001719{
Haibo Huangb2279672019-05-31 16:12:39 -07001720 char *eos = line + len;
Christopher Wileye8679812015-07-01 13:36:18 -07001721 char *method;
1722 char *uri;
1723 char *version;
1724 const char *hostname;
1725 const char *scheme;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001726 size_t method_len;
1727 enum evhttp_cmd_type type;
Christopher Wileye8679812015-07-01 13:36:18 -07001728
Haibo Huangb2279672019-05-31 16:12:39 -07001729 while (eos > line && *(eos-1) == ' ') {
1730 *(eos-1) = '\0';
1731 --eos;
1732 --len;
1733 }
1734 if (len < strlen("GET / HTTP/1.0"))
1735 return -1;
1736
Christopher Wileye8679812015-07-01 13:36:18 -07001737 /* Parse the request line */
1738 method = strsep(&line, " ");
Haibo Huangb2279672019-05-31 16:12:39 -07001739 if (!line)
1740 return -1;
1741 uri = line;
1742 version = strrchr(uri, ' ');
1743 if (!version || uri == version)
1744 return -1;
1745 *version = '\0';
1746 version++;
Christopher Wileye8679812015-07-01 13:36:18 -07001747
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001748 method_len = (uri - method) - 1;
1749 type = EVHTTP_REQ_UNKNOWN_;
1750
Christopher Wileye8679812015-07-01 13:36:18 -07001751 /* First line */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001752 switch (method_len) {
1753 case 3:
1754 /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */
1755
1756 /* Since both GET and PUT share the same character 'T' at the end,
1757 * if the string doesn't have 'T', we can immediately determine this
1758 * is an invalid HTTP method */
1759
1760 if (method[2] != 'T') {
1761 break;
1762 }
1763
1764 switch (*method) {
1765 case 'G':
1766 /* This first byte is 'G', so make sure the next byte is
1767 * 'E', if it isn't then this isn't a valid method */
1768
1769 if (method[1] == 'E') {
1770 type = EVHTTP_REQ_GET;
1771 }
1772
1773 break;
1774 case 'P':
1775 /* First byte is P, check second byte for 'U', if not,
1776 * we know it's an invalid method */
1777 if (method[1] == 'U') {
1778 type = EVHTTP_REQ_PUT;
1779 }
1780 break;
1781 default:
1782 break;
1783 }
1784 break;
1785 case 4:
1786 /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */
1787 switch (*method) {
1788 case 'P':
1789 if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') {
1790 type = EVHTTP_REQ_POST;
1791 }
1792 break;
1793 case 'H':
1794 if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') {
1795 type = EVHTTP_REQ_HEAD;
1796 }
1797 break;
1798 default:
1799 break;
1800 }
1801 break;
1802 case 5:
1803 /* Method length is 5 bytes, which can only encompass PATCH and TRACE */
1804 switch (*method) {
1805 case 'P':
1806 if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') {
1807 type = EVHTTP_REQ_PATCH;
1808 }
1809 break;
1810 case 'T':
1811 if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') {
1812 type = EVHTTP_REQ_TRACE;
1813 }
1814
1815 break;
1816 default:
1817 break;
1818 }
1819 break;
1820 case 6:
1821 /* Method length is 6, only valid method 6 bytes in length is DELEte */
1822
1823 /* If the first byte isn't 'D' then it's invalid */
1824 if (*method != 'D') {
1825 break;
1826 }
1827
1828 if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') {
1829 type = EVHTTP_REQ_DELETE;
1830 }
1831
1832 break;
1833 case 7:
1834 /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */
1835 switch (*method) {
1836 case 'O':
1837 if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' &&
1838 method[3] == 'I' && method[2] == 'T' && method[1] == 'P') {
1839 type = EVHTTP_REQ_OPTIONS;
1840 }
1841
1842 break;
1843 case 'C':
1844 if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' &&
1845 method[3] == 'N' && method[2] == 'N' && method[1] == 'O') {
1846 type = EVHTTP_REQ_CONNECT;
1847 }
1848
1849 break;
1850 default:
1851 break;
1852 }
1853 break;
1854 } /* switch */
1855
1856 if ((int)type == EVHTTP_REQ_UNKNOWN_) {
1857 event_debug(("%s: bad method %s on request %p from %s",
Christopher Wileye8679812015-07-01 13:36:18 -07001858 __func__, method, req, req->remote_host));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001859 /* No error yet; we'll give a better error later when
1860 * we see that req->type is unsupported. */
Christopher Wileye8679812015-07-01 13:36:18 -07001861 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001862
1863 req->type = type;
Christopher Wileye8679812015-07-01 13:36:18 -07001864
1865 if (evhttp_parse_http_version(version, req) < 0)
Haibo Huangb2279672019-05-31 16:12:39 -07001866 return -1;
Christopher Wileye8679812015-07-01 13:36:18 -07001867
1868 if ((req->uri = mm_strdup(uri)) == NULL) {
1869 event_debug(("%s: mm_strdup", __func__));
Haibo Huangb2279672019-05-31 16:12:39 -07001870 return -1;
Christopher Wileye8679812015-07-01 13:36:18 -07001871 }
1872
Haibo Huangb2279672019-05-31 16:12:39 -07001873 if (type == EVHTTP_REQ_CONNECT) {
1874 if ((req->uri_elems = evhttp_uri_parse_authority(req->uri)) == NULL) {
1875 return -1;
1876 }
1877 } else {
1878 if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri,
1879 EVHTTP_URI_NONCONFORMANT)) == NULL) {
1880 return -1;
1881 }
Christopher Wileye8679812015-07-01 13:36:18 -07001882 }
1883
1884 /* If we have an absolute-URI, check to see if it is an http request
1885 for a known vhost or server alias. If we don't know about this
1886 host, we consider it a proxy request. */
1887 scheme = evhttp_uri_get_scheme(req->uri_elems);
1888 hostname = evhttp_uri_get_host(req->uri_elems);
1889 if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") ||
1890 !evutil_ascii_strcasecmp(scheme, "https")) &&
1891 hostname &&
1892 !evhttp_find_vhost(req->evcon->http_server, NULL, hostname))
1893 req->flags |= EVHTTP_PROXY_REQUEST;
1894
Haibo Huangb2279672019-05-31 16:12:39 -07001895 return 0;
Christopher Wileye8679812015-07-01 13:36:18 -07001896}
1897
1898const char *
1899evhttp_find_header(const struct evkeyvalq *headers, const char *key)
1900{
1901 struct evkeyval *header;
1902
1903 TAILQ_FOREACH(header, headers, next) {
1904 if (evutil_ascii_strcasecmp(header->key, key) == 0)
1905 return (header->value);
1906 }
1907
1908 return (NULL);
1909}
1910
1911void
1912evhttp_clear_headers(struct evkeyvalq *headers)
1913{
1914 struct evkeyval *header;
1915
1916 for (header = TAILQ_FIRST(headers);
1917 header != NULL;
1918 header = TAILQ_FIRST(headers)) {
1919 TAILQ_REMOVE(headers, header, next);
1920 mm_free(header->key);
1921 mm_free(header->value);
1922 mm_free(header);
1923 }
1924}
1925
1926/*
1927 * Returns 0, if the header was successfully removed.
1928 * Returns -1, if the header could not be found.
1929 */
1930
1931int
1932evhttp_remove_header(struct evkeyvalq *headers, const char *key)
1933{
1934 struct evkeyval *header;
1935
1936 TAILQ_FOREACH(header, headers, next) {
1937 if (evutil_ascii_strcasecmp(header->key, key) == 0)
1938 break;
1939 }
1940
1941 if (header == NULL)
1942 return (-1);
1943
1944 /* Free and remove the header that we found */
1945 TAILQ_REMOVE(headers, header, next);
1946 mm_free(header->key);
1947 mm_free(header->value);
1948 mm_free(header);
1949
1950 return (0);
1951}
1952
1953static int
1954evhttp_header_is_valid_value(const char *value)
1955{
1956 const char *p = value;
1957
1958 while ((p = strpbrk(p, "\r\n")) != NULL) {
1959 /* we really expect only one new line */
1960 p += strspn(p, "\r\n");
1961 /* we expect a space or tab for continuation */
1962 if (*p != ' ' && *p != '\t')
1963 return (0);
1964 }
1965 return (1);
1966}
1967
1968int
1969evhttp_add_header(struct evkeyvalq *headers,
1970 const char *key, const char *value)
1971{
1972 event_debug(("%s: key: %s val: %s\n", __func__, key, value));
1973
1974 if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
1975 /* drop illegal headers */
1976 event_debug(("%s: dropping illegal header key\n", __func__));
1977 return (-1);
1978 }
1979
1980 if (!evhttp_header_is_valid_value(value)) {
1981 event_debug(("%s: dropping illegal header value\n", __func__));
1982 return (-1);
1983 }
1984
1985 return (evhttp_add_header_internal(headers, key, value));
1986}
1987
1988static int
1989evhttp_add_header_internal(struct evkeyvalq *headers,
1990 const char *key, const char *value)
1991{
1992 struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval));
1993 if (header == NULL) {
1994 event_warn("%s: calloc", __func__);
1995 return (-1);
1996 }
1997 if ((header->key = mm_strdup(key)) == NULL) {
1998 mm_free(header);
1999 event_warn("%s: strdup", __func__);
2000 return (-1);
2001 }
2002 if ((header->value = mm_strdup(value)) == NULL) {
2003 mm_free(header->key);
2004 mm_free(header);
2005 event_warn("%s: strdup", __func__);
2006 return (-1);
2007 }
2008
2009 TAILQ_INSERT_TAIL(headers, header, next);
2010
2011 return (0);
2012}
2013
2014/*
2015 * Parses header lines from a request or a response into the specified
2016 * request object given an event buffer.
2017 *
2018 * Returns
2019 * DATA_CORRUPTED on error
2020 * MORE_DATA_EXPECTED when we need to read more headers
2021 * ALL_DATA_READ when all headers have been read.
2022 */
2023
2024enum message_read_status
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002025evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer)
Christopher Wileye8679812015-07-01 13:36:18 -07002026{
2027 char *line;
2028 enum message_read_status status = ALL_DATA_READ;
2029
Haibo Huangb2279672019-05-31 16:12:39 -07002030 size_t len;
Christopher Wileye8679812015-07-01 13:36:18 -07002031 /* XXX try */
Haibo Huangb2279672019-05-31 16:12:39 -07002032 line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF);
Christopher Wileye8679812015-07-01 13:36:18 -07002033 if (line == NULL) {
2034 if (req->evcon != NULL &&
2035 evbuffer_get_length(buffer) > req->evcon->max_headers_size)
2036 return (DATA_TOO_LONG);
2037 else
2038 return (MORE_DATA_EXPECTED);
2039 }
2040
Haibo Huangb2279672019-05-31 16:12:39 -07002041 if (req->evcon != NULL && len > req->evcon->max_headers_size) {
Christopher Wileye8679812015-07-01 13:36:18 -07002042 mm_free(line);
2043 return (DATA_TOO_LONG);
2044 }
2045
Haibo Huangb2279672019-05-31 16:12:39 -07002046 req->headers_size = len;
Christopher Wileye8679812015-07-01 13:36:18 -07002047
2048 switch (req->kind) {
2049 case EVHTTP_REQUEST:
Haibo Huangb2279672019-05-31 16:12:39 -07002050 if (evhttp_parse_request_line(req, line, len) == -1)
Christopher Wileye8679812015-07-01 13:36:18 -07002051 status = DATA_CORRUPTED;
2052 break;
2053 case EVHTTP_RESPONSE:
2054 if (evhttp_parse_response_line(req, line) == -1)
2055 status = DATA_CORRUPTED;
2056 break;
2057 default:
2058 status = DATA_CORRUPTED;
2059 }
2060
2061 mm_free(line);
2062 return (status);
2063}
2064
2065static int
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002066evhttp_append_to_last_header(struct evkeyvalq *headers, char *line)
Christopher Wileye8679812015-07-01 13:36:18 -07002067{
2068 struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
2069 char *newval;
2070 size_t old_len, line_len;
2071
2072 if (header == NULL)
2073 return (-1);
2074
2075 old_len = strlen(header->value);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002076
2077 /* Strip space from start and end of line. */
2078 while (*line == ' ' || *line == '\t')
2079 ++line;
2080 evutil_rtrim_lws_(line);
2081
Christopher Wileye8679812015-07-01 13:36:18 -07002082 line_len = strlen(line);
2083
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002084 newval = mm_realloc(header->value, old_len + line_len + 2);
Christopher Wileye8679812015-07-01 13:36:18 -07002085 if (newval == NULL)
2086 return (-1);
2087
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002088 newval[old_len] = ' ';
2089 memcpy(newval + old_len + 1, line, line_len + 1);
Christopher Wileye8679812015-07-01 13:36:18 -07002090 header->value = newval;
2091
2092 return (0);
2093}
2094
2095enum message_read_status
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002096evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
Christopher Wileye8679812015-07-01 13:36:18 -07002097{
2098 enum message_read_status errcode = DATA_CORRUPTED;
2099 char *line;
2100 enum message_read_status status = MORE_DATA_EXPECTED;
2101
2102 struct evkeyvalq* headers = req->input_headers;
Haibo Huangb2279672019-05-31 16:12:39 -07002103 size_t len;
2104 while ((line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF))
Christopher Wileye8679812015-07-01 13:36:18 -07002105 != NULL) {
2106 char *skey, *svalue;
2107
Haibo Huangb2279672019-05-31 16:12:39 -07002108 req->headers_size += len;
Christopher Wileye8679812015-07-01 13:36:18 -07002109
2110 if (req->evcon != NULL &&
2111 req->headers_size > req->evcon->max_headers_size) {
2112 errcode = DATA_TOO_LONG;
2113 goto error;
2114 }
2115
2116 if (*line == '\0') { /* Last header - Done */
2117 status = ALL_DATA_READ;
2118 mm_free(line);
2119 break;
2120 }
2121
2122 /* Check if this is a continuation line */
2123 if (*line == ' ' || *line == '\t') {
2124 if (evhttp_append_to_last_header(headers, line) == -1)
2125 goto error;
2126 mm_free(line);
2127 continue;
2128 }
2129
2130 /* Processing of header lines */
2131 svalue = line;
2132 skey = strsep(&svalue, ":");
2133 if (svalue == NULL)
2134 goto error;
2135
2136 svalue += strspn(svalue, " ");
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002137 evutil_rtrim_lws_(svalue);
Christopher Wileye8679812015-07-01 13:36:18 -07002138
2139 if (evhttp_add_header(headers, skey, svalue) == -1)
2140 goto error;
2141
2142 mm_free(line);
2143 }
2144
2145 if (status == MORE_DATA_EXPECTED) {
2146 if (req->evcon != NULL &&
2147 req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size)
2148 return (DATA_TOO_LONG);
2149 }
2150
2151 return (status);
2152
2153 error:
2154 mm_free(line);
2155 return (errcode);
2156}
2157
2158static int
2159evhttp_get_body_length(struct evhttp_request *req)
2160{
2161 struct evkeyvalq *headers = req->input_headers;
2162 const char *content_length;
2163 const char *connection;
2164
2165 content_length = evhttp_find_header(headers, "Content-Length");
2166 connection = evhttp_find_header(headers, "Connection");
2167
2168 if (content_length == NULL && connection == NULL)
2169 req->ntoread = -1;
2170 else if (content_length == NULL &&
2171 evutil_ascii_strcasecmp(connection, "Close") != 0) {
Haibo Huangb2279672019-05-31 16:12:39 -07002172 req->ntoread = 0;
Christopher Wileye8679812015-07-01 13:36:18 -07002173 } else if (content_length == NULL) {
2174 req->ntoread = -1;
2175 } else {
2176 char *endp;
2177 ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
2178 if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
2179 event_debug(("%s: illegal content length: %s",
2180 __func__, content_length));
2181 return (-1);
2182 }
2183 req->ntoread = ntoread;
2184 }
2185
2186 event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n",
2187 __func__, EV_I64_ARG(req->ntoread),
2188 EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev)))));
2189
2190 return (0);
2191}
2192
2193static int
2194evhttp_method_may_have_body(enum evhttp_cmd_type type)
2195{
2196 switch (type) {
2197 case EVHTTP_REQ_POST:
2198 case EVHTTP_REQ_PUT:
2199 case EVHTTP_REQ_PATCH:
Haibo Huangb2279672019-05-31 16:12:39 -07002200
Christopher Wileye8679812015-07-01 13:36:18 -07002201 case EVHTTP_REQ_GET:
Christopher Wileye8679812015-07-01 13:36:18 -07002202 case EVHTTP_REQ_DELETE:
2203 case EVHTTP_REQ_OPTIONS:
2204 case EVHTTP_REQ_CONNECT:
Haibo Huangb2279672019-05-31 16:12:39 -07002205 return 1;
2206
2207 case EVHTTP_REQ_TRACE:
2208 case EVHTTP_REQ_HEAD:
Christopher Wileye8679812015-07-01 13:36:18 -07002209 default:
2210 return 0;
2211 }
2212}
2213
2214static void
2215evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
2216{
2217 const char *xfer_enc;
2218
2219 /* If this is a request without a body, then we are done */
2220 if (req->kind == EVHTTP_REQUEST &&
2221 !evhttp_method_may_have_body(req->type)) {
2222 evhttp_connection_done(evcon);
2223 return;
2224 }
2225 evcon->state = EVCON_READING_BODY;
2226 xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
2227 if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) {
2228 req->chunked = 1;
2229 req->ntoread = -1;
2230 } else {
2231 if (evhttp_get_body_length(req) == -1) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002232 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002233 return;
2234 }
2235 if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
2236 /* An incoming request with no content-length and no
2237 * transfer-encoding has no body. */
2238 evhttp_connection_done(evcon);
2239 return;
2240 }
2241 }
2242
2243 /* Should we send a 100 Continue status line? */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002244 switch (evhttp_have_expect(req, 1)) {
2245 case CONTINUE:
Christopher Wileye8679812015-07-01 13:36:18 -07002246 /* XXX It would be nice to do some sanity
2247 checking here. Does the resource exist?
2248 Should the resource accept post requests? If
2249 no, we should respond with an error. For
2250 now, just optimistically tell the client to
2251 send their message body. */
2252 if (req->ntoread > 0) {
2253 /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002254 if ((req->evcon->max_body_size <= EV_INT64_MAX) &&
2255 (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
2256 evhttp_lingering_fail(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07002257 return;
2258 }
2259 }
2260 if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
2261 evhttp_send_continue(evcon, req);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002262 break;
2263 case OTHER:
2264 evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL);
2265 return;
2266 case NO: break;
Christopher Wileye8679812015-07-01 13:36:18 -07002267 }
2268
2269 evhttp_read_body(evcon, req);
2270 /* note the request may have been freed in evhttp_read_body */
2271}
2272
2273static void
2274evhttp_read_firstline(struct evhttp_connection *evcon,
2275 struct evhttp_request *req)
2276{
2277 enum message_read_status res;
2278
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002279 res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev));
Christopher Wileye8679812015-07-01 13:36:18 -07002280 if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
2281 /* Error while reading, terminate */
2282 event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
2283 __func__, EV_SOCK_ARG(evcon->fd)));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002284 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002285 return;
2286 } else if (res == MORE_DATA_EXPECTED) {
2287 /* Need more header lines */
2288 return;
2289 }
2290
2291 evcon->state = EVCON_READING_HEADERS;
2292 evhttp_read_header(evcon, req);
2293}
2294
2295static void
2296evhttp_read_header(struct evhttp_connection *evcon,
2297 struct evhttp_request *req)
2298{
2299 enum message_read_status res;
2300 evutil_socket_t fd = evcon->fd;
2301
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002302 res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev));
Christopher Wileye8679812015-07-01 13:36:18 -07002303 if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
2304 /* Error while reading, terminate */
2305 event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
2306 __func__, EV_SOCK_ARG(fd)));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002307 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002308 return;
2309 } else if (res == MORE_DATA_EXPECTED) {
2310 /* Need more header lines */
2311 return;
2312 }
2313
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002314 /* Callback can shut down connection with negative return value */
2315 if (req->header_cb != NULL) {
2316 if ((*req->header_cb)(req, req->cb_arg) < 0) {
2317 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
2318 return;
2319 }
2320 }
Christopher Wileye8679812015-07-01 13:36:18 -07002321
2322 /* Done reading headers, do the real work */
2323 switch (req->kind) {
2324 case EVHTTP_REQUEST:
2325 event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n",
2326 __func__, EV_SOCK_ARG(fd)));
2327 evhttp_get_body(evcon, req);
2328 /* note the request may have been freed in evhttp_get_body */
2329 break;
2330
2331 case EVHTTP_RESPONSE:
2332 /* Start over if we got a 100 Continue response. */
2333 if (req->response_code == 100) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002334 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
2335 evbuffer_add_buffer(output, req->output_buffer);
2336 evhttp_start_write_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07002337 return;
2338 }
2339 if (!evhttp_response_needs_body(req)) {
2340 event_debug(("%s: skipping body for code %d\n",
2341 __func__, req->response_code));
2342 evhttp_connection_done(evcon);
2343 } else {
2344 event_debug(("%s: start of read body for %s on "
2345 EV_SOCK_FMT"\n",
2346 __func__, req->remote_host, EV_SOCK_ARG(fd)));
2347 evhttp_get_body(evcon, req);
2348 /* note the request may have been freed in
2349 * evhttp_get_body */
2350 }
2351 break;
2352
2353 default:
2354 event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
2355 EV_SOCK_ARG(fd));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002356 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002357 break;
2358 }
2359 /* request may have been freed above */
2360}
2361
2362/*
2363 * Creates a TCP connection to the specified port and executes a callback
2364 * when finished. Failure or success is indicate by the passed connection
2365 * object.
2366 *
2367 * Although this interface accepts a hostname, it is intended to take
2368 * only numeric hostnames so that non-blocking DNS resolution can
2369 * happen elsewhere.
2370 */
2371
2372struct evhttp_connection *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002373evhttp_connection_new(const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07002374{
2375 return (evhttp_connection_base_new(NULL, NULL, address, port));
2376}
2377
2378struct evhttp_connection *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002379evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
2380 const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07002381{
2382 struct evhttp_connection *evcon = NULL;
2383
2384 event_debug(("Attempting connection to %s:%d\n", address, port));
2385
2386 if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) {
2387 event_warn("%s: calloc failed", __func__);
2388 goto error;
2389 }
2390
2391 evcon->fd = -1;
2392 evcon->port = port;
2393
2394 evcon->max_headers_size = EV_SIZE_MAX;
2395 evcon->max_body_size = EV_SIZE_MAX;
2396
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002397 evutil_timerclear(&evcon->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07002398 evcon->retry_cnt = evcon->retry_max = 0;
2399
2400 if ((evcon->address = mm_strdup(address)) == NULL) {
2401 event_warn("%s: strdup failed", __func__);
2402 goto error;
2403 }
2404
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002405 if (bev == NULL) {
2406 if (!(bev = bufferevent_socket_new(base, -1, 0))) {
2407 event_warn("%s: bufferevent_socket_new failed", __func__);
2408 goto error;
2409 }
Christopher Wileye8679812015-07-01 13:36:18 -07002410 }
2411
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002412 bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon);
2413 evcon->bufev = bev;
2414
Christopher Wileye8679812015-07-01 13:36:18 -07002415 evcon->state = EVCON_DISCONNECTED;
2416 TAILQ_INIT(&evcon->requests);
2417
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002418 evcon->initial_retry_timeout.tv_sec = 2;
2419 evcon->initial_retry_timeout.tv_usec = 0;
2420
Christopher Wileye8679812015-07-01 13:36:18 -07002421 if (base != NULL) {
2422 evcon->base = base;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002423 if (bufferevent_get_base(bev) != base)
2424 bufferevent_base_set(base, evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07002425 }
2426
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002427 event_deferred_cb_init_(
2428 &evcon->read_more_deferred_cb,
2429 bufferevent_get_priority(bev),
Christopher Wileye8679812015-07-01 13:36:18 -07002430 evhttp_deferred_read_cb, evcon);
2431
2432 evcon->dns_base = dnsbase;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002433 evcon->ai_family = AF_UNSPEC;
Christopher Wileye8679812015-07-01 13:36:18 -07002434
2435 return (evcon);
2436
2437 error:
2438 if (evcon != NULL)
2439 evhttp_connection_free(evcon);
2440 return (NULL);
2441}
2442
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002443struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002444{
2445 return evcon->bufev;
2446}
2447
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002448struct evhttp *
2449evhttp_connection_get_server(struct evhttp_connection *evcon)
2450{
2451 return evcon->http_server;
2452}
2453
2454struct evhttp_connection *
2455evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
2456 const char *address, ev_uint16_t port)
2457{
2458 return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port);
2459}
2460
2461void evhttp_connection_set_family(struct evhttp_connection *evcon,
2462 int family)
2463{
2464 evcon->ai_family = family;
2465}
2466
2467int evhttp_connection_set_flags(struct evhttp_connection *evcon,
2468 int flags)
2469{
2470 int avail_flags = 0;
2471 avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR;
2472 avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR;
2473
2474 if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END)
2475 return 1;
2476 evcon->flags &= ~avail_flags;
2477
2478 evcon->flags |= flags;
2479
2480 return 0;
2481}
2482
Christopher Wileye8679812015-07-01 13:36:18 -07002483void
2484evhttp_connection_set_base(struct evhttp_connection *evcon,
2485 struct event_base *base)
2486{
2487 EVUTIL_ASSERT(evcon->base == NULL);
2488 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
2489 evcon->base = base;
2490 bufferevent_base_set(base, evcon->bufev);
2491}
2492
2493void
2494evhttp_connection_set_timeout(struct evhttp_connection *evcon,
2495 int timeout_in_secs)
2496{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002497 if (timeout_in_secs == -1)
2498 evhttp_connection_set_timeout_tv(evcon, NULL);
2499 else {
2500 struct timeval tv;
2501 tv.tv_sec = timeout_in_secs;
2502 tv.tv_usec = 0;
2503 evhttp_connection_set_timeout_tv(evcon, &tv);
2504 }
2505}
Christopher Wileye8679812015-07-01 13:36:18 -07002506
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002507void
2508evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
2509 const struct timeval* tv)
2510{
2511 if (tv) {
2512 evcon->timeout = *tv;
2513 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
2514 } else {
2515 const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
2516 const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
2517 evutil_timerclear(&evcon->timeout);
2518 bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
2519 }
2520}
2521
2522void
2523evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon,
2524 const struct timeval *tv)
2525{
2526 if (tv) {
2527 evcon->initial_retry_timeout = *tv;
2528 } else {
2529 evutil_timerclear(&evcon->initial_retry_timeout);
2530 evcon->initial_retry_timeout.tv_sec = 2;
2531 }
Christopher Wileye8679812015-07-01 13:36:18 -07002532}
2533
2534void
2535evhttp_connection_set_retries(struct evhttp_connection *evcon,
2536 int retry_max)
2537{
2538 evcon->retry_max = retry_max;
2539}
2540
2541void
2542evhttp_connection_set_closecb(struct evhttp_connection *evcon,
2543 void (*cb)(struct evhttp_connection *, void *), void *cbarg)
2544{
2545 evcon->closecb = cb;
2546 evcon->closecb_arg = cbarg;
2547}
2548
2549void
2550evhttp_connection_get_peer(struct evhttp_connection *evcon,
2551 char **address, ev_uint16_t *port)
2552{
2553 *address = evcon->address;
2554 *port = evcon->port;
2555}
2556
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002557const struct sockaddr*
2558evhttp_connection_get_addr(struct evhttp_connection *evcon)
2559{
2560 return bufferevent_socket_get_conn_address_(evcon->bufev);
2561}
2562
Christopher Wileye8679812015-07-01 13:36:18 -07002563int
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002564evhttp_connection_connect_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002565{
2566 int old_state = evcon->state;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002567 const char *address = evcon->address;
2568 const struct sockaddr *sa = evhttp_connection_get_addr(evcon);
2569 int ret;
Christopher Wileye8679812015-07-01 13:36:18 -07002570
2571 if (evcon->state == EVCON_CONNECTING)
2572 return (0);
2573
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002574 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07002575
2576 EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING));
2577 evcon->flags |= EVHTTP_CON_OUTGOING;
2578
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002579 if (evcon->bind_address || evcon->bind_port) {
2580 evcon->fd = bind_socket(
2581 evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
2582 if (evcon->fd == -1) {
2583 event_debug(("%s: failed to bind to \"%s\"",
2584 __func__, evcon->bind_address));
2585 return (-1);
2586 }
2587
Haibo Huangb2279672019-05-31 16:12:39 -07002588 if (bufferevent_setfd(evcon->bufev, evcon->fd))
2589 return (-1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002590 } else {
Haibo Huangb2279672019-05-31 16:12:39 -07002591 if (bufferevent_setfd(evcon->bufev, -1))
2592 return (-1);
Christopher Wileye8679812015-07-01 13:36:18 -07002593 }
2594
2595 /* Set up a callback for successful connection setup */
Christopher Wileye8679812015-07-01 13:36:18 -07002596 bufferevent_setcb(evcon->bufev,
2597 NULL /* evhttp_read_cb */,
2598 NULL /* evhttp_write_cb */,
2599 evhttp_connection_cb,
2600 evcon);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002601 if (!evutil_timerisset(&evcon->timeout)) {
2602 const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 };
2603 bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv);
2604 } else {
2605 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
2606 }
Christopher Wileye8679812015-07-01 13:36:18 -07002607 /* make sure that we get a write callback */
Haibo Huangb2279672019-05-31 16:12:39 -07002608 if (bufferevent_enable(evcon->bufev, EV_WRITE))
2609 return (-1);
Christopher Wileye8679812015-07-01 13:36:18 -07002610
2611 evcon->state = EVCON_CONNECTING;
2612
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002613 if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR &&
2614 sa &&
2615 (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) {
2616 int socklen = sizeof(struct sockaddr_in);
2617 if (sa->sa_family == AF_INET6) {
2618 socklen = sizeof(struct sockaddr_in6);
2619 }
2620 ret = bufferevent_socket_connect(evcon->bufev, sa, socklen);
2621 } else {
2622 ret = bufferevent_socket_connect_hostname(evcon->bufev,
2623 evcon->dns_base, evcon->ai_family, address, evcon->port);
2624 }
2625
2626 if (ret < 0) {
Christopher Wileye8679812015-07-01 13:36:18 -07002627 evcon->state = old_state;
2628 event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
2629 __func__, evcon->address);
2630 /* some operating systems return ECONNREFUSED immediately
2631 * when connecting to a local address. the cleanup is going
2632 * to reschedule this function call.
2633 */
2634 evhttp_connection_cb_cleanup(evcon);
2635 return (0);
2636 }
2637
2638 return (0);
2639}
2640
2641/*
2642 * Starts an HTTP request on the provided evhttp_connection object.
2643 * If the connection object is not connected to the web server already,
2644 * this will start the connection.
2645 */
2646
2647int
2648evhttp_make_request(struct evhttp_connection *evcon,
2649 struct evhttp_request *req,
2650 enum evhttp_cmd_type type, const char *uri)
2651{
2652 /* We are making a request */
2653 req->kind = EVHTTP_REQUEST;
2654 req->type = type;
2655 if (req->uri != NULL)
2656 mm_free(req->uri);
2657 if ((req->uri = mm_strdup(uri)) == NULL) {
2658 event_warn("%s: strdup", __func__);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002659 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002660 return (-1);
2661 }
2662
2663 /* Set the protocol version if it is not supplied */
2664 if (!req->major && !req->minor) {
2665 req->major = 1;
2666 req->minor = 1;
2667 }
2668
2669 EVUTIL_ASSERT(req->evcon == NULL);
2670 req->evcon = evcon;
2671 EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
2672
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002673 TAILQ_INSERT_TAIL(&evcon->requests, req, next);
Christopher Wileye8679812015-07-01 13:36:18 -07002674
Haibo Huangb2279672019-05-31 16:12:39 -07002675 /* We do not want to conflict with retry_ev */
2676 if (evcon->retry_cnt)
2677 return (0);
2678
Christopher Wileye8679812015-07-01 13:36:18 -07002679 /* If the connection object is not connected; make it so */
2680 if (!evhttp_connected(evcon)) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002681 int res = evhttp_connection_connect_(evcon);
2682 /* evhttp_connection_fail_(), which is called through
2683 * evhttp_connection_connect_(), assumes that req lies in
2684 * evcon->requests. Thus, enqueue the request in advance and
2685 * remove it in the error case. */
2686 if (res != 0)
2687 TAILQ_REMOVE(&evcon->requests, req, next);
Christopher Wileye8679812015-07-01 13:36:18 -07002688
Haibo Huangb2279672019-05-31 16:12:39 -07002689 return (res);
Christopher Wileye8679812015-07-01 13:36:18 -07002690 }
2691
2692 /*
2693 * If it's connected already and we are the first in the queue,
2694 * then we can dispatch this request immediately. Otherwise, it
2695 * will be dispatched once the pending requests are completed.
2696 */
2697 if (TAILQ_FIRST(&evcon->requests) == req)
2698 evhttp_request_dispatch(evcon);
2699
2700 return (0);
2701}
2702
2703void
2704evhttp_cancel_request(struct evhttp_request *req)
2705{
2706 struct evhttp_connection *evcon = req->evcon;
2707 if (evcon != NULL) {
2708 /* We need to remove it from the connection */
2709 if (TAILQ_FIRST(&evcon->requests) == req) {
2710 /* it's currently being worked on, so reset
2711 * the connection.
2712 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002713 evhttp_connection_fail_(evcon,
2714 EVREQ_HTTP_REQUEST_CANCEL);
Christopher Wileye8679812015-07-01 13:36:18 -07002715
2716 /* connection fail freed the request */
2717 return;
2718 } else {
2719 /* otherwise, we can just remove it from the
2720 * queue
2721 */
2722 TAILQ_REMOVE(&evcon->requests, req, next);
2723 }
2724 }
2725
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002726 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002727}
2728
2729/*
2730 * Reads data from file descriptor into request structure
2731 * Request structure needs to be set up correctly.
2732 */
2733
2734void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002735evhttp_start_read_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002736{
Christopher Wileye8679812015-07-01 13:36:18 -07002737 bufferevent_disable(evcon->bufev, EV_WRITE);
2738 bufferevent_enable(evcon->bufev, EV_READ);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002739
Christopher Wileye8679812015-07-01 13:36:18 -07002740 evcon->state = EVCON_READING_FIRSTLINE;
2741 /* Reset the bufferevent callbacks */
2742 bufferevent_setcb(evcon->bufev,
2743 evhttp_read_cb,
2744 evhttp_write_cb,
2745 evhttp_error_cb,
2746 evcon);
2747
2748 /* If there's still data pending, process it next time through the
2749 * loop. Don't do it now; that could get recusive. */
2750 if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002751 event_deferred_cb_schedule_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07002752 &evcon->read_more_deferred_cb);
2753 }
2754}
2755
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002756void
2757evhttp_start_write_(struct evhttp_connection *evcon)
2758{
2759 bufferevent_disable(evcon->bufev, EV_WRITE);
2760 bufferevent_enable(evcon->bufev, EV_READ);
2761
2762 evcon->state = EVCON_WRITING;
2763 evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
2764}
2765
Christopher Wileye8679812015-07-01 13:36:18 -07002766static void
2767evhttp_send_done(struct evhttp_connection *evcon, void *arg)
2768{
2769 int need_close;
2770 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
2771 TAILQ_REMOVE(&evcon->requests, req, next);
2772
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002773 if (req->on_complete_cb != NULL) {
2774 req->on_complete_cb(req, req->on_complete_cb_arg);
2775 }
2776
Christopher Wileye8679812015-07-01 13:36:18 -07002777 need_close =
2778 (REQ_VERSION_BEFORE(req, 1, 1) &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002779 !evhttp_is_connection_keepalive(req->input_headers)) ||
2780 evhttp_is_request_connection_close(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002781
2782 EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION);
2783 evhttp_request_free(req);
2784
2785 if (need_close) {
2786 evhttp_connection_free(evcon);
2787 return;
2788 }
2789
2790 /* we have a persistent connection; try to accept another request. */
2791 if (evhttp_associate_new_request_with_connection(evcon) == -1) {
2792 evhttp_connection_free(evcon);
2793 }
2794}
2795
2796/*
2797 * Returns an error page.
2798 */
2799
2800void
2801evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
2802{
2803
2804#define ERR_FORMAT "<HTML><HEAD>\n" \
2805 "<TITLE>%d %s</TITLE>\n" \
2806 "</HEAD><BODY>\n" \
2807 "<H1>%s</H1>\n" \
2808 "</BODY></HTML>\n"
2809
2810 struct evbuffer *buf = evbuffer_new();
2811 if (buf == NULL) {
2812 /* if we cannot allocate memory; we just drop the connection */
2813 evhttp_connection_free(req->evcon);
2814 return;
2815 }
2816 if (reason == NULL) {
2817 reason = evhttp_response_phrase_internal(error);
2818 }
2819
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002820 evhttp_response_code_(req, error, reason);
Christopher Wileye8679812015-07-01 13:36:18 -07002821
2822 evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason);
2823
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002824 evhttp_send_page_(req, buf);
Christopher Wileye8679812015-07-01 13:36:18 -07002825
2826 evbuffer_free(buf);
2827#undef ERR_FORMAT
2828}
2829
2830/* Requires that headers and response code are already set up */
2831
2832static inline void
2833evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
2834{
2835 struct evhttp_connection *evcon = req->evcon;
2836
2837 if (evcon == NULL) {
2838 evhttp_request_free(req);
2839 return;
2840 }
2841
2842 EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req);
2843
2844 /* we expect no more calls form the user on this request */
2845 req->userdone = 1;
2846
2847 /* xxx: not sure if we really should expose the data buffer this way */
2848 if (databuf != NULL)
2849 evbuffer_add_buffer(req->output_buffer, databuf);
2850
2851 /* Adds headers to the response */
2852 evhttp_make_header(evcon, req);
2853
2854 evhttp_write_buffer(evcon, evhttp_send_done, NULL);
2855}
2856
2857void
2858evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
2859 struct evbuffer *databuf)
2860{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002861 evhttp_response_code_(req, code, reason);
Christopher Wileye8679812015-07-01 13:36:18 -07002862
2863 evhttp_send(req, databuf);
2864}
2865
2866void
2867evhttp_send_reply_start(struct evhttp_request *req, int code,
2868 const char *reason)
2869{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002870 evhttp_response_code_(req, code, reason);
Haibo Huangb2279672019-05-31 16:12:39 -07002871
2872 if (req->evcon == NULL)
2873 return;
2874
Christopher Wileye8679812015-07-01 13:36:18 -07002875 if (evhttp_find_header(req->output_headers, "Content-Length") == NULL &&
2876 REQ_VERSION_ATLEAST(req, 1, 1) &&
2877 evhttp_response_needs_body(req)) {
2878 /*
2879 * prefer HTTP/1.1 chunked encoding to closing the connection;
2880 * note RFC 2616 section 4.4 forbids it with Content-Length:
2881 * and it's not necessary then anyway.
2882 */
2883 evhttp_add_header(req->output_headers, "Transfer-Encoding",
2884 "chunked");
2885 req->chunked = 1;
2886 } else {
2887 req->chunked = 0;
2888 }
2889 evhttp_make_header(req->evcon, req);
2890 evhttp_write_buffer(req->evcon, NULL, NULL);
2891}
2892
2893void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002894evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf,
2895 void (*cb)(struct evhttp_connection *, void *), void *arg)
Christopher Wileye8679812015-07-01 13:36:18 -07002896{
2897 struct evhttp_connection *evcon = req->evcon;
2898 struct evbuffer *output;
2899
2900 if (evcon == NULL)
2901 return;
2902
2903 output = bufferevent_get_output(evcon->bufev);
2904
2905 if (evbuffer_get_length(databuf) == 0)
2906 return;
2907 if (!evhttp_response_needs_body(req))
2908 return;
2909 if (req->chunked) {
2910 evbuffer_add_printf(output, "%x\r\n",
2911 (unsigned)evbuffer_get_length(databuf));
2912 }
2913 evbuffer_add_buffer(output, databuf);
2914 if (req->chunked) {
2915 evbuffer_add(output, "\r\n", 2);
2916 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002917 evhttp_write_buffer(evcon, cb, arg);
Christopher Wileye8679812015-07-01 13:36:18 -07002918}
2919
2920void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002921evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
2922{
2923 evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL);
2924}
2925void
Christopher Wileye8679812015-07-01 13:36:18 -07002926evhttp_send_reply_end(struct evhttp_request *req)
2927{
2928 struct evhttp_connection *evcon = req->evcon;
2929 struct evbuffer *output;
2930
2931 if (evcon == NULL) {
2932 evhttp_request_free(req);
2933 return;
2934 }
2935
2936 output = bufferevent_get_output(evcon->bufev);
2937
2938 /* we expect no more calls form the user on this request */
2939 req->userdone = 1;
2940
2941 if (req->chunked) {
2942 evbuffer_add(output, "0\r\n\r\n", 5);
2943 evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
2944 req->chunked = 0;
2945 } else if (evbuffer_get_length(output) == 0) {
2946 /* let the connection know that we are done with the request */
2947 evhttp_send_done(evcon, NULL);
2948 } else {
2949 /* make the callback execute after all data has been written */
2950 evcon->cb = evhttp_send_done;
2951 evcon->cb_arg = NULL;
2952 }
2953}
2954
2955static const char *informational_phrases[] = {
2956 /* 100 */ "Continue",
2957 /* 101 */ "Switching Protocols"
2958};
2959
2960static const char *success_phrases[] = {
2961 /* 200 */ "OK",
2962 /* 201 */ "Created",
2963 /* 202 */ "Accepted",
2964 /* 203 */ "Non-Authoritative Information",
2965 /* 204 */ "No Content",
2966 /* 205 */ "Reset Content",
2967 /* 206 */ "Partial Content"
2968};
2969
2970static const char *redirection_phrases[] = {
2971 /* 300 */ "Multiple Choices",
2972 /* 301 */ "Moved Permanently",
2973 /* 302 */ "Found",
2974 /* 303 */ "See Other",
2975 /* 304 */ "Not Modified",
2976 /* 305 */ "Use Proxy",
2977 /* 307 */ "Temporary Redirect"
2978};
2979
2980static const char *client_error_phrases[] = {
2981 /* 400 */ "Bad Request",
2982 /* 401 */ "Unauthorized",
2983 /* 402 */ "Payment Required",
2984 /* 403 */ "Forbidden",
2985 /* 404 */ "Not Found",
2986 /* 405 */ "Method Not Allowed",
2987 /* 406 */ "Not Acceptable",
2988 /* 407 */ "Proxy Authentication Required",
2989 /* 408 */ "Request Time-out",
2990 /* 409 */ "Conflict",
2991 /* 410 */ "Gone",
2992 /* 411 */ "Length Required",
2993 /* 412 */ "Precondition Failed",
2994 /* 413 */ "Request Entity Too Large",
2995 /* 414 */ "Request-URI Too Large",
2996 /* 415 */ "Unsupported Media Type",
2997 /* 416 */ "Requested range not satisfiable",
2998 /* 417 */ "Expectation Failed"
2999};
3000
3001static const char *server_error_phrases[] = {
3002 /* 500 */ "Internal Server Error",
3003 /* 501 */ "Not Implemented",
3004 /* 502 */ "Bad Gateway",
3005 /* 503 */ "Service Unavailable",
3006 /* 504 */ "Gateway Time-out",
3007 /* 505 */ "HTTP Version not supported"
3008};
3009
3010struct response_class {
3011 const char *name;
3012 size_t num_responses;
3013 const char **responses;
3014};
3015
3016#ifndef MEMBERSOF
3017#define MEMBERSOF(x) (sizeof(x)/sizeof(x[0]))
3018#endif
3019
3020static const struct response_class response_classes[] = {
3021 /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases },
3022 /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases },
3023 /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases },
3024 /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases },
3025 /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases }
3026};
3027
3028static const char *
3029evhttp_response_phrase_internal(int code)
3030{
3031 int klass = code / 100 - 1;
3032 int subcode = code % 100;
3033
3034 /* Unknown class - can't do any better here */
3035 if (klass < 0 || klass >= (int) MEMBERSOF(response_classes))
3036 return "Unknown Status Class";
3037
3038 /* Unknown sub-code, return class name at least */
3039 if (subcode >= (int) response_classes[klass].num_responses)
3040 return response_classes[klass].name;
3041
3042 return response_classes[klass].responses[subcode];
3043}
3044
3045void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003046evhttp_response_code_(struct evhttp_request *req, int code, const char *reason)
Christopher Wileye8679812015-07-01 13:36:18 -07003047{
3048 req->kind = EVHTTP_RESPONSE;
3049 req->response_code = code;
3050 if (req->response_code_line != NULL)
3051 mm_free(req->response_code_line);
3052 if (reason == NULL)
3053 reason = evhttp_response_phrase_internal(code);
3054 req->response_code_line = mm_strdup(reason);
3055 if (req->response_code_line == NULL) {
3056 event_warn("%s: strdup", __func__);
3057 /* XXX what else can we do? */
3058 }
3059}
3060
3061void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003062evhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf)
Christopher Wileye8679812015-07-01 13:36:18 -07003063{
3064 if (!req->major || !req->minor) {
3065 req->major = 1;
3066 req->minor = 1;
3067 }
3068
3069 if (req->kind != EVHTTP_RESPONSE)
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003070 evhttp_response_code_(req, 200, "OK");
Christopher Wileye8679812015-07-01 13:36:18 -07003071
3072 evhttp_clear_headers(req->output_headers);
3073 evhttp_add_header(req->output_headers, "Content-Type", "text/html");
3074 evhttp_add_header(req->output_headers, "Connection", "close");
3075
3076 evhttp_send(req, databuf);
3077}
3078
3079static const char uri_chars[256] = {
3080 /* 0 */
3081 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, 1, 1, 0,
3084 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
3085 /* 64 */
3086 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3087 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
3088 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3089 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
3090 /* 128 */
3091 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3092 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3093 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3094 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3095 /* 192 */
3096 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3099 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3100};
3101
3102#define CHAR_IS_UNRESERVED(c) \
3103 (uri_chars[(unsigned char)(c)])
3104
3105/*
3106 * Helper functions to encode/decode a string for inclusion in a URI.
3107 * The returned string must be freed by the caller.
3108 */
3109char *
3110evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus)
3111{
3112 struct evbuffer *buf = evbuffer_new();
3113 const char *p, *end;
Haibo Huangb2279672019-05-31 16:12:39 -07003114 char *result = NULL;
Christopher Wileye8679812015-07-01 13:36:18 -07003115
Haibo Huangb2279672019-05-31 16:12:39 -07003116 if (!buf) {
3117 goto out;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003118 }
Christopher Wileye8679812015-07-01 13:36:18 -07003119
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003120 if (len >= 0) {
3121 if (uri + len < uri) {
Haibo Huangb2279672019-05-31 16:12:39 -07003122 goto out;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003123 }
3124
3125 end = uri + len;
3126 } else {
3127 size_t slen = strlen(uri);
3128
3129 if (slen >= EV_SSIZE_MAX) {
3130 /* we don't want to mix signed and unsigned */
Haibo Huangb2279672019-05-31 16:12:39 -07003131 goto out;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003132 }
3133
3134 if (uri + slen < uri) {
Haibo Huangb2279672019-05-31 16:12:39 -07003135 goto out;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003136 }
3137
3138 end = uri + slen;
3139 }
Christopher Wileye8679812015-07-01 13:36:18 -07003140
3141 for (p = uri; p < end; p++) {
3142 if (CHAR_IS_UNRESERVED(*p)) {
3143 evbuffer_add(buf, p, 1);
3144 } else if (*p == ' ' && space_as_plus) {
3145 evbuffer_add(buf, "+", 1);
3146 } else {
3147 evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p));
3148 }
3149 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003150
Christopher Wileye8679812015-07-01 13:36:18 -07003151 evbuffer_add(buf, "", 1); /* NUL-terminator. */
3152 result = mm_malloc(evbuffer_get_length(buf));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003153
Christopher Wileye8679812015-07-01 13:36:18 -07003154 if (result)
3155 evbuffer_remove(buf, result, evbuffer_get_length(buf));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003156
Haibo Huangb2279672019-05-31 16:12:39 -07003157out:
3158 if (buf)
3159 evbuffer_free(buf);
3160 return result;
Christopher Wileye8679812015-07-01 13:36:18 -07003161}
3162
3163char *
3164evhttp_encode_uri(const char *str)
3165{
3166 return evhttp_uriencode(str, -1, 0);
3167}
3168
3169/*
3170 * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't.
3171 * If -1, when true we transform plus to space only after we've seen
3172 * a ?. -1 is deprecated.
3173 * @return the number of bytes written to 'ret'.
3174 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003175int
Christopher Wileye8679812015-07-01 13:36:18 -07003176evhttp_decode_uri_internal(
3177 const char *uri, size_t length, char *ret, int decode_plus_ctl)
3178{
3179 char c;
3180 int j;
3181 int decode_plus = (decode_plus_ctl == 1) ? 1: 0;
3182 unsigned i;
3183
3184 for (i = j = 0; i < length; i++) {
3185 c = uri[i];
3186 if (c == '?') {
3187 if (decode_plus_ctl < 0)
3188 decode_plus = 1;
3189 } else if (c == '+' && decode_plus) {
3190 c = ' ';
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003191 } else if ((i + 2) < length && c == '%' &&
3192 EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) {
Christopher Wileye8679812015-07-01 13:36:18 -07003193 char tmp[3];
3194 tmp[0] = uri[i+1];
3195 tmp[1] = uri[i+2];
3196 tmp[2] = '\0';
3197 c = (char)strtol(tmp, NULL, 16);
3198 i += 2;
3199 }
3200 ret[j++] = c;
3201 }
3202 ret[j] = '\0';
3203
3204 return (j);
3205}
3206
3207/* deprecated */
3208char *
3209evhttp_decode_uri(const char *uri)
3210{
3211 char *ret;
3212
3213 if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
3214 event_warn("%s: malloc(%lu)", __func__,
3215 (unsigned long)(strlen(uri) + 1));
3216 return (NULL);
3217 }
3218
3219 evhttp_decode_uri_internal(uri, strlen(uri),
3220 ret, -1 /*always_decode_plus*/);
3221
3222 return (ret);
3223}
3224
3225char *
3226evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out)
3227{
3228 char *ret;
3229 int n;
3230
3231 if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
3232 event_warn("%s: malloc(%lu)", __func__,
3233 (unsigned long)(strlen(uri) + 1));
3234 return (NULL);
3235 }
3236
3237 n = evhttp_decode_uri_internal(uri, strlen(uri),
3238 ret, !!decode_plus/*always_decode_plus*/);
3239
3240 if (size_out) {
3241 EVUTIL_ASSERT(n >= 0);
3242 *size_out = (size_t)n;
3243 }
3244
3245 return (ret);
3246}
3247
3248/*
3249 * Helper function to parse out arguments in a query.
3250 * The arguments are separated by key and value.
3251 */
3252
3253static int
3254evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
3255 int is_whole_uri)
3256{
3257 char *line=NULL;
3258 char *argument;
3259 char *p;
3260 const char *query_part;
3261 int result = -1;
3262 struct evhttp_uri *uri=NULL;
3263
3264 TAILQ_INIT(headers);
3265
3266 if (is_whole_uri) {
3267 uri = evhttp_uri_parse(str);
3268 if (!uri)
3269 goto error;
3270 query_part = evhttp_uri_get_query(uri);
3271 } else {
3272 query_part = str;
3273 }
3274
3275 /* No arguments - we are done */
3276 if (!query_part || !strlen(query_part)) {
3277 result = 0;
3278 goto done;
3279 }
3280
3281 if ((line = mm_strdup(query_part)) == NULL) {
3282 event_warn("%s: strdup", __func__);
3283 goto error;
3284 }
3285
3286 p = argument = line;
3287 while (p != NULL && *p != '\0') {
3288 char *key, *value, *decoded_value;
Haibo Huangf0077b82020-07-10 20:21:19 -07003289 int err;
Christopher Wileye8679812015-07-01 13:36:18 -07003290 argument = strsep(&p, "&");
3291
3292 value = argument;
3293 key = strsep(&value, "=");
3294 if (value == NULL || *key == '\0') {
3295 goto error;
3296 }
3297
3298 if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) {
3299 event_warn("%s: mm_malloc", __func__);
3300 goto error;
3301 }
3302 evhttp_decode_uri_internal(value, strlen(value),
3303 decoded_value, 1 /*always_decode_plus*/);
3304 event_debug(("Query Param: %s -> %s\n", key, decoded_value));
Haibo Huangf0077b82020-07-10 20:21:19 -07003305 err = evhttp_add_header_internal(headers, key, decoded_value);
Christopher Wileye8679812015-07-01 13:36:18 -07003306 mm_free(decoded_value);
Haibo Huangf0077b82020-07-10 20:21:19 -07003307 if (err)
3308 goto error;
Christopher Wileye8679812015-07-01 13:36:18 -07003309 }
3310
3311 result = 0;
3312 goto done;
3313error:
3314 evhttp_clear_headers(headers);
3315done:
3316 if (line)
3317 mm_free(line);
3318 if (uri)
3319 evhttp_uri_free(uri);
3320 return result;
3321}
3322
3323int
3324evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
3325{
3326 return evhttp_parse_query_impl(uri, headers, 1);
3327}
3328int
3329evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers)
3330{
3331 return evhttp_parse_query_impl(uri, headers, 0);
3332}
3333
3334static struct evhttp_cb *
3335evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
3336{
3337 struct evhttp_cb *cb;
3338 size_t offset = 0;
3339 char *translated;
3340 const char *path;
3341
3342 /* Test for different URLs */
3343 path = evhttp_uri_get_path(req->uri_elems);
3344 offset = strlen(path);
3345 if ((translated = mm_malloc(offset + 1)) == NULL)
3346 return (NULL);
3347 evhttp_decode_uri_internal(path, offset, translated,
3348 0 /* decode_plus */);
3349
3350 TAILQ_FOREACH(cb, callbacks, next) {
3351 if (!strcmp(cb->what, translated)) {
3352 mm_free(translated);
3353 return (cb);
3354 }
3355 }
3356
3357 mm_free(translated);
3358 return (NULL);
3359}
3360
3361
3362static int
3363prefix_suffix_match(const char *pattern, const char *name, int ignorecase)
3364{
3365 char c;
3366
3367 while (1) {
3368 switch (c = *pattern++) {
3369 case '\0':
3370 return *name == '\0';
3371
3372 case '*':
3373 while (*name != '\0') {
3374 if (prefix_suffix_match(pattern, name,
3375 ignorecase))
3376 return (1);
3377 ++name;
3378 }
3379 return (0);
3380 default:
3381 if (c != *name) {
3382 if (!ignorecase ||
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003383 EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name))
Christopher Wileye8679812015-07-01 13:36:18 -07003384 return (0);
3385 }
3386 ++name;
3387 }
3388 }
3389 /* NOTREACHED */
3390}
3391
3392/*
3393 Search the vhost hierarchy beginning with http for a server alias
3394 matching hostname. If a match is found, and outhttp is non-null,
3395 outhttp is set to the matching http object and 1 is returned.
3396*/
3397
3398static int
3399evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp,
3400 const char *hostname)
3401{
3402 struct evhttp_server_alias *alias;
3403 struct evhttp *vhost;
3404
3405 TAILQ_FOREACH(alias, &http->aliases, next) {
3406 /* XXX Do we need to handle IP addresses? */
3407 if (!evutil_ascii_strcasecmp(alias->alias, hostname)) {
3408 if (outhttp)
3409 *outhttp = http;
3410 return 1;
3411 }
3412 }
3413
3414 /* XXX It might be good to avoid recursion here, but I don't
3415 see a way to do that w/o a list. */
3416 TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
3417 if (evhttp_find_alias(vhost, outhttp, hostname))
3418 return 1;
3419 }
3420
3421 return 0;
3422}
3423
3424/*
3425 Attempts to find the best http object to handle a request for a hostname.
3426 All aliases for the root http object and vhosts are searched for an exact
3427 match. Then, the vhost hierarchy is traversed again for a matching
3428 pattern.
3429
3430 If an alias or vhost is matched, 1 is returned, and outhttp, if non-null,
3431 is set with the best matching http object. If there are no matches, the
3432 root http object is stored in outhttp and 0 is returned.
3433*/
3434
3435static int
3436evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
3437 const char *hostname)
3438{
3439 struct evhttp *vhost;
3440 struct evhttp *oldhttp;
3441 int match_found = 0;
3442
3443 if (evhttp_find_alias(http, outhttp, hostname))
3444 return 1;
3445
3446 do {
3447 oldhttp = http;
3448 TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
3449 if (prefix_suffix_match(vhost->vhost_pattern,
3450 hostname, 1 /* ignorecase */)) {
3451 http = vhost;
3452 match_found = 1;
3453 break;
3454 }
3455 }
3456 } while (oldhttp != http);
3457
3458 if (outhttp)
3459 *outhttp = http;
3460
3461 return match_found;
3462}
3463
3464static void
3465evhttp_handle_request(struct evhttp_request *req, void *arg)
3466{
3467 struct evhttp *http = arg;
3468 struct evhttp_cb *cb = NULL;
3469 const char *hostname;
3470
3471 /* we have a new request on which the user needs to take action */
3472 req->userdone = 0;
3473
Haibo Huangb2279672019-05-31 16:12:39 -07003474 bufferevent_disable(req->evcon->bufev, EV_READ);
3475
Christopher Wileye8679812015-07-01 13:36:18 -07003476 if (req->type == 0 || req->uri == NULL) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003477 evhttp_send_error(req, req->response_code, NULL);
Christopher Wileye8679812015-07-01 13:36:18 -07003478 return;
3479 }
3480
3481 if ((http->allowed_methods & req->type) == 0) {
3482 event_debug(("Rejecting disallowed method %x (allowed: %x)\n",
3483 (unsigned)req->type, (unsigned)http->allowed_methods));
3484 evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL);
3485 return;
3486 }
3487
3488 /* handle potential virtual hosts */
3489 hostname = evhttp_request_get_host(req);
3490 if (hostname != NULL) {
3491 evhttp_find_vhost(http, &http, hostname);
3492 }
3493
3494 if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
3495 (*cb->cb)(req, cb->cbarg);
3496 return;
3497 }
3498
3499 /* Generic call back */
3500 if (http->gencb) {
3501 (*http->gencb)(req, http->gencbarg);
3502 return;
3503 } else {
3504 /* We need to send a 404 here */
3505#define ERR_FORMAT "<html><head>" \
3506 "<title>404 Not Found</title>" \
3507 "</head><body>" \
3508 "<h1>Not Found</h1>" \
3509 "<p>The requested URL %s was not found on this server.</p>"\
3510 "</body></html>\n"
3511
3512 char *escaped_html;
3513 struct evbuffer *buf;
3514
3515 if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) {
3516 evhttp_connection_free(req->evcon);
3517 return;
3518 }
3519
3520 if ((buf = evbuffer_new()) == NULL) {
3521 mm_free(escaped_html);
3522 evhttp_connection_free(req->evcon);
3523 return;
3524 }
3525
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003526 evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found");
Christopher Wileye8679812015-07-01 13:36:18 -07003527
3528 evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
3529
3530 mm_free(escaped_html);
3531
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003532 evhttp_send_page_(req, buf);
Christopher Wileye8679812015-07-01 13:36:18 -07003533
3534 evbuffer_free(buf);
3535#undef ERR_FORMAT
3536 }
3537}
3538
3539/* Listener callback when a connection arrives at a server. */
3540static void
3541accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg)
3542{
3543 struct evhttp *http = arg;
3544
3545 evhttp_get_request(http, nfd, peer_sa, peer_socklen);
3546}
3547
3548int
3549evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port)
3550{
3551 struct evhttp_bound_socket *bound =
3552 evhttp_bind_socket_with_handle(http, address, port);
3553 if (bound == NULL)
3554 return (-1);
3555 return (0);
3556}
3557
3558struct evhttp_bound_socket *
3559evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port)
3560{
3561 evutil_socket_t fd;
3562 struct evhttp_bound_socket *bound;
Haibo Huangb2279672019-05-31 16:12:39 -07003563 int serrno;
Christopher Wileye8679812015-07-01 13:36:18 -07003564
3565 if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
3566 return (NULL);
3567
3568 if (listen(fd, 128) == -1) {
Haibo Huangb2279672019-05-31 16:12:39 -07003569 serrno = EVUTIL_SOCKET_ERROR();
Christopher Wileye8679812015-07-01 13:36:18 -07003570 event_sock_warn(fd, "%s: listen", __func__);
3571 evutil_closesocket(fd);
Haibo Huangb2279672019-05-31 16:12:39 -07003572 EVUTIL_SET_SOCKET_ERROR(serrno);
Christopher Wileye8679812015-07-01 13:36:18 -07003573 return (NULL);
3574 }
3575
3576 bound = evhttp_accept_socket_with_handle(http, fd);
3577
3578 if (bound != NULL) {
3579 event_debug(("Bound to port %d - Awaiting connections ... ",
3580 port));
3581 return (bound);
3582 }
3583
3584 return (NULL);
3585}
3586
3587int
3588evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)
3589{
3590 struct evhttp_bound_socket *bound =
3591 evhttp_accept_socket_with_handle(http, fd);
3592 if (bound == NULL)
3593 return (-1);
3594 return (0);
3595}
3596
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003597void
3598evhttp_foreach_bound_socket(struct evhttp *http,
3599 evhttp_bound_socket_foreach_fn *function,
3600 void *argument)
3601{
3602 struct evhttp_bound_socket *bound;
3603
3604 TAILQ_FOREACH(bound, &http->sockets, next)
3605 function(bound, argument);
3606}
Christopher Wileye8679812015-07-01 13:36:18 -07003607
3608struct evhttp_bound_socket *
3609evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd)
3610{
3611 struct evhttp_bound_socket *bound;
3612 struct evconnlistener *listener;
3613 const int flags =
3614 LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE;
3615
3616 listener = evconnlistener_new(http->base, NULL, NULL,
3617 flags,
3618 0, /* Backlog is '0' because we already said 'listen' */
3619 fd);
3620 if (!listener)
3621 return (NULL);
3622
3623 bound = evhttp_bind_listener(http, listener);
3624 if (!bound) {
3625 evconnlistener_free(listener);
3626 return (NULL);
3627 }
3628 return (bound);
3629}
3630
3631struct evhttp_bound_socket *
3632evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener)
3633{
3634 struct evhttp_bound_socket *bound;
3635
3636 bound = mm_malloc(sizeof(struct evhttp_bound_socket));
3637 if (bound == NULL)
3638 return (NULL);
3639
3640 bound->listener = listener;
3641 TAILQ_INSERT_TAIL(&http->sockets, bound, next);
3642
3643 evconnlistener_set_cb(listener, accept_socket_cb, http);
3644 return bound;
3645}
3646
3647evutil_socket_t
3648evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound)
3649{
3650 return evconnlistener_get_fd(bound->listener);
3651}
3652
3653struct evconnlistener *
3654evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
3655{
3656 return bound->listener;
3657}
3658
3659void
3660evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound)
3661{
3662 TAILQ_REMOVE(&http->sockets, bound, next);
3663 evconnlistener_free(bound->listener);
3664 mm_free(bound);
3665}
3666
3667static struct evhttp*
3668evhttp_new_object(void)
3669{
3670 struct evhttp *http = NULL;
3671
3672 if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) {
3673 event_warn("%s: calloc", __func__);
3674 return (NULL);
3675 }
3676
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003677 evutil_timerclear(&http->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07003678 evhttp_set_max_headers_size(http, EV_SIZE_MAX);
3679 evhttp_set_max_body_size(http, EV_SIZE_MAX);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003680 evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1");
Christopher Wileye8679812015-07-01 13:36:18 -07003681 evhttp_set_allowed_methods(http,
3682 EVHTTP_REQ_GET |
3683 EVHTTP_REQ_POST |
3684 EVHTTP_REQ_HEAD |
3685 EVHTTP_REQ_PUT |
3686 EVHTTP_REQ_DELETE);
3687
3688 TAILQ_INIT(&http->sockets);
3689 TAILQ_INIT(&http->callbacks);
3690 TAILQ_INIT(&http->connections);
3691 TAILQ_INIT(&http->virtualhosts);
3692 TAILQ_INIT(&http->aliases);
3693
3694 return (http);
3695}
3696
3697struct evhttp *
3698evhttp_new(struct event_base *base)
3699{
3700 struct evhttp *http = NULL;
3701
3702 http = evhttp_new_object();
3703 if (http == NULL)
3704 return (NULL);
3705 http->base = base;
3706
3707 return (http);
3708}
3709
3710/*
3711 * Start a web server on the specified address and port.
3712 */
3713
3714struct evhttp *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003715evhttp_start(const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07003716{
3717 struct evhttp *http = NULL;
3718
3719 http = evhttp_new_object();
3720 if (http == NULL)
3721 return (NULL);
3722 if (evhttp_bind_socket(http, address, port) == -1) {
3723 mm_free(http);
3724 return (NULL);
3725 }
3726
3727 return (http);
3728}
3729
3730void
3731evhttp_free(struct evhttp* http)
3732{
3733 struct evhttp_cb *http_cb;
3734 struct evhttp_connection *evcon;
3735 struct evhttp_bound_socket *bound;
3736 struct evhttp* vhost;
3737 struct evhttp_server_alias *alias;
3738
3739 /* Remove the accepting part */
3740 while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
3741 TAILQ_REMOVE(&http->sockets, bound, next);
3742
3743 evconnlistener_free(bound->listener);
3744
3745 mm_free(bound);
3746 }
3747
3748 while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
3749 /* evhttp_connection_free removes the connection */
3750 evhttp_connection_free(evcon);
3751 }
3752
3753 while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
3754 TAILQ_REMOVE(&http->callbacks, http_cb, next);
3755 mm_free(http_cb->what);
3756 mm_free(http_cb);
3757 }
3758
3759 while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) {
3760 TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
3761
3762 evhttp_free(vhost);
3763 }
3764
3765 if (http->vhost_pattern != NULL)
3766 mm_free(http->vhost_pattern);
3767
3768 while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) {
3769 TAILQ_REMOVE(&http->aliases, alias, next);
3770 mm_free(alias->alias);
3771 mm_free(alias);
3772 }
3773
3774 mm_free(http);
3775}
3776
3777int
3778evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
3779 struct evhttp* vhost)
3780{
3781 /* a vhost can only be a vhost once and should not have bound sockets */
3782 if (vhost->vhost_pattern != NULL ||
3783 TAILQ_FIRST(&vhost->sockets) != NULL)
3784 return (-1);
3785
3786 vhost->vhost_pattern = mm_strdup(pattern);
3787 if (vhost->vhost_pattern == NULL)
3788 return (-1);
3789
3790 TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost);
3791
3792 return (0);
3793}
3794
3795int
3796evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost)
3797{
3798 if (vhost->vhost_pattern == NULL)
3799 return (-1);
3800
3801 TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
3802
3803 mm_free(vhost->vhost_pattern);
3804 vhost->vhost_pattern = NULL;
3805
3806 return (0);
3807}
3808
3809int
3810evhttp_add_server_alias(struct evhttp *http, const char *alias)
3811{
3812 struct evhttp_server_alias *evalias;
3813
3814 evalias = mm_calloc(1, sizeof(*evalias));
3815 if (!evalias)
3816 return -1;
3817
3818 evalias->alias = mm_strdup(alias);
3819 if (!evalias->alias) {
3820 mm_free(evalias);
3821 return -1;
3822 }
3823
3824 TAILQ_INSERT_TAIL(&http->aliases, evalias, next);
3825
3826 return 0;
3827}
3828
3829int
3830evhttp_remove_server_alias(struct evhttp *http, const char *alias)
3831{
3832 struct evhttp_server_alias *evalias;
3833
3834 TAILQ_FOREACH(evalias, &http->aliases, next) {
3835 if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) {
3836 TAILQ_REMOVE(&http->aliases, evalias, next);
3837 mm_free(evalias->alias);
3838 mm_free(evalias);
3839 return 0;
3840 }
3841 }
3842
3843 return -1;
3844}
3845
3846void
3847evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
3848{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003849 if (timeout_in_secs == -1) {
3850 evhttp_set_timeout_tv(http, NULL);
3851 } else {
3852 struct timeval tv;
3853 tv.tv_sec = timeout_in_secs;
3854 tv.tv_usec = 0;
3855 evhttp_set_timeout_tv(http, &tv);
3856 }
3857}
3858
3859void
3860evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
3861{
3862 if (tv) {
3863 http->timeout = *tv;
3864 } else {
3865 evutil_timerclear(&http->timeout);
3866 }
3867}
3868
3869int evhttp_set_flags(struct evhttp *http, int flags)
3870{
3871 int avail_flags = 0;
3872 avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE;
3873
3874 if (flags & ~avail_flags)
3875 return 1;
3876 http->flags &= ~avail_flags;
3877
3878 http->flags |= flags;
3879
3880 return 0;
Christopher Wileye8679812015-07-01 13:36:18 -07003881}
3882
3883void
3884evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size)
3885{
3886 if (max_headers_size < 0)
3887 http->default_max_headers_size = EV_SIZE_MAX;
3888 else
3889 http->default_max_headers_size = max_headers_size;
3890}
3891
3892void
3893evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size)
3894{
3895 if (max_body_size < 0)
3896 http->default_max_body_size = EV_UINT64_MAX;
3897 else
3898 http->default_max_body_size = max_body_size;
3899}
3900
3901void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003902evhttp_set_default_content_type(struct evhttp *http,
3903 const char *content_type) {
3904 http->default_content_type = content_type;
3905}
3906
3907void
Christopher Wileye8679812015-07-01 13:36:18 -07003908evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods)
3909{
3910 http->allowed_methods = methods;
3911}
3912
3913int
3914evhttp_set_cb(struct evhttp *http, const char *uri,
3915 void (*cb)(struct evhttp_request *, void *), void *cbarg)
3916{
3917 struct evhttp_cb *http_cb;
3918
3919 TAILQ_FOREACH(http_cb, &http->callbacks, next) {
3920 if (strcmp(http_cb->what, uri) == 0)
3921 return (-1);
3922 }
3923
3924 if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) {
3925 event_warn("%s: calloc", __func__);
3926 return (-2);
3927 }
3928
3929 http_cb->what = mm_strdup(uri);
3930 if (http_cb->what == NULL) {
3931 event_warn("%s: strdup", __func__);
3932 mm_free(http_cb);
3933 return (-3);
3934 }
3935 http_cb->cb = cb;
3936 http_cb->cbarg = cbarg;
3937
3938 TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
3939
3940 return (0);
3941}
3942
3943int
3944evhttp_del_cb(struct evhttp *http, const char *uri)
3945{
3946 struct evhttp_cb *http_cb;
3947
3948 TAILQ_FOREACH(http_cb, &http->callbacks, next) {
3949 if (strcmp(http_cb->what, uri) == 0)
3950 break;
3951 }
3952 if (http_cb == NULL)
3953 return (-1);
3954
3955 TAILQ_REMOVE(&http->callbacks, http_cb, next);
3956 mm_free(http_cb->what);
3957 mm_free(http_cb);
3958
3959 return (0);
3960}
3961
3962void
3963evhttp_set_gencb(struct evhttp *http,
3964 void (*cb)(struct evhttp_request *, void *), void *cbarg)
3965{
3966 http->gencb = cb;
3967 http->gencbarg = cbarg;
3968}
3969
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003970void
3971evhttp_set_bevcb(struct evhttp *http,
3972 struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg)
3973{
3974 http->bevcb = cb;
3975 http->bevcbarg = cbarg;
3976}
3977
Christopher Wileye8679812015-07-01 13:36:18 -07003978/*
3979 * Request related functions
3980 */
3981
3982struct evhttp_request *
3983evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
3984{
3985 struct evhttp_request *req = NULL;
3986
3987 /* Allocate request structure */
3988 if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) {
3989 event_warn("%s: calloc", __func__);
3990 goto error;
3991 }
3992
3993 req->headers_size = 0;
3994 req->body_size = 0;
3995
3996 req->kind = EVHTTP_RESPONSE;
3997 req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq));
3998 if (req->input_headers == NULL) {
3999 event_warn("%s: calloc", __func__);
4000 goto error;
4001 }
4002 TAILQ_INIT(req->input_headers);
4003
4004 req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq));
4005 if (req->output_headers == NULL) {
4006 event_warn("%s: calloc", __func__);
4007 goto error;
4008 }
4009 TAILQ_INIT(req->output_headers);
4010
4011 if ((req->input_buffer = evbuffer_new()) == NULL) {
4012 event_warn("%s: evbuffer_new", __func__);
4013 goto error;
4014 }
4015
4016 if ((req->output_buffer = evbuffer_new()) == NULL) {
4017 event_warn("%s: evbuffer_new", __func__);
4018 goto error;
4019 }
4020
4021 req->cb = cb;
4022 req->cb_arg = arg;
4023
4024 return (req);
4025
4026 error:
4027 if (req != NULL)
4028 evhttp_request_free(req);
4029 return (NULL);
4030}
4031
4032void
4033evhttp_request_free(struct evhttp_request *req)
4034{
4035 if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) {
4036 req->flags |= EVHTTP_REQ_NEEDS_FREE;
4037 return;
4038 }
4039
4040 if (req->remote_host != NULL)
4041 mm_free(req->remote_host);
4042 if (req->uri != NULL)
4043 mm_free(req->uri);
4044 if (req->uri_elems != NULL)
4045 evhttp_uri_free(req->uri_elems);
4046 if (req->response_code_line != NULL)
4047 mm_free(req->response_code_line);
4048 if (req->host_cache != NULL)
4049 mm_free(req->host_cache);
4050
4051 evhttp_clear_headers(req->input_headers);
4052 mm_free(req->input_headers);
4053
4054 evhttp_clear_headers(req->output_headers);
4055 mm_free(req->output_headers);
4056
4057 if (req->input_buffer != NULL)
4058 evbuffer_free(req->input_buffer);
4059
4060 if (req->output_buffer != NULL)
4061 evbuffer_free(req->output_buffer);
4062
4063 mm_free(req);
4064}
4065
4066void
4067evhttp_request_own(struct evhttp_request *req)
4068{
4069 req->flags |= EVHTTP_USER_OWNED;
4070}
4071
4072int
4073evhttp_request_is_owned(struct evhttp_request *req)
4074{
4075 return (req->flags & EVHTTP_USER_OWNED) != 0;
4076}
4077
4078struct evhttp_connection *
4079evhttp_request_get_connection(struct evhttp_request *req)
4080{
4081 return req->evcon;
4082}
4083
4084struct event_base *
4085evhttp_connection_get_base(struct evhttp_connection *conn)
4086{
4087 return conn->base;
4088}
4089
4090void
4091evhttp_request_set_chunked_cb(struct evhttp_request *req,
4092 void (*cb)(struct evhttp_request *, void *))
4093{
4094 req->chunk_cb = cb;
4095}
4096
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004097void
4098evhttp_request_set_header_cb(struct evhttp_request *req,
4099 int (*cb)(struct evhttp_request *, void *))
4100{
4101 req->header_cb = cb;
4102}
4103
4104void
4105evhttp_request_set_error_cb(struct evhttp_request *req,
4106 void (*cb)(enum evhttp_request_error, void *))
4107{
4108 req->error_cb = cb;
4109}
4110
4111void
4112evhttp_request_set_on_complete_cb(struct evhttp_request *req,
4113 void (*cb)(struct evhttp_request *, void *), void *cb_arg)
4114{
4115 req->on_complete_cb = cb;
4116 req->on_complete_cb_arg = cb_arg;
4117}
4118
Christopher Wileye8679812015-07-01 13:36:18 -07004119/*
4120 * Allows for inspection of the request URI
4121 */
4122
4123const char *
4124evhttp_request_get_uri(const struct evhttp_request *req) {
4125 if (req->uri == NULL)
4126 event_debug(("%s: request %p has no uri\n", __func__, req));
4127 return (req->uri);
4128}
4129
4130const struct evhttp_uri *
4131evhttp_request_get_evhttp_uri(const struct evhttp_request *req) {
4132 if (req->uri_elems == NULL)
4133 event_debug(("%s: request %p has no uri elems\n",
4134 __func__, req));
4135 return (req->uri_elems);
4136}
4137
4138const char *
4139evhttp_request_get_host(struct evhttp_request *req)
4140{
4141 const char *host = NULL;
4142
4143 if (req->host_cache)
4144 return req->host_cache;
4145
4146 if (req->uri_elems)
4147 host = evhttp_uri_get_host(req->uri_elems);
4148 if (!host && req->input_headers) {
4149 const char *p;
4150 size_t len;
4151
4152 host = evhttp_find_header(req->input_headers, "Host");
4153 /* The Host: header may include a port. Remove it here
4154 to be consistent with uri_elems case above. */
4155 if (host) {
4156 p = host + strlen(host) - 1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004157 while (p > host && EVUTIL_ISDIGIT_(*p))
Christopher Wileye8679812015-07-01 13:36:18 -07004158 --p;
4159 if (p > host && *p == ':') {
4160 len = p - host;
4161 req->host_cache = mm_malloc(len + 1);
4162 if (!req->host_cache) {
4163 event_warn("%s: malloc", __func__);
4164 return NULL;
4165 }
4166 memcpy(req->host_cache, host, len);
4167 req->host_cache[len] = '\0';
4168 host = req->host_cache;
4169 }
4170 }
4171 }
4172
4173 return host;
4174}
4175
4176enum evhttp_cmd_type
4177evhttp_request_get_command(const struct evhttp_request *req) {
4178 return (req->type);
4179}
4180
4181int
4182evhttp_request_get_response_code(const struct evhttp_request *req)
4183{
4184 return req->response_code;
4185}
4186
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004187const char *
4188evhttp_request_get_response_code_line(const struct evhttp_request *req)
4189{
4190 return req->response_code_line;
4191}
4192
Christopher Wileye8679812015-07-01 13:36:18 -07004193/** Returns the input headers */
4194struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req)
4195{
4196 return (req->input_headers);
4197}
4198
4199/** Returns the output headers */
4200struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req)
4201{
4202 return (req->output_headers);
4203}
4204
4205/** Returns the input buffer */
4206struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req)
4207{
4208 return (req->input_buffer);
4209}
4210
4211/** Returns the output buffer */
4212struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req)
4213{
4214 return (req->output_buffer);
4215}
4216
4217
4218/*
4219 * Takes a file descriptor to read a request from.
4220 * The callback is executed once the whole request has been read.
4221 */
4222
4223static struct evhttp_connection*
4224evhttp_get_request_connection(
4225 struct evhttp* http,
4226 evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen)
4227{
4228 struct evhttp_connection *evcon;
4229 char *hostname = NULL, *portname = NULL;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004230 struct bufferevent* bev = NULL;
Christopher Wileye8679812015-07-01 13:36:18 -07004231
Haibo Huangb2279672019-05-31 16:12:39 -07004232#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
4233 if (sa->sa_family == AF_UNIX) {
4234 struct sockaddr_un *sa_un = (struct sockaddr_un *)sa;
4235 sa_un->sun_path[0] = '\0';
4236 }
4237#endif
4238
Christopher Wileye8679812015-07-01 13:36:18 -07004239 name_from_addr(sa, salen, &hostname, &portname);
4240 if (hostname == NULL || portname == NULL) {
4241 if (hostname) mm_free(hostname);
4242 if (portname) mm_free(portname);
4243 return (NULL);
4244 }
4245
4246 event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
4247 __func__, hostname, portname, EV_SOCK_ARG(fd)));
4248
4249 /* we need a connection object to put the http request on */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004250 if (http->bevcb != NULL) {
4251 bev = (*http->bevcb)(http->base, http->bevcbarg);
4252 }
4253 evcon = evhttp_connection_base_bufferevent_new(
4254 http->base, NULL, bev, hostname, atoi(portname));
Christopher Wileye8679812015-07-01 13:36:18 -07004255 mm_free(hostname);
4256 mm_free(portname);
4257 if (evcon == NULL)
4258 return (NULL);
4259
4260 evcon->max_headers_size = http->default_max_headers_size;
4261 evcon->max_body_size = http->default_max_body_size;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004262 if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE)
4263 evcon->flags |= EVHTTP_CON_LINGERING_CLOSE;
Christopher Wileye8679812015-07-01 13:36:18 -07004264
4265 evcon->flags |= EVHTTP_CON_INCOMING;
4266 evcon->state = EVCON_READING_FIRSTLINE;
4267
4268 evcon->fd = fd;
4269
Haibo Huangb2279672019-05-31 16:12:39 -07004270 if (bufferevent_setfd(evcon->bufev, fd))
4271 goto err;
4272 if (bufferevent_enable(evcon->bufev, EV_READ))
4273 goto err;
4274 if (bufferevent_disable(evcon->bufev, EV_WRITE))
4275 goto err;
4276 bufferevent_socket_set_conn_address_(evcon->bufev, sa, salen);
Christopher Wileye8679812015-07-01 13:36:18 -07004277
4278 return (evcon);
Haibo Huangb2279672019-05-31 16:12:39 -07004279
4280err:
4281 evhttp_connection_free(evcon);
4282 return (NULL);
Christopher Wileye8679812015-07-01 13:36:18 -07004283}
4284
4285static int
4286evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
4287{
4288 struct evhttp *http = evcon->http_server;
4289 struct evhttp_request *req;
4290 if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
4291 return (-1);
4292
4293 if ((req->remote_host = mm_strdup(evcon->address)) == NULL) {
4294 event_warn("%s: strdup", __func__);
4295 evhttp_request_free(req);
4296 return (-1);
4297 }
4298 req->remote_port = evcon->port;
4299
4300 req->evcon = evcon; /* the request ends up owning the connection */
4301 req->flags |= EVHTTP_REQ_OWN_CONNECTION;
4302
4303 /* We did not present the request to the user user yet, so treat it as
4304 * if the user was done with the request. This allows us to free the
4305 * request on a persistent connection if the client drops it without
4306 * sending a request.
4307 */
4308 req->userdone = 1;
4309
4310 TAILQ_INSERT_TAIL(&evcon->requests, req, next);
4311
4312 req->kind = EVHTTP_REQUEST;
4313
4314
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004315 evhttp_start_read_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07004316
4317 return (0);
4318}
4319
4320static void
4321evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
4322 struct sockaddr *sa, ev_socklen_t salen)
4323{
4324 struct evhttp_connection *evcon;
4325
4326 evcon = evhttp_get_request_connection(http, fd, sa, salen);
4327 if (evcon == NULL) {
4328 event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT,
4329 __func__, EV_SOCK_ARG(fd));
4330 evutil_closesocket(fd);
4331 return;
4332 }
4333
4334 /* the timeout can be used by the server to close idle connections */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004335 if (evutil_timerisset(&http->timeout))
4336 evhttp_connection_set_timeout_tv(evcon, &http->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07004337
4338 /*
4339 * if we want to accept more than one request on a connection,
4340 * we need to know which http server it belongs to.
4341 */
4342 evcon->http_server = http;
4343 TAILQ_INSERT_TAIL(&http->connections, evcon, next);
4344
4345 if (evhttp_associate_new_request_with_connection(evcon) == -1)
4346 evhttp_connection_free(evcon);
4347}
4348
4349
4350/*
4351 * Network helper functions that we do not want to export to the rest of
4352 * the world.
4353 */
4354
4355static void
4356name_from_addr(struct sockaddr *sa, ev_socklen_t salen,
4357 char **phost, char **pport)
4358{
4359 char ntop[NI_MAXHOST];
4360 char strport[NI_MAXSERV];
4361 int ni_result;
4362
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004363#ifdef EVENT__HAVE_GETNAMEINFO
Christopher Wileye8679812015-07-01 13:36:18 -07004364 ni_result = getnameinfo(sa, salen,
4365 ntop, sizeof(ntop), strport, sizeof(strport),
4366 NI_NUMERICHOST|NI_NUMERICSERV);
4367
4368 if (ni_result != 0) {
4369#ifdef EAI_SYSTEM
4370 /* Windows doesn't have an EAI_SYSTEM. */
4371 if (ni_result == EAI_SYSTEM)
4372 event_err(1, "getnameinfo failed");
4373 else
4374#endif
4375 event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
4376 return;
4377 }
4378#else
4379 ni_result = fake_getnameinfo(sa, salen,
4380 ntop, sizeof(ntop), strport, sizeof(strport),
4381 NI_NUMERICHOST|NI_NUMERICSERV);
4382 if (ni_result != 0)
4383 return;
4384#endif
4385
4386 *phost = mm_strdup(ntop);
4387 *pport = mm_strdup(strport);
4388}
4389
4390/* Create a non-blocking socket and bind it */
Christopher Wileye8679812015-07-01 13:36:18 -07004391static evutil_socket_t
Haibo Huangf0077b82020-07-10 20:21:19 -07004392create_bind_socket_nonblock(struct evutil_addrinfo *ai, int reuse)
Christopher Wileye8679812015-07-01 13:36:18 -07004393{
4394 evutil_socket_t fd;
4395
4396 int on = 1, r;
4397 int serrno;
4398
4399 /* Create listen socket */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004400 fd = evutil_socket_(ai ? ai->ai_family : AF_INET,
4401 SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
Christopher Wileye8679812015-07-01 13:36:18 -07004402 if (fd == -1) {
4403 event_sock_warn(-1, "socket");
4404 return (-1);
4405 }
4406
Christopher Wileye8679812015-07-01 13:36:18 -07004407 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0)
4408 goto out;
4409 if (reuse) {
4410 if (evutil_make_listen_socket_reuseable(fd) < 0)
4411 goto out;
4412 }
4413
4414 if (ai != NULL) {
4415 r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen);
4416 if (r == -1)
4417 goto out;
4418 }
4419
4420 return (fd);
4421
4422 out:
4423 serrno = EVUTIL_SOCKET_ERROR();
4424 evutil_closesocket(fd);
4425 EVUTIL_SET_SOCKET_ERROR(serrno);
4426 return (-1);
4427}
4428
4429static struct evutil_addrinfo *
4430make_addrinfo(const char *address, ev_uint16_t port)
4431{
4432 struct evutil_addrinfo *ai = NULL;
4433
4434 struct evutil_addrinfo hints;
4435 char strport[NI_MAXSERV];
4436 int ai_result;
4437
4438 memset(&hints, 0, sizeof(hints));
4439 hints.ai_family = AF_UNSPEC;
4440 hints.ai_socktype = SOCK_STREAM;
4441 /* turn NULL hostname into INADDR_ANY, and skip looking up any address
4442 * types we don't have an interface to connect to. */
4443 hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG;
4444 evutil_snprintf(strport, sizeof(strport), "%d", port);
4445 if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai))
4446 != 0) {
4447 if (ai_result == EVUTIL_EAI_SYSTEM)
4448 event_warn("getaddrinfo");
4449 else
4450 event_warnx("getaddrinfo: %s",
4451 evutil_gai_strerror(ai_result));
4452 return (NULL);
4453 }
4454
4455 return (ai);
4456}
4457
4458static evutil_socket_t
4459bind_socket(const char *address, ev_uint16_t port, int reuse)
4460{
4461 evutil_socket_t fd;
4462 struct evutil_addrinfo *aitop = NULL;
4463
4464 /* just create an unbound socket */
4465 if (address == NULL && port == 0)
Haibo Huangf0077b82020-07-10 20:21:19 -07004466 return create_bind_socket_nonblock(NULL, 0);
Christopher Wileye8679812015-07-01 13:36:18 -07004467
4468 aitop = make_addrinfo(address, port);
4469
4470 if (aitop == NULL)
4471 return (-1);
4472
Haibo Huangf0077b82020-07-10 20:21:19 -07004473 fd = create_bind_socket_nonblock(aitop, reuse);
Christopher Wileye8679812015-07-01 13:36:18 -07004474
4475 evutil_freeaddrinfo(aitop);
4476
4477 return (fd);
4478}
4479
4480struct evhttp_uri {
4481 unsigned flags;
4482 char *scheme; /* scheme; e.g http, ftp etc */
4483 char *userinfo; /* userinfo (typically username:pass), or NULL */
4484 char *host; /* hostname, IP address, or NULL */
4485 int port; /* port, or zero */
4486 char *path; /* path, or "". */
4487 char *query; /* query, or NULL */
4488 char *fragment; /* fragment or NULL */
4489};
4490
4491struct evhttp_uri *
4492evhttp_uri_new(void)
4493{
4494 struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1);
4495 if (uri)
4496 uri->port = -1;
4497 return uri;
4498}
4499
4500void
4501evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags)
4502{
4503 uri->flags = flags;
4504}
4505
4506/* Return true if the string starting at s and ending immediately before eos
4507 * is a valid URI scheme according to RFC3986
4508 */
4509static int
4510scheme_ok(const char *s, const char *eos)
4511{
4512 /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
4513 EVUTIL_ASSERT(eos >= s);
4514 if (s == eos)
4515 return 0;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004516 if (!EVUTIL_ISALPHA_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004517 return 0;
4518 while (++s < eos) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004519 if (! EVUTIL_ISALNUM_(*s) &&
Christopher Wileye8679812015-07-01 13:36:18 -07004520 *s != '+' && *s != '-' && *s != '.')
4521 return 0;
4522 }
4523 return 1;
4524}
4525
4526#define SUBDELIMS "!$&'()*+,;="
4527
4528/* Return true iff [s..eos) is a valid userinfo */
4529static int
4530userinfo_ok(const char *s, const char *eos)
4531{
4532 while (s < eos) {
4533 if (CHAR_IS_UNRESERVED(*s) ||
4534 strchr(SUBDELIMS, *s) ||
4535 *s == ':')
4536 ++s;
4537 else if (*s == '%' && s+2 < eos &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004538 EVUTIL_ISXDIGIT_(s[1]) &&
4539 EVUTIL_ISXDIGIT_(s[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004540 s += 3;
4541 else
4542 return 0;
4543 }
4544 return 1;
4545}
4546
4547static int
4548regname_ok(const char *s, const char *eos)
4549{
4550 while (s && s<eos) {
4551 if (CHAR_IS_UNRESERVED(*s) ||
4552 strchr(SUBDELIMS, *s))
4553 ++s;
4554 else if (*s == '%' &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004555 EVUTIL_ISXDIGIT_(s[1]) &&
4556 EVUTIL_ISXDIGIT_(s[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004557 s += 3;
4558 else
4559 return 0;
4560 }
4561 return 1;
4562}
4563
4564static int
4565parse_port(const char *s, const char *eos)
4566{
4567 int portnum = 0;
4568 while (s < eos) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004569 if (! EVUTIL_ISDIGIT_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004570 return -1;
4571 portnum = (portnum * 10) + (*s - '0');
4572 if (portnum < 0)
4573 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004574 if (portnum > 65535)
4575 return -1;
Christopher Wileye8679812015-07-01 13:36:18 -07004576 ++s;
4577 }
4578 return portnum;
4579}
4580
4581/* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */
4582static int
4583bracket_addr_ok(const char *s, const char *eos)
4584{
4585 if (s + 3 > eos || *s != '[' || *(eos-1) != ']')
4586 return 0;
4587 if (s[1] == 'v') {
4588 /* IPvFuture, or junk.
4589 "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
4590 */
4591 s += 2; /* skip [v */
4592 --eos;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004593 if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/
Christopher Wileye8679812015-07-01 13:36:18 -07004594 return 0;
4595 while (s < eos && *s != '.') {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004596 if (EVUTIL_ISXDIGIT_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004597 ++s;
4598 else
4599 return 0;
4600 }
4601 if (*s != '.')
4602 return 0;
4603 ++s;
4604 while (s < eos) {
4605 if (CHAR_IS_UNRESERVED(*s) ||
4606 strchr(SUBDELIMS, *s) ||
4607 *s == ':')
4608 ++s;
4609 else
4610 return 0;
4611 }
4612 return 2;
4613 } else {
4614 /* IPv6, or junk */
4615 char buf[64];
4616 ev_ssize_t n_chars = eos-s-2;
4617 struct in6_addr in6;
4618 if (n_chars >= 64) /* way too long */
4619 return 0;
4620 memcpy(buf, s+1, n_chars);
4621 buf[n_chars]='\0';
4622 return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0;
4623 }
4624}
4625
4626static int
4627parse_authority(struct evhttp_uri *uri, char *s, char *eos)
4628{
4629 char *cp, *port;
4630 EVUTIL_ASSERT(eos);
4631 if (eos == s) {
4632 uri->host = mm_strdup("");
4633 if (uri->host == NULL) {
4634 event_warn("%s: strdup", __func__);
4635 return -1;
4636 }
4637 return 0;
4638 }
4639
4640 /* Optionally, we start with "userinfo@" */
4641
4642 cp = strchr(s, '@');
4643 if (cp && cp < eos) {
4644 if (! userinfo_ok(s,cp))
4645 return -1;
4646 *cp++ = '\0';
4647 uri->userinfo = mm_strdup(s);
4648 if (uri->userinfo == NULL) {
4649 event_warn("%s: strdup", __func__);
4650 return -1;
4651 }
4652 } else {
4653 cp = s;
4654 }
4655 /* Optionally, we end with ":port" */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004656 for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port)
Christopher Wileye8679812015-07-01 13:36:18 -07004657 ;
4658 if (port >= cp && *port == ':') {
4659 if (port+1 == eos) /* Leave port unspecified; the RFC allows a
4660 * nil port */
4661 uri->port = -1;
4662 else if ((uri->port = parse_port(port+1, eos))<0)
4663 return -1;
4664 eos = port;
4665 }
4666 /* Now, cp..eos holds the "host" port, which can be an IPv4Address,
4667 * an IP-Literal, or a reg-name */
4668 EVUTIL_ASSERT(eos >= cp);
4669 if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') {
4670 /* IPv6address, IP-Literal, or junk. */
4671 if (! bracket_addr_ok(cp, eos))
4672 return -1;
4673 } else {
4674 /* Make sure the host part is ok. */
4675 if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */
4676 return -1;
4677 }
4678 uri->host = mm_malloc(eos-cp+1);
4679 if (uri->host == NULL) {
4680 event_warn("%s: malloc", __func__);
4681 return -1;
4682 }
4683 memcpy(uri->host, cp, eos-cp);
4684 uri->host[eos-cp] = '\0';
4685 return 0;
4686
4687}
4688
4689static char *
4690end_of_authority(char *cp)
4691{
4692 while (*cp) {
4693 if (*cp == '?' || *cp == '#' || *cp == '/')
4694 return cp;
4695 ++cp;
4696 }
4697 return cp;
4698}
4699
4700enum uri_part {
4701 PART_PATH,
4702 PART_QUERY,
4703 PART_FRAGMENT
4704};
4705
4706/* Return the character after the longest prefix of 'cp' that matches...
4707 * *pchar / "/" if allow_qchars is false, or
4708 * *(pchar / "/" / "?") if allow_qchars is true.
4709 */
4710static char *
4711end_of_path(char *cp, enum uri_part part, unsigned flags)
4712{
4713 if (flags & EVHTTP_URI_NONCONFORMANT) {
4714 /* If NONCONFORMANT:
4715 * Path is everything up to a # or ? or nul.
4716 * Query is everything up a # or nul
4717 * Fragment is everything up to a nul.
4718 */
4719 switch (part) {
4720 case PART_PATH:
4721 while (*cp && *cp != '#' && *cp != '?')
4722 ++cp;
4723 break;
4724 case PART_QUERY:
4725 while (*cp && *cp != '#')
4726 ++cp;
4727 break;
4728 case PART_FRAGMENT:
4729 cp += strlen(cp);
4730 break;
4731 };
4732 return cp;
4733 }
4734
4735 while (*cp) {
4736 if (CHAR_IS_UNRESERVED(*cp) ||
4737 strchr(SUBDELIMS, *cp) ||
4738 *cp == ':' || *cp == '@' || *cp == '/')
4739 ++cp;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004740 else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) &&
4741 EVUTIL_ISXDIGIT_(cp[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004742 cp += 3;
4743 else if (*cp == '?' && part != PART_PATH)
4744 ++cp;
4745 else
4746 return cp;
4747 }
4748 return cp;
4749}
4750
4751static int
4752path_matches_noscheme(const char *cp)
4753{
4754 while (*cp) {
4755 if (*cp == ':')
4756 return 0;
4757 else if (*cp == '/')
4758 return 1;
4759 ++cp;
4760 }
4761 return 1;
4762}
4763
4764struct evhttp_uri *
4765evhttp_uri_parse(const char *source_uri)
4766{
4767 return evhttp_uri_parse_with_flags(source_uri, 0);
4768}
4769
4770struct evhttp_uri *
4771evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags)
4772{
4773 char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL;
4774 char *path = NULL, *fragment = NULL;
4775 int got_authority = 0;
4776
4777 struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
4778 if (uri == NULL) {
4779 event_warn("%s: calloc", __func__);
4780 goto err;
4781 }
4782 uri->port = -1;
4783 uri->flags = flags;
4784
4785 readbuf = mm_strdup(source_uri);
4786 if (readbuf == NULL) {
4787 event_warn("%s: strdup", __func__);
4788 goto err;
4789 }
4790
4791 readp = readbuf;
4792 token = NULL;
4793
4794 /* We try to follow RFC3986 here as much as we can, and match
4795 the productions
4796
4797 URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
4798
4799 relative-ref = relative-part [ "?" query ] [ "#" fragment ]
4800 */
4801
4802 /* 1. scheme: */
4803 token = strchr(readp, ':');
4804 if (token && scheme_ok(readp,token)) {
4805 *token = '\0';
4806 uri->scheme = mm_strdup(readp);
4807 if (uri->scheme == NULL) {
4808 event_warn("%s: strdup", __func__);
4809 goto err;
4810 }
4811 readp = token+1; /* eat : */
4812 }
4813
4814 /* 2. Optionally, "//" then an 'authority' part. */
4815 if (readp[0]=='/' && readp[1] == '/') {
4816 char *authority;
4817 readp += 2;
4818 authority = readp;
4819 path = end_of_authority(readp);
4820 if (parse_authority(uri, authority, path) < 0)
4821 goto err;
4822 readp = path;
4823 got_authority = 1;
4824 }
4825
4826 /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty
4827 */
4828 path = readp;
4829 readp = end_of_path(path, PART_PATH, flags);
4830
4831 /* Query */
4832 if (*readp == '?') {
4833 *readp = '\0';
4834 ++readp;
4835 query = readp;
4836 readp = end_of_path(readp, PART_QUERY, flags);
4837 }
4838 /* fragment */
4839 if (*readp == '#') {
4840 *readp = '\0';
4841 ++readp;
4842 fragment = readp;
4843 readp = end_of_path(readp, PART_FRAGMENT, flags);
4844 }
4845 if (*readp != '\0') {
4846 goto err;
4847 }
4848
4849 /* These next two cases may be unreachable; I'm leaving them
4850 * in to be defensive. */
4851 /* If you didn't get an authority, the path can't begin with "//" */
4852 if (!got_authority && path[0]=='/' && path[1]=='/')
4853 goto err;
4854 /* If you did get an authority, the path must begin with "/" or be
4855 * empty. */
4856 if (got_authority && path[0] != '/' && path[0] != '\0')
4857 goto err;
4858 /* (End of maybe-unreachable cases) */
4859
4860 /* If there was no scheme, the first part of the path (if any) must
4861 * have no colon in it. */
4862 if (! uri->scheme && !path_matches_noscheme(path))
4863 goto err;
4864
4865 EVUTIL_ASSERT(path);
4866 uri->path = mm_strdup(path);
4867 if (uri->path == NULL) {
4868 event_warn("%s: strdup", __func__);
4869 goto err;
4870 }
4871
4872 if (query) {
4873 uri->query = mm_strdup(query);
4874 if (uri->query == NULL) {
4875 event_warn("%s: strdup", __func__);
4876 goto err;
4877 }
4878 }
4879 if (fragment) {
4880 uri->fragment = mm_strdup(fragment);
4881 if (uri->fragment == NULL) {
4882 event_warn("%s: strdup", __func__);
4883 goto err;
4884 }
4885 }
4886
4887 mm_free(readbuf);
4888
4889 return uri;
4890err:
4891 if (uri)
4892 evhttp_uri_free(uri);
4893 if (readbuf)
4894 mm_free(readbuf);
4895 return NULL;
4896}
4897
Haibo Huangb2279672019-05-31 16:12:39 -07004898static struct evhttp_uri *
4899evhttp_uri_parse_authority(char *source_uri)
4900{
4901 struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
4902 char *end;
4903
4904 if (uri == NULL) {
4905 event_warn("%s: calloc", __func__);
4906 goto err;
4907 }
4908 uri->port = -1;
4909 uri->flags = 0;
4910
4911 end = end_of_authority(source_uri);
4912 if (parse_authority(uri, source_uri, end) < 0)
4913 goto err;
4914
4915 uri->path = mm_strdup("");
4916 if (uri->path == NULL) {
4917 event_warn("%s: strdup", __func__);
4918 goto err;
4919 }
4920
4921 return uri;
4922err:
4923 if (uri)
4924 evhttp_uri_free(uri);
4925 return NULL;
4926}
4927
Christopher Wileye8679812015-07-01 13:36:18 -07004928void
4929evhttp_uri_free(struct evhttp_uri *uri)
4930{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004931#define URI_FREE_STR_(f) \
Christopher Wileye8679812015-07-01 13:36:18 -07004932 if (uri->f) { \
4933 mm_free(uri->f); \
4934 }
4935
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004936 URI_FREE_STR_(scheme);
4937 URI_FREE_STR_(userinfo);
4938 URI_FREE_STR_(host);
4939 URI_FREE_STR_(path);
4940 URI_FREE_STR_(query);
4941 URI_FREE_STR_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07004942
4943 mm_free(uri);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004944#undef URI_FREE_STR_
Christopher Wileye8679812015-07-01 13:36:18 -07004945}
4946
4947char *
4948evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
4949{
4950 struct evbuffer *tmp = 0;
4951 size_t joined_size = 0;
4952 char *output = NULL;
4953
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004954#define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f))
Christopher Wileye8679812015-07-01 13:36:18 -07004955
4956 if (!uri || !buf || !limit)
4957 return NULL;
4958
4959 tmp = evbuffer_new();
4960 if (!tmp)
4961 return NULL;
4962
4963 if (uri->scheme) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004964 URI_ADD_(scheme);
Christopher Wileye8679812015-07-01 13:36:18 -07004965 evbuffer_add(tmp, ":", 1);
4966 }
4967 if (uri->host) {
4968 evbuffer_add(tmp, "//", 2);
4969 if (uri->userinfo)
4970 evbuffer_add_printf(tmp,"%s@", uri->userinfo);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004971 URI_ADD_(host);
Christopher Wileye8679812015-07-01 13:36:18 -07004972 if (uri->port >= 0)
4973 evbuffer_add_printf(tmp,":%d", uri->port);
4974
4975 if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0')
4976 goto err;
4977 }
4978
4979 if (uri->path)
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004980 URI_ADD_(path);
Christopher Wileye8679812015-07-01 13:36:18 -07004981
4982 if (uri->query) {
4983 evbuffer_add(tmp, "?", 1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004984 URI_ADD_(query);
Christopher Wileye8679812015-07-01 13:36:18 -07004985 }
4986
4987 if (uri->fragment) {
4988 evbuffer_add(tmp, "#", 1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004989 URI_ADD_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07004990 }
4991
4992 evbuffer_add(tmp, "\0", 1); /* NUL */
4993
4994 joined_size = evbuffer_get_length(tmp);
4995
4996 if (joined_size > limit) {
4997 /* It doesn't fit. */
4998 evbuffer_free(tmp);
4999 return NULL;
5000 }
5001 evbuffer_remove(tmp, buf, joined_size);
5002
5003 output = buf;
5004err:
5005 evbuffer_free(tmp);
5006
5007 return output;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005008#undef URI_ADD_
Christopher Wileye8679812015-07-01 13:36:18 -07005009}
5010
5011const char *
5012evhttp_uri_get_scheme(const struct evhttp_uri *uri)
5013{
5014 return uri->scheme;
5015}
5016const char *
5017evhttp_uri_get_userinfo(const struct evhttp_uri *uri)
5018{
5019 return uri->userinfo;
5020}
5021const char *
5022evhttp_uri_get_host(const struct evhttp_uri *uri)
5023{
5024 return uri->host;
5025}
5026int
5027evhttp_uri_get_port(const struct evhttp_uri *uri)
5028{
5029 return uri->port;
5030}
5031const char *
5032evhttp_uri_get_path(const struct evhttp_uri *uri)
5033{
5034 return uri->path;
5035}
5036const char *
5037evhttp_uri_get_query(const struct evhttp_uri *uri)
5038{
5039 return uri->query;
5040}
5041const char *
5042evhttp_uri_get_fragment(const struct evhttp_uri *uri)
5043{
5044 return uri->fragment;
5045}
5046
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005047#define URI_SET_STR_(f) do { \
Christopher Wileye8679812015-07-01 13:36:18 -07005048 if (uri->f) \
5049 mm_free(uri->f); \
5050 if (f) { \
5051 if ((uri->f = mm_strdup(f)) == NULL) { \
5052 event_warn("%s: strdup()", __func__); \
5053 return -1; \
5054 } \
5055 } else { \
5056 uri->f = NULL; \
5057 } \
5058 } while(0)
5059
5060int
5061evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme)
5062{
5063 if (scheme && !scheme_ok(scheme, scheme+strlen(scheme)))
5064 return -1;
5065
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005066 URI_SET_STR_(scheme);
Christopher Wileye8679812015-07-01 13:36:18 -07005067 return 0;
5068}
5069int
5070evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo)
5071{
5072 if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo)))
5073 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005074 URI_SET_STR_(userinfo);
Christopher Wileye8679812015-07-01 13:36:18 -07005075 return 0;
5076}
5077int
5078evhttp_uri_set_host(struct evhttp_uri *uri, const char *host)
5079{
5080 if (host) {
5081 if (host[0] == '[') {
5082 if (! bracket_addr_ok(host, host+strlen(host)))
5083 return -1;
5084 } else {
5085 if (! regname_ok(host, host+strlen(host)))
5086 return -1;
5087 }
5088 }
5089
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005090 URI_SET_STR_(host);
Christopher Wileye8679812015-07-01 13:36:18 -07005091 return 0;
5092}
5093int
5094evhttp_uri_set_port(struct evhttp_uri *uri, int port)
5095{
5096 if (port < -1)
5097 return -1;
5098 uri->port = port;
5099 return 0;
5100}
5101#define end_of_cpath(cp,p,f) \
5102 ((const char*)(end_of_path(((char*)(cp)), (p), (f))))
5103
5104int
5105evhttp_uri_set_path(struct evhttp_uri *uri, const char *path)
5106{
5107 if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path))
5108 return -1;
5109
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005110 URI_SET_STR_(path);
Christopher Wileye8679812015-07-01 13:36:18 -07005111 return 0;
5112}
5113int
5114evhttp_uri_set_query(struct evhttp_uri *uri, const char *query)
5115{
5116 if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query))
5117 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005118 URI_SET_STR_(query);
Christopher Wileye8679812015-07-01 13:36:18 -07005119 return 0;
5120}
5121int
5122evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment)
5123{
5124 if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment))
5125 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005126 URI_SET_STR_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07005127 return 0;
5128}