diff --git a/config b/config index 37f7f49..50d1891 100644 --- a/config +++ b/config @@ -1,6 +1,7 @@ USE_MD5=YES USE_SHA1=YES +USE_ZLIB=YES ngx_addon_name=ngx_http_upload_module -HTTP_MODULES="$HTTP_MODULES ngx_http_upload_module ngx_http_unzip_filter_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_upload_module.c $ngx_addon_dir/ngx_http_unzip_filter_module.c" +HTTP_MODULES="$HTTP_MODULES ngx_http_upload_module ngx_upload_unzip_filter_module ngx_upload_discard_filter_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_upload_module.c $ngx_addon_dir/ngx_upload_unzip_filter_module.c $ngx_addon_dir/ngx_upload_discard_filter_module.c" HTTP_INCS="$HTTP_INCS $ngx_addon_dir" diff --git a/nginx-unzip.conf b/nginx-unzip.conf new file mode 100644 index 0000000..0ee61b1 --- /dev/null +++ b/nginx-unzip.conf @@ -0,0 +1,56 @@ + +worker_processes 20; + +error_log logs/error.log notice; + +working_directory /usr/local/nginx; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + + server { + listen 80; + client_max_body_size 100m; + + # Upload form should be submitted to this location + location /upload { + # Pass altered request body to this location + upload_pass /test; + + # Store files to this directory + # The directory is hashed, subdirectories 0 1 2 3 4 5 6 7 8 9 should exist + upload_store /tmp 1; + + # Allow uploaded files to be read only by user + upload_store_access user:r; + + # Set specified fields in request body + upload_set_form_field "${upload_field_name}${upload_archive_elm}_name" $upload_file_name; + upload_set_form_field "${upload_field_name}${upload_archive_elm}_content_type" $upload_content_type; + upload_set_form_field "${upload_field_name}${upload_archive_elm}_path" $upload_tmp_path; + upload_set_form_field "${upload_field_name}${upload_archive_elm}_archive_path" $upload_archive_path; + + # Inform backend about hash and size of a file + upload_aggregate_form_field "${upload_field_name}${upload_archive_elm}_md5" $upload_file_md5; + upload_aggregate_form_field "${upload_field_name}${upload_archive_elm}_size" $upload_file_size; + + upload_pass_form_field "^submit$|^description$"; + + upload_cleanup 400-599; + + upload_filter application/zip { + upload_unzip on; + } + } + + # Pass altered request body to a backend + location /test { + proxy_pass http://localhost:8080; + } + } +} diff --git a/nginx.conf b/nginx.conf index 64f92fc..ee1de57 100644 --- a/nginx.conf +++ b/nginx.conf @@ -39,6 +39,10 @@ http { upload_aggregate_form_field "${upload_field_name}_size" $upload_file_size; upload_pass_form_field "^submit$|^description$"; + + upload_filter "application/zip" { + unzip on; + } } # Pass altered request body to a backend diff --git a/ngx_http_upload.h b/ngx_http_upload.h index a6b81d4..b48e81b 100644 --- a/ngx_http_upload.h +++ b/ngx_http_upload.h @@ -128,6 +128,9 @@ typedef struct ngx_http_upload_loc_conf_s { ngx_array_t *content_filters; ngx_array_t *content_type_map; + ngx_str_t archive_elm_separator; + ngx_str_t archive_path_separator; + unsigned int md5:1; unsigned int sha1:1; unsigned int crc32:1; @@ -160,6 +163,7 @@ typedef struct ngx_http_upload_ctx_s { ngx_str_t field_name; ngx_str_t file_name; ngx_str_t content_type; + ngx_str_t archive_elm; ngx_str_t archive_path; ngx_buf_t *output_buffer; @@ -197,9 +201,54 @@ ngx_module_t ngx_http_upload_module; ngx_int_t ngx_upload_set_exten(ngx_http_upload_ctx_t *u, ngx_str_t *file_name, ngx_str_t *exten); ngx_int_t ngx_upload_resolve_content_type(ngx_http_upload_ctx_t *u, ngx_str_t *exten, ngx_str_t *content_type); -ngx_int_t ngx_upload_set_file_name(ngx_http_upload_ctx_t *ctx, ngx_str_t *file_name); -ngx_int_t ngx_upload_set_content_type(ngx_http_upload_ctx_t *ctx, ngx_str_t *content_type); -ngx_int_t ngx_upload_set_archive_path(ngx_http_upload_ctx_t *ctx, ngx_str_t *archive_path); + +#define ngx_upload_set_file_name(ctx, fn) \ + do{ \ + (ctx)->file_name.data = (fn)->data; \ + (ctx)->file_name.len = (fn)->len; \ + }while(0); \ + +#define ngx_upload_get_file_name(ctx, fn) \ + do{ \ + (fn)->data = (ctx)->file_name.data; \ + (fn)->len = (ctx)->file_name.len; \ + }while(0); \ + +#define ngx_upload_set_content_type(ctx, ct) \ + do{ \ + (ctx)->content_type.data = (ct)->data; \ + (ctx)->content_type.len = (ct)->len; \ + }while(0); \ + +#define ngx_upload_get_content_type(ctx, ct) \ + do{ \ + (ct)->data = (ctx)->content_type.data; \ + (ct)->len = (ctx)->content_type.len; \ + }while(0); \ + +#define ngx_upload_set_archive_elm(ctx, ae) \ + do{ \ + (ctx)->archive_elm.data = (ae)->data; \ + (ctx)->archive_elm.len = (ae)->len; \ + }while(0); \ + +#define ngx_upload_get_archive_elm(ctx, ae) \ + do{ \ + (ae)->data = (ctx)->archive_elm.data; \ + (ae)->len = (ctx)->archive_elm.len; \ + }while(0); \ + +#define ngx_upload_set_archive_path(ctx, ap) \ + do{ \ + (ctx)->archive_path.data = (ap)->data; \ + (ctx)->archive_path.len = (ap)->len; \ + }while(0); \ + +#define ngx_upload_get_archive_path(ctx, ap) \ + do{ \ + (ap)->data = (ctx)->archive_path.data; \ + (ap)->len = (ctx)->archive_path.len; \ + }while(0); \ ngx_upload_field_filter_t* ngx_upload_get_next_field_filter(ngx_http_upload_ctx_t *ctx); diff --git a/ngx_http_upload_module.c b/ngx_http_upload_module.c index fa4b61c..d8a4b0e 100644 --- a/ngx_http_upload_module.c +++ b/ngx_http_upload_module.c @@ -263,6 +263,26 @@ static ngx_command_t ngx_http_upload_commands[] = { /* {{{ */ 0, NULL}, + /* + * Specifies a separator for archive element tokens + */ + { ngx_string("upload_archive_elm_separator"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_upload_loc_conf_t, archive_elm_separator), + NULL}, + + /* + * Specifies a separator for archive path tokens + */ + { ngx_string("upload_archive_path_separator"), + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_upload_loc_conf_t, archive_path_separator), + NULL}, + ngx_null_command }; /* }}} */ @@ -313,6 +333,10 @@ static ngx_http_variable_t ngx_http_upload_variables[] = { /* {{{ */ (uintptr_t) offsetof(ngx_http_upload_ctx_t, output_file.name), NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + { ngx_string("upload_archive_elm"), NULL, ngx_http_upload_variable, + (uintptr_t) offsetof(ngx_http_upload_ctx_t, archive_elm), + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + { ngx_string("upload_archive_path"), NULL, ngx_http_upload_variable, (uintptr_t) offsetof(ngx_http_upload_ctx_t, archive_path), NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, @@ -798,6 +822,7 @@ ngx_http_upload_append_str(ngx_http_upload_ctx_t *u, ngx_buf_t *b, ngx_chain_t * b->temporary = 1; b->in_file = 0; b->last_buf = 0; + b->flush = 0; b->last_in_chain = 0; b->last_buf = 0; @@ -922,35 +947,38 @@ static void ngx_http_upload_field_abort(ngx_http_upload_ctx_t *u) { /* {{{ */ } } /* }}} */ -static ngx_int_t ngx_http_upload_field_process_chain(ngx_http_upload_ctx_t *u, ngx_chain_t *chain) { /* {{{ */ +static ngx_int_t /* {{{ ngx_http_upload_field_process_chain */ +ngx_http_upload_field_process_chain(ngx_http_upload_ctx_t *u, ngx_chain_t *chain) { ngx_buf_t *b; ngx_chain_t *cl; - for(cl = chain; cl && !cl->buf->last_in_chain; cl = cl->next) { - b = ngx_create_temp_buf(u->request->pool, cl->buf->last - cl->buf->pos); + for(;chain && !chain->buf->last_in_chain; chain = chain->next) { + if(chain->buf->last - chain->buf->pos > 0) { + b = ngx_create_temp_buf(u->request->pool, chain->buf->last - chain->buf->pos); - if (b == NULL) { - return NGX_ERROR; - } + if (b == NULL) { + return NGX_ERROR; + } - cl = ngx_alloc_chain_link(u->request->pool); - if (cl == NULL) { - return NGX_ERROR; - } + cl = ngx_alloc_chain_link(u->request->pool); + if (cl == NULL) { + return NGX_ERROR; + } - b->last_in_chain = 0; + b->last_in_chain = 0; - cl->buf = b; - cl->next = NULL; + cl->buf = b; + cl->next = NULL; - b->last = ngx_cpymem(b->last, cl->buf->pos, cl->buf->last - cl->buf->pos); + b->last = ngx_cpymem(b->last, chain->buf->pos, chain->buf->last - chain->buf->pos); - if(u->chain == NULL) { - u->chain = cl; - u->last = cl; - }else{ - u->last->next = cl; - u->last = cl; + if(u->chain == NULL) { + u->chain = cl; + u->last = cl; + }else{ + u->last->next = cl; + u->last = cl; + } } } @@ -973,6 +1001,7 @@ ngx_http_upload_create_loc_conf(ngx_conf_t *cf) conf->max_header_len = NGX_CONF_UNSET_SIZE; /* + * conf->archive_elm_separator * conf->field_templates, * conf->aggregate_field_templates, * and conf->field_filters are @@ -1034,6 +1063,9 @@ ngx_http_upload_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->cleanup_statuses = prev->cleanup_statuses; } + ngx_conf_merge_str_value(conf->archive_elm_separator, prev->archive_elm_separator, "_"); + ngx_conf_merge_str_value(conf->archive_path_separator, prev->archive_path_separator, "!"); + return NGX_CONF_OK; } /* }}} */ @@ -1546,9 +1578,7 @@ ngx_http_upload_filter_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_HTTP_MODULE && - ngx_modules[i] != &ngx_http_upload_module && - ngx_modules[i] != &ngx_http_core_module) { + if (ngx_modules[i]->type != NGX_HTTP_MODULE) { continue; } @@ -2155,36 +2185,6 @@ ngx_upload_resolve_content_type(ngx_http_upload_ctx_t *u, ngx_str_t *exten, ngx_ return NGX_OK; } /* }}} */ -ngx_int_t /* {{{ ngx_upload_set_file_name */ -ngx_upload_set_file_name(ngx_http_upload_ctx_t *ctx, - ngx_str_t *file_name) -{ - ctx->file_name.data = file_name->data; - ctx->file_name.len = file_name->len; - - return NGX_OK; -} /* }}} */ - -ngx_int_t /* {{{ ngx_upload_set_content_type */ -ngx_upload_set_content_type(ngx_http_upload_ctx_t *ctx, - ngx_str_t *content_type) -{ - ctx->content_type.data = content_type->data; - ctx->content_type.len = content_type->len; - - return NGX_OK; -} /* }}} */ - -ngx_int_t /* {{{ ngx_upload_set_archive_path */ -ngx_upload_set_archive_path(ngx_http_upload_ctx_t *ctx, - ngx_str_t *archive_path) -{ - ctx->archive_path.data = archive_path->data; - ctx->archive_path.len = archive_path->len; - - return NGX_OK; -} /* }}} */ - static ngx_int_t /* {{{ ngx_upload_set_content_filter */ ngx_upload_set_content_filter(ngx_http_upload_ctx_t *u, ngx_str_t *content_type) { @@ -2277,13 +2277,16 @@ static void upload_abort_file(ngx_http_upload_ctx_t *upload_ctx) { /* {{{ */ static void upload_flush_output_buffer(ngx_http_upload_ctx_t *upload_ctx) { /* {{{ */ ngx_chain_t chain = { upload_ctx->output_buffer, NULL }; + ngx_int_t rc; if(upload_ctx->output_buffer->pos > upload_ctx->output_buffer->start) { if(upload_ctx->process_chain_f) { upload_ctx->output_buffer->last = upload_ctx->output_buffer->pos; upload_ctx->output_buffer->pos = upload_ctx->output_buffer->start; - if(upload_ctx->process_chain_f(upload_ctx, &chain) != NGX_OK) { + rc = upload_ctx->process_chain_f(upload_ctx, &chain); + + if(rc != NGX_OK && rc != NGX_AGAIN) { upload_ctx->discard_data = 1; } } diff --git a/ngx_upload_discard_filter_module.c b/ngx_upload_discard_filter_module.c new file mode 100644 index 0000000..1e78b79 --- /dev/null +++ b/ngx_upload_discard_filter_module.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008 Valery Kholodkov + */ +#include +#include +#include + +#include + +static ngx_int_t ngx_upload_discard_start_handler(ngx_http_upload_ctx_t *u); +static void ngx_upload_discard_finish_handler(ngx_http_upload_ctx_t *u); +static void ngx_upload_discard_abort_handler(ngx_http_upload_ctx_t *u); +static ngx_int_t ngx_upload_discard_data_handler(ngx_http_upload_ctx_t *u, + ngx_chain_t *chain); + +static char *ngx_upload_discard_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static ngx_upload_content_filter_t /* {{{ */ +ngx_upload_discard_content_filter = { + ngx_upload_discard_start_handler, + ngx_upload_discard_finish_handler, + ngx_upload_discard_abort_handler, + ngx_upload_discard_data_handler +} /* }}} */; + +static ngx_command_t ngx_upload_discard_filter_commands[] = { /* {{{ */ + + /* + * Discards uploaded file + */ + { ngx_string("upload_discard"), + NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, + ngx_upload_discard_command, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; /* }}} */ + +ngx_http_module_t ngx_upload_discard_filter_module_ctx = { /* {{{ */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; /* }}} */ + +ngx_module_t ngx_upload_discard_filter_module = { /* {{{ */ + NGX_MODULE_V1, + &ngx_upload_discard_filter_module_ctx, /* module context */ + ngx_upload_discard_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; /* }}} */ + +static char * /* {{{ ngx_upload_discard_command */ +ngx_upload_discard_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_upload_loc_conf_t *ulcf; + + ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_upload_module); + + if(ngx_http_upload_add_filter(ulcf, &ngx_upload_discard_content_filter, cf->pool) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} /* }}} */ + +static ngx_int_t /* {{{ ngx_upload_discard_start_handler */ +ngx_upload_discard_start_handler(ngx_http_upload_ctx_t *u) { + return NGX_OK; +} /* }}} */ + +static void /* {{{ ngx_upload_discard_finish_handler */ +ngx_upload_discard_finish_handler(ngx_http_upload_ctx_t *u) { +} /* }}} */ + +static void /* {{{ ngx_upload_discard_abort_handler */ +ngx_upload_discard_abort_handler(ngx_http_upload_ctx_t *u) { +} /* }}} */ + +static ngx_int_t /* {{{ ngx_upload_discard_data_handler */ +ngx_upload_discard_data_handler(ngx_http_upload_ctx_t *u, ngx_chain_t *chain) { + return NGX_OK; +} /* }}} */ + diff --git a/ngx_http_unzip_filter_module.c b/ngx_upload_unzip_filter_module.c similarity index 90% rename from ngx_http_unzip_filter_module.c rename to ngx_upload_unzip_filter_module.c index e25eda0..475b9fe 100644 --- a/ngx_http_unzip_filter_module.c +++ b/ngx_upload_unzip_filter_module.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008 Valery Kholodkov + * Copyright (C) 2008 Valery Kholodkov */ #include #include @@ -169,8 +169,13 @@ typedef struct ngx_unzip_ctx_s { ngx_unzip_extra_data_record_t extra_data_record; }; + ngx_str_t archive_name; ngx_str_t file_name; + ngx_str_t prev_elm, current_elm; + ngx_str_t prev_archive_path, current_archive_path; + ngx_int_t entry_no; + void *preallocated; char *free_mem; ngx_uint_t allocated; @@ -202,8 +207,8 @@ ngx_http_unzip_chain_copy_range(ngx_chain_t *chain, ngx_chain_t **copy, off_t *l void ngx_http_unzip_reclaim_chain(ngx_chain_t *cl, ngx_chain_t **free); void ngx_http_unzip_chain_advance(ngx_chain_t *chain, ngx_chain_t *copy); -static char * ngx_http_unzip_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static void *ngx_http_unzip_create_loc_conf(ngx_conf_t *cf); +static char * ngx_upload_unzip_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static void *ngx_upload_unzip_create_loc_conf(ngx_conf_t *cf); static ngx_int_t ngx_http_unzip_start_handler(ngx_http_upload_ctx_t *u); static void ngx_http_unzip_finish_handler(ngx_http_upload_ctx_t *u); @@ -255,14 +260,14 @@ ngx_http_unzip_content_filter = { static ngx_conf_post_handler_pt ngx_http_unzip_window_p = ngx_http_unzip_window; -static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */ +static ngx_command_t ngx_upload_unzip_filter_commands[] = { /* {{{ */ /* * Enables unzipping of uploaded file */ - { ngx_string("unzip"), + { ngx_string("upload_unzip"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_unzip_command, + ngx_upload_unzip_command, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, @@ -270,7 +275,7 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */ /* * Specifies size and number of buffers to use for decompressing */ - { ngx_string("unzip_buffers"), + { ngx_string("upload_unzip_buffers"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, ngx_conf_set_bufs_slot, NGX_HTTP_LOC_CONF_OFFSET, @@ -280,7 +285,7 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */ /* * Specifies size window to use for decompressing */ - { ngx_string("unzip_window"), + { ngx_string("upload_unzip_window"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, @@ -291,7 +296,7 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */ * Specifies a form field with a special content to generate * in output form */ - { ngx_string("unzip_set_form_field"), + { ngx_string("upload_unzip_set_form_field"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, @@ -302,7 +307,7 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */ * Specifies a form field with a special aggregate content to generate * in output form */ - { ngx_string("unzip_aggregate_form_field"), + { ngx_string("upload_unzip_aggregate_form_field"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, @@ -312,7 +317,7 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */ /* * Specifies the maximal length of a file name in archive */ - { ngx_string("unzip_max_file_name_len"), + { ngx_string("upload_unzip_max_file_name_len"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, @@ -322,7 +327,7 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */ ngx_null_command }; /* }}} */ -ngx_http_module_t ngx_http_unzip_filter_module_ctx = { /* {{{ */ +ngx_http_module_t ngx_upload_unzip_filter_module_ctx = { /* {{{ */ NULL, /* preconfiguration */ NULL, /* postconfiguration */ @@ -332,14 +337,14 @@ ngx_http_module_t ngx_http_unzip_filter_module_ctx = { /* {{{ */ NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_unzip_create_loc_conf, /* create location configuration */ + ngx_upload_unzip_create_loc_conf, /* create location configuration */ NULL /* merge location configuration */ }; /* }}} */ -ngx_module_t ngx_http_unzip_filter_module = { /* {{{ */ +ngx_module_t ngx_upload_unzip_filter_module = { /* {{{ */ NGX_MODULE_V1, - &ngx_http_unzip_filter_module_ctx, /* module context */ - ngx_http_unzip_filter_commands, /* module directives */ + &ngx_upload_unzip_filter_module_ctx, /* module context */ + ngx_upload_unzip_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ @@ -351,8 +356,8 @@ ngx_module_t ngx_http_unzip_filter_module = { /* {{{ */ NGX_MODULE_V1_PADDING }; /* }}} */ -static char * /* {{{ ngx_http_unzip_command */ -ngx_http_unzip_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static char * /* {{{ ngx_upload_unzip_command */ +ngx_upload_unzip_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_unzip_conf_t *uzcf = conf; ngx_http_upload_loc_conf_t *ulcf; @@ -382,7 +387,7 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) { ngx_buf_t *buf; ngx_unzip_conf_t *uzcf; - uzcf = ngx_http_get_module_loc_conf(ctx->upload_ctx->request, ngx_http_unzip_filter_module); + uzcf = ngx_http_get_module_loc_conf(ctx->upload_ctx->request, ngx_upload_unzip_filter_module); while(chain != NULL) { for(buf = chain->buf ; buf->pos != buf->last ; buf->pos++) { @@ -852,10 +857,12 @@ static ngx_int_t /* {{{ ngx_http_unzip_start_handler */ ngx_http_unzip_start_handler(ngx_http_upload_ctx_t *u) { ngx_unzip_conf_t *uzcf; ngx_unzip_ctx_t *ctx, *parent; + ngx_http_upload_loc_conf_t *ulcf; - uzcf = ngx_http_get_module_loc_conf(u->request, ngx_http_unzip_filter_module); + uzcf = ngx_http_get_module_loc_conf(u->request, ngx_upload_unzip_filter_module); + ulcf = ngx_http_get_module_loc_conf(u->request, ngx_http_upload_module); - ctx = ngx_http_get_module_ctx(u->request, ngx_http_unzip_filter_module); + ctx = ngx_http_get_module_ctx(u->request, ngx_upload_unzip_filter_module); parent = ctx; @@ -871,16 +878,31 @@ ngx_http_unzip_start_handler(ngx_http_upload_ctx_t *u) { ctx->parent = parent; - ngx_http_set_ctx(u->request, ctx, ngx_http_unzip_filter_module); + ngx_http_set_ctx(u->request, ctx, ngx_upload_unzip_filter_module); ctx->state = unzip_state_signature; ctx->upload_ctx = u; - ctx->next_field_filter = ngx_upload_get_next_field_filter(u); - ctx->next_content_filter = ngx_upload_get_next_content_filter(u); ctx->pool = u->request->pool; ctx->log = u->log; + ctx->next_field_filter = ngx_upload_get_next_field_filter(u); + ctx->next_content_filter = ngx_upload_get_next_content_filter(u); + + ngx_upload_get_archive_elm(u, &ctx->prev_elm); + + ngx_upload_get_archive_path(u, &ctx->prev_archive_path); + + ngx_upload_get_file_name(u, &ctx->archive_name); + + ctx->entry_no = 0; + + ctx->current_elm.len = ctx->prev_elm.len + ulcf->archive_elm_separator.len + NGX_OFF_T_LEN; + ctx->current_elm.data = ngx_palloc(ctx->pool, ctx->current_elm.len); + + if(ctx->current_elm.data == NULL) + return NGX_UPLOAD_NOMEM; + return NGX_OK; } /* }}} */ @@ -888,41 +910,49 @@ static void /* {{{ ngx_http_unzip_finish_handler */ ngx_http_unzip_finish_handler(ngx_http_upload_ctx_t *u) { ngx_unzip_ctx_t *ctx; - ctx = ngx_http_get_module_ctx(u->request, ngx_http_unzip_filter_module); + ctx = ngx_http_get_module_ctx(u->request, ngx_upload_unzip_filter_module); if (ctx->state == unzip_state_file_data) { if(!ctx->discard_data) ctx->decompression_method->abort(ctx); } - ngx_http_set_ctx(u->request, ctx->parent, ngx_http_unzip_filter_module); + ngx_upload_set_archive_elm(u, &ctx->prev_elm); + + ngx_upload_set_archive_path(u, &ctx->prev_archive_path); + + ngx_http_set_ctx(u->request, ctx->parent, ngx_upload_unzip_filter_module); } /* }}} */ static void /* {{{ ngx_http_unzip_abort_handler */ ngx_http_unzip_abort_handler(ngx_http_upload_ctx_t *u) { ngx_unzip_ctx_t *ctx; - ctx = ngx_http_get_module_ctx(u->request, ngx_http_unzip_filter_module); + ctx = ngx_http_get_module_ctx(u->request, ngx_upload_unzip_filter_module); if (ctx->state == unzip_state_file_data) { if(!ctx->discard_data) ctx->decompression_method->abort(ctx); } - ngx_http_set_ctx(u->request, ctx->parent, ngx_http_unzip_filter_module); + ngx_upload_set_archive_elm(u, &ctx->prev_elm); + + ngx_upload_set_archive_path(u, &ctx->prev_archive_path); + + ngx_http_set_ctx(u->request, ctx->parent, ngx_upload_unzip_filter_module); } /* }}} */ static ngx_int_t /* {{{ ngx_http_unzip_data_handler */ ngx_http_unzip_data_handler(ngx_http_upload_ctx_t *u, ngx_chain_t *chain) { ngx_unzip_ctx_t *ctx; - ctx = ngx_http_get_module_ctx(u->request, ngx_http_unzip_filter_module); + ctx = ngx_http_get_module_ctx(u->request, ngx_upload_unzip_filter_module); return ngx_http_unzip_process_chain(ctx, chain); } /* }}} */ -static void * /* {{{ ngx_http_unzip_create_loc_conf */ -ngx_http_unzip_create_loc_conf(ngx_conf_t *cf) +static void * /* {{{ ngx_upload_unzip_create_loc_conf */ +ngx_upload_unzip_create_loc_conf(ngx_conf_t *cf) { ngx_unzip_conf_t *conf; @@ -998,7 +1028,7 @@ ngx_http_unzip_inflate_start(ngx_unzip_ctx_t *ctx) { ctx->stream.avail_in = 0; ctx->stream.next_in = Z_NULL; - uzcf = ngx_http_get_module_loc_conf(ctx->upload_ctx->request, ngx_http_unzip_filter_module); + uzcf = ngx_http_get_module_loc_conf(ctx->upload_ctx->request, ngx_upload_unzip_filter_module); if(ctx->output_buffer == NULL) { ctx->output_buffer = ngx_create_temp_buf(ctx->pool, uzcf->bufs.size); @@ -1118,14 +1148,18 @@ static ngx_int_t /* {{{ ngx_http_unzip_inflate_process_chain */ ngx_http_unzip_inflate_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) { int rc; size_t remaining; + int flush; while(chain != NULL && !chain->buf->last_in_chain) { remaining = chain->buf->last - chain->buf->pos; - if(ctx->current_field_len - ctx->current_field_pos > remaining) + if(ctx->current_field_len - ctx->current_field_pos > remaining) { ctx->stream.avail_in = remaining; - else + flush = Z_NO_FLUSH; + }else{ ctx->stream.avail_in = ctx->current_field_len - ctx->current_field_pos; + flush = Z_SYNC_FLUSH; + } ctx->stream.next_in = chain->buf->pos; @@ -1133,7 +1167,21 @@ ngx_http_unzip_inflate_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) { ctx->stream.avail_out = ctx->output_buffer->end - ctx->output_buffer->start; ctx->stream.next_out = ctx->output_buffer->pos = ctx->output_buffer->start; - rc = inflate(&ctx->stream, Z_NO_FLUSH); + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "inflate in: ai:%ud ni:%p ao:%ud no:%p fl:%d", + ctx->stream.avail_in, ctx->stream.next_in, + ctx->stream.avail_out, ctx->stream.next_out, + flush + ); + + rc = inflate(&ctx->stream, flush); + + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "inflate out: ai:%ud ni:%p ao:%ud no:%p rc:%d", + ctx->stream.avail_in, ctx->stream.next_in, + ctx->stream.avail_out, ctx->stream.next_out, + rc + ); if(rc == Z_OK || rc == Z_STREAM_END) { ctx->output_buffer->last = ctx->stream.next_out; @@ -1155,7 +1203,7 @@ ngx_http_unzip_inflate_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) { "inflate() failed: %d", rc); return NGX_ERROR; } - }while(ctx->stream.avail_out == 0 && rc == Z_OK); + }while(ctx->stream.avail_out == 0 && ctx->stream.avail_in > 0 && rc == Z_OK); ctx->current_field_pos += (ctx->stream.next_in - chain->buf->pos); @@ -1229,6 +1277,37 @@ ngx_http_unzip_extract_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) { return NGX_OK; } /* }}} */ +static void /* {{{ ngx_http_unzip_set_archive_elm */ +ngx_http_unzip_set_archive_elm(ngx_unzip_ctx_t *ctx, off_t elm_id) { + ngx_http_upload_loc_conf_t *ulcf; + + ulcf = ngx_http_get_module_loc_conf(ctx->upload_ctx->request, ngx_http_upload_module); + + ctx->current_elm.len = ngx_sprintf(ctx->current_elm.data, "%V%V%O", &ctx->prev_elm, &ulcf->archive_elm_separator, elm_id) - ctx->current_elm.data; + + ngx_upload_set_archive_elm(ctx->upload_ctx, &ctx->current_elm); +} /* }}} */ + +static ngx_int_t /* {{{ ngx_http_unzip_set_archive_path */ +ngx_http_unzip_set_archive_path(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name, ngx_str_t *path) { + ngx_http_upload_loc_conf_t *ulcf; + + ulcf = ngx_http_get_module_loc_conf(ctx->upload_ctx->request, ngx_http_upload_module); + + ctx->current_archive_path.len = ctx->prev_archive_path.len + file_name->len + ulcf->archive_path_separator.len + path->len; + + ctx->current_archive_path.data = ngx_palloc(ctx->pool, ctx->current_archive_path.len); + + if(ctx->current_archive_path.data == NULL) + return NGX_UPLOAD_NOMEM; + + ctx->current_archive_path.len = ngx_sprintf(ctx->current_archive_path.data, "%V%V%V%V", &ctx->prev_archive_path, file_name, &ulcf->archive_path_separator, path) - ctx->current_archive_path.data; + + ngx_upload_set_archive_path(ctx->upload_ctx, &ctx->current_archive_path); + + return NGX_OK; +} /* }}} */ + static ngx_int_t /* {{{ ngx_http_unzip_parse_file_name */ ngx_http_unzip_parse_file_name(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name) { u_char *p; @@ -1251,11 +1330,7 @@ ngx_http_unzip_parse_file_name(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name) { archive_path.len = 0; set: - rc = ngx_upload_set_file_name(ctx->upload_ctx, &element_name); - - if(rc != NGX_OK) { - return rc; - } + ngx_upload_set_file_name(ctx->upload_ctx, &element_name); rc = ngx_upload_set_exten(ctx->upload_ctx, &element_name, &exten); @@ -1269,18 +1344,16 @@ ngx_http_unzip_parse_file_name(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name) { return rc; } - rc = ngx_upload_set_content_type(ctx->upload_ctx, &content_type); + ngx_upload_set_content_type(ctx->upload_ctx, &content_type); - if(rc != NGX_OK) { - return rc; - } - - rc = ngx_upload_set_archive_path(ctx->upload_ctx, &archive_path); + rc = ngx_http_unzip_set_archive_path(ctx, &ctx->archive_name, &archive_path); if(rc != NGX_OK) { return rc; } + ngx_http_unzip_set_archive_elm(ctx, ctx->entry_no++); + return NGX_OK; } /* }}} */