MeterLogger
httpd.c
Go to the documentation of this file.
1 /*
2 Esp8266 http server - core routines
3 */
4 
5 /*
6  * ----------------------------------------------------------------------------
7  * "THE BEER-WARE LICENSE" (Revision 42):
8  * Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
9  * this notice you can do whatever you want with this stuff. If we meet some day,
10  * and you think this stuff is worth it, you can buy me a beer in return.
11  * ----------------------------------------------------------------------------
12  */
13 
14 
15 #include <esp8266.h>
16 // open lwip networking
17 #ifdef AP
18 #include <lwip/ip.h>
19 #include <lwip/udp.h>
20 #include <lwip/tcp_impl.h>
21 #include <netif/etharp.h>
22 #include <lwip/netif.h>
23 #include <lwip/lwip_napt.h>
24 #include <lwip/dns.h>
25 #include <lwip/app/dhcpserver.h>
26 #include <lwip/opt.h>
27 #else
28 #include <ip_addr.h>
29 #endif // AP
30 #include <espconn.h>
31 
32 #include "httpd.h"
33 #include "espfs.h"
34 #include "debug.h"
35 #include "tinyprintf.h"
36 
37 
38 //Max length of request head
39 #define MAX_HEAD_LEN 1024
40 //Max amount of connections
41 #define MAX_CONN 4
42 //Max post buffer len
43 #define MAX_POST 1024
44 //Max send buffer len
45 #define MAX_SENDBUFF_LEN 2048
46 
47 
48 //This gets set at init time.
50 
51 //Private data for http connection
52 struct HttpdPriv {
54  int headPos;
55  int postPos;
56  char *sendBuff;
58 };
59 
60 //Connection pool
61 //static HttpdPriv connPrivData[MAX_CONN];
62 static HttpdPriv *connPrivData; // allocate dynamically
64 
65 //Listening connection data
66 static struct espconn httpdConn = (struct espconn){ 0 };
68 
69 //Struct to keep extension->mime data in
70 typedef struct {
71  const char *ext;
72  const char *mimetype;
73 } MimeMap;
74 
75 //The mappings from file extensions to mime types. If you need an extra mime type,
76 //add it here.
77 static const MimeMap mimeTypes[]={
78  {"htm", "text/htm"},
79  {"html", "text/html"},
80  {"css", "text/css"},
81  {"js", "text/javascript"},
82  {"txt", "text/plain"},
83  {"jpg", "image/jpeg"},
84  {"jpeg", "image/jpeg"},
85  {"png", "image/png"},
86  {NULL, "text/html"}, //default value
87 };
88 
90 
91 //Returns a static char* to a mime type for a given url to a file.
93 const char *httpdGetMimetype(char *url) {
94  int i=0;
95  //Go find the extension
96  char *ext=url+(strlen(url)-1);
97  while (ext!=url && *ext!='.') ext--;
98  if (*ext=='.') ext++;
99 
100  //ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here...
101  while (mimeTypes[i].ext!=NULL && os_strcmp(ext, mimeTypes[i].ext)!=0) i++;
102  return mimeTypes[i].mimetype;
103 }
104 
105 //Looks up the connData info for a specific esp connection
107 static HttpdConnData *httpdFindConnData(void *arg) {
108  int i;
109  for (i=0; i<MAX_CONN; i++) {
110  if (connData[i].conn==(struct espconn *)arg) return &connData[i];
111  }
112  INFO("FindConnData: Huh? Couldn't find connection for %p\n", arg);
113  return NULL; //WtF?
114 }
115 
116 //Retires a connection for re-use
119  if (conn->postBuff!=NULL) os_free(conn->postBuff);
120  conn->postBuff=NULL;
121  conn->cgi=NULL;
122  conn->conn=NULL;
123 }
124 
125 //Stupid li'l helper function that returns the value of a hex char.
126 static int httpdHexVal(char c) {
127  if (c>='0' && c<='9') return c-'0';
128  if (c>='A' && c<='F') return c-'A'+10;
129  if (c>='a' && c<='f') return c-'a'+10;
130  return 0;
131 }
132 
133 //Decode a percent-encoded value.
134 //Takes the valLen bytes stored in val, and converts it into at most retLen bytes that
135 //are stored in the ret buffer. Returns the actual amount of bytes used in ret. Also
136 //zero-terminates the ret buffer.
137 int httpdUrlDecode(char *val, int valLen, char *ret, int retLen) {
138  int s=0, d=0;
139  int esced=0, escVal=0;
140  while (s<valLen && d<retLen) {
141  if (esced==1) {
142  escVal=httpdHexVal(val[s])<<4;
143  esced=2;
144  } else if (esced==2) {
145  escVal+=httpdHexVal(val[s]);
146  ret[d++]=escVal;
147  esced=0;
148  } else if (val[s]=='%') {
149  esced=1;
150  } else if (val[s]=='+') {
151  ret[d++]=' ';
152  } else {
153  ret[d++]=val[s];
154  }
155  s++;
156  }
157  if (d<retLen) ret[d]=0;
158  return d;
159 }
160 
161 //Find a specific arg in a string of get- or post-data.
162 //Line is the string of post/get-data, arg is the name of the value to find. The
163 //zero-terminated result is written in buff, with at most buffLen bytes used. The
164 //function returns the length of the result, or -1 if the value wasn't found. The
165 //returned string will be urldecoded already.
167 int httpdFindArg(char *line, char *arg, char *buff, int buffLen) {
168  char *p, *e;
169  if (line==NULL) return 0;
170  p=line;
171  while(p!=NULL && *p!='\n' && *p!='\r' && *p!=0) {
172  INFO("findArg: %s\n", p);
173  if (os_strncmp(p, arg, os_strlen(arg))==0 && p[strlen(arg)]=='=') {
174  p+=os_strlen(arg)+1; //move p to start of value
175  e=(char*)os_strstr(p, "&");
176  if (e==NULL) e=p+os_strlen(p);
177  INFO("findArg: val %s len %d\n", p, (e-p));
178  return httpdUrlDecode(p, (e-p), buff, buffLen);
179  }
180  p=(char*)os_strstr(p, "&");
181  if (p!=NULL) p+=1;
182  }
183  INFO("Finding %s in %s: Not found :/\n", arg, line);
184  return -1; //not found
185 }
186 
187 //Get the value of a certain header in the HTTP client head
189 int httpdGetHeader(HttpdConnData *conn, char *header, char *ret, int retLen) {
190  char *p=conn->priv->head;
191  p=p+strlen(p)+1; //skip GET/POST part
192  p=p+strlen(p)+1; //skip HTTP part
193  while (p<(conn->priv->head+conn->priv->headPos)) {
194  while(*p<=32 && *p!=0) p++; //skip crap at start
195 // INFO("Looking for %s, Header: '%s'\n", header, p);
196  //See if this is the header
197  if (os_strncmp(p, header, strlen(header))==0 && p[strlen(header)]==':') {
198  //Skip 'key:' bit of header line
199  p=p+strlen(header)+1;
200  //Skip past spaces after the colon
201  while(*p==' ') p++;
202  //Copy from p to end
203  while (*p!=0 && *p!='\r' && *p!='\n' && retLen>1) {
204  *ret++=*p++;
205  retLen--;
206  }
207  //Zero-terminate string
208  *ret=0;
209  //All done :)
210  return 1;
211  }
212  p+=strlen(p)+1; //Skip past end of string and \0 terminator
213  }
214  return 0;
215 }
216 
217 //Start the response headers.
220  char buff[128];
221  int l;
222  tfp_snprintf(buff, 128, "HTTP/1.0 %d OK\r\nServer: esp8266-httpd/"HTTPDVER"\r\n", code);
223  l = strlen(buff);
224  httpdSend(conn, buff, l);
225 }
226 
227 //Send a http header.
229 void httpdHeader(HttpdConnData *conn, const char *field, const char *val) {
230  char buff[256];
231  int l;
232 
233  tfp_snprintf(buff, 256, "%s: %s\r\n", field, val);
234  l = strlen(buff);
235  httpdSend(conn, buff, l);
236 }
237 
238 //Finish the headers.
241  httpdSend(conn, "\r\n", -1);
242 }
243 
244 //Redirect to the given URL.
246 void httpdRedirect(HttpdConnData *conn, char *newUrl) {
247  char buff[1024];
248  int l;
249  tfp_snprintf(buff, 1024, "HTTP/1.1 302 Found\r\nLocation: %s\r\n\r\nMoved to %s\r\n", newUrl, newUrl);
250  l = strlen(buff);
251  httpdSend(conn, buff, l);
252 }
253 
254 //Use this as a cgi function to redirect one url to another.
256 int cgiRedirect(HttpdConnData *connData) {
257  if (connData->conn==NULL) {
258  //Connection aborted. Clean up.
259  return HTTPD_CGI_DONE;
260  }
261  httpdRedirect(connData, (char*)connData->cgiArg);
262  return HTTPD_CGI_DONE;
263 }
264 
265 
266 //Add data to the send buffer. len is the length of the data. If len is -1
267 //the data is seen as a C-string.
268 //Returns 1 for success, 0 for out-of-memory.
270 int httpdSend(HttpdConnData *conn, const char *data, int len) {
271  if (len<0) len=strlen(data);
272  if (conn->priv->sendBuffLen+len>MAX_SENDBUFF_LEN) return 0;
273  os_memcpy(conn->priv->sendBuff+conn->priv->sendBuffLen, data, len);
274  conn->priv->sendBuffLen+=len;
275  return 1;
276 }
277 
278 //Helper function to send any data in conn->priv->sendBuff
281  if (conn->priv->sendBuffLen!=0) {
282  espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen);
283  conn->priv->sendBuffLen=0;
284  }
285 }
286 
287 //Callback called when the data on a socket has been successfully
288 //sent.
290 static void httpdSentCb(void *arg) {
291  int r;
294 
295 // INFO("Sent callback on conn %p\n", conn);
296  if (conn==NULL) return;
297  conn->priv->sendBuff=sendBuff;
298  conn->priv->sendBuffLen=0;
299 
300  if (conn->cgi==NULL) { //Marked for destruction?
301  INFO("Conn %p is done. Closing.\n", conn->conn);
302  espconn_disconnect(conn->conn);
303  httpdRetireConn(conn);
304  return; //No need to call xmitSendBuff.
305  }
306 
307  r=conn->cgi(conn); //Execute cgi fn.
308  if (r==HTTPD_CGI_DONE) {
309  conn->cgi=NULL; //mark for destruction.
310  }
311  xmitSendBuff(conn);
312 }
313 
314 static const char *httpNotFoundHeader="HTTP/1.0 404 Not Found\r\nServer: esp8266-httpd/0.1\r\nContent-Type: text/plain\r\n\r\nNot Found.\r\n";
315 
316 //This is called when the headers have been received and the connection is ready to send
317 //the result headers and data.
320  int i=0;
321  int r;
322  //See if the url is somewhere in our internal url table.
323  while (builtInUrls[i].url!=NULL && conn->url!=NULL) {
324  int match=0;
325 // INFO("%s == %s?\n", builtInUrls[i].url, conn->url);
326  if (os_strcmp(builtInUrls[i].url, conn->url)==0) match=1;
327  if (builtInUrls[i].url[os_strlen(builtInUrls[i].url)-1]=='*' &&
328  os_strncmp(builtInUrls[i].url, conn->url, os_strlen(builtInUrls[i].url)-1)==0) match=1;
329  if (match) {
330  INFO("Is url index %d\n", i);
331  conn->cgiData=NULL;
332  conn->cgi=builtInUrls[i].cgiCb;
333  conn->cgiArg=builtInUrls[i].cgiArg;
334  r=conn->cgi(conn);
335  if (r!=HTTPD_CGI_NOTFOUND) {
336  if (r==HTTPD_CGI_DONE) conn->cgi=NULL; //If cgi finishes immediately: mark conn for destruction.
337  return;
338  }
339  }
340  i++;
341  }
342  //Can't find :/
343  INFO("%s not found. 404!\n", conn->url);
344  httpdSend(conn, httpNotFoundHeader, -1);
345  conn->cgi=NULL; //mark for destruction
346 }
347 
348 //Parse a line of header data and modify the connection data accordingly.
350 static void httpdParseHeader(char *h, HttpdConnData *conn) {
351  int i;
352 // INFO("Got header %s\n", h);
353  if (os_strncmp(h, "GET ", 4)==0 || os_strncmp(h, "POST ", 5)==0) {
354  char *e;
355 
356  //Skip past the space after POST/GET
357  i=0;
358  while (h[i]!=' ') i++;
359  conn->url=h+i+1;
360 
361  //Figure out end of url.
362  e=(char*)os_strstr(conn->url, " ");
363  if (e==NULL) return; //wtf?
364  *e=0; //terminate url part
365 
366  INFO("URL = %s\n", conn->url);
367  //Parse out the URL part before the GET parameters.
368  conn->getArgs=(char*)os_strstr(conn->url, "?");
369  if (conn->getArgs!=0) {
370  *conn->getArgs=0;
371  conn->getArgs++;
372  INFO("GET args = %s\n", conn->getArgs);
373  } else {
374  conn->getArgs=NULL;
375  }
376  } else if (os_strncmp(h, "Content-Length: ", 16)==0) {
377  i=0;
378  //Skip trailing spaces
379  while (h[i]!=' ') i++;
380  //Get POST data length
381  conn->postLen=atoi(h+i+1);
382  //Clamp if too big. Hmm, maybe we should error out instead?
383  if (conn->postLen>MAX_POST) conn->postLen=MAX_POST;
384  INFO("Mallocced buffer for %d bytes of post data.\n", conn->postLen);
385  //Alloc the memory.
386  conn->postBuff=(char*)os_malloc(conn->postLen+1);
387  conn->priv->postPos=0;
388  }
389 }
390 
391 
392 //Callback called when there's data available on a socket.
394 static void httpdRecvCb(void *arg, char *data, unsigned short len) {
395  int x;
396  char *p, *e;
399  if (conn==NULL) return;
400  conn->priv->sendBuff=sendBuff;
401  conn->priv->sendBuffLen=0;
402 
403  for (x=0; x<len; x++) {
404  if (conn->postLen<0) {
405  //This byte is a header byte.
406  if (conn->priv->headPos!=MAX_HEAD_LEN) conn->priv->head[conn->priv->headPos++]=data[x];
407  conn->priv->head[conn->priv->headPos]=0;
408  //Scan for /r/n/r/n
409  if (data[x]=='\n' && (char *)os_strstr(conn->priv->head, "\r\n\r\n")!=NULL) {
410  //Indicate we're done with the headers.
411  conn->postLen=0;
412  //Reset url data
413  conn->url=NULL;
414  //Find end of next header line
415  p=conn->priv->head;
416  while(p<(&conn->priv->head[conn->priv->headPos-4])) {
417  e=(char *)os_strstr(p, "\r\n");
418  if (e==NULL) break;
419  e[0]=0;
420  httpdParseHeader(p, conn);
421  p=e+2;
422  }
423  //If we don't need to receive post data, we can send the response now.
424  if (conn->postLen==0) {
425  httpdSendResp(conn);
426  }
427  }
428  } else if (conn->priv->postPos!=-1 && conn->postLen!=0 && conn->priv->postPos <= conn->postLen) {
429  //This byte is a POST byte.
430  conn->postBuff[conn->priv->postPos++]=data[x];
431  if (conn->priv->postPos>=conn->postLen) {
432  //Received post stuff.
433  conn->postBuff[conn->priv->postPos]=0; //zero-terminate
434  conn->priv->postPos=-1;
435  INFO("Post data: %s\n", conn->postBuff);
436  //Send the response.
437  httpdSendResp(conn);
438  break;
439  }
440  }
441  }
442  xmitSendBuff(conn);
443 }
444 
446 static void httpdReconCb(void *arg, sint8 err) {
448  INFO("ReconCb\n");
449  if (conn==NULL) return;
450  //Yeah... No idea what to do here. ToDo: figure something out.
451 }
452 
454 static void httpdDisconCb(void *arg) {
455 #if 0
456  //Stupid esp sdk passes through wrong arg here, namely the one of the *listening* socket.
457  //If it ever gets fixed, be sure to update the code in this snippet; it's probably out-of-date.
459  INFO("Disconnected, conn=%p\n", conn);
460  if (conn==NULL) return;
461  conn->conn=NULL;
462  if (conn->cgi!=NULL) conn->cgi(conn); //flush cgi data
463 #endif
464  //Just look at all the sockets and kill the slot if needed.
465  int i;
466  for (i=0; i<MAX_CONN; i++) {
467  if (connData[i].conn!=NULL) {
468  //Why the >=ESPCONN_CLOSE and not ==? Well, seems the stack sometimes de-allocates
469  //espconns under our noses, especially when connections are interrupted. The memory
470  //is then used for something else, and we can use that to capture *most* of the
471  //disconnect cases.
472  if (connData[i].conn->state==ESPCONN_NONE || connData[i].conn->state>=ESPCONN_CLOSE) {
473  connData[i].conn=NULL;
474  if (connData[i].cgi!=NULL) connData[i].cgi(&connData[i]); //flush cgi data
475  httpdRetireConn(&connData[i]);
476  }
477  }
478  }
479 }
480 
481 
483 static void httpdConnectCb(void *arg) {
484  struct espconn *conn=arg;
485  int i;
486  //Find empty conndata in pool
487  for (i=0; i<MAX_CONN; i++) if (connData[i].conn==NULL) break;
488  INFO("Con req, conn=%p, pool slot %d\n", conn, i);
489  if (i==MAX_CONN) {
490  INFO("Aiee, conn pool overflow!\n");
491  espconn_disconnect(conn);
492  return;
493  }
494  connData[i].priv=&connPrivData[i];
495  connData[i].conn=conn;
496  connData[i].priv->headPos=0;
497  connData[i].postBuff=NULL;
498  connData[i].priv->postPos=0;
499  connData[i].postLen=-1;
500 
505 }
506 
507 
509 void httpdInit(HttpdBuiltInUrl *fixedUrls, int port) {
510  int i;
511 
512  connPrivData = malloc(sizeof(HttpdPriv) * MAX_CONN);
513 
514  for (i=0; i<MAX_CONN; i++) {
515  connData[i].conn=NULL;
516  }
517  httpdConn.type=ESPCONN_TCP;
518  httpdConn.state=ESPCONN_NONE;
519  httpdTcp.local_port=port;
520  httpdConn.proto.tcp=&httpdTcp;
521  builtInUrls=fixedUrls;
522 
523  INFO("Httpd init, conn=%p\n", &httpdConn);
525  espconn_accept(&httpdConn);
526 }
527 
529 void static httpdDisconnectTimerFunc(void *arg) {
530  httpdStop();
531 }
532 
534 void httpdStop() {
535  INFO("Httpd stopping, state=%d conn=%p\n", httpdConn.state, &httpdConn);
536 
537  if (httpdConn.state != ESPCONN_NONE) {
538  if (espconn_delete(&httpdConn) == 0) {
540  httpdRetireConn(connData);
541  free(connPrivData);
542  INFO("Httpd stopped\n");
543  }
544  else {
545  espconn_disconnect(&httpdConn);
549  INFO("Httpd still running rescheduling httpdStop\n");
550  }
551  }
552 }
sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb)
Definition: espconn.c:712
#define free(x)
Definition: platform.h:20
static ICACHE_FLASH_ATTR void httpdParseHeader(char *h, HttpdConnData *conn)
Definition: httpd.c:350
sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb)
Definition: espconn.c:770
#define os_timer_t
Definition: os_type.h:34
sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length)
Definition: espconn.c:368
#define os_timer_disarm
Definition: osapi.h:51
#define os_strncmp
Definition: osapi.h:44
static struct espconn httpdConn
Definition: httpd.c:66
char * getArgs
Definition: httpd.h:22
esp_tcp * tcp
Definition: espconn.h:105
Definition: httpd.c:70
static ICACHE_FLASH_ATTR void httpdRecvCb(void *arg, char *data, unsigned short len)
Definition: httpd.c:394
static struct espconn conn
Definition: captdns.c:50
ICACHE_FLASH_ATTR void httpdStop()
Definition: httpd.c:534
static ICACHE_FLASH_ATTR void httpdDisconCb(void *arg)
Definition: httpd.c:454
#define NULL
Definition: def.h:47
int local_port
Definition: espconn.h:72
sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb)
Definition: espconn.c:789
ICACHE_FLASH_ATTR void httpdRedirect(HttpdConnData *conn, char *newUrl)
Definition: httpd.c:246
#define ICACHE_FLASH_ATTR
Definition: c_types.h:99
#define os_timer_func_t
Definition: os_type.h:35
#define MAX_HEAD_LEN
Definition: httpd.c:39
#define MAX_POST
Definition: httpd.c:43
const char * ext
Definition: httpd.c:71
const void * cgiArg
Definition: httpd.h:23
#define HTTPDVER
Definition: httpd.h:6
static os_timer_t httpdDisconnectTimer
Definition: httpd.c:89
#define malloc(x)
Definition: platform.h:19
char * url
Definition: httpd.h:21
#define HTTPD_CGI_NOTFOUND
Definition: httpd.h:10
#define HTTPD_CGI_DONE
Definition: httpd.h:9
#define os_timer_setfn
Definition: osapi.h:52
static ICACHE_FLASH_ATTR void httpdReconCb(void *arg, sint8 err)
Definition: httpd.c:446
#define MAX_CONN
Definition: httpd.c:41
static ICACHE_FLASH_ATTR void httpdRetireConn(HttpdConnData *conn)
Definition: httpd.c:118
ICACHE_FLASH_ATTR int httpdFindArg(char *line, char *arg, char *buff, int buffLen)
Definition: httpd.c:167
const void * cgiArg
Definition: httpd.h:36
#define os_memcpy
Definition: osapi.h:36
const char * mimetype
Definition: httpd.c:72
int headPos
Definition: httpd.c:54
static const char * httpNotFoundHeader
Definition: httpd.c:314
#define os_strlen
Definition: osapi.h:43
int postPos
Definition: httpd.c:55
#define os_strcmp
Definition: osapi.h:41
#define os_malloc(s)
Definition: mem.h:41
ICACHE_FLASH_ATTR void httpdInit(HttpdBuiltInUrl *fixedUrls, int port)
Definition: httpd.c:509
sint8 espconn_disconnect(struct espconn *espconn)
Definition: espconn.c:942
static ICACHE_FLASH_ATTR void xmitSendBuff(HttpdConnData *conn)
Definition: httpd.c:280
static ICACHE_FLASH_ATTR HttpdConnData * httpdFindConnData(void *arg)
Definition: httpd.c:107
static esp_tcp httpdTcp
Definition: httpd.c:67
static HttpdBuiltInUrl * builtInUrls
Definition: httpd.c:49
char head[MAX_HEAD_LEN]
Definition: httpd.c:53
ICACHE_FLASH_ATTR static void httpdDisconnectTimerFunc(void *arg)
Definition: httpd.c:529
static ICACHE_FLASH_ATTR void httpdConnectCb(void *arg)
Definition: httpd.c:483
sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb)
Definition: espconn.c:807
static const MimeMap mimeTypes[]
Definition: httpd.c:77
#define os_strstr
Definition: osapi.h:46
sint8 espconn_accept(struct espconn *espconn)
Definition: espconn.c:875
ICACHE_FLASH_ATTR int httpdGetHeader(HttpdConnData *conn, char *header, char *ret, int retLen)
Definition: httpd.c:189
#define os_free(s)
Definition: mem.h:40
static const char url[]
Definition: heatshrink.c:27
ICACHE_FLASH_ATTR void httpdStartResponse(HttpdConnData *conn, int code)
Definition: httpd.c:219
ICACHE_FLASH_ATTR void httpdEndHeaders(HttpdConnData *conn)
Definition: httpd.c:240
sint8 espconn_delete(struct espconn *espconn)
Definition: espconn.c:1217
static HttpdPriv * connPrivData
Definition: httpd.c:62
ICACHE_FLASH_ATTR const char * httpdGetMimetype(char *url)
Definition: httpd.c:93
ICACHE_FLASH_ATTR int tfp_snprintf(char *str, size_t size, const char *format,...)
Definition: tinyprintf.c:480
ICACHE_FLASH_ATTR int cgiRedirect(HttpdConnData *connData)
Definition: httpd.c:256
union espconn::@1 proto
ICACHE_FLASH_ATTR void httpdHeader(HttpdConnData *conn, const char *field, const char *val)
Definition: httpd.c:229
static ICACHE_FLASH_ATTR void httpdSendResp(HttpdConnData *conn)
Definition: httpd.c:319
void * cgiData
Definition: httpd.h:24
struct espconn * conn
Definition: httpd.h:20
#define os_timer_arm(a, b, c)
Definition: osapi.h:50
#define MAX_SENDBUFF_LEN
Definition: httpd.c:45
enum espconn_type type
Definition: espconn.h:101
static int httpdHexVal(char c)
Definition: httpd.c:126
enum espconn_state state
Definition: espconn.h:103
ICACHE_FLASH_ATTR int httpdSend(HttpdConnData *conn, const char *data, int len)
Definition: httpd.c:270
sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb)
Definition: espconn.c:751
char * sendBuff
Definition: httpd.c:56
char * postBuff
Definition: httpd.h:28
cgiSendCallback cgiCb
Definition: httpd.h:35
static HttpdConnData connData[MAX_CONN]
Definition: httpd.c:63
#define INFO(...)
Definition: debug.h:17
int postLen
Definition: httpd.h:27
signed char sint8
Definition: c_types.h:47
#define strlen(a)
Definition: platform.h:25
int httpdUrlDecode(char *val, int valLen, char *ret, int retLen)
Definition: httpd.c:137
int sendBuffLen
Definition: httpd.c:57
static ICACHE_FLASH_ATTR void httpdSentCb(void *arg)
Definition: httpd.c:290
cgiSendCallback cgi
Definition: httpd.h:26
HttpdPriv * priv
Definition: httpd.h:25