Code Monkey home page Code Monkey logo

esp-ginx's Introduction

esp-ginx

##Robust HTTP server for the ESP8266

This project was inspired esp-httpd by Sprite_tm, NodeMcu ( https://github.com/nodemcu/nodemcu-firmware ) and NGINX

Main features

  1. Event-driven, single threaded. No blocking, nowhere.
  2. DNS Server built in, means we have a captive portal ( will open upon connection os most phones and computers )
  3. Host check, means we can ensure server is on here.com and not there.com
  4. Redirects ( so #2 will work )
  5. HTTP Method enforcement
  6. URL rewrite ( very simple one but gives us friendly urls)
  7. CGI ( similar to esp-httpd but with more features )
  8. CORS enabled
  9. Zero-copy ( or almost ) request parse, inspired on NGINX parse.
  10. ROFS compressed with gzip
  11. WebSockects!
  12. Bonus http client :)

Overview

After playing around with esp-httpd I decided to extend it and ended up deciding to take it to the next level. I've used the NodeMcu firmware as base, removed all the lua related code and got a solid framework to work on. Later I ported Joyent's http parser (https://github.com/joyent/http-parser), which is almost the NGINX implementation, to the esp and developed from there.

The File System

I personally didn't like the overhead of decompressing static files to send over http as in esp-httpd, so I created a rom file system that consists of a static FS descriptor and an array with the data concatenated. To keep size short, I compress the files with gzip and send the compressed data stream with the gzip content-encoding. I could fit the whole bootstrap css+js files even if I didn't need to, plus cats pictures to honor Sprite_tm.

Static files are placed in the folder 'html' and there's a tool written in python to create the file system. The file system in the end id just a c file. Issuing 'Make html' creates/updates the file system.

There's a Spiffs built on the firmware, so a next step should be use it instead, but for my needs right now a static FS is enough.

CGI

I don't believe in template html for such low memory devices. I rather prefer the static html + json api approach. So that's what you will see.

When a request arrives, the server will start to parse it and call a cgi dispatcher on several points of the process, mainly on the http parser callbacks. This allows me to reject a request even before the body was received for example. It also allows me not to copy unnecessary data to the precious ESP memory. CGI functions can say which headers they need to read and the parser will extract them as the data comes. We never save the whole request on a buffer.

CGI functions are very flexible. They can allow other rules to proccess or keep the processing to themselfs. We can plugin features like request filtering by inserting wildcard cgi functions on the pipe for example. CORS cgi will plug itself on the pre-headers received and post headers received only.

DNS server and Captive Portal

I wanted to have captive portal-like featured on the server. To do so the first step was to compile our own version of LwIP stack so we can enable DNS server announce via DHCP. Fortunatelly NodeMCU had LwIP sources already. We then need to answer some known domains queries with our own ip, so we can capture those requests. Iphones for example to detect captive portal will issue a request to some random apple owned domains expecting 200 OK response, if we respond those requests with a redirect, voilà, the phone will open a login page with anything we like. It also works on PCs, windows will issue a requet to msftncsi.com to check for internet connection. When we redirect it, it will open our esp-ginx server on our loved browser. There's a list of knows domains on the DNS server. I could just answer all DNS queries with our esp ip, but it would then flood our little esp with nonsense http requests.

Websockets

Why? Mostly because I didn't see it around. I use it to speed test the esp's tcp capabilities, so a very simple application is written on top of the websocket stack that will keep flushing tcp packets of the chosen size so we can measure how many bytes / second we receive on the other end.

The Demo

This demo application assumes:

  • Relays connects to GPIO 5 and 4
  • DHT22 sensor connected to GPIO 2

You can :

  • Scan available wifi networks
  • Connect to an wifi network
  • Direct test the relays
  • Read temperature and humidity data
  • Do a tcp speed test on ESP8266 using websockets ( no more discussion about it, data wins )
  • See the required pictures of cats

Speed Test

esp-ginx's People

Contributors

israellot avatar slawx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esp-ginx's Issues

Wrong value in Content-Length

Hi,
I noticed that server set inappropriate value in "Content-Length" header.
See example below.

Content-Length:"![!@R��@à¨þ?À3ÿ?"

Best Regards
Krzysztof Cybulski

BUG report

http_process.c
http_connection * http_process_find_connection(void *arg)

this function find http_connection by arg that comes from espconn_*_callback.
it works by comparing arg with http_connection.espConnection in connection_poll.
However, in esp8266_non_os_sdk_api_reference_cn.pdf

Parameter arg of callback is the pointer corresponding structure espconn. This pointer may be different
in different callbacks, please do not use this pointer directly to distinguish one from another in multiple
connections. Use remote_ip and remote_port in espconn instead.

For example, parameter arg in espconn_disconnect_callback and espconn_sent_callback
is differrent.

no 0x00000.bin and 0x10000.bin files

Hi there,

I installed the toolchain according this wiki https://github.com/esp8266/esp8266-wiki/wiki/Toolchain and after some tweaks (copying libhal.a and libc.a to ./lib) succeded to compile the project
Unfortunatly I can't flash anything since it looks like I do not have the 0x00000.bin and 0x10000.bin files ?

here the end of the make output (seems all is okay)

xtensa-lx106-elf-ar ru .output/eagle/debug/lib/spiffs.a .output/eagle/debug/obj/spiffs.o .output/eagle/debug/obj/spiffs_cache.o .output/eagle/debug/obj/spiffs_check.o .output/eagle/debug/obj/spiffs_gc.o .output/eagle/debug/obj/spiffs_hydrogen.o .output/eagle/debug/obj/spiffs_nucleus.o
xtensa-lx106-elf-ar: creating .output/eagle/debug/lib/spiffs.a
make[2]: Leaving directory `/opt/Espressif/ESP8266_SDK/esp-ginx/app/spiffs'
xtensa-lx106-elf-gcc  -L../lib -nostdlib -T../ld/eagle.app.v6.ld -Wl,--no-check-sections -u call_user_start -Wl,-static -Wl,--start-group -lc -lgcc -lhal -lphy -lpp -lnet80211 -lwpa -lmain -ljson -lsmartconfig -lssl user/.output/eagle/debug/lib/libuser.a http/.output/eagle/debug/lib/http.a dns/.output/eagle/debug/lib/dns.a driver/.output/eagle/debug/lib/libdriver.a lwip/.output/eagle/debug/lib/liblwip.a json/.output/eagle/debug/lib/libjson.a platform/.output/eagle/debug/lib/libplatform.a libc/.output/eagle/debug/lib/liblibc.a mqtt/.output/eagle/debug/lib/mqtt.a smart/.output/eagle/debug/lib/smart.a util/.output/eagle/debug/lib/util.a sensor/.output/eagle/debug/lib/sensors.a spiffs/.output/eagle/debug/lib/spiffs.a -Wl,--end-group -o .output/eagle/debug/image/eagle.app.v6.out
xtensa-lx106-elf-objcopy -O binary .output/eagle/debug/image/eagle.app.v6.out .output/eagle/debug/bin/eagle.app.v6.bin
make[1]: Leaving directory `/opt/Espressif/ESP8266_SDK/esp-ginx/app'
challard@DiskStation:/opt/Espressif/ESP8266_SDK/esp-ginx$

here the only bin file I have :

challard@DiskStation:/opt/Espressif/ESP8266_SDK/esp-ginx$ find . -name *.bin
./app/.output/eagle/debug/bin/eagle.app.v6.bin
./bin/blank.bin
./bin/esp_init_data_default.bin
challard@DiskStation:/opt/Espressif/ESP8266_SDK/esp-ginx$ ls -al ./app/.output/eagle/debug/bin/*.bin ./bin/*.bin
-rwxr-xr-x 1 challard challard 2559880 Jul 26 23:14 ./app/.output/eagle/debug/bin/eagle.app.v6.bin
-rw-r--r-- 1 challard challard    4096 Jul 26 22:05 ./bin/blank.bin
-rw-r--r-- 1 challard challard     128 Jul 26 22:05 ./bin/esp_init_data_default.bin
challard@DiskStation:/opt/Espressif/ESP8266_SDK/esp-ginx$

of course trying a make flash bring me a file not found

challard@DiskStation:/opt/Espressif/ESP8266_SDK/esp-ginx$ make flash
../Makefile:95: warning: overriding commands for target `clean'
Makefile:167: warning: ignoring old commands for target `clean'
../Makefile:99: warning: overriding commands for target `clobber'
Makefile:171: warning: ignoring old commands for target `clobber'
../Makefile:103: warning: overriding commands for target `.subdirs'
Makefile:185: warning: ignoring old commands for target `.subdirs'
make -C ./app flash
make[1]: Entering directory `/opt/Espressif/ESP8266_SDK/esp-ginx/app'
../../Makefile:95: warning: overriding commands for target `clean'
../Makefile:167: warning: ignoring old commands for target `clean'
../../Makefile:99: warning: overriding commands for target `clobber'
../Makefile:171: warning: ignoring old commands for target `clobber'
../../Makefile:103: warning: overriding commands for target `.subdirs'
../Makefile:185: warning: ignoring old commands for target `.subdirs'
../../Makefile:158: warning: overriding commands for target `.output/eagle/debug/image/eagle.app.v6.out'
../Makefile:240: warning: ignoring old commands for target `.output/eagle/debug/image/eagle.app.v6.out'
../tools/esptool.py --port /dev/ttyUSB0 write_flash 0x00000 ../bin/0x00000.bin 0x10000 ../bin/0x10000.bin
Connecting...
Traceback (most recent call last):
  File "../tools/esptool.py", line 556, in <module>
    image = file(filename, 'rb').read()
IOError: [Errno 2] No such file or directory: '../bin/0x00000.bin'
make[1]: *** [flash] Error 1
make[1]: Leaving directory `/opt/Espressif/ESP8266_SDK/esp-ginx/app'
make: *** [flash] Error 2
challard@DiskStation:/opt/Espressif/ESP8266_SDK/esp-ginx$

I think the 2nd file should be the file eagle.app.v6.bin but not sure of the 1st one to flash at 0x00000 ?

Any ideas ? Thank's for your help

Compile error

Hello,'I'm getting compilation error:

/opt/Espressif/crosstool-NG/builds/xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld: cannot find -lc
/opt/Espressif/crosstool-NG/builds/xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld: cannot find -lhal

esp8266 reverse-engineering

A bit offtopic, but - saw your (I guess so) topic on bbs.espressif about packet injection work you did. Would like to make sure that folks who're interested in getting more of esp8266 know about each other's efforts and hopefully stay in touch. Some my stuff of interest mentioned here: tommie/lx106-hal#1 (comment)

cJSON floating point issue

Hi,
i tried your code today and its working very well but cJSON is not converting a float number correctly.
You hit the problem if you try to read the dht22. The output looks like this:
{
"temp": %.0f,
"hum": %.0f
}
My current fix is to typecast the values like this:
cJSON_AddNumberToObject(root,"temp",(int8_t)data.dht22.temp);
cJSON_AddNumberToObject(root,"hum",(uint8_t)data.dht22.hum);
Maybe someone know how to fix the cJSON lib easily?!

I am using the esp-open-sdk (espressif lib v1.0.1) to compile the code.

Compile error

Hi,

thanks for your great job but I could not compile the project. I am using Ubuntu VM and not a linux guy at all. I set the xtensa path
(XTENSA_TOOLS_ROOT ?= /opt/esp-open-sdk/xtensa-lx106-elf/bin)
at make file but still I get this error.

make[1]: Entering directory /opt/esp-ginx/app' make[2]: Entering directory/opt/esp-ginx/app/user'
DEPEND: xtensa-lx106-elf-gcc -M -Os -Os -ffunction-sections -fno-jump-tables -g -O2 -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH -DLWIP_OPEN_SRC -DPBUF_RSV_FOR_WLAN -DEBUF_LWIP -I include -I ./ -I ../../include/ets -I ../libc -I ../platform -I ../http -I ../dns -I ../ -I ../include -I ./ -I ../../include -I ../../include/eagle user_main.c
/bin/sh: 2: xtensa-lx106-elf-gcc: not found
xtensa-lx106-elf-gcc -Os -Os -ffunction-sections -fno-jump-tables -g -O2 -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH -DLWIP_OPEN_SRC -DPBUF_RSV_FOR_WLAN -DEBUF_LWIP -I include -I ./ -I ../../include/ets -I ../libc -I ../platform -I ../http -I ../dns -I ../ -I ../include -I ./ -I ../../include -I ../../include/eagle -o .output/eagle/debug/obj/user_main.o -c user_main.c
make[2]: xtensa-lx106-elf-gcc: Command not found
make[2]: *** [.output/eagle/debug/obj/user_main.o] Error 127
make[2]: Leaving directory /opt/esp-ginx/app/user' make[1]: *** [.subdirs] Error 2 make[1]: Leaving directory/opt/esp-ginx/app'
make: *** [.subdirs] Error 2

Could you please help me on this?

Thanks.

Big thank for esp-ginx project

Hi
I've lost 1 month to find the http server esp8266 for my project.
I think that this project is the BEST project esp8266.
Thankyou again, thank very much

hello

Hi. An interesting project. Can I see a demo photos or videos? thank

WDT Reset with demo application

I've got the latest master and have tried to flash my ESP8266 (actually a nodeMCU v0.9).

With the esptool.py provided, I get a 'Failed to connect' exception:

james@JAMES-DEB-PC:~/Downloads/esp-ginx$ make flash
make -C ./app flash
make[1]: Entering directory '/home/james/Downloads/esp-ginx/app'
../tools/esptool.py --port /dev/ttyUSB0 write_flash 0x00000 ../bin/0x00000.bin 0x10000 ../bin/0x10000.bin
Connecting...
Traceback (most recent call last):
  File "../tools/esptool.py", line 388, in <module>
    esp.connect()
  File "../tools/esptool.py", line 156, in connect
    raise Exception('Failed to connect')
Exception: Failed to connect
../Makefile:177: recipe for target 'flash' failed

If I replace the provided esptool.py with the latest from https://github.com/themadinventor/esptool, I can flash the ESP, but I get watchdog timer resets:

 ets Jan  8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x40100000, len 28428, room 16 
tail 12
chksum 0x82

I haven't changed anything in the esp-ginx repository besides the esptool.py file.

Do you think the esptool changes could cause the flash to be written incorrectly, causing WDT resets? I'm not skilled/knowledgeable enough to go through the changes and work out what could be wrong.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.