ESP8266 POST Server
Overview
I have added this code because I needed my ESP8266 to serve 'Web Hooks' or HTTP POST Requests.
I searched long and hard, but found no solutions.
So, I started from the simple web server example, linked below, and, after some research, came up with the working example posted here.
The key is that the Header is all nicely terminated with carriage return / line feed combinations, but the Body is not.
The body starts after a blank line terminated by cr/lf.
In the header there is a parameter called Content_Length, and that tells us how many more bytes to expect. We then read()
those, as opposed to using readline()
for the header lines.
The client then expects to be told the result of the POST
We send "HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\nSUCCESS"
, which tells the client the request was successful, and sends its own BODY content back. The Content-Length: 7
describes the seven bytes that make up the word SUCCESS
This works fine so long as the client is well behaved, but, ideally, there would be much error checking in here so that it can recover from badly formed requests.
Also, the first line, for example POST /post HTTP/1.1\r\n
, contains the request type and also the path. This could be parsed out to deal with GET requests, and the path, in this case /post
, could be used for determining the type of data we might expect in the Body or to provide some security.
The code as it stands will allow you to use IFTTT to control your ESP8266. I have demonstrated using Amazon Alexa and IFTTT to pass POST requests to a server in my tutorial Controlling_Anything_With_Alexa_And_Raspberry_Pi. There is no reason why you shouldn't use the ESP8266 in place of the Pi.
Code
import socket port = 8080 addr = socket.getaddrinfo('0.0.0.0', port)[0][-1] s = socket.socket() s.bind(addr) s.listen(1) print('listening on', addr) header = True while True: cl, addr = s.accept() print('client connected from', addr) cl_file = cl.makefile('rwb', 0) while True: if header: line = cl_file.readline() # parse out Content-Length - e.g. b'Content-Length: 24\r\n' if b"Content-Length: " in line: content_length = int(line[16:len(line)-2]) print ("content length", content_length) print("Line:",line) # first new line with no content means end of header if line == b"\r\n": header = False else: # this is where we collect the body # line will contain all the body and will need parsing appropriately line = cl_file.read(content_length) print("Body:",line) break response = "HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\nSUCCESS" cl.send(response) cl.close() # start again header = True