|
|
|
@ -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; |
|
|
|
|
|
|
|
|
|