10 #include "stat_cache.h"
17 * this is a uploadprogress for a lighttpd plugin
24 } connection_map_entry
;
27 connection_map_entry
**ptr
;
33 /* plugin config for all request/connections */
42 connection_map
*con_map
;
44 plugin_config
**config_storage
;
55 /* init the plugin data */
56 static connection_map
*connection_map_init() {
59 cm
= calloc(1, sizeof(*cm
));
64 static void connection_map_free(connection_map
*cm
) {
66 for (i
= 0; i
< cm
->size
; i
++) {
67 connection_map_entry
*cme
= cm
->ptr
[i
];
72 buffer_free(cme
->con_id
);
80 static int connection_map_insert(connection_map
*cm
, connection
*con
, buffer
*con_id
) {
81 connection_map_entry
*cme
;
86 cm
->ptr
= malloc(cm
->size
* sizeof(*(cm
->ptr
)));
87 for (i
= 0; i
< cm
->size
; i
++) {
90 } else if (cm
->used
== cm
->size
) {
92 cm
->ptr
= realloc(cm
->ptr
, cm
->size
* sizeof(*(cm
->ptr
)));
93 for (i
= cm
->used
; i
< cm
->size
; i
++) {
98 if (cm
->ptr
[cm
->used
]) {
99 /* is already alloced, just reuse it */
100 cme
= cm
->ptr
[cm
->used
];
102 cme
= malloc(sizeof(*cme
));
103 cme
->con_id
= buffer_init();
105 buffer_copy_buffer(cme
->con_id
, con_id
);
108 cm
->ptr
[cm
->used
++] = cme
;
113 static connection
*connection_map_get_connection(connection_map
*cm
, buffer
*con_id
) {
116 for (i
= 0; i
< cm
->used
; i
++) {
117 connection_map_entry
*cme
= cm
->ptr
[i
];
119 if (buffer_is_equal(cme
->con_id
, con_id
)) {
120 /* found connection */
128 static int connection_map_remove_connection(connection_map
*cm
, connection
*con
) {
131 for (i
= 0; i
< cm
->used
; i
++) {
132 connection_map_entry
*cme
= cm
->ptr
[i
];
134 if (cme
->con
== con
) {
135 /* found connection */
137 buffer_reset(cme
->con_id
);
142 /* swap positions with the last entry */
144 cm
->ptr
[i
] = cm
->ptr
[cm
->used
];
145 cm
->ptr
[cm
->used
] = cme
;
155 /* init the plugin data */
156 INIT_FUNC(mod_uploadprogress_init
) {
159 p
= calloc(1, sizeof(*p
));
161 p
->con_map
= connection_map_init();
166 /* detroy the plugin data */
167 FREE_FUNC(mod_uploadprogress_free
) {
168 plugin_data
*p
= p_d
;
172 if (!p
) return HANDLER_GO_ON
;
174 if (p
->config_storage
) {
176 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
177 plugin_config
*s
= p
->config_storage
[i
];
179 if (NULL
== s
) continue;
181 buffer_free(s
->progress_url
);
185 free(p
->config_storage
);
188 connection_map_free(p
->con_map
);
192 return HANDLER_GO_ON
;
195 /* handle plugin config and check values */
197 SETDEFAULTS_FUNC(mod_uploadprogress_set_defaults
) {
198 plugin_data
*p
= p_d
;
201 config_values_t cv
[] = {
202 { "upload-progress.progress-url", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 0 */
203 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
206 if (!p
) return HANDLER_ERROR
;
208 p
->config_storage
= calloc(1, srv
->config_context
->used
* sizeof(plugin_config
*));
210 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
211 data_config
const* config
= (data_config
const*)srv
->config_context
->data
[i
];
214 s
= calloc(1, sizeof(plugin_config
));
215 s
->progress_url
= buffer_init();
217 cv
[0].destination
= s
->progress_url
;
219 p
->config_storage
[i
] = s
;
221 if (0 != config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
)) {
222 return HANDLER_ERROR
;
226 return HANDLER_GO_ON
;
231 static int mod_uploadprogress_patch_connection(server
*srv
, connection
*con
, plugin_data
*p
) {
233 plugin_config
*s
= p
->config_storage
[0];
237 /* skip the first, the global context */
238 for (i
= 1; i
< srv
->config_context
->used
; i
++) {
239 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
240 s
= p
->config_storage
[i
];
242 /* condition didn't match */
243 if (!config_check_cond(srv
, con
, dc
)) continue;
246 for (j
= 0; j
< dc
->value
->used
; j
++) {
247 data_unset
*du
= dc
->value
->data
[j
];
249 if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("upload-progress.progress-url"))) {
263 * for the first request we check if it is a post-request
265 * if no, move out, don't care about them
267 * if yes, take the connection structure and register it locally
268 * in the progress-struct together with an session-id (md5 ... )
270 * if the connections closes, cleanup the entry in the progress-struct
272 * a second request can now get the info about the size of the upload,
277 URIHANDLER_FUNC(mod_uploadprogress_uri_handler
) {
278 plugin_data
*p
= p_d
;
282 connection
*post_con
= NULL
;
286 if (buffer_string_is_empty(con
->uri
.path
)) return HANDLER_GO_ON
;
287 switch(con
->request
.http_method
) {
288 case HTTP_METHOD_GET
:
289 case HTTP_METHOD_POST
: break;
290 default: return HANDLER_GO_ON
;
293 mod_uploadprogress_patch_connection(srv
, con
, p
);
294 if (buffer_string_is_empty(p
->conf
.progress_url
)) return HANDLER_GO_ON
;
296 if (con
->request
.http_method
== HTTP_METHOD_GET
) {
297 if (!buffer_is_equal(con
->uri
.path
, p
->conf
.progress_url
)) {
298 return HANDLER_GO_ON
;
302 /* the request has to contain a 32byte ID */
304 if (NULL
== (ds
= (data_string
*)array_get_element(con
->request
.headers
, "X-Progress-ID"))) {
305 if (!buffer_string_is_empty(con
->uri
.query
)) {
306 /* perhaps the POST request is using the querystring to pass the X-Progress-ID */
309 return HANDLER_GO_ON
;
315 len
= buffer_string_length(b
);
317 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
318 "len of progress-id != 32:", len
);
319 return HANDLER_GO_ON
;
322 for (i
= 0; i
< len
; i
++) {
325 if (!light_isxdigit(c
)) {
326 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
327 "non-xdigit in progress-id:", b
);
328 return HANDLER_GO_ON
;
332 /* check if this is a POST request */
333 switch(con
->request
.http_method
) {
334 case HTTP_METHOD_POST
:
336 connection_map_insert(p
->con_map
, con
, b
);
338 return HANDLER_GO_ON
;
339 case HTTP_METHOD_GET
:
340 buffer_reset(con
->physical
.path
);
342 con
->file_started
= 1;
343 con
->file_finished
= 1;
345 con
->http_status
= 200;
348 /* get the connection */
349 if (NULL
== (post_con
= connection_map_get_connection(p
->con_map
, b
))) {
350 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
353 chunkqueue_get_append_mem(con
->write_queue
, CONST_STR_LEN("not in progress"));
355 return HANDLER_FINISHED
;
358 response_header_overwrite(srv
, con
, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml"));
360 /* just an attempt the force the IE/proxies to NOT cache the request ... doesn't help :( */
361 response_header_overwrite(srv
, con
, CONST_STR_LEN("Pragma"), CONST_STR_LEN("no-cache"));
362 response_header_overwrite(srv
, con
, CONST_STR_LEN("Expires"), CONST_STR_LEN("Thu, 19 Nov 1981 08:52:00 GMT"));
363 response_header_overwrite(srv
, con
, CONST_STR_LEN("Cache-Control"), CONST_STR_LEN("no-store, no-cache, must-revalidate, post-check=0, pre-check=0"));
368 buffer_copy_string_len(b
, CONST_STR_LEN(
369 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>"
372 buffer_append_int(b
, post_con
->request
.content_length
);
373 buffer_append_string_len(b
, CONST_STR_LEN(
376 buffer_append_int(b
, post_con
->request_content_queue
->bytes_in
);
377 buffer_append_string_len(b
, CONST_STR_LEN(
382 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "...", b
);
385 chunkqueue_append_buffer(con
->write_queue
, b
);
388 return HANDLER_FINISHED
;
393 return HANDLER_GO_ON
;
396 REQUESTDONE_FUNC(mod_uploadprogress_request_done
) {
397 plugin_data
*p
= p_d
;
401 if (con
->request
.http_method
!= HTTP_METHOD_POST
) return HANDLER_GO_ON
;
402 if (buffer_string_is_empty(con
->uri
.path
)) return HANDLER_GO_ON
;
404 if (connection_map_remove_connection(p
->con_map
, con
)) {
408 return HANDLER_GO_ON
;
411 /* this function is called at dlopen() time and inits the callbacks */
413 int mod_uploadprogress_plugin_init(plugin
*p
);
414 int mod_uploadprogress_plugin_init(plugin
*p
) {
415 p
->version
= LIGHTTPD_VERSION_ID
;
416 p
->name
= buffer_init_string("uploadprogress");
418 p
->init
= mod_uploadprogress_init
;
419 p
->handle_uri_clean
= mod_uploadprogress_uri_handler
;
420 p
->handle_request_done
= mod_uploadprogress_request_done
;
421 p
->handle_connection_close
= mod_uploadprogress_request_done
;
422 p
->set_defaults
= mod_uploadprogress_set_defaults
;
423 p
->cleanup
= mod_uploadprogress_free
;