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