// Handles an upload parameter. If the user didn't select a file, it calls the // regular porter_handle_parameter function. For uploads it appends several // sub-parameters: // // * filename: File name that the user has uploaded. // * content_type: The content type the browser has provided (sometimes not present). // * path: The location of the tempfile where the contents were copied to. // * signature: A base64 encoded SHA1 hash of the filename and the PorterSharedSecret. apr_status_t porter_handle_upload(porter_upload_request_t *ur, apreq_param_t *p) { const char *content_disposition; const char *file_name; const char *content_type; const char *signature; apr_size_t size; apr_status_t rv; apr_finfo_t finfo; apr_pool_t *pool = ur->pool; char *escaped_key = apreq_escape(pool, p->v.name, strlen(p->v.name)); apr_table_t *info = p->info; PORTER_LOG("Handling Upload"); PORTER_LOG(p->v.name); porter_server_conf *config = (porter_server_conf *)ap_get_module_config(ur->raw_request->server->module_config, &porter_module); content_disposition = apr_table_get(info, "content-disposition"); apreq_header_attribute(content_disposition, "filename", 8, &file_name, &size); if (size == 0) { // There was no file, or at least it had no name, so let's // just skip it. PORTER_LOG("Appears there was no file, skipping the parameter"); return APR_SUCCESS; } PORTER_LOG("Appears there was a file, continuing"); // We know we have a file so push the param name into the array // of parameter names so it can be added to the request header. *(const char**)apr_array_push(ur->param_names) = p->v.name; PORTER_HANDLE_ERROR(porter_append_sub_parameter(pool, ur->bucket_brigade, escaped_key, "filename", file_name, size)); // content type is optional, and safari doesn't send it if it's unsure. content_type = apr_table_get(info, "content-type"); if (content_type) { PORTER_HANDLE_ERROR(porter_append_sub_parameter(pool, ur->bucket_brigade, escaped_key, "content_type", content_type, strlen(content_type))); } // Write the actual upload to disk PORTER_HANDLE_ERROR(porter_stream_file_to_disk(pool, p, &finfo, config->directory)); // Set appropriate tempfile permissions PORTER_HANDLE_ERROR(apr_file_perms_set(finfo.fname, config->permission)); PORTER_HANDLE_ERROR(porter_append_sub_parameter(pool, ur->bucket_brigade, escaped_key, "path", finfo.fname, strlen(finfo.fname))); signature = porter_sign_filename(ur, &finfo); PORTER_HANDLE_ERROR(porter_append_sub_parameter(pool, ur->bucket_brigade, escaped_key, "signature", signature, strlen(signature))); return APR_SUCCESS; }
static void test_header_attribute(dAT) { const char hdr[] = "filename=\"filename=foo\" filename=\"quux.txt\""; const char *val; apr_size_t vlen; AT_int_eq(apreq_header_attribute(hdr+4, "name", 4, &val, &vlen), APR_SUCCESS); AT_int_eq(vlen, 12); AT_mem_eq("filename=foo", val, 12); AT_int_eq(apreq_header_attribute(hdr+4, "filename", 8, &val, &vlen), APR_SUCCESS); AT_int_eq(vlen, 8); AT_mem_eq("quux.txt", val, 8); }
static void header_attributes(dAT) { const char *hdr = "text/plain; boundary=\"-foo-\", charset=ISO-8859-1"; const char *val; apr_size_t vlen; apr_status_t s; s = apreq_header_attribute(hdr, "none", 4, &val, &vlen); AT_int_eq(s, APREQ_ERROR_NOATTR); s = apreq_header_attribute(hdr, "set", 3, &val, &vlen); AT_int_eq(s, APREQ_ERROR_NOATTR); s = apreq_header_attribute(hdr, "boundary", 8, &val, &vlen); AT_int_eq(s, APR_SUCCESS); AT_int_eq(vlen, 5); AT_mem_eq(val, "-foo-", 5); s = apreq_header_attribute(hdr, "charset", 7, &val, &vlen); AT_int_eq(s, APR_SUCCESS); AT_int_eq(vlen, 10); AT_mem_eq(val, "ISO-8859-1", 10); hdr = "max-age=20; no-quote=\"..."; s = apreq_header_attribute(hdr, "max-age", 7, &val, &vlen); AT_int_eq(s, APR_SUCCESS); AT_int_eq(vlen, 2); AT_mem_eq(val, "20", 2); s = apreq_header_attribute(hdr, "age", 3, &val, &vlen); AT_int_eq(s, APREQ_ERROR_BADSEQ); s = apreq_header_attribute(hdr, "no-quote", 8, &val, &vlen); AT_int_eq(s, APREQ_ERROR_BADSEQ); }