12c593315Sopenharmony_ci#include <stdio.h>
22c593315Sopenharmony_ci#ifndef LLHTTP__TEST
32c593315Sopenharmony_ci# include "llhttp.h"
42c593315Sopenharmony_ci#else
52c593315Sopenharmony_ci# define llhttp_t llparse_t
62c593315Sopenharmony_ci#endif  /* */
72c593315Sopenharmony_ci
82c593315Sopenharmony_ciint llhttp_message_needs_eof(const llhttp_t* parser);
92c593315Sopenharmony_ciint llhttp_should_keep_alive(const llhttp_t* parser);
102c593315Sopenharmony_ci
112c593315Sopenharmony_ciint llhttp__before_headers_complete(llhttp_t* parser, const char* p,
122c593315Sopenharmony_ci                                    const char* endp) {
132c593315Sopenharmony_ci  /* Set this here so that on_headers_complete() callbacks can see it */
142c593315Sopenharmony_ci  if ((parser->flags & F_UPGRADE) &&
152c593315Sopenharmony_ci      (parser->flags & F_CONNECTION_UPGRADE)) {
162c593315Sopenharmony_ci    /* For responses, "Upgrade: foo" and "Connection: upgrade" are
172c593315Sopenharmony_ci     * mandatory only when it is a 101 Switching Protocols response,
182c593315Sopenharmony_ci     * otherwise it is purely informational, to announce support.
192c593315Sopenharmony_ci     */
202c593315Sopenharmony_ci    parser->upgrade =
212c593315Sopenharmony_ci        (parser->type == HTTP_REQUEST || parser->status_code == 101);
222c593315Sopenharmony_ci  } else {
232c593315Sopenharmony_ci    parser->upgrade = (parser->method == HTTP_CONNECT);
242c593315Sopenharmony_ci  }
252c593315Sopenharmony_ci  return 0;
262c593315Sopenharmony_ci}
272c593315Sopenharmony_ci
282c593315Sopenharmony_ci
292c593315Sopenharmony_ci/* Return values:
302c593315Sopenharmony_ci * 0 - No body, `restart`, message_complete
312c593315Sopenharmony_ci * 1 - CONNECT request, `restart`, message_complete, and pause
322c593315Sopenharmony_ci * 2 - chunk_size_start
332c593315Sopenharmony_ci * 3 - body_identity
342c593315Sopenharmony_ci * 4 - body_identity_eof
352c593315Sopenharmony_ci * 5 - invalid transfer-encoding for request
362c593315Sopenharmony_ci */
372c593315Sopenharmony_ciint llhttp__after_headers_complete(llhttp_t* parser, const char* p,
382c593315Sopenharmony_ci                                   const char* endp) {
392c593315Sopenharmony_ci  int hasBody;
402c593315Sopenharmony_ci
412c593315Sopenharmony_ci  hasBody = parser->flags & F_CHUNKED || parser->content_length > 0;
422c593315Sopenharmony_ci  if (parser->upgrade && (parser->method == HTTP_CONNECT ||
432c593315Sopenharmony_ci                          (parser->flags & F_SKIPBODY) || !hasBody)) {
442c593315Sopenharmony_ci    /* Exit, the rest of the message is in a different protocol. */
452c593315Sopenharmony_ci    return 1;
462c593315Sopenharmony_ci  }
472c593315Sopenharmony_ci
482c593315Sopenharmony_ci  if (parser->flags & F_SKIPBODY) {
492c593315Sopenharmony_ci    return 0;
502c593315Sopenharmony_ci  } else if (parser->flags & F_CHUNKED) {
512c593315Sopenharmony_ci    /* chunked encoding - ignore Content-Length header, prepare for a chunk */
522c593315Sopenharmony_ci    return 2;
532c593315Sopenharmony_ci  } else if (parser->flags & F_TRANSFER_ENCODING) {
542c593315Sopenharmony_ci    if (parser->type == HTTP_REQUEST &&
552c593315Sopenharmony_ci        (parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0 &&
562c593315Sopenharmony_ci        (parser->lenient_flags & LENIENT_TRANSFER_ENCODING) == 0) {
572c593315Sopenharmony_ci      /* RFC 7230 3.3.3 */
582c593315Sopenharmony_ci
592c593315Sopenharmony_ci      /* If a Transfer-Encoding header field
602c593315Sopenharmony_ci       * is present in a request and the chunked transfer coding is not
612c593315Sopenharmony_ci       * the final encoding, the message body length cannot be determined
622c593315Sopenharmony_ci       * reliably; the server MUST respond with the 400 (Bad Request)
632c593315Sopenharmony_ci       * status code and then close the connection.
642c593315Sopenharmony_ci       */
652c593315Sopenharmony_ci      return 5;
662c593315Sopenharmony_ci    } else {
672c593315Sopenharmony_ci      /* RFC 7230 3.3.3 */
682c593315Sopenharmony_ci
692c593315Sopenharmony_ci      /* If a Transfer-Encoding header field is present in a response and
702c593315Sopenharmony_ci       * the chunked transfer coding is not the final encoding, the
712c593315Sopenharmony_ci       * message body length is determined by reading the connection until
722c593315Sopenharmony_ci       * it is closed by the server.
732c593315Sopenharmony_ci       */
742c593315Sopenharmony_ci      return 4;
752c593315Sopenharmony_ci    }
762c593315Sopenharmony_ci  } else {
772c593315Sopenharmony_ci    if (!(parser->flags & F_CONTENT_LENGTH)) {
782c593315Sopenharmony_ci      if (!llhttp_message_needs_eof(parser)) {
792c593315Sopenharmony_ci        /* Assume content-length 0 - read the next */
802c593315Sopenharmony_ci        return 0;
812c593315Sopenharmony_ci      } else {
822c593315Sopenharmony_ci        /* Read body until EOF */
832c593315Sopenharmony_ci        return 4;
842c593315Sopenharmony_ci      }
852c593315Sopenharmony_ci    } else if (parser->content_length == 0) {
862c593315Sopenharmony_ci      /* Content-Length header given but zero: Content-Length: 0\r\n */
872c593315Sopenharmony_ci      return 0;
882c593315Sopenharmony_ci    } else {
892c593315Sopenharmony_ci      /* Content-Length header given and non-zero */
902c593315Sopenharmony_ci      return 3;
912c593315Sopenharmony_ci    }
922c593315Sopenharmony_ci  }
932c593315Sopenharmony_ci}
942c593315Sopenharmony_ci
952c593315Sopenharmony_ci
962c593315Sopenharmony_ciint llhttp__after_message_complete(llhttp_t* parser, const char* p,
972c593315Sopenharmony_ci                                   const char* endp) {
982c593315Sopenharmony_ci  int should_keep_alive;
992c593315Sopenharmony_ci
1002c593315Sopenharmony_ci  should_keep_alive = llhttp_should_keep_alive(parser);
1012c593315Sopenharmony_ci  parser->finish = HTTP_FINISH_SAFE;
1022c593315Sopenharmony_ci  parser->flags = 0;
1032c593315Sopenharmony_ci
1042c593315Sopenharmony_ci  /* NOTE: this is ignored in loose parsing mode */
1052c593315Sopenharmony_ci  return should_keep_alive;
1062c593315Sopenharmony_ci}
1072c593315Sopenharmony_ci
1082c593315Sopenharmony_ci
1092c593315Sopenharmony_ciint llhttp_message_needs_eof(const llhttp_t* parser) {
1102c593315Sopenharmony_ci  if (parser->type == HTTP_REQUEST) {
1112c593315Sopenharmony_ci    return 0;
1122c593315Sopenharmony_ci  }
1132c593315Sopenharmony_ci
1142c593315Sopenharmony_ci  /* See RFC 2616 section 4.4 */
1152c593315Sopenharmony_ci  if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
1162c593315Sopenharmony_ci      parser->status_code == 204 ||     /* No Content */
1172c593315Sopenharmony_ci      parser->status_code == 304 ||     /* Not Modified */
1182c593315Sopenharmony_ci      (parser->flags & F_SKIPBODY)) {     /* response to a HEAD request */
1192c593315Sopenharmony_ci    return 0;
1202c593315Sopenharmony_ci  }
1212c593315Sopenharmony_ci
1222c593315Sopenharmony_ci  /* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */
1232c593315Sopenharmony_ci  if ((parser->flags & F_TRANSFER_ENCODING) &&
1242c593315Sopenharmony_ci      (parser->flags & F_CHUNKED) == 0) {
1252c593315Sopenharmony_ci    return 1;
1262c593315Sopenharmony_ci  }
1272c593315Sopenharmony_ci
1282c593315Sopenharmony_ci  if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) {
1292c593315Sopenharmony_ci    return 0;
1302c593315Sopenharmony_ci  }
1312c593315Sopenharmony_ci
1322c593315Sopenharmony_ci  return 1;
1332c593315Sopenharmony_ci}
1342c593315Sopenharmony_ci
1352c593315Sopenharmony_ci
1362c593315Sopenharmony_ciint llhttp_should_keep_alive(const llhttp_t* parser) {
1372c593315Sopenharmony_ci  if (parser->http_major > 0 && parser->http_minor > 0) {
1382c593315Sopenharmony_ci    /* HTTP/1.1 */
1392c593315Sopenharmony_ci    if (parser->flags & F_CONNECTION_CLOSE) {
1402c593315Sopenharmony_ci      return 0;
1412c593315Sopenharmony_ci    }
1422c593315Sopenharmony_ci  } else {
1432c593315Sopenharmony_ci    /* HTTP/1.0 or earlier */
1442c593315Sopenharmony_ci    if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
1452c593315Sopenharmony_ci      return 0;
1462c593315Sopenharmony_ci    }
1472c593315Sopenharmony_ci  }
1482c593315Sopenharmony_ci
1492c593315Sopenharmony_ci  return !llhttp_message_needs_eof(parser);
1502c593315Sopenharmony_ci}
151