tor  0.4.2.1-alpha-dev
proto_http.c
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 */
6 
7 #define PROTO_HTTP_PRIVATE
8 #include "core/or/or.h"
9 #include "lib/buf/buffers.h"
10 #include "core/proto/proto_http.h"
11 
13 int
14 peek_buf_has_http_command(const buf_t *buf)
15 {
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;
23 }
24 
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)
49 {
50  const char *headers;
51  size_t headerlen, bodylen, contentlen=0;
52  int crlf_offset;
53  int r;
54 
55  if (buf_datalen(buf) == 0)
56  return 0;
57 
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;
66  }
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);
72 
73  bodylen = buf_datalen(buf) - headerlen;
74  log_debug(LD_HTTP,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen);
75 
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;
80  }
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;
85  }
86 
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 */
99  }
100  }
101  if (bodylen > contentlen) {
102  bodylen = contentlen;
103  log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen);
104  }
105  } else {
106  tor_assert(r == 0);
107  /* Leave bodylen alone */
108  }
109 
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 */
115  }
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 */
122  }
123  return 1;
124 }
125 
133 STATIC int
134 buf_http_find_content_length(const char *headers, size_t headerlen,
135  size_t *result_out)
136 {
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 */
143 
144 #define CONTENT_LENGTH "\r\nContent-Length: "
145  p = (char*) tor_memstr(headers, headerlen, CONTENT_LENGTH);
146  if (p == NULL)
147  return 0;
148 
149  tor_assert(p >= headers && p < headers+headerlen);
150  remaining = (headers+headerlen)-p;
151  p += strlen(CONTENT_LENGTH);
152  remaining -= strlen(CONTENT_LENGTH);
153 
154  newline = memchr(p, '\n', remaining);
155  if (newline == NULL)
156  return -1;
157 
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;
166  }
167  tor_free(len_str);
168 
169  return ok ? 1 : -1;
170 }
171 
void buf_pullup(buf_t *buf, size_t bytes, const char **head_out, size_t *len_out)
Definition: buffers.c:209
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, uint64_t max, int *ok, char **next)
Definition: parse_int.c:107
int buf_peek_startswith(const buf_t *buf, const char *cmd)
Definition: buffers.c:824
#define LD_HTTP
Definition: log.h:74
#define tor_free(p)
Definition: malloc.h:52
tor_assert(buffer)
int buf_find_string_offset(const buf_t *buf, const char *s, size_t n)
Definition: buffers.c:805
int buf_get_bytes(buf_t *buf, char *string, size_t string_len)
Definition: buffers.c:634
Master header file for Tor-specific functionality.
int tor_strisspace(const char *s)
Definition: util_string.c:175
Header file for buffers.c.
#define LD_PROTOCOL
Definition: log.h:70