Skip to content
Browse files

Uploaded data is now being processed in nginx chains

  • Loading branch information...
1 parent 3cec90a commit 07406fe12d1767bbbf5bf97971772a6978b979c6 @vkholodkov vkholodkov committed
Showing with 726 additions and 377 deletions.
  1. +642 −319 ngx_http_unzip_filter_module.c
  2. +5 −5 ngx_http_upload.h
  3. +79 −53 ngx_http_upload_module.c
View
961 ngx_http_unzip_filter_module.c
@@ -14,10 +14,13 @@
#define LOCAL_DATA_HEADER_SIGNATURE 0x04034b50
#define ARCHIVE_EXTRA_DATA_SIGNATURE 0x08064b50
#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50
+#define DIGITAL_SIGNATURE_HEADER_SIGNATURE 0x05054b50
+#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50
#define SIGNATURE_LEN 4
#define LOCAL_DATA_HEADER_LEN 30
#define FILE_HEADER_LEN 46
#define DATA_DESCRIPTOR_LEN 12
+#define END_OF_CENTRAL_DIR_LEN 18
#define ZIP_METHOD_STORED 0
#define ZIP_METHOD_DEFLATED 8
@@ -34,8 +37,22 @@
#define EXTRACT_LONG(x) (uint32_t)(*(x) << 24 | *((x)+1) << 16 | *((x)+2) << 8 | *((x)+3))
#endif
+struct ngx_unzip_ctx_s;
+
+typedef struct {
+ uint16_t method;
+ ngx_int_t (*start)(struct ngx_unzip_ctx_s*);
+ void (*finish)(struct ngx_unzip_ctx_s*);
+ void (*abort)(struct ngx_unzip_ctx_s*);
+ ngx_int_t (*process_chain)(struct ngx_unzip_ctx_s*, ngx_chain_t*);
+} ngx_unzip_decompression_method_t;
+
+#define ngx_unzip_decompression_method_null { 0xffff, NULL, NULL, NULL, NULL }
+
typedef struct {
ngx_bufs_t bufs;
+ size_t wbits;
+ size_t max_file_name_len;
unsigned int recursive:1;
} ngx_unzip_conf_t;
@@ -49,6 +66,7 @@ typedef enum {
unzip_state_decryption_header,
unzip_state_extra_data_record,
unzip_state_file_header,
+ unzip_state_digital_sig_header,
unzip_state_central_directory_end,
unzip_state_finish
} ngx_unzip_state_e;
@@ -67,6 +85,50 @@ typedef struct {
} ngx_unzip_local_data_header_t;
typedef struct {
+ uint16_t version_made_by;
+ uint16_t version_needed;
+ uint16_t flags;
+ uint16_t compression_method;
+ uint16_t last_mod_time;
+ uint16_t last_mod_date;
+ uint32_t crc32;
+ size_t compressed_size;
+ size_t uncompressed_size;
+ size_t file_name_len;
+ size_t extra_field_len;
+ size_t file_comment_len;
+ uint16_t disk_number_start;
+ uint16_t internal_file_attributes;
+ uint16_t external_file_attributes;
+ off_t relative_offset;
+} ngx_unzip_file_data_header_t;
+
+typedef struct {
+ size_t data_size;
+} ngx_unzip_digital_signature_t;
+
+typedef struct {
+ uint16_t version_made_by;
+ uint16_t version_needed;
+ uint16_t flags;
+ uint16_t compression_method;
+ uint16_t last_mod_time;
+ uint16_t last_mod_date;
+ uint32_t crc32;
+ size_t compressed_size;
+ size_t uncompressed_size;
+ size_t file_name_len;
+ size_t extra_field_len;
+ size_t file_comment_len;
+ uint16_t disk_number_start;
+ uint16_t internal_file_attrs;
+ uint16_t external_file_attrs;
+ off_t relative_offset;
+} ngx_unzip_end_of_central_dir_t;
+
+typedef struct ngx_unzip_ctx_s {
+ struct ngx_unzip_ctx_s *parent;
+
ngx_unzip_state_e state;
size_t current_field_len;
size_t current_field_pos;
@@ -74,14 +136,14 @@ typedef struct {
ngx_pool_t *pool;
ngx_log_t *log;
- u_char buffer[512];
+ u_char accumulator[512];
u_char *current_field;
u_char *current_field_ptr;
uint16_t version_needed;
uint16_t flags;
- uint16_t compression_method;
+ uint16_t compression_method_number;
uint16_t last_mod_time;
uint16_t last_mod_date;
uint32_t crc32;
@@ -94,8 +156,12 @@ typedef struct {
z_stream stream;
+ ngx_buf_t *output_buffer;
+ ngx_chain_t *output_chain;
+
ngx_http_upload_ctx_t *upload_ctx;
ngx_upload_content_filter_t *next_content_filter;
+ ngx_unzip_decompression_method_t *decompression_method;
unsigned int discard_data:1;
} ngx_unzip_ctx_t;
@@ -107,14 +173,51 @@ 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);
static void ngx_http_unzip_abort_handler(ngx_http_upload_ctx_t *u);
static ngx_int_t ngx_http_unzip_data_handler(ngx_http_upload_ctx_t *u,
- u_char *buf, size_t len);
+ ngx_chain_t *chain);
-static ngx_upload_content_filter_t ngx_unzip_content_filter = {
+static ngx_int_t ngx_http_unzip_retrieve_start(ngx_unzip_ctx_t *ctx);
+static void ngx_http_unzip_retrieve_finish(ngx_unzip_ctx_t *ctx);
+static void ngx_http_unzip_retrieve_abort(ngx_unzip_ctx_t *ctx);
+static ngx_int_t ngx_http_unzip_retrieve_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain);
+
+static ngx_int_t ngx_http_unzip_inflate_start(ngx_unzip_ctx_t *ctx);
+static void ngx_http_unzip_inflate_finish(ngx_unzip_ctx_t *ctx);
+static void ngx_http_unzip_inflate_abort(ngx_unzip_ctx_t *ctx);
+static ngx_int_t ngx_http_unzip_inflate_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain);
+
+static char *ngx_http_unzip_window(ngx_conf_t *cf, void *post, void *data);
+
+static ngx_int_t
+ngx_http_unzip_set_decompression_method(ngx_unzip_ctx_t *ctx, uint16_t compression_method_number);
+static ngx_int_t ngx_http_unzip_parse_file_name(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name);
+
+static ngx_unzip_decompression_method_t /* {{{ */
+ngx_unzip_decompression_methods[] = {
+
+ { ZIP_METHOD_STORED,
+ ngx_http_unzip_retrieve_start,
+ ngx_http_unzip_retrieve_finish,
+ ngx_http_unzip_retrieve_abort,
+ ngx_http_unzip_retrieve_process_chain },
+
+ { ZIP_METHOD_DEFLATED,
+ ngx_http_unzip_inflate_start,
+ ngx_http_unzip_inflate_finish,
+ ngx_http_unzip_inflate_abort,
+ ngx_http_unzip_inflate_process_chain },
+
+ ngx_unzip_decompression_method_null
+} /* }}} */;
+
+static ngx_upload_content_filter_t /* {{{ */
+ngx_http_unzip_content_filter = {
ngx_http_unzip_start_handler,
ngx_http_unzip_finish_handler,
ngx_http_unzip_abort_handler,
ngx_http_unzip_data_handler
-};
+} /* }}} */;
+
+static ngx_conf_post_handler_pt ngx_http_unzip_window_p = ngx_http_unzip_window;
static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */
@@ -129,7 +232,7 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */
NULL },
/*
- * Specifies size and numbers of buffers to use for decompressing
+ * Specifies size and number of buffers to use for decompressing
*/
{ ngx_string("unzip_buffers"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
@@ -138,6 +241,27 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */
offsetof(ngx_unzip_conf_t, bufs),
NULL },
+ { ngx_string("unzip_window"),
+ NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_unzip_conf_t, wbits),
+ &ngx_http_unzip_window_p },
+
+ { ngx_string("unzip_set_form_field"),
+ NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_unzip_conf_t, wbits),
+ NULL },
+
+ { ngx_string("unzip_aggregate_form_field"),
+ NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_unzip_conf_t, wbits),
+ NULL },
+
ngx_null_command
}; /* }}} */
@@ -170,8 +294,6 @@ ngx_module_t ngx_http_unzip_filter_module = { /* {{{ */
NGX_MODULE_V1_PADDING
}; /* }}} */
-u_char unzip_buffer[4096];
-
static char * /* {{{ ngx_http_unzip_command */
ngx_http_unzip_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
@@ -180,365 +302,285 @@ ngx_http_unzip_command(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_str_t *value;
- unsigned int on = 0;
-
ulcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_upload_module);
value = cf->args->elts;
- if(ngx_strcmp(value[1].data, "on") == 0) {
- on = 1;
- uzcf->recursive = 0;
- }
-
- if(ngx_strcmp(value[1].data, "recursive") == 0) {
- on = 1;
- uzcf->recursive = 1;
+ if(cf->args->nelts > 1) {
+ if(ngx_strcmp(value[1].data, "recursive") == 0) {
+ uzcf->recursive = 1;
+ }
}
- if(on) {
- if(ngx_http_upload_add_filter(ulcf, &ngx_unzip_content_filter, cf->pool) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
+ if(ngx_http_upload_add_filter(ulcf, &ngx_http_unzip_content_filter, cf->pool) != NGX_OK) {
+ return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
} /* }}} */
-static ngx_int_t
-ngx_unzip_decompress_start(ngx_unzip_ctx_t *ctx) {
- ngx_int_t rc;
-
- ctx->stream.zalloc = Z_NULL;
- ctx->stream.zfree = Z_NULL;
- ctx->stream.opaque = Z_NULL;
- ctx->stream.avail_in = 0;
- ctx->stream.next_in = Z_NULL;
-
- rc = inflateInit2(&ctx->stream, -15);
-
- if (rc != Z_OK) {
- ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
- "inflateInit() failed: %d", rc);
- return NGX_ERROR;
- }
+static ngx_int_t /* {{{ ngx_http_unzip_process_chain */
+ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
+ ngx_int_t result;
+ ngx_buf_t *buf;
- ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
- "started unzipping file \"%V\"", &ctx->file_name);
+ while(chain != NULL && !chain->buf->last_in_chain) {
+ buf = chain->buf;
- rc = ngx_upload_set_file_name(ctx->upload_ctx, &ctx->file_name);
+ for(buf = chain->buf ; buf->pos != buf->last ; buf->pos++) {
+ switch(ctx->state) {
+ case unzip_state_signature: /* {{{ */
+ if(ctx->current_field_pos == 0) {
+ ctx->current_field_len = SIGNATURE_LEN;
+ ctx->current_field_ptr = ctx->current_field = ctx->accumulator;
+ }
- if(rc != NGX_OK) {
- goto cleanup;
- }
+ *ctx->current_field_ptr++ = *buf->pos;
+ ctx->current_field_pos++;
+
+ if(ctx->current_field_pos == ctx->current_field_len) {
+ ctx->current_field_pos = 0;
+
+ switch(EXTRACT_LONG(ctx->current_field)) {
+ case LOCAL_DATA_HEADER_SIGNATURE:
+ ctx->state = unzip_state_local_data_header;
+ break;
+ case ARCHIVE_EXTRA_DATA_SIGNATURE:
+ ctx->state = unzip_state_local_data_header;
+ break;
+ case CENTRAL_FILE_HEADER_SIGNATURE:
+ ctx->state = unzip_state_file_header;
+ break;
+ case DIGITAL_SIGNATURE_HEADER_SIGNATURE:
+ ctx->state = unzip_state_digital_sig_header;
+ break;
+ default:
+ return NGX_UNZIP_MALFORMED;
+ }
+ }
+ break; /* }}} */
+ case unzip_state_local_data_header: /* {{{ */
+ if(ctx->current_field_pos == 0) {
+ ctx->current_field_len = LOCAL_DATA_HEADER_LEN - SIGNATURE_LEN;
+ ctx->current_field_ptr = ctx->current_field = ctx->accumulator;
- if(ctx->next_content_filter->start) {
- rc = ctx->next_content_filter->start(ctx->upload_ctx);
+ ctx->discard_data = 0;
+ }
- if(rc != NGX_OK) {
- goto cleanup;
- }
+ *ctx->current_field_ptr++ = *buf->pos;
+ ctx->current_field_pos++;
- return rc;
- }
+ if(ctx->current_field_pos == ctx->current_field_len) {
+ ctx->current_field_pos = 0;
- return NGX_OK;
-cleanup:
- inflateEnd(&ctx->stream);
- return rc;
-}
+ ctx->version_needed = EXTRACT_SHORT(ctx->current_field);
+ ctx->flags = EXTRACT_SHORT(ctx->current_field + 2);
+ ctx->compression_method_number = EXTRACT_SHORT(ctx->current_field + 4);
+ ctx->last_mod_time = EXTRACT_SHORT(ctx->current_field + 6);
+ ctx->last_mod_date = EXTRACT_SHORT(ctx->current_field + 8);
+ ctx->crc32 = EXTRACT_LONG(ctx->current_field + 10);
+ ctx->compressed_size = EXTRACT_LONG(ctx->current_field + 14);
+ ctx->uncompressed_size = EXTRACT_LONG(ctx->current_field + 18);
-static void
-ngx_unzip_decompress_finish(ngx_unzip_ctx_t *ctx) {
- if(ctx->next_content_filter->finish)
- ctx->next_content_filter->finish(ctx->upload_ctx);
+ ctx->file_name_len = EXTRACT_SHORT(ctx->current_field + 22);
+ ctx->extra_field_len = EXTRACT_SHORT(ctx->current_field + 24);
- inflateEnd(&ctx->stream);
+ if(ngx_http_unzip_set_decompression_method(ctx,
+ ctx->compression_method_number) != NGX_OK)
+ {
+ return NGX_UNZIP_MALFORMED;
+ }
- ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
- "finished unzipping file \"%V\"", &ctx->file_name);
-}
+ if(ctx->version_needed > ZIP_VERSION)
+ {
+ return NGX_UNZIP_MALFORMED;
+ }
+
+ if(ctx->file_name_len > 0)
+ ctx->state = unzip_state_file_name;
+ else if(ctx->extra_field_len > 0)
+ ctx->state = unzip_state_extra_field;
+ else if(ctx->compressed_size > 0)
+ ctx->state = unzip_state_file_data;
+ else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
+ ctx->state = unzip_state_data_descriptor;
+ else
+ ctx->state = unzip_state_signature;
+ }
+ break; /* }}} */
+ case unzip_state_file_name: /* {{{ */
+ if(ctx->current_field_pos == 0) {
+ ctx->file_name.len = ctx->file_name_len;
-static void
-ngx_unzip_decompress_abort(ngx_unzip_ctx_t *ctx) {
- if(ctx->next_content_filter->abort)
- ctx->next_content_filter->abort(ctx->upload_ctx);
+ ctx->file_name.data = ngx_palloc(ctx->pool, ctx->file_name_len + 1);
- inflateEnd(&ctx->stream);
+ if(ctx->file_name.data == NULL) {
+ return NGX_UPLOAD_NOMEM;
+ }
- ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
- "aborted unzipping file \"%V\"", &ctx->file_name);
-}
+ ctx->current_field_len = ctx->file_name_len;
+ ctx->current_field_ptr = ctx->current_field = ctx->file_name.data;
+ }
-static ngx_int_t
-ngx_unzip_decompress_data(ngx_unzip_ctx_t *ctx, u_char *start, u_char *end) {
- int rc;
- size_t remaining = end - start;
+ *ctx->current_field_ptr++ = *buf->pos;
+ ctx->current_field_pos++;
+
+ if(ctx->current_field_pos == ctx->current_field_len) {
+ ctx->current_field_pos = 0;
- if(ctx->current_field_len - ctx->current_field_pos > remaining)
- ctx->stream.avail_in = remaining;
- else
- ctx->stream.avail_in = ctx->current_field_len - ctx->current_field_pos;
+ *ctx->current_field_ptr = '\0';
- ctx->stream.next_in = start;
+ if(ngx_http_unzip_parse_file_name(ctx, &ctx->file_name) != NGX_OK) {
+ return NGX_UNZIP_MALFORMED;
+ }
+
+ if(ctx->extra_field_len > 0)
+ ctx->state = unzip_state_extra_field;
+ else if(ctx->compressed_size > 0)
+ ctx->state = unzip_state_file_data;
+ else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
+ ctx->state = unzip_state_data_descriptor;
+ else
+ ctx->state = unzip_state_signature;
+ }
+ break; /* }}} */
+ case unzip_state_extra_field:
+ if(ctx->current_field_pos == 0) {
+ ctx->current_field_len = ctx->extra_field_len;
+ }
- do{
- ctx->stream.avail_out = sizeof(unzip_buffer);
- ctx->stream.next_out = unzip_buffer;
+ ctx->current_field_pos++;
+
+ if(ctx->current_field_pos == ctx->current_field_len) {
+ ctx->current_field_pos = 0;
+
+ if(ctx->compressed_size > 0)
+ ctx->state = unzip_state_file_data;
+ else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
+ ctx->state = unzip_state_data_descriptor;
+ else
+ ctx->state = unzip_state_signature;
+ }
+ break;
+ case unzip_state_file_data:
+ if(ctx->current_field_pos == 0) {
+ ctx->current_field_len = ctx->compressed_size;
+
+ if(ctx->decompression_method->start(ctx) != NGX_OK) {
+ ctx->discard_data = 1;
+ }
+ }
+
+ if(!ctx->discard_data) {
+ result = ctx->decompression_method->process_chain(ctx, chain);
- rc = inflate(&ctx->stream, Z_NO_FLUSH);
+ buf->pos--;
- if(rc == Z_OK || rc == Z_STREAM_END) {
- if(ctx->next_content_filter->process_buf)
- ctx->next_content_filter->process_buf(ctx->upload_ctx,
- unzip_buffer, sizeof(unzip_buffer) - ctx->stream.avail_out);
- }
+ if(result == NGX_AGAIN) {
+ return NGX_AGAIN;
+ }
- if(rc == Z_STREAM_END) {
- return ctx->stream.next_in - start;
- }
+ if(result != NGX_OK) {
+ ctx->discard_data = 1;
- if (rc != Z_OK) {
- ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
- "inflate() failed: %d", rc);
- return NGX_ERROR;
- }
- }while(ctx->stream.avail_out == 0);
+ ctx->decompression_method->abort(ctx);
- return ctx->stream.next_in - start;
-}
+ ctx->current_field_pos++;
+ }
+ }else
+ ctx->current_field_pos++;
+
+ if(ctx->current_field_pos >= ctx->current_field_len) {
+ if(!ctx->discard_data)
+ ctx->decompression_method->finish(ctx);
-static ngx_int_t
-unzip_process_buf(ngx_unzip_ctx_t *ctx, u_char *start, u_char *end) {
- ngx_int_t result;
- u_char *p;
+ ctx->current_field_pos = 0;
- for(p = start ; p != end ; p++) {
- switch(ctx->state) {
- case unzip_state_signature:
- if(ctx->current_field_pos == 0) {
- ctx->current_field_len = SIGNATURE_LEN;
- ctx->current_field_ptr = ctx->current_field = ctx->buffer;
- }
-
- *ctx->current_field_ptr++ = *p;
- ctx->current_field_pos++;
-
- if(ctx->current_field_pos == ctx->current_field_len) {
- ctx->current_field_pos = 0;
-
- switch(EXTRACT_LONG(ctx->current_field)) {
- case LOCAL_DATA_HEADER_SIGNATURE:
- ctx->state = unzip_state_local_data_header;
- break;
- case ARCHIVE_EXTRA_DATA_SIGNATURE:
- ctx->state = unzip_state_local_data_header;
- break;
- case CENTRAL_FILE_HEADER_SIGNATURE:
- ctx->state = unzip_state_file_header;
- break;
- default:
- return NGX_UNZIP_MALFORMED;
- }
- }
- break;
- case unzip_state_local_data_header:
- if(ctx->current_field_pos == 0) {
- ctx->current_field_len = LOCAL_DATA_HEADER_LEN - SIGNATURE_LEN;
- ctx->current_field_ptr = ctx->current_field = ctx->buffer;
-
- ctx->discard_data = 0;
- }
-
- *ctx->current_field_ptr++ = *p;
- ctx->current_field_pos++;
-
- if(ctx->current_field_pos == ctx->current_field_len) {
- ctx->current_field_pos = 0;
-
- ctx->version_needed = EXTRACT_SHORT(ctx->current_field);
- ctx->flags = EXTRACT_SHORT(ctx->current_field + 2);
- ctx->compression_method = EXTRACT_SHORT(ctx->current_field + 4);
- ctx->last_mod_time = EXTRACT_SHORT(ctx->current_field + 6);
- ctx->last_mod_date = EXTRACT_SHORT(ctx->current_field + 8);
- ctx->crc32 = EXTRACT_LONG(ctx->current_field + 10);
- ctx->compressed_size = EXTRACT_LONG(ctx->current_field + 14);
- ctx->uncompressed_size = EXTRACT_LONG(ctx->current_field + 18);
-
- ctx->file_name_len = EXTRACT_SHORT(ctx->current_field + 22);
- ctx->extra_field_len = EXTRACT_SHORT(ctx->current_field + 24);
-
- if(ctx->compression_method != ZIP_METHOD_STORED &&
- ctx->compression_method != ZIP_METHOD_DEFLATED)
- {
- return NGX_UNZIP_MALFORMED;
+ if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
+ ctx->state = unzip_state_data_descriptor;
+ else
+ ctx->state = unzip_state_signature;
}
-
- if(ctx->version_needed > ZIP_VERSION)
- {
- return NGX_UNZIP_MALFORMED;
+ break;
+ case unzip_state_data_descriptor:
+ if(ctx->current_field_pos == 0) {
+ ctx->current_field_len = DATA_DESCRIPTOR_LEN;
+ ctx->current_field_ptr = ctx->current_field = ctx->accumulator;
}
- if(ctx->file_name_len > 0)
- ctx->state = unzip_state_file_name;
- else if(ctx->extra_field_len > 0)
- ctx->state = unzip_state_extra_field;
- else if(ctx->compressed_size > 0)
- ctx->state = unzip_state_file_data;
- else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
- ctx->state = unzip_state_data_descriptor;
- else
+ *ctx->current_field_ptr++ = *buf->pos;
+ ctx->current_field_pos++;
+
+ if(ctx->current_field_pos == ctx->current_field_len) {
+ ctx->current_field_pos = 0;
ctx->state = unzip_state_signature;
- }
- break;
- case unzip_state_file_name:
- if(ctx->current_field_pos == 0) {
- ctx->file_name.len = ctx->file_name_len;
-
- ctx->file_name.data = ngx_palloc(ctx->pool, ctx->file_name_len + 1);
-
- if(ctx->file_name.data == NULL) {
- return NGX_UPLOAD_NOMEM;
+ }
+ break;
+ case unzip_state_decryption_header:
+ break;
+ case unzip_state_extra_data_record:
+ break;
+ case unzip_state_file_header:
+ if(ctx->current_field_pos == 0) {
+ ctx->current_field_len = FILE_HEADER_LEN - SIGNATURE_LEN;
+ ctx->current_field_ptr = ctx->current_field = ctx->accumulator;
}
- ctx->current_field_len = ctx->file_name_len;
- ctx->current_field_ptr = ctx->current_field = ctx->file_name.data;
- }
-
- *ctx->current_field_ptr++ = *p;
- ctx->current_field_pos++;
-
- if(ctx->current_field_pos == ctx->current_field_len) {
- ctx->current_field_pos = 0;
-
- *ctx->current_field_ptr = '\0';
-
- if(ctx->extra_field_len > 0)
- ctx->state = unzip_state_extra_field;
- else if(ctx->compressed_size > 0)
- ctx->state = unzip_state_file_data;
- else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
- ctx->state = unzip_state_data_descriptor;
- else
- ctx->state = unzip_state_signature;
- }
- break;
- case unzip_state_extra_field:
- if(ctx->current_field_pos == 0) {
- ctx->current_field_len = ctx->extra_field_len;
- }
-
- ctx->current_field_pos++;
-
- if(ctx->current_field_pos == ctx->current_field_len) {
- ctx->current_field_pos = 0;
-
- if(ctx->compressed_size > 0)
- ctx->state = unzip_state_file_data;
- else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
- ctx->state = unzip_state_data_descriptor;
- else
+ *ctx->current_field_ptr++ = *buf->pos;
+ ctx->current_field_pos++;
+
+ if(ctx->current_field_pos == ctx->current_field_len) {
+ ctx->current_field_pos = 0;
ctx->state = unzip_state_signature;
- }
- break;
- case unzip_state_file_data:
- if(ctx->current_field_pos == 0) {
- ctx->current_field_len = ctx->compressed_size;
-
- if(ngx_unzip_decompress_start(ctx) != NGX_OK) {
- ctx->discard_data = 1;
}
- }
-
- if(!ctx->discard_data) {
- result = ngx_unzip_decompress_data(ctx, p, end);
-
- if(result < 0) {
- ctx->discard_data = 1;
-
- ngx_unzip_decompress_abort(ctx);
-
- ctx->current_field_pos++;
- }else{
- ctx->current_field_pos += result;
- p += (result - 1);
+ break;
+ case unzip_state_digital_sig_header:
+ break;
+ case unzip_state_central_directory_end:
+ if(ctx->current_field_pos == 0) {
+ ctx->current_field_len = END_OF_CENTRAL_DIR_LEN - SIGNATURE_LEN;
+ ctx->current_field_ptr = ctx->current_field = ctx->accumulator;
}
- }else
- ctx->current_field_pos++;
-
- if(ctx->current_field_pos == ctx->current_field_len) {
- if(!ctx->discard_data)
- ngx_unzip_decompress_finish(ctx);
-
- ctx->current_field_pos = 0;
- if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
- ctx->state = unzip_state_data_descriptor;
- else
+ *ctx->current_field_ptr++ = *buf->pos;
+ ctx->current_field_pos++;
+
+ if(ctx->current_field_pos == ctx->current_field_len) {
+ ctx->current_field_pos = 0;
ctx->state = unzip_state_signature;
- }
- break;
- case unzip_state_data_descriptor:
- if(ctx->current_field_pos == 0) {
- ctx->current_field_len = DATA_DESCRIPTOR_LEN;
- ctx->current_field_ptr = ctx->current_field = ctx->buffer;
- }
-
- *ctx->current_field_ptr++ = *p;
- ctx->current_field_pos++;
-
- if(ctx->current_field_pos == ctx->current_field_len) {
- ctx->current_field_pos = 0;
- ctx->state = unzip_state_signature;
- }
- break;
- case unzip_state_decryption_header:
- break;
- case unzip_state_extra_data_record:
- break;
- case unzip_state_file_header:
- if(ctx->current_field_pos == 0) {
- ctx->current_field_len = FILE_HEADER_LEN - SIGNATURE_LEN;
- ctx->current_field_ptr = ctx->current_field = ctx->buffer;
- }
-
- *ctx->current_field_ptr++ = *p;
- ctx->current_field_pos++;
-
- if(ctx->current_field_pos == ctx->current_field_len) {
- ctx->current_field_pos = 0;
- ctx->state = unzip_state_signature;
- }
- break;
- break;
- case unzip_state_central_directory_end:
- break;
- case unzip_state_finish:
- break;
+ }
+ break;
+ case unzip_state_finish:
+ break;
+ }
}
+
+ chain = chain->next;
}
return NGX_OK;
-}
+} /* }}} */
-static ngx_int_t
+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;
+ ngx_unzip_ctx_t *ctx, *parent;
uzcf = ngx_http_get_module_loc_conf(u->request, ngx_http_unzip_filter_module);
ctx = ngx_http_get_module_ctx(u->request, ngx_http_unzip_filter_module);
- if (ctx == NULL) {
- ctx = ngx_pcalloc(u->request->pool, sizeof(ngx_unzip_ctx_t));
- if (ctx == NULL) {
- return NGX_UPLOAD_NOMEM;
- }
+ parent = ctx;
- ngx_http_set_ctx(u->request, ctx, ngx_http_unzip_filter_module);
+ ctx = ngx_pcalloc(u->request->pool, sizeof(ngx_unzip_ctx_t));
+ if (ctx == NULL) {
+ return NGX_UPLOAD_NOMEM;
}
+ ctx->parent = parent;
+
+ ngx_http_set_ctx(u->request, ctx, ngx_http_unzip_filter_module);
+
ctx->state = unzip_state_signature;
ctx->upload_ctx = u;
ctx->next_content_filter = ngx_upload_get_next_content_filter(u);
@@ -547,13 +589,23 @@ ngx_http_unzip_start_handler(ngx_http_upload_ctx_t *u) {
ctx->log = u->log;
return NGX_OK;
-}
+} /* }}} */
-static void
+static void /* {{{ ngx_http_unzip_finish_handler */
ngx_http_unzip_finish_handler(ngx_http_upload_ctx_t *u) {
-}
+ ngx_unzip_ctx_t *ctx;
-static void
+ ctx = ngx_http_get_module_ctx(u->request, ngx_http_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);
+} /* }}} */
+
+static void /* {{{ ngx_http_unzip_abort_handler */
ngx_http_unzip_abort_handler(ngx_http_upload_ctx_t *u) {
ngx_unzip_ctx_t *ctx;
@@ -561,20 +613,22 @@ ngx_http_unzip_abort_handler(ngx_http_upload_ctx_t *u) {
if (ctx->state == unzip_state_file_data) {
if(!ctx->discard_data)
- ngx_unzip_decompress_abort(ctx);
+ ctx->decompression_method->abort(ctx);
}
-}
-static ngx_int_t
-ngx_http_unzip_data_handler(ngx_http_upload_ctx_t *u, u_char *buf, size_t len) {
+ ngx_http_set_ctx(u->request, ctx->parent, ngx_http_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);
- return unzip_process_buf(ctx, buf, buf + len);
-}
+ return ngx_http_unzip_process_chain(ctx, chain);
+} /* }}} */
-static void *
+static void * /* {{{ ngx_http_unzip_create_loc_conf */
ngx_http_unzip_create_loc_conf(ngx_conf_t *cf)
{
ngx_unzip_conf_t *conf;
@@ -584,11 +638,280 @@ ngx_http_unzip_create_loc_conf(ngx_conf_t *cf)
return NGX_CONF_ERROR;
}
+ conf->wbits = 15;
+ conf->bufs.num = 4;
+ conf->bufs.size = ngx_pagesize;
+
/*
- * conf->bufs,
+ * conf->bufs
* zeroed by ngx_pcalloc
*/
return conf;
-}
+} /* }}} */
+
+static char * /* {{{ ngx_http_unzip_window */
+ngx_http_unzip_window(ngx_conf_t *cf, void *post, void *data)
+{
+ int *np = data;
+
+ int wbits, wsize;
+
+ wbits = 15;
+
+ for (wsize = 32 * 1024; wsize > 256; wsize >>= 1) {
+
+ if (wsize == *np) {
+ *np = wbits;
+
+ return NGX_CONF_OK;
+ }
+
+ wbits--;
+ }
+
+ return "must be 512, 1k, 2k, 4k, 8k, 16k, or 32k";
+} /* }}} */
+
+static ngx_int_t /* {{{ ngx_http_unzip_set_decompression_method */
+ngx_http_unzip_set_decompression_method(ngx_unzip_ctx_t *ctx, uint16_t compression_method)
+{
+ ngx_unzip_decompression_method_t *m = ngx_unzip_decompression_methods;
+
+ while(m->method != 0xffff) {
+ if(m->method== compression_method) {
+ ctx->decompression_method = m;
+ return NGX_OK;
+ }
+
+ m++;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
+ "unknown compression method: %u", compression_method);
+
+ return NGX_ERROR;
+} /* }}} */
+
+static ngx_int_t /* {{{ ngx_http_unzip_inflate_start */
+ngx_http_unzip_inflate_start(ngx_unzip_ctx_t *ctx) {
+ ngx_int_t rc;
+ ngx_unzip_conf_t *uzcf;
+
+ ctx->stream.zalloc = Z_NULL;
+ ctx->stream.zfree = Z_NULL;
+ ctx->stream.opaque = Z_NULL;
+ 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);
+
+ if(ctx->output_buffer == NULL) {
+ ctx->output_buffer = ngx_create_temp_buf(ctx->pool, uzcf->bufs.size);
+
+ if (ctx->output_buffer == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ if(ctx->output_chain == NULL) {
+ ctx->output_chain = ngx_alloc_chain_link(ctx->pool);
+
+ if (ctx->output_chain == NULL) {
+ return NGX_ERROR;
+ }
+
+ ctx->output_chain->buf = ctx->output_buffer;
+ ctx->output_chain->next = NULL;
+ }
+
+ rc = inflateInit2(&ctx->stream, -uzcf->wbits);
+
+ if (rc != Z_OK) {
+ ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
+ "inflateInit() failed: %d", rc);
+ return NGX_ERROR;
+ }
+
+ ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
+ "started inflating file \"%V\"", &ctx->file_name);
+
+ if(ctx->next_content_filter->start) {
+ rc = ctx->next_content_filter->start(ctx->upload_ctx);
+
+ if(rc != NGX_OK) {
+ goto cleanup;
+ }
+
+ return rc;
+ }
+
+ return NGX_OK;
+cleanup:
+ inflateEnd(&ctx->stream);
+ return rc;
+} /* }}} */
+
+static void /* {{{ ngx_http_unzip_inflate_finish */
+ngx_http_unzip_inflate_finish(ngx_unzip_ctx_t *ctx) {
+ if(ctx->next_content_filter->finish)
+ ctx->next_content_filter->finish(ctx->upload_ctx);
+
+ inflateEnd(&ctx->stream);
+
+ ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
+ "finished inflating file \"%V\"", &ctx->file_name);
+} /* }}} */
+
+static void /* {{{ ngx_http_unzip_inflate_abort */
+ngx_http_unzip_inflate_abort(ngx_unzip_ctx_t *ctx) {
+ if(ctx->next_content_filter->abort)
+ ctx->next_content_filter->abort(ctx->upload_ctx);
+
+ inflateEnd(&ctx->stream);
+
+ ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
+ "aborted inflating file \"%V\"", &ctx->file_name);
+} /* }}} */
+
+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;
+
+ 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)
+ ctx->stream.avail_in = remaining;
+ else
+ ctx->stream.avail_in = ctx->current_field_len - ctx->current_field_pos;
+
+ ctx->stream.next_in = chain->buf->pos;
+
+ do{
+ 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);
+
+ if(rc == Z_OK || rc == Z_STREAM_END) {
+ ctx->output_buffer->last = ctx->stream.next_out;
+
+ if(ctx->next_content_filter->process_chain)
+ ctx->next_content_filter->process_chain(ctx->upload_ctx,
+ ctx->output_chain);
+ }
+
+ if(rc == Z_STREAM_END) {
+ break;
+ }
+
+ if (rc != Z_OK) {
+ ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
+ "inflate() failed: %d", rc);
+ return NGX_ERROR;
+ }
+ }while(ctx->stream.avail_out == 0 && rc == Z_OK);
+
+ ctx->current_field_pos += (ctx->stream.next_in - chain->buf->pos);
+
+ chain->buf->pos = ctx->stream.next_in;
+
+ if(rc == Z_STREAM_END) {
+ break;
+ }
+
+ chain = chain->next;
+ }
+
+ if(ctx->current_field_len - ctx->current_field_pos == 0)
+ return NGX_OK;
+ else
+ return NGX_AGAIN;
+} /* }}} */
+
+static ngx_int_t /* {{{ ngx_http_unzip_retrieve_start */
+ngx_http_unzip_retrieve_start(ngx_unzip_ctx_t *ctx) {
+ ngx_int_t rc;
+
+ rc = ngx_upload_set_file_name(ctx->upload_ctx, &ctx->file_name);
+
+ if(rc != NGX_OK)
+ return rc;
+
+ ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
+ "started retrieving file \"%V\"", &ctx->file_name);
+
+ if(ctx->next_content_filter->start)
+ return ctx->next_content_filter->start(ctx->upload_ctx);
+ else
+ return NGX_OK;
+} /* }}} */
+
+static void /* {{{ ngx_http_unzip_retrieve_finish */
+ngx_http_unzip_retrieve_finish(ngx_unzip_ctx_t *ctx) {
+ if(ctx->next_content_filter->finish)
+ ctx->next_content_filter->finish(ctx->upload_ctx);
+
+ ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
+ "finished retrieving file \"%V\"", &ctx->file_name);
+} /* }}} */
+
+static void /* {{{ ngx_http_unzip_retrieve_abort */
+ngx_http_unzip_retrieve_abort(ngx_unzip_ctx_t *ctx) {
+ if(ctx->next_content_filter->abort)
+ ctx->next_content_filter->abort(ctx->upload_ctx);
+
+ ngx_log_error(NGX_LOG_INFO, ctx->log, 0,
+ "aborted retrieving file \"%V\"", &ctx->file_name);
+} /* }}} */
+
+static ngx_int_t /* {{{ ngx_http_unzip_retrieve_process_chain */
+ngx_http_unzip_retrieve_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
+ ngx_chain_t *cl;
+
+ if(ctx->next_content_filter->process_chain) {
+ for(cl = chain; cl; cl = cl->next)
+ ctx->current_field_pos += (cl->buf->pos - cl->buf->last);
+
+ return ctx->next_content_filter->process_chain(ctx->upload_ctx, chain);
+ }else
+ 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;
+ ngx_int_t rc;
+
+ ngx_str_t archive_path = { file_name->len, file_name->data };
+ ngx_str_t element_name = { file_name->len, file_name->data };
+
+ for(p = file_name->data + file_name->len - 1; p >= file_name->data ; p--, archive_path.len--) {
+ if(*p == '/') {
+ element_name.data = p + 1;
+ element_name.len = file_name->len - (p - file_name->data) - 1;
+
+ goto set;
+ }
+ }
+
+ archive_path.len = 0;
+
+set:
+ rc = ngx_upload_set_file_name(ctx->upload_ctx, &element_name);
+
+ if(rc != NGX_OK) {
+ return rc;
+ }
+
+ rc = ngx_upload_set_archive_path(ctx->upload_ctx, &archive_path);
+
+ if(rc != NGX_OK) {
+ return rc;
+ }
+
+ return NGX_OK;
+} /* }}} */
View
10 ngx_http_upload.h
@@ -82,7 +82,7 @@ typedef struct {
ngx_int_t (*start)(struct ngx_http_upload_ctx_s *upload_ctx);
void (*finish)(struct ngx_http_upload_ctx_s *upload_ctx);
void (*abort)(struct ngx_http_upload_ctx_s *upload_ctx);
- ngx_int_t (*process_buf)(struct ngx_http_upload_ctx_s *upload_ctx, u_char *buf, size_t len);
+ ngx_int_t (*process_chain)(struct ngx_http_upload_ctx_s *upload_ctx, ngx_chain_t *chain);
} ngx_upload_content_filter_t;
/*
@@ -144,15 +144,14 @@ 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_path;
- u_char *output_buffer;
- u_char *output_buffer_end;
- u_char *output_buffer_pos;
+ ngx_buf_t *output_buffer;
ngx_int_t (*start_part_f)(struct ngx_http_upload_ctx_s *upload_ctx);
void (*finish_part_f)(struct ngx_http_upload_ctx_s *upload_ctx);
void (*abort_part_f)(struct ngx_http_upload_ctx_s *upload_ctx);
- ngx_int_t (*flush_output_buffer_f)(struct ngx_http_upload_ctx_s *upload_ctx, u_char *buf, size_t len);
+ ngx_int_t (*process_chain_f)(struct ngx_http_upload_ctx_s *upload_ctx, ngx_chain_t *chain);
ngx_http_request_t *request;
ngx_log_t *log;
@@ -180,6 +179,7 @@ ngx_module_t ngx_http_upload_module;
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);
ngx_upload_content_filter_t*
ngx_upload_get_next_content_filter(ngx_http_upload_ctx_t *ctx);
View
132 ngx_http_upload_module.c
@@ -30,8 +30,8 @@ static ngx_int_t ngx_http_upload_start_handler(ngx_http_upload_ctx_t *u);
static void ngx_http_upload_finish_handler(ngx_http_upload_ctx_t *u);
static void ngx_http_upload_abort_handler(ngx_http_upload_ctx_t *u);
-static ngx_int_t ngx_http_upload_flush_output_buffer(ngx_http_upload_ctx_t *u,
- u_char *buf, size_t len);
+static ngx_int_t ngx_http_upload_process_chain(ngx_http_upload_ctx_t *u,
+ ngx_chain_t *chain);
static ngx_int_t ngx_http_upload_append_field(ngx_http_upload_ctx_t *u,
ngx_str_t *name, ngx_str_t *value);
@@ -137,7 +137,7 @@ static ngx_upload_content_filter_t ngx_write_content_filter = {
ngx_http_upload_start_handler,
ngx_http_upload_finish_handler,
ngx_http_upload_abort_handler,
- ngx_http_upload_flush_output_buffer
+ ngx_http_upload_process_chain
};
static ngx_command_t ngx_http_upload_commands[] = { /* {{{ */
@@ -287,6 +287,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_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 },
+
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
}; /* }}} */
@@ -604,7 +608,7 @@ static ngx_int_t ngx_http_upload_start_handler(ngx_http_upload_ctx_t *u) { /* {{
SHA1_Init(&u->sha1_ctx->sha1);
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0
- , "started uploading file \"%V\" to \"%V\" (field \"%V\", content type \"%V\")"
+ , "started writing file \"%V\" to \"%V\" (field \"%V\", content type \"%V\")"
, &u->file_name
, &u->output_file.name
, &u->field_name
@@ -670,7 +674,7 @@ static void ngx_http_upload_finish_handler(ngx_http_upload_ctx_t *u) { /* {{{ */
ngx_close_file(u->output_file.fd);
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0
- , "finished uploading file \"%V\" to \"%V\""
+ , "finished writing file \"%V\" to \"%V\""
, &u->file_name
, &u->output_file.name
);
@@ -729,12 +733,12 @@ static void ngx_http_upload_abort_handler(ngx_http_upload_ctx_t *u) { /* {{{ */
if(ngx_delete_file(u->output_file.name.data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ERR, u->log, ngx_errno
- , "aborted uploading file \"%V\" to \"%V\", failed to remove destination file"
+ , "aborted writing file \"%V\" to \"%V\", failed to remove destination file"
, &u->file_name
, &u->output_file.name);
} else {
ngx_log_error(NGX_LOG_ALERT, u->log, 0
- , "aborted uploading file \"%V\" to \"%V\", dest file removed"
+ , "aborted writing file \"%V\" to \"%V\", dest file removed"
, &u->file_name
, &u->output_file.name);
}
@@ -750,49 +754,57 @@ static void ngx_http_upload_abort_handler(ngx_http_upload_ctx_t *u) { /* {{{ */
}
} /* }}} */
-static ngx_int_t ngx_http_upload_flush_output_buffer(ngx_http_upload_ctx_t *u, u_char *buf, size_t len) { /* {{{ */
- ngx_http_request_t *r = u->request;
+static ngx_int_t ngx_http_upload_process_chain(ngx_http_upload_ctx_t *u, ngx_chain_t *chain) { /* {{{ */
ngx_buf_t *b;
ngx_chain_t *cl;
if(u->is_file) {
- if(u->md5_ctx)
- MD5Update(&u->md5_ctx->md5, buf, len);
+ if(u->md5_ctx || u->sha1_ctx) {
+ for(cl = chain; cl && !cl->buf->last_in_chain; cl = cl->next) {
+ if(u->md5_ctx)
+ MD5Update(&u->md5_ctx->md5, cl->buf->pos, cl->buf->last - cl->buf->pos);
- if(u->sha1_ctx)
- SHA1_Update(&u->sha1_ctx->sha1, buf, len);
+ if(u->sha1_ctx)
+ SHA1_Update(&u->sha1_ctx->sha1, cl->buf->pos, cl->buf->last - cl->buf->pos);
+ }
+ }
- if(ngx_write_file(&u->output_file, buf, len, u->output_file.offset) == NGX_ERROR) {
- ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
- "write to file \"%V\" failed", &u->output_file.name);
+ if(ngx_write_chain_to_file(&u->output_file, chain, u->output_file.offset,
+ u->request->pool) == NGX_ERROR) {
return NGX_UPLOAD_IOERROR;
- }else
- return NGX_OK;
+ }
+
+ for(cl = chain; cl; cl = cl->next)
+ cl->buf->pos = cl->buf->last;
+
+ return NGX_OK;
}else{
- b = ngx_create_temp_buf(u->request->pool, len);
+ 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);
- 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, buf, len);
+ b->last = ngx_cpymem(b->last, cl->buf->pos, cl->buf->last - cl->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;
+ }
}
return NGX_OK;
@@ -1954,6 +1966,16 @@ ngx_upload_set_file_name(ngx_http_upload_ctx_t *ctx,
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)
{
@@ -1984,15 +2006,18 @@ ngx_upload_set_content_filter(ngx_http_upload_ctx_t *u, ngx_str_t *content_type)
} /* }}} */
static ngx_int_t upload_start_file(ngx_http_upload_ctx_t *upload_ctx) { /* {{{ */
- ngx_str_t exten, content_type;
+ ngx_str_t exten, content_type = ngx_null_string;
ngx_upload_content_filter_t* cflt;
upload_ctx->start_part_f = ngx_http_upload_start_handler;
upload_ctx->finish_part_f = ngx_http_upload_finish_handler;
upload_ctx->abort_part_f = ngx_http_upload_abort_handler;
- upload_ctx->flush_output_buffer_f = ngx_http_upload_flush_output_buffer;
+ upload_ctx->process_chain_f = ngx_http_upload_process_chain;
if(upload_ctx->is_file) {
+ upload_ctx->archive_path.data = NULL;
+ upload_ctx->archive_path.len = 0;
+
ngx_upload_set_exten(upload_ctx, &exten);
ngx_upload_resolve_content_type(upload_ctx, &exten, &content_type);
@@ -2010,7 +2035,7 @@ static ngx_int_t upload_start_file(ngx_http_upload_ctx_t *upload_ctx) { /* {{{ *
upload_ctx->start_part_f = cflt->start;
upload_ctx->finish_part_f = cflt->finish;
upload_ctx->abort_part_f = cflt->abort;
- upload_ctx->flush_output_buffer_f = cflt->process_buf;
+ upload_ctx->process_chain_f = cflt->process_chain;
}
// Call user-defined event handler
@@ -2040,13 +2065,19 @@ 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) { /* {{{ */
- if(upload_ctx->output_buffer_pos > upload_ctx->output_buffer) {
- if(upload_ctx->flush_output_buffer_f)
- if(upload_ctx->flush_output_buffer_f(upload_ctx, (void*)upload_ctx->output_buffer,
- (size_t)(upload_ctx->output_buffer_pos - upload_ctx->output_buffer)) != NGX_OK)
+ ngx_chain_t chain = { upload_ctx->output_buffer, NULL };
+
+ 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) {
upload_ctx->discard_data = 1;
+ }
+ }
- upload_ctx->output_buffer_pos = upload_ctx->output_buffer;
+ upload_ctx->output_buffer->pos = upload_ctx->output_buffer->start;
}
} /* }}} */
@@ -2091,14 +2122,11 @@ ngx_int_t upload_start(ngx_http_upload_ctx_t *upload_ctx, ngx_http_upload_loc_co
upload_ctx->header_accumulator_pos = upload_ctx->header_accumulator;
upload_ctx->header_accumulator_end = upload_ctx->header_accumulator + ulcf->max_header_len;
- upload_ctx->output_buffer = ngx_pcalloc(upload_ctx->request->pool, ulcf->buffer_size);
+ upload_ctx->output_buffer = ngx_create_temp_buf(upload_ctx->request->pool, ulcf->buffer_size);
if(upload_ctx->output_buffer == NULL)
return NGX_ERROR;
- upload_ctx->output_buffer_pos = upload_ctx->output_buffer;
- upload_ctx->output_buffer_end = upload_ctx->output_buffer + ulcf->buffer_size;
-
upload_ctx->header_accumulator_pos = upload_ctx->header_accumulator;
upload_ctx->first_part = 1;
@@ -2172,11 +2200,9 @@ ngx_int_t upload_parse_content_type(ngx_http_upload_ctx_t *upload_ctx, ngx_str_t
void upload_putc(ngx_http_upload_ctx_t *upload_ctx, u_char c) { /* {{{ */
if(!upload_ctx->discard_data) {
- *upload_ctx->output_buffer_pos = c;
-
- upload_ctx->output_buffer_pos++;
+ *upload_ctx->output_buffer->pos++ = c;
- if(upload_ctx->output_buffer_pos == upload_ctx->output_buffer_end)
+ if(upload_ctx->output_buffer->pos == upload_ctx->output_buffer->end)
upload_flush_output_buffer(upload_ctx);
}
} /* }}} */
@@ -2239,7 +2265,7 @@ ngx_int_t upload_process_buf(ngx_http_upload_ctx_t *upload_ctx, u_char *start, u
return rc; // User requested to cancel processing
} else {
upload_ctx->state = upload_state_data;
- upload_ctx->output_buffer_pos = upload_ctx->output_buffer;
+ upload_ctx->output_buffer->pos = upload_ctx->output_buffer->start;
}
} else {
*upload_ctx->header_accumulator_pos = '\0';

0 comments on commit 07406fe

Please sign in to comment.
Something went wrong with that request. Please try again.