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. */
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 " ))
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.
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
,
51 size_t headerlen
, bodylen
, contentlen
=0;
55 if (buf_datalen(buf
) == 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.");
63 } else if (crlf_offset
< 0) {
64 log_debug(LD_HTTP
,"headers not all here yet.");
67 /* Okay, we have a full header. Make sure it all appears in the first
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);
81 if (max_bodylen
<= bodylen
) {
82 log_warn(LD_HTTP
,"bodylen %d larger than %d. Failing.",
83 (int)bodylen
, (int)max_bodylen
-1);
87 r
= buf_http_find_content_length(headers
, headerlen
, &contentlen
);
89 log_warn(LD_PROTOCOL
, "Content-Length is bogus; maybe "
90 "someone is trying to crash us.");
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
);
107 /* Leave bodylen alone */
110 /* all happy. copy into the appropriate places, and return 1 */
112 *headers_out
= tor_malloc(headerlen
+1);
113 buf_get_bytes(buf
, *headers_out
, headerlen
);
114 (*headers_out
)[headerlen
] = 0; /* NUL terminate it */
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 */
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.
134 buf_http_find_content_length(const char *headers
, size_t headerlen
,
137 const char *p
, *newline
;
138 char *len_str
, *eos
=NULL
;
139 size_t remaining
, result
;
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
);
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
);
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
)) {
165 *result_out
= result
;