Parcourir la source

* 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 il y a 18 ans
Parent
révision
e9ccdcd75c
1 fichiers modifiés avec 369 ajouts et 173 suppressions
  1. 369
    173
      ngx_http_uploadprogress_module.c

+ 369
- 173
ngx_http_uploadprogress_module.c Voir le fichier

7
 #include <ngx_core.h>
7
 #include <ngx_core.h>
8
 #include <ngx_http.h>
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
  		ngx_http_request_t *r;
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
     u_char              len;
19
     u_char              len;
14
     u_char              data[1];
20
     u_char              data[1];
15
-} ngx_http_uploadprogress_node_t;
16
-
21
+};
17
 
22
 
18
 typedef struct {
23
 typedef struct {
19
     ngx_shm_zone_t     *shm_zone;
24
     ngx_shm_zone_t     *shm_zone;
22
 
27
 
23
 typedef struct {
28
 typedef struct {
24
     ngx_rbtree_t       *rbtree;
29
     ngx_rbtree_t       *rbtree;
30
+    ngx_http_uploadprogress_node_t   list_head;
31
+    ngx_http_uploadprogress_node_t   list_tail;
25
 } ngx_http_uploadprogress_ctx_t;
32
 } ngx_http_uploadprogress_ctx_t;
26
 
33
 
27
 typedef struct {
34
 typedef struct {
28
     ngx_shm_zone_t     *shm_zone;
35
     ngx_shm_zone_t     *shm_zone;
29
 		u_char							track;
36
 		u_char							track;
37
+		ngx_event_t					cleanup;
30
 } ngx_http_uploadprogress_conf_t;
38
 } ngx_http_uploadprogress_conf_t;
31
 
39
 
32
-static ngx_int_t ngx_http_reportuploads_handler(ngx_http_request_t *r);
33
 static ngx_int_t ngx_http_reportuploads_handler(ngx_http_request_t *r);
40
 static ngx_int_t ngx_http_reportuploads_handler(ngx_http_request_t *r);
34
 static void ngx_http_uploadprogress_cleanup(void *data);
41
 static void ngx_http_uploadprogress_cleanup(void *data);
35
 static char *ngx_http_report_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
42
 static char *ngx_http_report_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
40
 static char *ngx_http_track_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
47
 static char *ngx_http_track_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
41
 static char *ngx_http_report_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
48
 static char *ngx_http_report_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
42
 static char *ngx_http_upload_progress(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
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
 static ngx_command_t  ngx_http_uploadprogress_commands[] = {
54
 static ngx_command_t  ngx_http_uploadprogress_commands[] = {
45
 
55
 
155
 	return NULL;
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
 /* This generates the response for the report */
220
 /* This generates the response for the report */
160
 static ngx_int_t
221
 static ngx_int_t
164
   ngx_buf_t    *b;
225
   ngx_buf_t    *b;
165
   ngx_chain_t   out;
226
   ngx_chain_t   out;
166
 	ngx_http_request_t								 *orig;
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
   ngx_slab_pool_t                *shpool;
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
   ngx_http_uploadprogress_ctx_t      *ctx;
232
   ngx_http_uploadprogress_ctx_t      *ctx;
173
-  ngx_http_uploadprogress_node_t     *lz;
233
+  ngx_http_uploadprogress_node_t     *up;
174
   ngx_table_elt_t  *expires, *cc, **ccp;
234
   ngx_table_elt_t  *expires, *cc, **ccp;
175
 
235
 
176
   if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
236
   if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
197
   ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
257
   ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
198
                  "reportuploads handler found id: %V", id);
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
 	  	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
263
 	  	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
204
 	                 "reportuploads no shm_zone for id: %V", id);
264
 	                 "reportuploads no shm_zone for id: %V", id);
205
       return NGX_DECLINED;
265
       return NGX_DECLINED;
206
   }
266
   }
207
 
267
 
208
 	orig = NULL;
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
 	/* get the original connection of the upload */
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
 	ngx_shmtx_unlock(&shpool->mutex);
288
 	ngx_shmtx_unlock(&shpool->mutex);
277
 
289
 
278
 	/* send the output */
290
 	/* send the output */
279
   r->headers_out.content_type.len = sizeof("text/javascript") - 1;
291
   r->headers_out.content_type.len = sizeof("text/javascript") - 1;
280
   r->headers_out.content_type.data = (u_char *) "text/javascript";
292
   r->headers_out.content_type.data = (u_char *) "text/javascript";
281
 
293
 
282
-	/* no-cache */
283
-
294
+	/* force no-cache */
284
   expires = r->headers_out.expires;
295
   expires = r->headers_out.expires;
285
 
296
 
286
   if (expires == NULL) {
297
   if (expires == NULL) {
352
 
363
 
353
 	if ( orig == NULL )
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
 			size = sizeof("new Object({ 'state' : 'done' })\r\n");
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
 		else
374
 		else
360
 		{
375
 		{
361
 			size = sizeof("new Object({ 'state' : 'starting' })\r\n");
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
 		size = sizeof("new Object({ 'state' : 'error', 'status' : 413 })\r\n");
381
 		size = sizeof("new Object({ 'state' : 'error', 'status' : 413 })\r\n");
367
 	}
382
 	}
381
 	
396
 	
382
 	if (orig == NULL)
397
 	if (orig == NULL)
383
 	{
398
 	{
384
-		if (lz == NULL )
399
+		if (up == NULL )
385
 		{
400
 		{
386
 			b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'starting' })\r\n",
401
 			b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'starting' })\r\n",
387
 		                       sizeof("new Object({ 'state' : 'starting' })\r\n") - 1);
402
 		                       sizeof("new Object({ 'state' : 'starting' })\r\n") - 1);
388
 			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
403
 			ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
389
 											               "reportuploads returning starting");
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
 		else 
413
 		else 
392
 		{
414
 		{
393
 			b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'done' })\r\n",
415
 			b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'done' })\r\n",
396
 		               "reportuploads returning done");
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
 		b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'error', 'status' : 413 })\r\n",
423
 		b->last = ngx_cpymem(b->last, "new Object({ 'state' : 'error', 'status' : 413 })\r\n",
402
 	                       sizeof("new Object({ 'state' : 'error', 'status' : 413 })\r\n") - 1);
424
 	                       sizeof("new Object({ 'state' : 'error', 'status' : 413 })\r\n") - 1);
415
 
437
 
416
 	}
438
 	}
417
 
439
 
418
-	// force no caching for proxy
419
-	
420
-
421
 	r->headers_out.status = NGX_HTTP_OK;
440
 	r->headers_out.status = NGX_HTTP_OK;
422
 	r->headers_out.content_length_n = b->last - b->pos;
441
 	r->headers_out.content_length_n = b->last - b->pos;
423
 
442
 
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
 static ngx_int_t
456
 static ngx_int_t
438
 ngx_http_uploadprogress_handler(ngx_http_request_t *r)
457
 ngx_http_uploadprogress_handler(ngx_http_request_t *r)
439
 {
458
 {
440
   size_t                          n;
459
   size_t                          n;
441
 	ngx_str_t 												 *id;
460
 	ngx_str_t 												 *id;
442
-  ngx_int_t                       rc;
443
   uint32_t                        hash;
461
   uint32_t                        hash;
444
   ngx_slab_pool_t                *shpool;
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
   ngx_http_uploadprogress_ctx_t      *ctx;
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
   ngx_pool_cleanup_t             *cln;
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
 	id = get_tracking_id(r);
475
 	id = get_tracking_id(r);
453
 	if ( id == NULL )
476
 	if ( id == NULL )
454
 	{
477
 	{
460
 	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
483
 	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
461
            "trackuploads id found: %V", id);
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
 	  	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
489
 	  	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
467
 	                 "trackuploads not tracking in this location for id: %V", id);
490
 	                 "trackuploads not tracking in this location for id: %V", id);
468
       return NGX_DECLINED;
491
       return NGX_DECLINED;
469
   }
492
   }
470
 
493
 
471
-  if (lzcf->shm_zone == NULL) {
494
+  if (upcf->shm_zone == NULL) {
472
   	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
495
   	ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
473
                  "trackuploads no shm_zone for id: %V", id);
496
                  "trackuploads no shm_zone for id: %V", id);
474
       return NGX_DECLINED;
497
       return NGX_DECLINED;
475
   }
498
   }
476
 
499
 
477
-  ctx = lzcf->shm_zone->data;
500
+  ctx = upcf->shm_zone->data;
478
 	
501
 	
479
   hash = ngx_crc32_short(id->data, id->len);
502
   hash = ngx_crc32_short(id->data, id->len);
480
 
503
 
481
 	ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
504
 	ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
482
                "trackuploads hash %08XD for id: %V",hash, id);
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
   ngx_shmtx_lock(&shpool->mutex);
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
       + id->len;
528
       + id->len;
534
 
529
 
535
   node = ngx_slab_alloc_locked(shpool, n);
530
   node = ngx_slab_alloc_locked(shpool, n);
538
       return NGX_HTTP_SERVICE_UNAVAILABLE;
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
   node->key = hash;
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
   ngx_rbtree_insert(ctx->rbtree, node);
550
   ngx_rbtree_insert(ctx->rbtree, node);
549
   ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
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
   ngx_shmtx_unlock(&shpool->mutex);
554
   ngx_shmtx_unlock(&shpool->mutex);
553
 
555
 
554
   cln->handler = ngx_http_uploadprogress_cleanup;
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
   return NGX_DECLINED;
571
   return NGX_DECLINED;
561
 }
572
 }
564
 ngx_http_uploadprogress_rbtree_insert_value(ngx_rbtree_node_t *temp,
575
 ngx_http_uploadprogress_rbtree_insert_value(ngx_rbtree_node_t *temp,
565
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
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
     for ( ;; ) {
580
     for ( ;; ) {
570
 
581
 
588
 
599
 
589
         } else { /* node->key == temp->key */
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
                 if (temp->left == sentinel) {
607
                 if (temp->left == sentinel) {
597
                     temp->left = node;
608
                     temp->left = node;
618
     ngx_rbt_red(node);
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
 removes the expired node from the upload rbtree
690
 removes the expired node from the upload rbtree
623
 */
691
 */
624
 static void
692
 static void
625
 ngx_http_uploadprogress_cleanup(void *data)
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
     ngx_http_uploadprogress_ctx_t   *ctx;
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
 	           "uploadprogress cleanup called");
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
 static ngx_int_t
717
 static ngx_int_t
688
     return NGX_OK;
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
 static ngx_int_t
868
 static ngx_int_t
693
 ngx_http_uploadprogress_init(ngx_conf_t *cf)
869
 ngx_http_uploadprogress_init(ngx_conf_t *cf)
697
 
873
 
698
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
874
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
699
 
875
 
876
+		/* install the tracking handler */
700
     h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
877
     h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
701
     if (h == NULL) {
878
     if (h == NULL) {
702
         return NGX_ERROR;
879
         return NGX_ERROR;
703
     }
880
     }
704
 
881
 
705
     *h = ngx_http_uploadprogress_handler;
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
     return NGX_OK;
894
     return NGX_OK;
707
 }
895
 }
708
 
896
 
751
         return NGX_CONF_ERROR;
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
     n = ngx_parse_size(&value[2]);
948
     n = ngx_parse_size(&value[2]);
755
 
949
 
756
     if (n == NGX_ERROR) {
950
     if (n == NGX_ERROR) {
772
     }
966
     }
773
 
967
 
774
 	  ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
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
     if (shm_zone->data) {
971
     if (shm_zone->data) {
778
         ctx = shm_zone->data;
972
         ctx = shm_zone->data;
789
     return NGX_CONF_OK;
983
     return NGX_CONF_OK;
790
 }
984
 }
791
 
985
 
986
+
987
+
792
 static char *
988
 static char *
793
 ngx_http_track_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
989
 ngx_http_track_uploads(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
794
 {
990
 {
801
     value = cf->args->elts;
997
     value = cf->args->elts;
802
 
998
 
803
 		ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
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
     lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
1002
     lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
807
                                            &ngx_http_uploadprogress_module);
1003
                                            &ngx_http_uploadprogress_module);
812
 		lzcf->track = (u_char)1;
1008
 		lzcf->track = (u_char)1;
813
 
1009
 
814
 	  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
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
     return NGX_CONF_OK;
1013
     return NGX_CONF_OK;
818
 }
1014
 }
831
     value = cf->args->elts;
1027
     value = cf->args->elts;
832
 
1028
 
833
 	  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
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
     lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
1032
     lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
837
                                            &ngx_http_uploadprogress_module);
1033
                                            &ngx_http_uploadprogress_module);
840
     }
1036
     }
841
 
1037
 
842
 	  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
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
 		lzcf->track = (u_char)0;
1041
 		lzcf->track = (u_char)0;
846
 
1042
 

Chargement…
Annuler
Enregistrer