WebServer.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. WebServer.cpp - Dead simple web-server.
  3. Supports only one simultaneous client, knows how to handle GET and POST.
  4. Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
  17. */
  18. #include "WebServer.h"
  19. #include <Arduino.h>
  20. #include <libb64/cencode.h>
  21. #include "FS.h"
  22. #include "WiFiClient.h"
  23. #include "WiFiServer.h"
  24. #include "detail/RequestHandlersImpl.h"
  25. //#define DEBUG_ESP_HTTP_SERVER
  26. #ifdef DEBUG_ESP_PORT
  27. #define DEBUG_OUTPUT DEBUG_ESP_PORT
  28. #else
  29. #define DEBUG_OUTPUT Serial
  30. #endif
  31. const char* AUTHORIZATION_HEADER = "Authorization";
  32. WebServer::WebServer(IPAddress addr, int port)
  33. : _server(addr, port),
  34. _currentMethod(HTTP_ANY),
  35. _currentVersion(0),
  36. _currentStatus(HC_NONE),
  37. _statusChange(0),
  38. _currentHandler(0),
  39. _firstHandler(0),
  40. _lastHandler(0),
  41. _currentArgCount(0),
  42. _currentArgs(0),
  43. _headerKeysCount(0),
  44. _currentHeaders(0),
  45. _contentLength(0),
  46. _chunked(false) {}
  47. WebServer::WebServer(int port)
  48. : _server(port),
  49. _currentMethod(HTTP_ANY),
  50. _currentVersion(0),
  51. _currentStatus(HC_NONE),
  52. _statusChange(0),
  53. _currentHandler(0),
  54. _firstHandler(0),
  55. _lastHandler(0),
  56. _currentArgCount(0),
  57. _currentArgs(0),
  58. _headerKeysCount(0),
  59. _currentHeaders(0),
  60. _contentLength(0),
  61. _chunked(false) {}
  62. WebServer::~WebServer() {
  63. if (_currentHeaders) delete[] _currentHeaders;
  64. _headerKeysCount = 0;
  65. RequestHandler* handler = _firstHandler;
  66. while (handler) {
  67. RequestHandler* next = handler->next();
  68. delete handler;
  69. handler = next;
  70. }
  71. close();
  72. }
  73. void WebServer::begin() {
  74. _currentStatus = HC_NONE;
  75. _server.begin();
  76. if (!_headerKeysCount) collectHeaders(0, 0);
  77. }
  78. bool WebServer::authenticate(const char* username, const char* password) {
  79. if (hasHeader(AUTHORIZATION_HEADER)) {
  80. String authReq = header(AUTHORIZATION_HEADER);
  81. if (authReq.startsWith("Basic")) {
  82. authReq = authReq.substring(6);
  83. authReq.trim();
  84. char toencodeLen = strlen(username) + strlen(password) + 1;
  85. char* toencode = new char[toencodeLen + 1];
  86. if (toencode == NULL) {
  87. authReq = String();
  88. return false;
  89. }
  90. char* encoded =
  91. new char[base64_encode_expected_len(toencodeLen) + 1];
  92. if (encoded == NULL) {
  93. authReq = String();
  94. delete[] toencode;
  95. return false;
  96. }
  97. sprintf(toencode, "%s:%s", username, password);
  98. if (base64_encode_chars(toencode, toencodeLen, encoded) > 0 &&
  99. authReq.equals(encoded)) {
  100. authReq = String();
  101. delete[] toencode;
  102. delete[] encoded;
  103. return true;
  104. }
  105. delete[] toencode;
  106. delete[] encoded;
  107. }
  108. authReq = String();
  109. }
  110. return false;
  111. }
  112. void WebServer::requestAuthentication() {
  113. sendHeader("WWW-Authenticate", "Basic realm=\"Login Required\"");
  114. send(401);
  115. }
  116. void WebServer::on(const String& uri, WebServer::THandlerFunction handler) {
  117. on(uri, HTTP_ANY, handler);
  118. }
  119. void WebServer::on(const String& uri, HTTPMethod method,
  120. WebServer::THandlerFunction fn) {
  121. on(uri, method, fn, _fileUploadHandler);
  122. }
  123. void WebServer::on(const String& uri, HTTPMethod method,
  124. WebServer::THandlerFunction fn,
  125. WebServer::THandlerFunction ufn) {
  126. _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method));
  127. }
  128. void WebServer::addHandler(RequestHandler* handler) {
  129. _addRequestHandler(handler);
  130. }
  131. void WebServer::_addRequestHandler(RequestHandler* handler) {
  132. if (!_lastHandler) {
  133. _firstHandler = handler;
  134. _lastHandler = handler;
  135. } else {
  136. _lastHandler->next(handler);
  137. _lastHandler = handler;
  138. }
  139. }
  140. void WebServer::serveStatic(const char* uri, FS& fs, const char* path,
  141. const char* cache_header) {
  142. _addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
  143. }
  144. void WebServer::handleClient() {
  145. if (_currentStatus == HC_NONE) {
  146. WiFiClient client = _server.available();
  147. if (!client) {
  148. return;
  149. }
  150. #ifdef DEBUG_ESP_HTTP_SERVER
  151. DEBUG_OUTPUT.println("New client");
  152. #endif
  153. _currentClient = client;
  154. _currentStatus = HC_WAIT_READ;
  155. _statusChange = millis();
  156. }
  157. if (!_currentClient.connected()) {
  158. _currentClient = WiFiClient();
  159. _currentStatus = HC_NONE;
  160. return;
  161. }
  162. // Wait for data from client to become available
  163. if (_currentStatus == HC_WAIT_READ) {
  164. if (!_currentClient.available()) {
  165. if (millis() - _statusChange > HTTP_MAX_DATA_WAIT) {
  166. _currentClient = WiFiClient();
  167. _currentStatus = HC_NONE;
  168. }
  169. yield();
  170. return;
  171. }
  172. if (!_parseRequest(_currentClient)) {
  173. _currentClient = WiFiClient();
  174. _currentStatus = HC_NONE;
  175. return;
  176. }
  177. _currentClient.setTimeout(HTTP_MAX_SEND_WAIT);
  178. _contentLength = CONTENT_LENGTH_NOT_SET;
  179. _handleRequest();
  180. if (!_currentClient.connected()) {
  181. _currentClient = WiFiClient();
  182. _currentStatus = HC_NONE;
  183. return;
  184. } else {
  185. _currentStatus = HC_WAIT_CLOSE;
  186. _statusChange = millis();
  187. return;
  188. }
  189. }
  190. if (_currentStatus == HC_WAIT_CLOSE) {
  191. if (millis() - _statusChange > HTTP_MAX_CLOSE_WAIT) {
  192. _currentClient = WiFiClient();
  193. _currentStatus = HC_NONE;
  194. } else {
  195. yield();
  196. return;
  197. }
  198. }
  199. }
  200. void WebServer::close() { _server.end(); }
  201. void WebServer::stop() { close(); }
  202. void WebServer::sendHeader(const String& name, const String& value,
  203. bool first) {
  204. String headerLine = name;
  205. headerLine += ": ";
  206. headerLine += value;
  207. headerLine += "\r\n";
  208. if (first) {
  209. _responseHeaders = headerLine + _responseHeaders;
  210. } else {
  211. _responseHeaders += headerLine;
  212. }
  213. }
  214. void WebServer::setContentLength(size_t contentLength) {
  215. _contentLength = contentLength;
  216. }
  217. void WebServer::_prepareHeader(String& response, int code,
  218. const char* content_type, size_t contentLength) {
  219. response = "HTTP/1." + String(_currentVersion) + " ";
  220. response += String(code);
  221. response += " ";
  222. response += _responseCodeToString(code);
  223. response += "\r\n";
  224. if (!content_type) content_type = "text/html";
  225. sendHeader("Content-Type", content_type, true);
  226. if (_contentLength == CONTENT_LENGTH_NOT_SET) {
  227. sendHeader("Content-Length", String(contentLength));
  228. } else if (_contentLength != CONTENT_LENGTH_UNKNOWN) {
  229. sendHeader("Content-Length", String(_contentLength));
  230. } else if (_contentLength == CONTENT_LENGTH_UNKNOWN &&
  231. _currentVersion) { // HTTP/1.1 or above client
  232. // let's do chunked
  233. _chunked = true;
  234. sendHeader("Accept-Ranges", "none");
  235. sendHeader("Transfer-Encoding", "chunked");
  236. }
  237. sendHeader("Connection", "close");
  238. response += _responseHeaders;
  239. response += "\r\n";
  240. _responseHeaders = String();
  241. }
  242. void WebServer::send(int code, const char* content_type,
  243. const String& content) {
  244. String header;
  245. // Can we asume the following?
  246. // if(code == 200 && content.length() == 0 && _contentLength ==
  247. // CONTENT_LENGTH_NOT_SET)
  248. // _contentLength = CONTENT_LENGTH_UNKNOWN;
  249. _prepareHeader(header, code, content_type, content.length());
  250. _currentClient.write(header.c_str(), header.length());
  251. if (content.length()) sendContent(content);
  252. }
  253. void WebServer::send_P(int code, PGM_P content_type, PGM_P content) {
  254. size_t contentLength = 0;
  255. if (content != NULL) {
  256. contentLength = strlen_P(content);
  257. }
  258. String header;
  259. char type[64];
  260. memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
  261. _prepareHeader(header, code, (const char*)type, contentLength);
  262. _currentClient.write(header.c_str(), header.length());
  263. sendContent_P(content);
  264. }
  265. void WebServer::send_P(int code, PGM_P content_type, PGM_P content,
  266. size_t contentLength) {
  267. String header;
  268. char type[64];
  269. memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
  270. _prepareHeader(header, code, (const char*)type, contentLength);
  271. sendContent(header);
  272. sendContent_P(content, contentLength);
  273. }
  274. void WebServer::send(int code, char* content_type, const String& content) {
  275. send(code, (const char*)content_type, content);
  276. }
  277. void WebServer::send(int code, const String& content_type,
  278. const String& content) {
  279. send(code, (const char*)content_type.c_str(), content);
  280. }
  281. void WebServer::sendContent(const String& content) {
  282. const char* footer = "\r\n";
  283. size_t len = content.length();
  284. if (_chunked) {
  285. char* chunkSize = (char*)malloc(11);
  286. if (chunkSize) {
  287. sprintf(chunkSize, "%x%s", len, footer);
  288. _currentClient.write(chunkSize, strlen(chunkSize));
  289. free(chunkSize);
  290. }
  291. }
  292. _currentClient.write(content.c_str(), len);
  293. if (_chunked) {
  294. _currentClient.write(footer, 2);
  295. }
  296. }
  297. void WebServer::sendContent_P(PGM_P content) {
  298. sendContent_P(content, strlen_P(content));
  299. }
  300. void WebServer::sendContent_P(PGM_P content, size_t size) {
  301. const char* footer = "\r\n";
  302. if (_chunked) {
  303. char* chunkSize = (char*)malloc(11);
  304. if (chunkSize) {
  305. sprintf(chunkSize, "%x%s", size, footer);
  306. _currentClient.write(chunkSize, strlen(chunkSize));
  307. free(chunkSize);
  308. }
  309. }
  310. _currentClient.write(content, size);
  311. if (_chunked) {
  312. _currentClient.write(footer, 2);
  313. }
  314. }
  315. String WebServer::arg(String name) {
  316. for (int i = 0; i < _currentArgCount; ++i) {
  317. if (_currentArgs[i].key == name) return _currentArgs[i].value;
  318. }
  319. return String();
  320. }
  321. String WebServer::arg(int i) {
  322. if (i < _currentArgCount) return _currentArgs[i].value;
  323. return String();
  324. }
  325. String WebServer::argName(int i) {
  326. if (i < _currentArgCount) return _currentArgs[i].key;
  327. return String();
  328. }
  329. int WebServer::args() { return _currentArgCount; }
  330. bool WebServer::hasArg(String name) {
  331. for (int i = 0; i < _currentArgCount; ++i) {
  332. if (_currentArgs[i].key == name) return true;
  333. }
  334. return false;
  335. }
  336. String WebServer::header(String name) {
  337. for (int i = 0; i < _headerKeysCount; ++i) {
  338. if (_currentHeaders[i].key.equalsIgnoreCase(name))
  339. return _currentHeaders[i].value;
  340. }
  341. return String();
  342. }
  343. void WebServer::collectHeaders(const char* headerKeys[],
  344. const size_t headerKeysCount) {
  345. _headerKeysCount = headerKeysCount + 1;
  346. if (_currentHeaders) delete[] _currentHeaders;
  347. _currentHeaders = new RequestArgument[_headerKeysCount];
  348. _currentHeaders[0].key = AUTHORIZATION_HEADER;
  349. for (int i = 1; i < _headerKeysCount; i++) {
  350. _currentHeaders[i].key = headerKeys[i - 1];
  351. }
  352. }
  353. String WebServer::header(int i) {
  354. if (i < _headerKeysCount) return _currentHeaders[i].value;
  355. return String();
  356. }
  357. String WebServer::headerName(int i) {
  358. if (i < _headerKeysCount) return _currentHeaders[i].key;
  359. return String();
  360. }
  361. int WebServer::headers() { return _headerKeysCount; }
  362. bool WebServer::hasHeader(String name) {
  363. for (int i = 0; i < _headerKeysCount; ++i) {
  364. if ((_currentHeaders[i].key.equalsIgnoreCase(name)) &&
  365. (_currentHeaders[i].value.length() > 0))
  366. return true;
  367. }
  368. return false;
  369. }
  370. String WebServer::hostHeader() { return _hostHeader; }
  371. void WebServer::onFileUpload(THandlerFunction fn) { _fileUploadHandler = fn; }
  372. void WebServer::onNotFound(THandlerFunction fn) { _notFoundHandler = fn; }
  373. void WebServer::_handleRequest() {
  374. bool handled = false;
  375. if (!_currentHandler) {
  376. #ifdef DEBUG_ESP_HTTP_SERVER
  377. DEBUG_OUTPUT.println("request handler not found");
  378. #endif
  379. } else {
  380. handled = _currentHandler->handle(*this, _currentMethod, _currentUri);
  381. #ifdef DEBUG_ESP_HTTP_SERVER
  382. if (!handled) {
  383. DEBUG_OUTPUT.println("request handler failed to handle request");
  384. }
  385. #endif
  386. }
  387. if (!handled) {
  388. if (_notFoundHandler) {
  389. _notFoundHandler();
  390. } else {
  391. send(404, "text/plain", String("Not found: ") + _currentUri);
  392. }
  393. }
  394. _currentUri = String();
  395. }
  396. String WebServer::_responseCodeToString(int code) {
  397. switch (code) {
  398. case 100:
  399. return F("Continue");
  400. case 101:
  401. return F("Switching Protocols");
  402. case 200:
  403. return F("OK");
  404. case 201:
  405. return F("Created");
  406. case 202:
  407. return F("Accepted");
  408. case 203:
  409. return F("Non-Authoritative Information");
  410. case 204:
  411. return F("No Content");
  412. case 205:
  413. return F("Reset Content");
  414. case 206:
  415. return F("Partial Content");
  416. case 300:
  417. return F("Multiple Choices");
  418. case 301:
  419. return F("Moved Permanently");
  420. case 302:
  421. return F("Found");
  422. case 303:
  423. return F("See Other");
  424. case 304:
  425. return F("Not Modified");
  426. case 305:
  427. return F("Use Proxy");
  428. case 307:
  429. return F("Temporary Redirect");
  430. case 400:
  431. return F("Bad Request");
  432. case 401:
  433. return F("Unauthorized");
  434. case 402:
  435. return F("Payment Required");
  436. case 403:
  437. return F("Forbidden");
  438. case 404:
  439. return F("Not Found");
  440. case 405:
  441. return F("Method Not Allowed");
  442. case 406:
  443. return F("Not Acceptable");
  444. case 407:
  445. return F("Proxy Authentication Required");
  446. case 408:
  447. return F("Request Time-out");
  448. case 409:
  449. return F("Conflict");
  450. case 410:
  451. return F("Gone");
  452. case 411:
  453. return F("Length Required");
  454. case 412:
  455. return F("Precondition Failed");
  456. case 413:
  457. return F("Request Entity Too Large");
  458. case 414:
  459. return F("Request-URI Too Large");
  460. case 415:
  461. return F("Unsupported Media Type");
  462. case 416:
  463. return F("Requested range not satisfiable");
  464. case 417:
  465. return F("Expectation Failed");
  466. case 500:
  467. return F("Internal Server Error");
  468. case 501:
  469. return F("Not Implemented");
  470. case 502:
  471. return F("Bad Gateway");
  472. case 503:
  473. return F("Service Unavailable");
  474. case 504:
  475. return F("Gateway Time-out");
  476. case 505:
  477. return F("HTTP Version not supported");
  478. default:
  479. return "";
  480. }
  481. }