|
|
@ -19,6 +19,7 @@ Esp8266 http server - core routines |
|
|
|
#include "httpd-logging.h" |
|
|
|
#include "httpd-logging.h" |
|
|
|
|
|
|
|
|
|
|
|
static void cleanupCgiAndUserData(HttpdConnData *hconn); |
|
|
|
static void cleanupCgiAndUserData(HttpdConnData *hconn); |
|
|
|
|
|
|
|
|
|
|
|
static void httpdRetireConn(HttpdConnData *hconn); |
|
|
|
static void httpdRetireConn(HttpdConnData *hconn); |
|
|
|
|
|
|
|
|
|
|
|
_Static_assert(HTTPD_MAX_CONNECTIONS < 256, "HTTPD_MAX_CONNECTIONS must be at most 255"); |
|
|
|
_Static_assert(HTTPD_MAX_CONNECTIONS < 256, "HTTPD_MAX_CONNECTIONS must be at most 255"); |
|
|
@ -27,6 +28,14 @@ _Static_assert(HTTPD_MAX_CONNECTIONS < 256, "HTTPD_MAX_CONNECTIONS must be at mo |
|
|
|
static const HttpdBuiltInUrl *s_builtInUrls; |
|
|
|
static const HttpdBuiltInUrl *s_builtInUrls; |
|
|
|
static const char *s_serverName = HTTPD_SERVERNAME; |
|
|
|
static const char *s_serverName = HTTPD_SERVERNAME; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct HttpdQueuedHeader; |
|
|
|
|
|
|
|
typedef struct HttpdQueuedHeader { |
|
|
|
|
|
|
|
/// Pointer to the next queued header
|
|
|
|
|
|
|
|
struct HttpdQueuedHeader *next; |
|
|
|
|
|
|
|
/// Text of the header, including CRLF
|
|
|
|
|
|
|
|
char headerLine[]; |
|
|
|
|
|
|
|
} HttpdQueuedHeader; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct HttpSendBacklogItem HttpSendBacklogItem; |
|
|
|
typedef struct HttpSendBacklogItem HttpSendBacklogItem; |
|
|
|
|
|
|
|
|
|
|
|
struct HttpSendBacklogItem { |
|
|
|
struct HttpSendBacklogItem { |
|
|
@ -52,6 +61,7 @@ struct HttpdPriv { |
|
|
|
size_t sendBuffLen; |
|
|
|
size_t sendBuffLen; |
|
|
|
char *chunkHdr; |
|
|
|
char *chunkHdr; |
|
|
|
HttpSendBacklogItem *sendBacklog; |
|
|
|
HttpSendBacklogItem *sendBacklog; |
|
|
|
|
|
|
|
HttpdQueuedHeader *headersToSend; // Linked list of headers to send with the response. Will be freed with the request.
|
|
|
|
size_t sendBacklogSize; |
|
|
|
size_t sendBacklogSize; |
|
|
|
uint8_t flags; |
|
|
|
uint8_t flags; |
|
|
|
}; |
|
|
|
}; |
|
|
@ -60,7 +70,7 @@ struct HttpdPriv { |
|
|
|
//Connection pool
|
|
|
|
//Connection pool
|
|
|
|
HttpdConnData *s_connData[HTTPD_MAX_CONNECTIONS]; |
|
|
|
HttpdConnData *s_connData[HTTPD_MAX_CONNECTIONS]; |
|
|
|
|
|
|
|
|
|
|
|
void httpdInternalCloseAllSockets() |
|
|
|
void httpdInternalCloseAllSockets(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
httpdPlatLock(); |
|
|
|
httpdPlatLock(); |
|
|
|
/*release data connection*/ |
|
|
|
/*release data connection*/ |
|
|
@ -89,8 +99,7 @@ void httpdAddCacheHeaders(HttpdConnData *connData, const char *mime) |
|
|
|
if (streq(mime, "text/html") |
|
|
|
if (streq(mime, "text/html") |
|
|
|
|| streq(mime, "text/plain") |
|
|
|
|| streq(mime, "text/plain") |
|
|
|
|| streq(mime, "text/csv") |
|
|
|
|| streq(mime, "text/csv") |
|
|
|
|| streq(mime, "application/json") |
|
|
|
|| streq(mime, "application/json")) { |
|
|
|
) { |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -191,6 +200,37 @@ int httpdGetHeader(HttpdConnData *conn, const char *header, char *buff, size_t b |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void httpdQueueHeader(HttpdConnData *conn, const char *header, const char *value) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!conn || !header || !value) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (conn->priv->flags & HFL_SENDINGBODY) { |
|
|
|
|
|
|
|
http_error("Headers already sent."); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HttpdQueuedHeader *queEntry = httpdPlatMalloc(sizeof(void *) + strlen(header) + strlen(value) + 5); |
|
|
|
|
|
|
|
if (!queEntry) { |
|
|
|
|
|
|
|
http_error("httpdQueueHeader - no mem"); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
queEntry->next = NULL; |
|
|
|
|
|
|
|
queEntry->headerLine[0] = 0; |
|
|
|
|
|
|
|
strcat(queEntry->headerLine, header); |
|
|
|
|
|
|
|
strcat(queEntry->headerLine, ": "); |
|
|
|
|
|
|
|
strcat(queEntry->headerLine, value); |
|
|
|
|
|
|
|
strcat(queEntry->headerLine, "\r\n"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Attach it to the linked list
|
|
|
|
|
|
|
|
HttpdQueuedHeader **ph = &conn->priv->headersToSend; |
|
|
|
|
|
|
|
while (*ph) { |
|
|
|
|
|
|
|
ph = &(*ph)->next; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*ph = queEntry; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void httdSetTransferMode(HttpdConnData *conn, httpd_transfer_opt mode) |
|
|
|
void httdSetTransferMode(HttpdConnData *conn, httpd_transfer_opt mode) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (mode == HTTPD_TRANSFER_CLOSE) { |
|
|
|
if (mode == HTTPD_TRANSFER_CLOSE) { |
|
|
@ -224,12 +264,12 @@ void httpdStartResponse(HttpdConnData *conn, int code) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
size_t l = (size_t)sprintf(buff, "HTTP/1.%d %d %s\r\nServer: %s\r\n%s", |
|
|
|
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, |
|
|
|
code, |
|
|
|
httpdStatusName(code), |
|
|
|
httpdStatusName(code), |
|
|
|
s_serverName, |
|
|
|
s_serverName, |
|
|
|
connStr); |
|
|
|
connStr); |
|
|
|
|
|
|
|
|
|
|
|
httpdSendStrN(conn, buff, l); |
|
|
|
httpdSendStrN(conn, buff, l); |
|
|
|
|
|
|
|
|
|
|
@ -252,6 +292,15 @@ void httpdHeader(HttpdConnData *conn, const char *field, const char *val) |
|
|
|
//Finish the headers.
|
|
|
|
//Finish the headers.
|
|
|
|
void httpdEndHeaders(HttpdConnData *conn) |
|
|
|
void httpdEndHeaders(HttpdConnData *conn) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
// Add queued headers
|
|
|
|
|
|
|
|
HttpdQueuedHeader *qh = conn->priv->headersToSend; |
|
|
|
|
|
|
|
while (qh) { |
|
|
|
|
|
|
|
httpdSendStr(conn, qh->headerLine); |
|
|
|
|
|
|
|
HttpdQueuedHeader *next = qh->next; |
|
|
|
|
|
|
|
httpdPlatFree(qh); |
|
|
|
|
|
|
|
qh = next; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
httpdSendStr(conn, "\r\n"); |
|
|
|
httpdSendStr(conn, "\r\n"); |
|
|
|
conn->priv->flags |= HFL_SENDINGBODY; |
|
|
|
conn->priv->flags |= HFL_SENDINGBODY; |
|
|
|
} |
|
|
|
} |
|
|
@ -309,17 +358,21 @@ int httpdSend_html(HttpdConnData *conn, const char *data, ssize_t len) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (c == '"' || c == '\'' || c == '<' || c == '>') { |
|
|
|
if (c == '"' || c == '\'' || c == '<' || c == '>') { |
|
|
|
if (start < end) httpdSend_orDie(conn, data + start, end - start); |
|
|
|
if (start < end) { |
|
|
|
|
|
|
|
httpdSend_orDie(conn, data + start, end - start); |
|
|
|
|
|
|
|
} |
|
|
|
start = end + 1; |
|
|
|
start = end + 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (c == '"') httpdSendStr_orDie(conn, """); |
|
|
|
if (c == '"') { httpdSendStr_orDie(conn, """); } |
|
|
|
else if (c == '\'') httpdSendStr_orDie(conn, "'"); |
|
|
|
else if (c == '\'') { httpdSendStr_orDie(conn, "'"); } |
|
|
|
else if (c == '<') httpdSendStr_orDie(conn, "<"); |
|
|
|
else if (c == '<') { httpdSendStr_orDie(conn, "<"); } |
|
|
|
else if (c == '>') httpdSendStr_orDie(conn, ">"); |
|
|
|
else if (c == '>') { httpdSendStr_orDie(conn, ">"); } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (start < end) httpdSend_orDie(conn, data + start, end - start); |
|
|
|
if (start < end) { |
|
|
|
|
|
|
|
httpdSend_orDie(conn, data + start, end - start); |
|
|
|
|
|
|
|
} |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -340,20 +393,24 @@ int httpdSend_js(HttpdConnData *conn, const char *data, ssize_t len) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (c == '"' || c == '\\' || c == '\'' || c == '<' || c == '>' || c == '\n' || c == '\r') { |
|
|
|
if (c == '"' || c == '\\' || c == '\'' || c == '<' || c == '>' || c == '\n' || c == '\r') { |
|
|
|
if (start < end) httpdSend_orDie(conn, data + start, end - start); |
|
|
|
if (start < end) { |
|
|
|
|
|
|
|
httpdSend_orDie(conn, data + start, end - start); |
|
|
|
|
|
|
|
} |
|
|
|
start = end + 1; |
|
|
|
start = end + 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (c == '"') httpdSendStr_orDie(conn, "\\\""); |
|
|
|
if (c == '"') { httpdSendStr_orDie(conn, "\\\""); } |
|
|
|
else if (c == '\'') httpdSendStr_orDie(conn, "\\'"); |
|
|
|
else if (c == '\'') { httpdSendStr_orDie(conn, "\\'"); } |
|
|
|
else if (c == '\\') httpdSendStr_orDie(conn, "\\\\"); |
|
|
|
else if (c == '\\') { httpdSendStr_orDie(conn, "\\\\"); } |
|
|
|
else if (c == '<') httpdSendStr_orDie(conn, "\\u003C"); |
|
|
|
else if (c == '<') { httpdSendStr_orDie(conn, "\\u003C"); } |
|
|
|
else if (c == '>') httpdSendStr_orDie(conn, "\\u003E"); |
|
|
|
else if (c == '>') { httpdSendStr_orDie(conn, "\\u003E"); } |
|
|
|
else if (c == '\n') httpdSendStr_orDie(conn, "\\n"); |
|
|
|
else if (c == '\n') { httpdSendStr_orDie(conn, "\\n"); } |
|
|
|
else if (c == '\r') httpdSendStr_orDie(conn, "\\r"); |
|
|
|
else if (c == '\r') { httpdSendStr_orDie(conn, "\\r"); } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (start < end) httpdSend_orDie(conn, data + start, end - start); |
|
|
|
if (start < end) { |
|
|
|
|
|
|
|
httpdSend_orDie(conn, data + start, end - start); |
|
|
|
|
|
|
|
} |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -371,7 +428,7 @@ bool httpdFlushSendBuffer(HttpdConnData *conn) |
|
|
|
//Finish chunk with cr/lf
|
|
|
|
//Finish chunk with cr/lf
|
|
|
|
httpdSendStr(conn, "\r\n"); |
|
|
|
httpdSendStr(conn, "\r\n"); |
|
|
|
//Calculate length of chunk
|
|
|
|
//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
|
|
|
|
//Fix up chunk header to correct value
|
|
|
|
conn->priv->chunkHdr[0] = httpdHexNibble((uint8_t) (len >> 12)); |
|
|
|
conn->priv->chunkHdr[0] = httpdHexNibble((uint8_t) (len >> 12)); |
|
|
|
conn->priv->chunkHdr[1] = httpdHexNibble((uint8_t) (len >> 8)); |
|
|
|
conn->priv->chunkHdr[1] = httpdHexNibble((uint8_t) (len >> 8)); |
|
|
@ -507,7 +564,6 @@ void httpdContinue(HttpdConnData *conn) |
|
|
|
//find the next cgi function, wait till the cgi data is sent or close up the connection.
|
|
|
|
//find the next cgi function, wait till the cgi data is sent or close up the connection.
|
|
|
|
static void httpdProcessRequest(HttpdConnData *conn) |
|
|
|
static void httpdProcessRequest(HttpdConnData *conn) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int r; |
|
|
|
|
|
|
|
int i = 0; |
|
|
|
int i = 0; |
|
|
|
if (conn->url == NULL) { |
|
|
|
if (conn->url == NULL) { |
|
|
|
router_warn("WtF? url = NULL"); |
|
|
|
router_warn("WtF? url = NULL"); |
|
|
@ -564,7 +620,7 @@ static void httpdProcessRequest(HttpdConnData *conn) |
|
|
|
|
|
|
|
|
|
|
|
//Okay, we have a CGI function that matches the URL. See if it wants to handle the
|
|
|
|
//Okay, we have a CGI function that matches the URL. See if it wants to handle the
|
|
|
|
//particular URL we're supposed to handle.
|
|
|
|
//particular URL we're supposed to handle.
|
|
|
|
r = conn->cgi(conn); |
|
|
|
httpd_cgi_state r = conn->cgi(conn); |
|
|
|
if (r == HTTPD_CGI_MORE) { |
|
|
|
if (r == HTTPD_CGI_MORE) { |
|
|
|
//Yep, it's happy to do so and has more data to send.
|
|
|
|
//Yep, it's happy to do so and has more data to send.
|
|
|
|
if (conn->recvHdl) { |
|
|
|
if (conn->recvHdl) { |
|
|
|