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