|
NAMEPSGI - Perl Web Server Gateway Interface SpecificationABSTRACTThis document specifies a standard interface between web servers and Perl web applications or frameworks. This interface is designed to promote web application portability and reduce the duplication of effort by web application framework developers.Please keep in mind that PSGI is not Yet Another web application framework. PSGI is a specification to decouple web server environments from web application framework code. Nor is PSGI a web application API. Web application developers (end users) will not run their web applications directly using the PSGI interface, but instead are encouraged to use frameworks that support PSGI. TERMINOLOGY
SPECIFICATIONApplicationA PSGI application is a Perl code reference. It takes exactly one argument, the environment, and returns an array reference containing exactly three values.my $app = sub { my $env = shift; return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World" ], # or IO::Handle-like object ]; }; The Environment The environment MUST be a hash reference that includes CGI-like headers, as detailed below. The application is free to modify the environment. The environment MUST include these keys (adopted from PEP 333 <http://www.python.org/dev/peps/pep-0333/>, Rack <http://rack.rubyforge.org/doc/files/SPEC.html> and JSGI <http://jackjs.org/jsgi-spec.html>) except when they would normally be empty. When an environment key is described as a boolean, its value MUST conform to Perl's notion of boolean-ness. This means that an empty string or an explicit 0 are both valid false values. If a boolean key is not present, an application MAY treat this as a false value. The values for all CGI keys (named without a period) MUST be a scalar string. See below for details.
A server should attempt to provide as many other CGI variables as are applicable. Note, however, that an application that uses any CGI variables other than the ones listed above are necessarily non-portable to web servers that do not support the relevant extensions. In addition to the keys above, the PSGI environment MUST also include these PSGI-specific keys:
The server or the application can store its own data in the environment as well. These keys MUST contain at least one dot, and SHOULD be prefixed uniquely. The "psgi." prefix is reserved for use with the PSGI core specification, and "psgix." prefix is reserved for officially blessed extensions. These prefixes MUST NOT be used by other servers or application. See psgi-extensions for the list of officially approved extensions. The environment MUST NOT contain keys named "HTTP_CONTENT_TYPE" or "HTTP_CONTENT_LENGTH". One of "SCRIPT_NAME" or "PATH_INFO" MUST be set. When "REQUEST_URI" is "/", "PATH_INFO" should be "/" and "SCRIPT_NAME" should be empty. "SCRIPT_NAME" MUST NOT be "/", but MAY be empty. The Input Stream The input stream in "psgi.input" is an IO::Handle-like object which streams the raw HTTP POST or PUT data. If it is a file handle then it MUST be opened in binary mode. The input stream MUST respond to "read" and MAY implement "seek". Perl's built-in filehandles or IO::Handle based objects should work as-is in a PSGI server. Application developers SHOULD NOT inspect the type or class of the stream. Instead, they SHOULD simply call "read" on the object. Application developers SHOULD NOT use Perl's built-in "read" or iterator ("<$fh>") to read from the input stream. Instead, application developers should call "read" as a method ("$fh->read") to allow for duck typing. Framework developers, if they know the input stream will be used with the built-in read() in any upstream code they can't touch, SHOULD use PerlIO or a tied handle to work around with this problem. The input stream object is expected to provide a "read" method:
It may also implement an optional "seek" method. If "psgix.input.buffered" environment is true, it MUST implement the "seek" method.
See the IO::Handle documentation for more details on exactly how these methods should work. The Error Stream The error stream in "psgi.errors" is an IO::Handle-like object to print errors. The error stream must implement a "print" method. As with the input stream, Perl's built-in filehandles or IO::Handle based objects should work as-is in a PSGI server. Application developers SHOULD NOT inspect the type or class of the stream. Instead, they SHOULD simply call "print" on the object.
The Response Applications MUST return a response as either a three element array reference, or a code reference for a delayed/streaming response. The response array reference consists of the following elements: Status An HTTP status code. This MUST be an integer greater than or equal to 100, and SHOULD be an HTTP status code as documented in RFC 2616 <http://www.w3.org/Protocols/rfc2616>. Headers The headers MUST be an array reference (not a hash reference) of key/value pairs. This means it MUST contain an even number of elements. The header MUST NOT contain a key named "Status", nor any keys with ":" or newlines in their name. It MUST NOT contain any keys that end in "-" or "_". All keys MUST consist only of letters, digits, "_" or "-". All keys MUST start with a letter. The value of the header MUST be a scalar string and defined. The value string MUST NOT contain characters below octal 037 i.e. chr(31). If the same key name appears multiple times in an array ref, those header lines MUST be sent to the client separately (e.g. multiple "Set-Cookie" lines). Content-Type There MUST be a "Content-Type" except when the "Status" is 1xx, 204 or 304, in which case there MUST NOT be a content type. Content-Length There MUST NOT be a "Content-Length" header when the "Status" is 1xx, 204 or 304. If the Status is not 1xx, 204 or 304 and there is no "Content-Length" header, a PSGI server MAY calculate the content length by looking at the Body. This value can then be appended to the list of headers returned by the application. Body The response body MUST be returned from the application as either an array reference or a handle containing the response body as byte strings. The body MUST be encoded into appropriate encodings and MUST NOT contain wide characters (> 255).
Delayed Response and Streaming BodyThe PSGI interface allows applications and servers to provide a callback-style response instead of the three-element array reference. This allows for a delayed response and a streaming body (server push).This interface SHOULD be implemented by PSGI servers, and "psgi.streaming" environment MUST be set to true in such servers. To enable a delayed response, the application SHOULD return a callback as its response. An application MAY check if the "psgi.streaming" environment is true and falls back to the direct response if it isn't. This callback will be called with another subroutine reference (referred to as the responder from now on) as its only argument. The responder should in turn be called with the standard three element array reference response. This is best illustrated with an example: my $app = sub { my $env = shift; # Delays response until it fetches content from the network return sub { my $responder = shift; fetch_content_from_server(sub { my $content = shift; $responder->([ 200, $headers, [ $content ] ]); }); }; }; An application MAY omit the third element (the body) when calling the responder. If the body is omitted, the responder MUST return yet another object which implements "write" and "close" methods. Again, an example illustrates this best. my $app = sub { my $env = shift; # immediately starts the response and stream the content return sub { my $responder = shift; my $writer = $responder->( [ 200, [ 'Content-Type', 'application/json' ]]); wait_for_events(sub { my $new_event = shift; if ($new_event) { $writer->write($new_event->as_json . "\n"); } else { $writer->close; } }); }; }; This delayed response and streaming API is useful if you want to implement a non-blocking I/O based server streaming or long-poll Comet push technology, but could also be used to implement unbuffered writes in a blocking server. MiddlewareA middleware component takes another PSGI application and runs it. From the perspective of a server, a middleware component is a PSGI application. From the perspective of the application being run by the middleware component, the middleware is the server. Generally, this will be done in order to implement some sort of pre-processing on the PSGI environment hash or post-processing on the response.Here's a simple example that appends a special HTTP header X-PSGI-Used to any PSGI application. # $app is a simple PSGI application my $app = sub { my $env = shift; return [ '200', [ 'Content-Type' => 'text/plain' ], [ "Hello World" ] ]; }; # $xheader is a piece of middleware that wraps $app my $xheader = sub { my $env = shift; my $res = $app->($env); push @{$res->[1]}, 'X-PSGI-Used' => 1; return $res; }; Middleware MUST behave exactly like a PSGI application from the perspective of a server. Middleware MAY decide not to support the streaming interface discussed earlier, but SHOULD pass through the response types that it doesn't understand. CHANGELOGS1.1: 2010.02.xx
ACKNOWLEDGEMENTSSome parts of this specification are adopted from the following specifications.
I'd like to thank authors of these great documents. AUTHORTatsuhiko Miyagawa <miyagawa@bulknews.net>CONTRIBUTORSThe following people have contributed to the PSGI specification and Plack implementation by commiting their code, sending patches, reporting bugs, asking questions, suggesting useful advices, nitpicking, chatting on IRC or commenting on my blog (in no particular order):Tokuhiro Matsuno Kazuhiro Osawa Yuval Kogman Kazuho Oku Alexis Sukrieh Takatoshi Kitano Stevan Little Daisuke Murase mala Pedro Melo Jesse Luehrs John Beppu Shawn M Moore Mark Stosberg Matt S Trout Jesse Vincent Chia-liang Kao Dave Rolsky Hans Dieter Pearcey Randy J Ray Benjamin Trott Max Maischein Slaven Rezić Marcel Grünauer Masayoshi Sekimura Brock Wilcox Piers Cawley Daisuke Maki Kang-min Liu Yasuhiro Matsumoto Ash Berlin Artur Bergman Simon Cozens Scott McWhirter Jiro Nishiguchi Masahiro Chiba Patrick Donelan Paul Driver Florian Ragwitz COPYRIGHT AND LICENSECopyright Tatsuhiko Miyagawa, 2009-2011.This document is licensed under the Creative Commons license by-sa.
Visit the GSP FreeBSD Man Page Interface. |