Skip to content

Commit 1bb3923

Browse files
authored
Merge pull request #1 from imwhocodes/cleanup
ServeStatic logic refactoring
2 parents ae3d925 + aa8419c commit 1bb3923

File tree

4 files changed

+109
-134
lines changed

4 files changed

+109
-134
lines changed

.vscode/settings.json

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"files.associations": {
3+
"__config": "cpp",
4+
"fstream": "cpp",
5+
"locale": "cpp"
6+
}
7+
}

libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h

+21-54
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,18 @@ void ESP8266WebServerTemplate<ServerType>::_addRequestHandler(RequestHandlerType
255255

256256
template <typename ServerType>
257257
void ESP8266WebServerTemplate<ServerType>::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) {
258-
_addRequestHandler(new StaticRequestHandler<ServerType>(fs, path, uri, cache_header));
258+
bool is_file = false;
259+
260+
if (fs.exists(path)) {
261+
File file = fs.open(path, "r");
262+
is_file = file && file.isFile();
263+
file.close();
264+
}
265+
266+
if(is_file)
267+
_addRequestHandler(new StaticFileRequestHandler<ServerType>(fs, path, uri, cache_header));
268+
else
269+
_addRequestHandler(new StaticDirectoryRequestHandler<ServerType>(fs, path, uri, cache_header));
259270
}
260271

261272
template <typename ServerType>
@@ -607,29 +618,18 @@ const String& ESP8266WebServerTemplate<ServerType>::header(const String& name) c
607618
return emptyString;
608619
}
609620

610-
template <typename ServerType>
611-
void ESP8266WebServerTemplate<ServerType>::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
612-
_headerKeysCount = headerKeysCount + 1;
613-
if (_currentHeaders)
614-
delete[]_currentHeaders;
615-
_currentHeaders = new RequestArgument[_headerKeysCount];
616-
_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER);
617-
for (int i = 1; i < _headerKeysCount; i++){
618-
_currentHeaders[i].key = headerKeys[i-1];
619-
}
620-
}
621621

622622
template<typename ServerType>
623-
void ESP8266WebServerETagTemplate<ServerType>::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
624-
WST::_headerKeysCount = headerKeysCount + 2;
625-
if (WST::_currentHeaders){
626-
delete[] WST::_currentHeaders;
623+
void ESP8266WebServerTemplate<ServerType>::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
624+
_headerKeysCount = headerKeysCount + 2;
625+
if (_currentHeaders){
626+
delete[] _currentHeaders;
627627
}
628-
WST::_currentHeaders = new typename WST::RequestArgument[WST::_headerKeysCount];
629-
WST::_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER);
630-
WST::_currentHeaders[1].key = FPSTR(ETAG_HEADER);
631-
for (int i = 2; i < WST::_headerKeysCount; i++){
632-
WST::_currentHeaders[i].key = headerKeys[i-2];
628+
_currentHeaders = new RequestArgument[_headerKeysCount];
629+
_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER);
630+
_currentHeaders[1].key = FPSTR(ETAG_HEADER);
631+
for (int i = 2; i < _headerKeysCount; i++){
632+
_currentHeaders[i].key = headerKeys[i-2];
633633
}
634634
}
635635

@@ -846,37 +846,4 @@ String ESP8266WebServerTemplate<ServerType>::responseCodeToString(const int code
846846
return String(r);
847847
}
848848

849-
template<typename ServerType>
850-
void ESP8266WebServerETagTemplate<ServerType>::serveStaticETag(const char* uri, FS& fs, const char* path, const char* cache_header){
851-
WST::_addRequestHandler(new StaticRequestETagHandler<ServerType>(fs, path, uri, cache_header));
852-
}
853-
854-
template<typename ServerType>
855-
void ESP8266WebServerETagTemplate<ServerType>::serveStaticETag(const char* uri, FS& fs, const char * path) {
856-
857-
File toHash = fs.open(path, "r");
858-
859-
if(toHash){
860-
861-
MD5Builder calcMD5;
862-
calcMD5.begin();
863-
864-
calcMD5.addStream(toHash, toHash.size());
865-
866-
toHash.close();
867-
868-
calcMD5.calculate();
869-
870-
uint8_t buff[16];
871-
872-
calcMD5.getBytes(buff);
873-
874-
const String etag = "\"" + base64::encode(buff, 16, false) + "\"";
875-
876-
serveStaticETag(uri, fs, path, etag.c_str());
877-
878-
}
879-
880-
}
881-
882849
} // namespace

libraries/ESP8266WebServer/src/ESP8266WebServer.h

-16
Original file line numberDiff line numberDiff line change
@@ -300,20 +300,6 @@ class ESP8266WebServerTemplate
300300
HookFunction _hook;
301301
};
302302

303-
304-
template<typename ServerType>
305-
class ESP8266WebServerETagTemplate : public ESP8266WebServerTemplate<ServerType>
306-
{
307-
using WST = ESP8266WebServerTemplate<ServerType>;
308-
309-
using WST::WST;
310-
311-
public:
312-
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount);
313-
void serveStaticETag(const char* uri, FS& fs, const char* path, const char* cache_header);
314-
void serveStaticETag(const char* uri, FS& fs, const char* path);
315-
};
316-
317303
} // namespace
318304

319305
#include "ESP8266WebServer-impl.h"
@@ -322,6 +308,4 @@ class ESP8266WebServerETagTemplate : public ESP8266WebServerTemplate<ServerType>
322308
using ESP8266WebServer = esp8266webserver::ESP8266WebServerTemplate<WiFiServer>;
323309
using RequestHandler = esp8266webserver::RequestHandler<WiFiServer>;
324310

325-
using ESP8266WebServerETag = esp8266webserver::ESP8266WebServerETagTemplate<WiFiServer>;
326-
327311
#endif //ESP8266WEBSERVER_H

libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h

+81-64
Original file line numberDiff line numberDiff line change
@@ -72,70 +72,82 @@ class StaticRequestHandler : public RequestHandler<ServerType> {
7272
, _path(path)
7373
, _cache_header(cache_header)
7474
{
75-
if (fs.exists(path)) {
76-
File file = fs.open(path, "r");
77-
_isFile = file && file.isFile();
78-
file.close();
79-
}
80-
else {
81-
_isFile = false;
82-
}
83-
8475
DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header == __null ? "" : cache_header);
85-
_baseUriLength = _uri.length();
8676
}
8777

88-
bool canHandle(HTTPMethod requestMethod, const String& requestUri) override {
89-
if ((requestMethod != HTTP_GET) && (requestMethod != HTTP_HEAD))
90-
return false;
78+
bool validMethod(HTTPMethod requestMethod){
79+
return (requestMethod == HTTP_GET) || (requestMethod == HTTP_HEAD);
80+
}
9181

92-
if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri))
93-
return false;
82+
/* Deprecated version. Please use mime::getContentType instead */
83+
static String getContentType(const String& path) __attribute__((deprecated)) {
84+
return mime::getContentType(path);
85+
}
9486

95-
return true;
87+
protected:
88+
FS _fs;
89+
String _uri;
90+
String _path;
91+
String _cache_header;
92+
};
93+
94+
95+
template<typename ServerType>
96+
class StaticDirectoryRequestHandler : public StaticRequestHandler<ServerType> {
97+
98+
using SRH = StaticRequestHandler<ServerType>;
99+
using WebServerType = ESP8266WebServerTemplate<ServerType>;
100+
101+
public:
102+
StaticDirectoryRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
103+
:
104+
SRH(fs, path, uri, cache_header),
105+
_baseUriLength{SRH::_uri.length()}
106+
{}
107+
108+
bool canHandle(HTTPMethod requestMethod, const String& requestUri) override {
109+
return SRH::validMethod(requestMethod) && requestUri.startsWith(SRH::_uri);
96110
}
97111

98112
bool handle(WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override {
99113

100114
if (!canHandle(requestMethod, requestUri))
101115
return false;
102116

103-
DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str());
117+
DEBUGV("DirectoryRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), SRH::_uri.c_str());
104118

105119
String path;
106-
path.reserve(_path.length() + requestUri.length() + 32);
107-
path = _path;
108-
109-
if (!_isFile) {
120+
path.reserve(SRH::_path.length() + requestUri.length() + 32);
121+
path = SRH::_path;
110122

111-
// Append whatever follows this URI in request to get the file path.
112-
path += requestUri.substring(_baseUriLength);
123+
// Append whatever follows this URI in request to get the file path.
124+
path += requestUri.substring(_baseUriLength);
113125

114-
// Base URI doesn't point to a file.
115-
// If a directory is requested, look for index file.
116-
if (path.endsWith("/"))
117-
path += F("index.htm");
126+
// Base URI doesn't point to a file.
127+
// If a directory is requested, look for index file.
128+
if (path.endsWith("/"))
129+
path += F("index.htm");
118130

119-
// If neither <blah> nor <blah>.gz exist, and <blah> is a file.htm, try it with file.html instead
120-
// For the normal case this will give a search order of index.htm, index.htm.gz, index.html, index.html.gz
121-
if (!_fs.exists(path) && !_fs.exists(path + ".gz") && path.endsWith(".htm")) {
122-
path += 'l';
123-
}
131+
// If neither <blah> nor <blah>.gz exist, and <blah> is a file.htm, try it with file.html instead
132+
// For the normal case this will give a search order of index.htm, index.htm.gz, index.html, index.html.gz
133+
if (!SRH::_fs.exists(path) && !SRH::_fs.exists(path + ".gz") && path.endsWith(".htm")) {
134+
path += 'l';
124135
}
125-
DEBUGV("StaticRequestHandler::handle: path=%s, isFile=%d\r\n", path.c_str(), _isFile);
136+
137+
DEBUGV("DirectoryRequestHandler::handle: path=%s\r\n", path.c_str());
126138

127139
String contentType = mime::getContentType(path);
128140

129141
using namespace mime;
130142
// look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for
131143
// if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc...
132-
if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !_fs.exists(path)) {
144+
if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !SRH::_fs.exists(path)) {
133145
String pathWithGz = path + FPSTR(mimeTable[gz].endsWith);
134-
if(_fs.exists(pathWithGz))
146+
if(SRH::_fs.exists(pathWithGz))
135147
path += FPSTR(mimeTable[gz].endsWith);
136148
}
137149

138-
File f = _fs.open(path, "r");
150+
File f = SRH::_fs.open(path, "r");
139151
if (!f)
140152
return false;
141153

@@ -144,70 +156,75 @@ class StaticRequestHandler : public RequestHandler<ServerType> {
144156
return false;
145157
}
146158

147-
if (_cache_header.length() != 0)
148-
server.sendHeader("Cache-Control", _cache_header);
159+
if (SRH::_cache_header.length() != 0)
160+
server.sendHeader("Cache-Control", SRH::_cache_header);
149161

150162
server.streamFile(f, contentType, requestMethod);
151163
return true;
152164
}
153165

154-
/* Deprecated version. Please use mime::getContentType instead */
155-
static String getContentType(const String& path) __attribute__((deprecated)) {
156-
return mime::getContentType(path);
157-
}
158-
159166
protected:
160-
FS _fs;
161-
String _uri;
162-
String _path;
163-
String _cache_header;
164-
bool _isFile;
165167
size_t _baseUriLength;
166168
};
167169

168170
template<typename ServerType>
169-
class StaticRequestETagHandler
171+
class StaticFileRequestHandler
170172
:
171173
public StaticRequestHandler<ServerType> {
172174

173175
using SRH = StaticRequestHandler<ServerType>;
176+
using WebServerType = ESP8266WebServerTemplate<ServerType>;
174177

175-
using SRH::SRH;
178+
public:
179+
StaticFileRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
180+
:
181+
StaticRequestHandler<ServerType>{fs, path, uri, cache_header}
182+
{
183+
File f = SRH::_fs.open(path, "r");
184+
MD5Builder calcMD5;
185+
calcMD5.begin();
186+
calcMD5.addStream(f, f.size());
187+
calcMD5.calculate();
188+
calcMD5.getBytes(_ETag_md5);
189+
f.close();
190+
}
176191

177-
using WebServerType = ESP8266WebServerTemplate<ServerType>;
192+
bool canHandle(HTTPMethod requestMethod, const String& requestUri) override {
193+
return SRH::validMethod(requestMethod) && requestUri == SRH::_uri;
194+
}
178195

179-
public:
180196
bool handle(WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override {
181-
if (!SRH::canHandle(requestMethod, requestUri)){
197+
if (!canHandle(requestMethod, requestUri))
182198
return false;
183-
}
184199

185-
if(server.header("If-None-Match") == SRH::_cache_header){
186-
// Serial.println("Sending 304!!!");
200+
const String etag = "\"" + base64::encode(_ETag_md5, 16, false) + "\"";
201+
202+
if(server.header("If-None-Match") == etag){
187203
server.send(304);
188204
return true;
189205
}
190206

191-
192207
File f = SRH::_fs.open(SRH::_path, "r");
193208

194-
if (!f){
209+
if (!f)
195210
return false;
196-
}
197211

198212
if (!f.isFile()) {
199213
f.close();
200214
return false;
201215
}
202216

203-
if (SRH::_cache_header.length() != 0){
204-
server.sendHeader("ETag", SRH::_cache_header);
205-
}
217+
if (SRH::_cache_header.length() != 0)
218+
server.sendHeader("Cache-Control", SRH::_cache_header);
206219

207-
server.streamFile(f, SRH::getContentType(SRH::_path), requestMethod);
220+
server.sendHeader("ETag", etag);
221+
222+
server.streamFile(f, mime::getContentType(SRH::_path), requestMethod);
208223
return true;
209224
}
210-
225+
226+
protected:
227+
uint8_t _ETag_md5[16];
211228
};
212229

213230
} // namespace

0 commit comments

Comments
 (0)