Skip to content

Implemented compatibility layer #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 54 commits into from
Apr 11, 2020
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7941e94
Different way of HTTPMethod->string mapping, original one didn't work…
jackjansen Dec 16, 2019
40889be
Print message when calling unimplemented method
jackjansen Dec 16, 2019
21b5c60
Added temporary platformio.ini to build the example (for easier testing)
jackjansen Dec 20, 2019
234df9b
Added a few more methods
jackjansen Dec 20, 2019
7ef82c5
Implemented Content-Length and CORS headers
jackjansen Dec 21, 2019
8407ea7
Do enableCORS differently
jackjansen Dec 21, 2019
0705226
Started on implementing serveStatic()
jackjansen Dec 21, 2019
2af21f7
Getting started on uploadHandler
jackjansen Dec 21, 2019
4a2e7c2
Switching to forked esp32_https_server, which has feature/request_par…
jackjansen Dec 21, 2019
018fcab
Removed code to test that we're actually in a request: the original W…
jackjansen Dec 21, 2019
90aae15
Implemented integer-based arg() interfaces
jackjansen Dec 21, 2019
4c5dc83
Implemented access to headers
jackjansen Dec 21, 2019
9b65938
Got rid of serveStatic() attempt: it's difficult, I don't need it and…
jackjansen Dec 21, 2019
3eafa17
Debug prints for authentication
jackjansen Dec 21, 2019
727a8b8
Implemented streamFile()
jackjansen Dec 22, 2019
f09784b
Fixed issue with setting Content-Length incorrectly if it had been se…
jackjansen Dec 22, 2019
4ef3d2b
Getting started with WebServerSecure
jackjansen Dec 22, 2019
32cdeab
Added getServer()
jackjansen Feb 7, 2020
4e3abe8
Implemented get("plain") returning BODY. Closes #2.
jackjansen Feb 8, 2020
5abd395
Attempting to add form test
jackjansen Feb 8, 2020
eddc67e
Fixed example to be buildable with platformio
jackjansen Feb 8, 2020
58daa74
Added /form to the server
jackjansen Feb 8, 2020
5a696b4
Allow NULL parameters for send() strings
jackjansen Mar 4, 2020
92bfe60
Modifying example for POST forms
jackjansen Mar 4, 2020
1476fdc
Started implementing post
jackjansen Mar 7, 2020
669f7c7
Adding .pio
jackjansen Mar 7, 2020
8a5ef92
Example fileserver copied from exp32_https_server and adapted. Untested.
jackjansen Mar 7, 2020
e24192b
Adapted FormServer example to work with normal webserver too
jackjansen Mar 8, 2020
66328c4
Implemented url-encoded parameters (which are merged with URL paramet…
jackjansen Mar 8, 2020
78c73fd
Implemented basic authentication
jackjansen Mar 8, 2020
dc8cca8
Fixed basic authentication, and test it in the edit form example
jackjansen Mar 8, 2020
d1a3062
Do basic auth using the infrastructure already implemented in esp32_h…
jackjansen Mar 8, 2020
905e6cf
Changed example to use serveStatic to serve static files
jackjansen Mar 8, 2020
a9d4489
Getting started on static page serving
jackjansen Mar 8, 2020
5da03f0
Fixed to compile. Still untested
jackjansen Mar 8, 2020
73cccc0
Static file serving working, for 1 level of directories
jackjansen Mar 9, 2020
195aaef
Updated for current state of things
jackjansen Mar 10, 2020
ac5f6cd
A bit of cleanup
jackjansen Mar 10, 2020
2323864
Cleanup
jackjansen Mar 10, 2020
0df8800
This branch has references to jackjansen for URLs, etc
jackjansen Mar 10, 2020
0fe906e
Changed URL references to fhessel
jackjansen Mar 10, 2020
d0d1353
Got rid of ino/cpp workaround that only I seem to need
jackjansen Mar 10, 2020
b6b5569
Copy key and cert to malloc()ed memory. Needed for persistency, but a…
jackjansen Apr 8, 2020
6b7af09
Initialize keyStore and certStore in all constructors
jackjansen Apr 8, 2020
e2efba8
Revert "Initialize keyStore and certStore in all constructors"
jackjansen Apr 9, 2020
5e2424b
Revert "Copy key and cert to malloc()ed memory. Needed for persistenc…
jackjansen Apr 9, 2020
cdbb718
Rationalized example to only show that three methods of form submissi…
jackjansen Apr 11, 2020
31d361f
Remove outdated file parameter
jackjansen Apr 11, 2020
689a089
Removed copy/paste turd
jackjansen Apr 11, 2020
cead0c1
No need to refer to esp32_https_server by GitHub url anymore
jackjansen Apr 11, 2020
c49ceb1
No need to refer to esp32_https_server by GitHub url anymore
jackjansen Apr 11, 2020
2c2b822
No need to refer to esp32_https_server by GitHub url anymore
jackjansen Apr 11, 2020
c571ce1
No need to refer to esp32_https_server by GitHub url anymore
jackjansen Apr 11, 2020
ce11e22
esp32_https_server is now version 1.0.0
jackjansen Apr 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.vscode
.vscode
.pio
34 changes: 14 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# esp32_https_server_compat
# esp32\_https\_server\_compat

This library is a wrapper around the [TLS-enabled web server for the ESP32 using the Arduino core](https://github.com/fhessel/esp32_https_server), to make it compatible with the [default Webserver API](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer).

Expand All @@ -8,7 +8,7 @@ The setup depends on the IDE that you're using.

### Using PlatformIO (recommended)

If you're using PlatformIO, just add esp32_https_server_compat to the library depenendencies in your platform.ini:
If you're using PlatformIO, just add `esp32\_https\_server\_compat` to the library depenendencies in your `platform.ini`:

```ini
[env:myenv]
Expand Down Expand Up @@ -37,24 +37,18 @@ void loop() {
}
```

More information and examples can be found in the default WebServer's [repository](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer).
To use the HTTPS server use `<ESPWebServerSecure.hpp>` and `ESPWebServerSecure` in stead of `ESPWebServer`.

More information and examples can be found in the default WebServer's [repository](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer). There are two minimal examples (more test programs, really) in the [examples](examples) directory.

## State of Development

This wrapper is still very WIP.

| Function | State | Comment |
| -------- | ----- | ------- |
| Starting and stopping the server | ✅ | (but not tested) |
| Handling basic requests | ✅ | `on(...)` |
| Handling 404 | ✅ | `onNotFound(...)` |
| Providing access to request properties | ✅ | `uri()`, `method()` |
| Handling file uploads | ❌ | `onFileUpload(...)`, `upload()`, and `on()` with 4 parameters |
| Handling headers | ❌ | `header()`, `headerName()`, `headers()` etc. |
| Handling arguments | ❌ | `arg()`, `argName()`, `hasArg()` etc. |
| Handling forms | ❌ | Needs [esp32_https_server#29](https://github.com/fhessel/esp32_https_server/issues/29) first. |
| Sending responses | ❌ | `send()` etc. |
| CORS and cross-origin | ❌ | Needs headers first |
| Streaming files | ❌ | `streamFile()` |
| `FS` support | ❌ | |
| TLS | ❌ | Needs `ESPWebServerSecure` that extends `ESPWebServer` |
The following issues are known:

- `serveStatic()` will serve only a single file or a single directory (as opposed to serving a whole subtree in the default WebServer).
- `serveStatic()` does not implement automatic gzip support.
- `serveStatic()` knows about only a limited set of mimetypes for file extensions.
- `authenticate()` and `requestAuthentication()` handle only `Basic` authentication, not `Digest` authentication.
- `sendHeader()` ignores the `first=true` parameter.
- `collectHeaders()` is not implemented.
- Handling of `POST` forms with mimetype `application/x-www-form-urlencoded` is memory-inefficient: the whole POST body is loaded into memory twice.
223 changes: 223 additions & 0 deletions examples/FormServer/FormServer.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
#include <WiFi.h>
#include <WiFiClient.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>
#ifdef USE_DEFAULT_WEBSERVER
#include <WebServer.h>
typedef WebServer ESPWebServer;
#else
#include <ESPWebServer.hpp>
#endif

const char* ssid = "........";
const char* password = "........";

ESPWebServer server(80);

static std::string htmlEncode(std::string data) {
const char *p = data.c_str();
std::string rv = "";
while(p && *p) {
char escapeChar = *p++;
switch(escapeChar) {
case '&': rv += "&amp;"; break;
case '<': rv += "&lt;"; break;
case '>': rv += "&gt;"; break;
case '"': rv += "&quot;"; break;
case '\'': rv += "&#x27;"; break;
case '/': rv += "&#x2F;"; break;
default: rv += escapeChar; break;
}
}
return rv;
}

void handleRoot() {
String rv;
rv += "<!DOCTYPE html>";
rv += "<html>";
rv += "<head><title>Very simple file server</title></head>";
rv += "<body>";
rv += "<h1>Very simple file server</h1>";
rv += "<p>This is a very simple file server to demonstrate the use of POST forms. </p>";
rv += "<h2>List existing files</h2>";
rv += "<p>See <a href=\"/public\">/public</a> to list existing files and retrieve or edit them.</p>";
rv += "<h2>Upload new file</h2>";
rv += "<p>This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.</p>";
rv += "<form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\">";
rv += "file: <input type=\"file\" name=\"file\"><br>";
rv += "<input type=\"submit\" value=\"Upload\">";
rv += "</form>";
rv += "</body>";
rv += "</html>";
server.send(200, "text/html", rv);
}

void handleFormEdit() {
if (!server.authenticate("admin", "admin")) return server.requestAuthentication();
bool hasFilename = server.hasArg("filename");;
String filename = server.arg("filename");
String pathname = String("/public/") + filename;
if (server.hasArg("content") ){
// Content has been edited. Save.
File file = SPIFFS.open(pathname.c_str(), "w");
String content = server.arg("content");
file.write((uint8_t *)content.c_str(), content.length());
file.close();
}
String content = server.arg("content");
String rv;
rv += "<html><head><title>Edit File</title><head><body>\n";
File file = SPIFFS.open(pathname.c_str());
if (!hasFilename) {
rv += "<p>No filename specified.</p>\n";
} else if (!file.available()) {
rv += "<p>File not found:";
rv += pathname;
rv += "</p>\n";
} else {
rv += "<h2>Edit content of ";
rv += pathname;
rv += "</h2>\n";
rv += "<form method=\"POST\" enctype=\"application/x-www-form-urlencoded\">\n";
rv += "<input name=\"filename\" type=\"hidden\" value=\"";
rv += filename;
rv += "\">\n";
rv += "<textarea name=\"content\" rows=\"24\" cols=\"80\">";
// Read the file and write it to the response
size_t length = 0;
do {
char buffer[256];
length = file.read((uint8_t *)buffer, 256);
std::string bufferString(buffer, length);
bufferString = htmlEncode(bufferString);
rv += String(bufferString.c_str());
} while (length > 0);
rv += "</textarea><br>";
rv += "<input type=\"submit\" value=\"Save\">";
rv += "</form>";
}
rv += "</body></html>";
server.send(200, "text/html", rv);
}

void handleFormUpload() {
Serial.println("handleUpload() called");
server.send(200);
}

File fsUploadFile;

void handleFormUploadFile() {
Serial.println("handleUploadFile() called");
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
String filename = String("/public/") + upload.filename;
Serial.printf("upload filename=%s\n", filename.c_str());
Serial.print("handleFileUpload Name: "); Serial.println(filename);
fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist)
} else if(upload.status == UPLOAD_FILE_WRITE){
Serial.printf("uploaded %d bytes\n", upload.currentSize);
if(fsUploadFile)
fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file
} else if(upload.status == UPLOAD_FILE_END){
Serial.printf("upload total %d bytes\n", upload.totalSize);
if(fsUploadFile) { // If the file was successfully created
fsUploadFile.close(); // Close the file again
Serial.print("handleFileUpload Size: "); Serial.println(upload.totalSize);
server.sendHeader("Location","/public"); // Redirect the client to the success page
server.send(303);
} else {
server.send(500, "text/plain", "500: couldn't create file");
}
server.send(200, "text/plain", "OK");
}
}

void handleDirectory() {
String rv;
rv += "<html><head><title>File Listing</title><head><body>\n";
File d = SPIFFS.open("/public");
if (!d.isDirectory()) {
rv += "<p>No files found.</p>\n";
} else {
rv += "<h1>File Listing</h1>\n";
rv += "<ul>\n";
File f = d.openNextFile();
while (f) {
std::string pathname(f.name());
std::string filename = pathname.substr(8); // Remove /public/
rv += "<li><a href=\"";
rv += String(pathname.c_str());
rv += "\">";
rv += String(filename.c_str());
rv += "</a>";
if (pathname.rfind(".txt") != std::string::npos) {
rv += " <a href=\"/edit?filename=";
rv += String(filename.c_str());
rv += "\">[edit]</a>";
}
rv += "</li>";
f = d.openNextFile();
}
rv += "</ul>";
}
rv += "</body></html>";
server.send(200, "text/html", rv);
}

void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}

void setup(void) {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

if (MDNS.begin("esp32")) {
Serial.println("MDNS responder started");
}
// Setup filesystem
if (!SPIFFS.begin(true)) Serial.println("Mounting SPIFFS failed");

server.on("/", handleRoot);
server.on("/upload", HTTP_POST, handleFormUpload, handleFormUploadFile);
server.on("/edit", HTTP_GET, handleFormEdit);
server.on("/edit", HTTP_POST, handleFormEdit);
// Note: /public (without trailing /) gives directory listing, but /public/... retrieves static files.
server.on("/public", HTTP_GET, handleDirectory);
server.serveStatic("/public/", SPIFFS, "/public/");

server.onNotFound(handleNotFound);

server.begin();
Serial.println("HTTP server started");
}

void loop(void) {
server.handleClient();
}
Loading