25
25
#define ZIP_METHOD_STORED 0
26
26
#define ZIP_METHOD_DEFLATED 8
27
27
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
29
38
30
39
#define ZIP_VERSION 20
31
40
@@ -62,6 +71,7 @@ typedef enum {
62
71
unzip_state_file_name ,
63
72
unzip_state_extra_field ,
64
73
unzip_state_file_data ,
74
+ unzip_state_unlimited_file_data ,
65
75
unzip_state_data_descriptor ,
66
76
unzip_state_decryption_header ,
67
77
unzip_state_extra_data_record ,
@@ -143,7 +153,7 @@ typedef struct ngx_unzip_ctx_s {
143
153
144
154
uint16_t version_needed ;
145
155
uint16_t flags ;
146
- uint16_t compression_method_number ;
156
+ uint16_t compression_method ;
147
157
uint16_t last_mod_time ;
148
158
uint16_t last_mod_date ;
149
159
uint32_t crc32 ;
@@ -163,6 +173,8 @@ typedef struct ngx_unzip_ctx_s {
163
173
ngx_upload_content_filter_t * next_content_filter ;
164
174
ngx_unzip_decompression_method_t * decompression_method ;
165
175
176
+ uint32_t calculated_crc32 ;
177
+
166
178
unsigned int discard_data :1 ;
167
179
} ngx_unzip_ctx_t ;
168
180
@@ -241,27 +253,48 @@ static ngx_command_t ngx_http_unzip_filter_commands[] = { /* {{{ */
241
253
offsetof(ngx_unzip_conf_t , bufs ),
242
254
NULL },
243
255
256
+ /*
257
+ * Specifies size window to use for decompressing
258
+ */
244
259
{ ngx_string ("unzip_window" ),
245
260
NGX_HTTP_LOC_CONF |NGX_CONF_TAKE1 ,
246
261
ngx_conf_set_size_slot ,
247
262
NGX_HTTP_LOC_CONF_OFFSET ,
248
263
offsetof(ngx_unzip_conf_t , wbits ),
249
264
& ngx_http_unzip_window_p },
250
265
266
+ /*
267
+ * Specifies a form field with a special content to generate
268
+ * in output form
269
+ */
251
270
{ ngx_string ("unzip_set_form_field" ),
252
271
NGX_HTTP_LOC_CONF |NGX_CONF_TAKE2 ,
253
272
ngx_conf_set_size_slot ,
254
273
NGX_HTTP_LOC_CONF_OFFSET ,
255
274
offsetof(ngx_unzip_conf_t , wbits ),
256
275
NULL },
257
276
277
+ /*
278
+ * Specifies a form field with a special aggregate content to generate
279
+ * in output form
280
+ */
258
281
{ ngx_string ("unzip_aggregate_form_field" ),
259
282
NGX_HTTP_LOC_CONF |NGX_CONF_TAKE2 ,
260
283
ngx_conf_set_size_slot ,
261
284
NGX_HTTP_LOC_CONF_OFFSET ,
262
285
offsetof(ngx_unzip_conf_t , wbits ),
263
286
NULL },
264
287
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
+
265
298
ngx_null_command
266
299
}; /* }}} */
267
300
@@ -323,10 +356,11 @@ static ngx_int_t /* {{{ ngx_http_unzip_process_chain */
323
356
ngx_http_unzip_process_chain (ngx_unzip_ctx_t * ctx , ngx_chain_t * chain ) {
324
357
ngx_int_t result ;
325
358
ngx_buf_t * buf ;
359
+ ngx_unzip_conf_t * uzcf ;
326
360
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 );
329
362
363
+ while (chain != NULL ) {
330
364
for (buf = chain -> buf ; buf -> pos != buf -> last ; buf -> pos ++ ) {
331
365
switch (ctx -> state ) {
332
366
case unzip_state_signature : /* {{{ */
@@ -375,7 +409,7 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
375
409
376
410
ctx -> version_needed = EXTRACT_SHORT (ctx -> current_field );
377
411
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 );
379
413
ctx -> last_mod_time = EXTRACT_SHORT (ctx -> current_field + 6 );
380
414
ctx -> last_mod_date = EXTRACT_SHORT (ctx -> current_field + 8 );
381
415
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) {
385
419
ctx -> file_name_len = EXTRACT_SHORT (ctx -> current_field + 22 );
386
420
ctx -> extra_field_len = EXTRACT_SHORT (ctx -> current_field + 24 );
387
421
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
+
388
428
if (ngx_http_unzip_set_decompression_method (ctx ,
389
- ctx -> compression_method_number ) != NGX_OK )
429
+ ctx -> compression_method ) != NGX_OK )
390
430
{
391
431
return NGX_UNZIP_MALFORMED ;
392
432
}
393
433
394
434
if (ctx -> version_needed > ZIP_VERSION )
395
435
{
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 );
396
438
return NGX_UNZIP_MALFORMED ;
397
439
}
398
440
399
441
if (ctx -> file_name_len > 0 )
400
442
ctx -> state = unzip_state_file_name ;
401
443
else if (ctx -> extra_field_len > 0 )
402
444
ctx -> state = unzip_state_extra_field ;
445
+ else if (ctx -> flags & ZIP_FLAG_UNLIMITED )
446
+ ctx -> state = unzip_state_unlimited_file_data ;
403
447
else if (ctx -> compressed_size > 0 )
404
448
ctx -> state = unzip_state_file_data ;
405
- else if (ctx -> flags & ZIP_FLAG_HAVE_DATA_DESC )
449
+ else if (ctx -> flags & ZIP_FLAG_UNLIMITED )
406
450
ctx -> state = unzip_state_data_descriptor ;
407
451
else
408
452
ctx -> state = unzip_state_signature ;
@@ -412,7 +456,7 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
412
456
if (ctx -> current_field_pos == 0 ) {
413
457
ctx -> file_name .len = ctx -> file_name_len ;
414
458
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 );
416
460
417
461
if (ctx -> file_name .data == NULL ) {
418
462
return NGX_UPLOAD_NOMEM ;
@@ -428,17 +472,17 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
428
472
if (ctx -> current_field_pos == ctx -> current_field_len ) {
429
473
ctx -> current_field_pos = 0 ;
430
474
431
- * ctx -> current_field_ptr = '\0' ;
432
-
433
475
if (ngx_http_unzip_parse_file_name (ctx , & ctx -> file_name ) != NGX_OK ) {
434
476
return NGX_UNZIP_MALFORMED ;
435
477
}
436
478
437
479
if (ctx -> extra_field_len > 0 )
438
480
ctx -> state = unzip_state_extra_field ;
481
+ else if (ctx -> flags & ZIP_FLAG_UNLIMITED )
482
+ ctx -> state = unzip_state_unlimited_file_data ;
439
483
else if (ctx -> compressed_size > 0 )
440
484
ctx -> state = unzip_state_file_data ;
441
- else if (ctx -> flags & ZIP_FLAG_HAVE_DATA_DESC )
485
+ else if (ctx -> flags & ZIP_FLAG_UNLIMITED )
442
486
ctx -> state = unzip_state_data_descriptor ;
443
487
else
444
488
ctx -> state = unzip_state_signature ;
@@ -454,15 +498,17 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
454
498
if (ctx -> current_field_pos == ctx -> current_field_len ) {
455
499
ctx -> current_field_pos = 0 ;
456
500
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 )
458
504
ctx -> state = unzip_state_file_data ;
459
- else if (ctx -> flags & ZIP_FLAG_HAVE_DATA_DESC )
505
+ else if (ctx -> flags & ZIP_FLAG_UNLIMITED )
460
506
ctx -> state = unzip_state_data_descriptor ;
461
507
else
462
508
ctx -> state = unzip_state_signature ;
463
509
}
464
510
break ;
465
- case unzip_state_file_data :
511
+ case unzip_state_file_data : /* {{{ */
466
512
if (ctx -> current_field_pos == 0 ) {
467
513
ctx -> current_field_len = ctx -> compressed_size ;
468
514
@@ -496,12 +542,43 @@ ngx_http_unzip_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
496
542
497
543
ctx -> current_field_pos = 0 ;
498
544
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
+
500
578
ctx -> state = unzip_state_data_descriptor ;
501
- else
502
- ctx -> state = unzip_state_signature ;
579
+ }
503
580
}
504
- break ;
581
+ break ; /* }}} */
505
582
case unzip_state_data_descriptor :
506
583
if (ctx -> current_field_pos == 0 ) {
507
584
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) {
513
590
514
591
if (ctx -> current_field_pos == ctx -> current_field_len ) {
515
592
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
+
516
598
ctx -> state = unzip_state_signature ;
517
599
}
518
600
break ;
@@ -746,6 +828,8 @@ ngx_http_unzip_inflate_start(ngx_unzip_ctx_t *ctx) {
746
828
return rc ;
747
829
}
748
830
831
+ ngx_crc32_init (ctx -> calculated_crc32 );
832
+
749
833
return NGX_OK ;
750
834
cleanup :
751
835
inflateEnd (& ctx -> stream );
@@ -754,6 +838,8 @@ ngx_http_unzip_inflate_start(ngx_unzip_ctx_t *ctx) {
754
838
755
839
static void /* {{{ ngx_http_unzip_inflate_finish */
756
840
ngx_http_unzip_inflate_finish (ngx_unzip_ctx_t * ctx ) {
841
+ ngx_crc32_final (ctx -> calculated_crc32 );
842
+
757
843
if (ctx -> next_content_filter -> finish )
758
844
ctx -> next_content_filter -> finish (ctx -> upload_ctx );
759
845
@@ -798,6 +884,9 @@ ngx_http_unzip_inflate_process_chain(ngx_unzip_ctx_t *ctx, ngx_chain_t *chain) {
798
884
if (rc == Z_OK || rc == Z_STREAM_END ) {
799
885
ctx -> output_buffer -> last = ctx -> stream .next_out ;
800
886
887
+ ngx_crc32_update (& ctx -> calculated_crc32 , ctx -> output_buffer -> pos ,
888
+ ctx -> output_buffer -> last - ctx -> output_buffer -> pos );
889
+
801
890
if (ctx -> next_content_filter -> process_chain )
802
891
ctx -> next_content_filter -> process_chain (ctx -> upload_ctx ,
803
892
ctx -> output_chain );
@@ -887,6 +976,8 @@ ngx_http_unzip_parse_file_name(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name) {
887
976
888
977
ngx_str_t archive_path = { file_name -> len , file_name -> data };
889
978
ngx_str_t element_name = { file_name -> len , file_name -> data };
979
+ ngx_str_t exten ;
980
+ ngx_str_t content_type ;
890
981
891
982
for (p = file_name -> data + file_name -> len - 1 ; p >= file_name -> data ; p -- , archive_path .len -- ) {
892
983
if (* p == '/' ) {
@@ -906,6 +997,24 @@ ngx_http_unzip_parse_file_name(ngx_unzip_ctx_t *ctx, ngx_str_t *file_name) {
906
997
return rc ;
907
998
}
908
999
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
+
909
1018
rc = ngx_upload_set_archive_path (ctx -> upload_ctx , & archive_path );
910
1019
911
1020
if (rc != NGX_OK ) {
0 commit comments