Browse Source

[stream-http-response] support chunk encoded responses

personal/stbuehler/wip
Stefan Bühler 9 years ago
parent
commit
5e0a58be53
  1. 69
      src/main/stream_http_response.c
  2. 18
      tests/t-cgi.py

69
src/main/stream_http_response.c

@ -7,17 +7,58 @@ struct liStreamHttpResponse {
liStream stream;
liVRequest *vr;
gboolean response_headers_finished;
gboolean response_headers_finished, transfer_encoding_chunked;
liFilterChunkedDecodeState chunked_decode_state;
};
static gboolean check_response_header(liStreamHttpResponse* shr) {
liResponse *resp = &shr->vr->response;
liHttpHeader *hh;
GList *l;
shr->transfer_encoding_chunked = FALSE;
/* Transfer-Encoding: chunked */
l = li_http_header_find_first(resp->headers, CONST_STR_LEN("transfer-encoding"));
if (l) {
for ( ; l ; l = li_http_header_find_next(l, CONST_STR_LEN("transfer-encoding")) ) {
hh = (liHttpHeader*) l->data;
if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "identity" )) {
/* ignore */
continue;
} if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "chunked" )) {
if (shr->transfer_encoding_chunked) {
VR_ERROR(shr->vr, "%s", "Response is chunked encoded twice");
li_vrequest_error(shr->vr);
return FALSE;
}
shr->transfer_encoding_chunked = TRUE;
} else {
VR_ERROR(shr->vr, "Response has unsupported Transfer-Encoding: %s", LI_HEADER_VALUE(hh));
li_vrequest_error(shr->vr);
return FALSE;
}
}
li_http_header_remove(resp->headers, CONST_STR_LEN("transfer-encoding"));
/* any non trivial transfer-encoding overwrites content-length */
if (shr->transfer_encoding_chunked) {
li_http_header_remove(resp->headers, CONST_STR_LEN("content-length"));
}
}
shr->response_headers_finished = TRUE;
li_vrequest_indirect_headers_ready(shr->vr);
return TRUE;
}
static void stream_http_response_data(liStreamHttpResponse* shr) {
if (NULL == shr->stream.source) return;
if (!shr->response_headers_finished) {
switch (li_http_response_parse(shr->vr, &shr->parse_response_ctx)) {
case LI_HANDLER_GO_ON:
shr->response_headers_finished = TRUE;
li_vrequest_indirect_headers_ready(shr->vr);
if (!check_response_header(shr)) return;
break;
case LI_HANDLER_ERROR:
VR_ERROR(shr->vr, "%s", "Parsing response header failed");
@ -34,10 +75,24 @@ static void stream_http_response_data(liStreamHttpResponse* shr) {
}
}
li_chunkqueue_steal_all(shr->stream.out, shr->stream.source->out);
if (shr->stream.source->out->is_closed) {
shr->stream.out->is_closed = TRUE;
li_stream_disconnect(&shr->stream);
if (shr->transfer_encoding_chunked) {
if (!li_filter_chunked_decode(shr->vr, shr->stream.out, shr->stream.source->out, &shr->chunked_decode_state)) {
if (NULL != shr->vr) {
VR_ERROR(shr->vr, "%s", "Decoding chunks failed");
li_vrequest_error(shr->vr);
} else {
li_stream_reset(&shr->stream);
}
}
if (shr->stream.source->out->is_closed) {
li_stream_disconnect(&shr->stream);
}
} else {
li_chunkqueue_steal_all(shr->stream.out, shr->stream.source->out);
if (shr->stream.source->out->is_closed) {
shr->stream.out->is_closed = TRUE;
li_stream_disconnect(&shr->stream);
}
}
li_stream_notify(&shr->stream);
}

18
tests/t-cgi.py

@ -38,6 +38,15 @@ printf '%s' "${csum}"
"""
SCRIPT_CHUNKEDENCODINGCHECK="""#!/bin/sh
printf 'Status: 200\\r\\nContent-Type: text/plain\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n'
printf 'd\\r\\nHello World!\\n\\r\\n0\\r\\n\\r\\n'
"""
class TestPathInfo1(CurlRequest):
URL = "/envcheck.cgi/abc/xyz?PATH_INFO"
EXPECT_RESPONSE_BODY = "/abc/xyz"
@ -81,12 +90,18 @@ class TestUploadLargeChunked1(CurlRequest):
c.setopt(c.UPLOAD, 1)
c.setopt(pycurl.READFUNCTION, ChunkedBodyReader(BODY).read)
class TestChunkedEncoding1(CurlRequest):
URL = "/chunkedencodingcheck.cgi"
EXPECT_RESPONSE_BODY = "Hello World!\n"
EXPECT_RESPONSE_CODE = 200
class Test(GroupTest):
group = [
TestPathInfo1,
TestRequestUri1,
TestUploadLarge1,
TestUploadLargeChunked1
TestUploadLargeChunked1,
TestChunkedEncoding1,
]
config = """
@ -117,3 +132,4 @@ cgi = {{
def Prepare(self):
self.PrepareVHostFile("envcheck.cgi", SCRIPT_ENVCHECK, mode = 0755)
self.PrepareVHostFile("uploadcheck.cgi", SCRIPT_UPLOADCHECK, mode = 0755)
self.PrepareVHostFile("chunkedencodingcheck.cgi", SCRIPT_CHUNKEDENCODINGCHECK, mode = 0755)

Loading…
Cancel
Save