Bump copyright date to 2019
[tor.git] / src / core / proto / proto_http.c
blob88c59ef56193b960889f08f8c380002e2c502a9a
1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2019, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 #define PROTO_HTTP_PRIVATE
8 #include "core/or/or.h"
9 #include "lib/buf/buffers.h"
10 #include "core/proto/proto_http.h"
12 /** Return true if <b>cmd</b> looks like a HTTP (proxy) request. */
13 int
14 peek_buf_has_http_command(const buf_t *buf)
16 if (buf_peek_startswith(buf, "CONNECT ") ||
17 buf_peek_startswith(buf, "DELETE ") ||
18 buf_peek_startswith(buf, "GET ") ||
19 buf_peek_startswith(buf, "POST ") ||
20 buf_peek_startswith(buf, "PUT " ))
21 return 1;
22 return 0;
25 /** There is a (possibly incomplete) http statement on <b>buf</b>, of the
26 * form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain NULs.)
27 * If a) the headers include a Content-Length field and all bytes in
28 * the body are present, or b) there's no Content-Length field and
29 * all headers are present, then:
31 * - strdup headers into <b>*headers_out</b>, and NUL-terminate it.
32 * - memdup body into <b>*body_out</b>, and NUL-terminate it.
33 * - Then remove them from <b>buf</b>, and return 1.
35 * - If headers or body is NULL, discard that part of the buf.
36 * - If a headers or body doesn't fit in the arg, return -1.
37 * (We ensure that the headers or body don't exceed max len,
38 * _even if_ we're planning to discard them.)
39 * - If force_complete is true, then succeed even if not all of the
40 * content has arrived.
42 * Else, change nothing and return 0.
44 int
45 fetch_from_buf_http(buf_t *buf,
46 char **headers_out, size_t max_headerlen,
47 char **body_out, size_t *body_used, size_t max_bodylen,
48 int force_complete)
50 const char *headers;
51 size_t headerlen, bodylen, contentlen=0;
52 int crlf_offset;
53 int r;
55 if (buf_datalen(buf) == 0)
56 return 0;
58 crlf_offset = buf_find_string_offset(buf, "\r\n\r\n", 4);
59 if (crlf_offset > (int)max_headerlen ||
60 (crlf_offset < 0 && buf_datalen(buf) > max_headerlen)) {
61 log_debug(LD_HTTP,"headers too long.");
62 return -1;
63 } else if (crlf_offset < 0) {
64 log_debug(LD_HTTP,"headers not all here yet.");
65 return 0;
67 /* Okay, we have a full header. Make sure it all appears in the first
68 * chunk. */
69 headerlen = crlf_offset + 4;
70 size_t headers_in_chunk = 0;
71 buf_pullup(buf, headerlen, &headers, &headers_in_chunk);
73 bodylen = buf_datalen(buf) - headerlen;
74 log_debug(LD_HTTP,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen);
76 if (max_headerlen <= headerlen) {
77 log_warn(LD_HTTP,"headerlen %d larger than %d. Failing.",
78 (int)headerlen, (int)max_headerlen-1);
79 return -1;
81 if (max_bodylen <= bodylen) {
82 log_warn(LD_HTTP,"bodylen %d larger than %d. Failing.",
83 (int)bodylen, (int)max_bodylen-1);
84 return -1;
87 r = buf_http_find_content_length(headers, headerlen, &contentlen);
88 if (r == -1) {
89 log_warn(LD_PROTOCOL, "Content-Length is bogus; maybe "
90 "someone is trying to crash us.");
91 return -1;
92 } else if (r == 1) {
93 /* if content-length is malformed, then our body length is 0. fine. */
94 log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen);
95 if (bodylen < contentlen) {
96 if (!force_complete) {
97 log_debug(LD_HTTP,"body not all here yet.");
98 return 0; /* not all there yet */
101 if (bodylen > contentlen) {
102 bodylen = contentlen;
103 log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen);
105 } else {
106 tor_assert(r == 0);
107 /* Leave bodylen alone */
110 /* all happy. copy into the appropriate places, and return 1 */
111 if (headers_out) {
112 *headers_out = tor_malloc(headerlen+1);
113 buf_get_bytes(buf, *headers_out, headerlen);
114 (*headers_out)[headerlen] = 0; /* NUL terminate it */
116 if (body_out) {
117 tor_assert(body_used);
118 *body_used = bodylen;
119 *body_out = tor_malloc(bodylen+1);
120 buf_get_bytes(buf, *body_out, bodylen);
121 (*body_out)[bodylen] = 0; /* NUL terminate it */
123 return 1;
127 * Scan the HTTP headers in the <b>headerlen</b>-byte memory range at
128 * <b>headers</b>, looking for a "Content-Length" header. Try to set
129 * *<b>result_out</b> to the numeric value of that header if possible.
130 * Return -1 if the header was malformed, 0 if it was missing, and 1 if
131 * it was present and well-formed.
133 STATIC int
134 buf_http_find_content_length(const char *headers, size_t headerlen,
135 size_t *result_out)
137 const char *p, *newline;
138 char *len_str, *eos=NULL;
139 size_t remaining, result;
140 int ok;
141 *result_out = 0; /* The caller shouldn't look at this unless the
142 * return value is 1, but let's prevent confusion */
144 #define CONTENT_LENGTH "\r\nContent-Length: "
145 p = (char*) tor_memstr(headers, headerlen, CONTENT_LENGTH);
146 if (p == NULL)
147 return 0;
149 tor_assert(p >= headers && p < headers+headerlen);
150 remaining = (headers+headerlen)-p;
151 p += strlen(CONTENT_LENGTH);
152 remaining -= strlen(CONTENT_LENGTH);
154 newline = memchr(p, '\n', remaining);
155 if (newline == NULL)
156 return -1;
158 len_str = tor_memdup_nulterm(p, newline-p);
159 /* We limit the size to INT_MAX because other parts of the buffer.c
160 * code don't like buffers to be any bigger than that. */
161 result = (size_t) tor_parse_uint64(len_str, 10, 0, INT_MAX, &ok, &eos);
162 if (eos && !tor_strisspace(eos)) {
163 ok = 0;
164 } else {
165 *result_out = result;
167 tor_free(len_str);
169 return ok ? 1 : -1;