Home | History | Annotate | Download | only in http
      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 <stdbool.h>
     24 #include <string.h>
     25 
     26 #include <grpc/support/alloc.h>
     27 #include <grpc/support/log.h>
     28 
     29 #include "src/core/lib/gpr/useful.h"
     30 
     31 grpc_core::TraceFlag grpc_http1_trace(false, "http1");
     32 
     33 static char* buf2str(void* buffer, size_t length) {
     34   char* out = static_cast<char*>(gpr_malloc(length + 1));
     35   memcpy(out, buffer, length);
     36   out[length] = 0;
     37   return out;
     38 }
     39 
     40 static grpc_error* handle_response_line(grpc_http_parser* parser) {
     41   uint8_t* beg = parser->cur_line;
     42   uint8_t* cur = beg;
     43   uint8_t* end = beg + parser->cur_line_length;
     44 
     45   if (cur == end || *cur++ != 'H')
     46     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'");
     47   if (cur == end || *cur++ != 'T')
     48     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
     49   if (cur == end || *cur++ != 'T')
     50     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
     51   if (cur == end || *cur++ != 'P')
     52     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'");
     53   if (cur == end || *cur++ != '/')
     54     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'");
     55   if (cur == end || *cur++ != '1')
     56     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '1'");
     57   if (cur == end || *cur++ != '.')
     58     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '.'");
     59   if (cur == end || *cur < '0' || *cur++ > '1') {
     60     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
     61         "Expected HTTP/1.0 or HTTP/1.1");
     62   }
     63   if (cur == end || *cur++ != ' ')
     64     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected ' '");
     65   if (cur == end || *cur < '1' || *cur++ > '9')
     66     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
     67   if (cur == end || *cur < '0' || *cur++ > '9')
     68     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
     69   if (cur == end || *cur < '0' || *cur++ > '9')
     70     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
     71   parser->http.response->status =
     72       (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
     73   if (cur == end || *cur++ != ' ')
     74     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected ' '");
     75 
     76   /* we don't really care about the status code message */
     77 
     78   return GRPC_ERROR_NONE;
     79 }
     80 
     81 static grpc_error* handle_request_line(grpc_http_parser* parser) {
     82   uint8_t* beg = parser->cur_line;
     83   uint8_t* cur = beg;
     84   uint8_t* end = beg + parser->cur_line_length;
     85   uint8_t vers_major = 0;
     86   uint8_t vers_minor = 0;
     87 
     88   while (cur != end && *cur++ != ' ')
     89     ;
     90   if (cur == end)
     91     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
     92         "No method on HTTP request line");
     93   parser->http.request->method =
     94       buf2str(beg, static_cast<size_t>(cur - beg - 1));
     95 
     96   beg = cur;
     97   while (cur != end && *cur++ != ' ')
     98     ;
     99   if (cur == end)
    100     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No path on HTTP request line");
    101   parser->http.request->path = buf2str(beg, static_cast<size_t>(cur - beg - 1));
    102 
    103   if (cur == end || *cur++ != 'H')
    104     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'");
    105   if (cur == end || *cur++ != 'T')
    106     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
    107   if (cur == end || *cur++ != 'T')
    108     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
    109   if (cur == end || *cur++ != 'P')
    110     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'");
    111   if (cur == end || *cur++ != '/')
    112     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'");
    113   vers_major = static_cast<uint8_t>(*cur++ - '1' + 1);
    114   ++cur;
    115   if (cur == end)
    116     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    117         "End of line in HTTP version string");
    118   vers_minor = static_cast<uint8_t>(*cur++ - '1' + 1);
    119 
    120   if (vers_major == 1) {
    121     if (vers_minor == 0) {
    122       parser->http.request->version = GRPC_HTTP_HTTP10;
    123     } else if (vers_minor == 1) {
    124       parser->http.request->version = GRPC_HTTP_HTTP11;
    125     } else {
    126       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    127           "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
    128     }
    129   } else if (vers_major == 2) {
    130     if (vers_minor == 0) {
    131       parser->http.request->version = GRPC_HTTP_HTTP20;
    132     } else {
    133       return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    134           "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
    135     }
    136   } else {
    137     return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    138         "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
    139   }
    140 
    141   return GRPC_ERROR_NONE;
    142 }
    143 
    144 static grpc_error* handle_first_line(grpc_http_parser* parser) {
    145   switch (parser->type) {
    146     case GRPC_HTTP_REQUEST:
    147       return handle_request_line(parser);
    148     case GRPC_HTTP_RESPONSE:
    149       return handle_response_line(parser);
    150   }
    151   GPR_UNREACHABLE_CODE(
    152       return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
    153 }
    154 
    155 static grpc_error* add_header(grpc_http_parser* parser) {
    156   uint8_t* beg = parser->cur_line;
    157   uint8_t* cur = beg;
    158   uint8_t* end = beg + parser->cur_line_length;
    159   size_t* hdr_count = nullptr;
    160   grpc_http_header** hdrs = nullptr;
    161   grpc_http_header hdr = {nullptr, nullptr};
    162   grpc_error* error = GRPC_ERROR_NONE;
    163 
    164   GPR_ASSERT(cur != end);
    165 
    166   if (*cur == ' ' || *cur == '\t') {
    167     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    168         "Continued header lines not supported yet");
    169     goto done;
    170   }
    171 
    172   while (cur != end && *cur != ':') {
    173     cur++;
    174   }
    175   if (cur == end) {
    176     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    177         "Didn't find ':' in header string");
    178     goto done;
    179   }
    180   GPR_ASSERT(cur >= beg);
    181   hdr.key = buf2str(beg, static_cast<size_t>(cur - beg));
    182   cur++; /* skip : */
    183 
    184   while (cur != end && (*cur == ' ' || *cur == '\t')) {
    185     cur++;
    186   }
    187   GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
    188   hdr.value = buf2str(
    189       cur, static_cast<size_t>(end - cur) - parser->cur_line_end_length);
    190 
    191   switch (parser->type) {
    192     case GRPC_HTTP_RESPONSE:
    193       hdr_count = &parser->http.response->hdr_count;
    194       hdrs = &parser->http.response->hdrs;
    195       break;
    196     case GRPC_HTTP_REQUEST:
    197       hdr_count = &parser->http.request->hdr_count;
    198       hdrs = &parser->http.request->hdrs;
    199       break;
    200   }
    201 
    202   if (*hdr_count == parser->hdr_capacity) {
    203     parser->hdr_capacity =
    204         GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
    205     *hdrs = static_cast<grpc_http_header*>(
    206         gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)));
    207   }
    208   (*hdrs)[(*hdr_count)++] = hdr;
    209 
    210 done:
    211   if (error != GRPC_ERROR_NONE) {
    212     gpr_free(hdr.key);
    213     gpr_free(hdr.value);
    214   }
    215   return error;
    216 }
    217 
    218 static grpc_error* finish_line(grpc_http_parser* parser,
    219                                bool* found_body_start) {
    220   grpc_error* err;
    221   switch (parser->state) {
    222     case GRPC_HTTP_FIRST_LINE:
    223       err = handle_first_line(parser);
    224       if (err != GRPC_ERROR_NONE) return err;
    225       parser->state = GRPC_HTTP_HEADERS;
    226       break;
    227     case GRPC_HTTP_HEADERS:
    228       if (parser->cur_line_length == parser->cur_line_end_length) {
    229         parser->state = GRPC_HTTP_BODY;
    230         *found_body_start = true;
    231         break;
    232       }
    233       err = add_header(parser);
    234       if (err != GRPC_ERROR_NONE) {
    235         return err;
    236       }
    237       break;
    238     case GRPC_HTTP_BODY:
    239       GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    240           "Should never reach here"));
    241   }
    242 
    243   parser->cur_line_length = 0;
    244   return GRPC_ERROR_NONE;
    245 }
    246 
    247 static grpc_error* addbyte_body(grpc_http_parser* parser, uint8_t byte) {
    248   size_t* body_length = nullptr;
    249   char** body = nullptr;
    250 
    251   if (parser->type == GRPC_HTTP_RESPONSE) {
    252     body_length = &parser->http.response->body_length;
    253     body = &parser->http.response->body;
    254   } else if (parser->type == GRPC_HTTP_REQUEST) {
    255     body_length = &parser->http.request->body_length;
    256     body = &parser->http.request->body;
    257   } else {
    258     GPR_UNREACHABLE_CODE(
    259         return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
    260   }
    261 
    262   if (*body_length == parser->body_capacity) {
    263     parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
    264     *body =
    265         static_cast<char*>(gpr_realloc((void*)*body, parser->body_capacity));
    266   }
    267   (*body)[*body_length] = static_cast<char>(byte);
    268   (*body_length)++;
    269 
    270   return GRPC_ERROR_NONE;
    271 }
    272 
    273 static bool check_line(grpc_http_parser* parser) {
    274   if (parser->cur_line_length >= 2 &&
    275       parser->cur_line[parser->cur_line_length - 2] == '\r' &&
    276       parser->cur_line[parser->cur_line_length - 1] == '\n') {
    277     return true;
    278   }
    279 
    280   // HTTP request with \n\r line termiantors.
    281   else if (parser->cur_line_length >= 2 &&
    282            parser->cur_line[parser->cur_line_length - 2] == '\n' &&
    283            parser->cur_line[parser->cur_line_length - 1] == '\r') {
    284     return true;
    285   }
    286 
    287   // HTTP request with only \n line terminators.
    288   else if (parser->cur_line_length >= 1 &&
    289            parser->cur_line[parser->cur_line_length - 1] == '\n') {
    290     parser->cur_line_end_length = 1;
    291     return true;
    292   }
    293 
    294   return false;
    295 }
    296 
    297 static grpc_error* addbyte(grpc_http_parser* parser, uint8_t byte,
    298                            bool* found_body_start) {
    299   switch (parser->state) {
    300     case GRPC_HTTP_FIRST_LINE:
    301     case GRPC_HTTP_HEADERS:
    302       if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
    303         if (grpc_http1_trace.enabled())
    304           gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded",
    305                   GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
    306         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    307             "HTTP header max line length exceeded");
    308       }
    309       parser->cur_line[parser->cur_line_length] = byte;
    310       parser->cur_line_length++;
    311       if (check_line(parser)) {
    312         return finish_line(parser, found_body_start);
    313       }
    314       return GRPC_ERROR_NONE;
    315     case GRPC_HTTP_BODY:
    316       return addbyte_body(parser, byte);
    317   }
    318   GPR_UNREACHABLE_CODE(return GRPC_ERROR_NONE);
    319 }
    320 
    321 void grpc_http_parser_init(grpc_http_parser* parser, grpc_http_type type,
    322                            void* request_or_response) {
    323   memset(parser, 0, sizeof(*parser));
    324   parser->state = GRPC_HTTP_FIRST_LINE;
    325   parser->type = type;
    326   parser->http.request_or_response = request_or_response;
    327   parser->cur_line_end_length = 2;
    328 }
    329 
    330 void grpc_http_parser_destroy(grpc_http_parser* parser) {}
    331 
    332 void grpc_http_request_destroy(grpc_http_request* request) {
    333   size_t i;
    334   gpr_free(request->body);
    335   for (i = 0; i < request->hdr_count; i++) {
    336     gpr_free(request->hdrs[i].key);
    337     gpr_free(request->hdrs[i].value);
    338   }
    339   gpr_free(request->hdrs);
    340   gpr_free(request->method);
    341   gpr_free(request->path);
    342 }
    343 
    344 void grpc_http_response_destroy(grpc_http_response* response) {
    345   size_t i;
    346   gpr_free(response->body);
    347   for (i = 0; i < response->hdr_count; i++) {
    348     gpr_free(response->hdrs[i].key);
    349     gpr_free(response->hdrs[i].value);
    350   }
    351   gpr_free(response->hdrs);
    352 }
    353 
    354 grpc_error* grpc_http_parser_parse(grpc_http_parser* parser, grpc_slice slice,
    355                                    size_t* start_of_body) {
    356   for (size_t i = 0; i < GRPC_SLICE_LENGTH(slice); i++) {
    357     bool found_body_start = false;
    358     grpc_error* err =
    359         addbyte(parser, GRPC_SLICE_START_PTR(slice)[i], &found_body_start);
    360     if (err != GRPC_ERROR_NONE) return err;
    361     if (found_body_start && start_of_body != nullptr) *start_of_body = i + 1;
    362   }
    363   return GRPC_ERROR_NONE;
    364 }
    365 
    366 grpc_error* grpc_http_parser_eof(grpc_http_parser* parser) {
    367   if (parser->state != GRPC_HTTP_BODY) {
    368     return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Did not finish headers");
    369   }
    370   return GRPC_ERROR_NONE;
    371 }
    372