zena 0.15.0 → 0.15.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }