mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-19 23:22:16 +03:00
Web server refactoring
This commit is contained in:
parent
eb37830238
commit
36d0968ada
@ -34,7 +34,6 @@
|
|||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <SD.h>
|
#include <SD.h>
|
||||||
|
|
||||||
#define WWW_BUF_SIZE 1460
|
|
||||||
#define DBG_OUTPUT_PORT Serial
|
#define DBG_OUTPUT_PORT Serial
|
||||||
|
|
||||||
const char* ssid = "**********";
|
const char* ssid = "**********";
|
||||||
@ -47,28 +46,17 @@ ESP8266WebServer server(80);
|
|||||||
static bool hasSD = false;
|
static bool hasSD = false;
|
||||||
File uploadFile;
|
File uploadFile;
|
||||||
|
|
||||||
void returnOK(){
|
|
||||||
WiFiClient client = server.client();
|
void returnOK() {
|
||||||
String message = "HTTP/1.1 200 OK\r\n";
|
server.sendHeader("Connection", "close");
|
||||||
message += "Content-Type: text/plain\r\n";
|
server.sendHeader("Access-Control-Allow-Origin", "*");
|
||||||
message += "Connection: close\r\n";
|
server.send(200, "text/plain", "");
|
||||||
message += "Access-Control-Allow-Origin: *\r\n";
|
|
||||||
message += "\r\n";
|
|
||||||
client.print(message);
|
|
||||||
client.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void returnFail(String msg){
|
void returnFail(String msg) {
|
||||||
WiFiClient client = server.client();
|
server.sendHeader("Connection", "close");
|
||||||
String message = "HTTP/1.1 500 Fail\r\n";
|
server.sendHeader("Access-Control-Allow-Origin", "*");
|
||||||
message += "Content-Type: text/plain\r\n";
|
server.send(500, "text/plain", msg + "\r\n");
|
||||||
message += "Connection: close\r\n";
|
|
||||||
message += "Access-Control-Allow-Origin: *\r\n";
|
|
||||||
message += "\r\n";
|
|
||||||
message += msg;
|
|
||||||
message += "\r\n";
|
|
||||||
client.print(message);
|
|
||||||
client.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loadFromSdCard(String path){
|
bool loadFromSdCard(String path){
|
||||||
@ -94,58 +82,39 @@ bool loadFromSdCard(String path){
|
|||||||
dataFile = SD.open(path.c_str());
|
dataFile = SD.open(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dataFile)
|
||||||
|
return false;
|
||||||
|
|
||||||
if(server.hasArg("download")) dataType = "application/octet-stream";
|
if(server.hasArg("download")) dataType = "application/octet-stream";
|
||||||
|
|
||||||
if (dataFile) {
|
server.sendHeader("Content-Length", String(dataFile.size()));
|
||||||
|
server.sendHeader("Connection", "close");
|
||||||
|
server.sendHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
server.send(200, dataType.c_str(), "");
|
||||||
|
|
||||||
WiFiClient client = server.client();
|
WiFiClient client = server.client();
|
||||||
String head = "HTTP/1.1 200 OK\r\nContent-Type: ";
|
size_t totalSize = dataFile.size();
|
||||||
head += dataType;
|
if (client.write(dataFile, PAYLOAD_UNIT_SIZE) != totalSize) {
|
||||||
head += "\r\nContent-Length: ";
|
|
||||||
head += dataFile.size();
|
|
||||||
head += "\r\nConnection: close";
|
|
||||||
head += "\r\nAccess-Control-Allow-Origin: *";
|
|
||||||
head += "\r\n\r\n";
|
|
||||||
client.print(head);
|
|
||||||
dataType = String();
|
|
||||||
path = String();
|
|
||||||
|
|
||||||
uint8_t obuf[WWW_BUF_SIZE];
|
|
||||||
|
|
||||||
while (dataFile.available() > WWW_BUF_SIZE){
|
|
||||||
dataFile.read(obuf, WWW_BUF_SIZE);
|
|
||||||
if(client.write(obuf, WWW_BUF_SIZE) != WWW_BUF_SIZE){
|
|
||||||
DBG_OUTPUT_PORT.println("Sent less data than expected!");
|
DBG_OUTPUT_PORT.println("Sent less data than expected!");
|
||||||
|
}
|
||||||
|
|
||||||
dataFile.close();
|
dataFile.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
uint16_t leftLen = dataFile.available();
|
|
||||||
dataFile.read(obuf, leftLen);
|
|
||||||
if(client.write(obuf, leftLen) != leftLen){
|
|
||||||
DBG_OUTPUT_PORT.println("Sent less data than expected!");
|
|
||||||
dataFile.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
dataFile.close();
|
|
||||||
client.stop();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleFileUpload(){
|
void handleFileUpload(){
|
||||||
if(server.uri() != "/edit") return;
|
if(server.uri() != "/edit") return;
|
||||||
HTTPUpload upload = server.upload();
|
HTTPUpload& upload = server.upload();
|
||||||
if(upload.status == UPLOAD_FILE_START){
|
if(upload.status == UPLOAD_FILE_START){
|
||||||
if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str());
|
if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str());
|
||||||
uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
|
uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
|
||||||
DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename);
|
DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename);
|
||||||
} else if(upload.status == UPLOAD_FILE_WRITE){
|
} else if(upload.status == UPLOAD_FILE_WRITE){
|
||||||
if(uploadFile) uploadFile.write(upload.buf, upload.buflen);
|
if(uploadFile) uploadFile.write(upload.buf, upload.currentSize);
|
||||||
DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.buflen);
|
DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.currentSize);
|
||||||
} else if(upload.status == UPLOAD_FILE_END){
|
} else if(upload.status == UPLOAD_FILE_END){
|
||||||
if(uploadFile) uploadFile.close();
|
if(uploadFile) uploadFile.close();
|
||||||
DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.size);
|
DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,13 +125,12 @@ void deleteRecursive(String path){
|
|||||||
SD.remove((char *)path.c_str());
|
SD.remove((char *)path.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.rewindDirectory();
|
file.rewindDirectory();
|
||||||
File entry;
|
|
||||||
String entryPath;
|
|
||||||
while(true) {
|
while(true) {
|
||||||
entry = file.openNextFile();
|
File entry = file.openNextFile();
|
||||||
if (!entry) break;
|
if (!entry) break;
|
||||||
entryPath = path + "/" +entry.name();
|
String entryPath = path + "/" +entry.name();
|
||||||
if(entry.isDirectory()){
|
if(entry.isDirectory()){
|
||||||
entry.close();
|
entry.close();
|
||||||
deleteRecursive(entryPath);
|
deleteRecursive(entryPath);
|
||||||
@ -170,27 +138,32 @@ void deleteRecursive(String path){
|
|||||||
entry.close();
|
entry.close();
|
||||||
SD.remove((char *)entryPath.c_str());
|
SD.remove((char *)entryPath.c_str());
|
||||||
}
|
}
|
||||||
entryPath = String();
|
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
SD.rmdir((char *)path.c_str());
|
SD.rmdir((char *)path.c_str());
|
||||||
path = String();
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleDelete(){
|
void handleDelete(){
|
||||||
if(server.args() == 0) return returnFail("BAD ARGS");
|
if(server.args() == 0) return returnFail("BAD ARGS");
|
||||||
String path = server.arg(0);
|
String path = server.arg(0);
|
||||||
if(path == "/" || !SD.exists((char *)path.c_str())) return returnFail("BAD PATH");
|
if(path == "/" || !SD.exists((char *)path.c_str())) {
|
||||||
|
returnFail("BAD PATH");
|
||||||
|
return;
|
||||||
|
}
|
||||||
deleteRecursive(path);
|
deleteRecursive(path);
|
||||||
returnOK();
|
returnOK();
|
||||||
path = String();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleCreate(){
|
void handleCreate(){
|
||||||
if(server.args() == 0) return returnFail("BAD ARGS");
|
if(server.args() == 0) return returnFail("BAD ARGS");
|
||||||
String path = server.arg(0);
|
String path = server.arg(0);
|
||||||
if(path == "/" || SD.exists((char *)path.c_str())) return returnFail("BAD PATH");
|
if(path == "/" || SD.exists((char *)path.c_str())) {
|
||||||
|
returnFail("BAD PATH");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(path.indexOf('.') > 0){
|
if(path.indexOf('.') > 0){
|
||||||
File file = SD.open((char *)path.c_str(), FILE_WRITE);
|
File file = SD.open((char *)path.c_str(), FILE_WRITE);
|
||||||
if(file){
|
if(file){
|
||||||
@ -201,7 +174,6 @@ void handleCreate(){
|
|||||||
SD.mkdir((char *)path.c_str());
|
SD.mkdir((char *)path.c_str());
|
||||||
}
|
}
|
||||||
returnOK();
|
returnOK();
|
||||||
path = String();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void printDirectory() {
|
void printDirectory() {
|
||||||
@ -216,31 +188,31 @@ void printDirectory() {
|
|||||||
}
|
}
|
||||||
dir.rewindDirectory();
|
dir.rewindDirectory();
|
||||||
|
|
||||||
File entry;
|
server.send(200, "text/json", "");
|
||||||
WiFiClient client = server.client();
|
WiFiClient client = server.client();
|
||||||
client.print("HTTP/1.1 200 OK\r\nContent-Type: text/json\r\n\r\n");
|
|
||||||
String output = "[";
|
for (int cnt = 0; true; ++cnt) {
|
||||||
while(true) {
|
File entry = dir.openNextFile();
|
||||||
entry = dir.openNextFile();
|
if (!entry)
|
||||||
if (!entry) break;
|
break;
|
||||||
if(output != "[") output += ',';
|
|
||||||
|
String output;
|
||||||
|
if (cnt == 0)
|
||||||
|
output = '[';
|
||||||
|
else
|
||||||
|
output = ',';
|
||||||
|
|
||||||
output += "{\"type\":\"";
|
output += "{\"type\":\"";
|
||||||
output += (entry.isDirectory())?"dir":"file";
|
output += (entry.isDirectory()) ? "dir" : "file";
|
||||||
output += "\",\"name\":\"";
|
output += "\",\"name\":\"";
|
||||||
output += entry.name();
|
output += entry.name();
|
||||||
output += "\"";
|
output += "\"";
|
||||||
output += "}";
|
output += "}";
|
||||||
|
server.sendContent(output);
|
||||||
entry.close();
|
entry.close();
|
||||||
if(output.length() > 1460){
|
|
||||||
client.write(output.substring(0, 1460).c_str(), 1460);
|
|
||||||
output = output.substring(1460);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
server.sendContent("]");
|
||||||
dir.close();
|
dir.close();
|
||||||
output += "]";
|
|
||||||
client.write(output.c_str(), output.length());
|
|
||||||
client.stop();
|
|
||||||
output = String();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNotFound(){
|
void handleNotFound(){
|
||||||
@ -280,14 +252,14 @@ void setup(void){
|
|||||||
}
|
}
|
||||||
DBG_OUTPUT_PORT.print("Connected! IP address: ");
|
DBG_OUTPUT_PORT.print("Connected! IP address: ");
|
||||||
DBG_OUTPUT_PORT.println(WiFi.localIP());
|
DBG_OUTPUT_PORT.println(WiFi.localIP());
|
||||||
/*
|
|
||||||
if (mdns.begin(hostname, WiFi.localIP())) {
|
if (mdns.begin(hostname, WiFi.localIP())) {
|
||||||
DBG_OUTPUT_PORT.println("MDNS responder started");
|
DBG_OUTPUT_PORT.println("MDNS responder started");
|
||||||
DBG_OUTPUT_PORT.print("You can now connect to http://");
|
DBG_OUTPUT_PORT.print("You can now connect to http://");
|
||||||
DBG_OUTPUT_PORT.print(hostname);
|
DBG_OUTPUT_PORT.print(hostname);
|
||||||
DBG_OUTPUT_PORT.println(".local");
|
DBG_OUTPUT_PORT.println(".local");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
server.on("/list", HTTP_GET, printDirectory);
|
server.on("/list", HTTP_GET, printDirectory);
|
||||||
server.on("/edit", HTTP_DELETE, handleDelete);
|
server.on("/edit", HTTP_DELETE, handleDelete);
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
#include "WiFiClient.h"
|
#include "WiFiClient.h"
|
||||||
#include "ESP8266WebServer.h"
|
#include "ESP8266WebServer.h"
|
||||||
|
|
||||||
//#define DEBUG
|
// #define DEBUG
|
||||||
#define DEBUG_OUTPUT Serial1
|
#define DEBUG_OUTPUT Serial
|
||||||
|
|
||||||
struct ESP8266WebServer::RequestHandler {
|
struct ESP8266WebServer::RequestHandler {
|
||||||
RequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
|
RequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
|
||||||
@ -99,110 +99,32 @@ void ESP8266WebServer::handleClient()
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
DEBUG_OUTPUT.println("New client");
|
DEBUG_OUTPUT.println("New client");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Wait for data from client to become available
|
// Wait for data from client to become available
|
||||||
while(client.connected() && !client.available()){
|
while(client.connected() && !client.available()){
|
||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the first line of HTTP request
|
if (!_parseRequest(client)) {
|
||||||
String req = client.readStringUntil('\r');
|
|
||||||
client.readStringUntil('\n');
|
|
||||||
|
|
||||||
// First line of HTTP request looks like "GET /path HTTP/1.1"
|
|
||||||
// Retrieve the "/path" part by finding the spaces
|
|
||||||
int addr_start = req.indexOf(' ');
|
|
||||||
int addr_end = req.indexOf(' ', addr_start + 1);
|
|
||||||
if (addr_start == -1 || addr_end == -1) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("Invalid request: ");
|
|
||||||
DEBUG_OUTPUT.println(req);
|
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String methodStr = req.substring(0, addr_start);
|
_currentClient = client;
|
||||||
String url = req.substring(addr_start + 1, addr_end);
|
_handleRequest();
|
||||||
String searchStr = "";
|
}
|
||||||
int hasSearch = url.indexOf('?');
|
|
||||||
if(hasSearch != -1){
|
|
||||||
searchStr = url.substring(hasSearch + 1);
|
|
||||||
url = url.substring(0, hasSearch);
|
|
||||||
}
|
|
||||||
_currentUri = url;
|
|
||||||
|
|
||||||
HTTPMethod method = HTTP_GET;
|
void ESP8266WebServer::sendHeader(String name, String value, bool first) {
|
||||||
if (methodStr == "POST") {
|
String headerLine = name;
|
||||||
method = HTTP_POST;
|
headerLine += ": ";
|
||||||
} else if (methodStr == "DELETE") {
|
headerLine += value;
|
||||||
method = HTTP_DELETE;
|
headerLine += "\r\n";
|
||||||
} else if (methodStr == "PUT") {
|
|
||||||
method = HTTP_PUT;
|
|
||||||
} else if (methodStr == "PATCH") {
|
|
||||||
method = HTTP_PATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
if (first) {
|
||||||
DEBUG_OUTPUT.print("method: ");
|
_responseHeaders = headerLine + _responseHeaders;
|
||||||
DEBUG_OUTPUT.print(methodStr);
|
|
||||||
DEBUG_OUTPUT.print(" url: ");
|
|
||||||
DEBUG_OUTPUT.print(url);
|
|
||||||
DEBUG_OUTPUT.print(" search: ");
|
|
||||||
DEBUG_OUTPUT.println(searchStr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String formData;
|
|
||||||
//bellow is needed only when POST type request
|
|
||||||
if(method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){
|
|
||||||
String boundaryStr;
|
|
||||||
String headerName;
|
|
||||||
String headerValue;
|
|
||||||
bool isForm = false;
|
|
||||||
uint32_t contentLength = 0;
|
|
||||||
//parse headers
|
|
||||||
while(1){
|
|
||||||
req = client.readStringUntil('\r');
|
|
||||||
client.readStringUntil('\n');
|
|
||||||
if(req == "") break;//no moar headers
|
|
||||||
int headerDiv = req.indexOf(':');
|
|
||||||
if(headerDiv == -1){
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
headerName = req.substring(0, headerDiv);
|
else {
|
||||||
headerValue = req.substring(headerDiv + 2);
|
_responseHeaders += headerLine;
|
||||||
if(headerName == "Content-Type"){
|
|
||||||
if(headerValue.startsWith("text/plain")){
|
|
||||||
isForm = false;
|
|
||||||
} else if(headerValue.startsWith("multipart/form-data")){
|
|
||||||
boundaryStr = headerValue.substring(headerValue.indexOf('=')+1);
|
|
||||||
isForm = true;
|
|
||||||
}
|
}
|
||||||
} else if(headerName == "Content-Length"){
|
|
||||||
contentLength = headerValue.toInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!isForm){
|
|
||||||
if(searchStr != "") searchStr += '&';
|
|
||||||
searchStr += client.readStringUntil('\r');
|
|
||||||
client.readStringUntil('\n');
|
|
||||||
}
|
|
||||||
_parseArguments(searchStr);
|
|
||||||
if(isForm){
|
|
||||||
_parseForm(client, boundaryStr, contentLength);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_parseArguments(searchStr);
|
|
||||||
}
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("Request: ");
|
|
||||||
DEBUG_OUTPUT.println(url);
|
|
||||||
DEBUG_OUTPUT.print(" Arguments: ");
|
|
||||||
DEBUG_OUTPUT.println(searchStr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_handleRequest(client, url, method);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::send(int code, const char* content_type, String content) {
|
void ESP8266WebServer::send(int code, const char* content_type, String content) {
|
||||||
@ -214,11 +136,28 @@ void ESP8266WebServer::send(int code, const char* content_type, String content)
|
|||||||
|
|
||||||
if (!content_type)
|
if (!content_type)
|
||||||
content_type = "text/html";
|
content_type = "text/html";
|
||||||
_appendHeader(response, "Content-Type", content_type);
|
sendHeader("Content-Type", content_type, true);
|
||||||
|
|
||||||
|
response += _responseHeaders;
|
||||||
response += "\r\n";
|
response += "\r\n";
|
||||||
response += content;
|
response += content;
|
||||||
_currentClient.print(response);
|
_responseHeaders = String();
|
||||||
|
sendContent(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266WebServer::sendContent(String content) {
|
||||||
|
size_t size_to_send = content.length();
|
||||||
|
size_t size_sent = 0;
|
||||||
|
while(size_to_send) {
|
||||||
|
const size_t unit_size = PAYLOAD_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) {
|
String ESP8266WebServer::arg(const char* name) {
|
||||||
@ -253,298 +192,6 @@ bool ESP8266WebServer::hasArg(const char* name) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::_parseArguments(String data) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("args: ");
|
|
||||||
DEBUG_OUTPUT.println(data);
|
|
||||||
#endif
|
|
||||||
if (_currentArgs)
|
|
||||||
delete[] _currentArgs;
|
|
||||||
_currentArgs = 0;
|
|
||||||
if (data.length() == 0) {
|
|
||||||
_currentArgCount = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_currentArgCount = 1;
|
|
||||||
|
|
||||||
for (int i = 0; i < data.length(); ) {
|
|
||||||
i = data.indexOf('&', i);
|
|
||||||
if (i == -1)
|
|
||||||
break;
|
|
||||||
++i;
|
|
||||||
++_currentArgCount;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("args count: ");
|
|
||||||
DEBUG_OUTPUT.println(_currentArgCount);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_currentArgs = new RequestArgument[_currentArgCount];
|
|
||||||
int pos = 0;
|
|
||||||
int iarg;
|
|
||||||
for (iarg = 0; iarg < _currentArgCount;) {
|
|
||||||
int equal_sign_index = data.indexOf('=', pos);
|
|
||||||
int next_arg_index = data.indexOf('&', pos);
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("pos ");
|
|
||||||
DEBUG_OUTPUT.print(pos);
|
|
||||||
DEBUG_OUTPUT.print("=@ ");
|
|
||||||
DEBUG_OUTPUT.print(equal_sign_index);
|
|
||||||
DEBUG_OUTPUT.print(" &@ ");
|
|
||||||
DEBUG_OUTPUT.println(next_arg_index);
|
|
||||||
#endif
|
|
||||||
if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("arg missing value: ");
|
|
||||||
DEBUG_OUTPUT.println(iarg);
|
|
||||||
#endif
|
|
||||||
if (next_arg_index == -1)
|
|
||||||
break;
|
|
||||||
pos = next_arg_index + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
RequestArgument& arg = _currentArgs[iarg];
|
|
||||||
arg.key = data.substring(pos, equal_sign_index);
|
|
||||||
arg.value = data.substring(equal_sign_index + 1, next_arg_index);
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("arg ");
|
|
||||||
DEBUG_OUTPUT.print(iarg);
|
|
||||||
DEBUG_OUTPUT.print(" key: ");
|
|
||||||
DEBUG_OUTPUT.print(arg.key);
|
|
||||||
DEBUG_OUTPUT.print(" value: ");
|
|
||||||
DEBUG_OUTPUT.println(arg.value);
|
|
||||||
#endif
|
|
||||||
++iarg;
|
|
||||||
if (next_arg_index == -1)
|
|
||||||
break;
|
|
||||||
pos = next_arg_index + 1;
|
|
||||||
}
|
|
||||||
_currentArgCount = iarg;
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("args count: ");
|
|
||||||
DEBUG_OUTPUT.println(_currentArgCount);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
|
|
||||||
DEBUG_OUTPUT.print(boundary);
|
|
||||||
DEBUG_OUTPUT.print("Length: ");
|
|
||||||
DEBUG_OUTPUT.println(len);
|
|
||||||
#endif
|
|
||||||
String line;
|
|
||||||
line = client.readStringUntil('\r');
|
|
||||||
client.readStringUntil('\n');
|
|
||||||
//start reading the form
|
|
||||||
if(line == ("--"+boundary)){
|
|
||||||
RequestArgument* postArgs = new RequestArgument[32];
|
|
||||||
int postArgsLen = 0;
|
|
||||||
while(1){
|
|
||||||
String argName;
|
|
||||||
String argValue;
|
|
||||||
String argType;
|
|
||||||
String argFilename;
|
|
||||||
bool argIsFile = false;
|
|
||||||
|
|
||||||
line = client.readStringUntil('\r');
|
|
||||||
client.readStringUntil('\n');
|
|
||||||
if(line.startsWith("Content-Disposition")){
|
|
||||||
int nameStart = line.indexOf('=');
|
|
||||||
if(nameStart != -1){
|
|
||||||
argName = line.substring(nameStart+2);
|
|
||||||
nameStart = argName.indexOf('=');
|
|
||||||
if(nameStart == -1){
|
|
||||||
argName = argName.substring(0, argName.length() - 1);
|
|
||||||
} else {
|
|
||||||
argFilename = argName.substring(nameStart+2, argName.length() - 1);
|
|
||||||
argName = argName.substring(0, argName.indexOf('"'));
|
|
||||||
argIsFile = true;
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("PostArg FileName: ");
|
|
||||||
DEBUG_OUTPUT.println(argFilename);
|
|
||||||
#endif
|
|
||||||
//use GET to set the filename if uploading using blob
|
|
||||||
if(argFilename == "blob" && hasArg("filename")) argFilename = arg("filename");
|
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("PostArg Name: ");
|
|
||||||
DEBUG_OUTPUT.println(argName);
|
|
||||||
#endif
|
|
||||||
argType = "text/plain";
|
|
||||||
line = client.readStringUntil('\r');
|
|
||||||
client.readStringUntil('\n');
|
|
||||||
if(line.startsWith("Content-Type")){
|
|
||||||
argType = line.substring(line.indexOf(':')+2);
|
|
||||||
//skip next line
|
|
||||||
client.readStringUntil('\r');
|
|
||||||
client.readStringUntil('\n');
|
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("PostArg Type: ");
|
|
||||||
DEBUG_OUTPUT.println(argType);
|
|
||||||
#endif
|
|
||||||
if(!argIsFile){
|
|
||||||
while(1){
|
|
||||||
line = client.readStringUntil('\r');
|
|
||||||
client.readStringUntil('\n');
|
|
||||||
if(line.startsWith("--"+boundary)) break;
|
|
||||||
if(argValue.length() > 0) argValue += "\n";
|
|
||||||
argValue += line;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("PostArg Value: ");
|
|
||||||
DEBUG_OUTPUT.println(argValue);
|
|
||||||
DEBUG_OUTPUT.println();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RequestArgument& arg = postArgs[postArgsLen++];
|
|
||||||
arg.key = argName;
|
|
||||||
arg.value = argValue;
|
|
||||||
|
|
||||||
if(line == ("--"+boundary+"--")){
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.println("Done Parsing POST");
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_currentUpload.status = UPLOAD_FILE_START;
|
|
||||||
_currentUpload.name = argName;
|
|
||||||
_currentUpload.filename = argFilename;
|
|
||||||
_currentUpload.type = argType;
|
|
||||||
_currentUpload.size = 0;
|
|
||||||
_currentUpload.buflen = 0;
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("Start File: ");
|
|
||||||
DEBUG_OUTPUT.print(_currentUpload.filename);
|
|
||||||
DEBUG_OUTPUT.print(" Type: ");
|
|
||||||
DEBUG_OUTPUT.println(_currentUpload.type);
|
|
||||||
#endif
|
|
||||||
if(_fileUploadHandler) _fileUploadHandler();
|
|
||||||
_currentUpload.status = UPLOAD_FILE_WRITE;
|
|
||||||
uint8_t argByte = client.read();
|
|
||||||
readfile:
|
|
||||||
while(argByte != 0x0D){
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = argByte;
|
|
||||||
if(_currentUpload.buflen == 1460){
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.println("Write File: 1460");
|
|
||||||
#endif
|
|
||||||
if(_fileUploadHandler) _fileUploadHandler();
|
|
||||||
_currentUpload.size += _currentUpload.buflen;
|
|
||||||
_currentUpload.buflen = 0;
|
|
||||||
}
|
|
||||||
argByte = client.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
argByte = client.read();
|
|
||||||
if(argByte == 0x0A){
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("Write File: ");
|
|
||||||
DEBUG_OUTPUT.println(_currentUpload.buflen);
|
|
||||||
#endif
|
|
||||||
if(_fileUploadHandler) _fileUploadHandler();
|
|
||||||
_currentUpload.size += _currentUpload.buflen;
|
|
||||||
_currentUpload.buflen = 0;
|
|
||||||
|
|
||||||
argByte = client.read();
|
|
||||||
if((char)argByte != '-'){
|
|
||||||
//continue reading the file
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0A;
|
|
||||||
goto readfile;
|
|
||||||
} else {
|
|
||||||
argByte = client.read();
|
|
||||||
if((char)argByte != '-'){
|
|
||||||
//continue reading the file
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0A;
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = (uint8_t)('-');
|
|
||||||
goto readfile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t endBuf[boundary.length()];
|
|
||||||
client.readBytes(endBuf, boundary.length());
|
|
||||||
|
|
||||||
if(strstr((const char*)endBuf, (const char*)(boundary.c_str())) != NULL){
|
|
||||||
_currentUpload.status = UPLOAD_FILE_END;
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.print("End File: ");
|
|
||||||
DEBUG_OUTPUT.print(_currentUpload.filename);
|
|
||||||
DEBUG_OUTPUT.print(" Type: ");
|
|
||||||
DEBUG_OUTPUT.print(_currentUpload.type);
|
|
||||||
DEBUG_OUTPUT.print(" Size: ");
|
|
||||||
DEBUG_OUTPUT.println(_currentUpload.size);
|
|
||||||
#endif
|
|
||||||
if(_fileUploadHandler) _fileUploadHandler();
|
|
||||||
line = client.readStringUntil(0x0D);
|
|
||||||
client.readStringUntil(0x0A);
|
|
||||||
if(line == "--"){
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.println("Done Parsing POST");
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0A;
|
|
||||||
uint32_t i = 0;
|
|
||||||
while(i < boundary.length()){
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = endBuf[i++];
|
|
||||||
if(_currentUpload.buflen == 1460){
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.println("Write File: 1460");
|
|
||||||
#endif
|
|
||||||
if(_fileUploadHandler) _fileUploadHandler();
|
|
||||||
_currentUpload.size += _currentUpload.buflen;
|
|
||||||
_currentUpload.buflen = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argByte = client.read();
|
|
||||||
goto readfile;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
|
|
||||||
if(_currentUpload.buflen == 1460){
|
|
||||||
#ifdef DEBUG
|
|
||||||
DEBUG_OUTPUT.println("Write File: 1460");
|
|
||||||
#endif
|
|
||||||
if(_fileUploadHandler) _fileUploadHandler();
|
|
||||||
_currentUpload.size += _currentUpload.buflen;
|
|
||||||
_currentUpload.buflen = 0;
|
|
||||||
}
|
|
||||||
goto readfile;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int iarg;
|
|
||||||
int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
|
|
||||||
for (iarg = 0; iarg < totalArgs; iarg++){
|
|
||||||
RequestArgument& arg = postArgs[postArgsLen++];
|
|
||||||
arg.key = _currentArgs[iarg].key;
|
|
||||||
arg.value = _currentArgs[iarg].value;
|
|
||||||
}
|
|
||||||
if (_currentArgs) delete[] _currentArgs;
|
|
||||||
_currentArgs = new RequestArgument[postArgsLen];
|
|
||||||
for (iarg = 0; iarg < postArgsLen; iarg++){
|
|
||||||
RequestArgument& arg = _currentArgs[iarg];
|
|
||||||
arg.key = postArgs[iarg].key;
|
|
||||||
arg.value = postArgs[iarg].value;
|
|
||||||
}
|
|
||||||
_currentArgCount = iarg;
|
|
||||||
if (postArgs) delete[] postArgs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ESP8266WebServer::onFileUpload(THandlerFunction fn) {
|
void ESP8266WebServer::onFileUpload(THandlerFunction fn) {
|
||||||
_fileUploadHandler = fn;
|
_fileUploadHandler = fn;
|
||||||
}
|
}
|
||||||
@ -553,18 +200,14 @@ void ESP8266WebServer::onNotFound(THandlerFunction fn) {
|
|||||||
_notFoundHandler = fn;
|
_notFoundHandler = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::_handleRequest(WiFiClient& client, String uri, HTTPMethod method) {
|
void ESP8266WebServer::_handleRequest() {
|
||||||
_currentClient = client;
|
|
||||||
_currentUri = uri;
|
|
||||||
_currentMethod = method;
|
|
||||||
|
|
||||||
RequestHandler* handler;
|
RequestHandler* handler;
|
||||||
for (handler = _firstHandler; handler; handler = handler->next)
|
for (handler = _firstHandler; handler; handler = handler->next)
|
||||||
{
|
{
|
||||||
if (handler->method != HTTP_ANY && handler->method != method)
|
if (handler->method != HTTP_ANY && handler->method != _currentMethod)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (handler->uri != uri)
|
if (handler->uri != _currentUri)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
handler->fn();
|
handler->fn();
|
||||||
@ -580,26 +223,19 @@ void ESP8266WebServer::_handleRequest(WiFiClient& client, String uri, HTTPMethod
|
|||||||
_notFoundHandler();
|
_notFoundHandler();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
send(404, "text/plain", String("Not found: ") + uri);
|
send(404, "text/plain", String("Not found: ") + _currentUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentClient = WiFiClient();
|
_currentClient = WiFiClient();
|
||||||
_currentUri = String();
|
_currentUri = String();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ESP8266WebServer::_responseCodeToString(int code) {
|
const char* ESP8266WebServer::_responseCodeToString(int code) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 200: return "OK";
|
case 200: return "OK";
|
||||||
case 404: return "Not found";
|
case 404: return "Not found";
|
||||||
|
case 500: return "Fail";
|
||||||
default: return "";
|
default: return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::_appendHeader(String& response, const char* name, const char* value) {
|
|
||||||
response += name;
|
|
||||||
response += ": ";
|
|
||||||
response += value;
|
|
||||||
response += "\r\n";
|
|
||||||
}
|
|
||||||
|
@ -29,14 +29,17 @@
|
|||||||
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE };
|
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE };
|
||||||
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
|
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
|
||||||
|
|
||||||
|
#define PAYLOAD_UNIT_SIZE 1460
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HTTPUploadStatus status;
|
HTTPUploadStatus status;
|
||||||
String filename;
|
String filename;
|
||||||
String name;
|
String name;
|
||||||
String type;
|
String type;
|
||||||
size_t size;
|
size_t totalSize; // file size
|
||||||
size_t buflen;
|
size_t currentSize; // size of data currently in buf
|
||||||
uint8_t buf[1460];
|
uint8_t buf[PAYLOAD_UNIT_SIZE];
|
||||||
|
|
||||||
} HTTPUpload;
|
} HTTPUpload;
|
||||||
|
|
||||||
class ESP8266WebServer
|
class ESP8266WebServer
|
||||||
@ -58,7 +61,7 @@ public:
|
|||||||
String uri() { return _currentUri; }
|
String uri() { return _currentUri; }
|
||||||
HTTPMethod method() { return _currentMethod; }
|
HTTPMethod method() { return _currentMethod; }
|
||||||
WiFiClient client() { return _currentClient; }
|
WiFiClient client() { return _currentClient; }
|
||||||
HTTPUpload upload() { return _currentUpload; }
|
HTTPUpload& upload() { return _currentUpload; }
|
||||||
|
|
||||||
String arg(const char* name); // get request argument value by name
|
String arg(const char* name); // get request argument value by name
|
||||||
String arg(int i); // get request argument value by number
|
String arg(int i); // get request argument value by number
|
||||||
@ -72,11 +75,13 @@ public:
|
|||||||
// content - actual content body
|
// content - actual content body
|
||||||
void send(int code, const char* content_type = NULL, String content = String(""));
|
void send(int code, const char* content_type = NULL, String content = String(""));
|
||||||
|
|
||||||
|
void sendHeader(String name, String value, bool first = false);
|
||||||
|
void sendContent(String content);
|
||||||
protected:
|
protected:
|
||||||
void _handleRequest(WiFiClient& client, String uri, HTTPMethod method);
|
void _handleRequest();
|
||||||
|
bool _parseRequest(WiFiClient& client);
|
||||||
void _parseArguments(String data);
|
void _parseArguments(String data);
|
||||||
static const char* _responseCodeToString(int code);
|
static const char* _responseCodeToString(int code);
|
||||||
static void _appendHeader(String& response, const char* name, const char* value);
|
|
||||||
void _parseForm(WiFiClient& client, String boundary, uint32_t len);
|
void _parseForm(WiFiClient& client, String boundary, uint32_t len);
|
||||||
|
|
||||||
struct RequestHandler;
|
struct RequestHandler;
|
||||||
@ -95,6 +100,8 @@ protected:
|
|||||||
RequestArgument* _currentArgs;
|
RequestArgument* _currentArgs;
|
||||||
HTTPUpload _currentUpload;
|
HTTPUpload _currentUpload;
|
||||||
|
|
||||||
|
String _responseHeaders;
|
||||||
|
|
||||||
RequestHandler* _firstHandler;
|
RequestHandler* _firstHandler;
|
||||||
RequestHandler* _lastHandler;
|
RequestHandler* _lastHandler;
|
||||||
THandlerFunction _notFoundHandler;
|
THandlerFunction _notFoundHandler;
|
||||||
|
428
libraries/ESP8266WebServer/src/Parsing.cpp
Normal file
428
libraries/ESP8266WebServer/src/Parsing.cpp
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
/*
|
||||||
|
Parsing.cpp - HTTP request parsing.
|
||||||
|
|
||||||
|
Copyright (c) 2015 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 Serial1
|
||||||
|
|
||||||
|
bool ESP8266WebServer::_parseRequest(WiFiClient& client) {
|
||||||
|
// Read the first line of HTTP request
|
||||||
|
String req = client.readStringUntil('\r');
|
||||||
|
client.readStringUntil('\n');
|
||||||
|
|
||||||
|
// First line of HTTP request looks like "GET /path HTTP/1.1"
|
||||||
|
// Retrieve the "/path" part by finding the spaces
|
||||||
|
int addr_start = req.indexOf(' ');
|
||||||
|
int addr_end = req.indexOf(' ', addr_start + 1);
|
||||||
|
if (addr_start == -1 || addr_end == -1) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("Invalid request: ");
|
||||||
|
DEBUG_OUTPUT.println(req);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String methodStr = req.substring(0, addr_start);
|
||||||
|
String url = req.substring(addr_start + 1, addr_end);
|
||||||
|
String searchStr = "";
|
||||||
|
int hasSearch = url.indexOf('?');
|
||||||
|
if(hasSearch != -1){
|
||||||
|
searchStr = url.substring(hasSearch + 1);
|
||||||
|
url = url.substring(0, hasSearch);
|
||||||
|
}
|
||||||
|
_currentUri = url;
|
||||||
|
|
||||||
|
HTTPMethod method = HTTP_GET;
|
||||||
|
if (methodStr == "POST") {
|
||||||
|
method = HTTP_POST;
|
||||||
|
} else if (methodStr == "DELETE") {
|
||||||
|
method = HTTP_DELETE;
|
||||||
|
} else if (methodStr == "PUT") {
|
||||||
|
method = HTTP_PUT;
|
||||||
|
} else if (methodStr == "PATCH") {
|
||||||
|
method = HTTP_PATCH;
|
||||||
|
}
|
||||||
|
_currentMethod = method;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("method: ");
|
||||||
|
DEBUG_OUTPUT.print(methodStr);
|
||||||
|
DEBUG_OUTPUT.print(" url: ");
|
||||||
|
DEBUG_OUTPUT.print(url);
|
||||||
|
DEBUG_OUTPUT.print(" search: ");
|
||||||
|
DEBUG_OUTPUT.println(searchStr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String formData;
|
||||||
|
// below is needed only when POST type request
|
||||||
|
if(method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){
|
||||||
|
String boundaryStr;
|
||||||
|
String headerName;
|
||||||
|
String headerValue;
|
||||||
|
bool isForm = false;
|
||||||
|
uint32_t contentLength = 0;
|
||||||
|
//parse headers
|
||||||
|
while(1){
|
||||||
|
req = client.readStringUntil('\r');
|
||||||
|
client.readStringUntil('\n');
|
||||||
|
if(req == "") break;//no moar headers
|
||||||
|
int headerDiv = req.indexOf(':');
|
||||||
|
if(headerDiv == -1){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
headerName = req.substring(0, headerDiv);
|
||||||
|
headerValue = req.substring(headerDiv + 2);
|
||||||
|
if(headerName == "Content-Type"){
|
||||||
|
if(headerValue.startsWith("text/plain")){
|
||||||
|
isForm = false;
|
||||||
|
} else if(headerValue.startsWith("multipart/form-data")){
|
||||||
|
boundaryStr = headerValue.substring(headerValue.indexOf('=')+1);
|
||||||
|
isForm = true;
|
||||||
|
}
|
||||||
|
} else if(headerName == "Content-Length"){
|
||||||
|
contentLength = headerValue.toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isForm){
|
||||||
|
if(searchStr != "") searchStr += '&';
|
||||||
|
searchStr += client.readStringUntil('\r');
|
||||||
|
client.readStringUntil('\n');
|
||||||
|
}
|
||||||
|
_parseArguments(searchStr);
|
||||||
|
if(isForm){
|
||||||
|
_parseForm(client, boundaryStr, contentLength);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_parseArguments(searchStr);
|
||||||
|
}
|
||||||
|
client.flush();
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("Request: ");
|
||||||
|
DEBUG_OUTPUT.println(url);
|
||||||
|
DEBUG_OUTPUT.print(" Arguments: ");
|
||||||
|
DEBUG_OUTPUT.println(searchStr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ESP8266WebServer::_parseArguments(String data) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("args: ");
|
||||||
|
DEBUG_OUTPUT.println(data);
|
||||||
|
#endif
|
||||||
|
if (_currentArgs)
|
||||||
|
delete[] _currentArgs;
|
||||||
|
_currentArgs = 0;
|
||||||
|
if (data.length() == 0) {
|
||||||
|
_currentArgCount = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_currentArgCount = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < data.length(); ) {
|
||||||
|
i = data.indexOf('&', i);
|
||||||
|
if (i == -1)
|
||||||
|
break;
|
||||||
|
++i;
|
||||||
|
++_currentArgCount;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("args count: ");
|
||||||
|
DEBUG_OUTPUT.println(_currentArgCount);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_currentArgs = new RequestArgument[_currentArgCount];
|
||||||
|
int pos = 0;
|
||||||
|
int iarg;
|
||||||
|
for (iarg = 0; iarg < _currentArgCount;) {
|
||||||
|
int equal_sign_index = data.indexOf('=', pos);
|
||||||
|
int next_arg_index = data.indexOf('&', pos);
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("pos ");
|
||||||
|
DEBUG_OUTPUT.print(pos);
|
||||||
|
DEBUG_OUTPUT.print("=@ ");
|
||||||
|
DEBUG_OUTPUT.print(equal_sign_index);
|
||||||
|
DEBUG_OUTPUT.print(" &@ ");
|
||||||
|
DEBUG_OUTPUT.println(next_arg_index);
|
||||||
|
#endif
|
||||||
|
if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("arg missing value: ");
|
||||||
|
DEBUG_OUTPUT.println(iarg);
|
||||||
|
#endif
|
||||||
|
if (next_arg_index == -1)
|
||||||
|
break;
|
||||||
|
pos = next_arg_index + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RequestArgument& arg = _currentArgs[iarg];
|
||||||
|
arg.key = data.substring(pos, equal_sign_index);
|
||||||
|
arg.value = data.substring(equal_sign_index + 1, next_arg_index);
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("arg ");
|
||||||
|
DEBUG_OUTPUT.print(iarg);
|
||||||
|
DEBUG_OUTPUT.print(" key: ");
|
||||||
|
DEBUG_OUTPUT.print(arg.key);
|
||||||
|
DEBUG_OUTPUT.print(" value: ");
|
||||||
|
DEBUG_OUTPUT.println(arg.value);
|
||||||
|
#endif
|
||||||
|
++iarg;
|
||||||
|
if (next_arg_index == -1)
|
||||||
|
break;
|
||||||
|
pos = next_arg_index + 1;
|
||||||
|
}
|
||||||
|
_currentArgCount = iarg;
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("args count: ");
|
||||||
|
DEBUG_OUTPUT.println(_currentArgCount);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
|
||||||
|
DEBUG_OUTPUT.print(boundary);
|
||||||
|
DEBUG_OUTPUT.print("Length: ");
|
||||||
|
DEBUG_OUTPUT.println(len);
|
||||||
|
#endif
|
||||||
|
String line;
|
||||||
|
line = client.readStringUntil('\r');
|
||||||
|
client.readStringUntil('\n');
|
||||||
|
//start reading the form
|
||||||
|
if(line == ("--"+boundary)){
|
||||||
|
RequestArgument* postArgs = new RequestArgument[32];
|
||||||
|
int postArgsLen = 0;
|
||||||
|
while(1){
|
||||||
|
String argName;
|
||||||
|
String argValue;
|
||||||
|
String argType;
|
||||||
|
String argFilename;
|
||||||
|
bool argIsFile = false;
|
||||||
|
|
||||||
|
line = client.readStringUntil('\r');
|
||||||
|
client.readStringUntil('\n');
|
||||||
|
if(line.startsWith("Content-Disposition")){
|
||||||
|
int nameStart = line.indexOf('=');
|
||||||
|
if(nameStart != -1){
|
||||||
|
argName = line.substring(nameStart+2);
|
||||||
|
nameStart = argName.indexOf('=');
|
||||||
|
if(nameStart == -1){
|
||||||
|
argName = argName.substring(0, argName.length() - 1);
|
||||||
|
} else {
|
||||||
|
argFilename = argName.substring(nameStart+2, argName.length() - 1);
|
||||||
|
argName = argName.substring(0, argName.indexOf('"'));
|
||||||
|
argIsFile = true;
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("PostArg FileName: ");
|
||||||
|
DEBUG_OUTPUT.println(argFilename);
|
||||||
|
#endif
|
||||||
|
//use GET to set the filename if uploading using blob
|
||||||
|
if(argFilename == "blob" && hasArg("filename")) argFilename = arg("filename");
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("PostArg Name: ");
|
||||||
|
DEBUG_OUTPUT.println(argName);
|
||||||
|
#endif
|
||||||
|
argType = "text/plain";
|
||||||
|
line = client.readStringUntil('\r');
|
||||||
|
client.readStringUntil('\n');
|
||||||
|
if(line.startsWith("Content-Type")){
|
||||||
|
argType = line.substring(line.indexOf(':')+2);
|
||||||
|
//skip next line
|
||||||
|
client.readStringUntil('\r');
|
||||||
|
client.readStringUntil('\n');
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("PostArg Type: ");
|
||||||
|
DEBUG_OUTPUT.println(argType);
|
||||||
|
#endif
|
||||||
|
if(!argIsFile){
|
||||||
|
while(1){
|
||||||
|
line = client.readStringUntil('\r');
|
||||||
|
client.readStringUntil('\n');
|
||||||
|
if(line.startsWith("--"+boundary)) break;
|
||||||
|
if(argValue.length() > 0) argValue += "\n";
|
||||||
|
argValue += line;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("PostArg Value: ");
|
||||||
|
DEBUG_OUTPUT.println(argValue);
|
||||||
|
DEBUG_OUTPUT.println();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RequestArgument& arg = postArgs[postArgsLen++];
|
||||||
|
arg.key = argName;
|
||||||
|
arg.value = argValue;
|
||||||
|
|
||||||
|
if(line == ("--"+boundary+"--")){
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.println("Done Parsing POST");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_currentUpload.status = UPLOAD_FILE_START;
|
||||||
|
_currentUpload.name = argName;
|
||||||
|
_currentUpload.filename = argFilename;
|
||||||
|
_currentUpload.type = argType;
|
||||||
|
_currentUpload.totalSize = 0;
|
||||||
|
_currentUpload.currentSize = 0;
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("Start File: ");
|
||||||
|
DEBUG_OUTPUT.print(_currentUpload.filename);
|
||||||
|
DEBUG_OUTPUT.print(" Type: ");
|
||||||
|
DEBUG_OUTPUT.println(_currentUpload.type);
|
||||||
|
#endif
|
||||||
|
if(_fileUploadHandler) _fileUploadHandler();
|
||||||
|
_currentUpload.status = UPLOAD_FILE_WRITE;
|
||||||
|
uint8_t argByte = client.read();
|
||||||
|
readfile:
|
||||||
|
while(argByte != 0x0D){
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = argByte;
|
||||||
|
if(_currentUpload.currentSize == PAYLOAD_UNIT_SIZE){
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("Write File: ");
|
||||||
|
DEBUG_OUTPUT.println(PAYLOAD_UNIT_SIZE);
|
||||||
|
#endif
|
||||||
|
if(_fileUploadHandler) _fileUploadHandler();
|
||||||
|
_currentUpload.totalSize += _currentUpload.currentSize;
|
||||||
|
_currentUpload.currentSize = 0;
|
||||||
|
}
|
||||||
|
argByte = client.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
argByte = client.read();
|
||||||
|
if(argByte == 0x0A){
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("Write File: ");
|
||||||
|
DEBUG_OUTPUT.println(_currentUpload.currentSize);
|
||||||
|
#endif
|
||||||
|
if(_fileUploadHandler) _fileUploadHandler();
|
||||||
|
_currentUpload.totalSize += _currentUpload.currentSize;
|
||||||
|
_currentUpload.currentSize = 0;
|
||||||
|
|
||||||
|
argByte = client.read();
|
||||||
|
if((char)argByte != '-'){
|
||||||
|
//continue reading the file
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = 0x0D;
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = 0x0A;
|
||||||
|
goto readfile;
|
||||||
|
} else {
|
||||||
|
argByte = client.read();
|
||||||
|
if((char)argByte != '-'){
|
||||||
|
//continue reading the file
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = 0x0D;
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = 0x0A;
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = (uint8_t)('-');
|
||||||
|
goto readfile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t endBuf[boundary.length()];
|
||||||
|
client.readBytes(endBuf, boundary.length());
|
||||||
|
|
||||||
|
if(strstr((const char*)endBuf, (const char*)(boundary.c_str())) != NULL){
|
||||||
|
_currentUpload.status = UPLOAD_FILE_END;
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("End File: ");
|
||||||
|
DEBUG_OUTPUT.print(_currentUpload.filename);
|
||||||
|
DEBUG_OUTPUT.print(" Type: ");
|
||||||
|
DEBUG_OUTPUT.print(_currentUpload.type);
|
||||||
|
DEBUG_OUTPUT.print(" Size: ");
|
||||||
|
DEBUG_OUTPUT.println(_currentUpload.totalSize);
|
||||||
|
#endif
|
||||||
|
if(_fileUploadHandler) _fileUploadHandler();
|
||||||
|
line = client.readStringUntil(0x0D);
|
||||||
|
client.readStringUntil(0x0A);
|
||||||
|
if(line == "--"){
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.println("Done Parsing POST");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = 0x0D;
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = 0x0A;
|
||||||
|
uint32_t i = 0;
|
||||||
|
while(i < boundary.length()){
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = endBuf[i++];
|
||||||
|
if(_currentUpload.currentSize == PAYLOAD_UNIT_SIZE){
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("Write File: ");
|
||||||
|
DEBUG_OUTPUT.println(PAYLOAD_UNIT_SIZE);
|
||||||
|
#endif
|
||||||
|
if(_fileUploadHandler) _fileUploadHandler();
|
||||||
|
_currentUpload.totalSize += _currentUpload.currentSize;
|
||||||
|
_currentUpload.currentSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argByte = client.read();
|
||||||
|
goto readfile;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_currentUpload.buf[_currentUpload.currentSize++] = 0x0D;
|
||||||
|
if(_currentUpload.currentSize == PAYLOAD_UNIT_SIZE){
|
||||||
|
#ifdef DEBUG
|
||||||
|
DEBUG_OUTPUT.print("Write File: ");
|
||||||
|
DEBUG_OUTPUT.println(PAYLOAD_UNIT_SIZE);
|
||||||
|
#endif
|
||||||
|
if(_fileUploadHandler) _fileUploadHandler();
|
||||||
|
_currentUpload.totalSize += _currentUpload.currentSize;
|
||||||
|
_currentUpload.currentSize = 0;
|
||||||
|
}
|
||||||
|
goto readfile;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iarg;
|
||||||
|
int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
|
||||||
|
for (iarg = 0; iarg < totalArgs; iarg++){
|
||||||
|
RequestArgument& arg = postArgs[postArgsLen++];
|
||||||
|
arg.key = _currentArgs[iarg].key;
|
||||||
|
arg.value = _currentArgs[iarg].value;
|
||||||
|
}
|
||||||
|
if (_currentArgs) delete[] _currentArgs;
|
||||||
|
_currentArgs = new RequestArgument[postArgsLen];
|
||||||
|
for (iarg = 0; iarg < postArgsLen; iarg++){
|
||||||
|
RequestArgument& arg = _currentArgs[iarg];
|
||||||
|
arg.key = postArgs[iarg].key;
|
||||||
|
arg.value = postArgs[iarg].value;
|
||||||
|
}
|
||||||
|
_currentArgCount = iarg;
|
||||||
|
if (postArgs) delete[] postArgs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,7 @@
|
|||||||
#include "Print.h"
|
#include "Print.h"
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "IPAddress.h"
|
#include "IPAddress.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class ClientContext;
|
class ClientContext;
|
||||||
class WiFiServer;
|
class WiFiServer;
|
||||||
@ -44,6 +45,9 @@ public:
|
|||||||
virtual int connect(const char *host, uint16_t port);
|
virtual int connect(const char *host, uint16_t port);
|
||||||
virtual size_t write(uint8_t);
|
virtual size_t write(uint8_t);
|
||||||
virtual size_t write(const uint8_t *buf, size_t size);
|
virtual size_t write(const uint8_t *buf, size_t size);
|
||||||
|
template <typename T>
|
||||||
|
size_t write(T& source, size_t unitSize);
|
||||||
|
|
||||||
virtual int available();
|
virtual int available();
|
||||||
virtual int read();
|
virtual int read();
|
||||||
virtual int read(uint8_t *buf, size_t size);
|
virtual int read(uint8_t *buf, size_t size);
|
||||||
@ -72,4 +76,24 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline size_t WiFiClient::write(T& source, size_t unitSize) {
|
||||||
|
std::unique_ptr<uint8_t[]> buffer(new uint8_t[unitSize]);
|
||||||
|
size_t size_sent = 0;
|
||||||
|
while(true) {
|
||||||
|
size_t left = source.available();
|
||||||
|
if (!left)
|
||||||
|
break;
|
||||||
|
size_t will_send = (left < unitSize) ? left : unitSize;
|
||||||
|
source.read(buffer.get(), will_send);
|
||||||
|
size_t cb = write(buffer.get(), will_send);
|
||||||
|
size_sent += cb;
|
||||||
|
if (cb != will_send) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size_sent;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user