static int upload_progress_handle_request(request_rec *r)
{
/**/up_log(APLOG_MARK, APLOG_DEBUG, 0, r->server, "upload_progress_handle_request()");

    DirConfig* dir = (DirConfig*)ap_get_module_config(r->per_dir_config, &upload_progress_module);
    ServerConfig *config = get_server_config(r->server);

    if (dir && dir->track_enabled > 0) {
        if (r->method_number == M_POST) {

            int param_error;
            const char* id = get_progress_id(r, &param_error);

            if (id) {
                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                             "Upload Progress: Upload id='%s' in trackable location: %s.", id, r->uri);
                CACHE_LOCK();
                clean_old_connections(r);
                upload_progress_node_t *node = find_node(r, id);
                if (node == NULL) {
                    node = insert_node(r, id);
                    if (node)
                        up_log(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                               "Upload Progress: Added upload with id='%s' to list.", id);
                } else if (node->done) {
                    fill_new_upload_node_data(node, r);
                    up_log(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                                 "Upload Progress: Reused existing node with id='%s'.", id);
                } else {
                    node = NULL;
                    ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
                                 "Upload Progress: Upload with id='%s' already exists, ignoring.", id);
                }

                if (node) {
                    upload_progress_context_t *ctx = (upload_progress_context_t*)apr_pcalloc(r->pool, sizeof(upload_progress_context_t));
                    ctx->node = node;
                    ctx->r = r;
                    apr_pool_cleanup_register(r->pool, ctx, upload_progress_cleanup, apr_pool_cleanup_null);
                    ap_add_input_filter("UPLOAD_PROGRESS", NULL, r, r->connection);
                }
                CACHE_UNLOCK();

            } else if (param_error < 0) {
                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                             "Upload Progress: Upload with invalid ID in trackable location: %s.", r->uri);
                /*
                return HTTP_BAD_REQUEST;
                return HTTP_NOT_FOUND;
                */

            } else {
                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                             "Upload Progress: Upload without ID in trackable location: %s.", r->uri);
            }
        }
    }

    return DECLINED;
}
static int upload_progress_handle_request(request_rec *r)
{
  DirConfig* dir = (DirConfig*)ap_get_module_config(r->per_dir_config, &upload_progress_module);
  ServerConfig *config = get_server_config(r);
  
  if(dir->track_enabled) {
    if(r->method_number == M_POST) {
      ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "Upload Progress: Upload in trackable location: %s.", r->uri);
      const char* id = get_progress_id(r);
      if(id != NULL) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "Upload Progress: Progress id found: %s.", id);
        CACHE_LOCK();
        upload_progress_node_t *node = find_node(r, id);
	CACHE_UNLOCK();
        if(node == NULL) {
          add_upload_to_track(r, id);
          ap_add_input_filter("UPLOAD_PROGRESS", NULL, r, r->connection);
	} else {
          ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "Upload Progress: Node with id '%s' already exists.", id);
	}
        return DECLINED;
      }
    }
  }
  
  return DECLINED;
}
static int track_upload_progress(ap_filter_t *f, apr_bucket_brigade *bb,
                           ap_input_mode_t mode, apr_read_type_e block,
                           apr_off_t readbytes)
{
    apr_status_t rv;
    upload_progress_node_t *node;
    ServerConfig* config = get_server_config(f->r);
    
     if ((rv = ap_get_brigade(f->next, bb, mode, block,
                                 readbytes)) != APR_SUCCESS) {
       return rv;
     }

    apr_off_t length;
    apr_brigade_length(bb, 1, &length);
    const char* id = get_progress_id(f->r);
    if(id == NULL) 
        return APR_SUCCESS;

    CACHE_LOCK();
    node = find_node(f->r, id);
    CACHE_UNLOCK();
    if(node == NULL) {
      return APR_SUCCESS;
    } else {
      CACHE_LOCK();
      node->received += (int)length;
      int upload_time = time(NULL) - node->started_at;
      if(upload_time > 0) {
        node->speed = (int)(node->received / upload_time);
      }
      CACHE_UNLOCK();
    }
    
    return APR_SUCCESS;
}
static int reportuploads_handler(request_rec *r)
{ 
    int length, received, done, speed, err_status, found=0;
    char *response;
    DirConfig* dir = (DirConfig*)ap_get_module_config(r->per_dir_config, &upload_progress_module);

    if(!dir->report_enabled) {
        return DECLINED;
    }
    if (r->method_number != M_GET) {
        return HTTP_METHOD_NOT_ALLOWED;
    }

    /* get the tracking id if any */
    const char *id = get_progress_id(r);

    if (id == NULL) {
	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "Upload Progress: Not found id in location with reports enabled. uri=%s", id, r->uri);
        return HTTP_NOT_FOUND;
    } else {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "Upload Progress: Found id=%s in location with reports enables. uri=%s", id, r->uri);
    }

    ServerConfig *config = (ServerConfig*)ap_get_module_config(r->server->module_config, &upload_progress_module);

    if (config->cache_rmm == NULL) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "Upload Progress: Cache error while generating report");
        return HTTP_INTERNAL_SERVER_ERROR ;
    }

    CACHE_LOCK();
    upload_progress_node_t *node = find_node(r, id);
    if (node != NULL) {
	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "Node with id=%s found for report", id);
        received = node->received;
        length = node->length;
        done = node->done;
        speed = node->speed;
        err_status = node->err_status;
        found = 1;
        CACHE_UNLOCK();
    } else {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "Node with id=%s not found for report", id);
    }
    
    CACHE_UNLOCK();

    ap_set_content_type(r, "text/javascript");

    apr_table_set(r->headers_out, "Expires", "Mon, 28 Sep 1970 06:00:00 GMT");
    apr_table_set(r->headers_out, "Cache-Control", "no-cache");


/*
 There are 4 possibilities
   * request not yet started: found = false
   * request in error:        err_status >= NGX_HTTP_SPECIAL_RESPONSE
   * request finished:        done = true
   * request not yet started but registered:        length==0 && rest ==0
   * reauest in progress:     rest > 0 
 */

   
    if (!found) {
      response = apr_psprintf(r->pool, "new Object({ 'state' : 'starting', 'uuid' : '%s' })", id);
    } else if (err_status >= HTTP_BAD_REQUEST  ) {
      response = apr_psprintf(r->pool, "new Object({ 'state' : 'error', 'status' : %d, 'uuid' : '%s' })", err_status, id);
    } else if (done) {
      response = apr_psprintf(r->pool, "new Object({ 'state' : 'done', 'uuid' : '%s' })", id);
    } else if ( length == 0 && received == 0 ) {
      response = apr_psprintf(r->pool, "new Object({ 'state' : 'starting', 'uuid' : '%s' })", id);
    } else {
      response = apr_psprintf(r->pool, "new Object({ 'state' : 'uploading', 'received' : %d, 'size' : %d, 'speed' : %d, 'uuid' : '%s'  })", received, length, speed, id);
    }

    char *completed_response;
    
    /* get the jsonp callback if any */
    const char *jsonp = get_json_callback_param(r);
    
    // fix up response for jsonp request, if needed
    if (jsonp) {
      completed_response = apr_psprintf(r->pool, "%s(%s);\r\n", jsonp, response);
    } else {
      completed_response = apr_psprintf(r->pool, "%s\r\n", response);
    }
    
    ap_rputs(completed_response, r);

    return OK;
}