Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: coap-example Borsch coap-example
Fork of NetworkServices by
HTTPD_req.cpp
00001 /* Copyright (C) 2013 Hiroshi Suga, MIT License 00002 * 00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00004 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00005 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00006 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00007 * furnished to do so, subject to the following conditions: 00008 * 00009 * The above copyright notice and this permission notice shall be included in all copies or 00010 * substantial portions of the Software. 00011 * 00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00017 */ 00018 00019 #include "HTTPD.h" 00020 00021 00022 int HTTPD::httpdFile (int id, char *dir) { 00023 FILE *fp; 00024 int i, len; 00025 char buf[HTTPD_BUF_SIZE]; 00026 char file[HTTPD_CMD_SIZE]; 00027 00028 INFO("httpdFile %d %s", id, dir); 00029 00030 strcpy(file, dir); 00031 strcat(file, _state[id].filename); 00032 if (file[strlen(file) - 1] == '/') { 00033 strcat(file, "index.html"); 00034 } 00035 DBG("file: %s\r\n", file); 00036 00037 fp = fopen(file, "r"); 00038 if (fp) { 00039 strcpy(buf, "HTTP/1.1 200 OK\r\n"); 00040 _state[id].client->send(buf, strlen(buf)); 00041 { 00042 // file size 00043 i = ftell(fp); 00044 fseek(fp, 0, SEEK_END); 00045 len = ftell(fp); 00046 fseek(fp, i, SEEK_SET); 00047 } 00048 00049 strcpy(buf, "Server: GSwifi httpd\r\n"); 00050 _state[id].client->send(buf, strlen(buf)); 00051 if (_state[id].keepalive) { 00052 strcpy(buf, "Connection: Keep-Alive\r\n"); 00053 } else { 00054 strcpy(buf, "Connection: close\r\n"); 00055 } 00056 _state[id].client->send(buf, strlen(buf)); 00057 sprintf(buf, "Content-Type: %s\r\n", mimetype(file)); 00058 _state[id].client->send(buf, strlen(buf)); 00059 sprintf(buf, "Content-Length: %d\r\n\r\n", len); 00060 _state[id].client->send(buf, strlen(buf)); 00061 00062 for (;;) { 00063 i = fread(buf, sizeof(char), sizeof(buf), fp); 00064 if (i <= 0) break; 00065 _state[id].client->send(buf, i); 00066 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00067 if (feof(fp)) break; 00068 #endif 00069 } 00070 fclose(fp); 00071 return 0; 00072 } 00073 00074 httpdError(id, 404); 00075 return -1; 00076 } 00077 00078 void HTTPD::httpdError (int id, int err) { 00079 char buf[HTTPD_CMD_SIZE], msg[30]; 00080 00081 switch (err) { 00082 case 400: 00083 strcpy(msg, "Bad Request"); 00084 break; 00085 case 403: 00086 strcpy(msg, "Forbidden"); 00087 break; 00088 case 404: 00089 strcpy(msg, "Not Found"); 00090 break; 00091 case 500: 00092 default: 00093 strcpy(msg, "Internal Server Error"); 00094 break; 00095 } 00096 DBG("httpd error: %d %d %s\r\n", id, err, msg); 00097 00098 sprintf(buf, "HTTP/1.1 %d %s\r\n", err, msg); 00099 _state[id].client->send(buf, strlen(buf)); 00100 strcpy(buf, "Content-Type: text/html\r\n\r\n"); 00101 _state[id].client->send(buf, strlen(buf)); 00102 00103 sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg); 00104 _state[id].client->send(buf, strlen(buf)); 00105 sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg); 00106 _state[id].client->send(buf, strlen(buf)); 00107 wait_ms(100); 00108 _state[id].client->close(); 00109 //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]); 00110 //WARN("%s %s %d %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err); 00111 } 00112 00113 void HTTPD::recvData (int id, char c) { 00114 00115 switch (_state[id].mode) { 00116 case MODE_REQUEST: 00117 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { 00118 _state[id].buf->flush(); 00119 _state[id].buf->queue(c); 00120 _state[id].mode = MODE_REQSTR; 00121 } else { 00122 _state[id].buf->flush(); 00123 } 00124 break; 00125 case MODE_REQSTR: 00126 switch (c) { 00127 case 0: 00128 break; 00129 case 0x0a: // LF 00130 case 0x0d: // CR 00131 if (parseRequest(id)) { 00132 _state[id].mode = MODE_REQSTR; 00133 } else { 00134 _state[id].mode = MODE_HEADER; 00135 } 00136 _state[id].enter = 0; 00137 break; 00138 default: 00139 _state[id].buf->queue(c); 00140 break; 00141 } 00142 break; 00143 case MODE_HEADER: 00144 switch (c) { 00145 case 0: 00146 break; 00147 case 0x0a: // LF 00148 case 0x0d: // CR 00149 if (_state[id].buf->available() == 0) { 00150 if ((_state[id].enter == 0x0d && c == 0x0a) || (_state[id].enter == 0x0a && c == 0x0a)) { 00151 _state[id].buf->flush(); 00152 if (_state[id].websocket) { 00153 INFO("MODE_WEBSOCKET"); 00154 acceptWebsocket(id); 00155 _state[id].mode = MODE_WEBSOCKET; 00156 } else 00157 if (_state[id].length) { 00158 INFO("MODE_BODY"); 00159 _state[id].mode = MODE_BODY; 00160 } else { 00161 INFO("MODE_ENTER"); 00162 _state[id].mode = MODE_ENTER; 00163 } 00164 } 00165 _state[id].enter = c; 00166 _state[id].buf->flush(); 00167 break; 00168 } 00169 00170 parseHeader(id); 00171 _state[id].enter = 0; 00172 break; 00173 default: 00174 _state[id].buf->queue(c); 00175 _state[id].enter = 0; 00176 break; 00177 } 00178 break; 00179 case MODE_BODY: 00180 _state[id].buf->queue(c); 00181 if (_state[id].buf->available() >= _state[id].length) { 00182 _state[id].mode = MODE_ENTER; 00183 } 00184 break; 00185 case MODE_WEBSOCKET: 00186 case MODE_WEBSOCKET_MASK: 00187 case MODE_WEBSOCKET_BODY: 00188 recvWS(id, c); 00189 break; 00190 } 00191 00192 if (_state[id].mode == MODE_ENTER) { 00193 int i = getHandler(_state[id].uri); 00194 printf("handler = %d, uri = %s\r\n", i, _state[id].uri); 00195 if (i >= 0) { 00196 if (_handler[i].dir) { 00197 // file 00198 httpdFile(id, _handler[i].dir); 00199 } else if (_handler[i].funcCgi) { 00200 // cgi 00201 _handler[i].funcCgi(id); 00202 _state[id].keepalive = 0; 00203 } else { 00204 httpdError(id, 403); 00205 } 00206 } else { 00207 httpdError(id, 404); 00208 } 00209 00210 if (_state[id].keepalive) { 00211 DBG("keepalive %d", _state[id].keepalive); 00212 _state[id].keepalive--; 00213 } else { 00214 _state[id].client->close(); 00215 } 00216 _state[id].mode = MODE_REQUEST; 00217 } else 00218 if (_state[id].mode == MODE_WEBSOCKET_ENTER) { 00219 parseWebsocket(id); 00220 _state[id].mode = MODE_WEBSOCKET; 00221 } 00222 } 00223 00224 int HTTPD::parseRequest (int id) { 00225 int i, j, len; 00226 char buf[HTTPD_CMD_SIZE]; 00227 00228 for (len = 0; len < sizeof(buf); len++) { 00229 if (_state[id].buf->dequeue(&buf[len]) == false) break; 00230 } 00231 buf[len] = 0; 00232 00233 if (strnicmp(buf, "GET ", 4) == 0) { 00234 _state[id].req = REQ_HTTPGET; 00235 j = 4; 00236 } else 00237 if (strnicmp(buf, "POST ", 5) == 0) { 00238 _state[id].req = REQ_HTTPPOST; 00239 j = 5; 00240 } else { 00241 return -1; 00242 } 00243 00244 for (i = 0; i < len - j; i ++) { 00245 _state[id].uri[i] = buf[i + j]; 00246 if (buf[i + j] == ' ' || i >= sizeof(buf) - 1) { 00247 _state[id].uri[i] = 0; 00248 INFO("URI %d '%s'", _state[id].req, _state[id].uri); 00249 _state[id].mode = MODE_HEADER; 00250 _state[id].buf->flush(); 00251 _state[id].length = 0; 00252 _state[id].n = 0; 00253 _state[id].websocket = 0; 00254 _state[id].filename = NULL; 00255 _state[id].querystring = NULL; 00256 break; 00257 } 00258 } 00259 00260 i = getHandler(_state[id].uri); 00261 if (i >= 0) { 00262 _state[id].filename = &_state[id].uri[strlen(_handler[i].uri)]; 00263 for (i = 0; i < strlen(_state[id].filename); i ++) { 00264 if (_state[id].filename[i] == '?') { 00265 _state[id].filename[i] = 0; 00266 _state[id].querystring = _state[id].filename + i + 1; 00267 break; 00268 } 00269 } 00270 INFO("FILE '%s' QUERY '%s'", _state[id].filename, _state[id].querystring); 00271 } 00272 return 0; 00273 } 00274 00275 #define HEADER_TABLE_NUM 5 00276 int HTTPD::parseHeader (int id) { 00277 int i; 00278 char buf[HTTPD_CMD_SIZE]; 00279 static const struct HEADER_TABLE { 00280 const char header[24]; 00281 void (HTTPD::*func)(int id, const char*); 00282 } header_table[HEADER_TABLE_NUM] = { 00283 {"Content-Length:", &HTTPD::reqContentLength}, 00284 {"Connection:", &HTTPD::reqConnection}, 00285 {"Upgrade: websocket", &HTTPD::reqUpgrade}, 00286 {"Sec-WebSocket-Version:", &HTTPD::reqWebSocketVersion}, 00287 {"Sec-WebSocket-Key:", &HTTPD::reqWebSocketKey}, 00288 }; 00289 for (i = 0; i < sizeof(buf); i++) { 00290 if (_state[id].buf->dequeue(&buf[i]) == false) break; 00291 } 00292 buf[i] = 0; 00293 00294 for (i = 0; i < HEADER_TABLE_NUM; i ++) { 00295 if (strnicmp(buf, header_table[i].header, strlen(header_table[i].header)) == 0) { 00296 DBG("parse header %d '%s'\r\n", i, buf); 00297 if (header_table[i].func != NULL) { 00298 (this->*(header_table[i].func))(id, buf); 00299 } 00300 return 0; 00301 } 00302 } 00303 00304 return -1; 00305 } 00306 00307 void HTTPD::reqContentLength (int id, const char *buf) { 00308 _state[id].length = atoi(&buf[16]); 00309 } 00310 00311 void HTTPD::reqConnection (int id, const char *buf) { 00312 if (strnicmp(&buf[12], "Keep-Alive", 10) == 0 && _state[id].keepalive == 0) { 00313 _state[id].keepalive = HTTPD_KEEPALIVE; 00314 } else { 00315 _state[id].keepalive = 0; 00316 } 00317 } 00318 00319 void HTTPD::reqUpgrade (int id, const char *buf) { 00320 if (! _state[id].websocket) _state[id].websocket = 1; 00321 } 00322 00323 void HTTPD::reqWebSocketVersion (int id, const char *buf) { 00324 _state[id].websocket = atoi(&buf[23]); 00325 } 00326 00327 void HTTPD::reqWebSocketKey (int id, const char *buf) { 00328 if (_state[id].websocket_key == NULL) { 00329 _state[id].websocket_key = (char*)malloc(30); 00330 } 00331 strncpy(_state[id].websocket_key, &buf[19], 30); 00332 }
Generated on Fri Jul 15 2022 01:11:07 by
1.7.2
