diff options
Diffstat (limited to 'src/mod_chunked.c')
-rw-r--r-- | src/mod_chunked.c | 381 |
1 files changed, 0 insertions, 381 deletions
diff --git a/src/mod_chunked.c b/src/mod_chunked.c deleted file mode 100644 index 567a3bdb..00000000 --- a/src/mod_chunked.c +++ /dev/null @@ -1,381 +0,0 @@ -#include <ctype.h> -#include <stdlib.h> -#include <string.h> - -#include "base.h" -#include "log.h" -#include "buffer.h" -#include "response.h" -#include "filter.h" - -#include "plugin.h" - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define CONFIG_CHUNKED_ENCODING "chunked.encoding" -#define CONFIG_CHUNKED_DEBUG "chunked.debug" - -/** - * This plugin adds HTTP/1.1 chunked encoding support - * as a filter module. - * - */ - -/* plugin config for all request/connections */ - -typedef struct { - unsigned short encoding; - unsigned short debug; -} plugin_config; - -typedef struct { - PLUGIN_DATA; - - plugin_config **config_storage; - - plugin_config conf; -} plugin_data; - -typedef struct { - unsigned short debug; - filter *fl; -} handler_ctx; - -static handler_ctx * handler_ctx_init() { - handler_ctx * hctx; - - hctx = calloc(1, sizeof(*hctx)); - hctx->debug = 0; - hctx->fl = NULL; - - return hctx; -} - -static void handler_ctx_free(handler_ctx *hctx) { - - free(hctx); -} - -/* init the plugin data */ -INIT_FUNC(mod_chunked_init) { - plugin_data *p; - - UNUSED(srv); - - p = calloc(1, sizeof(*p)); - - return p; -} - -/* destroy the plugin data */ -FREE_FUNC(mod_chunked_free) { - plugin_data *p = p_d; - - UNUSED(srv); - - if (!p) return HANDLER_GO_ON; - - if (p->config_storage) { - size_t i; - - for (i = 0; i < srv->config_context->used; i++) { - plugin_config *s = p->config_storage[i]; - - if (!s) continue; - - free(s); - } - free(p->config_storage); - } - - free(p); - - return HANDLER_GO_ON; -} - -/* handle plugin config and check values */ - -SETDEFAULTS_FUNC(mod_chunked_set_defaults) { - plugin_data *p = p_d; - size_t i = 0; - - config_values_t cv[] = { - { CONFIG_CHUNKED_ENCODING, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ - { CONFIG_CHUNKED_DEBUG, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ - { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } - }; - - if (!p) return HANDLER_ERROR; - - p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - - for (i = 0; i < srv->config_context->used; i++) { - plugin_config *s; - - s = calloc(1, sizeof(plugin_config)); - s->encoding = 1; - s->debug = 0; - - cv[0].destination = &(s->encoding); - cv[1].destination = &(s->debug); - - p->config_storage[i] = s; - - if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { - return HANDLER_ERROR; - } - } - - return HANDLER_GO_ON; -} - -REQUESTDONE_FUNC(mod_chunked_reset) { - plugin_data *p = p_d; - handler_ctx *hctx = con->plugin_ctx[p->id]; - - UNUSED(srv); - - if (NULL == hctx) return HANDLER_GO_ON; - - handler_ctx_free(hctx); - con->plugin_ctx[p->id] = NULL; - - return HANDLER_GO_ON; -} - -static int mod_chunked_patch_connection(server *srv, connection *con, plugin_data *p) { - size_t i, j; - plugin_config *s = p->config_storage[0]; - - PATCH_OPTION(encoding); - PATCH_OPTION(debug); - - /* skip the first, the global context */ - for (i = 1; i < srv->config_context->used; i++) { - data_config *dc = (data_config *)srv->config_context->data[i]; - s = p->config_storage[i]; - - /* condition didn't match */ - if (!config_check_cond(srv, con, dc)) continue; - - /* merge config */ - for (j = 0; j < dc->value->used; j++) { - data_unset *du = dc->value->data[j]; - - if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_CHUNKED_ENCODING))) { - PATCH_OPTION(encoding); - } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_CHUNKED_DEBUG))) { - PATCH_OPTION(debug); - } - } - } - - return 0; -} - -URIHANDLER_FUNC(mod_chunked_response_header) { - plugin_data *p = p_d; - handler_ctx *hctx; - filter *fl; - chunkqueue *in; - int use_chunked = 0; - - mod_chunked_patch_connection(srv, con, p); - - /* get filter. */ - fl = filter_chain_get_filter(con->send_filters, p->id); - if (!fl) { - if (p->conf.debug > 0) TRACE("%s", "add chunked filter to filter chain"); - fl = filter_chain_create_filter(con->send_filters, p->id); - } - /* get our input and output chunkqueues. */ - if (!fl || !fl->prev) { - filter_chain_remove_filter(con->send_filters, fl); - return HANDLER_GO_ON; - } - in = fl->prev->cq; - - if (in->is_closed && (con->response.content_length < 0 || con->request.http_method != HTTP_METHOD_HEAD)) { - con->response.content_length = chunkqueue_length(in); - } - /* check if response needs chunked encoding. */ - if (con->request.http_method != HTTP_METHOD_HEAD) { - if(con->response.content_length >= 0) { - if (p->conf.debug > 0) TRACE("response content length known, disabling chunked encoding. len=%jd", (intmax_t) con->response.content_length); - use_chunked = 0; - } else { - /* a HEAD request never gets a chunk-encoding, but might stay with keep-alive - * in case the queue was closed already (above) we still have the content-length */ - - /* we don't know the size of the content yet - * - either enable chunking - * - or disable keep-alive */ - - if (con->request.http_version == HTTP_VERSION_1_1 && p->conf.encoding) { - use_chunked = 1; - } else { - if (p->conf.debug > 0) - TRACE("%s", "content length unknown and can't use chunked encoding. disable keep-alive"); - con->keep_alive = 0; - use_chunked = 0; - } - } - } - - if (!use_chunked) { - /* chunked encoding disabled. remove filter */ - con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; - filter_chain_remove_filter(con->send_filters, fl); - return HANDLER_GO_ON; - } - - /* enable chunked encoding */ - con->response.transfer_encoding |= HTTP_TRANSFER_ENCODING_CHUNKED; - hctx = handler_ctx_init(); - hctx->debug = p->conf.debug; - con->plugin_ctx[p->id] = hctx; - hctx->fl = fl; - - if (hctx->debug > 0) - TRACE("%s", "chunked encoding enabled"); - - return HANDLER_GO_ON; -} - -static int http_chunk_append_len(chunkqueue *cq, size_t len) { - size_t i, olen = len, j; - buffer *b; - - b = buffer_init(); - - if (len == 0) { - buffer_copy_string_len(b, CONST_STR_LEN("0")); - } else { - for (i = 0; i < 8 && len; i++) { - len >>= 4; - } - - /* i is the number of hex digits we have */ - buffer_prepare_copy(b, i + 1); - - for (j = i-1, len = olen; j+1 > 0; j--) { - b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10); - len >>= 4; - } - b->used = i; - b->ptr[b->used++] = '\0'; - } - - buffer_append_string_len(b, CONST_STR_LEN("\r\n")); - chunkqueue_append_buffer(cq, b); - len = b->used - 1; - - buffer_free(b); - - return len; -} - -/** - * apply HTTP/1.1 chunked encoding if necessary - */ -URIHANDLER_FUNC(mod_chunked_encode_response_content) { - plugin_data *p = p_d; - handler_ctx *hctx = con->plugin_ctx[p->id]; - chunkqueue *in; - chunkqueue *out; - int we_have = 0; - chunk *c; - - UNUSED(srv); - - /* check if chunk-encoding is enabled. */ - if (!hctx) return HANDLER_GO_ON; - - /* get our input and output chunkqueues. */ - if (!hctx->fl || !hctx->fl->prev) return HANDLER_GO_ON; - in = hctx->fl->prev->cq; - out = hctx->fl->cq; - - /* we are all done already (see the end of the function) */ - if (out->is_closed) return HANDLER_GO_ON; - - /* move all chunks to the out queue - * and append a HTTP/1.1 chunked header to each chunk - */ - for (c = in->first; c; c = c->next) { - switch (c->type) { - case MEM_CHUNK: - if (c->mem->used == 0) continue; - - we_have = c->mem->used - c->offset - 1; - in->bytes_out += we_have; - if(we_have == 0) continue; - we_have += http_chunk_append_len(out, we_have); - chunkqueue_append_buffer(out, c->mem); - - chunk_set_done(c); - - break; - case FILE_CHUNK: - if (c->file.length == 0) continue; - - we_have = c->file.length; - in->bytes_out += we_have; - we_have += http_chunk_append_len(out, c->file.length); - - if(c->file.is_temp) { - chunkqueue_steal_tempfile(out, c); - } else { - chunkqueue_append_file(out, c->file.name, c->file.start, c->file.length); - } - - chunk_set_done(c); - - break; - case UNUSED_CHUNK: - break; - } - chunkqueue_append_mem(out, CONST_STR_LEN("\r\n")); - we_have += 2; - out->bytes_in += we_have; - } - - /* terminate the last chunk */ - if (in->is_closed) { - chunkqueue_append_mem(out, CONST_STR_LEN("0\r\n\r\n")); - out->bytes_in += 5; - } - - if (hctx->debug > 1) TRACE("chunk encoded: in=%jd, out=%jd", (intmax_t) in->bytes_out, (intmax_t) out->bytes_in); - - chunkqueue_remove_finished_chunks(in); - - /* the in side is closed, close out too */ - if (in->is_closed) { - /* mark the output queue as finished. */ - out->is_closed = 1; - } - - return HANDLER_GO_ON; -} - -/* this function is called at dlopen() time and inits the callbacks */ - -LI_EXPORT int mod_chunked_plugin_init(plugin *p); -LI_EXPORT int mod_chunked_plugin_init(plugin *p) { - p->version = LIGHTTPD_VERSION_ID; - p->name = buffer_init_string("chunked"); - - p->init = mod_chunked_init; - p->set_defaults = mod_chunked_set_defaults; - p->handle_response_header = mod_chunked_response_header; - p->handle_filter_response_content = mod_chunked_encode_response_content; - p->connection_reset = mod_chunked_reset; - p->cleanup = mod_chunked_free; - - p->data = NULL; - - return 0; -} |