@@ -117,7 +117,7 @@ void setup() {
117117 ResourceNode * nodeDirectory = new ResourceNode (" /public" , " GET" , &handleDirectory);
118118 ResourceNode * nodeFile = new ResourceNode (" /public/*" , " GET" , &handleFile);
119119
120- // 404 node has no URL as it is used for all requests that don't match anything else
120+ // 404 node has no URL as it is used for all requests that don't match anything else
121121 ResourceNode * node404 = new ResourceNode (" " , " GET" , &handle404);
122122
123123 // Add the root nodes to the server
@@ -135,182 +135,186 @@ void setup() {
135135 Serial.println (" Starting server..." );
136136 secureServer.start ();
137137 if (secureServer.isRunning ()) {
138- Serial.println (" Server ready." );
138+ Serial.println (" Server ready." );
139139 }
140140}
141141
142142void loop () {
143- // This call will let the server do its work
144- secureServer.loop ();
143+ // This call will let the server do its work
144+ secureServer.loop ();
145145
146- // Other code would go here...
147- delay (1 );
146+ // Other code would go here...
147+ delay (1 );
148148}
149149
150150void handleRoot (HTTPRequest * req, HTTPResponse * res) {
151- // Status code is 200 OK by default.
152- // We want to deliver a simple HTML page, so we send a corresponding content type:
153- res->setHeader (" Content-Type" , " text/html" );
154-
155- // The response implements the Print interface, so you can use it just like
156- // you would write to Serial etc.
157- res->println (" <!DOCTYPE html>" );
158- res->println (" <html>" );
159- res->println (" <head><title>Very simple file server</title></head>" );
160- res->println (" <body>" );
161- res->println (" <h1>Very simple file server</h1>" );
162- res->println (" <p>This is a very simple file server to demonstrate the use of POST forms. </p>" );
163- res->println (" <h2>List existing files</h2>" );
164- res->println (" <p>See <a href=\" /public\" >/public</a> to list existing files and retrieve or edit them.</p>" );
165- res->println (" <h2>Upload new file</h2>" );
166- res->println (" <p>This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.</p>" );
167- res->println (" <form method=\" POST\" action=\" /upload\" enctype=\" multipart/form-data\" >" );
168- res->println (" file: <input type=\" file\" name=\" file\" ><br>" );
169- res->println (" <input type=\" submit\" value=\" Upload\" >" );
170- res->println (" </form>" );
171- res->println (" </body>" );
172- res->println (" </html>" );
151+ // Status code is 200 OK by default.
152+ // We want to deliver a simple HTML page, so we send a corresponding content type:
153+ res->setHeader (" Content-Type" , " text/html" );
154+
155+ // The response implements the Print interface, so you can use it just like
156+ // you would write to Serial etc.
157+ res->println (" <!DOCTYPE html>" );
158+ res->println (" <html>" );
159+ res->println (" <head><title>Very simple file server</title></head>" );
160+ res->println (" <body>" );
161+ res->println (" <h1>Very simple file server</h1>" );
162+ res->println (" <p>This is a very simple file server to demonstrate the use of POST forms. </p>" );
163+ res->println (" <h2>List existing files</h2>" );
164+ res->println (" <p>See <a href=\" /public\" >/public</a> to list existing files and retrieve or edit them.</p>" );
165+ res->println (" <h2>Upload new file</h2>" );
166+ res->println (" <p>This form allows you to upload files (text, jpg and png supported best). It demonstrates multipart/form-data.</p>" );
167+ res->println (" <form method=\" POST\" action=\" /upload\" enctype=\" multipart/form-data\" >" );
168+ res->println (" file: <input type=\" file\" name=\" file\" ><br>" );
169+ res->println (" <input type=\" submit\" value=\" Upload\" >" );
170+ res->println (" </form>" );
171+ res->println (" </body>" );
172+ res->println (" </html>" );
173173}
174174
175175void handleFormUpload (HTTPRequest * req, HTTPResponse * res) {
176- // First, we need to check the encoding of the form that we have received.
177- // The browser will set the Content-Type request header, so we can use it for that purpose.
178- // Then we select the body parser based on the encoding.
179- // Actually we do this only for documentary purposes, we know the form is going
180- // to be multipart/form-data.
181- HTTPBodyParser *parser;
182- std::string contentType = req->getHeader (" Content-Type" );
183- size_t semicolonPos = contentType.find (" ;" );
184- if (semicolonPos != std::string::npos) contentType = contentType.substr (0 , semicolonPos);
185- if (contentType == " multipart/form-data" ) {
186- parser = new HTTPMultipartBodyParser (req);
187- } else {
188- Serial.printf (" Unknown POST Content-Type: %s\n " , contentType.c_str ());
189- return ;
190- }
191- // We iterate over the fields. Any field with a filename is uploaded
192- res->println (" <html><head><title>File Upload</title></head><body><h1>File Upload</h1>" );
193- bool didwrite = false ;
194- while (parser->nextField ()) {
195- std::string name = parser->getFieldName ();
196- std::string filename = parser->getFieldFilename ();
197- std::string mimeType = parser->getFieldMimeType ();
198- Serial.printf (" handleFormUpload: field name='%s', filename='%s', mimetype='%s'\n " , name.c_str (), filename.c_str (), mimeType.c_str ());
199- // Double check that it is what we expect
200- if (name != " file" ) {
201- Serial.println (" Skipping unexpected field" );
202- break ;
203- }
204- // Should check file name validity and all that, but we skip that.
205- std::string pathname = " /public/" + filename;
206- File file = SPIFFS.open (pathname.c_str (), " w" );
207- size_t fileLength = 0 ;
208- didwrite = true ;
209- while (!parser->endOfField ()) {
210- byte buf[512 ];
211- size_t readLength = parser->read (buf, 512 );
212- file.write (buf, readLength);
213- fileLength += readLength;
214- }
215- file.close ();
216- res->printf (" <p>Saved %d bytes to %s</p>" , (int )fileLength, pathname.c_str ());
217- }
218- if (!didwrite) res->println (" <p>Did not write any file</p>" );
219- res->println (" </body></html>" );
220- delete parser;
176+ // First, we need to check the encoding of the form that we have received.
177+ // The browser will set the Content-Type request header, so we can use it for that purpose.
178+ // Then we select the body parser based on the encoding.
179+ // Actually we do this only for documentary purposes, we know the form is going
180+ // to be multipart/form-data.
181+ HTTPBodyParser *parser;
182+ std::string contentType = req->getHeader (" Content-Type" );
183+ size_t semicolonPos = contentType.find (" ;" );
184+ if (semicolonPos != std::string::npos) {
185+ contentType = contentType.substr (0 , semicolonPos);
186+ }
187+ if (contentType == " multipart/form-data" ) {
188+ parser = new HTTPMultipartBodyParser (req);
189+ } else {
190+ Serial.printf (" Unknown POST Content-Type: %s\n " , contentType.c_str ());
191+ return ;
192+ }
193+ // We iterate over the fields. Any field with a filename is uploaded
194+ res->println (" <html><head><title>File Upload</title></head><body><h1>File Upload</h1>" );
195+ bool didwrite = false ;
196+ while (parser->nextField ()) {
197+ std::string name = parser->getFieldName ();
198+ std::string filename = parser->getFieldFilename ();
199+ std::string mimeType = parser->getFieldMimeType ();
200+ Serial.printf (" handleFormUpload: field name='%s', filename='%s', mimetype='%s'\n " , name.c_str (), filename.c_str (), mimeType.c_str ());
201+ // Double check that it is what we expect
202+ if (name != " file" ) {
203+ Serial.println (" Skipping unexpected field" );
204+ break ;
205+ }
206+ // Should check file name validity and all that, but we skip that.
207+ std::string pathname = " /public/" + filename;
208+ File file = SPIFFS.open (pathname.c_str (), " w" );
209+ size_t fileLength = 0 ;
210+ didwrite = true ;
211+ while (!parser->endOfField ()) {
212+ byte buf[512 ];
213+ size_t readLength = parser->read (buf, 512 );
214+ file.write (buf, readLength);
215+ fileLength += readLength;
216+ }
217+ file.close ();
218+ res->printf (" <p>Saved %d bytes to %s</p>" , (int )fileLength, pathname.c_str ());
219+ }
220+ if (!didwrite) {
221+ res->println (" <p>Did not write any file</p>" );
222+ }
223+ res->println (" </body></html>" );
224+ delete parser;
221225}
222226
223227void handleFormEdit (HTTPRequest * req, HTTPResponse * res) {
224228 if (req->getMethod () == " GET" ) {
225- // Initial request. Get filename from request parameters and return form.
226- auto params = req->getParams ();
227- std::string filename;
228- bool hasFilename = params->getQueryParameter (" filename" , filename);
229- std::string pathname = std::string (" /public/" ) + filename;
230- res->println (" <html><head><title>Edit File</title><head><body>" );
231- File file = SPIFFS.open (pathname.c_str ());
232- if (!hasFilename) {
233- res->println (" <p>No filename specified.</p>" );
234- } else
235- if (!file. available ()) {
236- res-> printf ( " <p>File not found: %s</p> \n " , pathname. c_str ());
237- } else {
238- res->printf (" <h2>Edit content of %s</h2> \n " , pathname. c_str () );
239- res->println (" <form method =\" POST \" enctype =\" application/x-www-form-urlencoded \" > " );
240- res->printf (" <input name=\" filename \" type =\" hidden \" value =\" %s \" >" , filename. c_str () );
241- res-> print ( " <textarea name= \" content \" rows= \" 24 \" cols= \" 80 \" > " );
242- // Read the file and write it to the response
243- size_t length = 0 ;
244- do {
245- char buffer[ 256 ] ;
246- length = file. read (( uint8_t *) buffer, 256 );
247- std::string bufferString (buffer, length );
248- bufferString = htmlEncode ( bufferString);
249- res-> write (( uint8_t *)bufferString. c_str (), bufferString. size () );
250- } while (length > 0 );
251- res->println (" </textarea><br >" );
252- res->println (" <input type= \" submit \" value= \" Save \" >" );
253- res-> println ( " </form> " );
254- }
255- res-> println ( " </body></html> " );
256- } else {
257- // Assume POST request. Contains submitted data.
258- res-> println ( " <html><head><title>File Edited</title><head><body><h1>File Edited</h1> " );
259- HTTPURLEncodedBodyParser parser (req) ;
260- std::string filename ;
261- bool savedFile = false ;
262- while ( parser.nextField ()) {
263- std::string name = parser. getFieldName ();
264- if (name == " filename " ) {
265- char buf[ 512 ] ;
266- size_t readLength = parser. read ((byte *) buf, 512 );
267- filename = std::string ( " /public/ " ) + std::string (buf, readLength);
268- } else
269- if (name == " content" ) {
270- if (filename == " " ) {
271- res-> println ( " <p>Error: form contained content before filename.</p> " );
272- break ;
273- }
274- size_t fieldLength = 0 ;
275- File file = SPIFFS. open (filename. c_str (), " w " );
276- savedFile = true ;
277- while (! parser.endOfField ()) {
278- byte buf[ 512 ] ;
279- size_t readLength = parser. read (buf, 512 ) ;
280- file. write (buf, readLength);
281- fieldLength += readLength ;
282- }
283- file. close ();
284- res->printf (" <p>Saved %d bytes to %s</p>" , int (fieldLength), filename .c_str ());
285- } else {
286- res-> printf ( " <p>Unexpected field %s</p> " , name. c_str ());
287- }
288- }
289- if (!savedFile) res-> println ( " <p>No file to save...</p> " );
290- res->println (" </body></html>" );
229+ // Initial request. Get filename from request parameters and return form.
230+ auto params = req->getParams ();
231+ std::string filename;
232+ bool hasFilename = params->getQueryParameter (" filename" , filename);
233+ std::string pathname = std::string (" /public/" ) + filename;
234+ res->println (" <html><head><title>Edit File</title><head><body>" );
235+ File file = SPIFFS.open (pathname.c_str ());
236+ if (!hasFilename) {
237+ res->println (" <p>No filename specified.</p>" );
238+ } else if (!file. available ()) {
239+ res-> printf ( " <p>File not found: %s</p> \n " , pathname. c_str ());
240+ } else {
241+ res-> printf ( " <h2>Edit content of %s</h2> \n " , pathname. c_str ());
242+ res->println (" <form method= \" POST \" enctype= \" application/x-www-form-urlencoded \" > " );
243+ res->printf (" <input name =\" filename \" type =\" hidden \" value= \" %s \" > " , filename. c_str () );
244+ res->print (" <textarea name=\" content \" rows =\" 24 \" cols =\" 80 \" >" );
245+ // Read the file and write it to the response
246+ size_t length = 0 ;
247+ do {
248+ char buffer[ 256 ];
249+ length = file. read (( uint8_t *) buffer, 256 ) ;
250+ std::string bufferString ( buffer, length );
251+ bufferString = htmlEncode (bufferString );
252+ res-> write (( uint8_t *) bufferString. c_str (), bufferString. size () );
253+ } while (length > 0 );
254+ res-> println ( " </textarea><br> " );
255+ res->println (" <input type= \" submit \" value= \" Save \" >" );
256+ res->println (" </form >" );
257+ }
258+ res-> println ( " </body></html> " );
259+ } else { // method != GET
260+ // Assume POST request. Contains submitted data.
261+ res-> println ( " <html><head><title>File Edited</title><head><body><h1>File Edited</h1> " );
262+ HTTPURLEncodedBodyParser parser (req );
263+ std::string filename ;
264+ bool savedFile = false ;
265+ while (parser. nextField ()) {
266+ std::string name = parser.getFieldName ();
267+ if ( name == " filename " ) {
268+ char buf[ 512 ];
269+ size_t readLength = parser. read ((byte *) buf, 512 ) ;
270+ filename = std::string ( " /public/ " ) + std::string ( buf, readLength );
271+ } else if (name == " content " ) {
272+ if (filename == " " ) {
273+ res-> println ( " <p>Error: form contained content before filename.</p> " );
274+ break ;
275+ }
276+ size_t fieldLength = 0 ;
277+ File file = SPIFFS. open (filename. c_str (), " w " );
278+ savedFile = true ;
279+ while (!parser. endOfField ()) {
280+ byte buf[ 512 ] ;
281+ size_t readLength = parser.read (buf, 512 );
282+ file. write ( buf, readLength) ;
283+ fieldLength += readLength ;
284+ }
285+ file. close () ;
286+ res-> printf ( " <p>Saved %d bytes to %s</p> " , int (fieldLength), filename. c_str ());
287+ } else {
288+ res->printf (" <p>Unexpected field %s</p>" , name .c_str ());
289+ }
290+ }
291+ if (!savedFile) {
292+ res-> println ( " <p>No file to save...</p> " );
293+ }
294+ res->println (" </body></html>" );
291295 }
292296}
293297
294298void handleDirectory (HTTPRequest * req, HTTPResponse * res) {
295299 res->println (" <html><head><title>File Listing</title><head><body>" );
296300 File d = SPIFFS.open (" /public" );
297301 if (!d.isDirectory ()) {
298- res->println (" <p>No files found.</p>" );
302+ res->println (" <p>No files found.</p>" );
299303 } else {
300- res->println (" <h1>File Listing</h1>" );
301- res->println (" <ul>" );
302- File f = d.openNextFile ();
303- while (f) {
304- std::string pathname (f.name ());
305- res->printf (" <li><a href=\" %s\" >%s</a>" , pathname.c_str (), pathname.c_str ());
306- if (pathname.rfind (" .txt" ) != std::string::npos) {
307- std::string filename = pathname.substr (8 ); // Remove /public/
308- res->printf (" <a href=\" /edit?filename=%s\" >[edit]</a>" , filename.c_str ());
309- }
310- res->println (" </li>" );
311- f = d.openNextFile ();
312- }
313- res->println (" </ul>" );
304+ res->println (" <h1>File Listing</h1>" );
305+ res->println (" <ul>" );
306+ File f = d.openNextFile ();
307+ while (f) {
308+ std::string pathname (f.name ());
309+ res->printf (" <li><a href=\" %s\" >%s</a>" , pathname.c_str (), pathname.c_str ());
310+ if (pathname.rfind (" .txt" ) != std::string::npos) {
311+ std::string filename = pathname.substr (8 ); // Remove /public/
312+ res->printf (" <a href=\" /edit?filename=%s\" >[edit]</a>" , filename.c_str ());
313+ }
314+ res->println (" </li>" );
315+ f = d.openNextFile ();
316+ }
317+ res->println (" </ul>" );
314318 }
315319 res->println (" </body></html>" );
316320}
@@ -353,21 +357,21 @@ void handleFile(HTTPRequest * req, HTTPResponse * res) {
353357}
354358
355359void handle404 (HTTPRequest * req, HTTPResponse * res) {
356- // Discard request body, if we received any
357- // We do this, as this is the default node and may also server POST/PUT requests
358- req->discardRequestBody ();
359-
360- // Set the response status
361- res->setStatusCode (404 );
362- res->setStatusText (" Not Found" );
363-
364- // Set content type of the response
365- res->setHeader (" Content-Type" , " text/html" );
366-
367- // Write a tiny HTML page
368- res->println (" <!DOCTYPE html>" );
369- res->println (" <html>" );
370- res->println (" <head><title>Not Found</title></head>" );
371- res->println (" <body><h1>404 Not Found</h1><p>The requested resource was not found on this server.</p></body>" );
372- res->println (" </html>" );
360+ // Discard request body, if we received any
361+ // We do this, as this is the default node and may also server POST/PUT requests
362+ req->discardRequestBody ();
363+
364+ // Set the response status
365+ res->setStatusCode (404 );
366+ res->setStatusText (" Not Found" );
367+
368+ // Set content type of the response
369+ res->setHeader (" Content-Type" , " text/html" );
370+
371+ // Write a tiny HTML page
372+ res->println (" <!DOCTYPE html>" );
373+ res->println (" <html>" );
374+ res->println (" <head><title>Not Found</title></head>" );
375+ res->println (" <body><h1>404 Not Found</h1><p>The requested resource was not found on this server.</p></body>" );
376+ res->println (" </html>" );
373377}
0 commit comments