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