/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/http-message.c

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs · C · 900 lines · 782 code · 76 blank · 42 comment · 114 complexity · 160bbf8ff486ff79316ddb137d32082a MD5 · raw file

  1. /*
  2. http-message.c - HTTP message object
  3. Copyright (C) 2008 siliconforks.com
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include <config.h>
  17. #include "http-server.h"
  18. #include <assert.h>
  19. #include <string.h>
  20. #include "stream.h"
  21. #include "util.h"
  22. enum ChunkedBodyState {
  23. CHUNKED_BODY_CHUNK_SIZE, CHUNKED_BODY_CHUNK_DATA, CHUNKED_BODY_TRAILER, CHUNKED_BODY_DONE
  24. };
  25. struct HTTPMessage {
  26. char * start_line;
  27. HTTPHeader * headers;
  28. /* used for sending and receiving */
  29. struct HTTPConnection * connection;
  30. /* used only for receiving */
  31. bool has_content_length;
  32. bool is_chunked;
  33. size_t bytes_remaining;
  34. enum ChunkedBodyState chunked_body_state;
  35. Stream * chunk_buffer;
  36. /* used only for sending */
  37. bool is_started;
  38. };
  39. static bool is_lws(uint8_t c) {
  40. return c == '\r' || c == '\n' || c == ' ' || c == '\t';
  41. }
  42. static bool is_separator(uint8_t c) {
  43. /* RFC 2616 2.2 */
  44. return strchr("()<>@,;:\\\"/[]?={} \t", c) != NULL;
  45. }
  46. static bool is_token_char(uint8_t c) {
  47. /* RFC 2616 2.2 */
  48. return 32 <= c && c <= 126 && ! is_separator(c);
  49. }
  50. static bool is_text(uint8_t c) {
  51. return ! (c <= 31 || c == 127);
  52. }
  53. static void skip_lws(const uint8_t ** p) {
  54. while (**p != '\0' && is_lws(**p)) {
  55. (*p)++;
  56. }
  57. }
  58. static uint8_t * parse_token(const uint8_t ** p) {
  59. const uint8_t * start = *p;
  60. while (**p != '\0' && is_token_char(**p)) {
  61. (*p)++;
  62. }
  63. if (*p == start) {
  64. return NULL;
  65. }
  66. return (uint8_t *) xstrndup((char *) start, *p - start);
  67. }
  68. static uint8_t * parse_quoted_string(const uint8_t ** p) {
  69. const uint8_t * start = *p;
  70. if (**p != '"') {
  71. return NULL;
  72. }
  73. (*p)++;
  74. while (**p != '\0' && **p != '"') {
  75. if (**p == '\\') {
  76. (*p)++;
  77. if (**p < 1 || **p > 127) {
  78. return NULL;
  79. }
  80. (*p)++;
  81. }
  82. else if (is_text(**p)) {
  83. (*p)++;
  84. }
  85. else {
  86. return NULL;
  87. }
  88. }
  89. if (**p != '"') {
  90. return NULL;
  91. }
  92. (*p)++;
  93. return (uint8_t *) xstrndup((char *) start, *p - start);
  94. }
  95. HTTPMessage * HTTPMessage_new(HTTPConnection * connection) {
  96. HTTPMessage * message = xmalloc(sizeof(HTTPMessage));
  97. message->start_line = NULL;
  98. message->headers = NULL;
  99. message->connection = connection;
  100. message->has_content_length = false;
  101. message->is_chunked = false;
  102. message->bytes_remaining = 0;
  103. message->chunked_body_state = CHUNKED_BODY_CHUNK_SIZE;
  104. message->chunk_buffer = NULL;
  105. message->is_started = false;
  106. return message;
  107. }
  108. void HTTPMessage_delete(HTTPMessage * message) {
  109. free(message->start_line);
  110. HTTPHeader * h = message->headers;
  111. while (h != NULL) {
  112. HTTPHeader * doomed = h;
  113. h = h->next;
  114. free(doomed->name);
  115. free(doomed->value);
  116. free(doomed);
  117. }
  118. if (message->chunk_buffer != NULL) {
  119. Stream_delete(message->chunk_buffer);
  120. }
  121. free(message);
  122. }
  123. HTTPConnection * HTTPMessage_get_connection(const HTTPMessage * message) {
  124. return message->connection;
  125. }
  126. void HTTPMessage_add_header(HTTPMessage * message, const char * name, const char * value) {
  127. HTTPHeader * last = NULL;
  128. for (HTTPHeader * h = message->headers; h != NULL; h = h->next) {
  129. if (strcmp(h->name, name) == 0) {
  130. char * new_value;
  131. xasprintf(&new_value, "%s, %s", h->value, value);
  132. free(h->value);
  133. h->value = new_value;
  134. return;
  135. }
  136. last = h;
  137. }
  138. HTTPHeader * header = xmalloc(sizeof(HTTPHeader));
  139. header->name = xstrdup(name);
  140. header->value = xstrdup(value);
  141. header->next = NULL;
  142. if (last == NULL) {
  143. message->headers = header;
  144. }
  145. else {
  146. last->next = header;
  147. }
  148. }
  149. void HTTPMessage_set_header(HTTPMessage * message, const char * name, const char * value) {
  150. for (HTTPHeader * h = message->headers; h != NULL; h = h->next) {
  151. if (strcmp(name, h->name) == 0) {
  152. free(h->value);
  153. h->value = xstrdup(value);
  154. return;
  155. }
  156. }
  157. HTTPMessage_add_header(message, name, value);
  158. }
  159. char * HTTPMessage_get_charset(const HTTPMessage * message) {
  160. const char * content_type = HTTPMessage_find_header(message, HTTP_CONTENT_TYPE);
  161. if (content_type == NULL) {
  162. return NULL;
  163. }
  164. const uint8_t * p = (const uint8_t *) content_type;
  165. /* e.g., text/html */
  166. uint8_t * token;
  167. skip_lws(&p);
  168. if (! is_token_char(*p)) {
  169. return NULL;
  170. }
  171. token = parse_token(&p);
  172. free(token);
  173. skip_lws(&p);
  174. if (*p != '/') {
  175. return NULL;
  176. }
  177. p++;
  178. skip_lws(&p);
  179. if (! is_token_char(*p)) {
  180. return NULL;
  181. }
  182. token = parse_token(&p);
  183. free(token);
  184. skip_lws(&p);
  185. while (*p != '\0') {
  186. bool is_charset = false;
  187. if (*p != ';') {
  188. return NULL;
  189. }
  190. p++;
  191. skip_lws(&p);
  192. if (! is_token_char(*p)) {
  193. return NULL;
  194. }
  195. uint8_t * attribute = parse_token(&p);
  196. if (strcasecmp((char *) attribute, "charset") == 0) {
  197. is_charset = true;
  198. }
  199. free(attribute);
  200. skip_lws(&p);
  201. if (*p != '=') {
  202. return NULL;
  203. }
  204. p++;
  205. skip_lws(&p);
  206. if (*p == '"') {
  207. uint8_t * value = parse_quoted_string(&p);
  208. if (value == NULL) {
  209. return NULL;
  210. }
  211. if (is_charset) {
  212. return (char *) value;
  213. }
  214. free(value);
  215. }
  216. else if (is_token_char(*p)) {
  217. uint8_t * value = parse_token(&p);
  218. if (is_charset) {
  219. return (char *) value;
  220. }
  221. free(value);
  222. }
  223. else {
  224. return NULL;
  225. }
  226. skip_lws(&p);
  227. }
  228. return NULL;
  229. }
  230. void HTTPMessage_set_content_length(HTTPMessage * message, size_t value) {
  231. char * s;
  232. xasprintf(&s, "%u", value);
  233. HTTPMessage_set_header(message, HTTP_CONTENT_LENGTH, s);
  234. free(s);
  235. }
  236. const char * HTTPMessage_find_header(const HTTPMessage * message, const char * name) {
  237. for (HTTPHeader * h = message->headers; h != NULL; h = h->next) {
  238. if (strcasecmp(h->name, name) == 0) {
  239. return h->value;
  240. }
  241. }
  242. return NULL;
  243. }
  244. const HTTPHeader * HTTPMessage_get_headers(const HTTPMessage * message) {
  245. return message->headers;
  246. }
  247. const char * HTTPMessage_get_start_line(const HTTPMessage * message) {
  248. return message->start_line;
  249. }
  250. void HTTPMessage_set_start_line(HTTPMessage * message, const char * start_line) {
  251. free(message->start_line);
  252. message->start_line = xstrdup(start_line);
  253. }
  254. static int read_line(Stream * stream, HTTPConnection * connection) __attribute__((warn_unused_result));
  255. static int read_line(Stream * stream, HTTPConnection * connection) {
  256. for (;;) {
  257. int octet;
  258. int result = HTTPConnection_read_octet(connection, &octet);
  259. if (result != 0) {
  260. return result;
  261. }
  262. /* check for end of input */
  263. if (octet == -1) {
  264. return 0;
  265. }
  266. char c = (char) octet;
  267. Stream_write_char(stream, c);
  268. if (c == '\n') {
  269. return 0;
  270. }
  271. }
  272. }
  273. static int read_header(Stream * stream, HTTPConnection * connection) __attribute__((warn_unused_result));
  274. static int read_header(Stream * stream, HTTPConnection * connection) {
  275. int c;
  276. do {
  277. int result = read_line(stream, connection);
  278. if (result != 0) {
  279. return result;
  280. }
  281. /* check for blank line ending the headers */
  282. if (stream->length == 0 ||
  283. (stream->length == 1 && stream->data[0] == '\n') ||
  284. (stream->length == 2 && stream->data[0] == '\r' && stream->data[1] == '\n')) {
  285. break;
  286. }
  287. result = HTTPConnection_peek_octet(connection, &c);
  288. if (result != 0) {
  289. return result;
  290. }
  291. }
  292. while (c == ' ' || c == '\t');
  293. return 0;
  294. }
  295. static bool stream_contains_nul(const Stream * stream) {
  296. for (size_t i = 0; i < stream->length; i++) {
  297. if (stream->data[i] == '\0') {
  298. return true;
  299. }
  300. }
  301. return false;
  302. }
  303. int HTTPMessage_read_start_line_and_headers(HTTPMessage * message) {
  304. Stream * stream = Stream_new(0);
  305. /* read the start line */
  306. int result = read_line(stream, message->connection);
  307. if (result != 0) {
  308. Stream_delete(stream);
  309. return -1;
  310. }
  311. /* check for NUL byte */
  312. if (stream_contains_nul(stream)) {
  313. Stream_delete(stream);
  314. return -1;
  315. }
  316. message->start_line = xstrndup((char *) stream->data, stream->length);
  317. /* read the headers - RFC 2616 4.2 */
  318. message->headers = NULL;
  319. for (;;) {
  320. Stream_reset(stream);
  321. result = read_header(stream, message->connection);
  322. if (result != 0) {
  323. Stream_delete(stream);
  324. return -1;
  325. }
  326. /* check for CRLF (or similar) to terminate headers */
  327. if (stream->length == 0 ||
  328. (stream->length == 1 && stream->data[0] == '\n') ||
  329. (stream->length == 2 && stream->data[0] == '\r' && stream->data[1] == '\n')) {
  330. break;
  331. }
  332. /* check for NUL byte */
  333. if (stream_contains_nul(stream)) {
  334. Stream_delete(stream);
  335. return -1;
  336. }
  337. /* NUL-terminate the header */
  338. Stream_write_char(stream, '\0');
  339. const uint8_t * p = stream->data;
  340. char * name = (char *) parse_token(&p);
  341. if (name == NULL) {
  342. Stream_delete(stream);
  343. return -1;
  344. }
  345. skip_lws(&p);
  346. /* expect colon */
  347. if (*p != ':') {
  348. free(name);
  349. Stream_delete(stream);
  350. return -1;
  351. }
  352. /* skip over colon */
  353. p++;
  354. skip_lws(&p);
  355. if (*p == '\0') {
  356. free(name);
  357. Stream_delete(stream);
  358. return -1;
  359. }
  360. /* skip backward over LWS, starting from the last char in the buffer */
  361. uint8_t * end = stream->data + stream->length - 2;
  362. while (end > p && is_lws(*end)) {
  363. end--;
  364. }
  365. char * value = xstrndup((char *) p, end - p + 1);
  366. HTTPMessage_add_header(message, name, value);
  367. free(name);
  368. free(value);
  369. }
  370. Stream_delete(stream);
  371. /*
  372. RFC 2616 4.3:
  373. - a request has a body iff the request headers include Content-Length or Transfer-Encoding
  374. - a response has a body iff the request is not HEAD and the response is not 1xx, 204, 304
  375. */
  376. const char * content_length = HTTPMessage_find_header(message, HTTP_CONTENT_LENGTH);
  377. if (content_length != NULL) {
  378. size_t value = 0;
  379. for (const char * p = content_length; *p != '\0'; p++) {
  380. /* check for overflow */
  381. if (SIZE_MAX / 10 < value) {
  382. return -1;
  383. }
  384. value *= 10;
  385. uint8_t digit = *p;
  386. /* check that it contains only decimal digits */
  387. if (digit < '0' || digit > '9') {
  388. return -1;
  389. }
  390. size_t digit_value = digit - '0';
  391. /* check for overflow */
  392. if (SIZE_MAX - digit_value < value) {
  393. return -1;
  394. }
  395. value += digit_value;
  396. }
  397. message->bytes_remaining = value;
  398. message->has_content_length = true;
  399. }
  400. const char * transfer_encoding = HTTPMessage_find_header(message, HTTP_TRANSFER_ENCODING);
  401. if (transfer_encoding != NULL) {
  402. uint8_t * token = NULL;
  403. const uint8_t * p = (const uint8_t *) transfer_encoding;
  404. result = 0;
  405. for (;;) {
  406. skip_lws(&p);
  407. if (! is_token_char(*p)) {
  408. result = -1;
  409. break;
  410. }
  411. free(token);
  412. token = parse_token(&p);
  413. skip_lws(&p);
  414. while (*p == ';') {
  415. p++;
  416. skip_lws(&p);
  417. if (! is_token_char(*p)) {
  418. result = -1;
  419. break;
  420. }
  421. uint8_t * attribute = parse_token(&p);
  422. free(attribute);
  423. skip_lws(&p);
  424. if (*p != '=') {
  425. result = -1;
  426. break;
  427. }
  428. p++;
  429. skip_lws(&p);
  430. if (*p == '"') {
  431. uint8_t * value = parse_quoted_string(&p);
  432. if (value == NULL) {
  433. result = -1;
  434. break;
  435. }
  436. free(value);
  437. }
  438. else if (is_token_char(*p)) {
  439. uint8_t * value = parse_token(&p);
  440. free(value);
  441. }
  442. else {
  443. result = -1;
  444. break;
  445. }
  446. skip_lws(&p);
  447. }
  448. if (result == -1) {
  449. break;
  450. }
  451. if (*p != ',') {
  452. break;
  453. }
  454. p++;
  455. }
  456. if (result == 0 && *p == '\0' && token != NULL && strcasecmp((char *) token, "chunked") == 0) {
  457. message->is_chunked = true;
  458. message->chunk_buffer = Stream_new(0);
  459. }
  460. free(token);
  461. }
  462. return result;
  463. }
  464. int HTTPMessage_write_start_line_and_headers(HTTPMessage * message) {
  465. int result = 0;
  466. if (message->is_started) {
  467. return result;
  468. }
  469. message->is_started = true;
  470. /* send the start line */
  471. assert(message->start_line != NULL);
  472. size_t length = strlen(message->start_line);
  473. assert(length >= 2 && message->start_line[length - 2] == '\r' && message->start_line[length - 1] == '\n');
  474. result = HTTPConnection_write(message->connection, message->start_line, length);
  475. if (result != 0) {
  476. return result;
  477. }
  478. /* send the headers */
  479. HTTPMessage_set_header(message, HTTP_CONNECTION, "close");
  480. for (HTTPHeader * h = message->headers; h != NULL; h = h->next) {
  481. result = HTTPConnection_write(message->connection, h->name, strlen(h->name));
  482. if (result != 0) {
  483. return result;
  484. }
  485. result = HTTPConnection_write(message->connection, ": ", 2);
  486. if (result != 0) {
  487. return result;
  488. }
  489. result = HTTPConnection_write(message->connection, h->value, strlen(h->value));
  490. if (result != 0) {
  491. return result;
  492. }
  493. result = HTTPConnection_write(message->connection, "\r\n", 2);
  494. if (result != 0) {
  495. return result;
  496. }
  497. }
  498. result = HTTPConnection_write(message->connection, "\r\n", 2);
  499. return result;
  500. }
  501. bool HTTPMessage_has_sent_headers(const HTTPMessage * message) {
  502. return message->is_started;
  503. }
  504. int HTTPMessage_write(HTTPMessage * message, const void * p, size_t size) {
  505. int result = 0;
  506. result = HTTPMessage_write_start_line_and_headers(message);
  507. if (result != 0) {
  508. return result;
  509. }
  510. result = HTTPConnection_write(message->connection, p, size);
  511. return result;
  512. }
  513. int HTTPMessage_flush(HTTPMessage * message) {
  514. int result = 0;
  515. result = HTTPMessage_write_start_line_and_headers(message);
  516. if (result != 0) {
  517. return result;
  518. }
  519. result = HTTPConnection_flush(message->connection);
  520. return result;
  521. }
  522. static int read_chunk_size_line(HTTPMessage * message) __attribute__((warn_unused_result));
  523. static int read_chunk_size_line(HTTPMessage * message) {
  524. Stream_reset(message->chunk_buffer);
  525. int result = read_line(message->chunk_buffer, message->connection);
  526. if (result != 0) {
  527. return result;
  528. }
  529. if (message->chunk_buffer->length < 2) {
  530. return -1;
  531. }
  532. return 0;
  533. }
  534. static int read_chunk_size(Stream * stream, size_t * chunk_size) __attribute__((warn_unused_result));
  535. static int read_chunk_size(Stream * stream, size_t * chunk_size) {
  536. size_t value = 0;
  537. for (size_t i = 0; i < stream->length; i++) {
  538. uint8_t digit = stream->data[i];
  539. /* check that it contains only hexadecimal digits */
  540. size_t digit_value;
  541. if ('0' <= digit && digit <= '9') {
  542. digit_value = digit - '0';
  543. }
  544. else if ('a' <= digit && digit <= 'f') {
  545. digit_value = digit - 'a' + 10;
  546. }
  547. else if ('A' <= digit && digit <= 'F') {
  548. digit_value = digit - 'A' + 10;
  549. }
  550. else if (is_lws(digit) || digit == ';') {
  551. break;
  552. }
  553. else {
  554. return -1;
  555. }
  556. /* check for overflow */
  557. if (SIZE_MAX / 16 < value) {
  558. return -1;
  559. }
  560. value *= 16;
  561. /* check for overflow */
  562. if (SIZE_MAX - digit_value < value) {
  563. return -1;
  564. }
  565. value += digit_value;
  566. }
  567. *chunk_size = value;
  568. return 0;
  569. }
  570. static int read_chunked_message_body(HTTPMessage * message, void * p, size_t capacity, size_t * bytes_read) {
  571. int result = 0;
  572. *bytes_read = 0;
  573. if (message->chunked_body_state == CHUNKED_BODY_DONE) {
  574. return 0;
  575. }
  576. uint8_t * s = p;
  577. int c;
  578. for (*bytes_read = 0; *bytes_read < capacity; (*bytes_read)++) {
  579. switch (message->chunked_body_state) {
  580. case CHUNKED_BODY_CHUNK_SIZE:
  581. if (message->chunk_buffer->length == 0) {
  582. /* read a `chunk-size' line */
  583. result = read_chunk_size_line(message);
  584. if (result != 0) {
  585. return result;
  586. }
  587. message->bytes_remaining = message->chunk_buffer->length;
  588. }
  589. if (message->bytes_remaining == 0) {
  590. return -1;
  591. }
  592. /* serve from the chunk buffer */
  593. s[*bytes_read] = message->chunk_buffer->data[message->chunk_buffer->length - message->bytes_remaining];
  594. message->bytes_remaining--;
  595. if (message->bytes_remaining == 0) {
  596. size_t chunk_size;
  597. result = read_chunk_size(message->chunk_buffer, &chunk_size);
  598. if (result != 0) {
  599. return result;
  600. }
  601. Stream_reset(message->chunk_buffer);
  602. if (chunk_size == 0) {
  603. message->chunked_body_state = CHUNKED_BODY_TRAILER;
  604. }
  605. else if (SIZE_MAX - 2 < chunk_size) {
  606. /* overflow */
  607. return -1;
  608. }
  609. else {
  610. message->chunked_body_state = CHUNKED_BODY_CHUNK_DATA;
  611. message->bytes_remaining = chunk_size + 2;
  612. }
  613. }
  614. break;
  615. case CHUNKED_BODY_CHUNK_DATA:
  616. /* serve from the chunk */
  617. result = HTTPConnection_read_octet(message->connection, &c);
  618. if (result != 0) {
  619. return result;
  620. }
  621. if (c == -1) {
  622. result = -1;
  623. message->chunked_body_state = CHUNKED_BODY_DONE;
  624. return result;
  625. }
  626. s[*bytes_read] = (uint8_t) c;
  627. message->bytes_remaining--;
  628. if (message->bytes_remaining == 0) {
  629. message->chunked_body_state = CHUNKED_BODY_CHUNK_SIZE;
  630. }
  631. break;
  632. case CHUNKED_BODY_TRAILER:
  633. if (message->chunk_buffer->length == 0) {
  634. /* read a header */
  635. result = read_header(message->chunk_buffer, message->connection);
  636. if (result != 0) {
  637. return result;
  638. }
  639. message->bytes_remaining = message->chunk_buffer->length;
  640. }
  641. if (message->bytes_remaining == 0) {
  642. message->chunked_body_state = CHUNKED_BODY_DONE;
  643. return result;
  644. }
  645. /* serve from the chunk buffer */
  646. s[*bytes_read] = message->chunk_buffer->data[message->chunk_buffer->length - message->bytes_remaining];
  647. message->bytes_remaining--;
  648. if (message->bytes_remaining == 0) {
  649. size_t length = message->chunk_buffer->length;
  650. uint8_t * chunk_buffer = message->chunk_buffer->data;
  651. if (length == 0 ||
  652. (length == 1 && chunk_buffer[0] == '\n') ||
  653. (length == 2 && chunk_buffer[0] == '\r' && chunk_buffer[1] == '\n')) {
  654. message->chunked_body_state = CHUNKED_BODY_DONE;
  655. return result;
  656. }
  657. Stream_reset(message->chunk_buffer);
  658. }
  659. break;
  660. default:
  661. break;
  662. }
  663. }
  664. return result;
  665. }
  666. static int read_chunked_entity_body(HTTPMessage * message, void * p, size_t capacity, size_t * bytes_read) {
  667. int result = 0;
  668. *bytes_read = 0;
  669. if (message->chunked_body_state == CHUNKED_BODY_DONE) {
  670. return result;
  671. }
  672. uint8_t * s = p;
  673. for (*bytes_read = 0; *bytes_read < capacity; (*bytes_read)++) {
  674. if (message->bytes_remaining == 0) {
  675. result = read_chunk_size_line(message);
  676. if (result != 0) {
  677. break;
  678. }
  679. size_t chunk_size;
  680. result = read_chunk_size(message->chunk_buffer, &chunk_size);
  681. if (result != 0) {
  682. break;
  683. }
  684. message->bytes_remaining = chunk_size;
  685. if (chunk_size == 0) {
  686. message->chunked_body_state = CHUNKED_BODY_DONE;
  687. break;
  688. }
  689. }
  690. int c;
  691. result = HTTPConnection_read_octet(message->connection, &c);
  692. if (result != 0) {
  693. break;
  694. }
  695. if (c == -1) {
  696. result = -1;
  697. message->chunked_body_state = CHUNKED_BODY_DONE;
  698. break;
  699. }
  700. s[*bytes_read] = (uint8_t) c;
  701. message->bytes_remaining--;
  702. }
  703. return result;
  704. }
  705. int HTTPMessage_read_message_body(HTTPMessage * message, void * p, size_t capacity, size_t * bytes_read) {
  706. if (message->is_chunked) {
  707. return read_chunked_message_body(message, p, capacity, bytes_read);
  708. }
  709. int result = 0;
  710. uint8_t * s = p;
  711. for (*bytes_read = 0; *bytes_read < capacity; (*bytes_read)++) {
  712. if (message->has_content_length && message->bytes_remaining == 0) {
  713. break;
  714. }
  715. int c;
  716. result = HTTPConnection_read_octet(message->connection, &c);
  717. if (result != 0) {
  718. break;
  719. }
  720. if (c == -1) {
  721. break;
  722. }
  723. s[*bytes_read] = (uint8_t) c;
  724. message->bytes_remaining--;
  725. }
  726. return result;
  727. }
  728. int HTTPMessage_read_entity_body(HTTPMessage * message, void * p, size_t capacity, size_t * bytes_read) {
  729. if (message->is_chunked) {
  730. return read_chunked_entity_body(message, p, capacity, bytes_read);
  731. }
  732. return HTTPMessage_read_message_body(message, p, capacity, bytes_read);
  733. }
  734. int HTTPMessage_read_entire_entity_body(HTTPMessage * message, Stream * input_stream) {
  735. int result = 0;
  736. uint8_t * buffer[8192];
  737. for (;;) {
  738. size_t bytes_read;
  739. result = HTTPMessage_read_entity_body(message, buffer, 8192, &bytes_read);
  740. if (result != 0) {
  741. break;
  742. }
  743. if (bytes_read == 0) {
  744. break;
  745. }
  746. Stream_write(input_stream, buffer, bytes_read);
  747. }
  748. return result;
  749. }