@@ -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- }
75+ DEBUGV (" StaticRequestHandler: path=%s uri=%s, cache_header=%s\r\n " , path, uri, cache_header == __null ? " " : cache_header);
76+ }
8377
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 );
8680 }
8781
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+ }
9186
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+ };
9493
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);
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;
120+ path.reserve (SRH:: _path.length () + requestUri.length () + 32 );
121+ path = SRH:: _path;
108122
109- if (!_isFile) {
123+ // Append whatever follows this URI in request to get the file path.
124+ path += requestUri.substring (_baseUriLength);
110125
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" );
113130
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' ;
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,27 +156,77 @@ 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);
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 ;
157224 }
158225
159226protected:
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 ];
166228};
167229
168230} // namespace
169231
170- #endif // REQUESTHANDLERSIMPL_H
232+ #endif // REQUESTHANDLERSIMPL_H
0 commit comments