more handlers
Dependents: bandwidth-meter-net mbedRail24v
Fork of Tiny-HTTPD 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_all(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_name); 00050 _state[id].client->send_all(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_all(buf, strlen(buf)); 00057 sprintf(buf, "Content-Type: %s\r\n", mimetype(file)); 00058 _state[id].client->send_all(buf, strlen(buf)); 00059 sprintf(buf, "Content-Length: %d\r\n\r\n", len); 00060 _state[id].client->send_all(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_all(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_all(buf, strlen(buf)); 00100 strcpy(buf, "Content-Type: text/html\r\n\r\n"); 00101 _state[id].client->send_all(buf, strlen(buf)); 00102 00103 sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg); 00104 _state[id].client->send_all(buf, strlen(buf)); 00105 sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg); 00106 _state[id].client->send_all(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 00114 void HTTPD::recvData (int id, char c) { 00115 00116 switch (_state[id].mode) { 00117 case MODE_REQUEST: 00118 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { 00119 _state[id].buf->flush(); 00120 _state[id].buf->queue(c); 00121 _state[id].mode = MODE_REQSTR; 00122 } else { 00123 _state[id].buf->flush(); 00124 } 00125 break; 00126 case MODE_REQSTR: 00127 switch (c) { 00128 case 0: 00129 break; 00130 case 0x0a: // LF 00131 case 0x0d: // CR 00132 if (parseRequest(id)) { 00133 _state[id].mode = MODE_REQSTR; 00134 } else { 00135 _state[id].mode = MODE_HEADER; 00136 } 00137 _state[id].enter = 0; 00138 break; 00139 default: 00140 _state[id].buf->queue(c); 00141 break; 00142 } 00143 break; 00144 case MODE_HEADER: 00145 switch (c) { 00146 case 0: 00147 break; 00148 case 0x0a: // LF 00149 case 0x0d: // CR 00150 if (_state[id].buf->available() == 0) { 00151 if ((_state[id].enter == 0x0d && c == 0x0a) || (_state[id].enter == 0x0a && c == 0x0a)) { 00152 _state[id].buf->flush(); 00153 if (_state[id].websocket) { 00154 INFO("MODE_WEBSOCKET"); 00155 acceptWebsocket(id); 00156 _state[id].mode = MODE_WEBSOCKET; 00157 } else 00158 if (_state[id].length) { 00159 INFO("MODE_BODY"); 00160 _state[id].mode = MODE_BODY; 00161 } else { 00162 INFO("MODE_ENTER"); 00163 _state[id].mode = MODE_ENTER; 00164 } 00165 } 00166 _state[id].enter = c; 00167 _state[id].buf->flush(); 00168 break; 00169 } 00170 00171 parseHeader(id); 00172 _state[id].enter = 0; 00173 break; 00174 default: 00175 _state[id].buf->queue(c); 00176 _state[id].enter = 0; 00177 break; 00178 } 00179 break; 00180 case MODE_BODY: 00181 _state[id].buf->queue(c); 00182 if (_state[id].buf->available() >= _state[id].length) { 00183 _state[id].mode = MODE_ENTER; 00184 } 00185 break; 00186 case MODE_WEBSOCKET: 00187 case MODE_WEBSOCKET_MASK: 00188 case MODE_WEBSOCKET_BODY: 00189 recvWS(id, c); 00190 break; 00191 } 00192 00193 if (_state[id].mode == MODE_ENTER) { 00194 int i = getHandler(_state[id].uri); 00195 if (i >= 0) { 00196 if (_handler[i].dir) { 00197 // file 00198 httpdFile(id, _handler[i].dir); 00199 } else 00200 if (_handler[i].funcCgi) { 00201 // cgi 00202 _handler[i].funcCgi(id); 00203 // _state[id].keepalive = 0; 00204 } else { 00205 httpdError(id, 403); 00206 } 00207 } else { 00208 httpdError(id, 404); 00209 } 00210 00211 if (_state[id].keepalive) { 00212 DBG("keepalive %d", _state[id].keepalive); 00213 _state[id].keepalive --; 00214 } else { 00215 _state[id].client->close(); 00216 } 00217 _state[id].mode = MODE_REQUEST; 00218 } else 00219 if (_state[id].mode == MODE_WEBSOCKET_ENTER) { 00220 parseWebsocket(id); 00221 _state[id].mode = MODE_WEBSOCKET; 00222 } 00223 } 00224 00225 int HTTPD::parseRequest (int id) { 00226 int i, j, len; 00227 char buf[HTTPD_CMD_SIZE]; 00228 00229 for (len = 0; len < sizeof(buf); len++) { 00230 if (_state[id].buf->dequeue(&buf[len]) == false) break; 00231 } 00232 buf[len] = 0; 00233 00234 if (strnicmp(buf, "GET ", 4) == 0) { 00235 _state[id].req = REQ_HTTPGET; 00236 j = 4; 00237 } else 00238 if (strnicmp(buf, "POST ", 5) == 0) { 00239 _state[id].req = REQ_HTTPPOST; 00240 j = 5; 00241 } else { 00242 return -1; 00243 } 00244 00245 for (i = 0; i < len - j; i ++) { 00246 _state[id].uri[i] = buf[i + j]; 00247 if (buf[i + j] == ' ' || i >= sizeof(buf) - 1) { 00248 _state[id].uri[i] = 0; 00249 INFO("URI %d '%s'", _state[id].req, _state[id].uri); 00250 _state[id].mode = MODE_HEADER; 00251 _state[id].buf->flush(); 00252 _state[id].length = 0; 00253 _state[id].n = 0; 00254 _state[id].websocket = 0; 00255 _state[id].filename = NULL; 00256 _state[id].querystring = NULL; 00257 break; 00258 } 00259 } 00260 00261 i = getHandler(_state[id].uri); 00262 if (i >= 0) { 00263 _state[id].filename = &_state[id].uri[strlen(_handler[i].uri)]; 00264 for (i = 0; i < strlen(_state[id].filename); i ++) { 00265 if (_state[id].filename[i] == '?') { 00266 _state[id].filename[i] = 0; 00267 _state[id].querystring = _state[id].filename + i + 1; 00268 break; 00269 } 00270 } 00271 INFO("FILE '%s' QUERY '%s'", _state[id].filename, _state[id].querystring); 00272 } 00273 return 0; 00274 } 00275 00276 #define HEADER_TABLE_NUM 5 00277 int HTTPD::parseHeader (int id) { 00278 int i; 00279 char buf[HTTPD_CMD_SIZE]; 00280 static const struct HEADER_TABLE { 00281 const char header[24]; 00282 void (HTTPD::*func)(int id, const char*); 00283 } header_table[HEADER_TABLE_NUM] = { 00284 {"Content-Length:", &HTTPD::reqContentLength}, 00285 {"Connection:", &HTTPD::reqConnection}, 00286 {"Upgrade: websocket", &HTTPD::reqUpgrade}, 00287 {"Sec-WebSocket-Version:", &HTTPD::reqWebSocketVersion}, 00288 {"Sec-WebSocket-Key:", &HTTPD::reqWebSocketKey}, 00289 }; 00290 for (i = 0; i < sizeof(buf); i++) { 00291 if (_state[id].buf->dequeue(&buf[i]) == false) break; 00292 } 00293 buf[i] = 0; 00294 00295 for (i = 0; i < HEADER_TABLE_NUM; i ++) { 00296 if (strnicmp(buf, header_table[i].header, strlen(header_table[i].header)) == 0) { 00297 DBG("parse header %d '%s'\r\n", i, buf); 00298 if (header_table[i].func != NULL) { 00299 (this->*(header_table[i].func))(id, buf); 00300 } 00301 return 0; 00302 } 00303 } 00304 00305 return -1; 00306 } 00307 00308 void HTTPD::reqContentLength (int id, const char *buf) { 00309 _state[id].length = atoi(&buf[16]); 00310 } 00311 00312 void HTTPD::reqConnection (int id, const char *buf) { 00313 if (strnicmp(&buf[12], "Keep-Alive", 10) == 0 && _state[id].keepalive == 0) { 00314 _state[id].keepalive = HTTPD_KEEPALIVE; 00315 } else { 00316 _state[id].keepalive = 0; 00317 } 00318 } 00319 00320 void HTTPD::reqUpgrade (int id, const char *buf) { 00321 if (! _state[id].websocket) _state[id].websocket = 1; 00322 } 00323 00324 void HTTPD::reqWebSocketVersion (int id, const char *buf) { 00325 _state[id].websocket = atoi(&buf[23]); 00326 } 00327 00328 void HTTPD::reqWebSocketKey (int id, const char *buf) { 00329 if (_state[id].websocket_key == NULL) { 00330 _state[id].websocket_key = (char*)malloc(30); 00331 } 00332 strncpy(_state[id].websocket_key, &buf[19], 30); 00333 }
Generated on Sun Jul 24 2022 08:41:21 by 1.7.2