client refactor
This commit is contained in:
378
src/client.c
378
src/client.c
@ -133,216 +133,218 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
|
|||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf->type != CONFIG_TYPE_LOCAL) {
|
if (conf->type == CONFIG_TYPE_LOCAL) {
|
||||||
print("Reverse proxy for %s:%i", conf->rev_proxy.hostname, conf->rev_proxy.port);
|
http_uri uri;
|
||||||
// TODO Reverse Proxy
|
ret = uri_init(&uri, conf->local.webroot, req.uri, conf->local.dir_mode);
|
||||||
res.status = http_get_status(501);
|
|
||||||
goto respond;
|
|
||||||
}
|
|
||||||
|
|
||||||
http_uri uri;
|
|
||||||
ret = uri_init(&uri, conf->local.webroot, req.uri, conf->local.dir_mode);
|
|
||||||
if (ret != 0) {
|
|
||||||
if (ret == 1) {
|
|
||||||
sprintf(err_msg, "Invalid URI: has to start with slash.");
|
|
||||||
} else if (ret == 2) {
|
|
||||||
sprintf(err_msg, "Invalid URI: contains relative path change (/../).");
|
|
||||||
}
|
|
||||||
res.status = http_get_status(400);
|
|
||||||
goto respond;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t size = sizeof(buf0);
|
|
||||||
url_decode(req.uri, buf0, &size);
|
|
||||||
int change_proto = strncmp(uri.uri, "/.well-known/", 13) != 0 && !client->enc;
|
|
||||||
if (strcmp(uri.uri, buf0) != 0 || change_proto) {
|
|
||||||
res.status = http_get_status(308);
|
|
||||||
size = sizeof(buf0);
|
|
||||||
encode_url(uri.uri, buf0, &size);
|
|
||||||
if (change_proto) {
|
|
||||||
sprintf(buf1, "https://%s%s", host, buf0);
|
|
||||||
http_add_header_field(&res.hdr, "Location", buf1);
|
|
||||||
} else {
|
|
||||||
http_add_header_field(&res.hdr, "Location", buf0);
|
|
||||||
}
|
|
||||||
goto respond;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uri.filename == NULL && (int) uri.is_static && (int) uri.is_dir && strlen(uri.pathinfo) == 0) {
|
|
||||||
res.status = http_get_status(403);
|
|
||||||
sprintf(err_msg, "It is not allowed to list the contents of this directory.");
|
|
||||||
goto respond;
|
|
||||||
} else if (uri.filename == NULL && (int) !uri.is_static && (int) uri.is_dir && strlen(uri.pathinfo) == 0) {
|
|
||||||
// TODO list directory contents
|
|
||||||
res.status = http_get_status(501);
|
|
||||||
sprintf(err_msg, "Listing contents of an directory is currently not implemented.");
|
|
||||||
goto respond;
|
|
||||||
} else if (uri.filename == NULL || (strlen(uri.pathinfo) > 0 && (int) uri.is_static)) {
|
|
||||||
res.status = http_get_status(404);
|
|
||||||
goto respond;
|
|
||||||
} else if (strlen(uri.pathinfo) != 0 && conf->local.dir_mode != URI_DIR_MODE_INFO) {
|
|
||||||
res.status = http_get_status(404);
|
|
||||||
goto respond;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uri.is_static) {
|
|
||||||
res.status = http_get_status(200);
|
|
||||||
http_add_header_field(&res.hdr, "Allow", "GET, HEAD");
|
|
||||||
http_add_header_field(&res.hdr, "Accept-Ranges", "bytes");
|
|
||||||
if (strcmp(req.method, "GET") != 0 && strcmp(req.method, "HEAD") != 0) {
|
|
||||||
res.status = http_get_status(405);
|
|
||||||
goto respond;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = uri_cache_init(&uri);
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
res.status = http_get_status(500);
|
if (ret == 1) {
|
||||||
sprintf(err_msg, "Unable to communicate with internal file cache.");
|
sprintf(err_msg, "Invalid URI: has to start with slash.");
|
||||||
goto respond;
|
} else if (ret == 2) {
|
||||||
}
|
sprintf(err_msg, "Invalid URI: contains relative path change (/../).");
|
||||||
char *last_modified = http_format_date(uri.meta->stat.st_mtime, buf0, sizeof(buf0));
|
}
|
||||||
http_add_header_field(&res.hdr, "Last-Modified", last_modified);
|
res.status = http_get_status(400);
|
||||||
sprintf(buf1, "%s; charset=%s", uri.meta->type, uri.meta->charset);
|
|
||||||
http_add_header_field(&res.hdr, "Content-Type", buf1);
|
|
||||||
if (uri.meta->etag[0] != 0) {
|
|
||||||
http_add_header_field(&res.hdr, "ETag", uri.meta->etag);
|
|
||||||
}
|
|
||||||
if (strncmp(uri.meta->type, "text/", 5) == 0) {
|
|
||||||
http_add_header_field(&res.hdr, "Cache-Control", "public, max-age=3600");
|
|
||||||
} else {
|
|
||||||
http_add_header_field(&res.hdr, "Cache-Control", "public, max-age=86400");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *if_modified_since = http_get_header_field(&req.hdr, "If-Modified-Since");
|
|
||||||
char *if_none_match = http_get_header_field(&req.hdr, "If-None-Match");
|
|
||||||
if ((if_none_match != NULL && strstr(if_none_match, uri.meta->etag) == NULL) || (accept_if_modified_since &&
|
|
||||||
if_modified_since != NULL && strcmp(if_modified_since, last_modified) == 0)) {
|
|
||||||
res.status = http_get_status(304);
|
|
||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *range = http_get_header_field(&req.hdr, "Range");
|
ssize_t size = sizeof(buf0);
|
||||||
if (range != NULL) {
|
url_decode(req.uri, buf0, &size);
|
||||||
if (strlen(range) <= 6 || strncmp(range, "bytes=", 6) != 0) {
|
int change_proto = strncmp(uri.uri, "/.well-known/", 13) != 0 && !client->enc;
|
||||||
res.status = http_get_status(416);
|
if (strcmp(uri.uri, buf0) != 0 || change_proto) {
|
||||||
http_remove_header_field(&res.hdr, "Content-Type", HTTP_REMOVE_ALL);
|
res.status = http_get_status(308);
|
||||||
http_remove_header_field(&res.hdr, "Last-Modified", HTTP_REMOVE_ALL);
|
size = sizeof(buf0);
|
||||||
http_remove_header_field(&res.hdr, "ETag", HTTP_REMOVE_ALL);
|
encode_url(uri.uri, buf0, &size);
|
||||||
http_remove_header_field(&res.hdr, "Cache-Control", HTTP_REMOVE_ALL);
|
if (change_proto) {
|
||||||
|
sprintf(buf1, "https://%s%s", host, buf0);
|
||||||
|
http_add_header_field(&res.hdr, "Location", buf1);
|
||||||
|
} else {
|
||||||
|
http_add_header_field(&res.hdr, "Location", buf0);
|
||||||
|
}
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri.filename == NULL && (int) uri.is_static && (int) uri.is_dir && strlen(uri.pathinfo) == 0) {
|
||||||
|
res.status = http_get_status(403);
|
||||||
|
sprintf(err_msg, "It is not allowed to list the contents of this directory.");
|
||||||
|
goto respond;
|
||||||
|
} else if (uri.filename == NULL && (int) !uri.is_static && (int) uri.is_dir && strlen(uri.pathinfo) == 0) {
|
||||||
|
// TODO list directory contents
|
||||||
|
res.status = http_get_status(501);
|
||||||
|
sprintf(err_msg, "Listing contents of an directory is currently not implemented.");
|
||||||
|
goto respond;
|
||||||
|
} else if (uri.filename == NULL || (strlen(uri.pathinfo) > 0 && (int) uri.is_static)) {
|
||||||
|
res.status = http_get_status(404);
|
||||||
|
goto respond;
|
||||||
|
} else if (strlen(uri.pathinfo) != 0 && conf->local.dir_mode != URI_DIR_MODE_INFO) {
|
||||||
|
res.status = http_get_status(404);
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri.is_static) {
|
||||||
|
res.status = http_get_status(200);
|
||||||
|
http_add_header_field(&res.hdr, "Allow", "GET, HEAD");
|
||||||
|
http_add_header_field(&res.hdr, "Accept-Ranges", "bytes");
|
||||||
|
if (strcmp(req.method, "GET") != 0 && strcmp(req.method, "HEAD") != 0) {
|
||||||
|
res.status = http_get_status(405);
|
||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
range += 6;
|
|
||||||
char *ptr = strchr(range, '-');
|
ret = uri_cache_init(&uri);
|
||||||
if (ptr == NULL) {
|
if (ret != 0) {
|
||||||
res.status = http_get_status(416);
|
res.status = http_get_status(500);
|
||||||
|
sprintf(err_msg, "Unable to communicate with internal file cache.");
|
||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
file = fopen(uri.filename, "rb");
|
char *last_modified = http_format_date(uri.meta->stat.st_mtime, buf0, sizeof(buf0));
|
||||||
|
http_add_header_field(&res.hdr, "Last-Modified", last_modified);
|
||||||
|
sprintf(buf1, "%s; charset=%s", uri.meta->type, uri.meta->charset);
|
||||||
|
http_add_header_field(&res.hdr, "Content-Type", buf1);
|
||||||
|
if (uri.meta->etag[0] != 0) {
|
||||||
|
http_add_header_field(&res.hdr, "ETag", uri.meta->etag);
|
||||||
|
}
|
||||||
|
if (strncmp(uri.meta->type, "text/", 5) == 0) {
|
||||||
|
http_add_header_field(&res.hdr, "Cache-Control", "public, max-age=3600");
|
||||||
|
} else {
|
||||||
|
http_add_header_field(&res.hdr, "Cache-Control", "public, max-age=86400");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *if_modified_since = http_get_header_field(&req.hdr, "If-Modified-Since");
|
||||||
|
char *if_none_match = http_get_header_field(&req.hdr, "If-None-Match");
|
||||||
|
if ((if_none_match != NULL && strstr(if_none_match, uri.meta->etag) == NULL) ||
|
||||||
|
(accept_if_modified_since && if_modified_since != NULL && strcmp(if_modified_since, last_modified) == 0)) {
|
||||||
|
res.status = http_get_status(304);
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *range = http_get_header_field(&req.hdr, "Range");
|
||||||
|
if (range != NULL) {
|
||||||
|
if (strlen(range) <= 6 || strncmp(range, "bytes=", 6) != 0) {
|
||||||
|
res.status = http_get_status(416);
|
||||||
|
http_remove_header_field(&res.hdr, "Content-Type", HTTP_REMOVE_ALL);
|
||||||
|
http_remove_header_field(&res.hdr, "Last-Modified", HTTP_REMOVE_ALL);
|
||||||
|
http_remove_header_field(&res.hdr, "ETag", HTTP_REMOVE_ALL);
|
||||||
|
http_remove_header_field(&res.hdr, "Cache-Control", HTTP_REMOVE_ALL);
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
range += 6;
|
||||||
|
char *ptr = strchr(range, '-');
|
||||||
|
if (ptr == NULL) {
|
||||||
|
res.status = http_get_status(416);
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
file = fopen(uri.filename, "rb");
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
unsigned long file_len = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
if (file_len == 0) {
|
||||||
|
content_length = 0;
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
long num1 = 0;
|
||||||
|
long num2 = (long) file_len - 1;
|
||||||
|
|
||||||
|
if (ptr != range) num1 = (long) strtoul(range, NULL, 10);
|
||||||
|
if (ptr[1] != 0) num2 = (long) strtoul(ptr + 1, NULL, 10);
|
||||||
|
|
||||||
|
if (num1 >= file_len || num2 >= file_len || num1 > num2) {
|
||||||
|
res.status = http_get_status(416);
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
sprintf(buf0, "bytes %li-%li/%li", num1, num2, file_len);
|
||||||
|
http_add_header_field(&res.hdr, "Content-Range", buf0);
|
||||||
|
|
||||||
|
res.status = http_get_status(206);
|
||||||
|
fseek(file, num1, SEEK_SET);
|
||||||
|
content_length = num2 - num1 + 1;
|
||||||
|
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding");
|
||||||
|
if (uri.meta->filename_comp[0] != 0 && accept_encoding != NULL &&
|
||||||
|
strstr(accept_encoding, "deflate") != NULL) {
|
||||||
|
file = fopen(uri.meta->filename_comp, "rb");
|
||||||
|
if (file == NULL) {
|
||||||
|
cache_filename_comp_invalid(uri.filename);
|
||||||
|
goto not_compressed;
|
||||||
|
}
|
||||||
|
http_add_header_field(&res.hdr, "Content-Encoding", "deflate");
|
||||||
|
} else {
|
||||||
|
not_compressed:
|
||||||
|
file = fopen(uri.filename, "rb");
|
||||||
|
}
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
unsigned long file_len = ftell(file);
|
content_length = ftell(file);
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
if (file_len == 0) {
|
|
||||||
content_length = 0;
|
|
||||||
goto respond;
|
|
||||||
}
|
|
||||||
long num1 = 0;
|
|
||||||
long num2 = (long) file_len - 1;
|
|
||||||
|
|
||||||
if (ptr != range) num1 = (long) strtoul(range, NULL, 10);
|
|
||||||
if (ptr[1] != 0) num2 = (long) strtoul(ptr + 1, NULL, 10);
|
|
||||||
|
|
||||||
if (num1 >= file_len || num2 >= file_len || num1 > num2) {
|
|
||||||
res.status = http_get_status(416);
|
|
||||||
goto respond;
|
|
||||||
}
|
|
||||||
sprintf(buf0, "bytes %li-%li/%li", num1, num2, file_len);
|
|
||||||
http_add_header_field(&res.hdr, "Content-Range", buf0);
|
|
||||||
|
|
||||||
res.status = http_get_status(206);
|
|
||||||
fseek(file, num1, SEEK_SET);
|
|
||||||
content_length = num2 - num1 + 1;
|
|
||||||
|
|
||||||
goto respond;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding");
|
|
||||||
if (uri.meta->filename_comp[0] != 0 && accept_encoding != NULL && strstr(accept_encoding, "deflate") != NULL) {
|
|
||||||
file = fopen(uri.meta->filename_comp, "rb");
|
|
||||||
if (file == NULL) {
|
|
||||||
cache_filename_comp_invalid(uri.filename);
|
|
||||||
goto not_compressed;
|
|
||||||
}
|
|
||||||
http_add_header_field(&res.hdr, "Content-Encoding", "deflate");
|
|
||||||
} else {
|
} else {
|
||||||
not_compressed:
|
struct stat statbuf;
|
||||||
file = fopen(uri.filename, "rb");
|
stat(uri.filename, &statbuf);
|
||||||
}
|
char *last_modified = http_format_date(statbuf.st_mtime, buf0, sizeof(buf0));
|
||||||
fseek(file, 0, SEEK_END);
|
http_add_header_field(&res.hdr, "Last-Modified", last_modified);
|
||||||
content_length = ftell(file);
|
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
} else {
|
|
||||||
struct stat statbuf;
|
|
||||||
stat(uri.filename, &statbuf);
|
|
||||||
char *last_modified = http_format_date(statbuf.st_mtime, buf0, sizeof(buf0));
|
|
||||||
http_add_header_field(&res.hdr, "Last-Modified", last_modified);
|
|
||||||
|
|
||||||
res.status = http_get_status(200);
|
res.status = http_get_status(200);
|
||||||
if (fastcgi_init(&php_fpm, client_num, req_num, client, &req, &uri) != 0) {
|
if (fastcgi_init(&php_fpm, client_num, req_num, client, &req, &uri) != 0) {
|
||||||
res.status = http_get_status(502);
|
res.status = http_get_status(502);
|
||||||
sprintf(err_msg, "Unable to communicate with PHP-FPM.");
|
sprintf(err_msg, "Unable to communicate with PHP-FPM.");
|
||||||
goto respond;
|
goto respond;
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(req.method, "POST") == 0 || strcmp(req.method, "PUT") == 0) {
|
|
||||||
char *client_content_length = http_get_header_field(&req.hdr, "Content-Length");
|
|
||||||
unsigned long client_content_len = 0;
|
|
||||||
if (client_content_length == NULL) {
|
|
||||||
goto fastcgi_end;
|
|
||||||
}
|
}
|
||||||
client_content_len = strtoul(client_content_length, NULL, 10);
|
|
||||||
ret = fastcgi_receive(&php_fpm, client, client_content_len);
|
if (strcmp(req.method, "POST") == 0 || strcmp(req.method, "PUT") == 0) {
|
||||||
|
char *client_content_length = http_get_header_field(&req.hdr, "Content-Length");
|
||||||
|
unsigned long client_content_len = 0;
|
||||||
|
if (client_content_length == NULL) {
|
||||||
|
goto fastcgi_end;
|
||||||
|
}
|
||||||
|
client_content_len = strtoul(client_content_length, NULL, 10);
|
||||||
|
ret = fastcgi_receive(&php_fpm, client, client_content_len);
|
||||||
|
if (ret != 0) {
|
||||||
|
if (ret < 0) {
|
||||||
|
goto abort;
|
||||||
|
} else {
|
||||||
|
sprintf(err_msg, "Unable to communicate with PHP-FPM.");
|
||||||
|
}
|
||||||
|
res.status = http_get_status(502);
|
||||||
|
goto respond;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fastcgi_end:
|
||||||
|
fastcgi_close_stdin(&php_fpm);
|
||||||
|
|
||||||
|
ret = fastcgi_header(&php_fpm, &res, err_msg);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto abort;
|
goto abort;
|
||||||
} else {
|
|
||||||
sprintf(err_msg, "Unable to communicate with PHP-FPM.");
|
|
||||||
}
|
}
|
||||||
res.status = http_get_status(502);
|
|
||||||
goto respond;
|
goto respond;
|
||||||
}
|
}
|
||||||
}
|
char *status = http_get_header_field(&res.hdr, "Status");
|
||||||
fastcgi_end:
|
if (status != NULL) {
|
||||||
fastcgi_close_stdin(&php_fpm);
|
res.status = http_get_status(strtoul(status, NULL, 10));
|
||||||
|
http_remove_header_field(&res.hdr, "Status", HTTP_REMOVE_ALL);
|
||||||
ret = fastcgi_header(&php_fpm, &res, err_msg);
|
if (res.status == NULL) {
|
||||||
if (ret != 0) {
|
res.status = http_get_status(500);
|
||||||
if (ret < 0) {
|
sprintf(err_msg, "The status code was set to an invalid or unknown value.");
|
||||||
goto abort;
|
goto respond;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
goto respond;
|
|
||||||
}
|
char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding");
|
||||||
char *status = http_get_header_field(&res.hdr, "Status");
|
if (accept_encoding != NULL && strstr(accept_encoding, "deflate") != NULL) {
|
||||||
if (status != NULL) {
|
http_add_header_field(&res.hdr, "Content-Encoding", "deflate");
|
||||||
res.status = http_get_status(strtoul(status, NULL, 10));
|
}
|
||||||
http_remove_header_field(&res.hdr, "Status", HTTP_REMOVE_ALL);
|
|
||||||
if (res.status == NULL){
|
content_length = -1;
|
||||||
res.status = http_get_status(500);
|
use_fastcgi = 1;
|
||||||
sprintf(err_msg, "The status code was set to an invalid or unknown value.");
|
if (http_get_header_field(&res.hdr, "Content-Length") == NULL) {
|
||||||
goto respond;
|
http_add_header_field(&res.hdr, "Transfer-Encoding", "chunked");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (conf->type != CONFIG_TYPE_LOCAL) {
|
||||||
char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding");
|
print("Reverse proxy for %s:%i", conf->rev_proxy.hostname, conf->rev_proxy.port);
|
||||||
if (accept_encoding != NULL && strstr(accept_encoding, "deflate") != NULL) {
|
// TODO Reverse Proxy
|
||||||
http_add_header_field(&res.hdr, "Content-Encoding", "deflate");
|
res.status = http_get_status(501);
|
||||||
}
|
} else {
|
||||||
|
print(ERR_STR "Unknown host type: %i" CLR_STR, conf->type);
|
||||||
content_length = -1;
|
res.status = http_get_status(501);
|
||||||
use_fastcgi = 1;
|
|
||||||
if (http_get_header_field(&res.hdr, "Content-Length") == NULL) {
|
|
||||||
http_add_header_field(&res.hdr, "Transfer-Encoding", "chunked");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
respond:
|
respond:
|
||||||
|
Reference in New Issue
Block a user