http.c improvements
This commit is contained in:
@@ -33,6 +33,7 @@ And then open the `docs/html/index.html`.
|
|||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- Implement Keep-Alive
|
- Implement Keep-Alive
|
||||||
|
- Custom web pages (404)
|
||||||
- Support for virtual hosts
|
- Support for virtual hosts
|
||||||
- HTTPS support with TLS
|
- HTTPS support with TLS
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef CWS_HTTP_H
|
#ifndef CWS_HTTP_H
|
||||||
#define CWS_HTTP_H
|
#define CWS_HTTP_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "utils/config.h"
|
#include "utils/config.h"
|
||||||
#include "utils/hashmap.h"
|
#include "utils/hashmap.h"
|
||||||
|
|
||||||
@@ -16,6 +18,12 @@ typedef enum cws_http_method_t {
|
|||||||
CWS_HTTP_HEAD,
|
CWS_HTTP_HEAD,
|
||||||
} cws_http_method;
|
} cws_http_method;
|
||||||
|
|
||||||
|
typedef enum cws_http_status_t {
|
||||||
|
CWS_HTTP_OK,
|
||||||
|
CWS_HTTP_NOT_FOUND,
|
||||||
|
CWS_HTTP_NOT_IMPLEMENTED,
|
||||||
|
} cws_http_status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief HTTP request struct
|
* @brief HTTP request struct
|
||||||
*
|
*
|
||||||
@@ -40,12 +48,21 @@ typedef struct cws_http_t {
|
|||||||
*/
|
*/
|
||||||
cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config);
|
cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config);
|
||||||
|
|
||||||
void cws_http_parse_method(cws_http *request, const char *method);
|
int cws_http_parse_method(cws_http *request, const char *method);
|
||||||
void cws_http_get_content_type(cws_http *request, char *content_type);
|
void cws_http_get_content_type(cws_http *request, char *content_type);
|
||||||
|
char *cws_http_status_string(cws_http_status status);
|
||||||
|
|
||||||
void cws_http_send_response(cws_http *request);
|
/**
|
||||||
void cws_http_send_not_found(cws_http *request);
|
* @brief Build the http response
|
||||||
void cws_http_send_not_implemented(cws_http *request);
|
*
|
||||||
|
* @return Returns the size of the response
|
||||||
|
*/
|
||||||
|
size_t cws_http_response_builder(char **response, char *http_version, cws_http_status status, char *content_type, char *connection, char *body,
|
||||||
|
size_t body_len_bytes);
|
||||||
|
|
||||||
|
void cws_http_send_response(cws_http *request, cws_http_status status);
|
||||||
|
void cws_http_send_resource(cws_http *request);
|
||||||
|
void cws_http_send_error_page(cws_http *request, cws_http_status status, char *title, char *description);
|
||||||
|
|
||||||
void cws_http_free(cws_http *request);
|
void cws_http_free(cws_http *request);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "utils/config.h"
|
#include "utils/config.h"
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
#define CWS_SERVER_EPOLL_TIMEOUT -1
|
#define CWS_SERVER_EPOLL_TIMEOUT -1
|
||||||
|
|
||||||
/* Main server loop */
|
/* Main server loop */
|
||||||
extern volatile bool cws_server_run;
|
extern volatile sig_atomic_t cws_server_run;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Runs the server
|
* @brief Runs the server
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EVELOPER
|
#ifdef EVELOPER
|
||||||
#define CWS_LOG_DEBUG(msg, ...) fprintf(stdout, _DEBUG " " msg "\n", ##__VA_ARGS__)
|
#define CWS_LOG_DEBUG(msg, ...) fprintf(stdout, _DEBUG " [%s:%d] " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define CWS_LOG_DEBUG(msg, ...)
|
#define CWS_LOG_DEBUG(msg, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
212
src/http/http.c
212
src/http/http.c
@@ -9,33 +9,52 @@
|
|||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
|
|
||||||
cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) {
|
cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) {
|
||||||
cws_http *request = malloc(sizeof(cws_http));
|
if (!request_str || !config) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cws_http *request = calloc(1, sizeof(cws_http));
|
||||||
if (request == NULL) {
|
if (request == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(request, 0, sizeof(cws_http));
|
|
||||||
|
|
||||||
/* Insert socket file descriptor */
|
|
||||||
request->sockfd = sockfd;
|
request->sockfd = sockfd;
|
||||||
|
|
||||||
|
char *request_str_cpy = strdup(request_str);
|
||||||
|
if (!request_str_cpy) {
|
||||||
|
free(request);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *saveptr = NULL;
|
||||||
|
char *pch = NULL;
|
||||||
|
|
||||||
/* Parse HTTP method */
|
/* Parse HTTP method */
|
||||||
char *pch = strtok(request_str, " ");
|
pch = strtok_r(request_str_cpy, " ", &saveptr);
|
||||||
if (pch == NULL) {
|
if (pch == NULL) {
|
||||||
cws_http_free(request);
|
cws_http_free(request);
|
||||||
|
free(request_str_cpy);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
CWS_LOG_DEBUG("[http] method: %s", pch);
|
CWS_LOG_DEBUG("method: %s", pch);
|
||||||
cws_http_parse_method(request, pch);
|
int ret = cws_http_parse_method(request, pch);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* Not implemented */
|
||||||
|
cws_http_free(request);
|
||||||
|
free(request_str_cpy);
|
||||||
|
|
||||||
|
cws_http_send_error_page(request, CWS_HTTP_NOT_IMPLEMENTED, "501 Not Implemented", "501 Not Implemented");
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse location */
|
/* Parse location */
|
||||||
pch = strtok(NULL, " ");
|
pch = strtok_r(NULL, " ", &saveptr);
|
||||||
if (pch == NULL) {
|
if (pch == NULL) {
|
||||||
cws_http_free(request);
|
cws_http_free(request);
|
||||||
|
free(request_str_cpy);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
CWS_LOG_DEBUG("[http] location: %s", pch);
|
CWS_LOG_DEBUG("location: %s", pch);
|
||||||
strncpy(request->location, pch, CWS_HTTP_LOCATION_LEN);
|
strncpy(request->location, pch, CWS_HTTP_LOCATION_LEN);
|
||||||
|
|
||||||
/* Adjust location path */
|
/* Adjust location path */
|
||||||
@@ -44,16 +63,17 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) {
|
|||||||
} else {
|
} else {
|
||||||
snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s%s", config->www, request->location);
|
snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s%s", config->www, request->location);
|
||||||
}
|
}
|
||||||
CWS_LOG_DEBUG("[http] location path: %s", request->location_path);
|
CWS_LOG_DEBUG("location path: %s", request->location_path);
|
||||||
|
|
||||||
/* Parse HTTP version */
|
/* Parse HTTP version */
|
||||||
pch = strtok(NULL, " \r\n");
|
pch = strtok_r(NULL, " \r\n", &saveptr);
|
||||||
if (pch == NULL) {
|
if (pch == NULL) {
|
||||||
cws_http_free(request);
|
cws_http_free(request);
|
||||||
|
free(request_str_cpy);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
CWS_LOG_DEBUG("[http] version: %s", pch);
|
CWS_LOG_DEBUG("version: %s", pch);
|
||||||
strncpy(request->http_version, pch, CWS_HTTP_VERSION_LEN);
|
strncpy(request->http_version, pch, CWS_HTTP_VERSION_LEN);
|
||||||
|
|
||||||
/* Parse headers until a \r\n */
|
/* Parse headers until a \r\n */
|
||||||
@@ -61,7 +81,7 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) {
|
|||||||
char *header_colon;
|
char *header_colon;
|
||||||
while (pch) {
|
while (pch) {
|
||||||
/* Get header line */
|
/* Get header line */
|
||||||
pch = strtok(NULL, "\r\n");
|
pch = strtok_r(NULL, "\r\n", &saveptr);
|
||||||
if (pch == NULL) {
|
if (pch == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -83,29 +103,90 @@ cws_http *cws_http_parse(char *request_str, int sockfd, cws_config *config) {
|
|||||||
cws_hm_set(request->headers, hkey_dup, hvalue_dup);
|
cws_hm_set(request->headers, hkey_dup, hvalue_dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse body */
|
/* TODO: Parse body */
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cws_http_parse_method(cws_http *request, const char *method) {
|
int cws_http_parse_method(cws_http *request, const char *method) {
|
||||||
if (strcmp(method, "GET") == 0) {
|
if (strcmp(method, "GET") == 0) {
|
||||||
request->method = CWS_HTTP_GET;
|
request->method = CWS_HTTP_GET;
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(method, "POST") == 0) {
|
if (strcmp(method, "POST") == 0) {
|
||||||
request->method = CWS_HTTP_POST;
|
request->method = CWS_HTTP_POST;
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cws_http_send_not_implemented(request);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cws_http_send_response(cws_http *request) {
|
char *cws_http_status_string(cws_http_status status) {
|
||||||
|
switch (status) {
|
||||||
|
case CWS_HTTP_OK: {
|
||||||
|
return "200 OK";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CWS_HTTP_NOT_FOUND: {
|
||||||
|
return "404 Not Found";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CWS_HTTP_NOT_IMPLEMENTED: {
|
||||||
|
return "501 Not Implemented";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cws_http_response_builder(char **response, char *http_version, cws_http_status status, char *content_type, char *connection, char *body,
|
||||||
|
size_t body_len_bytes) {
|
||||||
|
char *status_code = cws_http_status_string(status);
|
||||||
|
|
||||||
|
size_t header_len = snprintf(NULL, 0,
|
||||||
|
"%s %s\r\n"
|
||||||
|
"Content-Type: %s\r\n"
|
||||||
|
"Content-Length: %ld\r\n"
|
||||||
|
"Connection: %s\r\n"
|
||||||
|
"\r\n",
|
||||||
|
http_version, status_code, content_type, body_len_bytes, connection);
|
||||||
|
|
||||||
|
size_t total_len = header_len + body_len_bytes;
|
||||||
|
|
||||||
|
*response = (char *)malloc(total_len);
|
||||||
|
if (*response == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(*response, header_len + 1, "%s %s\r\nContent-Type: %s\r\nContent-Length: %ld\r\nConnection: %s\r\n\r\n", http_version, status_code, content_type,
|
||||||
|
body_len_bytes, connection);
|
||||||
|
|
||||||
|
memcpy(*response + header_len, body, body_len_bytes);
|
||||||
|
|
||||||
|
return total_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cws_http_send_response(cws_http *request, cws_http_status status) {
|
||||||
|
switch (status) {
|
||||||
|
case CWS_HTTP_OK:
|
||||||
|
break;
|
||||||
|
case CWS_HTTP_NOT_FOUND: {
|
||||||
|
cws_http_send_error_page(request, CWS_HTTP_NOT_FOUND, "404 Not Found", "Resource not found, 404.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CWS_HTTP_NOT_IMPLEMENTED: {
|
||||||
|
cws_http_send_error_page(request, CWS_HTTP_NOT_IMPLEMENTED, "501 Not Implemented", "Method not implemented, 501.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cws_http_send_resource(cws_http *request) {
|
||||||
FILE *file = fopen(request->location_path, "rb");
|
FILE *file = fopen(request->location_path, "rb");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
/* 404 */
|
cws_http_send_response(request, CWS_HTTP_NOT_FOUND);
|
||||||
cws_http_send_not_found(request);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +196,7 @@ void cws_http_send_response(cws_http *request) {
|
|||||||
|
|
||||||
/* Retrieve file size */
|
/* Retrieve file size */
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
const size_t content_length = ftell(file); /* Returns the read bytes (we're at the end, so the file size) */
|
const size_t content_length = ftell(file);
|
||||||
rewind(file);
|
rewind(file);
|
||||||
|
|
||||||
/* Retrieve file data */
|
/* Retrieve file data */
|
||||||
@@ -127,28 +208,33 @@ void cws_http_send_response(cws_http *request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read 1 byte until content_length from file and put in file_data */
|
/* Read 1 byte until content_length from file and put in file_data */
|
||||||
fread(file_data, 1, content_length, file);
|
size_t read_bytes = fread(file_data, 1, content_length, file);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
char response_header[2048];
|
if (read_bytes != content_length) {
|
||||||
snprintf(response_header, sizeof response_header,
|
free(file_data);
|
||||||
"%s 200 OK\r\n"
|
CWS_LOG_ERROR("Partial read from file.");
|
||||||
"Content-Type: %s\r\n"
|
return;
|
||||||
"Content-Length: %zu\r\n"
|
}
|
||||||
"Connection: close\r\n"
|
|
||||||
"\r\n",
|
|
||||||
request->http_version, content_type, content_length);
|
|
||||||
|
|
||||||
send(request->sockfd, response_header, strlen(response_header), 0);
|
char *response = NULL;
|
||||||
send(request->sockfd, file_data, content_length, 0);
|
size_t response_len = cws_http_response_builder(&response, "HTTP/1.1", CWS_HTTP_OK, content_type, "close", file_data, content_length);
|
||||||
|
CWS_LOG_DEBUG("%s", response);
|
||||||
|
|
||||||
|
size_t bytes_sent = 0;
|
||||||
|
do {
|
||||||
|
size_t sent = send(request->sockfd, response + bytes_sent, response_len, 0);
|
||||||
|
bytes_sent += sent;
|
||||||
|
} while (bytes_sent < response_len);
|
||||||
|
|
||||||
|
free(response);
|
||||||
free(file_data);
|
free(file_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cws_http_get_content_type(cws_http *request, char *content_type) {
|
void cws_http_get_content_type(cws_http *request, char *content_type) {
|
||||||
char *ptr = strrchr(request->location_path, '.');
|
char *ptr = strrchr(request->location_path, '.');
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
cws_http_send_not_found(request);
|
cws_http_send_error_page(request, CWS_HTTP_NOT_FOUND, "404 Not Found", "404 Not Found.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ptr += 1;
|
ptr += 1;
|
||||||
@@ -167,46 +253,26 @@ void cws_http_get_content_type(cws_http *request, char *content_type) {
|
|||||||
snprintf(content_type, 1024, "%s/%s", ct, ptr);
|
snprintf(content_type, 1024, "%s/%s", ct, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cws_http_send_not_implemented(cws_http *request) {
|
void cws_http_send_error_page(cws_http *request, cws_http_status status, char *title, char *description) {
|
||||||
const char response[1024] =
|
char body[512];
|
||||||
"HTTP/1.1 501 Not Implemented\r\n"
|
memset(body, 0, sizeof(body));
|
||||||
"Content-Type: text/html\r\n"
|
|
||||||
"Content-Length: 216\r\n"
|
snprintf(body, sizeof(body),
|
||||||
"\r\n"
|
"<html>\n"
|
||||||
"<html>\n"
|
"<head>\n"
|
||||||
"<head>\n"
|
" <title>%s</title>\n"
|
||||||
" <title>501 Not Implemented</title>\n"
|
"</head>\n"
|
||||||
"</head>\n"
|
"<body>\n"
|
||||||
"<body>\n"
|
"<p>%s</p>\n"
|
||||||
"<p>501 Not Implemented</p>\n"
|
"</body>"
|
||||||
"</body>\n"
|
"</html>",
|
||||||
"</html>";
|
title, description);
|
||||||
const size_t response_len = strlen(response);
|
size_t body_len = strlen(body) * sizeof(char);
|
||||||
send(request->sockfd, response, response_len, 0);
|
|
||||||
}
|
char *response = NULL;
|
||||||
|
size_t response_len = cws_http_response_builder(&response, "HTTP/1.1", status, "text/html", "close", body, body_len);
|
||||||
void cws_http_send_not_found(cws_http *request) {
|
|
||||||
const char html_body[] =
|
|
||||||
"<html>\n"
|
|
||||||
"<head>\n"
|
|
||||||
" <title>404 Not Found</title>\n"
|
|
||||||
"</head>\n"
|
|
||||||
"<body>\n"
|
|
||||||
"<p>404 Not Found.</p>\n"
|
|
||||||
"</body>\n"
|
|
||||||
"</html>";
|
|
||||||
int html_body_len = strlen(html_body);
|
|
||||||
|
|
||||||
char response[1024];
|
|
||||||
int response_len = snprintf(response, sizeof(response),
|
|
||||||
"HTTP/1.1 404 Not Found\r\n"
|
|
||||||
"Content-Type: text/html\r\n"
|
|
||||||
"Content-Length: %d\r\n"
|
|
||||||
"\r\n"
|
|
||||||
"%s",
|
|
||||||
html_body_len, html_body);
|
|
||||||
|
|
||||||
send(request->sockfd, response, response_len, 0);
|
send(request->sockfd, response, response_len, 0);
|
||||||
|
free(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cws_http_free(cws_http *request) {
|
void cws_http_free(cws_http *request) {
|
||||||
|
|||||||
22
src/main.c
22
src/main.c
@@ -7,31 +7,29 @@
|
|||||||
#include "utils/colors.h"
|
#include "utils/colors.h"
|
||||||
#include "utils/config.h"
|
#include "utils/config.h"
|
||||||
|
|
||||||
void cws_signal_handler(int signo) { cws_server_run = false; }
|
void cws_signal_handler(int signo) { cws_server_run = 0; }
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(void) {
|
||||||
int ret;
|
struct sigaction act = {.sa_handler = cws_signal_handler, .sa_flags = 0, .sa_mask = {{0}}};
|
||||||
|
if (sigaction(SIGINT, &act, NULL)) {
|
||||||
struct sigaction act = {.sa_handler = cws_signal_handler};
|
|
||||||
ret = sigaction(SIGINT, &act, NULL);
|
|
||||||
if (ret) {
|
|
||||||
CWS_LOG_ERROR("sigaction(): %s", strerror(errno));
|
CWS_LOG_ERROR("sigaction(): %s", strerror(errno));
|
||||||
return 1;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
cws_config *config = cws_config_init();
|
cws_config *config = cws_config_init();
|
||||||
if (config == NULL) {
|
if (!config) {
|
||||||
CWS_LOG_ERROR("Unable to read config file");
|
CWS_LOG_ERROR("Unable to read config file");
|
||||||
return 1;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CWS_LOG_INFO("Running cws on http://%s:%s...", config->hostname, config->port);
|
CWS_LOG_INFO("Running cws on http://%s:%s...", config->hostname, config->port);
|
||||||
ret = cws_server_start(config);
|
int ret = cws_server_start(config);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
CWS_LOG_ERROR("Unable to start web server");
|
CWS_LOG_ERROR("Unable to start web server");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CWS_LOG_INFO("Shutting down cws...");
|
||||||
cws_config_free(config);
|
cws_config_free(config);
|
||||||
|
|
||||||
return 0;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#include "utils/colors.h"
|
#include "utils/colors.h"
|
||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
|
|
||||||
volatile bool cws_server_run = 1;
|
volatile sig_atomic_t cws_server_run = 1;
|
||||||
|
|
||||||
int cws_server_start(cws_config *config) {
|
int cws_server_start(cws_config *config) {
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
@@ -28,32 +28,32 @@ int cws_server_start(cws_config *config) {
|
|||||||
int status = getaddrinfo(config->hostname, config->port, &hints, &res);
|
int status = getaddrinfo(config->hostname, config->port, &hints, &res);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
CWS_LOG_ERROR("getaddrinfo() error: %s", gai_strerror(status));
|
CWS_LOG_ERROR("getaddrinfo() error: %s", gai_strerror(status));
|
||||||
exit(EXIT_FAILURE);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||||
if (sockfd < 0) {
|
if (sockfd < 0) {
|
||||||
CWS_LOG_ERROR("socket(): %s", strerror(errno));
|
CWS_LOG_ERROR("socket(): %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int opt = 1;
|
const int opt = 1;
|
||||||
status = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
|
status = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
CWS_LOG_ERROR("setsockopt(): %s", strerror(errno));
|
CWS_LOG_ERROR("setsockopt(): %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = bind(sockfd, res->ai_addr, res->ai_addrlen);
|
status = bind(sockfd, res->ai_addr, res->ai_addrlen);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
CWS_LOG_ERROR("bind(): %s", strerror(errno));
|
CWS_LOG_ERROR("bind(): %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = listen(sockfd, CWS_SERVER_BACKLOG);
|
status = listen(sockfd, CWS_SERVER_BACKLOG);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
CWS_LOG_ERROR("listen(): %s", strerror(status));
|
CWS_LOG_ERROR("listen(): %s", strerror(status));
|
||||||
exit(EXIT_FAILURE);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cws_server_loop(sockfd, config);
|
cws_server_loop(sockfd, config);
|
||||||
@@ -125,6 +125,7 @@ void cws_server_loop(int sockfd, cws_config *config) {
|
|||||||
cws_server_close_client(epfd, client_fd, clients);
|
cws_server_close_client(epfd, client_fd, clients);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_read < 0) {
|
if (bytes_read < 0) {
|
||||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||||
/* Error during read, handle it (close client) */
|
/* Error during read, handle it (close client) */
|
||||||
@@ -134,18 +135,15 @@ void cws_server_loop(int sockfd, cws_config *config) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
data[bytes_read] = '\0';
|
|
||||||
|
|
||||||
/* Parse HTTP request */
|
/* Parse HTTP request */
|
||||||
cws_http *request = cws_http_parse(data, client_fd, config);
|
cws_http *request = cws_http_parse(data, client_fd, config);
|
||||||
|
|
||||||
if (request == NULL) {
|
if (request == NULL) {
|
||||||
cws_server_close_client(epfd, client_fd, clients);
|
cws_server_close_client(epfd, client_fd, clients);
|
||||||
cws_http_free(request);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cws_http_send_response(request);
|
cws_http_send_resource(request);
|
||||||
CWS_LOG_INFO("Client (%s) disconnected", ip);
|
CWS_LOG_INFO("Client (%s) disconnected", ip);
|
||||||
cws_server_close_client(epfd, client_fd, clients);
|
cws_server_close_client(epfd, client_fd, clients);
|
||||||
cws_http_free(request);
|
cws_http_free(request);
|
||||||
@@ -188,7 +186,7 @@ void cws_fd_set_nonblocking(int sockfd) {
|
|||||||
const int status = fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
const int status = fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
if (status == -1) {
|
if (status == -1) {
|
||||||
CWS_LOG_ERROR("fcntl(): %s", gai_strerror(status));
|
CWS_LOG_ERROR("fcntl(): %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,12 @@ static const cyaml_config_t cyaml_config = {
|
|||||||
.log_level = CYAML_LOG_WARNING,
|
.log_level = CYAML_LOG_WARNING,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const cyaml_schema_field_t top_mapping_schema[] = {
|
static const cyaml_schema_field_t top_mapping_schema[] = {CYAML_FIELD_STRING_PTR("hostname", CYAML_FLAG_POINTER, cws_config, hostname, 0, CYAML_UNLIMITED),
|
||||||
CYAML_FIELD_STRING_PTR("hostname", CYAML_FLAG_POINTER, cws_config, hostname, 0, CYAML_UNLIMITED),
|
CYAML_FIELD_STRING_PTR("port", CYAML_FLAG_POINTER, cws_config, port, 0, CYAML_UNLIMITED),
|
||||||
CYAML_FIELD_STRING_PTR("port", CYAML_FLAG_POINTER, cws_config, port, 0, CYAML_UNLIMITED),
|
CYAML_FIELD_STRING_PTR("www", CYAML_FLAG_POINTER, cws_config, www, 0, CYAML_UNLIMITED),
|
||||||
CYAML_FIELD_STRING_PTR("www", CYAML_FLAG_POINTER, cws_config, www, 0, CYAML_UNLIMITED),
|
CYAML_FIELD_STRING_PTR("cert", CYAML_FLAG_POINTER, cws_config, cert, 0, CYAML_UNLIMITED),
|
||||||
CYAML_FIELD_STRING_PTR("cert", CYAML_FLAG_POINTER, cws_config, cert, 0, CYAML_UNLIMITED),
|
CYAML_FIELD_STRING_PTR("key", CYAML_FLAG_POINTER, cws_config, key, 0, CYAML_UNLIMITED),
|
||||||
CYAML_FIELD_STRING_PTR("key", CYAML_FLAG_POINTER, cws_config, key, 0, CYAML_UNLIMITED),
|
CYAML_FIELD_END};
|
||||||
CYAML_FIELD_END
|
|
||||||
};
|
|
||||||
|
|
||||||
static const cyaml_schema_value_t top_schema = {
|
static const cyaml_schema_value_t top_schema = {
|
||||||
CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, cws_config, top_mapping_schema),
|
CYAML_VALUE_MAPPING(CYAML_FLAG_POINTER, cws_config, top_mapping_schema),
|
||||||
|
|||||||
Reference in New Issue
Block a user