From ddcd7e38170cab3d9f740d3a546e4d88edc9cd24 Mon Sep 17 00:00:00 2001 From: Nishi Date: Fri, 13 Sep 2024 15:09:52 +0000 Subject: [PATCH] can parse http now git-svn-id: file:///raid/svn-personal/tewi/trunk@16 8739d7e6-ffea-ec47-b151-bdff447c6205 --- Common/cm_string.h | 1 + Common/string.c | 7 ++ Server/Makefile | 2 +- Server/config.c | 2 + Server/http.c | 243 +++++++++++++++++++++++++++++++++++++++++++++ Server/main.c | 6 ++ Server/server.c | 23 ++++- Server/ssl.c | 2 + Server/tw_http.h | 25 +++++ Server/tw_server.h | 4 + Server/version.c | 2 + 11 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 Server/http.c create mode 100644 Server/tw_http.h diff --git a/Common/cm_string.h b/Common/cm_string.h index 01f7f18..476e297 100644 --- a/Common/cm_string.h +++ b/Common/cm_string.h @@ -6,6 +6,7 @@ #include char* cm_strcat(const char* a, const char* b); +char* cm_strcat3(const char* a, const char* b, const char* c); char* cm_strdup(const char* str); char* cm_trimstart(const char* str); char* cm_trimend(const char* str); diff --git a/Common/string.c b/Common/string.c index bd34458..f858d77 100644 --- a/Common/string.c +++ b/Common/string.c @@ -13,6 +13,13 @@ char* cm_strcat(const char* a, const char* b) { return str; } +char* cm_strcat3(const char* a, const char* b, const char* c) { + char* tmp = cm_strcat(a, b); + char* str = cm_strcat(tmp, c); + free(tmp); + return str; +} + char* cm_strdup(const char* str) { return cm_strcat(str, ""); } char* cm_trimstart(const char* str) { diff --git a/Server/Makefile b/Server/Makefile index a2ef9e8..0053402 100644 --- a/Server/Makefile +++ b/Server/Makefile @@ -5,7 +5,7 @@ include $(PWD)/Platform/$(PLATFORM).mk .PHONY: all clean .SUFFIXES: .c .o -OBJS = version.o main.o config.o server.o ssl.o +OBJS = version.o main.o config.o server.o ssl.o http.o all: tewi$(EXEC) diff --git a/Server/config.c b/Server/config.c index 1104a03..1920627 100644 --- a/Server/config.c +++ b/Server/config.c @@ -1,5 +1,7 @@ /* $Id$ */ +#define SOURCE + #include "tw_config.h" #include diff --git a/Server/http.c b/Server/http.c new file mode 100644 index 0000000..0462d3d --- /dev/null +++ b/Server/http.c @@ -0,0 +1,243 @@ +/* $Id$ */ + +#define SOURCE + +#include "tw_http.h" + +#include "tw_server.h" + +#include +#include + +#include +#include +#include + +void tw_free_request(struct tw_http_request* req) { + if(req->method != NULL) free(req->method); + if(req->path != NULL) free(req->path); + if(req->headers != NULL) { + int i; + for(i = 0; req->headers[i] != NULL; i++) free(req->headers[i]); + free(req->headers); + } + if(req->body != NULL) free(req->body); + if(req->version != NULL) free(req->version); +} + +int tw_http_parse(SSL* ssl, int sock, struct tw_http_request* req) { + char buffer[512]; + char cbuf[2]; + int phase = 0; + fd_set fds; + + bool bad = false; + + cbuf[1] = 0; + + req->method = NULL; + req->path = NULL; + req->headers = NULL; + req->body = NULL; + req->version = NULL; + + char* header = malloc(1); + header[0] = 0; + int nl = 0; + + while(1) { + FD_ZERO(&fds); + FD_SET(sock, &fds); + struct timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + int n = select(FD_SETSIZE, &fds, NULL, NULL, &tv); + if(n == 0) break; + int len = tw_read(ssl, sock, buffer, 512); + if(len <= 0) break; + int i; + for(i = 0; i < len; i++) { + char c = buffer[i]; + if(phase == 0) { + if(c == ' ') { + if(req->method == NULL) { + tw_free_request(req); + bad = true; + goto getout; + } else { + phase++; + } + } else { + if(req->method == NULL) { + req->method = malloc(1); + req->method[0] = 0; + } + cbuf[0] = c; + char* tmp = req->method; + req->method = cm_strcat(tmp, cbuf); + free(tmp); + } + } else if(phase == 1) { + if(c == ' ') { + if(req->path == NULL) { + tw_free_request(req); + bad = true; + goto getout; + } else { + phase++; + } + } else { + if(req->path == NULL) { + req->path = malloc(1); + req->path[0] = 0; + } + cbuf[0] = c; + char* tmp = req->path; + req->path = cm_strcat(tmp, cbuf); + free(tmp); + } + } else if(phase == 2) { + if(c == '\n') { + if(req->version == NULL) { + tw_free_request(req); + bad = true; + goto getout; + } else { + /* We have Method, Path, Version now */ + + if(strcmp(req->version, "HTTP/1.1") != 0 && strcmp(req->version, "HTTP/1.0") != 0) { + cm_log("HTTP", "Bad HTTP Version"); + bad = true; + goto getout; + } + + int j; + char* p = malloc(1); + p[0] = 0; + for(j = 0; req->path[j] != 0; j++) { + if(req->path[j] == '/') { + cbuf[0] = '/'; + for(; req->path[j] != 0 && req->path[j] == '/'; j++) + ; + j--; + } else { + cbuf[0] = req->path[j]; + } + char* tmp = p; + p = cm_strcat(tmp, cbuf); + free(tmp); + } + free(req->path); + req->path = p; + + int incr = 0; + p = malloc(1); + p[0] = 0; + for(j = 0;; j++) { + if(req->path[j] == '/' || req->path[j] == 0) { + char oldc = req->path[j]; + cbuf[0] = oldc; + req->path[j] = 0; + + char* pth = req->path + incr; + + if(strcmp(pth, "..") == 0) { + int k; + if(p[strlen(p) - 1] == '/') p[strlen(p) - 1] = 0; + for(k = strlen(p) - 1; k >= 0; k--) { + if(p[k] == '/') { + p[k + 1] = 0; + break; + } + } + if(strlen(p) == 0) { + free(p); + p = cm_strdup("/"); + } + } else if(strcmp(pth, ".") == 0) { + } else { + char* tmp = p; + p = cm_strcat3(tmp, pth, cbuf); + free(tmp); + } + + incr = j + 1; + if(oldc == 0) break; + } + } + free(req->path); + req->path = p; + + cm_log("HTTP", "Request: %s %s %s", req->method, req->path, req->version); + + phase++; + } + } else if(c != '\r') { + if(req->version == NULL) { + req->version = malloc(1); + req->version[0] = 0; + } + cbuf[0] = c; + char* tmp = req->version; + req->version = cm_strcat(tmp, cbuf); + free(tmp); + } + } else if(phase == 3) { + if(c == '\n') { + nl++; + if(nl == 2) { + phase++; + goto getout; + } else { + if(req->headers == NULL) { + req->headers = malloc(sizeof(*req->headers)); + req->headers[0] = NULL; + } + int j; + for(j = 0; header[j] != 0; j++) { + if(header[j] == ':') { + header[j] = 0; + j++; + for(; header[j] != 0 && (header[j] == ' ' || header[j] == '\t'); j++) + ; + char* kv = header; + char* vv = header + j; + + char** old = req->headers; + int k; + for(k = 0; old[k] != NULL; k++) + ; + req->headers = malloc(sizeof(*req->headers) * (k + 3)); + for(k = 0; old[k] != NULL; k++) req->headers[k] = old[k]; + req->headers[k] = cm_strdup(kv); + req->headers[k + 1] = cm_strdup(vv); + req->headers[k + 2] = NULL; + free(old); + + cm_log("HTTP", "Header: %s: %s", kv, vv); + + break; + } + } + free(header); + header = malloc(1); + header[0] = 0; + } + } else if(c != '\r') { + nl = 0; + cbuf[0] = c; + char* tmp = header; + header = cm_strcat(tmp, cbuf); + free(tmp); + } + } + } + } +getout: + free(header); + if(bad) { + tw_free_request(req); + return 1; + } + return 0; +} diff --git a/Server/main.c b/Server/main.c index eb13a48..e0cccb2 100644 --- a/Server/main.c +++ b/Server/main.c @@ -1,8 +1,11 @@ /* $Id$ */ +#define SOURCE + #include #include #include +#include #include @@ -49,5 +52,8 @@ int main(int argc, char** argv) { return 1; } cm_log("Daemon", "Ready"); +#ifndef __MINGW32__ + signal(SIGCHLD, SIG_IGN); +#endif tw_server_loop(); } diff --git a/Server/server.c b/Server/server.c index 120e5a1..3f4d45d 100644 --- a/Server/server.c +++ b/Server/server.c @@ -1,9 +1,12 @@ /* $Id$ */ +#define SOURCE + #include "tw_server.h" #include "tw_ssl.h" #include "tw_config.h" +#include "tw_http.h" #include #include @@ -112,6 +115,22 @@ int tw_server_init(void) { return 0; } +size_t tw_read(SSL* ssl, int s, void* data, size_t len) { + if(ssl == NULL) { + return recv(s, data, len, 0); + } else { + return SSL_read(ssl, data, len); + } +} + +size_t tw_write(SSL* ssl, int s, void* data, size_t len) { + if(ssl == NULL) { + return send(s, data, len, 0); + } else { + return SSL_write(ssl, data, len); + } +} + #ifdef __MINGW32__ struct pass_entry { int sock; @@ -139,8 +158,10 @@ void tw_server_pass(int sock, bool ssl, int port) { if(SSL_accept(s) <= 0) goto cleanup; sslworks = true; } + struct tw_http_request req; + int ret = tw_http_parse(s, sock, &req); cleanup: - if(sslworks){ + if(sslworks) { SSL_shutdown(s); } SSL_free(s); diff --git a/Server/ssl.c b/Server/ssl.c index e5bb8d3..db4e001 100644 --- a/Server/ssl.c +++ b/Server/ssl.c @@ -1,5 +1,7 @@ /* $Id$ */ +#define SOURCE + #include "tw_ssl.h" #include "tw_config.h" diff --git a/Server/tw_http.h b/Server/tw_http.h new file mode 100644 index 0000000..2818c65 --- /dev/null +++ b/Server/tw_http.h @@ -0,0 +1,25 @@ +/* $Id$ */ + +#ifndef __TW_HTTP_H__ +#define __TW_HTTP_H__ + +struct tw_http_request { + char* method; + char* path; + char* version; + char** headers; + char* body; +}; + +struct tw_http_response { + char** headers; +}; + +struct tw_http_tool {}; + +#ifdef SOURCE +#include +int tw_http_parse(SSL* ssl, int sock, struct tw_http_request* req); +#endif + +#endif diff --git a/Server/tw_server.h b/Server/tw_server.h index 3ab54d6..eecb72c 100644 --- a/Server/tw_server.h +++ b/Server/tw_server.h @@ -3,7 +3,11 @@ #ifndef __TW_SERVER_H__ #define __TW_SERVER_H__ +#include + int tw_server_init(void); void tw_server_loop(void); +size_t tw_read(SSL* ssl, int s, void* data, size_t len); +size_t tw_write(SSL* ssl, int s, void* data, size_t len); #endif diff --git a/Server/version.c b/Server/version.c index ef33fab..4805770 100644 --- a/Server/version.c +++ b/Server/version.c @@ -1,5 +1,7 @@ /* $Id$ */ +#define SOURCE + #include "tw_version.h" const char* tw_version = "0.00";