Adaptation of the HttpServer by user yueee_yt. This version has improved handling of the HTTP headers (**NOTE**: There are limitations with this implementation and it is not fully functional. Use it only as a starting point.)

Dependents:   DMSupport DMSupport DMSupport DMSupport

Fork of DM_HttpServer by EmbeddedArtists AB

Committer:
embeddedartists
Date:
Tue Dec 02 15:04:43 2014 +0000
Revision:
6:7b3320c34654
Parent:
4:1b6b021ee21d
Child:
8:5779cee2e94a
Fixed stack sizes so that FSHandler works. Changed printfs to RtosLog. Changed sprintf to snprintf to prevent overwrite.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
yueee_yt 0:fdf9c2c5200f 1 /*
yueee_yt 0:fdf9c2c5200f 2 Permission is hereby granted, free of charge, to any person obtaining a copy
yueee_yt 0:fdf9c2c5200f 3 of this software and associated documentation files (the "Software"), to deal
yueee_yt 0:fdf9c2c5200f 4 in the Software without restriction, including without limitation the rights
yueee_yt 0:fdf9c2c5200f 5 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
yueee_yt 0:fdf9c2c5200f 6 copies of the Software, and to permit persons to whom the Software is
yueee_yt 0:fdf9c2c5200f 7 furnished to do so, subject to the following conditions:
yueee_yt 0:fdf9c2c5200f 8
yueee_yt 0:fdf9c2c5200f 9 The above copyright notice and this permission notice shall be included in
yueee_yt 0:fdf9c2c5200f 10 all copies or substantial portions of the Software.
yueee_yt 0:fdf9c2c5200f 11
yueee_yt 0:fdf9c2c5200f 12 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
yueee_yt 0:fdf9c2c5200f 13 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
yueee_yt 0:fdf9c2c5200f 14 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
yueee_yt 0:fdf9c2c5200f 15 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
yueee_yt 0:fdf9c2c5200f 16 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
yueee_yt 0:fdf9c2c5200f 17 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
yueee_yt 0:fdf9c2c5200f 18 THE SOFTWARE.
yueee_yt 0:fdf9c2c5200f 19 */
yueee_yt 4:1b6b021ee21d 20 #ifdef _DEBUG_ALL
yueee_yt 4:1b6b021ee21d 21 #define _DEBUG_REQUEST_HANDLER
yueee_yt 4:1b6b021ee21d 22 #endif
yueee_yt 0:fdf9c2c5200f 23
yueee_yt 0:fdf9c2c5200f 24 #include "HTTPRequestHandler.h"
embeddedartists 6:7b3320c34654 25 #include "DMBoard.h"
yueee_yt 0:fdf9c2c5200f 26
yueee_yt 0:fdf9c2c5200f 27 #include <string.h>
yueee_yt 0:fdf9c2c5200f 28
yueee_yt 0:fdf9c2c5200f 29 #define HTTP_REQUEST_TIMEOUT 5000
yueee_yt 0:fdf9c2c5200f 30
yueee_yt 0:fdf9c2c5200f 31 //HTTPRequestHandler::HTTPRequestHandler(const char* rootPath, const char* path, TCPSocket* pTCPSocket) : NetService(),
yueee_yt 0:fdf9c2c5200f 32 // m_pTCPSocketConnection(pTCPSocketConnection), m_reqHeaders(), m_respHeaders(),
yueee_yt 0:fdf9c2c5200f 33 // m_rootPath(rootPath), m_path(path), m_errc(200),
yueee_yt 0:fdf9c2c5200f 34 // m_watchdog(), m_timeout(0),**/ m_closed(false), m_headersSent(false) //OK
yueee_yt 0:fdf9c2c5200f 35 HTTPRequestHandler::HTTPRequestHandler(const char* rootPath, const char* path, TCPSocketConnection* pTCPSocketConnection) :
yueee_yt 0:fdf9c2c5200f 36 m_pTCPSocketConnection(pTCPSocketConnection), m_reqHeaders(), m_respHeaders(),
yueee_yt 0:fdf9c2c5200f 37 m_rootPath(rootPath), m_path(path), m_errc(200), m_closed(false), m_headersSent(false)
yueee_yt 0:fdf9c2c5200f 38 {
yueee_yt 4:1b6b021ee21d 39 #ifdef _DEBUG_REQUEST_HANDLER
embeddedartists 6:7b3320c34654 40 DMBoard::instance().logger()->printf("+++(HTTPRequestHandler) init \r\n");
yueee_yt 4:1b6b021ee21d 41 #endif
yueee_yt 0:fdf9c2c5200f 42 //Read & parse headers
yueee_yt 0:fdf9c2c5200f 43 readHeaders();
yueee_yt 0:fdf9c2c5200f 44 //* m_pTCPSocket->setOnEvent(this, &HTTPRequestHandler::onTCPSocketEvent);
yueee_yt 0:fdf9c2c5200f 45 //* setTimeout(HTTP_REQUEST_TIMEOUT);
yueee_yt 4:1b6b021ee21d 46 #ifdef _DEBUG_REQUEST_HANDLER
embeddedartists 6:7b3320c34654 47 DMBoard::instance().logger()->printf("+++(HTTPRequestHandler) init end \r\n");
yueee_yt 4:1b6b021ee21d 48 #endif
yueee_yt 0:fdf9c2c5200f 49 }
yueee_yt 0:fdf9c2c5200f 50
yueee_yt 0:fdf9c2c5200f 51 HTTPRequestHandler::~HTTPRequestHandler()
yueee_yt 0:fdf9c2c5200f 52 {
yueee_yt 0:fdf9c2c5200f 53 close();
yueee_yt 4:1b6b021ee21d 54 #ifdef _DEBUG_REQUEST_HANDLER
embeddedartists 6:7b3320c34654 55 DMBoard::instance().logger()->printf("+++(HTTPRequestHandler) Destroy end\r\n");
yueee_yt 4:1b6b021ee21d 56 #endif
yueee_yt 0:fdf9c2c5200f 57 }
yueee_yt 0:fdf9c2c5200f 58
yueee_yt 0:fdf9c2c5200f 59 void HTTPRequestHandler::onTimeout() //Connection has timed out
yueee_yt 0:fdf9c2c5200f 60 {
yueee_yt 0:fdf9c2c5200f 61 close();
yueee_yt 0:fdf9c2c5200f 62 }
yueee_yt 0:fdf9c2c5200f 63
yueee_yt 0:fdf9c2c5200f 64 void HTTPRequestHandler::close() //Close socket and destroy data
yueee_yt 0:fdf9c2c5200f 65 {
yueee_yt 0:fdf9c2c5200f 66 if(m_closed)
yueee_yt 0:fdf9c2c5200f 67 return;
yueee_yt 0:fdf9c2c5200f 68 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
yueee_yt 0:fdf9c2c5200f 69 /** m_watchdog.detach(); **/
yueee_yt 0:fdf9c2c5200f 70 //* onClose();
yueee_yt 0:fdf9c2c5200f 71 //* m_pTCPSocket->resetOnEvent();
yueee_yt 0:fdf9c2c5200f 72 //* m_pTCPSocket->close();
yueee_yt 0:fdf9c2c5200f 73 //* delete m_pTCPSocket; //Can safely destroy socket
yueee_yt 0:fdf9c2c5200f 74 //* NetService::close();
yueee_yt 0:fdf9c2c5200f 75 }
yueee_yt 0:fdf9c2c5200f 76
yueee_yt 0:fdf9c2c5200f 77 map<string, string>& HTTPRequestHandler::reqHeaders() //const
yueee_yt 0:fdf9c2c5200f 78 {
yueee_yt 0:fdf9c2c5200f 79 return m_reqHeaders;
yueee_yt 0:fdf9c2c5200f 80 }
yueee_yt 0:fdf9c2c5200f 81
yueee_yt 0:fdf9c2c5200f 82 string& HTTPRequestHandler::path() //const
yueee_yt 0:fdf9c2c5200f 83 {
yueee_yt 0:fdf9c2c5200f 84 return m_path;
yueee_yt 0:fdf9c2c5200f 85 }
yueee_yt 0:fdf9c2c5200f 86
yueee_yt 0:fdf9c2c5200f 87 int HTTPRequestHandler::dataLen() const
yueee_yt 0:fdf9c2c5200f 88 {
yueee_yt 0:fdf9c2c5200f 89 map<string,string>::iterator it;
yueee_yt 0:fdf9c2c5200f 90 it = m_reqHeaders.find("Content-Length");
yueee_yt 0:fdf9c2c5200f 91 if( it == m_reqHeaders.end() ) {
yueee_yt 0:fdf9c2c5200f 92 return 0;
yueee_yt 0:fdf9c2c5200f 93 }
yueee_yt 0:fdf9c2c5200f 94 return atoi((*it).second.c_str()); //return 0 if parse fails, so that's fine
yueee_yt 0:fdf9c2c5200f 95 }
yueee_yt 0:fdf9c2c5200f 96
yueee_yt 0:fdf9c2c5200f 97 int HTTPRequestHandler::readData(char* buf, int len)
yueee_yt 0:fdf9c2c5200f 98 {
yueee_yt 0:fdf9c2c5200f 99 return m_pTCPSocketConnection->receive(buf, len);
yueee_yt 0:fdf9c2c5200f 100 }
yueee_yt 0:fdf9c2c5200f 101
yueee_yt 0:fdf9c2c5200f 102 string& HTTPRequestHandler::rootPath() //const
yueee_yt 0:fdf9c2c5200f 103 {
yueee_yt 0:fdf9c2c5200f 104 return m_rootPath;
yueee_yt 0:fdf9c2c5200f 105 }
yueee_yt 0:fdf9c2c5200f 106
yueee_yt 0:fdf9c2c5200f 107 void HTTPRequestHandler::setErrCode(int errc)
yueee_yt 0:fdf9c2c5200f 108 {
yueee_yt 0:fdf9c2c5200f 109 m_errc = errc;
yueee_yt 0:fdf9c2c5200f 110 }
yueee_yt 0:fdf9c2c5200f 111
yueee_yt 0:fdf9c2c5200f 112 void HTTPRequestHandler::setContentLen(int len)
yueee_yt 0:fdf9c2c5200f 113 {
yueee_yt 0:fdf9c2c5200f 114 char len_str[6] = {0};
embeddedartists 6:7b3320c34654 115 snprintf(len_str, 6, "%d", len);
yueee_yt 0:fdf9c2c5200f 116 respHeaders()["Content-Length"] = len_str;
yueee_yt 0:fdf9c2c5200f 117 }
yueee_yt 0:fdf9c2c5200f 118
yueee_yt 0:fdf9c2c5200f 119 map<string, string>& HTTPRequestHandler::respHeaders()
yueee_yt 0:fdf9c2c5200f 120 {
yueee_yt 0:fdf9c2c5200f 121 return m_respHeaders;
yueee_yt 0:fdf9c2c5200f 122 }
yueee_yt 0:fdf9c2c5200f 123
yueee_yt 0:fdf9c2c5200f 124 int HTTPRequestHandler::writeData(const char* buf, int len)
yueee_yt 0:fdf9c2c5200f 125 {
yueee_yt 0:fdf9c2c5200f 126 if(!m_headersSent) {
yueee_yt 0:fdf9c2c5200f 127 m_headersSent = true;
yueee_yt 0:fdf9c2c5200f 128 writeHeaders();
yueee_yt 0:fdf9c2c5200f 129 }
yueee_yt 0:fdf9c2c5200f 130 return m_pTCPSocketConnection->send((char *)buf, len);
yueee_yt 0:fdf9c2c5200f 131 }
yueee_yt 0:fdf9c2c5200f 132 /**
yueee_yt 0:fdf9c2c5200f 133 void HTTPRequestHandler::setTimeout(int ms)
yueee_yt 0:fdf9c2c5200f 134 {
yueee_yt 0:fdf9c2c5200f 135 m_timeout = 1000*ms;
yueee_yt 0:fdf9c2c5200f 136 resetTimeout();
yueee_yt 0:fdf9c2c5200f 137 }
yueee_yt 0:fdf9c2c5200f 138 **/
yueee_yt 0:fdf9c2c5200f 139 /**
yueee_yt 0:fdf9c2c5200f 140 void HTTPRequestHandler::resetTimeout()
yueee_yt 0:fdf9c2c5200f 141 {
yueee_yt 0:fdf9c2c5200f 142 m_watchdog.detach();
yueee_yt 0:fdf9c2c5200f 143 m_watchdog.attach_us<HTTPRequestHandler>(this, &HTTPRequestHandler::onTimeout, m_timeout);
yueee_yt 0:fdf9c2c5200f 144 }
yueee_yt 0:fdf9c2c5200f 145 **/
yueee_yt 0:fdf9c2c5200f 146
yueee_yt 0:fdf9c2c5200f 147 void HTTPRequestHandler::readHeaders()
yueee_yt 0:fdf9c2c5200f 148 {
yueee_yt 0:fdf9c2c5200f 149 static char line[128];
yueee_yt 0:fdf9c2c5200f 150 static char key[128];
yueee_yt 0:fdf9c2c5200f 151 static char value[128];
yueee_yt 0:fdf9c2c5200f 152 while( readLine(line, 128) > 0) { //if == 0, it is an empty line = end of headers
yueee_yt 0:fdf9c2c5200f 153 int n = sscanf(line, "%[^:]: %[^\n]", key, value);
yueee_yt 0:fdf9c2c5200f 154 if ( n == 2 ) {
yueee_yt 4:1b6b021ee21d 155 #ifdef _DEBUG_REQUEST_HANDLER
embeddedartists 6:7b3320c34654 156 DMBoard::instance().logger()->printf("\r\n+++(HTTPRequestHandler)Read header : %s : %s\r\n", key, value);
yueee_yt 4:1b6b021ee21d 157 #endif
yueee_yt 0:fdf9c2c5200f 158 m_reqHeaders[key] = value;
yueee_yt 0:fdf9c2c5200f 159 }
yueee_yt 0:fdf9c2c5200f 160 //TODO: Impl n==1 case (part 2 of previous header)
yueee_yt 0:fdf9c2c5200f 161 }
yueee_yt 0:fdf9c2c5200f 162 }
yueee_yt 0:fdf9c2c5200f 163
yueee_yt 0:fdf9c2c5200f 164 void HTTPRequestHandler::writeHeaders() //Called at the first writeData call
yueee_yt 0:fdf9c2c5200f 165 {
yueee_yt 0:fdf9c2c5200f 166 static char line[128];
yueee_yt 0:fdf9c2c5200f 167
yueee_yt 0:fdf9c2c5200f 168 //Response line
embeddedartists 6:7b3320c34654 169 snprintf(line, 128, "HTTP/1.1 %d MbedInfo\r\n", m_errc); //Not a violation of the standard not to include the descriptive text
yueee_yt 0:fdf9c2c5200f 170 m_pTCPSocketConnection->send(line, strlen(line));
yueee_yt 0:fdf9c2c5200f 171
yueee_yt 0:fdf9c2c5200f 172 map<string,string>::iterator it;
yueee_yt 0:fdf9c2c5200f 173 while( !m_respHeaders.empty() ) {
yueee_yt 0:fdf9c2c5200f 174 it = m_respHeaders.begin();
embeddedartists 6:7b3320c34654 175 snprintf(line, 128, "%s: %s\r\n", (*it).first.c_str(), (*it).second.c_str() );
yueee_yt 4:1b6b021ee21d 176 #ifdef _DEBUG_REQUEST_HANDLER
embeddedartists 6:7b3320c34654 177 DMBoard::instance().logger()->printf("\r\n+++(HTTPRequestHandler)%s", line);
yueee_yt 4:1b6b021ee21d 178 #endif
yueee_yt 0:fdf9c2c5200f 179 m_pTCPSocketConnection->send(line, strlen(line));
yueee_yt 0:fdf9c2c5200f 180 m_respHeaders.erase(it);
yueee_yt 0:fdf9c2c5200f 181 }
yueee_yt 0:fdf9c2c5200f 182 m_pTCPSocketConnection->send("\r\n",2); //End of head
yueee_yt 0:fdf9c2c5200f 183 }
yueee_yt 0:fdf9c2c5200f 184
yueee_yt 0:fdf9c2c5200f 185 int HTTPRequestHandler::readLine(char* str, int maxLen)
yueee_yt 0:fdf9c2c5200f 186 {
yueee_yt 0:fdf9c2c5200f 187 int ret;
yueee_yt 0:fdf9c2c5200f 188 int len = 0;
yueee_yt 0:fdf9c2c5200f 189 for(int i = 0; i < maxLen - 1; i++) {
yueee_yt 0:fdf9c2c5200f 190 ret = m_pTCPSocketConnection->receive(str, 1);
yueee_yt 0:fdf9c2c5200f 191 if(!ret) {
yueee_yt 0:fdf9c2c5200f 192 break;
yueee_yt 0:fdf9c2c5200f 193 }
yueee_yt 0:fdf9c2c5200f 194 if( (len > 1) && *(str-1)=='\r' && *str=='\n' ) {
yueee_yt 0:fdf9c2c5200f 195 str--;
yueee_yt 0:fdf9c2c5200f 196 len-=2;
yueee_yt 0:fdf9c2c5200f 197 break;
yueee_yt 0:fdf9c2c5200f 198 } else if( *str=='\n' ) {
yueee_yt 0:fdf9c2c5200f 199 len--;
yueee_yt 0:fdf9c2c5200f 200 break;
yueee_yt 0:fdf9c2c5200f 201 }
yueee_yt 0:fdf9c2c5200f 202 str++;
yueee_yt 0:fdf9c2c5200f 203 len++;
yueee_yt 0:fdf9c2c5200f 204 }
yueee_yt 0:fdf9c2c5200f 205 *str = 0;
yueee_yt 0:fdf9c2c5200f 206 return len;
yueee_yt 0:fdf9c2c5200f 207 }
yueee_yt 0:fdf9c2c5200f 208 /**
yueee_yt 0:fdf9c2c5200f 209 void HTTPRequestHandler::onTCPSocketEvent(TCPSocketEvent e)
yueee_yt 0:fdf9c2c5200f 210 {
yueee_yt 0:fdf9c2c5200f 211 //printf("\r\nEvent %d in HTTPRequestHandler\r\n", e);
yueee_yt 0:fdf9c2c5200f 212 printf("\r\n+++(HTTPRequestHandler)Event in HTTPRequestHandler\r\n");
yueee_yt 0:fdf9c2c5200f 213
yueee_yt 0:fdf9c2c5200f 214 if(m_closed)
yueee_yt 0:fdf9c2c5200f 215 {
yueee_yt 0:fdf9c2c5200f 216 printf("\r\n+++(HTTPRequestHandler)WARN: Discarded\r\n");
yueee_yt 0:fdf9c2c5200f 217 return;
yueee_yt 0:fdf9c2c5200f 218 }
yueee_yt 0:fdf9c2c5200f 219
yueee_yt 0:fdf9c2c5200f 220 switch(e)
yueee_yt 0:fdf9c2c5200f 221 {
yueee_yt 0:fdf9c2c5200f 222 case TCPSOCKET_READABLE:
yueee_yt 0:fdf9c2c5200f 223 resetTimeout();
yueee_yt 0:fdf9c2c5200f 224 onReadable();
yueee_yt 0:fdf9c2c5200f 225 break;
yueee_yt 0:fdf9c2c5200f 226 case TCPSOCKET_WRITEABLE:
yueee_yt 0:fdf9c2c5200f 227 resetTimeout();
yueee_yt 0:fdf9c2c5200f 228 onWriteable();
yueee_yt 0:fdf9c2c5200f 229 break;
yueee_yt 0:fdf9c2c5200f 230 case TCPSOCKET_CONTIMEOUT:
yueee_yt 0:fdf9c2c5200f 231 case TCPSOCKET_CONRST:
yueee_yt 0:fdf9c2c5200f 232 case TCPSOCKET_CONABRT:
yueee_yt 0:fdf9c2c5200f 233 case TCPSOCKET_ERROR:
yueee_yt 0:fdf9c2c5200f 234 case TCPSOCKET_DISCONNECTED:
yueee_yt 0:fdf9c2c5200f 235 DBG("\r\nConnection error in handler\r\n");
yueee_yt 0:fdf9c2c5200f 236 close();
yueee_yt 0:fdf9c2c5200f 237 break;
yueee_yt 0:fdf9c2c5200f 238 }
yueee_yt 0:fdf9c2c5200f 239 }
embeddedartists 6:7b3320c34654 240 **/