A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.
Dependents: oldheating gps motorhome heating
Diff: http.cpp
- Revision:
- 2:849103b5a16d
- Parent:
- 1:5f70c361db20
- Child:
- 3:ab6fd66d172c
--- a/http.cpp Thu Jan 19 23:03:26 2017 +0000 +++ b/http.cpp Fri Jan 27 19:58:51 2017 +0000 @@ -1,25 +1,293 @@ -#include "mbed.h" +#include "mbed.h" +#include "favicon.h" +#include "css.h" +#include "arp.h" +#include "time.h" + +#define DO_NOT_FOUND 0 +#define DO_CSS 1 +#define DO_FAVICON 2 +#define DO_HTML 3 + +#define HTTP_DATE_LENGTH 30 + +static char* addNavItem(char* pText, int highlight, char* href, char* title) +{ + char *p; + p = "<li "; while (*p) *pText++ = *p++; + if (highlight) p = "class='this'"; + else p = " "; + while (*p) *pText++ = *p++; + p = "><a href='"; while (*p) *pText++ = *p++; + p = href; while (*p) *pText++ = *p++; + p = "'>"; while (*p) *pText++ = *p++; + p = title; while (*p) *pText++ = *p++; + p = "</a></li>\r\n"; while (*p) *pText++ = *p++; + + return pText; +} +enum pages +{ + HOME_PAGE, + PROGRAM_PAGE, + HEATING_PAGE, + BOILER_PAGE, + SYSTEM_PAGE, + LOG_PAGE +}; +static void addNav(char* pText, int page) +{ + char* p; + p = "<nav><ul>\r\n"; while (*p) *pText++ = *p++; + pText = addNavItem(pText, page == HOME_PAGE, "/", "Home"); + pText = addNavItem(pText, page == PROGRAM_PAGE, "/program", "Program"); + pText = addNavItem(pText, page == HEATING_PAGE, "/heating", "Heating"); + pText = addNavItem(pText, page == BOILER_PAGE, "/boiler", "Boiler"); + pText = addNavItem(pText, page == SYSTEM_PAGE, "/system", "System"); + pText = addNavItem(pText, page == LOG_PAGE, "/log", "Log"); + p = "</ul></nav>\r\n"; while (*p) *pText++ = *p++; + *pText = 0; +} + + +static void dateHeaderFromTm(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 +} +static void dateHeaderFromNow(char* pText) +{ + struct tm tm; + TimeToTmUtc(time(NULL), &tm); + dateHeaderFromTm(&tm, pText); +} +static void dateHeaderFromDateTime(const char* date, const char *ptime, char* ptext) +{ + struct tm tm; + TimeAsciiDateTimeToTm(date, ptime, &tm); + dateHeaderFromTm(&tm, ptext); +} + + -void HttpRequest(int position, int len, char *pData) +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 +} + +int HttpRequest(int position, int len, char *pData) +{ + char* pMethod; + char* pPath; + char* pQuery; + + splitRequest(pData, &pMethod, &pPath, &pQuery); + + int todo = DO_NOT_FOUND; + if (strcmp(pPath, "/" ) == 0) todo = DO_HTML; + if (strcmp(pPath, "/favicon.ico") == 0) todo = DO_FAVICON; + if (strcmp(pPath, "/gps.css" ) == 0) todo = DO_CSS; + + return todo; +} +int sendNotFound(int position, int mss, char* pData) { + printf("Sending 404 Not Found\r\n"); + char *pHttp = "HTTP/1.1 404 Not Found\r\n" + "\r\n"; + int lenHttp = strlen(pHttp); + char* p = pData; + for (int i = position; i < position + mss; i++) + { + if (i < lenHttp ) *p++ = pHttp[i]; + else break; + } + return p - pData; } -int HttpResponse(int position, char *pData) +int sendHtml(int position, int mss, char* pData) { - char *pHtml = "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=UTF-8\r\n" - "Connection: close\r\n" - "\r\n" - "<html>\r\n" - "<head>\r\n" - " <title>GPS Clock</title>\r\n" - "</head>\r\n" - "<body>\r\n" - " Hello World, this is the GPS Clock.\r\n" - "</body>\r\n" - "</html>\r\n"; - int len = strlen(pHtml) - position; - if (len <= 0) return 0; - strcpy(pData, pHtml); - return strlen(pHtml); + const char *pA = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Connection: close\r\n" + "Cache-control: no-cache\r\n" + "Date: "; + + char pB[HTTP_DATE_LENGTH]; + dateHeaderFromNow(pB); + + const char* pC = "\r\n" + "\r\n" + "<html>\r\n" + "<head>\r\n" + " <meta name='viewport' content='width=device-width, initial-scale=1'>\r\n" + " <link rel='icon' href='/favicon.ico' type='image/x-icon'/>\r\n" + " <link rel='stylesheet' href='/gps.css' type='text/css' />\r\n" + " <title>GPS Clock</title>\r\n" + "</head>\r\n" + "<body>\r\n"; + + char pD[400]; + addNav(pD, HOME_PAGE); + + const char* pE = "\r\n" + "<h1>GPS Clock</h1>\r\n" + "<h2>ARP</h2>\r\n" + "<code>"; + + char pF[400]; + ArpAsString(400, pF); + + const char* pG = "</code>\r\n" + "</body>\r\n" + "</html>\r\n"; + + int lA = strlen(pA); + int lB = lA + HTTP_DATE_LENGTH; + int lC = lB + strlen(pC); + int lD = lC + strlen(pD); + int lE = lD + strlen(pE); + int lF = lE + strlen(pF); + int lG = lF + strlen(pG); + + char* p = pData; + for (int i = position; i < position + mss; i++) + { + if (i < lA) *p++ = pA[i]; + else if (i < lB) *p++ = pB[i - lA]; + else if (i < lC) *p++ = pC[i - lB]; + else if (i < lD) *p++ = pD[i - lC]; + else if (i < lE) *p++ = pE[i - lD]; + else if (i < lF) *p++ = pF[i - lE]; + else if (i < lG) *p++ = pG[i - lF]; + else break; + } + return p - pData; +} +int sendCss(int position, int mss, char* pData) +{ + const char *pA = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/css; charset=UTF-8\r\n" + "Connection: close\r\n" + "Cache-Control: max-age=3600\r\n" + "Date: "; + + char pB[HTTP_DATE_LENGTH]; + dateHeaderFromNow(pB); + + const char *pC = "\r\n" + "Last-Modified: "; + + char pD[HTTP_DATE_LENGTH]; + dateHeaderFromDateTime(CssDate, CssTime, pD); + const char *pE = "\r\n\r\n"; + + const char *pF = Css; + + int lA = strlen(pA); + int lB = lA + HTTP_DATE_LENGTH; + int lC = lB + strlen(pC); + int lD = lC + HTTP_DATE_LENGTH; + int lE = lD + strlen(pE); + int lF = lE + strlen(pF); + + char* p = pData; + for (int i = position; i < position + mss; i++) + { + if (i < lA) *p++ = pA[i]; + else if (i < lB) *p++ = pB[i - lA]; + else if (i < lC) *p++ = pC[i - lB]; + else if (i < lD) *p++ = pD[i - lC]; + else if (i < lE) *p++ = pE[i - lD]; + else if (i < lF) *p++ = pF[i - lE]; + else break; + } + return p - pData; } +int sendFavicon(int position, int mss, char* pData) +{ + const char* pA = "HTTP/1.1 200 OK\r\n" + "Content-Type: image/x-icon\r\n" + "Connection: close\r\n" + "Cache-Control: max-age=3600\r\n" + "Date: "; + + char pB[HTTP_DATE_LENGTH]; + dateHeaderFromNow(pB); + + const char *pC = "\r\n" + "Last-Modified: "; + + char pD[HTTP_DATE_LENGTH]; + dateHeaderFromDateTime(FaviconDate, FaviconTime, pD); + + const char *pE = "\r\n\r\n"; + + const char *pF = Favicon; + + int lA = strlen(pA); + int lB = lA + HTTP_DATE_LENGTH; + int lC = lB + strlen(pC); + int lD = lC + HTTP_DATE_LENGTH; + int lE = lD + strlen(pE); + int lF = lE + FaviconSize; + + char* p = pData; + for (int i = position; i < position + mss; i++) + { + if (i < lA) *p++ = pA[i]; + else if (i < lB) *p++ = pB[i - lA]; + else if (i < lC) *p++ = pC[i - lB]; + else if (i < lD) *p++ = pD[i - lC]; + else if (i < lE) *p++ = pE[i - lD]; + else if (i < lF) *p++ = pF[i - lE]; + else break; + } + return p - pData; +} +int HttpResponse(int position, int mss, char *pData, int todo) +{ + switch (todo) + { + case DO_NOT_FOUND: return sendNotFound(position, mss, pData); + case DO_HTML: return sendHtml (position, mss, pData); + case DO_CSS: return sendCss (position, mss, pData); + case DO_FAVICON: return sendFavicon (position, mss, pData); + } + return 0; +}