From 73e63f027361554c35d0c173ce71f8b90f018fc4 Mon Sep 17 00:00:00 2001 From: jan Date: Thu, 3 Aug 2006 09:36:08 +0000 Subject: added FastCGI support to mod_proxy_core git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x@1236 152afb58-edef-0310-8abb-c4023f1b3aa9 --- src/mod_proxy_backend_fastcgi.c | 142 +++++++++++++++++++++++++++++++++------- src/mod_proxy_backend_fastcgi.h | 4 +- src/mod_proxy_backend_http.c | 58 ++++++++++++++++ src/mod_proxy_backend_http.h | 4 +- 4 files changed, 184 insertions(+), 24 deletions(-) diff --git a/src/mod_proxy_backend_fastcgi.c b/src/mod_proxy_backend_fastcgi.c index 2358fa3a..84df5dd2 100644 --- a/src/mod_proxy_backend_fastcgi.c +++ b/src/mod_proxy_backend_fastcgi.c @@ -1,5 +1,6 @@ #include #include +#include #include "inet_ntop_cache.h" #include "mod_proxy_core.h" @@ -249,26 +250,27 @@ static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_ } -int proxy_fastcgi_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) { +int proxy_fastcgi_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *out) { buffer *b, *packet; size_t i; FCGI_BeginRequestRecord beginRecord; FCGI_Header header; int request_id = 1; - b = chunkqueue_get_append_buffer(cq); + b = chunkqueue_get_append_buffer(out); /* send FCGI_BEGIN_REQUEST */ - fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0); + fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, FCGI_NULL_REQUEST_ID, sizeof(beginRecord.body), 0); beginRecord.body.roleB0 = FCGI_RESPONDER; beginRecord.body.roleB1 = 0; beginRecord.body.flags = 0; memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved)); buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord)); + out->bytes_in += sizeof(beginRecord); /* send FCGI_PARAMS */ - b = chunkqueue_get_append_buffer(cq); + b = chunkqueue_get_append_buffer(out); buffer_prepare_copy(b, 1024); /* fill the sess->env_headers */ @@ -285,20 +287,17 @@ int proxy_fastcgi_get_request_chunk(server *srv, connection *con, plugin_data *p fcgi_env_add(packet, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value)); } - fcgi_header(&(header), FCGI_PARAMS, request_id, packet->used, 0); + fcgi_header(&(header), FCGI_PARAMS, FCGI_NULL_REQUEST_ID, packet->used, 0); buffer_append_memory(b, (const char *)&header, sizeof(header)); buffer_append_memory(b, (const char *)packet->ptr, packet->used); + out->bytes_in += sizeof(header); + out->bytes_in += packet->used - 1; buffer_free(packet); - fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0); + fcgi_header(&(header), FCGI_PARAMS, FCGI_NULL_REQUEST_ID, 0, 0); buffer_append_memory(b, (const char *)&header, sizeof(header)); - - b = chunkqueue_get_append_buffer(cq); - /* terminate STDIN */ - fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0); - buffer_copy_memory(b, (const char *)&header, sizeof(header)); - b->used++; /* add virtual \0 */ + out->bytes_in += sizeof(header); return 0; } @@ -427,6 +426,111 @@ int proxy_fastcgi_stream_decoder(server *srv, proxy_session *sess, chunkqueue *r } } +/** + * transform the content-stream into a valid HTTP-content-stream + * + * as we don't apply chunked-encoding here, pass it on AS IS + */ +int proxy_fastcgi_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) { + chunk *c; + buffer *b; + FCGI_Header header; + + /* there is nothing that we have to send out anymore */ + for (c = in->first; in->bytes_out < in->bytes_in; ) { + off_t weWant = in->bytes_in - in->bytes_out > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : in->bytes_in - in->bytes_out; + off_t weHave = 0; + + /* we announce toWrite octects + * now take all the request_content chunk that we need to fill this request + */ + b = chunkqueue_get_append_buffer(out); + fcgi_header(&(header), FCGI_STDIN, FCGI_NULL_REQUEST_ID, weWant, 0); + buffer_copy_memory(b, (const char *)&header, sizeof(header) + 1); + out->bytes_in += sizeof(header); + + switch (c->type) { + case FILE_CHUNK: + weHave = c->file.length - c->offset; + + if (weHave > weWant) weHave = weWant; + + chunkqueue_append_file(out, c->file.name, c->offset, weHave); + + c->offset += weHave; + in->bytes_out += weHave; + + out->bytes_in += weHave; + + /* steal the tempfile + * + * This is tricky: + * - we reference the tempfile from the in-queue several times + * if the chunk is larger than FCGI_MAX_LENGTH + * - we can't simply cleanup the in-queue as soon as possible + * as it would remove the tempfiles + * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last + * referencing chunk of the fastcgi-write-queue + * + */ + + if (c->offset == c->file.length) { + chunk *out_c; + + out_c = out->last; + + /* the last of the out-queue should be a FILE_CHUNK (we just created it) + * and the incoming side should have given use a temp-file-chunk */ + assert(out_c->type == FILE_CHUNK); + assert(c->file.is_temp == 1); + + out_c->file.is_temp = 1; + c->file.is_temp = 0; + + c = c->next; + } + + break; + case MEM_CHUNK: + /* append to the buffer */ + weHave = c->mem->used - 1 - c->offset; + + if (weHave > weWant) weHave = weWant; + + b = chunkqueue_get_append_buffer(out); + buffer_append_memory(b, c->mem->ptr + c->offset, weHave); + b->used++; /* add virtual \0 */ + + c->offset += weHave; + in->bytes_out += weHave; + + out->bytes_in += weHave; + + if (c->offset == c->mem->used - 1) { + c = c->next; + } + + break; + default: + break; + } + } + + if (in->bytes_in == in->bytes_out && in->is_closed && !out->is_closed) { + /* send the closing packet */ + b = chunkqueue_get_append_buffer(out); + /* terminate STDIN */ + fcgi_header(&(header), FCGI_STDIN, FCGI_NULL_REQUEST_ID, 0, 0); + buffer_copy_memory(b, (const char *)&header, sizeof(header) + 1); + + out->bytes_in += sizeof(header); + out->is_closed = 1; + } + + return 0; + +} + /** * parse the response header * @@ -436,17 +540,17 @@ int proxy_fastcgi_stream_decoder(server *srv, proxy_session *sess, chunkqueue *r parse_status_t proxy_fastcgi_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) { int have_content_length = 0; size_t i; - off_t old_len = chunkqueue_length(cq); + off_t old_len; http_response_reset(p->resp); /* decode the whole packet stream */ do { - - old_len = chunkqueue_length(cq); + old_len = chunkqueue_length(sess->recv); /* decode the packet */ switch (proxy_fastcgi_stream_decoder(srv, sess, cq, sess->recv)) { case 0: + /* STDERR + STDOUT */ break; case 1: /* the FIN packet was catched, why ever */ @@ -454,7 +558,7 @@ parse_status_t proxy_fastcgi_parse_response_header(server *srv, connection *con, case -1: return PARSE_ERROR; } - } while (chunkqueue_length(cq) != old_len); + } while (chunkqueue_length(sess->recv) == old_len); switch (http_response_parse_cq(sess->recv, p->resp)) { case PARSE_ERROR: @@ -541,12 +645,6 @@ parse_status_t proxy_fastcgi_parse_response_header(server *srv, connection *con, array_insert_unique(con->response.headers, (data_unset *)ds); } - /* does the client allow us to send chunked encoding ? */ - if (con->request.http_version == HTTP_VERSION_1_1 && - !have_content_length) { - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; - } - break; } diff --git a/src/mod_proxy_backend_fastcgi.h b/src/mod_proxy_backend_fastcgi.h index 597ef180..8bdeb357 100644 --- a/src/mod_proxy_backend_fastcgi.h +++ b/src/mod_proxy_backend_fastcgi.h @@ -4,7 +4,9 @@ #include "mod_proxy_core.h" #include "base.h" -int proxy_fastcgi_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded); +int proxy_fastcgi_stream_decoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out); +int proxy_fastcgi_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out); + parse_status_t proxy_fastcgi_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq); int proxy_fastcgi_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq); diff --git a/src/mod_proxy_backend_http.c b/src/mod_proxy_backend_http.c index 5ef43579..306e9a10 100644 --- a/src/mod_proxy_backend_http.c +++ b/src/mod_proxy_backend_http.c @@ -149,7 +149,65 @@ int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, return 0; } +/** + * transform the content-stream into a valid HTTP-content-stream + * + * as we don't apply chunked-encoding here, pass it on AS IS + */ +int proxy_http_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) { + chunk *c; + + /* there is nothing that we have to send out anymore */ + if (in->bytes_in == in->bytes_out && + in->is_closed) return 0; + + for (c = in->first; in->bytes_out < in->bytes_in; c = c->next) { + buffer *b; + off_t weWant = in->bytes_in - in->bytes_out; + off_t weHave = 0; + + /* we announce toWrite octects + * now take all the request_content chunk that we need to fill this request + */ + + switch (c->type) { + case FILE_CHUNK: + weHave = c->file.length - c->offset; + + if (weHave > weWant) weHave = weWant; + + chunkqueue_append_file(out, c->file.name, c->offset, weHave); + + c->offset += weHave; + in->bytes_out += weHave; + + out->bytes_in += weHave; + + break; + case MEM_CHUNK: + /* append to the buffer */ + weHave = c->mem->used - 1 - c->offset; + + if (weHave > weWant) weHave = weWant; + + b = chunkqueue_get_append_buffer(out); + buffer_append_memory(b, c->mem->ptr + c->offset, weHave); + b->used++; /* add virtual \0 */ + + c->offset += weHave; + in->bytes_out += weHave; + out->bytes_in += weHave; + + break; + default: + break; + } + } + + return 0; + +} /** * generate a HTTP/1.1 proxy request from the set of request-headers * diff --git a/src/mod_proxy_backend_http.h b/src/mod_proxy_backend_http.h index a1b25a11..8b051149 100644 --- a/src/mod_proxy_backend_http.h +++ b/src/mod_proxy_backend_http.h @@ -4,7 +4,9 @@ #include "mod_proxy_core.h" #include "base.h" -int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded); +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out); +int proxy_http_stream_encoder(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out); + parse_status_t proxy_http_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq); int proxy_http_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq); -- cgit v1.2.1