Coverage Report

Created: 2025-06-10 13:21

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