mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-24 08:45:10 +03:00
266 lines
6.4 KiB
C++
266 lines
6.4 KiB
C++
/*
|
|
ESP8266WebServer.cpp - Dead simple web-server.
|
|
Supports only one simultaneous client, knows how to handle GET and POST.
|
|
|
|
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
|
*/
|
|
|
|
|
|
#include <Arduino.h>
|
|
#include "WiFiServer.h"
|
|
#include "WiFiClient.h"
|
|
#include "ESP8266WebServer.h"
|
|
|
|
// #define DEBUG
|
|
#define DEBUG_OUTPUT Serial
|
|
|
|
struct ESP8266WebServer::RequestHandler {
|
|
RequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
|
|
: fn(fn)
|
|
, uri(uri)
|
|
, method(method)
|
|
, next(NULL)
|
|
{
|
|
}
|
|
|
|
ESP8266WebServer::THandlerFunction fn;
|
|
String uri;
|
|
HTTPMethod method;
|
|
RequestHandler* next;
|
|
|
|
};
|
|
|
|
ESP8266WebServer::ESP8266WebServer(int port)
|
|
: _server(port)
|
|
, _firstHandler(0)
|
|
, _lastHandler(0)
|
|
, _currentArgCount(0)
|
|
, _currentArgs(0)
|
|
{
|
|
}
|
|
|
|
ESP8266WebServer::~ESP8266WebServer()
|
|
{
|
|
if (!_firstHandler)
|
|
return;
|
|
RequestHandler* handler = _firstHandler;
|
|
while (handler) {
|
|
RequestHandler* next = handler->next;
|
|
delete handler;
|
|
handler = next;
|
|
}
|
|
}
|
|
|
|
void ESP8266WebServer::begin() {
|
|
_server.begin();
|
|
}
|
|
|
|
|
|
void ESP8266WebServer::on(const char* uri, ESP8266WebServer::THandlerFunction handler)
|
|
{
|
|
on(uri, HTTP_ANY, handler);
|
|
}
|
|
|
|
void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn)
|
|
{
|
|
RequestHandler* handler = new RequestHandler(fn, uri, method);
|
|
if (!_lastHandler) {
|
|
_firstHandler = handler;
|
|
_lastHandler = handler;
|
|
}
|
|
else {
|
|
_lastHandler->next = handler;
|
|
_lastHandler = handler;
|
|
}
|
|
}
|
|
|
|
void ESP8266WebServer::handleClient()
|
|
{
|
|
WiFiClient client = _server.available();
|
|
if (!client) {
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
DEBUG_OUTPUT.println("New client");
|
|
#endif
|
|
|
|
// Wait for data from client to become available
|
|
uint16_t maxWait = HTTP_MAX_DATA_WAIT;
|
|
while(client.connected() && !client.available() && maxWait--){
|
|
delay(1);
|
|
}
|
|
|
|
if (!_parseRequest(client)) {
|
|
return;
|
|
}
|
|
|
|
_currentClient = client;
|
|
_contentLength = CONTENT_LENGTH_NOT_SET;
|
|
_handleRequest();
|
|
}
|
|
|
|
void ESP8266WebServer::sendHeader(const String& name, const String& value, bool first) {
|
|
String headerLine = name;
|
|
headerLine += ": ";
|
|
headerLine += value;
|
|
headerLine += "\r\n";
|
|
|
|
if (first) {
|
|
_responseHeaders = headerLine + _responseHeaders;
|
|
}
|
|
else {
|
|
_responseHeaders += headerLine;
|
|
}
|
|
}
|
|
|
|
void ESP8266WebServer::send(int code, const char* content_type, const String& content) {
|
|
String response = "HTTP/1.1 ";
|
|
response += String(code);
|
|
response += " ";
|
|
response += _responseCodeToString(code);
|
|
response += "\r\n";
|
|
|
|
if (!content_type)
|
|
content_type = "text/html";
|
|
|
|
sendHeader("Content-Type", content_type, true);
|
|
if (_contentLength != CONTENT_LENGTH_UNKNOWN && _contentLength != CONTENT_LENGTH_NOT_SET) {
|
|
sendHeader("Content-Length", String(_contentLength).c_str());
|
|
} else if(content.length() > 0){
|
|
sendHeader("Content-Length", String(content.length()).c_str());
|
|
}
|
|
sendHeader("Connection", "close");
|
|
sendHeader("Access-Control-Allow-Origin", "*");
|
|
|
|
response += _responseHeaders;
|
|
response += "\r\n";
|
|
response += content;
|
|
_responseHeaders = String();
|
|
sendContent(response);
|
|
}
|
|
|
|
void ESP8266WebServer::send(int code, char* content_type, const String& content) {
|
|
send(code, (const char*)content_type, content);
|
|
}
|
|
|
|
void ESP8266WebServer::send(int code, const String& content_type, const String& content) {
|
|
send(code, (const char*)content_type.c_str(), content);
|
|
}
|
|
|
|
void ESP8266WebServer::sendContent(const String& content) {
|
|
size_t size_to_send = content.length();
|
|
size_t size_sent = 0;
|
|
while(size_to_send) {
|
|
const size_t unit_size = HTTP_DOWNLOAD_UNIT_SIZE;
|
|
size_t will_send = (size_to_send < unit_size) ? size_to_send : unit_size;
|
|
size_t sent = _currentClient.write(content.c_str() + size_sent, will_send);
|
|
size_to_send -= sent;
|
|
size_sent += sent;
|
|
if (sent == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
String ESP8266WebServer::arg(const char* name) {
|
|
for (int i = 0; i < _currentArgCount; ++i) {
|
|
if (_currentArgs[i].key == name)
|
|
return _currentArgs[i].value;
|
|
}
|
|
return String();
|
|
}
|
|
|
|
String ESP8266WebServer::arg(int i) {
|
|
if (i < _currentArgCount)
|
|
return _currentArgs[i].value;
|
|
return String();
|
|
}
|
|
|
|
String ESP8266WebServer::argName(int i) {
|
|
if (i < _currentArgCount)
|
|
return _currentArgs[i].key;
|
|
return String();
|
|
}
|
|
|
|
int ESP8266WebServer::args() {
|
|
return _currentArgCount;
|
|
}
|
|
|
|
bool ESP8266WebServer::hasArg(const char* name) {
|
|
for (int i = 0; i < _currentArgCount; ++i) {
|
|
if (_currentArgs[i].key == name)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ESP8266WebServer::onFileUpload(THandlerFunction fn) {
|
|
_fileUploadHandler = fn;
|
|
}
|
|
|
|
void ESP8266WebServer::onNotFound(THandlerFunction fn) {
|
|
_notFoundHandler = fn;
|
|
}
|
|
|
|
void ESP8266WebServer::_handleRequest() {
|
|
RequestHandler* handler;
|
|
for (handler = _firstHandler; handler; handler = handler->next)
|
|
{
|
|
if (handler->method != HTTP_ANY && handler->method != _currentMethod)
|
|
continue;
|
|
|
|
if (handler->uri != _currentUri)
|
|
continue;
|
|
|
|
handler->fn();
|
|
break;
|
|
}
|
|
|
|
if (!handler){
|
|
#ifdef DEBUG
|
|
DEBUG_OUTPUT.println("request handler not found");
|
|
#endif
|
|
|
|
if(_notFoundHandler) {
|
|
_notFoundHandler();
|
|
}
|
|
else {
|
|
send(404, "text/plain", String("Not found: ") + _currentUri);
|
|
}
|
|
}
|
|
|
|
uint16_t maxWait = HTTP_MAX_CLOSE_WAIT;
|
|
while(_currentClient.connected() && maxWait--) {
|
|
delay(1);
|
|
}
|
|
_currentClient = WiFiClient();
|
|
_currentUri = String();
|
|
}
|
|
|
|
const char* ESP8266WebServer::_responseCodeToString(int code) {
|
|
switch (code) {
|
|
case 101: return "Switching Protocols";
|
|
case 200: return "OK";
|
|
case 403: return "Forbidden";
|
|
case 404: return "Not found";
|
|
case 500: return "Fail";
|
|
default: return "";
|
|
}
|
|
}
|