diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e0195a4..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "lib/heatshrink"] - path = libesphttpd/lib/heatshrink - url = https://github.com/atomicobject/heatshrink.git diff --git a/libesphttpd/.gitignore b/libesphttpd/.gitignore deleted file mode 100644 index 5e14a6f..0000000 --- a/libesphttpd/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -build/ -espfs/mkespfsimage/*.o -espfs/mkespfsimage/mkespfsimage -webpages.espfs -libesphttpd.a -espfs/espfstest/*.o -espfs/espfstest/espfstest -*.DS_Store -html_compressed/ -libwebpages-espfs.a \ No newline at end of file diff --git a/libesphttpd/Makefile b/libesphttpd/Makefile deleted file mode 100644 index a51a7ca..0000000 --- a/libesphttpd/Makefile +++ /dev/null @@ -1,145 +0,0 @@ - -# Directory the Makefile is in. Please don't include other Makefiles before this. -THISDIR:=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) - -#Include httpd config from lower level, if it exists --include ../esphttpdconfig.mk - - -#Default options. If you want to change them, please create ../esphttpdconfig.mk with the options you want in it. -GZIP_COMPRESSION ?= no -COMPRESS_W_YUI ?= no -YUI-COMPRESSOR ?= /usr/bin/yui-compressor -USE_HEATSHRINK ?= yes - - - -# Output directors to store intermediate compiled files -# relative to the project directory -BUILD_BASE = build - -# Base directory for the compiler. Needs a / at the end; if not set it'll use the tools that are in -# the PATH. -XTENSA_TOOLS_ROOT ?= - -# base directory of the ESP8266 SDK package, absolute -SDK_BASE ?= /opt/Espressif/ESP8266_SDK - -# name for the target project -LIB = libesphttpd.a - -# which modules (subdirectories) of the project to include in compiling -MODULES = espfs core util -EXTRA_INCDIR = ./include \ - . \ - lib/heatshrink/ - - -# compiler flags using during compilation of source files -CFLAGS = -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ - -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH -D_STDINT_H \ - -Wno-address - -# various paths from the SDK used in this project -SDK_LIBDIR = lib -SDK_LDDIR = ld -SDK_INCDIR = include - -# select which tools to use as compiler, librarian and linker -CC := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc -AR := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-ar -LD := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc -OBJCOPY := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy - -#### -#### no user configurable options below here -#### -SRC_DIR := $(MODULES) -BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES)) - -SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR)) - -SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c)) -OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC)) - -INCDIR := $(addprefix -I,$(SRC_DIR)) -EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR)) -MODULE_INCDIR := $(addsuffix /include,$(INCDIR)) - -V ?= $(VERBOSE) -ifeq ("$(V)","1") -Q := -vecho := @true -else -Q := @ -vecho := @echo -endif - -ifeq ("$(GZIP_COMPRESSION)","yes") -CFLAGS += -DGZIP_COMPRESSION -endif - -ifeq ("$(USE_HEATSHRINK)","yes") -CFLAGS += -DESPFS_HEATSHRINK -endif - -vpath %.c $(SRC_DIR) - -define compile-objects -$1/%.o: %.c - $(vecho) "CC $$<" - $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ -endef - -.PHONY: all checkdirs clean webpages.espfs - -all: checkdirs $(LIB) webpages.espfs libwebpages-espfs.a - - -$(LIB): $(OBJ) - $(vecho) "AR $@" - $(Q) $(AR) cru $@ $^ - -checkdirs: $(BUILD_DIR) - -$(BUILD_DIR): - $(Q) mkdir -p $@ - - -webpages.espfs: $(HTMLDIR) espfs/mkespfsimage/mkespfsimage -ifeq ("$(COMPRESS_W_YUI)","yes") - $(Q) rm -rf html_compressed; - $(Q) cp -r ../html html_compressed; - $(Q) echo "Compression assets with yui-compressor. This may take a while..." - $(Q) for file in `find html_compressed -type f -name "*.js"`; do $(YUI-COMPRESSOR) --type js $$file -o $$file; done - $(Q) for file in `find html_compressed -type f -name "*.css"`; do $(YUI-COMPRESSOR) --type css $$file -o $$file; done - $(Q) awk "BEGIN {printf \"YUI compression ratio was: %.2f%%\\n\", (`du -b -s html_compressed/ | sed 's/\([0-9]*\).*/\1/'`/`du -b -s ../html/ | sed 's/\([0-9]*\).*/\1/'`)*100}" -# mkespfsimage will compress html, css and js files with gzip by default if enabled -# override with -g cmdline parameter - $(Q) cd html_compressed; find | $(THISDIR)/espfs/mkespfsimage/mkespfsimage > $(THISDIR)/webpages.espfs; cd ..; -else - $(Q) cd ../html; find | $(THISDIR)/espfs/mkespfsimage/mkespfsimage > $(THISDIR)/webpages.espfs; cd .. -endif - -libwebpages-espfs.a: webpages.espfs - $(Q) $(OBJCOPY) -I binary -O elf32-xtensa-le -B xtensa --rename-section .data=.irom0.literal \ - --redefine-sym _binary_webpages_espfs_start=webpages_espfs_start \ - --redefine-sym _binary_webpages_espfs_end=webpages_espfs_end \ - --redefine-sym _binary_webpages_espfs_size=webpages_espfs_size \ - webpages.espfs build/webpages.espfs.o - $(Q) $(AR) cru $@ build/webpages.espfs.o - -espfs/mkespfsimage/mkespfsimage: espfs/mkespfsimage/ - $(Q) $(MAKE) -C espfs/mkespfsimage USE_HEATSHRINK="$(USE_HEATSHRINK)" GZIP_COMPRESSION="$(GZIP_COMPRESSION)" - -clean: - $(Q) rm -f $(LIB) - $(Q) find $(BUILD_BASE) -type f | xargs rm -f - $(Q) make -C espfs/mkespfsimage/ clean - $(Q) rm -rf $(FW_BASE) - $(Q) rm -f webpages.espfs -ifeq ("$(COMPRESS_W_YUI)","yes") - $(Q) rm -rf html_compressed -endif - -$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir)))) diff --git a/libesphttpd/core/auth.c b/libesphttpd/core/auth.c deleted file mode 100644 index 1e247a0..0000000 --- a/libesphttpd/core/auth.c +++ /dev/null @@ -1,61 +0,0 @@ -/* -HTTP auth implementation. Only does basic authentication for now. -*/ - -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - */ - - -#include -#include "auth.h" -#include "base64.h" - -int ICACHE_FLASH_ATTR authBasic(HttpdConnData *connData) { - const char *forbidden="401 Forbidden."; - int no=0; - int r; - char hdr[(AUTH_MAX_USER_LEN+AUTH_MAX_PASS_LEN+2)*10]; - char userpass[AUTH_MAX_USER_LEN+AUTH_MAX_PASS_LEN+2]; - char user[AUTH_MAX_USER_LEN]; - char pass[AUTH_MAX_PASS_LEN]; - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - - r=httpdGetHeader(connData, "Authorization", hdr, sizeof(hdr)); - if (r && strncmp(hdr, "Basic", 5)==0) { - r=base64_decode(strlen(hdr)-6, hdr+6, sizeof(userpass), (unsigned char *)userpass); - if (r<0) r=0; //just clean out string on decode error - userpass[r]=0; //zero-terminate user:pass string -// os_printf("Auth: %s\n", userpass); - while (((AuthGetUserPw)(connData->cgiArg))(connData, no, - user, AUTH_MAX_USER_LEN, pass, AUTH_MAX_PASS_LEN)) { - //Check user/pass against auth header - if (strlen(userpass)==strlen(user)+strlen(pass)+1 && - os_strncmp(userpass, user, strlen(user))==0 && - userpass[strlen(user)]==':' && - os_strcmp(userpass+strlen(user)+1, pass)==0) { - //Authenticated. Yay! - return HTTPD_CGI_AUTHENTICATED; - } - no++; //Not authenticated with this user/pass. Check next user/pass combo. - } - } - - //Not authenticated. Go bug user with login screen. - httpdStartResponse(connData, 401); - httpdHeader(connData, "Content-Type", "text/plain"); - httpdHeader(connData, "WWW-Authenticate", "Basic realm=\""HTTP_AUTH_REALM"\""); - httpdEndHeaders(connData); - httpdSend(connData, forbidden, -1); - //Okay, all done. - return HTTPD_CGI_DONE; -} - diff --git a/libesphttpd/core/base64.c b/libesphttpd/core/base64.c deleted file mode 100644 index 9d97a26..0000000 --- a/libesphttpd/core/base64.c +++ /dev/null @@ -1,112 +0,0 @@ -/* base64.c : base-64 / MIME encode/decode */ -/* PUBLIC DOMAIN - Jon Mayo - November 13, 2003 */ -#include -#include "base64.h" - -static const uint8_t base64dec_tab[256]= { - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255, - 255, 0, 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,255,255,255,255,255, - 255, 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,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, -}; - -#if 0 -static int ICACHE_FLASH_ATTR base64decode(const char in[4], char out[3]) { - uint8_t v[4]; - - v[0]=base64dec_tab[(unsigned)in[0]]; - v[1]=base64dec_tab[(unsigned)in[1]]; - v[2]=base64dec_tab[(unsigned)in[2]]; - v[3]=base64dec_tab[(unsigned)in[3]]; - - out[0]=(v[0]<<2)|(v[1]>>4); - out[1]=(v[1]<<4)|(v[2]>>2); - out[2]=(v[2]<<6)|(v[3]); - return (v[0]|v[1]|v[2]|v[3])!=255 ? in[3]=='=' ? in[2]=='=' ? 1 : 2 : 3 : 0; -} -#endif - -/* decode a base64 string in one shot */ -int ICACHE_FLASH_ATTR base64_decode(size_t in_len, const char *in, size_t out_len, unsigned char *out) { - unsigned int ii, io; - uint32_t v; - unsigned int rem; - - for(io=0,ii=0,v=0,rem=0;ii=8) { - rem-=8; - if(io>=out_len) return -1; /* truncation is failure */ - out[io++]=(v>>rem)&255; - } - } - if(rem>=8) { - rem-=8; - if(io>=out_len) return -1; /* truncation is failure */ - out[io++]=(v>>rem)&255; - } - return io; -} - -//Only need decode functions for now. -#if 0 - -static const uint8_t base64enc_tab[64]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -void base64encode(const unsigned char in[3], unsigned char out[4], int count) { - out[0]=base64enc_tab[(in[0]>>2)]; - out[1]=base64enc_tab[((in[0]&3)<<4)|(in[1]>>4)]; - out[2]=count<2 ? '=' : base64enc_tab[((in[1]&15)<<2)|(in[2]>>6)]; - out[3]=count<3 ? '=' : base64enc_tab[(in[2]&63)]; -} - - -int base64_encode(size_t in_len, const unsigned char *in, size_t out_len, char *out) { - unsigned ii, io; - uint_least32_t v; - unsigned rem; - - for(io=0,ii=0,v=0,rem=0;ii=6) { - rem-=6; - if(io>=out_len) return -1; /* truncation is failure */ - out[io++]=base64enc_tab[(v>>rem)&63]; - } - } - if(rem) { - v<<=(6-rem); - if(io>=out_len) return -1; /* truncation is failure */ - out[io++]=base64enc_tab[v&63]; - } - while(io&3) { - if(io>=out_len) return -1; /* truncation is failure */ - out[io++]='='; - } - if(io>=out_len) return -1; /* no room for null terminator */ - out[io]=0; - return io; -} - -#endif \ No newline at end of file diff --git a/libesphttpd/core/base64.h b/libesphttpd/core/base64.h deleted file mode 100644 index 4dc8621..0000000 --- a/libesphttpd/core/base64.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef BASE64_H -#define BASE64_H - -int base64_decode(size_t in_len, const char *in, size_t out_len, unsigned char *out); - -#endif \ No newline at end of file diff --git a/libesphttpd/core/httpd.c b/libesphttpd/core/httpd.c deleted file mode 100644 index 899e109..0000000 --- a/libesphttpd/core/httpd.c +++ /dev/null @@ -1,560 +0,0 @@ -/* -Esp8266 http server - core routines -*/ - -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - */ - - -#include -#include "httpd.h" - - -//Max length of request head -#define MAX_HEAD_LEN 1024 -//Max amount of connections -#define MAX_CONN 8 -//Max post buffer len -#define MAX_POST 1024 -//Max send buffer len -#define MAX_SENDBUFF_LEN 2048 - - -//This gets set at init time. -static HttpdBuiltInUrl *builtInUrls; - -//Private data for http connection -struct HttpdPriv { - char head[MAX_HEAD_LEN]; - int headPos; - char *sendBuff; - int sendBuffLen; -}; - -//Connection pool -static HttpdPriv connPrivData[MAX_CONN]; -static HttpdConnData connData[MAX_CONN]; -static HttpdPostData connPostData[MAX_CONN]; - -//Listening connection data -static struct espconn httpdConn; -static esp_tcp httpdTcp; - -//Struct to keep extension->mime data in -typedef struct { - const char *ext; - const char *mimetype; -} MimeMap; - -//The mappings from file extensions to mime types. If you need an extra mime type, -//add it here. -static const MimeMap mimeTypes[]={ - {"htm", "text/htm"}, - {"html", "text/html"}, - {"css", "text/css"}, - {"js", "text/javascript"}, - {"txt", "text/plain"}, - {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, - {"png", "image/png"}, - {NULL, "text/html"}, //default value -}; - -//Returns a static char* to a mime type for a given url to a file. -const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) { - int i=0; - //Go find the extension - char *ext=url+(strlen(url)-1); - while (ext!=url && *ext!='.') ext--; - if (*ext=='.') ext++; - - //ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here... - while (mimeTypes[i].ext!=NULL && os_strcmp(ext, mimeTypes[i].ext)!=0) i++; - return mimeTypes[i].mimetype; -} - -//Looks up the connData info for a specific esp connection -static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { - int i; - for (i=0; ipost->buff!=NULL) os_free(conn->post->buff); - conn->post->buff=NULL; - conn->cgi=NULL; - conn->conn=NULL; -} - -//Stupid li'l helper function that returns the value of a hex char. -static int httpdHexVal(char c) { - if (c>='0' && c<='9') return c-'0'; - if (c>='A' && c<='F') return c-'A'+10; - if (c>='a' && c<='f') return c-'a'+10; - return 0; -} - -//Decode a percent-encoded value. -//Takes the valLen bytes stored in val, and converts it into at most retLen bytes that -//are stored in the ret buffer. Returns the actual amount of bytes used in ret. Also -//zero-terminates the ret buffer. -int httpdUrlDecode(char *val, int valLen, char *ret, int retLen) { - int s=0, d=0; - int esced=0, escVal=0; - while (spriv->head; - p=p+strlen(p)+1; //skip GET/POST part - p=p+strlen(p)+1; //skip HTTP part - while (p<(conn->priv->head+conn->priv->headPos)) { - while(*p<=32 && *p!=0) p++; //skip crap at start - //See if this is the header - if (os_strncmp(p, header, strlen(header))==0 && p[strlen(header)]==':') { - //Skip 'key:' bit of header line - p=p+strlen(header)+1; - //Skip past spaces after the colon - while(*p==' ') p++; - //Copy from p to end - while (*p!=0 && *p!='\r' && *p!='\n' && retLen>1) { - *ret++=*p++; - retLen--; - } - //Zero-terminate string - *ret=0; - //All done :) - return 1; - } - p+=strlen(p)+1; //Skip past end of string and \0 terminator - } - return 0; -} - -//Start the response headers. -void ICACHE_FLASH_ATTR httpdStartResponse(HttpdConnData *conn, int code) { - char buff[128]; - int l; - l=os_sprintf(buff, "HTTP/1.0 %d OK\r\nServer: esp8266-httpd/"HTTPDVER"\r\nConnection: close\r\n", code); - httpdSend(conn, buff, l); -} - -//Send a http header. -void ICACHE_FLASH_ATTR httpdHeader(HttpdConnData *conn, const char *field, const char *val) { - char buff[256]; - int l; - - l=os_sprintf(buff, "%s: %s\r\n", field, val); - httpdSend(conn, buff, l); -} - -//Finish the headers. -void ICACHE_FLASH_ATTR httpdEndHeaders(HttpdConnData *conn) { - httpdSend(conn, "\r\n", -1); -} - -//ToDo: sprintf->snprintf everywhere... esp doesn't have snprintf tho' :/ -//Redirect to the given URL. -void ICACHE_FLASH_ATTR httpdRedirect(HttpdConnData *conn, char *newUrl) { - char buff[1024]; - int l; - l=os_sprintf(buff, "HTTP/1.1 302 Found\r\nServer: esp8266-httpd/"HTTPDVER"\r\nConnection: close\r\nLocation: %s\r\n\r\nMoved to %s\r\n", newUrl, newUrl); - httpdSend(conn, buff, l); -} - -//Use this as a cgi function to redirect one url to another. -int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - httpdRedirect(connData, (char*)connData->cgiArg); - return HTTPD_CGI_DONE; -} - -//This CGI function redirects to a fixed url of http://[hostname]/ if hostname field of request isn't -//already that hostname. Use this in combination with a DNS server that redirects everything to the -//ESP in order to load a HTML page as soon as a phone connects to the ESP. -int ICACHE_FLASH_ATTR cgiCheckHostname(HttpdConnData *connData) { - char buff[1024]; - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - //Check hostname; pass on if the same - if (connData->hostName==NULL || os_strcmp(connData->hostName, (char*)connData->cgiArg)==0) return HTTPD_CGI_NOTFOUND; - //Not the same. Redirect to real hostname. - os_sprintf(buff, "http://%s/", (char*)connData->cgiArg); - os_printf("Redirecting to hostname url %s\n", buff); - httpdRedirect(connData, buff); - return HTTPD_CGI_DONE; -} - -//Add data to the send buffer. len is the length of the data. If len is -1 -//the data is seen as a C-string. -//Returns 1 for success, 0 for out-of-memory. -int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len) { - if (len<0) len=strlen(data); - if (conn->priv->sendBuffLen+len>MAX_SENDBUFF_LEN) return 0; - os_memcpy(conn->priv->sendBuff+conn->priv->sendBuffLen, data, len); - conn->priv->sendBuffLen+=len; - return 1; -} - -//Helper function to send any data in conn->priv->sendBuff -static void ICACHE_FLASH_ATTR xmitSendBuff(HttpdConnData *conn) { - if (conn->priv->sendBuffLen!=0) { - espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen); - conn->priv->sendBuffLen=0; - } -} - -//Callback called when the data on a socket has been successfully -//sent. -static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { - int r; - HttpdConnData *conn=httpdFindConnData(arg); - char sendBuff[MAX_SENDBUFF_LEN]; - - if (conn==NULL) return; - conn->priv->sendBuff=sendBuff; - conn->priv->sendBuffLen=0; - - if (conn->cgi==NULL) { //Marked for destruction? - os_printf("Conn %p is done. Closing.\n", conn->conn); - espconn_disconnect(conn->conn); - httpdRetireConn(conn); - return; //No need to call xmitSendBuff. - } - - r=conn->cgi(conn); //Execute cgi fn. - if (r==HTTPD_CGI_DONE) { - conn->cgi=NULL; //mark for destruction. - } - if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { - os_printf("ERROR! CGI fn returns code %d after sending data! Bad CGI!\n", r); - conn->cgi=NULL; //mark for destruction. - } - xmitSendBuff(conn); -} - -static const char *httpNotFoundHeader="HTTP/1.0 404 Not Found\r\nServer: esp8266-httpd/"HTTPDVER"\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nNot Found.\r\n"; - -//This is called when the headers have been received and the connection is ready to send -//the result headers and data. -//We need to find the CGI function to call, call it, and dependent on what it returns either -//find the next cgi function, wait till the cgi data is sent or close up the connection. -static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { - int r; - int i=0; - if (conn->url==NULL) { - os_printf("WtF? url = NULL\n"); - return; //Shouldn't happen - } - //See if we can find a CGI that's happy to handle the request. - while (1) { - //Look up URL in the built-in URL table. - while (builtInUrls[i].url!=NULL) { - int match=0; - //See if there's a literal match - if (os_strcmp(builtInUrls[i].url, conn->url)==0) match=1; - //See if there's a wildcard match - if (builtInUrls[i].url[os_strlen(builtInUrls[i].url)-1]=='*' && - os_strncmp(builtInUrls[i].url, conn->url, os_strlen(builtInUrls[i].url)-1)==0) match=1; - if (match) { - os_printf("Is url index %d\n", i); - conn->cgiData=NULL; - conn->cgi=builtInUrls[i].cgiCb; - conn->cgiArg=builtInUrls[i].cgiArg; - break; - } - i++; - } - if (builtInUrls[i].url==NULL) { - //Drat, we're at the end of the URL table. This usually shouldn't happen. Well, just - //generate a built-in 404 to handle this. - os_printf("%s not found. 404!\n", conn->url); - httpdSend(conn, httpNotFoundHeader, -1); - xmitSendBuff(conn); - conn->cgi=NULL; //mark for destruction - return; - } - - //Okay, we have a CGI function that matches the URL. See if it wants to handle the - //particular URL we're supposed to handle. - r=conn->cgi(conn); - if (r==HTTPD_CGI_MORE) { - //Yep, it's happy to do so and has more data to send. - xmitSendBuff(conn); - return; - } else if (r==HTTPD_CGI_DONE) { - //Yep, it's happy to do so and already is done sending data. - xmitSendBuff(conn); - conn->cgi=NULL; //mark conn for destruction - return; - } else if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { - //URL doesn't want to handle the request: either the data isn't found or there's no - //need to generate a login screen. - i++; //look at next url the next iteration of the loop. - } - } -} - -//Parse a line of header data and modify the connection data accordingly. -static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { - int i; - char first_line = false; - - if (os_strncmp(h, "GET ", 4)==0) { - conn->requestType = HTTPD_METHOD_GET; - first_line = true; - } else if (os_strncmp(h, "Host:", 5)==0) { - i=5; - while (h[i]==' ') i++; - conn->hostName=&h[i]; - } else if (os_strncmp(h, "POST ", 5)==0) { - conn->requestType = HTTPD_METHOD_POST; - first_line = true; - } - - if (first_line) { - char *e; - - //Skip past the space after POST/GET - i=0; - while (h[i]!=' ') i++; - conn->url=h+i+1; - - //Figure out end of url. - e=(char*)os_strstr(conn->url, " "); - if (e==NULL) return; //wtf? - *e=0; //terminate url part - - os_printf("URL = %s\n", conn->url); - //Parse out the URL part before the GET parameters. - conn->getArgs=(char*)os_strstr(conn->url, "?"); - if (conn->getArgs!=0) { - *conn->getArgs=0; - conn->getArgs++; - os_printf("GET args = %s\n", conn->getArgs); - } else { - conn->getArgs=NULL; - } - - } else if (os_strncmp(h, "Content-Length:", 15)==0) { - i=15; - //Skip trailing spaces - while (h[i]==' ') i++; - //Get POST data length - conn->post->len=atoi(h+i); - - // Allocate the buffer - if (conn->post->len > MAX_POST) { - // we'll stream this in in chunks - conn->post->buffSize = MAX_POST; - } else { - conn->post->buffSize = conn->post->len; - } - os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); - conn->post->buff=(char*)os_malloc(conn->post->buffSize + 1); - conn->post->buffLen=0; - } else if (os_strncmp(h, "Content-Type: ", 14)==0) { - if (os_strstr(h, "multipart/form-data")) { - // It's multipart form data so let's pull out the boundary for future use - char *b; - if ((b = os_strstr(h, "boundary=")) != NULL) { - conn->post->multipartBoundary = b + 7; // move the pointer 2 chars before boundary then fill them with dashes - conn->post->multipartBoundary[0] = '-'; - conn->post->multipartBoundary[1] = '-'; - os_printf("boundary = %s\n", conn->post->multipartBoundary); - } - } - } -} - - -//Callback called when there's data available on a socket. -static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short len) { - int x; - char *p, *e; - char sendBuff[MAX_SENDBUFF_LEN]; - HttpdConnData *conn=httpdFindConnData(arg); - if (conn==NULL) return; - conn->priv->sendBuff=sendBuff; - conn->priv->sendBuffLen=0; - - //This is slightly evil/dirty: we abuse conn->post->len as a state variable for where in the http communications we are: - //<0 (-1): Post len unknown because we're still receiving headers - //==0: No post data - //>0: Need to receive post data - //ToDo: See if we can use something more elegant for this. - - for (x=0; xpost->len<0) { - //This byte is a header byte. - if (conn->priv->headPos!=MAX_HEAD_LEN) conn->priv->head[conn->priv->headPos++]=data[x]; - conn->priv->head[conn->priv->headPos]=0; - //Scan for /r/n/r/n. Receiving this indicate the headers end. - if (data[x]=='\n' && (char *)os_strstr(conn->priv->head, "\r\n\r\n")!=NULL) { - //Indicate we're done with the headers. - conn->post->len=0; - //Reset url data - conn->url=NULL; - //Iterate over all received headers and parse them. - p=conn->priv->head; - while(p<(&conn->priv->head[conn->priv->headPos-4])) { - e=(char *)os_strstr(p, "\r\n"); //Find end of header line - if (e==NULL) break; //Shouldn't happen. - e[0]=0; //Zero-terminate header - httpdParseHeader(p, conn); //and parse it. - p=e+2; //Skip /r/n (now /0/n) - } - //If we don't need to receive post data, we can send the response now. - if (conn->post->len==0) { - httpdProcessRequest(conn); - } - } - } else if (conn->post->len!=0) { - //This byte is a POST byte. - conn->post->buff[conn->post->buffLen++]=data[x]; - conn->post->received++; - conn->hostName=NULL; - if (conn->post->buffLen >= conn->post->buffSize || conn->post->received == conn->post->len) { - //Received a chunk of post data - conn->post->buff[conn->post->buffLen]=0; //zero-terminate, in case the cgi handler knows it can use strings - //Send the response. - httpdProcessRequest(conn); - conn->post->buffLen = 0; - } - } - } -} - -static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) { - HttpdConnData *conn=httpdFindConnData(arg); - os_printf("ReconCb\n"); - if (conn==NULL) return; - //Yeah... No idea what to do here. ToDo: figure something out. -} - -static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) { - //The esp sdk passes through wrong arg here, namely the one of the *listening* socket. - //That is why we can't use (HttpdConnData)arg->sock here. - //Just look at all the sockets and kill the slot if needed. - int i; - for (i=0; i=ESPCONN_CLOSE and not ==? Well, seems the stack sometimes de-allocates - //espconns under our noses, especially when connections are interrupted. The memory - //is then used for something else, and we can use that to capture *most* of the - //disconnect cases. - if (connData[i].conn->state==ESPCONN_NONE || connData[i].conn->state>=ESPCONN_CLOSE) { - connData[i].conn=NULL; - if (connData[i].cgi!=NULL) connData[i].cgi(&connData[i]); //flush cgi data - httpdRetireConn(&connData[i]); - } - } - } -} - - -static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) { - struct espconn *conn=arg; - int i; - //Find empty conndata in pool - for (i=0; iheadPos=0; - connData[i].post=&connPostData[i]; - connData[i].post->buff=NULL; - connData[i].post->buffLen=0; - connData[i].post->received=0; - connData[i].post->len=-1; - connData[i].hostName=NULL; - - espconn_regist_recvcb(conn, httpdRecvCb); - espconn_regist_reconcb(conn, httpdReconCb); - espconn_regist_disconcb(conn, httpdDisconCb); - espconn_regist_sentcb(conn, httpdSentCb); -} - -//Httpd initialization routine. Call this to kick off webserver functionality. -void ICACHE_FLASH_ATTR httpdInit(HttpdBuiltInUrl *fixedUrls, int port) { - int i; - - for (i=0; i wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - */ - -#include -#include "httpdespfs.h" -#include "espfs.h" -#include "espfsformat.h" - -// The static files marked with FLAG_GZIP are compressed and will be served with GZIP compression. -// If the client does not advertise that he accepts GZIP send following warning message (telnet users for e.g.) -static const char *gzipNonSupportedMessage = "HTTP/1.0 501 Not implemented\r\nServer: esp8266-httpd/"HTTPDVER"\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 52\r\n\r\nYour browser does not accept gzip-compressed data.\r\n"; - - -//This is a catch-all cgi function. It takes the url passed to it, looks up the corresponding -//path in the filesystem and if it exists, passes the file through. This simulates what a normal -//webserver would do with static files. -int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) { - EspFsFile *file=connData->cgiData; - int len; - char buff[1024]; - char acceptEncodingBuffer[64]; - int isGzip; - - if (connData->conn==NULL) { - //Connection aborted. Clean up. - espFsClose(file); - return HTTPD_CGI_DONE; - } - - if (file==NULL) { - //First call to this cgi. Open the file so we can read it. - file=espFsOpen(connData->url); - if (file==NULL) { - return HTTPD_CGI_NOTFOUND; - } - - // The gzip checking code is intentionally without #ifdefs because checking - // for FLAG_GZIP (which indicates gzip compressed file) is very easy, doesn't - // mean additional overhead and is actually safer to be on at all times. - // If there are no gzipped files in the image, the code bellow will not cause any harm. - - // Check if requested file was GZIP compressed - isGzip = espFsFlags(file) & FLAG_GZIP; - if (isGzip) { - // Check the browser's "Accept-Encoding" header. If the client does not - // advertise that he accepts GZIP send a warning message (telnet users for e.g.) - httpdGetHeader(connData, "Accept-Encoding", acceptEncodingBuffer, 64); - if (os_strstr(acceptEncodingBuffer, "gzip") == NULL) { - //No Accept-Encoding: gzip header present - httpdSend(connData, gzipNonSupportedMessage, -1); - espFsClose(file); - return HTTPD_CGI_DONE; - } - } - - connData->cgiData=file; - httpdStartResponse(connData, 200); - httpdHeader(connData, "Content-Type", httpdGetMimetype(connData->url)); - if (isGzip) { - httpdHeader(connData, "Content-Encoding", "gzip"); - } - httpdHeader(connData, "Cache-Control", "max-age=3600, must-revalidate"); - httpdEndHeaders(connData); - return HTTPD_CGI_MORE; - } - - len=espFsRead(file, buff, 1024); - if (len>0) espconn_sent(connData->conn, (uint8 *)buff, len); - if (len!=1024) { - //We're done. - espFsClose(file); - return HTTPD_CGI_DONE; - } else { - //Ok, till next time. - return HTTPD_CGI_MORE; - } -} - - -//cgiEspFsTemplate can be used as a template. - -typedef struct { - EspFsFile *file; - void *tplArg; - char token[64]; - int tokenPos; -} TplData; - -typedef void (* TplCallback)(HttpdConnData *connData, char *token, void **arg); - -int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData) { - TplData *tpd=connData->cgiData; - int len; - int x, sp=0; - char *e=NULL; - char buff[1025]; - - if (connData->conn==NULL) { - //Connection aborted. Clean up. - ((TplCallback)(connData->cgiArg))(connData, NULL, &tpd->tplArg); - espFsClose(tpd->file); - os_free(tpd); - return HTTPD_CGI_DONE; - } - - if (tpd==NULL) { - //First call to this cgi. Open the file so we can read it. - tpd=(TplData *)os_malloc(sizeof(TplData)); - tpd->file=espFsOpen(connData->url); - tpd->tplArg=NULL; - tpd->tokenPos=-1; - if (tpd->file==NULL) { - espFsClose(tpd->file); - os_free(tpd); - return HTTPD_CGI_NOTFOUND; - } - if (espFsFlags(tpd->file) & FLAG_GZIP) { - os_printf("cgiEspFsTemplate: Trying to use gzip-compressed file %s as template!\n", connData->url); - espFsClose(tpd->file); - os_free(tpd); - return HTTPD_CGI_NOTFOUND; - } - connData->cgiData=tpd; - httpdStartResponse(connData, 200); - httpdHeader(connData, "Content-Type", httpdGetMimetype(connData->url)); - httpdEndHeaders(connData); - return HTTPD_CGI_MORE; - } - - len=espFsRead(tpd->file, buff, 1024); - if (len>0) { - sp=0; - e=buff; - for (x=0; xtokenPos==-1) { - //Inside ordinary text. - if (buff[x]=='%') { - //Send raw data up to now - if (sp!=0) httpdSend(connData, e, sp); - sp=0; - //Go collect token chars. - tpd->tokenPos=0; - } else { - sp++; - } - } else { - if (buff[x]=='%') { - if (tpd->tokenPos==0) { - //This is the second % of a %% escape string. - //Send a single % and resume with the normal program flow. - httpdSend(connData, "%", 1); - } else { - //This is an actual token. - tpd->token[tpd->tokenPos++]=0; //zero-terminate token - ((TplCallback)(connData->cgiArg))(connData, tpd->token, &tpd->tplArg); - } - //Go collect normal chars again. - e=&buff[x+1]; - tpd->tokenPos=-1; - } else { - if (tpd->tokenPos<(sizeof(tpd->token)-1)) tpd->token[tpd->tokenPos++]=buff[x]; - } - } - } - } - //Send remaining bit. - if (sp!=0) httpdSend(connData, e, sp); - if (len!=1024) { - //We're done. - ((TplCallback)(connData->cgiArg))(connData, NULL, &tpd->tplArg); - espFsClose(tpd->file); - os_free(tpd); - return HTTPD_CGI_DONE; - } else { - //Ok, till next time. - return HTTPD_CGI_MORE; - } -} - diff --git a/libesphttpd/espfs/espfs.c b/libesphttpd/espfs/espfs.c deleted file mode 100644 index b14a589..0000000 --- a/libesphttpd/espfs/espfs.c +++ /dev/null @@ -1,274 +0,0 @@ -/* -This is a simple read-only implementation of a file system. It uses a block of data coming from the -mkespfsimg tool, and can use that block to do abstracted operations on the files that are in there. -It's written for use with httpd, but doesn't need to be used as such. -*/ - -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - */ - - -//These routines can also be tested by comping them in with the espfstest tool. This -//simplifies debugging, but needs some slightly different headers. The #ifdef takes -//care of that. - -#ifdef __ets__ -//esp build -#include -#else -//Test build -#include -#include -#include -#include -#define os_malloc malloc -#define os_free free -#define os_memcpy memcpy -#define os_strncmp strncmp -#define os_strcmp strcmp -#define os_strcpy strcpy -#define os_printf printf -#define ICACHE_FLASH_ATTR -#endif - -#include "espfsformat.h" -#include "espfs.h" - -#ifdef ESPFS_HEATSHRINK -#include "heatshrink_config_custom.h" -#include "heatshrink_decoder.h" -#endif - -static char* espFsData = NULL; - - -struct EspFsFile { - EspFsHeader *header; - char decompressor; - int32_t posDecomp; - char *posStart; - char *posComp; - void *decompData; -}; - -/* -Available locations, at least in my flash, with boundaries partially guessed. This -is using 0.9.1/0.9.2 SDK on a not-too-new module. -0x00000 (0x10000): Code/data (RAM data?) -0x10000 (0x02000): Gets erased by something? -0x12000 (0x2E000): Free (filled with zeroes) (parts used by ESPCloud and maybe SSL) -0x40000 (0x20000): Code/data (ROM data?) -0x60000 (0x1C000): Free -0x7c000 (0x04000): Param store -0x80000 - end of flash - -Accessing the flash through the mem emulation at 0x40200000 is a bit hairy: All accesses -*must* be aligned 32-bit accesses. Reading a short, byte or unaligned word will result in -a memory exception, crashing the program. -*/ - -EspFsInitResult ICACHE_FLASH_ATTR espFsInit(void *flashAddress) { - // base address must be aligned to 4 bytes - if (((int)flashAddress & 3) != 0) { - return ESPFS_INIT_RESULT_BAD_ALIGN; - } - - // check if there is valid header at address - EspFsHeader testHeader; - os_memcpy(&testHeader, flashAddress, sizeof(EspFsHeader)); - if (testHeader.magic != ESPFS_MAGIC) { - return ESPFS_INIT_RESULT_NO_IMAGE; - } - - espFsData = (char *)flashAddress; - return ESPFS_INIT_RESULT_OK; -} - -//Copies len bytes over from dst to src, but does it using *only* -//aligned 32-bit reads. Yes, it's no too optimized but it's short and sweet and it works. - -//ToDo: perhaps os_memcpy also does unaligned accesses? -#ifdef __ets__ -void ICACHE_FLASH_ATTR memcpyAligned(char *dst, char *src, int len) { - int x; - int w, b; - for (x=0; x>0); - if (b==1) *dst=(w>>8); - if (b==2) *dst=(w>>16); - if (b==3) *dst=(w>>24); - dst++; src++; - } -} -#else -#define memcpyAligned memcpy -#endif - -// Returns flags of opened file. -int ICACHE_FLASH_ATTR espFsFlags(EspFsFile *fh) { - if (fh == NULL) { - os_printf("File handle not ready\n"); - return -1; - } - - int8_t flags; - memcpyAligned((char*)&flags, (char*)&fh->header->flags, 1); - return (int)flags; -} - -//Open a file and return a pointer to the file desc struct. -EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { - if (espFsData == NULL) { - os_printf("Call espFsInit first!\n"); - return NULL; - } - char *p=espFsData; - char *hpos; - char namebuf[256]; - EspFsHeader h; - EspFsFile *r; - //Strip initial slashes - while(fileName[0]=='/') fileName++; - //Go find that file! - while(1) { - hpos=p; - //Grab the next file header. - os_memcpy(&h, p, sizeof(EspFsHeader)); - if (h.magic!=ESPFS_MAGIC) { - os_printf("Magic mismatch. EspFS image broken.\n"); - return NULL; - } - if (h.flags&FLAG_LASTFILE) { - os_printf("End of image.\n"); - return NULL; - } - //Grab the name of the file. - p+=sizeof(EspFsHeader); - os_memcpy(namebuf, p, sizeof(namebuf)); -// os_printf("Found file '%s'. Namelen=%x fileLenComp=%x, compr=%d flags=%d\n", -// namebuf, (unsigned int)h.nameLen, (unsigned int)h.fileLenComp, h.compression, h.flags); - if (os_strcmp(namebuf, fileName)==0) { - //Yay, this is the file we need! - p+=h.nameLen; //Skip to content. - r=(EspFsFile *)os_malloc(sizeof(EspFsFile)); //Alloc file desc mem -// os_printf("Alloc %p\n", r); - if (r==NULL) return NULL; - r->header=(EspFsHeader *)hpos; - r->decompressor=h.compression; - r->posComp=p; - r->posStart=p; - r->posDecomp=0; - if (h.compression==COMPRESS_NONE) { - r->decompData=NULL; -#ifdef ESPFS_HEATSHRINK - } else if (h.compression==COMPRESS_HEATSHRINK) { - //File is compressed with Heatshrink. - char parm; - heatshrink_decoder *dec; - //Decoder params are stored in 1st byte. - memcpyAligned(&parm, r->posComp, 1); - r->posComp++; - os_printf("Heatshrink compressed file; decode parms = %x\n", parm); - dec=heatshrink_decoder_alloc(16, (parm>>4)&0xf, parm&0xf); - r->decompData=dec; -#endif - } else { - os_printf("Invalid compression: %d\n", h.compression); - return NULL; - } - return r; - } - //We don't need this file. Skip name and file - p+=h.nameLen+h.fileLenComp; - if ((int)p&3) p+=4-((int)p&3); //align to next 32bit val - } -} - -//Read len bytes from the given file into buff. Returns the actual amount of bytes read. -int ICACHE_FLASH_ATTR espFsRead(EspFsFile *fh, char *buff, int len) { - int flen, fdlen; - if (fh==NULL) return 0; - //Cache file length. - memcpyAligned((char*)&flen, (char*)&fh->header->fileLenComp, 4); - memcpyAligned((char*)&fdlen, (char*)&fh->header->fileLenDecomp, 4); - //Do stuff depending on the way the file is compressed. - if (fh->decompressor==COMPRESS_NONE) { - int toRead; - toRead=flen-(fh->posComp-fh->posStart); - if (len>toRead) len=toRead; -// os_printf("Reading %d bytes from %x\n", len, (unsigned int)fh->posComp); - memcpyAligned(buff, fh->posComp, len); - fh->posDecomp+=len; - fh->posComp+=len; -// os_printf("Done reading %d bytes, pos=%x\n", len, fh->posComp); - return len; -#ifdef ESPFS_HEATSHRINK - } else if (fh->decompressor==COMPRESS_HEATSHRINK) { - int decoded=0; - size_t elen, rlen; - char ebuff[16]; - heatshrink_decoder *dec=(heatshrink_decoder *)fh->decompData; -// os_printf("Alloc %p\n", dec); - if (fh->posDecomp == fdlen) { - return 0; - } - - // We must ensure that whole file is decompressed and written to output buffer. - // This means even when there is no input data (elen==0) try to poll decoder until - // posDecomp equals decompressed file length - - while(decodedposComp - fh->posStart); - if (elen>0) { - memcpyAligned(ebuff, fh->posComp, 16); - heatshrink_decoder_sink(dec, (uint8_t *)ebuff, (elen>16)?16:elen, &rlen); - fh->posComp+=rlen; - } - //Grab decompressed data and put into buff - heatshrink_decoder_poll(dec, (uint8_t *)buff, len-decoded, &rlen); - fh->posDecomp+=rlen; - buff+=rlen; - decoded+=rlen; - -// os_printf("Elen %d rlen %d d %d pd %ld fdl %d\n",elen,rlen,decoded, fh->posDecomp, fdlen); - - if (elen == 0) { - if (fh->posDecomp == fdlen) { -// os_printf("Decoder finish\n"); - heatshrink_decoder_finish(dec); - } - return decoded; - } - } - return len; -#endif - } - return 0; -} - -//Close the file. -void ICACHE_FLASH_ATTR espFsClose(EspFsFile *fh) { - if (fh==NULL) return; -#ifdef ESPFS_HEATSHRINK - if (fh->decompressor==COMPRESS_HEATSHRINK) { - heatshrink_decoder *dec=(heatshrink_decoder *)fh->decompData; - heatshrink_decoder_free(dec); -// os_printf("Freed %p\n", dec); - } -#endif -// os_printf("Freed %p\n", fh); - os_free(fh); -} - - - diff --git a/libesphttpd/espfs/espfsformat.h b/libesphttpd/espfs/espfsformat.h deleted file mode 100644 index 8ce5549..0000000 --- a/libesphttpd/espfs/espfsformat.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ESPROFSFORMAT_H -#define ESPROFSFORMAT_H - -/* -Stupid cpio-like tool to make read-only 'filesystems' that live on the flash SPI chip of the module. -Can (will) use lzf compression (when I come around to it) to make shit quicker. Aligns names, files, -headers on 4-byte boundaries so the SPI abstraction hardware in the ESP8266 doesn't crap on itself -when trying to do a <4byte or unaligned read. -*/ - -/* -The idea 'borrows' from cpio: it's basically a concatenation of {header, filename, file} data. -Header, filename and file data is 32-bit aligned. The last file is indicated by data-less header -with the FLAG_LASTFILE flag set. -*/ - - -#define FLAG_LASTFILE (1<<0) -#define FLAG_GZIP (1<<1) -#define COMPRESS_NONE 0 -#define COMPRESS_HEATSHRINK 1 -#define ESPFS_MAGIC 0x73665345 - -typedef struct { - int32_t magic; - int8_t flags; - int8_t compression; - int16_t nameLen; - int32_t fileLenComp; - int32_t fileLenDecomp; -} __attribute__((packed)) EspFsHeader; - -#endif \ No newline at end of file diff --git a/libesphttpd/espfs/espfstest/Makefile b/libesphttpd/espfs/espfstest/Makefile deleted file mode 100644 index f8296f4..0000000 --- a/libesphttpd/espfs/espfstest/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -CFLAGS=-I../../lib/heatshrink -I.. -std=gnu99 -DESPFS_HEATSHRINK - -espfstest: main.o espfs.o heatshrink_decoder.o - $(CC) -o $@ $^ - -espfs.o: ../espfs.c - $(CC) $(CFLAGS) -c $^ -o $@ - -heatshrink_decoder.o: ../heatshrink_decoder.c - $(CC) $(CFLAGS) -c $^ -o $@ - -clean: - rm -f *.o espfstest diff --git a/libesphttpd/espfs/espfstest/main.c b/libesphttpd/espfs/espfstest/main.c deleted file mode 100644 index 16a6287..0000000 --- a/libesphttpd/espfs/espfstest/main.c +++ /dev/null @@ -1,67 +0,0 @@ -/* -Simple and stupid file decompressor for an espfs image. Mostly used as a testbed for espfs.c and -the decompressors: code compiled natively is way easier to debug using gdb et all :) -*/ -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "espfs.h" - -char *espFsData; - -int main(int argc, char **argv) { - int f, out; - int len; - char buff[128]; - EspFsFile *ef; - off_t size; - EspFsInitResult ir; - - if (argc!=3) { - printf("Usage: %s espfs-image file\nExpands file from the espfs-image archive.\n", argv[0]); - exit(0); - } - - f=open(argv[1], O_RDONLY); - if (f<=0) { - perror(argv[1]); - exit(1); - } - size=lseek(f, 0, SEEK_END); - espFsData=mmap(NULL, size, PROT_READ, MAP_SHARED, f, 0); - if (espFsData==MAP_FAILED) { - perror("mmap"); - exit(1); - } - - ir=espFsInit(espFsData); - if (ir != ESPFS_INIT_RESULT_OK) { - printf("Couldn't init espfs filesystem (code %d)\n", ir); - exit(1); - } - - ef=espFsOpen(argv[2]); - if (ef==NULL) { - printf("Couldn't find %s in image.\n", argv[2]); - exit(1); - } - - out=open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0644); - if (out<=0) { - perror(argv[2]); - exit(1); - } - - while ((len=espFsRead(ef, buff, 128))!=0) { - write(out, buff, len); - } - espFsClose(ef); - //munmap, close, ... I can't be bothered. -} diff --git a/libesphttpd/espfs/heatshrink_config_custom.h b/libesphttpd/espfs/heatshrink_config_custom.h deleted file mode 100644 index f885f87..0000000 --- a/libesphttpd/espfs/heatshrink_config_custom.h +++ /dev/null @@ -1,30 +0,0 @@ -//Heatshrink config for the decompressor. -#ifndef HEATSHRINK_CONFIG_H -#define HEATSHRINK_CONFIG_H - -/* Should functionality assuming dynamic allocation be used? */ -#define HEATSHRINK_DYNAMIC_ALLOC 1 - -#if HEATSHRINK_DYNAMIC_ALLOC - /* Optional replacement of malloc/free */ - #ifdef __ets__ - #define HEATSHRINK_MALLOC(SZ) os_malloc(SZ) - #define HEATSHRINK_FREE(P, SZ) os_free(P) - #else - #define HEATSHRINK_MALLOC(SZ) malloc(SZ) - #define HEATSHRINK_FREE(P, SZ) free(P) - #endif -#else - /* Required parameters for static configuration */ - #define HEATSHRINK_STATIC_INPUT_BUFFER_SIZE 32 - #define HEATSHRINK_STATIC_WINDOW_BITS 8 - #define HEATSHRINK_STATIC_LOOKAHEAD_BITS 4 -#endif - -/* Turn on logging for debugging. */ -#define HEATSHRINK_DEBUGGING_LOGS 0 - -/* Use indexing for faster compression. (This requires additional space.) */ -#define HEATSHRINK_USE_INDEX 1 - -#endif diff --git a/libesphttpd/espfs/heatshrink_decoder.c b/libesphttpd/espfs/heatshrink_decoder.c deleted file mode 100644 index 522b560..0000000 --- a/libesphttpd/espfs/heatshrink_decoder.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "espfs.h" -#ifdef ESPFS_HEATSHRINK -//Stupid wrapper so we don't have to move c-files around -//Also loads httpd-specific config. - -#ifdef __ets__ -//esp build - -#include - -#define memset(x,y,z) os_memset(x,y,z) -#define memcpy(x,y,z) os_memcpy(x,y,z) -#endif - -#include "heatshrink_config_custom.h" -#include "../lib/heatshrink/heatshrink_decoder.c" - - -#endif diff --git a/libesphttpd/espfs/mkespfsimage/Makefile b/libesphttpd/espfs/mkespfsimage/Makefile deleted file mode 100644 index 0d862e7..0000000 --- a/libesphttpd/espfs/mkespfsimage/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -GZIP_COMPRESSION ?= no -USE_HEATSHRINK ?= yes - -CFLAGS=-I../../lib/heatshrink -I../../include -I.. -std=gnu99 -ifeq ("$(GZIP_COMPRESSION)","yes") -CFLAGS += -DESPFS_GZIP -endif - -ifeq ("$(USE_HEATSHRINK)","yes") -CFLAGS += -DESPFS_HEATSHRINK -endif - -OBJS=main.o heatshrink_encoder.o -TARGET=mkespfsimage - -$(TARGET): $(OBJS) -ifeq ("$(GZIP_COMPRESSION)","yes") - $(CC) -o $@ $^ -lz -else - $(CC) -o $@ $^ -endif - -clean: - rm -f $(TARGET) $(OBJS) \ No newline at end of file diff --git a/libesphttpd/espfs/mkespfsimage/heatshrink_encoder.c b/libesphttpd/espfs/mkespfsimage/heatshrink_encoder.c deleted file mode 100644 index b563970..0000000 --- a/libesphttpd/espfs/mkespfsimage/heatshrink_encoder.c +++ /dev/null @@ -1,4 +0,0 @@ -//Stupid wraparound include to make sure object file doesn't end up in heatshrink dir -#ifdef ESPFS_HEATSHRINK -#include "../lib/heatshrink/heatshrink_encoder.c" -#endif \ No newline at end of file diff --git a/libesphttpd/espfs/mkespfsimage/main.c b/libesphttpd/espfs/mkespfsimage/main.c deleted file mode 100644 index 64187ff..0000000 --- a/libesphttpd/espfs/mkespfsimage/main.c +++ /dev/null @@ -1,364 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "espfs.h" -#include "espfsformat.h" - -//Heatshrink -#ifdef ESPFS_HEATSHRINK -#include "heatshrink_common.h" -#include "heatshrink_config.h" -#include "heatshrink_encoder.h" -#endif - -//Gzip -#ifdef ESPFS_GZIP -// If compiler complains about missing header, try running "sudo apt-get install zlib1g-dev" -// to install missing package. -#include -#endif - - -//Routines to convert host format to the endianness used in the xtensa -short htoxs(short in) { - char r[2]; - r[0]=in; - r[1]=in>>8; - return *((short *)r); -} - -int htoxl(int in) { - unsigned char r[4]; - r[0]=in; - r[1]=in>>8; - r[2]=in>>16; - r[3]=in>>24; - return *((int *)r); -} - -#ifdef ESPFS_HEATSHRINK -size_t compressHeatshrink(char *in, int insize, char *out, int outsize, int level) { - char *inp=in; - char *outp=out; - size_t len; - int ws[]={5, 6, 8, 11, 13}; - int ls[]={3, 3, 4, 4, 4}; - HSE_poll_res pres; - HSE_sink_res sres; - size_t r; - if (level==-1) level=8; - level=(level-1)/2; //level is now 0, 1, 2, 3, 4 - heatshrink_encoder *enc=heatshrink_encoder_alloc(ws[level], ls[level]); - if (enc==NULL) { - perror("allocating mem for heatshrink"); - exit(1); - } - //Save encoder parms as first byte - *outp=(ws[level]<<4)|ls[level]; - outp++; outsize--; - - r=1; - do { - if (insize>0) { - sres=heatshrink_encoder_sink(enc, inp, insize, &len); - if (sres!=HSER_SINK_OK) break; - inp+=len; insize-=len; - if (insize==0) heatshrink_encoder_finish(enc); - } - do { - pres=heatshrink_encoder_poll(enc, outp, outsize, &len); - if (pres!=HSER_POLL_MORE && pres!=HSER_POLL_EMPTY) break; - outp+=len; outsize-=len; - r+=len; - } while (pres==HSER_POLL_MORE); - } while (insize!=0); - - if (insize!=0) { - fprintf(stderr, "Heatshrink: Bug? insize is still %d. sres=%d pres=%d\n", insize, sres, pres); - exit(1); - } - - heatshrink_encoder_free(enc); - return r; -} -#endif - -#ifdef ESPFS_GZIP -size_t compressGzip(char *in, int insize, char *out, int outsize, int level) { - z_stream stream; - int zresult; - - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - stream.next_in = in; - stream.avail_in = insize; - stream.next_out = out; - stream.avail_out = outsize; - // 31 -> 15 window bits + 16 for gzip - zresult = deflateInit2 (&stream, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY); - if (zresult != Z_OK) { - fprintf(stderr, "DeflateInit2 failed with code %d\n", zresult); - exit(1); - } - - zresult = deflate(&stream, Z_FINISH); - if (zresult != Z_STREAM_END) { - fprintf(stderr, "Deflate failed with code %d\n", zresult); - exit(1); - } - - zresult = deflateEnd(&stream); - if (zresult != Z_OK) { - fprintf(stderr, "DeflateEnd failed with code %d\n", zresult); - exit(1); - } - - return stream.total_out; -} - -char **gzipExtensions = NULL; - -int shouldCompressGzip(char *name) { - char *ext = name + strlen(name); - while (*ext != '.') { - ext--; - if (ext < name) { - // no dot in file name -> no extension -> nothing to match against - return 0; - } - } - ext++; - - int i = 0; - while (gzipExtensions[i] != NULL) { - if (strcmp(ext,gzipExtensions[i]) == 0) { - return 1; - } - i++; - } - - return 0; -} - -int parseGzipExtensions(char *input) { - char *token; - char *extList = input; - int count = 2; // one for first element, second for terminator - - // count elements - while (*extList != 0) { - if (*extList == ',') count++; - extList++; - } - - // split string - extList = input; - gzipExtensions = malloc(count * sizeof(char*)); - count = 0; - token = strtok(extList, ","); - while (token) { - gzipExtensions[count++] = token; - token = strtok(NULL, ","); - } - // terminate list - gzipExtensions[count] = NULL; - - return 1; -} -#endif - -int handleFile(int f, char *name, int compression, int level, char **compName) { - char *fdat, *cdat; - off_t size, csize; - EspFsHeader h; - int nameLen; - int8_t flags = 0; - size=lseek(f, 0, SEEK_END); - fdat=mmap(NULL, size, PROT_READ, MAP_SHARED, f, 0); - if (fdat==MAP_FAILED) { - perror("mmap"); - return 0; - } - -#ifdef ESPFS_GZIP - if (shouldCompressGzip(name)) { - csize = size*3; - if (csize<100) // gzip has some headers that do not fit when trying to compress small files - csize = 100; // enlarge buffer if this is the case - cdat=malloc(csize); - csize=compressGzip(fdat, size, cdat, csize, level); - compression = COMPRESS_NONE; - flags = FLAG_GZIP; - } else -#endif - if (compression==COMPRESS_NONE) { - csize=size; - cdat=fdat; -#ifdef ESPFS_HEATSHRINK - } else if (compression==COMPRESS_HEATSHRINK) { - cdat=malloc(size*2); - csize=compressHeatshrink(fdat, size, cdat, size*2, level); -#endif - } else { - fprintf(stderr, "Unknown compression - %d\n", compression); - exit(1); - } - - if (csize>size) { - //Compressing enbiggened this file. Revert to uncompressed store. - compression=COMPRESS_NONE; - csize=size; - cdat=fdat; - flags=0; - } - - //Fill header data - h.magic=('E'<<0)+('S'<<8)+('f'<<16)+('s'<<24); - h.flags=flags; - h.compression=compression; - h.nameLen=nameLen=strlen(name)+1; - if (h.nameLen&3) h.nameLen+=4-(h.nameLen&3); //Round to next 32bit boundary - h.nameLen=htoxs(h.nameLen); - h.fileLenComp=htoxl(csize); - h.fileLenDecomp=htoxl(size); - - write(1, &h, sizeof(EspFsHeader)); - write(1, name, nameLen); - while (nameLen&3) { - write(1, "\000", 1); - nameLen++; - } - write(1, cdat, csize); - //Pad out to 32bit boundary - while (csize&3) { - write(1, "\000", 1); - csize++; - } - munmap(fdat, size); - - if (compName != NULL) { - if (h.compression==COMPRESS_HEATSHRINK) { - *compName = "heatshrink"; - } else if (h.compression==COMPRESS_NONE) { - if (h.flags & FLAG_GZIP) { - *compName = "gzip"; - } else { - *compName = "none"; - } - } else { - *compName = "unknown"; - } - } - return (csize*100)/size; -} - -//Write final dummy header with FLAG_LASTFILE set. -void finishArchive() { - EspFsHeader h; - h.magic=('E'<<0)+('S'<<8)+('f'<<16)+('s'<<24); - h.flags=FLAG_LASTFILE; - h.compression=COMPRESS_NONE; - h.nameLen=htoxs(0); - h.fileLenComp=htoxl(0); - h.fileLenDecomp=htoxl(0); - write(1, &h, sizeof(EspFsHeader)); -} - -int main(int argc, char **argv) { - int f, x; - char fileName[1024]; - char *realName; - struct stat statBuf; - int serr; - int rate; - int err=0; - int compType; //default compression type - heatshrink - int compLvl=-1; - -#ifdef ESPFS_HEATSHRINK - compType = COMPRESS_HEATSHRINK; -#else - compType = COMPRESS_NONE; -#endif - - for (x=1; x=x-2) { - compType=atoi(argv[x+1]); - x++; - } else if (strcmp(argv[x], "-l")==0 && argc>=x-2) { - compLvl=atoi(argv[x+1]); - if (compLvl<1 || compLvl>9) err=1; - x++; -#ifdef ESPFS_GZIP - } else if (strcmp(argv[x], "-g")==0 && argc>=x-2) { - if (!parseGzipExtensions(argv[x+1])) err=1; - x++; -#endif - } else { - err=1; - } - } - -#ifdef ESPFS_GZIP - if (gzipExtensions == NULL) { - parseGzipExtensions(strdup("html,css,js")); - } -#endif - - if (err) { - fprintf(stderr, "%s - Program to create espfs images\n", argv[0]); - fprintf(stderr, "Usage: \nfind | %s [-c compressor] [-l compression_level] ", argv[0]); -#ifdef ESPFS_GZIP - fprintf(stderr, "[-g gzipped_extensions] "); -#endif - fprintf(stderr, "> out.espfs\n"); - fprintf(stderr, "Compressors:\n"); -#ifdef ESPFS_HEATSHRINK - fprintf(stderr, "0 - None\n1 - Heatshrink(default)\n"); -#else - fprintf(stderr, "0 - None(default)\n"); -#endif - fprintf(stderr, "\nCompression level: 1 is worst but low RAM usage, higher is better compression \nbut uses more ram on decompression. -1 = compressors default.\n"); -#ifdef ESPFS_GZIP - fprintf(stderr, "\nGzipped extensions: list of comma separated, case sensitive file extensions \nthat will be gzipped. Defaults to 'html,css,js'\n"); -#endif - exit(0); - } - - while(fgets(fileName, sizeof(fileName), stdin)) { - //Kill off '\n' at the end - fileName[strlen(fileName)-1]=0; - //Only include files - serr=stat(fileName, &statBuf); - if ((serr==0) && S_ISREG(statBuf.st_mode)) { - //Strip off './' or '/' madness. - realName=fileName; - if (fileName[0]=='.') realName++; - if (realName[0]=='/') realName++; - f=open(fileName, O_RDONLY); - if (f>0) { - char *compName = "unknown"; - rate=handleFile(f, realName, compType, compLvl, &compName); - fprintf(stderr, "%s (%d%%, %s)\n", realName, rate, compName); - close(f); - } else { - perror(fileName); - } - } else { - if (serr!=0) { - perror(fileName); - } - } - } - finishArchive(); - return 0; -} - diff --git a/libesphttpd/include/auth.h b/libesphttpd/include/auth.h deleted file mode 100644 index 1ef0f61..0000000 --- a/libesphttpd/include/auth.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef AUTH_H -#define AUTH_H - -#include "httpd.h" - -#ifndef HTTP_AUTH_REALM -#define HTTP_AUTH_REALM "Protected" -#endif - -#define HTTPD_AUTH_SINGLE 0 -#define HTTPD_AUTH_CALLBACK 1 - -#define AUTH_MAX_USER_LEN 32 -#define AUTH_MAX_PASS_LEN 32 - -//Parameter given to authWhatever functions. This callback returns the usernames/passwords the device -//has. -typedef int (* AuthGetUserPw)(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen); - -int ICACHE_FLASH_ATTR authBasic(HttpdConnData *connData); - -#endif \ No newline at end of file diff --git a/libesphttpd/include/captdns.h b/libesphttpd/include/captdns.h deleted file mode 100644 index ba17ebd..0000000 --- a/libesphttpd/include/captdns.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef CAPTDNS_H -#define CAPTDNS_H -void ICACHE_FLASH_ATTR captdnsInit(void); - -#endif \ No newline at end of file diff --git a/libesphttpd/include/cgiflash.h b/libesphttpd/include/cgiflash.h deleted file mode 100644 index 5fe68a3..0000000 --- a/libesphttpd/include/cgiflash.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CGIFLASH_H -#define CGIFLASH_H - -#include "httpd.h" - -typedef struct { - int espFsPos; - int espFsSize; -} CgiUploadEspfsParams; - - -int cgiReadFlash(HttpdConnData *connData); -int cgiUploadEspfs(HttpdConnData *connData); - -#endif \ No newline at end of file diff --git a/libesphttpd/include/cgiwifi.h b/libesphttpd/include/cgiwifi.h deleted file mode 100644 index 21ef2fc..0000000 --- a/libesphttpd/include/cgiwifi.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CGIWIFI_H -#define CGIWIFI_H - -#include "httpd.h" - -int cgiWiFiScan(HttpdConnData *connData); -int tplWlan(HttpdConnData *connData, char *token, void **arg); -int cgiWiFi(HttpdConnData *connData); -int cgiWiFiConnect(HttpdConnData *connData); -int cgiWiFiSetMode(HttpdConnData *connData); -int cgiWiFiConnStatus(HttpdConnData *connData); - -#endif \ No newline at end of file diff --git a/libesphttpd/include/esp8266.h b/libesphttpd/include/esp8266.h deleted file mode 100644 index 31fa332..0000000 --- a/libesphttpd/include/esp8266.h +++ /dev/null @@ -1,18 +0,0 @@ -// Combined include file for esp8266 - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "espmissingincludes.h" - diff --git a/libesphttpd/include/espfs.h b/libesphttpd/include/espfs.h deleted file mode 100644 index c41df0a..0000000 --- a/libesphttpd/include/espfs.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ESPFS_H -#define ESPFS_H - -// This define is done in Makefile. If you do not use default Makefile, uncomment -// to be able to use Heatshrink-compressed espfs images. -//#define ESPFS_HEATSHRINK - -typedef enum { - ESPFS_INIT_RESULT_OK, - ESPFS_INIT_RESULT_NO_IMAGE, - ESPFS_INIT_RESULT_BAD_ALIGN, -} EspFsInitResult; - -typedef struct EspFsFile EspFsFile; - -EspFsInitResult espFsInit(void *flashAddress); -EspFsFile *espFsOpen(char *fileName); -int espFsFlags(EspFsFile *fh); -int espFsRead(EspFsFile *fh, char *buff, int len); -void espFsClose(EspFsFile *fh); - - -#endif \ No newline at end of file diff --git a/libesphttpd/include/espmissingincludes.h b/libesphttpd/include/espmissingincludes.h deleted file mode 100644 index 27e6652..0000000 --- a/libesphttpd/include/espmissingincludes.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef ESPMISSINGINCLUDES_H -#define ESPMISSINGINCLUDES_H - -#include -#include -#include -#include - -//Missing function prototypes in include folders. Gcc will warn on these if we don't define 'em anywhere. -//MOST OF THESE ARE GUESSED! but they seem to swork and shut up the compiler. -typedef struct espconn espconn; - -int atoi(const char *nptr); -void ets_install_putc1(void *routine); -void ets_isr_attach(int intr, void *handler, void *arg); -void ets_isr_mask(unsigned intr); -void ets_isr_unmask(unsigned intr); -int ets_memcmp(const void *s1, const void *s2, size_t n); -void *ets_memcpy(void *dest, const void *src, size_t n); -void *ets_memset(void *s, int c, size_t n); -int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); -int ets_str2macaddr(void *, void *); -int ets_strcmp(const char *s1, const char *s2); -char *ets_strcpy(char *dest, const char *src); -size_t ets_strlen(const char *s); -int ets_strncmp(const char *s1, const char *s2, int len); -char *ets_strncpy(char *dest, const char *src, size_t n); -char *ets_strstr(const char *haystack, const char *needle); -void ets_timer_arm_new(ETSTimer *a, int b, int c, int isMstimer); -void ets_timer_disarm(ETSTimer *a); -void ets_timer_setfn(ETSTimer *t, ETSTimerFunc *fn, void *parg); -void ets_update_cpu_frequency(int freqmhz); -int os_printf(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -int os_snprintf(char *str, size_t size, const char *format, ...) __attribute__ ((format (printf, 3, 4))); -int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void pvPortFree(void *ptr); -void *pvPortMalloc(size_t xWantedSize); -void *pvPortZalloc(size_t); -void uart_div_modify(int no, unsigned int freq); -void vPortFree(void *ptr); -void *vPortMalloc(size_t xWantedSize); -uint8 wifi_get_opmode(void); -uint32 system_get_time(); -int rand(void); -void ets_bzero(void *s, size_t n); -void ets_delay_us(int ms); - - -//Standard PIN_FUNC_SELECT gives a warning. Replace by a non-warning one. -#ifdef PIN_FUNC_SELECT -#undef PIN_FUNC_SELECT -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) do { \ - WRITE_PERI_REG(PIN_NAME, \ - (READ_PERI_REG(PIN_NAME) \ - & (~(PERIPHS_IO_MUX_FUNC< - -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - */ - - -/* -This is a 'captive portal' DNS server: it basically replies with a fixed IP (in this case: -the one of the SoftAP interface of this ESP module) for any and all DNS queries. This can -be used to send mobile phones, tablets etc which connect to the ESP in AP mode directly to -the internal webserver. -*/ - - -typedef struct __attribute__ ((packed)) { - uint16_t id; - uint8_t flags; - uint8_t rcode; - uint16_t qdcount; - uint16_t ancount; - uint16_t nscount; - uint16_t arcount; -} DnsHeader; - - -typedef struct __attribute__ ((packed)) { - uint8_t len; - uint8_t data; -} DnsLabel; - - -typedef struct __attribute__ ((packed)) { - //before: label - uint16_t type; - uint16_t class; -} DnsQuestionFooter; - - -typedef struct __attribute__ ((packed)) { - //before: label - uint16_t type; - uint16_t class; - uint32_t ttl; - uint16_t rdlength; - //after: rdata -} DnsResourceFooter; - -typedef struct __attribute__ ((packed)) { - uint16_t prio; - uint16_t weight; -} DnsUriHdr; - - -#define FLAG_QR (1<<7) -#define FLAG_AA (1<<2) -#define FLAG_TC (1<<1) -#define FLAG_RD (1<<0) - -#define QTYPE_A 1 -#define QTYPE_NS 2 -#define QTYPE_CNAME 5 -#define QTYPE_SOA 6 -#define QTYPE_WKS 11 -#define QTYPE_PTR 12 -#define QTYPE_HINFO 13 -#define QTYPE_MINFO 14 -#define QTYPE_MX 15 -#define QTYPE_TXT 16 -#define QTYPE_URI 256 - -#define QCLASS_IN 1 -#define QCLASS_ANY 255 -#define QCLASS_URI 256 - - -//Function to put unaligned 16-bit network values -static void ICACHE_FLASH_ATTR setn16(void *pp, int16_t n) { - char *p=pp; - *p++=(n>>8); - *p++=(n&0xff); -} - -//Function to put unaligned 32-bit network values -static void ICACHE_FLASH_ATTR setn32(void *pp, int32_t n) { - char *p=pp; - *p++=(n>>24)&0xff; - *p++=(n>>16)&0xff; - *p++=(n>>8)&0xff; - *p++=(n&0xff); -} - -static uint16_t ICACHE_FLASH_ATTR ntohs(uint16_t *in) { - char *p=(char*)in; - return ((p[0]<<8)&0xff00)|(p[1]&0xff); -} - - -//Parses a label into a C-string containing a dotted -//Returns pointer to start of next fields in packet -static char* ICACHE_FLASH_ATTR labelToStr(char *packet, char *labelPtr, int packetSz, char *res, int resMaxLen) { - int i, j, k; - char *endPtr=NULL; - i=0; - do { - if ((*labelPtr&0xC0)==0) { - j=*labelPtr++; //skip past length - //Add separator period if there already is data in res - if (ipacketSz) return NULL; - if (ipacketSz) return NULL; - labelPtr=&packet[offset]; - } - //check for out-of-bound-ness - if ((labelPtr-packet)>packetSz) return NULL; - } while (*labelPtr!=0); - res[i]=0; //zero-terminate - if (endPtr==NULL) endPtr=labelPtr+1; - return endPtr; -} - - -//Converts a dotted hostname to the weird label form dns uses. -static char ICACHE_FLASH_ATTR *strToLabel(char *str, char *label, int maxLen) { - char *len=label; //ptr to len byte - char *p=label+1; //ptr to next label byte to be written - while (1) { - if (*str=='.' || *str==0) { - *len=((p-len)-1); //write len of label bit - len=p; //pos of len for next part - p++; //data ptr is one past len - if (*str==0) break; //done - str++; - } else { - *p++=*str++; //copy byte -// if ((p-label)>maxLen) return NULL; //check out of bounds - } - } - *len=0; - return p; //ptr to first free byte in resp -} - - -//Receive a DNS packet and maybe send a response back -static void ICACHE_FLASH_ATTR captdnsRecv(void* arg, char *pusrdata, unsigned short length) { - struct espconn *conn=(struct espconn *)arg; - char buff[512]; - char reply[512]; - int i; - char *rend=&reply[length]; - char *p=pusrdata; - DnsHeader *hdr=(DnsHeader*)p; - DnsHeader *rhdr=(DnsHeader*)&reply[0]; - p+=sizeof(DnsHeader); -// os_printf("DNS packet: id 0x%X flags 0x%X rcode 0x%X qcnt %d ancnt %d nscount %d arcount %d len %d\n", -// ntohs(&hdr->id), hdr->flags, hdr->rcode, ntohs(&hdr->qdcount), ntohs(&hdr->ancount), ntohs(&hdr->nscount), ntohs(&hdr->arcount), length); - //Some sanity checks: - if (length>512) return; //Packet is longer than DNS implementation allows - if (lengthancount || hdr->nscount || hdr->arcount) return; //this is a reply, don't know what to do with it - if (hdr->flags&FLAG_TC) return; //truncated, can't use this - //Reply is basically the request plus the needed data - os_memcpy(reply, pusrdata, length); - rhdr->flags|=FLAG_QR; - for (i=0; iqdcount); i++) { - //Grab the labels in the q string - p=labelToStr(pusrdata, p, length, buff, sizeof(buff)); - if (p==NULL) return; - DnsQuestionFooter *qf=(DnsQuestionFooter*)p; - p+=sizeof(DnsQuestionFooter); - os_printf("DNS: Q (type 0x%X class 0x%X) for %s\n", ntohs(&qf->type), ntohs(&qf->class), buff); - if (ntohs(&qf->type)==QTYPE_A) { - //They want to know the IPv4 address of something. - //Build the response. - rend=strToLabel(buff, rend, sizeof(reply)-(rend-reply)); //Add the label - if (rend==NULL) return; - DnsResourceFooter *rf=(DnsResourceFooter *)rend; - rend+=sizeof(DnsResourceFooter); - setn16(&rf->type, QTYPE_A); - setn16(&rf->class, QCLASS_IN); - setn32(&rf->ttl, 1); - setn16(&rf->rdlength, 4); //IPv4 addr is 4 bytes; - //Grab the current IP of the softap interface - struct ip_info info; - wifi_get_ip_info(SOFTAP_IF, &info); - *rend++=ip4_addr1(&info.ip); - *rend++=ip4_addr2(&info.ip); - *rend++=ip4_addr3(&info.ip); - *rend++=ip4_addr4(&info.ip); - setn16(&rhdr->ancount, ntohs(&rhdr->ancount)+1); -// os_printf("Added A rec to resp. Resp len is %d\n", (rend-reply)); - } else if (ntohs(&qf->type)==QTYPE_NS) { - //Give ns server. Basically can be whatever we want because it'll get resolved to our IP later anyway. - rend=strToLabel(buff, rend, sizeof(reply)-(rend-reply)); //Add the label - DnsResourceFooter *rf=(DnsResourceFooter *)rend; - rend+=sizeof(DnsResourceFooter); - setn16(&rf->type, QTYPE_NS); - setn16(&rf->class, QCLASS_IN); - setn16(&rf->ttl, 1); - setn16(&rf->rdlength, 4); - *rend++=2; - *rend++='n'; - *rend++='s'; - *rend++=0; - setn16(&rhdr->ancount, ntohs(&rhdr->ancount)+1); -// os_printf("Added NS rec to resp. Resp len is %d\n", (rend-reply)); - } else if (ntohs(&qf->type)==QTYPE_URI) { - //Give uri to us - rend=strToLabel(buff, rend, sizeof(reply)-(rend-reply)); //Add the label - DnsResourceFooter *rf=(DnsResourceFooter *)rend; - rend+=sizeof(DnsResourceFooter); - DnsUriHdr *uh=(DnsUriHdr *)rend; - rend+=sizeof(DnsUriHdr); - setn16(&rf->type, QTYPE_URI); - setn16(&rf->class, QCLASS_URI); - setn16(&rf->ttl, 1); - setn16(&rf->rdlength, 4+16); - setn16(&uh->prio, 10); - setn16(&uh->weight, 1); - memcpy(rend, "http://esp.local", 16); - rend+=16; - setn16(&rhdr->ancount, ntohs(&rhdr->ancount)+1); -// os_printf("Added NS rec to resp. Resp len is %d\n", (rend-reply)); - } - } - //Send the response - espconn_sent(conn, (uint8*)reply, rend-reply); -} - -void ICACHE_FLASH_ATTR captdnsInit(void) { - static struct espconn conn; - static esp_udp udpconn; - conn.type=ESPCONN_UDP; - conn.proto.udp=&udpconn; - conn.proto.udp->local_port = 53; - espconn_regist_recvcb(&conn, captdnsRecv); - espconn_create(&conn); -} diff --git a/libesphttpd/util/cgiflash.c b/libesphttpd/util/cgiflash.c deleted file mode 100644 index b53200a..0000000 --- a/libesphttpd/util/cgiflash.c +++ /dev/null @@ -1,77 +0,0 @@ -/* -Some flash handling cgi routines. Used for reading the existing flash and updating the ESPFS image. -*/ - -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - */ - - -#include -#include "cgiflash.h" -#include "espfs.h" - - -//Cgi that reads the SPI flash. Assumes 512KByte flash. -int ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) { - int *pos=(int *)&connData->cgiData; - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - - if (*pos==0) { - os_printf("Start flash download.\n"); - httpdStartResponse(connData, 200); - httpdHeader(connData, "Content-Type", "application/bin"); - httpdEndHeaders(connData); - *pos=0x40200000; - return HTTPD_CGI_MORE; - } - //Send 1K of flash per call. We will get called again if we haven't sent 512K yet. - espconn_sent(connData->conn, (uint8 *)(*pos), 1024); - *pos+=1024; - if (*pos>=0x40200000+(512*1024)) return HTTPD_CGI_DONE; else return HTTPD_CGI_MORE; -} - - -//Cgi that allows the ESPFS image to be replaced via http POST -int ICACHE_FLASH_ATTR cgiUploadEspfs(HttpdConnData *connData) { - const CgiUploadEspfsParams *up=(CgiUploadEspfsParams*)connData->cgiArg; - - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - - if(connData->post->len > up->espFsSize){ - // The uploaded file is too large - os_printf("ESPFS file too large\n"); - httpdSend(connData, "HTTP/1.0 500 Internal Server Error\r\nServer: esp8266-httpd/0.3\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 24\r\n\r\nESPFS image loo large.\r\n", -1); - return HTTPD_CGI_DONE; - } - - // The source should be 4byte aligned, so go ahead and flash whatever we have - int address = up->espFsPos + connData->post->received - connData->post->buffLen; - if(address % SPI_FLASH_SEC_SIZE == 0){ - // We need to erase this block - os_printf("Erasing flash at %d\n", address/SPI_FLASH_SEC_SIZE); - spi_flash_erase_sector(address/SPI_FLASH_SEC_SIZE); - } - // Write the data - os_printf("Writing at: 0x%x\n", address); - spi_flash_write(address, (uint32 *)connData->post->buff, connData->post->buffLen); - os_printf("Wrote %d bytes (%dB of %d)\n", connData->post->buffSize, connData->post->received, connData->post->len);//&connData->postBuff)); - - if (connData->post->received == connData->post->len){ - httpdSend(connData, "Finished uploading", -1); - return HTTPD_CGI_DONE; - } else { - return HTTPD_CGI_MORE; - } -} diff --git a/libesphttpd/util/cgiwifi.c b/libesphttpd/util/cgiwifi.c deleted file mode 100644 index 3aaf5aa..0000000 --- a/libesphttpd/util/cgiwifi.c +++ /dev/null @@ -1,311 +0,0 @@ -/* -Cgi/template routines for the /wifi url. -*/ - -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - */ - - -#include -#include "cgiwifi.h" - -//Enable this to disallow any changes in AP settings -//#define DEMO_MODE - -//WiFi access point data -typedef struct { - char ssid[32]; - char rssi; - char enc; -} ApData; - -//Scan result -typedef struct { - char scanInProgress; //if 1, don't access the underlying stuff from the webpage. - ApData **apData; - int noAps; -} ScanResultData; - -//Static scan status storage. -static ScanResultData cgiWifiAps; - -#define CONNTRY_IDLE 0 -#define CONNTRY_WORKING 1 -#define CONNTRY_SUCCESS 2 -#define CONNTRY_FAIL 3 -//Connection result var -static int connTryStatus=CONNTRY_IDLE; -static ETSTimer resetTimer; - -//Callback the code calls when a wlan ap scan is done. Basically stores the result in -//the cgiWifiAps struct. -void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { - int n; - struct bss_info *bss_link = (struct bss_info *)arg; - os_printf("wifiScanDoneCb %d\n", status); - if (status!=OK) { - cgiWifiAps.scanInProgress=0; - return; - } - - //Clear prev ap data if needed. - if (cgiWifiAps.apData!=NULL) { - for (n=0; nnext.stqe_next; - n++; - } - //Allocate memory for access point data - cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n); - cgiWifiAps.noAps=n; - os_printf("Scan done: found %d APs\n", n); - - //Copy access point data to the static struct - n=0; - bss_link = (struct bss_info *)arg; - while (bss_link != NULL) { - if (n>=cgiWifiAps.noAps) { - //This means the bss_link changed under our nose. Shouldn't happen! - //Break because otherwise we will write in unallocated memory. - os_printf("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps); - break; - } - //Save the ap data. - cgiWifiAps.apData[n]=(ApData *)os_malloc(sizeof(ApData)); - cgiWifiAps.apData[n]->rssi=bss_link->rssi; - cgiWifiAps.apData[n]->enc=bss_link->authmode; - strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); - - bss_link = bss_link->next.stqe_next; - n++; - } - //We're done. - cgiWifiAps.scanInProgress=0; -} - - -//Routine to start a WiFi access point scan. -static void ICACHE_FLASH_ATTR wifiStartScan() { -// int x; - if (cgiWifiAps.scanInProgress) return; - cgiWifiAps.scanInProgress=1; - wifi_station_scan(NULL, wifiScanDoneCb); -} - -//This CGI is called from the bit of AJAX-code in wifi.tpl. It will initiate a -//scan for access points and if available will return the result of an earlier scan. -//The result is embedded in a bit of JSON parsed by the javascript in wifi.tpl. -int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) { - int pos=(int)connData->cgiData; - int len; - char buff[1024]; - - if (!cgiWifiAps.scanInProgress && pos!=0) { - //Fill in json code for an access point - if (pos-1ssid, cgiWifiAps.apData[pos-1]->rssi, - cgiWifiAps.apData[pos-1]->enc, (pos-1==cgiWifiAps.noAps-1)?"":","); - httpdSend(connData, buff, len); - } - pos++; - if ((pos-1)>=cgiWifiAps.noAps) { - len=os_sprintf(buff, "]\n}\n}\n"); - httpdSend(connData, buff, len); - //Also start a new scan. - wifiStartScan(); - return HTTPD_CGI_DONE; - } else { - connData->cgiData=(void*)pos; - return HTTPD_CGI_MORE; - } - } - - httpdStartResponse(connData, 200); - httpdHeader(connData, "Content-Type", "text/json"); - httpdEndHeaders(connData); - - if (cgiWifiAps.scanInProgress==1) { - //We're still scanning. Tell Javascript code that. - len=os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"1\"\n }\n}\n"); - httpdSend(connData, buff, len); - return HTTPD_CGI_DONE; - } else { - //We have a scan result. Pass it on. - len=os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"0\", \n\"APs\": [\n"); - httpdSend(connData, buff, len); - if (cgiWifiAps.apData==NULL) cgiWifiAps.noAps=0; - connData->cgiData=(void *)1; - return HTTPD_CGI_MORE; - } -} - -//Temp store for new ap info. -static struct station_config stconf; - -//This routine is ran some time after a connection attempt to an access point. If -//the connect succeeds, this gets the module in STA-only mode. -static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { - int x=wifi_station_get_connect_status(); - if (x==STATION_GOT_IP) { - //Go to STA mode. This needs a reset, so do that. - os_printf("Got IP. Going into STA mode..\n"); - wifi_set_opmode(1); - system_restart(); - } else { - connTryStatus=CONNTRY_FAIL; - os_printf("Connect fail. Not going into STA-only mode.\n"); - //Maybe also pass this through on the webpage? - } -} - - - -//Actually connect to a station. This routine is timed because I had problems -//with immediate connections earlier. It probably was something else that caused it, -//but I can't be arsed to put the code back :P -static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) { - int x; - os_printf("Try to connect to AP....\n"); - wifi_station_disconnect(); - wifi_station_set_config(&stconf); - wifi_station_connect(); - x=wifi_get_opmode(); - connTryStatus=CONNTRY_WORKING; - if (x!=1) { - //Schedule disconnect/connect - os_timer_disarm(&resetTimer); - os_timer_setfn(&resetTimer, resetTimerCb, NULL); - os_timer_arm(&resetTimer, 15000, 0); //time out after 15 secs of trying to connect - } -} - - -//This cgi uses the routines above to connect to a specific access point with the -//given ESSID using the given password. -int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { - char essid[128]; - char passwd[128]; - static ETSTimer reassTimer; - - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - - httpdFindArg(connData->post->buff, "essid", essid, sizeof(essid)); - httpdFindArg(connData->post->buff, "passwd", passwd, sizeof(passwd)); - - os_strncpy((char*)stconf.ssid, essid, 32); - os_strncpy((char*)stconf.password, passwd, 64); - os_printf("Try to connect to AP %s pw %s\n", essid, passwd); - - //Schedule disconnect/connect - os_timer_disarm(&reassTimer); - os_timer_setfn(&reassTimer, reassTimerCb, NULL); -//Set to 0 if you want to disable the actual reconnecting bit -#ifdef DEMO_MODE - httpdRedirect(connData, "/wifi"); -#else - os_timer_arm(&reassTimer, 500, 0); - httpdRedirect(connData, "connecting.html"); -#endif - return HTTPD_CGI_DONE; -} - -//This cgi uses the routines above to connect to a specific access point with the -//given ESSID using the given password. -int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { - int len; - char buff[1024]; - - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - - len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); - if (len!=0) { - os_printf("cgiWifiSetMode: %s\n", buff); -#ifndef DEMO_MODE - wifi_set_opmode(atoi(buff)); - system_restart(); -#endif - } - httpdRedirect(connData, "/wifi"); - return HTTPD_CGI_DONE; -} - -int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) { - char buff[1024]; - int len; - struct ip_info info; - int st=wifi_station_get_connect_status(); - httpdStartResponse(connData, 200); - httpdHeader(connData, "Content-Type", "text/json"); - httpdEndHeaders(connData); - if (connTryStatus==CONNTRY_IDLE) { - len=os_sprintf(buff, "{\n \"status\": \"idle\"\n }\n"); - } else if (connTryStatus==CONNTRY_WORKING || connTryStatus==CONNTRY_SUCCESS) { - if (st==STATION_GOT_IP) { - wifi_get_ip_info(0, &info); - len=os_sprintf(buff, "{\n \"status\": \"success\",\n \"ip\": \"%d.%d.%d.%d\" }\n", - (info.ip.addr>>0)&0xff, (info.ip.addr>>8)&0xff, - (info.ip.addr>>16)&0xff, (info.ip.addr>>24)&0xff); - //Reset into AP-only mode sooner. - os_timer_disarm(&resetTimer); - os_timer_setfn(&resetTimer, resetTimerCb, NULL); - os_timer_arm(&resetTimer, 1000, 0); - } else { - len=os_sprintf(buff, "{\n \"status\": \"working\"\n }\n"); - } - } else { - len=os_sprintf(buff, "{\n \"status\": \"fail\"\n }\n"); - } - - httpdSend(connData, buff, len); - return HTTPD_CGI_DONE; -} - -//Template code for the WLAN page. -int ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) { - char buff[1024]; - int x; - static struct station_config stconf; - if (token==NULL) return HTTPD_CGI_DONE; - wifi_station_get_config(&stconf); - - os_strcpy(buff, "Unknown"); - if (os_strcmp(token, "WiFiMode")==0) { - x=wifi_get_opmode(); - if (x==1) os_strcpy(buff, "Client"); - if (x==2) os_strcpy(buff, "SoftAP"); - if (x==3) os_strcpy(buff, "STA+AP"); - } else if (os_strcmp(token, "currSsid")==0) { - os_strcpy(buff, (char*)stconf.ssid); - } else if (os_strcmp(token, "WiFiPasswd")==0) { - os_strcpy(buff, (char*)stconf.password); - } else if (os_strcmp(token, "WiFiapwarn")==0) { - x=wifi_get_opmode(); - if (x==2) { - os_strcpy(buff, "Can't scan in this mode. Click here to go to STA+AP mode."); - } else { - os_strcpy(buff, "Click here to go to standalone AP mode."); - } - } - httpdSend(connData, buff, -1); - return HTTPD_CGI_DONE; -} - -