wsgiref — WSGI-Hilfsmittel und Referenzimplementierung

Quellcode: Lib/wsgiref


Warnung

wsgiref ist eine Referenzimplementierung und für den Produktivbetrieb nicht empfehlenswert. Das Modul führt nur grundlegende Sicherheitsprüfungen durch.

Das Web Server Gateway Interface (WSGI) ist eine genormte Schnittstelle zwischen Webserver-Software und in Python geschriebenen Webanwendungen. Dank dieser Norm lässt sich eine Anwendung, die WSGI unterstützt, mit vielen verschiedenen Webservern betreiben.

Jede Feinheit und jeden Sonderfall des WSGI-Entwurfs müssen nur die kennen, die Webserver oder Programmierframeworks schreiben. Um eine WSGI-Anwendung zu installieren oder mit einem bestehenden Framework eine Webanwendung zu schreiben, musst du nicht jede Einzelheit von WSGI verstehen.

wsgiref ist eine Referenzimplementierung der WSGI-Spezifikation. Mit ihr lässt sich ein Webserver oder ein Framework um WSGI-Unterstützung erweitern. Sie bietet Hilfsmittel zum Bearbeiten von WSGI-Umgebungsvariablen und Antwort-Headern, Basisklassen für WSGI-Server, einen HTTP-Server zur Veranschaulichung, der WSGI-Anwendungen ausliefert, Typen für die statische Typprüfung sowie ein Prüfwerkzeug, das WSGI-Server und -Anwendungen auf Übereinstimmung mit der WSGI-Spezifikation (PEP 3333) prüft.

Mehr über WSGI sowie Verweise auf Tutorials und weitere Quellen stehen unter wsgi.readthedocs.io.

wsgiref.util – Hilfsmittel für die WSGI-Umgebung

Dieses Modul bietet verschiedene Hilfsfunktionen für die Arbeit mit WSGI-Umgebungen. Eine WSGI-Umgebung ist ein Dictionary mit den Variablen einer HTTP-Anfrage, wie in PEP 3333 beschrieben. Alle Funktionen mit einem Parameter environ erwarten ein WSGI-konformes Dictionary. Die genaue Spezifikation steht in PEP 3333, und WSGIEnvironment ist ein Typalias für Typannotationen.

wsgiref.util.guess_scheme(environ)

Schätzt, ob wsgi.url_scheme „http“ oder „https“ sein sollte, indem im Dictionary environ nach einer Umgebungsvariablen HTTPS gesucht wird. Zurückgegeben wird eine Zeichenkette.

Diese Funktion ist nützlich, wenn man ein Gateway schreibt, das CGI oder ein CGI-ähnliches Protokoll wie FastCGI umhüllt. Server, die solche Protokolle anbieten, setzen bei einer Anfrage über SSL üblicherweise eine Variable HTTPS mit dem Wert „1“, „yes“ oder „on“. Diese Funktion gibt daher „https“ zurück, wenn sie einen solchen Wert findet, sonst „http“.

wsgiref.util.request_uri(environ, include_query=True)

Gibt die vollständige Anfrage-URI zurück, nach Wunsch samt Abfragezeichenkette, nach dem Verfahren aus dem Abschnitt „URL Reconstruction“ von PEP 3333. Ist include_query falsch, enthält die entstehende URI die Abfragezeichenkette nicht.

wsgiref.util.application_uri(environ)

Ähnlich wie request_uri(), nur bleiben die Variablen PATH_INFO und QUERY_STRING außer Betracht. Das Ergebnis ist die Basis-URI des Anwendungsobjekts, an das sich die Anfrage richtet.

wsgiref.util.shift_path_info(environ)

Schiebt einen einzelnen Namen von PATH_INFO nach SCRIPT_NAME und gibt den Namen zurück. Das Dictionary environ wird dabei an seinem Ort geändert. Nimm eine Kopie, wenn das ursprüngliche PATH_INFO oder SCRIPT_NAME erhalten bleiben soll.

Sind in PATH_INFO keine Pfadabschnitte mehr übrig, kommt None zurück.

Üblicherweise verarbeitet man mit dieser Routine jeden Teil des Pfades einer Anfrage-URI, etwa um den Pfad als Folge von Dictionary-Schlüsseln zu behandeln. Die Routine ändert die übergebene Umgebung so, dass sich damit eine weitere WSGI-Anwendung an der Ziel-URI aufrufen lässt. Liegt zum Beispiel eine WSGI-Anwendung unter /foo, lautet der Pfad der Anfrage-URI /foo/bar/baz und ruft die Anwendung unter /foo shift_path_info() auf, erhält sie die Zeichenkette „bar“, und die Umgebung passt danach zur Übergabe an eine WSGI-Anwendung unter /foo/bar. Das heißt: SCRIPT_NAME wechselt von /foo auf /foo/bar und PATH_INFO von /bar/baz auf /baz.

Ist PATH_INFO nur ein „/“, gibt die Routine eine leere Zeichenkette zurück und hängt an SCRIPT_NAME einen Schrägstrich an – obwohl leere Pfadabschnitte normalerweise übergangen werden und SCRIPT_NAME normalerweise nicht auf einen Schrägstrich endet. Das ist Absicht: So kann eine Anwendung, die mit dieser Routine durch Objekte wandert, URIs auf /x von solchen auf /x/ unterscheiden.

wsgiref.util.setup_testing_defaults(environ)

Ergänzt environ um einfache Vorgabewerte für Testzwecke.

Diese Routine fügt verschiedene von WSGI benötigte Parameter hinzu, darunter HTTP_HOST, SERVER_NAME, SERVER_PORT, REQUEST_METHOD, SCRIPT_NAME, PATH_INFO und alle in PEP 3333definierten wsgi.*-Variablen. Sie setzt nur Vorgabewerte und ersetzt bestehende Werte dieser Variablen nicht.

Diese Routine soll es Modultests von WSGI-Servern und -Anwendungen erleichtern, Scheinumgebungen einzurichten. Echte WSGI-Server und -Anwendungen sollten sie NICHT verwenden, denn die Daten sind erfunden!

Beispiel für die Verwendung. Ein weiteres Beispiel steht bei demo_app():

from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server

# A relatively simple WSGI application. It's going to print out the
# environment dictionary after being updated by setup_testing_defaults
def simple_app(environ, start_response):
    setup_testing_defaults(environ)

    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]

    start_response(status, headers)

    ret = [("%s: %s\n" % (key, value)).encode("utf-8")
           for key, value in environ.items()]
    return ret

with make_server('', 8000, simple_app) as httpd:
    print("Serving on port 8000...")
    httpd.serve_forever()

Neben den obigen Funktionen zur Umgebung bietet das Modul wsgiref.util noch diese weiteren Hilfsmittel:

wsgiref.util.is_hop_by_hop(header_name)

Gibt True zurück, wenn „header_name“ ein „Hop-by-Hop“-Header von HTTP/1.1 nach RFC 2616 ist.

class wsgiref.util.FileWrapper(filelike, blksize=8192)

Eine konkrete Umsetzung des Protokolls wsgiref.types.FileWrapper, mit der sich ein dateiähnliches Objekt in einen Iterator verwandeln lässt. Die entstehenden Objekte sind iterierbar. Beim Iterieren wird der optionale Parameter blksize wiederholt an die Methode read() des Objekts filelike übergeben, um die Bytefolgen zu holen, die geliefert werden. Gibt read() eine leere Bytefolge zurück, endet das Iterieren und lässt sich nicht fortsetzen.

Hat filelike eine Methode close(), hat auch das zurückgegebene Objekt eine Methode close(), die beim Aufruf die Methode close() des Objekts filelike aufruft.

Beispiel für die Verwendung:

from io import StringIO
from wsgiref.util import FileWrapper

# We're using a StringIO-buffer for as the file-like object
filelike = StringIO("This is an example file-like object"*10)
wrapper = FileWrapper(filelike, blksize=5)

for chunk in wrapper:
    print(chunk)

Geändert in Version 3.11: Die Unterstützung für die Methode __getitem__() wurde entfernt.

wsgiref.headers – Werkzeuge für WSGI-Antwort-Header

Dieses Modul enthält eine einzige Klasse, Headers, mit der sich WSGI-Antwort-Header bequem über eine abbildungsähnliche Schnittstelle bearbeiten lassen.

class wsgiref.headers.Headers([headers])

Erzeugt ein abbildungsähnliches Objekt um headers. Das muss eine Liste von Tupeln aus Headernamen und -wert sein, wie in PEP 3333 beschrieben. Vorgabewert von headers ist eine leere Liste.

Headers-Objekte unterstützen die üblichen Abbildungsoperationen, darunter __getitem__(), get(), __setitem__(), setdefault(), __delitem__() und __contains__(). Bei all diesen Methoden ist der Schlüssel der Headername, ohne Beachtung der Groß- und Kleinschreibung, und der Wert der erste zu diesem Headernamen gehörende Wert. Einen Header zu setzen löscht dessen bisherige Werte und fügt dann am Ende der umhüllten Headerliste einen neuen Wert hinzu. Die bestehende Reihenfolge der Header bleibt im Großen und Ganzen erhalten, neue Header kommen ans Ende der umhüllten Liste.

Anders als ein Dictionary lösen Headers-Objekte keinen Fehler aus, wenn du einen Schlüssel holen oder löschen willst, der nicht in der umhüllten Headerliste steht. Ein nicht vorhandener Header kommt einfach als None zurück, und ihn zu löschen tut nichts.

Headers-Objekte unterstützen auch die Methoden keys(), values() und items(). Die von keys() und items() zurückgegebenen Listen können denselben Schlüssel mehrfach enthalten, wenn ein Header mehrere Werte hat. Das len() eines Headers-Objekts entspricht der Länge seiner items() und damit der Länge der umhüllten Headerliste. Die Methode items() gibt nämlich einfach eine Kopie der umhüllten Headerliste zurück.

bytes() auf ein Headers-Objekt angewandt gibt eine formatierte Bytefolge zurück, die sich als HTTP-Antwort-Header senden lässt. Jeder Header steht mit seinem Wert in einer Zeile, getrennt durch Doppelpunkt und Leerzeichen. Jede Zeile endet mit Wagenrücklauf und Zeilenvorschub, die Bytefolge endet mit einer Leerzeile.

Neben der Abbildungsschnittstelle und der Formatierung haben Headers-Objekte die folgenden Methoden, um Header mit mehreren Werten abzufragen und hinzuzufügen und um Header mit MIME-Parametern hinzuzufügen:

get_all(name)

Gibt eine Liste aller Werte des genannten Headers zurück.

Die zurückgegebene Liste ist in der Reihenfolge sortiert, in der die Werte in der ursprünglichen Headerliste standen oder dieser Instanz hinzugefügt wurden, und kann Doppelungen enthalten. Gelöschte und wieder eingefügte Felder kommen stets ans Ende der Headerliste. Gibt es keine Felder mit dem angegebenen Namen, kommt eine leere Liste zurück.

add_header(name, value, **_params)

Fügt einen Header hinzu, der auch mehrere Werte haben kann, mit MIME-Parametern nach Bedarf über Schlüsselwortargumente.

name ist das hinzuzufügende Headerfeld. Über Schlüsselwortargumente lassen sich MIME-Parameter für das Headerfeld setzen. Jeder Parameter muss eine Zeichenkette oder None sein. Unterstriche in Parameternamen werden zu Bindestrichen, denn Bindestriche sind in Python-Namen nicht erlaubt, viele MIME-Parameternamen enthalten aber welche. Ist der Wert des Parameters eine Zeichenkette, kommt er in der Form name="value" zu den Parametern des Headerwerts. Ist er None, wird nur der Parametername hinzugefügt; das dient MIME-Parametern ohne Wert. Beispiel für die Verwendung:

h.add_header('content-disposition', 'attachment', filename='bud.gif')

Das fügt einen Header hinzu, der so aussieht:

Content-Disposition: attachment; filename="bud.gif"

Geändert in Version 3.5: Der Parameter headers ist jetzt optional.

wsgiref.simple_server – ein einfacher WSGI-HTTP-Server

Dieses Modul enthält einen einfachen HTTP-Server auf der Grundlage von http.server, der WSGI-Anwendungen ausliefert. Jede Serverinstanz liefert eine einzelne WSGI-Anwendung auf einem bestimmten Host und Port aus. Willst du mehrere Anwendungen auf einem Host und Port anbieten, schreibe eine WSGI-Anwendung, die PATH_INFO auswertet und so für jede Anfrage die passende Anwendung aufruft, etwa mit der Funktion shift_path_info() aus wsgiref.util.

wsgiref.simple_server.make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler)

Erzeugt einen neuen WSGI-Server, der auf host und port lauscht und Verbindungen für app annimmt. Zurückgegeben wird eine Instanz der angegebenen server_class, die Anfragen mit der angegebenen handler_class verarbeitet. app muss ein WSGI-Anwendungsobjekt nach PEP 3333 sein.

Beispiel für die Verwendung:

from wsgiref.simple_server import make_server, demo_app

with make_server('', 8000, demo_app) as httpd:
    print("Serving HTTP on port 8000...")

    # Respond to requests until process is killed
    httpd.serve_forever()

    # Alternative: serve one request, then exit
    httpd.handle_request()
wsgiref.simple_server.demo_app(environ, start_response)

Diese Funktion ist eine kleine, aber vollständige WSGI-Anwendung. Sie gibt eine Textseite mit der Meldung „Hello world!“ und einer Liste der Schlüssel-Wert-Paare aus dem Parameter environ zurück. Damit lässt sich prüfen, ob ein WSGI-Server wie wsgiref.simple_server eine einfache WSGI-Anwendung richtig ausführt.

Das aufrufbare Objekt start_response sollte dem Protokoll StartResponse folgen.

class wsgiref.simple_server.WSGIServer(server_address, RequestHandlerClass)

Erzeugt eine Instanz von WSGIServer. server_address sollte ein Tupel (host,port) sein und RequestHandlerClass die Unterklasse von http.server.BaseHTTPRequestHandler, mit der Anfragen verarbeitet werden.

Diesen Konstruktor musst du normalerweise nicht aufrufen, denn die Funktion make_server() erledigt alle Einzelheiten für dich.

WSGIServer ist eine Unterklasse von http.server.HTTPServer, daher stehen alle deren Methoden zur Verfügung, etwa serve_forever() und handle_request(). Zusätzlich bietet WSGIServer diese WSGI-eigenen Methoden:

set_app(application)

Setzt das aufrufbare Objekt application als die WSGI-Anwendung, die die Anfragen erhält.

get_app()

Gibt das gerade gesetzte aufrufbare Anwendungsobjekt zurück.

Normalerweise brauchst du diese zusätzlichen Methoden allerdings nicht: set_app() ruft üblicherweise make_server() auf, und get_app() gibt es vor allem für die Instanzen der Anfragebehandlung.

class wsgiref.simple_server.WSGIRequestHandler(request, client_address, server)

Erzeugt einen HTTP-Handler für die gegebene request, also einen Socket, client_address, ein Tupel (host,port), und server, eine Instanz von WSGIServer.

Instanzen dieser Klasse musst du nicht selbst erzeugen; WSGIServer-Objekte erzeugen sie bei Bedarf von sich aus. Du kannst aber von dieser Klasse erben und sie der Funktion make_server() als handler_class übergeben. Einige Methoden, die in Unterklassen zu überschreiben lohnen kann:

get_environ()

Gibt für eine Anfrage ein Dictionary WSGIEnvironment zurück. Die Standardausführung kopiert den Inhalt des Dictionary-Attributs base_environ des WSGIServer-Objekts und fügt dann verschiedene Header aus der HTTP-Anfrage hinzu. Jeder Aufruf dieser Methode sollte ein neues Dictionary mit allen einschlägigen CGI-Umgebungsvariablen nach PEP 3333 zurückgeben.

get_stderr()

Gibt das Objekt zurück, das als Strom wsgi.errors dienen soll. Die Standardausführung gibt einfach sys.stderr zurück.

handle()

Verarbeitet die HTTP-Anfrage. Die Standardausführung erzeugt mit einer Klasse aus wsgiref.handlers eine Handler-Instanz, die die eigentliche WSGI-Anwendungsschnittstelle bereitstellt.

wsgiref.validate — Prüfung der WSGI-Konformität

Wenn du neue WSGI-Anwendungsobjekte, Frameworks, Server oder Middleware schreibst, kann es nützlich sein, den neuen Code mit wsgiref.validate auf Konformität zu prüfen. Dieses Modul bietet eine Funktion, die WSGI-Anwendungsobjekte erzeugt. Diese prüfen die Verständigung zwischen einem WSGI-Server oder -Gateway und einem WSGI-Anwendungsobjekt und damit beide Seiten auf Konformität mit dem Protokoll.

Beachte, dass dieses Hilfsmittel keine vollständige Konformität mit PEP 3333 garantiert. Bleiben Fehlermeldungen aus, heißt das nicht zwangsläufig, dass es keine Fehler gibt. Meldet dieses Modul allerdings einen Fehler, ist so gut wie sicher, dass entweder der Server oder die Anwendung nicht vollständig konform ist.

Dieses Modul beruht auf dem Modul paste.lint aus Ian Bickings Bibliothek „Python Paste“.

wsgiref.validate.validator(application)

Umhüllt application und gibt ein neues WSGI-Anwendungsobjekt zurück. Die zurückgegebene Anwendung leitet alle Anfragen an die ursprüngliche application weiter und prüft, ob sowohl application als auch der aufrufende Server der WSGI-Spezifikation und RFC 2616 entsprechen.

Jede festgestellte Abweichung löst AssertionError aus. Wie mit diesen Fehlern umgegangen wird, hängt allerdings vom Server ab. So geben wsgiref.simple_server und andere Server auf der Grundlage von wsgiref.handlers, die die Methoden zur Fehlerbehandlung nicht überschreiben, einfach eine Meldung über den Fehler aus und schreiben den Traceback nach sys.stderr oder in einen anderen Fehlerstrom.

Diese Hülle kann über das Modul warnings auch Ausgaben erzeugen, um auf fragwürdiges Verhalten hinzuweisen, das PEP 3333 möglicherweise gar nicht verbietet. Solche Warnungen gehen nach sys.stderr – nicht nach wsgi.errors, es sei denn, beides ist dasselbe Objekt –, sofern sie nicht über Befehlszeilenoptionen von Python oder über die API von warnings unterdrückt werden.

Beispiel für die Verwendung:

from wsgiref.validate import validator
from wsgiref.simple_server import make_server

# Our callable object which is intentionally not compliant to the
# standard, so the validator is going to break
def simple_app(environ, start_response):
    status = '200 OK'  # HTTP Status
    headers = [('Content-type', 'text/plain')]  # HTTP Headers
    start_response(status, headers)

    # This is going to break because we need to return a list, and
    # the validator is going to inform us
    return b"Hello World"

# This is the application wrapped in a validator
validator_app = validator(simple_app)

with make_server('', 8000, validator_app) as httpd:
    print("Listening on port 8000....")
    httpd.serve_forever()

wsgiref.handlers – Basisklassen für Server und Gateways

Dieses Modul bietet Basisklassen für die Behandlung von Anfragen, mit denen sich WSGI-Server und -Gateways schreiben lassen. Diese Basisklassen übernehmen die meiste Arbeit der Verständigung mit einer WSGI-Anwendung, solange sie eine CGI-ähnliche Umgebung sowie Ströme für Eingabe, Ausgabe und Fehler erhalten.

class wsgiref.handlers.CGIHandler

Aufruf über CGI mittels sys.stdin, sys.stdout, sys.stderr und os.environ. Das ist nützlich, wenn du eine WSGI-Anwendung als CGI-Skript laufen lassen willst. Rufe einfach CGIHandler().run(app) auf, wobei app das aufzurufende WSGI-Anwendungsobjekt ist.

Diese Klasse ist eine Unterklasse von BaseCGIHandler. Sie setzt wsgi.run_once auf wahr, wsgi.multithread auf falsch und wsgi.multiprocess auf wahr und holt die nötigen CGI-Ströme und die Umgebung immer über sys und os.

class wsgiref.handlers.IISCGIHandler

Eine besondere Alternative zu CGIHandler für den Einsatz auf dem Webserver IIS von Microsoft, wenn die Konfigurationsoption allowPathInfo (IIS>=7) oder der Metabase-Eintrag allowPathInfoForScriptMappings (IIS<7) nicht gesetzt ist.

Standardmäßig liefert IIS ein PATH_INFO, das SCRIPT_NAME vorne doppelt enthält. Das macht WSGI-Anwendungen Schwierigkeiten, die Routing umsetzen wollen. Dieser Handler entfernt einen so gedoppelten Pfad.

IIS lässt sich so einstellen, dass es das richtige PATH_INFO übergibt, doch dann greift ein anderer Fehler, bei dem PATH_TRANSLATED falsch ist. Zum Glück wird diese Variable selten verwendet und von WSGI nicht garantiert. Bei IIS<7 lässt sich die Einstellung allerdings nur auf vhost-Ebene vornehmen und betrifft damit alle anderen Skriptzuordnungen, von denen viele am Fehler mit PATH_TRANSLATED scheitern. Deshalb wird IIS<7 so gut wie nie mit dieser Korrektur betrieben. Selbst IIS7 nutzt sie selten, weil es immer noch keine Oberfläche dafür gibt.

CGI-Code kann nicht feststellen, ob die Option gesetzt wurde, daher gibt es eine eigene Handler-Klasse. Sie wird wie CGIHandler verwendet, also mit dem Aufruf IISCGIHandler().run(app), wobei app das aufzurufende WSGI-Anwendungsobjekt ist.

Added in version 3.2.

class wsgiref.handlers.BaseCGIHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)

Ähnlich wie CGIHandler, doch statt über die Module sys und os werden die CGI-Umgebung und die Ein- und Ausgabeströme ausdrücklich angegeben. Die Werte multithread und multiprocess setzen die Flags wsgi.multithread und wsgi.multiprocess für alle Anwendungen, die die Handler-Instanz ausführt.

Diese Klasse ist eine Unterklasse von SimpleHandler und für Software gedacht, die kein HTTP-„Origin-Server“ ist. Schreibst du die Umsetzung eines Gateway-Protokolls wie CGI, FastCGI oder SCGI, das den HTTP-Status über einen Header Status: sendet, willst du wahrscheinlich von dieser Klasse erben und nicht von SimpleHandler.

class wsgiref.handlers.SimpleHandler(stdin, stdout, stderr, environ, multithread=True, multiprocess=False)

Ähnlich wie BaseCGIHandler, aber für HTTP-Origin-Server gedacht. Schreibst du einen HTTP-Server, willst du wahrscheinlich von dieser Klasse erben und nicht von BaseCGIHandler.

Diese Klasse ist eine Unterklasse von BaseHandler. Sie überschreibt die Methoden __init__(), get_stdin(), get_stderr(), add_cgi_vars(), _write() und _flush(), damit sich Umgebung und Ströme ausdrücklich über den Konstruktor setzen lassen. Die übergebene Umgebung und die Ströme liegen in den Attributen stdin, stdout, stderr und environ.

Die Methode write() von stdout sollte jeden Block vollständig schreiben, so wie io.BufferedIOBase.

class wsgiref.handlers.BaseHandler

Das ist eine abstrakte Basisklasse, um WSGI-Anwendungen auszuführen. Jede Instanz bearbeitet eine einzelne HTTP-Anfrage, auch wenn man grundsätzlich eine Unterklasse schreiben könnte, die sich für mehrere Anfragen wiederverwenden lässt.

BaseHandler-Instanzen haben nur eine Methode, die für die Verwendung von außen gedacht ist:

run(app)

Führt die angegebene WSGI-Anwendung app aus.

Alle anderen Methoden von BaseHandler ruft diese Methode beim Ausführen der Anwendung auf. Sie gibt es daher vor allem, damit sich der Ablauf anpassen lässt.

Die folgenden Methoden MÜSSEN in einer Unterklasse überschrieben werden:

_write(data)

Puffert die Bytes data für die Übertragung zum Client. Es ist in Ordnung, wenn diese Methode die Daten gleich überträgt. BaseHandler trennt Schreiben und Leeren nur, damit es zügiger geht, wenn das zugrundeliegende System diesen Unterschied tatsächlich kennt.

_flush()

Erzwingt, dass gepufferte Daten zum Client übertragen werden. Es ist in Ordnung, wenn diese Methode nichts tut, also wenn _write() die Daten bereits sendet.

get_stdin()

Gibt ein zu InputStream passendes Objekt zurück, das sich als wsgi.input der gerade verarbeiteten Anfrage eignet.

get_stderr()

Gibt ein zu ErrorStream passendes Objekt zurück, das sich als wsgi.errors der gerade verarbeiteten Anfrage eignet.

add_cgi_vars()

Trägt die CGI-Variablen der aktuellen Anfrage in das Attribut environ ein.

Hier sind weitere Methoden und Attribute, die du überschreiben möchtest. Diese Liste ist allerdings nur ein Überblick und nennt nicht jede überschreibbare Methode. Bevor du eine eigene Unterklasse von BaseHandler schreibst, solltest du die Docstrings und den Quellcode zu Rate ziehen.

Attribute und Methoden, um die WSGI-Umgebung anzupassen:

wsgi_multithread

Der Wert für die Umgebungsvariable wsgi.multithread. In BaseHandler ist er standardmäßig wahr, in den anderen Unterklassen kann die Vorgabe abweichen oder der Konstruktor den Wert setzen.

wsgi_multiprocess

Der Wert für die Umgebungsvariable wsgi.multiprocess. In BaseHandler ist er standardmäßig wahr, in den anderen Unterklassen kann die Vorgabe abweichen oder der Konstruktor den Wert setzen.

wsgi_run_once

Der Wert für die Umgebungsvariable wsgi.run_once. In BaseHandler ist er standardmäßig falsch, CGIHandler setzt ihn jedoch standardmäßig auf wahr.

os_environ

Die Umgebungsvariablen, die standardmäßig in der WSGI-Umgebung jeder Anfrage enthalten sind. Standardmäßig ist das eine Kopie von os.environ zum Zeitpunkt des Imports von wsgiref.handlers; Unterklassen können aber auf Klassen- oder Instanzebene eigene anlegen. Beachte, dass das Dictionary als nur lesbar zu betrachten ist, denn mehrere Klassen und Instanzen teilen sich den Vorgabewert.

server_software

Ist das Attribut origin_server gesetzt, dient der Wert dieses Attributs dazu, die WSGI-Umgebungsvariable SERVER_SOFTWARE vorzubelegen und in HTTP-Antworten einen Header Server: zu setzen. Bei Handlern, die keine HTTP-Origin-Server sind, etwa BaseCGIHandler und CGIHandler, bleibt es außer Betracht.

Geändert in Version 3.3: Der Begriff „Python“ wird durch einen Begriff der jeweiligen Implementierung ersetzt, etwa „CPython“ oder „Jython“.

get_scheme()

Gibt das URL-Schema der aktuellen Anfrage zurück. Die Standardausführung schätzt mit der Funktion guess_scheme() aus wsgiref.util anhand der environ-Variablen der aktuellen Anfrage, ob das Schema „http“ oder „https“ sein sollte.

setup_environ()

Setzt das Attribut environ auf eine vollständig gefüllte WSGI-Umgebung. Die Standardausführung verwendet dazu alle obigen Methoden und Attribute sowie die Methoden get_stdin(), get_stderr() und add_cgi_vars() und das Attribut wsgi_file_wrapper. Sie trägt außerdem den Schlüssel SERVER_SOFTWARE ein, falls er fehlt, solange das Attribut origin_server wahr und das Attribut server_software gesetzt ist.

Methoden und Attribute, um die Behandlung von Ausnahmen anzupassen:

log_exception(exc_info)

Schreibt das Tupel exc_info ins Serverprotokoll. exc_info ist ein Tupel (type, value, traceback). Die Standardausführung schreibt den Traceback einfach in den Strom wsgi.errors der Anfrage und leert diesen. Unterklassen können diese Methode überschreiben, um das Format zu ändern, die Ausgabe umzuleiten, den Traceback an eine Administratorin zu mailen oder was auch immer sinnvoll erscheint.

traceback_limit

Die größte Anzahl an Rahmen in den Tracebacks, die die Standardmethode log_exception() ausgibt. Bei None sind alle Rahmen enthalten.

error_output(environ, start_response)

Diese Methode ist eine WSGI-Anwendung, die eine Fehlerseite für den Benutzer erzeugt. Sie wird nur aufgerufen, wenn ein Fehler auftritt, bevor Header an den Client gesendet wurden.

Diese Methode kommt mit sys.exception() an den aktuellen Fehler und sollte diese Information beim Aufruf an start_response übergeben, wie im Abschnitt „Error Handling“ von PEP 3333 beschrieben. Insbesondere sollte das aufrufbare Objekt start_response dem Protokoll StartResponse folgen.

Die Standardausführung erzeugt die Ausgabeseite einfach aus den Attributen error_status, error_headers und error_body. Unterklassen können das überschreiben, um die Fehlerausgabe dynamischer zu gestalten.

Beachte allerdings, dass es aus Sicherheitssicht nicht empfehlenswert ist, jedem beliebigen Benutzer Diagnoseausgaben vorzusetzen. Im Idealfall muss man etwas Besonderes tun, um Diagnoseausgaben einzuschalten. Darum enthält die Standardausführung keine.

error_status

Der HTTP-Status für Fehlerantworten. Das sollte eine Statuszeichenkette nach PEP 3333 sein. Standardmäßig ist es Code 500 mit passender Meldung.

error_headers

Die HTTP-Header für Fehlerantworten. Das sollte eine Liste von WSGI-Antwort-Headern sein, also Tupel (name, value), wie in PEP 3333 beschrieben. Die Standardliste setzt nur den Inhaltstyp auf text/plain.

error_body

Der Körper der Fehlerantwort. Das sollte eine Bytefolge für einen HTTP-Antwortkörper sein. Standardmäßig ist es der einfache Text „A server error occurred. Please contact the administrator.“

Methoden und Attribute für das Feature „Optional Platform-Specific File Handling“ aus PEP 3333:

wsgi_file_wrapper

Eine Fabrik für wsgi.file_wrapper, passend zu wsgiref.types.FileWrapper, oder None. Vorgabewert dieses Attributs ist die Klasse wsgiref.util.FileWrapper.

sendfile()

Überschreibe diese Methode, um Dateien plattformeigen zu übertragen. Sie wird nur aufgerufen, wenn der Rückgabewert der Anwendung eine Instanz der Klasse ist, die das Attribut wsgi_file_wrapper angibt. Sie sollte einen wahren Wert zurückgeben, wenn sie die Datei erfolgreich übertragen hat, damit der Standardcode zur Übertragung nicht läuft. Die Standardausführung dieser Methode gibt einfach einen falschen Wert zurück.

Verschiedene weitere Methoden und Attribute:

origin_server

Dieses Attribut sollte wahr sein, wenn _write() und _flush() des Handlers unmittelbar mit dem Client verkehren und nicht über ein CGI-ähnliches Gateway-Protokoll, das den HTTP-Status in einem besonderen Header Status: erwartet.

Der Vorgabewert dieses Attributs ist in BaseHandler wahr, in BaseCGIHandler und CGIHandler falsch.

http_version

Ist origin_server wahr, legt dieses Zeichenketten-Attribut die HTTP-Version der an den Client gesendeten Antwort fest. Vorgabe ist "1.0".

wsgiref.handlers.read_environ()

Wandelt CGI-Variablen aus os.environ in „bytes in unicode“-Zeichenketten nach PEP 3333 um und gibt ein neues Dictionary zurück. CGIHandler und IISCGIHandler verwenden diese Funktion, statt os.environ unmittelbar zu nutzen, denn das ist unter Python 3 nicht auf allen Plattformen und Webservern zwangsläufig WSGI-konform: nämlich dort, wo die eigentliche Umgebung des Betriebssystems Unicode ist, also unter Windows, oder wo die Umgebung aus Bytes besteht, Python sie aber mit einer anderen Systemkodierung als ISO-8859-1 dekodiert, etwa auf Unix-Systemen mit UTF-8.

Schreibst du einen eigenen CGI-Handler, willst du wahrscheinlich diese Routine verwenden, statt Werte unmittelbar aus os.environ zu kopieren.

Added in version 3.2.

wsgiref.types – WSGI-Typen für die statische Typprüfung

Dieses Modul bietet verschiedene Typen für die statische Typprüfung, wie in PEP 3333 beschrieben.

Added in version 3.11.

class wsgiref.types.StartResponse

Ein typing.Protocol, das aufrufbare Objekte start_response() beschreibt (PEP 3333).

wsgiref.types.WSGIEnvironment

Ein Typalias, der ein Dictionary für eine WSGI-Umgebung beschreibt.

wsgiref.types.WSGIApplication

Ein Typalias, der ein aufrufbares WSGI-Anwendungsobjekt beschreibt.

class wsgiref.types.InputStream

Ein typing.Protocol, das einen WSGI-Eingabestrom beschreibt.

class wsgiref.types.ErrorStream

Ein typing.Protocol, das einen WSGI-Fehlerstrom beschreibt.

class wsgiref.types.FileWrapper

Ein typing.Protocol, das eine Dateihülle beschreibt. Eine konkrete Umsetzung dieses Protokolls ist wsgiref.util.FileWrapper.

Beispiele

Das ist eine funktionierende „Hello World“-WSGI-Anwendung. Das aufrufbare Objekt start_response sollte dem Protokoll StartResponse folgen:

"""
Every WSGI application must have an application object - a callable
object that accepts two arguments. For that purpose, we're going to
use a function (note that you're not limited to a function, you can
use a class for example). The first argument passed to the function
is a dictionary containing CGI-style environment variables and the
second variable is the callable object.
"""
from wsgiref.simple_server import make_server


def hello_world_app(environ, start_response):
    status = "200 OK"  # HTTP Status
    headers = [("Content-type", "text/plain; charset=utf-8")]  # HTTP Headers
    start_response(status, headers)

    # The returned object is going to be printed
    return [b"Hello World"]

with make_server("", 8000, hello_world_app) as httpd:
    print("Serving on port 8000...")

    # Serve until process is killed
    httpd.serve_forever()

Beispiel für eine WSGI-Anwendung, die das aktuelle Verzeichnis ausliefert und auf der Befehlszeile nach Bedarf ein Verzeichnis und eine Portnummer annimmt (Vorgabe: 8000):

"""
Small wsgiref based web server. Takes a path to serve from and an
optional port number (defaults to 8000), then tries to serve files.
MIME types are guessed from the file names, 404 errors are raised
if the file is not found.
"""
import mimetypes
import os
import sys
from wsgiref import simple_server, util


def app(environ, respond):
    # Get the file name and MIME type
    fn = os.path.join(path, environ["PATH_INFO"][1:])
    if "." not in fn.split(os.path.sep)[-1]:
        fn = os.path.join(fn, "index.html")
    mime_type = mimetypes.guess_file_type(fn)[0]

    # Return 200 OK if file exists, otherwise 404 Not Found
    if os.path.exists(fn):
        respond("200 OK", [("Content-Type", mime_type)])
        return util.FileWrapper(open(fn, "rb"))
    else:
        respond("404 Not Found", [("Content-Type", "text/plain")])
        return [b"not found"]


if __name__ == "__main__":
    # Get the path and port from command-line arguments
    path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 8000

    # Make and start the server until control-c
    httpd = simple_server.make_server("", port, app)
    print(f"Serving {path} on port {port}, control-C to stop")
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("Shutting down.")
        httpd.server_close()