summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gw_backend.c35
-rw-r--r--src/http-header-glue.c8
-rw-r--r--src/mod_cgi.c4
-rw-r--r--src/mod_proxy.c46
4 files changed, 64 insertions, 29 deletions
diff --git a/src/gw_backend.c b/src/gw_backend.c
index d8b88086..aa98a8e4 100644
--- a/src/gw_backend.c
+++ b/src/gw_backend.c
@@ -2052,43 +2052,40 @@ handler_t gw_handle_subrequest(request_st * const r, void *p_d) {
}
else {
handler_t rc = connection_handle_read_post_state(r);
- chunkqueue *req_cq = r->reqbody_queue;
- #if 0 /*(not reached since we send 411 Length Required below)*/
+
+ /* XXX: create configurable flag */
+ /* CGI environment requires that Content-Length be set.
+ * Send 411 Length Required if Content-Length missing.
+ * (occurs here if client sends Transfer-Encoding: chunked
+ * and module is flagged to stream request body to backend) */
+ if (-1 == r->reqbody_length && hctx->opts.backend != BACKEND_PROXY){
+ return (r->conf.stream_request_body & FDEVENT_STREAM_REQUEST)
+ ? connection_handle_read_post_error(r, 411)
+ : HANDLER_WAIT_FOR_EVENT;
+ }
+
if (hctx->wb_reqlen < -1 && r->reqbody_length >= 0) {
/* (completed receiving Transfer-Encoding: chunked) */
- hctx->wb_reqlen = -hctx->wb_reqlen + r->reqbody_length;
+ hctx->wb_reqlen = -hctx->wb_reqlen;
if (hctx->stdin_append) {
handler_t rca = hctx->stdin_append(hctx);
if (HANDLER_GO_ON != rca) return rca;
}
}
- #endif
+
if ((0 != hctx->wb->bytes_in || -1 == hctx->wb_reqlen)
- && !chunkqueue_is_empty(req_cq)) {
+ && !chunkqueue_is_empty(r->reqbody_queue)) {
if (hctx->stdin_append) {
handler_t rca = hctx->stdin_append(hctx);
if (HANDLER_GO_ON != rca) return rca;
}
else
- chunkqueue_append_chunkqueue(hctx->wb, req_cq);
+ chunkqueue_append_chunkqueue(hctx->wb, r->reqbody_queue);
if (fdevent_fdnode_interest(hctx->fdn) & FDEVENT_OUT) {
return (rc == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : rc;
}
}
if (rc != HANDLER_GO_ON) return rc;
-
-
- /* XXX: create configurable flag */
- /* CGI environment requires that Content-Length be set.
- * Send 411 Length Required if Content-Length missing.
- * (occurs here if client sends Transfer-Encoding: chunked
- * and module is flagged to stream request body to backend) */
- /* proxy currently sends HTTP/1.0 request and ideally should send
- * Content-Length with request if request body is present, so
- * send 411 Length Required if Content-Length missing. */
- if (-1 == r->reqbody_length) {
- return connection_handle_read_post_error(r, 411);
- }
}
}
diff --git a/src/http-header-glue.c b/src/http-header-glue.c
index 72a328e7..cf77ae1a 100644
--- a/src/http-header-glue.c
+++ b/src/http-header-glue.c
@@ -1036,14 +1036,6 @@ static int http_response_process_headers(request_st * const r, http_response_opt
r->content_length = strtoul(value, NULL, 10);
break;
case HTTP_HEADER_TRANSFER_ENCODING:
- if (opts->backend == BACKEND_PROXY) {
- log_error(r->conf.errh, __FILE__, __LINE__,
- "proxy backend sent invalid response header "
- "(Transfer-Encoding) to HTTP/1.0 request");
- r->http_status = 502; /* Bad Gateway */
- r->handler_module = NULL;
- return -1;
- }
break;
default:
break;
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index 5e14df17..78e89ce8 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -982,7 +982,9 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
* (occurs here if client sends Transfer-Encoding: chunked
* and module is flagged to stream request body to backend) */
if (-1 == r->reqbody_length) {
- return connection_handle_read_post_error(r, 411);
+ return (r->conf.stream_request_body & FDEVENT_STREAM_REQUEST)
+ ? connection_handle_read_post_error(r, 411)
+ : HANDLER_WAIT_FOR_EVENT;
}
}
}
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index 31a4f930..e0d2cf5e 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -813,6 +813,42 @@ static void proxy_set_Forwarded(connection * const con, request_st * const r, co
}
+static handler_t proxy_stdin_append(gw_handler_ctx *hctx) {
+ /*handler_ctx *hctx = (handler_ctx *)gwhctx;*/
+ chunkqueue * const req_cq = hctx->r->reqbody_queue;
+ const off_t req_cqlen = req_cq->bytes_in - req_cq->bytes_out;
+ if (req_cqlen) {
+ /* XXX: future: use http_chunk_len_append() */
+ buffer * const tb = hctx->r->tmp_buf;
+ buffer_clear(tb);
+ buffer_append_uint_hex_lc(tb, (uintmax_t)req_cqlen);
+ buffer_append_string_len(tb, CONST_STR_LEN("\r\n"));
+
+ const off_t len = (off_t)buffer_string_length(tb)
+ + 2 /*(+2 end chunk "\r\n")*/
+ + req_cqlen;
+ if (-1 != hctx->wb_reqlen)
+ hctx->wb_reqlen += (hctx->wb_reqlen >= 0) ? len : -len;
+
+ (chunkqueue_is_empty(hctx->wb) || hctx->wb->first->type == MEM_CHUNK)
+ /* else FILE_CHUNK for temp file */
+ ? chunkqueue_append_mem(hctx->wb, CONST_BUF_LEN(tb))
+ : chunkqueue_append_mem_min(hctx->wb, CONST_BUF_LEN(tb));
+ chunkqueue_steal(hctx->wb, req_cq, req_cqlen);
+
+ chunkqueue_append_mem_min(hctx->wb, CONST_STR_LEN("\r\n"));
+ }
+
+ if (hctx->wb->bytes_in == hctx->wb_reqlen) {/*hctx->r->reqbody_length >= 0*/
+ /* terminate STDIN */
+ chunkqueue_append_mem(hctx->wb, CONST_STR_LEN("0\r\n\r\n"));
+ hctx->wb_reqlen += (int)sizeof("0\r\n\r\n");
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
static handler_t proxy_create_env(gw_handler_ctx *gwhctx) {
handler_ctx *hctx = (handler_ctx *)gwhctx;
request_st * const r = hctx->gw.r;
@@ -831,7 +867,13 @@ static handler_t proxy_create_env(gw_handler_ctx *gwhctx) {
buffer_append_string_buffer(b, &r->target);
if (remap_headers)
http_header_remap_uri(b, buffer_string_length(b) - buffer_string_length(&r->target), &hctx->conf.header, 1);
- if (!upgrade)
+
+ int stream_chunked = 0;
+ if (-1 == r->reqbody_length && r->conf.stream_request_body) {
+ stream_chunked = 1;
+ hctx->gw.stdin_append = proxy_stdin_append;
+ }
+ if (!stream_chunked && !upgrade)
buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));
else
buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.1\r\n"));
@@ -869,6 +911,8 @@ static handler_t proxy_create_env(gw_handler_ctx *gwhctx) {
buf, li_itostrn(buf, sizeof(buf), r->reqbody_length));
}
}
+ else if (stream_chunked)
+ buffer_append_string_len(b, CONST_STR_LEN("Transfer-Encoding: chunked\r\n"));
/* request header */
for (size_t i = 0, used = r->rqst_headers.used; i < used; ++i) {