zena 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. data/History.txt +14 -0
  2. data/{README.txt → README.rdoc} +13 -19
  3. data/app/controllers/documents_controller.rb +7 -2
  4. data/app/controllers/nodes_controller.rb +4 -0
  5. data/app/models/iformat.rb +43 -1
  6. data/app/models/skin.rb +1 -2
  7. data/app/models/text_document.rb +2 -2
  8. data/app/models/version.rb +1 -0
  9. data/app/views/documents/new.rhtml +2 -2
  10. data/app/views/iformats/_form.rhtml +5 -4
  11. data/app/views/iformats/_li.rhtml +1 -0
  12. data/app/views/iformats/index.rhtml +1 -1
  13. data/app/views/nodes/_import_results.rhtml +1 -1
  14. data/app/views/nodes/edit.html.erb +2 -2
  15. data/app/views/templates/edit_tabs/_custom.rhtml +2 -2
  16. data/app/views/templates/edit_tabs/_document.rhtml +3 -3
  17. data/app/views/versions/_tr.rhtml +5 -6
  18. data/app/views/versions/edit.rhtml +2 -2
  19. data/bin/zena +2 -2
  20. data/bricks/captcha/patch/application_controller.rb +1 -1
  21. data/bricks/captcha/zafu/captcha.rb +1 -1
  22. data/config/deploy.rb +36 -380
  23. data/config/gems.yml +2 -7
  24. data/db/migrate/20091018200734_add_popup_info_to_image_format.rb +9 -0
  25. data/db/schema.rb +3 -2
  26. data/lib/gettext_strings.rb +8 -0
  27. data/lib/tasks/zena.rake +30 -12
  28. data/lib/zena/app.rb +2 -0
  29. data/{config → lib/zena/deploy}/awstats.conf.rhtml +0 -0
  30. data/{config → lib/zena/deploy}/database.rhtml +0 -0
  31. data/lib/zena/deploy/httpd.rhtml +22 -0
  32. data/{config → lib/zena/deploy}/start.html +2 -2
  33. data/{config → lib/zena/deploy}/stats.vhost.rhtml +0 -0
  34. data/{config/zena.rb → lib/zena/deploy/template.rb} +13 -8
  35. data/{config → lib/zena/deploy}/vhost.rhtml +28 -14
  36. data/{config → lib/zena/deploy}/vhost_www.rhtml +0 -0
  37. data/lib/zena/deploy.rb +377 -0
  38. data/lib/zena/info.rb +13 -0
  39. data/lib/zena/parser/zena_tags.rb +3 -0
  40. data/lib/zena/parser.rb +1 -0
  41. data/lib/zena/use/calendar.rb +2 -1
  42. data/lib/zena/use/dates.rb +6 -1
  43. data/lib/zena/use/fixtures.rb +9 -0
  44. data/lib/zena/use/html_tags.rb +44 -5
  45. data/lib/zena/use/node_query_finders.rb +1 -2
  46. data/lib/zena/use/refactor.rb +0 -13
  47. data/lib/zena/use/rendering.rb +13 -0
  48. data/lib/zena/use/zafu.rb +21 -9
  49. data/lib/zena.rb +4 -11
  50. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  51. data/locale/en/zena.po +29 -1
  52. data/locale/fr/LC_MESSAGES/zena.mo +0 -0
  53. data/locale/fr/zena.po +29 -1
  54. data/locale/zena.pot +28 -0
  55. data/public/images/popup_next.png +0 -0
  56. data/public/images/popup_prev.png +0 -0
  57. data/public/javascripts/upload-progress.js +13 -3
  58. data/public/javascripts/zena.js +177 -23
  59. data/public/stylesheets/popup.css +5 -3
  60. data/public/stylesheets/zena.css +10 -1
  61. data/{lib/zena/use → test}/custom_queries/complex.host.yml +0 -0
  62. data/test/fixtures/iformats.yml +1 -0
  63. data/test/fixtures/nodes.yml +1 -1
  64. data/test/fixtures/versions.yml +3 -1
  65. data/test/sites/zena/iformats.yml +1 -0
  66. data/test/sites/zena/versions.yml +3 -1
  67. data/test/test_helper.rb +2 -0
  68. data/test/unit/iformat_test.rb +53 -1
  69. data/test/unit/text_document_test.rb +3 -0
  70. data/test/unit/zena/use/html_tags_test.rb +24 -2
  71. data/test/unit/zena/use/refactor_test.rb +0 -4
  72. data/test/unit/zena/use/zafu_test.rb +12 -0
  73. data/test/unit/zena/use/zazen_test.rb +6 -3
  74. data/test/unit/zena/zena_tags/basic.yml +3 -3
  75. data/vendor/apache2_upload_progress/MIT-LICENSE +22 -0
  76. data/vendor/apache2_upload_progress/README +53 -0
  77. data/vendor/apache2_upload_progress/mod_upload_progress.c +813 -0
  78. metadata +45 -45
  79. data/config/deploy_config_example.rb +0 -7
  80. data/config/httpd.rhtml +0 -18
  81. data/config/locales/de.yml +0 -120
  82. data/config/locales/fr-CH.yml +0 -123
  83. data/config/locales/fr.yml +0 -123
  84. data/lib/zena/root.rb +0 -3
@@ -0,0 +1,813 @@
1
+ #include <ap_config.h>
2
+ #include <http_core.h>
3
+ #include <http_log.h>
4
+ #include <apr_pools.h>
5
+ #include <apr_strings.h>
6
+ #include "unixd.h"
7
+
8
+ #if APR_HAS_SHARED_MEMORY
9
+ #include "apr_rmm.h"
10
+ #include "apr_shm.h"
11
+ #endif
12
+
13
+ #if APR_HAVE_UNISTD_H
14
+ #include <unistd.h>
15
+ #endif
16
+
17
+ #define PROGRESS_ID "X-Progress-ID"
18
+
19
+ #define CACHE_LOCK() do { \
20
+ if (config->cache_lock) \
21
+ apr_global_mutex_lock(config->cache_lock); \
22
+ } while (0)
23
+
24
+ #define CACHE_UNLOCK() do { \
25
+ if (config->cache_lock) \
26
+ apr_global_mutex_unlock(config->cache_lock); \
27
+ } while (0)
28
+
29
+ typedef struct {
30
+ int track_enabled;
31
+ int report_enabled;
32
+ } DirConfig;
33
+
34
+
35
+ typedef struct upload_progress_node_s{
36
+ int done;
37
+ int length;
38
+ int received;
39
+ int err_status;
40
+ char *key;
41
+ int started_at;
42
+ int speed; /* bytes per second */
43
+ time_t expires;
44
+ struct upload_progress_node_s* next;
45
+ struct upload_progress_node_s* prev;
46
+ }upload_progress_node_t;
47
+
48
+ typedef struct {
49
+ upload_progress_node_t *head; /* keep head of the list */
50
+ }upload_progress_cache_t;
51
+
52
+ typedef struct {
53
+ request_rec *r;
54
+ upload_progress_node_t *node;
55
+ }upload_progress_context_t;
56
+
57
+
58
+ typedef struct {
59
+ apr_rmm_off_t cache_offset;
60
+ apr_pool_t *pool;
61
+ apr_global_mutex_t *cache_lock;
62
+ char *lock_file; /* filename for shm lock mutex */
63
+ apr_size_t cache_bytes;
64
+
65
+ #if APR_HAS_SHARED_MEMORY
66
+ apr_shm_t *cache_shm;
67
+ apr_rmm_t *cache_rmm;
68
+ #endif
69
+ char *cache_file;
70
+ upload_progress_cache_t *cache;
71
+
72
+
73
+ } ServerConfig;
74
+
75
+ static const char* upload_progress_shared_memory_size_cmd(cmd_parms *cmd, void *dummy, const char *arg);
76
+ static void upload_progress_child_init(apr_pool_t *p, server_rec *s);
77
+ static int reportuploads_handler(request_rec *r);
78
+ upload_progress_node_t* insert_node(request_rec *r, const char *key);
79
+ upload_progress_node_t *store_node(ServerConfig *config, const char *key);
80
+ upload_progress_node_t *find_node(request_rec *r, const char *key);
81
+ static void clean_old_connections(request_rec *r);
82
+ void fill_new_upload_node_data(upload_progress_node_t *node, request_rec *r);
83
+ static apr_status_t upload_progress_cleanup(void *data);
84
+ const char *get_progress_id(request_rec *r);
85
+ static const char *track_upload_progress_cmd(cmd_parms *cmd, void *dummy, int arg);
86
+ static const char *report_upload_progress_cmd(cmd_parms *cmd, void *dummy, int arg);
87
+ void *upload_progress_config_create_dir(apr_pool_t *p, char *dirspec);
88
+ void *upload_progress_config_create_server(apr_pool_t *p, server_rec *s);
89
+ static void upload_progress_register_hooks(apr_pool_t *p);
90
+ static int upload_progress_handle_request(request_rec *r);
91
+ static int track_upload_progress(ap_filter_t *f, apr_bucket_brigade *bb,
92
+ ap_input_mode_t mode, apr_read_type_e block,
93
+ apr_off_t readbytes);
94
+ int upload_progress_init(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *);
95
+
96
+ //from passenger
97
+ typedef const char * (*CmdFunc)();// Workaround for some weird C++-specific compiler error.
98
+
99
+ static const command_rec upload_progress_cmds[] =
100
+ {
101
+ AP_INIT_FLAG("TrackUploads", (CmdFunc) track_upload_progress_cmd, NULL, OR_AUTHCFG,
102
+ "Track upload progress in this location"),
103
+ AP_INIT_FLAG("ReportUploads", (CmdFunc) report_upload_progress_cmd, NULL, OR_AUTHCFG,
104
+ "Report upload progress in this location"),
105
+ AP_INIT_TAKE1("UploadProgressSharedMemorySize", (CmdFunc) upload_progress_shared_memory_size_cmd, NULL, RSRC_CONF,
106
+ "Size of shared memory used to keep uploads data, default 100KB"),
107
+ { NULL }
108
+ };
109
+
110
+ module AP_MODULE_DECLARE_DATA upload_progress_module =
111
+ {
112
+ STANDARD20_MODULE_STUFF,
113
+ upload_progress_config_create_dir,
114
+ NULL,
115
+ upload_progress_config_create_server,
116
+ NULL,
117
+ upload_progress_cmds,
118
+ upload_progress_register_hooks, /* callback for registering hooks */
119
+ };
120
+
121
+ static void upload_progress_register_hooks (apr_pool_t *p)
122
+ {
123
+ ap_hook_fixups(upload_progress_handle_request, NULL, NULL, APR_HOOK_FIRST);
124
+ ap_hook_handler(reportuploads_handler, NULL, NULL, APR_HOOK_FIRST);
125
+ ap_hook_post_config(upload_progress_init, NULL, NULL, APR_HOOK_MIDDLE);
126
+ ap_hook_child_init(upload_progress_child_init, NULL, NULL, APR_HOOK_MIDDLE);
127
+ ap_register_input_filter("UPLOAD_PROGRESS", track_upload_progress, NULL, AP_FTYPE_RESOURCE);
128
+ }
129
+
130
+ ServerConfig *get_server_config(request_rec *r) {
131
+ return (ServerConfig*)ap_get_module_config(r->server->module_config, &upload_progress_module);
132
+ }
133
+
134
+ static int upload_progress_handle_request(request_rec *r)
135
+ {
136
+ DirConfig* dir = (DirConfig*)ap_get_module_config(r->per_dir_config, &upload_progress_module);
137
+ ServerConfig *config = get_server_config(r);
138
+
139
+ if (dir->track_enabled) {
140
+ if (r->method_number == M_POST) {
141
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
142
+ "Upload Progress: Upload in trackable location: %s.", r->uri);
143
+ const char* id = get_progress_id(r);
144
+ if (id != NULL) {
145
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
146
+ "Upload Progress: Progress id found: %s.", id);
147
+ CACHE_LOCK();
148
+ clean_old_connections(r);
149
+ upload_progress_node_t *node = find_node(r, id);
150
+ if (node == NULL) {
151
+ node = insert_node(r, id);
152
+ if (node)
153
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
154
+ "Upload Progress: Added upload with id=%s to list.", id);
155
+ } else if (node->done) {
156
+ fill_new_upload_node_data(node, r);
157
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
158
+ "Upload Progress: Reused existing node with id '%s'.", id);
159
+ } else {
160
+ node = NULL;
161
+ }
162
+
163
+ if (node) {
164
+ upload_progress_context_t *ctx = (upload_progress_context_t*)apr_pcalloc(r->pool, sizeof(upload_progress_context_t));
165
+ ctx->node = node;
166
+ ctx->r = r;
167
+ apr_pool_cleanup_register(r->pool, ctx, upload_progress_cleanup, apr_pool_cleanup_null);
168
+ ap_add_input_filter("UPLOAD_PROGRESS", NULL, r, r->connection);
169
+ }
170
+ CACHE_UNLOCK();
171
+ }
172
+ }
173
+ }
174
+
175
+ return DECLINED;
176
+ }
177
+
178
+ static const char *report_upload_progress_cmd(cmd_parms *cmd, void *config, int arg)
179
+ {
180
+ DirConfig* dir = (DirConfig*)config ;
181
+ dir->report_enabled = arg;
182
+ return NULL;
183
+ }
184
+
185
+ static const char *track_upload_progress_cmd(cmd_parms *cmd, void *config, int arg)
186
+ {
187
+ DirConfig* dir = (DirConfig*)config ;
188
+ dir->track_enabled = arg;
189
+ return NULL;
190
+ }
191
+
192
+ static const char* upload_progress_shared_memory_size_cmd(cmd_parms *cmd, void *dummy,
193
+ const char *arg) {
194
+ ServerConfig *config = (ServerConfig*)ap_get_module_config(cmd->server->module_config, &upload_progress_module);
195
+
196
+ int n = atoi(arg);
197
+
198
+ if (n <= 0) {
199
+ return "UploadProgressSharedMemorySize should be positive";
200
+ }
201
+
202
+ config->cache_bytes = (apr_size_t)n;
203
+ return NULL;
204
+ }
205
+
206
+ void *
207
+ upload_progress_config_create_dir(apr_pool_t *p, char *dirspec) {
208
+ DirConfig* dir = (DirConfig*)apr_pcalloc(p, sizeof(DirConfig));
209
+ dir->report_enabled = 0;
210
+ dir->track_enabled = 0;
211
+ return dir;
212
+ }
213
+
214
+ void *upload_progress_config_create_server(apr_pool_t *p, server_rec *s) {
215
+ ServerConfig *config = (ServerConfig *)apr_pcalloc(p, sizeof(ServerConfig));
216
+ config->cache_file = apr_pstrdup(p, "/tmp/upload_progress_cache");
217
+ config->cache_bytes = 51200;
218
+ apr_pool_create(&config->pool, p);
219
+ return config;
220
+ }
221
+
222
+ static int track_upload_progress(ap_filter_t *f, apr_bucket_brigade *bb,
223
+ ap_input_mode_t mode, apr_read_type_e block,
224
+ apr_off_t readbytes)
225
+ {
226
+ apr_status_t rv;
227
+ upload_progress_node_t *node;
228
+ ServerConfig* config = get_server_config(f->r);
229
+
230
+ if ((rv = ap_get_brigade(f->next, bb, mode, block,
231
+ readbytes)) != APR_SUCCESS) {
232
+ return rv;
233
+ }
234
+
235
+ apr_off_t length;
236
+ apr_brigade_length(bb, 1, &length);
237
+ const char* id = get_progress_id(f->r);
238
+ if (id == NULL)
239
+ return APR_SUCCESS;
240
+
241
+ CACHE_LOCK();
242
+ node = find_node(f->r, id);
243
+ if (node != NULL) {
244
+ node->received += (int)length;
245
+ if (node->received > node->length) /* handle chunked tranfer */
246
+ node->length = node->received;
247
+ int upload_time = time(NULL) - node->started_at;
248
+ if (upload_time > 0) {
249
+ node->speed = (int)(node->received / upload_time);
250
+ }
251
+ }
252
+ CACHE_UNLOCK();
253
+
254
+ return APR_SUCCESS;
255
+ }
256
+
257
+ const char *get_progress_id(request_rec *r) {
258
+ char *p, *start_p, *end_p;
259
+ int i;
260
+ //try to find progress id in headers
261
+ const char *id = apr_table_get(r->headers_in, PROGRESS_ID);
262
+ //if not found check args
263
+ if(id == NULL) {
264
+ if (r->args) {
265
+ i = 0;
266
+ p = r->args;
267
+ do {
268
+ int len = strlen(p);
269
+ if (len >= 14 && strncasecmp(p, "X-Progress-ID=", 14) == 0) {
270
+ i = 1;
271
+ break;
272
+ }
273
+ if (len<=0)
274
+ break;
275
+ }
276
+ while(p++);
277
+
278
+ if (i) {
279
+ i = 0;
280
+ start_p = p += 14;
281
+ end_p = r->args + strlen(r->args);
282
+ while (p <= end_p && *p++ != '&') {
283
+ i++;
284
+ }
285
+ return apr_pstrndup(r->connection->pool, start_p, p-start_p-1);
286
+ }
287
+ }
288
+ }
289
+ return id;
290
+ }
291
+
292
+ const char *get_json_callback_param(request_rec *r) {
293
+ char *p, *start_p, *end_p;
294
+ int i;
295
+ const char *callback = NULL;
296
+
297
+ if (r->args) {
298
+ i = 0;
299
+ p = r->args;
300
+ do {
301
+ int len = strlen(p);
302
+ if (len >= 9 && strncasecmp(p, "callback=", 9) == 0) {
303
+ i = 1;
304
+ break;
305
+ }
306
+ if (len<=0)
307
+ break;
308
+ }
309
+ while(p++);
310
+
311
+ if (i) {
312
+ i = 0;
313
+ start_p = p += 9;
314
+ end_p = r->args + strlen(r->args);
315
+ while (p <= end_p && *p++ != '&') {
316
+ i++;
317
+ }
318
+ return apr_pstrndup(r->connection->pool, start_p, p-start_p-1);
319
+ }
320
+ }
321
+ return callback;
322
+ }
323
+
324
+ void cache_free(ServerConfig *config, const void *ptr)
325
+ {
326
+ if (config->cache_rmm) {
327
+ if (ptr)
328
+ /* Free in shared memory */
329
+ apr_rmm_free(config->cache_rmm, apr_rmm_offset_get(config->cache_rmm, (void *)ptr));
330
+ } else {
331
+ if (ptr)
332
+ /* Cache shm is not used */
333
+ free((void *)ptr);
334
+ }
335
+ }
336
+
337
+ char *fetch_key(ServerConfig *config, char *key) {
338
+ return (char *)apr_rmm_addr_get(config->cache_rmm, apr_rmm_offset_get(config->cache_rmm, key));
339
+ }
340
+
341
+ int check_node(ServerConfig *config, upload_progress_node_t *node, const char *key) {
342
+ char *node_key = fetch_key(config, node->key);
343
+ return strcasecmp(node_key, key) == 0 ? 1 : 0;
344
+ }
345
+
346
+ upload_progress_node_t *fetch_node(ServerConfig *config, upload_progress_node_t *node) {
347
+ return (upload_progress_node_t *)apr_rmm_addr_get(config->cache_rmm, apr_rmm_offset_get(config->cache_rmm, node));
348
+ }
349
+
350
+ upload_progress_cache_t *fetch_cache(ServerConfig *config) {
351
+ return (upload_progress_cache_t *)apr_rmm_addr_get(config->cache_rmm, apr_rmm_offset_get(config->cache_rmm, config->cache));
352
+ }
353
+
354
+ upload_progress_node_t *fetch_first_node(ServerConfig *config) {
355
+ upload_progress_cache_t *cache;
356
+
357
+ cache = fetch_cache(config);
358
+ if(cache->head == NULL) {
359
+ return NULL;
360
+ }
361
+
362
+ return fetch_node(config, cache->head);
363
+ }
364
+
365
+ upload_progress_node_t *fetch_last_node(ServerConfig *config) {
366
+ upload_progress_cache_t *cache;
367
+ upload_progress_node_t *node;
368
+
369
+ cache = fetch_cache(config);
370
+ if(cache->head == NULL) {
371
+ return NULL;
372
+ }
373
+
374
+ node = fetch_node(config, cache->head);
375
+ while(node->next != NULL) {
376
+ node = fetch_node(config, node->next);
377
+ }
378
+
379
+ return node;
380
+ }
381
+
382
+ upload_progress_node_t *store_node(ServerConfig *config, const char *key) {
383
+ apr_rmm_off_t block = apr_rmm_calloc(config->cache_rmm, sizeof(upload_progress_node_t));
384
+ upload_progress_node_t *node;
385
+
386
+ node = block ? (upload_progress_node_t *)apr_rmm_addr_get(config->cache_rmm, block) : NULL;
387
+ if (node == NULL) {
388
+ return NULL;
389
+ }
390
+ node->next = NULL;
391
+
392
+ block = apr_rmm_calloc(config->cache_rmm, strlen(key)+1);
393
+ node->key = block ? (char *)apr_rmm_addr_get(config->cache_rmm, block) : NULL;
394
+ if (node->key != NULL) {
395
+ sprintf(node->key, "%s\0", key);
396
+ } else {
397
+ apr_rmm_free(config->cache_rmm, apr_rmm_offset_get(config->cache_rmm, (void *)node));
398
+ node = NULL;
399
+ }
400
+ return node;
401
+ }
402
+
403
+ void fill_new_upload_node_data(upload_progress_node_t *node, request_rec *r) {
404
+ const char *content_length;
405
+
406
+ node->received = 0;
407
+ node->done = 0;
408
+ node->err_status = 0;
409
+ node->started_at = time(NULL);
410
+ node->speed = 0;
411
+ node->expires = -1;
412
+ content_length = apr_table_get(r->headers_in, "Content-Length");
413
+ node->length = 1;
414
+ /* Content-Length is missing is case of chunked transfer encoding */
415
+ if (content_length) sscanf(content_length, "%d", &(node->length));
416
+ }
417
+
418
+ upload_progress_node_t* insert_node(request_rec *r, const char *key) {
419
+ upload_progress_node_t *node;
420
+ upload_progress_cache_t *cache;
421
+
422
+ ServerConfig *config = (ServerConfig*)ap_get_module_config(r->server->module_config, &upload_progress_module);
423
+
424
+ upload_progress_node_t *head = fetch_first_node(config);
425
+ node = store_node(config, key);
426
+ if (node == NULL)
427
+ return NULL;
428
+
429
+ if (head == NULL) {
430
+ /* list is empty */
431
+ cache = fetch_cache(config);
432
+ cache->head = node;
433
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
434
+ "Upload Progress: Inserted node into an empty list.");
435
+ } else {
436
+ upload_progress_node_t *tail = fetch_last_node(config);
437
+ tail->next = node;
438
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
439
+ "Upload Progress: Inserted node at the end of the list.");
440
+ }
441
+ fill_new_upload_node_data(node, r);
442
+ node->next = NULL;
443
+ return node;
444
+ }
445
+
446
+ upload_progress_node_t *find_node(request_rec *r, const char *key) {
447
+ upload_progress_node_t *node;
448
+
449
+ ServerConfig *config = (ServerConfig*)ap_get_module_config(r->server->module_config, &upload_progress_module);
450
+
451
+ node = fetch_first_node(config);
452
+ if(node == NULL) {
453
+ return NULL;
454
+ }
455
+
456
+ while(node != NULL) {
457
+ if(check_node(config, node, key)) {
458
+ return node;
459
+ }
460
+ node = fetch_node(config, node->next);
461
+ }
462
+ return node;
463
+ }
464
+
465
+ static apr_status_t upload_progress_cleanup(void *data)
466
+ {
467
+ /* FIXME: this function should use locking because it modifies node data */
468
+ upload_progress_context_t *ctx = (upload_progress_context_t *)data;
469
+ if (ctx->node) {
470
+ if(ctx->r->status >= HTTP_BAD_REQUEST)
471
+ ctx->node->err_status = ctx->r->status;
472
+ ctx->node->expires = time(NULL) + 60; /*expires in 60s */
473
+ ctx->node->done = 1;
474
+ }
475
+ return APR_SUCCESS;
476
+ }
477
+
478
+ static void clean_old_connections(request_rec *r) {
479
+ upload_progress_node_t *prev = NULL;
480
+ ServerConfig *config = get_server_config(r);
481
+
482
+ upload_progress_node_t *node = fetch_first_node(config);
483
+ while(node != NULL) {
484
+ if(time(NULL) > node->expires && node->done == 1 && node->expires != -1) {
485
+ /*clean*/
486
+ if(prev == NULL) {
487
+ /* head */
488
+ upload_progress_cache_t *cache = fetch_cache(config);
489
+ cache->head = fetch_node(config, node->next);
490
+ cache_free(config, node->key);
491
+ cache_free(config, node);
492
+ node = cache->head;
493
+ continue;
494
+ } else {
495
+ prev->next = node->next;
496
+ cache_free(config, node->key);
497
+ cache_free(config, node);
498
+ node = prev;
499
+ continue;
500
+ }
501
+ }
502
+ prev = node;
503
+ node = fetch_node(config, node->next);
504
+ }
505
+ }
506
+
507
+ void upload_progress_destroy_cache(ServerConfig *config) {
508
+ upload_progress_cache_t *cache = fetch_cache(config);
509
+ upload_progress_node_t *node, *temp;
510
+
511
+ node = fetch_node(config, cache->head);
512
+ while(node != NULL) {
513
+ temp = fetch_node(config, node->next);
514
+
515
+ cache_free(config, node);
516
+ node = temp;
517
+ }
518
+ cache_free(config, cache);
519
+ }
520
+
521
+ static apr_status_t upload_progress_cache_module_kill(void *data)
522
+ {
523
+ ServerConfig *st = (ServerConfig*)data;
524
+
525
+ upload_progress_destroy_cache(st);
526
+
527
+ #if APR_HAS_SHARED_MEMORY
528
+ if (st->cache_rmm != NULL) {
529
+ apr_rmm_destroy (st->cache_rmm);
530
+ st->cache_rmm = NULL;
531
+ }
532
+ if (st->cache_shm != NULL) {
533
+ apr_status_t result = apr_shm_destroy(st->cache_shm);
534
+ st->cache_shm = NULL;
535
+ return result;
536
+ }
537
+ #endif
538
+ return APR_SUCCESS;
539
+ }
540
+
541
+ apr_status_t upload_progress_cache_init(apr_pool_t *pool, ServerConfig *config)
542
+ {
543
+
544
+ #if APR_HAS_SHARED_MEMORY
545
+ apr_status_t result;
546
+ apr_size_t size;
547
+ upload_progress_cache_t *cache;
548
+ apr_rmm_off_t block;
549
+
550
+ if (config->cache_file) {
551
+ /* Remove any existing shm segment with this name. */
552
+ apr_shm_remove(config->cache_file, config->pool);
553
+ }
554
+
555
+ size = APR_ALIGN_DEFAULT(config->cache_bytes);
556
+ result = apr_shm_create(&config->cache_shm, size, config->cache_file, config->pool);
557
+ if (result != APR_SUCCESS) {
558
+ return result;
559
+ }
560
+
561
+ /* Determine the usable size of the shm segment. */
562
+ size = apr_shm_size_get(config->cache_shm);
563
+
564
+ /* This will create a rmm "handler" to get into the shared memory area */
565
+ result = apr_rmm_init(&config->cache_rmm, NULL,
566
+ apr_shm_baseaddr_get(config->cache_shm), size,
567
+ config->pool);
568
+ if (result != APR_SUCCESS) {
569
+ return result;
570
+ }
571
+
572
+ apr_pool_cleanup_register(config->pool, config , upload_progress_cache_module_kill, apr_pool_cleanup_null);
573
+
574
+ /* init cache object */
575
+ block = apr_rmm_calloc(config->cache_rmm, sizeof(upload_progress_cache_t));
576
+ cache = block ? (upload_progress_cache_t *)apr_rmm_addr_get(config->cache_rmm, block) : NULL;
577
+ if (cache == NULL) {
578
+ return 0;
579
+ }
580
+ cache->head = NULL;
581
+ config->cache_offset = block;
582
+ config->cache = cache;
583
+ #endif
584
+ return APR_SUCCESS;
585
+ }
586
+
587
+ int upload_progress_init(apr_pool_t *p, apr_pool_t *plog,
588
+ apr_pool_t *ptemp,
589
+ server_rec *s) {
590
+ apr_status_t result;
591
+ server_rec *s_vhost;
592
+ ServerConfig *st_vhost;
593
+
594
+ ServerConfig *config = (ServerConfig*)ap_get_module_config(s->module_config, &upload_progress_module);
595
+
596
+ void *data;
597
+ const char *userdata_key = "upload_progress_init";
598
+
599
+ /* upload_progress_init will be called twice. Don't bother
600
+ * going through all of the initialization on the first call
601
+ * because it will just be thrown away.*/
602
+ apr_pool_userdata_get(&data, userdata_key, s->process->pool);
603
+ if (!data) {
604
+ apr_pool_userdata_set((const void *)1, userdata_key,
605
+ apr_pool_cleanup_null, s->process->pool);
606
+
607
+ #if APR_HAS_SHARED_MEMORY
608
+ /* If the cache file already exists then delete it. Otherwise we are
609
+ * going to run into problems creating the shared memory. */
610
+ if (config->cache_file) {
611
+ char *lck_file = apr_pstrcat(ptemp, config->cache_file, ".lck",
612
+ NULL);
613
+ apr_file_remove(lck_file, ptemp);
614
+ }
615
+ #endif
616
+ return OK;
617
+ }
618
+
619
+ #if APR_HAS_SHARED_MEMORY
620
+
621
+ /* initializing cache if shared memory size is not zero and we already
622
+ * don't have shm address
623
+ */
624
+ if (!config->cache_shm && config->cache_bytes > 0) {
625
+ #endif
626
+ result = upload_progress_cache_init(p, config);
627
+ if (result != APR_SUCCESS) {
628
+ ap_log_error(APLOG_MARK, APLOG_ERR, result, s,
629
+ "Upload Progress cache: could not create shared memory segment");
630
+ return DONE;
631
+ }
632
+
633
+ #if APR_HAS_SHARED_MEMORY
634
+ if (config->cache_file) {
635
+ config->lock_file = apr_pstrcat(config->pool, config->cache_file, ".lck",
636
+ NULL);
637
+ }
638
+ #endif
639
+
640
+ result = apr_global_mutex_create(&config->cache_lock,
641
+ config->lock_file, APR_LOCK_DEFAULT,
642
+ config->pool);
643
+ if (result != APR_SUCCESS) {
644
+ return result;
645
+ }
646
+
647
+ #ifdef AP_NEED_SET_MUTEX_PERMS
648
+ result = unixd_set_global_mutex_perms(config->cache_lock);
649
+ if (result != APR_SUCCESS) {
650
+ ap_log_error(APLOG_MARK, APLOG_CRIT, result, s,
651
+ "Upload progress cache: failed to set mutex permissions");
652
+ return result;
653
+ }
654
+ #endif
655
+ /* merge config in all vhost */
656
+ s_vhost = s->next;
657
+ while (s_vhost) {
658
+ st_vhost = (ServerConfig *)
659
+ ap_get_module_config(s_vhost->module_config,
660
+ &upload_progress_module);
661
+
662
+ #if APR_HAS_SHARED_MEMORY
663
+ st_vhost->cache_shm = config->cache_shm;
664
+ st_vhost->cache_rmm = config->cache_rmm;
665
+ st_vhost->cache_file = config->cache_file;
666
+ st_vhost->cache_offset = config->cache_offset;
667
+ st_vhost->cache = config->cache;
668
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, result, s,
669
+ "Upload Progress: merging Shared Cache conf: shm=0x%pp rmm=0x%pp "
670
+ "for VHOST: %s", config->cache_shm, config->cache_rmm,
671
+ s_vhost->server_hostname);
672
+ #endif
673
+ st_vhost->lock_file = config->lock_file;
674
+ s_vhost = s_vhost->next;
675
+ }
676
+ #if APR_HAS_SHARED_MEMORY
677
+ }
678
+ else {
679
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
680
+ "Upload Progress cache: cache size is zero, disabling "
681
+ "shared memory cache");
682
+ }
683
+ #endif
684
+
685
+ return(OK);
686
+ }
687
+
688
+ static int reportuploads_handler(request_rec *r)
689
+ {
690
+ int length, received, done, speed, err_status, found=0;
691
+ char *response;
692
+ DirConfig* dir = (DirConfig*)ap_get_module_config(r->per_dir_config, &upload_progress_module);
693
+
694
+ if(!dir->report_enabled) {
695
+ return DECLINED;
696
+ }
697
+ if (r->method_number != M_GET) {
698
+ return HTTP_METHOD_NOT_ALLOWED;
699
+ }
700
+
701
+ /* get the tracking id if any */
702
+ const char *id = get_progress_id(r);
703
+
704
+ if (id == NULL) {
705
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
706
+ "Upload Progress: Not found id in location with reports enabled. uri=%s", id, r->uri);
707
+ return HTTP_NOT_FOUND;
708
+ } else {
709
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
710
+ "Upload Progress: Found id=%s in location with reports enables. uri=%s", id, r->uri);
711
+ }
712
+
713
+ ServerConfig *config = (ServerConfig*)ap_get_module_config(r->server->module_config, &upload_progress_module);
714
+
715
+ if (config->cache_rmm == NULL) {
716
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
717
+ "Upload Progress: Cache error while generating report");
718
+ return HTTP_INTERNAL_SERVER_ERROR ;
719
+ }
720
+
721
+ CACHE_LOCK();
722
+ upload_progress_node_t *node = find_node(r, id);
723
+ if (node != NULL) {
724
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
725
+ "Node with id=%s found for report", id);
726
+ received = node->received;
727
+ length = node->length;
728
+ done = node->done;
729
+ speed = node->speed;
730
+ err_status = node->err_status;
731
+ found = 1;
732
+ } else {
733
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
734
+ "Node with id=%s not found for report", id);
735
+ }
736
+
737
+ CACHE_UNLOCK();
738
+
739
+ ap_set_content_type(r, "text/javascript");
740
+
741
+ apr_table_set(r->headers_out, "Expires", "Mon, 28 Sep 1970 06:00:00 GMT");
742
+ apr_table_set(r->headers_out, "Cache-Control", "no-cache");
743
+
744
+
745
+ /*
746
+ There are 4 possibilities
747
+ * request not yet started: found = false
748
+ * request in error: err_status >= NGX_HTTP_SPECIAL_RESPONSE
749
+ * request finished: done = true
750
+ * request not yet started but registered: length==0 && rest ==0
751
+ * reauest in progress: rest > 0
752
+ */
753
+
754
+
755
+ if (!found) {
756
+ response = apr_psprintf(r->pool, "new Object({ 'state' : 'starting' })");
757
+ } else if (err_status >= HTTP_BAD_REQUEST ) {
758
+ response = apr_psprintf(r->pool, "new Object({ 'state' : 'error', 'status' : %d })", err_status);
759
+ } else if (done) {
760
+ response = apr_psprintf(r->pool, "new Object({ 'state' : 'done' })");
761
+ } else if ( length == 0 && received == 0 ) {
762
+ response = apr_psprintf(r->pool, "new Object({ 'state' : 'starting' })");
763
+ } else {
764
+ response = apr_psprintf(r->pool, "new Object({ 'state' : 'uploading', 'received' : %d, 'size' : %d, 'speed' : %d })", received, length, speed);
765
+ }
766
+
767
+ char *completed_response;
768
+
769
+ /* get the jsonp callback if any */
770
+ const char *jsonp = get_json_callback_param(r);
771
+
772
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
773
+ "Upload Progress: JSON-P callback: %s.", jsonp);
774
+
775
+ // fix up response for jsonp request, if needed
776
+ if (jsonp) {
777
+ completed_response = apr_psprintf(r->pool, "%s(%s);\r\n", jsonp, response);
778
+ } else {
779
+ completed_response = apr_psprintf(r->pool, "%s\r\n", response);
780
+ }
781
+
782
+ ap_rputs(completed_response, r);
783
+
784
+ return OK;
785
+ }
786
+
787
+
788
+ static void upload_progress_child_init(apr_pool_t *p, server_rec *s)
789
+ {
790
+ apr_status_t sts;
791
+ ServerConfig *st = (ServerConfig *)ap_get_module_config(s->module_config,
792
+ &upload_progress_module);
793
+ server_rec *s_vhost;
794
+ ServerConfig *st_vhost;
795
+
796
+ if (!st->cache_lock) return;
797
+
798
+ sts = apr_global_mutex_child_init(&st->cache_lock,
799
+ st->lock_file, p);
800
+ if (sts != APR_SUCCESS) {
801
+ ap_log_error(APLOG_MARK, APLOG_CRIT, sts, s,
802
+ "Failed to initialise global mutex %s in child process %"
803
+ APR_PID_T_FMT ".",
804
+ st->lock_file, getpid());
805
+ }
806
+ s_vhost = s->next;
807
+ while (s_vhost) {
808
+ st_vhost = (ServerConfig *)ap_get_module_config(s_vhost->module_config,
809
+ &upload_progress_module);
810
+ st_vhost->cache_lock = st->cache_lock;
811
+ s_vhost = s_vhost->next;
812
+ }
813
+ }