Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
Revision 130:9a5b8fe308f1, committed 2019-09-24
- Comitter:
- andrewboyson
- Date:
- Tue Sep 24 18:16:47 2019 +0000
- Parent:
- 129:6d9bffc72676
- Child:
- 131:a9793a9721c7
- Commit message:
- Added http
Changed in this revision
--- a/base/net-trace/web-trace-ajax.c Sun Sep 01 18:12:48 2019 +0000
+++ b/base/net-trace/web-trace-ajax.c Tue Sep 24 18:16:47 2019 +0000
@@ -26,7 +26,7 @@
#include "ip6.h"
#include "udp.h"
#include "tcp.h"
-#include "http.h"
+#include "web.h"
#include "tftp.h"
#include "ntpclient.h"
@@ -94,7 +94,7 @@
nibble = 0; //12
if (UdpTrace ) nibble |= 1;
if (TcpTrace ) nibble |= 2;
- if (HttpTrace ) nibble |= 4;
+ if (WebTrace ) nibble |= 4;
if (TftpTrace ) nibble |= 8;
HttpAddNibbleAsHex(nibble);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/http-connection.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,74 @@
+#include <stdlib.h>
+
+#include "http-connection.h"
+#include "mstimer.h"
+
+#define MAX_CONNECTIONS 10
+
+static struct HttpConnection connections[MAX_CONNECTIONS];
+
+static void zeroConnection(struct HttpConnection* p)
+{
+ p->id = 0;
+ p->lastUsed = 0;
+ p->toDo = 0;
+ p->postComplete = false;
+ p->delayUntil = 0;
+}
+
+struct HttpConnection* HttpConnectionNew(int connectionId) //Never fails so never returns NULL
+{
+ struct HttpConnection* p;
+
+ //Look for an existing connection
+ for (p = connections; p < connections + MAX_CONNECTIONS; p++)
+ {
+ if (p->id == connectionId) goto end;
+ }
+
+ //look for an empty connection
+ {
+ struct HttpConnection* pOldest = 0;
+ uint32_t ageOldest = 0;
+ for (p = connections; p < connections + MAX_CONNECTIONS; p++)
+ {
+ if (!p->id) goto end;
+
+ //Otherwise record the oldest and keep going
+ uint32_t age = MsTimerCount - p->lastUsed;
+ if (age >= ageOldest)
+ {
+ ageOldest = age;
+ pOldest = p;
+ }
+ }
+
+ //No empty ones found so use the oldest
+ p = pOldest;
+ }
+
+end:
+ zeroConnection(p);
+ p->id = connectionId;
+ p->lastUsed = MsTimerCount;
+ return p;
+}
+struct HttpConnection* HttpConnectionOrNull(int connectionId)
+{
+ for (struct HttpConnection* p = connections; p < connections + MAX_CONNECTIONS; p++)
+ {
+ if (p->id == connectionId)
+ {
+ p->lastUsed = MsTimerCount;
+ return p;
+ }
+ }
+ return NULL;
+}
+void HttpConnectionReset(int connectionId)
+{
+ for (struct HttpConnection* p = connections; p < connections + MAX_CONNECTIONS; p++)
+ {
+ if (p->id == connectionId) zeroConnection(p);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/http-connection.h Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,15 @@
+#include <stdint.h>
+#include <stdbool.h>
+
+struct HttpConnection
+{
+ int id; //An id of zero means the record is empty
+ uint32_t lastUsed;
+ int toDo;
+ bool postComplete;
+ uint32_t delayUntil;
+};
+
+extern struct HttpConnection* HttpConnectionNew (int connectionId); //Never fails so never returns NULL
+extern struct HttpConnection* HttpConnectionOrNull(int connectionId);
+extern void HttpConnectionReset (int connectionId);
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/http.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,105 @@
+#include "http.h"
+#include "http-connection.h"
+#include "web.h"
+#include "mstimer.h"
+#include "log.h"
+
+bool HttpGetTrace()
+{
+ return WebTrace;
+}
+
+void HttpReset(int connection)
+{
+ HttpConnectionReset(connection);
+}
+bool HttpResponse(int connection, bool clientFinished, int* pWindowSize, char* pWindow, uint32_t windowPositionInStream)
+{
+ int status = HttpPoll(connection, clientFinished);
+ bool finished;
+ switch (status)
+ {
+ case HTTP_WAIT: finished = false; *pWindowSize = 0; break;
+ case HTTP_FINISHED: finished = true; *pWindowSize = 0; break;
+ case HTTP_HAVE_SOMETHING_TO_SEND: finished = HttpAdd(connection, pWindowSize, pWindow, windowPositionInStream); break;
+ }
+ return finished;
+}
+bool HttpAdd(int connectionId, int* pWindowSize, char* pWindow, uint32_t windowPositionInStream)
+{
+ HttpAddStart(windowPositionInStream, *pWindowSize, pWindow); //We have something to send so start the buffer
+ *pWindowSize = 0;
+
+ struct HttpConnection* pConnection = HttpConnectionOrNull(connectionId);
+ if (!pConnection) return false; //Protects the gap between the connection being established and the request being started
+
+ int todo = pConnection->toDo; //Make a copy so that we don't modify todo in the state
+
+ WebAddResponse(todo);
+
+ *pWindowSize = HttpAddLength();
+
+ return !HttpAddFilled(); //If we haven't used a full buffer then we have finished
+}
+int HttpPoll(int connectionId, bool clientFinished)
+{
+ struct HttpConnection* pConnection = HttpConnectionOrNull(connectionId);
+ if (!pConnection) return HTTP_WAIT; //Protects the gap between the connection being established and the request being started
+
+ if (!pConnection->toDo)
+ {
+ if (clientFinished) return HTTP_FINISHED; //The client hasn't requested anything and never will so finish
+ else return HTTP_WAIT; //The client hasn't requested anything yet but still could
+ }
+ if (!pConnection->postComplete ) return HTTP_WAIT; //Wait for the request (usually a POST) to finish
+ if (!MsTimerAbsolute(pConnection->delayUntil)) return HTTP_WAIT; //Wait a while (usually after a LOGIN attempt)
+
+ return HTTP_HAVE_SOMETHING_TO_SEND;
+}
+void HttpRequest(int connectionId, int windowSize, char* pWindow, uint32_t windowPositionInStream)
+{
+ struct HttpConnection* pConnection;
+ if (!windowPositionInStream)
+ {
+ pConnection = HttpConnectionNew(connectionId);
+ }
+ else
+ {
+ pConnection = HttpConnectionOrNull(connectionId);
+ if (!pConnection)
+ {
+ LogTimeF("WebRequest - no connection corresponds to id %d\r\n", connectionId);
+ return;
+ }
+ }
+
+ pConnection->delayUntil = MsTimerCount; //Default to no delay unless modified;
+
+ //Handle request for the first packet of data received but leave todo the same after that.
+ int contentLength = 0;
+ int contentStart = 0;
+ if (windowSize && windowPositionInStream == 0)
+ {
+ //Read the headers
+ char* pMethod;
+ char* pPath;
+ char* pQuery;
+ char* pLastModified;
+ char* pCookies;
+ contentStart = HttpRequestRead(pWindow, windowSize, &pMethod, &pPath, &pQuery, &pLastModified, &pCookies, &contentLength);
+
+ //Ask the web server what to do
+ pConnection->toDo = WebDecideWhatToDo(pPath, pLastModified);
+
+ //Handle the query
+ int stop = WebHandleQuery(pQuery, pCookies, &pConnection->toDo, &pConnection->delayUntil); //return -1 on stop; 0 on continue
+ if (stop)
+ {
+ pConnection->postComplete = true;
+ return;
+ }
+ }
+
+ //Do the upload of anything that needs it. Todos it doesn't understand are ignored.
+ if (!pConnection->postComplete) WebHandlePost(pConnection->toDo, contentLength, contentStart, windowSize, pWindow, windowPositionInStream, &pConnection->postComplete);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/http.h Tue Sep 24 18:16:47 2019 +0000 @@ -0,0 +1,62 @@ +#include <stdbool.h> +#include <stdarg.h> +#include <stdint.h> +#include <time.h> + +#define HTTP_WAIT 0 +#define HTTP_FINISHED 1 +#define HTTP_HAVE_SOMETHING_TO_SEND 2 + +extern void HttpReset (int connectionId); +extern bool HttpResponse(int connectionId, bool clientFinished, int* pWindowSize, char* pWindow, uint32_t windowPositionInStream); +extern bool HttpAdd (int connectionId, int* pWindowSize, char* pWindow, uint32_t windowPositionInStream); //returns true if finished; false if not +extern int HttpPoll (int connectionId, bool clientFinished); //returns true if something to send; false if not +extern void HttpRequest (int connectionId, int windowSize, char* pWindow, uint32_t windowPositionInStream); + +extern bool HttpGetTrace(void); + +extern void HttpAddStart (uint32_t position, int mss, char *pData); +extern int HttpAddLength (void); +extern bool HttpAddFilled (void); + +extern void HttpAddChar (char c); +extern void HttpAddFillChar (char c, int length); +extern int HttpAddText (const char* text); +extern int HttpAddV (char *fmt, va_list argptr); +extern int HttpAddF (char *fmt, ...); +extern void HttpAddData (const char* data, int length); +extern void HttpAddStream (void (*startFunction)(void), int (*enumerateFunction)(void)); +extern void HttpAddNibbleAsHex (int value); +extern void HttpAddByteAsHex (int value); +extern void HttpAddInt12AsHex (int value); +extern void HttpAddInt16AsHex (int value); +extern void HttpAddInt32AsHex (int value); +extern void HttpAddInt64AsHex (int64_t value); +extern void HttpAddBytesAsHex (const uint8_t* value, int size); +extern void HttpAddBytesAsHexRev(const uint8_t* value, int size); +extern void HttpAddTm (struct tm* ptm); + +extern void HttpOk(const char* contentType, const char* cacheControl, const char* lastModifiedDate, const char* lastModifiedTime); +extern char* HttpOkCookieName; +extern char* HttpOkCookieValue; +extern int HttpOkCookieMaxAge; + +extern void HttpNotFound (void); +extern void HttpNotModified (void); + +extern int HttpRequestRead(char *p, int len, char** ppMethod, char** ppPath, char** ppQuery, char** ppLastModified, char** ppCookies, int* pContentLength); + +extern char* HttpCookiesSplit (char* pCookies, char** ppName, char** ppValue); +extern char* HttpQuerySplit (char* pQuery, char** ppName, char** ppValue); +extern int HttpQueryValueAsInt(char* pValue); +extern void HttpQueryUnencode (char* pValue); + +extern void HttpDateFromDateTime(const char* date, const char *ptime, char* ptext); +extern void HttpDateFromNow(char* pText); + +extern bool HttpSameStr (const char* pa, const char* pb); +extern bool HttpSameStrCaseInsensitive(const char* pa, const char* pb); +extern bool HttpSameDate (const char* date, const char* time, const char* pOtherDate); + +#define HTTP_DATE_LENGTH 30 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/httpadd.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,190 @@
+#include <time.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+static uint32_t currentPositionInMessage;
+static uint32_t bufferPositionInMessage;
+static int bufferLength;
+static char* pBuffer;
+static char* p;
+
+void HttpAddStart(uint32_t position, int mss, char *pData)
+{
+ currentPositionInMessage = 0;
+ bufferPositionInMessage = position;
+ bufferLength = mss;
+ pBuffer = pData;
+ p = pData;
+}
+int HttpAddLength()
+{
+ return p - pBuffer;
+}
+bool HttpAddFilled()
+{
+ return p - pBuffer >= bufferLength;
+}
+
+void HttpAddChar(char c)
+{
+ //Add character if the current position is within the buffer
+ if (currentPositionInMessage >= bufferPositionInMessage &&
+ currentPositionInMessage < bufferPositionInMessage + bufferLength) *p++ = c;
+
+ currentPositionInMessage++;
+}
+
+void HttpAddFillChar (char c, int length)
+{
+ while (length > 0)
+ {
+ HttpAddChar(c);
+ length--;
+ }
+}
+int HttpAddText (const char* text)
+{
+ const char* start = text;
+ while (*text)
+ {
+ HttpAddChar(*text);
+ text++;
+ }
+ return text - start;
+}
+int HttpAddV (char *fmt, va_list argptr)
+{
+ int size = vsnprintf(NULL, 0, fmt, argptr); //Find the size required
+ char text[size + 1]; //Allocate enough memory for the size required with an extra byte for the terminating null
+ vsprintf(text, fmt, argptr); //Fill the new buffer
+ return HttpAddText(text); //Add the text
+}
+int HttpAddF (char *fmt, ...)
+{
+ va_list argptr;
+ va_start(argptr, fmt);
+ int size = HttpAddV(fmt, argptr);
+ va_end(argptr);
+ return size;
+}
+void HttpAddData (const char* data, int length)
+{
+ while (length > 0)
+ {
+ HttpAddChar(*data);
+ data++;
+ length--;
+ }
+}
+void HttpAddStream(void (*startFunction)(void), int (*enumerateFunction)(void))
+{
+ startFunction();
+ while (true)
+ {
+ int c = enumerateFunction();
+ if (c == EOF) break;
+ HttpAddChar(c);
+ }
+}
+void HttpAddNibbleAsHex(int nibble)
+{
+ nibble &= 0x0F;
+ char c;
+ if (nibble < 0x0A) c = nibble + '0';
+ else if (nibble < 0x10) c = nibble - 0xA + 'A';
+ else c = '0';
+ HttpAddChar(c);
+}
+void HttpAddByteAsHex(int value)
+{
+ HttpAddNibbleAsHex(value >> 4);
+ HttpAddNibbleAsHex(value >> 0);
+}
+void HttpAddInt12AsHex(int value)
+{
+ HttpAddNibbleAsHex(value >> 8);
+ HttpAddNibbleAsHex(value >> 4);
+ HttpAddNibbleAsHex(value >> 0);
+}
+void HttpAddInt16AsHex(int value)
+{
+ HttpAddNibbleAsHex(value >> 12);
+ HttpAddNibbleAsHex(value >> 8);
+ HttpAddNibbleAsHex(value >> 4);
+ HttpAddNibbleAsHex(value >> 0);
+}
+void HttpAddInt32AsHex(int value)
+{
+ HttpAddNibbleAsHex(value >> 28);
+ HttpAddNibbleAsHex(value >> 24);
+ HttpAddNibbleAsHex(value >> 20);
+ HttpAddNibbleAsHex(value >> 16);
+ HttpAddNibbleAsHex(value >> 12);
+ HttpAddNibbleAsHex(value >> 8);
+ HttpAddNibbleAsHex(value >> 4);
+ HttpAddNibbleAsHex(value >> 0);
+}
+void HttpAddInt64AsHex(int64_t value)
+{
+ HttpAddNibbleAsHex(value >> 60);
+ HttpAddNibbleAsHex(value >> 56);
+ HttpAddNibbleAsHex(value >> 52);
+ HttpAddNibbleAsHex(value >> 48);
+ HttpAddNibbleAsHex(value >> 44);
+ HttpAddNibbleAsHex(value >> 40);
+ HttpAddNibbleAsHex(value >> 36);
+ HttpAddNibbleAsHex(value >> 32);
+ HttpAddNibbleAsHex(value >> 28);
+ HttpAddNibbleAsHex(value >> 24);
+ HttpAddNibbleAsHex(value >> 20);
+ HttpAddNibbleAsHex(value >> 16);
+ HttpAddNibbleAsHex(value >> 12);
+ HttpAddNibbleAsHex(value >> 8);
+ HttpAddNibbleAsHex(value >> 4);
+ HttpAddNibbleAsHex(value >> 0);
+}
+void HttpAddBytesAsHex(const uint8_t* value, int size)
+{
+ int i = 0;
+ while(true)
+ {
+ HttpAddByteAsHex(value[i]);
+ i++;
+ if (i >= size) break;
+ if (i % 16 == 0) HttpAddText("\r\n");
+ else HttpAddChar(' ');
+ }
+}
+void HttpAddBytesAsHexRev(const uint8_t* value, int size)
+{
+ int i = 0;
+ while(true)
+ {
+ HttpAddByteAsHex(value[size - i - 1]);
+ i++;
+ if (i >= size) break;
+ if (i % 16 == 0) HttpAddText("\r\n");
+ else HttpAddChar(' ');
+ }
+}
+void HttpAddTm(struct tm* ptm)
+{
+ HttpAddF("%d-%02d-%02d ", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday);
+ switch(ptm->tm_wday)
+ {
+ case 0: HttpAddText("Sun"); break;
+ case 1: HttpAddText("Mon"); break;
+ case 2: HttpAddText("Tue"); break;
+ case 3: HttpAddText("Wed"); break;
+ case 4: HttpAddText("Thu"); break;
+ case 5: HttpAddText("Fri"); break;
+ case 6: HttpAddText("Sat"); break;
+ default: HttpAddText("???"); break;
+ }
+ HttpAddF(" %02d:%02d:%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
+ if (ptm->tm_isdst > 0) HttpAddText(" BST");
+ else if (ptm->tm_isdst == 0) HttpAddText(" GMT");
+ else HttpAddText(" UTC");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/httpdate.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+
+#include "tm.h"
+#include "http.h"
+#include "clk.h"
+
+static void dateFromTm(struct tm* ptm, char* ptext)
+{
+ size_t size = strftime(ptext, HTTP_DATE_LENGTH, "%a, %d %b %Y %H:%M:%S GMT", ptm);//Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+}
+void HttpDateFromNow(char* pText)
+{
+ struct tm tm;
+ ClkNowTmUtc(&tm);
+ dateFromTm(&tm, pText);
+}
+void HttpDateFromDateTime(const char* date, const char *ptime, char* ptext)
+{
+ struct tm tm;
+ TmFromAsciiDateTime(date, ptime, &tm);
+ dateFromTm(&tm, ptext);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/httpquery.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+static int hexToInt(char c)
+{
+ int nibble;
+ if (c >= '0' && c <= '9') nibble = c - '0';
+ if (c >= 'A' && c <= 'F') nibble = c - 'A' + 0xA;
+ if (c >= 'a' && c <= 'f') nibble = c - 'a' + 0xA;
+ return nibble;
+}
+void HttpQueryUnencode(char* pValue)
+{
+ char* pDst = pValue;
+ int a;
+ for (char* pSrc = pValue; *pSrc; pSrc++)
+ {
+ char c = *pSrc;
+ switch (c)
+ {
+ case '+':
+ c = ' ';
+ break;
+ case '%':
+ c = *++pSrc;
+ if (c == 0) break;
+ a = hexToInt(c);
+ a <<= 4;
+ c = *++pSrc;
+ if (c == 0) break;
+ a += hexToInt(c);
+ c = a;
+ break;
+ default:
+ c = *pSrc;
+ break;
+ }
+ *pDst++ = c;
+ }
+ *pDst = 0;
+}
+char* HttpQuerySplit(char* p, char** ppName, char** ppValue) //returns the start of the next name value pair
+{
+ *ppName = p; //Record the start of the name
+ *ppValue = NULL;
+
+ while (*p != '=') //Loop to an '='
+ {
+ if (*p == 0) return 0;
+ p++;
+ }
+ *p = 0; //Terminate the name by replacing the '=' with a NUL char
+ p++; //Move on to the start of the value
+ *ppValue = p; //Record the start of the value
+ while (*p != '&') //Loop to a '&'
+ {
+ if (*p == 0) return 0;
+ p++;
+ }
+ *p = 0; //Terminate the value by replacing the '&' with a NULL
+ return p + 1;
+}
+int HttpQueryValueAsInt(char* pValue)
+{
+ return (int)strtol(pValue, NULL, 10);
+}
+char* HttpCookiesSplit(char* p, char** ppName, char** ppValue) //returns the start of the next name value pair
+{
+ *ppValue = NULL;
+ *ppName = NULL;
+
+ *ppName = p; //Record the start of the name
+ while (*p != '=') //Loop to an '='
+ {
+ if (*p == 0) return 0;
+ p++;
+ }
+ *p = 0; //Terminate the name by replacing the '=' with a NUL char
+ p++; //Move on to the start of the value
+ *ppValue = p; //Record the start of the value
+ while (*p != ';') //Loop to a ';'
+ {
+ if (*p == 0) return 0;
+ p++;
+ }
+ *p = 0; //Terminate the value by replacing the ';' with a NULL
+ p++;
+ if (*p == 0) return 0;
+ while (*p == ' ') p++; //Move past any spaces after the ';'
+ return p;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/httprequest.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,105 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "http.h"
+#include "log.h"
+
+static char* terminateThisAndGetNextLine(char* p, char* pE) //Terminates this line and returns the start of the next line or NULL if none
+{
+ while (true)
+ {
+ if ( p == pE) { *p = 0; return NULL; } //no more buffer - relies on having designed the buffer to be bigger than an ethernet packet
+ if (*p == 0) return NULL; //there are no more lines
+ if (*p == '\n') { *p = 0; return p + 1; } //return the start of the next line
+ if (*p < ' ') *p = 0; //terminate the line at any invalid characters but keep going to find the start of the next line
+ if (*p >= 0x7f) *p = 0; //terminate the line at any invalid characters but keep going to find the start of the next line
+ p++;
+ }
+}
+
+static void splitRequest(char* p, char** ppMethod, char** ppPath, char** ppQuery)
+{
+ *ppMethod = NULL;
+ *ppPath = NULL;
+ *ppQuery = NULL;
+
+ while (*p == ' ') //Move past any leading spaces
+ {
+ if (*p == 0) return;
+ p++;
+ }
+ *ppMethod = p; //Record the start of the method (GET or POST)
+
+ while (*p != ' ') //Move past the method
+ {
+ if (*p == 0) return;
+ p++;
+ }
+ *p = 0; //Terminate the method
+ p++; //Start at next character
+
+ while (*p == ' ') //Move past any spaces
+ {
+ if (*p == 0) return;
+ p++;
+ }
+ *ppPath = p; //Record the start of the path
+
+ while (*p != ' ') //Move past the path and query
+ {
+ if (*p == 0) return;
+ if (*p == '?')
+ {
+ *p = 0; //Terminate the path
+ *ppQuery = p + 1; //Record the start of the query
+ }
+ p++;
+ }
+ *p = 0; //Terminate the path or query
+}
+static void splitHeader(char* p, char** ppName, char** ppValue)
+{
+ *ppName = p; //Record the start of the name
+ *ppValue = NULL;
+
+ while (*p != ':') //Loop to an ':'
+ {
+ if (!*p) return;
+ p++;
+ }
+ *p = 0; //Terminate the name by replacing the ':' with a NUL char
+ p++;
+ while (*p == ' ') //Move past any spaces
+ {
+ if (*p == 0) return;
+ p++;
+ }
+ *ppValue = p; //Record the start of the value
+}
+int HttpRequestRead(char *pData, int len, char** ppMethod, char** ppPath, char** ppQuery, char** ppLastModified, char** ppCookies, int* pContentLength)
+{
+ char* pEnd = pData + len;
+ char* pThis = pData;
+ char* pNext = terminateThisAndGetNextLine(pThis, pEnd);
+ splitRequest(pThis, ppMethod, ppPath, ppQuery);
+
+ *ppLastModified = NULL; //Return NULL if no 'If-Modified-Since' line
+ *ppCookies = NULL; //Return NULL if no 'Cookie' line
+ *pContentLength = 0; //Return 0 if no 'Content-Length' line
+ while(pNext)
+ {
+ pThis = pNext;
+ pNext = terminateThisAndGetNextLine(pThis, pEnd);
+ if (*pThis == 0) break; //This line is empty ie no more headers
+ char* pName;
+ char* pValue;
+ splitHeader(pThis, &pName, &pValue);
+ if (HttpSameStrCaseInsensitive(pName, "If-Modified-Since")) *ppLastModified = pValue;
+ if (HttpSameStrCaseInsensitive(pName, "Cookie" )) *ppCookies = pValue;
+ if (HttpSameStrCaseInsensitive(pName, "Content-Length" )) *pContentLength = atoi(pValue);
+ }
+ if (pNext) return pNext - pData;
+ else return len;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/https.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,22 @@
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "tls.h"
+#include "http.h"
+
+bool HttpsGetTrace()
+{
+ return HttpGetTrace() || TlsTrace;
+}
+void HttpsReset(int connectionId)
+{
+ TlsReset(connectionId);
+}
+bool HttpsResponse(int connectionId, bool clientFinished, int* pWindowSize, uint8_t* pWindow, uint32_t windowPositionInStream)
+{
+ return TlsResponse(connectionId, clientFinished, pWindowSize, pWindow, windowPositionInStream);
+}
+void HttpsRequest (int connectionId, int windowSize, uint8_t* pWindow, uint32_t windowPositionInStream)
+{
+ TlsRequest(connectionId, windowSize, pWindow, windowPositionInStream);
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/http/https.h Tue Sep 24 18:16:47 2019 +0000 @@ -0,0 +1,7 @@ +#include <stdint.h> +#include <stdbool.h> + +extern bool HttpsGetTrace(void); +extern void HttpsReset (int connectionId); +extern bool HttpsResponse(int connectionId, bool clientFinished, int* pWindowSize, uint8_t* pWindow, uint32_t windowPositionInStream); +extern void HttpsRequest (int connectionId, int windowSize, uint8_t* pWindow, uint32_t windowPositionInStream); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/httpsame.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,37 @@
+#include <stdbool.h>
+#include <ctype.h>
+#include "http.h"
+
+bool HttpSameStr(const char* pa, const char* pb)
+{
+ if (!pa || !pb) return false; //Handle NULL references
+
+ while(true)
+ {
+ if ( *pa != *pb) return false; //If they are not the same return false
+ if (!*pa) return true; //If finished return true;
+ pa++;
+ pb++;
+ }
+}
+bool HttpSameStrCaseInsensitive(const char* pa, const char* pb)
+{
+ if (!pa || !pb) return false; //Handle NULL references
+
+ while(true)
+ {
+ if ( toupper(*pa) != toupper(*pb)) return false; //If they are not the same return false
+ if (!*pa) return true; //If finished return true;
+ pa++;
+ pb++;
+ }
+}
+bool HttpSameDate(const char* date, const char* time, const char* pOtherDate)
+{
+ if (!pOtherDate) return false; //Not the same if no lastModified
+
+ char pFileDate[HTTP_DATE_LENGTH];
+ HttpDateFromDateTime(date, time, pFileDate);
+
+ return HttpSameStr(pFileDate, pOtherDate);
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/status/http-not-found.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,7 @@
+#include "http.h"
+
+void HttpNotFound()
+{
+ HttpAddText("HTTP/1.1 404 Not Found\r\n"
+ "\r\n");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/status/http-not-modified.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,12 @@
+#include "http.h"
+
+void HttpNotModified()
+{
+ HttpAddText("HTTP/1.1 304 Not Modified\r\n"
+ "Date: ");
+ char pDate[HTTP_DATE_LENGTH];
+ HttpDateFromNow(pDate);
+ HttpAddText(pDate);
+ HttpAddText("\r\n"
+ "\r\n");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/http/status/http-ok.c Tue Sep 24 18:16:47 2019 +0000
@@ -0,0 +1,38 @@
+#include "log.h"
+#include "http.h"
+
+char* HttpOkCookieName;
+char* HttpOkCookieValue;
+int HttpOkCookieMaxAge = -1; //-1 = none, 0 = clear, +ve values = number of seconds
+
+void HttpOk(const char* contentType, const char* cacheControl, const char* lastModifiedDate, const char* lastModifiedTime)
+{
+ char pDate[HTTP_DATE_LENGTH];
+
+ if (!contentType) LogTimeF("HtmlOk - missing Content-Type info\r\n");
+ if (!cacheControl) LogTimeF("HtmlOk - missing Cache-Control info\r\n");
+
+ HttpAddF("HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Type: %s\r\n", contentType);
+
+ HttpAddF("Cache-Control: %s\r\n", cacheControl);
+
+ HttpDateFromNow(pDate);
+ HttpAddF("Date: %s\r\n", pDate);
+
+ if (lastModifiedDate)
+ {
+ HttpDateFromDateTime(lastModifiedDate, lastModifiedTime, pDate);
+ HttpAddF("Last-Modified: %s\r\n", pDate);
+ }
+
+ if (HttpOkCookieName && HttpOkCookieValue)
+ {
+ HttpAddF("Set-Cookie: %s=%s", HttpOkCookieName, HttpOkCookieValue );
+ if (HttpOkCookieMaxAge >= 0) HttpAddF("; Max-Age=%d", HttpOkCookieMaxAge);
+ HttpAddText("\r\n");
+ }
+
+ HttpAddText("\r\n");
+}
--- a/web-connection.c Sun Sep 01 18:12:48 2019 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-#include <stdlib.h>
-
-#include "web-connection.h"
-#include "mstimer.h"
-
-#define MAX_CONNECTIONS 10
-
-static struct WebConnection connections[MAX_CONNECTIONS];
-
-static void zeroConnection(struct WebConnection* p)
-{
- p->id = 0;
- p->lastUsed = 0;
- p->toDo = 0;
- p->postComplete = false;
- p->delayUntil = 0;
-}
-
-struct WebConnection* WebConnectionNew(int connectionId) //Never fails so never returns NULL
-{
- struct WebConnection* p;
-
- //Look for an existing connection
- for (p = connections; p < connections + MAX_CONNECTIONS; p++)
- {
- if (p->id == connectionId) goto end;
- }
-
- //look for an empty connection
- {
- struct WebConnection* pOldest = 0;
- uint32_t ageOldest = 0;
- for (p = connections; p < connections + MAX_CONNECTIONS; p++)
- {
- if (!p->id) goto end;
-
- //Otherwise record the oldest and keep going
- uint32_t age = MsTimerCount - p->lastUsed;
- if (age >= ageOldest)
- {
- ageOldest = age;
- pOldest = p;
- }
- }
-
- //No empty ones found so use the oldest
- p = pOldest;
- }
-
-end:
- zeroConnection(p);
- p->id = connectionId;
- p->lastUsed = MsTimerCount;
- return p;
-}
-struct WebConnection* WebConnectionOrNull(int connectionId)
-{
- for (struct WebConnection* p = connections; p < connections + MAX_CONNECTIONS; p++)
- {
- if (p->id == connectionId)
- {
- p->lastUsed = MsTimerCount;
- return p;
- }
- }
- return NULL;
-}
-void WebConnectionReset(int connectionId)
-{
- for (struct WebConnection* p = connections; p < connections + MAX_CONNECTIONS; p++)
- {
- if (p->id == connectionId) zeroConnection(p);
- }
-}
--- a/web-connection.h Sun Sep 01 18:12:48 2019 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-#include <stdint.h>
-#include <stdbool.h>
-
-struct WebConnection
-{
- int id; //An id of zero means the record is empty
- uint32_t lastUsed;
- int toDo;
- bool postComplete;
- uint32_t delayUntil;
-};
-
-extern struct WebConnection* WebConnectionNew (int connectionId); //Never fails so never returns NULL
-extern struct WebConnection* WebConnectionOrNull(int connectionId);
-extern void WebConnectionReset (int connectionId);
\ No newline at end of file
--- a/web.c Sun Sep 01 18:12:48 2019 +0000
+++ b/web.c Tue Sep 24 18:16:47 2019 +0000
@@ -3,15 +3,17 @@
#include "web-server-this.h"
#include "web.h"
#include "web-pages-base.h"
-#include "web-connection.h"
+#include "http-connection.h"
+#include "log.h"
#include "mstimer.h"
-#include "log.h"
#define LOGIN_DELAY_MS 200
#define DO_LOGIN DO_SERVER + 0
-static int decideWhatToDo(char *pPath, char* pLastModified)
+bool WebTrace = false;
+
+int WebDecideWhatToDo(char *pPath, char* pLastModified)
{
if (HttpSameStr(pPath, "/login")) return DO_LOGIN;
@@ -20,124 +22,49 @@
todo = WebServerThisDecideWhatToDo(pPath, pLastModified); if (todo != DO_NOT_FOUND) return todo;
return DO_NOT_FOUND;
}
-static void handleQuery(int todo, char* pQuery)
+int WebHandleQuery(char* pQuery, char* pCookies, int* pTodo, uint32_t* pDelayUntil) //return -1 on stop; 0 on continue
{
- switch (todo)
+ //If what to do is NOTHING, NOT_FOUND or NOT_MODIFIED then no query or post will be valid so stop now
+ if (*pTodo < DO_LOGIN) return -1;
+
+ //If what to do is LOGIN then the user has just returned the login form
+ if (*pTodo == DO_LOGIN)
{
- case DO_LOGIN: WebLoginQuery (pQuery); return;
+ WebLoginQuery(pQuery); //Read the password and the original location
+ if (WebLoginQueryPasswordOk)
+ {
+ if (!WebLoginSessionIdIsSet()) //If there isn't a session id already
+ {
+ WebLoginSessionIdNew(); //Create a new session id
+ }
+ *pTodo = WebLoginOriginalToDo; //Load the original todo and SEND_SESSION_ID
+ *pTodo += DO_SEND_SESSION_ID;
+ }
+ *pDelayUntil = MsTimerCount + LOGIN_DELAY_MS; //To prevent brute forcing the hash delay the reply to the login
+ return -1; //Either way no query or post will be valid
}
- if (WebServerBaseHandleQuery(todo, pQuery)) return;
- if (WebServerThisHandleQuery(todo, pQuery)) return;
+
+ //Have a normal request so authenticate
+ if (!WebLoginCookiesContainValidSessionId(pCookies))
+ {
+ WebLoginOriginalToDo = *pTodo; //Record the original destination for redirection
+ *pTodo = DO_LOGIN;
+ return -1; //Ignore any query or post as the user is not authenticated
+ }
+
+ if (WebServerBaseHandleQuery(*pTodo, pQuery)) return 0;
+ if (WebServerThisHandleQuery(*pTodo, pQuery)) return 0;
+ return 0;
}
-static void handlePost(int todo, int contentLength, int contentStart, int size, char* pRequestStream, uint32_t positionInRequestStream, bool* pComplete)
+void WebHandlePost(int todo, int contentLength, int contentStart, int size, char* pRequestStream, uint32_t positionInRequestStream, bool* pComplete)
{
if (WebServerBasePost(todo, contentLength, contentStart, size, pRequestStream, positionInRequestStream, pComplete)) return;
if (WebServerThisPost(todo, contentLength, contentStart, size, pRequestStream, positionInRequestStream, pComplete)) return;
*pComplete = true;
}
-static void reply(int todo)
-{
- //Try all the base modules
- switch (todo)
- {
- case DO_LOGIN: WebLoginHtml (); return;
- case DO_NOT_FOUND: HttpNotFound (); return;
- case DO_NOT_MODIFIED: HttpNotModified (); return;
- }
-
- //If not called then call the derived (child) module
- if (WebServerBaseReply(todo)) return;
- if (WebServerThisReply(todo)) return;
-}
-static void handleRequest(int connectionId, int size, char* pRequestStream, uint32_t positionInRequestStream)
+void WebAddResponse(int todo)
{
- struct WebConnection* pConnection;
- if (!positionInRequestStream)
- {
- pConnection = WebConnectionNew(connectionId);
- }
- else
- {
- pConnection = WebConnectionOrNull(connectionId);
- if (!pConnection)
- {
- LogTimeF("WebRequest - no connection corresponds to id %d\r\n", connectionId);
- return;
- }
- }
-
- pConnection->delayUntil = MsTimerCount; //Default to no delay unless modified;
-
- //Handle request for the first packet of data received but leave todo the same after that.
- int contentLength = 0;
- int contentStart = 0;
- if (size && positionInRequestStream == 0)
- {
- //Read the headers
- char* pMethod;
- char* pPath;
- char* pQuery;
- char* pLastModified;
- char* pCookies;
- contentStart = HttpRequestRead(pRequestStream, size, &pMethod, &pPath, &pQuery, &pLastModified, &pCookies, &contentLength);
-
- //Ask the web server what to do
- pConnection->toDo = decideWhatToDo(pPath, pLastModified);
-
- //If what to do is NOTHING, NOT_FOUND or NOT_MODIFIED then no query or post will be valid so stop now
- if (pConnection->toDo < DO_LOGIN) { pConnection->postComplete = true; return; }
-
- //If what to do is LOGIN then the user has just returned the login form
- if (pConnection->toDo == DO_LOGIN)
- {
- handleQuery(pConnection->toDo, pQuery); //Read the password and the original location
- if (WebLoginQueryPasswordOk)
- {
- if (!WebLoginSessionIdIsSet()) //If there isn't a session id already
- {
- WebLoginSessionIdNew(); //Create a new session id
- }
- pConnection->toDo = WebLoginOriginalToDo; //Load the original todo and SEND_SESSION_ID
- pConnection->toDo += DO_SEND_SESSION_ID;
- }
- pConnection->delayUntil = MsTimerCount + LOGIN_DELAY_MS; //To prevent brute forcing the hash delay the reply to the login
- pConnection->postComplete = true;
- return; //Either way no query or post will be valid
- }
-
- //Have a normal request so authenticate
- if (!WebLoginCookiesContainValidSessionId(pCookies))
- {
- WebLoginOriginalToDo = pConnection->toDo; //Record the original destination for redirection
- pConnection->toDo = DO_LOGIN;
- pConnection->postComplete = true;
- return; //Ignore any query or post as the user is not authenticated
- }
-
- //Handle the query
- handleQuery(pConnection->toDo, pQuery);
- }
-
- //Do the upload of anything that needs it. Todos it doesn't understand are ignored.
- if (!pConnection->postComplete) handlePost(pConnection->toDo, contentLength, contentStart, size, pRequestStream, positionInRequestStream, &pConnection->postComplete);
-}
-
-static bool pollSomethingToSend(int connectionId, bool clientFinished) //returns true if finished; false if not;
-{
- struct WebConnection* pConnection = WebConnectionOrNull(connectionId);
- if (!pConnection) return false; //Protects the gap between the connection being established and the request being started
-
- if (!pConnection->toDo)
- {
- if (clientFinished) return true; //The client hasn't requested anything and never will so finish
- else return false; //The client hasn't requested anything yet but still could
- }
- if (!pConnection->postComplete ) return false; //Wait for the request (usually a POST) to finish
- if (!MsTimerAbsolute(pConnection->delayUntil)) return false; //Wait a while (usually after a LOGIN attempt)
-
- int todo = pConnection->toDo; //Make a copy so that we don't modify todo in the state
-
//Check if todo includes the need to send a cookie
if (todo >= DO_SEND_SESSION_ID)
{
@@ -153,18 +80,20 @@
HttpOkCookieMaxAge = -1;
}
- reply(todo);
+ //Try all the base modules
+ switch (todo)
+ {
+ case DO_LOGIN: WebLoginHtml (); return;
+ case DO_NOT_FOUND: HttpNotFound (); return;
+ case DO_NOT_MODIFIED: HttpNotModified (); return;
+ }
- return !HttpBufFilled(); //If we haven't used a full buffer then we have finished
+ //If not called then call the derived (child) module
+ if (WebServerBaseReply(todo)) return;
+ if (WebServerThisReply(todo)) return;
}
-int WebInit()
-{
- HttpFunctionReset = WebConnectionReset;
- HttpFunctionRequest = handleRequest;
- HttpFunctionPoll = pollSomethingToSend;
-
- WebLoginInit();
-
- return 0;
+void WebInit()
+{
+ WebLoginInit();
}
\ No newline at end of file
--- a/web.h Sun Sep 01 18:12:48 2019 +0000 +++ b/web.h Tue Sep 24 18:16:47 2019 +0000 @@ -7,4 +7,11 @@ #define DO_THIS 200 #define DO_SEND_SESSION_ID 300 -extern int WebInit(void); \ No newline at end of file +extern bool WebTrace; + +extern void WebInit (void); + +extern void WebAddResponse (int todo); +extern int WebHandleQuery (char* pQuery, char* pCookies, int* pTodo, uint32_t* pDelayUntil); //return -1 on stop; 0 on continue +extern void WebHandlePost (int todo, int contentLength, int contentStart, int size, char* pRequestStream, uint32_t positionInRequestStream, bool* pComplete); +extern int WebDecideWhatToDo(char *pPath, char* pLastModified);