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-2021, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
9 * @brief Parse a subset of the HTTP protocol.
12 #define PROTO_HTTP_PRIVATE
13 #include "core/or/or.h"
14 #include "lib/buf/buffers.h"
15 #include "core/proto/proto_http.h"
17 /** Return true if <b>cmd</b> looks like a HTTP (proxy) request. */
19 peek_buf_has_http_command(const buf_t
*buf
)
21 if (buf_peek_startswith(buf
, "CONNECT ") ||
22 buf_peek_startswith(buf
, "DELETE ") ||
23 buf_peek_startswith(buf
, "GET ") ||
24 buf_peek_startswith(buf
, "POST ") ||
25 buf_peek_startswith(buf
, "PUT " ))
30 /** There is a (possibly incomplete) http statement on <b>buf</b>, of the
31 * form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain NULs.)
32 * If a) the headers include a Content-Length field and all bytes in
33 * the body are present, or b) there's no Content-Length field and
34 * all headers are present, then:
36 * - strdup headers into <b>*headers_out</b>, and NUL-terminate it.
37 * - memdup body into <b>*body_out</b>, and NUL-terminate it.
38 * - Then remove them from <b>buf</b>, and return 1.
40 * - If headers or body is NULL, discard that part of the buf.
41 * - If a headers or body doesn't fit in the arg, return -1.
42 * (We ensure that the headers or body don't exceed max len,
43 * _even if_ we're planning to discard them.)
44 * - If force_complete is true, then succeed even if not all of the
45 * content has arrived.
47 * Else, change nothing and return 0.
50 fetch_from_buf_http(buf_t
*buf
,
51 char **headers_out
, size_t max_headerlen
,
52 char **body_out
, size_t *body_used
, size_t max_bodylen
,
56 size_t headerlen
, bodylen
, contentlen
=0;
60 if (buf_datalen(buf
) == 0)
63 crlf_offset
= buf_find_string_offset(buf
, "\r\n\r\n", 4);
64 if (crlf_offset
> (int)max_headerlen
||
65 (crlf_offset
< 0 && buf_datalen(buf
) > max_headerlen
)) {
66 log_debug(LD_HTTP
,"headers too long.");
68 } else if (crlf_offset
< 0) {
69 log_debug(LD_HTTP
,"headers not all here yet.");
72 /* Okay, we have a full header. Make sure it all appears in the first
74 headerlen
= crlf_offset
+ 4;
75 size_t headers_in_chunk
= 0;
76 buf_pullup(buf
, headerlen
, &headers
, &headers_in_chunk
);
78 bodylen
= buf_datalen(buf
) - headerlen
;
79 log_debug(LD_HTTP
,"headerlen %d, bodylen %d.", (int)headerlen
, (int)bodylen
);
81 if (max_headerlen
<= headerlen
) {
82 log_warn(LD_HTTP
,"headerlen %d larger than %d. Failing.",
83 (int)headerlen
, (int)max_headerlen
-1);
86 if (max_bodylen
<= bodylen
) {
87 log_warn(LD_HTTP
,"bodylen %d larger than %d. Failing.",
88 (int)bodylen
, (int)max_bodylen
-1);
92 r
= buf_http_find_content_length(headers
, headerlen
, &contentlen
);
94 log_warn(LD_PROTOCOL
, "Content-Length is bogus; maybe "
95 "someone is trying to crash us.");
98 /* if content-length is malformed, then our body length is 0. fine. */
99 log_debug(LD_HTTP
,"Got a contentlen of %d.",(int)contentlen
);
100 if (bodylen
< contentlen
) {
101 if (!force_complete
) {
102 log_debug(LD_HTTP
,"body not all here yet.");
103 return 0; /* not all there yet */
106 if (bodylen
> contentlen
) {
107 bodylen
= contentlen
;
108 log_debug(LD_HTTP
,"bodylen reduced to %d.",(int)bodylen
);
112 /* Leave bodylen alone */
115 /* all happy. copy into the appropriate places, and return 1 */
117 *headers_out
= tor_malloc(headerlen
+1);
118 buf_get_bytes(buf
, *headers_out
, headerlen
);
119 (*headers_out
)[headerlen
] = 0; /* NUL terminate it */
122 tor_assert(body_used
);
123 *body_used
= bodylen
;
124 *body_out
= tor_malloc(bodylen
+1);
125 buf_get_bytes(buf
, *body_out
, bodylen
);
126 (*body_out
)[bodylen
] = 0; /* NUL terminate it */
132 * Scan the HTTP headers in the <b>headerlen</b>-byte memory range at
133 * <b>headers</b>, looking for a "Content-Length" header. Try to set
134 * *<b>result_out</b> to the numeric value of that header if possible.
135 * Return -1 if the header was malformed, 0 if it was missing, and 1 if
136 * it was present and well-formed.
139 buf_http_find_content_length(const char *headers
, size_t headerlen
,
142 const char *p
, *newline
;
143 char *len_str
, *eos
=NULL
;
144 size_t remaining
, result
;
146 *result_out
= 0; /* The caller shouldn't look at this unless the
147 * return value is 1, but let's prevent confusion */
149 #define CONTENT_LENGTH "\r\nContent-Length: "
150 p
= (char*) tor_memstr(headers
, headerlen
, CONTENT_LENGTH
);
154 tor_assert(p
>= headers
&& p
< headers
+headerlen
);
155 remaining
= (headers
+headerlen
)-p
;
156 p
+= strlen(CONTENT_LENGTH
);
157 remaining
-= strlen(CONTENT_LENGTH
);
159 newline
= memchr(p
, '\n', remaining
);
163 len_str
= tor_memdup_nulterm(p
, newline
-p
);
164 /* We limit the size to INT_MAX because other parts of the buffer.c
165 * code don't like buffers to be any bigger than that. */
166 result
= (size_t) tor_parse_uint64(len_str
, 10, 0, INT_MAX
, &ok
, &eos
);
167 if (eos
&& !tor_strisspace(eos
)) {
170 *result_out
= result
;