Skip to content

Commit a378f00

Browse files
committedAug 31, 2008
Merged changes from branch 2.0; added resolution of content type for files in ZIP archive
1 parent 07406fe commit a378f00

File tree

3 files changed

+444
-108
lines changed

3 files changed

+444
-108
lines changed
 

‎ngx_http_unzip_filter_module.c

+127-18
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,16 @@
2525
#define ZIP_METHOD_STORED 0
2626
#define ZIP_METHOD_DEFLATED 8
2727

28-
#define ZIP_FLAG_HAVE_DATA_DESC 0x0008
28+
#define ZIP_FLAG_ENCRYPTED 0x0001
29+
#define ZIP_FLAG_UNLIMITED 0x0008
30+
#define ZIP_FLAG_RESERVED1 0x0010
31+
#define ZIP_FLAG_PATCH 0x0020
32+
#define ZIP_FLAG_STRONG_ENCRYPTION 0x0040
33+
#define ZIP_FLAG_USE_UTF8 0x0800
34+
#define ZIP_FLAG_RESERVED2 0x1000
35+
#define ZIP_FLAG_LOCAL_HEADER_OBFUSCATED 0x2000
36+
#define ZIP_FLAG_RESERVED3 0x4000
37+
#define ZIP_FLAG_RESERVED4 0x8000
2938

3039
#define ZIP_VERSION 20
3140

@@ -62,6 +71,7 @@ typedef enum {
6271
unzip_state_file_name,
6372
unzip_state_extra_field,
6473
unzip_state_file_data,
74+
unzip_state_unlimited_file_data,
6575
unzip_state_data_descriptor,
6676
unzip_state_decryption_header,
6777
unzip_state_extra_data_record,
@@ -143,7 +153,7 @@ typedef struct ngx_unzip_ctx_s {
143153

144154
uint16_t version_needed;
145155
uint16_t flags;
146-
uint16_t compression_method_number;
156+
uint16_t compression_method;
147157
uint16_t last_mod_time;
148158
uint16_t last_mod_date;
149159
uint32_t crc32;
@@ -163,6 +173,8 @@ typedef struct ngx_unzip_ctx_s {
163173
ngx_upload_content_filter_t *next_content_filter;
164174
ngx_unzip_decompression_method_t *decompression_method;
165175

176+
uint32_t calculated_crc32;
177+
166178
unsigned int discard_data:1;
167179
} ngx_unzip_ctx_t;
168180

@@ -241,27 +253,48 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */
241253
offsetof(ngx_unzip_conf_t, bufs),
242254
NULL },
243255

256+
/*
257+
* Specifies size window to use for decompressing
258+
*/
244259
{ ngx_string("unzip_window"),
245260
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
246261
ngx_conf_set_size_slot,
247262
NGX_HTTP_LOC_CONF_OFFSET,
248263
offsetof(ngx_unzip_conf_t, wbits),
249264
&ngx_http_unzip_window_p },
250265

266+
/*
267+
* Specifies a form field with a special content to generate
268+
* in output form
269+
*/
251270
{ ngx_string("unzip_set_form_field"),
252271
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
253272
ngx_conf_set_size_slot,
254273
NGX_HTTP_LOC_CONF_OFFSET,
255274
offsetof(ngx_unzip_conf_t, wbits),
256275
NULL },
257276

277+
/*
278+
* Specifies a form field with a special aggregate content to generate
279+
* in output form
280+
*/
258281
{ ngx_string("unzip_aggregate_form_field"),
259282
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
260283
ngx_conf_set_size_slot,
261284
NGX_HTTP_LOC_CONF_OFFSET,
262285
offsetof(ngx_unzip_conf_t, wbits),
263286
NULL },
264287

288+
/*
289+
* Specifies the maximal length of a file name in archive
290+
*/
291+
{ ngx_string("unzip_max_file_name_len"),
292+
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
293+
ngx_conf_set_size_slot,
294+
NGX_HTTP_LOC_CONF_OFFSET,
295+
offsetof(ngx_unzip_conf_t, max_file_name_len),
296+
NULL },
297+
265298
ngx_null_command
266299
}; /* }}} */
267300

@@ -323,10 +356,11 @@ static ngx_int_t /* {{{ ngx_http_unzip_process_chain */
323356
ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
324357
ngx_int_t result;
325358
ngx_buf_t *buf;
359+
ngx_unzip_conf_t *uzcf;
326360

327-
while(chain != NULL && !chain->buf->last_in_chain) {
328-
buf = chain->buf;
361+
uzcf = ngx_http_get_module_loc_conf(ctx->upload_ctx->request, ngx_http_unzip_filter_module);
329362

363+
while(chain != NULL) {
330364
for(buf = chain->buf ; buf->pos != buf->last ; buf->pos++) {
331365
switch(ctx->state) {
332366
case unzip_state_signature: /* {{{ */
@@ -375,7 +409,7 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
375409

376410
ctx->version_needed = EXTRACT_SHORT(ctx->current_field);
377411
ctx->flags = EXTRACT_SHORT(ctx->current_field + 2);
378-
ctx->compression_method_number = EXTRACT_SHORT(ctx->current_field + 4);
412+
ctx->compression_method = EXTRACT_SHORT(ctx->current_field + 4);
379413
ctx->last_mod_time = EXTRACT_SHORT(ctx->current_field + 6);
380414
ctx->last_mod_date = EXTRACT_SHORT(ctx->current_field + 8);
381415
ctx->crc32 = EXTRACT_LONG(ctx->current_field + 10);
@@ -385,24 +419,34 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
385419
ctx->file_name_len = EXTRACT_SHORT(ctx->current_field + 22);
386420
ctx->extra_field_len = EXTRACT_SHORT(ctx->current_field + 24);
387421

422+
if(uzcf->max_file_name_len > 0 && ctx->file_name_len > uzcf->max_file_name_len) {
423+
ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
424+
"file name in is too long: %u", ctx->file_name_len);
425+
return NGX_UNZIP_MALFORMED;
426+
}
427+
388428
if(ngx_http_unzip_set_decompression_method(ctx,
389-
ctx->compression_method_number) != NGX_OK)
429+
ctx->compression_method) != NGX_OK)
390430
{
391431
return NGX_UNZIP_MALFORMED;
392432
}
393433

394434
if(ctx->version_needed > ZIP_VERSION)
395435
{
436+
ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
437+
"more recent version of unzip implementation required: %u, have %u", ctx->version_needed, ZIP_VERSION);
396438
return NGX_UNZIP_MALFORMED;
397439
}
398440

399441
if(ctx->file_name_len > 0)
400442
ctx->state = unzip_state_file_name;
401443
else if(ctx->extra_field_len > 0)
402444
ctx->state = unzip_state_extra_field;
445+
else if(ctx->flags & ZIP_FLAG_UNLIMITED)
446+
ctx->state = unzip_state_unlimited_file_data;
403447
else if(ctx->compressed_size > 0)
404448
ctx->state = unzip_state_file_data;
405-
else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
449+
else if(ctx->flags & ZIP_FLAG_UNLIMITED)
406450
ctx->state = unzip_state_data_descriptor;
407451
else
408452
ctx->state = unzip_state_signature;
@@ -412,7 +456,7 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
412456
if(ctx->current_field_pos == 0) {
413457
ctx->file_name.len = ctx->file_name_len;
414458

415-
ctx->file_name.data = ngx_palloc(ctx->pool, ctx->file_name_len + 1);
459+
ctx->file_name.data = ngx_palloc(ctx->pool, ctx->file_name_len);
416460

417461
if(ctx->file_name.data == NULL) {
418462
return NGX_UPLOAD_NOMEM;
@@ -428,17 +472,17 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
428472
if(ctx->current_field_pos == ctx->current_field_len) {
429473
ctx->current_field_pos = 0;
430474

431-
*ctx->current_field_ptr = '\0';
432-
433475
if(ngx_http_unzip_parse_file_name(ctx, &ctx->file_name) != NGX_OK) {
434476
return NGX_UNZIP_MALFORMED;
435477
}
436478

437479
if(ctx->extra_field_len > 0)
438480
ctx->state = unzip_state_extra_field;
481+
else if(ctx->flags & ZIP_FLAG_UNLIMITED)
482+
ctx->state = unzip_state_unlimited_file_data;
439483
else if(ctx->compressed_size > 0)
440484
ctx->state = unzip_state_file_data;
441-
else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
485+
else if(ctx->flags & ZIP_FLAG_UNLIMITED)
442486
ctx->state = unzip_state_data_descriptor;
443487
else
444488
ctx->state = unzip_state_signature;
@@ -454,15 +498,17 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
454498
if(ctx->current_field_pos == ctx->current_field_len) {
455499
ctx->current_field_pos = 0;
456500

457-
if(ctx->compressed_size > 0)
501+
if(ctx->flags & ZIP_FLAG_UNLIMITED)
502+
ctx->state = unzip_state_unlimited_file_data;
503+
else if(ctx->compressed_size > 0)
458504
ctx->state = unzip_state_file_data;
459-
else if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
505+
else if(ctx->flags & ZIP_FLAG_UNLIMITED)
460506
ctx->state = unzip_state_data_descriptor;
461507
else
462508
ctx->state = unzip_state_signature;
463509
}
464510
break;
465-
case unzip_state_file_data:
511+
case unzip_state_file_data: /* {{{ */
466512
if(ctx->current_field_pos == 0) {
467513
ctx->current_field_len = ctx->compressed_size;
468514

@@ -496,12 +542,43 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
496542

497543
ctx->current_field_pos = 0;
498544

499-
if(ctx->flags & ZIP_FLAG_HAVE_DATA_DESC)
545+
ctx->state = unzip_state_signature;
546+
}
547+
break; /* }}} */
548+
case unzip_state_unlimited_file_data: /* {{{ */
549+
if(ctx->current_field_pos == 0) {
550+
if(ctx->decompression_method->start(ctx) != NGX_OK) {
551+
ctx->discard_data = 1;
552+
}
553+
554+
ctx->current_field_pos = 1;
555+
}
556+
557+
if(!ctx->discard_data) {
558+
result = ctx->decompression_method->process_chain(ctx, chain);
559+
560+
buf->pos--;
561+
562+
if(result == NGX_AGAIN) {
563+
return NGX_AGAIN;
564+
}
565+
566+
if(result != NGX_OK) {
567+
ctx->discard_data = 1;
568+
569+
ctx->decompression_method->abort(ctx);
570+
571+
return NGX_UNZIP_MALFORMED;
572+
}else{
573+
if(!ctx->discard_data)
574+
ctx->decompression_method->finish(ctx);
575+
576+
ctx->current_field_pos = 0;
577+
500578
ctx->state = unzip_state_data_descriptor;
501-
else
502-
ctx->state = unzip_state_signature;
579+
}
503580
}
504-
break;
581+
break; /* }}} */
505582
case unzip_state_data_descriptor:
506583
if(ctx->current_field_pos == 0) {
507584
ctx->current_field_len = DATA_DESCRIPTOR_LEN;
@@ -513,6 +590,11 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
513590

514591
if(ctx->current_field_pos == ctx->current_field_len) {
515592
ctx->current_field_pos = 0;
593+
594+
ctx->crc32 = EXTRACT_LONG(ctx->current_field);
595+
ctx->compressed_size = EXTRACT_LONG(ctx->current_field + 4);
596+
ctx->uncompressed_size = EXTRACT_LONG(ctx->current_field + 8);
597+
516598
ctx->state = unzip_state_signature;
517599
}
518600
break;
@@ -746,6 +828,8 @@ ngx_http_unzip_inflate_start(ngx_unzip_ctx_t *ctx) {
746828
return rc;
747829
}
748830

831+
ngx_crc32_init(ctx->calculated_crc32);
832+
749833
return NGX_OK;
750834
cleanup:
751835
inflateEnd(&ctx->stream);
@@ -754,6 +838,8 @@ ngx_http_unzip_inflate_start(ngx_unzip_ctx_t *ctx) {
754838

755839
static void /* {{{ ngx_http_unzip_inflate_finish */
756840
ngx_http_unzip_inflate_finish(ngx_unzip_ctx_t *ctx) {
841+
ngx_crc32_final(ctx->calculated_crc32);
842+
757843
if(ctx->next_content_filter->finish)
758844
ctx->next_content_filter->finish(ctx->upload_ctx);
759845

@@ -798,6 +884,9 @@ ngx_http_unzip_inflate_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
798884
if(rc == Z_OK || rc == Z_STREAM_END) {
799885
ctx->output_buffer->last = ctx->stream.next_out;
800886

887+
ngx_crc32_update(&ctx->calculated_crc32, ctx->output_buffer->pos,
888+
ctx->output_buffer->last - ctx->output_buffer->pos);
889+
801890
if(ctx->next_content_filter->process_chain)
802891
ctx->next_content_filter->process_chain(ctx->upload_ctx,
803892
ctx->output_chain);
@@ -887,6 +976,8 @@ ngx_http_unzip_parse_file_name(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name) {
887976

888977
ngx_str_t archive_path = { file_name->len, file_name->data };
889978
ngx_str_t element_name = { file_name->len, file_name->data };
979+
ngx_str_t exten;
980+
ngx_str_t content_type;
890981

891982
for(p = file_name->data + file_name->len - 1; p >= file_name->data ; p--, archive_path.len--) {
892983
if(*p == '/') {
@@ -906,6 +997,24 @@ ngx_http_unzip_parse_file_name(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name) {
906997
return rc;
907998
}
908999

1000+
rc = ngx_upload_set_exten(ctx->upload_ctx, &element_name, &exten);
1001+
1002+
if(rc != NGX_OK) {
1003+
return rc;
1004+
}
1005+
1006+
rc = ngx_upload_resolve_content_type(ctx->upload_ctx, &exten, &content_type);
1007+
1008+
if(rc != NGX_OK) {
1009+
return rc;
1010+
}
1011+
1012+
rc = ngx_upload_set_content_type(ctx->upload_ctx, &content_type);
1013+
1014+
if(rc != NGX_OK) {
1015+
return rc;
1016+
}
1017+
9091018
rc = ngx_upload_set_archive_path(ctx->upload_ctx, &archive_path);
9101019

9111020
if(rc != NGX_OK) {

‎ngx_http_upload.h

+18
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ typedef struct {
9595
struct ngx_http_upload_loc_conf_s *conf;
9696
} ngx_upload_content_type_map_t;
9797

98+
/*
99+
* Upload cleanup record
100+
*/
101+
typedef struct ngx_http_upload_cleanup_s {
102+
ngx_fd_t fd;
103+
u_char *filename;
104+
ngx_http_headers_out_t *headers_out;
105+
ngx_array_t *cleanup_statuses;
106+
ngx_log_t *log;
107+
unsigned int aborted:1;
108+
} ngx_upload_cleanup_t;
109+
98110
/*
99111
* Upload configuration for specific location
100112
*/
@@ -109,12 +121,14 @@ typedef struct ngx_http_upload_loc_conf_s {
109121
ngx_array_t *field_templates;
110122
ngx_array_t *aggregate_field_templates;
111123
ngx_array_t *field_filters;
124+
ngx_array_t *cleanup_statuses;
112125

113126
ngx_array_t *content_filters;
114127
ngx_array_t *content_type_map;
115128

116129
unsigned int md5:1;
117130
unsigned int sha1:1;
131+
unsigned int crc32:1;
118132
} ngx_http_upload_loc_conf_t;
119133

120134
typedef struct ngx_http_upload_md5_ctx_s {
@@ -166,17 +180,21 @@ typedef struct ngx_http_upload_ctx_s {
166180

167181
ngx_http_upload_md5_ctx_t *md5_ctx;
168182
ngx_http_upload_sha1_ctx_t *sha1_ctx;
183+
uint32_t crc32;
169184

170185
ngx_array_t *current_content_filter_chain;
171186
ngx_uint_t current_content_filter_idx;
172187

173188
unsigned int first_part:1;
174189
unsigned int discard_data:1;
175190
unsigned int is_file:1;
191+
unsigned int calculate_crc32:1;
176192
} ngx_http_upload_ctx_t;
177193

178194
ngx_module_t ngx_http_upload_module;
179195

196+
ngx_int_t ngx_upload_set_exten(ngx_http_upload_ctx_t *u, ngx_str_t *file_name, ngx_str_t *exten);
197+
ngx_int_t ngx_upload_resolve_content_type(ngx_http_upload_ctx_t *u, ngx_str_t *exten, ngx_str_t *content_type);
180198
ngx_int_t ngx_upload_set_file_name(ngx_http_upload_ctx_t *ctx, ngx_str_t *file_name);
181199
ngx_int_t ngx_upload_set_content_type(ngx_http_upload_ctx_t *ctx, ngx_str_t *content_type);
182200
ngx_int_t ngx_upload_set_archive_path(ngx_http_upload_ctx_t *ctx, ngx_str_t *archive_path);

0 commit comments

Comments
 (0)
Please sign in to comment.