From cb46767a6da4efae396a7626aba73850212f6f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=A0=E8=BE=9C=E7=9A=84=E7=86=8A=E6=9C=AC=E7=86=8A?= <10804640+innocent-kumamoto@user.noreply.gitee.com> Date: Tue, 7 May 2024 17:57:54 +0800 Subject: [PATCH 1/3] update src --- simplehttpd.c | 517 ++++++++++++++++++++++++++++++++++++++++++++++++++ simplehttpd.h | 31 +++ test.c | 20 ++ 3 files changed, 568 insertions(+) create mode 100644 simplehttpd.c create mode 100644 simplehttpd.h create mode 100644 test.c diff --git a/simplehttpd.c b/simplehttpd.c new file mode 100644 index 0000000..19d62fc --- /dev/null +++ b/simplehttpd.c @@ -0,0 +1,517 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "simplehttpd.h" + +#define ISspace(x) isspace((int)(x)) + +#define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n" + +typedef void (*PostProcessDoneCallback)(int, const char *, int); +static PostProcessDoneCallback post_process_done_callback = NULL; + +typedef int (*PrintLog)(const char *, ...); +static PrintLog HTTPD_LOG_INFO = printf; +static PrintLog HTTPD_LOG_ERROR = printf; + +static char log_dir_path[128] = {0}; + +void *accept_request(void *arg); +void bad_request(int); +void cat(int, FILE *); +void cannot_execute(int); +int get_line(int, char *, int); +void headers(int, const char *); +void not_found(int); +void request_ok(int); +void serve_file(int, const char *); +void unimplemented(int); +void post_process(int, const char *, const char *, const char *); +void get_process(int, const char *, const char *, const char *); +int save_log_file(char *filename, char *buf, int len); + +void *accept_request(void *arg) +{ + int client = *(int *)arg; + char buf[1024]; + int numchars; + char method[255]; + char url[255]; + size_t i, j; + char *query_string = NULL; + + numchars = get_line(client, buf, sizeof(buf)); + i = 0; + j = 0; + + while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) + { + method[i] = buf[j]; + i++; + j++; + } + method[i] = '\0'; + + if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) + { + unimplemented(client); + close(client); + return NULL; + } + + i = 0; + while (ISspace(buf[j]) && (j < sizeof(buf))) + j++; + while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) + { + + url[i] = buf[j]; + i++; + j++; + } + url[i] = '\0'; + + if (strcasecmp(method, "GET") == 0) + { + query_string = url; + while ((*query_string != '?') && (*query_string != '\0')) + query_string++; + + if (*query_string == '?') + { + *query_string = '\0'; + query_string++; + } + } + + if (strcasecmp(method, "POST") == 0) + { + post_process(client, url, method, query_string); + } + else + { + get_process(client, url, method, query_string); + } + + close(client); + return NULL; +} + +void bad_request(int client) +{ + char buf[1024]; + + sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n"); + send(client, buf, sizeof(buf), MSG_NOSIGNAL); + sprintf(buf, "Content-type: text/html\r\n"); + send(client, buf, sizeof(buf), MSG_NOSIGNAL); + sprintf(buf, "\r\n"); + send(client, buf, sizeof(buf), MSG_NOSIGNAL); + sprintf(buf, "

Your browser sent a bad request, "); + send(client, buf, sizeof(buf), MSG_NOSIGNAL); + sprintf(buf, "such as a POST without a Content-Length.\r\n"); + send(client, buf, sizeof(buf), MSG_NOSIGNAL); +} + +void cat(int client, FILE *resource) +{ + char buf[1024]; + + fgets(buf, sizeof(buf), resource); + while (!feof(resource)) + { + send(client, buf, strlen(buf), MSG_NOSIGNAL); + fgets(buf, sizeof(buf), resource); + } +} + +void cannot_execute(int client) +{ + char buf[1024]; + + sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "Content-type: text/html\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "

Error prohibited CGI execution.\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); +} + +int save_log_file(char *filename, char *buf, int len) +{ + char path[255] = {0}; + sprintf(path, "%s%s", log_dir_path, filename); + FILE *fp = fopen(path, "a"); + if (fp == NULL) + { + HTTPD_LOG_ERROR("open log file %s failed.", path); + return -1; + } + if (fwrite(buf, 1, len, fp) != len) + { + HTTPD_LOG_ERROR("write log file %s failed.", path); + return -1; + } + if (fclose(fp) != 0) + { + HTTPD_LOG_ERROR("close log file %s failed.", path); + return -1; + } + return 0; +} + +void post_process(int client, const char *path, const char *method, const char *query_string) +{ + char buf[1024]; + char boundary[1024] = {0}; + char filename[1024] = {0}; + char *tmp; + int i; + int numchars = 1; + int content_length = -1; + + numchars = get_line(client, buf, sizeof(buf)); + + while ((numchars > 0) && strcmp("\n", buf)) + { + char tmp_char = buf[15]; + buf[15] = '\0'; + if (strcasecmp(buf, "Content-Length:") == 0) + { + content_length = atoi(&(buf[16])); + } + buf[15] = tmp_char; + + tmp_char = buf[13]; + buf[13] = '\0'; + if (strcasecmp(buf, "Content-Type:") == 0) + { + tmp = strstr(&buf[14], "boundary="); + if (tmp != NULL) + { + for (i = 0; i < 1023 && tmp[i + 9] != '\n'; i++) + { + boundary[i] = tmp[i + 9]; + } + boundary[i] = '\0'; + } + } + buf[13] = tmp_char; + numchars = get_line(client, buf, sizeof(buf)); + } + if (content_length == -1 || boundary[0] == '\0') + { + bad_request(client); + return; + } + + request_ok(client); + + char *tmp_buf = malloc(4096 * 1024); + memset(tmp_buf, 0, 4096 * 1024); + int total = 0; + while (1) + { + int n = recv(client, &tmp_buf[total], content_length, 0); + if (n < 0) + { + HTTPD_LOG_ERROR("recv data failed."); + return; + } + total += n; + if (total >= content_length) + { + break; + } + } + + tmp = strstr(tmp_buf, "filename=\""); + if (tmp == NULL) + { + HTTPD_LOG_ERROR("log filename not found."); + return; + } + + for (i = 0; i < 1023 && tmp[i + 10] != '\"'; i++) + { + filename[i] = tmp[i + 10]; + } + filename[i] = '\0'; + + char *data_start; + tmp = strstr(tmp_buf, "\r\n\r\n"); + if (tmp == NULL) + { + HTTPD_LOG_ERROR("log file data start flag failed."); + return; + } + data_start = &tmp[4]; + + char boundary_end[2048] = {0}; + sprintf(boundary_end, "--%s--", boundary); + char *data_end; + data_end = strstr(tmp_buf, boundary_end); + int data_len; + if (data_end == NULL) + { + HTTPD_LOG_ERROR("log file data end flag failed."); + return; + } + data_len = data_end - data_start - 2; + + HTTPD_LOG_INFO("recv log file datalen: %d.", data_len); + int ret = save_log_file(filename, data_start, data_len); + + if (post_process_done_callback != NULL) + { + post_process_done_callback(ret, filename, data_len); + } + + free(tmp_buf); + close(client); +} + +void get_process(int client, const char *path, const char *method, const char *query_string) +{ + char buf[1024]; + int numchars = 1; + buf[0] = 'A'; + buf[1] = '\0'; + while ((numchars > 0) && strcmp("\n", buf)) + { + numchars = get_line(client, buf, sizeof(buf)); + // Todo... + } + sprintf(buf, "HTTP/1.0 200 OK\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); +} + +int get_line(int sock, char *buf, int size) +{ + int i = 0; + char c = '\0'; + int n; + + while ((i < size - 1) && (c != '\n')) + { + n = recv(sock, &c, 1, 0); + if (n > 0) + { + if (c == '\r') + { + n = recv(sock, &c, 1, MSG_PEEK); + if ((n > 0) && (c == '\n')) + recv(sock, &c, 1, 0); + else + c = '\n'; + } + buf[i] = c; + i++; + } + else + c = '\n'; + } + buf[i] = '\0'; + + return (i); +} + +void headers(int client, const char *filename) +{ + char buf[1024]; + (void)filename; + + strcpy(buf, "HTTP/1.0 200 OK\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + + strcpy(buf, SERVER_STRING); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "Content-Type: text/html\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + strcpy(buf, "\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); +} + +void request_ok(int client) +{ + char buf[1024]; + sprintf(buf, "HTTP/1.0 200 OK\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); +} + +void not_found(int client) +{ + char buf[1024]; + + sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + + sprintf(buf, SERVER_STRING); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "Content-Type: text/html\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "Not Found\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "

The server could not fulfill\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "your request because the resource specified\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "is unavailable or nonexistent.\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); +} + +void serve_file(int client, const char *filename) +{ + FILE *resource = NULL; + int numchars = 1; + char buf[1024]; + + buf[0] = 'A'; + buf[1] = '\0'; + while ((numchars > 0) && strcmp("\n", buf)) + numchars = get_line(client, buf, sizeof(buf)); + + resource = fopen(filename, "r"); + if (resource == NULL) + not_found(client); + else + { + headers(client, filename); + + cat(client, resource); + } + fclose(resource); +} + +void unimplemented(int client) +{ + char buf[1024]; + + sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, SERVER_STRING); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "Content-Type: text/html\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "Method Not Implemented\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "

HTTP request method not supported.\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); + sprintf(buf, "\r\n"); + send(client, buf, strlen(buf), MSG_NOSIGNAL); +} + +int RegisterPostProcessDoneCallback(PostProcessDoneCallback callback) +{ + post_process_done_callback = callback; + return 0; +} + +int RegisterLogFunc(struct PrintLogFuncSet funcSet) +{ + if (funcSet.errorLog != NULL && funcSet.infoLog != NULL) + { + HTTPD_LOG_ERROR = funcSet.errorLog; + HTTPD_LOG_INFO = funcSet.infoLog; + return 0; + } + return -1; +} + +int SetLogSavePath(const char *path) +{ + if (strlen(path) >= 128) + { + HTTPD_LOG_ERROR("log save path is too long."); + return -1; + } + strcpy(log_dir_path, path); + return 0; +} + +int StartHttpServerSync(uint16_t port) +{ + int server_sock = -1; + int client_sock = -1; + struct sockaddr_in client_name; + int client_name_len = sizeof(client_name); + pthread_t newthread; + struct sockaddr_in name; + + server_sock = socket(PF_INET, SOCK_STREAM, 0); + if (server_sock == -1) + { + HTTPD_LOG_ERROR("socket create failed."); + return -1; + } + memset(&name, 0, sizeof(name)); + name.sin_family = AF_INET; + name.sin_port = htons(port); + name.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(server_sock, (struct sockaddr *)&name, sizeof(name)) < 0) + { + HTTPD_LOG_ERROR("bind failed."); + close(server_sock); + return -1; + } + if (port == 0) + { + int namelen = sizeof(name); + if (getsockname(server_sock, (struct sockaddr *)&name, &namelen) == -1) + { + HTTPD_LOG_ERROR("getsockname failed."); + close(server_sock); + return -1; + } + port = ntohs(name.sin_port); + } + if (listen(server_sock, 20) < 0) + { + HTTPD_LOG_ERROR("listen failed."); + close(server_sock); + return -1; + } + + HTTPD_LOG_INFO("simplehttpd running on port %d.", port); + + while (1) + { + client_sock = accept(server_sock, (struct sockaddr *)&client_name, &client_name_len); + if (client_sock == -1) + { + HTTPD_LOG_ERROR("accept failed."); + close(server_sock); + return -1; + } + + if (pthread_create(&newthread, NULL, accept_request, (void *)&client_sock) != 0) + { + close(server_sock); + return -1; + } + } + + close(server_sock); + return -1; +} diff --git a/simplehttpd.h b/simplehttpd.h new file mode 100644 index 0000000..e73a2f6 --- /dev/null +++ b/simplehttpd.h @@ -0,0 +1,31 @@ +#ifndef HTTPD_H +#define HTTPD_H + +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif +typedef void (*PostProcessDoneCallback)(int code, const char * filename, int datalen); +typedef int (*PrintLog)(const char* format, ...); + +struct PrintLogFuncSet +{ + PrintLog infoLog; + PrintLog errorLog; +}; + +int RegisterPostProcessDoneCallback(PostProcessDoneCallback callback); +int RegisterLogFunc(struct PrintLogFuncSet funcSet); +int SetLogSavePath(const char *path); +int StartHttpServerSync(uint16_t port); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif //HTTPD_H \ No newline at end of file diff --git a/test.c b/test.c new file mode 100644 index 0000000..f32a540 --- /dev/null +++ b/test.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include "simplehttpd.h" + +void ProcessDoneCallback(int code, const char *filename, int datalen) +{ + printf("code: %d, filename: %s, datalen: %d\n", code, filename, datalen); +} + +int main() +{ + int ret; + ret = RegisterPostProcessDoneCallback(ProcessDoneCallback); + printf("RegisterPostProcessDoneCallback ret=%d\n", ret); + ret = SetLogSavePath("/home/tongkang/"); + printf("SetLogSavePath ret=%d\n", ret); + ret = StartHttpServerSync(9999); + return 0; +} \ No newline at end of file -- Gitee From 4cd09b49a31f52b09590e668d2f9cb0fdcd2b757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=A0=E8=BE=9C=E7=9A=84=E7=86=8A=E6=9C=AC=E7=86=8A?= <10804640+innocent-kumamoto@user.noreply.gitee.com> Date: Tue, 7 May 2024 18:45:21 +0800 Subject: [PATCH 2/3] update --- simplehttpd.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/simplehttpd.c b/simplehttpd.c index 19d62fc..07a20c9 100644 --- a/simplehttpd.c +++ b/simplehttpd.c @@ -34,7 +34,7 @@ void cannot_execute(int); int get_line(int, char *, int); void headers(int, const char *); void not_found(int); -void request_ok(int); +void reponse_ok(int); void serve_file(int, const char *); void unimplemented(int); void post_process(int, const char *, const char *, const char *); @@ -98,10 +98,12 @@ void *accept_request(void *arg) if (strcasecmp(method, "POST") == 0) { post_process(client, url, method, query_string); + reponse_ok(client); } else { get_process(client, url, method, query_string); + reponse_ok(client); } close(client); @@ -218,9 +220,12 @@ void post_process(int client, const char *path, const char *method, const char * return; } - request_ok(client); - char *tmp_buf = malloc(4096 * 1024); + if (tmp_buf == NULL) + { + HTTPD_LOG_ERROR("malloc buffer failed."); + return; + } memset(tmp_buf, 0, 4096 * 1024); int total = 0; while (1) @@ -229,6 +234,7 @@ void post_process(int client, const char *path, const char *method, const char * if (n < 0) { HTTPD_LOG_ERROR("recv data failed."); + free(tmp_buf); return; } total += n; @@ -242,6 +248,7 @@ void post_process(int client, const char *path, const char *method, const char * if (tmp == NULL) { HTTPD_LOG_ERROR("log filename not found."); + free(tmp_buf); return; } @@ -256,6 +263,7 @@ void post_process(int client, const char *path, const char *method, const char * if (tmp == NULL) { HTTPD_LOG_ERROR("log file data start flag failed."); + free(tmp_buf); return; } data_start = &tmp[4]; @@ -268,6 +276,7 @@ void post_process(int client, const char *path, const char *method, const char * if (data_end == NULL) { HTTPD_LOG_ERROR("log file data end flag failed."); + free(tmp_buf); return; } data_len = data_end - data_start - 2; @@ -281,7 +290,6 @@ void post_process(int client, const char *path, const char *method, const char * } free(tmp_buf); - close(client); } void get_process(int client, const char *path, const char *method, const char *query_string) @@ -295,8 +303,6 @@ void get_process(int client, const char *path, const char *method, const char *q numchars = get_line(client, buf, sizeof(buf)); // Todo... } - sprintf(buf, "HTTP/1.0 200 OK\r\n"); - send(client, buf, strlen(buf), MSG_NOSIGNAL); } int get_line(int sock, char *buf, int size) @@ -345,7 +351,7 @@ void headers(int client, const char *filename) send(client, buf, strlen(buf), MSG_NOSIGNAL); } -void request_ok(int client) +void reponse_ok(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 200 OK\r\n"); -- Gitee From e0a7c6e3ecaf7782c0c42209542fa03c5e042871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=A0=E8=BE=9C=E7=9A=84=E7=86=8A=E6=9C=AC=E7=86=8A?= <10804640+innocent-kumamoto@user.noreply.gitee.com> Date: Tue, 7 May 2024 18:48:23 +0800 Subject: [PATCH 3/3] update --- simplehttpd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/simplehttpd.c b/simplehttpd.c index 07a20c9..74b1a34 100644 --- a/simplehttpd.c +++ b/simplehttpd.c @@ -34,7 +34,7 @@ void cannot_execute(int); int get_line(int, char *, int); void headers(int, const char *); void not_found(int); -void reponse_ok(int); +void response_ok(int); void serve_file(int, const char *); void unimplemented(int); void post_process(int, const char *, const char *, const char *); @@ -98,12 +98,12 @@ void *accept_request(void *arg) if (strcasecmp(method, "POST") == 0) { post_process(client, url, method, query_string); - reponse_ok(client); + response_ok(client); } else { get_process(client, url, method, query_string); - reponse_ok(client); + response_ok(client); } close(client); @@ -351,7 +351,7 @@ void headers(int client, const char *filename) send(client, buf, strlen(buf), MSG_NOSIGNAL); } -void reponse_ok(int client) +void response_ok(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 200 OK\r\n"); -- Gitee