1a3bb4a03SNiels Provos /*
2b85b710cSNick Mathewson * Copyright (c) 2002-2007 Niels Provos <[email protected]>
3e49e2891SNick Mathewson * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
4a3bb4a03SNiels Provos *
538b33048SNiels Provos * Redistribution and use in source and binary forms, with or without
638b33048SNiels Provos * modification, are permitted provided that the following conditions
738b33048SNiels Provos * are met:
838b33048SNiels Provos * 1. Redistributions of source code must retain the above copyright
938b33048SNiels Provos * notice, this list of conditions and the following disclaimer.
1038b33048SNiels Provos * 2. Redistributions in binary form must reproduce the above copyright
1138b33048SNiels Provos * notice, this list of conditions and the following disclaimer in the
1238b33048SNiels Provos * documentation and/or other materials provided with the distribution.
1338b33048SNiels Provos * 3. The name of the author may not be used to endorse or promote products
1438b33048SNiels Provos * derived from this software without specific prior written permission.
1538b33048SNiels Provos *
1638b33048SNiels Provos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1738b33048SNiels Provos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1838b33048SNiels Provos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1938b33048SNiels Provos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2038b33048SNiels Provos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2138b33048SNiels Provos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2238b33048SNiels Provos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2338b33048SNiels Provos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2438b33048SNiels Provos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2538b33048SNiels Provos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26a3bb4a03SNiels Provos */
27a3bb4a03SNiels Provos
28ec347b92SNick Mathewson #include "event2/event-config.h"
290915ca0aSKevin Bowling #include "evconfig-private.h"
30784b8773SNick Mathewson
3168120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_PARAM_H
324e1ec3e0SNick Mathewson #include <sys/param.h>
334e1ec3e0SNick Mathewson #endif
3468120d9bSNick Mathewson #ifdef EVENT__HAVE_SYS_TYPES_H
354e1ec3e0SNick Mathewson #include <sys/types.h>
364e1ec3e0SNick Mathewson #endif
374e1ec3e0SNick Mathewson
38a3bb4a03SNiels Provos #ifdef HAVE_SYS_IOCCOM_H
39a3bb4a03SNiels Provos #include <sys/ioccom.h>
40a3bb4a03SNiels Provos #endif
41c1404b56SEd Schouten #ifdef EVENT__HAVE_SYS_RESOURCE_H
42c1404b56SEd Schouten #include <sys/resource.h>
43c1404b56SEd Schouten #endif
44c1404b56SEd Schouten #ifdef EVENT__HAVE_SYS_TIME_H
45c1404b56SEd Schouten #include <sys/time.h>
46c1404b56SEd Schouten #endif
47c1404b56SEd Schouten #ifdef EVENT__HAVE_SYS_WAIT_H
48c1404b56SEd Schouten #include <sys/wait.h>
49c1404b56SEd Schouten #endif
50868f10e7SNiels Provos
519f560bfaSNick Mathewson #ifndef _WIN32
52a3bb4a03SNiels Provos #include <sys/socket.h>
53a3bb4a03SNiels Provos #include <sys/stat.h>
547c4da937SAzat Khuzhin #else /* _WIN32 */
5513e4f3bdSBrodie Thiesfield #include <winsock2.h>
5686f57420SNick Mathewson #include <ws2tcpip.h>
577c4da937SAzat Khuzhin #endif /* _WIN32 */
587c4da937SAzat Khuzhin
597c4da937SAzat Khuzhin #ifdef EVENT__HAVE_SYS_UN_H
607c4da937SAzat Khuzhin #include <sys/un.h>
617c4da937SAzat Khuzhin #endif
627c4da937SAzat Khuzhin #ifdef EVENT__HAVE_AFUNIX_H
637c4da937SAzat Khuzhin #include <afunix.h>
64868f10e7SNiels Provos #endif
65868f10e7SNiels Provos
66a3bb4a03SNiels Provos #include <sys/queue.h>
67a3bb4a03SNiels Provos
6868120d9bSNick Mathewson #ifdef EVENT__HAVE_NETINET_IN_H
69a3bb4a03SNiels Provos #include <netinet/in.h>
700b9eb1bfSNick Mathewson #endif
7168120d9bSNick Mathewson #ifdef EVENT__HAVE_ARPA_INET_H
7210c834c4SHarlan Stenn #include <arpa/inet.h>
7310c834c4SHarlan Stenn #endif
7468120d9bSNick Mathewson #ifdef EVENT__HAVE_NETDB_H
75a3bb4a03SNiels Provos #include <netdb.h>
76868f10e7SNiels Provos #endif
77a3bb4a03SNiels Provos
789f560bfaSNick Mathewson #ifdef _WIN32
794e1ec3e0SNick Mathewson #include <winsock2.h>
804e1ec3e0SNick Mathewson #endif
814e1ec3e0SNick Mathewson
82a3bb4a03SNiels Provos #include <errno.h>
83a3bb4a03SNiels Provos #include <stdio.h>
84a3bb4a03SNiels Provos #include <stdlib.h>
85a3bb4a03SNiels Provos #include <string.h>
869f560bfaSNick Mathewson #ifndef _WIN32
87a3bb4a03SNiels Provos #include <syslog.h>
887c4da937SAzat Khuzhin #endif /* !_WIN32 */
89a3bb4a03SNiels Provos #include <signal.h>
9068120d9bSNick Mathewson #ifdef EVENT__HAVE_UNISTD_H
91a3bb4a03SNiels Provos #include <unistd.h>
924e1ec3e0SNick Mathewson #endif
9368120d9bSNick Mathewson #ifdef EVENT__HAVE_FCNTL_H
94a3bb4a03SNiels Provos #include <fcntl.h>
954e1ec3e0SNick Mathewson #endif
96a3bb4a03SNiels Provos
97a3bb4a03SNiels Provos #undef timeout_pending
98a3bb4a03SNiels Provos #undef timeout_initialized
99a3bb4a03SNiels Provos
1000db257b8SNiels Provos #include "strlcpy-internal.h"
101de1c4392SNiels Provos #include "event2/http.h"
1027defe4cbSNick Mathewson #include "event2/event.h"
1037defe4cbSNick Mathewson #include "event2/buffer.h"
1047defe4cbSNick Mathewson #include "event2/bufferevent.h"
105de1c4392SNiels Provos #include "event2/http_struct.h"
106f37d1685SNick Mathewson #include "event2/http_compat.h"
1077defe4cbSNick Mathewson #include "event2/util.h"
108ec34533aSNick Mathewson #include "event2/listener.h"
109169321c9SNick Mathewson #include "log-internal.h"
1107dd362b1SNick Mathewson #include "util-internal.h"
111147b71e3SNiels Provos #include "http-internal.h"
1127eb250e9SNick Mathewson #include "mm-internal.h"
113c8baac90SNick Mathewson #include "bufferevent-internal.h"
114a3bb4a03SNiels Provos
11568120d9bSNick Mathewson #ifndef EVENT__HAVE_GETNAMEINFO
11630abfd99SNiels Provos #define NI_MAXSERV 32
11730abfd99SNiels Provos #define NI_MAXHOST 1025
11830abfd99SNiels Provos
11986f57420SNick Mathewson #ifndef NI_NUMERICHOST
12030abfd99SNiels Provos #define NI_NUMERICHOST 1
12186f57420SNick Mathewson #endif
12286f57420SNick Mathewson
12386f57420SNick Mathewson #ifndef NI_NUMERICSERV
12430abfd99SNiels Provos #define NI_NUMERICSERV 2
12586f57420SNick Mathewson #endif
12630abfd99SNiels Provos
1279935d5b0SNick Mathewson static int
fake_getnameinfo(const struct sockaddr * sa,size_t salen,char * host,size_t hostlen,char * serv,size_t servlen,int flags)12830abfd99SNiels Provos fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
12930abfd99SNiels Provos size_t hostlen, char *serv, size_t servlen, int flags)
13030abfd99SNiels Provos {
13130abfd99SNiels Provos struct sockaddr_in *sin = (struct sockaddr_in *)sa;
13230abfd99SNiels Provos
13330abfd99SNiels Provos if (serv != NULL) {
13430abfd99SNiels Provos char tmpserv[16];
13530abfd99SNiels Provos evutil_snprintf(tmpserv, sizeof(tmpserv),
13630abfd99SNiels Provos "%d", ntohs(sin->sin_port));
13730abfd99SNiels Provos if (strlcpy(serv, tmpserv, servlen) >= servlen)
13830abfd99SNiels Provos return (-1);
13930abfd99SNiels Provos }
14030abfd99SNiels Provos
14130abfd99SNiels Provos if (host != NULL) {
14230abfd99SNiels Provos if (flags & NI_NUMERICHOST) {
14330abfd99SNiels Provos if (strlcpy(host, inet_ntoa(sin->sin_addr),
14430abfd99SNiels Provos hostlen) >= hostlen)
14530abfd99SNiels Provos return (-1);
14630abfd99SNiels Provos else
14730abfd99SNiels Provos return (0);
14830abfd99SNiels Provos } else {
14930abfd99SNiels Provos struct hostent *hp;
15030abfd99SNiels Provos hp = gethostbyaddr((char *)&sin->sin_addr,
15130abfd99SNiels Provos sizeof(struct in_addr), AF_INET);
15230abfd99SNiels Provos if (hp == NULL)
15330abfd99SNiels Provos return (-2);
15430abfd99SNiels Provos
15530abfd99SNiels Provos if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
15630abfd99SNiels Provos return (-1);
15730abfd99SNiels Provos else
15830abfd99SNiels Provos return (0);
15930abfd99SNiels Provos }
16030abfd99SNiels Provos }
16130abfd99SNiels Provos return (0);
16230abfd99SNiels Provos }
16330abfd99SNiels Provos
16430abfd99SNiels Provos #endif
16530abfd99SNiels Provos
166647e094cSNick Mathewson #define REQ_VERSION_BEFORE(req, major_v, minor_v) \
167647e094cSNick Mathewson ((req)->major < (major_v) || \
168647e094cSNick Mathewson ((req)->major == (major_v) && (req)->minor < (minor_v)))
169647e094cSNick Mathewson
170647e094cSNick Mathewson #define REQ_VERSION_ATLEAST(req, major_v, minor_v) \
171647e094cSNick Mathewson ((req)->major > (major_v) || \
172647e094cSNick Mathewson ((req)->major == (major_v) && (req)->minor >= (minor_v)))
173647e094cSNick Mathewson
174bfb9f44fSNiels Provos #ifndef MIN
175bfb9f44fSNiels Provos #define MIN(a,b) (((a)<(b))?(a):(b))
176bfb9f44fSNiels Provos #endif
177bfb9f44fSNiels Provos
178a3bb4a03SNiels Provos extern int debug;
179a3bb4a03SNiels Provos
180c169bdcbSyuangongji static evutil_socket_t create_bind_socket_nonblock(struct evutil_addrinfo *, int reuse);
1814c56ba1cSNiels Provos static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse);
1827c20a6aeSNick Mathewson static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **);
1837d1ffe64SGreg Hazel static struct evhttp_uri *evhttp_uri_parse_authority(char *source_uri);
18436212f9dSNiels Provos static int evhttp_associate_new_request_with_connection(
18536212f9dSNiels Provos struct evhttp_connection *evcon);
186942656bbSNiels Provos static void evhttp_connection_start_detectclose(
187942656bbSNiels Provos struct evhttp_connection *evcon);
188942656bbSNiels Provos static void evhttp_connection_stop_detectclose(
189942656bbSNiels Provos struct evhttp_connection *evcon);
190942656bbSNiels Provos static void evhttp_request_dispatch(struct evhttp_connection* evcon);
1919998c0cbSNiels Provos static void evhttp_read_firstline(struct evhttp_connection *evcon,
1929998c0cbSNiels Provos struct evhttp_request *req);
1939998c0cbSNiels Provos static void evhttp_read_header(struct evhttp_connection *evcon,
1949998c0cbSNiels Provos struct evhttp_request *req);
195ce146eb1SNiels Provos static int evhttp_add_header_internal(struct evkeyvalq *headers,
196ce146eb1SNiels Provos const char *key, const char *value);
19706bd0563SFelix Nawothnig static const char *evhttp_response_phrase_internal(int code);
19890b3ed5bSNick Mathewson static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t);
19990b3ed5bSNick Mathewson static void evhttp_write_buffer(struct evhttp_connection *,
20090b3ed5bSNick Mathewson void (*)(struct evhttp_connection *, void *), void *);
20190b3ed5bSNick Mathewson static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
202a3bb4a03SNiels Provos
203e44ef375SNiels Provos /* callbacks for bufferevent */
204e44ef375SNiels Provos static void evhttp_read_cb(struct bufferevent *, void *);
205e44ef375SNiels Provos static void evhttp_write_cb(struct bufferevent *, void *);
206e44ef375SNiels Provos static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg);
207aab8c38bSChristopher Davis static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
208aab8c38bSChristopher Davis const char *hostname);
209a3bb4a03SNiels Provos
21068120d9bSNick Mathewson #ifndef EVENT__HAVE_STRSEP
211bc7b7c24SNick Mathewson /* strsep replacement for platforms that lack it. Only works if
212bc7b7c24SNick Mathewson * del is one character long. */
213868f10e7SNiels Provos static char *
strsep(char ** s,const char * del)214868f10e7SNiels Provos strsep(char **s, const char *del)
215868f10e7SNiels Provos {
216868f10e7SNiels Provos char *d, *tok;
2172e36dbe1SNick Mathewson EVUTIL_ASSERT(strlen(del) == 1);
218868f10e7SNiels Provos if (!s || !*s)
219868f10e7SNiels Provos return NULL;
220868f10e7SNiels Provos tok = *s;
221868f10e7SNiels Provos d = strstr(tok, del);
222bc7b7c24SNick Mathewson if (d) {
223bc7b7c24SNick Mathewson *d = '\0';
224bc7b7c24SNick Mathewson *s = d + 1;
225bc7b7c24SNick Mathewson } else
226868f10e7SNiels Provos *s = NULL;
227868f10e7SNiels Provos return tok;
228868f10e7SNiels Provos }
229868f10e7SNiels Provos #endif
230868f10e7SNiels Provos
23106c51cdfSMansour Moufid static size_t
html_replace(const char ch,const char ** escaped)23206c51cdfSMansour Moufid html_replace(const char ch, const char **escaped)
233a3bb4a03SNiels Provos {
234a3bb4a03SNiels Provos switch (ch) {
235a3bb4a03SNiels Provos case '<':
23606c51cdfSMansour Moufid *escaped = "<";
23706c51cdfSMansour Moufid return 4;
238a3bb4a03SNiels Provos case '>':
23906c51cdfSMansour Moufid *escaped = ">";
24006c51cdfSMansour Moufid return 4;
241a3bb4a03SNiels Provos case '"':
24206c51cdfSMansour Moufid *escaped = """;
24306c51cdfSMansour Moufid return 6;
244a3bb4a03SNiels Provos case '\'':
24506c51cdfSMansour Moufid *escaped = "'";
24606c51cdfSMansour Moufid return 6;
247a3bb4a03SNiels Provos case '&':
24806c51cdfSMansour Moufid *escaped = "&";
24906c51cdfSMansour Moufid return 5;
250a3bb4a03SNiels Provos default:
251a3bb4a03SNiels Provos break;
252a3bb4a03SNiels Provos }
253a3bb4a03SNiels Provos
25406c51cdfSMansour Moufid return 1;
255a3bb4a03SNiels Provos }
256a3bb4a03SNiels Provos
257a3bb4a03SNiels Provos /*
258a3bb4a03SNiels Provos * Replaces <, >, ", ' and & with <, >, ",
259a3bb4a03SNiels Provos * ' and & correspondingly.
260a3bb4a03SNiels Provos *
261a3bb4a03SNiels Provos * The returned string needs to be freed by the caller.
262a3bb4a03SNiels Provos */
263a3bb4a03SNiels Provos
264a3bb4a03SNiels Provos char *
evhttp_htmlescape(const char * html)265a3bb4a03SNiels Provos evhttp_htmlescape(const char *html)
266a3bb4a03SNiels Provos {
26774a91e5aSNick Mathewson size_t i;
26806c51cdfSMansour Moufid size_t new_size = 0, old_size = 0;
269a3bb4a03SNiels Provos char *escaped_html, *p;
270a3bb4a03SNiels Provos
27106c51cdfSMansour Moufid if (html == NULL)
27206c51cdfSMansour Moufid return (NULL);
273a3bb4a03SNiels Provos
27406c51cdfSMansour Moufid old_size = strlen(html);
27506c51cdfSMansour Moufid for (i = 0; i < old_size; ++i) {
27606c51cdfSMansour Moufid const char *replaced = NULL;
27706c51cdfSMansour Moufid const size_t replace_size = html_replace(html[i], &replaced);
27806c51cdfSMansour Moufid if (replace_size > EV_SIZE_MAX - new_size) {
27906c51cdfSMansour Moufid event_warn("%s: html_replace overflow", __func__);
28006c51cdfSMansour Moufid return (NULL);
28106c51cdfSMansour Moufid }
28206c51cdfSMansour Moufid new_size += replace_size;
28306c51cdfSMansour Moufid }
28406c51cdfSMansour Moufid
28506c51cdfSMansour Moufid if (new_size == EV_SIZE_MAX)
28606c51cdfSMansour Moufid return (NULL);
28749868b61SNick Mathewson p = escaped_html = mm_malloc(new_size + 1);
288f1691539SNiels Provos if (escaped_html == NULL) {
28906c51cdfSMansour Moufid event_warn("%s: malloc(%lu)", __func__,
29006c51cdfSMansour Moufid (unsigned long)(new_size + 1));
291f1691539SNiels Provos return (NULL);
292f1691539SNiels Provos }
29306d0f8c0SNiels Provos for (i = 0; i < old_size; ++i) {
29406c51cdfSMansour Moufid const char *replaced = &html[i];
29506c51cdfSMansour Moufid const size_t len = html_replace(html[i], &replaced);
296caca2f45SNick Mathewson memcpy(p, replaced, len);
297caca2f45SNick Mathewson p += len;
298a3bb4a03SNiels Provos }
299a3bb4a03SNiels Provos
300a3bb4a03SNiels Provos *p = '\0';
301a3bb4a03SNiels Provos
302a3bb4a03SNiels Provos return (escaped_html);
303a3bb4a03SNiels Provos }
304a3bb4a03SNiels Provos
30590b3ed5bSNick Mathewson /** Given an evhttp_cmd_type, returns a constant string containing the
30690b3ed5bSNick Mathewson * equivalent HTTP command, or NULL if the evhttp_command_type is
30790b3ed5bSNick Mathewson * unrecognized. */
308a3f122d6SNick Mathewson static const char *
evhttp_method(enum evhttp_cmd_type type)309a3bb4a03SNiels Provos evhttp_method(enum evhttp_cmd_type type)
310a3bb4a03SNiels Provos {
311a3bb4a03SNiels Provos const char *method;
312a3bb4a03SNiels Provos
313a3bb4a03SNiels Provos switch (type) {
314a3bb4a03SNiels Provos case EVHTTP_REQ_GET:
315a3bb4a03SNiels Provos method = "GET";
316a3bb4a03SNiels Provos break;
317a3bb4a03SNiels Provos case EVHTTP_REQ_POST:
318a3bb4a03SNiels Provos method = "POST";
319a3bb4a03SNiels Provos break;
320a3bb4a03SNiels Provos case EVHTTP_REQ_HEAD:
321a3bb4a03SNiels Provos method = "HEAD";
322a3bb4a03SNiels Provos break;
323b14cd655SNiels Provos case EVHTTP_REQ_PUT:
324b14cd655SNiels Provos method = "PUT";
325b14cd655SNiels Provos break;
326b14cd655SNiels Provos case EVHTTP_REQ_DELETE:
327b14cd655SNiels Provos method = "DELETE";
328b14cd655SNiels Provos break;
32975a73414SFelix Nawothnig case EVHTTP_REQ_OPTIONS:
33075a73414SFelix Nawothnig method = "OPTIONS";
33175a73414SFelix Nawothnig break;
33275a73414SFelix Nawothnig case EVHTTP_REQ_TRACE:
33375a73414SFelix Nawothnig method = "TRACE";
33475a73414SFelix Nawothnig break;
33575a73414SFelix Nawothnig case EVHTTP_REQ_CONNECT:
33675a73414SFelix Nawothnig method = "CONNECT";
33775a73414SFelix Nawothnig break;
33875a73414SFelix Nawothnig case EVHTTP_REQ_PATCH:
33975a73414SFelix Nawothnig method = "PATCH";
34075a73414SFelix Nawothnig break;
341a3bb4a03SNiels Provos default:
342a3bb4a03SNiels Provos method = NULL;
343a3bb4a03SNiels Provos break;
344a3bb4a03SNiels Provos }
345a3bb4a03SNiels Provos
346a3bb4a03SNiels Provos return (method);
347a3bb4a03SNiels Provos }
348a3bb4a03SNiels Provos
349df97fca9SNiels Provos /**
350df97fca9SNiels Provos * Determines if a response should have a body.
351df97fca9SNiels Provos * Follows the rules in RFC 2616 section 4.3.
352e5bbd40aSNick Mathewson * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
353e5bbd40aSNick Mathewson * a body.
354df97fca9SNiels Provos */
355df97fca9SNiels Provos static int
evhttp_response_needs_body(struct evhttp_request * req)356df97fca9SNiels Provos evhttp_response_needs_body(struct evhttp_request *req)
357df97fca9SNiels Provos {
358df97fca9SNiels Provos return (req->response_code != HTTP_NOCONTENT &&
359df97fca9SNiels Provos req->response_code != HTTP_NOTMODIFIED &&
360df97fca9SNiels Provos (req->response_code < 100 || req->response_code >= 200) &&
3611b42270bSAzat Khuzhin req->type != EVHTTP_REQ_CONNECT &&
362df97fca9SNiels Provos req->type != EVHTTP_REQ_HEAD);
363df97fca9SNiels Provos }
364df97fca9SNiels Provos
36590b3ed5bSNick Mathewson /** Helper: called after we've added some data to an evcon's bufferevent's
36690b3ed5bSNick Mathewson * output buffer. Sets the evconn's writing-is-done callback, and puts
36790b3ed5bSNick Mathewson * the bufferevent into writing mode.
36890b3ed5bSNick Mathewson */
36990b3ed5bSNick Mathewson static void
evhttp_write_buffer(struct evhttp_connection * evcon,void (* cb)(struct evhttp_connection *,void *),void * arg)370ba7262ebSNiels Provos evhttp_write_buffer(struct evhttp_connection *evcon,
371ba7262ebSNiels Provos void (*cb)(struct evhttp_connection *, void *), void *arg)
372a3bb4a03SNiels Provos {
373a3bb4a03SNiels Provos event_debug(("%s: preparing to write buffer\n", __func__));
374a3bb4a03SNiels Provos
375a3bb4a03SNiels Provos /* Set call back */
376ba7262ebSNiels Provos evcon->cb = cb;
377ba7262ebSNiels Provos evcon->cb_arg = arg;
378a3bb4a03SNiels Provos
37905124879SNick Mathewson /* Disable the read callback: we don't actually care about data;
3805b40744dSAzat Khuzhin * we only care about close detection. (We don't disable reading --
3815b40744dSAzat Khuzhin * EV_READ, since we *do* want to learn about any close events.) */
38205124879SNick Mathewson bufferevent_setcb(evcon->bufev,
38305124879SNick Mathewson NULL, /*read*/
38405124879SNick Mathewson evhttp_write_cb,
38505124879SNick Mathewson evhttp_error_cb,
38605124879SNick Mathewson evcon);
3875eb17885SNate Rosenblum
3885b40744dSAzat Khuzhin bufferevent_enable(evcon->bufev, EV_READ|EV_WRITE);
389a3bb4a03SNiels Provos }
390a3bb4a03SNiels Provos
391fa9305f8SChristopher Davis static void
evhttp_send_continue_done(struct evhttp_connection * evcon,void * arg)392fa9305f8SChristopher Davis evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg)
393fa9305f8SChristopher Davis {
394fa9305f8SChristopher Davis bufferevent_disable(evcon->bufev, EV_WRITE);
395fa9305f8SChristopher Davis }
396fa9305f8SChristopher Davis
397fa9305f8SChristopher Davis static void
evhttp_send_continue(struct evhttp_connection * evcon,struct evhttp_request * req)398fa9305f8SChristopher Davis evhttp_send_continue(struct evhttp_connection *evcon,
399fa9305f8SChristopher Davis struct evhttp_request *req)
400fa9305f8SChristopher Davis {
401fa9305f8SChristopher Davis bufferevent_enable(evcon->bufev, EV_WRITE);
402fa9305f8SChristopher Davis evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
403fa9305f8SChristopher Davis "HTTP/%d.%d 100 Continue\r\n\r\n",
404fa9305f8SChristopher Davis req->major, req->minor);
405fa9305f8SChristopher Davis evcon->cb = evhttp_send_continue_done;
406fa9305f8SChristopher Davis evcon->cb_arg = NULL;
407fa9305f8SChristopher Davis bufferevent_setcb(evcon->bufev,
408fa9305f8SChristopher Davis evhttp_read_cb,
409fa9305f8SChristopher Davis evhttp_write_cb,
410fa9305f8SChristopher Davis evhttp_error_cb,
411fa9305f8SChristopher Davis evcon);
412fa9305f8SChristopher Davis }
413fa9305f8SChristopher Davis
41490b3ed5bSNick Mathewson /** Helper: returns true iff evconn is in any connected state. */
4159998c0cbSNiels Provos static int
evhttp_connected(struct evhttp_connection * evcon)4169998c0cbSNiels Provos evhttp_connected(struct evhttp_connection *evcon)
4179998c0cbSNiels Provos {
4189998c0cbSNiels Provos switch (evcon->state) {
4199998c0cbSNiels Provos case EVCON_DISCONNECTED:
4209998c0cbSNiels Provos case EVCON_CONNECTING:
4219998c0cbSNiels Provos return (0);
4229998c0cbSNiels Provos case EVCON_IDLE:
4239998c0cbSNiels Provos case EVCON_READING_FIRSTLINE:
4249998c0cbSNiels Provos case EVCON_READING_HEADERS:
4259998c0cbSNiels Provos case EVCON_READING_BODY:
4269998c0cbSNiels Provos case EVCON_READING_TRAILER:
4279998c0cbSNiels Provos case EVCON_WRITING:
4289998c0cbSNiels Provos default:
4299998c0cbSNiels Provos return (1);
4309998c0cbSNiels Provos }
4319998c0cbSNiels Provos }
4329998c0cbSNiels Provos
43390b3ed5bSNick Mathewson /* Create the headers needed for an outgoing HTTP request, adds them to
43490b3ed5bSNick Mathewson * the request's header list, and writes the request line to the
43590b3ed5bSNick Mathewson * connection's output buffer.
43638b33048SNiels Provos */
437896bf3a2SNiels Provos static void
evhttp_make_header_request(struct evhttp_connection * evcon,struct evhttp_request * req)438ba7262ebSNiels Provos evhttp_make_header_request(struct evhttp_connection *evcon,
439ba7262ebSNiels Provos struct evhttp_request *req)
440a3bb4a03SNiels Provos {
441a3bb4a03SNiels Provos const char *method;
442a3bb4a03SNiels Provos
443a3bb4a03SNiels Provos evhttp_remove_header(req->output_headers, "Proxy-Connection");
444a3bb4a03SNiels Provos
445a3bb4a03SNiels Provos /* Generate request line */
44617cc6362SMark Ellzey if (!(method = evhttp_method(req->type))) {
44717cc6362SMark Ellzey method = "NULL";
44817cc6362SMark Ellzey }
44917cc6362SMark Ellzey
4508acb80b4SNick Mathewson evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
451e44ef375SNiels Provos "%s %s HTTP/%d.%d\r\n",
452a3bb4a03SNiels Provos method, req->uri, req->major, req->minor);
453a3bb4a03SNiels Provos
454b14cd655SNiels Provos /* Add the content length on a post or put request if missing */
455b14cd655SNiels Provos if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) &&
456896bf3a2SNiels Provos evhttp_find_header(req->output_headers, "Content-Length") == NULL){
457525da3e1SNick Mathewson char size[22];
4583203f88cSNick Mathewson evutil_snprintf(size, sizeof(size), EV_SIZE_FMT,
4593203f88cSNick Mathewson EV_SIZE_ARG(evbuffer_get_length(req->output_buffer)));
460896bf3a2SNiels Provos evhttp_add_header(req->output_headers, "Content-Length", size);
461a3bb4a03SNiels Provos }
462896bf3a2SNiels Provos }
463896bf3a2SNiels Provos
46490b3ed5bSNick Mathewson /** Return true if the list of headers in 'headers', intepreted with respect
46590b3ed5bSNick Mathewson * to flags, means that we should send a "connection: close" when the request
46690b3ed5bSNick Mathewson * is done. */
46736212f9dSNiels Provos static int
evhttp_is_connection_close(int flags,struct evkeyvalq * headers)468fe266238SNiels Provos evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
46936212f9dSNiels Provos {
470fe266238SNiels Provos if (flags & EVHTTP_PROXY_REQUEST) {
471fe266238SNiels Provos /* proxy connection */
472fe266238SNiels Provos const char *connection = evhttp_find_header(headers, "Proxy-Connection");
47372ea534fSNick Mathewson return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0);
474fe266238SNiels Provos } else {
47536212f9dSNiels Provos const char *connection = evhttp_find_header(headers, "Connection");
47672ea534fSNick Mathewson return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0);
47736212f9dSNiels Provos }
478fe266238SNiels Provos }
4796540da38SAzat Khuzhin static int
evhttp_is_request_connection_close(struct evhttp_request * req)4806540da38SAzat Khuzhin evhttp_is_request_connection_close(struct evhttp_request *req)
4816540da38SAzat Khuzhin {
482e2424229SAzat Khuzhin if (req->type == EVHTTP_REQ_CONNECT)
483e2424229SAzat Khuzhin return 0;
484e2424229SAzat Khuzhin
4856540da38SAzat Khuzhin return
4866540da38SAzat Khuzhin evhttp_is_connection_close(req->flags, req->input_headers) ||
4876540da38SAzat Khuzhin evhttp_is_connection_close(req->flags, req->output_headers);
4886540da38SAzat Khuzhin }
48936212f9dSNiels Provos
49090b3ed5bSNick Mathewson /* Return true iff 'headers' contains 'Connection: keep-alive' */
49136950cefSNiels Provos static int
evhttp_is_connection_keepalive(struct evkeyvalq * headers)49236950cefSNiels Provos evhttp_is_connection_keepalive(struct evkeyvalq* headers)
49336950cefSNiels Provos {
49436950cefSNiels Provos const char *connection = evhttp_find_header(headers, "Connection");
49536950cefSNiels Provos return (connection != NULL
49672ea534fSNick Mathewson && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0);
49736950cefSNiels Provos }
49836950cefSNiels Provos
49990b3ed5bSNick Mathewson /* Add a correct "Date" header to headers, unless it already has one. */
500896bf3a2SNiels Provos static void
evhttp_maybe_add_date_header(struct evkeyvalq * headers)50174b3db50SNiels Provos evhttp_maybe_add_date_header(struct evkeyvalq *headers)
502896bf3a2SNiels Provos {
50374b3db50SNiels Provos if (evhttp_find_header(headers, "Date") == NULL) {
5048d5ef326SNick Mathewson char date[50];
505db60ade8SVis Virial if (sizeof(date) - evutil_date_rfc1123(date, sizeof(date), NULL) > 0) {
50674b3db50SNiels Provos evhttp_add_header(headers, "Date", date);
50774b3db50SNiels Provos }
5088d5ef326SNick Mathewson }
5098d5ef326SNick Mathewson }
5108d5ef326SNick Mathewson
51190b3ed5bSNick Mathewson /* Add a "Content-Length" header with value 'content_length' to headers,
51290b3ed5bSNick Mathewson * unless it already has a content-length or transfer-encoding header. */
51374b3db50SNiels Provos static void
evhttp_maybe_add_content_length_header(struct evkeyvalq * headers,size_t content_length)51474b3db50SNiels Provos evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
5153203f88cSNick Mathewson size_t content_length)
51674b3db50SNiels Provos {
51774b3db50SNiels Provos if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
51874b3db50SNiels Provos evhttp_find_header(headers, "Content-Length") == NULL) {
519525da3e1SNick Mathewson char len[22];
5203203f88cSNick Mathewson evutil_snprintf(len, sizeof(len), EV_SIZE_FMT,
5213203f88cSNick Mathewson EV_SIZE_ARG(content_length));
52274b3db50SNiels Provos evhttp_add_header(headers, "Content-Length", len);
5239a65d013SNiels Provos }
52474b3db50SNiels Provos }
52574b3db50SNiels Provos
52674b3db50SNiels Provos /*
52790b3ed5bSNick Mathewson * Create the headers needed for an HTTP reply in req->output_headers,
52890b3ed5bSNick Mathewson * and write the first HTTP response for req line to evcon.
52974b3db50SNiels Provos */
53074b3db50SNiels Provos static void
evhttp_make_header_response(struct evhttp_connection * evcon,struct evhttp_request * req)53174b3db50SNiels Provos evhttp_make_header_response(struct evhttp_connection *evcon,
53274b3db50SNiels Provos struct evhttp_request *req)
53374b3db50SNiels Provos {
534ec3956baSNiels Provos int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
5358acb80b4SNick Mathewson evbuffer_add_printf(bufferevent_get_output(evcon->bufev),
536e44ef375SNiels Provos "HTTP/%d.%d %d %s\r\n",
53774b3db50SNiels Provos req->major, req->minor, req->response_code,
53874b3db50SNiels Provos req->response_code_line);
53974b3db50SNiels Provos
540ec3956baSNiels Provos if (req->major == 1) {
541647e094cSNick Mathewson if (req->minor >= 1)
54274b3db50SNiels Provos evhttp_maybe_add_date_header(req->output_headers);
5439a65d013SNiels Provos
54436212f9dSNiels Provos /*
545ec3956baSNiels Provos * if the protocol is 1.0; and the connection was keep-alive
546ec3956baSNiels Provos * we need to add a keep-alive header, too.
54736212f9dSNiels Provos */
548ec3956baSNiels Provos if (req->minor == 0 && is_keepalive)
549ec3956baSNiels Provos evhttp_add_header(req->output_headers,
550ec3956baSNiels Provos "Connection", "keep-alive");
551ec3956baSNiels Provos
552647e094cSNick Mathewson if ((req->minor >= 1 || is_keepalive) &&
553df97fca9SNiels Provos evhttp_response_needs_body(req)) {
554ec3956baSNiels Provos /*
555ec3956baSNiels Provos * we need to add the content length if the
556ec3956baSNiels Provos * user did not give it, this is required for
557ec3956baSNiels Provos * persistent connections to work.
558ec3956baSNiels Provos */
559ec3956baSNiels Provos evhttp_maybe_add_content_length_header(
560ec3956baSNiels Provos req->output_headers,
5613203f88cSNick Mathewson evbuffer_get_length(req->output_buffer));
56274b3db50SNiels Provos }
563ec3956baSNiels Provos }
56474b3db50SNiels Provos
56574b3db50SNiels Provos /* Potentially add headers for unidentified content. */
566df97fca9SNiels Provos if (evhttp_response_needs_body(req)) {
56774b3db50SNiels Provos if (evhttp_find_header(req->output_headers,
5685a5acd9aSNicolas Martyanoff "Content-Type") == NULL
5695a5acd9aSNicolas Martyanoff && evcon->http_server->default_content_type) {
570ec067919SNiels Provos evhttp_add_header(req->output_headers,
5715a5acd9aSNicolas Martyanoff "Content-Type",
5725a5acd9aSNicolas Martyanoff evcon->http_server->default_content_type);
573ec067919SNiels Provos }
57436212f9dSNiels Provos }
57536212f9dSNiels Provos
57636212f9dSNiels Provos /* if the request asked for a close, we send a close, too */
577fe266238SNiels Provos if (evhttp_is_connection_close(req->flags, req->input_headers)) {
57836212f9dSNiels Provos evhttp_remove_header(req->output_headers, "Connection");
579fe266238SNiels Provos if (!(req->flags & EVHTTP_PROXY_REQUEST))
580a67d9cb1SNiels Provos evhttp_add_header(req->output_headers, "Connection", "close");
581fe266238SNiels Provos evhttp_remove_header(req->output_headers, "Proxy-Connection");
582a67d9cb1SNiels Provos }
583a3bb4a03SNiels Provos }
584a3bb4a03SNiels Provos
5850b46b39eSAzat Khuzhin enum expect { NO, CONTINUE, OTHER };
evhttp_have_expect(struct evhttp_request * req,int input)5860b46b39eSAzat Khuzhin static enum expect evhttp_have_expect(struct evhttp_request *req, int input)
5870b46b39eSAzat Khuzhin {
5880b46b39eSAzat Khuzhin const char *expect;
5890b46b39eSAzat Khuzhin struct evkeyvalq *h = input ? req->input_headers : req->output_headers;
5900b46b39eSAzat Khuzhin
59124b52149SAzat Khuzhin if (!(req->kind == EVHTTP_REQUEST) || !REQ_VERSION_ATLEAST(req, 1, 1))
5920b46b39eSAzat Khuzhin return NO;
5930b46b39eSAzat Khuzhin
5940b46b39eSAzat Khuzhin expect = evhttp_find_header(h, "Expect");
5950b46b39eSAzat Khuzhin if (!expect)
5960b46b39eSAzat Khuzhin return NO;
5970b46b39eSAzat Khuzhin
5980b46b39eSAzat Khuzhin return !evutil_ascii_strcasecmp(expect, "100-continue") ? CONTINUE : OTHER;
5990b46b39eSAzat Khuzhin }
6000b46b39eSAzat Khuzhin
6010b46b39eSAzat Khuzhin
60290b3ed5bSNick Mathewson /** Generate all headers appropriate for sending the http request in req (or
60390b3ed5bSNick Mathewson * the response, if we're sending a response), and write them to evcon's
60490b3ed5bSNick Mathewson * bufferevent. Also writes all data from req->output_buffer */
60590b3ed5bSNick Mathewson static void
evhttp_make_header(struct evhttp_connection * evcon,struct evhttp_request * req)606ba7262ebSNiels Provos evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
607896bf3a2SNiels Provos {
608896bf3a2SNiels Provos struct evkeyval *header;
6098acb80b4SNick Mathewson struct evbuffer *output = bufferevent_get_output(evcon->bufev);
610896bf3a2SNiels Provos
611896bf3a2SNiels Provos /*
612896bf3a2SNiels Provos * Depending if this is a HTTP request or response, we might need to
613896bf3a2SNiels Provos * add some new headers or remove existing headers.
614896bf3a2SNiels Provos */
615896bf3a2SNiels Provos if (req->kind == EVHTTP_REQUEST) {
616ba7262ebSNiels Provos evhttp_make_header_request(evcon, req);
617896bf3a2SNiels Provos } else {
618ba7262ebSNiels Provos evhttp_make_header_response(evcon, req);
619896bf3a2SNiels Provos }
620896bf3a2SNiels Provos
621a3bb4a03SNiels Provos TAILQ_FOREACH(header, req->output_headers, next) {
622e44ef375SNiels Provos evbuffer_add_printf(output, "%s: %s\r\n",
623a3bb4a03SNiels Provos header->key, header->value);
624a3bb4a03SNiels Provos }
625e44ef375SNiels Provos evbuffer_add(output, "\r\n", 2);
626a3bb4a03SNiels Provos
6270b46b39eSAzat Khuzhin if (evhttp_have_expect(req, 0) != CONTINUE &&
6280b46b39eSAzat Khuzhin evbuffer_get_length(req->output_buffer)) {
629ba7262ebSNiels Provos /*
630ba7262ebSNiels Provos * For a request, we add the POST data, for a reply, this
631ba7262ebSNiels Provos * is the regular data.
632ba7262ebSNiels Provos */
633e44ef375SNiels Provos evbuffer_add_buffer(output, req->output_buffer);
634a3bb4a03SNiels Provos }
635a3bb4a03SNiels Provos }
636a3bb4a03SNiels Provos
63747bad8abSNick Mathewson void
evhttp_connection_set_max_headers_size(struct evhttp_connection * evcon,ev_ssize_t new_max_headers_size)63847bad8abSNick Mathewson evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon,
63947bad8abSNick Mathewson ev_ssize_t new_max_headers_size)
64047bad8abSNick Mathewson {
64147bad8abSNick Mathewson if (new_max_headers_size<0)
64247bad8abSNick Mathewson evcon->max_headers_size = EV_SIZE_MAX;
64347bad8abSNick Mathewson else
64447bad8abSNick Mathewson evcon->max_headers_size = new_max_headers_size;
64547bad8abSNick Mathewson }
64647bad8abSNick Mathewson void
evhttp_connection_set_max_body_size(struct evhttp_connection * evcon,ev_ssize_t new_max_body_size)64747bad8abSNick Mathewson evhttp_connection_set_max_body_size(struct evhttp_connection* evcon,
64847bad8abSNick Mathewson ev_ssize_t new_max_body_size)
64947bad8abSNick Mathewson {
65047bad8abSNick Mathewson if (new_max_body_size<0)
65147bad8abSNick Mathewson evcon->max_body_size = EV_UINT64_MAX;
65247bad8abSNick Mathewson else
65347bad8abSNick Mathewson evcon->max_body_size = new_max_body_size;
65447bad8abSNick Mathewson }
65547bad8abSNick Mathewson
656ce436242SNiels Provos static int
evhttp_connection_incoming_fail(struct evhttp_request * req,enum evhttp_request_error error)657ce436242SNiels Provos evhttp_connection_incoming_fail(struct evhttp_request *req,
6587b077194SAzat Khuzhin enum evhttp_request_error error)
659ce436242SNiels Provos {
660ce436242SNiels Provos switch (error) {
661ac448a74SAzat Khuzhin case EVREQ_HTTP_DATA_TOO_LONG:
662ac448a74SAzat Khuzhin req->response_code = HTTP_ENTITYTOOLARGE;
663ac448a74SAzat Khuzhin break;
664ac448a74SAzat Khuzhin default:
665ac448a74SAzat Khuzhin req->response_code = HTTP_BADREQUEST;
666ac448a74SAzat Khuzhin }
667ac448a74SAzat Khuzhin
668ac448a74SAzat Khuzhin switch (error) {
6697b077194SAzat Khuzhin case EVREQ_HTTP_TIMEOUT:
6707b077194SAzat Khuzhin case EVREQ_HTTP_EOF:
671ce436242SNiels Provos /*
672c6e285d3SNiels Provos * these are cases in which we probably should just
673c6e285d3SNiels Provos * close the connection and not send a reply. this
674c6e285d3SNiels Provos * case may happen when a browser keeps a persistent
67593d73691SNiels Provos * connection open and we timeout on the read. when
67693d73691SNiels Provos * the request is still being used for sending, we
67793d73691SNiels Provos * need to disassociated it from the connection here.
678ce436242SNiels Provos */
67993d73691SNiels Provos if (!req->userdone) {
68093d73691SNiels Provos /* remove it so that it will not be freed */
68193d73691SNiels Provos TAILQ_REMOVE(&req->evcon->requests, req, next);
68293d73691SNiels Provos /* indicate that this request no longer has a
68393d73691SNiels Provos * connection object
68493d73691SNiels Provos */
68593d73691SNiels Provos req->evcon = NULL;
68693d73691SNiels Provos }
687ce436242SNiels Provos return (-1);
6887b077194SAzat Khuzhin case EVREQ_HTTP_INVALID_HEADER:
6897b077194SAzat Khuzhin case EVREQ_HTTP_BUFFER_ERROR:
6907b077194SAzat Khuzhin case EVREQ_HTTP_REQUEST_CANCEL:
6917b077194SAzat Khuzhin case EVREQ_HTTP_DATA_TOO_LONG:
692ce436242SNiels Provos default: /* xxx: probably should just error on default */
693ce436242SNiels Provos /* the callback looks at the uri to determine errors */
694ce436242SNiels Provos if (req->uri) {
69549868b61SNick Mathewson mm_free(req->uri);
696ce436242SNiels Provos req->uri = NULL;
697ce436242SNiels Provos }
698aab8c38bSChristopher Davis if (req->uri_elems) {
699aab8c38bSChristopher Davis evhttp_uri_free(req->uri_elems);
700aab8c38bSChristopher Davis req->uri_elems = NULL;
701aab8c38bSChristopher Davis }
702c6e285d3SNiels Provos
703c6e285d3SNiels Provos /*
704c6e285d3SNiels Provos * the callback needs to send a reply, once the reply has
705c6e285d3SNiels Provos * been send, the connection should get freed.
706c6e285d3SNiels Provos */
707ce436242SNiels Provos (*req->cb)(req, req->cb_arg);
708ce436242SNiels Provos }
709ce436242SNiels Provos
710ce436242SNiels Provos return (0);
711ce436242SNiels Provos }
712ce436242SNiels Provos
713b0d3964fSAzat Khuzhin /* Free connection ownership of which can be acquired by user using
714b0d3964fSAzat Khuzhin * evhttp_request_own(). */
715b0d3964fSAzat Khuzhin static inline void
evhttp_request_free_auto(struct evhttp_request * req)716b0d3964fSAzat Khuzhin evhttp_request_free_auto(struct evhttp_request *req)
717b0d3964fSAzat Khuzhin {
718365f181aSAzat Khuzhin if (!(req->flags & EVHTTP_USER_OWNED))
719b0d3964fSAzat Khuzhin evhttp_request_free(req);
720b0d3964fSAzat Khuzhin }
721b0d3964fSAzat Khuzhin
72222061ac1SAzat Khuzhin static void
evhttp_request_free_(struct evhttp_connection * evcon,struct evhttp_request * req)72322061ac1SAzat Khuzhin evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req)
72422061ac1SAzat Khuzhin {
72522061ac1SAzat Khuzhin TAILQ_REMOVE(&evcon->requests, req, next);
726b0d3964fSAzat Khuzhin evhttp_request_free_auto(req);
72722061ac1SAzat Khuzhin }
72822061ac1SAzat Khuzhin
72990b3ed5bSNick Mathewson /* Called when evcon has experienced a (non-recoverable? -NM) error, as
73090b3ed5bSNick Mathewson * given in error. If it's an outgoing connection, reset the connection,
73190b3ed5bSNick Mathewson * retry any pending requests, and inform the user. If it's incoming,
73290b3ed5bSNick Mathewson * delegates to evhttp_connection_incoming_fail(). */
733a3bb4a03SNiels Provos void
evhttp_connection_fail_(struct evhttp_connection * evcon,enum evhttp_request_error error)7348ac3c4c2SNick Mathewson evhttp_connection_fail_(struct evhttp_connection *evcon,
7357b077194SAzat Khuzhin enum evhttp_request_error error)
736a3bb4a03SNiels Provos {
7377afbd602SNick Mathewson const int errsave = EVUTIL_SOCKET_ERROR();
738ba7262ebSNiels Provos struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
739ff9e1af6SNiels Provos void (*cb)(struct evhttp_request *, void *);
740ff9e1af6SNiels Provos void *cb_arg;
7417b077194SAzat Khuzhin void (*error_cb)(enum evhttp_request_error, void *);
7427b077194SAzat Khuzhin void *error_cb_arg;
7432e36dbe1SNick Mathewson EVUTIL_ASSERT(req != NULL);
744ba7262ebSNiels Provos
745e44ef375SNiels Provos bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE);
746e44ef375SNiels Provos
74744bd5ab4SNiels Provos if (evcon->flags & EVHTTP_CON_INCOMING) {
748c6e285d3SNiels Provos /*
749c6e285d3SNiels Provos * for incoming requests, there are two different
750c6e285d3SNiels Provos * failure cases. it's either a network level error
751c6e285d3SNiels Provos * or an http layer error. for problems on the network
752c6e285d3SNiels Provos * layer like timeouts we just drop the connections.
753c6e285d3SNiels Provos * For HTTP problems, we might have to send back a
754c6e285d3SNiels Provos * reply before the connection can be freed.
755c6e285d3SNiels Provos */
756c6e285d3SNiels Provos if (evhttp_connection_incoming_fail(req, error) == -1)
757c6e285d3SNiels Provos evhttp_connection_free(evcon);
75844bd5ab4SNiels Provos return;
759ce436242SNiels Provos }
760ba7262ebSNiels Provos
7617b077194SAzat Khuzhin error_cb = req->error_cb;
7627b077194SAzat Khuzhin error_cb_arg = req->cb_arg;
7631080852eSNiels Provos /* when the request was canceled, the callback is not executed */
7647b077194SAzat Khuzhin if (error != EVREQ_HTTP_REQUEST_CANCEL) {
765ff9e1af6SNiels Provos /* save the callback for later; the cb might free our object */
766ff9e1af6SNiels Provos cb = req->cb;
767ff9e1af6SNiels Provos cb_arg = req->cb_arg;
7681080852eSNiels Provos } else {
7691080852eSNiels Provos cb = NULL;
7701080852eSNiels Provos cb_arg = NULL;
7711080852eSNiels Provos }
77244bd5ab4SNiels Provos
7731080852eSNiels Provos /* do not fail all requests; the next request is going to get
7741080852eSNiels Provos * send over a new connection. when a user cancels a request,
7751080852eSNiels Provos * all other pending requests should be processed as normal
7761080852eSNiels Provos */
77722061ac1SAzat Khuzhin evhttp_request_free_(evcon, req);
778ba7262ebSNiels Provos
779c6e285d3SNiels Provos /* reset the connection */
7808ac3c4c2SNick Mathewson evhttp_connection_reset_(evcon);
781c6e285d3SNiels Provos
782ba7262ebSNiels Provos /* We are trying the next request that was queued on us */
783ba7262ebSNiels Provos if (TAILQ_FIRST(&evcon->requests) != NULL)
7848ac3c4c2SNick Mathewson evhttp_connection_connect_(evcon);
7851be25938SAzat Khuzhin else
7861be25938SAzat Khuzhin if ((evcon->flags & EVHTTP_CON_OUTGOING) &&
7871be25938SAzat Khuzhin (evcon->flags & EVHTTP_CON_AUTOFREE)) {
7881be25938SAzat Khuzhin evhttp_connection_free(evcon);
7891be25938SAzat Khuzhin }
790ff9e1af6SNiels Provos
79136d0ee5cSPatrick Pelletier /* The call to evhttp_connection_reset_ overwrote errno.
79236d0ee5cSPatrick Pelletier * Let's restore the original errno, so that the user's
79336d0ee5cSPatrick Pelletier * callback can have a better idea of what the error was.
79436d0ee5cSPatrick Pelletier */
7957afbd602SNick Mathewson EVUTIL_SET_SOCKET_ERROR(errsave);
79636d0ee5cSPatrick Pelletier
797ff9e1af6SNiels Provos /* inform the user */
7987b077194SAzat Khuzhin if (error_cb != NULL)
7997b077194SAzat Khuzhin error_cb(error, error_cb_arg);
800ff9e1af6SNiels Provos if (cb != NULL)
801ff9e1af6SNiels Provos (*cb)(NULL, cb_arg);
802a3bb4a03SNiels Provos }
803a3bb4a03SNiels Provos
80490b3ed5bSNick Mathewson /* Bufferevent callback: invoked when any data has been written from an
80590b3ed5bSNick Mathewson * http connection's bufferevent */
806e44ef375SNiels Provos static void
evhttp_write_cb(struct bufferevent * bufev,void * arg)807e44ef375SNiels Provos evhttp_write_cb(struct bufferevent *bufev, void *arg)
808a3bb4a03SNiels Provos {
809ba7262ebSNiels Provos struct evhttp_connection *evcon = arg;
810a3bb4a03SNiels Provos
811a3bb4a03SNiels Provos /* Activate our call back */
812de7db33aSNiels Provos if (evcon->cb != NULL)
813ba7262ebSNiels Provos (*evcon->cb)(evcon, evcon->cb_arg);
814ba7262ebSNiels Provos }
815ba7262ebSNiels Provos
8169998c0cbSNiels Provos /**
8179998c0cbSNiels Provos * Advance the connection state.
8189998c0cbSNiels Provos * - If this is an outgoing connection, we've just processed the response;
8199998c0cbSNiels Provos * idle or close the connection.
8209998c0cbSNiels Provos * - If this is an incoming connection, we've just processed the request;
8219998c0cbSNiels Provos * respond.
8229998c0cbSNiels Provos */
823a3f122d6SNick Mathewson static void
evhttp_connection_done(struct evhttp_connection * evcon)824ba7262ebSNiels Provos evhttp_connection_done(struct evhttp_connection *evcon)
825ba7262ebSNiels Provos {
826ba7262ebSNiels Provos struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
8275b5400f6SNiels Provos int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
8282b9ec4c1SJohn Ohl int free_evcon = 0;
829ba7262ebSNiels Provos
8305b5400f6SNiels Provos if (con_outgoing) {
8319998c0cbSNiels Provos /* idle or close the connection */
8326540da38SAzat Khuzhin int need_close = evhttp_is_request_connection_close(req);
833ba7262ebSNiels Provos TAILQ_REMOVE(&evcon->requests, req, next);
834ba7262ebSNiels Provos req->evcon = NULL;
835ba7262ebSNiels Provos
8369998c0cbSNiels Provos evcon->state = EVCON_IDLE;
8379998c0cbSNiels Provos
838a67d9cb1SNiels Provos /* check if we got asked to close the connection */
839942656bbSNiels Provos if (need_close)
8408ac3c4c2SNick Mathewson evhttp_connection_reset_(evcon);
841a67d9cb1SNiels Provos
842ba7262ebSNiels Provos if (TAILQ_FIRST(&evcon->requests) != NULL) {
843ba7262ebSNiels Provos /*
844ba7262ebSNiels Provos * We have more requests; reset the connection
8459998c0cbSNiels Provos * and deal with the next request.
846ba7262ebSNiels Provos */
8479998c0cbSNiels Provos if (!evhttp_connected(evcon))
8488ac3c4c2SNick Mathewson evhttp_connection_connect_(evcon);
849942656bbSNiels Provos else
850942656bbSNiels Provos evhttp_request_dispatch(evcon);
851942656bbSNiels Provos } else if (!need_close) {
852942656bbSNiels Provos /*
853942656bbSNiels Provos * The connection is going to be persistent, but we
854942656bbSNiels Provos * need to detect if the other side closes it.
855942656bbSNiels Provos */
856942656bbSNiels Provos evhttp_connection_start_detectclose(evcon);
8572b9ec4c1SJohn Ohl } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) {
8582b9ec4c1SJohn Ohl /*
8592b9ec4c1SJohn Ohl * If we have no more requests that need completion
8602b9ec4c1SJohn Ohl * and we're not waiting for the connection to close
8612b9ec4c1SJohn Ohl */
8622b9ec4c1SJohn Ohl free_evcon = 1;
863ba7262ebSNiels Provos }
8649998c0cbSNiels Provos } else {
8659998c0cbSNiels Provos /*
8669998c0cbSNiels Provos * incoming connection - we need to leave the request on the
8679998c0cbSNiels Provos * connection so that we can reply to it.
8689998c0cbSNiels Provos */
8699998c0cbSNiels Provos evcon->state = EVCON_WRITING;
870ba7262ebSNiels Provos }
871ba7262ebSNiels Provos
872ba7262ebSNiels Provos /* notify the user of the request */
873a3bb4a03SNiels Provos (*req->cb)(req, req->cb_arg);
874ba7262ebSNiels Provos
875b0d3964fSAzat Khuzhin /* if this was an outgoing request, we own and it's done. so free it. */
876b0d3964fSAzat Khuzhin if (con_outgoing) {
877b0d3964fSAzat Khuzhin evhttp_request_free_auto(req);
878ba7262ebSNiels Provos }
8792b9ec4c1SJohn Ohl
8802b9ec4c1SJohn Ohl /* If this was the last request of an outgoing connection and we're
8812b9ec4c1SJohn Ohl * not waiting to receive a connection close event and we want to
8822b9ec4c1SJohn Ohl * automatically free the connection. We check to ensure our request
8832b9ec4c1SJohn Ohl * list is empty one last time just in case our callback added a
8842b9ec4c1SJohn Ohl * new request.
8852b9ec4c1SJohn Ohl */
8862b9ec4c1SJohn Ohl if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) {
8872b9ec4c1SJohn Ohl evhttp_connection_free(evcon);
8882b9ec4c1SJohn Ohl }
889a3bb4a03SNiels Provos }
890a3bb4a03SNiels Provos
891a3bb4a03SNiels Provos /*
892557e0f62SNiels Provos * Handles reading from a chunked request.
893344c2b56SNiels Provos * return ALL_DATA_READ:
894344c2b56SNiels Provos * all data has been read
895344c2b56SNiels Provos * return MORE_DATA_EXPECTED:
896344c2b56SNiels Provos * more data is expected
897344c2b56SNiels Provos * return DATA_CORRUPTED:
898344c2b56SNiels Provos * data is corrupted
899e3fd294aSNick Mathewson * return REQUEST_CANCELED:
900344c2b56SNiels Provos * request was canceled by the user calling evhttp_cancel_request
90147bad8abSNick Mathewson * return DATA_TOO_LONG:
90247bad8abSNick Mathewson * ran over the maximum limit
903557e0f62SNiels Provos */
904557e0f62SNiels Provos
9059998c0cbSNiels Provos static enum message_read_status
evhttp_handle_chunked_read(struct evhttp_request * req,struct evbuffer * buf)906557e0f62SNiels Provos evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
907557e0f62SNiels Provos {
908a2792722SMark Ellzey if (req == NULL || buf == NULL) {
909a2792722SMark Ellzey return DATA_CORRUPTED;
910a2792722SMark Ellzey }
911557e0f62SNiels Provos
912a2792722SMark Ellzey while (1) {
913a2792722SMark Ellzey size_t buflen;
914a2792722SMark Ellzey
915a2792722SMark Ellzey if ((buflen = evbuffer_get_length(buf)) == 0) {
916a2792722SMark Ellzey break;
917a2792722SMark Ellzey }
918a2792722SMark Ellzey
919a2792722SMark Ellzey /* evbuffer_get_length returns size_t, but len variable is ssize_t,
920a2792722SMark Ellzey * check for overflow conditions */
9211814ae96SMark Ellzey if (buflen > EV_SSIZE_MAX) {
922a2792722SMark Ellzey return DATA_CORRUPTED;
923a2792722SMark Ellzey }
924a2792722SMark Ellzey
925557e0f62SNiels Provos if (req->ntoread < 0) {
926557e0f62SNiels Provos /* Read chunk size */
927707f6784SNiels Provos ev_int64_t ntoread;
9286773a597SNick Mathewson char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF);
929557e0f62SNiels Provos char *endp;
930557e0f62SNiels Provos int error;
931557e0f62SNiels Provos if (p == NULL)
932557e0f62SNiels Provos break;
9338901c141SNiels Provos /* the last chunk is on a new line? */
934b7ff0248SNiels Provos if (strlen(p) == 0) {
93549868b61SNick Mathewson mm_free(p);
9368901c141SNiels Provos continue;
937b7ff0248SNiels Provos }
938707f6784SNiels Provos ntoread = evutil_strtoll(p, &endp, 16);
939707f6784SNiels Provos error = (*p == '\0' ||
940707f6784SNiels Provos (*endp != '\0' && *endp != ' ') ||
941707f6784SNiels Provos ntoread < 0);
94249868b61SNick Mathewson mm_free(p);
943557e0f62SNiels Provos if (error) {
944557e0f62SNiels Provos /* could not get chunk size */
945344c2b56SNiels Provos return (DATA_CORRUPTED);
946557e0f62SNiels Provos }
947a2792722SMark Ellzey
948a2792722SMark Ellzey /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */
949203ba274SNick Mathewson if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) {
950a2792722SMark Ellzey return DATA_CORRUPTED;
951a2792722SMark Ellzey }
952a2792722SMark Ellzey
953ac633aebSNick Mathewson if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) {
95447bad8abSNick Mathewson /* failed body length test */
95547bad8abSNick Mathewson event_debug(("Request body is too long"));
95647bad8abSNick Mathewson return (DATA_TOO_LONG);
95747bad8abSNick Mathewson }
9581814ae96SMark Ellzey
959ac633aebSNick Mathewson req->body_size += (size_t)ntoread;
960707f6784SNiels Provos req->ntoread = ntoread;
961557e0f62SNiels Provos if (req->ntoread == 0) {
962557e0f62SNiels Provos /* Last chunk */
963344c2b56SNiels Provos return (ALL_DATA_READ);
964557e0f62SNiels Provos }
9658901c141SNiels Provos continue;
9668901c141SNiels Provos }
9678901c141SNiels Provos
968a2792722SMark Ellzey /* req->ntoread is signed int64, len is ssize_t, based on arch,
969a2792722SMark Ellzey * ssize_t could only be 32b, check for these conditions */
9701814ae96SMark Ellzey if (req->ntoread > EV_SSIZE_MAX) {
971a2792722SMark Ellzey return DATA_CORRUPTED;
972a2792722SMark Ellzey }
973a2792722SMark Ellzey
9748901c141SNiels Provos /* don't have enough to complete a chunk; wait for more */
975203ba274SNick Mathewson if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread)
976344c2b56SNiels Provos return (MORE_DATA_EXPECTED);
9778901c141SNiels Provos
978557e0f62SNiels Provos /* Completed chunk */
979e865eb93SNick Mathewson evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread);
980557e0f62SNiels Provos req->ntoread = -1;
9818901c141SNiels Provos if (req->chunk_cb != NULL) {
982344c2b56SNiels Provos req->flags |= EVHTTP_REQ_DEFER_FREE;
9838901c141SNiels Provos (*req->chunk_cb)(req, req->cb_arg);
984557e0f62SNiels Provos evbuffer_drain(req->input_buffer,
985a8f6d961SNick Mathewson evbuffer_get_length(req->input_buffer));
986344c2b56SNiels Provos req->flags &= ~EVHTTP_REQ_DEFER_FREE;
987344c2b56SNiels Provos if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
988344c2b56SNiels Provos return (REQUEST_CANCELED);
989344c2b56SNiels Provos }
990557e0f62SNiels Provos }
991557e0f62SNiels Provos }
992557e0f62SNiels Provos
993344c2b56SNiels Provos return (MORE_DATA_EXPECTED);
994557e0f62SNiels Provos }
995557e0f62SNiels Provos
996a3f122d6SNick Mathewson static void
evhttp_read_trailer(struct evhttp_connection * evcon,struct evhttp_request * req)9979998c0cbSNiels Provos evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
9989998c0cbSNiels Provos {
9999998c0cbSNiels Provos struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
10009998c0cbSNiels Provos
10018ac3c4c2SNick Mathewson switch (evhttp_parse_headers_(req, buf)) {
10029998c0cbSNiels Provos case DATA_CORRUPTED:
100347bad8abSNick Mathewson case DATA_TOO_LONG:
10047b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
10059998c0cbSNiels Provos break;
10069998c0cbSNiels Provos case ALL_DATA_READ:
10079998c0cbSNiels Provos bufferevent_disable(evcon->bufev, EV_READ);
10089998c0cbSNiels Provos evhttp_connection_done(evcon);
10099998c0cbSNiels Provos break;
10109998c0cbSNiels Provos case MORE_DATA_EXPECTED:
1011c5c9589fSNick Mathewson case REQUEST_CANCELED: /* ??? */
10129998c0cbSNiels Provos default:
10139998c0cbSNiels Provos break;
10149998c0cbSNiels Provos }
10159998c0cbSNiels Provos }
10169998c0cbSNiels Provos
10179998c0cbSNiels Provos static void
evhttp_lingering_close(struct evhttp_connection * evcon,struct evhttp_request * req)1018ac448a74SAzat Khuzhin evhttp_lingering_close(struct evhttp_connection *evcon,
1019ac448a74SAzat Khuzhin struct evhttp_request *req)
10209fde5189SAzat Khuzhin {
10219fde5189SAzat Khuzhin struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
10229fde5189SAzat Khuzhin
10239fde5189SAzat Khuzhin size_t n = evbuffer_get_length(buf);
10249fde5189SAzat Khuzhin if (n > (size_t) req->ntoread)
10259fde5189SAzat Khuzhin n = (size_t) req->ntoread;
10269fde5189SAzat Khuzhin req->ntoread -= n;
10279fde5189SAzat Khuzhin req->body_size += n;
10289fde5189SAzat Khuzhin
10291cbf26f6SAzat Khuzhin event_debug(("Request body is too long, left " EV_I64_FMT,
10301cbf26f6SAzat Khuzhin EV_I64_ARG(req->ntoread)));
10319fde5189SAzat Khuzhin
10329fde5189SAzat Khuzhin evbuffer_drain(buf, n);
10339fde5189SAzat Khuzhin if (!req->ntoread)
10349fde5189SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
10359fde5189SAzat Khuzhin }
1036ac448a74SAzat Khuzhin static void
evhttp_lingering_fail(struct evhttp_connection * evcon,struct evhttp_request * req)1037ac448a74SAzat Khuzhin evhttp_lingering_fail(struct evhttp_connection *evcon,
1038ac448a74SAzat Khuzhin struct evhttp_request *req)
1039ac448a74SAzat Khuzhin {
1040ac448a74SAzat Khuzhin if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE)
1041ac448a74SAzat Khuzhin evhttp_lingering_close(evcon, req);
1042ac448a74SAzat Khuzhin else
1043ac448a74SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG);
1044ac448a74SAzat Khuzhin }
10459fde5189SAzat Khuzhin
10469fde5189SAzat Khuzhin static void
evhttp_read_body(struct evhttp_connection * evcon,struct evhttp_request * req)1047ba8289beSNiels Provos evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
1048ba8289beSNiels Provos {
10498acb80b4SNick Mathewson struct evbuffer *buf = bufferevent_get_input(evcon->bufev);
1050ba8289beSNiels Provos
1051ba8289beSNiels Provos if (req->chunked) {
1052344c2b56SNiels Provos switch (evhttp_handle_chunked_read(req, buf)) {
1053344c2b56SNiels Provos case ALL_DATA_READ:
1054ba8289beSNiels Provos /* finished last chunk */
10559998c0cbSNiels Provos evcon->state = EVCON_READING_TRAILER;
10569998c0cbSNiels Provos evhttp_read_trailer(evcon, req);
1057ba8289beSNiels Provos return;
1058344c2b56SNiels Provos case DATA_CORRUPTED:
10597b077194SAzat Khuzhin case DATA_TOO_LONG:
1060ba8289beSNiels Provos /* corrupted data */
10618ac3c4c2SNick Mathewson evhttp_connection_fail_(evcon,
10627b077194SAzat Khuzhin EVREQ_HTTP_DATA_TOO_LONG);
1063ba8289beSNiels Provos return;
1064344c2b56SNiels Provos case REQUEST_CANCELED:
1065344c2b56SNiels Provos /* request canceled */
1066b0d3964fSAzat Khuzhin evhttp_request_free_auto(req);
1067344c2b56SNiels Provos return;
1068344c2b56SNiels Provos case MORE_DATA_EXPECTED:
1069344c2b56SNiels Provos default:
1070344c2b56SNiels Provos break;
1071ba8289beSNiels Provos }
1072ba8289beSNiels Provos } else if (req->ntoread < 0) {
1073ba8289beSNiels Provos /* Read until connection close. */
10741814ae96SMark Ellzey if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) {
10757b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
107684560fc4SMark Ellzey return;
107784560fc4SMark Ellzey }
107884560fc4SMark Ellzey
107947bad8abSNick Mathewson req->body_size += evbuffer_get_length(buf);
10808e342e56SNick Mathewson evbuffer_add_buffer(req->input_buffer, buf);
108184560fc4SMark Ellzey } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) {
108284560fc4SMark Ellzey /* XXX: the above get_length comparison has to be fixed for overflow conditions! */
1083344c2b56SNiels Provos /* We've postponed moving the data until now, but we're
1084344c2b56SNiels Provos * about to use it. */
108558a1cc6bSNick Mathewson size_t n = evbuffer_get_length(buf);
108684560fc4SMark Ellzey
108758a1cc6bSNick Mathewson if (n > (size_t) req->ntoread)
108858a1cc6bSNick Mathewson n = (size_t) req->ntoread;
108958a1cc6bSNick Mathewson req->ntoread -= n;
109058a1cc6bSNick Mathewson req->body_size += n;
109158a1cc6bSNick Mathewson evbuffer_remove_buffer(buf, req->input_buffer, n);
1092344c2b56SNiels Provos }
1093344c2b56SNiels Provos
109463a715e1SNick Mathewson if (req->body_size > req->evcon->max_body_size ||
109563a715e1SNick Mathewson (!req->chunked && req->ntoread >= 0 &&
109663a715e1SNick Mathewson (size_t)req->ntoread > req->evcon->max_body_size)) {
109784560fc4SMark Ellzey /* XXX: The above casted comparison must checked for overflow */
109847bad8abSNick Mathewson /* failed body length test */
10999fde5189SAzat Khuzhin
1100ac448a74SAzat Khuzhin evhttp_lingering_fail(evcon, req);
110147bad8abSNick Mathewson return;
110247bad8abSNick Mathewson }
110347bad8abSNick Mathewson
1104a8f6d961SNick Mathewson if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) {
1105344c2b56SNiels Provos req->flags |= EVHTTP_REQ_DEFER_FREE;
1106344c2b56SNiels Provos (*req->chunk_cb)(req, req->cb_arg);
1107344c2b56SNiels Provos req->flags &= ~EVHTTP_REQ_DEFER_FREE;
1108344c2b56SNiels Provos evbuffer_drain(req->input_buffer,
1109a8f6d961SNick Mathewson evbuffer_get_length(req->input_buffer));
1110344c2b56SNiels Provos if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) {
1111b0d3964fSAzat Khuzhin evhttp_request_free_auto(req);
1112344c2b56SNiels Provos return;
1113344c2b56SNiels Provos }
1114344c2b56SNiels Provos }
1115344c2b56SNiels Provos
11169fde5189SAzat Khuzhin if (!req->ntoread) {
1117e44ef375SNiels Provos bufferevent_disable(evcon->bufev, EV_READ);
1118ba8289beSNiels Provos /* Completed content length */
1119ba8289beSNiels Provos evhttp_connection_done(evcon);
1120ba8289beSNiels Provos return;
1121ba8289beSNiels Provos }
1122ba8289beSNiels Provos }
1123ba8289beSNiels Provos
112474c0e862SNick Mathewson #define get_deferred_queue(evcon) \
1125a4079aa8SNick Mathewson ((evcon)->base)
112674c0e862SNick Mathewson
1127557e0f62SNiels Provos /*
1128e44ef375SNiels Provos * Gets called when more data becomes available
1129a3bb4a03SNiels Provos */
1130a3bb4a03SNiels Provos
1131e44ef375SNiels Provos static void
evhttp_read_cb(struct bufferevent * bufev,void * arg)1132e44ef375SNiels Provos evhttp_read_cb(struct bufferevent *bufev, void *arg)
1133a3bb4a03SNiels Provos {
1134ba7262ebSNiels Provos struct evhttp_connection *evcon = arg;
1135ba7262ebSNiels Provos struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1136a3bb4a03SNiels Provos
113774c0e862SNick Mathewson /* Cancel if it's pending. */
11388ac3c4c2SNick Mathewson event_deferred_cb_cancel_(get_deferred_queue(evcon),
113974c0e862SNick Mathewson &evcon->read_more_deferred_cb);
114074c0e862SNick Mathewson
11419998c0cbSNiels Provos switch (evcon->state) {
11429998c0cbSNiels Provos case EVCON_READING_FIRSTLINE:
11439998c0cbSNiels Provos evhttp_read_firstline(evcon, req);
11449998c0cbSNiels Provos /* note the request may have been freed in
11459998c0cbSNiels Provos * evhttp_read_body */
11469998c0cbSNiels Provos break;
11479998c0cbSNiels Provos case EVCON_READING_HEADERS:
11489998c0cbSNiels Provos evhttp_read_header(evcon, req);
11499998c0cbSNiels Provos /* note the request may have been freed in
11509998c0cbSNiels Provos * evhttp_read_body */
11519998c0cbSNiels Provos break;
11529998c0cbSNiels Provos case EVCON_READING_BODY:
1153ba8289beSNiels Provos evhttp_read_body(evcon, req);
11549998c0cbSNiels Provos /* note the request may have been freed in
11559998c0cbSNiels Provos * evhttp_read_body */
11569998c0cbSNiels Provos break;
11579998c0cbSNiels Provos case EVCON_READING_TRAILER:
11589998c0cbSNiels Provos evhttp_read_trailer(evcon, req);
11599998c0cbSNiels Provos break;
1160272823f8STomash Brechko case EVCON_IDLE:
1161272823f8STomash Brechko {
1162e49e64e7SNick Mathewson #ifdef USE_DEBUG
1163272823f8STomash Brechko struct evbuffer *input;
1164272823f8STomash Brechko size_t total_len;
1165272823f8STomash Brechko
1166272823f8STomash Brechko input = bufferevent_get_input(evcon->bufev);
1167272823f8STomash Brechko total_len = evbuffer_get_length(input);
11683203f88cSNick Mathewson event_debug(("%s: read "EV_SIZE_FMT
11693203f88cSNick Mathewson " bytes in EVCON_IDLE state,"
1170272823f8STomash Brechko " resetting connection",
11713203f88cSNick Mathewson __func__, EV_SIZE_ARG(total_len)));
1172e49e64e7SNick Mathewson #endif
1173272823f8STomash Brechko
11748ac3c4c2SNick Mathewson evhttp_connection_reset_(evcon);
1175272823f8STomash Brechko }
1176272823f8STomash Brechko break;
11779998c0cbSNiels Provos case EVCON_DISCONNECTED:
11789998c0cbSNiels Provos case EVCON_CONNECTING:
11799998c0cbSNiels Provos case EVCON_WRITING:
11809998c0cbSNiels Provos default:
11819998c0cbSNiels Provos event_errx(1, "%s: illegal connection state %d",
11829998c0cbSNiels Provos __func__, evcon->state);
11839998c0cbSNiels Provos }
1184a3bb4a03SNiels Provos }
1185a3bb4a03SNiels Provos
1186a3f122d6SNick Mathewson static void
evhttp_deferred_read_cb(struct event_callback * cb,void * data)1187a4079aa8SNick Mathewson evhttp_deferred_read_cb(struct event_callback *cb, void *data)
118874c0e862SNick Mathewson {
118974c0e862SNick Mathewson struct evhttp_connection *evcon = data;
1190eb7b472bSAzat Khuzhin struct bufferevent *bev = evcon->bufev;
1191eb7b472bSAzat Khuzhin if (bev->readcb)
1192eb7b472bSAzat Khuzhin (bev->readcb)(evcon->bufev, evcon);
119374c0e862SNick Mathewson }
119474c0e862SNick Mathewson
119574c0e862SNick Mathewson static void
evhttp_write_connectioncb(struct evhttp_connection * evcon,void * arg)1196ba7262ebSNiels Provos evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
1197a3bb4a03SNiels Provos {
1198a3bb4a03SNiels Provos /* This is after writing the request to the server */
1199ba7262ebSNiels Provos struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
12000b46b39eSAzat Khuzhin struct evbuffer *output = bufferevent_get_output(evcon->bufev);
12012e36dbe1SNick Mathewson EVUTIL_ASSERT(req != NULL);
1202a3bb4a03SNiels Provos
12032e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon->state == EVCON_WRITING);
12049998c0cbSNiels Provos
12050b46b39eSAzat Khuzhin /* We need to wait until we've written all of our output data before we can
12060b46b39eSAzat Khuzhin * continue */
12070b46b39eSAzat Khuzhin if (evbuffer_get_length(output) > 0)
12080b46b39eSAzat Khuzhin return;
120924eea0daSJohn Ohl
1210a3bb4a03SNiels Provos /* We are done writing our header and are now expecting the response */
1211a3bb4a03SNiels Provos req->kind = EVHTTP_RESPONSE;
1212a3bb4a03SNiels Provos
12138ac3c4c2SNick Mathewson evhttp_start_read_(evcon);
1214a3bb4a03SNiels Provos }
1215a3bb4a03SNiels Provos
1216a3bb4a03SNiels Provos /*
1217a3bb4a03SNiels Provos * Clean up a connection object
1218a3bb4a03SNiels Provos */
1219a3bb4a03SNiels Provos
1220a3bb4a03SNiels Provos void
evhttp_connection_free(struct evhttp_connection * evcon)1221a3bb4a03SNiels Provos evhttp_connection_free(struct evhttp_connection *evcon)
1222a3bb4a03SNiels Provos {
1223c6e285d3SNiels Provos struct evhttp_request *req;
12246ac2ec25SAzat Khuzhin int need_close = 0;
1225c6e285d3SNiels Provos
1226de7db33aSNiels Provos /* notify interested parties that this connection is going down */
1227de7db33aSNiels Provos if (evcon->fd != -1) {
12289998c0cbSNiels Provos if (evhttp_connected(evcon) && evcon->closecb != NULL)
1229de7db33aSNiels Provos (*evcon->closecb)(evcon, evcon->closecb_arg);
1230de7db33aSNiels Provos }
1231de7db33aSNiels Provos
123293d73691SNiels Provos /* remove all requests that might be queued on this
123393d73691SNiels Provos * connection. for server connections, this should be empty.
123493d73691SNiels Provos * because it gets dequeued either in evhttp_connection_done or
12358ac3c4c2SNick Mathewson * evhttp_connection_fail_.
123693d73691SNiels Provos */
1237c6e285d3SNiels Provos while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
123822061ac1SAzat Khuzhin evhttp_request_free_(evcon, req);
1239c6e285d3SNiels Provos }
1240c6e285d3SNiels Provos
124136212f9dSNiels Provos if (evcon->http_server != NULL) {
124236212f9dSNiels Provos struct evhttp *http = evcon->http_server;
124336212f9dSNiels Provos TAILQ_REMOVE(&http->connections, evcon, next);
124436212f9dSNiels Provos }
124536212f9dSNiels Provos
1246a19b4a05SNick Mathewson if (event_initialized(&evcon->retry_ev)) {
1247e44ef375SNiels Provos event_del(&evcon->retry_ev);
1248a19b4a05SNick Mathewson event_debug_unassign(&evcon->retry_ev);
1249a19b4a05SNick Mathewson }
1250e44ef375SNiels Provos
12518ac3c4c2SNick Mathewson event_deferred_cb_cancel_(get_deferred_queue(evcon),
125274c0e862SNick Mathewson &evcon->read_more_deferred_cb);
125374c0e862SNick Mathewson
12546ac2ec25SAzat Khuzhin if (evcon->bufev != NULL) {
12556ac2ec25SAzat Khuzhin need_close =
12566ac2ec25SAzat Khuzhin !(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE);
1257f0e13411SAzat Khuzhin if (evcon->fd == -1)
1258f0e13411SAzat Khuzhin evcon->fd = bufferevent_getfd(evcon->bufev);
1259f0e13411SAzat Khuzhin
12606ac2ec25SAzat Khuzhin bufferevent_free(evcon->bufev);
1261e0fd8708SChristopher Davis }
12626ac2ec25SAzat Khuzhin
12636ac2ec25SAzat Khuzhin if (evcon->fd != -1) {
12646ac2ec25SAzat Khuzhin shutdown(evcon->fd, EVUTIL_SHUT_WR);
12656ac2ec25SAzat Khuzhin if (need_close)
12666ac2ec25SAzat Khuzhin evutil_closesocket(evcon->fd);
126731db8a02SMaxime Henrion }
1268a3bb4a03SNiels Provos
126998f9616bSNiels Provos if (evcon->bind_address != NULL)
127049868b61SNick Mathewson mm_free(evcon->bind_address);
127198f9616bSNiels Provos
1272a3bb4a03SNiels Provos if (evcon->address != NULL)
127349868b61SNick Mathewson mm_free(evcon->address);
1274a3bb4a03SNiels Provos
127549868b61SNick Mathewson mm_free(evcon);
1276a3bb4a03SNiels Provos }
1277a3bb4a03SNiels Provos
127898f9616bSNiels Provos void
evhttp_connection_free_on_completion(struct evhttp_connection * evcon)12792b9ec4c1SJohn Ohl evhttp_connection_free_on_completion(struct evhttp_connection *evcon) {
12802b9ec4c1SJohn Ohl evcon->flags |= EVHTTP_CON_AUTOFREE;
12812b9ec4c1SJohn Ohl }
12822b9ec4c1SJohn Ohl
12832b9ec4c1SJohn Ohl void
evhttp_connection_set_local_address(struct evhttp_connection * evcon,const char * address)128498f9616bSNiels Provos evhttp_connection_set_local_address(struct evhttp_connection *evcon,
128598f9616bSNiels Provos const char *address)
128698f9616bSNiels Provos {
12872e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
128898f9616bSNiels Provos if (evcon->bind_address)
128949868b61SNick Mathewson mm_free(evcon->bind_address);
129049868b61SNick Mathewson if ((evcon->bind_address = mm_strdup(address)) == NULL)
12913f8d22a1SJardel Weyrich event_warn("%s: strdup", __func__);
129298f9616bSNiels Provos }
129398f9616bSNiels Provos
12945792d42fSNiels Provos void
evhttp_connection_set_local_port(struct evhttp_connection * evcon,ev_uint16_t port)12955792d42fSNiels Provos evhttp_connection_set_local_port(struct evhttp_connection *evcon,
12965792d42fSNiels Provos ev_uint16_t port)
12975792d42fSNiels Provos {
12982e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
12995792d42fSNiels Provos evcon->bind_port = port;
13005792d42fSNiels Provos }
130198f9616bSNiels Provos
1302942656bbSNiels Provos static void
evhttp_request_dispatch(struct evhttp_connection * evcon)1303ba7262ebSNiels Provos evhttp_request_dispatch(struct evhttp_connection* evcon)
1304ba7262ebSNiels Provos {
1305ba7262ebSNiels Provos struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1306ba7262ebSNiels Provos
1307ba7262ebSNiels Provos /* this should not usually happy but it's possible */
1308ba7262ebSNiels Provos if (req == NULL)
1309ba7262ebSNiels Provos return;
1310ba7262ebSNiels Provos
1311d30e7bbaSAzat Khuzhin EVUTIL_ASSERT(req->kind == EVHTTP_REQUEST);
1312d30e7bbaSAzat Khuzhin
1313942656bbSNiels Provos /* delete possible close detection events */
1314942656bbSNiels Provos evhttp_connection_stop_detectclose(evcon);
1315942656bbSNiels Provos
1316ba7262ebSNiels Provos /* we assume that the connection is connected already */
13172e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
13189998c0cbSNiels Provos
13199998c0cbSNiels Provos evcon->state = EVCON_WRITING;
1320ba7262ebSNiels Provos
1321ba7262ebSNiels Provos /* Create the header from the store arguments */
1322ba7262ebSNiels Provos evhttp_make_header(evcon, req);
1323ba7262ebSNiels Provos
1324ba7262ebSNiels Provos evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
1325ba7262ebSNiels Provos }
1326ba7262ebSNiels Provos
132790b3ed5bSNick Mathewson /* Reset our connection state: disables reading/writing, closes our fd (if
132890b3ed5bSNick Mathewson * any), clears out buffers, and puts us in state DISCONNECTED. */
1329ba7262ebSNiels Provos void
evhttp_connection_reset_(struct evhttp_connection * evcon)13308ac3c4c2SNick Mathewson evhttp_connection_reset_(struct evhttp_connection *evcon)
1331ba7262ebSNiels Provos {
13325e796901SNiels Provos struct evbuffer *tmp;
13337c899995SAzat Khuzhin int err;
13345e796901SNiels Provos
13357e91622bSAzat Khuzhin bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL);
13367e91622bSAzat Khuzhin
1337c8baac90SNick Mathewson /* XXXX This is not actually an optimal fix. Instead we ought to have
1338c8baac90SNick Mathewson an API for "stop connecting", or use bufferevent_setfd to turn off
1339c8baac90SNick Mathewson connecting. But for Libevent 2.0, this seems like a minimal change
1340c8baac90SNick Mathewson least likely to disrupt the rest of the bufferevent and http code.
1341c8baac90SNick Mathewson
1342c8baac90SNick Mathewson Why is this here? If the fd is set in the bufferevent, and the
1343c8baac90SNick Mathewson bufferevent is connecting, then you can't actually stop the
1344c8baac90SNick Mathewson bufferevent from trying to connect with bufferevent_disable(). The
1345c8baac90SNick Mathewson connect will never trigger, since we close the fd, but the timeout
13468ac3c4c2SNick Mathewson might. That caused an assertion failure in evhttp_connection_fail_.
1347c8baac90SNick Mathewson */
13488ac3c4c2SNick Mathewson bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE);
1349ba7262ebSNiels Provos
13504a53c54bSAzat Khuzhin if (evcon->fd == -1)
13514a53c54bSAzat Khuzhin evcon->fd = bufferevent_getfd(evcon->bufev);
13524a53c54bSAzat Khuzhin
1353ba7262ebSNiels Provos if (evcon->fd != -1) {
1354de7db33aSNiels Provos /* inform interested parties about connection close */
13559998c0cbSNiels Provos if (evhttp_connected(evcon) && evcon->closecb != NULL)
1356de7db33aSNiels Provos (*evcon->closecb)(evcon, evcon->closecb_arg);
1357de7db33aSNiels Provos
1358145f221eSNick Mathewson shutdown(evcon->fd, EVUTIL_SHUT_WR);
1359899c1dccSSebastian Sjöberg evutil_closesocket(evcon->fd);
1360ba7262ebSNiels Provos evcon->fd = -1;
1361ba7262ebSNiels Provos }
1362a8cc449eSAzat Khuzhin err = bufferevent_setfd(evcon->bufev, -1);
1363a8cc449eSAzat Khuzhin EVUTIL_ASSERT(!err && "setfd");
13645e796901SNiels Provos
13655e796901SNiels Provos /* we need to clean up any buffered data */
13665e796901SNiels Provos tmp = bufferevent_get_output(evcon->bufev);
13677c899995SAzat Khuzhin err = evbuffer_drain(tmp, -1);
13687c899995SAzat Khuzhin EVUTIL_ASSERT(!err && "drain output");
13695e796901SNiels Provos tmp = bufferevent_get_input(evcon->bufev);
13707c899995SAzat Khuzhin err = evbuffer_drain(tmp, -1);
13717c899995SAzat Khuzhin EVUTIL_ASSERT(!err && "drain input");
13725e796901SNiels Provos
1373d4054928SAzat Khuzhin evcon->flags &= ~EVHTTP_CON_READING_ERROR;
1374d4054928SAzat Khuzhin
1375ba7262ebSNiels Provos evcon->state = EVCON_DISCONNECTED;
1376942656bbSNiels Provos }
1377942656bbSNiels Provos
1378942656bbSNiels Provos static void
evhttp_connection_start_detectclose(struct evhttp_connection * evcon)1379942656bbSNiels Provos evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
1380942656bbSNiels Provos {
1381942656bbSNiels Provos evcon->flags |= EVHTTP_CON_CLOSEDETECT;
1382f700566cSNiels Provos bufferevent_enable(evcon->bufev, EV_READ);
1383942656bbSNiels Provos }
1384942656bbSNiels Provos
1385942656bbSNiels Provos static void
evhttp_connection_stop_detectclose(struct evhttp_connection * evcon)1386942656bbSNiels Provos evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
1387942656bbSNiels Provos {
13880faaa395SNick Mathewson evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
1389f700566cSNiels Provos bufferevent_disable(evcon->bufev, EV_READ);
1390ba7262ebSNiels Provos }
1391ba7262ebSNiels Provos
1392852d05a3SNiels Provos static void
evhttp_connection_retry(evutil_socket_t fd,short what,void * arg)13931120f04fSNick Mathewson evhttp_connection_retry(evutil_socket_t fd, short what, void *arg)
1394852d05a3SNiels Provos {
1395852d05a3SNiels Provos struct evhttp_connection *evcon = arg;
1396852d05a3SNiels Provos
1397852d05a3SNiels Provos evcon->state = EVCON_DISCONNECTED;
13988ac3c4c2SNick Mathewson evhttp_connection_connect_(evcon);
1399852d05a3SNiels Provos }
1400852d05a3SNiels Provos
1401e44ef375SNiels Provos static void
evhttp_connection_cb_cleanup(struct evhttp_connection * evcon)1402e44ef375SNiels Provos evhttp_connection_cb_cleanup(struct evhttp_connection *evcon)
1403e44ef375SNiels Provos {
1404218cf197STomash Brechko struct evcon_requestq requests;
1405218cf197STomash Brechko
1406bc79cc5cSAzat Khuzhin evhttp_connection_reset_(evcon);
1407e44ef375SNiels Provos if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
1408350a3c40SNick Mathewson struct timeval tv_retry = evcon->initial_retry_timeout;
1409350a3c40SNick Mathewson int i;
14105fbc7f0aSNick Mathewson evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon);
1411ff3f6cd4SNick Mathewson /* XXXX handle failure from evhttp_add_event */
1412350a3c40SNick Mathewson for (i=0; i < evcon->retry_cnt; ++i) {
1413350a3c40SNick Mathewson tv_retry.tv_usec *= 2;
1414350a3c40SNick Mathewson if (tv_retry.tv_usec > 1000000) {
1415350a3c40SNick Mathewson tv_retry.tv_usec -= 1000000;
1416350a3c40SNick Mathewson tv_retry.tv_sec += 1;
1417350a3c40SNick Mathewson }
1418350a3c40SNick Mathewson tv_retry.tv_sec *= 2;
1419350a3c40SNick Mathewson if (tv_retry.tv_sec > 3600) {
1420350a3c40SNick Mathewson tv_retry.tv_sec = 3600;
1421350a3c40SNick Mathewson tv_retry.tv_usec = 0;
1422350a3c40SNick Mathewson }
1423350a3c40SNick Mathewson }
1424350a3c40SNick Mathewson event_add(&evcon->retry_ev, &tv_retry);
1425e44ef375SNiels Provos evcon->retry_cnt++;
1426e44ef375SNiels Provos return;
1427e44ef375SNiels Provos }
1428e44ef375SNiels Provos
1429218cf197STomash Brechko /*
1430218cf197STomash Brechko * User callback can do evhttp_make_request() on the same
1431218cf197STomash Brechko * evcon so new request will be added to evcon->requests. To
1432218cf197STomash Brechko * avoid freeing it prematurely we iterate over the copy of
1433218cf197STomash Brechko * the queue.
1434218cf197STomash Brechko */
1435218cf197STomash Brechko TAILQ_INIT(&requests);
1436e44ef375SNiels Provos while (TAILQ_FIRST(&evcon->requests) != NULL) {
1437e44ef375SNiels Provos struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
1438e44ef375SNiels Provos TAILQ_REMOVE(&evcon->requests, request, next);
1439218cf197STomash Brechko TAILQ_INSERT_TAIL(&requests, request, next);
1440218cf197STomash Brechko }
1441218cf197STomash Brechko
1442218cf197STomash Brechko /* for now, we just signal all requests by executing their callbacks */
1443218cf197STomash Brechko while (TAILQ_FIRST(&requests) != NULL) {
1444218cf197STomash Brechko struct evhttp_request *request = TAILQ_FIRST(&requests);
1445218cf197STomash Brechko TAILQ_REMOVE(&requests, request, next);
1446e44ef375SNiels Provos request->evcon = NULL;
1447e44ef375SNiels Provos
1448e44ef375SNiels Provos /* we might want to set an error here */
1449e44ef375SNiels Provos request->cb(request, request->cb_arg);
1450b0d3964fSAzat Khuzhin evhttp_request_free_auto(request);
1451e44ef375SNiels Provos }
1452e44ef375SNiels Provos }
1453e44ef375SNiels Provos
1454e44ef375SNiels Provos static void
evhttp_connection_read_on_write_error(struct evhttp_connection * evcon,struct evhttp_request * req)1455680742e1SAzat Khuzhin evhttp_connection_read_on_write_error(struct evhttp_connection *evcon,
1456680742e1SAzat Khuzhin struct evhttp_request *req)
1457680742e1SAzat Khuzhin {
1458680742e1SAzat Khuzhin struct evbuffer *buf;
1459680742e1SAzat Khuzhin
1460d4054928SAzat Khuzhin /** Second time, we can't read anything */
1461d4054928SAzat Khuzhin if (evcon->flags & EVHTTP_CON_READING_ERROR) {
1462d4054928SAzat Khuzhin evcon->flags &= ~EVHTTP_CON_READING_ERROR;
1463d4054928SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
1464d4054928SAzat Khuzhin return;
1465d4054928SAzat Khuzhin }
1466d4054928SAzat Khuzhin
1467680742e1SAzat Khuzhin req->kind = EVHTTP_RESPONSE;
1468680742e1SAzat Khuzhin
1469680742e1SAzat Khuzhin buf = bufferevent_get_output(evcon->bufev);
1470680742e1SAzat Khuzhin evbuffer_unfreeze(buf, 1);
1471680742e1SAzat Khuzhin evbuffer_drain(buf, evbuffer_get_length(buf));
1472680742e1SAzat Khuzhin evbuffer_freeze(buf, 1);
1473680742e1SAzat Khuzhin
1474d4054928SAzat Khuzhin evhttp_start_read_(evcon);
14752ff164abSAzat Khuzhin evcon->flags |= EVHTTP_CON_READING_ERROR;
1476680742e1SAzat Khuzhin }
1477680742e1SAzat Khuzhin
1478680742e1SAzat Khuzhin static void
evhttp_error_cb(struct bufferevent * bufev,short what,void * arg)1479e44ef375SNiels Provos evhttp_error_cb(struct bufferevent *bufev, short what, void *arg)
1480e44ef375SNiels Provos {
1481e44ef375SNiels Provos struct evhttp_connection *evcon = arg;
14829998c0cbSNiels Provos struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
1483e44ef375SNiels Provos
148471e709c7SAzat Khuzhin if (evcon->fd == -1)
148571e709c7SAzat Khuzhin evcon->fd = bufferevent_getfd(bufev);
148671e709c7SAzat Khuzhin
1487e44ef375SNiels Provos switch (evcon->state) {
1488e44ef375SNiels Provos case EVCON_CONNECTING:
148904861d5eSNick Mathewson if (what & BEV_EVENT_TIMEOUT) {
149062bd2c44SNick Mathewson event_debug(("%s: connection timeout for \"%s:%d\" on "
149162bd2c44SNick Mathewson EV_SOCK_FMT,
1492e44ef375SNiels Provos __func__, evcon->address, evcon->port,
149362bd2c44SNick Mathewson EV_SOCK_ARG(evcon->fd)));
1494e44ef375SNiels Provos evhttp_connection_cb_cleanup(evcon);
1495e44ef375SNiels Provos return;
1496e44ef375SNiels Provos }
1497e44ef375SNiels Provos break;
1498e44ef375SNiels Provos
14999998c0cbSNiels Provos case EVCON_READING_BODY:
15009998c0cbSNiels Provos if (!req->chunked && req->ntoread < 0
150183f46e51SNick Mathewson && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) {
1502e44ef375SNiels Provos /* EOF on read can be benign */
1503e44ef375SNiels Provos evhttp_connection_done(evcon);
1504e44ef375SNiels Provos return;
1505e44ef375SNiels Provos }
1506e44ef375SNiels Provos break;
1507e44ef375SNiels Provos
1508e44ef375SNiels Provos case EVCON_DISCONNECTED:
15099998c0cbSNiels Provos case EVCON_IDLE:
15109998c0cbSNiels Provos case EVCON_READING_FIRSTLINE:
15119998c0cbSNiels Provos case EVCON_READING_HEADERS:
15129998c0cbSNiels Provos case EVCON_READING_TRAILER:
15139998c0cbSNiels Provos case EVCON_WRITING:
1514e44ef375SNiels Provos default:
1515e44ef375SNiels Provos break;
1516e44ef375SNiels Provos }
1517e44ef375SNiels Provos
1518f700566cSNiels Provos /* when we are in close detect mode, a read error means that
1519f700566cSNiels Provos * the other side closed their connection.
1520f700566cSNiels Provos */
1521f700566cSNiels Provos if (evcon->flags & EVHTTP_CON_CLOSEDETECT) {
1522f700566cSNiels Provos evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
15232e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon->http_server == NULL);
1524f700566cSNiels Provos /* For connections from the client, we just
1525f700566cSNiels Provos * reset the connection so that it becomes
1526f700566cSNiels Provos * disconnected.
1527f700566cSNiels Provos */
15282e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon->state == EVCON_IDLE);
15298ac3c4c2SNick Mathewson evhttp_connection_reset_(evcon);
15302b9ec4c1SJohn Ohl
15312b9ec4c1SJohn Ohl /*
15322b9ec4c1SJohn Ohl * If we have no more requests that need completion
15332b9ec4c1SJohn Ohl * and we want to auto-free the connection when all
15342b9ec4c1SJohn Ohl * requests have been completed.
15352b9ec4c1SJohn Ohl */
15362b9ec4c1SJohn Ohl if (TAILQ_FIRST(&evcon->requests) == NULL
15372b9ec4c1SJohn Ohl && (evcon->flags & EVHTTP_CON_OUTGOING)
15382b9ec4c1SJohn Ohl && (evcon->flags & EVHTTP_CON_AUTOFREE)) {
15392b9ec4c1SJohn Ohl evhttp_connection_free(evcon);
15402b9ec4c1SJohn Ohl }
1541f700566cSNiels Provos return;
1542f700566cSNiels Provos }
1543f700566cSNiels Provos
154483f46e51SNick Mathewson if (what & BEV_EVENT_TIMEOUT) {
15457b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT);
154683f46e51SNick Mathewson } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
1547680742e1SAzat Khuzhin if (what & BEV_EVENT_WRITING &&
1548680742e1SAzat Khuzhin evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) {
1549680742e1SAzat Khuzhin evhttp_connection_read_on_write_error(evcon, req);
1550680742e1SAzat Khuzhin return;
1551680742e1SAzat Khuzhin }
1552680742e1SAzat Khuzhin
1553eb7b472bSAzat Khuzhin if (what & BEV_EVENT_READING &&
1554eb7b472bSAzat Khuzhin evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR &&
1555eb7b472bSAzat Khuzhin evbuffer_get_length(bufferevent_get_input(bufev))) {
1556eb7b472bSAzat Khuzhin event_deferred_cb_schedule_(get_deferred_queue(evcon),
1557eb7b472bSAzat Khuzhin &evcon->read_more_deferred_cb);
1558eb7b472bSAzat Khuzhin return;
1559eb7b472bSAzat Khuzhin }
1560eb7b472bSAzat Khuzhin
15617b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
15628d3a8500SNick Mathewson } else if (what == BEV_EVENT_CONNECTED) {
1563e44ef375SNiels Provos } else {
15647b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR);
1565e44ef375SNiels Provos }
1566e44ef375SNiels Provos }
1567e44ef375SNiels Provos
1568a3bb4a03SNiels Provos /*
1569c698b77dSNick Mathewson * Event callback for asynchronous connection attempt.
1570a3bb4a03SNiels Provos */
1571942656bbSNiels Provos static void
evhttp_connection_cb(struct bufferevent * bufev,short what,void * arg)1572c698b77dSNick Mathewson evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
1573a3bb4a03SNiels Provos {
1574a3bb4a03SNiels Provos struct evhttp_connection *evcon = arg;
1575a3bb4a03SNiels Provos int error;
15767c20a6aeSNick Mathewson ev_socklen_t errsz = sizeof(error);
1577a3bb4a03SNiels Provos
157871e709c7SAzat Khuzhin if (evcon->fd == -1)
157971e709c7SAzat Khuzhin evcon->fd = bufferevent_getfd(bufev);
158071e709c7SAzat Khuzhin
1581c698b77dSNick Mathewson if (!(what & BEV_EVENT_CONNECTED)) {
1582c698b77dSNick Mathewson /* some operating systems return ECONNREFUSED immediately
1583c698b77dSNick Mathewson * when connecting to a local address. the cleanup is going
1584c698b77dSNick Mathewson * to reschedule this function call.
1585c698b77dSNick Mathewson */
15869f560bfaSNick Mathewson #ifndef _WIN32
1587c698b77dSNick Mathewson if (errno == ECONNREFUSED)
1588c698b77dSNick Mathewson goto cleanup;
15895c7a7bcaSNick Mathewson #endif
1590c698b77dSNick Mathewson evhttp_error_cb(bufev, what, arg);
1591c698b77dSNick Mathewson return;
1592c698b77dSNick Mathewson }
1593c698b77dSNick Mathewson
1594f22049e3SNick Mathewson if (evcon->fd == -1) {
1595f22049e3SNick Mathewson event_debug(("%s: bufferevent_getfd returned -1",
1596f22049e3SNick Mathewson __func__));
1597f22049e3SNick Mathewson goto cleanup;
1598f22049e3SNick Mathewson }
1599f22049e3SNick Mathewson
1600a3bb4a03SNiels Provos /* Check if the connection completed */
1601868f10e7SNiels Provos if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
1602a3bb4a03SNiels Provos &errsz) == -1) {
160362bd2c44SNick Mathewson event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT,
160462bd2c44SNick Mathewson __func__, evcon->address, evcon->port,
160562bd2c44SNick Mathewson EV_SOCK_ARG(evcon->fd)));
1606a3bb4a03SNiels Provos goto cleanup;
1607a3bb4a03SNiels Provos }
1608a3bb4a03SNiels Provos
1609a3bb4a03SNiels Provos if (error) {
161062bd2c44SNick Mathewson event_debug(("%s: connect failed for \"%s:%d\" on "
161162bd2c44SNick Mathewson EV_SOCK_FMT": %s",
161262bd2c44SNick Mathewson __func__, evcon->address, evcon->port,
161362bd2c44SNick Mathewson EV_SOCK_ARG(evcon->fd),
1614de069b99SNick Mathewson evutil_socket_error_to_string(error)));
1615a3bb4a03SNiels Provos goto cleanup;
1616a3bb4a03SNiels Provos }
1617a3bb4a03SNiels Provos
1618a3bb4a03SNiels Provos /* We are connected to the server now */
161962bd2c44SNick Mathewson event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n",
162062bd2c44SNick Mathewson __func__, evcon->address, evcon->port,
162162bd2c44SNick Mathewson EV_SOCK_ARG(evcon->fd)));
1622a3bb4a03SNiels Provos
1623852d05a3SNiels Provos /* Reset the retry count as we were successful in connecting */
1624852d05a3SNiels Provos evcon->retry_cnt = 0;
16259998c0cbSNiels Provos evcon->state = EVCON_IDLE;
1626e44ef375SNiels Provos
1627e44ef375SNiels Provos /* reset the bufferevent cbs */
1628e44ef375SNiels Provos bufferevent_setcb(evcon->bufev,
16299998c0cbSNiels Provos evhttp_read_cb,
1630e44ef375SNiels Provos evhttp_write_cb,
1631e44ef375SNiels Provos evhttp_error_cb,
1632e44ef375SNiels Provos evcon);
1633e44ef375SNiels Provos
16346350e6c4SConstantine Verutin if (!evutil_timerisset(&evcon->timeout)) {
16354d637583SNick Mathewson const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
16364d637583SNick Mathewson const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
16374d637583SNick Mathewson bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
16386350e6c4SConstantine Verutin } else {
16396350e6c4SConstantine Verutin bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
16405a3eddf0SNick Mathewson }
1641ba7262ebSNiels Provos
1642ba7262ebSNiels Provos /* try to start requests that have queued up on this connection */
1643ba7262ebSNiels Provos evhttp_request_dispatch(evcon);
1644a3bb4a03SNiels Provos return;
1645a3bb4a03SNiels Provos
1646a3bb4a03SNiels Provos cleanup:
1647e44ef375SNiels Provos evhttp_connection_cb_cleanup(evcon);
1648a3bb4a03SNiels Provos }
1649a3bb4a03SNiels Provos
1650a3bb4a03SNiels Provos /*
1651a3bb4a03SNiels Provos * Check if we got a valid response code.
1652a3bb4a03SNiels Provos */
1653a3bb4a03SNiels Provos
1654a3f122d6SNick Mathewson static int
evhttp_valid_response_code(int code)1655a3bb4a03SNiels Provos evhttp_valid_response_code(int code)
1656a3bb4a03SNiels Provos {
1657a3bb4a03SNiels Provos if (code == 0)
1658a3bb4a03SNiels Provos return (0);
1659a3bb4a03SNiels Provos
1660a3bb4a03SNiels Provos return (1);
1661a3bb4a03SNiels Provos }
1662a3bb4a03SNiels Provos
1663a38140beSNick Mathewson static int
evhttp_parse_http_version(const char * version,struct evhttp_request * req)1664a38140beSNick Mathewson evhttp_parse_http_version(const char *version, struct evhttp_request *req)
1665a38140beSNick Mathewson {
1666a38140beSNick Mathewson int major, minor;
1667a38140beSNick Mathewson char ch;
1668a38140beSNick Mathewson int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch);
1669790f6b3bSCatalin Patulea if (n != 2 || major > 1) {
1670a38140beSNick Mathewson event_debug(("%s: bad version %s on message %p from %s",
1671a38140beSNick Mathewson __func__, version, req, req->remote_host));
1672a38140beSNick Mathewson return (-1);
1673a38140beSNick Mathewson }
1674a38140beSNick Mathewson req->major = major;
1675a38140beSNick Mathewson req->minor = minor;
1676a38140beSNick Mathewson return (0);
1677a38140beSNick Mathewson }
1678a38140beSNick Mathewson
1679a3bb4a03SNiels Provos /* Parses the status line of a web server */
1680a3bb4a03SNiels Provos
1681a3f122d6SNick Mathewson static int
evhttp_parse_response_line(struct evhttp_request * req,char * line)1682a3bb4a03SNiels Provos evhttp_parse_response_line(struct evhttp_request *req, char *line)
1683a3bb4a03SNiels Provos {
1684a3bb4a03SNiels Provos char *protocol;
1685a3bb4a03SNiels Provos char *number;
1686bd1ed5f3SSebastian Hahn const char *readable = "";
1687a3bb4a03SNiels Provos
1688a3bb4a03SNiels Provos protocol = strsep(&line, " ");
1689a3bb4a03SNiels Provos if (line == NULL)
1690a3bb4a03SNiels Provos return (-1);
1691a3bb4a03SNiels Provos number = strsep(&line, " ");
1692739e6882SPierre Phaneuf if (line != NULL)
1693a3bb4a03SNiels Provos readable = line;
1694a3bb4a03SNiels Provos
1695a38140beSNick Mathewson if (evhttp_parse_http_version(protocol, req) < 0)
1696a3bb4a03SNiels Provos return (-1);
1697a3bb4a03SNiels Provos
1698a3bb4a03SNiels Provos req->response_code = atoi(number);
1699a3bb4a03SNiels Provos if (!evhttp_valid_response_code(req->response_code)) {
1700ff9e1af6SNiels Provos event_debug(("%s: bad response code \"%s\"",
1701ff9e1af6SNiels Provos __func__, number));
1702a3bb4a03SNiels Provos return (-1);
1703a3bb4a03SNiels Provos }
1704a3bb4a03SNiels Provos
17058f18a626SAzat Khuzhin if (req->response_code_line != NULL)
17068f18a626SAzat Khuzhin mm_free(req->response_code_line);
1707f1691539SNiels Provos if ((req->response_code_line = mm_strdup(readable)) == NULL) {
1708f1691539SNiels Provos event_warn("%s: strdup", __func__);
1709f1691539SNiels Provos return (-1);
1710f1691539SNiels Provos }
1711a3bb4a03SNiels Provos
1712a3bb4a03SNiels Provos return (0);
1713a3bb4a03SNiels Provos }
1714a3bb4a03SNiels Provos
1715a3bb4a03SNiels Provos /* Parse the first line of a HTTP request */
1716a3bb4a03SNiels Provos
1717a3f122d6SNick Mathewson static int
evhttp_parse_request_line(struct evhttp_request * req,char * line,size_t len)1718cdcfbafeSAzat Khuzhin evhttp_parse_request_line(struct evhttp_request *req, char *line, size_t len)
1719a3bb4a03SNiels Provos {
1720cdcfbafeSAzat Khuzhin char *eos = line + len;
1721a3bb4a03SNiels Provos char *method;
1722a3bb4a03SNiels Provos char *uri;
1723a3bb4a03SNiels Provos char *version;
1724aab8c38bSChristopher Davis const char *hostname;
1725aab8c38bSChristopher Davis const char *scheme;
1726aee1a97dSMark Ellzey size_t method_len;
1727aee1a97dSMark Ellzey enum evhttp_cmd_type type;
1728a3bb4a03SNiels Provos
1729cdcfbafeSAzat Khuzhin while (eos > line && *(eos-1) == ' ') {
1730cdcfbafeSAzat Khuzhin *(eos-1) = '\0';
1731cdcfbafeSAzat Khuzhin --eos;
1732cdcfbafeSAzat Khuzhin --len;
1733cdcfbafeSAzat Khuzhin }
1734cdcfbafeSAzat Khuzhin if (len < strlen("GET / HTTP/1.0"))
1735cdcfbafeSAzat Khuzhin return -1;
1736cdcfbafeSAzat Khuzhin
1737a3bb4a03SNiels Provos /* Parse the request line */
1738a3bb4a03SNiels Provos method = strsep(&line, " ");
1739cdcfbafeSAzat Khuzhin if (!line)
1740cdcfbafeSAzat Khuzhin return -1;
1741cdcfbafeSAzat Khuzhin uri = line;
1742cdcfbafeSAzat Khuzhin version = strrchr(uri, ' ');
1743cdcfbafeSAzat Khuzhin if (!version || uri == version)
1744cdcfbafeSAzat Khuzhin return -1;
1745cdcfbafeSAzat Khuzhin *version = '\0';
1746cdcfbafeSAzat Khuzhin version++;
1747a3bb4a03SNiels Provos
1748aee1a97dSMark Ellzey method_len = (uri - method) - 1;
1749cb9da0bfSNick Mathewson type = EVHTTP_REQ_UNKNOWN_;
1750aee1a97dSMark Ellzey
1751a3bb4a03SNiels Provos /* First line */
1752aee1a97dSMark Ellzey switch (method_len) {
1753aee1a97dSMark Ellzey case 3:
1754aee1a97dSMark Ellzey /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */
1755aee1a97dSMark Ellzey
1756aee1a97dSMark Ellzey /* Since both GET and PUT share the same character 'T' at the end,
1757aee1a97dSMark Ellzey * if the string doesn't have 'T', we can immediately determine this
1758aee1a97dSMark Ellzey * is an invalid HTTP method */
1759aee1a97dSMark Ellzey
1760aee1a97dSMark Ellzey if (method[2] != 'T') {
1761aee1a97dSMark Ellzey break;
1762aee1a97dSMark Ellzey }
1763aee1a97dSMark Ellzey
1764aee1a97dSMark Ellzey switch (*method) {
1765aee1a97dSMark Ellzey case 'G':
1766aee1a97dSMark Ellzey /* This first byte is 'G', so make sure the next byte is
1767aee1a97dSMark Ellzey * 'E', if it isn't then this isn't a valid method */
1768aee1a97dSMark Ellzey
1769aee1a97dSMark Ellzey if (method[1] == 'E') {
1770aee1a97dSMark Ellzey type = EVHTTP_REQ_GET;
1771aee1a97dSMark Ellzey }
1772aee1a97dSMark Ellzey
1773aee1a97dSMark Ellzey break;
1774aee1a97dSMark Ellzey case 'P':
1775aee1a97dSMark Ellzey /* First byte is P, check second byte for 'U', if not,
1776aee1a97dSMark Ellzey * we know it's an invalid method */
1777aee1a97dSMark Ellzey if (method[1] == 'U') {
1778aee1a97dSMark Ellzey type = EVHTTP_REQ_PUT;
1779aee1a97dSMark Ellzey }
1780aee1a97dSMark Ellzey break;
1781aee1a97dSMark Ellzey default:
1782aee1a97dSMark Ellzey break;
1783aee1a97dSMark Ellzey }
1784aee1a97dSMark Ellzey break;
1785aee1a97dSMark Ellzey case 4:
1786aee1a97dSMark Ellzey /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */
1787aee1a97dSMark Ellzey switch (*method) {
1788aee1a97dSMark Ellzey case 'P':
1789aee1a97dSMark Ellzey if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') {
1790aee1a97dSMark Ellzey type = EVHTTP_REQ_POST;
1791aee1a97dSMark Ellzey }
1792aee1a97dSMark Ellzey break;
1793aee1a97dSMark Ellzey case 'H':
1794aee1a97dSMark Ellzey if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') {
1795aee1a97dSMark Ellzey type = EVHTTP_REQ_HEAD;
1796aee1a97dSMark Ellzey }
1797aee1a97dSMark Ellzey break;
1798aee1a97dSMark Ellzey default:
1799aee1a97dSMark Ellzey break;
1800aee1a97dSMark Ellzey }
18010fcc536bSNick Mathewson break;
1802aee1a97dSMark Ellzey case 5:
1803aee1a97dSMark Ellzey /* Method length is 5 bytes, which can only encompass PATCH and TRACE */
1804aee1a97dSMark Ellzey switch (*method) {
1805aee1a97dSMark Ellzey case 'P':
1806aee1a97dSMark Ellzey if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') {
1807aee1a97dSMark Ellzey type = EVHTTP_REQ_PATCH;
1808aee1a97dSMark Ellzey }
1809aee1a97dSMark Ellzey break;
1810aee1a97dSMark Ellzey case 'T':
1811aee1a97dSMark Ellzey if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') {
1812aee1a97dSMark Ellzey type = EVHTTP_REQ_TRACE;
1813aee1a97dSMark Ellzey }
1814aee1a97dSMark Ellzey
1815aee1a97dSMark Ellzey break;
1816aee1a97dSMark Ellzey default:
1817aee1a97dSMark Ellzey break;
1818aee1a97dSMark Ellzey }
1819aee1a97dSMark Ellzey break;
1820aee1a97dSMark Ellzey case 6:
1821aee1a97dSMark Ellzey /* Method length is 6, only valid method 6 bytes in length is DELEte */
1822aee1a97dSMark Ellzey
1823aee1a97dSMark Ellzey /* If the first byte isn't 'D' then it's invalid */
1824aee1a97dSMark Ellzey if (*method != 'D') {
1825aee1a97dSMark Ellzey break;
1826aee1a97dSMark Ellzey }
1827aee1a97dSMark Ellzey
1828aee1a97dSMark Ellzey if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') {
1829aee1a97dSMark Ellzey type = EVHTTP_REQ_DELETE;
1830aee1a97dSMark Ellzey }
1831aee1a97dSMark Ellzey
1832aee1a97dSMark Ellzey break;
1833aee1a97dSMark Ellzey case 7:
1834aee1a97dSMark Ellzey /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */
1835aee1a97dSMark Ellzey switch (*method) {
1836aee1a97dSMark Ellzey case 'O':
1837aee1a97dSMark Ellzey if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' &&
1838aee1a97dSMark Ellzey method[3] == 'I' && method[2] == 'T' && method[1] == 'P') {
1839aee1a97dSMark Ellzey type = EVHTTP_REQ_OPTIONS;
1840aee1a97dSMark Ellzey }
1841aee1a97dSMark Ellzey
1842aee1a97dSMark Ellzey break;
1843aee1a97dSMark Ellzey case 'C':
1844aee1a97dSMark Ellzey if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' &&
1845aee1a97dSMark Ellzey method[3] == 'N' && method[2] == 'N' && method[1] == 'O') {
1846aee1a97dSMark Ellzey type = EVHTTP_REQ_CONNECT;
1847aee1a97dSMark Ellzey }
1848aee1a97dSMark Ellzey
1849aee1a97dSMark Ellzey break;
1850aee1a97dSMark Ellzey default:
1851aee1a97dSMark Ellzey break;
1852aee1a97dSMark Ellzey }
1853aee1a97dSMark Ellzey break;
1854aee1a97dSMark Ellzey } /* switch */
1855aee1a97dSMark Ellzey
1856b452a434SSebastian Hahn if ((int)type == EVHTTP_REQ_UNKNOWN_) {
1857ff9e1af6SNiels Provos event_debug(("%s: bad method %s on request %p from %s",
1858ff9e1af6SNiels Provos __func__, method, req, req->remote_host));
1859536311a4SNick Mathewson /* No error yet; we'll give a better error later when
1860536311a4SNick Mathewson * we see that req->type is unsupported. */
1861a3bb4a03SNiels Provos }
1862a3bb4a03SNiels Provos
1863aee1a97dSMark Ellzey req->type = type;
1864aee1a97dSMark Ellzey
1865a38140beSNick Mathewson if (evhttp_parse_http_version(version, req) < 0)
1866cdcfbafeSAzat Khuzhin return -1;
1867a3bb4a03SNiels Provos
186849868b61SNick Mathewson if ((req->uri = mm_strdup(uri)) == NULL) {
1869f1691539SNiels Provos event_debug(("%s: mm_strdup", __func__));
1870cdcfbafeSAzat Khuzhin return -1;
1871a3bb4a03SNiels Provos }
1872a3bb4a03SNiels Provos
18737d1ffe64SGreg Hazel if (type == EVHTTP_REQ_CONNECT) {
18747d1ffe64SGreg Hazel if ((req->uri_elems = evhttp_uri_parse_authority(req->uri)) == NULL) {
18757d1ffe64SGreg Hazel return -1;
18767d1ffe64SGreg Hazel }
18777d1ffe64SGreg Hazel } else {
187895060b54SNick Mathewson if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri,
187995060b54SNick Mathewson EVHTTP_URI_NONCONFORMANT)) == NULL) {
1880aab8c38bSChristopher Davis return -1;
1881aab8c38bSChristopher Davis }
18827d1ffe64SGreg Hazel }
1883aab8c38bSChristopher Davis
1884aab8c38bSChristopher Davis /* If we have an absolute-URI, check to see if it is an http request
1885aab8c38bSChristopher Davis for a known vhost or server alias. If we don't know about this
1886aab8c38bSChristopher Davis host, we consider it a proxy request. */
1887aab8c38bSChristopher Davis scheme = evhttp_uri_get_scheme(req->uri_elems);
1888aab8c38bSChristopher Davis hostname = evhttp_uri_get_host(req->uri_elems);
1889aab8c38bSChristopher Davis if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") ||
1890aab8c38bSChristopher Davis !evutil_ascii_strcasecmp(scheme, "https")) &&
1891aab8c38bSChristopher Davis hostname &&
1892aab8c38bSChristopher Davis !evhttp_find_vhost(req->evcon->http_server, NULL, hostname))
1893fe266238SNiels Provos req->flags |= EVHTTP_PROXY_REQUEST;
1894fe266238SNiels Provos
1895cdcfbafeSAzat Khuzhin return 0;
1896a3bb4a03SNiels Provos }
1897a3bb4a03SNiels Provos
189838b33048SNiels Provos const char *
evhttp_find_header(const struct evkeyvalq * headers,const char * key)189936212f9dSNiels Provos evhttp_find_header(const struct evkeyvalq *headers, const char *key)
1900a3bb4a03SNiels Provos {
1901a3bb4a03SNiels Provos struct evkeyval *header;
1902a3bb4a03SNiels Provos
1903a3bb4a03SNiels Provos TAILQ_FOREACH(header, headers, next) {
190472ea534fSNick Mathewson if (evutil_ascii_strcasecmp(header->key, key) == 0)
1905a3bb4a03SNiels Provos return (header->value);
1906a3bb4a03SNiels Provos }
1907a3bb4a03SNiels Provos
1908a3bb4a03SNiels Provos return (NULL);
1909a3bb4a03SNiels Provos }
1910a3bb4a03SNiels Provos
1911a3bb4a03SNiels Provos void
evhttp_clear_headers(struct evkeyvalq * headers)1912a3bb4a03SNiels Provos evhttp_clear_headers(struct evkeyvalq *headers)
1913a3bb4a03SNiels Provos {
1914a3bb4a03SNiels Provos struct evkeyval *header;
1915a3bb4a03SNiels Provos
1916a3bb4a03SNiels Provos for (header = TAILQ_FIRST(headers);
1917a3bb4a03SNiels Provos header != NULL;
1918a3bb4a03SNiels Provos header = TAILQ_FIRST(headers)) {
1919a3bb4a03SNiels Provos TAILQ_REMOVE(headers, header, next);
192049868b61SNick Mathewson mm_free(header->key);
192149868b61SNick Mathewson mm_free(header->value);
192249868b61SNick Mathewson mm_free(header);
1923a3bb4a03SNiels Provos }
1924a3bb4a03SNiels Provos }
1925a3bb4a03SNiels Provos
192638b33048SNiels Provos /*
192738b33048SNiels Provos * Returns 0, if the header was successfully removed.
192838b33048SNiels Provos * Returns -1, if the header could not be found.
192938b33048SNiels Provos */
193038b33048SNiels Provos
193138b33048SNiels Provos int
evhttp_remove_header(struct evkeyvalq * headers,const char * key)1932a3bb4a03SNiels Provos evhttp_remove_header(struct evkeyvalq *headers, const char *key)
1933a3bb4a03SNiels Provos {
1934a3bb4a03SNiels Provos struct evkeyval *header;
1935a3bb4a03SNiels Provos
1936a3bb4a03SNiels Provos TAILQ_FOREACH(header, headers, next) {
193772ea534fSNick Mathewson if (evutil_ascii_strcasecmp(header->key, key) == 0)
1938a3bb4a03SNiels Provos break;
1939a3bb4a03SNiels Provos }
1940a3bb4a03SNiels Provos
1941a3bb4a03SNiels Provos if (header == NULL)
194238b33048SNiels Provos return (-1);
1943a3bb4a03SNiels Provos
1944a3bb4a03SNiels Provos /* Free and remove the header that we found */
1945a3bb4a03SNiels Provos TAILQ_REMOVE(headers, header, next);
194649868b61SNick Mathewson mm_free(header->key);
194749868b61SNick Mathewson mm_free(header->value);
194849868b61SNick Mathewson mm_free(header);
194938b33048SNiels Provos
195038b33048SNiels Provos return (0);
1951a3bb4a03SNiels Provos }
1952a3bb4a03SNiels Provos
1953ce146eb1SNiels Provos static int
evhttp_header_is_valid_value(const char * value)1954ce146eb1SNiels Provos evhttp_header_is_valid_value(const char *value)
1955ce146eb1SNiels Provos {
1956ce146eb1SNiels Provos const char *p = value;
1957ce146eb1SNiels Provos
1958ce146eb1SNiels Provos while ((p = strpbrk(p, "\r\n")) != NULL) {
1959ce146eb1SNiels Provos /* we really expect only one new line */
1960ce146eb1SNiels Provos p += strspn(p, "\r\n");
1961ce146eb1SNiels Provos /* we expect a space or tab for continuation */
1962ce146eb1SNiels Provos if (*p != ' ' && *p != '\t')
1963ce146eb1SNiels Provos return (0);
1964ce146eb1SNiels Provos }
1965ce146eb1SNiels Provos return (1);
1966ce146eb1SNiels Provos }
1967ce146eb1SNiels Provos
1968a3bb4a03SNiels Provos int
evhttp_add_header(struct evkeyvalq * headers,const char * key,const char * value)1969d7918e79SNiels Provos evhttp_add_header(struct evkeyvalq *headers,
1970d7918e79SNiels Provos const char *key, const char *value)
1971a3bb4a03SNiels Provos {
1972073d3590SNiels Provos event_debug(("%s: key: %s val: %s\n", __func__, key, value));
1973073d3590SNiels Provos
1974ce146eb1SNiels Provos if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
1975d7918e79SNiels Provos /* drop illegal headers */
1976ce146eb1SNiels Provos event_debug(("%s: dropping illegal header key\n", __func__));
1977d7918e79SNiels Provos return (-1);
1978d7918e79SNiels Provos }
1979d7918e79SNiels Provos
1980ce146eb1SNiels Provos if (!evhttp_header_is_valid_value(value)) {
1981e3fd294aSNick Mathewson event_debug(("%s: dropping illegal header value\n", __func__));
1982ce146eb1SNiels Provos return (-1);
1983ce146eb1SNiels Provos }
1984ce146eb1SNiels Provos
1985ce146eb1SNiels Provos return (evhttp_add_header_internal(headers, key, value));
1986ce146eb1SNiels Provos }
1987ce146eb1SNiels Provos
1988ce146eb1SNiels Provos static int
evhttp_add_header_internal(struct evkeyvalq * headers,const char * key,const char * value)1989ce146eb1SNiels Provos evhttp_add_header_internal(struct evkeyvalq *headers,
1990ce146eb1SNiels Provos const char *key, const char *value)
1991ce146eb1SNiels Provos {
1992ce146eb1SNiels Provos struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval));
1993a3bb4a03SNiels Provos if (header == NULL) {
1994a3bb4a03SNiels Provos event_warn("%s: calloc", __func__);
1995a3bb4a03SNiels Provos return (-1);
1996a3bb4a03SNiels Provos }
199749868b61SNick Mathewson if ((header->key = mm_strdup(key)) == NULL) {
199849868b61SNick Mathewson mm_free(header);
1999a3bb4a03SNiels Provos event_warn("%s: strdup", __func__);
2000a3bb4a03SNiels Provos return (-1);
2001a3bb4a03SNiels Provos }
200249868b61SNick Mathewson if ((header->value = mm_strdup(value)) == NULL) {
200349868b61SNick Mathewson mm_free(header->key);
200449868b61SNick Mathewson mm_free(header);
2005a3bb4a03SNiels Provos event_warn("%s: strdup", __func__);
2006a3bb4a03SNiels Provos return (-1);
2007a3bb4a03SNiels Provos }
2008a3bb4a03SNiels Provos
2009a3bb4a03SNiels Provos TAILQ_INSERT_TAIL(headers, header, next);
2010a3bb4a03SNiels Provos
2011a3bb4a03SNiels Provos return (0);
2012a3bb4a03SNiels Provos }
2013a3bb4a03SNiels Provos
2014a3bb4a03SNiels Provos /*
2015a3bb4a03SNiels Provos * Parses header lines from a request or a response into the specified
2016a3bb4a03SNiels Provos * request object given an event buffer.
2017a3bb4a03SNiels Provos *
2018a3bb4a03SNiels Provos * Returns
20199998c0cbSNiels Provos * DATA_CORRUPTED on error
20209998c0cbSNiels Provos * MORE_DATA_EXPECTED when we need to read more headers
20219998c0cbSNiels Provos * ALL_DATA_READ when all headers have been read.
2022a3bb4a03SNiels Provos */
2023a3bb4a03SNiels Provos
20249998c0cbSNiels Provos enum message_read_status
evhttp_parse_firstline_(struct evhttp_request * req,struct evbuffer * buffer)20258ac3c4c2SNick Mathewson evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer)
2026a3bb4a03SNiels Provos {
202711a0a9e4SNiels Provos char *line;
20289998c0cbSNiels Provos enum message_read_status status = ALL_DATA_READ;
20299998c0cbSNiels Provos
2030cdcfbafeSAzat Khuzhin size_t len;
203147bad8abSNick Mathewson /* XXX try */
2032cdcfbafeSAzat Khuzhin line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF);
203347bad8abSNick Mathewson if (line == NULL) {
203447bad8abSNick Mathewson if (req->evcon != NULL &&
203547bad8abSNick Mathewson evbuffer_get_length(buffer) > req->evcon->max_headers_size)
203647bad8abSNick Mathewson return (DATA_TOO_LONG);
203747bad8abSNick Mathewson else
20389998c0cbSNiels Provos return (MORE_DATA_EXPECTED);
203947bad8abSNick Mathewson }
204047bad8abSNick Mathewson
2041cdcfbafeSAzat Khuzhin if (req->evcon != NULL && len > req->evcon->max_headers_size) {
204247bad8abSNick Mathewson mm_free(line);
204347bad8abSNick Mathewson return (DATA_TOO_LONG);
204447bad8abSNick Mathewson }
204547bad8abSNick Mathewson
2046cdcfbafeSAzat Khuzhin req->headers_size = len;
20479998c0cbSNiels Provos
20489998c0cbSNiels Provos switch (req->kind) {
20499998c0cbSNiels Provos case EVHTTP_REQUEST:
2050cdcfbafeSAzat Khuzhin if (evhttp_parse_request_line(req, line, len) == -1)
20519998c0cbSNiels Provos status = DATA_CORRUPTED;
20529998c0cbSNiels Provos break;
20539998c0cbSNiels Provos case EVHTTP_RESPONSE:
20549998c0cbSNiels Provos if (evhttp_parse_response_line(req, line) == -1)
20559998c0cbSNiels Provos status = DATA_CORRUPTED;
20569998c0cbSNiels Provos break;
20579998c0cbSNiels Provos default:
20589998c0cbSNiels Provos status = DATA_CORRUPTED;
20599998c0cbSNiels Provos }
20609998c0cbSNiels Provos
20619998c0cbSNiels Provos mm_free(line);
20629998c0cbSNiels Provos return (status);
20639998c0cbSNiels Provos }
20649998c0cbSNiels Provos
2065cb7c3bd6SNiels Provos static int
evhttp_append_to_last_header(struct evkeyvalq * headers,char * line)2066c6ff3812SNick Mathewson evhttp_append_to_last_header(struct evkeyvalq *headers, char *line)
2067cb7c3bd6SNiels Provos {
2068cb7c3bd6SNiels Provos struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
2069cb7c3bd6SNiels Provos char *newval;
2070cb7c3bd6SNiels Provos size_t old_len, line_len;
2071cb7c3bd6SNiels Provos
2072cb7c3bd6SNiels Provos if (header == NULL)
2073cb7c3bd6SNiels Provos return (-1);
2074cb7c3bd6SNiels Provos
2075cb7c3bd6SNiels Provos old_len = strlen(header->value);
2076c6ff3812SNick Mathewson
2077c6ff3812SNick Mathewson /* Strip space from start and end of line. */
2078c6ff3812SNick Mathewson while (*line == ' ' || *line == '\t')
2079c6ff3812SNick Mathewson ++line;
2080c6ff3812SNick Mathewson evutil_rtrim_lws_(line);
2081c6ff3812SNick Mathewson
2082cb7c3bd6SNiels Provos line_len = strlen(line);
2083cb7c3bd6SNiels Provos
2084c6ff3812SNick Mathewson newval = mm_realloc(header->value, old_len + line_len + 2);
2085cb7c3bd6SNiels Provos if (newval == NULL)
2086cb7c3bd6SNiels Provos return (-1);
2087cb7c3bd6SNiels Provos
2088c6ff3812SNick Mathewson newval[old_len] = ' ';
2089c6ff3812SNick Mathewson memcpy(newval + old_len + 1, line, line_len + 1);
2090cb7c3bd6SNiels Provos header->value = newval;
2091cb7c3bd6SNiels Provos
2092cb7c3bd6SNiels Provos return (0);
2093cb7c3bd6SNiels Provos }
2094cb7c3bd6SNiels Provos
20959998c0cbSNiels Provos enum message_read_status
evhttp_parse_headers_(struct evhttp_request * req,struct evbuffer * buffer)20968ac3c4c2SNick Mathewson evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer)
20979998c0cbSNiels Provos {
209847bad8abSNick Mathewson enum message_read_status errcode = DATA_CORRUPTED;
20999998c0cbSNiels Provos char *line;
21009998c0cbSNiels Provos enum message_read_status status = MORE_DATA_EXPECTED;
2101a3bb4a03SNiels Provos
2102a3bb4a03SNiels Provos struct evkeyvalq* headers = req->input_headers;
2103cdcfbafeSAzat Khuzhin size_t len;
2104cdcfbafeSAzat Khuzhin while ((line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF))
21059998c0cbSNiels Provos != NULL) {
2106a3bb4a03SNiels Provos char *skey, *svalue;
2107a3bb4a03SNiels Provos
2108cdcfbafeSAzat Khuzhin req->headers_size += len;
210947bad8abSNick Mathewson
211047bad8abSNick Mathewson if (req->evcon != NULL &&
211147bad8abSNick Mathewson req->headers_size > req->evcon->max_headers_size) {
211247bad8abSNick Mathewson errcode = DATA_TOO_LONG;
211347bad8abSNick Mathewson goto error;
211447bad8abSNick Mathewson }
211547bad8abSNick Mathewson
211611a0a9e4SNiels Provos if (*line == '\0') { /* Last header - Done */
21179998c0cbSNiels Provos status = ALL_DATA_READ;
211849868b61SNick Mathewson mm_free(line);
2119a3bb4a03SNiels Provos break;
2120a3bb4a03SNiels Provos }
2121a3bb4a03SNiels Provos
2122cb7c3bd6SNiels Provos /* Check if this is a continuation line */
2123cb7c3bd6SNiels Provos if (*line == ' ' || *line == '\t') {
2124cb7c3bd6SNiels Provos if (evhttp_append_to_last_header(headers, line) == -1)
2125cb7c3bd6SNiels Provos goto error;
2126f700566cSNiels Provos mm_free(line);
2127cb7c3bd6SNiels Provos continue;
2128cb7c3bd6SNiels Provos }
2129cb7c3bd6SNiels Provos
2130a3bb4a03SNiels Provos /* Processing of header lines */
213111a0a9e4SNiels Provos svalue = line;
2132a3bb4a03SNiels Provos skey = strsep(&svalue, ":");
2133a3bb4a03SNiels Provos if (svalue == NULL)
213411a0a9e4SNiels Provos goto error;
2135a3bb4a03SNiels Provos
2136a3bb4a03SNiels Provos svalue += strspn(svalue, " ");
2137ac425197SNick Mathewson evutil_rtrim_lws_(svalue);
2138a3bb4a03SNiels Provos
2139a3bb4a03SNiels Provos if (evhttp_add_header(headers, skey, svalue) == -1)
214011a0a9e4SNiels Provos goto error;
2141a3bb4a03SNiels Provos
214249868b61SNick Mathewson mm_free(line);
2143a3bb4a03SNiels Provos }
2144a3bb4a03SNiels Provos
214547bad8abSNick Mathewson if (status == MORE_DATA_EXPECTED) {
214612311ff4SSebastian Hahn if (req->evcon != NULL &&
214712311ff4SSebastian Hahn req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size)
214847bad8abSNick Mathewson return (DATA_TOO_LONG);
214947bad8abSNick Mathewson }
215047bad8abSNick Mathewson
21519998c0cbSNiels Provos return (status);
215211a0a9e4SNiels Provos
215311a0a9e4SNiels Provos error:
215449868b61SNick Mathewson mm_free(line);
215547bad8abSNick Mathewson return (errcode);
2156a3bb4a03SNiels Provos }
2157a3bb4a03SNiels Provos
2158557e0f62SNiels Provos static int
evhttp_get_body_length(struct evhttp_request * req)2159557e0f62SNiels Provos evhttp_get_body_length(struct evhttp_request *req)
2160a3bb4a03SNiels Provos {
2161557e0f62SNiels Provos struct evkeyvalq *headers = req->input_headers;
216238b33048SNiels Provos const char *content_length;
216338b33048SNiels Provos const char *connection;
2164a3bb4a03SNiels Provos
2165a3bb4a03SNiels Provos content_length = evhttp_find_header(headers, "Content-Length");
2166a3bb4a03SNiels Provos connection = evhttp_find_header(headers, "Connection");
2167a3bb4a03SNiels Provos
2168a3bb4a03SNiels Provos if (content_length == NULL && connection == NULL)
2169a3bb4a03SNiels Provos req->ntoread = -1;
2170a3bb4a03SNiels Provos else if (content_length == NULL &&
217172ea534fSNick Mathewson evutil_ascii_strcasecmp(connection, "Close") != 0) {
217223eb38b9SAzat Khuzhin req->ntoread = 0;
2173557e0f62SNiels Provos } else if (content_length == NULL) {
2174a3bb4a03SNiels Provos req->ntoread = -1;
2175557e0f62SNiels Provos } else {
2176557e0f62SNiels Provos char *endp;
2177707f6784SNiels Provos ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
2178707f6784SNiels Provos if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
2179707f6784SNiels Provos event_debug(("%s: illegal content length: %s",
2180707f6784SNiels Provos __func__, content_length));
2181557e0f62SNiels Provos return (-1);
2182557e0f62SNiels Provos }
2183707f6784SNiels Provos req->ntoread = ntoread;
2184557e0f62SNiels Provos }
2185a3bb4a03SNiels Provos
21863203f88cSNick Mathewson event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n",
21873203f88cSNick Mathewson __func__, EV_I64_ARG(req->ntoread),
21883203f88cSNick Mathewson EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev)))));
2189a3bb4a03SNiels Provos
2190557e0f62SNiels Provos return (0);
2191557e0f62SNiels Provos }
2192557e0f62SNiels Provos
2193ec5c5aecSNick Mathewson static int
evhttp_method_may_have_body(enum evhttp_cmd_type type)2194ec5c5aecSNick Mathewson evhttp_method_may_have_body(enum evhttp_cmd_type type)
2195ec5c5aecSNick Mathewson {
2196ec5c5aecSNick Mathewson switch (type) {
2197ec5c5aecSNick Mathewson case EVHTTP_REQ_POST:
2198ec5c5aecSNick Mathewson case EVHTTP_REQ_PUT:
2199ec5c5aecSNick Mathewson case EVHTTP_REQ_PATCH:
220023eb38b9SAzat Khuzhin
2201ec5c5aecSNick Mathewson case EVHTTP_REQ_GET:
2202ec5c5aecSNick Mathewson case EVHTTP_REQ_DELETE:
2203ec5c5aecSNick Mathewson case EVHTTP_REQ_OPTIONS:
2204ec5c5aecSNick Mathewson case EVHTTP_REQ_CONNECT:
220523eb38b9SAzat Khuzhin return 1;
220623eb38b9SAzat Khuzhin
220723eb38b9SAzat Khuzhin case EVHTTP_REQ_TRACE:
220823eb38b9SAzat Khuzhin case EVHTTP_REQ_HEAD:
2209ec5c5aecSNick Mathewson default:
2210ec5c5aecSNick Mathewson return 0;
2211ec5c5aecSNick Mathewson }
2212ec5c5aecSNick Mathewson }
2213ec5c5aecSNick Mathewson
2214557e0f62SNiels Provos static void
evhttp_get_body(struct evhttp_connection * evcon,struct evhttp_request * req)2215557e0f62SNiels Provos evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
2216557e0f62SNiels Provos {
2217557e0f62SNiels Provos const char *xfer_enc;
2218557e0f62SNiels Provos
2219557e0f62SNiels Provos /* If this is a request without a body, then we are done */
2220b14cd655SNiels Provos if (req->kind == EVHTTP_REQUEST &&
2221ec5c5aecSNick Mathewson !evhttp_method_may_have_body(req->type)) {
2222557e0f62SNiels Provos evhttp_connection_done(evcon);
2223557e0f62SNiels Provos return;
2224557e0f62SNiels Provos }
22259998c0cbSNiels Provos evcon->state = EVCON_READING_BODY;
2226557e0f62SNiels Provos xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
222772ea534fSNick Mathewson if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) {
2228557e0f62SNiels Provos req->chunked = 1;
2229557e0f62SNiels Provos req->ntoread = -1;
2230557e0f62SNiels Provos } else {
2231557e0f62SNiels Provos if (evhttp_get_body_length(req) == -1) {
22320b46b39eSAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
2233557e0f62SNiels Provos return;
2234557e0f62SNiels Provos }
2235ec5c5aecSNick Mathewson if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) {
2236ec5c5aecSNick Mathewson /* An incoming request with no content-length and no
2237ec5c5aecSNick Mathewson * transfer-encoding has no body. */
2238ec5c5aecSNick Mathewson evhttp_connection_done(evcon);
2239ec5c5aecSNick Mathewson return;
2240ec5c5aecSNick Mathewson }
2241a3bb4a03SNiels Provos }
2242fa9305f8SChristopher Davis
2243fa9305f8SChristopher Davis /* Should we send a 100 Continue status line? */
22440b46b39eSAzat Khuzhin switch (evhttp_have_expect(req, 1)) {
22450b46b39eSAzat Khuzhin case CONTINUE:
2246fa9305f8SChristopher Davis /* XXX It would be nice to do some sanity
2247fa9305f8SChristopher Davis checking here. Does the resource exist?
2248fa9305f8SChristopher Davis Should the resource accept post requests? If
2249fa9305f8SChristopher Davis no, we should respond with an error. For
2250fa9305f8SChristopher Davis now, just optimistically tell the client to
2251fa9305f8SChristopher Davis send their message body. */
225284560fc4SMark Ellzey if (req->ntoread > 0) {
225384560fc4SMark Ellzey /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */
22540b46b39eSAzat Khuzhin if ((req->evcon->max_body_size <= EV_INT64_MAX) &&
22550b46b39eSAzat Khuzhin (ev_uint64_t)req->ntoread > req->evcon->max_body_size) {
2256ac448a74SAzat Khuzhin evhttp_lingering_fail(evcon, req);
2257d23839fcSConstantine Verutin return;
2258d23839fcSConstantine Verutin }
225984560fc4SMark Ellzey }
2260fa9305f8SChristopher Davis if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev)))
2261fa9305f8SChristopher Davis evhttp_send_continue(evcon, req);
22620b46b39eSAzat Khuzhin break;
22630b46b39eSAzat Khuzhin case OTHER:
22640b46b39eSAzat Khuzhin evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL);
2265fa9305f8SChristopher Davis return;
22660b46b39eSAzat Khuzhin case NO: break;
2267fa9305f8SChristopher Davis }
2268fa9305f8SChristopher Davis
2269ba8289beSNiels Provos evhttp_read_body(evcon, req);
2270344c2b56SNiels Provos /* note the request may have been freed in evhttp_read_body */
2271a3bb4a03SNiels Provos }
2272a3bb4a03SNiels Provos
2273e44ef375SNiels Provos static void
evhttp_read_firstline(struct evhttp_connection * evcon,struct evhttp_request * req)22749998c0cbSNiels Provos evhttp_read_firstline(struct evhttp_connection *evcon,
22759998c0cbSNiels Provos struct evhttp_request *req)
2276a3bb4a03SNiels Provos {
22779998c0cbSNiels Provos enum message_read_status res;
2278a3bb4a03SNiels Provos
22798ac3c4c2SNick Mathewson res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev));
228047bad8abSNick Mathewson if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
2281a3bb4a03SNiels Provos /* Error while reading, terminate */
228262bd2c44SNick Mathewson event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
228362bd2c44SNick Mathewson __func__, EV_SOCK_ARG(evcon->fd)));
22847b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
2285a3bb4a03SNiels Provos return;
22869998c0cbSNiels Provos } else if (res == MORE_DATA_EXPECTED) {
22879998c0cbSNiels Provos /* Need more header lines */
22889998c0cbSNiels Provos return;
22899998c0cbSNiels Provos }
22909998c0cbSNiels Provos
2291c968eb3eSNiels Provos evcon->state = EVCON_READING_HEADERS;
22929998c0cbSNiels Provos evhttp_read_header(evcon, req);
22939998c0cbSNiels Provos }
22949998c0cbSNiels Provos
22959998c0cbSNiels Provos static void
evhttp_read_header(struct evhttp_connection * evcon,struct evhttp_request * req)22969998c0cbSNiels Provos evhttp_read_header(struct evhttp_connection *evcon,
22979998c0cbSNiels Provos struct evhttp_request *req)
22989998c0cbSNiels Provos {
22999998c0cbSNiels Provos enum message_read_status res;
2300c7cf6f00SNick Mathewson evutil_socket_t fd = evcon->fd;
23019998c0cbSNiels Provos
23028ac3c4c2SNick Mathewson res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev));
230347bad8abSNick Mathewson if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) {
23049998c0cbSNiels Provos /* Error while reading, terminate */
230562bd2c44SNick Mathewson event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n",
230662bd2c44SNick Mathewson __func__, EV_SOCK_ARG(fd)));
23077b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
23089998c0cbSNiels Provos return;
23099998c0cbSNiels Provos } else if (res == MORE_DATA_EXPECTED) {
2310a3bb4a03SNiels Provos /* Need more header lines */
2311a3bb4a03SNiels Provos return;
2312a3bb4a03SNiels Provos }
2313a3bb4a03SNiels Provos
2314b0bd7fe1SBalint Reczey /* Callback can shut down connection with negative return value */
2315b0bd7fe1SBalint Reczey if (req->header_cb != NULL) {
2316b0bd7fe1SBalint Reczey if ((*req->header_cb)(req, req->cb_arg) < 0) {
2317b0bd7fe1SBalint Reczey evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF);
2318b0bd7fe1SBalint Reczey return;
2319b0bd7fe1SBalint Reczey }
2320b0bd7fe1SBalint Reczey }
2321b0bd7fe1SBalint Reczey
2322a3bb4a03SNiels Provos /* Done reading headers, do the real work */
2323a3bb4a03SNiels Provos switch (req->kind) {
2324a3bb4a03SNiels Provos case EVHTTP_REQUEST:
232562bd2c44SNick Mathewson event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n",
232662bd2c44SNick Mathewson __func__, EV_SOCK_ARG(fd)));
2327ba7262ebSNiels Provos evhttp_get_body(evcon, req);
2328344c2b56SNiels Provos /* note the request may have been freed in evhttp_get_body */
2329a3bb4a03SNiels Provos break;
2330a3bb4a03SNiels Provos
2331a3bb4a03SNiels Provos case EVHTTP_RESPONSE:
2332fa9305f8SChristopher Davis /* Start over if we got a 100 Continue response. */
2333fa9305f8SChristopher Davis if (req->response_code == 100) {
23340b46b39eSAzat Khuzhin struct evbuffer *output = bufferevent_get_output(evcon->bufev);
23350b46b39eSAzat Khuzhin evbuffer_add_buffer(output, req->output_buffer);
23360b46b39eSAzat Khuzhin evhttp_start_write_(evcon);
2337fa9305f8SChristopher Davis return;
2338fa9305f8SChristopher Davis }
2339df97fca9SNiels Provos if (!evhttp_response_needs_body(req)) {
234078592370SNiels Provos event_debug(("%s: skipping body for code %d\n",
234178592370SNiels Provos __func__, req->response_code));
234278592370SNiels Provos evhttp_connection_done(evcon);
234378592370SNiels Provos } else {
234462bd2c44SNick Mathewson event_debug(("%s: start of read body for %s on "
234562bd2c44SNick Mathewson EV_SOCK_FMT"\n",
234662bd2c44SNick Mathewson __func__, req->remote_host, EV_SOCK_ARG(fd)));
2347ba7262ebSNiels Provos evhttp_get_body(evcon, req);
2348344c2b56SNiels Provos /* note the request may have been freed in
2349344c2b56SNiels Provos * evhttp_get_body */
235078592370SNiels Provos }
2351a3bb4a03SNiels Provos break;
2352a3bb4a03SNiels Provos
2353a3bb4a03SNiels Provos default:
235494866c27SNick Mathewson event_warnx("%s: bad header on "EV_SOCK_FMT, __func__,
235594866c27SNick Mathewson EV_SOCK_ARG(fd));
23567b077194SAzat Khuzhin evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER);
2357a3bb4a03SNiels Provos break;
2358a3bb4a03SNiels Provos }
2359344c2b56SNiels Provos /* request may have been freed above */
2360a3bb4a03SNiels Provos }
2361a3bb4a03SNiels Provos
2362a3bb4a03SNiels Provos /*
2363a3bb4a03SNiels Provos * Creates a TCP connection to the specified port and executes a callback
2364e3fd294aSNick Mathewson * when finished. Failure or success is indicate by the passed connection
2365a3bb4a03SNiels Provos * object.
2366896bf3a2SNiels Provos *
2367896bf3a2SNiels Provos * Although this interface accepts a hostname, it is intended to take
2368896bf3a2SNiels Provos * only numeric hostnames so that non-blocking DNS resolution can
2369896bf3a2SNiels Provos * happen elsewhere.
2370a3bb4a03SNiels Provos */
2371a3bb4a03SNiels Provos
2372a3bb4a03SNiels Provos struct evhttp_connection *
evhttp_connection_new(const char * address,ev_uint16_t port)2373e9837124SThomas Bernard evhttp_connection_new(const char *address, ev_uint16_t port)
2374de1c4392SNiels Provos {
23755032e526SNiels Provos return (evhttp_connection_base_new(NULL, NULL, address, port));
2376de1c4392SNiels Provos }
2377de1c4392SNiels Provos
2378de1c4392SNiels Provos struct evhttp_connection *
evhttp_connection_base_bufferevent_new(struct event_base * base,struct evdns_base * dnsbase,struct bufferevent * bev,const char * address,ev_uint16_t port)23798d3a8500SNick Mathewson evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev,
2380e9837124SThomas Bernard const char *address, ev_uint16_t port)
2381a3bb4a03SNiels Provos {
2382a3bb4a03SNiels Provos struct evhttp_connection *evcon = NULL;
2383a3bb4a03SNiels Provos
2384a3bb4a03SNiels Provos event_debug(("Attempting connection to %s:%d\n", address, port));
2385a3bb4a03SNiels Provos
238649868b61SNick Mathewson if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) {
2387a3bb4a03SNiels Provos event_warn("%s: calloc failed", __func__);
2388a3bb4a03SNiels Provos goto error;
2389a3bb4a03SNiels Provos }
2390a3bb4a03SNiels Provos
2391a3bb4a03SNiels Provos evcon->fd = -1;
2392a3bb4a03SNiels Provos evcon->port = port;
2393ba7262ebSNiels Provos
239447bad8abSNick Mathewson evcon->max_headers_size = EV_SIZE_MAX;
239547bad8abSNick Mathewson evcon->max_body_size = EV_SIZE_MAX;
239647bad8abSNick Mathewson
23976350e6c4SConstantine Verutin evutil_timerclear(&evcon->timeout);
2398852d05a3SNiels Provos evcon->retry_cnt = evcon->retry_max = 0;
23992d028ef6SNiels Provos
240049868b61SNick Mathewson if ((evcon->address = mm_strdup(address)) == NULL) {
2401a3bb4a03SNiels Provos event_warn("%s: strdup failed", __func__);
2402a3bb4a03SNiels Provos goto error;
2403a3bb4a03SNiels Provos }
2404a3bb4a03SNiels Provos
24058d3a8500SNick Mathewson if (bev == NULL) {
24064d637583SNick Mathewson if (!(bev = bufferevent_socket_new(base, -1, 0))) {
24074d637583SNick Mathewson event_warn("%s: bufferevent_socket_new failed", __func__);
2408ba7262ebSNiels Provos goto error;
2409ba7262ebSNiels Provos }
24108d3a8500SNick Mathewson }
24114d637583SNick Mathewson
24128d3a8500SNick Mathewson bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon);
24138d3a8500SNick Mathewson evcon->bufev = bev;
2414ba7262ebSNiels Provos
2415ba7262ebSNiels Provos evcon->state = EVCON_DISCONNECTED;
2416ba7262ebSNiels Provos TAILQ_INIT(&evcon->requests);
2417a3bb4a03SNiels Provos
2418350a3c40SNick Mathewson evcon->initial_retry_timeout.tv_sec = 2;
2419350a3c40SNick Mathewson evcon->initial_retry_timeout.tv_usec = 0;
2420350a3c40SNick Mathewson
24211bce6f74SNiels Provos if (base != NULL) {
24221bce6f74SNiels Provos evcon->base = base;
24234d637583SNick Mathewson if (bufferevent_get_base(bev) != base)
24241bce6f74SNiels Provos bufferevent_base_set(base, evcon->bufev);
24251bce6f74SNiels Provos }
24261bce6f74SNiels Provos
2427c0e425abSNick Mathewson event_deferred_cb_init_(
2428ae2b84b2SNick Mathewson &evcon->read_more_deferred_cb,
2429c0e425abSNick Mathewson bufferevent_get_priority(bev),
243074c0e862SNick Mathewson evhttp_deferred_read_cb, evcon);
243174c0e862SNick Mathewson
24325032e526SNiels Provos evcon->dns_base = dnsbase;
243312c29b0fSAzat Khuzhin evcon->ai_family = AF_UNSPEC;
24345032e526SNiels Provos
2435a3bb4a03SNiels Provos return (evcon);
2436a3bb4a03SNiels Provos
2437a3bb4a03SNiels Provos error:
2438a32839c8SNiels Provos if (evcon != NULL)
2439a3bb4a03SNiels Provos evhttp_connection_free(evcon);
2440a3bb4a03SNiels Provos return (NULL);
2441a3bb4a03SNiels Provos }
2442a3bb4a03SNiels Provos
evhttp_connection_get_bufferevent(struct evhttp_connection * evcon)24438d3a8500SNick Mathewson struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon)
24448d3a8500SNick Mathewson {
24458d3a8500SNick Mathewson return evcon->bufev;
24468d3a8500SNick Mathewson }
24478d3a8500SNick Mathewson
2448a7f82a31SMaxime Henrion struct evhttp *
evhttp_connection_get_server(struct evhttp_connection * evcon)2449a7f82a31SMaxime Henrion evhttp_connection_get_server(struct evhttp_connection *evcon)
2450a7f82a31SMaxime Henrion {
2451a7f82a31SMaxime Henrion return evcon->http_server;
2452a7f82a31SMaxime Henrion }
2453a7f82a31SMaxime Henrion
24548d3a8500SNick Mathewson struct evhttp_connection *
evhttp_connection_base_new(struct event_base * base,struct evdns_base * dnsbase,const char * address,ev_uint16_t port)24558d3a8500SNick Mathewson evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase,
2456e9837124SThomas Bernard const char *address, ev_uint16_t port)
24578d3a8500SNick Mathewson {
24588d3a8500SNick Mathewson return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port);
24598d3a8500SNick Mathewson }
24608d3a8500SNick Mathewson
evhttp_connection_set_family(struct evhttp_connection * evcon,int family)246112c29b0fSAzat Khuzhin void evhttp_connection_set_family(struct evhttp_connection *evcon,
246212c29b0fSAzat Khuzhin int family)
246312c29b0fSAzat Khuzhin {
246412c29b0fSAzat Khuzhin evcon->ai_family = family;
246512c29b0fSAzat Khuzhin }
246612c29b0fSAzat Khuzhin
evhttp_connection_set_flags(struct evhttp_connection * evcon,int flags)2467a50f5f0aSAzat Khuzhin int evhttp_connection_set_flags(struct evhttp_connection *evcon,
2468a50f5f0aSAzat Khuzhin int flags)
2469a50f5f0aSAzat Khuzhin {
24704dc09795SAzat Khuzhin int avail_flags = 0;
24714dc09795SAzat Khuzhin avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR;
2472680742e1SAzat Khuzhin avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR;
24734dc09795SAzat Khuzhin
24744dc09795SAzat Khuzhin if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END)
2475a50f5f0aSAzat Khuzhin return 1;
24764dc09795SAzat Khuzhin evcon->flags &= ~avail_flags;
2477a50f5f0aSAzat Khuzhin
24784dc09795SAzat Khuzhin evcon->flags |= flags;
2479a50f5f0aSAzat Khuzhin
2480a50f5f0aSAzat Khuzhin return 0;
2481a50f5f0aSAzat Khuzhin }
2482a50f5f0aSAzat Khuzhin
24831bce6f74SNiels Provos void
evhttp_connection_set_base(struct evhttp_connection * evcon,struct event_base * base)24841bce6f74SNiels Provos evhttp_connection_set_base(struct evhttp_connection *evcon,
248567947ce3SNiels Provos struct event_base *base)
248667947ce3SNiels Provos {
24872e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon->base == NULL);
24882e36dbe1SNick Mathewson EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED);
248967947ce3SNiels Provos evcon->base = base;
2490e44ef375SNiels Provos bufferevent_base_set(base, evcon->bufev);
249167947ce3SNiels Provos }
249267947ce3SNiels Provos
24932d028ef6SNiels Provos void
evhttp_connection_set_timeout(struct evhttp_connection * evcon,int timeout_in_secs)24942d028ef6SNiels Provos evhttp_connection_set_timeout(struct evhttp_connection *evcon,
24952d028ef6SNiels Provos int timeout_in_secs)
24962d028ef6SNiels Provos {
24976350e6c4SConstantine Verutin if (timeout_in_secs == -1)
24986350e6c4SConstantine Verutin evhttp_connection_set_timeout_tv(evcon, NULL);
24996350e6c4SConstantine Verutin else {
25006350e6c4SConstantine Verutin struct timeval tv;
25016350e6c4SConstantine Verutin tv.tv_sec = timeout_in_secs;
25026350e6c4SConstantine Verutin tv.tv_usec = 0;
25036350e6c4SConstantine Verutin evhttp_connection_set_timeout_tv(evcon, &tv);
25046350e6c4SConstantine Verutin }
25056350e6c4SConstantine Verutin }
2506e44ef375SNiels Provos
25076350e6c4SConstantine Verutin void
evhttp_connection_set_timeout_tv(struct evhttp_connection * evcon,const struct timeval * tv)25086350e6c4SConstantine Verutin evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon,
25096350e6c4SConstantine Verutin const struct timeval* tv)
25106350e6c4SConstantine Verutin {
25116350e6c4SConstantine Verutin if (tv) {
25126350e6c4SConstantine Verutin evcon->timeout = *tv;
25136350e6c4SConstantine Verutin bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
25146350e6c4SConstantine Verutin } else {
25154d637583SNick Mathewson const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 };
25164d637583SNick Mathewson const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 };
25176350e6c4SConstantine Verutin evutil_timerclear(&evcon->timeout);
25184d637583SNick Mathewson bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv);
25196350e6c4SConstantine Verutin }
25202d028ef6SNiels Provos }
25212d028ef6SNiels Provos
2522852d05a3SNiels Provos void
evhttp_connection_set_initial_retry_tv(struct evhttp_connection * evcon,const struct timeval * tv)2523350a3c40SNick Mathewson evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon,
2524350a3c40SNick Mathewson const struct timeval *tv)
2525350a3c40SNick Mathewson {
2526350a3c40SNick Mathewson if (tv) {
2527350a3c40SNick Mathewson evcon->initial_retry_timeout = *tv;
2528350a3c40SNick Mathewson } else {
2529350a3c40SNick Mathewson evutil_timerclear(&evcon->initial_retry_timeout);
2530350a3c40SNick Mathewson evcon->initial_retry_timeout.tv_sec = 2;
2531350a3c40SNick Mathewson }
2532350a3c40SNick Mathewson }
2533350a3c40SNick Mathewson
2534350a3c40SNick Mathewson void
evhttp_connection_set_retries(struct evhttp_connection * evcon,int retry_max)2535852d05a3SNiels Provos evhttp_connection_set_retries(struct evhttp_connection *evcon,
2536852d05a3SNiels Provos int retry_max)
2537852d05a3SNiels Provos {
2538852d05a3SNiels Provos evcon->retry_max = retry_max;
2539852d05a3SNiels Provos }
2540852d05a3SNiels Provos
2541de7db33aSNiels Provos void
evhttp_connection_set_closecb(struct evhttp_connection * evcon,void (* cb)(struct evhttp_connection *,void *),void * cbarg)2542de7db33aSNiels Provos evhttp_connection_set_closecb(struct evhttp_connection *evcon,
2543de7db33aSNiels Provos void (*cb)(struct evhttp_connection *, void *), void *cbarg)
2544de7db33aSNiels Provos {
2545de7db33aSNiels Provos evcon->closecb = cb;
2546de7db33aSNiels Provos evcon->closecb_arg = cbarg;
2547de7db33aSNiels Provos }
2548de7db33aSNiels Provos
2549de7db33aSNiels Provos void
evhttp_connection_get_peer(struct evhttp_connection * evcon,char ** address,ev_uint16_t * port)2550de7db33aSNiels Provos evhttp_connection_get_peer(struct evhttp_connection *evcon,
25516bf1ca78SNick Mathewson char **address, ev_uint16_t *port)
2552de7db33aSNiels Provos {
2553de7db33aSNiels Provos *address = evcon->address;
2554de7db33aSNiels Provos *port = evcon->port;
2555de7db33aSNiels Provos }
2556de7db33aSNiels Provos
25570c7f0405SAzat Khuzhin const struct sockaddr*
evhttp_connection_get_addr(struct evhttp_connection * evcon)25580c7f0405SAzat Khuzhin evhttp_connection_get_addr(struct evhttp_connection *evcon)
25590c7f0405SAzat Khuzhin {
25608bb38425SAzat Khuzhin return bufferevent_socket_get_conn_address_(evcon->bufev);
25610c7f0405SAzat Khuzhin }
25620c7f0405SAzat Khuzhin
2563ba7262ebSNiels Provos int
evhttp_connection_connect_(struct evhttp_connection * evcon)25648ac3c4c2SNick Mathewson evhttp_connection_connect_(struct evhttp_connection *evcon)
2565ba7262ebSNiels Provos {
2566b6182042SGreg Hazel int old_state = evcon->state;
256754c887d8SAzat Khuzhin const char *address = evcon->address;
256854c887d8SAzat Khuzhin const struct sockaddr *sa = evhttp_connection_get_addr(evcon);
256954c887d8SAzat Khuzhin int ret;
2570b6182042SGreg Hazel
2571ba7262ebSNiels Provos if (evcon->state == EVCON_CONNECTING)
2572ba7262ebSNiels Provos return (0);
2573ba7262ebSNiels Provos
25748ac3c4c2SNick Mathewson evhttp_connection_reset_(evcon);
2575ba7262ebSNiels Provos
25762e36dbe1SNick Mathewson EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING));
2577ba7262ebSNiels Provos evcon->flags |= EVHTTP_CON_OUTGOING;
2578ba7262ebSNiels Provos
257971e709c7SAzat Khuzhin if (evcon->bind_address || evcon->bind_port) {
25805792d42fSNiels Provos evcon->fd = bind_socket(
25815792d42fSNiels Provos evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
258298f9616bSNiels Provos if (evcon->fd == -1) {
258398f9616bSNiels Provos event_debug(("%s: failed to bind to \"%s\"",
2584b835ee08SNiels Provos __func__, evcon->bind_address));
258598f9616bSNiels Provos return (-1);
258698f9616bSNiels Provos }
258798f9616bSNiels Provos
2588a8cc449eSAzat Khuzhin if (bufferevent_setfd(evcon->bufev, evcon->fd))
2589a8cc449eSAzat Khuzhin return (-1);
259071e709c7SAzat Khuzhin } else {
2591a8cc449eSAzat Khuzhin if (bufferevent_setfd(evcon->bufev, -1))
2592a8cc449eSAzat Khuzhin return (-1);
259371e709c7SAzat Khuzhin }
259471e709c7SAzat Khuzhin
259571e709c7SAzat Khuzhin /* Set up a callback for successful connection setup */
2596c698b77dSNick Mathewson bufferevent_setcb(evcon->bufev,
2597c698b77dSNick Mathewson NULL /* evhttp_read_cb */,
2598c698b77dSNick Mathewson NULL /* evhttp_write_cb */,
2599c698b77dSNick Mathewson evhttp_connection_cb,
2600c698b77dSNick Mathewson evcon);
26014d637583SNick Mathewson if (!evutil_timerisset(&evcon->timeout)) {
26024d637583SNick Mathewson const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 };
2603040000d7SAzat Khuzhin bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv);
26044d637583SNick Mathewson } else {
2605040000d7SAzat Khuzhin bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout);
26064d637583SNick Mathewson }
2607c698b77dSNick Mathewson /* make sure that we get a write callback */
2608a8cc449eSAzat Khuzhin if (bufferevent_enable(evcon->bufev, EV_WRITE))
2609a8cc449eSAzat Khuzhin return (-1);
2610c698b77dSNick Mathewson
2611b6182042SGreg Hazel evcon->state = EVCON_CONNECTING;
2612b6182042SGreg Hazel
2613a50f5f0aSAzat Khuzhin if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR &&
2614a50f5f0aSAzat Khuzhin sa &&
2615a50f5f0aSAzat Khuzhin (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) {
2616dfad1a46SAzat Khuzhin int socklen = sizeof(struct sockaddr_in);
2617dfad1a46SAzat Khuzhin if (sa->sa_family == AF_INET6) {
261854c887d8SAzat Khuzhin socklen = sizeof(struct sockaddr_in6);
261954c887d8SAzat Khuzhin }
262054c887d8SAzat Khuzhin ret = bufferevent_socket_connect(evcon->bufev, sa, socklen);
262154c887d8SAzat Khuzhin } else {
262254c887d8SAzat Khuzhin ret = bufferevent_socket_connect_hostname(evcon->bufev,
262354c887d8SAzat Khuzhin evcon->dns_base, evcon->ai_family, address, evcon->port);
262454c887d8SAzat Khuzhin }
262554c887d8SAzat Khuzhin
262654c887d8SAzat Khuzhin if (ret < 0) {
2627b6182042SGreg Hazel evcon->state = old_state;
2628de069b99SNick Mathewson event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed",
2629774d056cSNiels Provos __func__, evcon->address);
2630b8f222e0SNiels Provos /* some operating systems return ECONNREFUSED immediately
2631b8f222e0SNiels Provos * when connecting to a local address. the cleanup is going
2632b8f222e0SNiels Provos * to reschedule this function call.
2633b8f222e0SNiels Provos */
2634b8f222e0SNiels Provos evhttp_connection_cb_cleanup(evcon);
2635b8f222e0SNiels Provos return (0);
2636ba7262ebSNiels Provos }
2637ba7262ebSNiels Provos
2638ba7262ebSNiels Provos return (0);
2639ba7262ebSNiels Provos }
2640ba7262ebSNiels Provos
2641a3bb4a03SNiels Provos /*
2642896bf3a2SNiels Provos * Starts an HTTP request on the provided evhttp_connection object.
2643ba7262ebSNiels Provos * If the connection object is not connected to the web server already,
2644ba7262ebSNiels Provos * this will start the connection.
2645a3bb4a03SNiels Provos */
2646a3bb4a03SNiels Provos
2647a3bb4a03SNiels Provos int
evhttp_make_request(struct evhttp_connection * evcon,struct evhttp_request * req,enum evhttp_cmd_type type,const char * uri)2648896bf3a2SNiels Provos evhttp_make_request(struct evhttp_connection *evcon,
2649a3bb4a03SNiels Provos struct evhttp_request *req,
2650a3bb4a03SNiels Provos enum evhttp_cmd_type type, const char *uri)
2651a3bb4a03SNiels Provos {
2652a3bb4a03SNiels Provos /* We are making a request */
2653a3bb4a03SNiels Provos req->kind = EVHTTP_REQUEST;
2654a3bb4a03SNiels Provos req->type = type;
2655a3bb4a03SNiels Provos if (req->uri != NULL)
265649868b61SNick Mathewson mm_free(req->uri);
2657f1691539SNiels Provos if ((req->uri = mm_strdup(uri)) == NULL) {
2658f1691539SNiels Provos event_warn("%s: strdup", __func__);
2659b0d3964fSAzat Khuzhin evhttp_request_free_auto(req);
2660f1691539SNiels Provos return (-1);
2661f1691539SNiels Provos }
2662a3bb4a03SNiels Provos
2663a3bb4a03SNiels Provos /* Set the protocol version if it is not supplied */
2664a3bb4a03SNiels Provos if (!req->major && !req->minor) {
2665a3bb4a03SNiels Provos req->major = 1;
2666a3bb4a03SNiels Provos req->minor = 1;
2667a3bb4a03SNiels Provos }
2668a3bb4a03SNiels Provos
26692e36dbe1SNick Mathewson EVUTIL_ASSERT(req->evcon == NULL);
2670ba7262ebSNiels Provos req->evcon = evcon;
26712e36dbe1SNick Mathewson EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
2672a3bb4a03SNiels Provos
26730848814aSKevin Ko TAILQ_INSERT_TAIL(&evcon->requests, req, next);
26740848814aSKevin Ko
2675d30e7bbaSAzat Khuzhin /* We do not want to conflict with retry_ev */
2676d30e7bbaSAzat Khuzhin if (evcon->retry_cnt)
2677d30e7bbaSAzat Khuzhin return (0);
2678d30e7bbaSAzat Khuzhin
26790d6622e2STomash Brechko /* If the connection object is not connected; make it so */
26800d6622e2STomash Brechko if (!evhttp_connected(evcon)) {
26818ac3c4c2SNick Mathewson int res = evhttp_connection_connect_(evcon);
26828ac3c4c2SNick Mathewson /* evhttp_connection_fail_(), which is called through
26838ac3c4c2SNick Mathewson * evhttp_connection_connect_(), assumes that req lies in
268480e220eeSPatrick Pelletier * evcon->requests. Thus, enqueue the request in advance and
268580e220eeSPatrick Pelletier * remove it in the error case. */
26860848814aSKevin Ko if (res != 0)
26870848814aSKevin Ko TAILQ_REMOVE(&evcon->requests, req, next);
2688a3bb4a03SNiels Provos
2689d30e7bbaSAzat Khuzhin return (res);
26900d6622e2STomash Brechko }
26910d6622e2STomash Brechko
2692ba7262ebSNiels Provos /*
2693ba7262ebSNiels Provos * If it's connected already and we are the first in the queue,
2694ba7262ebSNiels Provos * then we can dispatch this request immediately. Otherwise, it
2695ba7262ebSNiels Provos * will be dispatched once the pending requests are completed.
2696ba7262ebSNiels Provos */
2697ba7262ebSNiels Provos if (TAILQ_FIRST(&evcon->requests) == req)
2698ba7262ebSNiels Provos evhttp_request_dispatch(evcon);
2699ba7262ebSNiels Provos
2700a3bb4a03SNiels Provos return (0);
2701a3bb4a03SNiels Provos }
2702a3bb4a03SNiels Provos
27031080852eSNiels Provos void
evhttp_cancel_request(struct evhttp_request * req)27041080852eSNiels Provos evhttp_cancel_request(struct evhttp_request *req)
27051080852eSNiels Provos {
27061080852eSNiels Provos struct evhttp_connection *evcon = req->evcon;
27071080852eSNiels Provos if (evcon != NULL) {
27081080852eSNiels Provos /* We need to remove it from the connection */
27091080852eSNiels Provos if (TAILQ_FIRST(&evcon->requests) == req) {
27101080852eSNiels Provos /* it's currently being worked on, so reset
27111080852eSNiels Provos * the connection.
27121080852eSNiels Provos */
27138ac3c4c2SNick Mathewson evhttp_connection_fail_(evcon,
27147b077194SAzat Khuzhin EVREQ_HTTP_REQUEST_CANCEL);
27151080852eSNiels Provos
27161080852eSNiels Provos /* connection fail freed the request */
27171080852eSNiels Provos return;
27181080852eSNiels Provos } else {
27191080852eSNiels Provos /* otherwise, we can just remove it from the
27201080852eSNiels Provos * queue
27211080852eSNiels Provos */
27221080852eSNiels Provos TAILQ_REMOVE(&evcon->requests, req, next);
27231080852eSNiels Provos }
27241080852eSNiels Provos }
27251080852eSNiels Provos
2726b0d3964fSAzat Khuzhin evhttp_request_free_auto(req);
27271080852eSNiels Provos }
27281080852eSNiels Provos
2729a3bb4a03SNiels Provos /*
2730a3bb4a03SNiels Provos * Reads data from file descriptor into request structure
2731a3bb4a03SNiels Provos * Request structure needs to be set up correctly.
2732a3bb4a03SNiels Provos */
2733a3bb4a03SNiels Provos
2734a3bb4a03SNiels Provos void
evhttp_start_read_(struct evhttp_connection * evcon)27358ac3c4c2SNick Mathewson evhttp_start_read_(struct evhttp_connection *evcon)
2736a3bb4a03SNiels Provos {
2737e44ef375SNiels Provos bufferevent_disable(evcon->bufev, EV_WRITE);
2738e44ef375SNiels Provos bufferevent_enable(evcon->bufev, EV_READ);
27397ed02ac1SAzat Khuzhin
27409998c0cbSNiels Provos evcon->state = EVCON_READING_FIRSTLINE;
274105124879SNick Mathewson /* Reset the bufferevent callbacks */
274205124879SNick Mathewson bufferevent_setcb(evcon->bufev,
274305124879SNick Mathewson evhttp_read_cb,
274405124879SNick Mathewson evhttp_write_cb,
274505124879SNick Mathewson evhttp_error_cb,
274605124879SNick Mathewson evcon);
274774c0e862SNick Mathewson
274874c0e862SNick Mathewson /* If there's still data pending, process it next time through the
274974c0e862SNick Mathewson * loop. Don't do it now; that could get recusive. */
275074c0e862SNick Mathewson if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) {
27518ac3c4c2SNick Mathewson event_deferred_cb_schedule_(get_deferred_queue(evcon),
275274c0e862SNick Mathewson &evcon->read_more_deferred_cb);
275374c0e862SNick Mathewson }
2754a3bb4a03SNiels Provos }
2755a3bb4a03SNiels Provos
27560b46b39eSAzat Khuzhin void
evhttp_start_write_(struct evhttp_connection * evcon)27570b46b39eSAzat Khuzhin evhttp_start_write_(struct evhttp_connection *evcon)
27580b46b39eSAzat Khuzhin {
27590b46b39eSAzat Khuzhin bufferevent_disable(evcon->bufev, EV_WRITE);
27600b46b39eSAzat Khuzhin bufferevent_enable(evcon->bufev, EV_READ);
27610b46b39eSAzat Khuzhin
27620b46b39eSAzat Khuzhin evcon->state = EVCON_WRITING;
27630b46b39eSAzat Khuzhin evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
27640b46b39eSAzat Khuzhin }
27650b46b39eSAzat Khuzhin
2766a3f122d6SNick Mathewson static void
evhttp_send_done(struct evhttp_connection * evcon,void * arg)2767ba7262ebSNiels Provos evhttp_send_done(struct evhttp_connection *evcon, void *arg)
2768a3bb4a03SNiels Provos {
27691a64c982SNiels Provos int need_close;
2770ba7262ebSNiels Provos struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
2771ba7262ebSNiels Provos TAILQ_REMOVE(&evcon->requests, req, next);
2772ba7262ebSNiels Provos
2773b083ca05SAndrew Sweeney if (req->on_complete_cb != NULL) {
2774b083ca05SAndrew Sweeney req->on_complete_cb(req, req->on_complete_cb_arg);
2775b083ca05SAndrew Sweeney }
2776b083ca05SAndrew Sweeney
277736950cefSNiels Provos need_close =
2778647e094cSNick Mathewson (REQ_VERSION_BEFORE(req, 1, 1) &&
277936950cefSNiels Provos !evhttp_is_connection_keepalive(req->input_headers)) ||
27806540da38SAzat Khuzhin evhttp_is_request_connection_close(req);
2781ba7262ebSNiels Provos
27822e36dbe1SNick Mathewson EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION);
2783a3bb4a03SNiels Provos evhttp_request_free(req);
278436212f9dSNiels Provos
278536212f9dSNiels Provos if (need_close) {
278636212f9dSNiels Provos evhttp_connection_free(evcon);
278736212f9dSNiels Provos return;
278836212f9dSNiels Provos }
278936212f9dSNiels Provos
2790942656bbSNiels Provos /* we have a persistent connection; try to accept another request. */
2791f700566cSNiels Provos if (evhttp_associate_new_request_with_connection(evcon) == -1) {
279236212f9dSNiels Provos evhttp_connection_free(evcon);
2793f700566cSNiels Provos }
2794a3bb4a03SNiels Provos }
2795a3bb4a03SNiels Provos
2796a3bb4a03SNiels Provos /*
2797a3bb4a03SNiels Provos * Returns an error page.
2798a3bb4a03SNiels Provos */
2799a3bb4a03SNiels Provos
2800a3bb4a03SNiels Provos void
evhttp_send_error(struct evhttp_request * req,int error,const char * reason)2801a3bb4a03SNiels Provos evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
2802a3bb4a03SNiels Provos {
280306bd0563SFelix Nawothnig
28043206bbcaSNick Mathewson #define ERR_FORMAT "<HTML><HEAD>\n" \
28053206bbcaSNick Mathewson "<TITLE>%d %s</TITLE>\n" \
28063206bbcaSNick Mathewson "</HEAD><BODY>\n" \
280706bd0563SFelix Nawothnig "<H1>%s</H1>\n" \
28083206bbcaSNick Mathewson "</BODY></HTML>\n"
2809a3bb4a03SNiels Provos
2810a3bb4a03SNiels Provos struct evbuffer *buf = evbuffer_new();
2811f1691539SNiels Provos if (buf == NULL) {
2812f1691539SNiels Provos /* if we cannot allocate memory; we just drop the connection */
2813f1691539SNiels Provos evhttp_connection_free(req->evcon);
2814f1691539SNiels Provos return;
2815f1691539SNiels Provos }
281606bd0563SFelix Nawothnig if (reason == NULL) {
281706bd0563SFelix Nawothnig reason = evhttp_response_phrase_internal(error);
281806bd0563SFelix Nawothnig }
281931ba30abSNiels Provos
28208ac3c4c2SNick Mathewson evhttp_response_code_(req, error, reason);
2821a3bb4a03SNiels Provos
282206bd0563SFelix Nawothnig evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason);
2823a3bb4a03SNiels Provos
28248ac3c4c2SNick Mathewson evhttp_send_page_(req, buf);
2825a3bb4a03SNiels Provos
2826a3bb4a03SNiels Provos evbuffer_free(buf);
28273206bbcaSNick Mathewson #undef ERR_FORMAT
2828a3bb4a03SNiels Provos }
2829a3bb4a03SNiels Provos
2830a3bb4a03SNiels Provos /* Requires that headers and response code are already set up */
2831a3bb4a03SNiels Provos
2832aa5c8068SNiels Provos static inline void
evhttp_send(struct evhttp_request * req,struct evbuffer * databuf)2833a3bb4a03SNiels Provos evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
2834a3bb4a03SNiels Provos {
2835ba7262ebSNiels Provos struct evhttp_connection *evcon = req->evcon;
2836a3bb4a03SNiels Provos
283739781801SNiels Provos if (evcon == NULL) {
283839781801SNiels Provos evhttp_request_free(req);
283939781801SNiels Provos return;
284039781801SNiels Provos }
284139781801SNiels Provos
28422e36dbe1SNick Mathewson EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req);
2843ba7262ebSNiels Provos
284493d73691SNiels Provos /* we expect no more calls form the user on this request */
284593d73691SNiels Provos req->userdone = 1;
284693d73691SNiels Provos
2847f554234fSNiels Provos /* xxx: not sure if we really should expose the data buffer this way */
28482225eec2SNiels Provos if (databuf != NULL)
2849ba7262ebSNiels Provos evbuffer_add_buffer(req->output_buffer, databuf);
2850a3bb4a03SNiels Provos
2851a3bb4a03SNiels Provos /* Adds headers to the response */
2852ba7262ebSNiels Provos evhttp_make_header(evcon, req);
2853a3bb4a03SNiels Provos
2854ba7262ebSNiels Provos evhttp_write_buffer(evcon, evhttp_send_done, NULL);
2855a3bb4a03SNiels Provos }
2856a3bb4a03SNiels Provos
2857a3bb4a03SNiels Provos void
evhttp_send_reply(struct evhttp_request * req,int code,const char * reason,struct evbuffer * databuf)2858a3bb4a03SNiels Provos evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
2859a3bb4a03SNiels Provos struct evbuffer *databuf)
2860a3bb4a03SNiels Provos {
28618ac3c4c2SNick Mathewson evhttp_response_code_(req, code, reason);
2862a3bb4a03SNiels Provos
2863a3bb4a03SNiels Provos evhttp_send(req, databuf);
2864a3bb4a03SNiels Provos }
2865a3bb4a03SNiels Provos
2866a3bb4a03SNiels Provos void
evhttp_send_reply_start(struct evhttp_request * req,int code,const char * reason)2867de7db33aSNiels Provos evhttp_send_reply_start(struct evhttp_request *req, int code,
2868de7db33aSNiels Provos const char *reason)
2869de7db33aSNiels Provos {
28708ac3c4c2SNick Mathewson evhttp_response_code_(req, code, reason);
2871826f1134SAndreas Gustafsson
2872826f1134SAndreas Gustafsson if (req->evcon == NULL)
2873826f1134SAndreas Gustafsson return;
2874826f1134SAndreas Gustafsson
2875df97fca9SNiels Provos if (evhttp_find_header(req->output_headers, "Content-Length") == NULL &&
2876647e094cSNick Mathewson REQ_VERSION_ATLEAST(req, 1, 1) &&
2877df97fca9SNiels Provos evhttp_response_needs_body(req)) {
2878df97fca9SNiels Provos /*
2879df97fca9SNiels Provos * prefer HTTP/1.1 chunked encoding to closing the connection;
2880df97fca9SNiels Provos * note RFC 2616 section 4.4 forbids it with Content-Length:
2881df97fca9SNiels Provos * and it's not necessary then anyway.
2882df97fca9SNiels Provos */
2883557e0f62SNiels Provos evhttp_add_header(req->output_headers, "Transfer-Encoding",
2884557e0f62SNiels Provos "chunked");
2885557e0f62SNiels Provos req->chunked = 1;
2886aa5f55faSJoachim Bauch } else {
2887aa5f55faSJoachim Bauch req->chunked = 0;
2888557e0f62SNiels Provos }
2889de7db33aSNiels Provos evhttp_make_header(req->evcon, req);
2890de7db33aSNiels Provos evhttp_write_buffer(req->evcon, NULL, NULL);
2891de7db33aSNiels Provos }
2892de7db33aSNiels Provos
2893de7db33aSNiels Provos void
evhttp_send_reply_chunk_with_cb(struct evhttp_request * req,struct evbuffer * databuf,void (* cb)(struct evhttp_connection *,void *),void * arg)28948d8decf1SJulien BLACHE evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf,
28958d8decf1SJulien BLACHE void (*cb)(struct evhttp_connection *, void *), void *arg)
2896de7db33aSNiels Provos {
289793d73691SNiels Provos struct evhttp_connection *evcon = req->evcon;
289893d73691SNiels Provos struct evbuffer *output;
289993d73691SNiels Provos
290093d73691SNiels Provos if (evcon == NULL)
290193d73691SNiels Provos return;
290293d73691SNiels Provos
290393d73691SNiels Provos output = bufferevent_get_output(evcon->bufev);
290493d73691SNiels Provos
2905a8f6d961SNick Mathewson if (evbuffer_get_length(databuf) == 0)
2906df97fca9SNiels Provos return;
2907df97fca9SNiels Provos if (!evhttp_response_needs_body(req))
2908df97fca9SNiels Provos return;
2909557e0f62SNiels Provos if (req->chunked) {
2910e44ef375SNiels Provos evbuffer_add_printf(output, "%x\r\n",
2911a8f6d961SNick Mathewson (unsigned)evbuffer_get_length(databuf));
2912557e0f62SNiels Provos }
2913e44ef375SNiels Provos evbuffer_add_buffer(output, databuf);
2914677a9586SNick Mathewson if (req->chunked) {
2915e44ef375SNiels Provos evbuffer_add(output, "\r\n", 2);
2916677a9586SNick Mathewson }
29178d8decf1SJulien BLACHE evhttp_write_buffer(evcon, cb, arg);
2918de7db33aSNiels Provos }
2919de7db33aSNiels Provos
2920de7db33aSNiels Provos void
evhttp_send_reply_chunk(struct evhttp_request * req,struct evbuffer * databuf)29218d8decf1SJulien BLACHE evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
29228d8decf1SJulien BLACHE {
29238d8decf1SJulien BLACHE evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL);
29248d8decf1SJulien BLACHE }
29258d8decf1SJulien BLACHE void
evhttp_send_reply_end(struct evhttp_request * req)2926557e0f62SNiels Provos evhttp_send_reply_end(struct evhttp_request *req)
2927de7db33aSNiels Provos {
2928de7db33aSNiels Provos struct evhttp_connection *evcon = req->evcon;
292929b2e233SFelix Nawothnig struct evbuffer *output;
2930de7db33aSNiels Provos
293193d73691SNiels Provos if (evcon == NULL) {
293293d73691SNiels Provos evhttp_request_free(req);
293393d73691SNiels Provos return;
293493d73691SNiels Provos }
293593d73691SNiels Provos
293629b2e233SFelix Nawothnig output = bufferevent_get_output(evcon->bufev);
293729b2e233SFelix Nawothnig
293893d73691SNiels Provos /* we expect no more calls form the user on this request */
293993d73691SNiels Provos req->userdone = 1;
294093d73691SNiels Provos
2941557e0f62SNiels Provos if (req->chunked) {
2942e44ef375SNiels Provos evbuffer_add(output, "0\r\n\r\n", 5);
2943557e0f62SNiels Provos evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
2944557e0f62SNiels Provos req->chunked = 0;
2945a8f6d961SNick Mathewson } else if (evbuffer_get_length(output) == 0) {
2946de7db33aSNiels Provos /* let the connection know that we are done with the request */
2947de7db33aSNiels Provos evhttp_send_done(evcon, NULL);
2948de7db33aSNiels Provos } else {
2949de7db33aSNiels Provos /* make the callback execute after all data has been written */
2950de7db33aSNiels Provos evcon->cb = evhttp_send_done;
2951de7db33aSNiels Provos evcon->cb_arg = NULL;
2952de7db33aSNiels Provos }
2953de7db33aSNiels Provos }
2954de7db33aSNiels Provos
295506bd0563SFelix Nawothnig static const char *informational_phrases[] = {
295606bd0563SFelix Nawothnig /* 100 */ "Continue",
295706bd0563SFelix Nawothnig /* 101 */ "Switching Protocols"
295806bd0563SFelix Nawothnig };
295906bd0563SFelix Nawothnig
296006bd0563SFelix Nawothnig static const char *success_phrases[] = {
296106bd0563SFelix Nawothnig /* 200 */ "OK",
296206bd0563SFelix Nawothnig /* 201 */ "Created",
296306bd0563SFelix Nawothnig /* 202 */ "Accepted",
296406bd0563SFelix Nawothnig /* 203 */ "Non-Authoritative Information",
296506bd0563SFelix Nawothnig /* 204 */ "No Content",
296606bd0563SFelix Nawothnig /* 205 */ "Reset Content",
296706bd0563SFelix Nawothnig /* 206 */ "Partial Content"
296806bd0563SFelix Nawothnig };
296906bd0563SFelix Nawothnig
297006bd0563SFelix Nawothnig static const char *redirection_phrases[] = {
297106bd0563SFelix Nawothnig /* 300 */ "Multiple Choices",
297206bd0563SFelix Nawothnig /* 301 */ "Moved Permanently",
297306bd0563SFelix Nawothnig /* 302 */ "Found",
297406bd0563SFelix Nawothnig /* 303 */ "See Other",
297506bd0563SFelix Nawothnig /* 304 */ "Not Modified",
297606bd0563SFelix Nawothnig /* 305 */ "Use Proxy",
297706bd0563SFelix Nawothnig /* 307 */ "Temporary Redirect"
297806bd0563SFelix Nawothnig };
297906bd0563SFelix Nawothnig
298006bd0563SFelix Nawothnig static const char *client_error_phrases[] = {
298106bd0563SFelix Nawothnig /* 400 */ "Bad Request",
298206bd0563SFelix Nawothnig /* 401 */ "Unauthorized",
298306bd0563SFelix Nawothnig /* 402 */ "Payment Required",
298406bd0563SFelix Nawothnig /* 403 */ "Forbidden",
298506bd0563SFelix Nawothnig /* 404 */ "Not Found",
298606bd0563SFelix Nawothnig /* 405 */ "Method Not Allowed",
298706bd0563SFelix Nawothnig /* 406 */ "Not Acceptable",
298806bd0563SFelix Nawothnig /* 407 */ "Proxy Authentication Required",
298906bd0563SFelix Nawothnig /* 408 */ "Request Time-out",
299006bd0563SFelix Nawothnig /* 409 */ "Conflict",
299106bd0563SFelix Nawothnig /* 410 */ "Gone",
299206bd0563SFelix Nawothnig /* 411 */ "Length Required",
299306bd0563SFelix Nawothnig /* 412 */ "Precondition Failed",
299406bd0563SFelix Nawothnig /* 413 */ "Request Entity Too Large",
299506bd0563SFelix Nawothnig /* 414 */ "Request-URI Too Large",
299606bd0563SFelix Nawothnig /* 415 */ "Unsupported Media Type",
299706bd0563SFelix Nawothnig /* 416 */ "Requested range not satisfiable",
299806bd0563SFelix Nawothnig /* 417 */ "Expectation Failed"
299906bd0563SFelix Nawothnig };
300006bd0563SFelix Nawothnig
300106bd0563SFelix Nawothnig static const char *server_error_phrases[] = {
300206bd0563SFelix Nawothnig /* 500 */ "Internal Server Error",
300306bd0563SFelix Nawothnig /* 501 */ "Not Implemented",
300406bd0563SFelix Nawothnig /* 502 */ "Bad Gateway",
300506bd0563SFelix Nawothnig /* 503 */ "Service Unavailable",
300606bd0563SFelix Nawothnig /* 504 */ "Gateway Time-out",
300706bd0563SFelix Nawothnig /* 505 */ "HTTP Version not supported"
300806bd0563SFelix Nawothnig };
300906bd0563SFelix Nawothnig
301006bd0563SFelix Nawothnig struct response_class {
301106bd0563SFelix Nawothnig const char *name;
301206bd0563SFelix Nawothnig size_t num_responses;
301306bd0563SFelix Nawothnig const char **responses;
301406bd0563SFelix Nawothnig };
301506bd0563SFelix Nawothnig
301606bd0563SFelix Nawothnig #ifndef MEMBERSOF
301706bd0563SFelix Nawothnig #define MEMBERSOF(x) (sizeof(x)/sizeof(x[0]))
301806bd0563SFelix Nawothnig #endif
301906bd0563SFelix Nawothnig
302006bd0563SFelix Nawothnig static const struct response_class response_classes[] = {
302106bd0563SFelix Nawothnig /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases },
302206bd0563SFelix Nawothnig /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases },
302306bd0563SFelix Nawothnig /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases },
302406bd0563SFelix Nawothnig /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases },
302506bd0563SFelix Nawothnig /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases }
302606bd0563SFelix Nawothnig };
302706bd0563SFelix Nawothnig
302806bd0563SFelix Nawothnig static const char *
evhttp_response_phrase_internal(int code)302906bd0563SFelix Nawothnig evhttp_response_phrase_internal(int code)
303006bd0563SFelix Nawothnig {
303106bd0563SFelix Nawothnig int klass = code / 100 - 1;
303206bd0563SFelix Nawothnig int subcode = code % 100;
303306bd0563SFelix Nawothnig
303406bd0563SFelix Nawothnig /* Unknown class - can't do any better here */
30359c8db0f8SNick Mathewson if (klass < 0 || klass >= (int) MEMBERSOF(response_classes))
303606bd0563SFelix Nawothnig return "Unknown Status Class";
303706bd0563SFelix Nawothnig
303806bd0563SFelix Nawothnig /* Unknown sub-code, return class name at least */
30399c8db0f8SNick Mathewson if (subcode >= (int) response_classes[klass].num_responses)
304006bd0563SFelix Nawothnig return response_classes[klass].name;
304106bd0563SFelix Nawothnig
304206bd0563SFelix Nawothnig return response_classes[klass].responses[subcode];
304306bd0563SFelix Nawothnig }
304406bd0563SFelix Nawothnig
3045de7db33aSNiels Provos void
evhttp_response_code_(struct evhttp_request * req,int code,const char * reason)30468ac3c4c2SNick Mathewson evhttp_response_code_(struct evhttp_request *req, int code, const char *reason)
3047a3bb4a03SNiels Provos {
3048a3bb4a03SNiels Provos req->kind = EVHTTP_RESPONSE;
3049a3bb4a03SNiels Provos req->response_code = code;
3050a3bb4a03SNiels Provos if (req->response_code_line != NULL)
305149868b61SNick Mathewson mm_free(req->response_code_line);
305206bd0563SFelix Nawothnig if (reason == NULL)
305306bd0563SFelix Nawothnig reason = evhttp_response_phrase_internal(code);
305449868b61SNick Mathewson req->response_code_line = mm_strdup(reason);
3055666b0966SJardel Weyrich if (req->response_code_line == NULL) {
3056666b0966SJardel Weyrich event_warn("%s: strdup", __func__);
3057666b0966SJardel Weyrich /* XXX what else can we do? */
3058666b0966SJardel Weyrich }
3059a3bb4a03SNiels Provos }
3060a3bb4a03SNiels Provos
3061a3bb4a03SNiels Provos void
evhttp_send_page_(struct evhttp_request * req,struct evbuffer * databuf)30628ac3c4c2SNick Mathewson evhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf)
3063a3bb4a03SNiels Provos {
3064c4836d10SNiels Provos if (!req->major || !req->minor) {
3065c4836d10SNiels Provos req->major = 1;
3066c4836d10SNiels Provos req->minor = 1;
3067c4836d10SNiels Provos }
3068c4836d10SNiels Provos
3069a3bb4a03SNiels Provos if (req->kind != EVHTTP_RESPONSE)
30708ac3c4c2SNick Mathewson evhttp_response_code_(req, 200, "OK");
3071a3bb4a03SNiels Provos
3072a3bb4a03SNiels Provos evhttp_clear_headers(req->output_headers);
3073a3bb4a03SNiels Provos evhttp_add_header(req->output_headers, "Content-Type", "text/html");
3074a3bb4a03SNiels Provos evhttp_add_header(req->output_headers, "Connection", "close");
3075a3bb4a03SNiels Provos
3076a3bb4a03SNiels Provos evhttp_send(req, databuf);
3077a3bb4a03SNiels Provos }
3078a3bb4a03SNiels Provos
3079557e0f62SNiels Provos static const char uri_chars[256] = {
30802e63a604SNick Mathewson /* 0 */
3081557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3082557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30832e63a604SNick Mathewson 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
30842e63a604SNick Mathewson 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
3085557e0f62SNiels Provos /* 64 */
30862e63a604SNick Mathewson 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3087557e0f62SNiels Provos 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
3088557e0f62SNiels Provos 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3089557e0f62SNiels Provos 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
3090557e0f62SNiels Provos /* 128 */
3091557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3092557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3093557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3094557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3095557e0f62SNiels Provos /* 192 */
3096557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3097557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3098557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3099557e0f62SNiels Provos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3100557e0f62SNiels Provos };
3101557e0f62SNiels Provos
3102eaa5f1d9SNick Mathewson #define CHAR_IS_UNRESERVED(c) \
3103eaa5f1d9SNick Mathewson (uri_chars[(unsigned char)(c)])
3104eaa5f1d9SNick Mathewson
3105557e0f62SNiels Provos /*
31062e63a604SNick Mathewson * Helper functions to encode/decode a string for inclusion in a URI.
3107557e0f62SNiels Provos * The returned string must be freed by the caller.
3108557e0f62SNiels Provos */
31092225eec2SNiels Provos char *
evhttp_uriencode(const char * uri,ev_ssize_t len,int space_as_plus)3110a8148cedSNick Mathewson evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus)
3111557e0f62SNiels Provos {
3112557e0f62SNiels Provos struct evbuffer *buf = evbuffer_new();
3113a8148cedSNick Mathewson const char *p, *end;
3114123362e9SAzat Khuzhin char *result = NULL;
3115557e0f62SNiels Provos
3116123362e9SAzat Khuzhin if (!buf) {
3117123362e9SAzat Khuzhin goto out;
311872afe4c9SMark Ellzey }
3119f1691539SNiels Provos
3120c6b1ec12SZonr Chang if (len >= 0) {
312172afe4c9SMark Ellzey if (uri + len < uri) {
3122123362e9SAzat Khuzhin goto out;
312372afe4c9SMark Ellzey }
312472afe4c9SMark Ellzey
3125a8148cedSNick Mathewson end = uri + len;
312672afe4c9SMark Ellzey } else {
312772afe4c9SMark Ellzey size_t slen = strlen(uri);
312872afe4c9SMark Ellzey
312972afe4c9SMark Ellzey if (slen >= EV_SSIZE_MAX) {
313072afe4c9SMark Ellzey /* we don't want to mix signed and unsigned */
3131123362e9SAzat Khuzhin goto out;
313272afe4c9SMark Ellzey }
313372afe4c9SMark Ellzey
313472afe4c9SMark Ellzey if (uri + slen < uri) {
3135123362e9SAzat Khuzhin goto out;
313672afe4c9SMark Ellzey }
313772afe4c9SMark Ellzey
313872afe4c9SMark Ellzey end = uri + slen;
313972afe4c9SMark Ellzey }
3140a8148cedSNick Mathewson
3141a8148cedSNick Mathewson for (p = uri; p < end; p++) {
3142eaa5f1d9SNick Mathewson if (CHAR_IS_UNRESERVED(*p)) {
3143557e0f62SNiels Provos evbuffer_add(buf, p, 1);
3144a8148cedSNick Mathewson } else if (*p == ' ' && space_as_plus) {
3145a8148cedSNick Mathewson evbuffer_add(buf, "+", 1);
3146557e0f62SNiels Provos } else {
31476bf1ca78SNick Mathewson evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p));
3148557e0f62SNiels Provos }
3149557e0f62SNiels Provos }
315072afe4c9SMark Ellzey
3151a8148cedSNick Mathewson evbuffer_add(buf, "", 1); /* NUL-terminator. */
3152a8148cedSNick Mathewson result = mm_malloc(evbuffer_get_length(buf));
315372afe4c9SMark Ellzey
315411c8b317SNick Mathewson if (result)
3155a8148cedSNick Mathewson evbuffer_remove(buf, result, evbuffer_get_length(buf));
315672afe4c9SMark Ellzey
3157123362e9SAzat Khuzhin out:
3158123362e9SAzat Khuzhin if (buf)
3159557e0f62SNiels Provos evbuffer_free(buf);
3160123362e9SAzat Khuzhin return result;
3161a8148cedSNick Mathewson }
3162a8148cedSNick Mathewson
3163a8148cedSNick Mathewson char *
evhttp_encode_uri(const char * str)3164a8148cedSNick Mathewson evhttp_encode_uri(const char *str)
3165a8148cedSNick Mathewson {
3166a8148cedSNick Mathewson return evhttp_uriencode(str, -1, 0);
3167557e0f62SNiels Provos }
3168557e0f62SNiels Provos
3169ce146eb1SNiels Provos /*
3170a8148cedSNick Mathewson * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't.
3171a8148cedSNick Mathewson * If -1, when true we transform plus to space only after we've seen
3172a8148cedSNick Mathewson * a ?. -1 is deprecated.
3173a8148cedSNick Mathewson * @return the number of bytes written to 'ret'.
3174ce146eb1SNiels Provos */
3175de8101a8SAzat Khuzhin int
evhttp_decode_uri_internal(const char * uri,size_t length,char * ret,int decode_plus_ctl)3176ce146eb1SNiels Provos evhttp_decode_uri_internal(
3177a8148cedSNick Mathewson const char *uri, size_t length, char *ret, int decode_plus_ctl)
31782225eec2SNiels Provos {
3179687be124SNiels Provos char c;
3180a8148cedSNick Mathewson int j;
3181a8148cedSNick Mathewson int decode_plus = (decode_plus_ctl == 1) ? 1: 0;
3182e865eb93SNick Mathewson unsigned i;
31832225eec2SNiels Provos
3184687be124SNiels Provos for (i = j = 0; i < length; i++) {
3185557e0f62SNiels Provos c = uri[i];
31862225eec2SNiels Provos if (c == '?') {
3187a8148cedSNick Mathewson if (decode_plus_ctl < 0)
3188a8148cedSNick Mathewson decode_plus = 1;
3189a8148cedSNick Mathewson } else if (c == '+' && decode_plus) {
31902225eec2SNiels Provos c = ' ';
3191e1903e3aSAzat Khuzhin } else if ((i + 2) < length && c == '%' &&
319264b6eceaSAzat Khuzhin EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) {
31939516df0eSNick Mathewson char tmp[3];
31949516df0eSNick Mathewson tmp[0] = uri[i+1];
31959516df0eSNick Mathewson tmp[1] = uri[i+2];
31969516df0eSNick Mathewson tmp[2] = '\0';
31972225eec2SNiels Provos c = (char)strtol(tmp, NULL, 16);
31982225eec2SNiels Provos i += 2;
31992225eec2SNiels Provos }
32002225eec2SNiels Provos ret[j++] = c;
32012225eec2SNiels Provos }
32022225eec2SNiels Provos ret[j] = '\0';
32032225eec2SNiels Provos
3204687be124SNiels Provos return (j);
3205687be124SNiels Provos }
3206687be124SNiels Provos
3207a8148cedSNick Mathewson /* deprecated */
3208687be124SNiels Provos char *
evhttp_decode_uri(const char * uri)3209687be124SNiels Provos evhttp_decode_uri(const char *uri)
3210687be124SNiels Provos {
3211687be124SNiels Provos char *ret;
3212687be124SNiels Provos
3213f1691539SNiels Provos if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
3214f1691539SNiels Provos event_warn("%s: malloc(%lu)", __func__,
3215687be124SNiels Provos (unsigned long)(strlen(uri) + 1));
3216f1691539SNiels Provos return (NULL);
3217f1691539SNiels Provos }
3218687be124SNiels Provos
3219ce146eb1SNiels Provos evhttp_decode_uri_internal(uri, strlen(uri),
3220a8148cedSNick Mathewson ret, -1 /*always_decode_plus*/);
3221a8148cedSNick Mathewson
3222a8148cedSNick Mathewson return (ret);
3223a8148cedSNick Mathewson }
3224a8148cedSNick Mathewson
3225a8148cedSNick Mathewson char *
evhttp_uridecode(const char * uri,int decode_plus,size_t * size_out)3226a8148cedSNick Mathewson evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out)
3227a8148cedSNick Mathewson {
3228a8148cedSNick Mathewson char *ret;
3229a8148cedSNick Mathewson int n;
3230a8148cedSNick Mathewson
3231a8148cedSNick Mathewson if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) {
3232a8148cedSNick Mathewson event_warn("%s: malloc(%lu)", __func__,
3233a8148cedSNick Mathewson (unsigned long)(strlen(uri) + 1));
3234a8148cedSNick Mathewson return (NULL);
3235a8148cedSNick Mathewson }
3236a8148cedSNick Mathewson
3237a8148cedSNick Mathewson n = evhttp_decode_uri_internal(uri, strlen(uri),
3238a8148cedSNick Mathewson ret, !!decode_plus/*always_decode_plus*/);
3239a8148cedSNick Mathewson
3240a8148cedSNick Mathewson if (size_out) {
3241a8148cedSNick Mathewson EVUTIL_ASSERT(n >= 0);
3242a8148cedSNick Mathewson *size_out = (size_t)n;
3243a8148cedSNick Mathewson }
3244687be124SNiels Provos
32452225eec2SNiels Provos return (ret);
32462225eec2SNiels Provos }
32472225eec2SNiels Provos
3248a3bb4a03SNiels Provos /*
3249a3bb4a03SNiels Provos * Helper function to parse out arguments in a query.
3250a3bb4a03SNiels Provos * The arguments are separated by key and value.
3251a3bb4a03SNiels Provos */
3252a3bb4a03SNiels Provos
3253a4063c06SNick Mathewson static int
evhttp_parse_query_impl(const char * str,struct evkeyvalq * headers,int is_whole_uri)3254a4063c06SNick Mathewson evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers,
32552075fbcfSNick Mathewson int is_whole_uri)
3256a3bb4a03SNiels Provos {
32572075fbcfSNick Mathewson char *line=NULL;
3258a3bb4a03SNiels Provos char *argument;
3259a3bb4a03SNiels Provos char *p;
32602075fbcfSNick Mathewson const char *query_part;
3261b1756d01SNick Mathewson int result = -1;
32622075fbcfSNick Mathewson struct evhttp_uri *uri=NULL;
3263a3bb4a03SNiels Provos
3264a3bb4a03SNiels Provos TAILQ_INIT(headers);
3265a3bb4a03SNiels Provos
32662075fbcfSNick Mathewson if (is_whole_uri) {
32672075fbcfSNick Mathewson uri = evhttp_uri_parse(str);
32682075fbcfSNick Mathewson if (!uri)
32692075fbcfSNick Mathewson goto error;
327045f6869cSNick Mathewson query_part = evhttp_uri_get_query(uri);
32712075fbcfSNick Mathewson } else {
32722075fbcfSNick Mathewson query_part = str;
3273f1691539SNiels Provos }
3274a3bb4a03SNiels Provos
32752075fbcfSNick Mathewson /* No arguments - we are done */
32762075fbcfSNick Mathewson if (!query_part || !strlen(query_part)) {
32772075fbcfSNick Mathewson result = 0;
32782075fbcfSNick Mathewson goto done;
32792075fbcfSNick Mathewson }
3280a3bb4a03SNiels Provos
32812075fbcfSNick Mathewson if ((line = mm_strdup(query_part)) == NULL) {
32822075fbcfSNick Mathewson event_warn("%s: strdup", __func__);
32832075fbcfSNick Mathewson goto error;
32842075fbcfSNick Mathewson }
3285a3bb4a03SNiels Provos
32862075fbcfSNick Mathewson p = argument = line;
3287a3bb4a03SNiels Provos while (p != NULL && *p != '\0') {
3288382a1587SNiels Provos char *key, *value, *decoded_value;
3289*97e28f09SAzat Khuzhin int err;
3290a3bb4a03SNiels Provos argument = strsep(&p, "&");
3291a3bb4a03SNiels Provos
3292a3bb4a03SNiels Provos value = argument;
3293a3bb4a03SNiels Provos key = strsep(&value, "=");
3294b1756d01SNick Mathewson if (value == NULL || *key == '\0') {
3295a3bb4a03SNiels Provos goto error;
3296b1756d01SNick Mathewson }
3297a3bb4a03SNiels Provos
3298f1691539SNiels Provos if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) {
3299f1691539SNiels Provos event_warn("%s: mm_malloc", __func__);
3300b1756d01SNick Mathewson goto error;
3301f1691539SNiels Provos }
3302382a1587SNiels Provos evhttp_decode_uri_internal(value, strlen(value),
3303382a1587SNiels Provos decoded_value, 1 /*always_decode_plus*/);
3304382a1587SNiels Provos event_debug(("Query Param: %s -> %s\n", key, decoded_value));
3305*97e28f09SAzat Khuzhin err = evhttp_add_header_internal(headers, key, decoded_value);
3306382a1587SNiels Provos mm_free(decoded_value);
3307*97e28f09SAzat Khuzhin if (err)
3308*97e28f09SAzat Khuzhin goto error;
3309a3bb4a03SNiels Provos }
3310a3bb4a03SNiels Provos
3311b1756d01SNick Mathewson result = 0;
3312b1756d01SNick Mathewson goto done;
3313a3bb4a03SNiels Provos error:
3314b1756d01SNick Mathewson evhttp_clear_headers(headers);
3315b1756d01SNick Mathewson done:
33162075fbcfSNick Mathewson if (line)
331749868b61SNick Mathewson mm_free(line);
33182075fbcfSNick Mathewson if (uri)
33192075fbcfSNick Mathewson evhttp_uri_free(uri);
3320b1756d01SNick Mathewson return result;
3321a3bb4a03SNiels Provos }
3322a3bb4a03SNiels Provos
3323a4063c06SNick Mathewson int
evhttp_parse_query(const char * uri,struct evkeyvalq * headers)33243b844893SNick Mathewson evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
33253b844893SNick Mathewson {
3326a4063c06SNick Mathewson return evhttp_parse_query_impl(uri, headers, 1);
3327a4063c06SNick Mathewson }
3328a4063c06SNick Mathewson int
evhttp_parse_query_str(const char * uri,struct evkeyvalq * headers)3329a4063c06SNick Mathewson evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers)
3330a4063c06SNick Mathewson {
3331a4063c06SNick Mathewson return evhttp_parse_query_impl(uri, headers, 0);
33323b844893SNick Mathewson }
33333b844893SNick Mathewson
3334a968da74SNiels Provos static struct evhttp_cb *
evhttp_dispatch_callback(struct httpcbq * callbacks,struct evhttp_request * req)3335a968da74SNiels Provos evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
3336a968da74SNiels Provos {
3337a968da74SNiels Provos struct evhttp_cb *cb;
33388ea5ffefSNiels Provos size_t offset = 0;
3339687be124SNiels Provos char *translated;
3340aab8c38bSChristopher Davis const char *path;
3341a968da74SNiels Provos
3342a968da74SNiels Provos /* Test for different URLs */
3343aab8c38bSChristopher Davis path = evhttp_uri_get_path(req->uri_elems);
3344aab8c38bSChristopher Davis offset = strlen(path);
3345054159f5SNick Mathewson if ((translated = mm_malloc(offset + 1)) == NULL)
3346687be124SNiels Provos return (NULL);
3347aab8c38bSChristopher Davis evhttp_decode_uri_internal(path, offset, translated,
3348aab8c38bSChristopher Davis 0 /* decode_plus */);
3349687be124SNiels Provos
3350a968da74SNiels Provos TAILQ_FOREACH(cb, callbacks, next) {
3351aab8c38bSChristopher Davis if (!strcmp(cb->what, translated)) {
3352054159f5SNick Mathewson mm_free(translated);
3353a968da74SNiels Provos return (cb);
3354a968da74SNiels Provos }
3355054159f5SNick Mathewson }
3356a968da74SNiels Provos
3357054159f5SNick Mathewson mm_free(translated);
3358a968da74SNiels Provos return (NULL);
3359a968da74SNiels Provos }
3360a968da74SNiels Provos
3361950af186SNiels Provos
3362950af186SNiels Provos static int
prefix_suffix_match(const char * pattern,const char * name,int ignorecase)3363950af186SNiels Provos prefix_suffix_match(const char *pattern, const char *name, int ignorecase)
3364950af186SNiels Provos {
3365950af186SNiels Provos char c;
3366950af186SNiels Provos
3367950af186SNiels Provos while (1) {
3368950af186SNiels Provos switch (c = *pattern++) {
3369950af186SNiels Provos case '\0':
3370950af186SNiels Provos return *name == '\0';
3371950af186SNiels Provos
3372950af186SNiels Provos case '*':
3373950af186SNiels Provos while (*name != '\0') {
3374950af186SNiels Provos if (prefix_suffix_match(pattern, name,
3375950af186SNiels Provos ignorecase))
3376950af186SNiels Provos return (1);
3377950af186SNiels Provos ++name;
3378950af186SNiels Provos }
3379950af186SNiels Provos return (0);
3380950af186SNiels Provos default:
3381950af186SNiels Provos if (c != *name) {
3382950af186SNiels Provos if (!ignorecase ||
33838ac3c4c2SNick Mathewson EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name))
3384950af186SNiels Provos return (0);
3385950af186SNiels Provos }
3386950af186SNiels Provos ++name;
3387950af186SNiels Provos }
3388950af186SNiels Provos }
3389950af186SNiels Provos /* NOTREACHED */
3390950af186SNiels Provos }
3391950af186SNiels Provos
3392aab8c38bSChristopher Davis /*
3393aab8c38bSChristopher Davis Search the vhost hierarchy beginning with http for a server alias
3394aab8c38bSChristopher Davis matching hostname. If a match is found, and outhttp is non-null,
3395aab8c38bSChristopher Davis outhttp is set to the matching http object and 1 is returned.
3396aab8c38bSChristopher Davis */
3397aab8c38bSChristopher Davis
3398aab8c38bSChristopher Davis static int
evhttp_find_alias(struct evhttp * http,struct evhttp ** outhttp,const char * hostname)3399aab8c38bSChristopher Davis evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp,
3400aab8c38bSChristopher Davis const char *hostname)
3401aab8c38bSChristopher Davis {
3402aab8c38bSChristopher Davis struct evhttp_server_alias *alias;
3403aab8c38bSChristopher Davis struct evhttp *vhost;
3404aab8c38bSChristopher Davis
3405aab8c38bSChristopher Davis TAILQ_FOREACH(alias, &http->aliases, next) {
3406aab8c38bSChristopher Davis /* XXX Do we need to handle IP addresses? */
3407aab8c38bSChristopher Davis if (!evutil_ascii_strcasecmp(alias->alias, hostname)) {
3408aab8c38bSChristopher Davis if (outhttp)
3409aab8c38bSChristopher Davis *outhttp = http;
3410aab8c38bSChristopher Davis return 1;
3411aab8c38bSChristopher Davis }
3412aab8c38bSChristopher Davis }
3413aab8c38bSChristopher Davis
3414aab8c38bSChristopher Davis /* XXX It might be good to avoid recursion here, but I don't
3415aab8c38bSChristopher Davis see a way to do that w/o a list. */
3416aab8c38bSChristopher Davis TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
3417aab8c38bSChristopher Davis if (evhttp_find_alias(vhost, outhttp, hostname))
3418aab8c38bSChristopher Davis return 1;
3419aab8c38bSChristopher Davis }
3420aab8c38bSChristopher Davis
3421aab8c38bSChristopher Davis return 0;
3422aab8c38bSChristopher Davis }
3423aab8c38bSChristopher Davis
3424aab8c38bSChristopher Davis /*
3425aab8c38bSChristopher Davis Attempts to find the best http object to handle a request for a hostname.
3426aab8c38bSChristopher Davis All aliases for the root http object and vhosts are searched for an exact
3427aab8c38bSChristopher Davis match. Then, the vhost hierarchy is traversed again for a matching
3428aab8c38bSChristopher Davis pattern.
3429aab8c38bSChristopher Davis
3430aab8c38bSChristopher Davis If an alias or vhost is matched, 1 is returned, and outhttp, if non-null,
3431aab8c38bSChristopher Davis is set with the best matching http object. If there are no matches, the
3432aab8c38bSChristopher Davis root http object is stored in outhttp and 0 is returned.
3433aab8c38bSChristopher Davis */
3434aab8c38bSChristopher Davis
3435aab8c38bSChristopher Davis static int
evhttp_find_vhost(struct evhttp * http,struct evhttp ** outhttp,const char * hostname)3436aab8c38bSChristopher Davis evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp,
3437aab8c38bSChristopher Davis const char *hostname)
3438aab8c38bSChristopher Davis {
3439aab8c38bSChristopher Davis struct evhttp *vhost;
3440aab8c38bSChristopher Davis struct evhttp *oldhttp;
3441aab8c38bSChristopher Davis int match_found = 0;
3442aab8c38bSChristopher Davis
3443aab8c38bSChristopher Davis if (evhttp_find_alias(http, outhttp, hostname))
3444aab8c38bSChristopher Davis return 1;
3445aab8c38bSChristopher Davis
3446aab8c38bSChristopher Davis do {
3447aab8c38bSChristopher Davis oldhttp = http;
3448aab8c38bSChristopher Davis TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) {
3449aab8c38bSChristopher Davis if (prefix_suffix_match(vhost->vhost_pattern,
3450aab8c38bSChristopher Davis hostname, 1 /* ignorecase */)) {
3451aab8c38bSChristopher Davis http = vhost;
3452aab8c38bSChristopher Davis match_found = 1;
3453aab8c38bSChristopher Davis break;
3454aab8c38bSChristopher Davis }
3455aab8c38bSChristopher Davis }
3456aab8c38bSChristopher Davis } while (oldhttp != http);
3457aab8c38bSChristopher Davis
3458aab8c38bSChristopher Davis if (outhttp)
3459aab8c38bSChristopher Davis *outhttp = http;
3460aab8c38bSChristopher Davis
3461aab8c38bSChristopher Davis return match_found;
3462aab8c38bSChristopher Davis }
3463aab8c38bSChristopher Davis
3464a3f122d6SNick Mathewson static void
evhttp_handle_request(struct evhttp_request * req,void * arg)3465a3bb4a03SNiels Provos evhttp_handle_request(struct evhttp_request *req, void *arg)
3466a3bb4a03SNiels Provos {
3467a3bb4a03SNiels Provos struct evhttp *http = arg;
3468a968da74SNiels Provos struct evhttp_cb *cb = NULL;
3469f2a81fbcSNiels Provos const char *hostname;
3470a3bb4a03SNiels Provos
34719d8edf2fSNiels Provos /* we have a new request on which the user needs to take action */
34729d8edf2fSNiels Provos req->userdone = 0;
34739d8edf2fSNiels Provos
3474b2581380SAzat Khuzhin bufferevent_disable(req->evcon->bufev, EV_READ);
3475b2581380SAzat Khuzhin
347675a73414SFelix Nawothnig if (req->type == 0 || req->uri == NULL) {
3477ac448a74SAzat Khuzhin evhttp_send_error(req, req->response_code, NULL);
347844bd5ab4SNiels Provos return;
347944bd5ab4SNiels Provos }
348044bd5ab4SNiels Provos
348175a73414SFelix Nawothnig if ((http->allowed_methods & req->type) == 0) {
3482f5b391e2SNick Mathewson event_debug(("Rejecting disallowed method %x (allowed: %x)\n",
3483f5b391e2SNick Mathewson (unsigned)req->type, (unsigned)http->allowed_methods));
3484f5b391e2SNick Mathewson evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL);
348575a73414SFelix Nawothnig return;
348675a73414SFelix Nawothnig }
348775a73414SFelix Nawothnig
3488f2a81fbcSNiels Provos /* handle potential virtual hosts */
3489aab8c38bSChristopher Davis hostname = evhttp_request_get_host(req);
3490f2a81fbcSNiels Provos if (hostname != NULL) {
3491aab8c38bSChristopher Davis evhttp_find_vhost(http, &http, hostname);
3492f2a81fbcSNiels Provos }
3493f2a81fbcSNiels Provos
3494a968da74SNiels Provos if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
3495a3bb4a03SNiels Provos (*cb->cb)(req, cb->cbarg);
3496a3bb4a03SNiels Provos return;
3497a3bb4a03SNiels Provos }
3498a3bb4a03SNiels Provos
3499a3bb4a03SNiels Provos /* Generic call back */
3500a3bb4a03SNiels Provos if (http->gencb) {
3501a3bb4a03SNiels Provos (*http->gencb)(req, http->gencbarg);
3502a3bb4a03SNiels Provos return;
3503a3bb4a03SNiels Provos } else {
3504a3bb4a03SNiels Provos /* We need to send a 404 here */
35053206bbcaSNick Mathewson #define ERR_FORMAT "<html><head>" \
35063206bbcaSNick Mathewson "<title>404 Not Found</title>" \
35073206bbcaSNick Mathewson "</head><body>" \
35083206bbcaSNick Mathewson "<h1>Not Found</h1>" \
35093206bbcaSNick Mathewson "<p>The requested URL %s was not found on this server.</p>"\
35103206bbcaSNick Mathewson "</body></html>\n"
3511a3bb4a03SNiels Provos
3512f1691539SNiels Provos char *escaped_html;
3513f1691539SNiels Provos struct evbuffer *buf;
3514f1691539SNiels Provos
3515f1691539SNiels Provos if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) {
3516f1691539SNiels Provos evhttp_connection_free(req->evcon);
3517f1691539SNiels Provos return;
3518f1691539SNiels Provos }
3519f1691539SNiels Provos
3520f1691539SNiels Provos if ((buf = evbuffer_new()) == NULL) {
3521f1691539SNiels Provos mm_free(escaped_html);
3522f1691539SNiels Provos evhttp_connection_free(req->evcon);
3523f1691539SNiels Provos return;
3524f1691539SNiels Provos }
3525a3bb4a03SNiels Provos
35268ac3c4c2SNick Mathewson evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found");
3527a3bb4a03SNiels Provos
35283206bbcaSNick Mathewson evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
3529a3bb4a03SNiels Provos
353049868b61SNick Mathewson mm_free(escaped_html);
3531a3bb4a03SNiels Provos
35328ac3c4c2SNick Mathewson evhttp_send_page_(req, buf);
3533a3bb4a03SNiels Provos
3534a3bb4a03SNiels Provos evbuffer_free(buf);
35353206bbcaSNick Mathewson #undef ERR_FORMAT
3536a3bb4a03SNiels Provos }
3537a3bb4a03SNiels Provos }
3538a3bb4a03SNiels Provos
353990b3ed5bSNick Mathewson /* Listener callback when a connection arrives at a server. */
3540a3bb4a03SNiels Provos static void
accept_socket_cb(struct evconnlistener * listener,evutil_socket_t nfd,struct sockaddr * peer_sa,int peer_socklen,void * arg)3541ec34533aSNick Mathewson accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg)
3542a3bb4a03SNiels Provos {
3543a3bb4a03SNiels Provos struct evhttp *http = arg;
3544a3bb4a03SNiels Provos
3545ec34533aSNick Mathewson evhttp_get_request(http, nfd, peer_sa, peer_socklen);
3546a3bb4a03SNiels Provos }
3547a3bb4a03SNiels Provos
354867947ce3SNiels Provos int
evhttp_bind_socket(struct evhttp * http,const char * address,ev_uint16_t port)35496bf1ca78SNick Mathewson evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port)
3550a3bb4a03SNiels Provos {
35516c53334cSNick Mathewson struct evhttp_bound_socket *bound =
35526c53334cSNick Mathewson evhttp_bind_socket_with_handle(http, address, port);
35536c53334cSNick Mathewson if (bound == NULL)
35546c53334cSNick Mathewson return (-1);
35556c53334cSNick Mathewson return (0);
35566c53334cSNick Mathewson }
35576c53334cSNick Mathewson
35586c53334cSNick Mathewson struct evhttp_bound_socket *
evhttp_bind_socket_with_handle(struct evhttp * http,const char * address,ev_uint16_t port)35596c53334cSNick Mathewson evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port)
35606c53334cSNick Mathewson {
35611120f04fSNick Mathewson evutil_socket_t fd;
35622c1b0e44SNick Mathewson struct evhttp_bound_socket *bound;
35632ccd00a6SLuke Dashjr int serrno;
3564a3bb4a03SNiels Provos
35654c56ba1cSNiels Provos if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
35666c53334cSNick Mathewson return (NULL);
3567a3bb4a03SNiels Provos
35687470ce52SNiels Provos if (listen(fd, 128) == -1) {
35692ccd00a6SLuke Dashjr serrno = EVUTIL_SOCKET_ERROR();
3570de069b99SNick Mathewson event_sock_warn(fd, "%s: listen", __func__);
3571899c1dccSSebastian Sjöberg evutil_closesocket(fd);
35722ccd00a6SLuke Dashjr EVUTIL_SET_SOCKET_ERROR(serrno);
35736c53334cSNick Mathewson return (NULL);
3574a3bb4a03SNiels Provos }
3575a3bb4a03SNiels Provos
35762c1b0e44SNick Mathewson bound = evhttp_accept_socket_with_handle(http, fd);
35770b114da2SNiels Provos
35786c53334cSNick Mathewson if (bound != NULL) {
35790b114da2SNiels Provos event_debug(("Bound to port %d - Awaiting connections ... ",
35800b114da2SNiels Provos port));
35816c53334cSNick Mathewson return (bound);
35826c53334cSNick Mathewson }
35830b114da2SNiels Provos
35846c53334cSNick Mathewson return (NULL);
35850b114da2SNiels Provos }
35860b114da2SNiels Provos
35870b114da2SNiels Provos int
evhttp_accept_socket(struct evhttp * http,evutil_socket_t fd)35880b114da2SNiels Provos evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)
35890b114da2SNiels Provos {
35906c53334cSNick Mathewson struct evhttp_bound_socket *bound =
35916c53334cSNick Mathewson evhttp_accept_socket_with_handle(http, fd);
35926c53334cSNick Mathewson if (bound == NULL)
35936c53334cSNick Mathewson return (-1);
35946c53334cSNick Mathewson return (0);
35956c53334cSNick Mathewson }
35966c53334cSNick Mathewson
3597a2c48e3bSSamy Al Bahra void
evhttp_foreach_bound_socket(struct evhttp * http,evhttp_bound_socket_foreach_fn * function,void * argument)3598a2c48e3bSSamy Al Bahra evhttp_foreach_bound_socket(struct evhttp *http,
3599a2c48e3bSSamy Al Bahra evhttp_bound_socket_foreach_fn *function,
3600a2c48e3bSSamy Al Bahra void *argument)
3601a2c48e3bSSamy Al Bahra {
3602a2c48e3bSSamy Al Bahra struct evhttp_bound_socket *bound;
3603a2c48e3bSSamy Al Bahra
3604a2c48e3bSSamy Al Bahra TAILQ_FOREACH(bound, &http->sockets, next)
3605a2c48e3bSSamy Al Bahra function(bound, argument);
3606a2c48e3bSSamy Al Bahra }
36076c53334cSNick Mathewson
36086c53334cSNick Mathewson struct evhttp_bound_socket *
evhttp_accept_socket_with_handle(struct evhttp * http,evutil_socket_t fd)36096c53334cSNick Mathewson evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd)
36106c53334cSNick Mathewson {
3611f940eb4bSNiels Provos struct evhttp_bound_socket *bound;
3612ec34533aSNick Mathewson struct evconnlistener *listener;
3613ec34533aSNick Mathewson const int flags =
3614ec34533aSNick Mathewson LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE;
3615f940eb4bSNiels Provos
3616006efa7dSNick Mathewson listener = evconnlistener_new(http->base, NULL, NULL,
3617006efa7dSNick Mathewson flags,
3618006efa7dSNick Mathewson 0, /* Backlog is '0' because we already said 'listen' */
3619006efa7dSNick Mathewson fd);
3620006efa7dSNick Mathewson if (!listener)
3621006efa7dSNick Mathewson return (NULL);
3622006efa7dSNick Mathewson
3623006efa7dSNick Mathewson bound = evhttp_bind_listener(http, listener);
3624006efa7dSNick Mathewson if (!bound) {
3625006efa7dSNick Mathewson evconnlistener_free(listener);
3626006efa7dSNick Mathewson return (NULL);
3627006efa7dSNick Mathewson }
3628006efa7dSNick Mathewson return (bound);
3629006efa7dSNick Mathewson }
3630006efa7dSNick Mathewson
3631006efa7dSNick Mathewson struct evhttp_bound_socket *
evhttp_bind_listener(struct evhttp * http,struct evconnlistener * listener)3632006efa7dSNick Mathewson evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener)
3633006efa7dSNick Mathewson {
3634006efa7dSNick Mathewson struct evhttp_bound_socket *bound;
3635006efa7dSNick Mathewson
3636f940eb4bSNiels Provos bound = mm_malloc(sizeof(struct evhttp_bound_socket));
3637f940eb4bSNiels Provos if (bound == NULL)
36386c53334cSNick Mathewson return (NULL);
3639f940eb4bSNiels Provos
3640ec34533aSNick Mathewson bound->listener = listener;
3641f940eb4bSNiels Provos TAILQ_INSERT_TAIL(&http->sockets, bound, next);
3642f940eb4bSNiels Provos
3643006efa7dSNick Mathewson evconnlistener_set_cb(listener, accept_socket_cb, http);
3644006efa7dSNick Mathewson return bound;
3645a3bb4a03SNiels Provos }
3646a3bb4a03SNiels Provos
3647aab8c38bSChristopher Davis evutil_socket_t
evhttp_bound_socket_get_fd(struct evhttp_bound_socket * bound)3648aab8c38bSChristopher Davis evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound)
36494bcd5646SNick Mathewson {
3650ec34533aSNick Mathewson return evconnlistener_get_fd(bound->listener);
36514bcd5646SNick Mathewson }
36524bcd5646SNick Mathewson
3653006efa7dSNick Mathewson struct evconnlistener *
evhttp_bound_socket_get_listener(struct evhttp_bound_socket * bound)3654006efa7dSNick Mathewson evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
3655006efa7dSNick Mathewson {
3656006efa7dSNick Mathewson return bound->listener;
3657006efa7dSNick Mathewson }
3658006efa7dSNick Mathewson
3659c8b0fe4aSNick Mathewson void
evhttp_del_accept_socket(struct evhttp * http,struct evhttp_bound_socket * bound)3660c8b0fe4aSNick Mathewson evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound)
3661c8b0fe4aSNick Mathewson {
3662c8b0fe4aSNick Mathewson TAILQ_REMOVE(&http->sockets, bound, next);
3663ec34533aSNick Mathewson evconnlistener_free(bound->listener);
3664c8b0fe4aSNick Mathewson mm_free(bound);
3665c8b0fe4aSNick Mathewson }
3666c8b0fe4aSNick Mathewson
366767947ce3SNiels Provos static struct evhttp*
evhttp_new_object(void)3668a3f122d6SNick Mathewson evhttp_new_object(void)
3669a3bb4a03SNiels Provos {
367067947ce3SNiels Provos struct evhttp *http = NULL;
3671a3bb4a03SNiels Provos
367249868b61SNick Mathewson if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) {
3673a3bb4a03SNiels Provos event_warn("%s: calloc", __func__);
3674a3bb4a03SNiels Provos return (NULL);
3675a3bb4a03SNiels Provos }
3676a3bb4a03SNiels Provos
36776350e6c4SConstantine Verutin evutil_timerclear(&http->timeout);
367847bad8abSNick Mathewson evhttp_set_max_headers_size(http, EV_SIZE_MAX);
367947bad8abSNick Mathewson evhttp_set_max_body_size(http, EV_SIZE_MAX);
36805a5acd9aSNicolas Martyanoff evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1");
3681bb0d2b4eSNick Mathewson evhttp_set_allowed_methods(http,
3682bb0d2b4eSNick Mathewson EVHTTP_REQ_GET |
368375a73414SFelix Nawothnig EVHTTP_REQ_POST |
368475a73414SFelix Nawothnig EVHTTP_REQ_HEAD |
368575a73414SFelix Nawothnig EVHTTP_REQ_PUT |
368675a73414SFelix Nawothnig EVHTTP_REQ_DELETE);
3687942656bbSNiels Provos
3688f940eb4bSNiels Provos TAILQ_INIT(&http->sockets);
3689a3bb4a03SNiels Provos TAILQ_INIT(&http->callbacks);
369036212f9dSNiels Provos TAILQ_INIT(&http->connections);
3691f2a81fbcSNiels Provos TAILQ_INIT(&http->virtualhosts);
3692aab8c38bSChristopher Davis TAILQ_INIT(&http->aliases);
3693a3bb4a03SNiels Provos
369467947ce3SNiels Provos return (http);
369567947ce3SNiels Provos }
369667947ce3SNiels Provos
369767947ce3SNiels Provos struct evhttp *
evhttp_new(struct event_base * base)369867947ce3SNiels Provos evhttp_new(struct event_base *base)
369967947ce3SNiels Provos {
3700446cc7a0SMansour Moufid struct evhttp *http = NULL;
370167947ce3SNiels Provos
3702446cc7a0SMansour Moufid http = evhttp_new_object();
3703446cc7a0SMansour Moufid if (http == NULL)
3704446cc7a0SMansour Moufid return (NULL);
370567947ce3SNiels Provos http->base = base;
370667947ce3SNiels Provos
370767947ce3SNiels Provos return (http);
370867947ce3SNiels Provos }
370967947ce3SNiels Provos
371067947ce3SNiels Provos /*
371167947ce3SNiels Provos * Start a web server on the specified address and port.
371267947ce3SNiels Provos */
371367947ce3SNiels Provos
371467947ce3SNiels Provos struct evhttp *
evhttp_start(const char * address,ev_uint16_t port)3715e9837124SThomas Bernard evhttp_start(const char *address, ev_uint16_t port)
371667947ce3SNiels Provos {
3717446cc7a0SMansour Moufid struct evhttp *http = NULL;
371867947ce3SNiels Provos
3719446cc7a0SMansour Moufid http = evhttp_new_object();
3720446cc7a0SMansour Moufid if (http == NULL)
3721446cc7a0SMansour Moufid return (NULL);
372267947ce3SNiels Provos if (evhttp_bind_socket(http, address, port) == -1) {
372349868b61SNick Mathewson mm_free(http);
3724a3bb4a03SNiels Provos return (NULL);
3725a3bb4a03SNiels Provos }
3726a3bb4a03SNiels Provos
3727a3bb4a03SNiels Provos return (http);
3728a3bb4a03SNiels Provos }
3729a3bb4a03SNiels Provos
3730a3bb4a03SNiels Provos void
evhttp_free(struct evhttp * http)3731a3bb4a03SNiels Provos evhttp_free(struct evhttp* http)
3732a3bb4a03SNiels Provos {
3733a3bb4a03SNiels Provos struct evhttp_cb *http_cb;
373436212f9dSNiels Provos struct evhttp_connection *evcon;
3735f940eb4bSNiels Provos struct evhttp_bound_socket *bound;
3736f2a81fbcSNiels Provos struct evhttp* vhost;
3737aab8c38bSChristopher Davis struct evhttp_server_alias *alias;
3738a3bb4a03SNiels Provos
3739a3bb4a03SNiels Provos /* Remove the accepting part */
3740f940eb4bSNiels Provos while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
3741f940eb4bSNiels Provos TAILQ_REMOVE(&http->sockets, bound, next);
3742f940eb4bSNiels Provos
3743ec34533aSNick Mathewson evconnlistener_free(bound->listener);
3744a3bb4a03SNiels Provos
3745f940eb4bSNiels Provos mm_free(bound);
3746f940eb4bSNiels Provos }
3747f940eb4bSNiels Provos
374836212f9dSNiels Provos while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
374936212f9dSNiels Provos /* evhttp_connection_free removes the connection */
375036212f9dSNiels Provos evhttp_connection_free(evcon);
375136212f9dSNiels Provos }
375236212f9dSNiels Provos
3753a3bb4a03SNiels Provos while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
3754a3bb4a03SNiels Provos TAILQ_REMOVE(&http->callbacks, http_cb, next);
375549868b61SNick Mathewson mm_free(http_cb->what);
375649868b61SNick Mathewson mm_free(http_cb);
3757a3bb4a03SNiels Provos }
3758a3bb4a03SNiels Provos
3759f2a81fbcSNiels Provos while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) {
376090b3ed5bSNick Mathewson TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
3761f2a81fbcSNiels Provos
3762f2a81fbcSNiels Provos evhttp_free(vhost);
3763f2a81fbcSNiels Provos }
3764f2a81fbcSNiels Provos
3765f2a81fbcSNiels Provos if (http->vhost_pattern != NULL)
3766f2a81fbcSNiels Provos mm_free(http->vhost_pattern);
3767f2a81fbcSNiels Provos
3768aab8c38bSChristopher Davis while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) {
3769aab8c38bSChristopher Davis TAILQ_REMOVE(&http->aliases, alias, next);
3770aab8c38bSChristopher Davis mm_free(alias->alias);
3771aab8c38bSChristopher Davis mm_free(alias);
3772aab8c38bSChristopher Davis }
3773aab8c38bSChristopher Davis
377449868b61SNick Mathewson mm_free(http);
3775a3bb4a03SNiels Provos }
3776a3bb4a03SNiels Provos
3777f2a81fbcSNiels Provos int
evhttp_add_virtual_host(struct evhttp * http,const char * pattern,struct evhttp * vhost)3778f2a81fbcSNiels Provos evhttp_add_virtual_host(struct evhttp* http, const char *pattern,
3779f2a81fbcSNiels Provos struct evhttp* vhost)
3780f2a81fbcSNiels Provos {
3781f2a81fbcSNiels Provos /* a vhost can only be a vhost once and should not have bound sockets */
3782f2a81fbcSNiels Provos if (vhost->vhost_pattern != NULL ||
3783f2a81fbcSNiels Provos TAILQ_FIRST(&vhost->sockets) != NULL)
3784f2a81fbcSNiels Provos return (-1);
3785f2a81fbcSNiels Provos
3786f2a81fbcSNiels Provos vhost->vhost_pattern = mm_strdup(pattern);
3787f2a81fbcSNiels Provos if (vhost->vhost_pattern == NULL)
3788f2a81fbcSNiels Provos return (-1);
3789f2a81fbcSNiels Provos
379090b3ed5bSNick Mathewson TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost);
3791f2a81fbcSNiels Provos
3792f2a81fbcSNiels Provos return (0);
3793f2a81fbcSNiels Provos }
3794f2a81fbcSNiels Provos
3795f2a81fbcSNiels Provos int
evhttp_remove_virtual_host(struct evhttp * http,struct evhttp * vhost)3796f2a81fbcSNiels Provos evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost)
3797f2a81fbcSNiels Provos {
3798f2a81fbcSNiels Provos if (vhost->vhost_pattern == NULL)
3799f2a81fbcSNiels Provos return (-1);
3800f2a81fbcSNiels Provos
380190b3ed5bSNick Mathewson TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost);
3802f2a81fbcSNiels Provos
3803f2a81fbcSNiels Provos mm_free(vhost->vhost_pattern);
3804f2a81fbcSNiels Provos vhost->vhost_pattern = NULL;
3805f2a81fbcSNiels Provos
3806f2a81fbcSNiels Provos return (0);
3807f2a81fbcSNiels Provos }
3808f2a81fbcSNiels Provos
3809aab8c38bSChristopher Davis int
evhttp_add_server_alias(struct evhttp * http,const char * alias)3810aab8c38bSChristopher Davis evhttp_add_server_alias(struct evhttp *http, const char *alias)
3811aab8c38bSChristopher Davis {
3812aab8c38bSChristopher Davis struct evhttp_server_alias *evalias;
3813aab8c38bSChristopher Davis
3814aab8c38bSChristopher Davis evalias = mm_calloc(1, sizeof(*evalias));
3815aab8c38bSChristopher Davis if (!evalias)
3816aab8c38bSChristopher Davis return -1;
3817aab8c38bSChristopher Davis
3818aab8c38bSChristopher Davis evalias->alias = mm_strdup(alias);
3819aab8c38bSChristopher Davis if (!evalias->alias) {
3820aab8c38bSChristopher Davis mm_free(evalias);
3821aab8c38bSChristopher Davis return -1;
3822aab8c38bSChristopher Davis }
3823aab8c38bSChristopher Davis
3824aab8c38bSChristopher Davis TAILQ_INSERT_TAIL(&http->aliases, evalias, next);
3825aab8c38bSChristopher Davis
3826aab8c38bSChristopher Davis return 0;
3827aab8c38bSChristopher Davis }
3828aab8c38bSChristopher Davis
3829aab8c38bSChristopher Davis int
evhttp_remove_server_alias(struct evhttp * http,const char * alias)3830aab8c38bSChristopher Davis evhttp_remove_server_alias(struct evhttp *http, const char *alias)
3831aab8c38bSChristopher Davis {
3832aab8c38bSChristopher Davis struct evhttp_server_alias *evalias;
3833aab8c38bSChristopher Davis
3834aab8c38bSChristopher Davis TAILQ_FOREACH(evalias, &http->aliases, next) {
3835aab8c38bSChristopher Davis if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) {
3836aab8c38bSChristopher Davis TAILQ_REMOVE(&http->aliases, evalias, next);
3837aab8c38bSChristopher Davis mm_free(evalias->alias);
3838aab8c38bSChristopher Davis mm_free(evalias);
3839aab8c38bSChristopher Davis return 0;
3840aab8c38bSChristopher Davis }
3841aab8c38bSChristopher Davis }
3842aab8c38bSChristopher Davis
3843aab8c38bSChristopher Davis return -1;
3844aab8c38bSChristopher Davis }
3845aab8c38bSChristopher Davis
3846a3bb4a03SNiels Provos void
evhttp_set_timeout(struct evhttp * http,int timeout_in_secs)3847942656bbSNiels Provos evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
3848942656bbSNiels Provos {
38496350e6c4SConstantine Verutin if (timeout_in_secs == -1) {
38506350e6c4SConstantine Verutin evhttp_set_timeout_tv(http, NULL);
38516350e6c4SConstantine Verutin } else {
38526350e6c4SConstantine Verutin struct timeval tv;
38536350e6c4SConstantine Verutin tv.tv_sec = timeout_in_secs;
38546350e6c4SConstantine Verutin tv.tv_usec = 0;
38556350e6c4SConstantine Verutin evhttp_set_timeout_tv(http, &tv);
38566350e6c4SConstantine Verutin }
38576350e6c4SConstantine Verutin }
38586350e6c4SConstantine Verutin
38596350e6c4SConstantine Verutin void
evhttp_set_timeout_tv(struct evhttp * http,const struct timeval * tv)38606350e6c4SConstantine Verutin evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv)
38616350e6c4SConstantine Verutin {
38626350e6c4SConstantine Verutin if (tv) {
38636350e6c4SConstantine Verutin http->timeout = *tv;
38646350e6c4SConstantine Verutin } else {
38656350e6c4SConstantine Verutin evutil_timerclear(&http->timeout);
38666350e6c4SConstantine Verutin }
3867942656bbSNiels Provos }
3868942656bbSNiels Provos
evhttp_set_flags(struct evhttp * http,int flags)38699fde5189SAzat Khuzhin int evhttp_set_flags(struct evhttp *http, int flags)
38709fde5189SAzat Khuzhin {
38719fde5189SAzat Khuzhin int avail_flags = 0;
38729fde5189SAzat Khuzhin avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE;
38739fde5189SAzat Khuzhin
38749fde5189SAzat Khuzhin if (flags & ~avail_flags)
38759fde5189SAzat Khuzhin return 1;
38769fde5189SAzat Khuzhin http->flags &= ~avail_flags;
38779fde5189SAzat Khuzhin
38789fde5189SAzat Khuzhin http->flags |= flags;
38799fde5189SAzat Khuzhin
38809fde5189SAzat Khuzhin return 0;
38819fde5189SAzat Khuzhin }
38829fde5189SAzat Khuzhin
388334f28e08SNick Mathewson void
evhttp_set_max_headers_size(struct evhttp * http,ev_ssize_t max_headers_size)388434f28e08SNick Mathewson evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size)
388534f28e08SNick Mathewson {
388634f28e08SNick Mathewson if (max_headers_size < 0)
388734f28e08SNick Mathewson http->default_max_headers_size = EV_SIZE_MAX;
388834f28e08SNick Mathewson else
388947bad8abSNick Mathewson http->default_max_headers_size = max_headers_size;
389047bad8abSNick Mathewson }
389147bad8abSNick Mathewson
389234f28e08SNick Mathewson void
evhttp_set_max_body_size(struct evhttp * http,ev_ssize_t max_body_size)389334f28e08SNick Mathewson evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size)
389434f28e08SNick Mathewson {
389534f28e08SNick Mathewson if (max_body_size < 0)
389634f28e08SNick Mathewson http->default_max_body_size = EV_UINT64_MAX;
389734f28e08SNick Mathewson else
389847bad8abSNick Mathewson http->default_max_body_size = max_body_size;
389947bad8abSNick Mathewson }
390047bad8abSNick Mathewson
390175a73414SFelix Nawothnig void
evhttp_set_default_content_type(struct evhttp * http,const char * content_type)39025a5acd9aSNicolas Martyanoff evhttp_set_default_content_type(struct evhttp *http,
39035a5acd9aSNicolas Martyanoff const char *content_type) {
39045a5acd9aSNicolas Martyanoff http->default_content_type = content_type;
39055a5acd9aSNicolas Martyanoff }
39065a5acd9aSNicolas Martyanoff
39075a5acd9aSNicolas Martyanoff void
evhttp_set_allowed_methods(struct evhttp * http,ev_uint16_t methods)3908f5b391e2SNick Mathewson evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods)
390975a73414SFelix Nawothnig {
391075a73414SFelix Nawothnig http->allowed_methods = methods;
391175a73414SFelix Nawothnig }
391275a73414SFelix Nawothnig
391330648529SNiels Provos int
evhttp_set_cb(struct evhttp * http,const char * uri,void (* cb)(struct evhttp_request *,void *),void * cbarg)3914a3bb4a03SNiels Provos evhttp_set_cb(struct evhttp *http, const char *uri,
3915a3bb4a03SNiels Provos void (*cb)(struct evhttp_request *, void *), void *cbarg)
3916a3bb4a03SNiels Provos {
3917a3bb4a03SNiels Provos struct evhttp_cb *http_cb;
3918a3bb4a03SNiels Provos
391930648529SNiels Provos TAILQ_FOREACH(http_cb, &http->callbacks, next) {
392030648529SNiels Provos if (strcmp(http_cb->what, uri) == 0)
392130648529SNiels Provos return (-1);
392230648529SNiels Provos }
392330648529SNiels Provos
3924f1691539SNiels Provos if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) {
3925f1691539SNiels Provos event_warn("%s: calloc", __func__);
3926f1691539SNiels Provos return (-2);
3927f1691539SNiels Provos }
3928a3bb4a03SNiels Provos
392949868b61SNick Mathewson http_cb->what = mm_strdup(uri);
3930666b0966SJardel Weyrich if (http_cb->what == NULL) {
3931666b0966SJardel Weyrich event_warn("%s: strdup", __func__);
3932666b0966SJardel Weyrich mm_free(http_cb);
3933666b0966SJardel Weyrich return (-3);
3934666b0966SJardel Weyrich }
3935a3bb4a03SNiels Provos http_cb->cb = cb;
3936a3bb4a03SNiels Provos http_cb->cbarg = cbarg;
3937a3bb4a03SNiels Provos
3938a3bb4a03SNiels Provos TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
393930648529SNiels Provos
394030648529SNiels Provos return (0);
3941a3bb4a03SNiels Provos }
3942a3bb4a03SNiels Provos
39430c280824SNiels Provos int
evhttp_del_cb(struct evhttp * http,const char * uri)39440c280824SNiels Provos evhttp_del_cb(struct evhttp *http, const char *uri)
39450c280824SNiels Provos {
39460c280824SNiels Provos struct evhttp_cb *http_cb;
39470c280824SNiels Provos
39480c280824SNiels Provos TAILQ_FOREACH(http_cb, &http->callbacks, next) {
39490c280824SNiels Provos if (strcmp(http_cb->what, uri) == 0)
39500c280824SNiels Provos break;
39510c280824SNiels Provos }
39520c280824SNiels Provos if (http_cb == NULL)
39530c280824SNiels Provos return (-1);
39540c280824SNiels Provos
39550c280824SNiels Provos TAILQ_REMOVE(&http->callbacks, http_cb, next);
395649868b61SNick Mathewson mm_free(http_cb->what);
395749868b61SNick Mathewson mm_free(http_cb);
39580c280824SNiels Provos
39590c280824SNiels Provos return (0);
39600c280824SNiels Provos }
39610c280824SNiels Provos
3962a3bb4a03SNiels Provos void
evhttp_set_gencb(struct evhttp * http,void (* cb)(struct evhttp_request *,void *),void * cbarg)3963a3bb4a03SNiels Provos evhttp_set_gencb(struct evhttp *http,
3964a3bb4a03SNiels Provos void (*cb)(struct evhttp_request *, void *), void *cbarg)
3965a3bb4a03SNiels Provos {
3966a3bb4a03SNiels Provos http->gencb = cb;
3967a3bb4a03SNiels Provos http->gencbarg = cbarg;
3968a3bb4a03SNiels Provos }
3969a3bb4a03SNiels Provos
39708d3a8500SNick Mathewson void
evhttp_set_bevcb(struct evhttp * http,struct bufferevent * (* cb)(struct event_base *,void *),void * cbarg)39718d3a8500SNick Mathewson evhttp_set_bevcb(struct evhttp *http,
39728d3a8500SNick Mathewson struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg)
39738d3a8500SNick Mathewson {
39748d3a8500SNick Mathewson http->bevcb = cb;
39758d3a8500SNick Mathewson http->bevcbarg = cbarg;
39768d3a8500SNick Mathewson }
39778d3a8500SNick Mathewson
3978a3bb4a03SNiels Provos /*
3979a3bb4a03SNiels Provos * Request related functions
3980a3bb4a03SNiels Provos */
3981a3bb4a03SNiels Provos
3982a3bb4a03SNiels Provos struct evhttp_request *
evhttp_request_new(void (* cb)(struct evhttp_request *,void *),void * arg)3983a3bb4a03SNiels Provos evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
3984a3bb4a03SNiels Provos {
3985a3bb4a03SNiels Provos struct evhttp_request *req = NULL;
3986a3bb4a03SNiels Provos
3987a3bb4a03SNiels Provos /* Allocate request structure */
398849868b61SNick Mathewson if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) {
3989a3bb4a03SNiels Provos event_warn("%s: calloc", __func__);
3990a3bb4a03SNiels Provos goto error;
3991a3bb4a03SNiels Provos }
3992a3bb4a03SNiels Provos
399347bad8abSNick Mathewson req->headers_size = 0;
399447bad8abSNick Mathewson req->body_size = 0;
399547bad8abSNick Mathewson
3996a3bb4a03SNiels Provos req->kind = EVHTTP_RESPONSE;
399749868b61SNick Mathewson req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq));
3998a3bb4a03SNiels Provos if (req->input_headers == NULL) {
3999a3bb4a03SNiels Provos event_warn("%s: calloc", __func__);
4000a3bb4a03SNiels Provos goto error;
4001a3bb4a03SNiels Provos }
4002a3bb4a03SNiels Provos TAILQ_INIT(req->input_headers);
4003a3bb4a03SNiels Provos
400449868b61SNick Mathewson req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq));
4005a3bb4a03SNiels Provos if (req->output_headers == NULL) {
4006a3bb4a03SNiels Provos event_warn("%s: calloc", __func__);
4007a3bb4a03SNiels Provos goto error;
4008a3bb4a03SNiels Provos }
4009a3bb4a03SNiels Provos TAILQ_INIT(req->output_headers);
4010a3bb4a03SNiels Provos
4011ba7262ebSNiels Provos if ((req->input_buffer = evbuffer_new()) == NULL) {
4012ba7262ebSNiels Provos event_warn("%s: evbuffer_new", __func__);
4013ba7262ebSNiels Provos goto error;
4014ba7262ebSNiels Provos }
4015ba7262ebSNiels Provos
4016ba7262ebSNiels Provos if ((req->output_buffer = evbuffer_new()) == NULL) {
4017ba7262ebSNiels Provos event_warn("%s: evbuffer_new", __func__);
4018ba7262ebSNiels Provos goto error;
4019ba7262ebSNiels Provos }
4020a3bb4a03SNiels Provos
4021a3bb4a03SNiels Provos req->cb = cb;
4022a3bb4a03SNiels Provos req->cb_arg = arg;
4023a3bb4a03SNiels Provos
4024a3bb4a03SNiels Provos return (req);
4025a3bb4a03SNiels Provos
4026a3bb4a03SNiels Provos error:
4027a3bb4a03SNiels Provos if (req != NULL)
4028a3bb4a03SNiels Provos evhttp_request_free(req);
4029a3bb4a03SNiels Provos return (NULL);
4030a3bb4a03SNiels Provos }
4031a3bb4a03SNiels Provos
4032a3bb4a03SNiels Provos void
evhttp_request_free(struct evhttp_request * req)4033a3bb4a03SNiels Provos evhttp_request_free(struct evhttp_request *req)
4034a3bb4a03SNiels Provos {
4035344c2b56SNiels Provos if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) {
4036344c2b56SNiels Provos req->flags |= EVHTTP_REQ_NEEDS_FREE;
4037344c2b56SNiels Provos return;
4038344c2b56SNiels Provos }
4039344c2b56SNiels Provos
4040a3bb4a03SNiels Provos if (req->remote_host != NULL)
404149868b61SNick Mathewson mm_free(req->remote_host);
4042a3bb4a03SNiels Provos if (req->uri != NULL)
404349868b61SNick Mathewson mm_free(req->uri);
4044aab8c38bSChristopher Davis if (req->uri_elems != NULL)
4045aab8c38bSChristopher Davis evhttp_uri_free(req->uri_elems);
4046a3bb4a03SNiels Provos if (req->response_code_line != NULL)
404749868b61SNick Mathewson mm_free(req->response_code_line);
4048aab8c38bSChristopher Davis if (req->host_cache != NULL)
4049aab8c38bSChristopher Davis mm_free(req->host_cache);
4050a3bb4a03SNiels Provos
4051a3bb4a03SNiels Provos evhttp_clear_headers(req->input_headers);
405249868b61SNick Mathewson mm_free(req->input_headers);
4053a3bb4a03SNiels Provos
4054a3bb4a03SNiels Provos evhttp_clear_headers(req->output_headers);
405549868b61SNick Mathewson mm_free(req->output_headers);
4056a3bb4a03SNiels Provos
4057ba7262ebSNiels Provos if (req->input_buffer != NULL)
4058ba7262ebSNiels Provos evbuffer_free(req->input_buffer);
4059ba7262ebSNiels Provos
4060ba7262ebSNiels Provos if (req->output_buffer != NULL)
4061ba7262ebSNiels Provos evbuffer_free(req->output_buffer);
4062ba7262ebSNiels Provos
406349868b61SNick Mathewson mm_free(req);
4064a3bb4a03SNiels Provos }
4065a3bb4a03SNiels Provos
40668901c141SNiels Provos void
evhttp_request_own(struct evhttp_request * req)4067955c6abfSNiels Provos evhttp_request_own(struct evhttp_request *req)
4068955c6abfSNiels Provos {
4069955c6abfSNiels Provos req->flags |= EVHTTP_USER_OWNED;
4070955c6abfSNiels Provos }
4071955c6abfSNiels Provos
4072955c6abfSNiels Provos int
evhttp_request_is_owned(struct evhttp_request * req)4073955c6abfSNiels Provos evhttp_request_is_owned(struct evhttp_request *req)
4074955c6abfSNiels Provos {
4075955c6abfSNiels Provos return (req->flags & EVHTTP_USER_OWNED) != 0;
4076955c6abfSNiels Provos }
4077955c6abfSNiels Provos
407893d73691SNiels Provos struct evhttp_connection *
evhttp_request_get_connection(struct evhttp_request * req)407993d73691SNiels Provos evhttp_request_get_connection(struct evhttp_request *req)
408093d73691SNiels Provos {
408193d73691SNiels Provos return req->evcon;
408293d73691SNiels Provos }
408393d73691SNiels Provos
4084cd00079bSNick Mathewson struct event_base *
evhttp_connection_get_base(struct evhttp_connection * conn)4085cd00079bSNick Mathewson evhttp_connection_get_base(struct evhttp_connection *conn)
4086cd00079bSNick Mathewson {
4087cd00079bSNick Mathewson return conn->base;
4088cd00079bSNick Mathewson }
408993d73691SNiels Provos
4090955c6abfSNiels Provos void
evhttp_request_set_chunked_cb(struct evhttp_request * req,void (* cb)(struct evhttp_request *,void *))40918901c141SNiels Provos evhttp_request_set_chunked_cb(struct evhttp_request *req,
40928901c141SNiels Provos void (*cb)(struct evhttp_request *, void *))
40938901c141SNiels Provos {
40948901c141SNiels Provos req->chunk_cb = cb;
40958901c141SNiels Provos }
40968901c141SNiels Provos
40977b077194SAzat Khuzhin void
evhttp_request_set_header_cb(struct evhttp_request * req,int (* cb)(struct evhttp_request *,void *))4098b0bd7fe1SBalint Reczey evhttp_request_set_header_cb(struct evhttp_request *req,
4099b0bd7fe1SBalint Reczey int (*cb)(struct evhttp_request *, void *))
4100b0bd7fe1SBalint Reczey {
4101b0bd7fe1SBalint Reczey req->header_cb = cb;
4102b0bd7fe1SBalint Reczey }
4103b0bd7fe1SBalint Reczey
4104b0bd7fe1SBalint Reczey void
evhttp_request_set_error_cb(struct evhttp_request * req,void (* cb)(enum evhttp_request_error,void *))41057b077194SAzat Khuzhin evhttp_request_set_error_cb(struct evhttp_request *req,
41067b077194SAzat Khuzhin void (*cb)(enum evhttp_request_error, void *))
41077b077194SAzat Khuzhin {
41087b077194SAzat Khuzhin req->error_cb = cb;
41097b077194SAzat Khuzhin }
41107b077194SAzat Khuzhin
4111b083ca05SAndrew Sweeney void
evhttp_request_set_on_complete_cb(struct evhttp_request * req,void (* cb)(struct evhttp_request *,void *),void * cb_arg)4112b083ca05SAndrew Sweeney evhttp_request_set_on_complete_cb(struct evhttp_request *req,
4113da86dda9SAndrew Sweeney void (*cb)(struct evhttp_request *, void *), void *cb_arg)
4114b083ca05SAndrew Sweeney {
4115b083ca05SAndrew Sweeney req->on_complete_cb = cb;
4116da86dda9SAndrew Sweeney req->on_complete_cb_arg = cb_arg;
4117b083ca05SAndrew Sweeney }
4118b083ca05SAndrew Sweeney
4119a3bb4a03SNiels Provos /*
412038b33048SNiels Provos * Allows for inspection of the request URI
412138b33048SNiels Provos */
412238b33048SNiels Provos
412338b33048SNiels Provos const char *
evhttp_request_get_uri(const struct evhttp_request * req)412449f4bf7cSNick Mathewson evhttp_request_get_uri(const struct evhttp_request *req) {
412538b33048SNiels Provos if (req->uri == NULL)
412677861fa7SNick Mathewson event_debug(("%s: request %p has no uri\n", __func__, req));
412738b33048SNiels Provos return (req->uri);
412838b33048SNiels Provos }
412938b33048SNiels Provos
4130aab8c38bSChristopher Davis const struct evhttp_uri *
evhttp_request_get_evhttp_uri(const struct evhttp_request * req)4131aab8c38bSChristopher Davis evhttp_request_get_evhttp_uri(const struct evhttp_request *req) {
4132aab8c38bSChristopher Davis if (req->uri_elems == NULL)
4133aab8c38bSChristopher Davis event_debug(("%s: request %p has no uri elems\n",
4134aab8c38bSChristopher Davis __func__, req));
4135aab8c38bSChristopher Davis return (req->uri_elems);
4136aab8c38bSChristopher Davis }
4137aab8c38bSChristopher Davis
4138aab8c38bSChristopher Davis const char *
evhttp_request_get_host(struct evhttp_request * req)4139aab8c38bSChristopher Davis evhttp_request_get_host(struct evhttp_request *req)
4140aab8c38bSChristopher Davis {
4141aab8c38bSChristopher Davis const char *host = NULL;
4142aab8c38bSChristopher Davis
4143aab8c38bSChristopher Davis if (req->host_cache)
4144aab8c38bSChristopher Davis return req->host_cache;
4145aab8c38bSChristopher Davis
4146aab8c38bSChristopher Davis if (req->uri_elems)
4147aab8c38bSChristopher Davis host = evhttp_uri_get_host(req->uri_elems);
4148aab8c38bSChristopher Davis if (!host && req->input_headers) {
4149aab8c38bSChristopher Davis const char *p;
4150aab8c38bSChristopher Davis size_t len;
4151aab8c38bSChristopher Davis
4152aab8c38bSChristopher Davis host = evhttp_find_header(req->input_headers, "Host");
4153aab8c38bSChristopher Davis /* The Host: header may include a port. Remove it here
4154aab8c38bSChristopher Davis to be consistent with uri_elems case above. */
4155aab8c38bSChristopher Davis if (host) {
4156aab8c38bSChristopher Davis p = host + strlen(host) - 1;
41578ac3c4c2SNick Mathewson while (p > host && EVUTIL_ISDIGIT_(*p))
4158aab8c38bSChristopher Davis --p;
4159aab8c38bSChristopher Davis if (p > host && *p == ':') {
4160aab8c38bSChristopher Davis len = p - host;
4161aab8c38bSChristopher Davis req->host_cache = mm_malloc(len + 1);
4162aab8c38bSChristopher Davis if (!req->host_cache) {
4163aab8c38bSChristopher Davis event_warn("%s: malloc", __func__);
4164aab8c38bSChristopher Davis return NULL;
4165aab8c38bSChristopher Davis }
4166aab8c38bSChristopher Davis memcpy(req->host_cache, host, len);
4167aab8c38bSChristopher Davis req->host_cache[len] = '\0';
4168aab8c38bSChristopher Davis host = req->host_cache;
4169aab8c38bSChristopher Davis }
4170aab8c38bSChristopher Davis }
4171aab8c38bSChristopher Davis }
4172aab8c38bSChristopher Davis
4173aab8c38bSChristopher Davis return host;
4174aab8c38bSChristopher Davis }
4175aab8c38bSChristopher Davis
417649f4bf7cSNick Mathewson enum evhttp_cmd_type
evhttp_request_get_command(const struct evhttp_request * req)417749f4bf7cSNick Mathewson evhttp_request_get_command(const struct evhttp_request *req) {
417849f4bf7cSNick Mathewson return (req->type);
417949f4bf7cSNick Mathewson }
418049f4bf7cSNick Mathewson
418122e0a9b2SNick Mathewson int
evhttp_request_get_response_code(const struct evhttp_request * req)418222e0a9b2SNick Mathewson evhttp_request_get_response_code(const struct evhttp_request *req)
418322e0a9b2SNick Mathewson {
418422e0a9b2SNick Mathewson return req->response_code;
418522e0a9b2SNick Mathewson }
418622e0a9b2SNick Mathewson
41874f4d0c93SJay R. Wren const char *
evhttp_request_get_response_code_line(const struct evhttp_request * req)41884f4d0c93SJay R. Wren evhttp_request_get_response_code_line(const struct evhttp_request *req)
41894f4d0c93SJay R. Wren {
41904f4d0c93SJay R. Wren return req->response_code_line;
41914f4d0c93SJay R. Wren }
41924f4d0c93SJay R. Wren
4193a57767faSNiels Provos /** Returns the input headers */
evhttp_request_get_input_headers(struct evhttp_request * req)4194a57767faSNiels Provos struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req)
4195a57767faSNiels Provos {
4196a57767faSNiels Provos return (req->input_headers);
4197a57767faSNiels Provos }
4198a57767faSNiels Provos
4199a57767faSNiels Provos /** Returns the output headers */
evhttp_request_get_output_headers(struct evhttp_request * req)4200a57767faSNiels Provos struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req)
4201a57767faSNiels Provos {
4202a57767faSNiels Provos return (req->output_headers);
4203a57767faSNiels Provos }
4204a57767faSNiels Provos
4205a57767faSNiels Provos /** Returns the input buffer */
evhttp_request_get_input_buffer(struct evhttp_request * req)4206a57767faSNiels Provos struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req)
4207a57767faSNiels Provos {
4208a57767faSNiels Provos return (req->input_buffer);
4209a57767faSNiels Provos }
4210a57767faSNiels Provos
4211a57767faSNiels Provos /** Returns the output buffer */
evhttp_request_get_output_buffer(struct evhttp_request * req)4212a57767faSNiels Provos struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req)
4213a57767faSNiels Provos {
4214a57767faSNiels Provos return (req->output_buffer);
4215a57767faSNiels Provos }
4216a57767faSNiels Provos
4217a57767faSNiels Provos
421838b33048SNiels Provos /*
4219a3bb4a03SNiels Provos * Takes a file descriptor to read a request from.
4220a3bb4a03SNiels Provos * The callback is executed once the whole request has been read.
4221a3bb4a03SNiels Provos */
4222a3bb4a03SNiels Provos
422336212f9dSNiels Provos static struct evhttp_connection*
evhttp_get_request_connection(struct evhttp * http,evutil_socket_t fd,struct sockaddr * sa,ev_socklen_t salen)422436212f9dSNiels Provos evhttp_get_request_connection(
422567947ce3SNiels Provos struct evhttp* http,
42267c20a6aeSNick Mathewson evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen)
4227a3bb4a03SNiels Provos {
4228ba7262ebSNiels Provos struct evhttp_connection *evcon;
4229fc41ffdeSNick Mathewson char *hostname = NULL, *portname = NULL;
42308d3a8500SNick Mathewson struct bufferevent* bev = NULL;
4231a3bb4a03SNiels Provos
42327c4da937SAzat Khuzhin #ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
42337c4da937SAzat Khuzhin if (sa->sa_family == AF_UNIX) {
4234e2790a7fSAzat Khuzhin struct sockaddr_un *sa_un = (struct sockaddr_un *)sa;
4235e2790a7fSAzat Khuzhin sa_un->sun_path[0] = '\0';
42367c4da937SAzat Khuzhin }
42377c4da937SAzat Khuzhin #endif
42387c4da937SAzat Khuzhin
4239a3bb4a03SNiels Provos name_from_addr(sa, salen, &hostname, &portname);
4240a55a67d5SNick Mathewson if (hostname == NULL || portname == NULL) {
424149868b61SNick Mathewson if (hostname) mm_free(hostname);
424249868b61SNick Mathewson if (portname) mm_free(portname);
42438863ff76SNick Mathewson return (NULL);
4244a55a67d5SNick Mathewson }
42458863ff76SNick Mathewson
424662bd2c44SNick Mathewson event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n",
424762bd2c44SNick Mathewson __func__, hostname, portname, EV_SOCK_ARG(fd)));
4248a3bb4a03SNiels Provos
4249ba7262ebSNiels Provos /* we need a connection object to put the http request on */
42508d3a8500SNick Mathewson if (http->bevcb != NULL) {
42518d3a8500SNick Mathewson bev = (*http->bevcb)(http->base, http->bevcbarg);
42528d3a8500SNick Mathewson }
42538d3a8500SNick Mathewson evcon = evhttp_connection_base_bufferevent_new(
42548d3a8500SNick Mathewson http->base, NULL, bev, hostname, atoi(portname));
425549868b61SNick Mathewson mm_free(hostname);
425649868b61SNick Mathewson mm_free(portname);
4257fc41ffdeSNick Mathewson if (evcon == NULL)
425836212f9dSNiels Provos return (NULL);
425967947ce3SNiels Provos
4260ac633aebSNick Mathewson evcon->max_headers_size = http->default_max_headers_size;
4261ac633aebSNick Mathewson evcon->max_body_size = http->default_max_body_size;
42629fde5189SAzat Khuzhin if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE)
42639fde5189SAzat Khuzhin evcon->flags |= EVHTTP_CON_LINGERING_CLOSE;
426447bad8abSNick Mathewson
4265ba7262ebSNiels Provos evcon->flags |= EVHTTP_CON_INCOMING;
42669998c0cbSNiels Provos evcon->state = EVCON_READING_FIRSTLINE;
4267a3bb4a03SNiels Provos
426836212f9dSNiels Provos evcon->fd = fd;
426936212f9dSNiels Provos
4270a8cc449eSAzat Khuzhin if (bufferevent_setfd(evcon->bufev, fd))
4271a8cc449eSAzat Khuzhin goto err;
4272a8cc449eSAzat Khuzhin if (bufferevent_enable(evcon->bufev, EV_READ))
4273a8cc449eSAzat Khuzhin goto err;
4274a8cc449eSAzat Khuzhin if (bufferevent_disable(evcon->bufev, EV_WRITE))
4275a8cc449eSAzat Khuzhin goto err;
42764215c003SGreg Hazel bufferevent_socket_set_conn_address_(evcon->bufev, sa, salen);
4277e44ef375SNiels Provos
427836212f9dSNiels Provos return (evcon);
4279a8cc449eSAzat Khuzhin
4280a8cc449eSAzat Khuzhin err:
4281a8cc449eSAzat Khuzhin evhttp_connection_free(evcon);
4282a8cc449eSAzat Khuzhin return (NULL);
4283ba7262ebSNiels Provos }
4284ba7262ebSNiels Provos
428536212f9dSNiels Provos static int
evhttp_associate_new_request_with_connection(struct evhttp_connection * evcon)428636212f9dSNiels Provos evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
428736212f9dSNiels Provos {
428836212f9dSNiels Provos struct evhttp *http = evcon->http_server;
428936212f9dSNiels Provos struct evhttp_request *req;
429036212f9dSNiels Provos if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
429136212f9dSNiels Provos return (-1);
4292ba7262ebSNiels Provos
4293f1691539SNiels Provos if ((req->remote_host = mm_strdup(evcon->address)) == NULL) {
4294f1691539SNiels Provos event_warn("%s: strdup", __func__);
4295f1691539SNiels Provos evhttp_request_free(req);
4296f1691539SNiels Provos return (-1);
4297f1691539SNiels Provos }
4298f1691539SNiels Provos req->remote_port = evcon->port;
4299f1691539SNiels Provos
4300ba7262ebSNiels Provos req->evcon = evcon; /* the request ends up owning the connection */
4301ba7262ebSNiels Provos req->flags |= EVHTTP_REQ_OWN_CONNECTION;
4302ba7262ebSNiels Provos
43039d8edf2fSNiels Provos /* We did not present the request to the user user yet, so treat it as
43049d8edf2fSNiels Provos * if the user was done with the request. This allows us to free the
43059d8edf2fSNiels Provos * request on a persistent connection if the client drops it without
43069d8edf2fSNiels Provos * sending a request.
43079d8edf2fSNiels Provos */
43089d8edf2fSNiels Provos req->userdone = 1;
43099d8edf2fSNiels Provos
4310ba7262ebSNiels Provos TAILQ_INSERT_TAIL(&evcon->requests, req, next);
4311ba7262ebSNiels Provos
4312a3bb4a03SNiels Provos req->kind = EVHTTP_REQUEST;
4313a3bb4a03SNiels Provos
4314a3bb4a03SNiels Provos
43158ac3c4c2SNick Mathewson evhttp_start_read_(evcon);
431636212f9dSNiels Provos
431736212f9dSNiels Provos return (0);
431836212f9dSNiels Provos }
431936212f9dSNiels Provos
432090b3ed5bSNick Mathewson static void
evhttp_get_request(struct evhttp * http,evutil_socket_t fd,struct sockaddr * sa,ev_socklen_t salen)43211120f04fSNick Mathewson evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
43227c20a6aeSNick Mathewson struct sockaddr *sa, ev_socklen_t salen)
432336212f9dSNiels Provos {
432436212f9dSNiels Provos struct evhttp_connection *evcon;
432536212f9dSNiels Provos
432667947ce3SNiels Provos evcon = evhttp_get_request_connection(http, fd, sa, salen);
432730abfd99SNiels Provos if (evcon == NULL) {
432894866c27SNick Mathewson event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT,
432994866c27SNick Mathewson __func__, EV_SOCK_ARG(fd));
4330899c1dccSSebastian Sjöberg evutil_closesocket(fd);
433136212f9dSNiels Provos return;
433230abfd99SNiels Provos }
433336212f9dSNiels Provos
4334942656bbSNiels Provos /* the timeout can be used by the server to close idle connections */
43356350e6c4SConstantine Verutin if (evutil_timerisset(&http->timeout))
43366350e6c4SConstantine Verutin evhttp_connection_set_timeout_tv(evcon, &http->timeout);
4337942656bbSNiels Provos
433836212f9dSNiels Provos /*
433936212f9dSNiels Provos * if we want to accept more than one request on a connection,
434036212f9dSNiels Provos * we need to know which http server it belongs to.
434136212f9dSNiels Provos */
434236212f9dSNiels Provos evcon->http_server = http;
434336212f9dSNiels Provos TAILQ_INSERT_TAIL(&http->connections, evcon, next);
434436212f9dSNiels Provos
434536212f9dSNiels Provos if (evhttp_associate_new_request_with_connection(evcon) == -1)
434636212f9dSNiels Provos evhttp_connection_free(evcon);
4347a3bb4a03SNiels Provos }
4348a3bb4a03SNiels Provos
4349a3bb4a03SNiels Provos
4350a3bb4a03SNiels Provos /*
4351a3bb4a03SNiels Provos * Network helper functions that we do not want to export to the rest of
4352a3bb4a03SNiels Provos * the world.
4353a3bb4a03SNiels Provos */
4354a3bb4a03SNiels Provos
4355a3bb4a03SNiels Provos static void
name_from_addr(struct sockaddr * sa,ev_socklen_t salen,char ** phost,char ** pport)43567c20a6aeSNick Mathewson name_from_addr(struct sockaddr *sa, ev_socklen_t salen,
4357a3bb4a03SNiels Provos char **phost, char **pport)
4358a3bb4a03SNiels Provos {
4359fc41ffdeSNick Mathewson char ntop[NI_MAXHOST];
4360fc41ffdeSNick Mathewson char strport[NI_MAXSERV];
4361d5d04949SNiels Provos int ni_result;
4362a3bb4a03SNiels Provos
436368120d9bSNick Mathewson #ifdef EVENT__HAVE_GETNAMEINFO
436430abfd99SNiels Provos ni_result = getnameinfo(sa, salen,
4365a3bb4a03SNiels Provos ntop, sizeof(ntop), strport, sizeof(strport),
436624580e2bSNiels Provos NI_NUMERICHOST|NI_NUMERICSERV);
436730abfd99SNiels Provos
436830abfd99SNiels Provos if (ni_result != 0) {
436986f57420SNick Mathewson #ifdef EAI_SYSTEM
437086f57420SNick Mathewson /* Windows doesn't have an EAI_SYSTEM. */
4371d5d04949SNiels Provos if (ni_result == EAI_SYSTEM)
4372a3bb4a03SNiels Provos event_err(1, "getnameinfo failed");
4373d5d04949SNiels Provos else
437486f57420SNick Mathewson #endif
4375d5d04949SNiels Provos event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
4376fc41ffdeSNick Mathewson return;
4377d5d04949SNiels Provos }
437830abfd99SNiels Provos #else
437930abfd99SNiels Provos ni_result = fake_getnameinfo(sa, salen,
438030abfd99SNiels Provos ntop, sizeof(ntop), strport, sizeof(strport),
438130abfd99SNiels Provos NI_NUMERICHOST|NI_NUMERICSERV);
438230abfd99SNiels Provos if (ni_result != 0)
438330abfd99SNiels Provos return;
438430abfd99SNiels Provos #endif
4385a3bb4a03SNiels Provos
438649868b61SNick Mathewson *phost = mm_strdup(ntop);
438749868b61SNick Mathewson *pport = mm_strdup(strport);
4388a3bb4a03SNiels Provos }
4389a3bb4a03SNiels Provos
439050202d75SNiels Provos /* Create a non-blocking socket and bind it */
43911120f04fSNick Mathewson static evutil_socket_t
create_bind_socket_nonblock(struct evutil_addrinfo * ai,int reuse)4392c169bdcbSyuangongji create_bind_socket_nonblock(struct evutil_addrinfo *ai, int reuse)
4393a3bb4a03SNiels Provos {
43941120f04fSNick Mathewson evutil_socket_t fd;
43951120f04fSNick Mathewson
43961120f04fSNick Mathewson int on = 1, r;
4397a3bb4a03SNiels Provos int serrno;
4398a3bb4a03SNiels Provos
4399a3bb4a03SNiels Provos /* Create listen socket */
44008ac3c4c2SNick Mathewson fd = evutil_socket_(ai ? ai->ai_family : AF_INET,
4401af6c9d8eSNick Mathewson SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
4402a3bb4a03SNiels Provos if (fd == -1) {
4403de069b99SNick Mathewson event_sock_warn(-1, "socket");
4404a3bb4a03SNiels Provos return (-1);
4405a3bb4a03SNiels Provos }
4406a3bb4a03SNiels Provos
4407a0912e32SNick Mathewson if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0)
4408a0912e32SNick Mathewson goto out;
4409a0912e32SNick Mathewson if (reuse) {
4410a0912e32SNick Mathewson if (evutil_make_listen_socket_reuseable(fd) < 0)
4411a0912e32SNick Mathewson goto out;
4412a0912e32SNick Mathewson }
4413a3bb4a03SNiels Provos
441450202d75SNiels Provos if (ai != NULL) {
4415545a6114SNick Mathewson r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen);
441698f9616bSNiels Provos if (r == -1)
441798f9616bSNiels Provos goto out;
441850202d75SNiels Provos }
441998f9616bSNiels Provos
442098f9616bSNiels Provos return (fd);
442198f9616bSNiels Provos
442298f9616bSNiels Provos out:
4423fe482977SNick Mathewson serrno = EVUTIL_SOCKET_ERROR();
4424899c1dccSSebastian Sjöberg evutil_closesocket(fd);
4425fe482977SNick Mathewson EVUTIL_SET_SOCKET_ERROR(serrno);
442698f9616bSNiels Provos return (-1);
442798f9616bSNiels Provos }
442898f9616bSNiels Provos
442986f57420SNick Mathewson static struct evutil_addrinfo *
make_addrinfo(const char * address,ev_uint16_t port)44306bf1ca78SNick Mathewson make_addrinfo(const char *address, ev_uint16_t port)
443198f9616bSNiels Provos {
443286f57420SNick Mathewson struct evutil_addrinfo *ai = NULL;
443398f9616bSNiels Provos
443486f57420SNick Mathewson struct evutil_addrinfo hints;
443598f9616bSNiels Provos char strport[NI_MAXSERV];
443698f9616bSNiels Provos int ai_result;
443798f9616bSNiels Provos
443886f57420SNick Mathewson memset(&hints, 0, sizeof(hints));
443986f57420SNick Mathewson hints.ai_family = AF_UNSPEC;
444086f57420SNick Mathewson hints.ai_socktype = SOCK_STREAM;
444186f57420SNick Mathewson /* turn NULL hostname into INADDR_ANY, and skip looking up any address
444286f57420SNick Mathewson * types we don't have an interface to connect to. */
444386f57420SNick Mathewson hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG;
4444c6da86ffSNick Mathewson evutil_snprintf(strport, sizeof(strport), "%d", port);
444586f57420SNick Mathewson if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai))
444686f57420SNick Mathewson != 0) {
444786f57420SNick Mathewson if (ai_result == EVUTIL_EAI_SYSTEM)
444898f9616bSNiels Provos event_warn("getaddrinfo");
4449868f10e7SNiels Provos else
445086f57420SNick Mathewson event_warnx("getaddrinfo: %s",
445186f57420SNick Mathewson evutil_gai_strerror(ai_result));
445298f9616bSNiels Provos return (NULL);
445398f9616bSNiels Provos }
445498f9616bSNiels Provos
445586f57420SNick Mathewson return (ai);
445698f9616bSNiels Provos }
445798f9616bSNiels Provos
44581120f04fSNick Mathewson static evutil_socket_t
bind_socket(const char * address,ev_uint16_t port,int reuse)44594c56ba1cSNiels Provos bind_socket(const char *address, ev_uint16_t port, int reuse)
446098f9616bSNiels Provos {
44611120f04fSNick Mathewson evutil_socket_t fd;
446286f57420SNick Mathewson struct evutil_addrinfo *aitop = NULL;
446350202d75SNiels Provos
446450202d75SNiels Provos /* just create an unbound socket */
446550202d75SNiels Provos if (address == NULL && port == 0)
4466c169bdcbSyuangongji return create_bind_socket_nonblock(NULL, 0);
446750202d75SNiels Provos
446850202d75SNiels Provos aitop = make_addrinfo(address, port);
446998f9616bSNiels Provos
447098f9616bSNiels Provos if (aitop == NULL)
447198f9616bSNiels Provos return (-1);
447298f9616bSNiels Provos
4473c169bdcbSyuangongji fd = create_bind_socket_nonblock(aitop, reuse);
447498f9616bSNiels Provos
447586f57420SNick Mathewson evutil_freeaddrinfo(aitop);
447698f9616bSNiels Provos
447798f9616bSNiels Provos return (fd);
447898f9616bSNiels Provos }
447998f9616bSNiels Provos
448045f6869cSNick Mathewson struct evhttp_uri {
448195060b54SNick Mathewson unsigned flags;
448245f6869cSNick Mathewson char *scheme; /* scheme; e.g http, ftp etc */
448345f6869cSNick Mathewson char *userinfo; /* userinfo (typically username:pass), or NULL */
448445f6869cSNick Mathewson char *host; /* hostname, IP address, or NULL */
448545f6869cSNick Mathewson int port; /* port, or zero */
448645f6869cSNick Mathewson char *path; /* path, or "". */
448745f6869cSNick Mathewson char *query; /* query, or NULL */
448845f6869cSNick Mathewson char *fragment; /* fragment or NULL */
448945f6869cSNick Mathewson };
449045f6869cSNick Mathewson
449145f6869cSNick Mathewson struct evhttp_uri *
evhttp_uri_new(void)449245f6869cSNick Mathewson evhttp_uri_new(void)
449345f6869cSNick Mathewson {
449445f6869cSNick Mathewson struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1);
449545f6869cSNick Mathewson if (uri)
449645f6869cSNick Mathewson uri->port = -1;
449745f6869cSNick Mathewson return uri;
449845f6869cSNick Mathewson }
449945f6869cSNick Mathewson
450095060b54SNick Mathewson void
evhttp_uri_set_flags(struct evhttp_uri * uri,unsigned flags)450195060b54SNick Mathewson evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags)
450295060b54SNick Mathewson {
450395060b54SNick Mathewson uri->flags = flags;
450495060b54SNick Mathewson }
450595060b54SNick Mathewson
450695060b54SNick Mathewson /* Return true if the string starting at s and ending immediately before eos
4507eaa5f1d9SNick Mathewson * is a valid URI scheme according to RFC3986
4508eaa5f1d9SNick Mathewson */
4509eaa5f1d9SNick Mathewson static int
scheme_ok(const char * s,const char * eos)4510eaa5f1d9SNick Mathewson scheme_ok(const char *s, const char *eos)
4511eaa5f1d9SNick Mathewson {
4512eaa5f1d9SNick Mathewson /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
4513eaa5f1d9SNick Mathewson EVUTIL_ASSERT(eos >= s);
4514eaa5f1d9SNick Mathewson if (s == eos)
4515eaa5f1d9SNick Mathewson return 0;
45168ac3c4c2SNick Mathewson if (!EVUTIL_ISALPHA_(*s))
4517eaa5f1d9SNick Mathewson return 0;
4518eaa5f1d9SNick Mathewson while (++s < eos) {
45198ac3c4c2SNick Mathewson if (! EVUTIL_ISALNUM_(*s) &&
4520eaa5f1d9SNick Mathewson *s != '+' && *s != '-' && *s != '.')
4521eaa5f1d9SNick Mathewson return 0;
4522eaa5f1d9SNick Mathewson }
4523eaa5f1d9SNick Mathewson return 1;
4524eaa5f1d9SNick Mathewson }
4525eaa5f1d9SNick Mathewson
4526eaa5f1d9SNick Mathewson #define SUBDELIMS "!$&'()*+,;="
4527eaa5f1d9SNick Mathewson
4528eaa5f1d9SNick Mathewson /* Return true iff [s..eos) is a valid userinfo */
4529eaa5f1d9SNick Mathewson static int
userinfo_ok(const char * s,const char * eos)4530eaa5f1d9SNick Mathewson userinfo_ok(const char *s, const char *eos)
4531eaa5f1d9SNick Mathewson {
4532eaa5f1d9SNick Mathewson while (s < eos) {
4533eaa5f1d9SNick Mathewson if (CHAR_IS_UNRESERVED(*s) ||
4534eaa5f1d9SNick Mathewson strchr(SUBDELIMS, *s) ||
4535eaa5f1d9SNick Mathewson *s == ':')
4536eaa5f1d9SNick Mathewson ++s;
4537eaa5f1d9SNick Mathewson else if (*s == '%' && s+2 < eos &&
45388ac3c4c2SNick Mathewson EVUTIL_ISXDIGIT_(s[1]) &&
45398ac3c4c2SNick Mathewson EVUTIL_ISXDIGIT_(s[2]))
4540eaa5f1d9SNick Mathewson s += 3;
4541eaa5f1d9SNick Mathewson else
4542eaa5f1d9SNick Mathewson return 0;
4543eaa5f1d9SNick Mathewson }
4544eaa5f1d9SNick Mathewson return 1;
4545eaa5f1d9SNick Mathewson }
4546eaa5f1d9SNick Mathewson
4547eaa5f1d9SNick Mathewson static int
regname_ok(const char * s,const char * eos)4548eaa5f1d9SNick Mathewson regname_ok(const char *s, const char *eos)
4549eaa5f1d9SNick Mathewson {
4550eaa5f1d9SNick Mathewson while (s && s<eos) {
4551eaa5f1d9SNick Mathewson if (CHAR_IS_UNRESERVED(*s) ||
4552eaa5f1d9SNick Mathewson strchr(SUBDELIMS, *s))
4553eaa5f1d9SNick Mathewson ++s;
4554eaa5f1d9SNick Mathewson else if (*s == '%' &&
45558ac3c4c2SNick Mathewson EVUTIL_ISXDIGIT_(s[1]) &&
45568ac3c4c2SNick Mathewson EVUTIL_ISXDIGIT_(s[2]))
4557eaa5f1d9SNick Mathewson s += 3;
4558eaa5f1d9SNick Mathewson else
4559eaa5f1d9SNick Mathewson return 0;
4560eaa5f1d9SNick Mathewson }
4561eaa5f1d9SNick Mathewson return 1;
4562eaa5f1d9SNick Mathewson }
4563eaa5f1d9SNick Mathewson
4564eaa5f1d9SNick Mathewson static int
parse_port(const char * s,const char * eos)4565eaa5f1d9SNick Mathewson parse_port(const char *s, const char *eos)
4566eaa5f1d9SNick Mathewson {
4567eaa5f1d9SNick Mathewson int portnum = 0;
4568eaa5f1d9SNick Mathewson while (s < eos) {
45698ac3c4c2SNick Mathewson if (! EVUTIL_ISDIGIT_(*s))
4570eaa5f1d9SNick Mathewson return -1;
4571eaa5f1d9SNick Mathewson portnum = (portnum * 10) + (*s - '0');
4572a5a76e68SNick Mathewson if (portnum < 0)
4573a5a76e68SNick Mathewson return -1;
4574e660db6dSNick Mathewson if (portnum > 65535)
4575e660db6dSNick Mathewson return -1;
4576eaa5f1d9SNick Mathewson ++s;
4577eaa5f1d9SNick Mathewson }
4578eaa5f1d9SNick Mathewson return portnum;
4579eaa5f1d9SNick Mathewson }
4580eaa5f1d9SNick Mathewson
4581eaa5f1d9SNick Mathewson /* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */
4582eaa5f1d9SNick Mathewson static int
bracket_addr_ok(const char * s,const char * eos)4583eaa5f1d9SNick Mathewson bracket_addr_ok(const char *s, const char *eos)
4584eaa5f1d9SNick Mathewson {
4585eaa5f1d9SNick Mathewson if (s + 3 > eos || *s != '[' || *(eos-1) != ']')
4586eaa5f1d9SNick Mathewson return 0;
4587eaa5f1d9SNick Mathewson if (s[1] == 'v') {
4588eaa5f1d9SNick Mathewson /* IPvFuture, or junk.
4589eaa5f1d9SNick Mathewson "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
4590eaa5f1d9SNick Mathewson */
4591eaa5f1d9SNick Mathewson s += 2; /* skip [v */
4592eaa5f1d9SNick Mathewson --eos;
45938ac3c4c2SNick Mathewson if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/
4594eaa5f1d9SNick Mathewson return 0;
4595eaa5f1d9SNick Mathewson while (s < eos && *s != '.') {
45968ac3c4c2SNick Mathewson if (EVUTIL_ISXDIGIT_(*s))
4597eaa5f1d9SNick Mathewson ++s;
4598eaa5f1d9SNick Mathewson else
4599eaa5f1d9SNick Mathewson return 0;
4600eaa5f1d9SNick Mathewson }
4601eaa5f1d9SNick Mathewson if (*s != '.')
4602eaa5f1d9SNick Mathewson return 0;
4603eaa5f1d9SNick Mathewson ++s;
4604eaa5f1d9SNick Mathewson while (s < eos) {
4605eaa5f1d9SNick Mathewson if (CHAR_IS_UNRESERVED(*s) ||
4606eaa5f1d9SNick Mathewson strchr(SUBDELIMS, *s) ||
4607eaa5f1d9SNick Mathewson *s == ':')
4608eaa5f1d9SNick Mathewson ++s;
4609eaa5f1d9SNick Mathewson else
4610eaa5f1d9SNick Mathewson return 0;
4611eaa5f1d9SNick Mathewson }
4612eaa5f1d9SNick Mathewson return 2;
4613eaa5f1d9SNick Mathewson } else {
4614eaa5f1d9SNick Mathewson /* IPv6, or junk */
4615eaa5f1d9SNick Mathewson char buf[64];
4616545a6114SNick Mathewson ev_ssize_t n_chars = eos-s-2;
4617eaa5f1d9SNick Mathewson struct in6_addr in6;
4618eaa5f1d9SNick Mathewson if (n_chars >= 64) /* way too long */
4619eaa5f1d9SNick Mathewson return 0;
4620eaa5f1d9SNick Mathewson memcpy(buf, s+1, n_chars);
4621eaa5f1d9SNick Mathewson buf[n_chars]='\0';
4622eaa5f1d9SNick Mathewson return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0;
4623eaa5f1d9SNick Mathewson }
4624eaa5f1d9SNick Mathewson }
4625eaa5f1d9SNick Mathewson
4626eaa5f1d9SNick Mathewson static int
parse_authority(struct evhttp_uri * uri,char * s,char * eos)4627eaa5f1d9SNick Mathewson parse_authority(struct evhttp_uri *uri, char *s, char *eos)
4628eaa5f1d9SNick Mathewson {
4629eaa5f1d9SNick Mathewson char *cp, *port;
4630eaa5f1d9SNick Mathewson EVUTIL_ASSERT(eos);
4631eaa5f1d9SNick Mathewson if (eos == s) {
4632eaa5f1d9SNick Mathewson uri->host = mm_strdup("");
4633666b0966SJardel Weyrich if (uri->host == NULL) {
4634666b0966SJardel Weyrich event_warn("%s: strdup", __func__);
4635666b0966SJardel Weyrich return -1;
4636666b0966SJardel Weyrich }
4637eaa5f1d9SNick Mathewson return 0;
4638eaa5f1d9SNick Mathewson }
4639eaa5f1d9SNick Mathewson
4640eaa5f1d9SNick Mathewson /* Optionally, we start with "userinfo@" */
4641eaa5f1d9SNick Mathewson
4642eaa5f1d9SNick Mathewson cp = strchr(s, '@');
4643eaa5f1d9SNick Mathewson if (cp && cp < eos) {
4644eaa5f1d9SNick Mathewson if (! userinfo_ok(s,cp))
4645eaa5f1d9SNick Mathewson return -1;
4646eaa5f1d9SNick Mathewson *cp++ = '\0';
4647eaa5f1d9SNick Mathewson uri->userinfo = mm_strdup(s);
4648666b0966SJardel Weyrich if (uri->userinfo == NULL) {
4649666b0966SJardel Weyrich event_warn("%s: strdup", __func__);
4650666b0966SJardel Weyrich return -1;
4651666b0966SJardel Weyrich }
4652eaa5f1d9SNick Mathewson } else {
4653eaa5f1d9SNick Mathewson cp = s;
4654eaa5f1d9SNick Mathewson }
4655eaa5f1d9SNick Mathewson /* Optionally, we end with ":port" */
46568ac3c4c2SNick Mathewson for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port)
4657eaa5f1d9SNick Mathewson ;
4658eaa5f1d9SNick Mathewson if (port >= cp && *port == ':') {
4659a5a76e68SNick Mathewson if (port+1 == eos) /* Leave port unspecified; the RFC allows a
4660a5a76e68SNick Mathewson * nil port */
4661a5a76e68SNick Mathewson uri->port = -1;
4662a5a76e68SNick Mathewson else if ((uri->port = parse_port(port+1, eos))<0)
4663eaa5f1d9SNick Mathewson return -1;
4664eaa5f1d9SNick Mathewson eos = port;
4665eaa5f1d9SNick Mathewson }
4666eaa5f1d9SNick Mathewson /* Now, cp..eos holds the "host" port, which can be an IPv4Address,
4667eaa5f1d9SNick Mathewson * an IP-Literal, or a reg-name */
4668eaa5f1d9SNick Mathewson EVUTIL_ASSERT(eos >= cp);
4669eaa5f1d9SNick Mathewson if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') {
4670eaa5f1d9SNick Mathewson /* IPv6address, IP-Literal, or junk. */
4671eaa5f1d9SNick Mathewson if (! bracket_addr_ok(cp, eos))
4672eaa5f1d9SNick Mathewson return -1;
4673eaa5f1d9SNick Mathewson } else {
4674eaa5f1d9SNick Mathewson /* Make sure the host part is ok. */
4675eaa5f1d9SNick Mathewson if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */
4676eaa5f1d9SNick Mathewson return -1;
4677eaa5f1d9SNick Mathewson }
4678eaa5f1d9SNick Mathewson uri->host = mm_malloc(eos-cp+1);
4679666b0966SJardel Weyrich if (uri->host == NULL) {
4680666b0966SJardel Weyrich event_warn("%s: malloc", __func__);
4681666b0966SJardel Weyrich return -1;
4682666b0966SJardel Weyrich }
4683eaa5f1d9SNick Mathewson memcpy(uri->host, cp, eos-cp);
4684eaa5f1d9SNick Mathewson uri->host[eos-cp] = '\0';
4685eaa5f1d9SNick Mathewson return 0;
4686eaa5f1d9SNick Mathewson
4687eaa5f1d9SNick Mathewson }
4688eaa5f1d9SNick Mathewson
4689a5a76e68SNick Mathewson static char *
end_of_authority(char * cp)4690a5a76e68SNick Mathewson end_of_authority(char *cp)
4691a5a76e68SNick Mathewson {
4692a5a76e68SNick Mathewson while (*cp) {
4693a5a76e68SNick Mathewson if (*cp == '?' || *cp == '#' || *cp == '/')
4694a5a76e68SNick Mathewson return cp;
4695a5a76e68SNick Mathewson ++cp;
4696a5a76e68SNick Mathewson }
4697a5a76e68SNick Mathewson return cp;
4698a5a76e68SNick Mathewson }
4699a5a76e68SNick Mathewson
470095060b54SNick Mathewson enum uri_part {
470195060b54SNick Mathewson PART_PATH,
470295060b54SNick Mathewson PART_QUERY,
470395060b54SNick Mathewson PART_FRAGMENT
470495060b54SNick Mathewson };
470595060b54SNick Mathewson
4706eaa5f1d9SNick Mathewson /* Return the character after the longest prefix of 'cp' that matches...
4707eaa5f1d9SNick Mathewson * *pchar / "/" if allow_qchars is false, or
470895060b54SNick Mathewson * *(pchar / "/" / "?") if allow_qchars is true.
4709eaa5f1d9SNick Mathewson */
4710eaa5f1d9SNick Mathewson static char *
end_of_path(char * cp,enum uri_part part,unsigned flags)471195060b54SNick Mathewson end_of_path(char *cp, enum uri_part part, unsigned flags)
4712eaa5f1d9SNick Mathewson {
471395060b54SNick Mathewson if (flags & EVHTTP_URI_NONCONFORMANT) {
471495060b54SNick Mathewson /* If NONCONFORMANT:
471595060b54SNick Mathewson * Path is everything up to a # or ? or nul.
471695060b54SNick Mathewson * Query is everything up a # or nul
471795060b54SNick Mathewson * Fragment is everything up to a nul.
471895060b54SNick Mathewson */
471995060b54SNick Mathewson switch (part) {
472095060b54SNick Mathewson case PART_PATH:
472195060b54SNick Mathewson while (*cp && *cp != '#' && *cp != '?')
472295060b54SNick Mathewson ++cp;
472395060b54SNick Mathewson break;
472495060b54SNick Mathewson case PART_QUERY:
472595060b54SNick Mathewson while (*cp && *cp != '#')
472695060b54SNick Mathewson ++cp;
472795060b54SNick Mathewson break;
472895060b54SNick Mathewson case PART_FRAGMENT:
472995060b54SNick Mathewson cp += strlen(cp);
473095060b54SNick Mathewson break;
473195060b54SNick Mathewson };
473295060b54SNick Mathewson return cp;
473395060b54SNick Mathewson }
473495060b54SNick Mathewson
4735eaa5f1d9SNick Mathewson while (*cp) {
4736eaa5f1d9SNick Mathewson if (CHAR_IS_UNRESERVED(*cp) ||
4737eaa5f1d9SNick Mathewson strchr(SUBDELIMS, *cp) ||
4738eaa5f1d9SNick Mathewson *cp == ':' || *cp == '@' || *cp == '/')
4739eaa5f1d9SNick Mathewson ++cp;
47408ac3c4c2SNick Mathewson else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) &&
47418ac3c4c2SNick Mathewson EVUTIL_ISXDIGIT_(cp[2]))
4742eaa5f1d9SNick Mathewson cp += 3;
474395060b54SNick Mathewson else if (*cp == '?' && part != PART_PATH)
4744eaa5f1d9SNick Mathewson ++cp;
4745eaa5f1d9SNick Mathewson else
4746eaa5f1d9SNick Mathewson return cp;
4747eaa5f1d9SNick Mathewson }
4748eaa5f1d9SNick Mathewson return cp;
4749eaa5f1d9SNick Mathewson }
4750eaa5f1d9SNick Mathewson
4751a5a76e68SNick Mathewson static int
path_matches_noscheme(const char * cp)4752a5a76e68SNick Mathewson path_matches_noscheme(const char *cp)
4753a5a76e68SNick Mathewson {
4754a5a76e68SNick Mathewson while (*cp) {
4755a5a76e68SNick Mathewson if (*cp == ':')
4756a5a76e68SNick Mathewson return 0;
4757a5a76e68SNick Mathewson else if (*cp == '/')
4758a5a76e68SNick Mathewson return 1;
4759a5a76e68SNick Mathewson ++cp;
4760a5a76e68SNick Mathewson }
4761a5a76e68SNick Mathewson return 1;
4762a5a76e68SNick Mathewson }
4763a5a76e68SNick Mathewson
476486212341SNick Mathewson struct evhttp_uri *
evhttp_uri_parse(const char * source_uri)476586212341SNick Mathewson evhttp_uri_parse(const char *source_uri)
476686dd720aSPavel Plesov {
476795060b54SNick Mathewson return evhttp_uri_parse_with_flags(source_uri, 0);
476895060b54SNick Mathewson }
476995060b54SNick Mathewson
477095060b54SNick Mathewson struct evhttp_uri *
evhttp_uri_parse_with_flags(const char * source_uri,unsigned flags)477195060b54SNick Mathewson evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags)
477295060b54SNick Mathewson {
4773eaa5f1d9SNick Mathewson char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL;
4774eaa5f1d9SNick Mathewson char *path = NULL, *fragment = NULL;
4775eaa5f1d9SNick Mathewson int got_authority = 0;
477686dd720aSPavel Plesov
477786212341SNick Mathewson struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
477886dd720aSPavel Plesov if (uri == NULL) {
47793f8d22a1SJardel Weyrich event_warn("%s: calloc", __func__);
4780fadbfd4eSNick Mathewson goto err;
478186dd720aSPavel Plesov }
4782eaa5f1d9SNick Mathewson uri->port = -1;
478395060b54SNick Mathewson uri->flags = flags;
478486dd720aSPavel Plesov
478586212341SNick Mathewson readbuf = mm_strdup(source_uri);
478686dd720aSPavel Plesov if (readbuf == NULL) {
47873f8d22a1SJardel Weyrich event_warn("%s: strdup", __func__);
4788fadbfd4eSNick Mathewson goto err;
478986dd720aSPavel Plesov }
479086dd720aSPavel Plesov
479186dd720aSPavel Plesov readp = readbuf;
479286dd720aSPavel Plesov token = NULL;
479386dd720aSPavel Plesov
4794eaa5f1d9SNick Mathewson /* We try to follow RFC3986 here as much as we can, and match
4795eaa5f1d9SNick Mathewson the productions
479686dd720aSPavel Plesov
4797eaa5f1d9SNick Mathewson URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
4798eaa5f1d9SNick Mathewson
4799eaa5f1d9SNick Mathewson relative-ref = relative-part [ "?" query ] [ "#" fragment ]
4800eaa5f1d9SNick Mathewson */
4801eaa5f1d9SNick Mathewson
4802eaa5f1d9SNick Mathewson /* 1. scheme: */
4803eaa5f1d9SNick Mathewson token = strchr(readp, ':');
4804eaa5f1d9SNick Mathewson if (token && scheme_ok(readp,token)) {
480586dd720aSPavel Plesov *token = '\0';
480686212341SNick Mathewson uri->scheme = mm_strdup(readp);
4807666b0966SJardel Weyrich if (uri->scheme == NULL) {
48083f8d22a1SJardel Weyrich event_warn("%s: strdup", __func__);
4809666b0966SJardel Weyrich goto err;
4810666b0966SJardel Weyrich }
4811eaa5f1d9SNick Mathewson readp = token+1; /* eat : */
481286dd720aSPavel Plesov }
481386dd720aSPavel Plesov
4814eaa5f1d9SNick Mathewson /* 2. Optionally, "//" then an 'authority' part. */
4815eaa5f1d9SNick Mathewson if (readp[0]=='/' && readp[1] == '/') {
4816eaa5f1d9SNick Mathewson char *authority;
4817eaa5f1d9SNick Mathewson readp += 2;
4818eaa5f1d9SNick Mathewson authority = readp;
4819a5a76e68SNick Mathewson path = end_of_authority(readp);
4820eaa5f1d9SNick Mathewson if (parse_authority(uri, authority, path) < 0)
4821eaa5f1d9SNick Mathewson goto err;
4822eaa5f1d9SNick Mathewson readp = path;
4823eaa5f1d9SNick Mathewson got_authority = 1;
4824eaa5f1d9SNick Mathewson }
4825eaa5f1d9SNick Mathewson
4826eaa5f1d9SNick Mathewson /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty
4827eaa5f1d9SNick Mathewson */
4828eaa5f1d9SNick Mathewson path = readp;
482995060b54SNick Mathewson readp = end_of_path(path, PART_PATH, flags);
4830eaa5f1d9SNick Mathewson
4831eaa5f1d9SNick Mathewson /* Query */
4832eaa5f1d9SNick Mathewson if (*readp == '?') {
4833eaa5f1d9SNick Mathewson *readp = '\0';
4834eaa5f1d9SNick Mathewson ++readp;
4835eaa5f1d9SNick Mathewson query = readp;
483695060b54SNick Mathewson readp = end_of_path(readp, PART_QUERY, flags);
4837eaa5f1d9SNick Mathewson }
4838eaa5f1d9SNick Mathewson /* fragment */
4839eaa5f1d9SNick Mathewson if (*readp == '#') {
4840eaa5f1d9SNick Mathewson *readp = '\0';
4841eaa5f1d9SNick Mathewson ++readp;
4842eaa5f1d9SNick Mathewson fragment = readp;
484395060b54SNick Mathewson readp = end_of_path(readp, PART_FRAGMENT, flags);
4844eaa5f1d9SNick Mathewson }
4845eaa5f1d9SNick Mathewson if (*readp != '\0') {
4846eaa5f1d9SNick Mathewson goto err;
4847eaa5f1d9SNick Mathewson }
4848eaa5f1d9SNick Mathewson
4849a5a76e68SNick Mathewson /* These next two cases may be unreachable; I'm leaving them
4850a5a76e68SNick Mathewson * in to be defensive. */
4851eaa5f1d9SNick Mathewson /* If you didn't get an authority, the path can't begin with "//" */
4852eaa5f1d9SNick Mathewson if (!got_authority && path[0]=='/' && path[1]=='/')
4853eaa5f1d9SNick Mathewson goto err;
4854eaa5f1d9SNick Mathewson /* If you did get an authority, the path must begin with "/" or be
4855eaa5f1d9SNick Mathewson * empty. */
4856eaa5f1d9SNick Mathewson if (got_authority && path[0] != '/' && path[0] != '\0')
4857eaa5f1d9SNick Mathewson goto err;
4858a5a76e68SNick Mathewson /* (End of maybe-unreachable cases) */
4859eaa5f1d9SNick Mathewson
4860a5a76e68SNick Mathewson /* If there was no scheme, the first part of the path (if any) must
4861a5a76e68SNick Mathewson * have no colon in it. */
4862a5a76e68SNick Mathewson if (! uri->scheme && !path_matches_noscheme(path))
4863a5a76e68SNick Mathewson goto err;
4864a5a76e68SNick Mathewson
4865a5a76e68SNick Mathewson EVUTIL_ASSERT(path);
4866eaa5f1d9SNick Mathewson uri->path = mm_strdup(path);
4867666b0966SJardel Weyrich if (uri->path == NULL) {
48683f8d22a1SJardel Weyrich event_warn("%s: strdup", __func__);
4869666b0966SJardel Weyrich goto err;
4870666b0966SJardel Weyrich }
4871eaa5f1d9SNick Mathewson
4872666b0966SJardel Weyrich if (query) {
487386212341SNick Mathewson uri->query = mm_strdup(query);
4874666b0966SJardel Weyrich if (uri->query == NULL) {
48753f8d22a1SJardel Weyrich event_warn("%s: strdup", __func__);
4876666b0966SJardel Weyrich goto err;
4877666b0966SJardel Weyrich }
4878666b0966SJardel Weyrich }
4879666b0966SJardel Weyrich if (fragment) {
4880eaa5f1d9SNick Mathewson uri->fragment = mm_strdup(fragment);
4881666b0966SJardel Weyrich if (uri->fragment == NULL) {
48823f8d22a1SJardel Weyrich event_warn("%s: strdup", __func__);
4883666b0966SJardel Weyrich goto err;
4884666b0966SJardel Weyrich }
4885666b0966SJardel Weyrich }
488686dd720aSPavel Plesov
488786212341SNick Mathewson mm_free(readbuf);
488886dd720aSPavel Plesov
488986dd720aSPavel Plesov return uri;
4890fadbfd4eSNick Mathewson err:
4891fadbfd4eSNick Mathewson if (uri)
4892fadbfd4eSNick Mathewson evhttp_uri_free(uri);
4893fadbfd4eSNick Mathewson if (readbuf)
4894fadbfd4eSNick Mathewson mm_free(readbuf);
4895fadbfd4eSNick Mathewson return NULL;
489686dd720aSPavel Plesov }
489786dd720aSPavel Plesov
48987d1ffe64SGreg Hazel static struct evhttp_uri *
evhttp_uri_parse_authority(char * source_uri)48997d1ffe64SGreg Hazel evhttp_uri_parse_authority(char *source_uri)
49007d1ffe64SGreg Hazel {
49017d1ffe64SGreg Hazel struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri));
49020d5dde53SNathan French char *end;
49030d5dde53SNathan French
49047d1ffe64SGreg Hazel if (uri == NULL) {
49057d1ffe64SGreg Hazel event_warn("%s: calloc", __func__);
49067d1ffe64SGreg Hazel goto err;
49077d1ffe64SGreg Hazel }
49087d1ffe64SGreg Hazel uri->port = -1;
49097d1ffe64SGreg Hazel uri->flags = 0;
49107d1ffe64SGreg Hazel
49110d5dde53SNathan French end = end_of_authority(source_uri);
49127d1ffe64SGreg Hazel if (parse_authority(uri, source_uri, end) < 0)
49137d1ffe64SGreg Hazel goto err;
49147d1ffe64SGreg Hazel
49157d1ffe64SGreg Hazel uri->path = mm_strdup("");
49167d1ffe64SGreg Hazel if (uri->path == NULL) {
49177d1ffe64SGreg Hazel event_warn("%s: strdup", __func__);
49187d1ffe64SGreg Hazel goto err;
49197d1ffe64SGreg Hazel }
49207d1ffe64SGreg Hazel
49217d1ffe64SGreg Hazel return uri;
49227d1ffe64SGreg Hazel err:
49237d1ffe64SGreg Hazel if (uri)
49247d1ffe64SGreg Hazel evhttp_uri_free(uri);
49257d1ffe64SGreg Hazel return NULL;
49267d1ffe64SGreg Hazel }
49277d1ffe64SGreg Hazel
4928fadbfd4eSNick Mathewson void
evhttp_uri_free(struct evhttp_uri * uri)4929fadbfd4eSNick Mathewson evhttp_uri_free(struct evhttp_uri *uri)
493086dd720aSPavel Plesov {
4931cb9da0bfSNick Mathewson #define URI_FREE_STR_(f) \
493286dd720aSPavel Plesov if (uri->f) { \
493386212341SNick Mathewson mm_free(uri->f); \
493486dd720aSPavel Plesov }
493586dd720aSPavel Plesov
4936cb9da0bfSNick Mathewson URI_FREE_STR_(scheme);
4937cb9da0bfSNick Mathewson URI_FREE_STR_(userinfo);
4938cb9da0bfSNick Mathewson URI_FREE_STR_(host);
4939cb9da0bfSNick Mathewson URI_FREE_STR_(path);
4940cb9da0bfSNick Mathewson URI_FREE_STR_(query);
4941cb9da0bfSNick Mathewson URI_FREE_STR_(fragment);
494286dd720aSPavel Plesov
494386212341SNick Mathewson mm_free(uri);
4944cb9da0bfSNick Mathewson #undef URI_FREE_STR_
494586dd720aSPavel Plesov }
494686dd720aSPavel Plesov
494786212341SNick Mathewson char *
evhttp_uri_join(struct evhttp_uri * uri,char * buf,size_t limit)49487d45431eSNick Mathewson evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit)
494986dd720aSPavel Plesov {
495086dd720aSPavel Plesov struct evbuffer *tmp = 0;
495186dd720aSPavel Plesov size_t joined_size = 0;
4952eaa5f1d9SNick Mathewson char *output = NULL;
495386dd720aSPavel Plesov
4954cb9da0bfSNick Mathewson #define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f))
4955eaa5f1d9SNick Mathewson
4956eaa5f1d9SNick Mathewson if (!uri || !buf || !limit)
495786dd720aSPavel Plesov return NULL;
495886dd720aSPavel Plesov
495986dd720aSPavel Plesov tmp = evbuffer_new();
496086dd720aSPavel Plesov if (!tmp)
496186dd720aSPavel Plesov return NULL;
496286dd720aSPavel Plesov
4963eaa5f1d9SNick Mathewson if (uri->scheme) {
4964cb9da0bfSNick Mathewson URI_ADD_(scheme);
496586dd720aSPavel Plesov evbuffer_add(tmp, ":", 1);
496686dd720aSPavel Plesov }
4967eaa5f1d9SNick Mathewson if (uri->host) {
4968eaa5f1d9SNick Mathewson evbuffer_add(tmp, "//", 2);
4969eaa5f1d9SNick Mathewson if (uri->userinfo)
4970eaa5f1d9SNick Mathewson evbuffer_add_printf(tmp,"%s@", uri->userinfo);
4971cb9da0bfSNick Mathewson URI_ADD_(host);
4972eaa5f1d9SNick Mathewson if (uri->port >= 0)
4973eaa5f1d9SNick Mathewson evbuffer_add_printf(tmp,":%d", uri->port);
497486dd720aSPavel Plesov
4975eaa5f1d9SNick Mathewson if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0')
4976eaa5f1d9SNick Mathewson goto err;
497786dd720aSPavel Plesov }
497886dd720aSPavel Plesov
4979eaa5f1d9SNick Mathewson if (uri->path)
4980cb9da0bfSNick Mathewson URI_ADD_(path);
4981eaa5f1d9SNick Mathewson
4982eaa5f1d9SNick Mathewson if (uri->query) {
4983eaa5f1d9SNick Mathewson evbuffer_add(tmp, "?", 1);
4984cb9da0bfSNick Mathewson URI_ADD_(query);
4985eaa5f1d9SNick Mathewson }
498686dd720aSPavel Plesov
4987eaa5f1d9SNick Mathewson if (uri->fragment) {
498886dd720aSPavel Plesov evbuffer_add(tmp, "#", 1);
4989cb9da0bfSNick Mathewson URI_ADD_(fragment);
499086dd720aSPavel Plesov }
499186dd720aSPavel Plesov
499286dd720aSPavel Plesov evbuffer_add(tmp, "\0", 1); /* NUL */
499386dd720aSPavel Plesov
499486dd720aSPavel Plesov joined_size = evbuffer_get_length(tmp);
499586dd720aSPavel Plesov
49967d45431eSNick Mathewson if (joined_size > limit) {
49977d45431eSNick Mathewson /* It doesn't fit. */
49987d45431eSNick Mathewson evbuffer_free(tmp);
49997d45431eSNick Mathewson return NULL;
500086dd720aSPavel Plesov }
50017d45431eSNick Mathewson evbuffer_remove(tmp, buf, joined_size);
50027d45431eSNick Mathewson
5003eaa5f1d9SNick Mathewson output = buf;
5004eaa5f1d9SNick Mathewson err:
500586dd720aSPavel Plesov evbuffer_free(tmp);
500686dd720aSPavel Plesov
5007eaa5f1d9SNick Mathewson return output;
5008cb9da0bfSNick Mathewson #undef URI_ADD_
500986dd720aSPavel Plesov }
501045f6869cSNick Mathewson
501145f6869cSNick Mathewson const char *
evhttp_uri_get_scheme(const struct evhttp_uri * uri)501245f6869cSNick Mathewson evhttp_uri_get_scheme(const struct evhttp_uri *uri)
501345f6869cSNick Mathewson {
501445f6869cSNick Mathewson return uri->scheme;
501545f6869cSNick Mathewson }
501645f6869cSNick Mathewson const char *
evhttp_uri_get_userinfo(const struct evhttp_uri * uri)501745f6869cSNick Mathewson evhttp_uri_get_userinfo(const struct evhttp_uri *uri)
501845f6869cSNick Mathewson {
501945f6869cSNick Mathewson return uri->userinfo;
502045f6869cSNick Mathewson }
502145f6869cSNick Mathewson const char *
evhttp_uri_get_host(const struct evhttp_uri * uri)502245f6869cSNick Mathewson evhttp_uri_get_host(const struct evhttp_uri *uri)
502345f6869cSNick Mathewson {
502445f6869cSNick Mathewson return uri->host;
502545f6869cSNick Mathewson }
502645f6869cSNick Mathewson int
evhttp_uri_get_port(const struct evhttp_uri * uri)502745f6869cSNick Mathewson evhttp_uri_get_port(const struct evhttp_uri *uri)
502845f6869cSNick Mathewson {
502945f6869cSNick Mathewson return uri->port;
503045f6869cSNick Mathewson }
503145f6869cSNick Mathewson const char *
evhttp_uri_get_path(const struct evhttp_uri * uri)503245f6869cSNick Mathewson evhttp_uri_get_path(const struct evhttp_uri *uri)
503345f6869cSNick Mathewson {
503445f6869cSNick Mathewson return uri->path;
503545f6869cSNick Mathewson }
503645f6869cSNick Mathewson const char *
evhttp_uri_get_query(const struct evhttp_uri * uri)503745f6869cSNick Mathewson evhttp_uri_get_query(const struct evhttp_uri *uri)
503845f6869cSNick Mathewson {
503945f6869cSNick Mathewson return uri->query;
504045f6869cSNick Mathewson }
504145f6869cSNick Mathewson const char *
evhttp_uri_get_fragment(const struct evhttp_uri * uri)504245f6869cSNick Mathewson evhttp_uri_get_fragment(const struct evhttp_uri *uri)
504345f6869cSNick Mathewson {
504445f6869cSNick Mathewson return uri->fragment;
504545f6869cSNick Mathewson }
504645f6869cSNick Mathewson
5047cb9da0bfSNick Mathewson #define URI_SET_STR_(f) do { \
504845f6869cSNick Mathewson if (uri->f) \
504945f6869cSNick Mathewson mm_free(uri->f); \
505045f6869cSNick Mathewson if (f) { \
505145f6869cSNick Mathewson if ((uri->f = mm_strdup(f)) == NULL) { \
505245f6869cSNick Mathewson event_warn("%s: strdup()", __func__); \
505345f6869cSNick Mathewson return -1; \
505445f6869cSNick Mathewson } \
505545f6869cSNick Mathewson } else { \
505645f6869cSNick Mathewson uri->f = NULL; \
505745f6869cSNick Mathewson } \
505845f6869cSNick Mathewson } while(0)
505945f6869cSNick Mathewson
506045f6869cSNick Mathewson int
evhttp_uri_set_scheme(struct evhttp_uri * uri,const char * scheme)506145f6869cSNick Mathewson evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme)
506245f6869cSNick Mathewson {
506345f6869cSNick Mathewson if (scheme && !scheme_ok(scheme, scheme+strlen(scheme)))
506445f6869cSNick Mathewson return -1;
506545f6869cSNick Mathewson
5066cb9da0bfSNick Mathewson URI_SET_STR_(scheme);
506745f6869cSNick Mathewson return 0;
506845f6869cSNick Mathewson }
506945f6869cSNick Mathewson int
evhttp_uri_set_userinfo(struct evhttp_uri * uri,const char * userinfo)507045f6869cSNick Mathewson evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo)
507145f6869cSNick Mathewson {
507245f6869cSNick Mathewson if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo)))
507345f6869cSNick Mathewson return -1;
5074cb9da0bfSNick Mathewson URI_SET_STR_(userinfo);
507545f6869cSNick Mathewson return 0;
507645f6869cSNick Mathewson }
507745f6869cSNick Mathewson int
evhttp_uri_set_host(struct evhttp_uri * uri,const char * host)507845f6869cSNick Mathewson evhttp_uri_set_host(struct evhttp_uri *uri, const char *host)
507945f6869cSNick Mathewson {
508045f6869cSNick Mathewson if (host) {
508145f6869cSNick Mathewson if (host[0] == '[') {
508245f6869cSNick Mathewson if (! bracket_addr_ok(host, host+strlen(host)))
508345f6869cSNick Mathewson return -1;
508445f6869cSNick Mathewson } else {
508545f6869cSNick Mathewson if (! regname_ok(host, host+strlen(host)))
508645f6869cSNick Mathewson return -1;
508745f6869cSNick Mathewson }
508845f6869cSNick Mathewson }
508945f6869cSNick Mathewson
5090cb9da0bfSNick Mathewson URI_SET_STR_(host);
509145f6869cSNick Mathewson return 0;
509245f6869cSNick Mathewson }
509345f6869cSNick Mathewson int
evhttp_uri_set_port(struct evhttp_uri * uri,int port)509445f6869cSNick Mathewson evhttp_uri_set_port(struct evhttp_uri *uri, int port)
509545f6869cSNick Mathewson {
509645f6869cSNick Mathewson if (port < -1)
509745f6869cSNick Mathewson return -1;
509845f6869cSNick Mathewson uri->port = port;
509945f6869cSNick Mathewson return 0;
510045f6869cSNick Mathewson }
510195060b54SNick Mathewson #define end_of_cpath(cp,p,f) \
510295060b54SNick Mathewson ((const char*)(end_of_path(((char*)(cp)), (p), (f))))
510345f6869cSNick Mathewson
510445f6869cSNick Mathewson int
evhttp_uri_set_path(struct evhttp_uri * uri,const char * path)510545f6869cSNick Mathewson evhttp_uri_set_path(struct evhttp_uri *uri, const char *path)
510645f6869cSNick Mathewson {
510795060b54SNick Mathewson if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path))
510845f6869cSNick Mathewson return -1;
510945f6869cSNick Mathewson
5110cb9da0bfSNick Mathewson URI_SET_STR_(path);
511145f6869cSNick Mathewson return 0;
511245f6869cSNick Mathewson }
511345f6869cSNick Mathewson int
evhttp_uri_set_query(struct evhttp_uri * uri,const char * query)511445f6869cSNick Mathewson evhttp_uri_set_query(struct evhttp_uri *uri, const char *query)
511545f6869cSNick Mathewson {
511695060b54SNick Mathewson if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query))
511745f6869cSNick Mathewson return -1;
5118cb9da0bfSNick Mathewson URI_SET_STR_(query);
511945f6869cSNick Mathewson return 0;
512045f6869cSNick Mathewson }
512145f6869cSNick Mathewson int
evhttp_uri_set_fragment(struct evhttp_uri * uri,const char * fragment)512245f6869cSNick Mathewson evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment)
512345f6869cSNick Mathewson {
512495060b54SNick Mathewson if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment))
512545f6869cSNick Mathewson return -1;
5126cb9da0bfSNick Mathewson URI_SET_STR_(fragment);
512745f6869cSNick Mathewson return 0;
512845f6869cSNick Mathewson }
5129