aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/http
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib/http')
-rw-r--r--src/core/lib/http/httpcli.c123
-rw-r--r--src/core/lib/http/httpcli.h21
-rw-r--r--src/core/lib/http/httpcli_security_connector.c6
-rw-r--r--src/core/lib/http/parser.c246
-rw-r--r--src/core/lib/http/parser.c.orig357
-rw-r--r--src/core/lib/http/parser.h17
6 files changed, 579 insertions, 191 deletions
diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c
index e8957bfe89..18135bcb58 100644
--- a/src/core/lib/http/httpcli.c
+++ b/src/core/lib/http/httpcli.c
@@ -39,12 +39,14 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
#include "src/core/lib/http/format_request.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/support/string.h"
@@ -59,8 +61,7 @@ typedef struct {
gpr_timespec deadline;
int have_read_byte;
const grpc_httpcli_handshaker *handshaker;
- grpc_httpcli_response_cb on_response;
- void *user_data;
+ grpc_closure *on_done;
grpc_httpcli_context *context;
grpc_polling_entity *pollent;
grpc_iomgr_object iomgr_obj;
@@ -69,6 +70,7 @@ typedef struct {
grpc_closure on_read;
grpc_closure done_write;
grpc_closure connected;
+ grpc_error *overall_error;
} internal_request;
static grpc_httpcli_get_override g_get_override = NULL;
@@ -76,6 +78,7 @@ static grpc_httpcli_post_override g_post_override = NULL;
static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint, const char *host,
+ gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx,
void *arg,
grpc_endpoint *endpoint)) {
@@ -93,14 +96,14 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context *context) {
grpc_pollset_set_destroy(context->pollset_set);
}
-static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req);
+static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
+ grpc_error *due_to_error);
static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
- int success) {
+ grpc_error *error) {
grpc_polling_entity_del_from_pollset_set(exec_ctx, req->pollent,
req->context->pollset_set);
- req->on_response(exec_ctx, req->user_data,
- success ? &req->parser.http.response : NULL);
+ grpc_exec_ctx_sched(exec_ctx, req->on_done, error, NULL);
grpc_http_parser_destroy(&req->parser);
if (req->addresses != NULL) {
grpc_resolved_addresses_destroy(req->addresses);
@@ -114,39 +117,49 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
grpc_iomgr_unregister_object(&req->iomgr_obj);
gpr_slice_buffer_destroy(&req->incoming);
gpr_slice_buffer_destroy(&req->outgoing);
+ GRPC_ERROR_UNREF(req->overall_error);
gpr_free(req);
}
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success);
+static void append_error(internal_request *req, grpc_error *error) {
+ if (req->overall_error == GRPC_ERROR_NONE) {
+ req->overall_error = GRPC_ERROR_CREATE("Failed HTTP/1 client request");
+ }
+ grpc_resolved_address *addr = &req->addresses->addrs[req->next_address - 1];
+ char *addr_text = grpc_sockaddr_to_uri((struct sockaddr *)addr->addr);
+ req->overall_error = grpc_error_add_child(
+ req->overall_error,
+ grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, addr_text));
+ gpr_free(addr_text);
+}
static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) {
grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read);
}
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_error *error) {
internal_request *req = user_data;
size_t i;
for (i = 0; i < req->incoming.count; i++) {
if (GPR_SLICE_LENGTH(req->incoming.slices[i])) {
req->have_read_byte = 1;
- if (!grpc_http_parser_parse(&req->parser, req->incoming.slices[i])) {
- finish(exec_ctx, req, 0);
+ grpc_error *err =
+ grpc_http_parser_parse(&req->parser, req->incoming.slices[i]);
+ if (err != GRPC_ERROR_NONE) {
+ finish(exec_ctx, req, err);
return;
}
}
}
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
do_read(exec_ctx, req);
} else if (!req->have_read_byte) {
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req, GRPC_ERROR_REF(error));
} else {
- int parse_success = grpc_http_parser_eof(&req->parser);
- if (parse_success && (req->parser.type != GRPC_HTTP_RESPONSE)) {
- parse_success = 0;
- }
- finish(exec_ctx, req, parse_success);
+ finish(exec_ctx, req, grpc_http_parser_eof(&req->parser));
}
}
@@ -154,12 +167,12 @@ static void on_written(grpc_exec_ctx *exec_ctx, internal_request *req) {
do_read(exec_ctx, req);
}
-static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void done_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
internal_request *req = arg;
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
on_written(exec_ctx, req);
} else {
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req, GRPC_ERROR_REF(error));
}
}
@@ -174,7 +187,8 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
internal_request *req = arg;
if (!ep) {
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req,
+ GRPC_ERROR_CREATE("Unexplained handshake failure"));
return;
}
@@ -182,23 +196,30 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
start_write(exec_ctx, req);
}
-static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void on_connected(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
internal_request *req = arg;
if (!req->ep) {
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req, GRPC_ERROR_REF(error));
return;
}
req->handshaker->handshake(
exec_ctx, req, req->ep,
req->ssl_host_override ? req->ssl_host_override : req->host,
- on_handshake_done);
+ req->deadline, on_handshake_done);
}
-static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
+static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
+ grpc_error *error) {
grpc_resolved_address *addr;
+ if (error != GRPC_ERROR_NONE) {
+ append_error(req, error);
+ }
if (req->next_address == req->addresses->naddrs) {
- finish(exec_ctx, req, 0);
+ finish(exec_ctx, req,
+ GRPC_ERROR_CREATE_REFERENCING("Failed HTTP requests to all targets",
+ &req->overall_error, 1));
return;
}
addr = &req->addresses->addrs[req->next_address++];
@@ -208,34 +229,34 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
(struct sockaddr *)&addr->addr, addr->len, req->deadline);
}
-static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_resolved_addresses *addresses) {
+static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
internal_request *req = arg;
- if (!addresses) {
- finish(exec_ctx, req, 0);
+ if (error != GRPC_ERROR_NONE) {
+ finish(exec_ctx, req, error);
return;
}
- req->addresses = addresses;
req->next_address = 0;
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req, GRPC_ERROR_NONE);
}
-static void internal_request_begin(
- grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
- grpc_polling_entity *pollent, const grpc_httpcli_request *request,
- gpr_timespec deadline, grpc_httpcli_response_cb on_response,
- void *user_data, const char *name, gpr_slice request_text) {
+static void internal_request_begin(grpc_exec_ctx *exec_ctx,
+ grpc_httpcli_context *context,
+ grpc_polling_entity *pollent,
+ const grpc_httpcli_request *request,
+ gpr_timespec deadline, grpc_closure *on_done,
+ grpc_httpcli_response *response,
+ const char *name, gpr_slice request_text) {
internal_request *req = gpr_malloc(sizeof(internal_request));
memset(req, 0, sizeof(*req));
req->request_text = request_text;
- grpc_http_parser_init(&req->parser);
- req->on_response = on_response;
- req->user_data = user_data;
+ grpc_http_parser_init(&req->parser, GRPC_HTTP_RESPONSE, response);
+ req->on_done = on_done;
req->deadline = deadline;
req->handshaker =
request->handshaker ? request->handshaker : &grpc_httpcli_plaintext;
req->context = context;
req->pollent = pollent;
+ req->overall_error = GRPC_ERROR_NONE;
grpc_closure_init(&req->on_read, on_read, req);
grpc_closure_init(&req->done_write, done_write, req);
gpr_slice_buffer_init(&req->incoming);
@@ -248,22 +269,22 @@ static void internal_request_begin(
grpc_polling_entity_add_to_pollset_set(exec_ctx, req->pollent,
req->context->pollset_set);
grpc_resolve_address(exec_ctx, request->host, req->handshaker->default_port,
- on_resolved, req);
+ grpc_closure_create(on_resolved, req), &req->addresses);
}
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
- gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data) {
+ gpr_timespec deadline, grpc_closure *on_done,
+ grpc_httpcli_response *response) {
char *name;
if (g_get_override &&
- g_get_override(exec_ctx, request, deadline, on_response, user_data)) {
+ g_get_override(exec_ctx, request, deadline, on_done, response)) {
return;
}
gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path);
- internal_request_begin(exec_ctx, context, pollent, request, deadline,
- on_response, user_data, name,
+ internal_request_begin(exec_ctx, context, pollent, request, deadline, on_done,
+ response, name,
grpc_httpcli_format_get_request(request));
gpr_free(name);
}
@@ -272,18 +293,18 @@ void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size,
- gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data) {
+ gpr_timespec deadline, grpc_closure *on_done,
+ grpc_httpcli_response *response) {
char *name;
if (g_post_override &&
g_post_override(exec_ctx, request, body_bytes, body_size, deadline,
- on_response, user_data)) {
+ on_done, response)) {
return;
}
gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path);
internal_request_begin(
- exec_ctx, context, pollent, request, deadline, on_response, user_data,
- name, grpc_httpcli_format_post_request(request, body_bytes, body_size));
+ exec_ctx, context, pollent, request, deadline, on_done, response, name,
+ grpc_httpcli_format_post_request(request, body_bytes, body_size));
gpr_free(name);
}
diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h
index 7e7784f1ab..662e176f4c 100644
--- a/src/core/lib/http/httpcli.h
+++ b/src/core/lib/http/httpcli.h
@@ -57,7 +57,7 @@ typedef struct grpc_httpcli_context {
typedef struct {
const char *default_port;
void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint,
- const char *host,
+ const char *host, gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint));
} grpc_httpcli_handshaker;
@@ -82,11 +82,6 @@ typedef struct grpc_httpcli_request {
/* Expose the parser response type as a httpcli response too */
typedef struct grpc_http_response grpc_httpcli_response;
-/* Callback for grpc_httpcli_get and grpc_httpcli_post. */
-typedef void (*grpc_httpcli_response_cb)(grpc_exec_ctx *exec_ctx,
- void *user_data,
- const grpc_http_response *response);
-
void grpc_httpcli_context_init(grpc_httpcli_context *context);
void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
@@ -103,8 +98,8 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
- gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data);
+ gpr_timespec deadline, grpc_closure *on_complete,
+ grpc_httpcli_response *response);
/* Asynchronously perform a HTTP POST.
'context' specifies the http context under which to do the post
@@ -125,19 +120,19 @@ void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size,
- gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data);
+ gpr_timespec deadline, grpc_closure *on_complete,
+ grpc_httpcli_response *response);
/* override functions return 1 if they handled the request, 0 otherwise */
typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx,
const grpc_httpcli_request *request,
gpr_timespec deadline,
- grpc_httpcli_response_cb on_response,
- void *user_data);
+ grpc_closure *on_complete,
+ grpc_httpcli_response *response);
typedef int (*grpc_httpcli_post_override)(
grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size, gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data);
+ grpc_closure *on_complete, grpc_httpcli_response *response);
void grpc_httpcli_set_override(grpc_httpcli_get_override get,
grpc_httpcli_post_override post);
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index 5590928968..a57d93bb7b 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -61,6 +61,7 @@ static void httpcli_ssl_destroy(grpc_security_connector *sc) {
static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
+ gpr_timespec deadline,
grpc_security_handshake_done_cb cb,
void *user_data) {
grpc_httpcli_ssl_channel_security_connector *c =
@@ -79,7 +80,7 @@ static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
- nonsecure_endpoint, cb, user_data);
+ nonsecure_endpoint, deadline, cb, user_data);
}
}
@@ -163,6 +164,7 @@ static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *tcp, const char *host,
+ gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint)) {
grpc_channel_security_connector *sc = NULL;
@@ -181,7 +183,7 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
pem_root_certs, pem_root_certs_size, host, &sc) ==
GRPC_SECURITY_OK);
grpc_channel_security_connector_do_handshake(
- exec_ctx, sc, tcp, on_secure_transport_setup_done, c);
+ exec_ctx, sc, tcp, deadline, on_secure_transport_setup_done, c);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
}
diff --git a/src/core/lib/http/parser.c b/src/core/lib/http/parser.c
index 09b2ed40d1..92ed08ae51 100644
--- a/src/core/lib/http/parser.c
+++ b/src/core/lib/http/parser.c
@@ -48,37 +48,38 @@ static char *buf2str(void *buffer, size_t length) {
return out;
}
-static int handle_response_line(grpc_http_parser *parser) {
+static grpc_error *handle_response_line(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
- if (cur == end || *cur++ != 'H') goto error;
- if (cur == end || *cur++ != 'T') goto error;
- if (cur == end || *cur++ != 'T') goto error;
- if (cur == end || *cur++ != 'P') goto error;
- if (cur == end || *cur++ != '/') goto error;
- if (cur == end || *cur++ != '1') goto error;
- if (cur == end || *cur++ != '.') goto error;
- if (cur == end || *cur < '0' || *cur++ > '1') goto error;
- if (cur == end || *cur++ != ' ') goto error;
- if (cur == end || *cur < '1' || *cur++ > '9') goto error;
- if (cur == end || *cur < '0' || *cur++ > '9') goto error;
- if (cur == end || *cur < '0' || *cur++ > '9') goto error;
- parser->http.response.status =
+ if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
+ if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
+ if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'");
+ if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'");
+ if (cur == end || *cur < '0' || *cur++ > '1') {
+ return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1");
+ }
+ if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
+ if (cur == end || *cur < '1' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ if (cur == end || *cur < '0' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ if (cur == end || *cur < '0' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ parser->http.response->status =
(cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
- if (cur == end || *cur++ != ' ') goto error;
+ if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
/* we don't really care about the status code message */
- return 1;
-
-error:
- if (grpc_http1_trace) gpr_log(GPR_ERROR, "Failed parsing response line");
- return 0;
+ return GRPC_ERROR_NONE;
}
-static int handle_request_line(grpc_http_parser *parser) {
+static grpc_error *handle_request_line(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
@@ -87,84 +88,81 @@ static int handle_request_line(grpc_http_parser *parser) {
while (cur != end && *cur++ != ' ')
;
- if (cur == end) goto error;
- parser->http.request.method = buf2str(beg, (size_t)(cur - beg - 1));
+ if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line");
+ parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1));
beg = cur;
while (cur != end && *cur++ != ' ')
;
- if (cur == end) goto error;
- parser->http.request.path = buf2str(beg, (size_t)(cur - beg - 1));
-
- if (cur == end || *cur++ != 'H') goto error;
- if (cur == end || *cur++ != 'T') goto error;
- if (cur == end || *cur++ != 'T') goto error;
- if (cur == end || *cur++ != 'P') goto error;
- if (cur == end || *cur++ != '/') goto error;
+ if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line");
+ parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1));
+
+ if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
+ if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
vers_major = (uint8_t)(*cur++ - '1' + 1);
++cur;
- if (cur == end) goto error;
+ if (cur == end)
+ return GRPC_ERROR_CREATE("End of line in HTTP version string");
vers_minor = (uint8_t)(*cur++ - '1' + 1);
if (vers_major == 1) {
if (vers_minor == 0) {
- parser->http.request.version = GRPC_HTTP_HTTP10;
+ parser->http.request->version = GRPC_HTTP_HTTP10;
} else if (vers_minor == 1) {
- parser->http.request.version = GRPC_HTTP_HTTP11;
+ parser->http.request->version = GRPC_HTTP_HTTP11;
} else {
- goto error;
+ return GRPC_ERROR_CREATE(
+ "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
} else if (vers_major == 2) {
if (vers_minor == 0) {
- parser->http.request.version = GRPC_HTTP_HTTP20;
+ parser->http.request->version = GRPC_HTTP_HTTP20;
} else {
- goto error;
+ return GRPC_ERROR_CREATE(
+ "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
} else {
- goto error;
+ return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
- return 1;
-
-error:
- if (grpc_http1_trace) gpr_log(GPR_ERROR, "Failed parsing request line");
- return 0;
+ return GRPC_ERROR_NONE;
}
-static int handle_first_line(grpc_http_parser *parser) {
- if (parser->cur_line[0] == 'H') {
- parser->type = GRPC_HTTP_RESPONSE;
- return handle_response_line(parser);
- } else {
- parser->type = GRPC_HTTP_REQUEST;
- return handle_request_line(parser);
+static grpc_error *handle_first_line(grpc_http_parser *parser) {
+ switch (parser->type) {
+ case GRPC_HTTP_REQUEST:
+ return handle_request_line(parser);
+ case GRPC_HTTP_RESPONSE:
+ return handle_response_line(parser);
}
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
-static int add_header(grpc_http_parser *parser) {
+static grpc_error *add_header(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
size_t *hdr_count = NULL;
grpc_http_header **hdrs = NULL;
grpc_http_header hdr = {NULL, NULL};
+ grpc_error *error = GRPC_ERROR_NONE;
GPR_ASSERT(cur != end);
if (*cur == ' ' || *cur == '\t') {
- if (grpc_http1_trace)
- gpr_log(GPR_ERROR, "Continued header lines not supported yet");
- goto error;
+ error = GRPC_ERROR_CREATE("Continued header lines not supported yet");
+ goto done;
}
while (cur != end && *cur != ':') {
cur++;
}
if (cur == end) {
- if (grpc_http1_trace) {
- gpr_log(GPR_ERROR, "Didn't find ':' in header string");
- }
- goto error;
+ error = GRPC_ERROR_CREATE("Didn't find ':' in header string");
+ goto done;
}
GPR_ASSERT(cur >= beg);
hdr.key = buf2str(beg, (size_t)(cur - beg));
@@ -176,14 +174,15 @@ static int add_header(grpc_http_parser *parser) {
GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length);
- if (parser->type == GRPC_HTTP_RESPONSE) {
- hdr_count = &parser->http.response.hdr_count;
- hdrs = &parser->http.response.hdrs;
- } else if (parser->type == GRPC_HTTP_REQUEST) {
- hdr_count = &parser->http.request.hdr_count;
- hdrs = &parser->http.request.hdrs;
- } else {
- return 0;
+ switch (parser->type) {
+ case GRPC_HTTP_RESPONSE:
+ hdr_count = &parser->http.response->hdr_count;
+ hdrs = &parser->http.response->hdrs;
+ break;
+ case GRPC_HTTP_REQUEST:
+ hdr_count = &parser->http.request->hdr_count;
+ hdrs = &parser->http.request->hdrs;
+ break;
}
if (*hdr_count == parser->hdr_capacity) {
@@ -192,20 +191,21 @@ static int add_header(grpc_http_parser *parser) {
*hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs));
}
(*hdrs)[(*hdr_count)++] = hdr;
- return 1;
-error:
- gpr_free(hdr.key);
- gpr_free(hdr.value);
- return 0;
+done:
+ if (error != GRPC_ERROR_NONE) {
+ gpr_free(hdr.key);
+ gpr_free(hdr.value);
+ }
+ return error;
}
-static int finish_line(grpc_http_parser *parser) {
+static grpc_error *finish_line(grpc_http_parser *parser) {
+ grpc_error *err;
switch (parser->state) {
case GRPC_HTTP_FIRST_LINE:
- if (!handle_first_line(parser)) {
- return 0;
- }
+ err = handle_first_line(parser);
+ if (err != GRPC_ERROR_NONE) return err;
parser->state = GRPC_HTTP_HEADERS;
break;
case GRPC_HTTP_HEADERS:
@@ -213,30 +213,31 @@ static int finish_line(grpc_http_parser *parser) {
parser->state = GRPC_HTTP_BODY;
break;
}
- if (!add_header(parser)) {
- return 0;
+ err = add_header(parser);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
break;
case GRPC_HTTP_BODY:
- GPR_UNREACHABLE_CODE(return 0);
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
parser->cur_line_length = 0;
- return 1;
+ return GRPC_ERROR_NONE;
}
-static int addbyte_body(grpc_http_parser *parser, uint8_t byte) {
+static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) {
size_t *body_length = NULL;
char **body = NULL;
if (parser->type == GRPC_HTTP_RESPONSE) {
- body_length = &parser->http.response.body_length;
- body = &parser->http.response.body;
+ body_length = &parser->http.response->body_length;
+ body = &parser->http.response->body;
} else if (parser->type == GRPC_HTTP_REQUEST) {
- body_length = &parser->http.request.body_length;
- body = &parser->http.request.body;
+ body_length = &parser->http.request->body_length;
+ body = &parser->http.request->body;
} else {
- return 0;
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
if (*body_length == parser->body_capacity) {
@@ -246,34 +247,34 @@ static int addbyte_body(grpc_http_parser *parser, uint8_t byte) {
(*body)[*body_length] = (char)byte;
(*body_length)++;
- return 1;
+ return GRPC_ERROR_NONE;
}
-static int check_line(grpc_http_parser *parser) {
+static bool check_line(grpc_http_parser *parser) {
if (parser->cur_line_length >= 2 &&
parser->cur_line[parser->cur_line_length - 2] == '\r' &&
parser->cur_line[parser->cur_line_length - 1] == '\n') {
- return 1;
+ return true;
}
// HTTP request with \n\r line termiantors.
else if (parser->cur_line_length >= 2 &&
parser->cur_line[parser->cur_line_length - 2] == '\n' &&
parser->cur_line[parser->cur_line_length - 1] == '\r') {
- return 1;
+ return true;
}
// HTTP request with only \n line terminators.
else if (parser->cur_line_length >= 1 &&
parser->cur_line[parser->cur_line_length - 1] == '\n') {
parser->cur_line_end_length = 1;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-static int addbyte(grpc_http_parser *parser, uint8_t byte) {
+static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte) {
switch (parser->state) {
case GRPC_HTTP_FIRST_LINE:
case GRPC_HTTP_HEADERS:
@@ -288,7 +289,7 @@ static int addbyte(grpc_http_parser *parser, uint8_t byte) {
if (check_line(parser)) {
return finish_line(parser);
} else {
- return 1;
+ return GRPC_ERROR_NONE;
}
GPR_UNREACHABLE_CODE(return 0);
case GRPC_HTTP_BODY:
@@ -297,46 +298,53 @@ static int addbyte(grpc_http_parser *parser, uint8_t byte) {
GPR_UNREACHABLE_CODE(return 0);
}
-void grpc_http_parser_init(grpc_http_parser *parser) {
+void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
+ void *request_or_response) {
memset(parser, 0, sizeof(*parser));
parser->state = GRPC_HTTP_FIRST_LINE;
- parser->type = GRPC_HTTP_UNKNOWN;
+ parser->type = type;
+ parser->http.request_or_response = request_or_response;
parser->cur_line_end_length = 2;
}
-void grpc_http_parser_destroy(grpc_http_parser *parser) {
+void grpc_http_parser_destroy(grpc_http_parser *parser) {}
+
+void grpc_http_request_destroy(grpc_http_request *request) {
size_t i;
- if (parser->type == GRPC_HTTP_RESPONSE) {
- gpr_free(parser->http.response.body);
- for (i = 0; i < parser->http.response.hdr_count; i++) {
- gpr_free(parser->http.response.hdrs[i].key);
- gpr_free(parser->http.response.hdrs[i].value);
- }
- gpr_free(parser->http.response.hdrs);
- } else if (parser->type == GRPC_HTTP_REQUEST) {
- gpr_free(parser->http.request.body);
- for (i = 0; i < parser->http.request.hdr_count; i++) {
- gpr_free(parser->http.request.hdrs[i].key);
- gpr_free(parser->http.request.hdrs[i].value);
- }
- gpr_free(parser->http.request.hdrs);
- gpr_free(parser->http.request.method);
- gpr_free(parser->http.request.path);
+ gpr_free(request->body);
+ for (i = 0; i < request->hdr_count; i++) {
+ gpr_free(request->hdrs[i].key);
+ gpr_free(request->hdrs[i].value);
}
+ gpr_free(request->hdrs);
+ gpr_free(request->method);
+ gpr_free(request->path);
}
-int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
+void grpc_http_response_destroy(grpc_http_response *response) {
+ size_t i;
+ gpr_free(response->body);
+ for (i = 0; i < response->hdr_count; i++) {
+ gpr_free(response->hdrs[i].key);
+ gpr_free(response->hdrs[i].value);
+ }
+ gpr_free(response->hdrs);
+}
+
+grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
size_t i;
for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
- if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) {
- return 0;
- }
+ grpc_error *err = addbyte(parser, GPR_SLICE_START_PTR(slice)[i]);
+ if (err != GRPC_ERROR_NONE) return err;
}
- return 1;
+ return GRPC_ERROR_NONE;
}
-int grpc_http_parser_eof(grpc_http_parser *parser) {
- return parser->state == GRPC_HTTP_BODY;
+grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) {
+ if (parser->state != GRPC_HTTP_BODY) {
+ return GRPC_ERROR_CREATE("Did not finish headers");
+ }
+ return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/http/parser.c.orig b/src/core/lib/http/parser.c.orig
new file mode 100644
index 0000000000..74d90fd8bf
--- /dev/null
+++ b/src/core/lib/http/parser.c.orig
@@ -0,0 +1,357 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/parser.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+int grpc_http1_trace = 0;
+
+static char *buf2str(void *buffer, size_t length) {
+ char *out = gpr_malloc(length + 1);
+ memcpy(out, buffer, length);
+ out[length] = 0;
+ return out;
+}
+
+static grpc_error *handle_response_line(grpc_http_parser *parser) {
+ uint8_t *beg = parser->cur_line;
+ uint8_t *cur = beg;
+ uint8_t *end = beg + parser->cur_line_length;
+
+ if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
+ if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
+ if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'");
+ if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'");
+ if (cur == end || *cur < '0' || *cur++ > '1') {
+ return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1");
+ }
+ if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
+ if (cur == end || *cur < '1' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ if (cur == end || *cur < '0' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ if (cur == end || *cur < '0' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ parser->http.response->status =
+ (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
+ if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
+
+ /* we don't really care about the status code message */
+
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error *handle_request_line(grpc_http_parser *parser) {
+ uint8_t *beg = parser->cur_line;
+ uint8_t *cur = beg;
+ uint8_t *end = beg + parser->cur_line_length;
+ uint8_t vers_major = 0;
+ uint8_t vers_minor = 0;
+
+ while (cur != end && *cur++ != ' ')
+ ;
+ if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line");
+ parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1));
+
+ beg = cur;
+ while (cur != end && *cur++ != ' ')
+ ;
+ if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line");
+ parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1));
+
+ if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
+ if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
+ vers_major = (uint8_t)(*cur++ - '1' + 1);
+ ++cur;
+ if (cur == end)
+ return GRPC_ERROR_CREATE("End of line in HTTP version string");
+ vers_minor = (uint8_t)(*cur++ - '1' + 1);
+
+ if (vers_major == 1) {
+ if (vers_minor == 0) {
+ parser->http.request->version = GRPC_HTTP_HTTP10;
+ } else if (vers_minor == 1) {
+ parser->http.request->version = GRPC_HTTP_HTTP11;
+ } else {
+ return GRPC_ERROR_CREATE(
+ "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
+ }
+ } else if (vers_major == 2) {
+ if (vers_minor == 0) {
+ parser->http.request->version = GRPC_HTTP_HTTP20;
+ } else {
+ return GRPC_ERROR_CREATE(
+ "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
+ }
+ } else {
+ return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
+ }
+
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error *handle_first_line(grpc_http_parser *parser) {
+ switch (parser->type) {
+ case GRPC_HTTP_REQUEST:
+ return handle_request_line(parser);
+ case GRPC_HTTP_RESPONSE:
+ return handle_response_line(parser);
+ }
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
+}
+
+static grpc_error *add_header(grpc_http_parser *parser) {
+ uint8_t *beg = parser->cur_line;
+ uint8_t *cur = beg;
+ uint8_t *end = beg + parser->cur_line_length;
+ size_t *hdr_count = NULL;
+ grpc_http_header **hdrs = NULL;
+ grpc_http_header hdr = {NULL, NULL};
+ grpc_error *error = GRPC_ERROR_NONE;
+
+ GPR_ASSERT(cur != end);
+
+ if (*cur == ' ' || *cur == '\t') {
+ error = GRPC_ERROR_CREATE("Continued header lines not supported yet");
+ goto done;
+ }
+
+ while (cur != end && *cur != ':') {
+ cur++;
+ }
+ if (cur == end) {
+<<<<<<< HEAD
+ error = GRPC_ERROR_CREATE("Didn't find ':' in header string");
+ goto done;
+=======
+ if (grpc_http1_trace) {
+ gpr_log(GPR_ERROR, "Didn't find ':' in header string");
+ }
+ goto error;
+>>>>>>> a709afe241d8b264a1c326315f757b4a8d330207
+ }
+ GPR_ASSERT(cur >= beg);
+ hdr.key = buf2str(beg, (size_t)(cur - beg));
+ cur++; /* skip : */
+
+ while (cur != end && (*cur == ' ' || *cur == '\t')) {
+ cur++;
+ }
+ GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
+ hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length);
+
+ switch (parser->type) {
+ case GRPC_HTTP_RESPONSE:
+ hdr_count = &parser->http.response->hdr_count;
+ hdrs = &parser->http.response->hdrs;
+ break;
+ case GRPC_HTTP_REQUEST:
+ hdr_count = &parser->http.request->hdr_count;
+ hdrs = &parser->http.request->hdrs;
+ break;
+ }
+
+ if (*hdr_count == parser->hdr_capacity) {
+ parser->hdr_capacity =
+ GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
+ *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs));
+ }
+ (*hdrs)[(*hdr_count)++] = hdr;
+
+done:
+ if (error != GRPC_ERROR_NONE) {
+ gpr_free(hdr.key);
+ gpr_free(hdr.value);
+ }
+ return error;
+}
+
+static grpc_error *finish_line(grpc_http_parser *parser) {
+ grpc_error *err;
+ switch (parser->state) {
+ case GRPC_HTTP_FIRST_LINE:
+ err = handle_first_line(parser);
+ if (err != GRPC_ERROR_NONE) return err;
+ parser->state = GRPC_HTTP_HEADERS;
+ break;
+ case GRPC_HTTP_HEADERS:
+ if (parser->cur_line_length == parser->cur_line_end_length) {
+ parser->state = GRPC_HTTP_BODY;
+ break;
+ }
+ err = add_header(parser);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
+ }
+ break;
+ case GRPC_HTTP_BODY:
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
+ }
+
+ parser->cur_line_length = 0;
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) {
+ size_t *body_length = NULL;
+ char **body = NULL;
+
+ if (parser->type == GRPC_HTTP_RESPONSE) {
+ body_length = &parser->http.response->body_length;
+ body = &parser->http.response->body;
+ } else if (parser->type == GRPC_HTTP_REQUEST) {
+ body_length = &parser->http.request->body_length;
+ body = &parser->http.request->body;
+ } else {
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
+ }
+
+ if (*body_length == parser->body_capacity) {
+ parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
+ *body = gpr_realloc((void *)*body, parser->body_capacity);
+ }
+ (*body)[*body_length] = (char)byte;
+ (*body_length)++;
+
+ return GRPC_ERROR_NONE;
+}
+
+static bool check_line(grpc_http_parser *parser) {
+ if (parser->cur_line_length >= 2 &&
+ parser->cur_line[parser->cur_line_length - 2] == '\r' &&
+ parser->cur_line[parser->cur_line_length - 1] == '\n') {
+ return true;
+ }
+
+ // HTTP request with \n\r line termiantors.
+ else if (parser->cur_line_length >= 2 &&
+ parser->cur_line[parser->cur_line_length - 2] == '\n' &&
+ parser->cur_line[parser->cur_line_length - 1] == '\r') {
+ return true;
+ }
+
+ // HTTP request with only \n line terminators.
+ else if (parser->cur_line_length >= 1 &&
+ parser->cur_line[parser->cur_line_length - 1] == '\n') {
+ parser->cur_line_end_length = 1;
+ return true;
+ }
+
+ return false;
+}
+
+static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte) {
+ switch (parser->state) {
+ case GRPC_HTTP_FIRST_LINE:
+ case GRPC_HTTP_HEADERS:
+ if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
+ if (grpc_http1_trace)
+ gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded",
+ GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
+ return 0;
+ }
+ parser->cur_line[parser->cur_line_length] = byte;
+ parser->cur_line_length++;
+ if (check_line(parser)) {
+ return finish_line(parser);
+ } else {
+ return GRPC_ERROR_NONE;
+ }
+ GPR_UNREACHABLE_CODE(return 0);
+ case GRPC_HTTP_BODY:
+ return addbyte_body(parser, byte);
+ }
+ GPR_UNREACHABLE_CODE(return 0);
+}
+
+void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
+ void *request_or_response) {
+ memset(parser, 0, sizeof(*parser));
+ parser->state = GRPC_HTTP_FIRST_LINE;
+ parser->type = type;
+ parser->http.request_or_response = request_or_response;
+ parser->cur_line_end_length = 2;
+}
+
+void grpc_http_parser_destroy(grpc_http_parser *parser) {}
+
+void grpc_http_request_destroy(grpc_http_request *request) {
+ size_t i;
+ gpr_free(request->body);
+ for (i = 0; i < request->hdr_count; i++) {
+ gpr_free(request->hdrs[i].key);
+ gpr_free(request->hdrs[i].value);
+ }
+ gpr_free(request->hdrs);
+ gpr_free(request->method);
+ gpr_free(request->path);
+}
+
+void grpc_http_response_destroy(grpc_http_response *response) {
+ size_t i;
+ gpr_free(response->body);
+ for (i = 0; i < response->hdr_count; i++) {
+ gpr_free(response->hdrs[i].key);
+ gpr_free(response->hdrs[i].value);
+ }
+ gpr_free(response->hdrs);
+}
+
+grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
+ size_t i;
+
+ for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
+ grpc_error *err = addbyte(parser, GPR_SLICE_START_PTR(slice)[i]);
+ if (err != GRPC_ERROR_NONE) return err;
+ }
+
+ return GRPC_ERROR_NONE;
+}
+
+grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) {
+ if (parser->state != GRPC_HTTP_BODY) {
+ return GRPC_ERROR_CREATE("Did not finish headers");
+ }
+ return GRPC_ERROR_NONE;
+}
diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h
index 536637e9a2..6df3cc8b13 100644
--- a/src/core/lib/http/parser.h
+++ b/src/core/lib/http/parser.h
@@ -36,6 +36,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/slice.h>
+#include "src/core/lib/iomgr/error.h"
/* Maximum length of a header string of the form 'Key: Value\r\n' */
#define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096
@@ -61,7 +62,6 @@ typedef enum {
typedef enum {
GRPC_HTTP_RESPONSE,
GRPC_HTTP_REQUEST,
- GRPC_HTTP_UNKNOWN
} grpc_http_type;
/* A request */
@@ -97,8 +97,9 @@ typedef struct {
grpc_http_type type;
union {
- grpc_http_response response;
- grpc_http_request request;
+ grpc_http_response *response;
+ grpc_http_request *request;
+ void *request_or_response;
} http;
size_t body_capacity;
size_t hdr_capacity;
@@ -108,11 +109,15 @@ typedef struct {
size_t cur_line_end_length;
} grpc_http_parser;
-void grpc_http_parser_init(grpc_http_parser *parser);
+void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
+ void *request_or_response);
void grpc_http_parser_destroy(grpc_http_parser *parser);
-int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice);
-int grpc_http_parser_eof(grpc_http_parser *parser);
+grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice);
+grpc_error *grpc_http_parser_eof(grpc_http_parser *parser);
+
+void grpc_http_request_destroy(grpc_http_request *request);
+void grpc_http_response_destroy(grpc_http_response *response);
extern int grpc_http1_trace;