
An example HTTP Server using new Ethernet Interface and localfilesystem.
Dependencies: EthernetInterface HttpServer mbed-rpc mbed-rtos mbed
Fork of giken9_HTMLServer_Sample by
Diff: HttpServer/HTTPRequestHandler.cpp
- Revision:
- 0:7766f6712673
- Child:
- 2:14b689a85306
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HttpServer/HTTPRequestHandler.cpp Wed Mar 12 04:19:54 2014 +0000 @@ -0,0 +1,408 @@ +/* +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +//#define _DEBUG_REQUEST_HANDLER +//#pragma O0 +#include "HTTPRequestHandler.h" + +#include <string.h> + +//#define HTTP_REQUEST_TIMEOUT 5000 +//#define HTTP_POST_REQUEST_TIMEOUT 2000 +#define READ_SIZE 128 +//HTTPRequestHandler::HTTPRequestHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : NetService(), +// m_pTCPSocketConnection(pTCPSocketConnection), m_reqHeaders(), m_respHeaders(), +// m_rootPath(rootPath), m_path(path), m_errc(200), +// m_watchdog(), m_timeout(0),**/ m_closed(false), m_headersSent(false) //OK +HTTPRequestHandler::HTTPRequestHandler(const char* rootPath, const char* path, TCPSocketConnection* pTCPSocketConnection) : + m_pTCPSocketConnection(pTCPSocketConnection), /*m_reqHeaders(), m_respHeaders(),*/ + m_rootPath(rootPath), m_path(path), m_errc(200), m_closed(false), m_headersSent(false) +{ +#ifdef _DEBUG_REQUEST_HANDLER + printf("+++(HTTPRequestHandler) init \r\n"); +#endif + req_headers_count=0; + resp_headers_count=0; + //Read & parse headers + readHeaders(); +//* m_pTCPSocket->setOnEvent(this, &HTTPRequestHandler::onTCPSocketEvent); +//* setTimeout(HTTP_REQUEST_TIMEOUT); +#ifdef _DEBUG_REQUEST_HANDLER + printf("+++(HTTPRequestHandler) init end \r\n"); +#endif +} + +HTTPRequestHandler::~HTTPRequestHandler() +{ + close(); +#ifdef _DEBUG_REQUEST_HANDLER + printf("+++(HTTPRequestHandler) Destroy end\r\n"); +#endif +} + +void HTTPRequestHandler::onTimeout() //Connection has timed out +{ + close(); +} + +void HTTPRequestHandler::close() //Close socket and destroy data +{ + if(m_closed) + return; + m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else + /** m_watchdog.detach(); **/ +//* onClose(); +//* m_pTCPSocket->resetOnEvent(); +//*m_pTCPSocketConnection->close(); +//* delete m_pTCPSocketConnection; //Can safely destroy socket +//* NetService::close(); +} + +//map<string, string>& HTTPRequestHandler::reqHeaders() //const +//{ +// return m_reqHeaders; +//} +void HTTPRequestHandler::reqHeaders(string *key,string *value,unsigned char *count) //const +{ + for(int i=0; i<10; i++) { + key[i]=req_headers_key[i]; + value[i]=req_headers_value[i]; + } + *count=req_headers_count; +// return m_reqHeaders; +} + +string& HTTPRequestHandler::path() //const +{ + return m_path; +} + +int HTTPRequestHandler::dataLen() const +{ + int ret=0; + if (clength>0) ret=clength; + // map<string,string>::iterator it; + // it = m_reqHeaders.find("Content-Length"); + // if( it == m_reqHeaders.end() ) { + // return 0; + // } + // return atoi((*it).second.c_str()); //return 0 if parse fails, so that's fine + return ret; +} + +int HTTPRequestHandler::readData(char* buf, int len) +{ + return m_pTCPSocketConnection->receive(buf, len); +} + +string& HTTPRequestHandler::rootPath() //const +{ + return m_rootPath; +} + +void HTTPRequestHandler::setErrCode(int errc) +{ + m_errc = errc; +} + +void HTTPRequestHandler::setContentLen(int len) +{ + char len_str[7] = {0}; +//#ifdef _DEBUG_REQUEST_HANDLER + printf( "+++(HTTPRequestHandler)Content-Length %d \r\n", len); +//#endif + sprintf(len_str, "%d", len); +// respHeaders()["Content-Length"] = len_str; + addRespHeaders("Content-Length",string(len_str)); +} + +//map<string, string>& HTTPRequestHandler::respHeaders() +//{ +// return m_respHeaders; +//} + +void HTTPRequestHandler::respHeaders(string *key,string *value,unsigned char *count ) +{ + for(int i=0; i<10; i++) { + key[i]=resp_headers_key[i]; + value[i]=resp_headers_value[i]; + } + *count=resp_headers_count; +} + + +int HTTPRequestHandler::writeData(const char* buf, int len) +{ + if(!m_headersSent) { + m_headersSent = true; + writeHeaders(); + } + return m_pTCPSocketConnection->send((char *)buf, len); +} +/** +void HTTPRequestHandler::setTimeout(int ms) +{ + m_timeout = 1000*ms; + resetTimeout(); +} +**/ +/** +void HTTPRequestHandler::resetTimeout() +{ + m_watchdog.detach(); + m_watchdog.attach_us<HTTPRequestHandler>(this, &HTTPRequestHandler::onTimeout, m_timeout); +} +**/ + +void HTTPRequestHandler::readHeaders() +{ + static char line[128]; + static char key[128]; + static char value[128]; + int i; + char *p; + req_headers_count=0; + resp_headers_count=0; + while( readLine(line, 128) > 0) { //if == 0, it is an empty line = end of headers + int n = sscanf(line, "%[^:]: %[^\n]", key, value); + if ( n == 2 ) { +#ifdef _DEBUG_REQUEST_HANDLER + printf("+++(HTTPRequestHandler)Read header : %s : %s\r\n", key, value); +#endif + // m_reqHeaders[key] = value; + if(req_headers_count<10) { + req_headers_key[req_headers_count]=string(key); + req_headers_value[req_headers_count]=string(value); + req_headers_count++; + } + //Check Content Length + for(p=&key[0]; p<(&key[0]+strlen(key)); p++) { + if((*p>0x60)&&(*p<0x7b))*p=*p-0x20; + } +#ifdef _DEBUG_REQUEST_SERVER_H + printf("+++(HTTPRequestHandler) HEADER %s\r\n",key); +#endif + if(strcmp(key,"CONTENT-LENGTH")==0) { + sscanf(value,"%d",&clength); + } + } + //TODO: Impl n==1 case (part 2 of previous header) + } +} + +void HTTPRequestHandler::readReqData() +{ + static char key[128]; + static char value[128]; + int cont_length=0; + bool chunk=false; + char *p; + int i; + //ReadHeader +// map< string, string >::iterator it; +// for (it = m_reqHeaders.begin(); it != m_reqHeaders.end(); it++) { + for (i=0; i<req_headers_count; i++) { +// sprintf(key,"%s",(*it).first.c_str()); +// sprintf(value,"%s",(*it).second.c_str()); + sprintf(key,"%s",req_headers_key[i].c_str()); + sprintf(value,"%s",req_headers_value[i].c_str()); + for(p=&key[0]; p<(&key[0]+strlen(key)); p++) { + if((*p>0x60)&&(*p<0x7b))*p=*p-0x20; + } +#ifdef _DEBUG_REQUEST_SERVER_H + printf("+++(HTTPRequestHandler) HEADER %s\r\n",key); +#endif + if(strcmp(key,"CONTENT-LENGTH")==0) { + sscanf(value,"%d",&cont_length); + } else if(strcmp(key,"TRANSFER-ENCODING")==0) { + for(p=&value[0]; p<(&value[0]+strlen(value)); p++) { + if((*p>0x60)&&(*p<0x7b))*p=*p-0x20; + } + if(strcmp(value,"CHUNKED")==0)chunk=true; + } + } +#ifdef _DEBUG_REQUEST_SERVER_H + printf("+++(HTTPRequestHandler)content-length: %d \r\n",cont_length); + if(chunk==true)printf("+++(HTTPRequestHandler)CHUNK Transfer \r\n"); + else printf("+++(HTTPRequestHandler)NO CHUNK Transfer \r\n"); +#endif +// m_pTCPSocketConnection->set_blocking(true,HTTP_POST_REQUEST_TIMEOUT); + char buffer[READ_SIZE+1]; + if(chunk==false) { + //no chunked mode + for(;;) { + if(cont_length>READ_SIZE) { + i=m_pTCPSocketConnection->receive(buffer,READ_SIZE); + buffer[READ_SIZE]=0x0; + m_reqData.append(string(buffer)); + cont_length-=READ_SIZE; + } else { + i=m_pTCPSocketConnection->receive(buffer, cont_length); + buffer[cont_length]=0x0; + m_reqData.append(string(buffer)); + break; + } + } + if(i>0)printf("Success \r\n"); + } else { + //chunked mode + int chunk_size; + + for(;;) { + i=readLine(buffer,20); + printf("chunk :%s:\r\n",buffer); + sscanf(buffer,"%x",&chunk_size); + printf("chunk_size = %d \r\n",chunk_size); + if(chunk_size==0)break; + for(;;) { + if(chunk_size>READ_SIZE) { + i=m_pTCPSocketConnection->receive(buffer, READ_SIZE); + buffer[READ_SIZE]=0x0; + m_reqData.append(string(buffer)); + chunk_size-=READ_SIZE; + } else { + i=m_pTCPSocketConnection->receive(buffer, chunk_size); + buffer[chunk_size]=0x0; + m_reqData.append(string(buffer)); + break; + } + } + i=m_pTCPSocketConnection->receive(buffer,2); //\r\n ro read + } +// i=readLine(buffer,20);//dummy + } +// m_pTCPSocketConnection->set_blocking(false); +// while(m_pTCPSocketConnection->receive(buffer,1)>0){} +// m_pTCPSocketConnection->set_blocking(false); +// printf("%s \r\n",m_reqData.c_str()); +} + +void HTTPRequestHandler::writeHeaders() //Called at the first writeData call +{ + char line[128]= {0}; + int i; + //Response line + //printf("Hdebug e1\r\n"); + //m_pTCPSocketConnection->receive(line, 1); + //printf("%d \r\n",line[0]); + + sprintf(line, "HTTP/1.1 %d OK\r\n", m_errc); //Not a violation of the standard not to include the descriptive text + //printf("debug e2 %d:%s \r\n",strlen(line),line); + //if(m_pTCPSocketConnection->is_connected()==true) { + // printf("Connect \r\n"); + //} else { + // printf("disconnected \r\n"); + //} + //return; + m_pTCPSocketConnection->send(line, strlen(line)); +// map<string,string>::iterator it; + //printf("%d debug e3 \r\n",resp_headers_count); + for(i=0; i<resp_headers_count; i++) { +// while( !m_respHeaders.empty() ) { +// it = m_respHeaders.begin(); +// sprintf(line, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() ); +// printf("debug e\r\n"); + sprintf(line, "%s: %s\r\n", resp_headers_key[i].c_str(),resp_headers_value[i].c_str()); +// printf("debug e2 %s %d\r\n",line,strlen(line)); +#ifdef _DEBUG_REQUEST_HANDLER + printf("\r\n+++(HTTPRequestHandler)Write header %s \r\n", line); +#endif + m_pTCPSocketConnection->send(line, strlen(line)); +// m_respHeaders.erase(it); + } + m_pTCPSocketConnection->send("\r\n",2); //End of head +} + +void HTTPRequestHandler::addRespHeaders(string key,string value) +{ + if(resp_headers_count<10) { + resp_headers_key[resp_headers_count]=string(key); + resp_headers_value[resp_headers_count]=string(value); + resp_headers_count++; + } else { + printf("MAX over resp_headers_num \r\n"); + } +} + +int HTTPRequestHandler::readLine(char* str, int maxLen) +{ + int ret; + int len = 0; + for(int i = 0; i < maxLen - 1; i++) { + ret = m_pTCPSocketConnection->receive(str, 1); + if(!ret) { + break; + } + if( (len > 1) && *(str-1)=='\r' && *str=='\n' ) { + str--; + len-=2; + break; + } else if( *str=='\n' ) { + len--; + break; + } + str++; + len++; + } + *str = 0; + return len; +} +/** +void HTTPRequestHandler::onTCPSocketEvent(TCPSocketEvent e) +{ + //printf("\r\nEvent %d in HTTPRequestHandler\r\n", e); + printf("\r\n+++(HTTPRequestHandler)Event in HTTPRequestHandler\r\n"); + + if(m_closed) + { + printf("\r\n+++(HTTPRequestHandler)WARN: Discarded\r\n"); + return; + } + + switch(e) + { + case TCPSOCKET_READABLE: + resetTimeout(); + onReadable(); + break; + case TCPSOCKET_WRITEABLE: + resetTimeout(); + onWriteable(); + break; + case TCPSOCKET_CONTIMEOUT: + case TCPSOCKET_CONRST: + case TCPSOCKET_CONABRT: + case TCPSOCKET_ERROR: + case TCPSOCKET_DISCONNECTED: + DBG("\r\nConnection error in handler\r\n"); + close(); + break; + } +} +**/ +char* HTTPRequestHandler::getAddress(void) +{ + return m_pTCPSocketConnection->get_address(); +} + +string& HTTPRequestHandler::getRequestData(void) +{ + return m_reqData; +} +