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

http.cpp

Committer:
andrewboyson
Date:
2017-01-27
Revision:
2:849103b5a16d
Parent:
1:5f70c361db20
Child:
3:ab6fd66d172c

File content as of revision 2:849103b5a16d:

#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);
}



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 sendHtml(int position, int mss, char* pData)
{
    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;
}