commit ea07ddef34d13aea1c203d8833595f24ab0c1367
parent c1bc0ce13f61ca636b9ba893eb6bdd1b6ba696d2
Author: Joris Vink <joris@coders.se>
Date: Sun, 27 Jul 2014 21:59:25 +0200
Properly send out early HTTP errors via the appropriate SPDY stream
Diffstat:
src/http.c | | | 73 | ++++++++++++++++++++++++++++++++++++++----------------------------------- |
src/spdy.c | | | 27 | +++++++++++++-------------- |
2 files changed, 51 insertions(+), 49 deletions(-)
diff --git a/src/http.c b/src/http.c
@@ -34,7 +34,8 @@
static char *http_status_text(int);
static int http_post_data_recv(struct netbuf *);
static char *http_post_data_text(struct http_request *);
-static void http_error_response(struct connection *, int);
+static void http_error_response(struct connection *,
+ struct spdy_stream *, int);
static u_int8_t *http_post_data_bytes(struct http_request *,
u_int32_t *);
static void http_argument_add(struct http_request *, char *,
@@ -44,7 +45,8 @@ static void http_file_add(struct http_request *, char *, char *,
static void http_response_normal(struct http_request *,
struct connection *, int, void *, u_int32_t);
static void http_response_spdy(struct http_request *,
- struct connection *, int, void *, u_int32_t);
+ struct connection *, struct spdy_stream *,
+ int, void *, u_int32_t);
static TAILQ_HEAD(, http_request) http_requests;
static TAILQ_HEAD(, http_request) http_requests_sleeping;
@@ -83,17 +85,17 @@ http_request_new(struct connection *c, struct spdy_stream *s, char *host,
host, method, path, version);
if (strlen(host) >= KORE_DOMAINNAME_LEN - 1) {
- http_error_response(c, 500);
+ http_error_response(c, s, 500);
return (KORE_RESULT_ERROR);
}
if (strlen(path) >= HTTP_URI_LEN - 1) {
- http_error_response(c, 414);
+ http_error_response(c, s, 414);
return (KORE_RESULT_ERROR);
}
if (strcasecmp(version, "http/1.1")) {
- http_error_response(c, 505);
+ http_error_response(c, s, 505);
return (KORE_RESULT_ERROR);
}
@@ -104,7 +106,7 @@ http_request_new(struct connection *c, struct spdy_stream *s, char *host,
flags = 0;
m = HTTP_METHOD_POST;
} else {
- http_error_response(c, 405);
+ http_error_response(c, s, 405);
return (KORE_RESULT_ERROR);
}
@@ -368,18 +370,18 @@ http_request_free(struct http_request *req)
}
void
-http_response(struct http_request *req, int status, void *d, u_int32_t len)
+http_response(struct http_request *req, int status, void *d, u_int32_t l)
{
- kore_debug("http_response(%p, %d, %p, %d)", req, status, d, len);
+ kore_debug("http_response(%p, %d, %p, %d)", req, status, d, l);
req->status = status;
switch (req->owner->proto) {
case CONN_PROTO_SPDY:
- http_response_spdy(req, req->owner, status, d, len);
+ http_response_spdy(req, req->owner, req->stream, status, d, l);
break;
case CONN_PROTO_HTTP:
- http_response_normal(req, req->owner, status, d, len);
+ http_response_normal(req, req->owner, status, d, l);
break;
}
}
@@ -444,13 +446,13 @@ http_header_recv(struct netbuf *nb)
h = kore_split_string(hbuf, "\r\n", headers, HTTP_REQ_HEADER_MAX);
if (h < 2) {
- http_error_response(c, 400);
+ http_error_response(c, NULL, 400);
return (KORE_RESULT_OK);
}
v = kore_split_string(headers[0], " ", request, 4);
if (v != 3) {
- http_error_response(c, 400);
+ http_error_response(c, NULL, 400);
return (KORE_RESULT_OK);
}
@@ -463,13 +465,13 @@ http_header_recv(struct netbuf *nb)
v = kore_split_string(headers[i], ":", host, 3);
if (v != 2) {
- http_error_response(c, 400);
+ http_error_response(c, NULL, 400);
return (KORE_RESULT_OK);
}
if (strlen(host[0]) != 4 || strncasecmp(host[0], "host", 4) ||
strlen(host[1]) < 4) {
- http_error_response(c, 400);
+ http_error_response(c, NULL, 400);
return (KORE_RESULT_OK);
}
@@ -479,7 +481,7 @@ http_header_recv(struct netbuf *nb)
}
if (host[0] == NULL) {
- http_error_response(c, 400);
+ http_error_response(c, NULL, 400);
return (KORE_RESULT_OK);
}
@@ -514,7 +516,7 @@ http_header_recv(struct netbuf *nb)
if (!http_request_header_get(req, "content-length", &p)) {
kore_debug("POST but no content-length");
req->flags |= HTTP_REQUEST_DELETE;
- http_error_response(req->owner, 411);
+ http_error_response(req->owner, NULL, 411);
return (KORE_RESULT_OK);
}
@@ -523,7 +525,7 @@ http_header_recv(struct netbuf *nb)
kore_debug("content-length invalid: %s", p);
kore_mem_free(p);
req->flags |= HTTP_REQUEST_DELETE;
- http_error_response(req->owner, 411);
+ http_error_response(req->owner, NULL, 411);
return (KORE_RESULT_OK);
}
@@ -538,7 +540,7 @@ http_header_recv(struct netbuf *nb)
kore_log(LOG_NOTICE, "POST data too large (%ld > %ld)",
clen, http_postbody_max);
req->flags |= HTTP_REQUEST_DELETE;
- http_error_response(req->owner, 411);
+ http_error_response(req->owner, NULL, 411);
return (KORE_RESULT_OK);
}
@@ -557,7 +559,7 @@ http_header_recv(struct netbuf *nb)
req->flags |= HTTP_REQUEST_COMPLETE;
} else {
kore_debug("bytes_left would become zero (%ld)", clen);
- http_error_response(req->owner, 500);
+ http_error_response(req->owner, NULL, 500);
}
}
@@ -988,9 +990,9 @@ http_post_data_bytes(struct http_request *req, u_int32_t *len)
}
static void
-http_error_response(struct connection *c, int status)
+http_error_response(struct connection *c, struct spdy_stream *s, int status)
{
- kore_debug("http_error_response(%p, %d)", c, status);
+ kore_debug("http_error_response(%p, %p, %d)", c, s, status);
c->flags |= CONN_READ_BLOCK;
c->flags |= CONN_CLOSE_EMPTY;
@@ -998,9 +1000,11 @@ http_error_response(struct connection *c, int status)
switch (c->proto) {
case CONN_PROTO_SPDY:
- http_response_spdy(NULL, c, status, NULL, 0);
+ http_response_spdy(NULL, c, s, status, NULL, 0);
break;
case CONN_PROTO_HTTP:
+ if (s != NULL)
+ kore_log(LOG_NOTICE, "http_error_response: s != NULL");
http_response_normal(NULL, c, status, NULL, 0);
break;
}
@@ -1008,7 +1012,7 @@ http_error_response(struct connection *c, int status)
static void
http_response_spdy(struct http_request *req, struct connection *c,
- int status, void *d, u_int32_t len)
+ struct spdy_stream *s, int status, void *d, u_int32_t len)
{
u_int32_t hlen;
struct http_header *hdr;
@@ -1038,29 +1042,28 @@ http_response_spdy(struct http_request *req, struct connection *c,
":strict-transport-security", sbuf);
}
- TAILQ_FOREACH(hdr, &(req->resp_headers), list)
- spdy_header_block_add(hblock, hdr->header, hdr->value);
+ if (req != NULL) {
+ TAILQ_FOREACH(hdr, &(req->resp_headers), list)
+ spdy_header_block_add(hblock, hdr->header, hdr->value);
+ }
- htext = spdy_header_block_release(req->owner, hblock, &hlen);
+ htext = spdy_header_block_release(c, hblock, &hlen);
if (htext == NULL) {
- spdy_session_teardown(req->owner, SPDY_SESSION_ERROR_INTERNAL);
+ spdy_session_teardown(c, SPDY_SESSION_ERROR_INTERNAL);
return;
}
- spdy_frame_send(req->owner, SPDY_CTRL_FRAME_SYN_REPLY,
- 0, hlen, req->stream, 0);
- net_send_queue(req->owner, htext, hlen, NULL);
+ spdy_frame_send(c, SPDY_CTRL_FRAME_SYN_REPLY, 0, hlen, s, 0);
+ net_send_queue(c, htext, hlen, NULL);
kore_mem_free(htext);
if (len > 0) {
req->stream->send_size += len;
- spdy_frame_send(req->owner, SPDY_DATA_FRAME,
- 0, len, req->stream, 0);
- net_send_queue(req->owner, d, len, req->stream);
+ spdy_frame_send(c, SPDY_DATA_FRAME, 0, len, s, 0);
+ net_send_queue(c, d, len, s);
}
- spdy_frame_send(req->owner, SPDY_DATA_FRAME,
- FLAG_FIN, 0, req->stream, 0);
+ spdy_frame_send(c, SPDY_DATA_FRAME, FLAG_FIN, 0, s, 0);
}
static void
diff --git a/src/spdy.c b/src/spdy.c
@@ -493,25 +493,24 @@ spdy_ctrl_frame_syn_stream(struct netbuf *nb)
GET_HEADER(":host", &host);
GET_HEADER(":version", &version);
- if (!http_request_new(c, s, host, method, path, version,
- (struct http_request **)&(s->httpreq))) {
- kore_mem_free(path);
- kore_mem_free(method);
- kore_mem_free(host);
- kore_mem_free(version);
- kore_mem_free(s->hblock->header_block);
- kore_mem_free(s->hblock);
- kore_mem_free(s);
- return (KORE_RESULT_OK);
- }
+ c->client_stream_id = s->stream_id;
+ TAILQ_INSERT_TAIL(&(c->spdy_streams), s, list);
+
+ /*
+ * We don't care so much for what http_request_new() tells us here,
+ * we just have to clean up after passing our stuff to it.
+ *
+ * In case of early errors (414, 500, ...) a net_send_flush() will
+ * clear out this stream properly via spdy_stream_close().
+ */
+ (void)http_request_new(c, s, host, method, path, version,
+ (struct http_request **)&(s->httpreq));
kore_mem_free(path);
- kore_mem_free(host);
kore_mem_free(method);
+ kore_mem_free(host);
kore_mem_free(version);
- c->client_stream_id = s->stream_id;
- TAILQ_INSERT_TAIL(&(c->spdy_streams), s, list);
kore_debug("SPDY_SYN_STREAM: %u:%u:%u", s->stream_id,
s->flags, s->prio);