Foundations of Python Network Programming

(WallPaper) #1
Chapter 10 ■ http ServerS

179

There are two ways to build the WSGI callable that your web server will invoke for HTTP requests that arrive and
are parsed successfully. You can build the callable yourself, or you can write code that plugs into a web framework that
provides its own WSGI callable. What is the difference?
The essential task of a web framework is to assume responsibility for dispatch. Each HTTP request names a
coordinate in the space of possible methods, hostnames, and paths. You are probably running your service at only one
or a couple of hostnames, not all possible hostnames. You might be prepared to process GET or POST, but a request
can name whatever method it wants—even an invented one. There may be many paths for which you can produce
useful responses but probably many more for which you cannot. The framework will let you declare which paths and
methods you do support, so the framework can shoulder the burden of replying automatically for those that do not
with status codes like these:


•    404 Not Found

•    405 Method Not Allowed

•    501 Not Implemented

Chapter 11 explores how both traditional and asynchronous frameworks assume responsibility for dispatch, and
it surveys the other major features that they offer programmers. But what might your code look like without them?
What if your own code interfaces directly with WSGI and takes charge of performing dispatch?
There are two ways of constructing such an application: either by reading the WSGI specification and learning
to read its environment dictionary yourself or by using a wrapper like those provided by the competing WebOb and
Werkzeug toolkits available from the Python Package Index. Listing 10-2 demonstrates the verbose coding style
necessary with working in the raw WSGI environment.


Listing 10-2. Raw WSGI Callable for Returning the Current Time


#!/usr/bin/env python3


Foundations of Python Network Programming, Third Edition


https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter10/timeapp_raw.py


A simple HTTP service built directly against the low-level WSGI spec.


import time


def app(environ, start_response):
host = environ.get('HTTP_HOST', '127.0.0.1')
path = environ.get('PATH_INFO', '/')
if ':' in host:
host, port = host.split(':', 1)
if '?' in path:
path, query = path.split('?', 1)
headers = [('Content-Type', 'text/plain; charset=utf-8')]
if environ['REQUEST_METHOD'] != 'GET':
start_response('501 Not Implemented', headers)
yield b'501 Not Implemented'
elif host != '127.0.0.1' or path != '/':
start_response('404 Not Found', headers)
yield b'404 Not Found'
else:
start_response('200 OK', headers)
yield time.ctime().encode('ascii')

Free download pdf