Dependencies:   mbed

Committer:
dirkx
Date:
Sat Aug 14 15:54:31 2010 +0000
Revision:
5:8e53abda9900
Parent:
0:355018f44c9f

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dirkx 0:355018f44c9f 1
dirkx 0:355018f44c9f 2 /*
dirkx 0:355018f44c9f 3 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
dirkx 0:355018f44c9f 4
dirkx 0:355018f44c9f 5 Permission is hereby granted, free of charge, to any person obtaining a copy
dirkx 0:355018f44c9f 6 of this software and associated documentation files (the "Software"), to deal
dirkx 0:355018f44c9f 7 in the Software without restriction, including without limitation the rights
dirkx 0:355018f44c9f 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
dirkx 0:355018f44c9f 9 copies of the Software, and to permit persons to whom the Software is
dirkx 0:355018f44c9f 10 furnished to do so, subject to the following conditions:
dirkx 0:355018f44c9f 11
dirkx 0:355018f44c9f 12 The above copyright notice and this permission notice shall be included in
dirkx 0:355018f44c9f 13 all copies or substantial portions of the Software.
dirkx 0:355018f44c9f 14
dirkx 0:355018f44c9f 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
dirkx 0:355018f44c9f 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
dirkx 0:355018f44c9f 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
dirkx 0:355018f44c9f 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
dirkx 0:355018f44c9f 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
dirkx 0:355018f44c9f 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
dirkx 0:355018f44c9f 21 THE SOFTWARE.
dirkx 0:355018f44c9f 22 */
dirkx 0:355018f44c9f 23
dirkx 0:355018f44c9f 24 #include "HTTPRequestDispatcher.h"
dirkx 0:355018f44c9f 25 #include "HTTPRequestHandler.h"
dirkx 0:355018f44c9f 26 #include <string.h>
dirkx 0:355018f44c9f 27
dirkx 0:355018f44c9f 28 //#define __DEBUG
dirkx 0:355018f44c9f 29 #include "dbg/dbg.h"
dirkx 0:355018f44c9f 30
dirkx 0:355018f44c9f 31 HTTPRequestDispatcher::HTTPRequestDispatcher(HTTPServer* pSvr, TCPSocket* pTCPSocket) : NetService(), m_pSvr(pSvr), m_pTCPSocket(pTCPSocket), m_watchdog(), m_closed(false)
dirkx 0:355018f44c9f 32 {
dirkx 0:355018f44c9f 33 m_pTCPSocket->setOnEvent(this, &HTTPRequestDispatcher::onTCPSocketEvent);
dirkx 0:355018f44c9f 34 m_watchdog.attach_us<HTTPRequestDispatcher>(this, &HTTPRequestDispatcher::onTimeout, HTTP_REQUEST_TIMEOUT * 1000);
dirkx 0:355018f44c9f 35 }
dirkx 0:355018f44c9f 36
dirkx 0:355018f44c9f 37 HTTPRequestDispatcher::~HTTPRequestDispatcher()
dirkx 0:355018f44c9f 38 {
dirkx 0:355018f44c9f 39 close();
dirkx 0:355018f44c9f 40 }
dirkx 0:355018f44c9f 41
dirkx 0:355018f44c9f 42 void HTTPRequestDispatcher::dispatchRequest()
dirkx 0:355018f44c9f 43 {
dirkx 0:355018f44c9f 44 string path;
dirkx 0:355018f44c9f 45 string meth;
dirkx 0:355018f44c9f 46 HTTP_METH methCode;
dirkx 0:355018f44c9f 47
dirkx 0:355018f44c9f 48 DBG("Dispatching req\r\n");
dirkx 0:355018f44c9f 49
dirkx 0:355018f44c9f 50 if( !getRequest(&path, &meth ) )
dirkx 0:355018f44c9f 51 {
dirkx 0:355018f44c9f 52 close();
dirkx 0:355018f44c9f 53 return; //Invalid request
dirkx 0:355018f44c9f 54 }
dirkx 0:355018f44c9f 55
dirkx 0:355018f44c9f 56 if( !meth.compare("GET") )
dirkx 0:355018f44c9f 57 {
dirkx 0:355018f44c9f 58 methCode = HTTP_GET;
dirkx 0:355018f44c9f 59 }
dirkx 0:355018f44c9f 60 else if( !meth.compare("POST") )
dirkx 0:355018f44c9f 61 {
dirkx 0:355018f44c9f 62 methCode = HTTP_POST;
dirkx 0:355018f44c9f 63 }
dirkx 0:355018f44c9f 64 else if( !meth.compare("HEAD") )
dirkx 0:355018f44c9f 65 {
dirkx 0:355018f44c9f 66 methCode = HTTP_HEAD;
dirkx 0:355018f44c9f 67 }
dirkx 0:355018f44c9f 68 else
dirkx 0:355018f44c9f 69 {
dirkx 0:355018f44c9f 70 close(); //Parse error
dirkx 0:355018f44c9f 71 return;
dirkx 0:355018f44c9f 72 }
dirkx 0:355018f44c9f 73
dirkx 0:355018f44c9f 74 DBG("Looking for a handler\r\n");
dirkx 0:355018f44c9f 75
dirkx 0:355018f44c9f 76 map< string, HTTPRequestHandler*(*)(const char*, const char*, TCPSocket*) >::iterator it;
dirkx 0:355018f44c9f 77 // it = m_pSvr->m_lpHandlers.find(rootPath); //We are friends so we can do that
dirkx 0:355018f44c9f 78 // NEW CODE START:
dirkx 0:355018f44c9f 79 int root_len = 0;
dirkx 0:355018f44c9f 80 for (it = m_pSvr->m_lpHandlers.begin(); it != m_pSvr->m_lpHandlers.end(); it++)
dirkx 0:355018f44c9f 81 {
dirkx 0:355018f44c9f 82 DBG("Checking %s...\n", (*it).first.c_str());
dirkx 0:355018f44c9f 83 root_len = (*it).first.length();
dirkx 0:355018f44c9f 84 if ( root_len &&
dirkx 0:355018f44c9f 85 !path.compare( 0, root_len, (*it).first ) &&
dirkx 0:355018f44c9f 86 (path[root_len] == '/' || path[root_len] == '\0'))
dirkx 0:355018f44c9f 87 {
dirkx 0:355018f44c9f 88 DBG("Found (%s)\n", (*it).first.c_str());
dirkx 0:355018f44c9f 89 // Found!
dirkx 0:355018f44c9f 90 break; // for
dirkx 0:355018f44c9f 91 }
dirkx 0:355018f44c9f 92 }
dirkx 0:355018f44c9f 93 // NEW CODE END
dirkx 0:355018f44c9f 94 if((it == m_pSvr->m_lpHandlers.end()) && !(m_pSvr->m_lpHandlers.empty()))
dirkx 0:355018f44c9f 95 {
dirkx 0:355018f44c9f 96 DBG("Using default handler\n");
dirkx 0:355018f44c9f 97 it = m_pSvr->m_lpHandlers.end();
dirkx 0:355018f44c9f 98 it--; //Get the last element
dirkx 0:355018f44c9f 99 if( ! (((*it).first.length() == 0) || !(*it).first.compare("/")) ) //This is not the default handler
dirkx 0:355018f44c9f 100 it = m_pSvr->m_lpHandlers.end();
dirkx 0:355018f44c9f 101 root_len = 0;
dirkx 0:355018f44c9f 102 }
dirkx 0:355018f44c9f 103 if(it == m_pSvr->m_lpHandlers.end())
dirkx 0:355018f44c9f 104 {
dirkx 0:355018f44c9f 105 DBG("No handler found\n");
dirkx 0:355018f44c9f 106 close(); //No handler found
dirkx 0:355018f44c9f 107 return;
dirkx 0:355018f44c9f 108 }
dirkx 0:355018f44c9f 109
dirkx 0:355018f44c9f 110 DBG("Handler found.\r\n");
dirkx 0:355018f44c9f 111
dirkx 0:355018f44c9f 112 //HTTPRequestHandler* pHdlr = (*it).second(rootPath.c_str(), subPath.c_str(), m_pTCPSocket);
dirkx 0:355018f44c9f 113 //NEW CODE 1 LINE:
dirkx 0:355018f44c9f 114 HTTPRequestHandler* pHdlr = (*it).second((*it).first.c_str(), path.c_str() + root_len, m_pTCPSocket);
dirkx 0:355018f44c9f 115 m_pTCPSocket = NULL; //We don't own it anymore
dirkx 0:355018f44c9f 116
dirkx 0:355018f44c9f 117 switch(methCode)
dirkx 0:355018f44c9f 118 {
dirkx 0:355018f44c9f 119 case HTTP_GET:
dirkx 0:355018f44c9f 120 pHdlr->doGet();
dirkx 0:355018f44c9f 121 break;
dirkx 0:355018f44c9f 122 case HTTP_POST:
dirkx 0:355018f44c9f 123 pHdlr->doPost();
dirkx 0:355018f44c9f 124 break;
dirkx 0:355018f44c9f 125 case HTTP_HEAD:
dirkx 0:355018f44c9f 126 pHdlr->doHead();
dirkx 0:355018f44c9f 127 break;
dirkx 0:355018f44c9f 128 }
dirkx 0:355018f44c9f 129
dirkx 0:355018f44c9f 130 DBG("Req handled (or being handled)\r\n");
dirkx 0:355018f44c9f 131 close();
dirkx 0:355018f44c9f 132 }
dirkx 0:355018f44c9f 133
dirkx 0:355018f44c9f 134 void HTTPRequestDispatcher::close() //Close socket and destroy data
dirkx 0:355018f44c9f 135 {
dirkx 0:355018f44c9f 136 if(m_closed)
dirkx 0:355018f44c9f 137 return;
dirkx 0:355018f44c9f 138 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
dirkx 0:355018f44c9f 139 m_watchdog.detach();
dirkx 0:355018f44c9f 140 if(m_pTCPSocket) //m_pTCPSocket Should only be destroyed if ownership not passed to an handler
dirkx 0:355018f44c9f 141 {
dirkx 0:355018f44c9f 142 m_pTCPSocket->resetOnEvent();
dirkx 0:355018f44c9f 143 m_pTCPSocket->close();
dirkx 0:355018f44c9f 144 delete m_pTCPSocket; //This fn might have been called by this socket (through an event), so DO NOT DESTROY IT HERE
dirkx 0:355018f44c9f 145 }
dirkx 0:355018f44c9f 146 NetService::close();
dirkx 0:355018f44c9f 147 }
dirkx 0:355018f44c9f 148
dirkx 0:355018f44c9f 149
dirkx 0:355018f44c9f 150 void HTTPRequestDispatcher::onTimeout() //Connection has timed out
dirkx 0:355018f44c9f 151 {
dirkx 0:355018f44c9f 152 close();
dirkx 0:355018f44c9f 153 }
dirkx 0:355018f44c9f 154
dirkx 0:355018f44c9f 155 bool HTTPRequestDispatcher::getRequest(string* path, string* meth)
dirkx 0:355018f44c9f 156 {
dirkx 0:355018f44c9f 157 char req[128];
dirkx 0:355018f44c9f 158 char c_path[128];
dirkx 0:355018f44c9f 159 char c_meth[128];
dirkx 0:355018f44c9f 160 const int maxLen = 128;
dirkx 0:355018f44c9f 161 char* p = req;
dirkx 0:355018f44c9f 162 //Read Line
dirkx 0:355018f44c9f 163 int ret;
dirkx 0:355018f44c9f 164 int len = 0;
dirkx 0:355018f44c9f 165 for(int i = 0; i < maxLen - 1; i++)
dirkx 0:355018f44c9f 166 {
dirkx 0:355018f44c9f 167 ret = m_pTCPSocket->recv(p, 1);
dirkx 0:355018f44c9f 168 if(!ret)
dirkx 0:355018f44c9f 169 {
dirkx 0:355018f44c9f 170 break;
dirkx 0:355018f44c9f 171 }
dirkx 0:355018f44c9f 172 if( (len > 1) && *(p-1)=='\r' && *p=='\n' )
dirkx 0:355018f44c9f 173 {
dirkx 0:355018f44c9f 174 p--;
dirkx 0:355018f44c9f 175 len-=2;
dirkx 0:355018f44c9f 176 break;
dirkx 0:355018f44c9f 177 }
dirkx 0:355018f44c9f 178 else if( *p=='\n' )
dirkx 0:355018f44c9f 179 {
dirkx 0:355018f44c9f 180 len--;
dirkx 0:355018f44c9f 181 break;
dirkx 0:355018f44c9f 182 }
dirkx 0:355018f44c9f 183 p++;
dirkx 0:355018f44c9f 184 len++;
dirkx 0:355018f44c9f 185 }
dirkx 0:355018f44c9f 186 *p = 0;
dirkx 0:355018f44c9f 187
dirkx 0:355018f44c9f 188 DBG("Parsing request : %s\r\n", req);
dirkx 0:355018f44c9f 189
dirkx 0:355018f44c9f 190 ret = sscanf(req, "%s %s HTTP/%*d.%*d", c_meth, c_path);
dirkx 0:355018f44c9f 191 if(ret !=2)
dirkx 0:355018f44c9f 192 return false;
dirkx 0:355018f44c9f 193
dirkx 0:355018f44c9f 194 *meth = string(c_meth);
dirkx 0:355018f44c9f 195 // NEW CODE (old code removed):
dirkx 0:355018f44c9f 196 *path = string(c_path);
dirkx 0:355018f44c9f 197 return true;
dirkx 0:355018f44c9f 198 }
dirkx 0:355018f44c9f 199
dirkx 0:355018f44c9f 200
dirkx 0:355018f44c9f 201
dirkx 0:355018f44c9f 202 void HTTPRequestDispatcher::onTCPSocketEvent(TCPSocketEvent e)
dirkx 0:355018f44c9f 203 {
dirkx 0:355018f44c9f 204
dirkx 0:355018f44c9f 205 DBG("\r\nEvent %d\r\n", e);
dirkx 0:355018f44c9f 206
dirkx 0:355018f44c9f 207 if(m_closed)
dirkx 0:355018f44c9f 208 {
dirkx 0:355018f44c9f 209 DBG("\r\nWARN: Discarded\r\n");
dirkx 0:355018f44c9f 210 return;
dirkx 0:355018f44c9f 211 }
dirkx 0:355018f44c9f 212
dirkx 0:355018f44c9f 213 switch(e)
dirkx 0:355018f44c9f 214 {
dirkx 0:355018f44c9f 215 case TCPSOCKET_READABLE:
dirkx 0:355018f44c9f 216 m_watchdog.detach();
dirkx 0:355018f44c9f 217 m_pTCPSocket->resetOnEvent();
dirkx 0:355018f44c9f 218 //Req arrived, dispatch :
dirkx 0:355018f44c9f 219 dispatchRequest();
dirkx 0:355018f44c9f 220 break;
dirkx 0:355018f44c9f 221 case TCPSOCKET_CONTIMEOUT:
dirkx 0:355018f44c9f 222 case TCPSOCKET_CONRST:
dirkx 0:355018f44c9f 223 case TCPSOCKET_CONABRT:
dirkx 0:355018f44c9f 224 case TCPSOCKET_ERROR:
dirkx 0:355018f44c9f 225 case TCPSOCKET_DISCONNECTED:
dirkx 0:355018f44c9f 226 close();
dirkx 0:355018f44c9f 227 break;
dirkx 0:355018f44c9f 228 }
dirkx 0:355018f44c9f 229
dirkx 0:355018f44c9f 230 }