10 #include "stat_cache.h"
16 * this is a uploadprogress for a lighttpd plugin
23 } connection_map_entry
;
26 connection_map_entry
**ptr
;
32 /* plugin config for all request/connections */
41 connection_map
*con_map
;
43 plugin_config
**config_storage
;
54 /* init the plugin data */
55 static connection_map
*connection_map_init() {
58 cm
= calloc(1, sizeof(*cm
));
63 static void connection_map_free(connection_map
*cm
) {
65 for (i
= 0; i
< cm
->size
; i
++) {
66 connection_map_entry
*cme
= cm
->ptr
[i
];
71 buffer_free(cme
->con_id
);
79 static int connection_map_insert(connection_map
*cm
, connection
*con
, buffer
*con_id
) {
80 connection_map_entry
*cme
;
85 cm
->ptr
= malloc(cm
->size
* sizeof(*(cm
->ptr
)));
86 for (i
= 0; i
< cm
->size
; i
++) {
89 } else if (cm
->used
== cm
->size
) {
91 cm
->ptr
= realloc(cm
->ptr
, cm
->size
* sizeof(*(cm
->ptr
)));
92 for (i
= cm
->used
; i
< cm
->size
; i
++) {
97 if (cm
->ptr
[cm
->used
]) {
98 /* is already alloced, just reuse it */
99 cme
= cm
->ptr
[cm
->used
];
101 cme
= malloc(sizeof(*cme
));
102 cme
->con_id
= buffer_init();
104 buffer_copy_buffer(cme
->con_id
, con_id
);
107 cm
->ptr
[cm
->used
++] = cme
;
112 static connection
*connection_map_get_connection(connection_map
*cm
, buffer
*con_id
) {
115 for (i
= 0; i
< cm
->used
; i
++) {
116 connection_map_entry
*cme
= cm
->ptr
[i
];
118 if (buffer_is_equal(cme
->con_id
, con_id
)) {
119 /* found connection */
127 static int connection_map_remove_connection(connection_map
*cm
, connection
*con
) {
130 for (i
= 0; i
< cm
->used
; i
++) {
131 connection_map_entry
*cme
= cm
->ptr
[i
];
133 if (cme
->con
== con
) {
134 /* found connection */
136 buffer_reset(cme
->con_id
);
141 /* swap positions with the last entry */
143 cm
->ptr
[i
] = cm
->ptr
[cm
->used
];
144 cm
->ptr
[cm
->used
] = cme
;
154 /* init the plugin data */
155 INIT_FUNC(mod_uploadprogress_init
) {
158 p
= calloc(1, sizeof(*p
));
160 p
->con_map
= connection_map_init();
165 /* detroy the plugin data */
166 FREE_FUNC(mod_uploadprogress_free
) {
167 plugin_data
*p
= p_d
;
171 if (!p
) return HANDLER_GO_ON
;
173 if (p
->config_storage
) {
175 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
176 plugin_config
*s
= p
->config_storage
[i
];
178 if (NULL
== s
) continue;
180 buffer_free(s
->progress_url
);
184 free(p
->config_storage
);
187 connection_map_free(p
->con_map
);
191 return HANDLER_GO_ON
;
194 /* handle plugin config and check values */
196 SETDEFAULTS_FUNC(mod_uploadprogress_set_defaults
) {
197 plugin_data
*p
= p_d
;
200 config_values_t cv
[] = {
201 { "upload-progress.progress-url", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 0 */
202 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
205 if (!p
) return HANDLER_ERROR
;
207 p
->config_storage
= calloc(1, srv
->config_context
->used
* sizeof(plugin_config
*));
209 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
210 data_config
const* config
= (data_config
const*)srv
->config_context
->data
[i
];
213 s
= calloc(1, sizeof(plugin_config
));
214 s
->progress_url
= buffer_init();
216 cv
[0].destination
= s
->progress_url
;
218 p
->config_storage
[i
] = s
;
220 if (0 != config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
)) {
221 return HANDLER_ERROR
;
225 return HANDLER_GO_ON
;
230 static int mod_uploadprogress_patch_connection(server
*srv
, connection
*con
, plugin_data
*p
) {
232 plugin_config
*s
= p
->config_storage
[0];
236 /* skip the first, the global context */
237 for (i
= 1; i
< srv
->config_context
->used
; i
++) {
238 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
239 s
= p
->config_storage
[i
];
241 /* condition didn't match */
242 if (!config_check_cond(srv
, con
, dc
)) continue;
245 for (j
= 0; j
< dc
->value
->used
; j
++) {
246 data_unset
*du
= dc
->value
->data
[j
];
248 if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("upload-progress.progress-url"))) {
262 * for the first request we check if it is a post-request
264 * if no, move out, don't care about them
266 * if yes, take the connection structure and register it locally
267 * in the progress-struct together with an session-id (md5 ... )
269 * if the connections closes, cleanup the entry in the progress-struct
271 * a second request can now get the info about the size of the upload,
276 URIHANDLER_FUNC(mod_uploadprogress_uri_handler
) {
277 plugin_data
*p
= p_d
;
281 connection
*post_con
= NULL
;
285 if (buffer_string_is_empty(con
->uri
.path
)) return HANDLER_GO_ON
;
286 switch(con
->request
.http_method
) {
287 case HTTP_METHOD_GET
:
288 case HTTP_METHOD_POST
: break;
289 default: return HANDLER_GO_ON
;
292 mod_uploadprogress_patch_connection(srv
, con
, p
);
293 if (buffer_string_is_empty(p
->conf
.progress_url
)) return HANDLER_GO_ON
;
295 if (con
->request
.http_method
== HTTP_METHOD_GET
) {
296 if (!buffer_is_equal(con
->uri
.path
, p
->conf
.progress_url
)) {
297 return HANDLER_GO_ON
;
301 /* the request has to contain a 32byte ID */
303 if (NULL
== (ds
= (data_string
*)array_get_element(con
->request
.headers
, "X-Progress-ID"))) {
304 if (!buffer_string_is_empty(con
->uri
.query
)) {
305 /* perhaps the POST request is using the querystring to pass the X-Progress-ID */
308 return HANDLER_GO_ON
;
314 len
= buffer_string_length(b
);
316 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
317 "len of progress-id != 32:", len
);
318 return HANDLER_GO_ON
;
321 for (i
= 0; i
< len
; i
++) {
324 if (!light_isxdigit(c
)) {
325 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
326 "non-xdigit in progress-id:", b
);
327 return HANDLER_GO_ON
;
331 /* check if this is a POST request */
332 switch(con
->request
.http_method
) {
333 case HTTP_METHOD_POST
:
335 connection_map_insert(p
->con_map
, con
, b
);
337 return HANDLER_GO_ON
;
338 case HTTP_METHOD_GET
:
339 buffer_reset(con
->physical
.path
);
341 con
->file_started
= 1;
342 con
->file_finished
= 1;
344 con
->http_status
= 200;
347 /* get the connection */
348 if (NULL
== (post_con
= connection_map_get_connection(p
->con_map
, b
))) {
349 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
352 chunkqueue_append_mem(con
->write_queue
, CONST_STR_LEN("not in progress"));
354 return HANDLER_FINISHED
;
357 response_header_overwrite(srv
, con
, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml"));
359 /* just an attempt the force the IE/proxies to NOT cache the request ... doesn't help :( */
360 response_header_overwrite(srv
, con
, CONST_STR_LEN("Pragma"), CONST_STR_LEN("no-cache"));
361 response_header_overwrite(srv
, con
, CONST_STR_LEN("Expires"), CONST_STR_LEN("Thu, 19 Nov 1981 08:52:00 GMT"));
362 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"));
367 buffer_copy_string_len(b
, CONST_STR_LEN(
368 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>"
371 buffer_append_int(b
, post_con
->request
.content_length
);
372 buffer_append_string_len(b
, CONST_STR_LEN(
375 buffer_append_int(b
, post_con
->request_content_queue
->bytes_in
);
376 buffer_append_string_len(b
, CONST_STR_LEN(
381 log_error_write(srv
, __FILE__
, __LINE__
, "sb", "...", b
);
384 chunkqueue_append_buffer(con
->write_queue
, b
);
387 return HANDLER_FINISHED
;
392 return HANDLER_GO_ON
;
395 REQUESTDONE_FUNC(mod_uploadprogress_request_done
) {
396 plugin_data
*p
= p_d
;
400 if (con
->request
.http_method
!= HTTP_METHOD_POST
) return HANDLER_GO_ON
;
401 if (buffer_string_is_empty(con
->uri
.path
)) return HANDLER_GO_ON
;
403 if (connection_map_remove_connection(p
->con_map
, con
)) {
407 return HANDLER_GO_ON
;
410 /* this function is called at dlopen() time and inits the callbacks */
412 int mod_uploadprogress_plugin_init(plugin
*p
);
413 int mod_uploadprogress_plugin_init(plugin
*p
) {
414 p
->version
= LIGHTTPD_VERSION_ID
;
415 p
->name
= buffer_init_string("uploadprogress");
417 p
->init
= mod_uploadprogress_init
;
418 p
->handle_uri_clean
= mod_uploadprogress_uri_handler
;
419 p
->handle_request_done
= mod_uploadprogress_request_done
;
420 p
->handle_connection_close
= mod_uploadprogress_request_done
;
421 p
->set_defaults
= mod_uploadprogress_set_defaults
;
422 p
->cleanup
= mod_uploadprogress_free
;