Ver código fonte

* Added connections cleanup timer

This timer help us track finished connections and still report the status to progress probe.

* Added header filter to track 413 errors (not working atm)
tags/v0.3
Brice Figureau 18 anos atrás
pai
commit
e9ccdcd75c
1 arquivos alterados com 369 adições e 173 exclusões
  1. 369
    173
      ngx_http_uploadprogress_module.c

+ 369
- 173
ngx_http_uploadprogress_module.c Ver arquivo

@@ -7,13 +7,18 @@
7 7
 #include <ngx_core.h>
8 8
 #include <ngx_http.h>
9 9
 
10
-typedef struct {
11
-    u_char              color;
10
+typedef struct ngx_http_uploadprogress_node_s ngx_http_uploadprogress_node_t;
11
+
12
+struct ngx_http_uploadprogress_node_s {
13
+		ngx_rbtree_node_t   node;
12 14
  		ngx_http_request_t *r;
15
+		ngx_uint_t					err_status;
16
+		time_t							timeout;
17
+    struct ngx_http_uploadprogress_node_s  *prev;
18
+    struct ngx_http_uploadprogress_node_s  *next;
13 19
     u_char              len;
14 20
     u_char              data[1];
15
-} ngx_http_uploadprogress_node_t;
16
-
21
+};
17 22
 
18 23
 typedef struct {
19 24
     ngx_shm_zone_t     *shm_zone;
@@ -22,14 +27,16 @@ typedef struct {
22 27
 
23 28
 typedef struct {
24 29
     ngx_rbtree_t       *rbtree;
30
+    ngx_http_uploadprogress_node_t   list_head;
31
+    ngx_http_uploadprogress_node_t   list_tail;
25 32
 } ngx_http_uploadprogress_ctx_t;
26 33
 
27 34
 typedef struct {
28 35
     ngx_shm_zone_t     *shm_zone;
29 36
 		u_char							track;
37
+		ngx_event_t					cleanup;
30 38
 } ngx_http_uploadprogress_conf_t;
31 39
 
32
-static ngx_int_t ngx_http_reportuploads_handler(ngx_http_request_t *r);
33 40
 static ngx_int_t ngx_http_reportuploads_handler(ngx_http_request_t *r);
34 41
 static void ngx_http_uploadprogress_cleanup(void *data);
35 42
 static char *ngx_http_report_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
@@ -40,6 +47,9 @@ static char *ngx_http_uploadprogress_merge_loc_conf(ngx_conf_t *cf, void *parent
40 47
 static char *ngx_http_track_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
41 48
 static char *ngx_http_report_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
42 49
 static char *ngx_http_upload_progress(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
50
+static void ngx_clean_old_connections(ngx_event_t *ev);
51
+
52
+static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
43 53
 
44 54
 static ngx_command_t  ngx_http_uploadprogress_commands[] = {
45 55
 
@@ -155,6 +165,57 @@ get_tracking_id(ngx_http_request_t *r)
155 165
 	return NULL;
156 166
 }
157 167
 
168
+static ngx_http_uploadprogress_node_t*
169
+find_node(ngx_str_t *id, ngx_http_uploadprogress_ctx_t *ctx, ngx_log_t *log)
170
+{
171
+  uint32_t                        hash;
172
+  ngx_rbtree_node_t              *node, *sentinel;
173
+	ngx_int_t                       rc;
174
+	ngx_http_uploadprogress_node_t *up;
175
+	
176
+  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
177
+                 "upload-progress: find_node %V", id);	
178
+	
179
+	hash = ngx_crc32_short(id->data, id->len);
180
+	
181
+  node = ctx->rbtree->root;
182
+  sentinel = ctx->rbtree->sentinel;
183
+
184
+  while (node != sentinel) {
185
+
186
+      if (hash < node->key) {
187
+          node = node->left;
188
+          continue;
189
+      }
190
+
191
+      if (hash > node->key) {
192
+          node = node->right;
193
+          continue;
194
+      }
195
+
196
+      /* hash == node->key */
197
+
198
+      do {
199
+          up = (ngx_http_uploadprogress_node_t *) node;
200
+
201
+          rc = ngx_memn2cmp(id->data, up->data, id->len, (size_t) up->len);
202
+
203
+          if (rc == 0) {
204
+					  	ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0,
205
+					                 "upload-progress: found node");	
206
+              return up;
207
+          }
208
+
209
+          node = (rc < 0) ? node->left : node->right;
210
+
211
+      } while (node != sentinel && hash == node->key);
212
+
213
+      break;
214
+  }
215
+	ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0,
216
+               "upload-progress: can't find node");	
217
+	return NULL;
218
+}
158 219
 
159 220
 /* This generates the response for the report */
160 221
 static ngx_int_t
@@ -164,13 +225,12 @@ ngx_http_reportuploads_handler(ngx_http_request_t *r)
164 225
   ngx_buf_t    *b;
165 226
   ngx_chain_t   out;
166 227
 	ngx_http_request_t								 *orig;
167
-  ngx_int_t                       rc, size;
168
-  uint32_t                        hash;
228
+	ngx_int_t                       rc, size; 
229
+		ngx_uint_t										len, i;
169 230
   ngx_slab_pool_t                *shpool;
170
-  ngx_rbtree_node_t              *node, *sentinel;
171
-	ngx_http_uploadprogress_conf_t     *lzcf;
231
+	ngx_http_uploadprogress_conf_t     *upcf;
172 232
   ngx_http_uploadprogress_ctx_t      *ctx;
173
-  ngx_http_uploadprogress_node_t     *lz;
233
+  ngx_http_uploadprogress_node_t     *up;
174 234
   ngx_table_elt_t  *expires, *cc, **ccp;
175 235
 
176 236
   if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
@@ -197,90 +257,41 @@ ngx_http_reportuploads_handler(ngx_http_request_t *r)
197 257
   ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
198 258
                  "reportuploads handler found id: %V", id);
199 259
 
200
-  lzcf = ngx_http_get_module_loc_conf(r, ngx_http_uploadprogress_module);
260
+  upcf = ngx_http_get_module_loc_conf(r, ngx_http_uploadprogress_module);
201 261
 
202
-  if (lzcf->shm_zone == NULL) {
262
+  if (upcf->shm_zone == NULL) {
203 263
 	  	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
204 264
 	                 "reportuploads no shm_zone for id: %V", id);
205 265
       return NGX_DECLINED;
206 266
   }
207 267
 
208 268
 	orig = NULL;
209
-  ctx = lzcf->shm_zone->data;
210
-	
211
-  hash = ngx_crc32_short(id->data, id->len);
212
-
213
-	ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
214
-               "reportuploads trying to find block with hash %08XD for id: %V", hash, id);
269
+  ctx = upcf->shm_zone->data;
215 270
 
216 271
 	/* get the original connection of the upload */
217
-  shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr;
218
-  ngx_shmtx_lock(&shpool->mutex);
219
-
220
-	ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
221
-               "reportuploads in mutex lock for hash %08XD for id: %V", hash, id);
272
+  shpool = (ngx_slab_pool_t *) upcf->shm_zone->shm.addr;
222 273
 
223
-  node = ctx->rbtree->root;
224
-  sentinel = ctx->rbtree->sentinel;
274
+	ngx_shmtx_lock(&shpool->mutex);
225 275
 
226
-	ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
227
-               "reportuploads root %p, sentinel %p for id: %V", node,sentinel, id);
228
-
229
-  while (node != sentinel) {
230
-
231
-      if (hash < node->key) {
232
-          node = node->left;
233
-          continue;
234
-      }
235
-
236
-      if (hash > node->key) {
237
-          node = node->right;
238
-          continue;
239
-      }
240
-
241
-			ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
242
-		               "reportuploads found matching hash %08XD, node %p for id: %V", hash, node, id);
243
-
244
-      /* hash == node->key */
245
-
246
-      do {
247
-          lz = (ngx_http_uploadprogress_node_t *) &node->color;
248
-
249
-          rc = ngx_memn2cmp(id->data, lz->data, id->len, (size_t) lz->len);
250
-
251
-          if (rc == 0) {
252
-						/* found the right one */
253
-						/* lz contains the right node*/
254
-						ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
255
-					               "reportuploads found request: %p", lz->r);
256
-						orig = lz->r;
257
-						goto found;
258
-          }
259
-
260
-					ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
261
-				               "reportuploads oops not the same : lz %V != id %V", lz, id);
262
-
263
-
264
-          node = (rc < 0) ? node->left : node->right;
265
-
266
-      } while (node != sentinel && hash == node->key);
267
-
268
-			lz = NULL;
269
-			
270
-			/* couldn't find one */
271
-			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
272
-		               "reportuploads not matching request");
273
-  }
274
-
275
-found:
276
+ 	up = find_node(id, ctx, r->connection->log);
277
+  if (up != NULL)
278
+  {
279
+	  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
280
+	                 "reportuploads found node: %V", id);
281
+		orig = up->r;
282
+	}
283
+	else
284
+	{
285
+	  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
286
+	                 "reportuploads not found: %V", id);		
287
+	}
276 288
 	ngx_shmtx_unlock(&shpool->mutex);
277 289
 
278 290
 	/* send the output */
279 291
   r->headers_out.content_type.len = sizeof("text/javascript") - 1;
280 292
   r->headers_out.content_type.data = (u_char *) "text/javascript";
281 293
 
282
-	/* no-cache */
283
-
294
+	/* force no-cache */
284 295
   expires = r->headers_out.expires;
285 296
 
286 297
   if (expires == NULL) {
@@ -352,16 +363,20 @@ found:
352 363
 
353 364
 	if ( orig == NULL )
354 365
 	{
355
-		if (lz != NULL )
366
+		if (up != NULL && up->err_status != NGX_HTTP_REQUEST_ENTITY_TOO_LARGE )
356 367
 		{
357 368
 			size = sizeof("new Object({ 'state' : 'done' })\r\n");
358 369
   	}
370
+		else if ( up != NULL && up->err_status == NGX_HTTP_REQUEST_ENTITY_TOO_LARGE )
371
+		{
372
+			size = sizeof("new Object({ 'state' : 'error', 'status' : 413 })\r\n");			
373
+		}
359 374
 		else
360 375
 		{
361 376
 			size = sizeof("new Object({ 'state' : 'starting' })\r\n");
362 377
   	}
363 378
 	}
364
-	else if ( orig->err_status == 413)
379
+	else if ( orig->err_status == NGX_HTTP_REQUEST_ENTITY_TOO_LARGE )
365 380
 	{
366 381
 		size = sizeof("new Object({ 'state' : 'error', 'status' : 413 })\r\n");
367 382
 	}
@@ -381,13 +396,20 @@ found:
381 396
 	
382 397
 	if (orig == NULL)
383 398
 	{
384
-		if (lz == NULL )
399
+		if (up == NULL )
385 400
 		{
386 401
 			b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'starting' })\r\n",
387 402
 		                       sizeof("new Object({ 'state' : 'starting' })\r\n") - 1);
388 403
 			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
389 404
 											               "reportuploads returning starting");
390 405
 		}
406
+		else if ( up != NULL && up->err_status == NGX_HTTP_REQUEST_ENTITY_TOO_LARGE )
407
+		{
408
+			b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'error', 'status' : 413 })\r\n",
409
+		                       sizeof("new Object({ 'state' : 'error', 'status' : 413 })\r\n") - 1);
410
+			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
411
+		               "reportuploads returning error 413");			
412
+		}
391 413
 		else 
392 414
 		{
393 415
 			b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'done' })\r\n",
@@ -396,7 +418,7 @@ found:
396 418
 		               "reportuploads returning done");
397 419
 		}
398 420
 	}
399
-	else if ( orig->err_status == 413)
421
+	else if ( orig->err_status == NGX_HTTP_REQUEST_ENTITY_TOO_LARGE)
400 422
 	{
401 423
 		b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'error', 'status' : 413 })\r\n",
402 424
 	                       sizeof("new Object({ 'state' : 'error', 'status' : 413 })\r\n") - 1);
@@ -415,9 +437,6 @@ found:
415 437
 
416 438
 	}
417 439
 
418
-	// force no caching for proxy
419
-	
420
-
421 440
 	r->headers_out.status = NGX_HTTP_OK;
422 441
 	r->headers_out.content_length_n = b->last - b->pos;
423 442
 
@@ -432,23 +451,27 @@ found:
432 451
 }
433 452
 
434 453
 /* 
435
-This is the post read phase. It registers the upload connection in the rb tree
454
+Let's register the upload connection in our connections rb-tree
436 455
 */
437 456
 static ngx_int_t
438 457
 ngx_http_uploadprogress_handler(ngx_http_request_t *r)
439 458
 {
440 459
   size_t                          n;
441 460
 	ngx_str_t 												 *id;
442
-  ngx_int_t                       rc;
443 461
   uint32_t                        hash;
444 462
   ngx_slab_pool_t                *shpool;
445
-  ngx_rbtree_node_t              *node, *sentinel;
446
-	ngx_http_uploadprogress_conf_t     *lzcf;
463
+  ngx_rbtree_node_t              *node;
464
+	ngx_http_uploadprogress_conf_t     *upcf;
447 465
   ngx_http_uploadprogress_ctx_t      *ctx;
448
-  ngx_http_uploadprogress_node_t     *lz;
449
-	ngx_http_uploadprogress_cleanup_t	 *lzcln;
466
+  ngx_http_uploadprogress_node_t     *up;
467
+	ngx_http_uploadprogress_cleanup_t	 *upcln;
450 468
   ngx_pool_cleanup_t             *cln;
451 469
 
470
+	/* Is it a POST connection */
471
+	if (r->method != NGX_HTTP_POST) {
472
+		return NGX_DECLINED;
473
+	}
474
+
452 475
 	id = get_tracking_id(r);
453 476
 	if ( id == NULL )
454 477
 	{
@@ -460,76 +483,48 @@ ngx_http_uploadprogress_handler(ngx_http_request_t *r)
460 483
 	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
461 484
            "trackuploads id found: %V", id);
462 485
 
463
-  lzcf = ngx_http_get_module_loc_conf(r, ngx_http_uploadprogress_module);
486
+  upcf = ngx_http_get_module_loc_conf(r, ngx_http_uploadprogress_module);
464 487
 
465
-  if (!lzcf->track) {
488
+  if (!upcf->track) {
466 489
 	  	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
467 490
 	                 "trackuploads not tracking in this location for id: %V", id);
468 491
       return NGX_DECLINED;
469 492
   }
470 493
 
471
-  if (lzcf->shm_zone == NULL) {
494
+  if (upcf->shm_zone == NULL) {
472 495
   	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
473 496
                  "trackuploads no shm_zone for id: %V", id);
474 497
       return NGX_DECLINED;
475 498
   }
476 499
 
477
-  ctx = lzcf->shm_zone->data;
500
+  ctx = upcf->shm_zone->data;
478 501
 	
479 502
   hash = ngx_crc32_short(id->data, id->len);
480 503
 
481 504
 	ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
482 505
                "trackuploads hash %08XD for id: %V",hash, id);
483 506
 
484
-  cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_uploadprogress_cleanup_t));
485
-  if (cln == NULL) {
486
-      return NGX_HTTP_INTERNAL_SERVER_ERROR;
487
-  }
488
-
489
-  shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr;
507
+  shpool = (ngx_slab_pool_t *) upcf->shm_zone->shm.addr;
490 508
 
491 509
   ngx_shmtx_lock(&shpool->mutex);
492 510
 
493
-  node = ctx->rbtree->root;
494
-  sentinel = ctx->rbtree->sentinel;
495
-
496
-  while (node != sentinel) {
497
-
498
-      if (hash < node->key) {
499
-          node = node->left;
500
-          continue;
501
-      }
502
-
503
-      if (hash > node->key) {
504
-          node = node->right;
505
-          continue;
506
-      }
507
-
508
-      /* hash == node->key */
509
-
510
-      do {
511
-          lz = (ngx_http_uploadprogress_node_t *) &node->color;
512
-
513
-          rc = ngx_memn2cmp(id->data, lz->data, id->len, (size_t) lz->len);
514
-
515
-          if (rc == 0) {
516
-							ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
517
-					               "trackuploads already registered: %V",id);
518
-							/* oops found already one */
519
-              ngx_shmtx_unlock(&shpool->mutex);
520
-
521
-              return NGX_HTTP_SERVICE_UNAVAILABLE;
522
-          }
523
-
524
-          node = (rc < 0) ? node->left : node->right;
525
-
526
-      } while (node != sentinel && hash == node->key);
511
+	if ( find_node(id, ctx, r->connection->log) != NULL )
512
+	{
513
+  	ngx_shmtx_unlock(&shpool->mutex);
514
+		/* already found a node with matching progress ID */
515
+		ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
516
+                  "upload_progress: tracking already registered id: %V", id);
517
+    
518
+		return NGX_HTTP_INTERNAL_SERVER_ERROR;
519
+	}
527 520
 
528
-      break;
521
+  cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_uploadprogress_cleanup_t));
522
+  if (cln == NULL) {
523
+    	ngx_shmtx_unlock(&shpool->mutex);
524
+      return NGX_HTTP_INTERNAL_SERVER_ERROR;
529 525
   }
530 526
 
531
-  n = offsetof(ngx_rbtree_node_t, color)
532
-      + offsetof(ngx_http_uploadprogress_node_t, data)
527
+  n = sizeof(ngx_http_uploadprogress_node_t)
533 528
       + id->len;
534 529
 
535 530
   node = ngx_slab_alloc_locked(shpool, n);
@@ -538,24 +533,40 @@ ngx_http_uploadprogress_handler(ngx_http_request_t *r)
538 533
       return NGX_HTTP_SERVICE_UNAVAILABLE;
539 534
   }
540 535
 
541
-  lz = (ngx_http_uploadprogress_node_t *) &node->color;
536
+  up = (ngx_http_uploadprogress_node_t *)node;
542 537
 
543 538
   node->key = hash;
544
-  lz->len = (u_char) id->len;
545
-	lz->r = r;
546
-  ngx_memcpy(lz->data, id->data, id->len);
539
+  up->len = (u_char) id->len;
540
+	up->r = r;
541
+	up->err_status = r->err_status;
542
+	
543
+  up->next = ctx->list_head.next;
544
+	up->next->prev = up;
545
+  up->prev = &ctx->list_head;
546
+  ctx->list_head.next = up;
547
+		
548
+  ngx_memcpy(up->data, id->data, id->len);
547 549
 
548 550
   ngx_rbtree_insert(ctx->rbtree, node);
549 551
   ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
550
-                 "trackuploads: %08XD", node->key);
552
+                 "trackuploads: %08XD inserted in rbtree", node->key);
551 553
 
552 554
   ngx_shmtx_unlock(&shpool->mutex);
553 555
 
554 556
   cln->handler = ngx_http_uploadprogress_cleanup;
555
-  lzcln = cln->data;
557
+  upcln = cln->data;
558
+
559
+  upcln->shm_zone = upcf->shm_zone;
560
+  upcln->node = node;
556 561
 
557
-  lzcln->shm_zone = lzcf->shm_zone;
558
-  lzcln->node = node;
562
+	/* start the timer if needed */
563
+	if ( !upcf->cleanup.timer_set)
564
+	{
565
+		upcf->cleanup.data = upcf->shm_zone;
566
+		upcf->cleanup.handler = ngx_clean_old_connections;
567
+		upcf->cleanup.log = r->connection->log;
568
+		ngx_add_timer(&upcf->cleanup, 60 * 1000);
569
+	}
559 570
 
560 571
   return NGX_DECLINED;
561 572
 }
@@ -564,7 +575,7 @@ static void
564 575
 ngx_http_uploadprogress_rbtree_insert_value(ngx_rbtree_node_t *temp,
565 576
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
566 577
 {
567
-    ngx_http_uploadprogress_node_t  *lzn, *lznt;
578
+    ngx_http_uploadprogress_node_t  *upn, *upnt;
568 579
 
569 580
     for ( ;; ) {
570 581
 
@@ -588,10 +599,10 @@ ngx_http_uploadprogress_rbtree_insert_value(ngx_rbtree_node_t *temp,
588 599
 
589 600
         } else { /* node->key == temp->key */
590 601
 
591
-            lzn = (ngx_http_uploadprogress_node_t *) &node->color;
592
-            lznt = (ngx_http_uploadprogress_node_t *) &temp->color;
602
+            upn = (ngx_http_uploadprogress_node_t *) node;
603
+            upnt = (ngx_http_uploadprogress_node_t *) temp;
593 604
 
594
-            if (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) {
605
+            if (ngx_memn2cmp(upn->data, upnt->data, upn->len, upnt->len) < 0) {
595 606
 
596 607
                 if (temp->left == sentinel) {
597 608
                     temp->left = node;
@@ -618,37 +629,89 @@ ngx_http_uploadprogress_rbtree_insert_value(ngx_rbtree_node_t *temp,
618 629
     ngx_rbt_red(node);
619 630
 }
620 631
 
632
+
633
+static void
634
+ngx_clean_old_connections(ngx_event_t *ev)
635
+{
636
+  ngx_shm_zone_t             *shm_zone;
637
+  ngx_http_uploadprogress_ctx_t  *ctx;
638
+  ngx_slab_pool_t                *shpool;
639
+  ngx_rbtree_node_t              *node;
640
+	ngx_http_uploadprogress_node_t	*up;
641
+	time_t	now = ngx_time();
642
+
643
+	
644
+	/* scan the rbtree */
645
+	shm_zone = ev->data; 
646
+	ctx = shm_zone->data;
647
+  shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
648
+
649
+	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0,
650
+           "uploadprogress clean old connections at %T", now);
651
+
652
+  ngx_shmtx_lock(&shpool->mutex);
653
+  node = (ngx_rbtree_node_t *)ctx->list_tail.prev;
654
+  for ( ;; ) {
655
+
656
+
657
+      if (node == &ctx->list_head.node) {
658
+          break;
659
+      }
660
+			
661
+			up = (ngx_http_uploadprogress_node_t *)node;
662
+
663
+			ngx_log_debug3(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0,
664
+		           "uploadprogress clean: scanning %08XD (req %p) timeout at %T", node->key, up->r, up->timeout);
665
+
666
+			if ( up->r == NULL && up->timeout < now )
667
+			{
668
+	      up->next->prev = up->prev;
669
+	      up->prev->next = up->next;
670
+
671
+				ngx_log_debug3(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0,
672
+			           "uploadprogress clean: removing %08XD (req %p) ", node->key, up->r, up->timeout);
673
+
674
+				ngx_rbtree_delete(ctx->rbtree, node);
675
+				ngx_slab_free_locked(shpool, node);
676
+			}
677
+			
678
+			node = (ngx_rbtree_node_t *)up->prev;
679
+		}
680
+	  ngx_shmtx_unlock(&shpool->mutex);
681
+		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0,
682
+	           "uploadprogress clean old connections restarting timer");
683
+
684
+	ngx_add_timer(ev, 60 * 1000); /* trigger again in 60s */
685
+}
686
+
687
+
688
+
621 689
 /*
622 690
 removes the expired node from the upload rbtree
623 691
 */
624 692
 static void
625 693
 ngx_http_uploadprogress_cleanup(void *data)
626 694
 {
627
-    ngx_http_uploadprogress_cleanup_t  *lzcln = data;
628
-
629
-    ngx_slab_pool_t             *shpool;
630
-    ngx_rbtree_node_t           *node;
695
+    ngx_http_uploadprogress_cleanup_t  *upcln = data;
696
+	  ngx_slab_pool_t             *shpool;
697
+	  ngx_rbtree_node_t           *node;
631 698
     ngx_http_uploadprogress_ctx_t   *ctx;
632
-    ngx_http_uploadprogress_node_t  *lz;
699
+    ngx_http_uploadprogress_node_t  *up;
633 700
 
634
-		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0,
701
+		ngx_log_debug0(NGX_LOG_DEBUG_HTTP, upcln->shm_zone->shm.log, 0,
635 702
 	           "uploadprogress cleanup called");
636 703
 
637
-    ctx = lzcln->shm_zone->data;
638
-    shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr;
639
-    node = lzcln->node;
640
-    lz = (ngx_http_uploadprogress_node_t *) &node->color;
704
+    ctx = upcln->shm_zone->data;
705
+    shpool = (ngx_slab_pool_t *) upcln->shm_zone->shm.addr;
706
+    node = upcln->node;
707
+    up = (ngx_http_uploadprogress_node_t *) node;
641 708
 
642
-    ngx_shmtx_lock(&shpool->mutex);
709
+		up->r = NULL; /* mark the original request as done */
710
+		up->timeout = ngx_time() + 60; /* keep tracking for 60s */
643 711
 
644
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0,
645
-                   "upload progress cleanup: %08XD", node->key);
646
-
647
-    ngx_rbtree_delete(ctx->rbtree, node);
648
-    ngx_slab_free_locked(shpool, node);
649
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0,
650
-			"upload progress cleanup node removed: %08XD", node->key);
651
-    ngx_shmtx_unlock(&shpool->mutex);
712
+		ngx_log_debug2(NGX_LOG_DEBUG_HTTP, upcln->shm_zone->shm.log, 0,
713
+	           "uploadprogress cleanup: connection %08XD to be deleted at %T", node->key, up->timeout);
714
+		
652 715
 }
653 716
 
654 717
 static ngx_int_t
@@ -688,6 +751,119 @@ ngx_http_uploadprogress_init_zone(ngx_shm_zone_t *shm_zone, void *data)
688 751
     return NGX_OK;
689 752
 }
690 753
 
754
+static ngx_int_t
755
+ngx_http_uploadprogress_errortracker(ngx_http_request_t *r)
756
+{
757
+  	size_t                          n;
758
+		ngx_str_t 										 *id;
759
+  	ngx_slab_pool_t                *shpool;
760
+  	ngx_rbtree_node_t              *node;
761
+  	ngx_http_uploadprogress_ctx_t      *ctx;
762
+  	ngx_http_uploadprogress_node_t     *up;
763
+    ngx_http_uploadprogress_conf_t	  *upcf;
764
+	  uint32_t                        hash;
765
+		ngx_http_uploadprogress_cleanup_t	 *upcln;
766
+	  ngx_pool_cleanup_t             *cln;
767
+
768
+		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
769
+	           "uploadprogress error-tracker error: %D", r->err_status);
770
+		if ( r->err_status == NGX_HTTP_REQUEST_ENTITY_TOO_LARGE )
771
+		{
772
+
773
+    	upcf = ngx_http_get_module_loc_conf(r, ngx_http_uploadprogress_module);
774
+
775
+		  if (!upcf->track) {
776
+			  	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
777
+			                 "uploadprogress error-tracker not tracking in this location for id: %V", id);
778
+		    goto finish;
779
+		  }
780
+
781
+			id = get_tracking_id(r);
782
+			if ( id == NULL )
783
+			{
784
+				ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
785
+		             "trackuploads error-tracker no id found in POST upload req");
786
+				goto finish;
787
+			}
788
+
789
+			ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
790
+		           "trackuploads error-tracker id found: %V", id);
791
+
792
+
793
+		  if (upcf->shm_zone == NULL) {
794
+		  	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
795
+		                 "trackuploads no shm_zone for id: %V", id);
796
+									goto finish;
797
+		  }
798
+
799
+		  ctx = upcf->shm_zone->data;
800
+
801
+		  hash = ngx_crc32_short(id->data, id->len);
802
+
803
+			ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
804
+		               "trackuploads error-tracking hash %08XD for id: %V",hash, id);
805
+
806
+		  shpool = (ngx_slab_pool_t *) upcf->shm_zone->shm.addr;
807
+
808
+		  ngx_shmtx_lock(&shpool->mutex);
809
+
810
+			if ( (up = find_node(id, ctx, r->connection->log)) != NULL )
811
+			{
812
+				ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
813
+			               "trackuploads error-tracking found node for id: %V", id);
814
+				up->r = NULL; /* don't really track it since it errors */
815
+				up->err_status = r->err_status;
816
+				goto finish;
817
+			}
818
+
819
+			/* no lz found for this tracking id */
820
+		  n = sizeof(ngx_http_uploadprogress_node_t)
821
+		      + id->len;
822
+
823
+			  cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_uploadprogress_cleanup_t));
824
+			  if (cln == NULL) {
825
+					goto finish;
826
+			  }
827
+
828
+
829
+		  node = ngx_slab_alloc_locked(shpool, n);
830
+		  if (node == NULL) {
831
+		      ngx_shmtx_unlock(&shpool->mutex);
832
+					goto finish;
833
+		  }
834
+
835
+		  up = (ngx_http_uploadprogress_node_t *) node;
836
+
837
+		  node->key = hash;
838
+		  up->len = (u_char) id->len;
839
+			up->r = NULL; /* don't really track it since it errors */
840
+			up->err_status = r->err_status;
841
+		  ngx_memcpy(up->data, id->data, id->len);
842
+
843
+		  up->next = ctx->list_head.next;
844
+			up->next->prev = up;
845
+		  up->prev = &ctx->list_head;
846
+		  ctx->list_head.next = up;
847
+
848
+		  ngx_rbtree_insert(ctx->rbtree, node);
849
+
850
+		  ngx_shmtx_unlock(&shpool->mutex);
851
+
852
+		  cln->handler = ngx_http_uploadprogress_cleanup;
853
+		  upcln = cln->data;
854
+		  upcln->shm_zone = upcf->shm_zone;
855
+		  upcln->node = node;
856
+
857
+		  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
858
+		                 "trackuploads error-tracking adding: %08XD", node->key);
859
+
860
+		}
861
+
862
+finish:		
863
+		/* call the filter chain as usual */ 
864
+    return ngx_http_next_header_filter(r);
865
+}
866
+
691 867
 
692 868
 static ngx_int_t
693 869
 ngx_http_uploadprogress_init(ngx_conf_t *cf)
@@ -697,12 +873,24 @@ ngx_http_uploadprogress_init(ngx_conf_t *cf)
697 873
 
698 874
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
699 875
 
876
+		/* install the tracking handler */
700 877
     h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
701 878
     if (h == NULL) {
702 879
         return NGX_ERROR;
703 880
     }
704 881
 
705 882
     *h = ngx_http_uploadprogress_handler;
883
+
884
+		/* 
885
+			we also need to track HTTP 413 errors 
886
+			unfortunately, the above handler is not called in case of 
887
+			errors.
888
+			we have to register a header output filter that will be
889
+			called in any case to track those errors
890
+		*/
891
+	  ngx_http_next_header_filter = ngx_http_top_header_filter;
892
+	  ngx_http_top_header_filter = ngx_http_uploadprogress_errortracker;
893
+		
706 894
     return NGX_OK;
707 895
 }
708 896
 
@@ -751,6 +939,12 @@ ngx_http_upload_progress(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
751 939
         return NGX_CONF_ERROR;
752 940
     }
753 941
 
942
+    ctx->list_head.prev = NULL;
943
+    ctx->list_head.next = &ctx->list_tail;
944
+
945
+    ctx->list_tail.prev = &ctx->list_head;
946
+    ctx->list_tail.next = NULL;
947
+
754 948
     n = ngx_parse_size(&value[2]);
755 949
 
756 950
     if (n == NGX_ERROR) {
@@ -772,7 +966,7 @@ ngx_http_upload_progress(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
772 966
     }
773 967
 
774 968
 	  ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
775
-	                 "ngx_upload_progress name: %V, szhm_zone: %p", value[1], shm_zone);
969
+	                 "ngx_upload_progress name: %V, szhm_zone: %p", &value[1], shm_zone);
776 970
 
777 971
     if (shm_zone->data) {
778 972
         ctx = shm_zone->data;
@@ -789,6 +983,8 @@ ngx_http_upload_progress(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
789 983
     return NGX_CONF_OK;
790 984
 }
791 985
 
986
+
987
+
792 988
 static char *
793 989
 ngx_http_track_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
794 990
 {
@@ -801,7 +997,7 @@ ngx_http_track_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
801 997
     value = cf->args->elts;
802 998
 
803 999
 		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
804
-		                 "ngx_track_uploads name: %V", value[1]);
1000
+		                 "ngx_track_uploads name: %V", &value[1]);
805 1001
 
806 1002
     lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
807 1003
                                            &ngx_http_uploadprogress_module);
@@ -812,7 +1008,7 @@ ngx_http_track_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
812 1008
 		lzcf->track = (u_char)1;
813 1009
 
814 1010
 	  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
815
-	                 "ngx_track_uploads name: %V,szhm_zone: %p", value[1], lzcf->shm_zone);
1011
+	                 "ngx_track_uploads name: %V,szhm_zone: %p", &value[1], lzcf->shm_zone);
816 1012
 
817 1013
     return NGX_CONF_OK;
818 1014
 }
@@ -831,7 +1027,7 @@ ngx_http_report_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
831 1027
     value = cf->args->elts;
832 1028
 
833 1029
 	  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
834
-	                 "ngx_report_uploads name: %V", value[1]);
1030
+	                 "ngx_report_uploads name: %V", &value[1]);
835 1031
 
836 1032
     lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
837 1033
                                            &ngx_http_uploadprogress_module);
@@ -840,7 +1036,7 @@ ngx_http_report_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
840 1036
     }
841 1037
 
842 1038
 	  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
843
-	                 "ngx_report_uploads name: %V, szhm_zone: %p", value[1], lzcf->shm_zone);
1039
+	                 "ngx_report_uploads name: %V, szhm_zone: %p", &value[1], lzcf->shm_zone);
844 1040
 
845 1041
 		lzcf->track = (u_char)0;
846 1042
 

Carregando…
Cancelar
Salvar