Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 820 lines (693 sloc) 28.539 kb
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
1 #include <stdint.h>
c38eedd @drogus Initial commit
authored
2 #include <ap_config.h>
3 #include <http_core.h>
4 #include <http_log.h>
e8a9850 @BenBE Backport the apr_shm_remove patch from mod_fcgid
BenBE authored
5 #include <apr_version.h>
c38eedd @drogus Initial commit
authored
6 #include <apr_pools.h>
7 #include <apr_strings.h>
76aa17c @drogus Destroy memory on exit
authored
8 #include "unixd.h"
c38eedd @drogus Initial commit
authored
9
10 #if APR_HAS_SHARED_MEMORY
11 #include "apr_rmm.h"
12 #include "apr_shm.h"
00930ea @mpokrywka Module will not work without shared memory, make APR_HAS_SHARED_MEMOR…
mpokrywka authored
13 #else
14 #error "APR_HAS_SHARED_MEMORY required for upload_progress module"
c38eedd @drogus Initial commit
authored
15 #endif
16
17 #if APR_HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20
cc8954b @mpokrywka Rename file containing backported function
mpokrywka authored
21 #include "ap_backports.h"
cf76b38 @mpokrywka Move apr_shm_remove backport to separate file
mpokrywka authored
22
d4369bb @mpokrywka Also allow passing PROGRESS_ID nad DEBUG_LOCKING as -D preprocessor p…
mpokrywka authored
23 #ifndef PROGRESS_ID
24 # define PROGRESS_ID "X-Progress-ID"
25 #endif
4a63976 @mpokrywka Fix json callback parameter reading
mpokrywka authored
26 #ifndef JSON_CB_PARAM
27 # define JSON_CB_PARAM "callback"
28 #endif
0aeed02 @mpokrywka Allow setting cache filename via -D preprocessor parameter
mpokrywka authored
29 #ifndef CACHE_FILENAME
30 # define CACHE_FILENAME "/tmp/upload_progress_cache"
31 #endif
f959e2a @mpokrywka "expires" node field changed to "updated_at", updated related logic
mpokrywka authored
32 #ifndef PROGRESS_EXPIRES
33 /* shared memory entries not updated in PROGRESS_EXPIRES seconds
34 will be reused when needed */
35 # define PROGRESS_EXPIRES 60
36 #endif
96c4ce8 @mpokrywka Make most debugging noise optional, pass -DUP_DEBUG=1 in CFLAGS to re…
mpokrywka authored
37 #ifndef UP_DEBUG
38 # define UP_DEBUG 0
d4369bb @mpokrywka Also allow passing PROGRESS_ID nad DEBUG_LOCKING as -D preprocessor p…
mpokrywka authored
39 #endif
0af21d9 @BenBE add: Check arguments against a character whitelist and enforce length…
BenBE authored
40
41 #ifndef ARG_ALLOWED_PROGRESSID
42 # define ARG_ALLOWED_PROGRESSID "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_:./!{}"
43 #endif
44 #ifndef ARG_ALLOWED_JSONPCALLBACK
45 # define ARG_ALLOWED_JSONPCALLBACK "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._$"
46 #endif
47 #ifndef ARG_MINLEN_PROGRESSID
48 # define ARG_MINLEN_PROGRESSID 8
49 #endif
50 #ifndef ARG_MAXLEN_PROGRESSID
51 # define ARG_MAXLEN_PROGRESSID 128
52 #endif
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
53 #define UP_STRINGIFY(arg) #arg
54 #define UP_TOSTRING(arg) UP_STRINGIFY(arg)
55 #define UP_ID_FMT "." UP_TOSTRING(ARG_MAXLEN_PROGRESSID) "s"
0af21d9 @BenBE add: Check arguments against a character whitelist and enforce length…
BenBE authored
56 #ifndef ARG_MINLEN_JSONPCALLBACK
57 # define ARG_MINLEN_JSONPCALLBACK 1
58 #endif
59 #ifndef ARG_MAXLEN_JSONPCALLBACK
60 /* This limit is set by most JS implementations on identifier length */
61 # define ARG_MAXLEN_JSONPCALLBACK 64
61eacdb @mpokrywka Prevent shared memory exhaustion by clients who set very long progres…
mpokrywka authored
62 #endif
2eef1b4 @mpokrywka Lock debugging made conditional
mpokrywka authored
63
87fdd77 @mpokrywka Add more debugging noise (useful for debugging apache prefork simulta…
mpokrywka authored
64 #if UP_DEBUG > 0
65 # if UP_DEBUG > 1
66 # define up_log(m,s,err,srv,fmtstr,...) ap_log_error( m, s, err, srv, "pid:%" APR_PID_T_FMT " " fmtstr, getpid(), ##__VA_ARGS__ )
67 # else
68 # define up_log(...) ap_log_error( __VA_ARGS__ )
69 # endif
2eef1b4 @mpokrywka Lock debugging made conditional
mpokrywka authored
70 #else
96c4ce8 @mpokrywka Make most debugging noise optional, pass -DUP_DEBUG=1 in CFLAGS to re…
mpokrywka authored
71 # define up_log(...)
2eef1b4 @mpokrywka Lock debugging made conditional
mpokrywka authored
72 #endif
c38eedd @drogus Initial commit
authored
73
74 #define CACHE_LOCK() do { \
c1cef44 @drogus Display error if apr_global_mutex_lock can't be applied
authored
75 if (config->cache_lock) { \
76 char errbuf[200]; \
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
77 up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "CACHE_LOCK()"); \
c1cef44 @drogus Display error if apr_global_mutex_lock can't be applied
authored
78 apr_status_t status = apr_global_mutex_lock(config->cache_lock); \
79 if (status != APR_SUCCESS) { \
66bd454 @mpokrywka Log cache locking failure to proper server error log
mpokrywka authored
80 ap_log_error(APLOG_MARK, APLOG_CRIT, status, server, \
c1cef44 @drogus Display error if apr_global_mutex_lock can't be applied
authored
81 "%s", apr_strerror(status, errbuf, sizeof(errbuf))); \
82 } \
83 } \
c38eedd @drogus Initial commit
authored
84 } while (0)
85
86 #define CACHE_UNLOCK() do { \
87 if (config->cache_lock) \
5d2f341 @mpokrywka Lock debugging
mpokrywka authored
88 { \
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
89 up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "CACHE_UNLOCK()"); \
c38eedd @drogus Initial commit
authored
90 apr_global_mutex_unlock(config->cache_lock); \
5d2f341 @mpokrywka Lock debugging
mpokrywka authored
91 } \
c38eedd @drogus Initial commit
authored
92 } while (0)
93
94 typedef struct {
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
95 int track_enabled;
96 int report_enabled;
c38eedd @drogus Initial commit
authored
97 } DirConfig;
98
99 typedef struct upload_progress_node_s{
c5c0e65 @mpokrywka Fix file size types and related format strings
mpokrywka authored
100 apr_off_t length;
101 apr_off_t received;
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
102 int err_status;
103 time_t started_at;
c5c0e65 @mpokrywka Fix file size types and related format strings
mpokrywka authored
104 apr_off_t speed; /* bytes per second */
f959e2a @mpokrywka "expires" node field changed to "updated_at", updated related logic
mpokrywka authored
105 time_t updated_at;
61eacdb @mpokrywka Prevent shared memory exhaustion by clients who set very long progres…
mpokrywka authored
106 int done;
0af21d9 @BenBE add: Check arguments against a character whitelist and enforce length…
BenBE authored
107 char key[ARG_MAXLEN_PROGRESSID];
0a95c16 @BenBE fix: Fix the source formatting
BenBE authored
108 } upload_progress_node_t;
c38eedd @drogus Initial commit
authored
109
110 typedef struct {
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
111 apr_time_t cache_updated_at;
112 upload_progress_node_t node;
113 } upload_progress_req_t;
114
115 typedef struct {
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
116 int count;
117 int active;
0a95c16 @BenBE fix: Fix the source formatting
BenBE authored
118 } upload_progress_cache_t;
c38eedd @drogus Initial commit
authored
119
120 typedef struct {
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
121 apr_global_mutex_t *cache_lock;
122 char *lock_file; /* filename for shm lock mutex */
123 apr_size_t cache_bytes;
c38eedd @drogus Initial commit
authored
124 apr_shm_t *cache_shm;
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
125 char *cache_file;
126 upload_progress_cache_t *cache;
36f0b2d @mpokrywka Do not store pointers in shared memory
mpokrywka authored
127 int *list; /* static array of node indexes, list begins with indexes of active nodes */
128 upload_progress_node_t *nodes; /* all nodes allocated at once */
c38eedd @drogus Initial commit
authored
129 } ServerConfig;
130
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
131 static void upload_progress_cache_write(server_rec *, upload_progress_node_t *);
a8c0eb3 @mpokrywka Change argument type of find_node function
mpokrywka authored
132 static upload_progress_node_t *find_node(server_rec *, const char *);
133 static apr_status_t upload_progress_cleanup(void *);
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
134 static const char *get_progress_id(request_rec *, int *);
c38eedd @drogus Initial commit
authored
135
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
136 extern module AP_MODULE_DECLARE_DATA upload_progress_module;
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
137
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
138 static server_rec *global_server = NULL;
c38eedd @drogus Initial commit
authored
139
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
140 static inline ServerConfig *get_server_config(server_rec *s)
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
141 {
142 return (ServerConfig *)ap_get_module_config(s->module_config, &upload_progress_module);
c38eedd @drogus Initial commit
authored
143 }
144
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
145 static inline DirConfig *get_dir_config(request_rec *r)
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
146 {
147 return (DirConfig *)ap_get_module_config(r->per_dir_config, &upload_progress_module);
c38eedd @drogus Initial commit
authored
148 }
149
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
150 static inline upload_progress_req_t *get_request_config(request_rec *r)
151 {
152 return (upload_progress_req_t *)ap_get_module_config(r->request_config, &upload_progress_module);
153 }
154
155
c38eedd @drogus Initial commit
authored
156 static int upload_progress_handle_request(request_rec *r)
157 {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
158 server_rec *server = r->server;
159 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "upload_progress_handle_request()");
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
160
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
161 DirConfig *dir = get_dir_config(r);
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
162
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
163 if (!dir || (dir->track_enabled <= 0)) {
164 return DECLINED;
165 }
166 if (r->method_number != M_POST) {
d5ac908 @BenBE Report non-POST requests when extensive debugging is enabled.
BenBE authored
167 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server,
168 "Upload Progress: Non-POST request in trackable location: %s.", r->uri);
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
169 return DECLINED;
170 }
171
172 int param_error;
173 const char *id = get_progress_id(r, &param_error);
174
175 if (id) {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
176 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server,
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
177 "Upload Progress: Upload id='%s' in trackable location: %s.", id, r->uri);
178
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
179 upload_progress_req_t *reqinfo = (upload_progress_req_t *)apr_pcalloc(r->pool,
180 sizeof(upload_progress_req_t));
181 upload_progress_node_t *node = NULL;
182 if (reqinfo) {
183 reqinfo->cache_updated_at = apr_time_now();
184 upload_progress_node_t *node = &(reqinfo->node);
185
186 strncpy(node->key, id, ARG_MAXLEN_PROGRESSID);
c5ac590 @mpokrywka Remove fill_new_upload_data function
mpokrywka authored
187 time_t t = time(NULL);
188
189 node->received = 0;
190 node->done = 0;
191 node->err_status = 0;
192 node->started_at = t;
193 node->speed = 0;
194 node->updated_at = t;
195 const char *content_length = apr_table_get(r->headers_in, "Content-Length");
196 node->length = 1;
197 /* Content-Length is missing is case of chunked transfer encoding */
198 if (content_length)
199 sscanf(content_length, "%" APR_OFF_T_FMT, &(node->length));
eb87ac0 @mpokrywka Allow reusing nodes of finished requests with same progress id
mpokrywka authored
200 }
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
201
202 ap_set_module_config(r->request_config, &upload_progress_module, reqinfo);
203 apr_pool_cleanup_register(r->pool, r, upload_progress_cleanup, apr_pool_cleanup_null);
204 ap_add_input_filter("UPLOAD_PROGRESS", NULL, r, r->connection);
205
206 upload_progress_cache_write(server, node);
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
207
208 } else if (param_error < 0) {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
209 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server,
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
210 "Upload Progress: Upload with invalid ID in trackable location: %s.", r->uri);
211 /*
212 return HTTP_BAD_REQUEST;
213 return HTTP_NOT_FOUND;
214 */
215
216 } else {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
217 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server,
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
218 "Upload Progress: Upload without ID in trackable location: %s.", r->uri);
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
219 }
eb87ac0 @mpokrywka Allow reusing nodes of finished requests with same progress id
mpokrywka authored
220
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
221 return DECLINED;
c38eedd @drogus Initial commit
authored
222 }
223
224 static const char *report_upload_progress_cmd(cmd_parms *cmd, void *config, int arg)
225 {
96c4ce8 @mpokrywka Make most debugging noise optional, pass -DUP_DEBUG=1 in CFLAGS to re…
mpokrywka authored
226 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, global_server, "report_upload_progress_cmd()");
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
227 DirConfig *dir = (DirConfig *)config;
228 dir->report_enabled = arg ? 1 : -1;
c38eedd @drogus Initial commit
authored
229 return NULL;
230 }
231
232 static const char *track_upload_progress_cmd(cmd_parms *cmd, void *config, int arg)
233 {
96c4ce8 @mpokrywka Make most debugging noise optional, pass -DUP_DEBUG=1 in CFLAGS to re…
mpokrywka authored
234 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, global_server, "track_upload_progress_cmd()");
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
235 DirConfig *dir = (DirConfig *)config;
236 dir->track_enabled = arg ? 1 : -1;
c38eedd @drogus Initial commit
authored
237 return NULL;
238 }
ff601e3 @drogus Ability to change size of shared memory (default id 10kB) with Upload…
authored
239
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
240 static const char* upload_progress_shared_memory_size_cmd(cmd_parms *cmd,
241 void *dummy, const char *arg)
242 {
96c4ce8 @mpokrywka Make most debugging noise optional, pass -DUP_DEBUG=1 in CFLAGS to re…
mpokrywka authored
243 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, global_server, "upload_progress_shared_memory_size_cmd()");
307413e @mpokrywka Move common code extracting server config to separate function
mpokrywka authored
244 ServerConfig *config = get_server_config(cmd->server);
ff601e3 @drogus Ability to change size of shared memory (default id 10kB) with Upload…
authored
245
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
246 long long int n = atoi(arg);
ff601e3 @drogus Ability to change size of shared memory (default id 10kB) with Upload…
authored
247
248 if (n <= 0) {
249 return "UploadProgressSharedMemorySize should be positive";
250 }
251
252 config->cache_bytes = (apr_size_t)n;
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
253
ff601e3 @drogus Ability to change size of shared memory (default id 10kB) with Upload…
authored
254 return NULL;
255 }
c38eedd @drogus Initial commit
authored
256
a79d3b8 @mpokrywka Use apache module infrastructure to merge vhosts configs
mpokrywka authored
257 static void *upload_progress_create_dir_config(apr_pool_t *p, char *dirspec)
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
258 {
a79d3b8 @mpokrywka Use apache module infrastructure to merge vhosts configs
mpokrywka authored
259 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, global_server, "upload_progress_create_dir_config()");
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
260 DirConfig *dir = (DirConfig *)apr_pcalloc(p, sizeof(DirConfig));
c38eedd @drogus Initial commit
authored
261 dir->track_enabled = 0;
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
262 dir->report_enabled = 0;
c38eedd @drogus Initial commit
authored
263 return dir;
264 }
265
a79d3b8 @mpokrywka Use apache module infrastructure to merge vhosts configs
mpokrywka authored
266 static void *upload_progress_merge_dir_config(apr_pool_t *p, void *basev, void *overridev)
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
267 {
268 DirConfig *new = (DirConfig *)apr_pcalloc(p, sizeof(DirConfig));
269 DirConfig *override = (DirConfig *)overridev;
270 DirConfig *base = (DirConfig *)basev;
271 new->track_enabled = (override->track_enabled == 0) ? base->track_enabled :
272 (override->track_enabled > 0 ? 1 : -1);
273 new->report_enabled = (override->report_enabled == 0) ? base->report_enabled :
274 (override->report_enabled > 0 ? 1 : -1);
275 return new;
276 }
277
a79d3b8 @mpokrywka Use apache module infrastructure to merge vhosts configs
mpokrywka authored
278 static void *upload_progress_create_server_config(apr_pool_t *p, server_rec *s)
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
279 {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
280 if (!global_server) global_server = s;
281 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, global_server, "upload_progress_create_server_config()");
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
282 ServerConfig *config = (ServerConfig *)apr_pcalloc(p, sizeof(ServerConfig));
0aeed02 @mpokrywka Allow setting cache filename via -D preprocessor parameter
mpokrywka authored
283 config->cache_file = apr_pstrdup(p, CACHE_FILENAME);
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
284 config->cache_bytes = 51200;
285 return config;
c38eedd @drogus Initial commit
authored
286 }
287
a79d3b8 @mpokrywka Use apache module infrastructure to merge vhosts configs
mpokrywka authored
288 static void *upload_progress_merge_server_config(apr_pool_t *p, void *basev,
289 void *overridesv)
290 {
291 return basev;
292 }
293
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
294 static int read_request_status(request_rec *r)
2e4f2c1 @mpokrywka Always save request status in progress cleanup function
mpokrywka authored
295 {
296 int status;
297
298 if (r) {
299 /* error status rendered in status line is preferred because passenger
300 clobbers request_rec->status when exception occurs */
d460a00 @BenBE add: Add note about a optimization we should check to implement
BenBE authored
301 /* FIXME: Shouldn't we read r->status instead as it's already preparsed? */
2e4f2c1 @mpokrywka Always save request status in progress cleanup function
mpokrywka authored
302 status = r->status_line ? atoi(r->status_line) : 0;
303 if (!ap_is_HTTP_VALID_RESPONSE(status))
304 status = r->status;
305 return status;
306 } else {
307 return 0;
308 }
309 }
310
c38eedd @drogus Initial commit
authored
311 static int track_upload_progress(ap_filter_t *f, apr_bucket_brigade *bb,
312 ap_input_mode_t mode, apr_read_type_e block,
313 apr_off_t readbytes)
314 {
37a4c1b @mpokrywka Use proper server for debug logging in track_upload_progress
mpokrywka authored
315 server_rec *server = f->r->server;
316 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "track_upload_progress()");
e5cfde5 @mpokrywka Fix cache locking
mpokrywka authored
317
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
318 apr_status_t rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
319
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
320 upload_progress_req_t *reqinfo = get_request_config(f->r);
321 if (!reqinfo) {
322 up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "Request config not available");
2163c1a @mpokrywka Add debugging for very unlikely condition in track_upload_progress
mpokrywka authored
323 return rv;
324 }
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
325 upload_progress_node_t *node = &(reqinfo->node);
c38eedd @drogus Initial commit
authored
326
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
327 time_t t = time(NULL);
328 node->updated_at = t;
329 if (rv == APR_SUCCESS) {
330 apr_off_t length;
331 apr_brigade_length(bb, 1, &length);
332 node->received += length;
333 if (node->received > node->length) /* handle chunked tranfer */
334 node->length = node->received;
335 int upload_time = t - node->started_at;
336 if (upload_time > 0) {
337 node->speed = node->received / upload_time;
6e27e38 @mpokrywka Make upload size limit violation immediately reported
mpokrywka authored
338 }
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
339 } else {
340 node->err_status = read_request_status(f->r);
341 reqinfo->cache_updated_at = 0; /* force cache update */
342 }
343
344 apr_time_t now = apr_time_now();
345 if ((now - reqinfo->cache_updated_at) > apr_time_from_msec(500)) {
346 reqinfo->cache_updated_at = now;
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
347 upload_progress_cache_write(server, node);
c38eedd @drogus Initial commit
authored
348 }
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
349
6e27e38 @mpokrywka Make upload size limit violation immediately reported
mpokrywka authored
350 return rv;
c38eedd @drogus Initial commit
authored
351 }
352
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
353 static int check_request_argument(const char *value, int len, char *allowed, int minlen, int maxlen) {
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
354 /* Check the length of the argument */
355 if (len > maxlen) return -1;
356 if (len < minlen) return -2;
357 /* If no whitelist given, assume everything whitelisted */
358 if (!allowed) return 0;
359 /* Check each char to be in the whitelist */
360 if (strspn(value, allowed) < len) return -3;
361 return 0;
0af21d9 @BenBE add: Check arguments against a character whitelist and enforce length…
BenBE authored
362 }
363
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
364 static char *get_param_value(char *p, const char *param_name, int *len) {
715c773 @mpokrywka Move common code from get_{progress_id,json_callback_param} to separa…
mpokrywka authored
365 char pn1[3] = {toupper(param_name[0]), tolower(param_name[0]), 0};
366 int pn_len = strlen(param_name);
367 char *val_end;
368 static char *param_sep = "&";
369
370 while (p) {
371 if ((strncasecmp(p, param_name, pn_len) == 0) && (p[pn_len] == '='))
372 break;
373 if (*p) p++;
374 p = strpbrk(p, pn1);
375 }
376 if (p) {
377 p += (pn_len + 1);
378 *len = strcspn(p, param_sep);
379 }
380 return p;
381 }
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
382
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
383 static const char *get_progress_id(request_rec *r, int *param_error) {
715c773 @mpokrywka Move common code from get_{progress_id,json_callback_param} to separa…
mpokrywka authored
384 int len;
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
385
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
386 /* try to find progress id in http headers */
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
387 const char *id = apr_table_get(r->headers_in, PROGRESS_ID);
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
388 if (id) {
389 *param_error = check_request_argument(id, strlen(id), ARG_ALLOWED_PROGRESSID,
390 ARG_MINLEN_PROGRESSID, ARG_MAXLEN_PROGRESSID);
391 if (*param_error) return NULL;
392 return id;
393 }
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
394
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
395 /* if progress id not found in headers, check request args (query string) */
396 id = get_param_value(r->args, PROGRESS_ID, &len);
397 if (id) {
398 *param_error = check_request_argument(id, len, ARG_ALLOWED_PROGRESSID,
399 ARG_MINLEN_PROGRESSID, ARG_MAXLEN_PROGRESSID);
400 if (*param_error) return NULL;
401 return apr_pstrndup(r->connection->pool, id, len);
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
402 }
403
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
404 *param_error = 1; /* not found */
405 return NULL;
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
406 }
407
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
408 static const char *get_json_callback_param(request_rec *r, int *param_error) {
715c773 @mpokrywka Move common code from get_{progress_id,json_callback_param} to separa…
mpokrywka authored
409 char *val;
410 int len;
20fed47 @deadprogram Handle cross-domain upload progress requests using JSON-P, in additio…
deadprogram authored
411
4a63976 @mpokrywka Fix json callback parameter reading
mpokrywka authored
412 val = get_param_value(r->args, JSON_CB_PARAM, &len);
715c773 @mpokrywka Move common code from get_{progress_id,json_callback_param} to separa…
mpokrywka authored
413 if (val) {
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
414 *param_error = check_request_argument(val, len, ARG_ALLOWED_JSONPCALLBACK,
415 ARG_MINLEN_JSONPCALLBACK, ARG_MAXLEN_JSONPCALLBACK);
416 if (*param_error) return NULL;
715c773 @mpokrywka Move common code from get_{progress_id,json_callback_param} to separa…
mpokrywka authored
417 return apr_pstrndup(r->connection->pool, val, len);
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
418 }
0af21d9 @BenBE add: Check arguments against a character whitelist and enforce length…
BenBE authored
419
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
420 *param_error = 1; /* not found */
0af21d9 @BenBE add: Check arguments against a character whitelist and enforce length…
BenBE authored
421 return NULL;
c38eedd @drogus Initial commit
authored
422 }
423
dff9a03 @BenBE mrg: Merged changes from drogus/master
BenBE authored
424 static inline int check_node(upload_progress_node_t *node, const char *key) {
425 return ((node) && (strncasecmp(node->key, key, ARG_MAXLEN_PROGRESSID) == 0)) ? 1 : 0;
c38eedd @drogus Initial commit
authored
426 }
427
a8c0eb3 @mpokrywka Change argument type of find_node function
mpokrywka authored
428 static upload_progress_node_t *find_node(server_rec *server, const char *key) {
429 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "find_node()");
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
430
a8c0eb3 @mpokrywka Change argument type of find_node function
mpokrywka authored
431 ServerConfig *config = get_server_config(server);
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
432 upload_progress_cache_t *cache = config->cache;
36f0b2d @mpokrywka Do not store pointers in shared memory
mpokrywka authored
433 upload_progress_node_t *node, *nodes = config->nodes;
434 int *list = config->list;
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
435 int active = cache->active;
436 int i;
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
437
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
438 for (i = 0; i < active; i++) {
439 node = &nodes[list[i]];
440 if (check_node(node, key))
441 return node;
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
442 }
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
443 return NULL;
c38eedd @drogus Initial commit
authored
444 }
445
446 static apr_status_t upload_progress_cleanup(void *data)
447 {
6ad1ef8 @mpokrywka Implemented proper locking on request cleanup function
mpokrywka authored
448 request_rec *r = (request_rec *)data;
449 server_rec *server = r->server;
450 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "upload_progress_cleanup()");
ec690b0 @BenBE fix: Added locking for upload_progress_cleanup
BenBE authored
451
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
452 upload_progress_req_t *reqinfo = get_request_config(r);
453 if (!reqinfo) {
454 up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "Request config not available");
6ad1ef8 @mpokrywka Implemented proper locking on request cleanup function
mpokrywka authored
455 return APR_SUCCESS;
c38eedd @drogus Initial commit
authored
456 }
d8246af @mpokrywka Increase performance by taking less global locks
mpokrywka authored
457 upload_progress_node_t *node = &(reqinfo->node);
458 node->err_status = read_request_status(r);
459 node->updated_at = time(NULL);
460 node->done = 1;
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
461 upload_progress_cache_write(server, node);
ec690b0 @BenBE fix: Added locking for upload_progress_cleanup
BenBE authored
462
c38eedd @drogus Initial commit
authored
463 return APR_SUCCESS;
464 }
465
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
466 static void upload_progress_cache_write(server_rec *server, upload_progress_node_t *new_data)
467 {
468 if (!new_data) return;
469 ServerConfig *config = get_server_config(server);
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
470
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
471 CACHE_LOCK();
472 upload_progress_node_t *node = find_node(server, new_data->key);
473 time_t now = time(NULL);
474 #define EXPIRED(node,now) ((now - node->updated_at) > PROGRESS_EXPIRES)
475 if (node) {
476 /* reuse node if: request finished, expired, or same started_at as node */
477 if (node->started_at == new_data->started_at || node->done || EXPIRED(node, now)) {
478 memcpy(node, new_data, sizeof(upload_progress_node_t));
479 up_log(APLOG_MARK, APLOG_DEBUG, 0, server,
480 "Upload Progress: Reused existing node with id='%" UP_ID_FMT "'.", node->key);
481 } else {
482 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server,
483 "Upload Progress: Upload with id='%" UP_ID_FMT "' already exists, ignoring.", node->key);
484 }
485 } else {
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
486
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
487 up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "cleaning expired cache nodes");
488
489 upload_progress_cache_t *cache = config->cache;
490 upload_progress_node_t *nodes = config->nodes;
491 int *list = config->list;
492 int i, tmp;
493
494 /* check active nodes list, if expired node found
495 then swap it with last active and shrink active list by one */
496 for (i = 0; i < cache->active; i++) {
497 node = &nodes[list[i]];
498 if (EXPIRED(node, now)) {
499 cache->active -= 1;
500 tmp = list[cache->active];
501 list[cache->active] = list[i];
502 list[i] = tmp;
503 i--;
504 }
9ce406b @drogus Expire upload data 60s after upload has ended.
authored
505 }
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
506
507 if (cache->active < cache->count) {
508 node = &config->nodes[config->list[cache->active]];
509 cache->active += 1;
510 memcpy(node, new_data, sizeof(upload_progress_node_t));
511 up_log(APLOG_MARK, APLOG_DEBUG, 0, server,
512 "Upload Progress: Added upload with id='%" UP_ID_FMT "' to list.", node->key);
513 } else {
514 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Cache full");
9ce406b @drogus Expire upload data 60s after upload has ended.
authored
515 }
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
516
e5cfde5 @mpokrywka Fix cache locking
mpokrywka authored
517 }
6e7b62d @mpokrywka Move cache data writing to separate function
mpokrywka authored
518 CACHE_UNLOCK();
9ce406b @drogus Expire upload data 60s after upload has ended.
authored
519
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
520 }
521
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
522 static apr_status_t upload_progress_cache_init(apr_pool_t *pool, ServerConfig *config)
c38eedd @drogus Initial commit
authored
523 {
96c4ce8 @mpokrywka Make most debugging noise optional, pass -DUP_DEBUG=1 in CFLAGS to re…
mpokrywka authored
524 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, global_server, "upload_progress_cache_init()");
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
525
c38eedd @drogus Initial commit
authored
526 apr_status_t result;
527 apr_size_t size;
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
528 int nodes_cnt, i;
c38eedd @drogus Initial commit
authored
529
530 if (config->cache_file) {
531 /* Remove any existing shm segment with this name. */
d88267f @mpokrywka Do not create private pool, use global
mpokrywka authored
532 apr_shm_remove(config->cache_file, pool);
c38eedd @drogus Initial commit
authored
533 }
534
535 size = APR_ALIGN_DEFAULT(config->cache_bytes);
d88267f @mpokrywka Do not create private pool, use global
mpokrywka authored
536 result = apr_shm_create(&config->cache_shm, size, config->cache_file, pool);
c38eedd @drogus Initial commit
authored
537 if (result != APR_SUCCESS) {
538 return result;
539 }
540
541 /* Determine the usable size of the shm segment. */
542 size = apr_shm_size_get(config->cache_shm);
36f0b2d @mpokrywka Do not store pointers in shared memory
mpokrywka authored
543 nodes_cnt = (size - sizeof(upload_progress_cache_t)) /
544 (sizeof(int) + sizeof(upload_progress_node_t));
c38eedd @drogus Initial commit
authored
545
36f0b2d @mpokrywka Do not store pointers in shared memory
mpokrywka authored
546 /* init cache */
547 config->cache = (upload_progress_cache_t *)apr_shm_baseaddr_get(config->cache_shm);
548 config->list = (int *)(config->cache + 1);
549 config->nodes = (upload_progress_node_t *)(config->list + nodes_cnt);
550 config->cache->count = nodes_cnt;
551 config->cache->active = 0;
552 for (i = 0; i < nodes_cnt; i++) config->list[i] = i;
2395a2f @mpokrywka Simplify progress nodes memory organization
mpokrywka authored
553
554 ap_log_error(APLOG_MARK, APLOG_INFO, 0, global_server,
c4477ba @mpokrywka Improve logging of parameter parsing in handle_request and reportuplo…
mpokrywka authored
555 "Upload Progress: monitoring max %i simultaneous uploads, id (%s) length %i..%i",
556 nodes_cnt, PROGRESS_ID, ARG_MINLEN_PROGRESSID, ARG_MAXLEN_PROGRESSID);
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
557
c38eedd @drogus Initial commit
authored
558 return APR_SUCCESS;
559 }
560
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
561 static int upload_progress_init(apr_pool_t *p, apr_pool_t *plog,
c38eedd @drogus Initial commit
authored
562 apr_pool_t *ptemp,
563 server_rec *s) {
96c4ce8 @mpokrywka Make most debugging noise optional, pass -DUP_DEBUG=1 in CFLAGS to re…
mpokrywka authored
564 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, s, "upload_progress_init()");
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
565
c38eedd @drogus Initial commit
authored
566 apr_status_t result;
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
567
307413e @mpokrywka Move common code extracting server config to separate function
mpokrywka authored
568 ServerConfig *config = get_server_config(s);
c38eedd @drogus Initial commit
authored
569
570 void *data;
571 const char *userdata_key = "upload_progress_init";
572
fbdf306 @drogus More debug messages
authored
573 /* upload_progress_init will be called twice. Don't bother
c38eedd @drogus Initial commit
authored
574 * going through all of the initialization on the first call
575 * because it will just be thrown away.*/
576 apr_pool_userdata_get(&data, userdata_key, s->process->pool);
577 if (!data) {
578 apr_pool_userdata_set((const void *)1, userdata_key,
579 apr_pool_cleanup_null, s->process->pool);
580
581 /* If the cache file already exists then delete it. Otherwise we are
582 * going to run into problems creating the shared memory. */
583 if (config->cache_file) {
584 char *lck_file = apr_pstrcat(ptemp, config->cache_file, ".lck",
585 NULL);
8266457 @mpokrywka Add debugging info when lock file is removed
mpokrywka authored
586 up_log(APLOG_MARK, APLOG_DEBUG, 0, s, "Upload Progress: Remove lock file");
c38eedd @drogus Initial commit
authored
587 apr_file_remove(lck_file, ptemp);
588 }
589 return OK;
590 }
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
591
c38eedd @drogus Initial commit
authored
592 /* initializing cache if shared memory size is not zero and we already
593 * don't have shm address
594 */
595 if (!config->cache_shm && config->cache_bytes > 0) {
596 result = upload_progress_cache_init(p, config);
597 if (result != APR_SUCCESS) {
598 ap_log_error(APLOG_MARK, APLOG_ERR, result, s,
ce8706c @drogus hiding copy&paste evidence ;-)
authored
599 "Upload Progress cache: could not create shared memory segment");
c38eedd @drogus Initial commit
authored
600 return DONE;
601 }
602
603 if (config->cache_file) {
d88267f @mpokrywka Do not create private pool, use global
mpokrywka authored
604 config->lock_file = apr_pstrcat(p, config->cache_file, ".lck",
c38eedd @drogus Initial commit
authored
605 NULL);
606 }
607
608 result = apr_global_mutex_create(&config->cache_lock,
609 config->lock_file, APR_LOCK_DEFAULT,
d88267f @mpokrywka Do not create private pool, use global
mpokrywka authored
610 p);
c38eedd @drogus Initial commit
authored
611 if (result != APR_SUCCESS) {
612 return result;
613 }
614
76aa17c @drogus Destroy memory on exit
authored
615 #ifdef AP_NEED_SET_MUTEX_PERMS
c38eedd @drogus Initial commit
authored
616 result = unixd_set_global_mutex_perms(config->cache_lock);
617 if (result != APR_SUCCESS) {
618 ap_log_error(APLOG_MARK, APLOG_CRIT, result, s,
fbdf306 @drogus More debug messages
authored
619 "Upload progress cache: failed to set mutex permissions");
c38eedd @drogus Initial commit
authored
620 return result;
621 }
76aa17c @drogus Destroy memory on exit
authored
622 #endif
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
623
624 } else {
c38eedd @drogus Initial commit
authored
625 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
626 "Upload Progress cache: cache size is zero, disabling "
627 "shared memory cache");
628 }
629
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
630 return(OK);
c38eedd @drogus Initial commit
authored
631 }
632
633 static int reportuploads_handler(request_rec *r)
634 {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
635 server_rec *server = r->server;
636 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, server, "reportuploads_handler()");
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
637
72ca5e5 @mpokrywka Implemented "ETA" and "download completed time" features
mpokrywka authored
638 upload_progress_node_t upload, *found;
639 int param_error;
c38eedd @drogus Initial commit
authored
640 char *response;
259102c @mpokrywka Reduce code indentation, move common code extracting per_dir_config t…
mpokrywka authored
641 DirConfig *dir = get_dir_config(r);
c38eedd @drogus Initial commit
authored
642
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
643 if (!dir || (dir->report_enabled <= 0)) {
c38eedd @drogus Initial commit
authored
644 return DECLINED;
645 }
646 if (r->method_number != M_GET) {
647 return HTTP_METHOD_NOT_ALLOWED;
648 }
649
650 /* get the tracking id if any */
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
651 const char *id = get_progress_id(r, &param_error);
c38eedd @drogus Initial commit
authored
652
653 if (id == NULL) {
c4477ba @mpokrywka Improve logging of parameter parsing in handle_request and reportuplo…
mpokrywka authored
654 if (param_error < 0) {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
655 ap_log_error(APLOG_MARK, APLOG_INFO, 0, server,
c4477ba @mpokrywka Improve logging of parameter parsing in handle_request and reportuplo…
mpokrywka authored
656 "Upload Progress: Report requested with invalid id. uri=%s", r->uri);
657 return HTTP_BAD_REQUEST;
658 } else {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
659 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server,
c4477ba @mpokrywka Improve logging of parameter parsing in handle_request and reportuplo…
mpokrywka authored
660 "Upload Progress: Report requested without id. uri=%s", r->uri);
661 return HTTP_NOT_FOUND;
662 }
c38eedd @drogus Initial commit
authored
663 }
664
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
665 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server,
c4477ba @mpokrywka Improve logging of parameter parsing in handle_request and reportuplo…
mpokrywka authored
666 "Upload Progress: Report requested with id='%s'. uri=%s", id, r->uri);
667
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
668 ServerConfig *config = get_server_config(server);
c38eedd @drogus Initial commit
authored
669
670 CACHE_LOCK();
a8c0eb3 @mpokrywka Change argument type of find_node function
mpokrywka authored
671 found = find_node(server, id);
72ca5e5 @mpokrywka Implemented "ETA" and "download completed time" features
mpokrywka authored
672 if (found) {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
673 up_log(APLOG_MARK, APLOG_DEBUG, 0, server,
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
674 "Node with id=%s found for report", id);
72ca5e5 @mpokrywka Implemented "ETA" and "download completed time" features
mpokrywka authored
675 memcpy(&upload, found, sizeof(upload));
fbdf306 @drogus More debug messages
authored
676 } else {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
677 up_log(APLOG_MARK, APLOG_DEBUG, 0, server,
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
678 "Node with id=%s not found for report", id);
c38eedd @drogus Initial commit
authored
679 }
680 CACHE_UNLOCK();
681
cfe02f1 changed the content-type from text/javascript to application/json
Francisco Dalla Rosa Soares authored
682 ap_set_content_type(r, "application/json");
c38eedd @drogus Initial commit
authored
683
684 apr_table_set(r->headers_out, "Expires", "Mon, 28 Sep 1970 06:00:00 GMT");
685 apr_table_set(r->headers_out, "Cache-Control", "no-cache");
686
3e92248 @BenBE Avoid integer overflows by using proper types everywhere
BenBE authored
687 /* There are 4 possibilities
688 * request not yet started: found = false
689 * request in error: err_status >= NGX_HTTP_SPECIAL_RESPONSE
690 * request finished: done = true
691 * request not yet started but registered: length==0 && rest ==0
446c296 @BenBE fix: Fixed typo reported by Jérémy Bobbio
BenBE authored
692 * request in progress: rest > 0
3e92248 @BenBE Avoid integer overflows by using proper types everywhere
BenBE authored
693 */
c38eedd @drogus Initial commit
authored
694
695 if (!found) {
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
696 response = apr_psprintf(r->pool, "{ \"state\" : \"starting\", \"uuid\" : \"%s\" }", id);
72ca5e5 @mpokrywka Implemented "ETA" and "download completed time" features
mpokrywka authored
697 } else if (upload.err_status >= HTTP_BAD_REQUEST ) {
698 response = apr_psprintf(r->pool, "{ "
699 "\"state\": \"error\", "
700 "\"status\": %d, "
701 "\"uuid\": \"%s\" "
702 "}", upload.err_status, id);
703 } else if (upload.done) {
704 response = apr_psprintf(r->pool, "{ "
705 "\"state\": \"done\", "
c5c0e65 @mpokrywka Fix file size types and related format strings
mpokrywka authored
706 "\"size\": %" APR_OFF_T_FMT ", "
707 "\"speed\": %" APR_OFF_T_FMT ", "
708 "\"started_at\": %li, "
709 "\"completed_at\": %li, "
72ca5e5 @mpokrywka Implemented "ETA" and "download completed time" features
mpokrywka authored
710 "\"uuid\": \"%s\" "
711 "}", upload.length, upload.speed, upload.started_at, upload.updated_at, id);
712 } else if (upload.received == 0) {
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
713 response = apr_psprintf(r->pool, "{ \"state\" : \"starting\", \"uuid\" : \"%s\" }", id);
c38eedd @drogus Initial commit
authored
714 } else {
72ca5e5 @mpokrywka Implemented "ETA" and "download completed time" features
mpokrywka authored
715 time_t eta = 0, t = time(NULL);
716 if (upload.speed > 0) eta = upload.started_at + upload.length / upload.speed;
717 if (eta <= t) eta = t + 1;
718 response = apr_psprintf(r->pool, "{ "
719 "\"state\": \"uploading\", "
c5c0e65 @mpokrywka Fix file size types and related format strings
mpokrywka authored
720 "\"received\": %" APR_OFF_T_FMT ", "
721 "\"size\": %" APR_OFF_T_FMT ", "
722 "\"speed\": %" APR_OFF_T_FMT ", "
723 "\"started_at\": %li, "
724 "\"eta\": %li, "
72ca5e5 @mpokrywka Implemented "ETA" and "download completed time" features
mpokrywka authored
725 "\"uuid\": \"%s\" "
726 "}", upload.received, upload.length, upload.speed, upload.started_at, eta, id);
c38eedd @drogus Initial commit
authored
727 }
728
20fed47 @deadprogram Handle cross-domain upload progress requests using JSON-P, in additio…
deadprogram authored
729 char *completed_response;
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
730
20fed47 @deadprogram Handle cross-domain upload progress requests using JSON-P, in additio…
deadprogram authored
731 /* get the jsonp callback if any */
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
732 const char *jsonp = get_json_callback_param(r, &param_error);
733
734 if (param_error < 0) {
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
735 ap_log_error(APLOG_MARK, APLOG_INFO, 0, server,
3cd3acc @mpokrywka Improve parameter checking
mpokrywka authored
736 "Upload Progress: Report requested with invalid JSON-P callback. uri=%s", r->uri);
737 return HTTP_BAD_REQUEST;
738 }
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
739
881d95c @mpokrywka Remove "server" field from ServerConfig
mpokrywka authored
740 up_log(APLOG_MARK, APLOG_DEBUG, 0, server,
f318ec5 @drogus callback should be assigned with null value
authored
741 "Upload Progress: JSON-P callback: %s.", jsonp);
742
20fed47 @deadprogram Handle cross-domain upload progress requests using JSON-P, in additio…
deadprogram authored
743 // fix up response for jsonp request, if needed
744 if (jsonp) {
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
745 completed_response = apr_psprintf(r->pool, "%s(%s);\r\n", jsonp, response);
20fed47 @deadprogram Handle cross-domain upload progress requests using JSON-P, in additio…
deadprogram authored
746 } else {
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
747 completed_response = apr_psprintf(r->pool, "%s\r\n", response);
20fed47 @deadprogram Handle cross-domain upload progress requests using JSON-P, in additio…
deadprogram authored
748 }
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
749
20fed47 @deadprogram Handle cross-domain upload progress requests using JSON-P, in additio…
deadprogram authored
750 ap_rputs(completed_response, r);
c38eedd @drogus Initial commit
authored
751
752 return OK;
753 }
754
755 static void upload_progress_child_init(apr_pool_t *p, server_rec *s)
756 {
96c4ce8 @mpokrywka Make most debugging noise optional, pass -DUP_DEBUG=1 in CFLAGS to re…
mpokrywka authored
757 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, s, "upload_progress_child_init()");
40b9b01 @BenBE Print our position for all functions for debugging purposes
BenBE authored
758
d9b3243 @mpokrywka Cosmetic code changes (removed unused local variables, renamed local …
mpokrywka authored
759 apr_status_t rv;
760 ServerConfig *config = get_server_config(s);
c38eedd @drogus Initial commit
authored
761
d9b3243 @mpokrywka Cosmetic code changes (removed unused local variables, renamed local …
mpokrywka authored
762 if (!config->cache_lock) {
525ab0f @mpokrywka Add logging of missing global mutex on child process init
mpokrywka authored
763 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, "Global mutex not set.");
6fc6a1c @BenBE Fixed Whitespace to 4 spaces per tab
BenBE authored
764 return;
525ab0f @mpokrywka Add logging of missing global mutex on child process init
mpokrywka authored
765 }
c38eedd @drogus Initial commit
authored
766
d9b3243 @mpokrywka Cosmetic code changes (removed unused local variables, renamed local …
mpokrywka authored
767 rv = apr_global_mutex_child_init(&config->cache_lock, config->lock_file, p);
768 if (rv != APR_SUCCESS) {
769 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
c38eedd @drogus Initial commit
authored
770 "Failed to initialise global mutex %s in child process %"
d9b3243 @mpokrywka Cosmetic code changes (removed unused local variables, renamed local …
mpokrywka authored
771 APR_PID_T_FMT ".", config->lock_file, getpid());
c38eedd @drogus Initial commit
authored
772 }
29becc8 @mpokrywka Regenerate shared memory pointers in child processes
mpokrywka authored
773
774 if (!config->cache_shm) {
775 rv = apr_shm_attach(&config->cache_shm, config->cache_file, p);
776 if (rv != APR_SUCCESS) {
777 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, "Failed to attach to "
778 "shared memory file '%s'", config->cache_file);
779 return;
780 }
c38eedd @drogus Initial commit
authored
781 }
29becc8 @mpokrywka Regenerate shared memory pointers in child processes
mpokrywka authored
782
783 config->cache = (upload_progress_cache_t *)apr_shm_baseaddr_get(config->cache_shm);
784 config->list = (int *)(config->cache + 1);
785 config->nodes = (upload_progress_node_t *)(config->list + config->cache->count);
c38eedd @drogus Initial commit
authored
786 }
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
787
788 static const command_rec upload_progress_cmds[] =
789 {
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
790 AP_INIT_FLAG("TrackUploads", track_upload_progress_cmd, NULL, OR_AUTHCFG,
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
791 "Track upload progress in this location"),
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
792 AP_INIT_FLAG("ReportUploads", report_upload_progress_cmd, NULL, OR_AUTHCFG,
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
793 "Report upload progress in this location"),
3d19606 @mpokrywka Make all functions static to restrict their visibility
mpokrywka authored
794 AP_INIT_TAKE1("UploadProgressSharedMemorySize", upload_progress_shared_memory_size_cmd, NULL, RSRC_CONF,
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
795 "Size of shared memory used to keep uploads data, default 100KB"),
796 { NULL }
797 };
798
799 static void upload_progress_register_hooks (apr_pool_t *p)
800 {
801 /**/up_log(APLOG_MARK, APLOG_DEBUG, 0, global_server, "upload_progress_register_hooks()");
802
803 ap_hook_fixups(upload_progress_handle_request, NULL, NULL, APR_HOOK_FIRST);
804 ap_hook_handler(reportuploads_handler, NULL, NULL, APR_HOOK_FIRST);
805 ap_hook_post_config(upload_progress_init, NULL, NULL, APR_HOOK_MIDDLE);
806 ap_hook_child_init(upload_progress_child_init, NULL, NULL, APR_HOOK_MIDDLE);
807 ap_register_input_filter("UPLOAD_PROGRESS", track_upload_progress, NULL, AP_FTYPE_RESOURCE);
808 }
809
810 module AP_MODULE_DECLARE_DATA upload_progress_module =
811 {
812 STANDARD20_MODULE_STUFF,
a79d3b8 @mpokrywka Use apache module infrastructure to merge vhosts configs
mpokrywka authored
813 upload_progress_create_dir_config,
814 upload_progress_merge_dir_config,
815 upload_progress_create_server_config,
816 upload_progress_merge_server_config,
9d52740 @mpokrywka Apache dir config merging implemented, Closes #16
mpokrywka authored
817 upload_progress_cmds,
818 upload_progress_register_hooks, /* callback for registering hooks */
819 };
Something went wrong with that request. Please try again.