aa
Dependents: Internet-Piano_WIZwiki-W7500
Fork of httpServer by
HTTPConnection.cpp@0:e59cc54df17c, 2015-06-29 (annotated)
- Committer:
- hjjeon
- Date:
- Mon Jun 29 09:03:40 2015 +0000
- Revision:
- 0:e59cc54df17c
httpServer
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hjjeon | 0:e59cc54df17c | 1 | /* HTTPConnection.cpp */ |
hjjeon | 0:e59cc54df17c | 2 | |
hjjeon | 0:e59cc54df17c | 3 | #include "mbed.h" |
hjjeon | 0:e59cc54df17c | 4 | #include "HTTPConnection.h" |
hjjeon | 0:e59cc54df17c | 5 | //#define DEBUG |
hjjeon | 0:e59cc54df17c | 6 | #include "hl_debug.h" |
hjjeon | 0:e59cc54df17c | 7 | |
hjjeon | 0:e59cc54df17c | 8 | #include <vector> |
hjjeon | 0:e59cc54df17c | 9 | using std::vector; |
hjjeon | 0:e59cc54df17c | 10 | |
hjjeon | 0:e59cc54df17c | 11 | using std::string; |
hjjeon | 0:e59cc54df17c | 12 | |
hjjeon | 0:e59cc54df17c | 13 | |
hjjeon | 0:e59cc54df17c | 14 | |
hjjeon | 0:e59cc54df17c | 15 | const struct HTTPRequestConfig { |
hjjeon | 0:e59cc54df17c | 16 | const char* request_string; |
hjjeon | 0:e59cc54df17c | 17 | HTTPRequestType request_type; |
hjjeon | 0:e59cc54df17c | 18 | } g_requestConfig[] = { |
hjjeon | 0:e59cc54df17c | 19 | { "GET", HTTP_RT_GET }, |
hjjeon | 0:e59cc54df17c | 20 | { "POST", HTTP_RT_POST}, |
hjjeon | 0:e59cc54df17c | 21 | { "PUT", HTTP_RT_PUT}, |
hjjeon | 0:e59cc54df17c | 22 | { "OPTIONS",HTTP_RT_OPTIONS}, |
hjjeon | 0:e59cc54df17c | 23 | { "HEAD", HTTP_RT_HEAD}, |
hjjeon | 0:e59cc54df17c | 24 | { "DELETE", HTTP_RT_DELETE}, |
hjjeon | 0:e59cc54df17c | 25 | { "TRACE", HTTP_RT_TRACE}, |
hjjeon | 0:e59cc54df17c | 26 | { "CONNECT",HTTP_RT_CONNECT} |
hjjeon | 0:e59cc54df17c | 27 | }; |
hjjeon | 0:e59cc54df17c | 28 | |
hjjeon | 0:e59cc54df17c | 29 | |
hjjeon | 0:e59cc54df17c | 30 | HTTPConnection::HTTPConnection(TCPSocketConnection& clnt) : m_Tcp(clnt) |
hjjeon | 0:e59cc54df17c | 31 | { |
hjjeon | 0:e59cc54df17c | 32 | } |
hjjeon | 0:e59cc54df17c | 33 | |
hjjeon | 0:e59cc54df17c | 34 | |
hjjeon | 0:e59cc54df17c | 35 | HTTPConnection::~HTTPConnection() |
hjjeon | 0:e59cc54df17c | 36 | { |
hjjeon | 0:e59cc54df17c | 37 | close(); |
hjjeon | 0:e59cc54df17c | 38 | } |
hjjeon | 0:e59cc54df17c | 39 | |
hjjeon | 0:e59cc54df17c | 40 | void HTTPConnection::close() |
hjjeon | 0:e59cc54df17c | 41 | { |
hjjeon | 0:e59cc54df17c | 42 | m_Msg.headers.clear(); |
hjjeon | 0:e59cc54df17c | 43 | } |
hjjeon | 0:e59cc54df17c | 44 | |
hjjeon | 0:e59cc54df17c | 45 | int HTTPConnection::poll() |
hjjeon | 0:e59cc54df17c | 46 | { |
hjjeon | 0:e59cc54df17c | 47 | static char buffer[256] = {}; |
hjjeon | 0:e59cc54df17c | 48 | int rcvd= 0; |
hjjeon | 0:e59cc54df17c | 49 | int ret = 0; |
hjjeon | 0:e59cc54df17c | 50 | int attri_len = 0; |
hjjeon | 0:e59cc54df17c | 51 | |
hjjeon | 0:e59cc54df17c | 52 | INFO("Waiting for new data in connection"); |
hjjeon | 0:e59cc54df17c | 53 | // Try receiving request line |
hjjeon | 0:e59cc54df17c | 54 | rcvd = receiveLine(buffer, 255, 3000); |
hjjeon | 0:e59cc54df17c | 55 | if (rcvd == -1) { |
hjjeon | 0:e59cc54df17c | 56 | // there was an error, probably the connection was closed, so close this connection as well |
hjjeon | 0:e59cc54df17c | 57 | INFO("No more data available. Will close this connection now."); |
hjjeon | 0:e59cc54df17c | 58 | close(); |
hjjeon | 0:e59cc54df17c | 59 | return -1; |
hjjeon | 0:e59cc54df17c | 60 | } |
hjjeon | 0:e59cc54df17c | 61 | |
hjjeon | 0:e59cc54df17c | 62 | // The Request has not yet been received so try it |
hjjeon | 0:e59cc54df17c | 63 | rcvd = parse(buffer); |
hjjeon | 0:e59cc54df17c | 64 | if (rcvd == -1) { |
hjjeon | 0:e59cc54df17c | 65 | // Invalid content received, so close the connection |
hjjeon | 0:e59cc54df17c | 66 | INFO("Invalid message received, so sending negative response and closing connection !"); |
hjjeon | 0:e59cc54df17c | 67 | //sprintf(buffer,"HTTP/1.1 400 BadRequest\n\rContent-Length: %d\n\rContent-Type: text\n\r\n\r\n\r",0); |
hjjeon | 0:e59cc54df17c | 68 | m_Tcp.set_blocking(true, 1500); |
hjjeon | 0:e59cc54df17c | 69 | //m_Tcp.send(buffer,strlen(buffer)); |
hjjeon | 0:e59cc54df17c | 70 | close(); |
hjjeon | 0:e59cc54df17c | 71 | rcvd = -1; |
hjjeon | 0:e59cc54df17c | 72 | return -1; |
hjjeon | 0:e59cc54df17c | 73 | } |
hjjeon | 0:e59cc54df17c | 74 | // The request has been received, try receive the body |
hjjeon | 0:e59cc54df17c | 75 | while(rcvd > 0) { |
hjjeon | 0:e59cc54df17c | 76 | rcvd = receiveLine((char*)buffer, 255, 3000); |
hjjeon | 0:e59cc54df17c | 77 | // First check if we received an empty line. This would indicate the end of the message or message body. |
hjjeon | 0:e59cc54df17c | 78 | if (rcvd < 0) { |
hjjeon | 0:e59cc54df17c | 79 | // there was an empty line, so we can start with performing the request |
hjjeon | 0:e59cc54df17c | 80 | INFO("Request Header was received completely. Performing request."); |
hjjeon | 0:e59cc54df17c | 81 | rcvd = 0; |
hjjeon | 0:e59cc54df17c | 82 | break; |
hjjeon | 0:e59cc54df17c | 83 | } |
hjjeon | 0:e59cc54df17c | 84 | else { |
hjjeon | 0:e59cc54df17c | 85 | // add message body |
hjjeon | 0:e59cc54df17c | 86 | ret = parseHeader(buffer); |
hjjeon | 0:e59cc54df17c | 87 | if (ret == 0) { |
hjjeon | 0:e59cc54df17c | 88 | |
hjjeon | 0:e59cc54df17c | 89 | } |
hjjeon | 0:e59cc54df17c | 90 | else { |
hjjeon | 0:e59cc54df17c | 91 | attri_len = ret; |
hjjeon | 0:e59cc54df17c | 92 | } |
hjjeon | 0:e59cc54df17c | 93 | } |
hjjeon | 0:e59cc54df17c | 94 | } |
hjjeon | 0:e59cc54df17c | 95 | |
hjjeon | 0:e59cc54df17c | 96 | //Receive attribute data |
hjjeon | 0:e59cc54df17c | 97 | if( attri_len != 0 ) |
hjjeon | 0:e59cc54df17c | 98 | { |
hjjeon | 0:e59cc54df17c | 99 | m_Tcp.receive( m_Msg.attri, attri_len ); |
hjjeon | 0:e59cc54df17c | 100 | } |
hjjeon | 0:e59cc54df17c | 101 | |
hjjeon | 0:e59cc54df17c | 102 | INFO("Leaving poll function!"); |
hjjeon | 0:e59cc54df17c | 103 | return rcvd; |
hjjeon | 0:e59cc54df17c | 104 | } |
hjjeon | 0:e59cc54df17c | 105 | |
hjjeon | 0:e59cc54df17c | 106 | int HTTPConnection::receiveLine(char* szLine, int nMaxLen, int nTimeout, char cLineTerm) |
hjjeon | 0:e59cc54df17c | 107 | { |
hjjeon | 0:e59cc54df17c | 108 | if ((szLine == NULL) || (nMaxLen == 0)) |
hjjeon | 0:e59cc54df17c | 109 | return -1; |
hjjeon | 0:e59cc54df17c | 110 | |
hjjeon | 0:e59cc54df17c | 111 | szLine[0] = 0; |
hjjeon | 0:e59cc54df17c | 112 | m_Tcp.set_blocking(false); |
hjjeon | 0:e59cc54df17c | 113 | |
hjjeon | 0:e59cc54df17c | 114 | if (!m_Tcp.is_connected()) { |
hjjeon | 0:e59cc54df17c | 115 | error("NOT COnnected anymore"); |
hjjeon | 0:e59cc54df17c | 116 | return -1; |
hjjeon | 0:e59cc54df17c | 117 | } |
hjjeon | 0:e59cc54df17c | 118 | Timer tm; |
hjjeon | 0:e59cc54df17c | 119 | int i; |
hjjeon | 0:e59cc54df17c | 120 | |
hjjeon | 0:e59cc54df17c | 121 | // Try to receive up to the max number of characters |
hjjeon | 0:e59cc54df17c | 122 | for (i = 0 ; i < nMaxLen-1 ; i++) { |
hjjeon | 0:e59cc54df17c | 123 | int c; |
hjjeon | 0:e59cc54df17c | 124 | c = m_Tcp.receive( szLine + i, 1 ); |
hjjeon | 0:e59cc54df17c | 125 | // Check that - if no character was currently received - the timeout period is reached. |
hjjeon | 0:e59cc54df17c | 126 | if ((c == 0) || (c==-1)) { |
hjjeon | 0:e59cc54df17c | 127 | // no character was read, so check if operation timed out |
hjjeon | 0:e59cc54df17c | 128 | if (tm.read_ms() > nTimeout) { |
hjjeon | 0:e59cc54df17c | 129 | // Operation timed out |
hjjeon | 0:e59cc54df17c | 130 | INFO("Timeout occured in function 'receiveLine'."); |
hjjeon | 0:e59cc54df17c | 131 | return -1; |
hjjeon | 0:e59cc54df17c | 132 | } |
hjjeon | 0:e59cc54df17c | 133 | } |
hjjeon | 0:e59cc54df17c | 134 | |
hjjeon | 0:e59cc54df17c | 135 | // Check if line terminating character was received |
hjjeon | 0:e59cc54df17c | 136 | if (szLine[i] == cLineTerm) |
hjjeon | 0:e59cc54df17c | 137 | { |
hjjeon | 0:e59cc54df17c | 138 | break; |
hjjeon | 0:e59cc54df17c | 139 | } |
hjjeon | 0:e59cc54df17c | 140 | } |
hjjeon | 0:e59cc54df17c | 141 | |
hjjeon | 0:e59cc54df17c | 142 | // Terminate with \0 |
hjjeon | 0:e59cc54df17c | 143 | szLine[i] = 0; |
hjjeon | 0:e59cc54df17c | 144 | |
hjjeon | 0:e59cc54df17c | 145 | // Trim for '\r' linefeed at the end |
hjjeon | 0:e59cc54df17c | 146 | if( (i >0) && (szLine[i-1] == '\r')) { |
hjjeon | 0:e59cc54df17c | 147 | i--; |
hjjeon | 0:e59cc54df17c | 148 | szLine[i] = 0; |
hjjeon | 0:e59cc54df17c | 149 | } |
hjjeon | 0:e59cc54df17c | 150 | |
hjjeon | 0:e59cc54df17c | 151 | // return number of characters received in the line or return -2 if an empty line was received |
hjjeon | 0:e59cc54df17c | 152 | if ((i == 0) || ((i==1) &&(szLine[0] == '\r'))) |
hjjeon | 0:e59cc54df17c | 153 | { |
hjjeon | 0:e59cc54df17c | 154 | // empty line received, so return -2 |
hjjeon | 0:e59cc54df17c | 155 | return -2; |
hjjeon | 0:e59cc54df17c | 156 | } |
hjjeon | 0:e59cc54df17c | 157 | return i; |
hjjeon | 0:e59cc54df17c | 158 | } |
hjjeon | 0:e59cc54df17c | 159 | |
hjjeon | 0:e59cc54df17c | 160 | int HTTPConnection::parse(char* buffer) |
hjjeon | 0:e59cc54df17c | 161 | { |
hjjeon | 0:e59cc54df17c | 162 | // Check if buffer is invalid or its content not long enough. |
hjjeon | 0:e59cc54df17c | 163 | if ((buffer == NULL) || (strlen(buffer) < 4)) { |
hjjeon | 0:e59cc54df17c | 164 | ERR("Buffer content is invalid or too short."); |
hjjeon | 0:e59cc54df17c | 165 | return -1; |
hjjeon | 0:e59cc54df17c | 166 | } |
hjjeon | 0:e59cc54df17c | 167 | |
hjjeon | 0:e59cc54df17c | 168 | std::vector<std::string> args; |
hjjeon | 0:e59cc54df17c | 169 | args.clear(); |
hjjeon | 0:e59cc54df17c | 170 | |
hjjeon | 0:e59cc54df17c | 171 | int argno = 0; |
hjjeon | 0:e59cc54df17c | 172 | // decompose string into a list of arguments |
hjjeon | 0:e59cc54df17c | 173 | char s = 0; // current starting char |
hjjeon | 0:e59cc54df17c | 174 | int nLen = strlen(buffer)+1; |
hjjeon | 0:e59cc54df17c | 175 | |
hjjeon | 0:e59cc54df17c | 176 | |
hjjeon | 0:e59cc54df17c | 177 | //for(int i = 0; i < nLen; i++) |
hjjeon | 0:e59cc54df17c | 178 | //printf("%d : %c\r\n", i, buffer[i]); |
hjjeon | 0:e59cc54df17c | 179 | |
hjjeon | 0:e59cc54df17c | 180 | |
hjjeon | 0:e59cc54df17c | 181 | for (int i = 0 ; i < nLen ; i++) { |
hjjeon | 0:e59cc54df17c | 182 | if ((buffer[i] == ' ') || (buffer[i] == '\n') || (buffer[i] == 0)) { |
hjjeon | 0:e59cc54df17c | 183 | // new arg found |
hjjeon | 0:e59cc54df17c | 184 | buffer[i] = 0; |
hjjeon | 0:e59cc54df17c | 185 | if (argno++ == 1) { |
hjjeon | 0:e59cc54df17c | 186 | // its the uri |
hjjeon | 0:e59cc54df17c | 187 | // parse the uri args |
hjjeon | 0:e59cc54df17c | 188 | parseUriArgs(&buffer[s], m_Msg.args); |
hjjeon | 0:e59cc54df17c | 189 | } |
hjjeon | 0:e59cc54df17c | 190 | INFO("Found argument \"%s\"", &buffer[s]); |
hjjeon | 0:e59cc54df17c | 191 | args.push_back(&buffer[s]); |
hjjeon | 0:e59cc54df17c | 192 | s = i+1; |
hjjeon | 0:e59cc54df17c | 193 | } |
hjjeon | 0:e59cc54df17c | 194 | } |
hjjeon | 0:e59cc54df17c | 195 | |
hjjeon | 0:e59cc54df17c | 196 | // store the uri and the HTTP version |
hjjeon | 0:e59cc54df17c | 197 | m_Msg.uri = args[1]; |
hjjeon | 0:e59cc54df17c | 198 | m_Msg.version = args[2]; |
hjjeon | 0:e59cc54df17c | 199 | |
hjjeon | 0:e59cc54df17c | 200 | // Find matching request type |
hjjeon | 0:e59cc54df17c | 201 | for (int i = 0 ; i < sizeof(g_requestConfig)/sizeof(struct HTTPRequestConfig) ; i++) { |
hjjeon | 0:e59cc54df17c | 202 | if (args.at(0) == g_requestConfig[i].request_string) { |
hjjeon | 0:e59cc54df17c | 203 | m_Msg.request = g_requestConfig[i].request_type; |
hjjeon | 0:e59cc54df17c | 204 | } |
hjjeon | 0:e59cc54df17c | 205 | } |
hjjeon | 0:e59cc54df17c | 206 | args.clear(); |
hjjeon | 0:e59cc54df17c | 207 | |
hjjeon | 0:e59cc54df17c | 208 | return 1; |
hjjeon | 0:e59cc54df17c | 209 | } |
hjjeon | 0:e59cc54df17c | 210 | |
hjjeon | 0:e59cc54df17c | 211 | |
hjjeon | 0:e59cc54df17c | 212 | int HTTPConnection::parseHeader(char *buffer) |
hjjeon | 0:e59cc54df17c | 213 | { |
hjjeon | 0:e59cc54df17c | 214 | // Check if the buffer is invalid or if the content is too short to be meaningful |
hjjeon | 0:e59cc54df17c | 215 | if ((strlen(buffer) <3) || (buffer == NULL)) |
hjjeon | 0:e59cc54df17c | 216 | return -1; |
hjjeon | 0:e59cc54df17c | 217 | |
hjjeon | 0:e59cc54df17c | 218 | //Find Content length |
hjjeon | 0:e59cc54df17c | 219 | if(strncmp(buffer, "Content-Length", 14) == 0) |
hjjeon | 0:e59cc54df17c | 220 | { |
hjjeon | 0:e59cc54df17c | 221 | m_Msg.attri_len = atoi(&buffer[16]); |
hjjeon | 0:e59cc54df17c | 222 | return m_Msg.attri_len; |
hjjeon | 0:e59cc54df17c | 223 | } |
hjjeon | 0:e59cc54df17c | 224 | /* |
hjjeon | 0:e59cc54df17c | 225 | for (int i = 0 ; i < buflen ; i++) { |
hjjeon | 0:e59cc54df17c | 226 | if (buffer[i] == ':') { |
hjjeon | 0:e59cc54df17c | 227 | // touple found |
hjjeon | 0:e59cc54df17c | 228 | buffer[i] = 0; |
hjjeon | 0:e59cc54df17c | 229 | value_start = i+1; |
hjjeon | 0:e59cc54df17c | 230 | m_Msg.headers[buffer] = &buffer[value_start]; |
hjjeon | 0:e59cc54df17c | 231 | |
hjjeon | 0:e59cc54df17c | 232 | INFO("Header name=\"%s\" : value=\"%s\".", buffer, &buffer[value_start]); |
hjjeon | 0:e59cc54df17c | 233 | return 0; |
hjjeon | 0:e59cc54df17c | 234 | } |
hjjeon | 0:e59cc54df17c | 235 | } |
hjjeon | 0:e59cc54df17c | 236 | */ |
hjjeon | 0:e59cc54df17c | 237 | return 0; |
hjjeon | 0:e59cc54df17c | 238 | //ERR("Did not recieve a valid header : \"%s\".", buffer); |
hjjeon | 0:e59cc54df17c | 239 | //return -1; |
hjjeon | 0:e59cc54df17c | 240 | } |
hjjeon | 0:e59cc54df17c | 241 | |
hjjeon | 0:e59cc54df17c | 242 | int HTTPConnection::parseUriArgs(char *buffer, map<string,string>&args) |
hjjeon | 0:e59cc54df17c | 243 | { |
hjjeon | 0:e59cc54df17c | 244 | // Check if the buffer is invalid or if the content is too short to be meaningful |
hjjeon | 0:e59cc54df17c | 245 | if ((strlen(buffer) <3) || (buffer == NULL)) |
hjjeon | 0:e59cc54df17c | 246 | return -1; |
hjjeon | 0:e59cc54df17c | 247 | |
hjjeon | 0:e59cc54df17c | 248 | int args_start = -1; |
hjjeon | 0:e59cc54df17c | 249 | int value_start = -1; |
hjjeon | 0:e59cc54df17c | 250 | int buflen = strlen(buffer) +1; |
hjjeon | 0:e59cc54df17c | 251 | const char* argname = NULL; |
hjjeon | 0:e59cc54df17c | 252 | const char* valuename = NULL; |
hjjeon | 0:e59cc54df17c | 253 | for (int i = 0; i < buflen ; i++) { |
hjjeon | 0:e59cc54df17c | 254 | if (args_start == -1) { // args section not yet found |
hjjeon | 0:e59cc54df17c | 255 | if (buffer[i] == '?') { // starts with a question mark, so got it |
hjjeon | 0:e59cc54df17c | 256 | buffer[i] = 0; |
hjjeon | 0:e59cc54df17c | 257 | args_start = i; // set the start of the args section |
hjjeon | 0:e59cc54df17c | 258 | INFO("Argument section found !"); |
hjjeon | 0:e59cc54df17c | 259 | } |
hjjeon | 0:e59cc54df17c | 260 | } |
hjjeon | 0:e59cc54df17c | 261 | else { // search arg-value touples |
hjjeon | 0:e59cc54df17c | 262 | if (argname == NULL) { // arg-name found ? |
hjjeon | 0:e59cc54df17c | 263 | if (buffer[i] == '=') { |
hjjeon | 0:e59cc54df17c | 264 | // yes, separate the arg-name |
hjjeon | 0:e59cc54df17c | 265 | buffer[i] = 0; |
hjjeon | 0:e59cc54df17c | 266 | argname = &buffer[args_start]; |
hjjeon | 0:e59cc54df17c | 267 | value_start = i+1; |
hjjeon | 0:e59cc54df17c | 268 | INFO("Argument name %s", argname); |
hjjeon | 0:e59cc54df17c | 269 | } |
hjjeon | 0:e59cc54df17c | 270 | } |
hjjeon | 0:e59cc54df17c | 271 | else { // search for end of value |
hjjeon | 0:e59cc54df17c | 272 | if ((buffer[i] == '&') || (buffer[i] == 0) || (buffer[i] == '\r') || (buffer[i] == '\n')) { |
hjjeon | 0:e59cc54df17c | 273 | buffer[i] = 0; |
hjjeon | 0:e59cc54df17c | 274 | valuename = &buffer[value_start]; |
hjjeon | 0:e59cc54df17c | 275 | INFO("Argument value %s", valuename); |
hjjeon | 0:e59cc54df17c | 276 | args[argname] = valuename; |
hjjeon | 0:e59cc54df17c | 277 | // reset all indicators |
hjjeon | 0:e59cc54df17c | 278 | argname = NULL; |
hjjeon | 0:e59cc54df17c | 279 | valuename = NULL; |
hjjeon | 0:e59cc54df17c | 280 | } |
hjjeon | 0:e59cc54df17c | 281 | } |
hjjeon | 0:e59cc54df17c | 282 | } |
hjjeon | 0:e59cc54df17c | 283 | } |
hjjeon | 0:e59cc54df17c | 284 | |
hjjeon | 0:e59cc54df17c | 285 | |
hjjeon | 0:e59cc54df17c | 286 | return 0; |
hjjeon | 0:e59cc54df17c | 287 | } |