243 lines
6.8 KiB
C
243 lines
6.8 KiB
C
#include "fcgi_server_internal.h"
|
||
|
||
#include "utils/response_builder.h"
|
||
|
||
#include <assert.h>
|
||
|
||
|
||
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;
|
||
}
|