Master The Pico WiFi: Simplest HTTP Client
Written by Harry Fairhead & Mike James   
Tuesday, 11 April 2023
Article Index
Master The Pico WiFi: Simplest HTTP Client
HTTP
HTTP Client
CMakeLists etc

HTTP

The simplest way to make use of a WiFi connection is to work with an HTTP server. This is simple because the difficult parts of the transaction are handled by the server, making the client much easier to implement.

Using what we know so far about raw TCP, we can easily connect to a server and send and receive data. What data we actually send and receive depends on the protocol in use. Web servers use HTTP, which is a very simple text-based protocol.

The HTTP protocol is essentially a set of text headers of the form:

headername: headerdata \r\n

that tell the server what to do, and a set of headers that the server sends back to tell you what it has done. There are very many HTTP headers and you can look up their details of in the documentation.

The most important header is the very first which acts as a command to tell the server what the client wants to do – a client request. HTTP supports a number of request methods which transfer data. Usually these are described in terms of what they do to resources hosted by a web server, but from our point of view what matters is what happens to the data.

The HTTP request methods available are:

GET

Transfers data from server to client

HEAD

Transfers HTTP headers for the equivalent GET request

PUT

Transfers data from the client to the server

POST

Transfers data from the client to the server

PATCH

Transfers data from the client to the server

DELETE

Specifies that the data on the server should be deleted

OPTIONS

Transfers data from the client to the server

If you know about HTTP request methods you will find the above list disconcerting. If you don’t know about HTTP requests then you will be wondering why there are so many requests that transfer data from the client to the server? The answer is that in the HTTP model the server stores the master copy of the resource – usually a file or a database entry. The client can request a copy of the resource using GET and then ask the server to modify the resource using the other requests. For example, the PUT request sends a new copy of the resource for the server to use, i.e. it replaces the old copy. POST does the same thing, but PUT should be idempotent which means that if you repeat it the result is as if you had done it just once. With POST you are allowed side effects. For example, PUT 1 might just store 1 but POST 1 might increment a count.

Another example is where you sends some text to the server to save under a supplied file name. For this you should use a PUT as repeating the request with the same text changes nothing. If, on the other hand, you supply text to the server and allow it to assign a name and store it then you should use a POST as you get a new file each time you send the data, even it is the same.

Similarly the PATCH request should be used by the client to request that that server makes a change to part of an existing resource. Exactly how the change is specified depends on the server. Usually a key value scheme is used, but this isn’t part of the specification.

Notice that all of these interpretations of the HTTP request methods are “optional” in the sense that it is up to you and the server you are using to interpret and implement them. If you write your own server, or server application, then you can treat POST as if it was PUT and vice versa.

picomaster180

A Custom Test Server

The problem with writing HTTP examples is that how they are handled depends on the server in use. Not all HTTP servers implement the same range of requests. A simple solution to this problem is to write a custom server and switching to Python makes this very easy. Before you try any of the following examples, create the following Python program on a suitable machine on your local network, the code can be downloaded from the book’s web page. Notice that this code is Python 3.10 or later:

from http.server import HTTPServer,
BaseHTTPRequestHandler
from io import BytesIO class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def sendResponse(self, cmd):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
self.send_response(200)
self.end_headers()
response = BytesIO()
response.write(b'This is a '+bytes(cmd, 'utf-8')+
b' request. ')
response.write(b'Received: ')
response.write(body)
self.wfile.write(response.getvalue())
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b'Hello, world!')
def do_HEAD(self):
self.send_response(200)
self.end_headers()

def do_POST(self):
self.sendResponse("POST")

def do_PUT(self):
self.sendResponse("PUT")

def do_DELETE(self):
self.sendResponse("DELETE")

def do_PATCH(self):
self.sendResponse("PATCH")
httpd = HTTPServer(('', 8080), SimpleHTTPRequestHandler)
httpd.serve_forever()

This server implements simple methods to respond to GET, HEAD, PUT, POST, DELETE and PATCH requests. If you want to support a custom request simply include a method that is called do_request where request is the command you want to use.

Notice that this custom request is unlikely to be serviced by a standard server, but there is nothing stopping you from implementing your own. In the case of GET, the server sends fixed data – “Hello World” - and for the others it sends back whatever was sent to it by the client, with the exception of HEAD that sends nothing at all except for the headers.

If you install this program on a remote machine on the same network as the Pico then you can use it to test HTTP request programs. With a little work you can also turn it into a server that supports your Pico app in the external world. You can even convert it into a TLS/ SSL server for HTTPS connections using the Python SSL module.



Last Updated ( Tuesday, 11 April 2023 )