|
24 | 24 | #include <Logger.h> |
25 | 25 | #include <cstring> |
26 | 26 | #include <cstdlib> |
| 27 | +#include <array> |
27 | 28 |
|
28 | 29 | #include "web/Webserver.h" |
29 | 30 |
|
30 | 31 | static constexpr size_t URI_BUF_SIZE = 192; |
31 | 32 | static constexpr size_t PATH_BUF_SIZE = 256; |
32 | 33 | static constexpr bool LOG_STATIC_HIT_INFO = false; |
33 | 34 |
|
| 35 | +namespace { |
| 36 | + |
| 37 | +struct ContentTypeMapping { |
| 38 | + const char* suffix; |
| 39 | + const char* mimeType; |
| 40 | +}; |
| 41 | + |
| 42 | +constexpr const char* DEFAULT_CONTENT_TYPE = "application/octet-stream"; |
| 43 | +constexpr const char* HTML_CONTENT_TYPE = "text/html"; |
| 44 | + |
| 45 | +constexpr std::array<ContentTypeMapping, 12> CONTENT_TYPE_MAPPINGS = {{ |
| 46 | + {".html", HTML_CONTENT_TYPE}, |
| 47 | + {".htm", HTML_CONTENT_TYPE}, |
| 48 | + {".css", "text/css"}, |
| 49 | + {".js", "application/javascript"}, |
| 50 | + {".json", "application/json"}, |
| 51 | + {".png", "image/png"}, |
| 52 | + {".jpg", "image/jpeg"}, |
| 53 | + {".jpeg", "image/jpeg"}, |
| 54 | + {".gif", "image/gif"}, |
| 55 | + {".svg", "image/svg+xml"}, |
| 56 | + {".ico", "image/x-icon"}, |
| 57 | + {".txt", "text/plain"}, |
| 58 | +}}; |
| 59 | + |
| 60 | +auto hasSuffix(const char* value, const char* suffix) -> bool { |
| 61 | + if (value == nullptr || suffix == nullptr) { |
| 62 | + return false; |
| 63 | + } |
| 64 | + |
| 65 | + const size_t valueLen = strlen(value); |
| 66 | + const size_t suffixLen = strlen(suffix); |
| 67 | + if (valueLen < suffixLen) { |
| 68 | + return false; |
| 69 | + } |
| 70 | + |
| 71 | + return strcmp(value + valueLen - suffixLen, suffix) == 0; |
| 72 | +} |
| 73 | + |
| 74 | +} // namespace |
| 75 | + |
34 | 76 | Webserver::Webserver(uint16_t port) : _server(port) {} |
35 | 77 |
|
36 | 78 | /** |
@@ -287,66 +329,20 @@ void Webserver::onNotFound(std::function<void()> handler) { |
287 | 329 | auto Webserver::raw() -> ESP8266WebServer& { return _server; } |
288 | 330 |
|
289 | 331 | auto Webserver::guessContentTypeC(const char* path) -> const char* { |
290 | | - if (path == nullptr) { |
291 | | - return "application/octet-stream"; |
| 332 | + if (path == nullptr || path[0] == '\0') { |
| 333 | + return DEFAULT_CONTENT_TYPE; |
292 | 334 | } |
293 | 335 |
|
294 | 336 | const size_t len = strlen(path); |
295 | | - if (len == 0) { |
296 | | - return "application/octet-stream"; |
297 | | - } |
298 | | - |
299 | | - if (len >= 5 && strcmp(path + len - 5, ".html") == 0) { |
300 | | - return "text/html"; |
301 | | - } |
302 | | - |
303 | | - if (len >= 4 && strcmp(path + len - 4, ".htm") == 0) { |
304 | | - return "text/html"; |
305 | | - } |
306 | | - |
307 | 337 | if (path[len - 1] == '/') { |
308 | | - return "text/html"; |
309 | | - } |
310 | | - |
311 | | - if (len >= 4 && strcmp(path + len - 4, ".css") == 0) { |
312 | | - return "text/css"; |
313 | | - } |
314 | | - |
315 | | - if (len >= 3 && strcmp(path + len - 3, ".js") == 0) { |
316 | | - return "application/javascript"; |
317 | | - } |
318 | | - |
319 | | - if (len >= 5 && strcmp(path + len - 5, ".json") == 0) { |
320 | | - return "application/json"; |
321 | | - } |
322 | | - |
323 | | - if (len >= 4 && strcmp(path + len - 4, ".png") == 0) { |
324 | | - return "image/png"; |
325 | | - } |
326 | | - |
327 | | - if (len >= 4 && strcmp(path + len - 4, ".jpg") == 0) { |
328 | | - return "image/jpeg"; |
329 | | - } |
330 | | - |
331 | | - if (len >= 5 && strcmp(path + len - 5, ".jpeg") == 0) { |
332 | | - return "image/jpeg"; |
333 | | - } |
334 | | - |
335 | | - if (len >= 4 && strcmp(path + len - 4, ".gif") == 0) { |
336 | | - return "image/gif"; |
337 | | - } |
338 | | - |
339 | | - if (len >= 4 && strcmp(path + len - 4, ".svg") == 0) { |
340 | | - return "image/svg+xml"; |
341 | | - } |
342 | | - |
343 | | - if (len >= 4 && strcmp(path + len - 4, ".ico") == 0) { |
344 | | - return "image/x-icon"; |
| 338 | + return HTML_CONTENT_TYPE; |
345 | 339 | } |
346 | 340 |
|
347 | | - if (len >= 4 && strcmp(path + len - 4, ".txt") == 0) { |
348 | | - return "text/plain"; |
| 341 | + for (const auto& mapping : CONTENT_TYPE_MAPPINGS) { |
| 342 | + if (hasSuffix(path, mapping.suffix)) { |
| 343 | + return mapping.mimeType; |
| 344 | + } |
349 | 345 | } |
350 | 346 |
|
351 | | - return "application/octet-stream"; |
| 347 | + return DEFAULT_CONTENT_TYPE; |
352 | 348 | } |
0 commit comments