/*
* 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_GOTGET 1 //Client just sent a GET request
#define STATE_GOTPOST 2 //Client just sent a POST request
#define STATE_POSTPARSE 3 //we are currently parsing the client's POST-data
#define STATE_SENDHEADER 4 //next we send him the HTTP header
#define STATE_SENDDATA 5 //followed by data
#define PARSEBYTES 167 //stop parsing POST data after 167 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[] =
""
""
"uWebSrv"
""
""
"uWebSrv
"
""
"";
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 CopyValue( uint8_t** ppBuffer,
uint32_t nValue)
{
static PROGMEM int32_t nDecTab[] =
{
1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10,
1, 0 };
int32_t nDec;
uint8_t nCurTabIndex = 0;
char cNumber;
uint8_t nBytes = 0;
while ((nDec = pgm_read_dword(&nDecTab[nCurTabIndex])) != 0)
{
for (cNumber='0'; cNumber<'9'; cNumber++)
{
int32_t nTmp = nValue - nDec;
if (nTmp < 0)
break;
nValue = nTmp;
}
**ppBuffer = cNumber;
*ppBuffer = *ppBuffer + 1;
nBytes++;
nCurTabIndex++;
}
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));
}
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;
}
else if (uip_newdata() || uip_acked())
{
if (pSocket->nState == STATE_CONNECTED)
{
if (nBytes > 6)
{
if (pBuffer[0] == 'G' && pBuffer[1] == 'E' && pBuffer[2] == 'T')
{
pSocket->nState = STATE_GOTGET;
}
else if (pBuffer[0] == 'P' && pBuffer[1] == 'O' && pBuffer[2]
== 'S' && pBuffer[3] == 'T')
{
pSocket->nState = STATE_GOTPOST;
}
}
}
if (pSocket->nState == STATE_GOTGET)
{
pSocket->nState = STATE_SENDHEADER;
}
if (pSocket->nState == STATE_GOTPOST)
{
//Search for beginning of POST data
while (nBytes != 0)
{
if (*pBuffer == '\n')
{
pSocket->nNewlines++;
}
else if (*pBuffer == '\r')
{
}
else
{
pSocket->nNewlines = 0;
}
pBuffer++;
nBytes--;
if (pSocket->nNewlines == 2)
{
//beginning found.
//Initialize Parsing variables
pSocket->nParseLeft = PARSEBYTES;
pSocket->ParseState = PARSE_CMD;
//start parsing
pSocket->nState = STATE_POSTPARSE;
break;
}
}
}
if (pSocket->nState == STATE_POSTPARSE)
{
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
nBufSize
= CopyHttpData(uip_appdata, &pSocket->pData, &pSocket->nDataLeft, uip_mss());
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())
{
//We will implement this later, maybe
uip_abort();
}
}