void clax_dispatch_download(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res) { char *file = req->path_info + strlen("/tree/"); char buf[255]; char base_buf[255]; char last_modified_buf[30]; struct stat st; struct tm last_modified_time; struct tm *last_modified_time_p; if (stat(file, &st) != 0 || !(st.st_mode & S_IFREG)) { clax_dispatch_not_found(clax_ctx, req, res); return; } unsigned long crc32 = clax_crc32_calc_file(file); char crc32_hex[9] = {0}; snprintf(crc32_hex, sizeof(crc32_hex), "%lx", crc32); FILE *fh = fopen(file, "rb"); if (fh == NULL) { clax_dispatch_not_found(clax_ctx, req, res); return; } snprintf(buf, sizeof(buf), "%d", (int)st.st_size); char *base = basename(file); strcpy(base_buf, "attachment; filename=\""); strcat(base_buf, base); strcat(base_buf, "\""); res->status_code = 200; clax_kv_list_push(&res->headers, "Content-Type", "application/octet-stream"); clax_kv_list_push(&res->headers, "Content-Disposition", base_buf); clax_kv_list_push(&res->headers, "Pragma", "no-cache"); clax_kv_list_push(&res->headers, "Content-Length", buf); last_modified_time_p = gmtime_r(&st.st_mtime, &last_modified_time); strftime(last_modified_buf, sizeof(last_modified_buf), "%a, %d %b %Y %H:%M:%S GMT", last_modified_time_p); clax_kv_list_push(&res->headers, "Last-Modified", last_modified_buf); clax_kv_list_push(&res->headers, "X-Clax-CRC32", crc32_hex); if (req->method == HTTP_GET) res->body_fh = fh; else fclose(fh); }
void clax_dispatch(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res) { char *path_info = req->path_info; size_t path_info_len = strlen(path_info); size_t len = sizeof clax_dispatcher_actions / sizeof clax_dispatcher_actions[0]; clax_log("Matching request %s %s", http_method_str(req->method), path_info); for (int i = 0; i < len; i++) { clax_dispatcher_action_t *action = &clax_dispatcher_actions[i]; size_t match = clax_dispatcher_match(path_info, path_info_len, action->path, strlen(action->path)); if (match) { clax_log("Action matched"); if (action->method_mask & (1 << req->method)) { clax_log("Method matched"); if (req->continue_expected) { if (action->flags_mask & (1 << CLAX_DISPATCHER_FLAG_100_CONTINUE)) { action->fn(clax_ctx, req, res); } else { return; } } else { action->fn(clax_ctx, req, res); } return; } else { clax_dispatch_method_not_allowed(clax_ctx, req, res); return; } } } clax_log("No suitable action matched"); clax_dispatch_not_found(clax_ctx, req, res); return; }
void clax_dispatch_delete(clax_ctx_t *clax_ctx, clax_http_request_t *req, clax_http_response_t *res) { char *file = req->path_info + strlen("/tree/"); struct stat st; if (stat(file, &st) != 0 || !(st.st_mode & S_IFREG)) { clax_dispatch_not_found(clax_ctx, req, res); return; } int ret = unlink(file); if (ret == 0) { res->status_code = 200; clax_kv_list_push(&res->headers, "Content-Type", "application/json"); clax_big_buf_append_str(&res->body, "{\"message\":\"ok\"}"); } else { clax_dispatch_system_error(clax_ctx, req, res); return; } }