ESPTerm - ESP8266 terminal emulator. Branches: [master] patches, [work] next release
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
espterm-firmware/user/httpd.c

244 lines
6.0 KiB

#include "driver/uart.h"
#include "c_types.h"
#include "user_interface.h"
#include "espconn.h"
#include "mem.h"
#include "osapi.h"
#include "espconn.h"
#include "httpd.h"
#include "io.h"
#include "espfs.h"
#define MAX_HEAD_LEN 1024
//struct UrlData;
typedef struct UrlData UrlData;
typedef struct {
char *url;
char *getArgs;
const UrlData *effUrl;
char *datPtr;
int datLen;
EspFsFile *file;
} GetData;
typedef int (* cgiSendCallback)(struct espconn *conn, GetData *getData);
struct UrlData {
const char *url;
const char *fixedResp;
cgiSendCallback cgiCb;
};
int cgiSet(struct espconn *conn, GetData *getData);
int cgiGetFlash(struct espconn *conn, GetData *getData);
static int cgiSendFile(struct espconn *conn, GetData *getData);
const char htmlIndex[]="<html><head><title>Hello World</title></head> \
<body><h1>Hello, World!</h1></body> \
</html>";
static const UrlData urls[]={
{"/", htmlIndex, NULL},
{"/set", NULL, cgiSet},
{"/flash.bin", NULL, cgiGetFlash},
{NULL, NULL, NULL},
};
static const UrlData cpioUrlData={"*", NULL, cgiSendFile};
static struct espconn conn;
static esp_tcp tcp;
static int recLen;
static char recBuff[MAX_HEAD_LEN];
static GetData getData;
//Find a specific arg in a string of get- or post-data.
static char *ICACHE_FLASH_ATTR httpdFindArg(char *line, char *arg) {
char *p;
int al;
if (line==NULL) return NULL;
p=line;
al=os_strlen(arg);
os_printf("Finding %s in %s\n", arg, line);
while (p[0]!=0) {
if (os_strncmp(p, arg, al)==0 && p[al]=='=') {
//Gotcha.
return &p[al+1];
} else {
//Wrong arg. Advance to start of next arg.
p+=os_strlen(p)+1;
}
}
os_printf("Finding %s in %s: Not found :/\n", arg, line);
return NULL; //not found
}
//ToDo: Move cgi functions to somewhere else
int ICACHE_FLASH_ATTR cgiSet(struct espconn *conn, GetData *getData) {
char *on;
static const char okStr[]="<html><head><title>OK</title></head><body><p>OK</p></body></html>";
on=httpdFindArg(getData->getArgs, "led");
os_printf("cgiSet: on=%s\n", on?on:"not found");
if (on!=NULL) ioLed(atoi(on));
espconn_sent(conn, (uint8 *)okStr, os_strlen(okStr));
return 1;
}
int ICACHE_FLASH_ATTR cgiGetFlash(struct espconn *conn, GetData *getData) {
static char *p=(char *)0x40200000;
static int t=0;
espconn_sent(conn, (uint8 *)p, 1024);
p+=1024;
t++;
if (t<1024) return 0;
t=0;
p=(char*)0x40200000;
return 1;
}
static int ICACHE_FLASH_ATTR cgiSendFile(struct espconn *conn, GetData *getData) {
int len;
char buff[1024];
len=espFsRead(getData->file, buff, 1024);
espconn_sent(conn, (uint8 *)buff, len);
return (len==0);
}
static const char *httpOkHeader="HTTP/1.0 200 OK\r\nServer: esp8266-thingie/0.1\r\nContent-Type: text/html\r\n\r\n";
static const char *httpNotFoundHeader="HTTP/1.0 404 Not Found\r\nServer: esp8266-thingie/0.1\r\n\r\nNot Found.\r\n";
static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) {
struct espconn *conn=arg;
if (getData.effUrl==NULL) {
espconn_disconnect(conn);
return;
}
if (getData.effUrl->cgiCb!=NULL) {
if (getData.effUrl->cgiCb(conn, &getData)) getData.effUrl=NULL;
} else {
espconn_sent(conn, (uint8 *)getData.effUrl->fixedResp, os_strlen(getData.effUrl->fixedResp));
getData.effUrl=NULL;
}
}
static void ICACHE_FLASH_ATTR httpdSendResp(struct espconn *conn) {
int i=0;
EspFsFile *fdat;
//See if the url is somewhere in our internal url table.
while (urls[i].url!=NULL) {
if (os_strcmp(urls[i].url, getData.url)==0) {
getData.effUrl=&urls[i];
os_printf("Is url index %d\n", i);
espconn_sent(conn, (uint8 *)httpOkHeader, os_strlen(httpOkHeader));
return;
}
i++;
}
//Nope. See if it's in the cpio archive
fdat=espFsOpen(getData.url);
if (fdat!=NULL) {
//Found
getData.file=fdat;
getData.effUrl=&cpioUrlData;
espconn_sent(conn, (uint8 *)httpOkHeader, os_strlen(httpOkHeader));
return;
}
//Can't find :/
espconn_sent(conn, (uint8 *)httpNotFoundHeader, os_strlen(httpNotFoundHeader));
}
static void ICACHE_FLASH_ATTR httpdParseHeader(char *h) {
os_printf("Got header %s\n", h);
if (os_strncmp(h, "GET ", 4)==0) {
char *e;
getData.url=h+4;
e=(char*)os_strstr(getData.url, " ");
if (e==NULL) return; //wtf?
*e=0; //terminate url part
os_printf("URL = %s\n", getData.url);
getData.getArgs=(char*)os_strstr(getData.url, "?");
if (getData.getArgs!=0) {
int x,l;
*getData.getArgs=0;
getData.getArgs++;
os_printf("GET args = %s\n", getData.getArgs);
l=os_strlen(getData.getArgs);
for (x=0; x<l; x++) if (getData.getArgs[x]=='&') getData.getArgs[x]=0;
//End with double-zero
getData.getArgs[l]=0;
getData.getArgs[l+1]=0;
} else {
getData.getArgs=NULL;
}
}
}
static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short len) {
struct espconn *conn=arg;
int x;
char *p, *e;
if (recLen==-1) return; //we don't accept data anymore
for (x=0; x<len && recLen!=MAX_HEAD_LEN; x++) recBuff[recLen++]=data[x];
recBuff[recLen]=0;
//Scan for /r/n/r/n
if ((char *)os_strstr(recBuff, "\r\n\r\n")!=NULL) {
//Reset url data
getData.url=NULL;
//Find end of next header line
p=recBuff;
while(p<(&recBuff[recLen-4])) {
e=(char *)os_strstr(p, "\r\n");
if (e==NULL) break;
e[0]=0;
httpdParseHeader(p);
p=e+2;
}
httpdSendResp(conn);
}
}
static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) {
os_printf("ReconCb\n");
httpdInit();
}
static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) {
struct espconn *conn=arg;
os_printf("Disconnected, conn=%p\n", conn);
}
static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) {
struct espconn *conn=arg;
os_printf("Con req, conn=%p\n", conn);
recLen=0;
espconn_regist_recvcb(conn, httpdRecvCb);
espconn_regist_reconcb(conn, httpdReconCb);
espconn_regist_disconcb(conn, httpdDisconCb);
espconn_regist_sentcb(conn, httpdSentCb);
}
void ICACHE_FLASH_ATTR httpdInit() {
conn.type=ESPCONN_TCP;
conn.state=ESPCONN_NONE;
tcp.local_port=80;
conn.proto.tcp=&tcp;
os_printf("Httpd init, conn=%p\n", conn);
espconn_regist_connectcb(&conn, httpdConnectCb);
espconn_accept(&conn);
}