1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-24 08:45:10 +03:00
esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp
2015-06-24 23:58:53 +03:00

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 "";
}
}