1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/lib/http/parser.h"
22
23 #include <string.h>
24
25 #include <algorithm>
26
27 #include "absl/status/status.h"
28
29 #include <grpc/support/alloc.h>
30 #include <grpc/support/log.h>
31
32 grpc_core::TraceFlag grpc_http1_trace(false, "http1");
33
buf2str(void * buffer,size_t length)34 static char* buf2str(void* buffer, size_t length) {
35 char* out = static_cast<char*>(gpr_malloc(length + 1));
36 memcpy(out, buffer, length);
37 out[length] = 0;
38 return out;
39 }
40
handle_response_line(grpc_http_parser * parser)41 static grpc_error_handle handle_response_line(grpc_http_parser* parser) {
42 uint8_t* beg = parser->cur_line;
43 uint8_t* cur = beg;
44 uint8_t* end = beg + parser->cur_line_length;
45
46 if (cur == end || *cur++ != 'H') {
47 return GRPC_ERROR_CREATE("Expected 'H'");
48 }
49 if (cur == end || *cur++ != 'T') {
50 return GRPC_ERROR_CREATE("Expected 'T'");
51 }
52 if (cur == end || *cur++ != 'T') {
53 return GRPC_ERROR_CREATE("Expected 'T'");
54 }
55 if (cur == end || *cur++ != 'P') {
56 return GRPC_ERROR_CREATE("Expected 'P'");
57 }
58 if (cur == end || *cur++ != '/') {
59 return GRPC_ERROR_CREATE("Expected '/'");
60 }
61 if (cur == end || *cur++ != '1') {
62 return GRPC_ERROR_CREATE("Expected '1'");
63 }
64 if (cur == end || *cur++ != '.') {
65 return GRPC_ERROR_CREATE("Expected '.'");
66 }
67 if (cur == end || *cur < '0' || *cur++ > '1') {
68 return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1");
69 }
70 if (cur == end || *cur++ != ' ') {
71 return GRPC_ERROR_CREATE("Expected ' '");
72 }
73 if (cur == end || *cur < '1' || *cur++ > '9') {
74 return GRPC_ERROR_CREATE("Expected status code");
75 }
76 if (cur == end || *cur < '0' || *cur++ > '9') {
77 return GRPC_ERROR_CREATE("Expected status code");
78 }
79 if (cur == end || *cur < '0' || *cur++ > '9') {
80 return GRPC_ERROR_CREATE("Expected status code");
81 }
82 parser->http.response->status =
83 (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
84 if (cur == end || *cur++ != ' ') {
85 return GRPC_ERROR_CREATE("Expected ' '");
86 }
87
88 // we don't really care about the status code message
89
90 return absl::OkStatus();
91 }
92
handle_request_line(grpc_http_parser * parser)93 static grpc_error_handle handle_request_line(grpc_http_parser* parser) {
94 uint8_t* beg = parser->cur_line;
95 uint8_t* cur = beg;
96 uint8_t* end = beg + parser->cur_line_length;
97 uint8_t vers_major = 0;
98 uint8_t vers_minor = 0;
99
100 while (cur != end && *cur++ != ' ') {
101 }
102 if (cur == end) {
103 return GRPC_ERROR_CREATE("No method on HTTP request line");
104 }
105 parser->http.request->method =
106 buf2str(beg, static_cast<size_t>(cur - beg - 1));
107
108 beg = cur;
109 while (cur != end && *cur++ != ' ') {
110 }
111 if (cur == end) {
112 return GRPC_ERROR_CREATE("No path on HTTP request line");
113 }
114 parser->http.request->path = buf2str(beg, static_cast<size_t>(cur - beg - 1));
115
116 if (cur == end || *cur++ != 'H') {
117 return GRPC_ERROR_CREATE("Expected 'H'");
118 }
119 if (cur == end || *cur++ != 'T') {
120 return GRPC_ERROR_CREATE("Expected 'T'");
121 }
122 if (cur == end || *cur++ != 'T') {
123 return GRPC_ERROR_CREATE("Expected 'T'");
124 }
125 if (cur == end || *cur++ != 'P') {
126 return GRPC_ERROR_CREATE("Expected 'P'");
127 }
128 if (cur == end || *cur++ != '/') {
129 return GRPC_ERROR_CREATE("Expected '/'");
130 }
131 vers_major = static_cast<uint8_t>(*cur++ - '1' + 1);
132 ++cur;
133 if (cur == end) {
134 return GRPC_ERROR_CREATE("End of line in HTTP version string");
135 }
136 vers_minor = static_cast<uint8_t>(*cur++ - '1' + 1);
137
138 if (vers_major == 1) {
139 if (vers_minor == 0) {
140 parser->http.request->version = GRPC_HTTP_HTTP10;
141 } else if (vers_minor == 1) {
142 parser->http.request->version = GRPC_HTTP_HTTP11;
143 } else {
144 return GRPC_ERROR_CREATE(
145 "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
146 }
147 } else if (vers_major == 2) {
148 if (vers_minor == 0) {
149 parser->http.request->version = GRPC_HTTP_HTTP20;
150 } else {
151 return GRPC_ERROR_CREATE(
152 "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
153 }
154 } else {
155 return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
156 }
157
158 return absl::OkStatus();
159 }
160
handle_first_line(grpc_http_parser * parser)161 static grpc_error_handle handle_first_line(grpc_http_parser* parser) {
162 switch (parser->type) {
163 case GRPC_HTTP_REQUEST:
164 return handle_request_line(parser);
165 case GRPC_HTTP_RESPONSE:
166 return handle_response_line(parser);
167 }
168 GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
169 }
170
add_header(grpc_http_parser * parser)171 static grpc_error_handle add_header(grpc_http_parser* parser) {
172 uint8_t* beg = parser->cur_line;
173 uint8_t* cur = beg;
174 uint8_t* end = beg + parser->cur_line_length;
175 size_t* hdr_count = nullptr;
176 size_t size = 0;
177 grpc_http_header** hdrs = nullptr;
178 grpc_http_header hdr = {nullptr, nullptr};
179 grpc_error_handle error;
180
181 GPR_ASSERT(cur != end);
182
183 if (*cur == ' ' || *cur == '\t') {
184 error = GRPC_ERROR_CREATE("Continued header lines not supported yet");
185 goto done;
186 }
187
188 while (cur != end && *cur != ':') {
189 cur++;
190 }
191 if (cur == end) {
192 error = GRPC_ERROR_CREATE("Didn't find ':' in header string");
193 goto done;
194 }
195 GPR_ASSERT(cur >= beg);
196 hdr.key = buf2str(beg, static_cast<size_t>(cur - beg));
197 cur++; // skip :
198
199 while (cur != end && (*cur == ' ' || *cur == '\t')) {
200 cur++;
201 }
202 GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
203 size = static_cast<size_t>(end - cur) - parser->cur_line_end_length;
204 if ((size != 0) && (cur[size - 1] == '\r')) {
205 size--;
206 }
207 hdr.value = buf2str(cur, size);
208
209 switch (parser->type) {
210 case GRPC_HTTP_RESPONSE:
211 hdr_count = &parser->http.response->hdr_count;
212 hdrs = &parser->http.response->hdrs;
213 if ((strcmp(hdr.key, "Transfer-Encoding") == 0) &&
214 (strcmp(hdr.value, "chunked") == 0)) {
215 parser->http.response->chunked_state = GRPC_HTTP_CHUNKED_LENGTH;
216 }
217 break;
218 case GRPC_HTTP_REQUEST:
219 hdr_count = &parser->http.request->hdr_count;
220 hdrs = &parser->http.request->hdrs;
221 break;
222 }
223
224 if (*hdr_count == parser->hdr_capacity) {
225 parser->hdr_capacity =
226 std::max(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
227 *hdrs = static_cast<grpc_http_header*>(
228 gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)));
229 }
230 (*hdrs)[(*hdr_count)++] = hdr;
231
232 done:
233 if (!error.ok()) {
234 gpr_free(hdr.key);
235 gpr_free(hdr.value);
236 }
237 return error;
238 }
239
finish_line(grpc_http_parser * parser,bool * found_body_start)240 static grpc_error_handle finish_line(grpc_http_parser* parser,
241 bool* found_body_start) {
242 grpc_error_handle err;
243 switch (parser->state) {
244 case GRPC_HTTP_FIRST_LINE:
245 err = handle_first_line(parser);
246 if (!err.ok()) return err;
247 parser->state = GRPC_HTTP_HEADERS;
248 break;
249 case GRPC_HTTP_HEADERS:
250 case GRPC_HTTP_TRAILERS:
251 if (parser->cur_line_length == parser->cur_line_end_length) {
252 if (parser->state == GRPC_HTTP_HEADERS) {
253 parser->state = GRPC_HTTP_BODY;
254 *found_body_start = true;
255 } else {
256 parser->state = GRPC_HTTP_END;
257 }
258 break;
259 } else {
260 err = add_header(parser);
261 if (!err.ok()) {
262 return err;
263 }
264 }
265 break;
266 case GRPC_HTTP_BODY:
267 case GRPC_HTTP_END:
268 GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
269 }
270
271 parser->cur_line_length = 0;
272 return absl::OkStatus();
273 }
274
addbyte_body(grpc_http_parser * parser,uint8_t byte)275 static grpc_error_handle addbyte_body(grpc_http_parser* parser, uint8_t byte) {
276 size_t* body_length = nullptr;
277 char** body = nullptr;
278
279 if (parser->type == GRPC_HTTP_RESPONSE) {
280 switch (parser->http.response->chunked_state) {
281 case GRPC_HTTP_CHUNKED_LENGTH:
282 if ((byte == '\r') || (byte == ';')) {
283 parser->http.response->chunked_state =
284 GRPC_HTTP_CHUNKED_IGNORE_ALL_UNTIL_LF;
285 } else if ((byte >= '0') && (byte <= '9')) {
286 parser->http.response->chunk_length *= 16;
287 parser->http.response->chunk_length += byte - '0';
288 } else if ((byte >= 'a') && (byte <= 'f')) {
289 parser->http.response->chunk_length *= 16;
290 parser->http.response->chunk_length += byte - 'a' + 10;
291 } else if ((byte >= 'A') && (byte <= 'F')) {
292 parser->http.response->chunk_length *= 16;
293 parser->http.response->chunk_length += byte - 'A' + 10;
294 } else {
295 return GRPC_ERROR_CREATE("Expected chunk size in hexadecimal");
296 }
297 return absl::OkStatus();
298 case GRPC_HTTP_CHUNKED_IGNORE_ALL_UNTIL_LF:
299 if (byte == '\n') {
300 if (parser->http.response->chunk_length == 0) {
301 parser->state = GRPC_HTTP_TRAILERS;
302 } else {
303 parser->http.response->chunked_state = GRPC_HTTP_CHUNKED_BODY;
304 }
305 }
306 return absl::OkStatus();
307 case GRPC_HTTP_CHUNKED_BODY:
308 if (parser->http.response->chunk_length == 0) {
309 if (byte != '\r') {
310 return GRPC_ERROR_CREATE("Expected '\\r\\n' after chunk body");
311 }
312 parser->http.response->chunked_state = GRPC_HTTP_CHUNKED_CONSUME_LF;
313 parser->http.response->chunk_length = 0;
314 return absl::OkStatus();
315 } else {
316 parser->http.response->chunk_length--;
317 // fallback to the normal body appending code below
318 }
319 break;
320 case GRPC_HTTP_CHUNKED_CONSUME_LF:
321 if (byte != '\n') {
322 return GRPC_ERROR_CREATE("Expected '\\r\\n' after chunk body");
323 }
324 parser->http.response->chunked_state = GRPC_HTTP_CHUNKED_LENGTH;
325 return absl::OkStatus();
326 case GRPC_HTTP_CHUNKED_PLAIN:
327 // avoiding warning; just fallback to normal codepath
328 break;
329 }
330 body_length = &parser->http.response->body_length;
331 body = &parser->http.response->body;
332 } else if (parser->type == GRPC_HTTP_REQUEST) {
333 body_length = &parser->http.request->body_length;
334 body = &parser->http.request->body;
335 } else {
336 GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
337 }
338
339 if (*body_length == parser->body_capacity) {
340 parser->body_capacity = std::max(size_t{8}, parser->body_capacity * 3 / 2);
341 *body = static_cast<char*>(gpr_realloc(*body, parser->body_capacity));
342 }
343 (*body)[*body_length] = static_cast<char>(byte);
344 (*body_length)++;
345
346 return absl::OkStatus();
347 }
348
check_line(grpc_http_parser * parser)349 static bool check_line(grpc_http_parser* parser) {
350 if (parser->cur_line_length >= 2 &&
351 parser->cur_line[parser->cur_line_length - 2] == '\r' &&
352 parser->cur_line[parser->cur_line_length - 1] == '\n') {
353 return true;
354 }
355
356 // HTTP request with \n\r line termiantors.
357 else if (parser->cur_line_length >= 2 &&
358 parser->cur_line[parser->cur_line_length - 2] == '\n' &&
359 parser->cur_line[parser->cur_line_length - 1] == '\r') {
360 return true;
361 }
362
363 // HTTP request with only \n line terminators.
364 else if (parser->cur_line_length >= 1 &&
365 parser->cur_line[parser->cur_line_length - 1] == '\n') {
366 parser->cur_line_end_length = 1;
367 return true;
368 }
369
370 return false;
371 }
372
addbyte(grpc_http_parser * parser,uint8_t byte,bool * found_body_start)373 static grpc_error_handle addbyte(grpc_http_parser* parser, uint8_t byte,
374 bool* found_body_start) {
375 switch (parser->state) {
376 case GRPC_HTTP_FIRST_LINE:
377 case GRPC_HTTP_HEADERS:
378 case GRPC_HTTP_TRAILERS:
379 if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
380 if (GRPC_TRACE_FLAG_ENABLED(grpc_http1_trace)) {
381 gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded",
382 GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
383 }
384 return GRPC_ERROR_CREATE("HTTP header max line length exceeded");
385 }
386 parser->cur_line[parser->cur_line_length] = byte;
387 parser->cur_line_length++;
388 if (check_line(parser)) {
389 return finish_line(parser, found_body_start);
390 }
391 return absl::OkStatus();
392 case GRPC_HTTP_BODY:
393 return addbyte_body(parser, byte);
394 case GRPC_HTTP_END:
395 return GRPC_ERROR_CREATE("Unexpected byte after end");
396 }
397 GPR_UNREACHABLE_CODE(return absl::OkStatus());
398 }
399
grpc_http_parser_init(grpc_http_parser * parser,grpc_http_type type,void * request_or_response)400 void grpc_http_parser_init(grpc_http_parser* parser, grpc_http_type type,
401 void* request_or_response) {
402 memset(parser, 0, sizeof(*parser));
403 parser->state = GRPC_HTTP_FIRST_LINE;
404 parser->type = type;
405 parser->http.request_or_response = request_or_response;
406 parser->cur_line_end_length = 2;
407 }
408
grpc_http_parser_destroy(grpc_http_parser *)409 void grpc_http_parser_destroy(grpc_http_parser* /*parser*/) {}
410
grpc_http_request_destroy(grpc_http_request * request)411 void grpc_http_request_destroy(grpc_http_request* request) {
412 size_t i;
413 gpr_free(request->body);
414 for (i = 0; i < request->hdr_count; i++) {
415 gpr_free(request->hdrs[i].key);
416 gpr_free(request->hdrs[i].value);
417 }
418 gpr_free(request->hdrs);
419 gpr_free(request->method);
420 gpr_free(request->path);
421 }
422
grpc_http_response_destroy(grpc_http_response * response)423 void grpc_http_response_destroy(grpc_http_response* response) {
424 size_t i;
425 gpr_free(response->body);
426 for (i = 0; i < response->hdr_count; i++) {
427 gpr_free(response->hdrs[i].key);
428 gpr_free(response->hdrs[i].value);
429 }
430 gpr_free(response->hdrs);
431 }
432
grpc_http_parser_parse(grpc_http_parser * parser,const grpc_slice & slice,size_t * start_of_body)433 grpc_error_handle grpc_http_parser_parse(grpc_http_parser* parser,
434 const grpc_slice& slice,
435 size_t* start_of_body) {
436 for (size_t i = 0; i < GRPC_SLICE_LENGTH(slice); i++) {
437 bool found_body_start = false;
438 grpc_error_handle err =
439 addbyte(parser, GRPC_SLICE_START_PTR(slice)[i], &found_body_start);
440 if (!err.ok()) return err;
441 if (found_body_start && start_of_body != nullptr) *start_of_body = i + 1;
442 }
443 return absl::OkStatus();
444 }
445
grpc_http_parser_eof(grpc_http_parser * parser)446 grpc_error_handle grpc_http_parser_eof(grpc_http_parser* parser) {
447 if ((parser->state != GRPC_HTTP_BODY) && (parser->state != GRPC_HTTP_END)) {
448 return GRPC_ERROR_CREATE("Did not finish headers");
449 }
450 return absl::OkStatus();
451 }
452