• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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