HTTP Server, WebSocket support
Dependents: HTTPD_sample ch5_mbed_lightweight_Web_server_dust_sensor ch8_mbed_websocket_client Renesas_GR-Peach_LCD
HTTPD_req.cpp@0:d18dff347122, 2013-11-13 (annotated)
- Committer:
- okini3939
- Date:
- Wed Nov 13 01:58:04 2013 +0000
- Revision:
- 0:d18dff347122
1st build;
Who changed what in which revision?
User | Revision | Line number | New 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 | |
okini3939 | 0:d18dff347122 | 49 | strcpy(buf, "Server: GSwifi httpd\r\n"); |
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 | } |