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

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;
+}