Coverage Report

Created: 2025-07-11 06:05

/src/libgit2/deps/llhttp/http.c
Line
Count
Source (jump to first uncovered line)
1
#include <stdio.h>
2
#ifndef LLHTTP__TEST
3
# include "llhttp.h"
4
#else
5
# define llhttp_t llparse_t
6
#endif  /* */
7
8
int llhttp_message_needs_eof(const llhttp_t* parser);
9
int llhttp_should_keep_alive(const llhttp_t* parser);
10
11
int llhttp__before_headers_complete(llhttp_t* parser, const char* p,
12
0
                                    const char* endp) {
13
  /* Set this here so that on_headers_complete() callbacks can see it */
14
0
  if ((parser->flags & F_UPGRADE) &&
15
0
      (parser->flags & F_CONNECTION_UPGRADE)) {
16
    /* For responses, "Upgrade: foo" and "Connection: upgrade" are
17
     * mandatory only when it is a 101 Switching Protocols response,
18
     * otherwise it is purely informational, to announce support.
19
     */
20
0
    parser->upgrade =
21
0
        (parser->type == HTTP_REQUEST || parser->status_code == 101);
22
0
  } else {
23
0
    parser->upgrade = (parser->method == HTTP_CONNECT);
24
0
  }
25
0
  return 0;
26
0
}
27
28
29
/* Return values:
30
 * 0 - No body, `restart`, message_complete
31
 * 1 - CONNECT request, `restart`, message_complete, and pause
32
 * 2 - chunk_size_start
33
 * 3 - body_identity
34
 * 4 - body_identity_eof
35
 * 5 - invalid transfer-encoding for request
36
 */
37
int llhttp__after_headers_complete(llhttp_t* parser, const char* p,
38
0
                                   const char* endp) {
39
0
  int hasBody;
40
41
0
  hasBody = parser->flags & F_CHUNKED || parser->content_length > 0;
42
0
  if (
43
0
      (parser->upgrade && (parser->method == HTTP_CONNECT ||
44
0
                          (parser->flags & F_SKIPBODY) || !hasBody)) ||
45
      /* See RFC 2616 section 4.4 - 1xx e.g. Continue */
46
0
      (parser->type == HTTP_RESPONSE && parser->status_code == 101)
47
0
  ) {
48
    /* Exit, the rest of the message is in a different protocol. */
49
0
    return 1;
50
0
  }
51
52
0
  if (parser->type == HTTP_RESPONSE && parser->status_code == 100) {
53
    /* No body, restart as the message is complete */
54
0
    return 0;
55
0
  }
56
57
  /* See RFC 2616 section 4.4 */
58
0
  if (
59
0
    parser->flags & F_SKIPBODY ||         /* response to a HEAD request */
60
0
    (
61
0
      parser->type == HTTP_RESPONSE && (
62
0
        parser->status_code == 102 ||     /* Processing */
63
0
        parser->status_code == 103 ||     /* Early Hints */
64
0
        parser->status_code == 204 ||     /* No Content */
65
0
        parser->status_code == 304        /* Not Modified */
66
0
      )
67
0
    )
68
0
  ) {
69
0
    return 0;
70
0
  } else if (parser->flags & F_CHUNKED) {
71
    /* chunked encoding - ignore Content-Length header, prepare for a chunk */
72
0
    return 2;
73
0
  } else if (parser->flags & F_TRANSFER_ENCODING) {
74
0
    if (parser->type == HTTP_REQUEST &&
75
0
        (parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0 &&
76
0
        (parser->lenient_flags & LENIENT_TRANSFER_ENCODING) == 0) {
77
      /* RFC 7230 3.3.3 */
78
79
      /* If a Transfer-Encoding header field
80
       * is present in a request and the chunked transfer coding is not
81
       * the final encoding, the message body length cannot be determined
82
       * reliably; the server MUST respond with the 400 (Bad Request)
83
       * status code and then close the connection.
84
       */
85
0
      return 5;
86
0
    } else {
87
      /* RFC 7230 3.3.3 */
88
89
      /* If a Transfer-Encoding header field is present in a response and
90
       * the chunked transfer coding is not the final encoding, the
91
       * message body length is determined by reading the connection until
92
       * it is closed by the server.
93
       */
94
0
      return 4;
95
0
    }
96
0
  } else {
97
0
    if (!(parser->flags & F_CONTENT_LENGTH)) {
98
0
      if (!llhttp_message_needs_eof(parser)) {
99
        /* Assume content-length 0 - read the next */
100
0
        return 0;
101
0
      } else {
102
        /* Read body until EOF */
103
0
        return 4;
104
0
      }
105
0
    } else if (parser->content_length == 0) {
106
      /* Content-Length header given but zero: Content-Length: 0\r\n */
107
0
      return 0;
108
0
    } else {
109
      /* Content-Length header given and non-zero */
110
0
      return 3;
111
0
    }
112
0
  }
113
0
}
114
115
116
int llhttp__after_message_complete(llhttp_t* parser, const char* p,
117
0
                                   const char* endp) {
118
0
  int should_keep_alive;
119
120
0
  should_keep_alive = llhttp_should_keep_alive(parser);
121
0
  parser->finish = HTTP_FINISH_SAFE;
122
0
  parser->flags = 0;
123
124
  /* NOTE: this is ignored in loose parsing mode */
125
0
  return should_keep_alive;
126
0
}
127
128
129
0
int llhttp_message_needs_eof(const llhttp_t* parser) {
130
0
  if (parser->type == HTTP_REQUEST) {
131
0
    return 0;
132
0
  }
133
134
  /* See RFC 2616 section 4.4 */
135
0
  if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
136
0
      parser->status_code == 204 ||     /* No Content */
137
0
      parser->status_code == 304 ||     /* Not Modified */
138
0
      (parser->flags & F_SKIPBODY)) {     /* response to a HEAD request */
139
0
    return 0;
140
0
  }
141
142
  /* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */
143
0
  if ((parser->flags & F_TRANSFER_ENCODING) &&
144
0
      (parser->flags & F_CHUNKED) == 0) {
145
0
    return 1;
146
0
  }
147
148
0
  if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) {
149
0
    return 0;
150
0
  }
151
152
0
  return 1;
153
0
}
154
155
156
0
int llhttp_should_keep_alive(const llhttp_t* parser) {
157
0
  if (parser->http_major > 0 && parser->http_minor > 0) {
158
    /* HTTP/1.1 */
159
0
    if (parser->flags & F_CONNECTION_CLOSE) {
160
0
      return 0;
161
0
    }
162
0
  } else {
163
    /* HTTP/1.0 or earlier */
164
0
    if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
165
0
      return 0;
166
0
    }
167
0
  }
168
169
0
  return !llhttp_message_needs_eof(parser);
170
0
}