Results tagged “plack”

leaves falling off the tree

For me, one of the promises of PSGI and Plack is to get away from programming with global variables in Perl, particularly being able to modify the request object after it’s been created. Long ago, CGI.pm replaced using a global

%FORM
hash with a “query object”, but it essentially has been used as always-accessible read/write data structure.

It would appear at first look that improving this might a fundamental part of the new system: A lexical environment hashref is explicitly passed around, as seen here:

Plack::Request->new($psgi_env);

vs the old implicit grab from the environment:

CGI->new;

You might hope to be escaping some of th action-at-a-distance badness of global variables, like having a change to environment alter your object after the object is created. You might like avoid having changes made to your object avoid changing the global environment as well.

Not only does Plack::Request require an explicit environment hash to be passed in, both nearly all methods are read-only, including a param() method inspired by a read/write method from CGI.pm of the same name. That’s all good.

This would all seem to speak to safety and simplicity for using Plack::Request, but the reality turns out to be far muddier than you might hope. I encourage you to down and run this short, safe interactive perl script which illustrates some differences. It shows that:

  • Plack::Request objects can be altered after they are created by changing the external environment.
  • Modifying a Plack::Request object can potentially alter the external environment hash (Something which CGI.pm explicitly does not allow).

In effect, the situation with global variables is in some regards worse. Plack::Request provides the impression that there is a move away from action-at-distance programming, but the fundamental properties of being affected by global changes and locally creating them are still present.

On the topic of surprising read/write behavior in Plack::Request, you may also interested to note the behavior of query_parameters(), body_parameters() and parameters() is not consistent in this regard. I submitted tests and suggestion to clarify this, although that contribution has not yet been accepted.

Here’s the deal: The hashref returned by query_parameters() and body_parameters() and parameters() are all read/write — subsequent calls to the same method return the modified hashref.

However, modifying the hashes returned by body_parameters() or query_paremeters() does not modify the hashref returned by parameters(), which claims to be a merger of the two.

It seems that either all the return values should be read-only, ( always returning the same values ), or if modifying them is supported then the parameters() hash should be updated when either of the body_parameters() or query_parameters() hashes are updated.

Reflections

An incoming HTTP request to your server is by it’s nature read-only. It’s analogous to a paper letter being delivered to you be postal mail.

It’s a perfect application for an immutable object object design that Yuval Kogman eloquently advocates for. Plack::Request comes close to implementing the idea with mostly read-only accessors, but falls short. The gap it leave unfortunately carries forward some possibilities for action-at-distance cases that have been been sources of bugs in the past. I’d like to see Plack::Request, or some alternative to it, with the holes plugged: It should copy the input, not modify it by reference, and parameter related methods should also return copies rather than reference to internal data structures.

A midwinter box bike ride
Recently I’ve been reviewing how various Perl frameworks and modules generate HTTP headers. After reviewing several approaches, it’s clear that there are two major camps: those which put the response headers in a specific order and those which don’t. Surely one approach or the other would seem like it would be more spec-compliant, but RFC 2616 provides conflicting guidance on this point.

The bottom line is that spec says that “the order in which header fields with differing field names are received is not significant”. But then it goes on to say that it is a “good practice” (and it puts “good practice” in quotes) to order the headers a particular way. So, without strict guidance from the spec about the importance of header ordering, it would be interesting to know if header order caused a problem in practice.

The Plack::Middleware::RearrangeHeaders documentation suggests there is some benefit to strict header ordering: “to work around buggy clients like very old MSIE or broken HTTP proxy servers”

You might wonder what the big deal is— why not just stick to the “good practice” recommendation all the time? The difference can be seen in the benchmarks provided by HTTP::Headers::Fast. By ignoring the good-practice header order, an alternate implementation was able to speed-up header generation to be about twice as fast. Considering that a web-app needs to generate a header on every single request, making header generation smaller and faster is potentially a tangible win, while also still being spec-compliant.

1
Close