/
LoadFromFS.cpp
184 lines (149 loc) · 4.68 KB
/
LoadFromFS.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include "../WebServer/LoadFromFS.h"
#include "../Globals/RamTracker.h"
#include "../Helpers/ESPEasy_Storage.h"
#include "../Helpers/Network.h"
#include "../WebServer/CustomPage.h"
#include "../WebServer/HTML_wrappers.h"
#include "../WebServer/WebServer.h"
#if FEATURE_SD
# include <SD.h>
#endif // if FEATURE_SD
bool match_ext(const String& path, const __FlashStringHelper *ext) {
return path.endsWith(ext) || path.endsWith(String(ext) + F(".gz"));
}
bool gzipEncoded(const String& path) {
return path.endsWith(F(".gz"));
}
String fileFromUrl(String path) {
const int questionmarkPos = path.indexOf('?');
if (questionmarkPos >= 0) {
path = path.substring(0, questionmarkPos);
}
// First prepend slash
if (!path.startsWith(F("/"))) {
path = String('/') + path;
}
if (path.endsWith(F("/"))) { path += F("index.htm"); }
#ifdef ESP8266
// Remove leading slash to generate filename from it.
if (path.startsWith(F("/"))) {
path = path.substring(1);
}
#endif
return path;
}
// ********************************************************************************
// Web Interface server web file from FS
// ********************************************************************************
bool loadFromFS(String path) {
// path is a deepcopy, since it will be changed here.
#ifndef BUILD_NO_RAM_TRACKER
checkRAM(F("loadFromFS"));
#endif // ifndef BUILD_NO_RAM_TRACKER
statusLED(true);
const __FlashStringHelper* dataType = F("text/plain");
bool mustCheckCredentials = false;
path = fileFromUrl(path);
if (path.endsWith(F(".src"))) { path = path.substring(0, path.lastIndexOf(".")); }
else if (match_ext(path, F(".htm")) || match_ext(path, F(".html"))) { dataType = F("text/html"); }
else if (match_ext(path, F(".css"))) { dataType = F("text/css"); }
else if (match_ext(path, F(".js"))) { dataType = F("application/javascript"); }
else if (match_ext(path, F(".png"))) { dataType = F("image/png"); }
else if (match_ext(path, F(".gif"))) { dataType = F("image/gif"); }
else if (match_ext(path, F(".jpg"))) { dataType = F("image/jpeg"); }
else if (path.endsWith(F(".ico"))) { dataType = F("image/x-icon"); }
else if (path.endsWith(F(".svg"))) { dataType = F("image/svg+xml"); }
else if (path.endsWith(F(".json"))) { dataType = F("application/json"); }
else if (path.endsWith(F(".txt")) ||
path.endsWith(F(".dat"))) {
mustCheckCredentials = true;
dataType = F("application/octet-stream");
}
#ifdef WEBSERVER_CUSTOM
else if (path.endsWith(F(".esp"))) {
return handle_custom(path);
}
#endif // ifdef WEBSERVER_CUSTOM
else {
mustCheckCredentials = true;
}
if (mustCheckCredentials) {
if (!isLoggedIn()) { return false; }
}
#ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("HTML : Request file ");
log += path;
addLogMove(LOG_LEVEL_DEBUG, log);
}
#endif // ifndef BUILD_NO_DEBUG
fs::File f;
// Search flash file system first, then SD if present
f = tryOpenFile(path.c_str(), "r");
#if FEATURE_SD
if (!f) {
f = SD.open(path.c_str(), "r");
}
#endif // if FEATURE_SD
if (!f) {
return false;
}
// prevent reloading stuff on every click
web_server.sendHeader(F("Cache-Control"), F("max-age=3600, public"));
web_server.sendHeader(F("Vary"), "*");
web_server.sendHeader(F("ETag"), F("\"2.0.0\""));
if (path.endsWith(F(".dat"))) {
web_server.sendHeader(F("Content-Disposition"), F("attachment;"));
}
web_server.streamFile(f, dataType);
f.close();
statusLED(true);
return true;
}
size_t streamFromFS(String path, bool htmlEscape) {
// path is a deepcopy, since it will be changed here.
path = fileFromUrl(path);
statusLED(true);
size_t bytesStreamed = 0;
fs::File f;
// Search flash file system first, then SD if present
f = tryOpenFile(path.c_str(), "r");
#if FEATURE_SD
if (!f) {
f = SD.open(path.c_str(), "r");
}
#endif // if FEATURE_SD
if (!f) {
return bytesStreamed;
}
int available = f.available();
String escaped;
while (available > 0) {
int32_t chunksize = 64;
if (available < chunksize) {
chunksize = available;
}
uint8_t buf[64] = {0};
const int read = f.read(buf, chunksize);
if (read == chunksize) {
for (int32_t i = 0; i < chunksize; ++i) {
const char c = (char)buf[i];
if (htmlEscape && htmlEscapeChar(c, escaped)) {
addHtml(escaped);
} else {
addHtml(c);
}
}
bytesStreamed += read;
available = f.available();
} else {
available = 0;
}
}
while (f.available()) {
addHtml((char)f.read());
}
statusLED(true);
f.close();
return bytesStreamed;
}