src/core/lib/http/parser.cc
Go to the documentation of this file.
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 
20 
22 
23 #include <string.h>
24 
25 #include <algorithm>
26 
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 
31 
32 static char* buf2str(void* buffer, size_t length) {
33  char* out = static_cast<char*>(gpr_malloc(length + 1));
35  out[length] = 0;
36  return out;
37 }
38 
40  uint8_t* beg = parser->cur_line;
41  uint8_t* cur = beg;
42  uint8_t* end = beg + parser->cur_line_length;
43 
44  if (cur == end || *cur++ != 'H') {
45  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'H'");
46  }
47  if (cur == end || *cur++ != 'T') {
48  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
49  }
50  if (cur == end || *cur++ != 'T') {
51  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
52  }
53  if (cur == end || *cur++ != 'P') {
54  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'");
55  }
56  if (cur == end || *cur++ != '/') {
57  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'");
58  }
59  if (cur == end || *cur++ != '1') {
60  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '1'");
61  }
62  if (cur == end || *cur++ != '.') {
63  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '.'");
64  }
65  if (cur == end || *cur < '0' || *cur++ > '1') {
67  "Expected HTTP/1.0 or HTTP/1.1");
68  }
69  if (cur == end || *cur++ != ' ') {
70  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected ' '");
71  }
72  if (cur == end || *cur < '1' || *cur++ > '9') {
73  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
74  }
75  if (cur == end || *cur < '0' || *cur++ > '9') {
76  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
77  }
78  if (cur == end || *cur < '0' || *cur++ > '9') {
79  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected status code");
80  }
81  parser->http.response->status =
82  (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
83  if (cur == end || *cur++ != ' ') {
84  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected ' '");
85  }
86 
87  /* we don't really care about the status code message */
88 
89  return GRPC_ERROR_NONE;
90 }
91 
93  uint8_t* beg = parser->cur_line;
94  uint8_t* cur = beg;
95  uint8_t* end = beg + parser->cur_line_length;
96  uint8_t vers_major = 0;
97  uint8_t vers_minor = 0;
98 
99  while (cur != end && *cur++ != ' ') {
100  }
101  if (cur == end) {
103  "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_FROM_STATIC_STRING("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_FROM_STATIC_STRING("Expected 'H'");
118  }
119  if (cur == end || *cur++ != 'T') {
120  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
121  }
122  if (cur == end || *cur++ != 'T') {
123  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'T'");
124  }
125  if (cur == end || *cur++ != 'P') {
126  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected 'P'");
127  }
128  if (cur == end || *cur++ != '/') {
129  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Expected '/'");
130  }
131  vers_major = static_cast<uint8_t>(*cur++ - '1' + 1);
132  ++cur;
133  if (cur == end) {
135  "End of line in HTTP version string");
136  }
137  vers_minor = static_cast<uint8_t>(*cur++ - '1' + 1);
138 
139  if (vers_major == 1) {
140  if (vers_minor == 0) {
141  parser->http.request->version = GRPC_HTTP_HTTP10;
142  } else if (vers_minor == 1) {
143  parser->http.request->version = GRPC_HTTP_HTTP11;
144  } else {
146  "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
147  }
148  } else if (vers_major == 2) {
149  if (vers_minor == 0) {
150  parser->http.request->version = GRPC_HTTP_HTTP20;
151  } else {
153  "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
154  }
155  } else {
157  "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
158  }
159 
160  return GRPC_ERROR_NONE;
161 }
162 
164  switch (parser->type) {
165  case GRPC_HTTP_REQUEST:
166  return handle_request_line(parser);
167  case GRPC_HTTP_RESPONSE:
169  }
171  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
172 }
173 
175  uint8_t* beg = parser->cur_line;
176  uint8_t* cur = beg;
177  uint8_t* end = beg + parser->cur_line_length;
178  size_t* hdr_count = nullptr;
179  size_t size = 0;
180  grpc_http_header** hdrs = nullptr;
181  grpc_http_header hdr = {nullptr, nullptr};
183 
184  GPR_ASSERT(cur != end);
185 
186  if (*cur == ' ' || *cur == '\t') {
188  "Continued header lines not supported yet");
189  goto done;
190  }
191 
192  while (cur != end && *cur != ':') {
193  cur++;
194  }
195  if (cur == end) {
197  "Didn't find ':' in header string");
198  goto done;
199  }
200  GPR_ASSERT(cur >= beg);
201  hdr.key = buf2str(beg, static_cast<size_t>(cur - beg));
202  cur++; /* skip : */
203 
204  while (cur != end && (*cur == ' ' || *cur == '\t')) {
205  cur++;
206  }
207  GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
208  size = static_cast<size_t>(end - cur) - parser->cur_line_end_length;
209  if ((size != 0) && (cur[size - 1] == '\r')) {
210  size--;
211  }
212  hdr.value = buf2str(cur, size);
213 
214  switch (parser->type) {
215  case GRPC_HTTP_RESPONSE:
216  hdr_count = &parser->http.response->hdr_count;
217  hdrs = &parser->http.response->hdrs;
218  if ((strcmp(hdr.key, "Transfer-Encoding") == 0) &&
219  (strcmp(hdr.value, "chunked") == 0)) {
220  parser->http.response->chunked_state = GRPC_HTTP_CHUNKED_LENGTH;
221  }
222  break;
223  case GRPC_HTTP_REQUEST:
224  hdr_count = &parser->http.request->hdr_count;
225  hdrs = &parser->http.request->hdrs;
226  break;
227  }
228 
229  if (*hdr_count == parser->hdr_capacity) {
230  parser->hdr_capacity =
231  std::max(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
232  *hdrs = static_cast<grpc_http_header*>(
233  gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)));
234  }
235  (*hdrs)[(*hdr_count)++] = hdr;
236 
237 done:
238  if (!GRPC_ERROR_IS_NONE(error)) {
239  gpr_free(hdr.key);
240  gpr_free(hdr.value);
241  }
242  return error;
243 }
244 
246  bool* found_body_start) {
248  switch (parser->state) {
251  if (!GRPC_ERROR_IS_NONE(err)) return err;
252  parser->state = GRPC_HTTP_HEADERS;
253  break;
254  case GRPC_HTTP_HEADERS:
255  case GRPC_HTTP_TRAILERS:
256  if (parser->cur_line_length == parser->cur_line_end_length) {
257  if (parser->state == GRPC_HTTP_HEADERS) {
258  parser->state = GRPC_HTTP_BODY;
259  *found_body_start = true;
260  } else {
261  parser->state = GRPC_HTTP_END;
262  }
263  break;
264  } else {
265  err = add_header(parser);
266  if (!GRPC_ERROR_IS_NONE(err)) {
267  return err;
268  }
269  }
270  break;
271  case GRPC_HTTP_BODY:
272  case GRPC_HTTP_END:
274  "Should never reach here"));
275  }
276 
277  parser->cur_line_length = 0;
278  return GRPC_ERROR_NONE;
279 }
280 
282  size_t* body_length = nullptr;
283  char** body = nullptr;
284 
285  if (parser->type == GRPC_HTTP_RESPONSE) {
286  switch (parser->http.response->chunked_state) {
288  if ((byte == '\r') || (byte == ';')) {
289  parser->http.response->chunked_state =
291  } else if ((byte >= '0') && (byte <= '9')) {
292  parser->http.response->chunk_length *= 16;
293  parser->http.response->chunk_length += byte - '0';
294  } else if ((byte >= 'a') && (byte <= 'f')) {
295  parser->http.response->chunk_length *= 16;
296  parser->http.response->chunk_length += byte - 'a' + 10;
297  } else if ((byte >= 'A') && (byte <= 'F')) {
298  parser->http.response->chunk_length *= 16;
299  parser->http.response->chunk_length += byte - 'A' + 10;
300  } else {
302  "Expected chunk size in hexadecimal");
303  }
304  return GRPC_ERROR_NONE;
306  if (byte == '\n') {
307  if (parser->http.response->chunk_length == 0) {
308  parser->state = GRPC_HTTP_TRAILERS;
309  } else {
310  parser->http.response->chunked_state = GRPC_HTTP_CHUNKED_BODY;
311  }
312  }
313  return GRPC_ERROR_NONE;
315  if (parser->http.response->chunk_length == 0) {
316  if (byte != '\r') {
318  "Expected '\\r\\n' after chunk body");
319  }
320  parser->http.response->chunked_state = GRPC_HTTP_CHUNKED_CONSUME_LF;
321  parser->http.response->chunk_length = 0;
322  return GRPC_ERROR_NONE;
323  } else {
324  parser->http.response->chunk_length--;
325  /* fallback to the normal body appending code below */
326  }
327  break;
329  if (byte != '\n') {
331  "Expected '\\r\\n' after chunk body");
332  }
333  parser->http.response->chunked_state = GRPC_HTTP_CHUNKED_LENGTH;
334  return GRPC_ERROR_NONE;
336  /* avoiding warning; just fallback to normal codepath */
337  break;
338  }
339  body_length = &parser->http.response->body_length;
340  body = &parser->http.response->body;
341  } else if (parser->type == GRPC_HTTP_REQUEST) {
342  body_length = &parser->http.request->body_length;
343  body = &parser->http.request->body;
344  } else {
346  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Should never reach here"));
347  }
348 
349  if (*body_length == parser->body_capacity) {
350  parser->body_capacity = std::max(size_t(8), parser->body_capacity * 3 / 2);
351  *body = static_cast<char*>(gpr_realloc(*body, parser->body_capacity));
352  }
353  (*body)[*body_length] = static_cast<char>(byte);
354  (*body_length)++;
355 
356  return GRPC_ERROR_NONE;
357 }
358 
360  if (parser->cur_line_length >= 2 &&
361  parser->cur_line[parser->cur_line_length - 2] == '\r' &&
362  parser->cur_line[parser->cur_line_length - 1] == '\n') {
363  return true;
364  }
365 
366  // HTTP request with \n\r line termiantors.
367  else if (parser->cur_line_length >= 2 &&
368  parser->cur_line[parser->cur_line_length - 2] == '\n' &&
369  parser->cur_line[parser->cur_line_length - 1] == '\r') {
370  return true;
371  }
372 
373  // HTTP request with only \n line terminators.
374  else if (parser->cur_line_length >= 1 &&
375  parser->cur_line[parser->cur_line_length - 1] == '\n') {
376  parser->cur_line_end_length = 1;
377  return true;
378  }
379 
380  return false;
381 }
382 
384  bool* found_body_start) {
385  switch (parser->state) {
387  case GRPC_HTTP_HEADERS:
388  case GRPC_HTTP_TRAILERS:
389  if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
391  gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded",
393  }
395  "HTTP header max line length exceeded");
396  }
397  parser->cur_line[parser->cur_line_length] = byte;
398  parser->cur_line_length++;
399  if (check_line(parser)) {
400  return finish_line(parser, found_body_start);
401  }
402  return GRPC_ERROR_NONE;
403  case GRPC_HTTP_BODY:
404  return addbyte_body(parser, byte);
405  case GRPC_HTTP_END:
406  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unexpected byte after end");
407  }
409 }
410 
412  void* request_or_response) {
413  memset(parser, 0, sizeof(*parser));
414  parser->state = GRPC_HTTP_FIRST_LINE;
415  parser->type = type;
416  parser->http.request_or_response = request_or_response;
417  parser->cur_line_end_length = 2;
418 }
419 
421 
423  size_t i;
424  gpr_free(request->body);
425  for (i = 0; i < request->hdr_count; i++) {
426  gpr_free(request->hdrs[i].key);
427  gpr_free(request->hdrs[i].value);
428  }
429  gpr_free(request->hdrs);
430  gpr_free(request->method);
431  gpr_free(request->path);
432 }
433 
435  size_t i;
436  gpr_free(response->body);
437  for (i = 0; i < response->hdr_count; i++) {
438  gpr_free(response->hdrs[i].key);
439  gpr_free(response->hdrs[i].value);
440  }
441  gpr_free(response->hdrs);
442 }
443 
445  const grpc_slice& slice,
446  size_t* start_of_body) {
447  for (size_t i = 0; i < GRPC_SLICE_LENGTH(slice); i++) {
448  bool found_body_start = false;
450  addbyte(parser, GRPC_SLICE_START_PTR(slice)[i], &found_body_start);
451  if (!GRPC_ERROR_IS_NONE(err)) return err;
452  if (found_body_start && start_of_body != nullptr) *start_of_body = i + 1;
453  }
454  return GRPC_ERROR_NONE;
455 }
456 
458  if ((parser->state != GRPC_HTTP_BODY) && (parser->state != GRPC_HTTP_END)) {
459  return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Did not finish headers");
460  }
461  return GRPC_ERROR_NONE;
462 }
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
log.h
memset
return memset(p, 0, total)
GRPC_HTTP_CHUNKED_BODY
@ GRPC_HTTP_CHUNKED_BODY
Definition: src/core/lib/http/parser.h:53
grpc_http_parser_eof
grpc_error_handle grpc_http_parser_eof(grpc_http_parser *parser)
Definition: src/core/lib/http/parser.cc:457
addbyte
static grpc_error_handle addbyte(grpc_http_parser *parser, uint8_t byte, bool *found_body_start)
Definition: src/core/lib/http/parser.cc:383
string.h
GRPC_HTTP_CHUNKED_PLAIN
@ GRPC_HTTP_CHUNKED_PLAIN
Definition: src/core/lib/http/parser.h:50
fix_build_deps.hdrs
hdrs
Definition: fix_build_deps.py:402
benchmark.request
request
Definition: benchmark.py:77
GRPC_HTTP_CHUNKED_LENGTH
@ GRPC_HTTP_CHUNKED_LENGTH
Definition: src/core/lib/http/parser.h:51
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
error
grpc_error_handle error
Definition: retry_filter.cc:499
GRPC_HTTP_HEADERS
@ GRPC_HTTP_HEADERS
Definition: src/core/lib/http/parser.h:43
GRPC_HTTP_HTTP20
@ GRPC_HTTP_HTTP20
Definition: src/core/lib/http/parser.h:60
error_ref_leak.err
err
Definition: error_ref_leak.py:35
gpr_malloc
GPRAPI void * gpr_malloc(size_t size)
Definition: alloc.cc:29
buf2str
static char * buf2str(void *buffer, size_t length)
Definition: src/core/lib/http/parser.cc:32
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
GRPC_TRACE_FLAG_ENABLED
#define GRPC_TRACE_FLAG_ENABLED(f)
Definition: debug/trace.h:114
grpc_http1_trace
grpc_core::TraceFlag grpc_http1_trace(false, "http1")
GRPC_HTTP_FIRST_LINE
@ GRPC_HTTP_FIRST_LINE
Definition: src/core/lib/http/parser.h:42
GRPC_HTTP_CHUNKED_CONSUME_LF
@ GRPC_HTTP_CHUNKED_CONSUME_LF
Definition: src/core/lib/http/parser.h:54
GRPC_HTTP_TRAILERS
@ GRPC_HTTP_TRAILERS
Definition: src/core/lib/http/parser.h:45
grpc_http_response
Definition: src/core/lib/http/parser.h:85
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
grpc_http_request_destroy
void grpc_http_request_destroy(grpc_http_request *request)
Definition: src/core/lib/http/parser.cc:422
asyncio_get_stats.parser
parser
Definition: asyncio_get_stats.py:34
grpc_http_header::key
char * key
Definition: src/core/lib/http/parser.h:37
GRPC_HTTP_HTTP10
@ GRPC_HTTP_HTTP10
Definition: src/core/lib/http/parser.h:58
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
gpr_realloc
GPRAPI void * gpr_realloc(void *p, size_t size)
Definition: alloc.cc:56
grpc_http_header
Definition: src/core/lib/http/parser.h:36
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
slice
grpc_slice slice
Definition: src/core/lib/surface/server.cc:467
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
done
struct tab * done
Definition: bloaty/third_party/zlib/examples/enough.c:176
GRPC_SLICE_START_PTR
#define GRPC_SLICE_START_PTR(slice)
Definition: include/grpc/impl/codegen/slice.h:101
GRPC_HTTP_REQUEST
@ GRPC_HTTP_REQUEST
Definition: src/core/lib/http/parser.h:65
handle_first_line
static grpc_error_handle handle_first_line(grpc_http_parser *parser)
Definition: src/core/lib/http/parser.cc:163
grpc_slice
Definition: include/grpc/impl/codegen/slice.h:65
grpc_http_response_destroy
void grpc_http_response_destroy(grpc_http_response *response)
Definition: src/core/lib/http/parser.cc:434
grpc_http_parser_destroy
void grpc_http_parser_destroy(grpc_http_parser *)
Definition: src/core/lib/http/parser.cc:420
buffer
char buffer[1024]
Definition: libuv/docs/code/idle-compute/main.c:8
GPR_ERROR
#define GPR_ERROR
Definition: include/grpc/impl/codegen/log.h:57
GPR_UNREACHABLE_CODE
#define GPR_UNREACHABLE_CODE(STATEMENT)
Definition: impl/codegen/port_platform.h:652
addbyte_body
static grpc_error_handle addbyte_body(grpc_http_parser *parser, uint8_t byte)
Definition: src/core/lib/http/parser.cc:281
add_header
static grpc_error_handle add_header(grpc_http_parser *parser)
Definition: src/core/lib/http/parser.cc:174
GRPC_ERROR_CREATE_FROM_STATIC_STRING
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc)
Definition: error.h:291
GRPC_HTTP_BODY
@ GRPC_HTTP_BODY
Definition: src/core/lib/http/parser.h:44
GRPC_SLICE_LENGTH
#define GRPC_SLICE_LENGTH(slice)
Definition: include/grpc/impl/codegen/slice.h:104
grpc_core::TraceFlag
Definition: debug/trace.h:63
finish_line
static grpc_error_handle finish_line(grpc_http_parser *parser, bool *found_body_start)
Definition: src/core/lib/http/parser.cc:245
memory_diff.cur
def cur
Definition: memory_diff.py:83
ares::byte
unsigned char byte
Definition: ares-test.h:33
parser.h
alloc.h
GRPC_HTTP_CHUNKED_IGNORE_ALL_UNTIL_LF
@ GRPC_HTTP_CHUNKED_IGNORE_ALL_UNTIL_LF
Definition: src/core/lib/http/parser.h:52
asyncio_get_stats.response
response
Definition: asyncio_get_stats.py:28
grpc_http_parser_parse
grpc_error_handle grpc_http_parser_parse(grpc_http_parser *parser, const grpc_slice &slice, size_t *start_of_body)
Definition: src/core/lib/http/parser.cc:444
grpc_http_parser_init
void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type, void *request_or_response)
Definition: src/core/lib/http/parser.cc:411
grpc_http_header::value
char * value
Definition: src/core/lib/http/parser.h:38
GRPC_HTTP_PARSER_MAX_HEADER_LENGTH
#define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH
Definition: src/core/lib/http/parser.h:33
GRPC_HTTP_END
@ GRPC_HTTP_END
Definition: src/core/lib/http/parser.h:46
check_line
static bool check_line(grpc_http_parser *parser)
Definition: src/core/lib/http/parser.cc:359
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
GRPC_HTTP_RESPONSE
@ GRPC_HTTP_RESPONSE
Definition: src/core/lib/http/parser.h:64
GRPC_HTTP_HTTP11
@ GRPC_HTTP_HTTP11
Definition: src/core/lib/http/parser.h:59
grpc_error
Definition: error_internal.h:42
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
length
std::size_t length
Definition: abseil-cpp/absl/time/internal/test_util.cc:57
grpc_http_parser
Definition: src/core/lib/http/parser.h:99
grpc_http_type
grpc_http_type
Definition: src/core/lib/http/parser.h:63
if
if(p->owned &&p->wrapped !=NULL)
Definition: call.c:42
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
handle_response_line
static grpc_error_handle handle_response_line(grpc_http_parser *parser)
Definition: src/core/lib/http/parser.cc:39
GRPC_ERROR_IS_NONE
#define GRPC_ERROR_IS_NONE(err)
Definition: error.h:241
grpc_http_request
Definition: src/core/lib/http/parser.h:69
handle_request_line
static grpc_error_handle handle_request_line(grpc_http_parser *parser)
Definition: src/core/lib/http/parser.cc:92
port_platform.h


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:39