blob: f5a2ef931a5f3b5ef605eae807a5cfbc490442ee [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>
Christopher Wileye8679812015-07-01 13:36:18 -070054#else
55#include <winsock2.h>
56#include <ws2tcpip.h>
57#endif
58
59#include <sys/queue.h>
60
Narayan Kamathfc74cb42017-09-13 12:53:52 +010061#ifdef EVENT__HAVE_NETINET_IN_H
Christopher Wileye8679812015-07-01 13:36:18 -070062#include <netinet/in.h>
63#endif
Narayan Kamathfc74cb42017-09-13 12:53:52 +010064#ifdef EVENT__HAVE_ARPA_INET_H
Christopher Wileye8679812015-07-01 13:36:18 -070065#include <arpa/inet.h>
66#endif
Narayan Kamathfc74cb42017-09-13 12:53:52 +010067#ifdef EVENT__HAVE_NETDB_H
Christopher Wileye8679812015-07-01 13:36:18 -070068#include <netdb.h>
69#endif
70
Narayan Kamathfc74cb42017-09-13 12:53:52 +010071#ifdef _WIN32
Christopher Wileye8679812015-07-01 13:36:18 -070072#include <winsock2.h>
73#endif
74
75#include <errno.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
Narayan Kamathfc74cb42017-09-13 12:53:52 +010079#ifndef _WIN32
Christopher Wileye8679812015-07-01 13:36:18 -070080#include <syslog.h>
81#endif
82#include <signal.h>
Narayan Kamathfc74cb42017-09-13 12:53:52 +010083#ifdef EVENT__HAVE_UNISTD_H
Christopher Wileye8679812015-07-01 13:36:18 -070084#include <unistd.h>
85#endif
Narayan Kamathfc74cb42017-09-13 12:53:52 +010086#ifdef EVENT__HAVE_FCNTL_H
Christopher Wileye8679812015-07-01 13:36:18 -070087#include <fcntl.h>
88#endif
89
90#undef timeout_pending
91#undef timeout_initialized
92
93#include "strlcpy-internal.h"
94#include "event2/http.h"
95#include "event2/event.h"
96#include "event2/buffer.h"
97#include "event2/bufferevent.h"
Christopher Wileye8679812015-07-01 13:36:18 -070098#include "event2/http_struct.h"
99#include "event2/http_compat.h"
100#include "event2/util.h"
101#include "event2/listener.h"
102#include "log-internal.h"
103#include "util-internal.h"
104#include "http-internal.h"
105#include "mm-internal.h"
106#include "bufferevent-internal.h"
107
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100108#ifndef EVENT__HAVE_GETNAMEINFO
Christopher Wileye8679812015-07-01 13:36:18 -0700109#define NI_MAXSERV 32
110#define NI_MAXHOST 1025
111
112#ifndef NI_NUMERICHOST
113#define NI_NUMERICHOST 1
114#endif
115
116#ifndef NI_NUMERICSERV
117#define NI_NUMERICSERV 2
118#endif
119
120static int
121fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
122 size_t hostlen, char *serv, size_t servlen, int flags)
123{
124 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
125
126 if (serv != NULL) {
127 char tmpserv[16];
128 evutil_snprintf(tmpserv, sizeof(tmpserv),
129 "%d", ntohs(sin->sin_port));
130 if (strlcpy(serv, tmpserv, servlen) >= servlen)
131 return (-1);
132 }
133
134 if (host != NULL) {
135 if (flags & NI_NUMERICHOST) {
136 if (strlcpy(host, inet_ntoa(sin->sin_addr),
137 hostlen) >= hostlen)
138 return (-1);
139 else
140 return (0);
141 } else {
142 struct hostent *hp;
143 hp = gethostbyaddr((char *)&sin->sin_addr,
144 sizeof(struct in_addr), AF_INET);
145 if (hp == NULL)
146 return (-2);
147
148 if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
149 return (-1);
150 else
151 return (0);
152 }
153 }
154 return (0);
155}
156
157#endif
158
159#define REQ_VERSION_BEFORE(req, major_v, minor_v) \
160 ((req)->major < (major_v) || \
161 ((req)->major == (major_v) && (req)->minor < (minor_v)))
162
163#define REQ_VERSION_ATLEAST(req, major_v, minor_v) \
164 ((req)->major > (major_v) || \
165 ((req)->major == (major_v) && (req)->minor >= (minor_v)))
166
167#ifndef MIN
168#define MIN(a,b) (((a)<(b))?(a):(b))
169#endif
170
171extern int debug;
172
173static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse);
174static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
175static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
176static int evhttp_associate_new_request_with_connection(
177 struct evhttp_connection *evcon);
178static void evhttp_connection_start_detectclose(
179 struct evhttp_connection *evcon);
180static void evhttp_connection_stop_detectclose(
181 struct evhttp_connection *evcon);
182static void evhttp_request_dispatch(struct evhttp_connection* evcon);
183static void evhttp_read_firstline(struct evhttp_connection *evcon,
184 struct evhttp_request *req);
185static void evhttp_read_header(struct evhttp_connection *evcon,
186 struct evhttp_request *req);
187static int evhttp_add_header_internal(struct evkeyvalq *headers,
188 const char *key, const char *value);
189static const char *evhttp_response_phrase_internal(int code);
190static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t);
191static void evhttp_write_buffer(struct evhttp_connection *,
192 void (*)(struct evhttp_connection *, void *), void *);
193static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
194
195/* callbacks for bufferevent */
196static void evhttp_read_cb(struct bufferevent *, void *);
197static void evhttp_write_cb(struct bufferevent *, void *);
198static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg);
Christopher Wileye8679812015-07-01 13:36:18 -0700199static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
200 const char *hostname);
201
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100202#ifndef EVENT__HAVE_STRSEP
Christopher Wileye8679812015-07-01 13:36:18 -0700203/* strsep replacement for platforms that lack it. Only works if
204 * del is one character long. */
205static char *
206strsep(char **s, const char *del)
207{
208 char *d, *tok;
209 EVUTIL_ASSERT(strlen(del) == 1);
210 if (!s || !*s)
211 return NULL;
212 tok = *s;
213 d = strstr(tok, del);
214 if (d) {
215 *d = '\0';
216 *s = d + 1;
217 } else
218 *s = NULL;
219 return tok;
220}
221#endif
222
223static size_t
224html_replace(const char ch, const char **escaped)
225{
226 switch (ch) {
227 case '<':
228 *escaped = "&lt;";
229 return 4;
230 case '>':
231 *escaped = "&gt;";
232 return 4;
233 case '"':
234 *escaped = "&quot;";
235 return 6;
236 case '\'':
237 *escaped = "&#039;";
238 return 6;
239 case '&':
240 *escaped = "&amp;";
241 return 5;
242 default:
243 break;
244 }
245
246 return 1;
247}
248
249/*
250 * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
251 * &#039; and &amp; correspondingly.
252 *
253 * The returned string needs to be freed by the caller.
254 */
255
256char *
257evhttp_htmlescape(const char *html)
258{
259 size_t i;
260 size_t new_size = 0, old_size = 0;
261 char *escaped_html, *p;
262
263 if (html == NULL)
264 return (NULL);
265
266 old_size = strlen(html);
267 for (i = 0; i < old_size; ++i) {
268 const char *replaced = NULL;
269 const size_t replace_size = html_replace(html[i], &replaced);
270 if (replace_size > EV_SIZE_MAX - new_size) {
271 event_warn("%s: html_replace overflow", __func__);
272 return (NULL);
273 }
274 new_size += replace_size;
275 }
276
277 if (new_size == EV_SIZE_MAX)
278 return (NULL);
279 p = escaped_html = mm_malloc(new_size + 1);
280 if (escaped_html == NULL) {
281 event_warn("%s: malloc(%lu)", __func__,
282 (unsigned long)(new_size + 1));
283 return (NULL);
284 }
285 for (i = 0; i < old_size; ++i) {
286 const char *replaced = &html[i];
287 const size_t len = html_replace(html[i], &replaced);
288 memcpy(p, replaced, len);
289 p += len;
290 }
291
292 *p = '\0';
293
294 return (escaped_html);
295}
296
297/** Given an evhttp_cmd_type, returns a constant string containing the
298 * equivalent HTTP command, or NULL if the evhttp_command_type is
299 * unrecognized. */
300static const char *
301evhttp_method(enum evhttp_cmd_type type)
302{
303 const char *method;
304
305 switch (type) {
306 case EVHTTP_REQ_GET:
307 method = "GET";
308 break;
309 case EVHTTP_REQ_POST:
310 method = "POST";
311 break;
312 case EVHTTP_REQ_HEAD:
313 method = "HEAD";
314 break;
315 case EVHTTP_REQ_PUT:
316 method = "PUT";
317 break;
318 case EVHTTP_REQ_DELETE:
319 method = "DELETE";
320 break;
321 case EVHTTP_REQ_OPTIONS:
322 method = "OPTIONS";
323 break;
324 case EVHTTP_REQ_TRACE:
325 method = "TRACE";
326 break;
327 case EVHTTP_REQ_CONNECT:
328 method = "CONNECT";
329 break;
330 case EVHTTP_REQ_PATCH:
331 method = "PATCH";
332 break;
333 default:
334 method = NULL;
335 break;
336 }
337
338 return (method);
339}
340
341/**
342 * Determines if a response should have a body.
343 * Follows the rules in RFC 2616 section 4.3.
344 * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
345 * a body.
346 */
347static int
348evhttp_response_needs_body(struct evhttp_request *req)
349{
350 return (req->response_code != HTTP_NOCONTENT &&
351 req->response_code != HTTP_NOTMODIFIED &&
352 (req->response_code < 100 || req->response_code >= 200) &&
353 req->type != EVHTTP_REQ_HEAD);
354}
355
Christopher Wileye8679812015-07-01 13:36:18 -0700356/** Helper: called after we've added some data to an evcon's bufferevent's
357 * output buffer. Sets the evconn's writing-is-done callback, and puts
358 * the bufferevent into writing mode.
359 */
360static void
361evhttp_write_buffer(struct evhttp_connection *evcon,
362 void (*cb)(struct evhttp_connection *, void *), void *arg)
363{
364 event_debug(("%s: preparing to write buffer\n", __func__));
365
366 /* Set call back */
367 evcon->cb = cb;
368 evcon->cb_arg = arg;
369
370 /* Disable the read callback: we don't actually care about data;
371 * we only care about close detection. (We don't disable reading,
372 * since we *do* want to learn about any close events.) */
373 bufferevent_setcb(evcon->bufev,
374 NULL, /*read*/
375 evhttp_write_cb,
376 evhttp_error_cb,
377 evcon);
378
379 bufferevent_enable(evcon->bufev, EV_WRITE);
380}
381
382static void
383evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg)
384{
385 bufferevent_disable(evcon->bufev, EV_WRITE);
386}
387
388static void
389evhttp_send_continue(struct evhttp_connection *evcon,
390 struct evhttp_request *req)
391{
392 bufferevent_enable(evcon->bufev, EV_WRITE);
393 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
394 "HTTP/%d.%d 100 Continue\r\n\r\n",
395 req->major, req->minor);
396 evcon->cb = evhttp_send_continue_done;
397 evcon->cb_arg = NULL;
398 bufferevent_setcb(evcon->bufev,
399 evhttp_read_cb,
400 evhttp_write_cb,
401 evhttp_error_cb,
402 evcon);
403}
404
405/** Helper: returns true iff evconn is in any connected state. */
406static int
407evhttp_connected(struct evhttp_connection *evcon)
408{
409 switch (evcon->state) {
410 case EVCON_DISCONNECTED:
411 case EVCON_CONNECTING:
412 return (0);
413 case EVCON_IDLE:
414 case EVCON_READING_FIRSTLINE:
415 case EVCON_READING_HEADERS:
416 case EVCON_READING_BODY:
417 case EVCON_READING_TRAILER:
418 case EVCON_WRITING:
419 default:
420 return (1);
421 }
422}
423
424/* Create the headers needed for an outgoing HTTP request, adds them to
425 * the request's header list, and writes the request line to the
426 * connection's output buffer.
427 */
428static void
429evhttp_make_header_request(struct evhttp_connection *evcon,
430 struct evhttp_request *req)
431{
432 const char *method;
433
434 evhttp_remove_header(req->output_headers, "Proxy-Connection");
435
436 /* Generate request line */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100437 if (!(method = evhttp_method(req->type))) {
438 method = "NULL";
439 }
440
Christopher Wileye8679812015-07-01 13:36:18 -0700441 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
442 "%s %s HTTP/%d.%d\r\n",
443 method, req->uri, req->major, req->minor);
444
445 /* Add the content length on a post or put request if missing */
446 if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
447 evhttp_find_header(req->output_headers, "Content-Length") == NULL){
448 char size[22];
449 evutil_snprintf(size, sizeof(size), EV_SIZE_FMT,
450 EV_SIZE_ARG(evbuffer_get_length(req->output_buffer)));
451 evhttp_add_header(req->output_headers, "Content-Length", size);
452 }
453}
454
455/** Return true if the list of headers in 'headers', intepreted with respect
456 * to flags, means that we should send a "connection: close" when the request
457 * is done. */
458static int
459evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
460{
461 if (flags & EVHTTP_PROXY_REQUEST) {
462 /* proxy connection */
463 const char *connection = evhttp_find_header(headers, "Proxy-Connection");
464 return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0);
465 } else {
466 const char *connection = evhttp_find_header(headers, "Connection");
467 return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0);
468 }
469}
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100470static int
471evhttp_is_request_connection_close(struct evhttp_request *req)
472{
473 return
474 evhttp_is_connection_close(req->flags, req->input_headers) ||
475 evhttp_is_connection_close(req->flags, req->output_headers);
476}
Christopher Wileye8679812015-07-01 13:36:18 -0700477
478/* Return true iff 'headers' contains 'Connection: keep-alive' */
479static int
480evhttp_is_connection_keepalive(struct evkeyvalq* headers)
481{
482 const char *connection = evhttp_find_header(headers, "Connection");
483 return (connection != NULL
484 && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0);
485}
486
487/* Add a correct "Date" header to headers, unless it already has one. */
488static void
489evhttp_maybe_add_date_header(struct evkeyvalq *headers)
490{
491 if (evhttp_find_header(headers, "Date") == NULL) {
492 char date[50];
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100493 if (sizeof(date) - evutil_date_rfc1123(date, sizeof(date), NULL) > 0) {
Christopher Wileye8679812015-07-01 13:36:18 -0700494 evhttp_add_header(headers, "Date", date);
495 }
496 }
497}
498
499/* Add a "Content-Length" header with value 'content_length' to headers,
500 * unless it already has a content-length or transfer-encoding header. */
501static void
502evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
503 size_t content_length)
504{
505 if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
506 evhttp_find_header(headers, "Content-Length") == NULL) {
507 char len[22];
508 evutil_snprintf(len, sizeof(len), EV_SIZE_FMT,
509 EV_SIZE_ARG(content_length));
510 evhttp_add_header(headers, "Content-Length", len);
511 }
512}
513
514/*
515 * Create the headers needed for an HTTP reply in req->output_headers,
516 * and write the first HTTP response for req line to evcon.
517 */
518static void
519evhttp_make_header_response(struct evhttp_connection *evcon,
520 struct evhttp_request *req)
521{
522 int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
523 evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
524 "HTTP/%d.%d %d %s\r\n",
525 req->major, req->minor, req->response_code,
526 req->response_code_line);
527
528 if (req->major == 1) {
529 if (req->minor >= 1)
530 evhttp_maybe_add_date_header(req->output_headers);
531
532 /*
533 * if the protocol is 1.0; and the connection was keep-alive
534 * we need to add a keep-alive header, too.
535 */
536 if (req->minor == 0 && is_keepalive)
537 evhttp_add_header(req->output_headers,
538 "Connection", "keep-alive");
539
540 if ((req->minor >= 1 || is_keepalive) &&
541 evhttp_response_needs_body(req)) {
542 /*
543 * we need to add the content length if the
544 * user did not give it, this is required for
545 * persistent connections to work.
546 */
547 evhttp_maybe_add_content_length_header(
548 req->output_headers,
549 evbuffer_get_length(req->output_buffer));
550 }
551 }
552
553 /* Potentially add headers for unidentified content. */
554 if (evhttp_response_needs_body(req)) {
555 if (evhttp_find_header(req->output_headers,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100556 "Content-Type") == NULL
557 && evcon->http_server->default_content_type) {
Christopher Wileye8679812015-07-01 13:36:18 -0700558 evhttp_add_header(req->output_headers,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100559 "Content-Type",
560 evcon->http_server->default_content_type);
Christopher Wileye8679812015-07-01 13:36:18 -0700561 }
562 }
563
564 /* if the request asked for a close, we send a close, too */
565 if (evhttp_is_connection_close(req->flags, req->input_headers)) {
566 evhttp_remove_header(req->output_headers, "Connection");
567 if (!(req->flags & EVHTTP_PROXY_REQUEST))
568 evhttp_add_header(req->output_headers, "Connection", "close");
569 evhttp_remove_header(req->output_headers, "Proxy-Connection");
570 }
571}
572
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100573enum expect { NO, CONTINUE, OTHER };
574static enum expect evhttp_have_expect(struct evhttp_request *req, int input)
575{
576 const char *expect;
577 struct evkeyvalq *h = input ? req->input_headers : req->output_headers;
578
579 if (!(req->kind == EVHTTP_REQUEST) || !REQ_VERSION_ATLEAST(req, 1, 1))
580 return NO;
581
582 expect = evhttp_find_header(h, "Expect");
583 if (!expect)
584 return NO;
585
586 return !evutil_ascii_strcasecmp(expect, "100-continue") ? CONTINUE : OTHER;
587}
588
589
Christopher Wileye8679812015-07-01 13:36:18 -0700590/** Generate all headers appropriate for sending the http request in req (or
591 * the response, if we're sending a response), and write them to evcon's
592 * bufferevent. Also writes all data from req->output_buffer */
593static void
594evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
595{
596 struct evkeyval *header;
597 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
598
599 /*
600 * Depending if this is a HTTP request or response, we might need to
601 * add some new headers or remove existing headers.
602 */
603 if (req->kind == EVHTTP_REQUEST) {
604 evhttp_make_header_request(evcon, req);
605 } else {
606 evhttp_make_header_response(evcon, req);
607 }
608
609 TAILQ_FOREACH(header, req->output_headers, next) {
610 evbuffer_add_printf(output, "%s: %s\r\n",
611 header->key, header->value);
612 }
613 evbuffer_add(output, "\r\n", 2);
614
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100615 if (evhttp_have_expect(req, 0) != CONTINUE &&
616 evbuffer_get_length(req->output_buffer)) {
Christopher Wileye8679812015-07-01 13:36:18 -0700617 /*
618 * For a request, we add the POST data, for a reply, this
619 * is the regular data.
620 */
Christopher Wileye8679812015-07-01 13:36:18 -0700621 evbuffer_add_buffer(output, req->output_buffer);
622 }
623}
624
625void
626evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon,
627 ev_ssize_t new_max_headers_size)
628{
629 if (new_max_headers_size<0)
630 evcon->max_headers_size = EV_SIZE_MAX;
631 else
632 evcon->max_headers_size = new_max_headers_size;
633}
634void
635evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
636 ev_ssize_t new_max_body_size)
637{
638 if (new_max_body_size<0)
639 evcon->max_body_size = EV_UINT64_MAX;
640 else
641 evcon->max_body_size = new_max_body_size;
642}
643
644static int
645evhttp_connection_incoming_fail(struct evhttp_request *req,
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100646 enum evhttp_request_error error)
Christopher Wileye8679812015-07-01 13:36:18 -0700647{
648 switch (error) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100649 case EVREQ_HTTP_DATA_TOO_LONG:
650 req->response_code = HTTP_ENTITYTOOLARGE;
651 break;
652 default:
653 req->response_code = HTTP_BADREQUEST;
654 }
655
656 switch (error) {
657 case EVREQ_HTTP_TIMEOUT:
658 case EVREQ_HTTP_EOF:
Christopher Wileye8679812015-07-01 13:36:18 -0700659 /*
660 * these are cases in which we probably should just
661 * close the connection and not send a reply. this
662 * case may happen when a browser keeps a persistent
663 * connection open and we timeout on the read. when
664 * the request is still being used for sending, we
665 * need to disassociated it from the connection here.
666 */
667 if (!req->userdone) {
668 /* remove it so that it will not be freed */
669 TAILQ_REMOVE(&req->evcon->requests, req, next);
670 /* indicate that this request no longer has a
671 * connection object
672 */
673 req->evcon = NULL;
674 }
675 return (-1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100676 case EVREQ_HTTP_INVALID_HEADER:
677 case EVREQ_HTTP_BUFFER_ERROR:
678 case EVREQ_HTTP_REQUEST_CANCEL:
679 case EVREQ_HTTP_DATA_TOO_LONG:
Christopher Wileye8679812015-07-01 13:36:18 -0700680 default: /* xxx: probably should just error on default */
681 /* the callback looks at the uri to determine errors */
682 if (req->uri) {
683 mm_free(req->uri);
684 req->uri = NULL;
685 }
686 if (req->uri_elems) {
687 evhttp_uri_free(req->uri_elems);
688 req->uri_elems = NULL;
689 }
690
691 /*
692 * the callback needs to send a reply, once the reply has
693 * been send, the connection should get freed.
694 */
695 (*req->cb)(req, req->cb_arg);
696 }
697
698 return (0);
699}
700
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100701/* Free connection ownership of which can be acquired by user using
702 * evhttp_request_own(). */
703static inline void
704evhttp_request_free_auto(struct evhttp_request *req)
705{
706 if (!(req->flags & EVHTTP_USER_OWNED))
707 evhttp_request_free(req);
708}
709
710static void
711evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req)
712{
713 TAILQ_REMOVE(&evcon->requests, req, next);
714 evhttp_request_free_auto(req);
715}
716
Christopher Wileye8679812015-07-01 13:36:18 -0700717/* Called when evcon has experienced a (non-recoverable? -NM) error, as
718 * given in error. If it's an outgoing connection, reset the connection,
719 * retry any pending requests, and inform the user. If it's incoming,
720 * delegates to evhttp_connection_incoming_fail(). */
721void
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100722evhttp_connection_fail_(struct evhttp_connection *evcon,
723 enum evhttp_request_error error)
Christopher Wileye8679812015-07-01 13:36:18 -0700724{
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100725 const int errsave = EVUTIL_SOCKET_ERROR();
Christopher Wileye8679812015-07-01 13:36:18 -0700726 struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
727 void (*cb)(struct evhttp_request *, void *);
728 void *cb_arg;
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100729 void (*error_cb)(enum evhttp_request_error, void *);
730 void *error_cb_arg;
Christopher Wileye8679812015-07-01 13:36:18 -0700731 EVUTIL_ASSERT(req != NULL);
732
733 bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
734
735 if (evcon->flags & EVHTTP_CON_INCOMING) {
736 /*
737 * for incoming requests, there are two different
738 * failure cases. it's either a network level error
739 * or an http layer error. for problems on the network
740 * layer like timeouts we just drop the connections.
741 * For HTTP problems, we might have to send back a
742 * reply before the connection can be freed.
743 */
744 if (evhttp_connection_incoming_fail(req, error) == -1)
745 evhttp_connection_free(evcon);
746 return;
747 }
748
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100749 error_cb = req->error_cb;
750 error_cb_arg = req->cb_arg;
Christopher Wileye8679812015-07-01 13:36:18 -0700751 /* when the request was canceled, the callback is not executed */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100752 if (error != EVREQ_HTTP_REQUEST_CANCEL) {
Christopher Wileye8679812015-07-01 13:36:18 -0700753 /* save the callback for later; the cb might free our object */
754 cb = req->cb;
755 cb_arg = req->cb_arg;
756 } else {
757 cb = NULL;
758 cb_arg = NULL;
759 }
760
761 /* do not fail all requests; the next request is going to get
762 * send over a new connection. when a user cancels a request,
763 * all other pending requests should be processed as normal
764 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100765 evhttp_request_free_(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -0700766
767 /* reset the connection */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100768 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700769
770 /* We are trying the next request that was queued on us */
771 if (TAILQ_FIRST(&evcon->requests) != NULL)
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100772 evhttp_connection_connect_(evcon);
773
774 /* The call to evhttp_connection_reset_ overwrote errno.
775 * Let's restore the original errno, so that the user's
776 * callback can have a better idea of what the error was.
777 */
778 EVUTIL_SET_SOCKET_ERROR(errsave);
Christopher Wileye8679812015-07-01 13:36:18 -0700779
780 /* inform the user */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100781 if (error_cb != NULL)
782 error_cb(error, error_cb_arg);
Christopher Wileye8679812015-07-01 13:36:18 -0700783 if (cb != NULL)
784 (*cb)(NULL, cb_arg);
785}
786
787/* Bufferevent callback: invoked when any data has been written from an
788 * http connection's bufferevent */
789static void
790evhttp_write_cb(struct bufferevent *bufev, void *arg)
791{
792 struct evhttp_connection *evcon = arg;
793
794 /* Activate our call back */
795 if (evcon->cb != NULL)
796 (*evcon->cb)(evcon, evcon->cb_arg);
797}
798
799/**
800 * Advance the connection state.
801 * - If this is an outgoing connection, we've just processed the response;
802 * idle or close the connection.
803 * - If this is an incoming connection, we've just processed the request;
804 * respond.
805 */
806static void
807evhttp_connection_done(struct evhttp_connection *evcon)
808{
809 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
810 int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100811 int free_evcon = 0;
Christopher Wileye8679812015-07-01 13:36:18 -0700812
813 if (con_outgoing) {
814 /* idle or close the connection */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100815 int need_close = evhttp_is_request_connection_close(req);
Christopher Wileye8679812015-07-01 13:36:18 -0700816 TAILQ_REMOVE(&evcon->requests, req, next);
817 req->evcon = NULL;
818
819 evcon->state = EVCON_IDLE;
820
Christopher Wileye8679812015-07-01 13:36:18 -0700821 /* check if we got asked to close the connection */
822 if (need_close)
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100823 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700824
825 if (TAILQ_FIRST(&evcon->requests) != NULL) {
826 /*
827 * We have more requests; reset the connection
828 * and deal with the next request.
829 */
830 if (!evhttp_connected(evcon))
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100831 evhttp_connection_connect_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700832 else
833 evhttp_request_dispatch(evcon);
834 } else if (!need_close) {
835 /*
836 * The connection is going to be persistent, but we
837 * need to detect if the other side closes it.
838 */
839 evhttp_connection_start_detectclose(evcon);
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100840 } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) {
841 /*
842 * If we have no more requests that need completion
843 * and we're not waiting for the connection to close
844 */
845 free_evcon = 1;
Christopher Wileye8679812015-07-01 13:36:18 -0700846 }
847 } else {
848 /*
849 * incoming connection - we need to leave the request on the
850 * connection so that we can reply to it.
851 */
852 evcon->state = EVCON_WRITING;
853 }
854
855 /* notify the user of the request */
856 (*req->cb)(req, req->cb_arg);
857
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100858 /* if this was an outgoing request, we own and it's done. so free it. */
859 if (con_outgoing) {
860 evhttp_request_free_auto(req);
861 }
862
863 /* If this was the last request of an outgoing connection and we're
864 * not waiting to receive a connection close event and we want to
865 * automatically free the connection. We check to ensure our request
866 * list is empty one last time just in case our callback added a
867 * new request.
Christopher Wileye8679812015-07-01 13:36:18 -0700868 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100869 if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) {
870 evhttp_connection_free(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -0700871 }
872}
873
874/*
875 * Handles reading from a chunked request.
876 * return ALL_DATA_READ:
877 * all data has been read
878 * return MORE_DATA_EXPECTED:
879 * more data is expected
880 * return DATA_CORRUPTED:
881 * data is corrupted
882 * return REQUEST_CANCELED:
883 * request was canceled by the user calling evhttp_cancel_request
884 * return DATA_TOO_LONG:
885 * ran over the maximum limit
886 */
887
888static enum message_read_status
889evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
890{
891 if (req == NULL || buf == NULL) {
892 return DATA_CORRUPTED;
893 }
894
895 while (1) {
896 size_t buflen;
897
898 if ((buflen = evbuffer_get_length(buf)) == 0) {
899 break;
900 }
901
902 /* evbuffer_get_length returns size_t, but len variable is ssize_t,
903 * check for overflow conditions */
904 if (buflen > EV_SSIZE_MAX) {
905 return DATA_CORRUPTED;
906 }
907
908 if (req->ntoread < 0) {
909 /* Read chunk size */
910 ev_int64_t ntoread;
911 char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF);
912 char *endp;
913 int error;
914 if (p == NULL)
915 break;
916 /* the last chunk is on a new line? */
917 if (strlen(p) == 0) {
918 mm_free(p);
919 continue;
920 }
921 ntoread = evutil_strtoll(p, &endp, 16);
922 error = (*p == '\0' ||
923 (*endp != '\0' && *endp != ' ') ||
924 ntoread < 0);
925 mm_free(p);
926 if (error) {
927 /* could not get chunk size */
928 return (DATA_CORRUPTED);
929 }
930
931 /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */
932 if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) {
933 return DATA_CORRUPTED;
934 }
935
936 if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) {
937 /* failed body length test */
938 event_debug(("Request body is too long"));
939 return (DATA_TOO_LONG);
940 }
941
942 req->body_size += (size_t)ntoread;
943 req->ntoread = ntoread;
944 if (req->ntoread == 0) {
945 /* Last chunk */
946 return (ALL_DATA_READ);
947 }
948 continue;
949 }
950
951 /* req->ntoread is signed int64, len is ssize_t, based on arch,
952 * ssize_t could only be 32b, check for these conditions */
953 if (req->ntoread > EV_SSIZE_MAX) {
954 return DATA_CORRUPTED;
955 }
956
957 /* don't have enough to complete a chunk; wait for more */
958 if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread)
959 return (MORE_DATA_EXPECTED);
960
961 /* Completed chunk */
962 evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread);
963 req->ntoread = -1;
964 if (req->chunk_cb != NULL) {
965 req->flags |= EVHTTP_REQ_DEFER_FREE;
966 (*req->chunk_cb)(req, req->cb_arg);
967 evbuffer_drain(req->input_buffer,
968 evbuffer_get_length(req->input_buffer));
969 req->flags &= ~EVHTTP_REQ_DEFER_FREE;
970 if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
971 return (REQUEST_CANCELED);
972 }
973 }
974 }
975
976 return (MORE_DATA_EXPECTED);
977}
978
979static void
980evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
981{
982 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
983
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100984 switch (evhttp_parse_headers_(req, buf)) {
Christopher Wileye8679812015-07-01 13:36:18 -0700985 case DATA_CORRUPTED:
986 case DATA_TOO_LONG:
Narayan Kamathfc74cb42017-09-13 12:53:52 +0100987 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
Christopher Wileye8679812015-07-01 13:36:18 -0700988 break;
989 case ALL_DATA_READ:
990 bufferevent_disable(evcon->bufev, EV_READ);
991 evhttp_connection_done(evcon);
992 break;
993 case MORE_DATA_EXPECTED:
994 case REQUEST_CANCELED: /* ??? */
995 default:
Christopher Wileye8679812015-07-01 13:36:18 -0700996 break;
997 }
998}
999
1000static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001001evhttp_lingering_close(struct evhttp_connection *evcon,
1002 struct evhttp_request *req)
1003{
1004 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
1005
1006 size_t n = evbuffer_get_length(buf);
1007 if (n > (size_t) req->ntoread)
1008 n = (size_t) req->ntoread;
1009 req->ntoread -= n;
1010 req->body_size += n;
1011
1012 event_debug(("Request body is too long, left " EV_I64_FMT,
1013 EV_I64_ARG(req->ntoread)));
1014
1015 evbuffer_drain(buf, n);
1016 if (!req->ntoread)
1017 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
1018}
1019static void
1020evhttp_lingering_fail(struct evhttp_connection *evcon,
1021 struct evhttp_request *req)
1022{
1023 if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE)
1024 evhttp_lingering_close(evcon, req);
1025 else
1026 evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
1027}
1028
1029static void
Christopher Wileye8679812015-07-01 13:36:18 -07001030evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
1031{
1032 struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
1033
1034 if (req->chunked) {
1035 switch (evhttp_handle_chunked_read(req, buf)) {
1036 case ALL_DATA_READ:
1037 /* finished last chunk */
1038 evcon->state = EVCON_READING_TRAILER;
1039 evhttp_read_trailer(evcon, req);
1040 return;
1041 case DATA_CORRUPTED:
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001042 case DATA_TOO_LONG:
Christopher Wileye8679812015-07-01 13:36:18 -07001043 /* corrupted data */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001044 evhttp_connection_fail_(evcon,
1045 EVREQ_HTTP_DATA_TOO_LONG);
Christopher Wileye8679812015-07-01 13:36:18 -07001046 return;
1047 case REQUEST_CANCELED:
1048 /* request canceled */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001049 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07001050 return;
1051 case MORE_DATA_EXPECTED:
1052 default:
1053 break;
1054 }
1055 } else if (req->ntoread < 0) {
1056 /* Read until connection close. */
1057 if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001058 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07001059 return;
1060 }
1061
1062 req->body_size += evbuffer_get_length(buf);
1063 evbuffer_add_buffer(req->input_buffer, buf);
1064 } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) {
1065 /* XXX: the above get_length comparison has to be fixed for overflow conditions! */
1066 /* We've postponed moving the data until now, but we're
1067 * about to use it. */
1068 size_t n = evbuffer_get_length(buf);
1069
1070 if (n > (size_t) req->ntoread)
1071 n = (size_t) req->ntoread;
1072 req->ntoread -= n;
1073 req->body_size += n;
1074 evbuffer_remove_buffer(buf, req->input_buffer, n);
1075 }
1076
1077 if (req->body_size > req->evcon->max_body_size ||
1078 (!req->chunked && req->ntoread >= 0 &&
1079 (size_t)req->ntoread > req->evcon->max_body_size)) {
1080 /* XXX: The above casted comparison must checked for overflow */
1081 /* failed body length test */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001082
1083 evhttp_lingering_fail(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07001084 return;
1085 }
1086
1087 if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) {
1088 req->flags |= EVHTTP_REQ_DEFER_FREE;
1089 (*req->chunk_cb)(req, req->cb_arg);
1090 req->flags &= ~EVHTTP_REQ_DEFER_FREE;
1091 evbuffer_drain(req->input_buffer,
1092 evbuffer_get_length(req->input_buffer));
1093 if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001094 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07001095 return;
1096 }
1097 }
1098
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001099 if (!req->ntoread) {
Christopher Wileye8679812015-07-01 13:36:18 -07001100 bufferevent_disable(evcon->bufev, EV_READ);
1101 /* Completed content length */
1102 evhttp_connection_done(evcon);
1103 return;
1104 }
Christopher Wileye8679812015-07-01 13:36:18 -07001105}
1106
1107#define get_deferred_queue(evcon) \
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001108 ((evcon)->base)
Christopher Wileye8679812015-07-01 13:36:18 -07001109
1110/*
1111 * Gets called when more data becomes available
1112 */
1113
1114static void
1115evhttp_read_cb(struct bufferevent *bufev, void *arg)
1116{
1117 struct evhttp_connection *evcon = arg;
1118 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1119
1120 /* Cancel if it's pending. */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001121 event_deferred_cb_cancel_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07001122 &evcon->read_more_deferred_cb);
1123
1124 switch (evcon->state) {
1125 case EVCON_READING_FIRSTLINE:
1126 evhttp_read_firstline(evcon, req);
1127 /* note the request may have been freed in
1128 * evhttp_read_body */
1129 break;
1130 case EVCON_READING_HEADERS:
1131 evhttp_read_header(evcon, req);
1132 /* note the request may have been freed in
1133 * evhttp_read_body */
1134 break;
1135 case EVCON_READING_BODY:
1136 evhttp_read_body(evcon, req);
1137 /* note the request may have been freed in
1138 * evhttp_read_body */
1139 break;
1140 case EVCON_READING_TRAILER:
1141 evhttp_read_trailer(evcon, req);
1142 break;
1143 case EVCON_IDLE:
1144 {
1145#ifdef USE_DEBUG
1146 struct evbuffer *input;
1147 size_t total_len;
1148
1149 input = bufferevent_get_input(evcon->bufev);
1150 total_len = evbuffer_get_length(input);
1151 event_debug(("%s: read "EV_SIZE_FMT
1152 " bytes in EVCON_IDLE state,"
1153 " resetting connection",
1154 __func__, EV_SIZE_ARG(total_len)));
1155#endif
1156
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001157 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001158 }
1159 break;
1160 case EVCON_DISCONNECTED:
1161 case EVCON_CONNECTING:
1162 case EVCON_WRITING:
1163 default:
1164 event_errx(1, "%s: illegal connection state %d",
1165 __func__, evcon->state);
1166 }
1167}
1168
1169static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001170evhttp_deferred_read_cb(struct event_callback *cb, void *data)
Christopher Wileye8679812015-07-01 13:36:18 -07001171{
1172 struct evhttp_connection *evcon = data;
1173 evhttp_read_cb(evcon->bufev, evcon);
1174}
1175
1176static void
1177evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
1178{
1179 /* This is after writing the request to the server */
1180 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001181 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07001182 EVUTIL_ASSERT(req != NULL);
1183
1184 EVUTIL_ASSERT(evcon->state == EVCON_WRITING);
1185
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001186 /* We need to wait until we've written all of our output data before we can
1187 * continue */
1188 if (evbuffer_get_length(output) > 0)
1189 return;
1190
Christopher Wileye8679812015-07-01 13:36:18 -07001191 /* We are done writing our header and are now expecting the response */
1192 req->kind = EVHTTP_RESPONSE;
1193
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001194 evhttp_start_read_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001195}
1196
1197/*
1198 * Clean up a connection object
1199 */
1200
1201void
1202evhttp_connection_free(struct evhttp_connection *evcon)
1203{
1204 struct evhttp_request *req;
1205
1206 /* notify interested parties that this connection is going down */
1207 if (evcon->fd != -1) {
1208 if (evhttp_connected(evcon) && evcon->closecb != NULL)
1209 (*evcon->closecb)(evcon, evcon->closecb_arg);
1210 }
1211
1212 /* remove all requests that might be queued on this
1213 * connection. for server connections, this should be empty.
1214 * because it gets dequeued either in evhttp_connection_done or
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001215 * evhttp_connection_fail_.
Christopher Wileye8679812015-07-01 13:36:18 -07001216 */
1217 while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001218 evhttp_request_free_(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07001219 }
1220
1221 if (evcon->http_server != NULL) {
1222 struct evhttp *http = evcon->http_server;
1223 TAILQ_REMOVE(&http->connections, evcon, next);
1224 }
1225
1226 if (event_initialized(&evcon->retry_ev)) {
1227 event_del(&evcon->retry_ev);
1228 event_debug_unassign(&evcon->retry_ev);
1229 }
1230
1231 if (evcon->bufev != NULL)
1232 bufferevent_free(evcon->bufev);
1233
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001234 event_deferred_cb_cancel_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07001235 &evcon->read_more_deferred_cb);
1236
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001237 if (evcon->fd == -1)
1238 evcon->fd = bufferevent_getfd(evcon->bufev);
1239
Christopher Wileye8679812015-07-01 13:36:18 -07001240 if (evcon->fd != -1) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001241 bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
Christopher Wileye8679812015-07-01 13:36:18 -07001242 shutdown(evcon->fd, EVUTIL_SHUT_WR);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001243 if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) {
1244 evutil_closesocket(evcon->fd);
1245 }
Christopher Wileye8679812015-07-01 13:36:18 -07001246 }
1247
1248 if (evcon->bind_address != NULL)
1249 mm_free(evcon->bind_address);
1250
1251 if (evcon->address != NULL)
1252 mm_free(evcon->address);
1253
1254 mm_free(evcon);
1255}
1256
1257void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001258evhttp_connection_free_on_completion(struct evhttp_connection *evcon) {
1259 evcon->flags |= EVHTTP_CON_AUTOFREE;
1260}
1261
1262void
Christopher Wileye8679812015-07-01 13:36:18 -07001263evhttp_connection_set_local_address(struct evhttp_connection *evcon,
1264 const char *address)
1265{
1266 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
1267 if (evcon->bind_address)
1268 mm_free(evcon->bind_address);
1269 if ((evcon->bind_address = mm_strdup(address)) == NULL)
1270 event_warn("%s: strdup", __func__);
1271}
1272
1273void
1274evhttp_connection_set_local_port(struct evhttp_connection *evcon,
1275 ev_uint16_t port)
1276{
1277 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
1278 evcon->bind_port = port;
1279}
1280
1281static void
1282evhttp_request_dispatch(struct evhttp_connection* evcon)
1283{
1284 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1285
1286 /* this should not usually happy but it's possible */
1287 if (req == NULL)
1288 return;
1289
1290 /* delete possible close detection events */
1291 evhttp_connection_stop_detectclose(evcon);
1292
1293 /* we assume that the connection is connected already */
1294 EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
1295
1296 evcon->state = EVCON_WRITING;
1297
1298 /* Create the header from the store arguments */
1299 evhttp_make_header(evcon, req);
1300
1301 evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
1302}
1303
1304/* Reset our connection state: disables reading/writing, closes our fd (if
1305* any), clears out buffers, and puts us in state DISCONNECTED. */
1306void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001307evhttp_connection_reset_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07001308{
1309 struct evbuffer *tmp;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001310 int err;
Christopher Wileye8679812015-07-01 13:36:18 -07001311
1312 /* XXXX This is not actually an optimal fix. Instead we ought to have
1313 an API for "stop connecting", or use bufferevent_setfd to turn off
1314 connecting. But for Libevent 2.0, this seems like a minimal change
1315 least likely to disrupt the rest of the bufferevent and http code.
1316
1317 Why is this here? If the fd is set in the bufferevent, and the
1318 bufferevent is connecting, then you can't actually stop the
1319 bufferevent from trying to connect with bufferevent_disable(). The
1320 connect will never trigger, since we close the fd, but the timeout
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001321 might. That caused an assertion failure in evhttp_connection_fail_.
Christopher Wileye8679812015-07-01 13:36:18 -07001322 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001323 bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE);
1324
1325 if (evcon->fd == -1)
1326 evcon->fd = bufferevent_getfd(evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07001327
1328 if (evcon->fd != -1) {
1329 /* inform interested parties about connection close */
1330 if (evhttp_connected(evcon) && evcon->closecb != NULL)
1331 (*evcon->closecb)(evcon, evcon->closecb_arg);
1332
1333 shutdown(evcon->fd, EVUTIL_SHUT_WR);
1334 evutil_closesocket(evcon->fd);
1335 evcon->fd = -1;
1336 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001337 bufferevent_setfd(evcon->bufev, -1);
Christopher Wileye8679812015-07-01 13:36:18 -07001338
1339 /* we need to clean up any buffered data */
1340 tmp = bufferevent_get_output(evcon->bufev);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001341 err = evbuffer_drain(tmp, -1);
1342 EVUTIL_ASSERT(!err && "drain output");
Christopher Wileye8679812015-07-01 13:36:18 -07001343 tmp = bufferevent_get_input(evcon->bufev);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001344 err = evbuffer_drain(tmp, -1);
1345 EVUTIL_ASSERT(!err && "drain input");
1346
1347 evcon->flags &= ~EVHTTP_CON_READING_ERROR;
Christopher Wileye8679812015-07-01 13:36:18 -07001348
1349 evcon->state = EVCON_DISCONNECTED;
1350}
1351
1352static void
1353evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
1354{
1355 evcon->flags |= EVHTTP_CON_CLOSEDETECT;
1356
1357 bufferevent_enable(evcon->bufev, EV_READ);
1358}
1359
1360static void
1361evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
1362{
1363 evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
1364
1365 bufferevent_disable(evcon->bufev, EV_READ);
1366}
1367
1368static void
1369evhttp_connection_retry(evutil_socket_t fd, short what, void *arg)
1370{
1371 struct evhttp_connection *evcon = arg;
1372
1373 evcon->state = EVCON_DISCONNECTED;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001374 evhttp_connection_connect_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001375}
1376
1377static void
1378evhttp_connection_cb_cleanup(struct evhttp_connection *evcon)
1379{
1380 struct evcon_requestq requests;
1381
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001382 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07001383 if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001384 struct timeval tv_retry = evcon->initial_retry_timeout;
1385 int i;
Christopher Wileye8679812015-07-01 13:36:18 -07001386 evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon);
1387 /* XXXX handle failure from evhttp_add_event */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001388 for (i=0; i < evcon->retry_cnt; ++i) {
1389 tv_retry.tv_usec *= 2;
1390 if (tv_retry.tv_usec > 1000000) {
1391 tv_retry.tv_usec -= 1000000;
1392 tv_retry.tv_sec += 1;
1393 }
1394 tv_retry.tv_sec *= 2;
1395 if (tv_retry.tv_sec > 3600) {
1396 tv_retry.tv_sec = 3600;
1397 tv_retry.tv_usec = 0;
1398 }
1399 }
1400 event_add(&evcon->retry_ev, &tv_retry);
Christopher Wileye8679812015-07-01 13:36:18 -07001401 evcon->retry_cnt++;
1402 return;
1403 }
Christopher Wileye8679812015-07-01 13:36:18 -07001404
1405 /*
1406 * User callback can do evhttp_make_request() on the same
1407 * evcon so new request will be added to evcon->requests. To
1408 * avoid freeing it prematurely we iterate over the copy of
1409 * the queue.
1410 */
1411 TAILQ_INIT(&requests);
1412 while (TAILQ_FIRST(&evcon->requests) != NULL) {
1413 struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
1414 TAILQ_REMOVE(&evcon->requests, request, next);
1415 TAILQ_INSERT_TAIL(&requests, request, next);
1416 }
1417
1418 /* for now, we just signal all requests by executing their callbacks */
1419 while (TAILQ_FIRST(&requests) != NULL) {
1420 struct evhttp_request *request = TAILQ_FIRST(&requests);
1421 TAILQ_REMOVE(&requests, request, next);
1422 request->evcon = NULL;
1423
1424 /* we might want to set an error here */
1425 request->cb(request, request->cb_arg);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001426 evhttp_request_free_auto(request);
Christopher Wileye8679812015-07-01 13:36:18 -07001427 }
1428}
1429
1430static void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001431evhttp_connection_read_on_write_error(struct evhttp_connection *evcon,
1432 struct evhttp_request *req)
1433{
1434 struct evbuffer *buf;
1435
1436 /** Second time, we can't read anything */
1437 if (evcon->flags & EVHTTP_CON_READING_ERROR) {
1438 evcon->flags &= ~EVHTTP_CON_READING_ERROR;
1439 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
1440 return;
1441 }
1442
1443 req->kind = EVHTTP_RESPONSE;
1444
1445 buf = bufferevent_get_output(evcon->bufev);
1446 evbuffer_unfreeze(buf, 1);
1447 evbuffer_drain(buf, evbuffer_get_length(buf));
1448 evbuffer_freeze(buf, 1);
1449
1450 evhttp_start_read_(evcon);
1451 evcon->flags |= EVHTTP_CON_READING_ERROR;
1452}
1453
1454static void
Christopher Wileye8679812015-07-01 13:36:18 -07001455evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
1456{
1457 struct evhttp_connection *evcon = arg;
1458 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1459
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001460 if (evcon->fd == -1)
1461 evcon->fd = bufferevent_getfd(bufev);
1462
Christopher Wileye8679812015-07-01 13:36:18 -07001463 switch (evcon->state) {
1464 case EVCON_CONNECTING:
1465 if (what & BEV_EVENT_TIMEOUT) {
1466 event_debug(("%s: connection timeout for \"%s:%d\" on "
1467 EV_SOCK_FMT,
1468 __func__, evcon->address, evcon->port,
1469 EV_SOCK_ARG(evcon->fd)));
1470 evhttp_connection_cb_cleanup(evcon);
1471 return;
1472 }
1473 break;
1474
1475 case EVCON_READING_BODY:
1476 if (!req->chunked && req->ntoread < 0
1477 && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) {
1478 /* EOF on read can be benign */
1479 evhttp_connection_done(evcon);
1480 return;
1481 }
1482 break;
1483
1484 case EVCON_DISCONNECTED:
1485 case EVCON_IDLE:
1486 case EVCON_READING_FIRSTLINE:
1487 case EVCON_READING_HEADERS:
1488 case EVCON_READING_TRAILER:
1489 case EVCON_WRITING:
1490 default:
1491 break;
1492 }
1493
1494 /* when we are in close detect mode, a read error means that
1495 * the other side closed their connection.
1496 */
1497 if (evcon->flags & EVHTTP_CON_CLOSEDETECT) {
1498 evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
1499 EVUTIL_ASSERT(evcon->http_server == NULL);
1500 /* For connections from the client, we just
1501 * reset the connection so that it becomes
1502 * disconnected.
1503 */
1504 EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001505 evhttp_connection_reset_(evcon);
1506
1507 /*
1508 * If we have no more requests that need completion
1509 * and we want to auto-free the connection when all
1510 * requests have been completed.
1511 */
1512 if (TAILQ_FIRST(&evcon->requests) == NULL
1513 && (evcon->flags & EVHTTP_CON_OUTGOING)
1514 && (evcon->flags & EVHTTP_CON_AUTOFREE)) {
1515 evhttp_connection_free(evcon);
1516 }
Christopher Wileye8679812015-07-01 13:36:18 -07001517 return;
1518 }
1519
1520 if (what & BEV_EVENT_TIMEOUT) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001521 evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
Christopher Wileye8679812015-07-01 13:36:18 -07001522 } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001523 if (what & BEV_EVENT_WRITING &&
1524 evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) {
1525 evhttp_connection_read_on_write_error(evcon, req);
1526 return;
1527 }
1528
1529 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
1530 } else if (what == BEV_EVENT_CONNECTED) {
Christopher Wileye8679812015-07-01 13:36:18 -07001531 } else {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001532 evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR);
Christopher Wileye8679812015-07-01 13:36:18 -07001533 }
1534}
1535
1536/*
1537 * Event callback for asynchronous connection attempt.
1538 */
1539static void
1540evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
1541{
1542 struct evhttp_connection *evcon = arg;
1543 int error;
1544 ev_socklen_t errsz = sizeof(error);
1545
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001546 if (evcon->fd == -1)
1547 evcon->fd = bufferevent_getfd(bufev);
1548
Christopher Wileye8679812015-07-01 13:36:18 -07001549 if (!(what & BEV_EVENT_CONNECTED)) {
1550 /* some operating systems return ECONNREFUSED immediately
1551 * when connecting to a local address. the cleanup is going
1552 * to reschedule this function call.
1553 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001554#ifndef _WIN32
Christopher Wileye8679812015-07-01 13:36:18 -07001555 if (errno == ECONNREFUSED)
1556 goto cleanup;
1557#endif
1558 evhttp_error_cb(bufev, what, arg);
1559 return;
1560 }
1561
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001562 if (evcon->fd == -1) {
1563 event_debug(("%s: bufferevent_getfd returned -1",
1564 __func__));
1565 goto cleanup;
1566 }
1567
Christopher Wileye8679812015-07-01 13:36:18 -07001568 /* Check if the connection completed */
1569 if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
1570 &errsz) == -1) {
1571 event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT,
1572 __func__, evcon->address, evcon->port,
1573 EV_SOCK_ARG(evcon->fd)));
1574 goto cleanup;
1575 }
1576
1577 if (error) {
1578 event_debug(("%s: connect failed for \"%s:%d\" on "
1579 EV_SOCK_FMT": %s",
1580 __func__, evcon->address, evcon->port,
1581 EV_SOCK_ARG(evcon->fd),
1582 evutil_socket_error_to_string(error)));
1583 goto cleanup;
1584 }
1585
1586 /* We are connected to the server now */
1587 event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n",
1588 __func__, evcon->address, evcon->port,
1589 EV_SOCK_ARG(evcon->fd)));
1590
1591 /* Reset the retry count as we were successful in connecting */
1592 evcon->retry_cnt = 0;
1593 evcon->state = EVCON_IDLE;
1594
1595 /* reset the bufferevent cbs */
1596 bufferevent_setcb(evcon->bufev,
1597 evhttp_read_cb,
1598 evhttp_write_cb,
1599 evhttp_error_cb,
1600 evcon);
1601
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001602 if (!evutil_timerisset(&evcon->timeout)) {
1603 const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
1604 const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
1605 bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
1606 } else {
1607 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07001608 }
1609
1610 /* try to start requests that have queued up on this connection */
1611 evhttp_request_dispatch(evcon);
1612 return;
1613
1614 cleanup:
1615 evhttp_connection_cb_cleanup(evcon);
1616}
1617
1618/*
1619 * Check if we got a valid response code.
1620 */
1621
1622static int
1623evhttp_valid_response_code(int code)
1624{
1625 if (code == 0)
1626 return (0);
1627
1628 return (1);
1629}
1630
1631static int
1632evhttp_parse_http_version(const char *version, struct evhttp_request *req)
1633{
1634 int major, minor;
1635 char ch;
1636 int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch);
1637 if (n != 2 || major > 1) {
1638 event_debug(("%s: bad version %s on message %p from %s",
1639 __func__, version, req, req->remote_host));
1640 return (-1);
1641 }
1642 req->major = major;
1643 req->minor = minor;
1644 return (0);
1645}
1646
1647/* Parses the status line of a web server */
1648
1649static int
1650evhttp_parse_response_line(struct evhttp_request *req, char *line)
1651{
1652 char *protocol;
1653 char *number;
1654 const char *readable = "";
1655
1656 protocol = strsep(&line, " ");
1657 if (line == NULL)
1658 return (-1);
1659 number = strsep(&line, " ");
1660 if (line != NULL)
1661 readable = line;
1662
1663 if (evhttp_parse_http_version(protocol, req) < 0)
1664 return (-1);
1665
1666 req->response_code = atoi(number);
1667 if (!evhttp_valid_response_code(req->response_code)) {
1668 event_debug(("%s: bad response code \"%s\"",
1669 __func__, number));
1670 return (-1);
1671 }
1672
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001673 if (req->response_code_line != NULL)
1674 mm_free(req->response_code_line);
Christopher Wileye8679812015-07-01 13:36:18 -07001675 if ((req->response_code_line = mm_strdup(readable)) == NULL) {
1676 event_warn("%s: strdup", __func__);
1677 return (-1);
1678 }
1679
1680 return (0);
1681}
1682
1683/* Parse the first line of a HTTP request */
1684
1685static int
1686evhttp_parse_request_line(struct evhttp_request *req, char *line)
1687{
1688 char *method;
1689 char *uri;
1690 char *version;
1691 const char *hostname;
1692 const char *scheme;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001693 size_t method_len;
1694 enum evhttp_cmd_type type;
Christopher Wileye8679812015-07-01 13:36:18 -07001695
1696 /* Parse the request line */
1697 method = strsep(&line, " ");
1698 if (line == NULL)
1699 return (-1);
1700 uri = strsep(&line, " ");
1701 if (line == NULL)
1702 return (-1);
1703 version = strsep(&line, " ");
1704 if (line != NULL)
1705 return (-1);
1706
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001707 method_len = (uri - method) - 1;
1708 type = EVHTTP_REQ_UNKNOWN_;
1709
Christopher Wileye8679812015-07-01 13:36:18 -07001710 /* First line */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001711 switch (method_len) {
1712 case 3:
1713 /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */
1714
1715 /* Since both GET and PUT share the same character 'T' at the end,
1716 * if the string doesn't have 'T', we can immediately determine this
1717 * is an invalid HTTP method */
1718
1719 if (method[2] != 'T') {
1720 break;
1721 }
1722
1723 switch (*method) {
1724 case 'G':
1725 /* This first byte is 'G', so make sure the next byte is
1726 * 'E', if it isn't then this isn't a valid method */
1727
1728 if (method[1] == 'E') {
1729 type = EVHTTP_REQ_GET;
1730 }
1731
1732 break;
1733 case 'P':
1734 /* First byte is P, check second byte for 'U', if not,
1735 * we know it's an invalid method */
1736 if (method[1] == 'U') {
1737 type = EVHTTP_REQ_PUT;
1738 }
1739 break;
1740 default:
1741 break;
1742 }
1743 break;
1744 case 4:
1745 /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */
1746 switch (*method) {
1747 case 'P':
1748 if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') {
1749 type = EVHTTP_REQ_POST;
1750 }
1751 break;
1752 case 'H':
1753 if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') {
1754 type = EVHTTP_REQ_HEAD;
1755 }
1756 break;
1757 default:
1758 break;
1759 }
1760 break;
1761 case 5:
1762 /* Method length is 5 bytes, which can only encompass PATCH and TRACE */
1763 switch (*method) {
1764 case 'P':
1765 if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') {
1766 type = EVHTTP_REQ_PATCH;
1767 }
1768 break;
1769 case 'T':
1770 if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') {
1771 type = EVHTTP_REQ_TRACE;
1772 }
1773
1774 break;
1775 default:
1776 break;
1777 }
1778 break;
1779 case 6:
1780 /* Method length is 6, only valid method 6 bytes in length is DELEte */
1781
1782 /* If the first byte isn't 'D' then it's invalid */
1783 if (*method != 'D') {
1784 break;
1785 }
1786
1787 if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') {
1788 type = EVHTTP_REQ_DELETE;
1789 }
1790
1791 break;
1792 case 7:
1793 /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */
1794 switch (*method) {
1795 case 'O':
1796 if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' &&
1797 method[3] == 'I' && method[2] == 'T' && method[1] == 'P') {
1798 type = EVHTTP_REQ_OPTIONS;
1799 }
1800
1801 break;
1802 case 'C':
1803 if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' &&
1804 method[3] == 'N' && method[2] == 'N' && method[1] == 'O') {
1805 type = EVHTTP_REQ_CONNECT;
1806 }
1807
1808 break;
1809 default:
1810 break;
1811 }
1812 break;
1813 } /* switch */
1814
1815 if ((int)type == EVHTTP_REQ_UNKNOWN_) {
1816 event_debug(("%s: bad method %s on request %p from %s",
Christopher Wileye8679812015-07-01 13:36:18 -07001817 __func__, method, req, req->remote_host));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001818 /* No error yet; we'll give a better error later when
1819 * we see that req->type is unsupported. */
Christopher Wileye8679812015-07-01 13:36:18 -07001820 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001821
1822 req->type = type;
Christopher Wileye8679812015-07-01 13:36:18 -07001823
1824 if (evhttp_parse_http_version(version, req) < 0)
1825 return (-1);
1826
1827 if ((req->uri = mm_strdup(uri)) == NULL) {
1828 event_debug(("%s: mm_strdup", __func__));
1829 return (-1);
1830 }
1831
1832 if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri,
1833 EVHTTP_URI_NONCONFORMANT)) == NULL) {
1834 return -1;
1835 }
1836
1837 /* If we have an absolute-URI, check to see if it is an http request
1838 for a known vhost or server alias. If we don't know about this
1839 host, we consider it a proxy request. */
1840 scheme = evhttp_uri_get_scheme(req->uri_elems);
1841 hostname = evhttp_uri_get_host(req->uri_elems);
1842 if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") ||
1843 !evutil_ascii_strcasecmp(scheme, "https")) &&
1844 hostname &&
1845 !evhttp_find_vhost(req->evcon->http_server, NULL, hostname))
1846 req->flags |= EVHTTP_PROXY_REQUEST;
1847
1848 return (0);
1849}
1850
1851const char *
1852evhttp_find_header(const struct evkeyvalq *headers, const char *key)
1853{
1854 struct evkeyval *header;
1855
1856 TAILQ_FOREACH(header, headers, next) {
1857 if (evutil_ascii_strcasecmp(header->key, key) == 0)
1858 return (header->value);
1859 }
1860
1861 return (NULL);
1862}
1863
1864void
1865evhttp_clear_headers(struct evkeyvalq *headers)
1866{
1867 struct evkeyval *header;
1868
1869 for (header = TAILQ_FIRST(headers);
1870 header != NULL;
1871 header = TAILQ_FIRST(headers)) {
1872 TAILQ_REMOVE(headers, header, next);
1873 mm_free(header->key);
1874 mm_free(header->value);
1875 mm_free(header);
1876 }
1877}
1878
1879/*
1880 * Returns 0, if the header was successfully removed.
1881 * Returns -1, if the header could not be found.
1882 */
1883
1884int
1885evhttp_remove_header(struct evkeyvalq *headers, const char *key)
1886{
1887 struct evkeyval *header;
1888
1889 TAILQ_FOREACH(header, headers, next) {
1890 if (evutil_ascii_strcasecmp(header->key, key) == 0)
1891 break;
1892 }
1893
1894 if (header == NULL)
1895 return (-1);
1896
1897 /* Free and remove the header that we found */
1898 TAILQ_REMOVE(headers, header, next);
1899 mm_free(header->key);
1900 mm_free(header->value);
1901 mm_free(header);
1902
1903 return (0);
1904}
1905
1906static int
1907evhttp_header_is_valid_value(const char *value)
1908{
1909 const char *p = value;
1910
1911 while ((p = strpbrk(p, "\r\n")) != NULL) {
1912 /* we really expect only one new line */
1913 p += strspn(p, "\r\n");
1914 /* we expect a space or tab for continuation */
1915 if (*p != ' ' && *p != '\t')
1916 return (0);
1917 }
1918 return (1);
1919}
1920
1921int
1922evhttp_add_header(struct evkeyvalq *headers,
1923 const char *key, const char *value)
1924{
1925 event_debug(("%s: key: %s val: %s\n", __func__, key, value));
1926
1927 if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
1928 /* drop illegal headers */
1929 event_debug(("%s: dropping illegal header key\n", __func__));
1930 return (-1);
1931 }
1932
1933 if (!evhttp_header_is_valid_value(value)) {
1934 event_debug(("%s: dropping illegal header value\n", __func__));
1935 return (-1);
1936 }
1937
1938 return (evhttp_add_header_internal(headers, key, value));
1939}
1940
1941static int
1942evhttp_add_header_internal(struct evkeyvalq *headers,
1943 const char *key, const char *value)
1944{
1945 struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval));
1946 if (header == NULL) {
1947 event_warn("%s: calloc", __func__);
1948 return (-1);
1949 }
1950 if ((header->key = mm_strdup(key)) == NULL) {
1951 mm_free(header);
1952 event_warn("%s: strdup", __func__);
1953 return (-1);
1954 }
1955 if ((header->value = mm_strdup(value)) == NULL) {
1956 mm_free(header->key);
1957 mm_free(header);
1958 event_warn("%s: strdup", __func__);
1959 return (-1);
1960 }
1961
1962 TAILQ_INSERT_TAIL(headers, header, next);
1963
1964 return (0);
1965}
1966
1967/*
1968 * Parses header lines from a request or a response into the specified
1969 * request object given an event buffer.
1970 *
1971 * Returns
1972 * DATA_CORRUPTED on error
1973 * MORE_DATA_EXPECTED when we need to read more headers
1974 * ALL_DATA_READ when all headers have been read.
1975 */
1976
1977enum message_read_status
Narayan Kamathfc74cb42017-09-13 12:53:52 +01001978evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer)
Christopher Wileye8679812015-07-01 13:36:18 -07001979{
1980 char *line;
1981 enum message_read_status status = ALL_DATA_READ;
1982
1983 size_t line_length;
1984 /* XXX try */
1985 line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF);
1986 if (line == NULL) {
1987 if (req->evcon != NULL &&
1988 evbuffer_get_length(buffer) > req->evcon->max_headers_size)
1989 return (DATA_TOO_LONG);
1990 else
1991 return (MORE_DATA_EXPECTED);
1992 }
1993
1994 if (req->evcon != NULL &&
1995 line_length > req->evcon->max_headers_size) {
1996 mm_free(line);
1997 return (DATA_TOO_LONG);
1998 }
1999
2000 req->headers_size = line_length;
2001
2002 switch (req->kind) {
2003 case EVHTTP_REQUEST:
2004 if (evhttp_parse_request_line(req, line) == -1)
2005 status = DATA_CORRUPTED;
2006 break;
2007 case EVHTTP_RESPONSE:
2008 if (evhttp_parse_response_line(req, line) == -1)
2009 status = DATA_CORRUPTED;
2010 break;
2011 default:
2012 status = DATA_CORRUPTED;
2013 }
2014
2015 mm_free(line);
2016 return (status);
2017}
2018
2019static int
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002020evhttp_append_to_last_header(struct evkeyvalq *headers, char *line)
Christopher Wileye8679812015-07-01 13:36:18 -07002021{
2022 struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
2023 char *newval;
2024 size_t old_len, line_len;
2025
2026 if (header == NULL)
2027 return (-1);
2028
2029 old_len = strlen(header->value);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002030
2031 /* Strip space from start and end of line. */
2032 while (*line == ' ' || *line == '\t')
2033 ++line;
2034 evutil_rtrim_lws_(line);
2035
Christopher Wileye8679812015-07-01 13:36:18 -07002036 line_len = strlen(line);
2037
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002038 newval = mm_realloc(header->value, old_len + line_len + 2);
Christopher Wileye8679812015-07-01 13:36:18 -07002039 if (newval == NULL)
2040 return (-1);
2041
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002042 newval[old_len] = ' ';
2043 memcpy(newval + old_len + 1, line, line_len + 1);
Christopher Wileye8679812015-07-01 13:36:18 -07002044 header->value = newval;
2045
2046 return (0);
2047}
2048
2049enum message_read_status
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002050evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
Christopher Wileye8679812015-07-01 13:36:18 -07002051{
2052 enum message_read_status errcode = DATA_CORRUPTED;
2053 char *line;
2054 enum message_read_status status = MORE_DATA_EXPECTED;
2055
2056 struct evkeyvalq* headers = req->input_headers;
2057 size_t line_length;
2058 while ((line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF))
2059 != NULL) {
2060 char *skey, *svalue;
2061
2062 req->headers_size += line_length;
2063
2064 if (req->evcon != NULL &&
2065 req->headers_size > req->evcon->max_headers_size) {
2066 errcode = DATA_TOO_LONG;
2067 goto error;
2068 }
2069
2070 if (*line == '\0') { /* Last header - Done */
2071 status = ALL_DATA_READ;
2072 mm_free(line);
2073 break;
2074 }
2075
2076 /* Check if this is a continuation line */
2077 if (*line == ' ' || *line == '\t') {
2078 if (evhttp_append_to_last_header(headers, line) == -1)
2079 goto error;
2080 mm_free(line);
2081 continue;
2082 }
2083
2084 /* Processing of header lines */
2085 svalue = line;
2086 skey = strsep(&svalue, ":");
2087 if (svalue == NULL)
2088 goto error;
2089
2090 svalue += strspn(svalue, " ");
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002091 evutil_rtrim_lws_(svalue);
Christopher Wileye8679812015-07-01 13:36:18 -07002092
2093 if (evhttp_add_header(headers, skey, svalue) == -1)
2094 goto error;
2095
2096 mm_free(line);
2097 }
2098
2099 if (status == MORE_DATA_EXPECTED) {
2100 if (req->evcon != NULL &&
2101 req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size)
2102 return (DATA_TOO_LONG);
2103 }
2104
2105 return (status);
2106
2107 error:
2108 mm_free(line);
2109 return (errcode);
2110}
2111
2112static int
2113evhttp_get_body_length(struct evhttp_request *req)
2114{
2115 struct evkeyvalq *headers = req->input_headers;
2116 const char *content_length;
2117 const char *connection;
2118
2119 content_length = evhttp_find_header(headers, "Content-Length");
2120 connection = evhttp_find_header(headers, "Connection");
2121
2122 if (content_length == NULL && connection == NULL)
2123 req->ntoread = -1;
2124 else if (content_length == NULL &&
2125 evutil_ascii_strcasecmp(connection, "Close") != 0) {
2126 /* Bad combination, we don't know when it will end */
2127 event_warnx("%s: we got no content length, but the "
2128 "server wants to keep the connection open: %s.",
2129 __func__, connection);
2130 return (-1);
2131 } else if (content_length == NULL) {
2132 req->ntoread = -1;
2133 } else {
2134 char *endp;
2135 ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
2136 if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
2137 event_debug(("%s: illegal content length: %s",
2138 __func__, content_length));
2139 return (-1);
2140 }
2141 req->ntoread = ntoread;
2142 }
2143
2144 event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n",
2145 __func__, EV_I64_ARG(req->ntoread),
2146 EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev)))));
2147
2148 return (0);
2149}
2150
2151static int
2152evhttp_method_may_have_body(enum evhttp_cmd_type type)
2153{
2154 switch (type) {
2155 case EVHTTP_REQ_POST:
2156 case EVHTTP_REQ_PUT:
2157 case EVHTTP_REQ_PATCH:
2158 return 1;
2159 case EVHTTP_REQ_TRACE:
2160 return 0;
2161 /* XXX May any of the below methods have a body? */
2162 case EVHTTP_REQ_GET:
2163 case EVHTTP_REQ_HEAD:
2164 case EVHTTP_REQ_DELETE:
2165 case EVHTTP_REQ_OPTIONS:
2166 case EVHTTP_REQ_CONNECT:
2167 return 0;
2168 default:
2169 return 0;
2170 }
2171}
2172
2173static void
2174evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
2175{
2176 const char *xfer_enc;
2177
2178 /* If this is a request without a body, then we are done */
2179 if (req->kind == EVHTTP_REQUEST &&
2180 !evhttp_method_may_have_body(req->type)) {
2181 evhttp_connection_done(evcon);
2182 return;
2183 }
2184 evcon->state = EVCON_READING_BODY;
2185 xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
2186 if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) {
2187 req->chunked = 1;
2188 req->ntoread = -1;
2189 } else {
2190 if (evhttp_get_body_length(req) == -1) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002191 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002192 return;
2193 }
2194 if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
2195 /* An incoming request with no content-length and no
2196 * transfer-encoding has no body. */
2197 evhttp_connection_done(evcon);
2198 return;
2199 }
2200 }
2201
2202 /* Should we send a 100 Continue status line? */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002203 switch (evhttp_have_expect(req, 1)) {
2204 case CONTINUE:
Christopher Wileye8679812015-07-01 13:36:18 -07002205 /* XXX It would be nice to do some sanity
2206 checking here. Does the resource exist?
2207 Should the resource accept post requests? If
2208 no, we should respond with an error. For
2209 now, just optimistically tell the client to
2210 send their message body. */
2211 if (req->ntoread > 0) {
2212 /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002213 if ((req->evcon->max_body_size <= EV_INT64_MAX) &&
2214 (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
2215 evhttp_lingering_fail(evcon, req);
Christopher Wileye8679812015-07-01 13:36:18 -07002216 return;
2217 }
2218 }
2219 if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
2220 evhttp_send_continue(evcon, req);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002221 break;
2222 case OTHER:
2223 evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL);
2224 return;
2225 case NO: break;
Christopher Wileye8679812015-07-01 13:36:18 -07002226 }
2227
2228 evhttp_read_body(evcon, req);
2229 /* note the request may have been freed in evhttp_read_body */
2230}
2231
2232static void
2233evhttp_read_firstline(struct evhttp_connection *evcon,
2234 struct evhttp_request *req)
2235{
2236 enum message_read_status res;
2237
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002238 res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev));
Christopher Wileye8679812015-07-01 13:36:18 -07002239 if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
2240 /* Error while reading, terminate */
2241 event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
2242 __func__, EV_SOCK_ARG(evcon->fd)));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002243 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002244 return;
2245 } else if (res == MORE_DATA_EXPECTED) {
2246 /* Need more header lines */
2247 return;
2248 }
2249
2250 evcon->state = EVCON_READING_HEADERS;
2251 evhttp_read_header(evcon, req);
2252}
2253
2254static void
2255evhttp_read_header(struct evhttp_connection *evcon,
2256 struct evhttp_request *req)
2257{
2258 enum message_read_status res;
2259 evutil_socket_t fd = evcon->fd;
2260
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002261 res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev));
Christopher Wileye8679812015-07-01 13:36:18 -07002262 if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
2263 /* Error while reading, terminate */
2264 event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
2265 __func__, EV_SOCK_ARG(fd)));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002266 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002267 return;
2268 } else if (res == MORE_DATA_EXPECTED) {
2269 /* Need more header lines */
2270 return;
2271 }
2272
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002273 /* Callback can shut down connection with negative return value */
2274 if (req->header_cb != NULL) {
2275 if ((*req->header_cb)(req, req->cb_arg) < 0) {
2276 evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
2277 return;
2278 }
2279 }
Christopher Wileye8679812015-07-01 13:36:18 -07002280
2281 /* Done reading headers, do the real work */
2282 switch (req->kind) {
2283 case EVHTTP_REQUEST:
2284 event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n",
2285 __func__, EV_SOCK_ARG(fd)));
2286 evhttp_get_body(evcon, req);
2287 /* note the request may have been freed in evhttp_get_body */
2288 break;
2289
2290 case EVHTTP_RESPONSE:
2291 /* Start over if we got a 100 Continue response. */
2292 if (req->response_code == 100) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002293 struct evbuffer *output = bufferevent_get_output(evcon->bufev);
2294 evbuffer_add_buffer(output, req->output_buffer);
2295 evhttp_start_write_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07002296 return;
2297 }
2298 if (!evhttp_response_needs_body(req)) {
2299 event_debug(("%s: skipping body for code %d\n",
2300 __func__, req->response_code));
2301 evhttp_connection_done(evcon);
2302 } else {
2303 event_debug(("%s: start of read body for %s on "
2304 EV_SOCK_FMT"\n",
2305 __func__, req->remote_host, EV_SOCK_ARG(fd)));
2306 evhttp_get_body(evcon, req);
2307 /* note the request may have been freed in
2308 * evhttp_get_body */
2309 }
2310 break;
2311
2312 default:
2313 event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
2314 EV_SOCK_ARG(fd));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002315 evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
Christopher Wileye8679812015-07-01 13:36:18 -07002316 break;
2317 }
2318 /* request may have been freed above */
2319}
2320
2321/*
2322 * Creates a TCP connection to the specified port and executes a callback
2323 * when finished. Failure or success is indicate by the passed connection
2324 * object.
2325 *
2326 * Although this interface accepts a hostname, it is intended to take
2327 * only numeric hostnames so that non-blocking DNS resolution can
2328 * happen elsewhere.
2329 */
2330
2331struct evhttp_connection *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002332evhttp_connection_new(const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07002333{
2334 return (evhttp_connection_base_new(NULL, NULL, address, port));
2335}
2336
2337struct evhttp_connection *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002338evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
2339 const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07002340{
2341 struct evhttp_connection *evcon = NULL;
2342
2343 event_debug(("Attempting connection to %s:%d\n", address, port));
2344
2345 if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) {
2346 event_warn("%s: calloc failed", __func__);
2347 goto error;
2348 }
2349
2350 evcon->fd = -1;
2351 evcon->port = port;
2352
2353 evcon->max_headers_size = EV_SIZE_MAX;
2354 evcon->max_body_size = EV_SIZE_MAX;
2355
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002356 evutil_timerclear(&evcon->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07002357 evcon->retry_cnt = evcon->retry_max = 0;
2358
2359 if ((evcon->address = mm_strdup(address)) == NULL) {
2360 event_warn("%s: strdup failed", __func__);
2361 goto error;
2362 }
2363
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002364 if (bev == NULL) {
2365 if (!(bev = bufferevent_socket_new(base, -1, 0))) {
2366 event_warn("%s: bufferevent_socket_new failed", __func__);
2367 goto error;
2368 }
Christopher Wileye8679812015-07-01 13:36:18 -07002369 }
2370
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002371 bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon);
2372 evcon->bufev = bev;
2373
Christopher Wileye8679812015-07-01 13:36:18 -07002374 evcon->state = EVCON_DISCONNECTED;
2375 TAILQ_INIT(&evcon->requests);
2376
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002377 evcon->initial_retry_timeout.tv_sec = 2;
2378 evcon->initial_retry_timeout.tv_usec = 0;
2379
Christopher Wileye8679812015-07-01 13:36:18 -07002380 if (base != NULL) {
2381 evcon->base = base;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002382 if (bufferevent_get_base(bev) != base)
2383 bufferevent_base_set(base, evcon->bufev);
Christopher Wileye8679812015-07-01 13:36:18 -07002384 }
2385
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002386 event_deferred_cb_init_(
2387 &evcon->read_more_deferred_cb,
2388 bufferevent_get_priority(bev),
Christopher Wileye8679812015-07-01 13:36:18 -07002389 evhttp_deferred_read_cb, evcon);
2390
2391 evcon->dns_base = dnsbase;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002392 evcon->ai_family = AF_UNSPEC;
Christopher Wileye8679812015-07-01 13:36:18 -07002393
2394 return (evcon);
2395
2396 error:
2397 if (evcon != NULL)
2398 evhttp_connection_free(evcon);
2399 return (NULL);
2400}
2401
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002402struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002403{
2404 return evcon->bufev;
2405}
2406
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002407struct evhttp *
2408evhttp_connection_get_server(struct evhttp_connection *evcon)
2409{
2410 return evcon->http_server;
2411}
2412
2413struct evhttp_connection *
2414evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
2415 const char *address, ev_uint16_t port)
2416{
2417 return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port);
2418}
2419
2420void evhttp_connection_set_family(struct evhttp_connection *evcon,
2421 int family)
2422{
2423 evcon->ai_family = family;
2424}
2425
2426int evhttp_connection_set_flags(struct evhttp_connection *evcon,
2427 int flags)
2428{
2429 int avail_flags = 0;
2430 avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR;
2431 avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR;
2432
2433 if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END)
2434 return 1;
2435 evcon->flags &= ~avail_flags;
2436
2437 evcon->flags |= flags;
2438
2439 return 0;
2440}
2441
Christopher Wileye8679812015-07-01 13:36:18 -07002442void
2443evhttp_connection_set_base(struct evhttp_connection *evcon,
2444 struct event_base *base)
2445{
2446 EVUTIL_ASSERT(evcon->base == NULL);
2447 EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
2448 evcon->base = base;
2449 bufferevent_base_set(base, evcon->bufev);
2450}
2451
2452void
2453evhttp_connection_set_timeout(struct evhttp_connection *evcon,
2454 int timeout_in_secs)
2455{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002456 if (timeout_in_secs == -1)
2457 evhttp_connection_set_timeout_tv(evcon, NULL);
2458 else {
2459 struct timeval tv;
2460 tv.tv_sec = timeout_in_secs;
2461 tv.tv_usec = 0;
2462 evhttp_connection_set_timeout_tv(evcon, &tv);
2463 }
2464}
Christopher Wileye8679812015-07-01 13:36:18 -07002465
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002466void
2467evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
2468 const struct timeval* tv)
2469{
2470 if (tv) {
2471 evcon->timeout = *tv;
2472 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
2473 } else {
2474 const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
2475 const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
2476 evutil_timerclear(&evcon->timeout);
2477 bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
2478 }
2479}
2480
2481void
2482evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon,
2483 const struct timeval *tv)
2484{
2485 if (tv) {
2486 evcon->initial_retry_timeout = *tv;
2487 } else {
2488 evutil_timerclear(&evcon->initial_retry_timeout);
2489 evcon->initial_retry_timeout.tv_sec = 2;
2490 }
Christopher Wileye8679812015-07-01 13:36:18 -07002491}
2492
2493void
2494evhttp_connection_set_retries(struct evhttp_connection *evcon,
2495 int retry_max)
2496{
2497 evcon->retry_max = retry_max;
2498}
2499
2500void
2501evhttp_connection_set_closecb(struct evhttp_connection *evcon,
2502 void (*cb)(struct evhttp_connection *, void *), void *cbarg)
2503{
2504 evcon->closecb = cb;
2505 evcon->closecb_arg = cbarg;
2506}
2507
2508void
2509evhttp_connection_get_peer(struct evhttp_connection *evcon,
2510 char **address, ev_uint16_t *port)
2511{
2512 *address = evcon->address;
2513 *port = evcon->port;
2514}
2515
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002516const struct sockaddr*
2517evhttp_connection_get_addr(struct evhttp_connection *evcon)
2518{
2519 return bufferevent_socket_get_conn_address_(evcon->bufev);
2520}
2521
Christopher Wileye8679812015-07-01 13:36:18 -07002522int
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002523evhttp_connection_connect_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002524{
2525 int old_state = evcon->state;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002526 const char *address = evcon->address;
2527 const struct sockaddr *sa = evhttp_connection_get_addr(evcon);
2528 int ret;
Christopher Wileye8679812015-07-01 13:36:18 -07002529
2530 if (evcon->state == EVCON_CONNECTING)
2531 return (0);
2532
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002533 evhttp_connection_reset_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07002534
2535 EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING));
2536 evcon->flags |= EVHTTP_CON_OUTGOING;
2537
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002538 if (evcon->bind_address || evcon->bind_port) {
2539 evcon->fd = bind_socket(
2540 evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
2541 if (evcon->fd == -1) {
2542 event_debug(("%s: failed to bind to \"%s\"",
2543 __func__, evcon->bind_address));
2544 return (-1);
2545 }
2546
2547 bufferevent_setfd(evcon->bufev, evcon->fd);
2548 } else {
2549 bufferevent_setfd(evcon->bufev, -1);
Christopher Wileye8679812015-07-01 13:36:18 -07002550 }
2551
2552 /* Set up a callback for successful connection setup */
Christopher Wileye8679812015-07-01 13:36:18 -07002553 bufferevent_setcb(evcon->bufev,
2554 NULL /* evhttp_read_cb */,
2555 NULL /* evhttp_write_cb */,
2556 evhttp_connection_cb,
2557 evcon);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002558 if (!evutil_timerisset(&evcon->timeout)) {
2559 const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 };
2560 bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv);
2561 } else {
2562 bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
2563 }
Christopher Wileye8679812015-07-01 13:36:18 -07002564 /* make sure that we get a write callback */
2565 bufferevent_enable(evcon->bufev, EV_WRITE);
2566
2567 evcon->state = EVCON_CONNECTING;
2568
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002569 if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR &&
2570 sa &&
2571 (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) {
2572 int socklen = sizeof(struct sockaddr_in);
2573 if (sa->sa_family == AF_INET6) {
2574 socklen = sizeof(struct sockaddr_in6);
2575 }
2576 ret = bufferevent_socket_connect(evcon->bufev, sa, socklen);
2577 } else {
2578 ret = bufferevent_socket_connect_hostname(evcon->bufev,
2579 evcon->dns_base, evcon->ai_family, address, evcon->port);
2580 }
2581
2582 if (ret < 0) {
Christopher Wileye8679812015-07-01 13:36:18 -07002583 evcon->state = old_state;
2584 event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
2585 __func__, evcon->address);
2586 /* some operating systems return ECONNREFUSED immediately
2587 * when connecting to a local address. the cleanup is going
2588 * to reschedule this function call.
2589 */
2590 evhttp_connection_cb_cleanup(evcon);
2591 return (0);
2592 }
2593
2594 return (0);
2595}
2596
2597/*
2598 * Starts an HTTP request on the provided evhttp_connection object.
2599 * If the connection object is not connected to the web server already,
2600 * this will start the connection.
2601 */
2602
2603int
2604evhttp_make_request(struct evhttp_connection *evcon,
2605 struct evhttp_request *req,
2606 enum evhttp_cmd_type type, const char *uri)
2607{
2608 /* We are making a request */
2609 req->kind = EVHTTP_REQUEST;
2610 req->type = type;
2611 if (req->uri != NULL)
2612 mm_free(req->uri);
2613 if ((req->uri = mm_strdup(uri)) == NULL) {
2614 event_warn("%s: strdup", __func__);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002615 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002616 return (-1);
2617 }
2618
2619 /* Set the protocol version if it is not supplied */
2620 if (!req->major && !req->minor) {
2621 req->major = 1;
2622 req->minor = 1;
2623 }
2624
2625 EVUTIL_ASSERT(req->evcon == NULL);
2626 req->evcon = evcon;
2627 EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
2628
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002629 TAILQ_INSERT_TAIL(&evcon->requests, req, next);
Christopher Wileye8679812015-07-01 13:36:18 -07002630
2631 /* If the connection object is not connected; make it so */
2632 if (!evhttp_connected(evcon)) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002633 int res = evhttp_connection_connect_(evcon);
2634 /* evhttp_connection_fail_(), which is called through
2635 * evhttp_connection_connect_(), assumes that req lies in
2636 * evcon->requests. Thus, enqueue the request in advance and
2637 * remove it in the error case. */
2638 if (res != 0)
2639 TAILQ_REMOVE(&evcon->requests, req, next);
Christopher Wileye8679812015-07-01 13:36:18 -07002640
2641 return res;
2642 }
2643
2644 /*
2645 * If it's connected already and we are the first in the queue,
2646 * then we can dispatch this request immediately. Otherwise, it
2647 * will be dispatched once the pending requests are completed.
2648 */
2649 if (TAILQ_FIRST(&evcon->requests) == req)
2650 evhttp_request_dispatch(evcon);
2651
2652 return (0);
2653}
2654
2655void
2656evhttp_cancel_request(struct evhttp_request *req)
2657{
2658 struct evhttp_connection *evcon = req->evcon;
2659 if (evcon != NULL) {
2660 /* We need to remove it from the connection */
2661 if (TAILQ_FIRST(&evcon->requests) == req) {
2662 /* it's currently being worked on, so reset
2663 * the connection.
2664 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002665 evhttp_connection_fail_(evcon,
2666 EVREQ_HTTP_REQUEST_CANCEL);
Christopher Wileye8679812015-07-01 13:36:18 -07002667
2668 /* connection fail freed the request */
2669 return;
2670 } else {
2671 /* otherwise, we can just remove it from the
2672 * queue
2673 */
2674 TAILQ_REMOVE(&evcon->requests, req, next);
2675 }
2676 }
2677
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002678 evhttp_request_free_auto(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002679}
2680
2681/*
2682 * Reads data from file descriptor into request structure
2683 * Request structure needs to be set up correctly.
2684 */
2685
2686void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002687evhttp_start_read_(struct evhttp_connection *evcon)
Christopher Wileye8679812015-07-01 13:36:18 -07002688{
Christopher Wileye8679812015-07-01 13:36:18 -07002689 bufferevent_disable(evcon->bufev, EV_WRITE);
2690 bufferevent_enable(evcon->bufev, EV_READ);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002691
Christopher Wileye8679812015-07-01 13:36:18 -07002692 evcon->state = EVCON_READING_FIRSTLINE;
2693 /* Reset the bufferevent callbacks */
2694 bufferevent_setcb(evcon->bufev,
2695 evhttp_read_cb,
2696 evhttp_write_cb,
2697 evhttp_error_cb,
2698 evcon);
2699
2700 /* If there's still data pending, process it next time through the
2701 * loop. Don't do it now; that could get recusive. */
2702 if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002703 event_deferred_cb_schedule_(get_deferred_queue(evcon),
Christopher Wileye8679812015-07-01 13:36:18 -07002704 &evcon->read_more_deferred_cb);
2705 }
2706}
2707
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002708void
2709evhttp_start_write_(struct evhttp_connection *evcon)
2710{
2711 bufferevent_disable(evcon->bufev, EV_WRITE);
2712 bufferevent_enable(evcon->bufev, EV_READ);
2713
2714 evcon->state = EVCON_WRITING;
2715 evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
2716}
2717
Christopher Wileye8679812015-07-01 13:36:18 -07002718static void
2719evhttp_send_done(struct evhttp_connection *evcon, void *arg)
2720{
2721 int need_close;
2722 struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
2723 TAILQ_REMOVE(&evcon->requests, req, next);
2724
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002725 if (req->on_complete_cb != NULL) {
2726 req->on_complete_cb(req, req->on_complete_cb_arg);
2727 }
2728
Christopher Wileye8679812015-07-01 13:36:18 -07002729 need_close =
2730 (REQ_VERSION_BEFORE(req, 1, 1) &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002731 !evhttp_is_connection_keepalive(req->input_headers)) ||
2732 evhttp_is_request_connection_close(req);
Christopher Wileye8679812015-07-01 13:36:18 -07002733
2734 EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION);
2735 evhttp_request_free(req);
2736
2737 if (need_close) {
2738 evhttp_connection_free(evcon);
2739 return;
2740 }
2741
2742 /* we have a persistent connection; try to accept another request. */
2743 if (evhttp_associate_new_request_with_connection(evcon) == -1) {
2744 evhttp_connection_free(evcon);
2745 }
2746}
2747
2748/*
2749 * Returns an error page.
2750 */
2751
2752void
2753evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
2754{
2755
2756#define ERR_FORMAT "<HTML><HEAD>\n" \
2757 "<TITLE>%d %s</TITLE>\n" \
2758 "</HEAD><BODY>\n" \
2759 "<H1>%s</H1>\n" \
2760 "</BODY></HTML>\n"
2761
2762 struct evbuffer *buf = evbuffer_new();
2763 if (buf == NULL) {
2764 /* if we cannot allocate memory; we just drop the connection */
2765 evhttp_connection_free(req->evcon);
2766 return;
2767 }
2768 if (reason == NULL) {
2769 reason = evhttp_response_phrase_internal(error);
2770 }
2771
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002772 evhttp_response_code_(req, error, reason);
Christopher Wileye8679812015-07-01 13:36:18 -07002773
2774 evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason);
2775
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002776 evhttp_send_page_(req, buf);
Christopher Wileye8679812015-07-01 13:36:18 -07002777
2778 evbuffer_free(buf);
2779#undef ERR_FORMAT
2780}
2781
2782/* Requires that headers and response code are already set up */
2783
2784static inline void
2785evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
2786{
2787 struct evhttp_connection *evcon = req->evcon;
2788
2789 if (evcon == NULL) {
2790 evhttp_request_free(req);
2791 return;
2792 }
2793
2794 EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req);
2795
2796 /* we expect no more calls form the user on this request */
2797 req->userdone = 1;
2798
2799 /* xxx: not sure if we really should expose the data buffer this way */
2800 if (databuf != NULL)
2801 evbuffer_add_buffer(req->output_buffer, databuf);
2802
2803 /* Adds headers to the response */
2804 evhttp_make_header(evcon, req);
2805
2806 evhttp_write_buffer(evcon, evhttp_send_done, NULL);
2807}
2808
2809void
2810evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
2811 struct evbuffer *databuf)
2812{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002813 evhttp_response_code_(req, code, reason);
Christopher Wileye8679812015-07-01 13:36:18 -07002814
2815 evhttp_send(req, databuf);
2816}
2817
2818void
2819evhttp_send_reply_start(struct evhttp_request *req, int code,
2820 const char *reason)
2821{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002822 evhttp_response_code_(req, code, reason);
Christopher Wileye8679812015-07-01 13:36:18 -07002823 if (evhttp_find_header(req->output_headers, "Content-Length") == NULL &&
2824 REQ_VERSION_ATLEAST(req, 1, 1) &&
2825 evhttp_response_needs_body(req)) {
2826 /*
2827 * prefer HTTP/1.1 chunked encoding to closing the connection;
2828 * note RFC 2616 section 4.4 forbids it with Content-Length:
2829 * and it's not necessary then anyway.
2830 */
2831 evhttp_add_header(req->output_headers, "Transfer-Encoding",
2832 "chunked");
2833 req->chunked = 1;
2834 } else {
2835 req->chunked = 0;
2836 }
2837 evhttp_make_header(req->evcon, req);
2838 evhttp_write_buffer(req->evcon, NULL, NULL);
2839}
2840
2841void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002842evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf,
2843 void (*cb)(struct evhttp_connection *, void *), void *arg)
Christopher Wileye8679812015-07-01 13:36:18 -07002844{
2845 struct evhttp_connection *evcon = req->evcon;
2846 struct evbuffer *output;
2847
2848 if (evcon == NULL)
2849 return;
2850
2851 output = bufferevent_get_output(evcon->bufev);
2852
2853 if (evbuffer_get_length(databuf) == 0)
2854 return;
2855 if (!evhttp_response_needs_body(req))
2856 return;
2857 if (req->chunked) {
2858 evbuffer_add_printf(output, "%x\r\n",
2859 (unsigned)evbuffer_get_length(databuf));
2860 }
2861 evbuffer_add_buffer(output, databuf);
2862 if (req->chunked) {
2863 evbuffer_add(output, "\r\n", 2);
2864 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002865 evhttp_write_buffer(evcon, cb, arg);
Christopher Wileye8679812015-07-01 13:36:18 -07002866}
2867
2868void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002869evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
2870{
2871 evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL);
2872}
2873void
Christopher Wileye8679812015-07-01 13:36:18 -07002874evhttp_send_reply_end(struct evhttp_request *req)
2875{
2876 struct evhttp_connection *evcon = req->evcon;
2877 struct evbuffer *output;
2878
2879 if (evcon == NULL) {
2880 evhttp_request_free(req);
2881 return;
2882 }
2883
2884 output = bufferevent_get_output(evcon->bufev);
2885
2886 /* we expect no more calls form the user on this request */
2887 req->userdone = 1;
2888
2889 if (req->chunked) {
2890 evbuffer_add(output, "0\r\n\r\n", 5);
2891 evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
2892 req->chunked = 0;
2893 } else if (evbuffer_get_length(output) == 0) {
2894 /* let the connection know that we are done with the request */
2895 evhttp_send_done(evcon, NULL);
2896 } else {
2897 /* make the callback execute after all data has been written */
2898 evcon->cb = evhttp_send_done;
2899 evcon->cb_arg = NULL;
2900 }
2901}
2902
2903static const char *informational_phrases[] = {
2904 /* 100 */ "Continue",
2905 /* 101 */ "Switching Protocols"
2906};
2907
2908static const char *success_phrases[] = {
2909 /* 200 */ "OK",
2910 /* 201 */ "Created",
2911 /* 202 */ "Accepted",
2912 /* 203 */ "Non-Authoritative Information",
2913 /* 204 */ "No Content",
2914 /* 205 */ "Reset Content",
2915 /* 206 */ "Partial Content"
2916};
2917
2918static const char *redirection_phrases[] = {
2919 /* 300 */ "Multiple Choices",
2920 /* 301 */ "Moved Permanently",
2921 /* 302 */ "Found",
2922 /* 303 */ "See Other",
2923 /* 304 */ "Not Modified",
2924 /* 305 */ "Use Proxy",
2925 /* 307 */ "Temporary Redirect"
2926};
2927
2928static const char *client_error_phrases[] = {
2929 /* 400 */ "Bad Request",
2930 /* 401 */ "Unauthorized",
2931 /* 402 */ "Payment Required",
2932 /* 403 */ "Forbidden",
2933 /* 404 */ "Not Found",
2934 /* 405 */ "Method Not Allowed",
2935 /* 406 */ "Not Acceptable",
2936 /* 407 */ "Proxy Authentication Required",
2937 /* 408 */ "Request Time-out",
2938 /* 409 */ "Conflict",
2939 /* 410 */ "Gone",
2940 /* 411 */ "Length Required",
2941 /* 412 */ "Precondition Failed",
2942 /* 413 */ "Request Entity Too Large",
2943 /* 414 */ "Request-URI Too Large",
2944 /* 415 */ "Unsupported Media Type",
2945 /* 416 */ "Requested range not satisfiable",
2946 /* 417 */ "Expectation Failed"
2947};
2948
2949static const char *server_error_phrases[] = {
2950 /* 500 */ "Internal Server Error",
2951 /* 501 */ "Not Implemented",
2952 /* 502 */ "Bad Gateway",
2953 /* 503 */ "Service Unavailable",
2954 /* 504 */ "Gateway Time-out",
2955 /* 505 */ "HTTP Version not supported"
2956};
2957
2958struct response_class {
2959 const char *name;
2960 size_t num_responses;
2961 const char **responses;
2962};
2963
2964#ifndef MEMBERSOF
2965#define MEMBERSOF(x) (sizeof(x)/sizeof(x[0]))
2966#endif
2967
2968static const struct response_class response_classes[] = {
2969 /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases },
2970 /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases },
2971 /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases },
2972 /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases },
2973 /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases }
2974};
2975
2976static const char *
2977evhttp_response_phrase_internal(int code)
2978{
2979 int klass = code / 100 - 1;
2980 int subcode = code % 100;
2981
2982 /* Unknown class - can't do any better here */
2983 if (klass < 0 || klass >= (int) MEMBERSOF(response_classes))
2984 return "Unknown Status Class";
2985
2986 /* Unknown sub-code, return class name at least */
2987 if (subcode >= (int) response_classes[klass].num_responses)
2988 return response_classes[klass].name;
2989
2990 return response_classes[klass].responses[subcode];
2991}
2992
2993void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01002994evhttp_response_code_(struct evhttp_request *req, int code, const char *reason)
Christopher Wileye8679812015-07-01 13:36:18 -07002995{
2996 req->kind = EVHTTP_RESPONSE;
2997 req->response_code = code;
2998 if (req->response_code_line != NULL)
2999 mm_free(req->response_code_line);
3000 if (reason == NULL)
3001 reason = evhttp_response_phrase_internal(code);
3002 req->response_code_line = mm_strdup(reason);
3003 if (req->response_code_line == NULL) {
3004 event_warn("%s: strdup", __func__);
3005 /* XXX what else can we do? */
3006 }
3007}
3008
3009void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003010evhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf)
Christopher Wileye8679812015-07-01 13:36:18 -07003011{
3012 if (!req->major || !req->minor) {
3013 req->major = 1;
3014 req->minor = 1;
3015 }
3016
3017 if (req->kind != EVHTTP_RESPONSE)
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003018 evhttp_response_code_(req, 200, "OK");
Christopher Wileye8679812015-07-01 13:36:18 -07003019
3020 evhttp_clear_headers(req->output_headers);
3021 evhttp_add_header(req->output_headers, "Content-Type", "text/html");
3022 evhttp_add_header(req->output_headers, "Connection", "close");
3023
3024 evhttp_send(req, databuf);
3025}
3026
3027static const char uri_chars[256] = {
3028 /* 0 */
3029 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3030 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3031 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
3032 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
3033 /* 64 */
3034 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3035 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
3036 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3037 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
3038 /* 128 */
3039 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3040 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3041 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3043 /* 192 */
3044 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3045 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3046 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3047 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3048};
3049
3050#define CHAR_IS_UNRESERVED(c) \
3051 (uri_chars[(unsigned char)(c)])
3052
3053/*
3054 * Helper functions to encode/decode a string for inclusion in a URI.
3055 * The returned string must be freed by the caller.
3056 */
3057char *
3058evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus)
3059{
3060 struct evbuffer *buf = evbuffer_new();
3061 const char *p, *end;
3062 char *result;
3063
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003064 if (buf == NULL) {
Christopher Wileye8679812015-07-01 13:36:18 -07003065 return (NULL);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003066 }
Christopher Wileye8679812015-07-01 13:36:18 -07003067
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003068
3069 if (len >= 0) {
3070 if (uri + len < uri) {
3071 return (NULL);
3072 }
3073
3074 end = uri + len;
3075 } else {
3076 size_t slen = strlen(uri);
3077
3078 if (slen >= EV_SSIZE_MAX) {
3079 /* we don't want to mix signed and unsigned */
3080 return (NULL);
3081 }
3082
3083 if (uri + slen < uri) {
3084 return (NULL);
3085 }
3086
3087 end = uri + slen;
3088 }
Christopher Wileye8679812015-07-01 13:36:18 -07003089
3090 for (p = uri; p < end; p++) {
3091 if (CHAR_IS_UNRESERVED(*p)) {
3092 evbuffer_add(buf, p, 1);
3093 } else if (*p == ' ' && space_as_plus) {
3094 evbuffer_add(buf, "+", 1);
3095 } else {
3096 evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p));
3097 }
3098 }
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003099
Christopher Wileye8679812015-07-01 13:36:18 -07003100 evbuffer_add(buf, "", 1); /* NUL-terminator. */
3101 result = mm_malloc(evbuffer_get_length(buf));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003102
Christopher Wileye8679812015-07-01 13:36:18 -07003103 if (result)
3104 evbuffer_remove(buf, result, evbuffer_get_length(buf));
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003105
Christopher Wileye8679812015-07-01 13:36:18 -07003106 evbuffer_free(buf);
3107
3108 return (result);
3109}
3110
3111char *
3112evhttp_encode_uri(const char *str)
3113{
3114 return evhttp_uriencode(str, -1, 0);
3115}
3116
3117/*
3118 * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't.
3119 * If -1, when true we transform plus to space only after we've seen
3120 * a ?. -1 is deprecated.
3121 * @return the number of bytes written to 'ret'.
3122 */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003123int
Christopher Wileye8679812015-07-01 13:36:18 -07003124evhttp_decode_uri_internal(
3125 const char *uri, size_t length, char *ret, int decode_plus_ctl)
3126{
3127 char c;
3128 int j;
3129 int decode_plus = (decode_plus_ctl == 1) ? 1: 0;
3130 unsigned i;
3131
3132 for (i = j = 0; i < length; i++) {
3133 c = uri[i];
3134 if (c == '?') {
3135 if (decode_plus_ctl < 0)
3136 decode_plus = 1;
3137 } else if (c == '+' && decode_plus) {
3138 c = ' ';
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003139 } else if ((i + 2) < length && c == '%' &&
3140 EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) {
Christopher Wileye8679812015-07-01 13:36:18 -07003141 char tmp[3];
3142 tmp[0] = uri[i+1];
3143 tmp[1] = uri[i+2];
3144 tmp[2] = '\0';
3145 c = (char)strtol(tmp, NULL, 16);
3146 i += 2;
3147 }
3148 ret[j++] = c;
3149 }
3150 ret[j] = '\0';
3151
3152 return (j);
3153}
3154
3155/* deprecated */
3156char *
3157evhttp_decode_uri(const char *uri)
3158{
3159 char *ret;
3160
3161 if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
3162 event_warn("%s: malloc(%lu)", __func__,
3163 (unsigned long)(strlen(uri) + 1));
3164 return (NULL);
3165 }
3166
3167 evhttp_decode_uri_internal(uri, strlen(uri),
3168 ret, -1 /*always_decode_plus*/);
3169
3170 return (ret);
3171}
3172
3173char *
3174evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out)
3175{
3176 char *ret;
3177 int n;
3178
3179 if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
3180 event_warn("%s: malloc(%lu)", __func__,
3181 (unsigned long)(strlen(uri) + 1));
3182 return (NULL);
3183 }
3184
3185 n = evhttp_decode_uri_internal(uri, strlen(uri),
3186 ret, !!decode_plus/*always_decode_plus*/);
3187
3188 if (size_out) {
3189 EVUTIL_ASSERT(n >= 0);
3190 *size_out = (size_t)n;
3191 }
3192
3193 return (ret);
3194}
3195
3196/*
3197 * Helper function to parse out arguments in a query.
3198 * The arguments are separated by key and value.
3199 */
3200
3201static int
3202evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
3203 int is_whole_uri)
3204{
3205 char *line=NULL;
3206 char *argument;
3207 char *p;
3208 const char *query_part;
3209 int result = -1;
3210 struct evhttp_uri *uri=NULL;
3211
3212 TAILQ_INIT(headers);
3213
3214 if (is_whole_uri) {
3215 uri = evhttp_uri_parse(str);
3216 if (!uri)
3217 goto error;
3218 query_part = evhttp_uri_get_query(uri);
3219 } else {
3220 query_part = str;
3221 }
3222
3223 /* No arguments - we are done */
3224 if (!query_part || !strlen(query_part)) {
3225 result = 0;
3226 goto done;
3227 }
3228
3229 if ((line = mm_strdup(query_part)) == NULL) {
3230 event_warn("%s: strdup", __func__);
3231 goto error;
3232 }
3233
3234 p = argument = line;
3235 while (p != NULL && *p != '\0') {
3236 char *key, *value, *decoded_value;
3237 argument = strsep(&p, "&");
3238
3239 value = argument;
3240 key = strsep(&value, "=");
3241 if (value == NULL || *key == '\0') {
3242 goto error;
3243 }
3244
3245 if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) {
3246 event_warn("%s: mm_malloc", __func__);
3247 goto error;
3248 }
3249 evhttp_decode_uri_internal(value, strlen(value),
3250 decoded_value, 1 /*always_decode_plus*/);
3251 event_debug(("Query Param: %s -> %s\n", key, decoded_value));
3252 evhttp_add_header_internal(headers, key, decoded_value);
3253 mm_free(decoded_value);
3254 }
3255
3256 result = 0;
3257 goto done;
3258error:
3259 evhttp_clear_headers(headers);
3260done:
3261 if (line)
3262 mm_free(line);
3263 if (uri)
3264 evhttp_uri_free(uri);
3265 return result;
3266}
3267
3268int
3269evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
3270{
3271 return evhttp_parse_query_impl(uri, headers, 1);
3272}
3273int
3274evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers)
3275{
3276 return evhttp_parse_query_impl(uri, headers, 0);
3277}
3278
3279static struct evhttp_cb *
3280evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
3281{
3282 struct evhttp_cb *cb;
3283 size_t offset = 0;
3284 char *translated;
3285 const char *path;
3286
3287 /* Test for different URLs */
3288 path = evhttp_uri_get_path(req->uri_elems);
3289 offset = strlen(path);
3290 if ((translated = mm_malloc(offset + 1)) == NULL)
3291 return (NULL);
3292 evhttp_decode_uri_internal(path, offset, translated,
3293 0 /* decode_plus */);
3294
3295 TAILQ_FOREACH(cb, callbacks, next) {
3296 if (!strcmp(cb->what, translated)) {
3297 mm_free(translated);
3298 return (cb);
3299 }
3300 }
3301
3302 mm_free(translated);
3303 return (NULL);
3304}
3305
3306
3307static int
3308prefix_suffix_match(const char *pattern, const char *name, int ignorecase)
3309{
3310 char c;
3311
3312 while (1) {
3313 switch (c = *pattern++) {
3314 case '\0':
3315 return *name == '\0';
3316
3317 case '*':
3318 while (*name != '\0') {
3319 if (prefix_suffix_match(pattern, name,
3320 ignorecase))
3321 return (1);
3322 ++name;
3323 }
3324 return (0);
3325 default:
3326 if (c != *name) {
3327 if (!ignorecase ||
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003328 EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name))
Christopher Wileye8679812015-07-01 13:36:18 -07003329 return (0);
3330 }
3331 ++name;
3332 }
3333 }
3334 /* NOTREACHED */
3335}
3336
3337/*
3338 Search the vhost hierarchy beginning with http for a server alias
3339 matching hostname. If a match is found, and outhttp is non-null,
3340 outhttp is set to the matching http object and 1 is returned.
3341*/
3342
3343static int
3344evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp,
3345 const char *hostname)
3346{
3347 struct evhttp_server_alias *alias;
3348 struct evhttp *vhost;
3349
3350 TAILQ_FOREACH(alias, &http->aliases, next) {
3351 /* XXX Do we need to handle IP addresses? */
3352 if (!evutil_ascii_strcasecmp(alias->alias, hostname)) {
3353 if (outhttp)
3354 *outhttp = http;
3355 return 1;
3356 }
3357 }
3358
3359 /* XXX It might be good to avoid recursion here, but I don't
3360 see a way to do that w/o a list. */
3361 TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
3362 if (evhttp_find_alias(vhost, outhttp, hostname))
3363 return 1;
3364 }
3365
3366 return 0;
3367}
3368
3369/*
3370 Attempts to find the best http object to handle a request for a hostname.
3371 All aliases for the root http object and vhosts are searched for an exact
3372 match. Then, the vhost hierarchy is traversed again for a matching
3373 pattern.
3374
3375 If an alias or vhost is matched, 1 is returned, and outhttp, if non-null,
3376 is set with the best matching http object. If there are no matches, the
3377 root http object is stored in outhttp and 0 is returned.
3378*/
3379
3380static int
3381evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
3382 const char *hostname)
3383{
3384 struct evhttp *vhost;
3385 struct evhttp *oldhttp;
3386 int match_found = 0;
3387
3388 if (evhttp_find_alias(http, outhttp, hostname))
3389 return 1;
3390
3391 do {
3392 oldhttp = http;
3393 TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
3394 if (prefix_suffix_match(vhost->vhost_pattern,
3395 hostname, 1 /* ignorecase */)) {
3396 http = vhost;
3397 match_found = 1;
3398 break;
3399 }
3400 }
3401 } while (oldhttp != http);
3402
3403 if (outhttp)
3404 *outhttp = http;
3405
3406 return match_found;
3407}
3408
3409static void
3410evhttp_handle_request(struct evhttp_request *req, void *arg)
3411{
3412 struct evhttp *http = arg;
3413 struct evhttp_cb *cb = NULL;
3414 const char *hostname;
3415
3416 /* we have a new request on which the user needs to take action */
3417 req->userdone = 0;
3418
3419 if (req->type == 0 || req->uri == NULL) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003420 evhttp_send_error(req, req->response_code, NULL);
Christopher Wileye8679812015-07-01 13:36:18 -07003421 return;
3422 }
3423
3424 if ((http->allowed_methods & req->type) == 0) {
3425 event_debug(("Rejecting disallowed method %x (allowed: %x)\n",
3426 (unsigned)req->type, (unsigned)http->allowed_methods));
3427 evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL);
3428 return;
3429 }
3430
3431 /* handle potential virtual hosts */
3432 hostname = evhttp_request_get_host(req);
3433 if (hostname != NULL) {
3434 evhttp_find_vhost(http, &http, hostname);
3435 }
3436
3437 if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
3438 (*cb->cb)(req, cb->cbarg);
3439 return;
3440 }
3441
3442 /* Generic call back */
3443 if (http->gencb) {
3444 (*http->gencb)(req, http->gencbarg);
3445 return;
3446 } else {
3447 /* We need to send a 404 here */
3448#define ERR_FORMAT "<html><head>" \
3449 "<title>404 Not Found</title>" \
3450 "</head><body>" \
3451 "<h1>Not Found</h1>" \
3452 "<p>The requested URL %s was not found on this server.</p>"\
3453 "</body></html>\n"
3454
3455 char *escaped_html;
3456 struct evbuffer *buf;
3457
3458 if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) {
3459 evhttp_connection_free(req->evcon);
3460 return;
3461 }
3462
3463 if ((buf = evbuffer_new()) == NULL) {
3464 mm_free(escaped_html);
3465 evhttp_connection_free(req->evcon);
3466 return;
3467 }
3468
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003469 evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found");
Christopher Wileye8679812015-07-01 13:36:18 -07003470
3471 evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
3472
3473 mm_free(escaped_html);
3474
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003475 evhttp_send_page_(req, buf);
Christopher Wileye8679812015-07-01 13:36:18 -07003476
3477 evbuffer_free(buf);
3478#undef ERR_FORMAT
3479 }
3480}
3481
3482/* Listener callback when a connection arrives at a server. */
3483static void
3484accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg)
3485{
3486 struct evhttp *http = arg;
3487
3488 evhttp_get_request(http, nfd, peer_sa, peer_socklen);
3489}
3490
3491int
3492evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port)
3493{
3494 struct evhttp_bound_socket *bound =
3495 evhttp_bind_socket_with_handle(http, address, port);
3496 if (bound == NULL)
3497 return (-1);
3498 return (0);
3499}
3500
3501struct evhttp_bound_socket *
3502evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port)
3503{
3504 evutil_socket_t fd;
3505 struct evhttp_bound_socket *bound;
3506
3507 if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
3508 return (NULL);
3509
3510 if (listen(fd, 128) == -1) {
3511 event_sock_warn(fd, "%s: listen", __func__);
3512 evutil_closesocket(fd);
3513 return (NULL);
3514 }
3515
3516 bound = evhttp_accept_socket_with_handle(http, fd);
3517
3518 if (bound != NULL) {
3519 event_debug(("Bound to port %d - Awaiting connections ... ",
3520 port));
3521 return (bound);
3522 }
3523
3524 return (NULL);
3525}
3526
3527int
3528evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)
3529{
3530 struct evhttp_bound_socket *bound =
3531 evhttp_accept_socket_with_handle(http, fd);
3532 if (bound == NULL)
3533 return (-1);
3534 return (0);
3535}
3536
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003537void
3538evhttp_foreach_bound_socket(struct evhttp *http,
3539 evhttp_bound_socket_foreach_fn *function,
3540 void *argument)
3541{
3542 struct evhttp_bound_socket *bound;
3543
3544 TAILQ_FOREACH(bound, &http->sockets, next)
3545 function(bound, argument);
3546}
Christopher Wileye8679812015-07-01 13:36:18 -07003547
3548struct evhttp_bound_socket *
3549evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd)
3550{
3551 struct evhttp_bound_socket *bound;
3552 struct evconnlistener *listener;
3553 const int flags =
3554 LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE;
3555
3556 listener = evconnlistener_new(http->base, NULL, NULL,
3557 flags,
3558 0, /* Backlog is '0' because we already said 'listen' */
3559 fd);
3560 if (!listener)
3561 return (NULL);
3562
3563 bound = evhttp_bind_listener(http, listener);
3564 if (!bound) {
3565 evconnlistener_free(listener);
3566 return (NULL);
3567 }
3568 return (bound);
3569}
3570
3571struct evhttp_bound_socket *
3572evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener)
3573{
3574 struct evhttp_bound_socket *bound;
3575
3576 bound = mm_malloc(sizeof(struct evhttp_bound_socket));
3577 if (bound == NULL)
3578 return (NULL);
3579
3580 bound->listener = listener;
3581 TAILQ_INSERT_TAIL(&http->sockets, bound, next);
3582
3583 evconnlistener_set_cb(listener, accept_socket_cb, http);
3584 return bound;
3585}
3586
3587evutil_socket_t
3588evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound)
3589{
3590 return evconnlistener_get_fd(bound->listener);
3591}
3592
3593struct evconnlistener *
3594evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
3595{
3596 return bound->listener;
3597}
3598
3599void
3600evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound)
3601{
3602 TAILQ_REMOVE(&http->sockets, bound, next);
3603 evconnlistener_free(bound->listener);
3604 mm_free(bound);
3605}
3606
3607static struct evhttp*
3608evhttp_new_object(void)
3609{
3610 struct evhttp *http = NULL;
3611
3612 if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) {
3613 event_warn("%s: calloc", __func__);
3614 return (NULL);
3615 }
3616
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003617 evutil_timerclear(&http->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07003618 evhttp_set_max_headers_size(http, EV_SIZE_MAX);
3619 evhttp_set_max_body_size(http, EV_SIZE_MAX);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003620 evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1");
Christopher Wileye8679812015-07-01 13:36:18 -07003621 evhttp_set_allowed_methods(http,
3622 EVHTTP_REQ_GET |
3623 EVHTTP_REQ_POST |
3624 EVHTTP_REQ_HEAD |
3625 EVHTTP_REQ_PUT |
3626 EVHTTP_REQ_DELETE);
3627
3628 TAILQ_INIT(&http->sockets);
3629 TAILQ_INIT(&http->callbacks);
3630 TAILQ_INIT(&http->connections);
3631 TAILQ_INIT(&http->virtualhosts);
3632 TAILQ_INIT(&http->aliases);
3633
3634 return (http);
3635}
3636
3637struct evhttp *
3638evhttp_new(struct event_base *base)
3639{
3640 struct evhttp *http = NULL;
3641
3642 http = evhttp_new_object();
3643 if (http == NULL)
3644 return (NULL);
3645 http->base = base;
3646
3647 return (http);
3648}
3649
3650/*
3651 * Start a web server on the specified address and port.
3652 */
3653
3654struct evhttp *
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003655evhttp_start(const char *address, ev_uint16_t port)
Christopher Wileye8679812015-07-01 13:36:18 -07003656{
3657 struct evhttp *http = NULL;
3658
3659 http = evhttp_new_object();
3660 if (http == NULL)
3661 return (NULL);
3662 if (evhttp_bind_socket(http, address, port) == -1) {
3663 mm_free(http);
3664 return (NULL);
3665 }
3666
3667 return (http);
3668}
3669
3670void
3671evhttp_free(struct evhttp* http)
3672{
3673 struct evhttp_cb *http_cb;
3674 struct evhttp_connection *evcon;
3675 struct evhttp_bound_socket *bound;
3676 struct evhttp* vhost;
3677 struct evhttp_server_alias *alias;
3678
3679 /* Remove the accepting part */
3680 while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
3681 TAILQ_REMOVE(&http->sockets, bound, next);
3682
3683 evconnlistener_free(bound->listener);
3684
3685 mm_free(bound);
3686 }
3687
3688 while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
3689 /* evhttp_connection_free removes the connection */
3690 evhttp_connection_free(evcon);
3691 }
3692
3693 while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
3694 TAILQ_REMOVE(&http->callbacks, http_cb, next);
3695 mm_free(http_cb->what);
3696 mm_free(http_cb);
3697 }
3698
3699 while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) {
3700 TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
3701
3702 evhttp_free(vhost);
3703 }
3704
3705 if (http->vhost_pattern != NULL)
3706 mm_free(http->vhost_pattern);
3707
3708 while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) {
3709 TAILQ_REMOVE(&http->aliases, alias, next);
3710 mm_free(alias->alias);
3711 mm_free(alias);
3712 }
3713
3714 mm_free(http);
3715}
3716
3717int
3718evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
3719 struct evhttp* vhost)
3720{
3721 /* a vhost can only be a vhost once and should not have bound sockets */
3722 if (vhost->vhost_pattern != NULL ||
3723 TAILQ_FIRST(&vhost->sockets) != NULL)
3724 return (-1);
3725
3726 vhost->vhost_pattern = mm_strdup(pattern);
3727 if (vhost->vhost_pattern == NULL)
3728 return (-1);
3729
3730 TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost);
3731
3732 return (0);
3733}
3734
3735int
3736evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost)
3737{
3738 if (vhost->vhost_pattern == NULL)
3739 return (-1);
3740
3741 TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
3742
3743 mm_free(vhost->vhost_pattern);
3744 vhost->vhost_pattern = NULL;
3745
3746 return (0);
3747}
3748
3749int
3750evhttp_add_server_alias(struct evhttp *http, const char *alias)
3751{
3752 struct evhttp_server_alias *evalias;
3753
3754 evalias = mm_calloc(1, sizeof(*evalias));
3755 if (!evalias)
3756 return -1;
3757
3758 evalias->alias = mm_strdup(alias);
3759 if (!evalias->alias) {
3760 mm_free(evalias);
3761 return -1;
3762 }
3763
3764 TAILQ_INSERT_TAIL(&http->aliases, evalias, next);
3765
3766 return 0;
3767}
3768
3769int
3770evhttp_remove_server_alias(struct evhttp *http, const char *alias)
3771{
3772 struct evhttp_server_alias *evalias;
3773
3774 TAILQ_FOREACH(evalias, &http->aliases, next) {
3775 if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) {
3776 TAILQ_REMOVE(&http->aliases, evalias, next);
3777 mm_free(evalias->alias);
3778 mm_free(evalias);
3779 return 0;
3780 }
3781 }
3782
3783 return -1;
3784}
3785
3786void
3787evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
3788{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003789 if (timeout_in_secs == -1) {
3790 evhttp_set_timeout_tv(http, NULL);
3791 } else {
3792 struct timeval tv;
3793 tv.tv_sec = timeout_in_secs;
3794 tv.tv_usec = 0;
3795 evhttp_set_timeout_tv(http, &tv);
3796 }
3797}
3798
3799void
3800evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
3801{
3802 if (tv) {
3803 http->timeout = *tv;
3804 } else {
3805 evutil_timerclear(&http->timeout);
3806 }
3807}
3808
3809int evhttp_set_flags(struct evhttp *http, int flags)
3810{
3811 int avail_flags = 0;
3812 avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE;
3813
3814 if (flags & ~avail_flags)
3815 return 1;
3816 http->flags &= ~avail_flags;
3817
3818 http->flags |= flags;
3819
3820 return 0;
Christopher Wileye8679812015-07-01 13:36:18 -07003821}
3822
3823void
3824evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size)
3825{
3826 if (max_headers_size < 0)
3827 http->default_max_headers_size = EV_SIZE_MAX;
3828 else
3829 http->default_max_headers_size = max_headers_size;
3830}
3831
3832void
3833evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size)
3834{
3835 if (max_body_size < 0)
3836 http->default_max_body_size = EV_UINT64_MAX;
3837 else
3838 http->default_max_body_size = max_body_size;
3839}
3840
3841void
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003842evhttp_set_default_content_type(struct evhttp *http,
3843 const char *content_type) {
3844 http->default_content_type = content_type;
3845}
3846
3847void
Christopher Wileye8679812015-07-01 13:36:18 -07003848evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods)
3849{
3850 http->allowed_methods = methods;
3851}
3852
3853int
3854evhttp_set_cb(struct evhttp *http, const char *uri,
3855 void (*cb)(struct evhttp_request *, void *), void *cbarg)
3856{
3857 struct evhttp_cb *http_cb;
3858
3859 TAILQ_FOREACH(http_cb, &http->callbacks, next) {
3860 if (strcmp(http_cb->what, uri) == 0)
3861 return (-1);
3862 }
3863
3864 if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) {
3865 event_warn("%s: calloc", __func__);
3866 return (-2);
3867 }
3868
3869 http_cb->what = mm_strdup(uri);
3870 if (http_cb->what == NULL) {
3871 event_warn("%s: strdup", __func__);
3872 mm_free(http_cb);
3873 return (-3);
3874 }
3875 http_cb->cb = cb;
3876 http_cb->cbarg = cbarg;
3877
3878 TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
3879
3880 return (0);
3881}
3882
3883int
3884evhttp_del_cb(struct evhttp *http, const char *uri)
3885{
3886 struct evhttp_cb *http_cb;
3887
3888 TAILQ_FOREACH(http_cb, &http->callbacks, next) {
3889 if (strcmp(http_cb->what, uri) == 0)
3890 break;
3891 }
3892 if (http_cb == NULL)
3893 return (-1);
3894
3895 TAILQ_REMOVE(&http->callbacks, http_cb, next);
3896 mm_free(http_cb->what);
3897 mm_free(http_cb);
3898
3899 return (0);
3900}
3901
3902void
3903evhttp_set_gencb(struct evhttp *http,
3904 void (*cb)(struct evhttp_request *, void *), void *cbarg)
3905{
3906 http->gencb = cb;
3907 http->gencbarg = cbarg;
3908}
3909
Narayan Kamathfc74cb42017-09-13 12:53:52 +01003910void
3911evhttp_set_bevcb(struct evhttp *http,
3912 struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg)
3913{
3914 http->bevcb = cb;
3915 http->bevcbarg = cbarg;
3916}
3917
Christopher Wileye8679812015-07-01 13:36:18 -07003918/*
3919 * Request related functions
3920 */
3921
3922struct evhttp_request *
3923evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
3924{
3925 struct evhttp_request *req = NULL;
3926
3927 /* Allocate request structure */
3928 if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) {
3929 event_warn("%s: calloc", __func__);
3930 goto error;
3931 }
3932
3933 req->headers_size = 0;
3934 req->body_size = 0;
3935
3936 req->kind = EVHTTP_RESPONSE;
3937 req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq));
3938 if (req->input_headers == NULL) {
3939 event_warn("%s: calloc", __func__);
3940 goto error;
3941 }
3942 TAILQ_INIT(req->input_headers);
3943
3944 req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq));
3945 if (req->output_headers == NULL) {
3946 event_warn("%s: calloc", __func__);
3947 goto error;
3948 }
3949 TAILQ_INIT(req->output_headers);
3950
3951 if ((req->input_buffer = evbuffer_new()) == NULL) {
3952 event_warn("%s: evbuffer_new", __func__);
3953 goto error;
3954 }
3955
3956 if ((req->output_buffer = evbuffer_new()) == NULL) {
3957 event_warn("%s: evbuffer_new", __func__);
3958 goto error;
3959 }
3960
3961 req->cb = cb;
3962 req->cb_arg = arg;
3963
3964 return (req);
3965
3966 error:
3967 if (req != NULL)
3968 evhttp_request_free(req);
3969 return (NULL);
3970}
3971
3972void
3973evhttp_request_free(struct evhttp_request *req)
3974{
3975 if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) {
3976 req->flags |= EVHTTP_REQ_NEEDS_FREE;
3977 return;
3978 }
3979
3980 if (req->remote_host != NULL)
3981 mm_free(req->remote_host);
3982 if (req->uri != NULL)
3983 mm_free(req->uri);
3984 if (req->uri_elems != NULL)
3985 evhttp_uri_free(req->uri_elems);
3986 if (req->response_code_line != NULL)
3987 mm_free(req->response_code_line);
3988 if (req->host_cache != NULL)
3989 mm_free(req->host_cache);
3990
3991 evhttp_clear_headers(req->input_headers);
3992 mm_free(req->input_headers);
3993
3994 evhttp_clear_headers(req->output_headers);
3995 mm_free(req->output_headers);
3996
3997 if (req->input_buffer != NULL)
3998 evbuffer_free(req->input_buffer);
3999
4000 if (req->output_buffer != NULL)
4001 evbuffer_free(req->output_buffer);
4002
4003 mm_free(req);
4004}
4005
4006void
4007evhttp_request_own(struct evhttp_request *req)
4008{
4009 req->flags |= EVHTTP_USER_OWNED;
4010}
4011
4012int
4013evhttp_request_is_owned(struct evhttp_request *req)
4014{
4015 return (req->flags & EVHTTP_USER_OWNED) != 0;
4016}
4017
4018struct evhttp_connection *
4019evhttp_request_get_connection(struct evhttp_request *req)
4020{
4021 return req->evcon;
4022}
4023
4024struct event_base *
4025evhttp_connection_get_base(struct evhttp_connection *conn)
4026{
4027 return conn->base;
4028}
4029
4030void
4031evhttp_request_set_chunked_cb(struct evhttp_request *req,
4032 void (*cb)(struct evhttp_request *, void *))
4033{
4034 req->chunk_cb = cb;
4035}
4036
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004037void
4038evhttp_request_set_header_cb(struct evhttp_request *req,
4039 int (*cb)(struct evhttp_request *, void *))
4040{
4041 req->header_cb = cb;
4042}
4043
4044void
4045evhttp_request_set_error_cb(struct evhttp_request *req,
4046 void (*cb)(enum evhttp_request_error, void *))
4047{
4048 req->error_cb = cb;
4049}
4050
4051void
4052evhttp_request_set_on_complete_cb(struct evhttp_request *req,
4053 void (*cb)(struct evhttp_request *, void *), void *cb_arg)
4054{
4055 req->on_complete_cb = cb;
4056 req->on_complete_cb_arg = cb_arg;
4057}
4058
Christopher Wileye8679812015-07-01 13:36:18 -07004059/*
4060 * Allows for inspection of the request URI
4061 */
4062
4063const char *
4064evhttp_request_get_uri(const struct evhttp_request *req) {
4065 if (req->uri == NULL)
4066 event_debug(("%s: request %p has no uri\n", __func__, req));
4067 return (req->uri);
4068}
4069
4070const struct evhttp_uri *
4071evhttp_request_get_evhttp_uri(const struct evhttp_request *req) {
4072 if (req->uri_elems == NULL)
4073 event_debug(("%s: request %p has no uri elems\n",
4074 __func__, req));
4075 return (req->uri_elems);
4076}
4077
4078const char *
4079evhttp_request_get_host(struct evhttp_request *req)
4080{
4081 const char *host = NULL;
4082
4083 if (req->host_cache)
4084 return req->host_cache;
4085
4086 if (req->uri_elems)
4087 host = evhttp_uri_get_host(req->uri_elems);
4088 if (!host && req->input_headers) {
4089 const char *p;
4090 size_t len;
4091
4092 host = evhttp_find_header(req->input_headers, "Host");
4093 /* The Host: header may include a port. Remove it here
4094 to be consistent with uri_elems case above. */
4095 if (host) {
4096 p = host + strlen(host) - 1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004097 while (p > host && EVUTIL_ISDIGIT_(*p))
Christopher Wileye8679812015-07-01 13:36:18 -07004098 --p;
4099 if (p > host && *p == ':') {
4100 len = p - host;
4101 req->host_cache = mm_malloc(len + 1);
4102 if (!req->host_cache) {
4103 event_warn("%s: malloc", __func__);
4104 return NULL;
4105 }
4106 memcpy(req->host_cache, host, len);
4107 req->host_cache[len] = '\0';
4108 host = req->host_cache;
4109 }
4110 }
4111 }
4112
4113 return host;
4114}
4115
4116enum evhttp_cmd_type
4117evhttp_request_get_command(const struct evhttp_request *req) {
4118 return (req->type);
4119}
4120
4121int
4122evhttp_request_get_response_code(const struct evhttp_request *req)
4123{
4124 return req->response_code;
4125}
4126
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004127const char *
4128evhttp_request_get_response_code_line(const struct evhttp_request *req)
4129{
4130 return req->response_code_line;
4131}
4132
Christopher Wileye8679812015-07-01 13:36:18 -07004133/** Returns the input headers */
4134struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req)
4135{
4136 return (req->input_headers);
4137}
4138
4139/** Returns the output headers */
4140struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req)
4141{
4142 return (req->output_headers);
4143}
4144
4145/** Returns the input buffer */
4146struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req)
4147{
4148 return (req->input_buffer);
4149}
4150
4151/** Returns the output buffer */
4152struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req)
4153{
4154 return (req->output_buffer);
4155}
4156
4157
4158/*
4159 * Takes a file descriptor to read a request from.
4160 * The callback is executed once the whole request has been read.
4161 */
4162
4163static struct evhttp_connection*
4164evhttp_get_request_connection(
4165 struct evhttp* http,
4166 evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen)
4167{
4168 struct evhttp_connection *evcon;
4169 char *hostname = NULL, *portname = NULL;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004170 struct bufferevent* bev = NULL;
Christopher Wileye8679812015-07-01 13:36:18 -07004171
4172 name_from_addr(sa, salen, &hostname, &portname);
4173 if (hostname == NULL || portname == NULL) {
4174 if (hostname) mm_free(hostname);
4175 if (portname) mm_free(portname);
4176 return (NULL);
4177 }
4178
4179 event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
4180 __func__, hostname, portname, EV_SOCK_ARG(fd)));
4181
4182 /* we need a connection object to put the http request on */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004183 if (http->bevcb != NULL) {
4184 bev = (*http->bevcb)(http->base, http->bevcbarg);
4185 }
4186 evcon = evhttp_connection_base_bufferevent_new(
4187 http->base, NULL, bev, hostname, atoi(portname));
Christopher Wileye8679812015-07-01 13:36:18 -07004188 mm_free(hostname);
4189 mm_free(portname);
4190 if (evcon == NULL)
4191 return (NULL);
4192
4193 evcon->max_headers_size = http->default_max_headers_size;
4194 evcon->max_body_size = http->default_max_body_size;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004195 if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE)
4196 evcon->flags |= EVHTTP_CON_LINGERING_CLOSE;
Christopher Wileye8679812015-07-01 13:36:18 -07004197
4198 evcon->flags |= EVHTTP_CON_INCOMING;
4199 evcon->state = EVCON_READING_FIRSTLINE;
4200
4201 evcon->fd = fd;
4202
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004203 bufferevent_enable(evcon->bufev, EV_READ);
4204 bufferevent_disable(evcon->bufev, EV_WRITE);
Christopher Wileye8679812015-07-01 13:36:18 -07004205 bufferevent_setfd(evcon->bufev, fd);
4206
4207 return (evcon);
4208}
4209
4210static int
4211evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
4212{
4213 struct evhttp *http = evcon->http_server;
4214 struct evhttp_request *req;
4215 if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
4216 return (-1);
4217
4218 if ((req->remote_host = mm_strdup(evcon->address)) == NULL) {
4219 event_warn("%s: strdup", __func__);
4220 evhttp_request_free(req);
4221 return (-1);
4222 }
4223 req->remote_port = evcon->port;
4224
4225 req->evcon = evcon; /* the request ends up owning the connection */
4226 req->flags |= EVHTTP_REQ_OWN_CONNECTION;
4227
4228 /* We did not present the request to the user user yet, so treat it as
4229 * if the user was done with the request. This allows us to free the
4230 * request on a persistent connection if the client drops it without
4231 * sending a request.
4232 */
4233 req->userdone = 1;
4234
4235 TAILQ_INSERT_TAIL(&evcon->requests, req, next);
4236
4237 req->kind = EVHTTP_REQUEST;
4238
4239
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004240 evhttp_start_read_(evcon);
Christopher Wileye8679812015-07-01 13:36:18 -07004241
4242 return (0);
4243}
4244
4245static void
4246evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
4247 struct sockaddr *sa, ev_socklen_t salen)
4248{
4249 struct evhttp_connection *evcon;
4250
4251 evcon = evhttp_get_request_connection(http, fd, sa, salen);
4252 if (evcon == NULL) {
4253 event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT,
4254 __func__, EV_SOCK_ARG(fd));
4255 evutil_closesocket(fd);
4256 return;
4257 }
4258
4259 /* the timeout can be used by the server to close idle connections */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004260 if (evutil_timerisset(&http->timeout))
4261 evhttp_connection_set_timeout_tv(evcon, &http->timeout);
Christopher Wileye8679812015-07-01 13:36:18 -07004262
4263 /*
4264 * if we want to accept more than one request on a connection,
4265 * we need to know which http server it belongs to.
4266 */
4267 evcon->http_server = http;
4268 TAILQ_INSERT_TAIL(&http->connections, evcon, next);
4269
4270 if (evhttp_associate_new_request_with_connection(evcon) == -1)
4271 evhttp_connection_free(evcon);
4272}
4273
4274
4275/*
4276 * Network helper functions that we do not want to export to the rest of
4277 * the world.
4278 */
4279
4280static void
4281name_from_addr(struct sockaddr *sa, ev_socklen_t salen,
4282 char **phost, char **pport)
4283{
4284 char ntop[NI_MAXHOST];
4285 char strport[NI_MAXSERV];
4286 int ni_result;
4287
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004288#ifdef EVENT__HAVE_GETNAMEINFO
Christopher Wileye8679812015-07-01 13:36:18 -07004289 ni_result = getnameinfo(sa, salen,
4290 ntop, sizeof(ntop), strport, sizeof(strport),
4291 NI_NUMERICHOST|NI_NUMERICSERV);
4292
4293 if (ni_result != 0) {
4294#ifdef EAI_SYSTEM
4295 /* Windows doesn't have an EAI_SYSTEM. */
4296 if (ni_result == EAI_SYSTEM)
4297 event_err(1, "getnameinfo failed");
4298 else
4299#endif
4300 event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
4301 return;
4302 }
4303#else
4304 ni_result = fake_getnameinfo(sa, salen,
4305 ntop, sizeof(ntop), strport, sizeof(strport),
4306 NI_NUMERICHOST|NI_NUMERICSERV);
4307 if (ni_result != 0)
4308 return;
4309#endif
4310
4311 *phost = mm_strdup(ntop);
4312 *pport = mm_strdup(strport);
4313}
4314
4315/* Create a non-blocking socket and bind it */
4316/* todo: rename this function */
4317static evutil_socket_t
4318bind_socket_ai(struct evutil_addrinfo *ai, int reuse)
4319{
4320 evutil_socket_t fd;
4321
4322 int on = 1, r;
4323 int serrno;
4324
4325 /* Create listen socket */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004326 fd = evutil_socket_(ai ? ai->ai_family : AF_INET,
4327 SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
Christopher Wileye8679812015-07-01 13:36:18 -07004328 if (fd == -1) {
4329 event_sock_warn(-1, "socket");
4330 return (-1);
4331 }
4332
Christopher Wileye8679812015-07-01 13:36:18 -07004333 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0)
4334 goto out;
4335 if (reuse) {
4336 if (evutil_make_listen_socket_reuseable(fd) < 0)
4337 goto out;
4338 }
4339
4340 if (ai != NULL) {
4341 r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen);
4342 if (r == -1)
4343 goto out;
4344 }
4345
4346 return (fd);
4347
4348 out:
4349 serrno = EVUTIL_SOCKET_ERROR();
4350 evutil_closesocket(fd);
4351 EVUTIL_SET_SOCKET_ERROR(serrno);
4352 return (-1);
4353}
4354
4355static struct evutil_addrinfo *
4356make_addrinfo(const char *address, ev_uint16_t port)
4357{
4358 struct evutil_addrinfo *ai = NULL;
4359
4360 struct evutil_addrinfo hints;
4361 char strport[NI_MAXSERV];
4362 int ai_result;
4363
4364 memset(&hints, 0, sizeof(hints));
4365 hints.ai_family = AF_UNSPEC;
4366 hints.ai_socktype = SOCK_STREAM;
4367 /* turn NULL hostname into INADDR_ANY, and skip looking up any address
4368 * types we don't have an interface to connect to. */
4369 hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG;
4370 evutil_snprintf(strport, sizeof(strport), "%d", port);
4371 if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai))
4372 != 0) {
4373 if (ai_result == EVUTIL_EAI_SYSTEM)
4374 event_warn("getaddrinfo");
4375 else
4376 event_warnx("getaddrinfo: %s",
4377 evutil_gai_strerror(ai_result));
4378 return (NULL);
4379 }
4380
4381 return (ai);
4382}
4383
4384static evutil_socket_t
4385bind_socket(const char *address, ev_uint16_t port, int reuse)
4386{
4387 evutil_socket_t fd;
4388 struct evutil_addrinfo *aitop = NULL;
4389
4390 /* just create an unbound socket */
4391 if (address == NULL && port == 0)
4392 return bind_socket_ai(NULL, 0);
4393
4394 aitop = make_addrinfo(address, port);
4395
4396 if (aitop == NULL)
4397 return (-1);
4398
4399 fd = bind_socket_ai(aitop, reuse);
4400
4401 evutil_freeaddrinfo(aitop);
4402
4403 return (fd);
4404}
4405
4406struct evhttp_uri {
4407 unsigned flags;
4408 char *scheme; /* scheme; e.g http, ftp etc */
4409 char *userinfo; /* userinfo (typically username:pass), or NULL */
4410 char *host; /* hostname, IP address, or NULL */
4411 int port; /* port, or zero */
4412 char *path; /* path, or "". */
4413 char *query; /* query, or NULL */
4414 char *fragment; /* fragment or NULL */
4415};
4416
4417struct evhttp_uri *
4418evhttp_uri_new(void)
4419{
4420 struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1);
4421 if (uri)
4422 uri->port = -1;
4423 return uri;
4424}
4425
4426void
4427evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags)
4428{
4429 uri->flags = flags;
4430}
4431
4432/* Return true if the string starting at s and ending immediately before eos
4433 * is a valid URI scheme according to RFC3986
4434 */
4435static int
4436scheme_ok(const char *s, const char *eos)
4437{
4438 /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
4439 EVUTIL_ASSERT(eos >= s);
4440 if (s == eos)
4441 return 0;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004442 if (!EVUTIL_ISALPHA_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004443 return 0;
4444 while (++s < eos) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004445 if (! EVUTIL_ISALNUM_(*s) &&
Christopher Wileye8679812015-07-01 13:36:18 -07004446 *s != '+' && *s != '-' && *s != '.')
4447 return 0;
4448 }
4449 return 1;
4450}
4451
4452#define SUBDELIMS "!$&'()*+,;="
4453
4454/* Return true iff [s..eos) is a valid userinfo */
4455static int
4456userinfo_ok(const char *s, const char *eos)
4457{
4458 while (s < eos) {
4459 if (CHAR_IS_UNRESERVED(*s) ||
4460 strchr(SUBDELIMS, *s) ||
4461 *s == ':')
4462 ++s;
4463 else if (*s == '%' && s+2 < eos &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004464 EVUTIL_ISXDIGIT_(s[1]) &&
4465 EVUTIL_ISXDIGIT_(s[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004466 s += 3;
4467 else
4468 return 0;
4469 }
4470 return 1;
4471}
4472
4473static int
4474regname_ok(const char *s, const char *eos)
4475{
4476 while (s && s<eos) {
4477 if (CHAR_IS_UNRESERVED(*s) ||
4478 strchr(SUBDELIMS, *s))
4479 ++s;
4480 else if (*s == '%' &&
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004481 EVUTIL_ISXDIGIT_(s[1]) &&
4482 EVUTIL_ISXDIGIT_(s[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004483 s += 3;
4484 else
4485 return 0;
4486 }
4487 return 1;
4488}
4489
4490static int
4491parse_port(const char *s, const char *eos)
4492{
4493 int portnum = 0;
4494 while (s < eos) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004495 if (! EVUTIL_ISDIGIT_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004496 return -1;
4497 portnum = (portnum * 10) + (*s - '0');
4498 if (portnum < 0)
4499 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004500 if (portnum > 65535)
4501 return -1;
Christopher Wileye8679812015-07-01 13:36:18 -07004502 ++s;
4503 }
4504 return portnum;
4505}
4506
4507/* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */
4508static int
4509bracket_addr_ok(const char *s, const char *eos)
4510{
4511 if (s + 3 > eos || *s != '[' || *(eos-1) != ']')
4512 return 0;
4513 if (s[1] == 'v') {
4514 /* IPvFuture, or junk.
4515 "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
4516 */
4517 s += 2; /* skip [v */
4518 --eos;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004519 if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/
Christopher Wileye8679812015-07-01 13:36:18 -07004520 return 0;
4521 while (s < eos && *s != '.') {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004522 if (EVUTIL_ISXDIGIT_(*s))
Christopher Wileye8679812015-07-01 13:36:18 -07004523 ++s;
4524 else
4525 return 0;
4526 }
4527 if (*s != '.')
4528 return 0;
4529 ++s;
4530 while (s < eos) {
4531 if (CHAR_IS_UNRESERVED(*s) ||
4532 strchr(SUBDELIMS, *s) ||
4533 *s == ':')
4534 ++s;
4535 else
4536 return 0;
4537 }
4538 return 2;
4539 } else {
4540 /* IPv6, or junk */
4541 char buf[64];
4542 ev_ssize_t n_chars = eos-s-2;
4543 struct in6_addr in6;
4544 if (n_chars >= 64) /* way too long */
4545 return 0;
4546 memcpy(buf, s+1, n_chars);
4547 buf[n_chars]='\0';
4548 return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0;
4549 }
4550}
4551
4552static int
4553parse_authority(struct evhttp_uri *uri, char *s, char *eos)
4554{
4555 char *cp, *port;
4556 EVUTIL_ASSERT(eos);
4557 if (eos == s) {
4558 uri->host = mm_strdup("");
4559 if (uri->host == NULL) {
4560 event_warn("%s: strdup", __func__);
4561 return -1;
4562 }
4563 return 0;
4564 }
4565
4566 /* Optionally, we start with "userinfo@" */
4567
4568 cp = strchr(s, '@');
4569 if (cp && cp < eos) {
4570 if (! userinfo_ok(s,cp))
4571 return -1;
4572 *cp++ = '\0';
4573 uri->userinfo = mm_strdup(s);
4574 if (uri->userinfo == NULL) {
4575 event_warn("%s: strdup", __func__);
4576 return -1;
4577 }
4578 } else {
4579 cp = s;
4580 }
4581 /* Optionally, we end with ":port" */
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004582 for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port)
Christopher Wileye8679812015-07-01 13:36:18 -07004583 ;
4584 if (port >= cp && *port == ':') {
4585 if (port+1 == eos) /* Leave port unspecified; the RFC allows a
4586 * nil port */
4587 uri->port = -1;
4588 else if ((uri->port = parse_port(port+1, eos))<0)
4589 return -1;
4590 eos = port;
4591 }
4592 /* Now, cp..eos holds the "host" port, which can be an IPv4Address,
4593 * an IP-Literal, or a reg-name */
4594 EVUTIL_ASSERT(eos >= cp);
4595 if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') {
4596 /* IPv6address, IP-Literal, or junk. */
4597 if (! bracket_addr_ok(cp, eos))
4598 return -1;
4599 } else {
4600 /* Make sure the host part is ok. */
4601 if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */
4602 return -1;
4603 }
4604 uri->host = mm_malloc(eos-cp+1);
4605 if (uri->host == NULL) {
4606 event_warn("%s: malloc", __func__);
4607 return -1;
4608 }
4609 memcpy(uri->host, cp, eos-cp);
4610 uri->host[eos-cp] = '\0';
4611 return 0;
4612
4613}
4614
4615static char *
4616end_of_authority(char *cp)
4617{
4618 while (*cp) {
4619 if (*cp == '?' || *cp == '#' || *cp == '/')
4620 return cp;
4621 ++cp;
4622 }
4623 return cp;
4624}
4625
4626enum uri_part {
4627 PART_PATH,
4628 PART_QUERY,
4629 PART_FRAGMENT
4630};
4631
4632/* Return the character after the longest prefix of 'cp' that matches...
4633 * *pchar / "/" if allow_qchars is false, or
4634 * *(pchar / "/" / "?") if allow_qchars is true.
4635 */
4636static char *
4637end_of_path(char *cp, enum uri_part part, unsigned flags)
4638{
4639 if (flags & EVHTTP_URI_NONCONFORMANT) {
4640 /* If NONCONFORMANT:
4641 * Path is everything up to a # or ? or nul.
4642 * Query is everything up a # or nul
4643 * Fragment is everything up to a nul.
4644 */
4645 switch (part) {
4646 case PART_PATH:
4647 while (*cp && *cp != '#' && *cp != '?')
4648 ++cp;
4649 break;
4650 case PART_QUERY:
4651 while (*cp && *cp != '#')
4652 ++cp;
4653 break;
4654 case PART_FRAGMENT:
4655 cp += strlen(cp);
4656 break;
4657 };
4658 return cp;
4659 }
4660
4661 while (*cp) {
4662 if (CHAR_IS_UNRESERVED(*cp) ||
4663 strchr(SUBDELIMS, *cp) ||
4664 *cp == ':' || *cp == '@' || *cp == '/')
4665 ++cp;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004666 else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) &&
4667 EVUTIL_ISXDIGIT_(cp[2]))
Christopher Wileye8679812015-07-01 13:36:18 -07004668 cp += 3;
4669 else if (*cp == '?' && part != PART_PATH)
4670 ++cp;
4671 else
4672 return cp;
4673 }
4674 return cp;
4675}
4676
4677static int
4678path_matches_noscheme(const char *cp)
4679{
4680 while (*cp) {
4681 if (*cp == ':')
4682 return 0;
4683 else if (*cp == '/')
4684 return 1;
4685 ++cp;
4686 }
4687 return 1;
4688}
4689
4690struct evhttp_uri *
4691evhttp_uri_parse(const char *source_uri)
4692{
4693 return evhttp_uri_parse_with_flags(source_uri, 0);
4694}
4695
4696struct evhttp_uri *
4697evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags)
4698{
4699 char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL;
4700 char *path = NULL, *fragment = NULL;
4701 int got_authority = 0;
4702
4703 struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
4704 if (uri == NULL) {
4705 event_warn("%s: calloc", __func__);
4706 goto err;
4707 }
4708 uri->port = -1;
4709 uri->flags = flags;
4710
4711 readbuf = mm_strdup(source_uri);
4712 if (readbuf == NULL) {
4713 event_warn("%s: strdup", __func__);
4714 goto err;
4715 }
4716
4717 readp = readbuf;
4718 token = NULL;
4719
4720 /* We try to follow RFC3986 here as much as we can, and match
4721 the productions
4722
4723 URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
4724
4725 relative-ref = relative-part [ "?" query ] [ "#" fragment ]
4726 */
4727
4728 /* 1. scheme: */
4729 token = strchr(readp, ':');
4730 if (token && scheme_ok(readp,token)) {
4731 *token = '\0';
4732 uri->scheme = mm_strdup(readp);
4733 if (uri->scheme == NULL) {
4734 event_warn("%s: strdup", __func__);
4735 goto err;
4736 }
4737 readp = token+1; /* eat : */
4738 }
4739
4740 /* 2. Optionally, "//" then an 'authority' part. */
4741 if (readp[0]=='/' && readp[1] == '/') {
4742 char *authority;
4743 readp += 2;
4744 authority = readp;
4745 path = end_of_authority(readp);
4746 if (parse_authority(uri, authority, path) < 0)
4747 goto err;
4748 readp = path;
4749 got_authority = 1;
4750 }
4751
4752 /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty
4753 */
4754 path = readp;
4755 readp = end_of_path(path, PART_PATH, flags);
4756
4757 /* Query */
4758 if (*readp == '?') {
4759 *readp = '\0';
4760 ++readp;
4761 query = readp;
4762 readp = end_of_path(readp, PART_QUERY, flags);
4763 }
4764 /* fragment */
4765 if (*readp == '#') {
4766 *readp = '\0';
4767 ++readp;
4768 fragment = readp;
4769 readp = end_of_path(readp, PART_FRAGMENT, flags);
4770 }
4771 if (*readp != '\0') {
4772 goto err;
4773 }
4774
4775 /* These next two cases may be unreachable; I'm leaving them
4776 * in to be defensive. */
4777 /* If you didn't get an authority, the path can't begin with "//" */
4778 if (!got_authority && path[0]=='/' && path[1]=='/')
4779 goto err;
4780 /* If you did get an authority, the path must begin with "/" or be
4781 * empty. */
4782 if (got_authority && path[0] != '/' && path[0] != '\0')
4783 goto err;
4784 /* (End of maybe-unreachable cases) */
4785
4786 /* If there was no scheme, the first part of the path (if any) must
4787 * have no colon in it. */
4788 if (! uri->scheme && !path_matches_noscheme(path))
4789 goto err;
4790
4791 EVUTIL_ASSERT(path);
4792 uri->path = mm_strdup(path);
4793 if (uri->path == NULL) {
4794 event_warn("%s: strdup", __func__);
4795 goto err;
4796 }
4797
4798 if (query) {
4799 uri->query = mm_strdup(query);
4800 if (uri->query == NULL) {
4801 event_warn("%s: strdup", __func__);
4802 goto err;
4803 }
4804 }
4805 if (fragment) {
4806 uri->fragment = mm_strdup(fragment);
4807 if (uri->fragment == NULL) {
4808 event_warn("%s: strdup", __func__);
4809 goto err;
4810 }
4811 }
4812
4813 mm_free(readbuf);
4814
4815 return uri;
4816err:
4817 if (uri)
4818 evhttp_uri_free(uri);
4819 if (readbuf)
4820 mm_free(readbuf);
4821 return NULL;
4822}
4823
4824void
4825evhttp_uri_free(struct evhttp_uri *uri)
4826{
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004827#define URI_FREE_STR_(f) \
Christopher Wileye8679812015-07-01 13:36:18 -07004828 if (uri->f) { \
4829 mm_free(uri->f); \
4830 }
4831
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004832 URI_FREE_STR_(scheme);
4833 URI_FREE_STR_(userinfo);
4834 URI_FREE_STR_(host);
4835 URI_FREE_STR_(path);
4836 URI_FREE_STR_(query);
4837 URI_FREE_STR_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07004838
4839 mm_free(uri);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004840#undef URI_FREE_STR_
Christopher Wileye8679812015-07-01 13:36:18 -07004841}
4842
4843char *
4844evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
4845{
4846 struct evbuffer *tmp = 0;
4847 size_t joined_size = 0;
4848 char *output = NULL;
4849
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004850#define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f))
Christopher Wileye8679812015-07-01 13:36:18 -07004851
4852 if (!uri || !buf || !limit)
4853 return NULL;
4854
4855 tmp = evbuffer_new();
4856 if (!tmp)
4857 return NULL;
4858
4859 if (uri->scheme) {
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004860 URI_ADD_(scheme);
Christopher Wileye8679812015-07-01 13:36:18 -07004861 evbuffer_add(tmp, ":", 1);
4862 }
4863 if (uri->host) {
4864 evbuffer_add(tmp, "//", 2);
4865 if (uri->userinfo)
4866 evbuffer_add_printf(tmp,"%s@", uri->userinfo);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004867 URI_ADD_(host);
Christopher Wileye8679812015-07-01 13:36:18 -07004868 if (uri->port >= 0)
4869 evbuffer_add_printf(tmp,":%d", uri->port);
4870
4871 if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0')
4872 goto err;
4873 }
4874
4875 if (uri->path)
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004876 URI_ADD_(path);
Christopher Wileye8679812015-07-01 13:36:18 -07004877
4878 if (uri->query) {
4879 evbuffer_add(tmp, "?", 1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004880 URI_ADD_(query);
Christopher Wileye8679812015-07-01 13:36:18 -07004881 }
4882
4883 if (uri->fragment) {
4884 evbuffer_add(tmp, "#", 1);
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004885 URI_ADD_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07004886 }
4887
4888 evbuffer_add(tmp, "\0", 1); /* NUL */
4889
4890 joined_size = evbuffer_get_length(tmp);
4891
4892 if (joined_size > limit) {
4893 /* It doesn't fit. */
4894 evbuffer_free(tmp);
4895 return NULL;
4896 }
4897 evbuffer_remove(tmp, buf, joined_size);
4898
4899 output = buf;
4900err:
4901 evbuffer_free(tmp);
4902
4903 return output;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004904#undef URI_ADD_
Christopher Wileye8679812015-07-01 13:36:18 -07004905}
4906
4907const char *
4908evhttp_uri_get_scheme(const struct evhttp_uri *uri)
4909{
4910 return uri->scheme;
4911}
4912const char *
4913evhttp_uri_get_userinfo(const struct evhttp_uri *uri)
4914{
4915 return uri->userinfo;
4916}
4917const char *
4918evhttp_uri_get_host(const struct evhttp_uri *uri)
4919{
4920 return uri->host;
4921}
4922int
4923evhttp_uri_get_port(const struct evhttp_uri *uri)
4924{
4925 return uri->port;
4926}
4927const char *
4928evhttp_uri_get_path(const struct evhttp_uri *uri)
4929{
4930 return uri->path;
4931}
4932const char *
4933evhttp_uri_get_query(const struct evhttp_uri *uri)
4934{
4935 return uri->query;
4936}
4937const char *
4938evhttp_uri_get_fragment(const struct evhttp_uri *uri)
4939{
4940 return uri->fragment;
4941}
4942
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004943#define URI_SET_STR_(f) do { \
Christopher Wileye8679812015-07-01 13:36:18 -07004944 if (uri->f) \
4945 mm_free(uri->f); \
4946 if (f) { \
4947 if ((uri->f = mm_strdup(f)) == NULL) { \
4948 event_warn("%s: strdup()", __func__); \
4949 return -1; \
4950 } \
4951 } else { \
4952 uri->f = NULL; \
4953 } \
4954 } while(0)
4955
4956int
4957evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme)
4958{
4959 if (scheme && !scheme_ok(scheme, scheme+strlen(scheme)))
4960 return -1;
4961
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004962 URI_SET_STR_(scheme);
Christopher Wileye8679812015-07-01 13:36:18 -07004963 return 0;
4964}
4965int
4966evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo)
4967{
4968 if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo)))
4969 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004970 URI_SET_STR_(userinfo);
Christopher Wileye8679812015-07-01 13:36:18 -07004971 return 0;
4972}
4973int
4974evhttp_uri_set_host(struct evhttp_uri *uri, const char *host)
4975{
4976 if (host) {
4977 if (host[0] == '[') {
4978 if (! bracket_addr_ok(host, host+strlen(host)))
4979 return -1;
4980 } else {
4981 if (! regname_ok(host, host+strlen(host)))
4982 return -1;
4983 }
4984 }
4985
Narayan Kamathfc74cb42017-09-13 12:53:52 +01004986 URI_SET_STR_(host);
Christopher Wileye8679812015-07-01 13:36:18 -07004987 return 0;
4988}
4989int
4990evhttp_uri_set_port(struct evhttp_uri *uri, int port)
4991{
4992 if (port < -1)
4993 return -1;
4994 uri->port = port;
4995 return 0;
4996}
4997#define end_of_cpath(cp,p,f) \
4998 ((const char*)(end_of_path(((char*)(cp)), (p), (f))))
4999
5000int
5001evhttp_uri_set_path(struct evhttp_uri *uri, const char *path)
5002{
5003 if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path))
5004 return -1;
5005
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005006 URI_SET_STR_(path);
Christopher Wileye8679812015-07-01 13:36:18 -07005007 return 0;
5008}
5009int
5010evhttp_uri_set_query(struct evhttp_uri *uri, const char *query)
5011{
5012 if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query))
5013 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005014 URI_SET_STR_(query);
Christopher Wileye8679812015-07-01 13:36:18 -07005015 return 0;
5016}
5017int
5018evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment)
5019{
5020 if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment))
5021 return -1;
Narayan Kamathfc74cb42017-09-13 12:53:52 +01005022 URI_SET_STR_(fragment);
Christopher Wileye8679812015-07-01 13:36:18 -07005023 return 0;
5024}