12 Commits

Author SHA1 Message Date
Godzil
53e12f21f1 Change text/plain to application/octet-stream 2019-10-31 02:04:27 +00:00
Fractal147
9f4d7a9988 Fixed unnecessary globals as in issue #113. (#122)
* Fixed global assignment that should be local

Made result variable be local, see Issue #113

* Made global variable local

Made ASCII variable be local, see Issue #113

* Made more variables local

Related to Issue #113. questionMarkPos, and b,c,d,e,f all are global in scope, and are not cleared from memory, so leak.
Frankly, b, c, d, e, and f are not used either, but will now get GC'd later, if they ever were assigned, so not problematic
line 114 also has _ and i to make local too, so were put on their own line.
i on line 24 also was unnecessarily global, and undetected in issue #113

* Made module more local

Made the basicAuth table local in scope. Since it is returned when dofile is called in httpserver.lua, that already has a correctly scoped table, 'auth'. This is related to issue #113, and should reduce memory loss to globals

* Made bufferedConnection local

bufferedConnection was global and didn't have to be. Part of issue #113.
Now no longer remains in _G (globals table) after a connection has closed.
2018-01-14 22:03:37 -06:00
Gregor Hartmann
7c8fe9c164 Upload for all files fix 119 (#120)
* allow uploading files not only to http + replace symbol images by unicode symbols

allow uploading files to root dir and http.
+ replace symbol images by unicode symbols

* backend for uploading arbitrary files

* fix uploading to http
2018-01-14 22:02:51 -06:00
Gregor Hartmann
5cf303de79 make cars dynamic to load 1 to 6 cars (#114)
For lazy people like me for not having to change the page by hand every
time.
+ adding 2 more cars.
2017-10-02 11:15:12 -05:00
Manoël Trapier
ab9a5d365f Use file.exists instead of open/close when relevant (#112) 2017-10-02 11:14:26 -05:00
Gregor Hartmann
6158d4b5ba support changes json API (#116)
use sjson instead of cjson
Also take care of backward compatibility before 2.1
2017-10-02 11:13:39 -05:00
Gregor Hartmann
c67ed16e10 Support long filenames in upload (#115)
appending '.dnl' to the filename shortens the available filename length by 4 chars. Now a long filename ist cut off first and then the dnl is appended resulting in a unique but short enough temp filename.
2017-10-02 08:50:47 -05:00
Dmitry
a70fa745b0 Small fix to upload form (#117)
Fixed bug when you cannot browse or D&D same file multiple times without reloading the whole page.
2017-10-02 08:49:49 -05:00
Manoël Trapier
b5baf6cd48 Fix mistake in config file (#107) 2017-09-04 20:42:47 -05:00
Manoël Trapier
28fbb6e7a7 now user proper table based parameter for wifi.ap.setip instead of a string (#106) 2017-09-03 17:40:38 -05:00
Gerhard Schwärzler
0f852665ec WiFi configuration using new, table based API (#105) 2017-07-26 16:25:14 -05:00
Marcos Kirsch
dacaf31dc6 Get README.md is up to date. 2017-07-02 22:40:40 -05:00
17 changed files with 214 additions and 161 deletions

View File

@@ -7,16 +7,16 @@ A (very) simple web server written in Lua for the ESP8266 running the NodeMCU fi
> you are really abusing its intended purpose. When it comes to scoping your ESP8266
> applications, the adage Keep It Simple Stupid truly applies.
>
> -- <cite>[Terry Ellison](https://github.com/TerryE)</cite>, nodemcu-firmware maintainer,
> -- <cite>[Terry Ellison](https://github.com/TerryE)</cite>, nodemcu-firmware maintainer
Let the abuse begin.
## Features
* GET, POST, PUT and minor changes to support other methods
* GET, POST, PUT (other methods can be supported with minor changes)
* Multiple MIME types
* Error pages (404 and others)
* Server-side execution of Lua scripts
* *Server-side execution of Lua scripts*
* Query string argument parsing with decoding of arguments
* Serving .gz compressed files
* HTTP Basic Authentication
@@ -24,7 +24,9 @@ Let the abuse begin.
## How to use
1. Upload server files using [nodemcu-uploader](https://github.com/kmpm/nodemcu-uploader).
1. Modify your local copy of the configuration file httpserver-conf.lua.
2. Upload server files using [nodemcu-uploader](https://github.com/kmpm/nodemcu-uploader).
The easiest is to use GNU Make with the bundled Makefile. Open the Makefile and modify the
user configuration to point to your nodemcu-uploader script and your serial port.
Type the following to upload the server code, init.lua (which you may want to modify),
@@ -32,28 +34,24 @@ Let the abuse begin.
make upload_all
If you only want to upload the server code, then type:
If you only want to upload just the server code, then type:
make upload_server
And if you only want to upload the server files:
And if you only want to upload just the files that can be served:
make upload_http
Restart the server. This will execute init.lua which will compile the server code.
Then, assuming init.lua doesn't have it, start the server yourself by typing:
Restart the server. This will execute included init.lua which will compile the server code,
configure WiFi, and start the server.
dofile("httpserver.lc")(80)
3. Want to serve your own files? Put them under the http/ folder and upload to the chip.
For example, assuming you want to serve myfile.html, upload by typing:
In this example, 80 is the port your server is listening at, but you can change it.
make upload FILE:=http/myfile.html
2. Want to upload your own files? Move them to the http/ folder. Be careful though,
the flash memory seems to fill up quickly and get corrupted.
All the files you upload must be prefixed with "http/". Wait, what?
Yes: NodeMCU's filesystem does not support folders, but filenames *can* contain slashes.
Only files that begin with "http/" will be accessible through the server.
Notice that while NodeMCU's filesystem does not support folders, filenames *can* contain slashes.
We take advantage of that and only files that begin with "http/" will be accessible through the server.
3. Visit your server from a web browser.
@@ -63,21 +61,19 @@ Let the abuse begin.
then index.html is served. By the way, unlike most HTTP servers, nodemcu_httpserver treats the URLs in a
case-sensitive manner.
4. How to use HTTP Basic Authentication.
## HTTP Basic Authentication.
Modify variables in configuration file httpserver-conf.lua in order to enable and to configure usernames/passwords.
See comments in that file for more details.
It's supported. Turn it on in httpserver-conf.lua.
When enabled, HTTP Basic Authentication is global to every file served by the server.
Use it with care and don't fall into a false sense of security: HTTP Basic Authentication should not be
considered secure since the server is not using encryption. Username and passwords travel
in the clear.
Remember that HTTP Basic Authentication is a very basic authentication protocol, and should not be
considered as secure since the server is not using encryption. Username and passwords travel
in plain text.
## Server-side scripting using your own Lua scripts
## How to use server-side scripting using your own Lua scripts
Similar to static files, upload a Lua script called "http/[name].lua where you replace [name] with your script's name.
The script should return a function that takes three parameters:
Yes, you can upload your own Lua scripts! This is pretty powerful.
Just put it under http/ and upload it. Make sure it has a .lua extension.
Your script should return a function that takes three parameters:
return function (connection, req, args)
-- code goes here
@@ -107,42 +103,40 @@ Let the abuse begin.
#### Hardware description
This example assumes that GPIO1 and GPIO2 on the ESP8266 are connected each to a relay
that can be controlled. How to wire such thing is outside of the scope of this document
[but information is easily found online](https://www.google.com/search?q=opening+a+garage+door+with+a+microcontroller).
This example assumes that you are using a [Wemos D1 Pro](https://wiki.wemos.cc/products:d1:d1_mini_pro)
with two relay shields and two reed switches.
The relays are controlled by the microcontroller and act as the push button,
and can actually be connected in parallel with the existing mechanical button.
The switches are wired so that the ESP8266 can tell whether the doors are open
or closed at any given time.
#### Software description
This example consists of the following files:
* **garage_door_opener.html**: Static HTML displays a button with a link
to the garage_door_opener.lua script. That's it!
* **garage_door_opener.css**: Provides styling for garage_door_opener.html
just so it looks pretty.
* **garage_door_opener.lua**: Does the actual work. The script first sends
a little javascript snippet to redirect the client back to garage_door_opener.html
and then toggles the GPIO2 line for a short amount of time (roughly equivalent to
the typical button press for opening a garage door) and then toggles it back.
* **garage_door.html**: Static HTML displays a form with all options for controlling the
two garage doors.
* **garage_door_control.html**: Looks like a garage door remote, how neat!
* **garage_door_control.css**: Provides styling for garage_door_control.html.
* **garage_door.lua**: Does the actual work. The script performs the desired action on
the requested door and returns the results as JSON.
* **apple-touch-icon.png**: This is optional. Provides an icon that
will be used if you "Add to Home Screen" the demo on an iPhone. Now it looks like an app!
will be used if you "Add to Home Screen" garage_door_control.html on an iPhone.
Now it looks like an app!
#### Security implications
Be careful permanently installing something like this in your home. The server provides
no encryption. Your only layers of security are the WiFi network's password and simple
HTTP authentication which sends your password unencrypted.
HTTP authentication (if you enable it) which sends your password unencrypted.
This script is provided simply as an educational example. You've been warned.
This script is provided for educational purposes. You've been warned.
## Not supported
* Other methods: HEAD, DELETE, TRACE, OPTIONS, CONNECT, PATCH
* Encryption / SSL
* Multiple users (HTTP Basic Authentication)
* Only protect certain directories (HTTP Basic Authentication)
* nodemcu-firmware versions older 1.5.1 (January 2016) because that's what I tested on.
* Old nodemcu-firmware versions prior to January 2017) because I don't bother to test them.
## Contributing
@@ -151,7 +145,9 @@ Let the abuse begin.
and that you add examples for new features. I won't test all your changes myself but I
am very grateful of improvements and fixes. Open issues in GitHub too, that's useful.
Please follow the coding style as close as possible:
Please keep your PRs focused on one thing. I don't mind lots of PRs. I mind PRs that fix multiple unrelated things.
Follow the coding style as closely as possible:
* No tabs, indent with 3 spaces
* Unix (LF) line endings
@@ -163,8 +159,9 @@ Let the abuse begin.
The chip is very, very memory constrained.
* Use a recent nodemcu-firmware with as few optional modules as possible.
* Use a firmware build without floating point support. This takes up a good chunk of RAM as well.
* Any help reducing the memory needs of the server without crippling its functionality is appreciated!
* Compile your Lua scripts in order to reduce their memory usage. The server knows to serve and treat
* Use a recent nodemcu-firmware. They've really improved memory usage and fixed leaks.
* Use only the modules you need.
* Use a firmware build without floating point support if you can.
* Any help reducing the memory needs of the server without crippling its functionality is much appreciated!
* Compile your Lua scripts in order to reduce their memory usage. The server knows to serve
both .lua and .lc files as scripts.

BIN
http/cars-bugatti.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
http/cars-mercedes.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

51
http/cars.lua Normal file
View File

@@ -0,0 +1,51 @@
return function (connection, req, args)
local function showCars(nr)
if not nr then return end
connection:send([===[<figure><img src="cars-ferrari.jpg" /><figcaption>Ferrari</figcaption></figure>]===])
if nr == "1" then return end
connection:send([===[<figure><img src="cars-lambo.jpg" /><figcaption>Lamborghini</figcaption></figure>]===])
if nr == "2" then return end
connection:send([===[<figure><img src="cars-mas.jpg" /><figcaption>Maserati</figcaption></figure>]===])
if nr == "3" then return end
connection:send([===[<figure><img src="cars-porsche.jpg" /><figcaption>Porsche</figcaption></figure>]===])
if nr == "4" then return end
connection:send([===[<figure><img src="cars-bugatti.jpg" /><figcaption>Bugatti</figcaption></figure>]===])
if nr == "5" then return end
connection:send([===[<figure><img src="cars-mercedes.jpg" /><figcaption>Mercedes</figcaption></figure>]===])
end
dofile("httpserver-header.lc")(connection, 200, 'html')
connection:send([===[
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Nice cars</title>
</head>
<body>
<h1>Nice cars!</h1>
<p>
This page loads "large" images of fancy cars. It is meant to serve as a stress test for nodemcu-httpserver.<br>
It works with three embedded images of cars, but the server crashes with four. Select the number of cars you want to see below.<br>
Whoever manages to modify nodemcu-httpserver to load all four images without crashing wins a prize!
</p>
<p>
choose: <a href="?n=1">show one car</a>
<a href="?n=2">show two cars</a>
<a href="?n=3">show three cars</a>
<a href="?n=4">show four cars</a>
<a href="?n=5">show five cars</a>
<a href="?n=6">show six cars</a>
</p>
]===])
showCars(args.n)
connection:send([===[
</body>
</html>
]===])
end

View File

@@ -1,45 +0,0 @@
-- Author: moononournation
-- Notes by Marcos: This example could be improved quite a bit.
-- We should provide a way to return available access points as JSON, then populated
-- a drop down list using JavaScript every 5-10 seconds. I'm not sure it's worth it,
-- however.
return function (connection, req, args)
dofile('httpserver-header.lc')(connection, 200, 'html')
connection:send('<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Connect AP</title></head><body><h1>Connect AP</h1>')
if req.method == 'GET' then
local ip = wifi.sta.getip()
if not (ip == nil) then
connection:send('<p>IP: ' .. ip .. '</p>')
end
connection:send('<form method="POST">SSID:<br><input type="text" name="ssid"><br>PWD:<br><input type="text" name="pwd"><br><input type="submit" name="submit" value="Submit"></form>')
elseif req.method == 'POST' then
local rd = req.getRequestData()
collectgarbage()
wifi.sta.config(rd['ssid'], rd['pwd'])
wifi.sta.connect()
local joinCounter = 0
local joinMaxAttempts = 15
tmr.alarm(0, 1000, 1, function()
local ip = wifi.sta.getip()
if ip == nil and joinCounter < joinMaxAttempts then
joinCounter = joinCounter + 1
else
if joinCounter >= joinMaxAttempts then
connection:send('<p>Failed to connect to WiFi Access Point.</p>')
else
connection:send('<p>IP: ' .. ip .. '</p>')
end
tmr.stop(0)
joinCounter = nil
joinMaxAttempts = nil
collectgarbage()
end
end)
end
connection:send('</body></html>')
end

View File

@@ -22,6 +22,7 @@
<li><a href="index.html">Index</a>: This page (static)</li>
<li><a href="hello_world.txt">A text file</a>: Simple text, to verify MIME type is ok. (static)</li>
<li><a href="cars.html">Nice cars</a>: Stress test, loads several "large" images. Makes the chip panic and restart :( (static)</li>
<li><a href="cars.lua">Nice cars</a>: Stress test, loads several "large" images. Makes the chip panic and restart :( (dynamic to change number of cars)</li>
<li><a href="counter.html">Count Requests</a>: Stress test, loads the same page over and over, counting every load. (static)</li>
<li><a href="zipped.html">Zipped</a>: File is actually saved as zipped.html.gz. A compressed file! (static but gzipped)</li>
<li><a href="zipped.html.gz">Zipped</a>: Same exact file as served above. Server is smart enough to treat the .gz extension correctly (static but gzipped)</li>

View File

@@ -33,6 +33,29 @@
.dropBox {width:100vw; height:100vh; margin-top: -200px; padding-top: 200px;}
#uploaddir{
background-color: #2E3134;
font-size:16px;
font-weight:bold;
color:#7f858a;
padding: 40px 50px;
margin-bottom: 30px;
}
#uploaddir a{
background-color:#007a96;
padding:12px 26px;
color:#fff;
font-size:14px;
border-radius:2px;
cursor:pointer;
margin-top:12px;
line-height:1;
margin-left: 10px;
}
#selectedDir {
margin-top:20px;
}
#upload{
font-family:'PT Sans Narrow', sans-serif;
background-color:#373a3d;
@@ -140,14 +163,24 @@
position: absolute;
}
.delete:after{
color: #ff0000;
content: "\2718";
}
.uploaded:after{
color: #00ff00;
content: "\2714";
}
#upload ul li span{
width: 15px;
height: 12px;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAaCAYAAABozQZiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpFQUY1MzY0QUU3QjdFMjExODE0NkUyMUJBNERDNDk0NyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCOTc5MTBDQ0I3RUYxMUUyOUVBQkNFOURERDIzQkU4NSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCOTc5MTBDQkI3RUYxMUUyOUVBQkNFOURERDIzQkU4NSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFQUY1MzY0QUU3QjdFMjExODE0NkUyMUJBNERDNDk0NyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFQUY1MzY0QUU3QjdFMjExODE0NkUyMUJBNERDNDk0NyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvX6SiYAAAGjSURBVHjanJRPRMRREMfbNtE19hQlolNdomsRaZUiIlHKdiml7CpFolU6pEOWTUTRJZKIakmHsqQ99UedOiT2lG6xRPSdzFtjGi+/ho99836/78z8Zt7bUN3VfElAKwcRkC/9h/AAPIKmsgDCMNgB3ezvB8m8BQZ4/QkmSVwJbsCcR7gOYrz+Av0gQ2WfgWaGvimphEsgLvwRcEQLypxVLy4KP678cbDnHMqc4GZMiQBU2huX62wWbMqSXLenWeDKW1alr4A13QjZ7YT1AmwDLFhd1KOi0naFf8lVmWYdklHuQTXo8g3eOiT07UOgFXy4zcPB2wpTjAdpcA8iVgbs0yTe8dsi90N3NdEUfifYfwBtPCZn9CzF6wJXlGt8Of3JXCVebAAXfOXIxoTQfVJYlk3n9NgIQGc9LfYpaxRcSzHdkD4jwKoStqujXOy2FUBnzPpGRQHODfErePprzjHVHGf1qom/xCTcVlXkPFMoiocNYQ/PM+MLQOIZJexlUUGsZYBOKaYRPAvhieq0DJCUt45uVZ5LrLXGIQJ0uP8uZ98CDADM9WkEBoK0xwAAAABJRU5ErkJggg==') no-repeat;
cursor:pointer;
position: absolute;
top: 34px;
right: 33px;
cursor:pointer;
font-size:18px;
}
#upload ul li.working span{
@@ -189,7 +222,7 @@
var chunkSize = 128;
var totalUploaded = 0;
var tpl = '<li class="working" id="file%filenum%"><div class="chart" id="graph%filenum%" data-percent="0"></div><p>%filename%<i>%filesize%</i></p><span id="fileStatus%filenum%" onclick="DeleteFiles(%filenum%);"></span></li>';
var tpl = '<li class="working" id="file%filenum%"><div class="chart" id="graph%filenum%" data-percent="0"></div><p>%filename%<i>%filesize%</i></p><span class="delete" id="fileStatus%filenum%" onclick="DeleteFiles(%filenum%);"></span></li>';
document.addEventListener("DOMContentLoaded", function() {
var dropbox;
@@ -200,6 +233,8 @@
dropbox.addEventListener("drop", drop, false);
UpdateFileList();
UploadDir("http");
});
function dragenter(e) {
@@ -235,13 +270,13 @@
var fileNames = {};
for (var i = 0; i < filesCount; i++) {
fileNames[tfiles[i].name] = i;
fileNames[uploadDir + tfiles[i].name] = i;
}
Keys(fileNames).sort(function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c<d?-1:c>d?1:0}).forEach(function(item) {
var i = fileNames[item];
var append = tpl.replace(/%filename%/g, tfiles[i].name);
var append = tpl.replace(/%filename%/g, uploadDir + tfiles[i].name);
append = append.replace(/%filesize%/g, formatFileSize(tfiles[i].size));
append = append.replace(/%filenum%/g, i);
@@ -380,7 +415,7 @@
totalUploaded = 0;
if (statusElement) {
statusElement.style["background-position"] = "0 3px";
statusElement.classList.add("uploaded");
}
if (currentUploadingFile < files.length) {
@@ -396,7 +431,7 @@
fileUploadRequest = 0;
}
lastRequest = 'upload.lua?cmd=upload&filename=' + file.name + '&filesize=' + file.size + '&len=' + chunkLen + '&offset=' + sendingOffset + '&data=' + filedata;
lastRequest = 'upload.lua?cmd=upload&filename=' + uploadDir + file.name + '&filesize=' + file.size + '&len=' + chunkLen + '&offset=' + sendingOffset + '&data=' + filedata;
fileUploadRequest.timeout = 5000;
fileUploadRequest.open('GET', lastRequest, true);
@@ -406,6 +441,16 @@
fr.readAsArrayBuffer(file);
}
function UploadDir(dir) {
if (uploadingInProgress == 0) {
document.getElementById('dir').innerHTML = "/" + dir;
uploadDir = dir;
if (!(uploadDir == "")) {
uploadDir += "/";
}
}
}
function formatFileSize(bytes) {
if (typeof bytes !== 'number') {
return '';
@@ -494,14 +539,14 @@
document.getElementById('fileInfo').innerHTML = '';
var tpl = '<li class="working"><p style="left: 30px;">%filenamelink%<i>%filesize%</i></p><span id="fileStatus" onclick="RemoveFile(\'%filename%\');"></span></li>';
var tpl = '<li class="working"><p style="left: 30px;">%filenamelink%<i>%filesize%</i></p><span class="delete" id="fileStatus" onclick="RemoveFile(\'%filename%\');"></span></li>';
var tplTotal = '<li class="working"><p style="left: 30px;">Used:<i>%used%</i></p></li><li class="working"><p style="left: 30px;">Free:<i>%free%</i></p></li><li class="working"><p style="left: 30px;">Total:<i>%total%</i></p></li>';
var append, link;
Keys(fileList).sort(function(a,b){var c=a.toLowerCase(),d=b.toLowerCase();return c<d?-1:c>d?1:0}).forEach(function(item) {
if (!(item.match(/\.lc$/ig))) {
link = item.replace(/\.gz$/g, '');
if (!item.match(/\.lc$/ig) && item.match(/^http\//ig)) {
link = item.replace(/\.gz$/g, '').replace(/^http\//g, '');
append = tpl.replace(/%filenamelink%/g, '<a href="' + link + '" target="_blank">' + item + '</a>');
}
else {
@@ -549,12 +594,16 @@
<body>
<div id="dropbox" class="dropBox">
<div id="upload">
<div id="uploaddir" class="uploadDir">
<a onclick='UploadDir("");'>/</a>
<a onclick='UploadDir("http");'>/http</a>
<div id="selectedDir">selected Directory: <div id = "dir">bla</div></div></div>
<div id="drop">
Drop Here
<a onclick='document.getElementById("browseInput").click();'>Browse</a>
<a onclick='UploadFiles();'>Upload</a>
<input id="browseInput" type="file" name="upl" onchange="handleFiles(this.files);" multiple />
<form><input id="browseInput" type="file" name="upl" onclick="this.form.reset();" onchange="handleFiles(this.files);" multiple /></form>
</div>
<ul id="fileList">

View File

@@ -48,23 +48,22 @@ return function (connection, req, args)
if (mbCmd == 'upload') then
if (fieldsCount > 5) then
if (mbFilename ~= 'upload.lua') then
if (mbFilename ~= 'http/upload.lua') then
connection:send('"offset":"' .. mbOffset .. '",')
connection:send('"len":"' .. mbLen .. '",')
connection:send('"filename":"' .. mbFilename .. '"')
mbFilename = 'http/' .. mbFilename
for i=1,string.len(mbData),2 do
currentByte = tonumber(string.sub(mbData, i, i + 1), 16)
binaryData = binaryData .. string.char(currentByte)
end
local mbTmpFilename = string.sub(mbFilename, 0, 27) .. '.dnl'
if (mbOffset > 0) then
file.open(mbFilename .. '.dnl','a+')
file.open(mbTmpFilename,'a+')
else
file.remove(mbFilename .. '.dnl')
file.open(mbFilename .. '.dnl','w+')
file.remove(mbTmpFilename)
file.open(mbTmpFilename,'w+')
end
file.seek("set", mbOffset)
file.write(binaryData)
@@ -74,8 +73,8 @@ return function (connection, req, args)
if (fileSize == mbLen + mbOffset) then
file.remove(mbFilename)
file.rename(mbFilename .. '.dnl', mbFilename)
file.remove(mbFilename .. '.dnl')
file.rename(mbTmpFilename, mbFilename)
file.remove(mbTmpFilename)
if (string.sub(mbFilename, -4) == '.lua') then
file.remove(string.sub(mbFilename, 0, -3) .. "lc")
@@ -93,20 +92,16 @@ return function (connection, req, args)
connection:send('"files":{')
for name, size in pairs(file.list()) do
local isHttpFile = string.match(name, "(http/)") ~= nil
if isHttpFile then
if (headerExist > 0) then
connection:send(',')
end
local url = string.match(name, ".*/(.*)")
url = name
connection:send('"' .. url .. '":"' .. size .. '"')
headerExist = 1
end
end
connection:send('},')
@@ -115,8 +110,8 @@ return function (connection, req, args)
connection:send('"free":"' .. remaining .. '"')
elseif (mbCmd == 'remove') then
if (fieldsCount > 1) then
if (mbFilename ~= 'upload.lua') and (mbFilename ~= 'upload.lc') and (mbFilename ~= 'upload.html.gz') then
file.remove('http/' .. mbFilename)
if (mbFilename ~= 'http/upload.lua') and (mbFilename ~= 'http/upload.lc') and (mbFilename ~= 'http/upload.html.gz') then
file.remove(mbFilename)
end
end
end
@@ -124,4 +119,3 @@ return function (connection, req, args)
connection:send('}')
collectgarbage()
end

View File

@@ -37,14 +37,14 @@ end
-- logic OR for number values
local function lor(x,y)
result = 0
local result = 0
for p=1,8 do result = result + (((bit(x,p) or bit(y,p)) == true) and uipow(2, (p-1)) or 0) end
return result
end
-- Character decoding table
local function toBase64Byte(char)
ascii = string.byte(char, 1)
local ascii = string.byte(char, 1)
if ascii >= string.byte('A', 1) and ascii <= string.byte('Z', 1) then return ascii - string.byte('A', 1)
elseif ascii >= string.byte('a', 1) and ascii <= string.byte('z', 1) then return ascii - string.byte('a', 1) + 26
elseif ascii >= string.byte('0', 1) and ascii <= string.byte('9', 1) then return ascii + 4

View File

@@ -2,7 +2,7 @@
-- Part of nodemcu-httpserver, authenticates a user using http basic auth.
-- Author: Sam Dieck
basicAuth = {}
local basicAuth = {}
-- Returns true if the user/password match one of the users/passwords in httpserver-conf.lua.
-- Returns false otherwise.

View File

@@ -3,8 +3,7 @@
-- Author: Marcos Kirsch
local compileAndRemoveIfNeeded = function(f)
if file.open(f) then
file.close()
if file.exists(f) then
print('Compiling:', f)
node.compile(f)
file.remove(f)

View File

@@ -20,9 +20,10 @@ if (conf.wifi.mode == wifi.SOFTAP) or (conf.wifi.mode == wifi.STATIONAP) then
conf.wifi.accessPoint.config = {}
conf.wifi.accessPoint.config.ssid = "ESP-"..node.chipid() -- Name of the WiFi network to create.
conf.wifi.accessPoint.config.pwd = "ESP-"..node.chipid() -- WiFi password for joining - at least 8 characters
conf.wifi.accessPoint.ip = "192.168.111.1"
-- conf.wifi.accessPoint.netmask = "255.255.255.0"
-- conf.wifi.accessPoint.gateway = "192.168.111.1"
conf.wifi.accessPoint.net = {}
conf.wifi.accessPoint.net.ip = "192.168.111.1"
conf.wifi.accessPoint.net.netmask="255.255.255.0"
conf.wifi.accessPoint.net.gateway="192.168.111.1"
end
-- These apply only when connecting to a router as a client
if (conf.wifi.mode == wifi.STATION) or (conf.wifi.mode == wifi.STATIONAP) then

View File

@@ -5,7 +5,7 @@
-- flush() and for closing the connection.
-- Author: Philip Gladstone, Marcos Kirsch
BufferedConnection = {}
local BufferedConnection = {}
-- parameter is the nodemcu-firmware connection
function BufferedConnection:new(connection)

View File

@@ -15,7 +15,7 @@ return function(connection, code, extension, isGzipped, extraHeaders)
-- A few MIME types. Keep list short. If you need something that is missing, let's add it.
local mt = {css = "text/css", gif = "image/gif", html = "text/html", ico = "image/x-icon", jpeg = "image/jpeg",
jpg = "image/jpeg", js = "application/javascript", json = "application/json", png = "image/png", xml = "text/xml"}
if mt[ext] then return mt[ext] else return "text/plain" end
if mt[ext] then return mt[ext] else return "application/octet-stream" end
end
local mimeType = getMimeType(extension)

View File

@@ -21,7 +21,8 @@ local function uri_decode(input)
end
local function parseArgs(args)
local r = {}; i=1
local r = {}
local i = 1
if args == nil or args == "" then return r end
for arg in string.gmatch(args, "([^&]+)") do
local name, value = string.match(arg, "(.*)=(.*)")
@@ -46,6 +47,10 @@ local function getRequestData(payload)
local requestData
return function ()
--print("Getting Request Data")
-- for backward compatibility before v2.1
if (sjson == nil) then
sjson = cjson
end
if requestData then
return requestData
else
@@ -60,7 +65,7 @@ local function getRequestData(payload)
--print("body = [" .. body .. "]")
if mimeType == "application/json" then
--print("JSON: " .. body)
requestData = cjson.decode(body)
requestData = sjson.decode(body)
elseif mimeType == "application/x-www-form-urlencoded" then
requestData = parseFormData(body)
else
@@ -79,7 +84,7 @@ local function parseUri(uri)
if uri == nil then return r end
if uri == "/" then uri = "/index.html" end
questionMarkPos, b, c, d, e, f = uri:find("?")
local questionMarkPos, b, c, d, e, f = uri:find("?")
if questionMarkPos == nil then
r.file = uri:sub(1, questionMarkPos)
r.args = {}
@@ -111,6 +116,7 @@ return function (request)
if not e then return nil end
local line = request:sub(1, e - 1)
local r = {}
local _, i
_, i, r.method, r.request = line:find("^([A-Z]+) (.-) HTTP/[1-9]+.[0-9]+$")
if not (r.method and r.request) then
--print("invalid request: ")

View File

@@ -14,12 +14,12 @@ wifi.setmode(conf.wifi.mode)
if (conf.wifi.mode == wifi.SOFTAP) or (conf.wifi.mode == wifi.STATIONAP) then
print('AP MAC: ',wifi.ap.getmac())
wifi.ap.config(conf.wifi.accessPoint.config)
wifi.ap.setip(conf.wifi.accessPoint.ip)
wifi.ap.setip(conf.wifi.accessPoint.net)
end
if (conf.wifi.mode == wifi.STATION) or (conf.wifi.mode == wifi.STATIONAP) then
print('Client MAC: ',wifi.sta.getmac())
wifi.sta.config(conf.wifi.station.ssid, conf.wifi.station.pwd, 1)
wifi.sta.config(conf.wifi.station)
end
print('chip: ',node.chipid())

View File

@@ -61,19 +61,19 @@ return function (port)
uri.args = {code = 400, errorString = "Bad Request", logFunction = log}
fileServeFunction = dofile("httpserver-error.lc")
else
local fileExists = file.open(uri.file, "r")
file.close()
local fileExists = false
if not fileExists then
if not file.exists(uri.file) then
-- print(uri.file .. " not found, checking gz version...")
-- gzip check
fileExists = file.open(uri.file .. ".gz", "r")
file.close()
if fileExists then
if file.exists(uri.file .. ".gz") then
-- print("gzip variant exists, serving that one")
uri.file = uri.file .. ".gz"
uri.isGzipped = true
fileExists = true
end
else
fileExists = true
end
if not fileExists then