NAME
PSGI::FAQ - Frequently Asked Questions and answers
QUESTIONS
General
How do you pronounce PSGI?
We read it simply P-S-G-I, but you may be able to pronounce it "sky" :)
So what is this?
PSGI is an interface between web servers and perl-based web applications akin to what CGI does for web servers and CGI scripts.
Why do we need this?
Perl has CGI as a core module that somewhat abstracts the difference between CGI, mod_perl and FastCGI. However, most web application framework developers (e.g. Catalyst and Jifty) usually avoid using it to maximize the performance and to access low-level APIs. So they end up writing adapters for all of those different environments, some of which may be well tested while others are not.
PSGI allows web application framework developers to only write an adapter for PSGI. End users can choose from among all the backends that support the PSGI interface.
You said PSGI is similar to CGI. How is the PSGI interaface different from CGI?
The PSGI interface is intentionally designed to be very similar to CGI so that supporting PSGI in addition to CGI would be extremely easy. Here's a highlight of the key differences between CGI and PSGI:
In CGI, servers are the actual web servers written in any languages but mostly in C, and script is a script that can be written in any language such as C, Perl, Shell scripts, Ruby or Python.
In PSGI, servers are still web servers, but they're perl processes that are usually embedded in the web server (like mod_perl) or a perl daemon process called by a web server (like FastCGI), or an entirely perl based web server.
In CGI, we use STDIN, STDERR, and environment variables to read parameters and the HTTP request body and to send errors from the application.
In PSGI, we use the
$env
hash references and the psgi.input and psgi.errors streams to pass that data between servers and applications.In CGI, applications are supposed to print HTTP headers and body to STDOUT to pass it back to the web server.
In PSGI, applications are supposed to return a HTTP status code, headers, and body (as an array ref or a filehandle-like object) to the application as an array reference.
My framework already does CGI, FCGI and mod_perl. Why do I want to support PSGI?
If your web application framework already supports most server environments, performance is good, and the backends are well tested, there may not be a direct benefit for you to support PSGI immediately -- though you would be able to remove any code that overlaps with PSGI backends. But if only CGI environment is currently supported, supporting PSGI in addition should be extremely easy, and the benefit you and your framework users will enjoy is huge.
I'm writing a web application. What's the benefit of PSGI for me?
If the framework you're using supports PSGI, that means your application can run on any of existing and future PSGI implementations.
if you provide a .psgi
file that returns PSGI application, the end users of your application should be able to configure and run your application in a bunch of different ways.
What should I do to support PSGI?
If you're a web server developer, write a PSGI implementation that calls a PSGI application. Or join the development on Plack, the reference implementation of PSGI, to add backends for more web servers.
If you're a web application framework developer, write an adapter for PSGI. Now you're freed from supporting all different server environments.
If you're a web application developer (or a web application framework user), choose the framework that supports PSGI, or ask the author to support it. :) If your application is a large scale installable application that doesn't use any existing frameworks (e.g. WebGUI or Movable Type) you're considered as a framework developer instead from the PSGI point of view. So, writing an adapter for PSGI on your application would make more sense.
Is PSGI faster than (my framework)?
Again, PSGI is not an implementation, but there's a potential for a very fast PSGI implementation that preloads everything and runs fully optimized code as a preforked standalone with XS parsers and sendfile(2) kernel call, an event-based tiny web server written in C and embedded perl that supports PSGI, or a plain-old CGI.pm based backend that doesn't load any modules at all and runs pretty quickly without eating so much memory under the CGI environment.
The reference implementation Plack already has very fast backends like Standalone::Prefork and Coro.
Users of your framework can choose which backend is the best for their needs. You, as a web application framework developer, don't need to think about lots of different users with different needs.
Plack
What is Plack? What is the difference between PSGI and Plack?
PSGI is a specification, so there's no software or module called PSGI. End users will need to choose one of PSGI server implementations to run PSGI applications on. Plack is a reference PSGI implementation that supports environments like prefork standalone server, CGI, FastCGI, mod_perl, AnyEvent and Coro.
Plack also has useful APIs and helpers on top of PSGI, such as Plack::Request to provide a nice object-oriented API on request objects, plackup that allows you to run an PSGI application from the command line and configure it using app.psgi
(a la Rack's Rackup), and Plack::Test that allows you to test your application using standard HTTP::Request and HTTP::Response pair through mocked HTTP or live HTTP servers. See Plack for details.
What kind of server backends would be available?
In Plack, we already support most web servers like Apache2, and also the ones that supports standard CGI or FastCGI, but also want to support special web servers that can embed perl, like nginx. We think it would be really nice if Apache module mod_perlite and Google AppEngine supported PSGI too, so that you could run your PSGI/Plack based perl app in the cloud.
Ruby is Rack and JavaScript is Jack. Why is it not called Pack?
Well Pack indeed is a cute name, but Perl has a built-in function pack so it's a little confusing, especially when speaking instead of writing.
What namespaces should I use to implement PSGI support?
Do not use the PSGI:: namespace to implement PSGI backends or adapters.
The PSGI namespace is reserved for PSGI specifications and reference unit tests that implementors have to pass. It should not be used by particular implementations.
If you write a plugin or an extension to support PSGI for an (imaginary) web application framework called Camper
, name the code such as Camper::Engine::PSGI
. If you write a PSGI backend that runs on an imaginary pure perl web server called mightyd
, name it such as Mightyd::Handler::PSGI
or consider contributing the code to Plack project as Plack::Server::Mightyd
(so that you don't need to worry about how to run/load PSGI applications).
I have a CGI or mod_perl application that I want to run on PSGI/Plack. What should I do?
You have several choices:
- CGI::PSGI
-
If you have a web application (or framework) that uses CGI.pm to handle query parameters, CGI::PSGI can help you migrate to PSGI. You'll need to change how you create CGI objects and how to return the response headers and body, but the rest of your code will work unchanged.
- CGI::Emulate::PSGI
-
If you have a dead old CGI script that you want to change as little as possible (or even no change at all, by running it with
do
), then CGI::Emulate::PSGI can wrap it up as a PSGI application. Compared to CGI::PSGI, this is less efficient, but should work with any CGI implementation, not just CGI.pm. - Plack::Request and Plack::Response
-
If you have an HTTP::Engine based application (framework), or want to write an app from scratch and need a better interface than CGI, or you're used to Apache::Request, then Plack::Request and Plack::Response might be what you want. It gives you a nice Request/Response object API on top of the PSGI env hash and response array.
NOTE: Don't forget that whenever you have a CGI script that runs once and exits, and you turn it into a persistent process, it may have cleanup that needs to happen after every request -- variables that need to be reset, files that need to be closed or deleted, etc. PSGI can do nothing about that (you have to fix it) except give you this friendly reminder.
HTTP::Engine
Why PSGI/Plack instead of HTTP::Engine?
HTTP::Engine was a great experiment, but it mixed the application interface (the request_handler
interface) with implementations, and the monolithic class hierarchy and role based interfaces make it really hard to write a new backend. We kept the existing HTTP::Engine and broke it into three parts: The interface specification (PSGI), Reference server implementations (Plack::Server) and Standard APIs and Tools (Plack).
Will HTTP::Engine be dead?
It won't be dead. HTTP::Engine will stay as it is and still be useful if you want to write a micro webserver application rather than a framework.
Do I have to rewrite my HTTP::Engine application to follow PSGI interface?
No, you don't need to rewrite your existing HTTP::Engine application. It can be easily turned into a PSGI application using HTTP::Engine::Interface::PSGI.
Alternatively, you can use Plack::Request and Plack::Response which gives compatible APIs to HTTP::Engine::Request and HTTP::Engine::Response:
use Plack::Request;
use Plack::Response;
sub request_handler {
my $req = Plack::Request->new(shift);
my $res = Plack::Response->new;
# ...
return $res->finalize;
}
And this request_handler
is a PSGI application now.
What's the benefit of converting my HTTP::Engine app to run on PSGI?
As of today most web server implementations and middlewares implemented by Plack are mostly available on HTTP::Engine as well, so there might not be direct immediate benefit of switching to PSGI. But PSGI is more future proof, and there are high hope that in the near future we'll have a pretty fast server environments (think of Passenger for Ruby Rack) and/or plenty of useful middlewares that HTTP::Engine doesn't have today.
See the question My framework already does CGI, FCGI and mod_perl. Why do I want to support PSGI? for more details.
API Design
Keep in mind that most design choices made in the PSGI spec are to minimize the requirements on backends so they can optimize things. Adding a fancy interface or allowing flexibility in the PSGI layers might sound catchy to end users, but it would just add things that backends have to support, which would end up getting in the way of optimizations, or introducing more bugs. What makes a fancy API to attract web application developers is your framework, not PSGI.
Why a big env hash instead of objects with APIs?
The simplicity of the interface is the key that made WSGI and Rack successful. PSGI is a low-level interface between backends and web application framework developers. If we define an API on what type of objects should be passed and which method they need to implement, there will be so much duplicated code in the backends, some of which may be buggy.
For instance, PSGI defines $env->{REMOTE_ADDR}
as a string. What if the PSGI spec required it to be an instance of Net::IP? Backend code would have to depend on the Net::IP module, or have to write a mock object that implements ALL of Net::IP's methods. Backends depending on specific modules or having to reinvent lots of stuff is considered harmful and that's why the interface is as minimal as possible.
Making a nice API for the end users is a job that web application frameworks (adapter developers) should do, not something PSGI needs to define.
Why is the application a code ref rather than an object with a ->call method?
Requiring an object in addition to a code ref would make EVERY backend's code a few lines more tedious, while requiring an object instead of a code ref would make application developers write another class and instanciate an object.
In other words, yes an object with a call
method could work, but again PSGI was designed to be as simple as possible, and making a code reference out of class/object is no brainer but the other way round always requires a few lines of code and possibly a new file.
Why are the headers returned as an array ref and not a hash ref?
Short: In order to support multiple headers (e.g. Set-Cookie
).
Long: In Python WSGI, the response header is a list of (header_name
, header_value
) tuples i.e. type(response_headers) is ListType
so there can be multiple entries for the same header key. In Rack and JSGI, a header value is a String consisting of lines separated by "\n
".
We liked Python's specification here, and since Perl hashes don't allow multiple entries with the same key (unless it's tie
d), using an array reference to store [ key => value, key => value ]
is the simplest solution to keep both framework adapters and backends simple. Other options, like allowing an array ref in addition to a plain scalar, make either side of the code unnecessarily tedious.
Note that I'm talking about multiple header lines with the same key, and NOT about multiple header values (e.g. Accept: text/html, text/plain, *
). Joining the header values with ,
is obviously the application's job. HTTP::Headers does exactly that when it's passed an array reference as a header value, for instance.
The other option is to always require the application to set a value as an array ref, even if there is only one entry: this would make backend code less tedious, but, for the exact reason of multiple header values vs. multiple header lines with the same name mentioned in the paragraph before, I think it's confusing.
No iterators support in $body?
We learned that WSGI and Rack really enjoy the benefit of Python and Ruby's language beauty, which are iterable objects in Python or iterators in Ruby.
Rack, for instance, expects the body as an object that responds to the each
method and then yields the buffer, so
body.each { |buf| request.write(buf) }
would just magically work whether body is an Array, FileIO object or an object that implements iterators. Perl doesn't have such a beautiful thing in the language unless autobox is loaded. PSGI should not make autobox as a requirement, so we only support a simple array ref or file handle.
Writing an IO::Handle-like object is pretty easy since it's only getline
and close
. You can also use PerlIO to write an object that behaves like a filehandle, though it might be considered a little unstable.
See also IO::Handle::Util to turn anything iterators-like into IO::Handle-like.
How should server determine to switch to sendfile(2) based serving?
First of all, an application SHOULD always set a IO::Handle-like object (or an array of chunks) that responds to getline
and close
as a body. That is guaranteed to work with any servers.
Optionally, if the server is written in perl or can tell a file descriptor number to the C-land to serve the file, then the server MAY check if the body is a real filehandle (possibly using Plack::Util's is_real_fh
function), then get a file descriptor with fileno
and call sendfile(2) or equivalent zero-copy data transfer using that.
Otherwise, if the server can't send a file using the file descriptor but needs a local file path (like mod_perl or nginx), the application can return an IO::Handle-like object that also responds to path
method. This type of IO-like object can easily be created using IO::File::WithPath, IO::Handle::Util or Plack::Util's set_io_path
function.
Middlewares can also look to see if the body has path
method and does something interesting with it, like setting X-Sendfile
headers.
To summarize:
When to serve static files, applications should always return a real filehandle or IO::Handle object. That should work everywhere, and can be optimized in some environments.
Applications can also set IO::Handle like object with an additional
path
method, then it should work everywhere again, and can be optimized in even more environments.
What if I want to stream content or do a long-poll Comet?
For the server push, your application can return a IO::Handle-like object as a content body that implements getline
to return pushed content. Some implementations are also allowed to do an optimized non-blocking read from special filehandle-like objects like IO::Writer.
Fo the long poll comet you can also use co-routine based implementations like Plack::Server::Coro and do your own threading.
Which framework should I use to do streaming though?
We have servers that support non-blocking (where psgi.nonblocking
is set to true), but the problem is that framework side doesn't necessary support streaming. For instance Catalyst has write
method on the response object:
while ($cond) {
$c->res->write($some_stuff);
}
But it obviously blocks in the application unless you run your application in multithread (or Coro) environments. Catalyst::Engine::PSGI also supports setting an IO::Handle-like object that supports getline
, so using IO::Handle::Util
my $io = io_from_getline sub {
return $data; # or undef when done()
};
$c->res->body($io);
And that works fine to do streaming, but it's blocking so you should be careful not to run on non-blocking (and non-multiprocess) server environments.
For the nonblocking single process server (like AnyEvent or Perlbal) the solution we're working on is a non-blocking IO handle that falls back to blocking, called IO::Writer. Once we figure that out, then you can set the writer object to response body, like:
my $io = writer {
my $handle = shift;
$handle->print($stuff);
};
$c->res->body($io);
And it will do the right thing in blocking and non-blocking server environments transparently.
Why CGI-style environment variables instead of HTTP headers as a hash?
Most existing web application frameworks already have code or a handler to run under the CGI environment. Using CGI-style hash keys instead of HTTP headers makes it trivial for the framework developers to implement an adapter to support PSGI. For instance, Catalyst::Engine::PSGI is only a few dozens lines different from Catalyst::Engine::CGI and was written in less than an hour.
Why is PATH_INFO URI decoded?
To be compatible with CGI spec (RFC 3875) and most web servers' implementations (like Apache and lighttpd).
I understand it could be inconvenient that you can't distinguish foo%2fbar
from foo/bar
in the trailing path, but the CGI spec clearly says PATH_INFO
should be decoded by servers, and that web servers can deny such requests containing %2f
(since such requests would lose information in PATH_INFO). Leaving those reserved characters undecoded (partial decoding) would make things worse, since then you can't tell foo%2fbar
from foo%252fbar
and could be a security hole with double encoding or decoding.
For web application frameworks that need more control over the actual raw URI (such as Catalyst), we made the REQUEST_URI
environment hash key REQUIRED. The servers should set the undecoded (unparsed) original URI (containing the query string) to this key. Note that REQUEST_URI
is completely raw even if the encoded entities are URI-safe.
For comparison, WSGI (PEP-333) defines both SCRIPT_NAME
and PATH_INFO
be decoded and Rack leaves it implementation dependent, while fixing most of PATH_INFO left encoded in Ruby web server implementations.
http://www.python.org/dev/peps/pep-0333/#url-reconstruction http://groups.google.com/group/rack-devel/browse_thread/thread/ddf4622e69bea53f
SEE ALSO
WSGI's FAQ clearly answers lots of questions about how some API design decisions were made, some of which can directly apply to PSGI.
http://www.python.org/dev/peps/pep-0333/#questions-and-answers
MORE QUESTIONS?
If you have a question that is not answered here, or things you totally disagree with, come join the IRC channel #http-engine on irc.perl.org or mailing list http://groups.google.com/group/psgi-plack. Be sure you clarify which hat you're wearing: application developers, server implementors or middleware developers. And don't criticize the spec just to criticize it: show your exact code that doesn't work or get too messy because of spec restrictions etc. We'll ignore all nitpicks and bikeshed discussion.
AUTHOR
Tatsuhiko Miyagawa <miyagawa@bulknews.net>