Compare commits

..

5 Commits

9 changed files with 277 additions and 94 deletions

View File

@ -13,15 +13,16 @@ void *CFGFileParser::parseFile()
CFGDictionary<CFGParameterValue> *dictioRef = new CFGDictionary<CFGParameterValue>; CFGDictionary<CFGParameterValue> *dictioRef = new CFGDictionary<CFGParameterValue>;
char readChar(0), *parsedParameter(NULL), *parsedValue(NULL); char readChar(0), *parsedParameter(NULL), *parsedValue(NULL);
if(!_sdCardManager.isMounted()) return NULL;
file = _sdCardManager.open(_resource); file = _sdCardManager.open(_resource);
if(!file) if(!file)
{ {
delete dictioRef; delete dictioRef;
file.close();
return NULL; return NULL;
} }
_state = INIT; _state = INIT;
while(file.available()) while(file.available())
{ {
readChar = (char)file.read(); readChar = (char)file.read();
@ -167,17 +168,18 @@ void *CFGFileParser::parseFile()
boolean CFGFileParser::save(void *data) boolean CFGFileParser::save(void *data)
{ {
if(data == NULL) if(data == NULL) return false;
return false;
Dictionary<CFGParameterValue> *ref = (Dictionary<CFGParameterValue> *) data; Dictionary<CFGParameterValue> *ref = (Dictionary<CFGParameterValue> *) data;
int truncateHere(0); uint64_t truncateHere(0);
char readChar(0); char readChar(0);
if(!_sdCardManager.isMounted()) return NULL;
File file = _sdCardManager.open(_resource, FILE_READWRITE); File file = _sdCardManager.open(_resource, FILE_READWRITE);
if(!file) if(!file)
{ {
file.close();
return false; return false;
} }
@ -187,65 +189,65 @@ boolean CFGFileParser::save(void *data)
//We find out where to truncate the file //We find out where to truncate the file
while(file.available()) while(file.available())
{ {
readChar = (char)file.read(); readChar = (char)file.read();
switch(_state) switch(_state)
{ {
case INIT: case INIT:
if(readChar == '#') if(readChar == '#')
{ {
truncateHere++; truncateHere++;
_state = COMMENT_SECTION; _state = COMMENT_SECTION;
} }
else else
_state = DONE; _state = DONE;
break; break;
case COMMENT_SECTION: case COMMENT_SECTION:
truncateHere++; truncateHere++;
if(readChar == '\n') _state = LINE_BREAK; if(readChar == '\n') _state = LINE_BREAK;
break; break;
case LINE_BREAK: case LINE_BREAK:
truncateHere++; truncateHere++;
if(readChar == '#') if(readChar == '#')
_state = COMMENT_SECTION; _state = COMMENT_SECTION;
else if(readChar == '\n') _state = DONE; else if(readChar == '\n') _state = DONE;
break; break;
} }
} }
if(!file.truncate(truncateHere)) if(!file.truncate(truncateHere))
{ {
file.close(); file.close();
return false; return false;
} }
//Let's write the settings //Let's write the settings
for(int i = 0; i < ref->count(); i++) for(int i = 0; i < ref->count(); i++)
{ {
CFGParameterValue *cfgPV = ref->getAt(i); CFGParameterValue *cfgPV = ref->getAt(i);
if(cfgPV->isQuotedParameter()) if(cfgPV->isQuotedParameter())
{ {
file.write('\''); file.write('\'');
file.print(cfgPV->getParameter()); file.print(cfgPV->getParameter());
file.write('\''); file.write('\'');
} }
else else
{ {
file.print(cfgPV->getParameter()); file.print(cfgPV->getParameter());
} }
file.print(F(" : ")); file.print(F(" : "));
if(cfgPV->isQuotedValue()) if(cfgPV->isQuotedValue())
{ {
file.write('\''); file.write('\'');
file.print(cfgPV->stringValue()); file.print(cfgPV->stringValue());
file.println('\''); file.println('\'');
} }
else else
{ {
file.println(cfgPV->stringValue()); file.println(cfgPV->stringValue());
} }
} }
file.close(); file.close();

View File

@ -7,6 +7,9 @@
#include "definition.h" #include "definition.h"
#include "CFGParameterValue.h" #include "CFGParameterValue.h"
//Forward class declaration because of cross includes...
class SDCardManager;
class CFGFileParser : public AbstractParser class CFGFileParser : public AbstractParser
{ {
public: public:

View File

@ -4,6 +4,7 @@ CFGParameterValue::CFGParameterValue():DictionaryInterface(),_parameter(NULL), _
{ {
} }
CFGParameterValue::CFGParameterValue(const char *parameter, const char *value, boolean quotedParameter, boolean quotedValue):_quotedParameter(quotedParameter), _quotedValue(quotedValue) CFGParameterValue::CFGParameterValue(const char *parameter, const char *value, boolean quotedParameter, boolean quotedValue):_quotedParameter(quotedParameter), _quotedValue(quotedValue)
{ {
_parameter = (char *) malloc((strlen(parameter) * sizeof(char)) + 1); //+1 for the string terminating character _parameter = (char *) malloc((strlen(parameter) * sizeof(char)) + 1); //+1 for the string terminating character
@ -12,6 +13,7 @@ CFGParameterValue::CFGParameterValue(const char *parameter, const char *value, b
strcpy(_parameter, parameter); strcpy(_parameter, parameter);
strcpy(_value, value); strcpy(_value, value);
} }
CFGParameterValue::CFGParameterValue(const char *parameter, const char *value):CFGParameterValue() CFGParameterValue::CFGParameterValue(const char *parameter, const char *value):CFGParameterValue()
{ {
_parameter = (char *) malloc((strlen(parameter) * sizeof(char)) + 1); //+1 for the string terminating character _parameter = (char *) malloc((strlen(parameter) * sizeof(char)) + 1); //+1 for the string terminating character
@ -20,6 +22,7 @@ CFGParameterValue::CFGParameterValue(const char *parameter, const char *value):C
strcpy(_parameter, parameter); strcpy(_parameter, parameter);
strcpy(_value, value); strcpy(_value, value);
} }
CFGParameterValue::CFGParameterValue(const CFGParameterValue &Object) CFGParameterValue::CFGParameterValue(const CFGParameterValue &Object)
{ {
_parameter = (char *) malloc((strlen(Object._parameter) * sizeof(char)) + 1); //+1 for the string terminating character _parameter = (char *) malloc((strlen(Object._parameter) * sizeof(char)) + 1); //+1 for the string terminating character
@ -31,6 +34,7 @@ CFGParameterValue::CFGParameterValue(const CFGParameterValue &Object)
_quotedParameter = Object._quotedParameter; _quotedParameter = Object._quotedParameter;
_quotedValue = Object._quotedValue; _quotedValue = Object._quotedValue;
} }
CFGParameterValue::~CFGParameterValue() CFGParameterValue::~CFGParameterValue()
{ {
free(_parameter); free(_parameter);
@ -38,3 +42,12 @@ CFGParameterValue::~CFGParameterValue()
free(_value); free(_value);
_value = NULL; _value = NULL;
} }
void CFGParameterValue::setValue(const char *value, bool isQuoted)
{
_quotedValue = isQuoted;
free(_value);_value = NULL;
_value = (char *) malloc((strlen(value) * sizeof(char)) + 1); //+1 for the string terminating character
strcpy(_value, value);
}

View File

@ -29,10 +29,11 @@ public:
const char *getParameter() const{return _parameter == NULL ? "" : _parameter;} const char *getParameter() const{return _parameter == NULL ? "" : _parameter;}
const bool isQuotedParameter()const{return _quotedParameter;} const bool isQuotedParameter()const{return _quotedParameter;}
const bool isQuotedValue()const{return _quotedValue;} const bool isQuotedValue()const{return _quotedValue;}
virtual const char *toString() virtual const char *toString()
{ {
return _value; return _value;
} }
void setValue(const char *value, bool isQuoted);
protected: protected:
private: private:
char *_parameter; char *_parameter;

View File

@ -45,3 +45,8 @@ PowerManager::PowerInfo PowerManager::getPowerInfo(const uint16_t nbOfMeasures)
return p; return p;
} }
bool PowerManager::setCpuFreq(uint8_t frequency)
{
return system_update_cpu_freq(frequency);
}

View File

@ -3,6 +3,7 @@
#include "Arduino.h" #include "Arduino.h"
#include "definition.h" #include "definition.h"
#include <user_interface.h>
class PowerManager class PowerManager
{ {
@ -20,6 +21,7 @@ class PowerManager
~PowerManager(); ~PowerManager();
PowerManager::PowerInfo getPowerInfo(const uint16_t nbOfMeasures = 5) const; PowerManager::PowerInfo getPowerInfo(const uint16_t nbOfMeasures = 5) const;
bool setCpuFreq(uint8_t frequency);
protected: protected:
PowerManager(); PowerManager();
private: private:

View File

@ -54,3 +54,9 @@ boolean SDCardManager::isMounted()
{ {
return _mounted; return _mounted;
} }
CFGDictionary<CFGParameterValue> *SDCardManager::getCFGFile(const char *cfgFile)
{
CFGFileParser cfgFileParser(*this, cfgFile);
return (CFGDictionary<CFGParameterValue> *) cfgFileParser.parseFile();
}

View File

@ -2,21 +2,29 @@
#define SDCARDMANAGER_H #define SDCARDMANAGER_H
#include <SD.h> #include <SD.h>
#include "definition.h" #include "definition.h"
#include "CFGDictionary.h"
#include "CFGParameterValue.h"
#include "CFGFileParser.h"
class SDCardManager : public SDClass class SDCardManager : public SDClass
{ {
friend class SAB; friend class SAB;
public: public:
SDCardManager(const Pin csPin, SPISettings cfg); SDCardManager(const Pin csPin, SPISettings cfg);
double getSize(const SizeUnit sizeUnit = GBYTE); double getSize(const SizeUnit sizeUnit = GBYTE);
boolean mountSD(); boolean mountSD();
void unMountSD(); void unMountSD();
boolean isMounted(); boolean isMounted();
/*
* Quick way to retrieve the keys and values of a config file.
* If you need to performe other actions on the file, you will have to use the CFGFileParser object instead
* Remember to free the returned object ie : delete
*/
CFGDictionary<CFGParameterValue> *getCFGFile(const char *cfgFile);
protected: protected:
SDCardManager(); SDCardManager();
private: private:
const Pin _csPin; const Pin _csPin;
SPISettings _spiCfg; SPISettings _spiCfg;

View File

@ -14,7 +14,7 @@ class WEBServer : public TCPServer<T>
enum HttpRequestMethod {UNDEFINED, GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH}; enum HttpRequestMethod {UNDEFINED, GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH};
enum HttpVersion {UNKNOWN, HTTP_0_9, HTTP_1_1, HTTP_1_0, HTTP_2_0}; enum HttpVersion {UNKNOWN, HTTP_0_9, HTTP_1_1, HTTP_1_0, HTTP_2_0};
enum HttpMIMEType{UNKNOWN_MIME, TEXT_PLAIN, TEXT_CSS, TEXT_HTML, TEXT_JAVASCRIPT, APPLICATION_JSON, APPLICATION_X_WWW_FORM_URLENCODED, IMAGE_PNG, IMAGE_JPEG, AUDIO_MPEG, APPLICATION_OCTET_STREAM}; enum HttpMIMEType{UNKNOWN_MIME, TEXT_PLAIN, TEXT_CSS, TEXT_HTML, TEXT_JAVASCRIPT, APPLICATION_JSON, APPLICATION_X_WWW_FORM_URLENCODED, IMAGE_PNG, IMAGE_JPEG, AUDIO_MPEG, APPLICATION_OCTET_STREAM};
enum HttpParserStatus {HTTP_VERB, HTTP_RESSOURCE, HTTP_VERSION, HTTP_PARAMS, POST_DATA}; enum HttpParserStatus {HTTP_VERB, HTTP_RESSOURCE, HTTP_VERSION, HTTP_PARAMS, POST_DATA, HEADER_PARAMS};
enum WEBClientState {ACCEPTED, QUERY_PARSED, RESPONSE_SENT, DONE}; enum WEBClientState {ACCEPTED, QUERY_PARSED, RESPONSE_SENT, DONE};
enum HTTP_CODE {_100, _101, _200, _400, _401, _403, _404, _405, _500, _501}; enum HTTP_CODE {_100, _101, _200, _400, _401, _403, _404, _405, _500, _501};
@ -48,6 +48,18 @@ class WEBServer : public TCPServer<T>
{ {
return _apiDictionary.remove(uri); return _apiDictionary.remove(uri);
} }
//Helper function used for the webApi
static void injectApiHeader(char *header, const char *contentType, char *content)
{
char *buffer = (char *)malloc(sizeof(char) * strlen(content) + 1);
if(buffer != NULL)
{
strcpy(buffer, content);
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n%s",contentType,strlen(buffer), buffer);
free(buffer);
}
}
protected: protected:
private: private:
virtual T* createNewClient(WiFiClient wc) virtual T* createNewClient(WiFiClient wc)
@ -208,12 +220,12 @@ class WEBServer : public TCPServer<T>
Serial.println((char *)client->_data); Serial.println((char *)client->_data);
#endif #endif
client->_httpParserState = HttpParserStatus::POST_DATA; client->_httpParserState = HttpParserStatus::HEADER_PARAMS;
} }
} }
break; break;
case HttpParserStatus::HTTP_PARAMS: //index.htm?var1=1&var2=2... case HttpParserStatus::HTTP_PARAMS: //index.htm?var1=1&var2=2...
if(!httpParamParser(client)) if(!httpRsrcParamParser(client))
{ {
#ifdef DEBUG_WEBS #ifdef DEBUG_WEBS
Serial.print("Resrc : ");Serial.println(client->_httpRequestData.httpResource); Serial.print("Resrc : ");Serial.println(client->_httpRequestData.httpResource);
@ -226,9 +238,62 @@ class WEBServer : public TCPServer<T>
client->_httpParserState = HttpParserStatus::HTTP_VERSION; client->_httpParserState = HttpParserStatus::HTTP_VERSION;
} }
break; break;
case HttpParserStatus::HEADER_PARAMS: //Here we parse the different header params until we arrive to \r\n\r\n
{
char *pEndLine = strstr((char *)client->_data, "\r\n");
if( pEndLine != NULL )
{
*pEndLine = '\0';
httpHeaderParamParser(client);
if(*(pEndLine+2) == '\r') //We got \r\n\r\n -> so we go to the post data section
{
client->_httpParserState = HttpParserStatus::POST_DATA;
client->freeDataBuffer((pEndLine - (char *)client->_data) +3); //client->_data must not be empty...
break;
}
//Before in the buffer : key1: value1\0\nkey2: value2
//After in the buffer : key2: value2\r\n
client->freeDataBuffer((pEndLine - (char *)client->_data) + 2);
}
else //Error : indeed, we should at least have : \r\n. We go to the next step anyway
{
client->_httpParserState = HttpParserStatus::POST_DATA;
}
}
break;
case HttpParserStatus::POST_DATA: case HttpParserStatus::POST_DATA:
switch(client->_httpRequestData.HMT)
{
case APPLICATION_X_WWW_FORM_URLENCODED:
#ifdef DEBUG_WEBS
Serial.printf("Post data : APPLICATION_X_WWW_FORM_URLENCODED\n");
Serial.printf("Post data : %s\n", client->_data);
#endif
//we parse it !
if(!httpPostParamParser(client))
{
//Parsing done!
#ifdef DEBUG_WEBS
Serial.println("Post params :");
for(int i = 0; i < client->_httpRequestData.postParams.count(); i++)
{
Serial.print(client->_httpRequestData.postParams.getParameter(i));Serial.print(" : ");Serial.println(client->_httpRequestData.postParams.getAt(i)->getString());
}
#endif
client->_WEBClientState = WEBClientState::QUERY_PARSED;
}
break;
default :
client->_WEBClientState = WEBClientState::QUERY_PARSED;
}
client->_WEBClientState = WEBClientState::QUERY_PARSED;
break; break;
default : default :
sendInfoResponse(HTTP_CODE::_500, client, "WEB server error"); sendInfoResponse(HTTP_CODE::_500, client, "WEB server error");
@ -237,7 +302,44 @@ class WEBServer : public TCPServer<T>
} }
} }
boolean httpParamParser(T *client) /*
* This function parses the header parameters in order to find particular parameters.
* For example we look for the "Content-Type" header or for the "Range: bytes=" header
*/
void httpHeaderParamParser(T *client)
{
#ifdef DEBUG_WEBS
Serial.printf("Header param : %s\n",(char *)client->_data);
#endif
//Here we check if we have interesting params
char *contentTypeP = strstr((char *)client->_data, "t-Type: application/x-www-form-urlen");
if(contentTypeP != NULL)
{
#ifdef DEBUG_WEBS
Serial.printf("Data is of type : APPLICATION_X_WWW_FORM_URLENCODED\n");
#endif
client->_httpRequestData.HMT = APPLICATION_X_WWW_FORM_URLENCODED;
}
//Range part for file downloads
/*char *startingP = strstr((char *)client->_data, "nge: bytes="), *endP = strchr((char *)client->_data, '-');
if(startingP != NULL && endP != NULL)
{
endP = '\0';
client->_range = strtoul(startingP + 11,NULL, 10);
#ifdef DEBUG_WEBS
Serial.printf("Range : %d\n", client->_range);
#endif
}*/
}
/*
* This function is here to parse resources parameters
*/
boolean httpRsrcParamParser(T *client)
{ {
char *pGetParam = strchr((char *)client->_httpRequestData.httpResource, '?'); char *pGetParam = strchr((char *)client->_httpRequestData.httpResource, '?');
@ -264,7 +366,7 @@ class WEBServer : public TCPServer<T>
*value = '\0'; *value = '\0';
client->_httpRequestData.getParams.add(client->_httpRequestData.getParamsDataPointer, new DictionaryHelper::StringEntity(key > value ? NULL : key + 1)); client->_httpRequestData.getParams.add(client->_httpRequestData.getParamsDataPointer, new DictionaryHelper::StringEntity(key > value ? NULL : key + 1));
strcpy(client->_httpRequestData.getParamsDataPointer,value+1); memmove(client->_httpRequestData.getParamsDataPointer, value+1, strlen(value+1)+1);
#ifdef DEBUG_WEBS #ifdef DEBUG_WEBS
Serial.print("Params pointer : ");Serial.println(client->_httpRequestData.getParamsDataPointer); Serial.print("Params pointer : ");Serial.println(client->_httpRequestData.getParamsDataPointer);
@ -283,13 +385,48 @@ class WEBServer : public TCPServer<T>
*value = '\0'; *value = '\0';
client->_httpRequestData.getParams.add(client->_httpRequestData.getParamsDataPointer, new DictionaryHelper::StringEntity(NULL)); client->_httpRequestData.getParams.add(client->_httpRequestData.getParamsDataPointer, new DictionaryHelper::StringEntity(NULL));
strcpy(client->_httpRequestData.getParamsDataPointer,value+1); memmove(client->_httpRequestData.getParamsDataPointer, value+1, strlen(value+1)+1);
} }
} }
else //nothing to parse or done else //nothing to parse or done
{ {
return false; return false;
} }
return true;
}
boolean httpPostParamParser(T* client)
{
if(client->_httpRequestData.postParamsDataPointer == NULL)
{
client->_httpRequestData.postParamsDataPointer = (char *)client->_data + 1;//We save the starting position of the string to parse and we ignore the \n
}
char *key = strchr(client->_httpRequestData.postParamsDataPointer, '=');
char *value = strchr(client->_httpRequestData.postParamsDataPointer, '&');
if(key == NULL && value == NULL) //Nothing to parse or done
{
return false;
}
else if(key != NULL && value == NULL) //Only one key is present
{
*key = '\0';
client->_httpRequestData.postParams.add(client->_httpRequestData.postParamsDataPointer, new DictionaryHelper::StringEntity(key+1));
return false;
}
else if(key != NULL && value != NULL)
{
*key = '\0';
*value = '\0';
client->_httpRequestData.postParams.add(client->_httpRequestData.postParamsDataPointer, new DictionaryHelper::StringEntity(key+1));
memmove(client->_httpRequestData.postParamsDataPointer, value +1, strlen(value+1) + 1);
}
else if(key == NULL && value != NULL)//Should never happen
return false;
return true;
} }
void sendDataToClient(T *client) void sendDataToClient(T *client)
@ -387,7 +524,7 @@ class WEBServer : public TCPServer<T>
return false; return false;
} }
if(client->_fileSentBytes == 0) if(client->_fileSentBytes == 0 /*&& client->_range == 0*/)
{ {
char *fileName = (char *) malloc(sizeof(char) * strlen(pageToSend.name()) + 1); char *fileName = (char *) malloc(sizeof(char) * strlen(pageToSend.name()) + 1);
@ -411,6 +548,11 @@ class WEBServer : public TCPServer<T>
client->_client.print(header); client->_client.print(header);
free(header);header = NULL; free(header);header = NULL;
} }
/*else if(client->_fileSentBytes == 0 && (!client->_range == 0))
{
client->_fileSentBytes = client->_range-500;
Serial.println("RANGE SET");
}*/
else else
{ {
pageToSend.seek(client->_fileSentBytes); pageToSend.seek(client->_fileSentBytes);
@ -438,6 +580,7 @@ class WEBServer : public TCPServer<T>
break; break;
default: //If not supported default: //If not supported
sendInfoResponse(HTTP_CODE::_500, client, "The method used is not allowed"); sendInfoResponse(HTTP_CODE::_500, client, "The method used is not allowed");
return false;
break; break;
} }
}else }else
@ -448,8 +591,10 @@ class WEBServer : public TCPServer<T>
return true; return true;
} }
/*Static helper methods*/
void sendInfoResponse(HTTP_CODE http_code, T *client, const char *message) static void sendInfoResponse(HTTP_CODE http_code, T *client, const char *message)
{ {
uint16_t code(0); uint16_t code(0);
char codeLiteral[100]; char codeLiteral[100];
@ -457,39 +602,32 @@ class WEBServer : public TCPServer<T>
{ {
case _400: case _400:
code = 400; code = 400;
strcpy_P(codeLiteral,(PGM_P)F("Bad Request")); strcpy_P(codeLiteral,PSTR("Bad Request"));
break; break;
case _404: case _404:
code = 404; code = 404;
strcpy_P(codeLiteral,(PGM_P)F("Not Found")); strcpy_P(codeLiteral,PSTR("Not Found"));
break; break;
case _403: case _403:
code = 403; code = 403;
strcpy_P(codeLiteral,(PGM_P)F("Forbidden")); strcpy_P(codeLiteral,PSTR("Forbidden"));
break; break;
case _405: case _405:
code = 405; code = 405;
strcpy_P(codeLiteral,(PGM_P)F("Method Not Allowed")); strcpy_P(codeLiteral,PSTR("Method Not Allowed"));
break; break;
case _500: case _500:
code = 500; code = 500;
strcpy_P(codeLiteral,(PGM_P)F("Internal Server Error")); strcpy_P(codeLiteral,PSTR("Internal Server Error"));
break; break;
default: default:
code = 000; code = 000;
strcpy_P(codeLiteral,(PGM_P)F("Error Not Defined")); strcpy_P(codeLiteral,PSTR("Error Not Defined"));
break; break;
} }
client->_client.printf_P(PSTR("HTTP/1.1 %d %s\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n<h1>Error %d</h1><p>%s</p>\r\n</html>"), code, codeLiteral, strlen(message) + 56 + (code != 0 ? 3:1), code , message);
client->_client.print(F("HTTP/1.1 "));client->_client.print(code);client->_client.print(F(" "));client->_client.print(codeLiteral);client->_client.print(F("\r\nContent-Type: text/html\r\nContent-Length: "));
client->_client.print(strlen(message) + 59);
client->_client.print(F("\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n<h1>Error "));client->_client.print(code);client->_client.print(F("</h1><p>"));
client->_client.print(message);
client->_client.print(F("</p>\r\n</html>"));
} }
/*Static helper methods*/
static HttpRequestMethod getHttpVerbEnumValue(const char *parseBuffer) static HttpRequestMethod getHttpVerbEnumValue(const char *parseBuffer)
{ {
if(parseBuffer == NULL)return HttpRequestMethod::UNDEFINED; if(parseBuffer == NULL)return HttpRequestMethod::UNDEFINED;
@ -523,43 +661,48 @@ class WEBServer : public TCPServer<T>
else return UNKNOWN_MIME; else return UNKNOWN_MIME;
} }
char *getHTTPHeader(HttpMIMEType httpMIMEType, unsigned long size) static char *getHTTPHeader(HttpMIMEType httpMIMEType, size_t size)
{ {
char *header = (char *) malloc(sizeof(char) + strlen("HTTP/1.1 200 OK\r\nContent-Type: \r\nContent-Length: \r\n\r\n") + 74/*Longest MIME-TYPE*/ + 10 /*Max unsigned long footprint*/ + 1); char *header = (char *) malloc(sizeof(char) /*strlen("HTTP/1.1 200 OK\r\nContent-Type: \r\nContent-Length: \r\nCache-Control: max-age=31536000\r\n\r\n")*/* (86 + 74/*Longest MIME-TYPE*/ + 10 /*Max unsigned long footprint*/ + 1));
switch(httpMIMEType) switch(httpMIMEType)
{ {
case TEXT_HTML: case TEXT_HTML:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","text/html",size); injectHeaderLayout(header,"text/html", size);
break; break;
case TEXT_CSS: case TEXT_CSS:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","text/css",size); injectHeaderLayout(header,"text/css", size);
break; break;
case TEXT_JAVASCRIPT: case TEXT_JAVASCRIPT:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","text/javascript",size); injectHeaderLayout(header,"text/javascript", size);
break; break;
case IMAGE_PNG: case IMAGE_PNG:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","image/png",size); injectHeaderLayout(header,"image/png", size);
break; break;
case IMAGE_JPEG: case IMAGE_JPEG:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","image/jpeg",size); injectHeaderLayout(header,"image/jpeg", size);
break; break;
case TEXT_PLAIN: case TEXT_PLAIN:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","text/plain",size); injectHeaderLayout(header,"text/plain", size);
break; break;
case AUDIO_MPEG: case AUDIO_MPEG:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","audio/mpeg",size); injectHeaderLayout(header,"audio/mpeg", size);
break; break;
case APPLICATION_OCTET_STREAM: case APPLICATION_OCTET_STREAM:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","application/octet-stream",size); injectHeaderLayout(header,"application/octet-stream", size);
break; break;
default: default:
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\n\r\n","application/octet-stream",size); injectHeaderLayout(header,"application/octet-stream", size);
break; break;
} }
return header; return header;
} }
static void injectHeaderLayout(char *header, const char *contentType, size_t size)
{
sprintf(header,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %lu\r\nCache-Control: max-age=31536000\r\n\r\n",contentType,size);
}
static char *getFileExtension(char *name) static char *getFileExtension(char *name)
{ {