proto_http.c 5.5 KB

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