@@ -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-
159166protected:
160- FS _fs;
161- String _uri;
162- String _path;
163- String _cache_header;
164- bool _isFile;
165167 size_t _baseUriLength;
166168};
167169
168170template <typename ServerType>
169- class StaticRequestETagHandler
171+ class StaticFileRequestHandler
170172 :
171173public 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