Skip to content

Commit e8b2791

Browse files
committed
ESP8266WebServer: serve static files from FS
1 parent b5d9db9 commit e8b2791

File tree

3 files changed

+129
-44
lines changed

3 files changed

+129
-44
lines changed

libraries/ESP8266WebServer/src/ESP8266WebServer.cpp

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
/*
1+
/*
22
ESP8266WebServer.cpp - Dead simple web-server.
33
Supports only one simultaneous client, knows how to handle GET and POST.
44
55
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
6-
6+
77
This library is free software; you can redistribute it and/or
88
modify it under the terms of the GNU Lesser General Public
99
License as published by the Free Software Foundation; either
@@ -25,25 +25,10 @@
2525
#include "WiFiServer.h"
2626
#include "WiFiClient.h"
2727
#include "ESP8266WebServer.h"
28-
28+
#include "detail/RequestHandler.h"
2929
// #define DEBUG
3030
#define DEBUG_OUTPUT Serial
3131

32-
struct ESP8266WebServer::RequestHandler {
33-
RequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
34-
: fn(fn)
35-
, uri(uri)
36-
, method(method)
37-
, next(NULL)
38-
{
39-
}
40-
41-
ESP8266WebServer::THandlerFunction fn;
42-
String uri;
43-
HTTPMethod method;
44-
RequestHandler* next;
45-
46-
};
4732

4833
ESP8266WebServer::ESP8266WebServer(int port)
4934
: _server(port)
@@ -78,15 +63,22 @@ void ESP8266WebServer::on(const char* uri, ESP8266WebServer::THandlerFunction ha
7863

7964
void ESP8266WebServer::on(const char* uri, HTTPMethod method, ESP8266WebServer::THandlerFunction fn)
8065
{
81-
RequestHandler* handler = new RequestHandler(fn, uri, method);
82-
if (!_lastHandler) {
83-
_firstHandler = handler;
84-
_lastHandler = handler;
85-
}
86-
else {
87-
_lastHandler->next = handler;
88-
_lastHandler = handler;
89-
}
66+
_addRequestHandler(new FunctionRequestHandler(fn, uri, method));
67+
}
68+
69+
void ESP8266WebServer::_addRequestHandler(RequestHandler* handler) {
70+
if (!_lastHandler) {
71+
_firstHandler = handler;
72+
_lastHandler = handler;
73+
}
74+
else {
75+
_lastHandler->next = handler;
76+
_lastHandler = handler;
77+
}
78+
}
79+
80+
void ESP8266WebServer::serveStatic(const char* uri, FS fs, const char* path) {
81+
_addRequestHandler(new StaticRequestHandler(fs, uri));
9082
}
9183

9284
void ESP8266WebServer::handleClient()
@@ -269,16 +261,9 @@ void ESP8266WebServer::onNotFound(THandlerFunction fn) {
269261

270262
void ESP8266WebServer::_handleRequest() {
271263
RequestHandler* handler;
272-
for (handler = _firstHandler; handler; handler = handler->next)
273-
{
274-
if (handler->method != HTTP_ANY && handler->method != _currentMethod)
275-
continue;
276-
277-
if (handler->uri != _currentUri)
278-
continue;
279-
280-
handler->fn();
281-
break;
264+
for (handler = _firstHandler; handler; handler = handler->next) {
265+
if (handler->handle(*this, _currentMethod, _currentUri))
266+
break;
282267
}
283268

284269
if (!handler){

libraries/ESP8266WebServer/src/ESP8266WebServer.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
/*
1+
/*
22
ESP8266WebServer.h - Dead simple web-server.
33
Supports only one simultaneous client, knows how to handle GET and POST.
44
55
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
6-
6+
77
This library is free software; you can redistribute it and/or
88
modify it under the terms of the GNU Lesser General Public
99
License as published by the Free Software Foundation; either
@@ -25,6 +25,7 @@
2525
#define ESP8266WEBSERVER_H
2626

2727
#include <functional>
28+
#include <FS.h>
2829

2930
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE };
3031
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
@@ -37,6 +38,8 @@ enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
3738
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
3839
#define CONTENT_LENGTH_NOT_SET ((size_t) -2)
3940

41+
class RequestHandler;
42+
4043
typedef struct {
4144
HTTPUploadStatus status;
4245
String filename;
@@ -59,20 +62,21 @@ class ESP8266WebServer
5962
typedef std::function<void(void)> THandlerFunction;
6063
void on(const char* uri, THandlerFunction handler);
6164
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
65+
void serveStatic(const char* uri, FS fs, const char* path);
6266
void onNotFound(THandlerFunction fn); //called when handler is not assigned
6367
void onFileUpload(THandlerFunction fn); //handle file uploads
6468

6569
String uri() { return _currentUri; }
6670
HTTPMethod method() { return _currentMethod; }
6771
WiFiClient client() { return _currentClient; }
6872
HTTPUpload& upload() { return _currentUpload; }
69-
73+
7074
String arg(const char* name); // get request argument value by name
7175
String arg(int i); // get request argument value by number
7276
String argName(int i); // get request argument name by number
7377
int args(); // get arguments count
7478
bool hasArg(const char* name); // check if argument exists
75-
79+
7680
// send response to the client
7781
// code - HTTP response code, can be 200 or 404
7882
// content_type - HTTP content type, like "text/plain" or "image/png"
@@ -89,16 +93,17 @@ class ESP8266WebServer
8993

9094
template<typename T> size_t streamFile(T &file, const String& contentType){
9195
setContentLength(file.size());
92-
if (String(file.name()).endsWith(".gz") &&
96+
if (String(file.name()).endsWith(".gz") &&
9397
contentType != "application/x-gzip" &&
9498
contentType != "application/octet-stream"){
9599
sendHeader("Content-Encoding", "gzip");
96100
}
97101
send(200, contentType, "");
98102
return _currentClient.write(file, HTTP_DOWNLOAD_UNIT_SIZE);
99103
}
100-
104+
101105
protected:
106+
void _addRequestHandler(RequestHandler* handler);
102107
void _handleRequest();
103108
bool _parseRequest(WiFiClient& client);
104109
void _parseArguments(String data);
@@ -108,7 +113,6 @@ template<typename T> size_t streamFile(T &file, const String& contentType){
108113
uint8_t _uploadReadByte(WiFiClient& client);
109114
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
110115

111-
struct RequestHandler;
112116
struct RequestArgument {
113117
String key;
114118
String value;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#ifndef REQUESTHANDLER_H
2+
#define REQUESTHANDLER_H
3+
4+
class RequestHandler {
5+
public:
6+
RequestHandler(const char* uri, HTTPMethod method)
7+
: uri(uri)
8+
, method(method)
9+
, next(NULL)
10+
{
11+
}
12+
13+
virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) = 0;
14+
15+
RequestHandler* next;
16+
17+
protected:
18+
String uri;
19+
HTTPMethod method;
20+
};
21+
22+
23+
class FunctionRequestHandler : public RequestHandler {
24+
typedef RequestHandler base;
25+
26+
public:
27+
FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
28+
: fn(fn)
29+
, base(uri, method)
30+
{
31+
}
32+
33+
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
34+
if (method != HTTP_ANY && method != requestMethod)
35+
return false;
36+
37+
if (requestUri != uri)
38+
return false;
39+
40+
fn();
41+
return true;
42+
}
43+
44+
protected:
45+
ESP8266WebServer::THandlerFunction fn;
46+
};
47+
48+
class StaticRequestHandler : public RequestHandler {
49+
typedef RequestHandler base;
50+
51+
public:
52+
StaticRequestHandler(FS& fs, const char* uri)
53+
: fs(fs)
54+
, base(uri, HTTP_GET)
55+
{
56+
}
57+
58+
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
59+
if (requestMethod != method)
60+
return false;
61+
DEBUGV("StaticRequestHandler::handle: %s\r\n", requestUri.c_str());
62+
if (!requestUri.startsWith(uri))
63+
return false;
64+
65+
auto prefixLength = uri.length() - 1;
66+
String path = requestUri.substring(prefixLength);
67+
DEBUGV("StaticRequestHandler::handle: %d %s\r\n", prefixLength, path.c_str());
68+
File f = fs.open(path, "r");
69+
if (!f)
70+
return false;
71+
72+
server.streamFile(f, getContentType(path));
73+
return true;
74+
}
75+
76+
static String getContentType(const String& path) {
77+
if (path.endsWith(".html")) return "text/html";
78+
else if (path.endsWith(".htm")) return "text/html";
79+
else if (path.endsWith(".css")) return "text/css";
80+
else if (path.endsWith(".txt")) return "text/plain";
81+
else if (path.endsWith(".js")) return "application/javascript";
82+
else if (path.endsWith(".png")) return "image/png";
83+
else if (path.endsWith(".gif")) return "image/gif";
84+
else if (path.endsWith(".jpg")) return "image/jpeg";
85+
else if (path.endsWith(".ico")) return "image/x-icon";
86+
else if (path.endsWith(".xml")) return "text/xml";
87+
else if (path.endsWith(".pdf")) return "application/pdf";
88+
else if (path.endsWith(".zip")) return "application/zip";
89+
return "text/plain";
90+
}
91+
92+
protected:
93+
FS fs;
94+
};
95+
96+
#endif //REQUESTHANDLER_H

0 commit comments

Comments
 (0)