@@ -72,70 +72,82 @@ class StaticRequestHandler : public RequestHandler<ServerType> {
72
72
, _path(path)
73
73
, _cache_header(cache_header)
74
74
{
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
- }
75
+ DEBUGV (" StaticRequestHandler: path=%s uri=%s, cache_header=%s\r\n " , path, uri, cache_header == __null ? " " : cache_header);
76
+ }
83
77
84
- 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 ( );
78
+ bool validMethod (HTTPMethod requestMethod){
79
+ return (requestMethod == HTTP_GET) || (requestMethod == HTTP_HEAD );
86
80
}
87
81
88
- bool canHandle (HTTPMethod requestMethod, const String& requestUri) override {
89
- if ((requestMethod != HTTP_GET) && (requestMethod != HTTP_HEAD))
90
- 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
+ }
91
86
92
- if ((_isFile && requestUri != _uri) || !requestUri.startsWith (_uri))
93
- return false ;
87
+ protected:
88
+ FS _fs;
89
+ String _uri;
90
+ String _path;
91
+ String _cache_header;
92
+ };
94
93
95
- return true ;
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);
96
110
}
97
111
98
112
bool handle (WebServerType& server, HTTPMethod requestMethod, const String& requestUri) override {
99
113
100
114
if (!canHandle (requestMethod, requestUri))
101
115
return false ;
102
116
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 ());
104
118
105
119
String path;
106
- path.reserve (_path.length () + requestUri.length () + 32 );
107
- path = _path;
120
+ path.reserve (SRH:: _path.length () + requestUri.length () + 32 );
121
+ path = SRH:: _path;
108
122
109
- if (!_isFile) {
123
+ // Append whatever follows this URI in request to get the file path.
124
+ path += requestUri.substring (_baseUriLength);
110
125
111
- // Append whatever follows this URI in request to get the file path.
112
- path += requestUri.substring (_baseUriLength);
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" );
113
130
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" );
118
-
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' ;
124
135
}
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 ());
126
138
127
139
String contentType = mime::getContentType (path);
128
140
129
141
using namespace mime ;
130
142
// 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
131
143
// 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)) {
133
145
String pathWithGz = path + FPSTR (mimeTable[gz].endsWith );
134
- if (_fs.exists (pathWithGz))
146
+ if (SRH:: _fs.exists (pathWithGz))
135
147
path += FPSTR (mimeTable[gz].endsWith );
136
148
}
137
149
138
- File f = _fs.open (path, " r" );
150
+ File f = SRH:: _fs.open (path, " r" );
139
151
if (!f)
140
152
return false ;
141
153
@@ -144,27 +156,77 @@ class StaticRequestHandler : public RequestHandler<ServerType> {
144
156
return false ;
145
157
}
146
158
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);
149
161
150
162
server.streamFile (f, contentType, requestMethod);
151
163
return true ;
152
164
}
153
165
154
- /* Deprecated version. Please use mime::getContentType instead */
155
- static String getContentType (const String& path) __attribute__((deprecated)) {
156
- return mime::getContentType (path);
166
+ protected:
167
+ size_t _baseUriLength;
168
+ };
169
+
170
+ template <typename ServerType>
171
+ class StaticFileRequestHandler
172
+ :
173
+ public StaticRequestHandler<ServerType> {
174
+
175
+ using SRH = StaticRequestHandler<ServerType>;
176
+ using WebServerType = ESP8266WebServerTemplate<ServerType>;
177
+
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
+ }
191
+
192
+ bool canHandle (HTTPMethod requestMethod, const String& requestUri) override {
193
+ return SRH::validMethod (requestMethod) && requestUri == SRH::_uri;
194
+ }
195
+
196
+ bool handle (WebServerType& server, HTTPMethod requestMethod, const String & requestUri) override {
197
+ if (!canHandle (requestMethod, requestUri))
198
+ return false ;
199
+
200
+ const String etag = " \" " + base64::encode (_ETag_md5, 16 , false ) + " \" " ;
201
+
202
+ if (server.header (" If-None-Match" ) == etag){
203
+ server.send (304 );
204
+ return true ;
205
+ }
206
+
207
+ File f = SRH::_fs.open (SRH::_path, " r" );
208
+
209
+ if (!f)
210
+ return false ;
211
+
212
+ if (!f.isFile ()) {
213
+ f.close ();
214
+ return false ;
215
+ }
216
+
217
+ if (SRH::_cache_header.length () != 0 )
218
+ server.sendHeader (" Cache-Control" , SRH::_cache_header);
219
+
220
+ server.sendHeader (" ETag" , etag);
221
+
222
+ server.streamFile (f, mime::getContentType (SRH::_path), requestMethod);
223
+ return true ;
157
224
}
158
225
159
226
protected:
160
- FS _fs;
161
- String _uri;
162
- String _path;
163
- String _cache_header;
164
- bool _isFile;
165
- size_t _baseUriLength;
227
+ uint8_t _ETag_md5[16 ];
166
228
};
167
229
168
230
} // namespace
169
231
170
- #endif // REQUESTHANDLERSIMPL_H
232
+ #endif // REQUESTHANDLERSIMPL_H
0 commit comments