more handlers

Dependents:   bandwidth-meter-net mbedRail24v

Fork of Tiny-HTTPD by ban4jp -

Committer:
Jasper
Date:
Fri May 30 03:55:43 2014 +0000
Revision:
3:145c65ab9805
Parent:
2:905fe8dfebd6
NULL isn't always 0, we need more handlers

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 0:d18dff347122 1 /* Copyright (C) 2013 Hiroshi Suga, MIT License
okini3939 0:d18dff347122 2 *
okini3939 0:d18dff347122 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
okini3939 0:d18dff347122 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
okini3939 0:d18dff347122 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
okini3939 0:d18dff347122 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
okini3939 0:d18dff347122 7 * furnished to do so, subject to the following conditions:
okini3939 0:d18dff347122 8 *
okini3939 0:d18dff347122 9 * The above copyright notice and this permission notice shall be included in all copies or
okini3939 0:d18dff347122 10 * substantial portions of the Software.
okini3939 0:d18dff347122 11 *
okini3939 0:d18dff347122 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
okini3939 0:d18dff347122 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
okini3939 0:d18dff347122 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
okini3939 0:d18dff347122 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
okini3939 0:d18dff347122 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
okini3939 0:d18dff347122 17 */
okini3939 0:d18dff347122 18
okini3939 0:d18dff347122 19 #include "HTTPD.h"
okini3939 0:d18dff347122 20
okini3939 0:d18dff347122 21
okini3939 0:d18dff347122 22 int HTTPD::httpdFile (int id, char *dir) {
okini3939 0:d18dff347122 23 FILE *fp;
okini3939 0:d18dff347122 24 int i, len;
okini3939 0:d18dff347122 25 char buf[HTTPD_BUF_SIZE];
okini3939 0:d18dff347122 26 char file[HTTPD_CMD_SIZE];
okini3939 0:d18dff347122 27
okini3939 0:d18dff347122 28 INFO("httpdFile %d %s", id, dir);
okini3939 0:d18dff347122 29
okini3939 0:d18dff347122 30 strcpy(file, dir);
okini3939 0:d18dff347122 31 strcat(file, _state[id].filename);
okini3939 0:d18dff347122 32 if (file[strlen(file) - 1] == '/') {
okini3939 0:d18dff347122 33 strcat(file, "index.html");
okini3939 0:d18dff347122 34 }
okini3939 0:d18dff347122 35 DBG("file: %s\r\n", file);
okini3939 0:d18dff347122 36
okini3939 0:d18dff347122 37 fp = fopen(file, "r");
okini3939 0:d18dff347122 38 if (fp) {
okini3939 0:d18dff347122 39 strcpy(buf, "HTTP/1.1 200 OK\r\n");
okini3939 0:d18dff347122 40 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 41 {
okini3939 0:d18dff347122 42 // file size
okini3939 0:d18dff347122 43 i = ftell(fp);
okini3939 0:d18dff347122 44 fseek(fp, 0, SEEK_END);
okini3939 0:d18dff347122 45 len = ftell(fp);
okini3939 0:d18dff347122 46 fseek(fp, i, SEEK_SET);
okini3939 0:d18dff347122 47 }
okini3939 0:d18dff347122 48
ban4jp 2:905fe8dfebd6 49 strcpy(buf, server_name);
okini3939 0:d18dff347122 50 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 51 if (_state[id].keepalive) {
okini3939 0:d18dff347122 52 strcpy(buf, "Connection: Keep-Alive\r\n");
okini3939 0:d18dff347122 53 } else {
okini3939 0:d18dff347122 54 strcpy(buf, "Connection: close\r\n");
okini3939 0:d18dff347122 55 }
okini3939 0:d18dff347122 56 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 57 sprintf(buf, "Content-Type: %s\r\n", mimetype(file));
okini3939 0:d18dff347122 58 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 59 sprintf(buf, "Content-Length: %d\r\n\r\n", len);
okini3939 0:d18dff347122 60 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 61
okini3939 0:d18dff347122 62 for (;;) {
okini3939 0:d18dff347122 63 i = fread(buf, sizeof(char), sizeof(buf), fp);
okini3939 0:d18dff347122 64 if (i <= 0) break;
okini3939 0:d18dff347122 65 _state[id].client->send_all(buf, i);
okini3939 0:d18dff347122 66 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
okini3939 0:d18dff347122 67 if (feof(fp)) break;
okini3939 0:d18dff347122 68 #endif
okini3939 0:d18dff347122 69 }
okini3939 0:d18dff347122 70 fclose(fp);
okini3939 0:d18dff347122 71 return 0;
okini3939 0:d18dff347122 72 }
okini3939 0:d18dff347122 73
okini3939 0:d18dff347122 74 httpdError(id, 404);
okini3939 0:d18dff347122 75 return -1;
okini3939 0:d18dff347122 76 }
okini3939 0:d18dff347122 77
okini3939 0:d18dff347122 78 void HTTPD::httpdError (int id, int err) {
okini3939 0:d18dff347122 79 char buf[HTTPD_CMD_SIZE], msg[30];
okini3939 0:d18dff347122 80
okini3939 0:d18dff347122 81 switch (err) {
okini3939 0:d18dff347122 82 case 400:
okini3939 0:d18dff347122 83 strcpy(msg, "Bad Request");
okini3939 0:d18dff347122 84 break;
okini3939 0:d18dff347122 85 case 403:
okini3939 0:d18dff347122 86 strcpy(msg, "Forbidden");
okini3939 0:d18dff347122 87 break;
okini3939 0:d18dff347122 88 case 404:
okini3939 0:d18dff347122 89 strcpy(msg, "Not Found");
okini3939 0:d18dff347122 90 break;
okini3939 0:d18dff347122 91 case 500:
okini3939 0:d18dff347122 92 default:
okini3939 0:d18dff347122 93 strcpy(msg, "Internal Server Error");
okini3939 0:d18dff347122 94 break;
okini3939 0:d18dff347122 95 }
okini3939 0:d18dff347122 96 DBG("httpd error: %d %d %s\r\n", id, err, msg);
okini3939 0:d18dff347122 97
okini3939 0:d18dff347122 98 sprintf(buf, "HTTP/1.1 %d %s\r\n", err, msg);
okini3939 0:d18dff347122 99 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 100 strcpy(buf, "Content-Type: text/html\r\n\r\n");
okini3939 0:d18dff347122 101 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 102
okini3939 0:d18dff347122 103 sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg);
okini3939 0:d18dff347122 104 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 105 sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg);
okini3939 0:d18dff347122 106 _state[id].client->send_all(buf, strlen(buf));
okini3939 0:d18dff347122 107 wait_ms(100);
okini3939 0:d18dff347122 108 _state[id].client->close();
okini3939 0:d18dff347122 109 // WARN("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
okini3939 0:d18dff347122 110 // WARN("%s %s %d %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err);
okini3939 0:d18dff347122 111 }
okini3939 0:d18dff347122 112
okini3939 0:d18dff347122 113
okini3939 0:d18dff347122 114 void HTTPD::recvData (int id, char c) {
okini3939 0:d18dff347122 115
okini3939 0:d18dff347122 116 switch (_state[id].mode) {
okini3939 0:d18dff347122 117 case MODE_REQUEST:
okini3939 0:d18dff347122 118 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
okini3939 0:d18dff347122 119 _state[id].buf->flush();
okini3939 0:d18dff347122 120 _state[id].buf->queue(c);
okini3939 0:d18dff347122 121 _state[id].mode = MODE_REQSTR;
okini3939 0:d18dff347122 122 } else {
okini3939 0:d18dff347122 123 _state[id].buf->flush();
okini3939 0:d18dff347122 124 }
okini3939 0:d18dff347122 125 break;
okini3939 0:d18dff347122 126 case MODE_REQSTR:
okini3939 0:d18dff347122 127 switch (c) {
okini3939 0:d18dff347122 128 case 0:
okini3939 0:d18dff347122 129 break;
okini3939 0:d18dff347122 130 case 0x0a: // LF
okini3939 0:d18dff347122 131 case 0x0d: // CR
okini3939 0:d18dff347122 132 if (parseRequest(id)) {
okini3939 0:d18dff347122 133 _state[id].mode = MODE_REQSTR;
okini3939 0:d18dff347122 134 } else {
okini3939 0:d18dff347122 135 _state[id].mode = MODE_HEADER;
okini3939 0:d18dff347122 136 }
okini3939 0:d18dff347122 137 _state[id].enter = 0;
okini3939 0:d18dff347122 138 break;
okini3939 0:d18dff347122 139 default:
okini3939 0:d18dff347122 140 _state[id].buf->queue(c);
okini3939 0:d18dff347122 141 break;
okini3939 0:d18dff347122 142 }
okini3939 0:d18dff347122 143 break;
okini3939 0:d18dff347122 144 case MODE_HEADER:
okini3939 0:d18dff347122 145 switch (c) {
okini3939 0:d18dff347122 146 case 0:
okini3939 0:d18dff347122 147 break;
okini3939 0:d18dff347122 148 case 0x0a: // LF
okini3939 0:d18dff347122 149 case 0x0d: // CR
okini3939 0:d18dff347122 150 if (_state[id].buf->available() == 0) {
okini3939 0:d18dff347122 151 if ((_state[id].enter == 0x0d && c == 0x0a) || (_state[id].enter == 0x0a && c == 0x0a)) {
okini3939 0:d18dff347122 152 _state[id].buf->flush();
okini3939 0:d18dff347122 153 if (_state[id].websocket) {
okini3939 0:d18dff347122 154 INFO("MODE_WEBSOCKET");
okini3939 0:d18dff347122 155 acceptWebsocket(id);
okini3939 0:d18dff347122 156 _state[id].mode = MODE_WEBSOCKET;
okini3939 0:d18dff347122 157 } else
okini3939 0:d18dff347122 158 if (_state[id].length) {
okini3939 0:d18dff347122 159 INFO("MODE_BODY");
okini3939 0:d18dff347122 160 _state[id].mode = MODE_BODY;
okini3939 0:d18dff347122 161 } else {
okini3939 0:d18dff347122 162 INFO("MODE_ENTER");
okini3939 0:d18dff347122 163 _state[id].mode = MODE_ENTER;
okini3939 0:d18dff347122 164 }
okini3939 0:d18dff347122 165 }
okini3939 0:d18dff347122 166 _state[id].enter = c;
okini3939 0:d18dff347122 167 _state[id].buf->flush();
okini3939 0:d18dff347122 168 break;
okini3939 0:d18dff347122 169 }
okini3939 0:d18dff347122 170
okini3939 0:d18dff347122 171 parseHeader(id);
okini3939 0:d18dff347122 172 _state[id].enter = 0;
okini3939 0:d18dff347122 173 break;
okini3939 0:d18dff347122 174 default:
okini3939 0:d18dff347122 175 _state[id].buf->queue(c);
okini3939 0:d18dff347122 176 _state[id].enter = 0;
okini3939 0:d18dff347122 177 break;
okini3939 0:d18dff347122 178 }
okini3939 0:d18dff347122 179 break;
okini3939 0:d18dff347122 180 case MODE_BODY:
okini3939 0:d18dff347122 181 _state[id].buf->queue(c);
okini3939 0:d18dff347122 182 if (_state[id].buf->available() >= _state[id].length) {
okini3939 0:d18dff347122 183 _state[id].mode = MODE_ENTER;
okini3939 0:d18dff347122 184 }
okini3939 0:d18dff347122 185 break;
okini3939 0:d18dff347122 186 case MODE_WEBSOCKET:
okini3939 0:d18dff347122 187 case MODE_WEBSOCKET_MASK:
okini3939 0:d18dff347122 188 case MODE_WEBSOCKET_BODY:
okini3939 0:d18dff347122 189 recvWS(id, c);
okini3939 0:d18dff347122 190 break;
okini3939 0:d18dff347122 191 }
okini3939 0:d18dff347122 192
okini3939 0:d18dff347122 193 if (_state[id].mode == MODE_ENTER) {
okini3939 0:d18dff347122 194 int i = getHandler(_state[id].uri);
okini3939 0:d18dff347122 195 if (i >= 0) {
okini3939 0:d18dff347122 196 if (_handler[i].dir) {
okini3939 0:d18dff347122 197 // file
okini3939 0:d18dff347122 198 httpdFile(id, _handler[i].dir);
okini3939 0:d18dff347122 199 } else
okini3939 0:d18dff347122 200 if (_handler[i].funcCgi) {
okini3939 0:d18dff347122 201 // cgi
okini3939 0:d18dff347122 202 _handler[i].funcCgi(id);
okini3939 0:d18dff347122 203 // _state[id].keepalive = 0;
okini3939 0:d18dff347122 204 } else {
okini3939 0:d18dff347122 205 httpdError(id, 403);
okini3939 0:d18dff347122 206 }
okini3939 0:d18dff347122 207 } else {
okini3939 0:d18dff347122 208 httpdError(id, 404);
okini3939 0:d18dff347122 209 }
okini3939 0:d18dff347122 210
okini3939 0:d18dff347122 211 if (_state[id].keepalive) {
okini3939 0:d18dff347122 212 DBG("keepalive %d", _state[id].keepalive);
okini3939 0:d18dff347122 213 _state[id].keepalive --;
okini3939 0:d18dff347122 214 } else {
okini3939 0:d18dff347122 215 _state[id].client->close();
okini3939 0:d18dff347122 216 }
okini3939 0:d18dff347122 217 _state[id].mode = MODE_REQUEST;
okini3939 0:d18dff347122 218 } else
okini3939 0:d18dff347122 219 if (_state[id].mode == MODE_WEBSOCKET_ENTER) {
okini3939 0:d18dff347122 220 parseWebsocket(id);
okini3939 0:d18dff347122 221 _state[id].mode = MODE_WEBSOCKET;
okini3939 0:d18dff347122 222 }
okini3939 0:d18dff347122 223 }
okini3939 0:d18dff347122 224
okini3939 0:d18dff347122 225 int HTTPD::parseRequest (int id) {
okini3939 0:d18dff347122 226 int i, j, len;
okini3939 0:d18dff347122 227 char buf[HTTPD_CMD_SIZE];
okini3939 0:d18dff347122 228
okini3939 0:d18dff347122 229 for (len = 0; len < sizeof(buf); len++) {
okini3939 0:d18dff347122 230 if (_state[id].buf->dequeue(&buf[len]) == false) break;
okini3939 0:d18dff347122 231 }
okini3939 0:d18dff347122 232 buf[len] = 0;
okini3939 0:d18dff347122 233
okini3939 0:d18dff347122 234 if (strnicmp(buf, "GET ", 4) == 0) {
okini3939 0:d18dff347122 235 _state[id].req = REQ_HTTPGET;
okini3939 0:d18dff347122 236 j = 4;
okini3939 0:d18dff347122 237 } else
okini3939 0:d18dff347122 238 if (strnicmp(buf, "POST ", 5) == 0) {
okini3939 0:d18dff347122 239 _state[id].req = REQ_HTTPPOST;
okini3939 0:d18dff347122 240 j = 5;
okini3939 0:d18dff347122 241 } else {
okini3939 0:d18dff347122 242 return -1;
okini3939 0:d18dff347122 243 }
okini3939 0:d18dff347122 244
okini3939 0:d18dff347122 245 for (i = 0; i < len - j; i ++) {
okini3939 0:d18dff347122 246 _state[id].uri[i] = buf[i + j];
okini3939 0:d18dff347122 247 if (buf[i + j] == ' ' || i >= sizeof(buf) - 1) {
okini3939 0:d18dff347122 248 _state[id].uri[i] = 0;
okini3939 0:d18dff347122 249 INFO("URI %d '%s'", _state[id].req, _state[id].uri);
okini3939 0:d18dff347122 250 _state[id].mode = MODE_HEADER;
okini3939 0:d18dff347122 251 _state[id].buf->flush();
okini3939 0:d18dff347122 252 _state[id].length = 0;
okini3939 0:d18dff347122 253 _state[id].n = 0;
okini3939 0:d18dff347122 254 _state[id].websocket = 0;
okini3939 0:d18dff347122 255 _state[id].filename = NULL;
okini3939 0:d18dff347122 256 _state[id].querystring = NULL;
okini3939 0:d18dff347122 257 break;
okini3939 0:d18dff347122 258 }
okini3939 0:d18dff347122 259 }
okini3939 0:d18dff347122 260
okini3939 0:d18dff347122 261 i = getHandler(_state[id].uri);
okini3939 0:d18dff347122 262 if (i >= 0) {
okini3939 0:d18dff347122 263 _state[id].filename = &_state[id].uri[strlen(_handler[i].uri)];
okini3939 0:d18dff347122 264 for (i = 0; i < strlen(_state[id].filename); i ++) {
okini3939 0:d18dff347122 265 if (_state[id].filename[i] == '?') {
okini3939 0:d18dff347122 266 _state[id].filename[i] = 0;
okini3939 0:d18dff347122 267 _state[id].querystring = _state[id].filename + i + 1;
okini3939 0:d18dff347122 268 break;
okini3939 0:d18dff347122 269 }
okini3939 0:d18dff347122 270 }
okini3939 0:d18dff347122 271 INFO("FILE '%s' QUERY '%s'", _state[id].filename, _state[id].querystring);
okini3939 0:d18dff347122 272 }
okini3939 0:d18dff347122 273 return 0;
okini3939 0:d18dff347122 274 }
okini3939 0:d18dff347122 275
okini3939 0:d18dff347122 276 #define HEADER_TABLE_NUM 5
okini3939 0:d18dff347122 277 int HTTPD::parseHeader (int id) {
okini3939 0:d18dff347122 278 int i;
okini3939 0:d18dff347122 279 char buf[HTTPD_CMD_SIZE];
okini3939 0:d18dff347122 280 static const struct HEADER_TABLE {
okini3939 0:d18dff347122 281 const char header[24];
okini3939 0:d18dff347122 282 void (HTTPD::*func)(int id, const char*);
okini3939 0:d18dff347122 283 } header_table[HEADER_TABLE_NUM] = {
okini3939 0:d18dff347122 284 {"Content-Length:", &HTTPD::reqContentLength},
okini3939 0:d18dff347122 285 {"Connection:", &HTTPD::reqConnection},
okini3939 0:d18dff347122 286 {"Upgrade: websocket", &HTTPD::reqUpgrade},
okini3939 0:d18dff347122 287 {"Sec-WebSocket-Version:", &HTTPD::reqWebSocketVersion},
okini3939 0:d18dff347122 288 {"Sec-WebSocket-Key:", &HTTPD::reqWebSocketKey},
okini3939 0:d18dff347122 289 };
okini3939 0:d18dff347122 290 for (i = 0; i < sizeof(buf); i++) {
okini3939 0:d18dff347122 291 if (_state[id].buf->dequeue(&buf[i]) == false) break;
okini3939 0:d18dff347122 292 }
okini3939 0:d18dff347122 293 buf[i] = 0;
okini3939 0:d18dff347122 294
okini3939 0:d18dff347122 295 for (i = 0; i < HEADER_TABLE_NUM; i ++) {
okini3939 0:d18dff347122 296 if (strnicmp(buf, header_table[i].header, strlen(header_table[i].header)) == 0) {
okini3939 0:d18dff347122 297 DBG("parse header %d '%s'\r\n", i, buf);
okini3939 0:d18dff347122 298 if (header_table[i].func != NULL) {
okini3939 0:d18dff347122 299 (this->*(header_table[i].func))(id, buf);
okini3939 0:d18dff347122 300 }
okini3939 0:d18dff347122 301 return 0;
okini3939 0:d18dff347122 302 }
okini3939 0:d18dff347122 303 }
okini3939 0:d18dff347122 304
okini3939 0:d18dff347122 305 return -1;
okini3939 0:d18dff347122 306 }
okini3939 0:d18dff347122 307
okini3939 0:d18dff347122 308 void HTTPD::reqContentLength (int id, const char *buf) {
okini3939 0:d18dff347122 309 _state[id].length = atoi(&buf[16]);
okini3939 0:d18dff347122 310 }
okini3939 0:d18dff347122 311
okini3939 0:d18dff347122 312 void HTTPD::reqConnection (int id, const char *buf) {
okini3939 0:d18dff347122 313 if (strnicmp(&buf[12], "Keep-Alive", 10) == 0 && _state[id].keepalive == 0) {
okini3939 0:d18dff347122 314 _state[id].keepalive = HTTPD_KEEPALIVE;
okini3939 0:d18dff347122 315 } else {
okini3939 0:d18dff347122 316 _state[id].keepalive = 0;
okini3939 0:d18dff347122 317 }
okini3939 0:d18dff347122 318 }
okini3939 0:d18dff347122 319
okini3939 0:d18dff347122 320 void HTTPD::reqUpgrade (int id, const char *buf) {
okini3939 0:d18dff347122 321 if (! _state[id].websocket) _state[id].websocket = 1;
okini3939 0:d18dff347122 322 }
okini3939 0:d18dff347122 323
okini3939 0:d18dff347122 324 void HTTPD::reqWebSocketVersion (int id, const char *buf) {
okini3939 0:d18dff347122 325 _state[id].websocket = atoi(&buf[23]);
okini3939 0:d18dff347122 326 }
okini3939 0:d18dff347122 327
okini3939 0:d18dff347122 328 void HTTPD::reqWebSocketKey (int id, const char *buf) {
okini3939 0:d18dff347122 329 if (_state[id].websocket_key == NULL) {
okini3939 0:d18dff347122 330 _state[id].websocket_key = (char*)malloc(30);
okini3939 0:d18dff347122 331 }
okini3939 0:d18dff347122 332 strncpy(_state[id].websocket_key, &buf[19], 30);
okini3939 0:d18dff347122 333 }