diff --git a/Makefile b/Makefile index 5b1eca6..c4da7d3 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,7 @@ LIB_SOURCES = \ src/httpd-auth.c \ src/httpd-utils.c \ src/httpd-loop.c \ + src/httpd-heap.c \ src/cgi-espfs.c \ src/cgi-redirects.c \ src/cgi-websocket.c diff --git a/demo/server_demo.c b/demo/server_demo.c index 236e1c0..5186307 100644 --- a/demo/server_demo.c +++ b/demo/server_demo.c @@ -5,6 +5,7 @@ #include "httpd.h" #include "httpd-utils.h" #include "cgi-espfs.h" +#include "httpd-heap.h" extern unsigned char espfs_image[]; extern unsigned int espfs_image_len; @@ -35,7 +36,7 @@ httpd_cgi_state templateReplacer(HttpdConnData *conn, const char *token) } if (!conn->userData) { - rd = httpdPlatMalloc(sizeof(struct RequestData)); + rd = httpdMalloc(sizeof(struct RequestData)); conn->userData = rd; rd->counter = 0; @@ -130,7 +131,7 @@ int main(void) // prevent abort on sigpipe sigaction(SIGPIPE, &(struct sigaction) {{sigpipe_handler},.sa_mask={}}, NULL); - struct httpd_options opts = { + struct httpd_init_options opts = { .port = 8080, }; diff --git a/fstool/httpd-heap.h b/fstool/httpd-heap.h new file mode 100644 index 0000000..8b2b42b --- /dev/null +++ b/fstool/httpd-heap.h @@ -0,0 +1,10 @@ +/** + * HTTPD malloc/free wrappers with debug instrumentation + */ + +#pragma once + +#include + +#define httpdMalloc(len) malloc((len)) +#define httpdFree(ptr) free((ptr)) diff --git a/fstool/main.c b/fstool/main.c index 0392819..434e147 100644 --- a/fstool/main.c +++ b/fstool/main.c @@ -38,17 +38,6 @@ static char **s_gzipExtensions = NULL; /// Gzip all files static bool s_gzipAll = false; -// impls to satisfy defs in the config header -void *httpdPlatMalloc(size_t len) -{ - return malloc(len); -} - -void httpdPlatFree(void *ptr) -{ - free(ptr); -} - /** * Compress a file using Heatshrink * diff --git a/spritehttpd/include/httpd-heap.h b/spritehttpd/include/httpd-heap.h new file mode 100644 index 0000000..e4fe9a6 --- /dev/null +++ b/spritehttpd/include/httpd-heap.h @@ -0,0 +1,22 @@ +/** + * HTTPD malloc/free wrappers with debug instrumentation + */ + +#pragma once +#include "httpd-logging.h" +#include "httpd-platform.h" + +#if DEBUG_MALLOC + +void* httpdMalloc_(size_t len, const char * filename, int lineno, const char * funcname); +void httpdFree_(void *ptr, const char * filename, int lineno, const char * funcname); + +#define httpdMalloc(len_) httpdMalloc_((len_), __FILE__, __LINE__, __FUNCTION__) +#define httpdFree(ptr_) httpdFree_((ptr_), __FILE__, __LINE__, __FUNCTION__) + +#else + +#define httpdMalloc(len, purpose) httpdPlatMalloc((len)) +#define httpdFree(ptr) httpdPlatFree((ptr)) + +#endif diff --git a/spritehttpd/include/httpd-logging.h b/spritehttpd/include/httpd-logging.h index 8aee7ba..280f8af 100755 --- a/spritehttpd/include/httpd-logging.h +++ b/spritehttpd/include/httpd-logging.h @@ -108,7 +108,7 @@ #endif #ifndef DEBUG_MALLOC -#define DEBUG_MALLOC 0 +#define DEBUG_MALLOC 1 #endif // router (resolving urls to serve) diff --git a/spritehttpd/include/httpd-platform.h b/spritehttpd/include/httpd-platform.h index 2273f2b..2116dfc 100644 --- a/spritehttpd/include/httpd-platform.h +++ b/spritehttpd/include/httpd-platform.h @@ -22,7 +22,9 @@ void httpdPlatLock(void); void httpdPlatUnlock(void); /** - * Allocate memory + * Allocate memory. + * + * @attention Do not use directly - call httpdMalloc() instead ! * * @param len - alloc size * @return pointer to allocated data or NULL @@ -32,6 +34,8 @@ void *httpdPlatMalloc(size_t len); /** * Free allocated data * + * @attention Do not use directly - call httpdFree() instead ! + * * @param ptr - data pointer */ void httpdPlatFree(void *ptr); @@ -83,7 +87,7 @@ void httpdPlatInit(void); * @param opts - server options * @return join handle */ -httpd_thread_handle_t *httpdPlatStart(struct httpd_options *opts); +httpd_thread_handle_t *httpdPlatStart(struct httpd_init_options *opts); /** * Wait for the server to end diff --git a/spritehttpd/include/httpd-types.h b/spritehttpd/include/httpd-types.h index 08d8b85..7ac3063 100644 --- a/spritehttpd/include/httpd-types.h +++ b/spritehttpd/include/httpd-types.h @@ -16,7 +16,7 @@ typedef HttpdConnType* ConnTypePtr; struct httpd_thread_handle; typedef struct httpd_thread_handle httpd_thread_handle_t; -struct httpd_options; +struct httpd_init_options; typedef uint32_t httpd_ipaddr_t; @@ -61,7 +61,7 @@ typedef enum { /* init options */ -struct httpd_options { +struct httpd_init_options { uint16_t port; }; @@ -76,10 +76,10 @@ typedef struct HttpdQueuedHeader { char headerLine[]; } HttpdQueuedHeader; -typedef struct HttpSendBacklogItem HttpSendBacklogItem; -struct HttpSendBacklogItem { +typedef struct HttpdSendBacklogItem HttpdSendBacklogItem; +struct HttpdSendBacklogItem { size_t len; - HttpSendBacklogItem *next; + HttpdSendBacklogItem *next; uint8_t data[]; }; @@ -92,7 +92,7 @@ struct HttpdPriv { uint8_t *sendBuff; size_t sendBuffLen; char *chunkHdr; - HttpSendBacklogItem *sendBacklog; + HttpdSendBacklogItem *sendBacklog; HttpdQueuedHeader *headersToSend; // Linked list of headers to send with the response. Will be freed with the request. size_t sendBacklogSize; uint8_t flags; @@ -122,7 +122,7 @@ typedef httpd_cgi_state (* cgiRecvHandler)(HttpdConnData *connData, uint8_t *dat //A struct describing a http connection. This gets passed to cgi functions. struct HttpdConnData { ConnTypePtr conn; // The TCP connection. Exact type depends on the platform. - HttpdPriv *priv; // Internal httpd state for the connection + HttpdPriv priv; // Internal httpd state for the connection httpd_method requestType; // One of the HTTPD_METHOD_* values char *hostName; // Host name field of request diff --git a/spritehttpd/include/httpd.h b/spritehttpd/include/httpd.h index e7b3193..c3c2ea6 100644 --- a/spritehttpd/include/httpd.h +++ b/spritehttpd/include/httpd.h @@ -42,7 +42,7 @@ void httpdRedirect(HttpdConnData *conn, const char *newUrl); * @param options - server options * @return server thread handle or NULL on error */ -httpd_thread_handle_t *httpdStart(const HttpdBuiltInUrl *fixedUrls, struct httpd_options *options); +httpd_thread_handle_t *httpdStart(const HttpdBuiltInUrl *fixedUrls, struct httpd_init_options *options); /** * Shutdown the server & wait for the thread to end. diff --git a/spritehttpd/lib/espfs/espfs.c b/spritehttpd/lib/espfs/espfs.c index ee6920e..d65e070 100644 --- a/spritehttpd/lib/espfs/espfs.c +++ b/spritehttpd/lib/espfs/espfs.c @@ -23,6 +23,7 @@ It's written for use with httpd, but doesn't need to be used as such. #include "espfs.h" #include "httpd-logging.h" +#include "httpd-heap.h" // internal fields struct EspFsFile { @@ -135,7 +136,7 @@ EspFsFile *espFsOpenFromHeader(EspFsHeader *h, uint32_t hpos) return NULL; } - EspFsFile *r = (EspFsFile *) httpdPlatMalloc(sizeof(EspFsFile)); //Alloc file desc mem + EspFsFile *r = (EspFsFile *) httpdMalloc(sizeof(EspFsFile)); //Alloc file desc mem if (r == NULL) { return NULL; } r->headerPos = hpos; r->decompressor = h->compression; @@ -166,7 +167,7 @@ EspFsFile *espFsOpenFromHeader(EspFsHeader *h, uint32_t hpos) return r; } else { espfs_error("[EspFS] Invalid compression: %d", h->compression); - httpdPlatFree(r); + httpdFree(r); return NULL; } return NULL; @@ -339,5 +340,5 @@ void espFsClose(EspFsFile *fh) heatshrink_decoder *dec = (heatshrink_decoder *) fh->decompData; heatshrink_decoder_free(dec); } - httpdPlatFree(fh); + httpdFree(fh); } diff --git a/spritehttpd/lib/heatshrink/heatshrink_config.h b/spritehttpd/lib/heatshrink/heatshrink_config.h index 38d00b2..7c63e29 100644 --- a/spritehttpd/lib/heatshrink/heatshrink_config.h +++ b/spritehttpd/lib/heatshrink/heatshrink_config.h @@ -5,29 +5,10 @@ #define HEATSHRINK_DYNAMIC_ALLOC 1 #endif -#if HEATSHRINK_DYNAMIC_ALLOC - - // forward declare - needed when building the heatshrink compressor - void *httpdPlatMalloc(size_t len); - void httpdPlatFree(void *ptr); - - /* Optional replacement of malloc/free */ - #define HEATSHRINK_MALLOC(SZ) httpdPlatMalloc(SZ) - #define HEATSHRINK_FREE(P, SZ) httpdPlatFree(P) -#else - /* Required parameters for static configuration */ - #ifndef HEATSHRINK_STATIC_INPUT_BUFFER_SIZE - #define HEATSHRINK_STATIC_INPUT_BUFFER_SIZE 32 - #endif - - #ifndef HEATSHRINK_STATIC_WINDOW_BITS - #define HEATSHRINK_STATIC_WINDOW_BITS 8 - #endif - - #ifndef HEATSHRINK_STATIC_LOOKAHEAD_BITS - #define HEATSHRINK_STATIC_LOOKAHEAD_BITS 4 - #endif -#endif +/* Optional replacement of malloc/free */ +#include "httpd-heap.h" +#define HEATSHRINK_MALLOC(SZ) httpdMalloc((SZ)) +#define HEATSHRINK_FREE(P, SZ) httpdFree((P)) /* Turn on logging for debugging. */ #ifndef HEATSHRINK_DEBUGGING_LOGS diff --git a/spritehttpd/src/cgi-espfs.c b/spritehttpd/src/cgi-espfs.c index 88ec1c5..bc01311 100644 --- a/spritehttpd/src/cgi-espfs.c +++ b/spritehttpd/src/cgi-espfs.c @@ -226,14 +226,14 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn) } espFsClose(tdi->file); - httpdPlatFree(tdi); + httpdFree(tdi); } return HTTPD_CGI_DONE; } if (tdi == NULL) { //First call to this cgi. Open the file so we can read it. - tdi = (TplDataInternal *) httpdPlatMalloc(sizeof(TplDataInternal)); + tdi = (TplDataInternal *) httpdMalloc(sizeof(TplDataInternal)); if (tdi == NULL) { espfs_error("Failed to malloc tpl struct"); return HTTPD_CGI_NOTFOUND; @@ -255,7 +255,7 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn) tdi->file = tryOpenIndex(filepath); if (tdi->file == NULL) { espfs_error("cgiEspFsTemplate: Couldn't find template for path: %s", conn->url); - httpdPlatFree(tdi); + httpdFree(tdi); return HTTPD_CGI_NOTFOUND; } } @@ -263,7 +263,7 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn) if (espFsFlags(tdi->file) & EFS_FLAG_GZIP) { espfs_error("cgiEspFsTemplate: Trying to use gzip-compressed file %s as template!", conn->url); espFsClose(tdi->file); - httpdPlatFree(tdi); + httpdFree(tdi); return HTTPD_CGI_NOTFOUND; } @@ -418,7 +418,7 @@ httpd_cgi_state cgiEspFsTemplate(HttpdConnData *conn) espfs_info("Template sent."); espFsClose(tdi->file); - httpdPlatFree(tdi); + httpdFree(tdi); return HTTPD_CGI_DONE; } else { //Ok, till next time. diff --git a/spritehttpd/src/cgi-redirects.c b/spritehttpd/src/cgi-redirects.c index 137b946..90a4109 100644 --- a/spritehttpd/src/cgi-redirects.c +++ b/spritehttpd/src/cgi-redirects.c @@ -1,5 +1,6 @@ #include "httpd.h" #include "httpd-logging.h" +#include "httpd-heap.h" //Use this as a cgi function to redirect one url to another. @@ -53,7 +54,7 @@ httpd_cgi_state cgiRedirectToHostname(HttpdConnData *connData) //Check hostname; pass on if the same if (strcmp(connData->hostName, (char *) connData->cgiArg) == 0) { return HTTPD_CGI_NOTFOUND; } //Not the same. Redirect to real hostname. - buff = httpdPlatMalloc(strlen((char *) connData->cgiArg) + sizeof(hostFmt)); + buff = httpdMalloc(strlen((char *) connData->cgiArg) + sizeof(hostFmt)); if (buff == NULL) { //Bail out return HTTPD_CGI_DONE; @@ -61,6 +62,6 @@ httpd_cgi_state cgiRedirectToHostname(HttpdConnData *connData) sprintf(buff, hostFmt, (char *) connData->cgiArg); http_info("Redirecting to hostname url %s", buff); httpdRedirect(connData, buff); - httpdPlatFree(buff); + httpdFree(buff); return HTTPD_CGI_DONE; } diff --git a/spritehttpd/src/cgi-websocket.c b/spritehttpd/src/cgi-websocket.c index e863aa9..f3b06df 100644 --- a/spritehttpd/src/cgi-websocket.c +++ b/spritehttpd/src/cgi-websocket.c @@ -19,6 +19,7 @@ Websocket support for esphttpd. Inspired by https://github.com/dangrie158/ESP-82 #include "utils/base64.h" #include "cgi-websocket.h" #include "httpd-logging.h" +#include "httpd-heap.h" #define WS_KEY_IDENTIFIER "Sec-WebSocket-Key: " #define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" @@ -228,7 +229,7 @@ static void websockFree(Websock *ws) } if (ws->priv) { - httpdPlatFree(ws->priv); + httpdFree(ws->priv); } } @@ -377,7 +378,7 @@ httpd_cgi_state cgiWebSocketRecv(HttpdConnData *connData, uint8_t *data, size_t //We're going to tell the main webserver we're done. The webserver expects us to clean up by ourselves //we're chosing to be done. Do so. websockFree(ws); - httpdPlatFree(connData->cgiData); + httpdFree(connData->cgiData); connData->cgiData = NULL; } return r; @@ -395,7 +396,7 @@ httpd_cgi_state cgiWebsocket(HttpdConnData *connData) if (connData->cgiData) { Websock *ws = (Websock *) connData->cgiData; websockFree(ws); - httpdPlatFree(connData->cgiData); + httpdFree(connData->cgiData); connData->cgiData = NULL; } return HTTPD_CGI_DONE; @@ -418,7 +419,7 @@ httpd_cgi_state cgiWebsocket(HttpdConnData *connData) // httpd_printf("WS: Key: %s\n", buff); //Seems like a WebSocket connection. // Alloc structs - connData->cgiData = httpdPlatMalloc(sizeof(Websock)); + connData->cgiData = httpdMalloc(sizeof(Websock)); if (connData->cgiData == NULL) { ws_error("Can't allocate mem for websocket"); return HTTPD_CGI_DONE; @@ -427,10 +428,10 @@ httpd_cgi_state cgiWebsocket(HttpdConnData *connData) Websock *ws = (Websock *) connData->cgiData; - ws->priv = httpdPlatMalloc(sizeof(WebsockPriv)); + ws->priv = httpdMalloc(sizeof(WebsockPriv)); if (ws->priv == NULL) { ws_error("Can't allocate mem for websocket priv"); - httpdPlatFree(connData->cgiData); + httpdFree(connData->cgiData); connData->cgiData = NULL; return HTTPD_CGI_DONE; } diff --git a/spritehttpd/src/httpd-heap.c b/spritehttpd/src/httpd-heap.c new file mode 100644 index 0000000..7acc0e0 --- /dev/null +++ b/spritehttpd/src/httpd-heap.c @@ -0,0 +1,27 @@ +/** + * Malloc instrumentation + */ + +#include "httpd-heap.h" +#include "httpd-logging.h" +#include + +#if DEBUG_MALLOC + +void* httpdMalloc_(size_t len, const char * filename, int lineno, const char * funcname) +{ + void *ptr = httpdPlatMalloc(len); + mem_dbg("%s:%d %s - malloc [%lu] @ %p", + filename, lineno, funcname, + len, ptr); + return ptr; +} + +void httpdFree_(void *ptr, const char * filename, int lineno, const char * funcname) +{ + mem_dbg("%s:%d %s - free @ %p", + filename, lineno, funcname, ptr); + httpdPlatFree(ptr); +} + +#endif diff --git a/spritehttpd/src/httpd-loop.c b/spritehttpd/src/httpd-loop.c index f580e80..3835af9 100644 --- a/spritehttpd/src/httpd-loop.c +++ b/spritehttpd/src/httpd-loop.c @@ -61,7 +61,7 @@ void httpdServerTask(void *pvParameters) s_shutdown_requested = false; - const struct httpd_options *options = pvParameters; + const struct httpd_init_options *options = pvParameters; if (options == NULL) { httpPort = 80; } else { diff --git a/spritehttpd/src/httpd.c b/spritehttpd/src/httpd.c index b7d8e17..5014874 100644 --- a/spritehttpd/src/httpd.c +++ b/spritehttpd/src/httpd.c @@ -17,6 +17,7 @@ Esp8266 http server - core routines #include "httpd-platform.h" #include "httpd-utils.h" #include "httpd-logging.h" +#include "httpd-heap.h" static void cleanupCgiAndUserData(HttpdConnData *hconn); @@ -84,7 +85,7 @@ const char *httpdGetVersion(void) size_t httpGetBacklogSize(const HttpdConnData *conn) { - HttpSendBacklogItem *bl = conn->priv->sendBacklog; + HttpdSendBacklogItem *bl = conn->priv.sendBacklog; if (!bl) { return 0; } size_t bytes = 0; while (bl != NULL) { @@ -122,38 +123,34 @@ static void httpdRetireConn(HttpdConnData *hconn) cleanupCgiAndUserData(hconn); // Free any memory allocated for backlog - walk the linked list - if (hconn->priv->sendBacklog != NULL) { - HttpSendBacklogItem *i, *j; - i = hconn->priv->sendBacklog; + if (hconn->priv.sendBacklog != NULL) { + HttpdSendBacklogItem *i, *j; + i = hconn->priv.sendBacklog; do { j = i; i = i->next; - httpdPlatFree(j); + httpdFree(j); } while (i != NULL); } if (hconn->post.buff != NULL) { - httpdPlatFree(hconn->post.buff); + httpdFree(hconn->post.buff); hconn->post.buff = NULL; } - if (hconn->priv != NULL) { - httpdPlatFree(hconn->priv); - hconn->priv = NULL; - } // Unlink from the connection list s_connData[hconn->slot] = NULL; // release memory - httpdPlatFree(hconn); + httpdFree(hconn); } //Get the value of a certain header in the HTTP client head //Returns true when found, false when not found. int httpdGetHeader(HttpdConnData *conn, const char *header, char *buff, size_t buffLen) { - char *p = conn->priv->head; + char *p = conn->priv.head; p = p + strlen(p) + 1; //skip GET/POST part p = p + strlen(p) + 1; //skip HTTP part - while (p < (conn->priv->head + conn->priv->headPos)) { + while (p < (conn->priv.head + conn->priv.headPos)) { while (*p <= 32 && *p != 0) { p++; } //skip crap at start //See if this is the header if (strstarts(p, header) && p[strlen(header)] == ':') { @@ -181,12 +178,12 @@ void httpdQueueHeader(HttpdConnData *conn, const char *header, const char *value if (!conn || !header || !value) { return; } - if (conn->priv->flags & HFL_SENDINGBODY) { + if (conn->priv.flags & HFL_SENDINGBODY) { http_error("Headers already sent."); return; } - HttpdQueuedHeader *queEntry = httpdPlatMalloc(sizeof(void *) + strlen(header) + strlen(value) + 5); + HttpdQueuedHeader *queEntry = httpdMalloc(sizeof(void *) + strlen(header) + strlen(value) + 5); if (!queEntry) { http_error("httpdQueueHeader - no mem"); return; @@ -199,10 +196,10 @@ void httpdQueueHeader(HttpdConnData *conn, const char *header, const char *value strcat(queEntry->headerLine, value); strcat(queEntry->headerLine, "\r\n"); - if (!conn->priv->headersToSend) { - conn->priv->headersToSend = queEntry; + if (!conn->priv.headersToSend) { + conn->priv.headersToSend = queEntry; } else { - HttpdQueuedHeader *ph = conn->priv->headersToSend; + HttpdQueuedHeader *ph = conn->priv.headersToSend; // Go to the end of the linked list while (ph->next) { ph = ph->next; @@ -214,20 +211,20 @@ void httpdQueueHeader(HttpdConnData *conn, const char *header, const char *value void httdSetTransferMode(HttpdConnData *conn, httpd_transfer_opt mode) { if (mode == HTTPD_TRANSFER_CLOSE) { - conn->priv->flags &= (uint8_t) ~HFL_CHUNKED; - conn->priv->flags &= (uint8_t) ~HFL_NOCONNECTIONSTR; + conn->priv.flags &= (uint8_t) ~HFL_CHUNKED; + conn->priv.flags &= (uint8_t) ~HFL_NOCONNECTIONSTR; } else if (mode == HTTPD_TRANSFER_CHUNKED) { - conn->priv->flags |= HFL_CHUNKED; - conn->priv->flags &= (uint8_t) ~HFL_NOCONNECTIONSTR; + conn->priv.flags |= HFL_CHUNKED; + conn->priv.flags &= (uint8_t) ~HFL_NOCONNECTIONSTR; } else if (mode == HTTPD_TRANSFER_NONE) { - conn->priv->flags &= (uint8_t) ~HFL_CHUNKED; - conn->priv->flags |= HFL_NOCONNECTIONSTR; + conn->priv.flags &= (uint8_t) ~HFL_CHUNKED; + conn->priv.flags |= HFL_NOCONNECTIONSTR; } } void httdResponseOptions(HttpdConnData *conn, int cors) { - if (cors == 0) { conn->priv->flags |= HFL_NOCORS; } + if (cors == 0) { conn->priv.flags |= HFL_NOCORS; } } //Start the response headers. @@ -236,8 +233,8 @@ void httpdStartResponse(HttpdConnData *conn, int code) char buff[256]; const char *connStr = ""; - if (!(conn->priv->flags & HFL_NOCONNECTIONSTR)) { - if (conn->priv->flags & HFL_CHUNKED) { + if (!(conn->priv.flags & HFL_NOCONNECTIONSTR)) { + if (conn->priv.flags & HFL_CHUNKED) { connStr = "Transfer-Encoding: chunked\r\n"; } else { connStr = "Connection: close\r\n"; @@ -245,7 +242,7 @@ void httpdStartResponse(HttpdConnData *conn, int code) } size_t l = (size_t) sprintf(buff, "HTTP/1.%d %d %s\r\nServer: %s\r\n%s", - ((conn->priv->flags & HFL_HTTP11) ? 1 : 0), + ((conn->priv.flags & HFL_HTTP11) ? 1 : 0), code, httpdStatusName(code), s_serverName, @@ -253,7 +250,7 @@ void httpdStartResponse(HttpdConnData *conn, int code) httpdSendStrN(conn, buff, l); - if (!(conn->priv->flags & HFL_NOCORS)) { + if (!(conn->priv.flags & HFL_NOCORS)) { // CORS headers httpdSendStr(conn, "Access-Control-Allow-Origin: *\r\n"); httpdSendStr(conn, "Access-Control-Allow-Methods: GET,POST,OPTIONS\r\n"); @@ -273,17 +270,17 @@ void httpdHeader(HttpdConnData *conn, const char *field, const char *val) void httpdEndHeaders(HttpdConnData *conn) { // Add queued headers & dealloc the struct - HttpdQueuedHeader *qh = conn->priv->headersToSend; - conn->priv->headersToSend = NULL; + HttpdQueuedHeader *qh = conn->priv.headersToSend; + conn->priv.headersToSend = NULL; while (qh) { httpdSendStr(conn, qh->headerLine); HttpdQueuedHeader *next = qh->next; - httpdPlatFree(qh); + httpdFree(qh); qh = next; } httpdSendStr(conn, "\r\n"); - conn->priv->flags |= HFL_SENDINGBODY; + conn->priv.flags |= HFL_SENDINGBODY; } //Redirect to the given URL. @@ -305,16 +302,16 @@ int httpdSend(HttpdConnData *conn, const uint8_t *data, size_t len) { if (conn->conn == NULL) { return 0; } if (len == 0) { return 0; } - if (conn->priv->flags & HFL_CHUNKED && conn->priv->flags & HFL_SENDINGBODY && conn->priv->chunkHdr == NULL) { - if (conn->priv->sendBuffLen + len + 6 > HTTPD_MAX_SENDBUFF_LEN) { return 0; } + if (conn->priv.flags & HFL_CHUNKED && conn->priv.flags & HFL_SENDINGBODY && conn->priv.chunkHdr == NULL) { + if (conn->priv.sendBuffLen + len + 6 > HTTPD_MAX_SENDBUFF_LEN) { return 0; } //Establish start of chunk - conn->priv->chunkHdr = (char *) &conn->priv->sendBuff[conn->priv->sendBuffLen]; - strcpy(conn->priv->chunkHdr, "0000\r\n"); - conn->priv->sendBuffLen += 6; + conn->priv.chunkHdr = (char *) &conn->priv.sendBuff[conn->priv.sendBuffLen]; + strcpy(conn->priv.chunkHdr, "0000\r\n"); + conn->priv.sendBuffLen += 6; } - if (conn->priv->sendBuffLen + len > HTTPD_MAX_SENDBUFF_LEN) { return 0; } - memcpy(conn->priv->sendBuff + conn->priv->sendBuffLen, data, len); - conn->priv->sendBuffLen += len; + if (conn->priv.sendBuffLen + len > HTTPD_MAX_SENDBUFF_LEN) { return 0; } + memcpy(conn->priv.sendBuff + conn->priv.sendBuffLen, data, len); + conn->priv.sendBuffLen += len; return 1; } @@ -395,7 +392,7 @@ int httpdSend_js(HttpdConnData *conn, const char *data, ssize_t len) return 1; } -//Function to send any data in conn->priv->sendBuff. Do not use in CGIs unless you know what you +//Function to send any data in conn->priv.sendBuff. Do not use in CGIs unless you know what you //are doing! Also, if you do set conn->cgi to NULL to indicate the connection is closed, do it BEFORE //calling this. //Returns false if data could not be sent nor put in backlog. @@ -404,52 +401,52 @@ bool httpdFlushSendBuffer(HttpdConnData *conn) int r; size_t len; if (conn->conn == NULL) { return false; } - if (conn->priv->chunkHdr != NULL) { + if (conn->priv.chunkHdr != NULL) { //We're sending chunked data, and the chunk needs fixing up. //Finish chunk with cr/lf httpdSendStr(conn, "\r\n"); //Calculate length of chunk - len = (size_t) ((char *) (&conn->priv->sendBuff[conn->priv->sendBuffLen]) - conn->priv->chunkHdr) - 8; + len = (size_t) ((char *) (&conn->priv.sendBuff[conn->priv.sendBuffLen]) - conn->priv.chunkHdr) - 8; //Fix up chunk header to correct value - conn->priv->chunkHdr[0] = httpdHexNibble((uint8_t) (len >> 12)); - conn->priv->chunkHdr[1] = httpdHexNibble((uint8_t) (len >> 8)); - conn->priv->chunkHdr[2] = httpdHexNibble((uint8_t) (len >> 4)); - conn->priv->chunkHdr[3] = httpdHexNibble((uint8_t) (len >> 0)); + conn->priv.chunkHdr[0] = httpdHexNibble((uint8_t) (len >> 12)); + conn->priv.chunkHdr[1] = httpdHexNibble((uint8_t) (len >> 8)); + conn->priv.chunkHdr[2] = httpdHexNibble((uint8_t) (len >> 4)); + conn->priv.chunkHdr[3] = httpdHexNibble((uint8_t) (len >> 0)); //Reset chunk hdr for next call - conn->priv->chunkHdr = NULL; + conn->priv.chunkHdr = NULL; } - if (conn->priv->flags & HFL_CHUNKED && conn->priv->flags & HFL_SENDINGBODY && conn->cgi == NULL) { + if (conn->priv.flags & HFL_CHUNKED && conn->priv.flags & HFL_SENDINGBODY && conn->cgi == NULL) { //Connection finished sending whatever needs to be sent. Add NULL chunk to indicate this. - strcpy((char *) &conn->priv->sendBuff[conn->priv->sendBuffLen], "0\r\n\r\n"); - conn->priv->sendBuffLen += 5; + strcpy((char *) &conn->priv.sendBuff[conn->priv.sendBuffLen], "0\r\n\r\n"); + conn->priv.sendBuffLen += 5; } - if (conn->priv->sendBuffLen != 0) { - r = httpdConnSendData(conn->conn, conn->priv->sendBuff, conn->priv->sendBuffLen); + if (conn->priv.sendBuffLen != 0) { + r = httpdConnSendData(conn->conn, conn->priv.sendBuff, conn->priv.sendBuffLen); if (!r) { //Can't send this for some reason. Dump packet in backlog, we can send it later. - if (conn->priv->sendBacklogSize + conn->priv->sendBuffLen > HTTPD_MAX_BACKLOG_SIZE) { - http_error("Httpd: Backlog overrun, dropped %dB", (int) conn->priv->sendBuffLen); - conn->priv->sendBuffLen = 0; + if (conn->priv.sendBacklogSize + conn->priv.sendBuffLen > HTTPD_MAX_BACKLOG_SIZE) { + http_error("Httpd: Backlog overrun, dropped %dB", (int) conn->priv.sendBuffLen); + conn->priv.sendBuffLen = 0; return false; } - HttpSendBacklogItem *i = httpdPlatMalloc(sizeof(HttpSendBacklogItem) + conn->priv->sendBuffLen); - if (i == NULL) { + HttpdSendBacklogItem *backlogItem = httpdMalloc(sizeof(HttpdSendBacklogItem) + conn->priv.sendBuffLen); + if (backlogItem == NULL) { http_error("Httpd: Backlog: malloc failed, out of memory!"); return false; } - memcpy(i->data, conn->priv->sendBuff, conn->priv->sendBuffLen); - i->len = conn->priv->sendBuffLen; - i->next = NULL; - if (conn->priv->sendBacklog == NULL) { - conn->priv->sendBacklog = i; + memcpy(backlogItem->data, conn->priv.sendBuff, conn->priv.sendBuffLen); + backlogItem->len = conn->priv.sendBuffLen; + backlogItem->next = NULL; + if (conn->priv.sendBacklog == NULL) { + conn->priv.sendBacklog = backlogItem; } else { - HttpSendBacklogItem *e = conn->priv->sendBacklog; + HttpdSendBacklogItem *e = conn->priv.sendBacklog; while (e->next != NULL) { e = e->next; } - e->next = i; + e->next = backlogItem; } - conn->priv->sendBacklogSize += conn->priv->sendBuffLen; + conn->priv.sendBacklogSize += conn->priv.sendBuffLen; } - conn->priv->sendBuffLen = 0; + conn->priv.sendBuffLen = 0; } return true; } @@ -457,15 +454,15 @@ bool httpdFlushSendBuffer(HttpdConnData *conn) static void httpdCgiIsDone(HttpdConnData *conn) { conn->cgi = NULL; //no need to call this anymore - if (conn->priv->flags & HFL_CHUNKED) { + if (conn->priv.flags & HFL_CHUNKED) { http_dbg("Pool slot %d is done. Cleaning up for next req", conn->slot); httpdFlushSendBuffer(conn); //Note: Do not clean up sendBacklog, it may still contain data at this point. - conn->priv->headPos = 0; + conn->priv.headPos = 0; conn->post.len = -1; - conn->priv->flags = 0; + conn->priv.flags = 0; if (conn->post.buff) { - httpdPlatFree(conn->post.buff); + httpdFree(conn->post.buff); conn->post.buff = NULL; } conn->post.buffLen = 0; @@ -473,7 +470,7 @@ static void httpdCgiIsDone(HttpdConnData *conn) conn->hostName = NULL; } else { //Cannot re-use this connection. Mark to get it killed after all data is sent. - conn->priv->flags |= HFL_DISCONAFTERSENT; + conn->priv.flags |= HFL_DISCONAFTERSENT; } } @@ -495,18 +492,18 @@ void httpdContinue(HttpdConnData *conn) if (conn == NULL) { return; } - if (conn->priv->sendBacklog != NULL) { + if (conn->priv.sendBacklog != NULL) { //We have some backlog to send first. - HttpSendBacklogItem *next = conn->priv->sendBacklog->next; - httpdConnSendData(conn->conn, (uint8_t *) conn->priv->sendBacklog->data, conn->priv->sendBacklog->len); - conn->priv->sendBacklogSize -= conn->priv->sendBacklog->len; - httpdPlatFree(conn->priv->sendBacklog); - conn->priv->sendBacklog = next; + HttpdSendBacklogItem *next = conn->priv.sendBacklog->next; + httpdConnSendData(conn->conn, (uint8_t *) conn->priv.sendBacklog->data, conn->priv.sendBacklog->len); + conn->priv.sendBacklogSize -= conn->priv.sendBacklog->len; + httpdFree(conn->priv.sendBacklog); + conn->priv.sendBacklog = next; httpdPlatUnlock(); return; } - if (conn->priv->flags & HFL_DISCONAFTERSENT) { //Marked for destruction? + if (conn->priv.flags & HFL_DISCONAFTERSENT) { //Marked for destruction? http_dbg("Pool slot %d is done. Closing.", conn->slot); httpdConnDisconnect(conn->conn); httpdPlatUnlock(); @@ -519,14 +516,14 @@ void httpdContinue(HttpdConnData *conn) return; } - sendBuff = httpdPlatMalloc(HTTPD_MAX_SENDBUFF_LEN); + sendBuff = httpdMalloc(HTTPD_MAX_SENDBUFF_LEN); if (sendBuff == NULL) { http_error("Malloc of sendBuff failed!"); httpdPlatUnlock(); return; } - conn->priv->sendBuff = sendBuff; - conn->priv->sendBuffLen = 0; + conn->priv.sendBuff = sendBuff; + conn->priv.sendBuffLen = 0; httpd_cgi_state r = conn->cgi(conn); //Execute cgi fn. if (r == HTTPD_CGI_DONE) { httpdCgiIsDone(conn); @@ -536,7 +533,7 @@ void httpdContinue(HttpdConnData *conn) httpdCgiIsDone(conn); } httpdFlushSendBuffer(conn); - httpdPlatFree(sendBuff); + httpdFree(sendBuff); httpdPlatUnlock(); } @@ -555,7 +552,7 @@ static void httpdProcessRequest(HttpdConnData *conn) // CORS preflight, allow the token we received before if (conn->requestType == HTTPD_METHOD_OPTIONS) { httpdStartResponse(conn, 200); - httpdHeader(conn, "Access-Control-Allow-Headers", conn->priv->corsToken); + httpdHeader(conn, "Access-Control-Allow-Headers", conn->priv.corsToken); httpdEndHeaders(conn); httpdCgiIsDone(conn); @@ -670,7 +667,7 @@ static void httpdParseHeader(char *h, HttpdConnData *conn) while (*e == ' ') { e++; } //Skip spaces. //If HTTP/1.1, note that and set chunked encoding if (strcasecmp(e, "HTTP/1.1") == 0) { - conn->priv->flags |= HFL_HTTP11 | HFL_CHUNKED; + conn->priv.flags |= HFL_HTTP11 | HFL_CHUNKED; } http_info("URL = %s", conn->url); @@ -687,7 +684,7 @@ static void httpdParseHeader(char *h, HttpdConnData *conn) i = 11; //Skip trailing spaces while (h[i] == ' ') { i++; } - if (strstarts(&h[i], "close")) { conn->priv->flags &= (uint8_t) ~HFL_CHUNKED; } //Don't use chunked conn + if (strstarts(&h[i], "close")) { conn->priv.flags &= (uint8_t) ~HFL_CHUNKED; } //Don't use chunked conn } else if (strstarts(h, "Content-Length:")) { i = 15; //Skip trailing spaces @@ -703,7 +700,7 @@ static void httpdParseHeader(char *h, HttpdConnData *conn) conn->post.buffSize = (size_t) conn->post.len; } http_dbg("Mallocced buffer for %d + 1 bytes of post data.", (int) conn->post.buffSize); - conn->post.buff = (char *) httpdPlatMalloc(conn->post.buffSize + 1); + conn->post.buff = (char *) httpdMalloc(conn->post.buffSize + 1); if (conn->post.buff == NULL) { http_error("post buf alloc failed"); return; @@ -725,7 +722,7 @@ static void httpdParseHeader(char *h, HttpdConnData *conn) http_info("CORS preflight request."); - strncpy(conn->priv->corsToken, h + strlen("Access-Control-Request-Headers: "), HTTPD_MAX_CORS_TOKEN_LEN); + strncpy(conn->priv.corsToken, h + strlen("Access-Control-Request-Headers: "), HTTPD_MAX_CORS_TOKEN_LEN); } } @@ -735,20 +732,21 @@ static void httpdParseHeader(char *h, HttpdConnData *conn) void httpdConnSendStart(HttpdConnData *conn) { httpdPlatLock(); - uint8_t *sendBuff = httpdPlatMalloc(HTTPD_MAX_SENDBUFF_LEN); + uint8_t *sendBuff = httpdMalloc(HTTPD_MAX_SENDBUFF_LEN); if (sendBuff == NULL) { http_error("Malloc sendBuff failed!"); return; } - conn->priv->sendBuff = sendBuff; - conn->priv->sendBuffLen = 0; + conn->priv.sendBuff = sendBuff; + conn->priv.sendBuffLen = 0; } //Finish the live-ness of a connection. Always call this after httpdConnStart void httpdConnSendFinish(HttpdConnData *conn) { if (conn->conn) { httpdFlushSendBuffer(conn); } - httpdPlatFree(conn->priv->sendBuff); + httpdFree(conn->priv.sendBuff); + conn->priv.sendBuff = NULL; httpdPlatUnlock(); } @@ -766,16 +764,16 @@ void httpdRecvCb(ConnTypePtr rconn, httpd_ipaddr_t remIp, uint16_t remPort, uint return; } - uint8_t *sendBuff = httpdPlatMalloc(HTTPD_MAX_SENDBUFF_LEN); + uint8_t *sendBuff = httpdMalloc(HTTPD_MAX_SENDBUFF_LEN); if (sendBuff == NULL) { http_error("Malloc sendBuff failed!"); httpdPlatUnlock(); return; } - conn->priv->sendBuff = sendBuff; - conn->priv->sendBuffLen = 0; - conn->priv->corsToken[0] = 0; + conn->priv.sendBuff = sendBuff; + conn->priv.sendBuffLen = 0; + conn->priv.corsToken[0] = 0; //This is slightly evil/dirty: we abuse conn->post->len as a state variable for where in the http communications we are: //<0 (-1): Post len unknown because we're still receiving headers @@ -788,22 +786,22 @@ void httpdRecvCb(ConnTypePtr rconn, httpd_ipaddr_t remIp, uint16_t remPort, uint //This byte is a header byte. if (data[x] == '\n') { //Compatibility with clients that send \n only: fake a \r in front of this. - if (conn->priv->headPos != 0 && conn->priv->head[conn->priv->headPos - 1] != '\r') { - conn->priv->head[conn->priv->headPos++] = '\r'; + if (conn->priv.headPos != 0 && conn->priv.head[conn->priv.headPos - 1] != '\r') { + conn->priv.head[conn->priv.headPos++] = '\r'; } } //ToDo: return http error code 431 (request header too long) if this happens - if (conn->priv->headPos != HTTPD_MAX_HEAD_LEN) { conn->priv->head[conn->priv->headPos++] = (char) data[x]; } - conn->priv->head[conn->priv->headPos] = 0; + if (conn->priv.headPos != HTTPD_MAX_HEAD_LEN) { conn->priv.head[conn->priv.headPos++] = (char) data[x]; } + conn->priv.head[conn->priv.headPos] = 0; //Scan for /r/n/r/n. Receiving this indicates the headers end. - if (data[x] == '\n' && strstr(conn->priv->head, "\r\n\r\n") != NULL) { + if (data[x] == '\n' && strstr(conn->priv.head, "\r\n\r\n") != NULL) { //Indicate we're done with the headers. conn->post.len = 0; //Reset url data conn->url = NULL; //Iterate over all received headers and parse them. - p = conn->priv->head; - while (p < (&conn->priv->head[conn->priv->headPos - 4])) { + p = conn->priv.head; + while (p < (&conn->priv.head[conn->priv.headPos - 4])) { e = strstr(p, "\r\n"); //Find end of header line if (e == NULL) { break; } //Shouldn't happen. e[0] = 0; //Zero-terminate header @@ -855,7 +853,7 @@ void httpdRecvCb(ConnTypePtr rconn, httpd_ipaddr_t remIp, uint16_t remPort, uint if (conn->conn) { httpdFlushSendBuffer(conn); } - httpdPlatFree(sendBuff); + httpdFree(sendBuff); httpdPlatUnlock(); } @@ -913,7 +911,7 @@ int httpdConnectCb(ConnTypePtr conn, httpd_ipaddr_t remIp, uint16_t remPort) return 0; } - s_connData[ci] = httpdPlatMalloc(sizeof(HttpdConnData)); + s_connData[ci] = httpdMalloc(sizeof(HttpdConnData)); if (s_connData[ci] == NULL) { http_warn("Out of memory allocating connData!"); httpdPlatUnlock(); @@ -921,26 +919,21 @@ int httpdConnectCb(ConnTypePtr conn, httpd_ipaddr_t remIp, uint16_t remPort) } memset(s_connData[ci], 0, sizeof(HttpdConnData)); + memset(&s_connData[ci]->post, 0, sizeof(HttpdPostData)); + memset(&s_connData[ci]->priv, 0, sizeof(HttpdPriv)); + s_connData[ci]->conn = conn; s_connData[ci]->slot = ci; s_connData[ci]->remote_ip = remIp; s_connData[ci]->remote_port = remPort; s_connData[ci]->post.len = -1; - s_connData[ci]->priv = httpdPlatMalloc(sizeof(HttpdPriv)); - if (s_connData[ci]->priv == NULL) { - http_error("Out of memory allocating connData priv struct!"); - httpdPlatUnlock(); - return 0; - } - memset(s_connData[ci]->priv, 0, sizeof(HttpdPriv)); - httpdPlatUnlock(); return 1; } //Httpd initialization routine. Call this to kick off webserver functionality. -httpd_thread_handle_t *httpdStart(const HttpdBuiltInUrl *fixedUrls, struct httpd_options *options) +httpd_thread_handle_t *httpdStart(const HttpdBuiltInUrl *fixedUrls, struct httpd_init_options *options) { int i; diff --git a/spritehttpd/src/port/httpd-posix.c b/spritehttpd/src/port/httpd-posix.c index bdd3010..c14b959 100644 --- a/spritehttpd/src/port/httpd-posix.c +++ b/spritehttpd/src/port/httpd-posix.c @@ -1,4 +1,6 @@ #include "httpd-platform.h" +#include "httpd-logging.h" +#include "httpd-heap.h" #include #include #include @@ -52,9 +54,9 @@ void* httpdServerTaskPosix(void *pvParameters) } //Initialize listening socket, do general initialization -httpd_thread_handle_t *httpdPlatStart(struct httpd_options *opts) +httpd_thread_handle_t *httpdPlatStart(struct httpd_init_options *opts) { - struct httpd_thread_handle* handle = httpdPlatMalloc(sizeof(struct httpd_thread_handle)); + struct httpd_thread_handle* handle = httpdMalloc(sizeof(struct httpd_thread_handle)); if (!handle) { return NULL; }