/*
* Code file containing the HTTP Daemon module.
* It supports GET (not completely implemented) and POST Request methods
*
* Author: Simon Kueppers
* Email: simon.kueppers@web.de
* Homepage: http://klinkerstein.m-faq.de
*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Copyright 2008 Simon Kueppers
* */
#include
#include "HttpD.h"
#include "../uip/uip.h"
#include "../../Hardware/Gpio.h"
#define STATE_CONNECTED 0 //Client has just connected
#define STATE_GET_G 1 //G
#define STATE_GET_GE 2 //GE
#define STATE_GET_GET 3 //GET
#define STATE_POST_P 4 //P
#define STATE_POST_PO 5 //PO
#define STATE_POST_POS 6 //POS
#define STATE_POST_POST 7 //POST
#define STATE_GOTGET 8 //Client just sent a GET request
#define STATE_GOTPOST 9 //Client just sent a POST request
#define STATE_PARSEPOST 10 //we are currently parsing the client's POST-data
#define STATE_SENDHEADER 11 //next we send him the HTTP header
#define STATE_SENDDATA 12 //followed by data
#define PARSEBYTES 59 //stop parsing POST data after 59 bytes
#define PARSE_CMD 0
#define PARSE_NUM10 1
#define PARSE_NUM1 2
#define PARSE_EQUAL 3
#define PARSE_VAL 4
#define PARSE_DELIM 5
static const prog_char
g_HtmlPageDefault[] =
"\n"
"\n"
""
"Home Automation and Security\n"
"\n"
"\n"
"\n"
"Home Automation
\n"
"\n"
"\n";
static uint16_t CopyStringP(uint8_t** ppBuffer,
const prog_char* pString)
{
uint16_t nBytes = 0;
char Character;
while ((Character = pgm_read_byte(pString)) != '\0')
{
**ppBuffer = Character;
*ppBuffer = *ppBuffer + 1;
pString = pString + 1;
nBytes++;
}
return nBytes;
}
static uint16_t CopyHttpHeader( uint8_t* pBuffer,
uint32_t nDataLen)
{
uint16_t nBytes = 0;
nBytes += CopyStringP(&pBuffer, PSTR("HTTP/1.1 200 OK"));
nBytes += CopyStringP(&pBuffer, PSTR("\r\n"));
//nBytes += CopyStringP(&pBuffer, PSTR("Content-Length:"));
//nBytes += CopyValue(&pBuffer, nDataLen);
//nBytes += CopyStringP(&pBuffer, PSTR("\r\n"));
nBytes += CopyStringP(&pBuffer, PSTR("Content-Type:text/html\r\n"));
nBytes += CopyStringP(&pBuffer, PSTR("Connection:close\r\n"));
nBytes += CopyStringP(&pBuffer, PSTR("\r\n"));
return nBytes;
}
static uint16_t CopyHttpData( uint8_t* pBuffer,
const prog_void** ppData,
uint32_t* pDataLeft,
uint16_t nMaxBytes)
{
uint16_t nBytes = 0;
uint8_t nByte;
uint8_t nParsedNum;
uint8_t nParsedMode;
while (nMaxBytes--)
{
if (*pDataLeft > 0)
{
nByte = pgm_read_byte(*ppData);
if (nByte == '%')
{
*ppData = *ppData + 1;
*pDataLeft = *pDataLeft - 1;
nParsedMode = pgm_read_byte(*ppData);
*ppData = *ppData + 1;
*pDataLeft = *pDataLeft - 1;
nParsedNum = (pgm_read_byte(*ppData) - '0') * 10;
*ppData = *ppData + 1;
*pDataLeft = *pDataLeft - 1;
nParsedNum += (pgm_read_byte(*ppData) - '0') * 1;
if (nParsedMode == 'i')
*pBuffer = GpioGetPin(nParsedNum) + '0';
else if (nParsedMode == 'o')
*pBuffer = GpioGetPort(nParsedNum) + '0';
else if (nParsedMode == 'd')
*pBuffer = GpioGetDdr(nParsedNum) + '0';
}
else
*pBuffer = nByte;
*ppData = *ppData + 1;
*pDataLeft = *pDataLeft - 1;
pBuffer++;
nBytes++;
}
else
break;
}
return nBytes;
}
void HttpDInit()
{
//Start listening on our port
uip_listen(HTONS(PORT_HTTPD));
//Set Inputs/Outputs
uint8_t i;
for (i=0; i<14; i++)
{
if (i>8)
GpioSetDdr(i, 0);
else
GpioSetDdr(i, 1);
}
}
void HttpDCall( uint8_t* pBuffer,
uint16_t nBytes,
struct tHttpD* pSocket)
{
uint16_t nBufSize;
if (uip_connected())
{
//Initialize this connection
pSocket->pData = g_HtmlPageDefault;
pSocket->nDataLeft = sizeof(g_HtmlPageDefault)-1;
pSocket->nNewlines = 0;
pSocket->nState = STATE_CONNECTED;
pSocket->nPrevBytes = 0xFFFF;
}
else if (uip_newdata() || uip_acked())
{
if (pSocket->nState == STATE_CONNECTED)
{
if (nBytes == 0)
return;
if (*pBuffer == 'G')
pSocket->nState = STATE_GET_G;
else if (*pBuffer == 'P')
pSocket->nState = STATE_POST_P;
nBytes--;
pBuffer++;
}
if (pSocket->nState == STATE_GET_G)
{
if (nBytes == 0)
return;
if (*pBuffer == 'E')
pSocket->nState = STATE_GET_GE;
nBytes--;
pBuffer++;
}
if (pSocket->nState == STATE_GET_GE)
{
if (nBytes == 0)
return;
if (*pBuffer == 'T')
pSocket->nState = STATE_GET_GET;
nBytes--;
pBuffer++;
}
if (pSocket->nState == STATE_GET_GET)
{
if (nBytes == 0)
return;
if (*pBuffer == ' ')
pSocket->nState = STATE_GOTGET;
nBytes--;
pBuffer++;
}
if (pSocket->nState == STATE_POST_P)
{
if (nBytes == 0)
return;
if (*pBuffer == 'O')
pSocket->nState = STATE_POST_PO;
nBytes--;
pBuffer++;
}
if (pSocket->nState == STATE_POST_PO)
{
if (nBytes == 0)
return;
if (*pBuffer == 'S')
pSocket->nState = STATE_POST_POS;
nBytes--;
pBuffer++;
}
if (pSocket->nState == STATE_POST_POS)
{
if (nBytes == 0)
return;
if (*pBuffer == 'T')
pSocket->nState = STATE_POST_POST;
nBytes--;
pBuffer++;
}
if (pSocket->nState == STATE_POST_POST)
{
if (nBytes == 0)
return;
if (*pBuffer == ' ')
pSocket->nState = STATE_GOTPOST;
nBytes--;
pBuffer++;
}
if (pSocket->nState == STATE_GOTPOST || pSocket->nState == STATE_GOTGET)
{
//Search for \r\n\r\n
while (nBytes != 0)
{
if (*pBuffer == '\n')
{
pSocket->nNewlines++;
}
else if (*pBuffer == '\r')
{
}
else
{
pSocket->nNewlines = 0;
}
pBuffer++;
nBytes--;
if (pSocket->nNewlines == 2)
{
//beginning found.
if (pSocket->nState == STATE_GOTPOST)
{
//Initialize Parsing variables
pSocket->nParseLeft = PARSEBYTES;
pSocket->ParseState = PARSE_CMD;
//start parsing
pSocket->nState = STATE_PARSEPOST;
}
else if (pSocket->nState == STATE_GOTGET)
{
pSocket->nState = STATE_SENDHEADER;
}
break;
}
}
}
if (pSocket->nState == STATE_PARSEPOST)
{
while (nBytes--)
{
if (pSocket->ParseState == PARSE_CMD)
{
pSocket->ParseCmd = *pBuffer;
pSocket->ParseState = PARSE_NUM10;
}
else if (pSocket->ParseState == PARSE_NUM10)
{
pSocket->ParseNum = (*pBuffer - '0') * 10;
pSocket->ParseState = PARSE_NUM1;
}
else if (pSocket->ParseState == PARSE_NUM1)
{
pSocket->ParseNum += (*pBuffer - '0');
pSocket->ParseState = PARSE_EQUAL;
}
else if (pSocket->ParseState == PARSE_EQUAL)
{
pSocket->ParseState = PARSE_VAL;
}
else if (pSocket->ParseState == PARSE_VAL)
{
if (pSocket->ParseCmd == 'd')
GpioSetDdr(pSocket->ParseNum, *pBuffer - '0');
else
GpioSetPort(pSocket->ParseNum, *pBuffer - '0');
pSocket->ParseState = PARSE_DELIM;
}
else if (pSocket->ParseState == PARSE_DELIM)
{
pSocket->ParseState = PARSE_CMD;
}
pSocket->nParseLeft--;
pBuffer++;
if (pSocket->nParseLeft == 0)
{
//finished parsing
pSocket->nState = STATE_SENDHEADER;
break;
}
}
}
if (pSocket->nState == STATE_SENDHEADER)
{
uip_send(uip_appdata, CopyHttpHeader(uip_appdata, pSocket->nDataLeft));
pSocket->nState = STATE_SENDDATA;
return;
}
if (pSocket->nState == STATE_SENDDATA)
{
//We have sent the HTML Header or HTML Data previously.
//Now we send (further) Data depending on the Socket's pData pointer
//If all data has been sent, we close the connection
pSocket->nPrevBytes = pSocket->nDataLeft;
nBufSize
= CopyHttpData(uip_appdata, &pSocket->pData, &pSocket->nDataLeft, uip_mss());
pSocket->nPrevBytes -= pSocket->nDataLeft;
if (nBufSize == 0)
{
//No Data has been copied. Close connection
uip_close();
}
else
{
//Else send copied data
uip_send(uip_appdata, nBufSize);
}
return;
}
}
else if (uip_rexmit())
{
if (pSocket->nPrevBytes == 0xFFFF)
{
/* Send header again */
uip_send(uip_appdata, CopyHttpHeader(uip_appdata, pSocket->nDataLeft));
}else
{
pSocket->pData -= pSocket->nPrevBytes;
pSocket->nDataLeft += pSocket->nPrevBytes;
pSocket->nPrevBytes = pSocket->nDataLeft;
nBufSize
= CopyHttpData(uip_appdata, &pSocket->pData, &pSocket->nDataLeft, uip_mss());
pSocket->nPrevBytes -= pSocket->nDataLeft;
if (nBufSize == 0)
{
//No Data has been copied. Close connection
uip_close();
}
else
{
//Else send copied data
uip_send(uip_appdata, nBufSize);
}
}
return;
}
}