#include "fcgi_server_internal.h" #include "utils/response_builder.h" #include int fcgi_get_content_length(const FCGX_Request* request) { int content_length = 0; char* p = FCGX_GetParam(FCGI_PARAM_NAME_CONTENT_LENGTH, request->envp); if (p != NULL) { content_length = atoi(p); } return content_length; } fcgi_handler_status_t check_content_length(int content_length, int client_max_body_size) { LOG_TRACE("check_content_length"); if (content_length > 0 && content_length <= client_max_body_size) { LOG_DEBUG("Content-Length is ok"); return HANDLER_SUCCESS; } if (content_length == 0) { LOG_DEBUG("Content-Length == 0, so there is no body"); return HANDLER_HTTP_OK; } if (content_length < 0) { LOG_WARN("Content-Length < 0 (%d)", content_length); return HANDLER_HTTP_BAD_REQUEST; } /* (content_length > client_max_body_size) */ LOG_WARN("Content-Length (%d) is too large (> %d)", content_length, client_max_body_size); return HANDLER_HTTP_REQUEST_ENTITY_TOO_LARGE; } fcgi_handler_status_t check_content_type(const FCGX_Request* request, const str_t* acceptable_content_type, const char** actual_content_type) { LOG_TRACE("check_content_type"); const char* content_type = FCGX_GetParam(FCGI_PARAM_NAME_CONTENT_TYPE, request->envp); if (content_type == NULL) { LOG_ERROR("Could not get FCGI param: "FCGI_PARAM_NAME_CONTENT_TYPE); return HANDLER_HTTP_BAD_REQUEST; } if (actual_content_type) { *actual_content_type = content_type; } /* * Проверяем, начинается ли заголовок Content-Type с допустимого префикса * Сравнение производится только для начальной части строки * (игнорируя дополнительные параметры после точки с запятой) * Пример: "multipart/form-data;boundary=--123" является допустимым для "multipart/form-data" */ if (strncmp(content_type, acceptable_content_type->data, acceptable_content_type->len) == 0) { LOG_DEBUG("Content-Type is ok"); return HANDLER_SUCCESS; } LOG_WARN("Content-Type is not acceptable, '%s' (!= '%.*s')", content_type, (int) acceptable_content_type->len, acceptable_content_type->data); return HANDLER_HTTP_NOT_ACCEPTABLE; } char* fcgi_request_get_param(const FCGX_Request* request, const char* name, /*out*/ bool* err) { assert(request != NULL); assert(name != NULL); char* param_value = FCGX_GetParam(name, request->envp); if (param_value == NULL) { LOG_ERROR("Could not get fcgi parameter '%s'", name); goto error; } LOG_DEBUG("fcgi_request_get_param. name: %s, value: %s", name, param_value); if (err) { *err = false; } return param_value; error: LOG_ERROR("fcgi_request_get_param exit with error"); if (err) { *err = true; } return NULL; } fcgi_handler_status_t fcgi_request_load_data(const FCGX_Request* request, int content_length, char** content) { LOG_TRACE("fcgi_request_load_data enter"); char* data = malloc(content_length + 1); if (data == NULL) { LOG_ERROR("Could not allocate memory for request body (%d bytes)", content_length + 1); return HANDLER_ERROR; } int actual_content_length = FCGX_GetStr(data, content_length, request->in); if (actual_content_length != content_length) { LOG_ERROR("fcgi_request_load_data: " "actual_content_length(%d) != content_length(%d); content: '%.*s'", actual_content_length, content_length, actual_content_length, data); free(data); return HANDLER_HTTP_BAD_REQUEST; } data[content_length] = '\0'; *content = data; LOG_DEBUG("content_length: %d", content_length); LOG_DEBUG("content: '%s'", *content); LOG_TRACE("fcgi_request_load_data exit"); return HANDLER_SUCCESS; } fcgi_handler_status_t fcgi_printf_str(const FCGX_Request* request, const char* response, int response_len) { assert(request != NULL); assert(response != NULL); //int n = FCGX_FPrintF(request->out, response); int n = FCGX_PutStr(response, response_len, request->out); if (n < 0) { LOG_ERROR("FCGX_PutStr failed"); return HANDLER_ERROR; } if (n != response_len) { LOG_ERROR("response_len (%d) differs from the number of characters written (%d)", response_len, n); return HANDLER_ERROR; } return HANDLER_SUCCESS; } fcgi_handler_status_t fcgi_printf_header(const FCGX_Request* request, const char* name, const char* value, int value_len) { if (FCGX_FPrintF(request->out, "%s: %.*s"CRLF, name, value_len, value) == -1) { LOG_ERROR("FCGX_FPrintF failed"); return HANDLER_ERROR; } return HANDLER_SUCCESS; } fcgi_handler_status_t fcgi_200_ok_handler(const FCGX_Request* request, const char* response) { LOG_TRACE("fcgi_200_ok_handler"); const char *format = response ? FCGI_200_JSON_RESPONSE_FORMAT : FCGI_200_EMPTY_RESPONSE_FORMAT; if (response) { LOG_DEBUG("response:\n" FCGI_200_JSON_RESPONSE_FORMAT, response); } else { LOG_DEBUG("response:\n" FCGI_200_EMPTY_RESPONSE_FORMAT); } if (FCGX_FPrintF(request->out, format, response) < 0) { LOG_ERROR("FCGX_FPrintF() failed"); LOG_ERROR("fcgi_200_ok_handler exit with error"); return HANDLER_ERROR; } return HANDLER_SUCCESS; } fcgi_handler_status_t fcgi_401_bad_signature_handler(const FCGX_Request* request, const char* verify_error) { LOG_TRACE("fcgi_401_bad_signature_handler"); assert(verify_error != NULL); LOG_DEBUG("response status: " FCGI_401_RESPONSE_FORMAT, verify_error); if (FCGX_FPrintF(request->out, FCGI_401_RESPONSE_FORMAT, verify_error) < 0) { LOG_ERROR("FCGX_FPrintF() failed"); return HANDLER_ERROR; } fcgi_print_log(request, "401 Unauthorized"); return HANDLER_SUCCESS; } fcgi_handler_status_t fcgi_500_internal_server_error_handler(const FCGX_Request* request, const char *error_code) { LOG_TRACE("fcgi_500_internal_server_error_handler"); char *response = build_response_from_error_code(error_code); if (response == NULL) { goto error; } LOG_DEBUG("response status: " FCGI_500_RESPONSE_FORMAT, response); if (FCGX_FPrintF(request->out, FCGI_500_RESPONSE_FORMAT, response) < 0) { LOG_ERROR("FCGX_FPrintF() failed"); goto error; } fcgi_print_log(request, "500 Internal Server Error"); free(response); return HANDLER_SUCCESS; error: free(response); LOG_ERROR("fcgi_500_internal_server_error_handler exit with error"); return HANDLER_ERROR; }