Search code examples
perlplack

Snooping on http headers between different plack middlewares


If I understand right, the PSGI application works as next:

  • got the request from a browser
  • the request is "bubbles" thru some middlewares in the order as them is defined in the builder
  • the request comes to my app
  • my app produces some respond
  • this respond again bubbles thru some middlewares
  • finally the respon is send to the browser

I can easily debug-print all headers (e.g. cookies) when the request landed in my $app.

The question is: How to debug-print the actual state of headers while the request coming thru many middlewares to my app and while the respond is going-out again thru middlewares.

So, Having an (simplyfied) app.psgi, like the next:

use strict;
use warnings;
use Plack::Builder;

my $app = sub { ... };

builder {
         # <- debug-print the first request headers
         #                and the last respond headers here
    enable "Debug";
         # <- debug-print the actual state of request/respond headers here
    enable "mid2";
         # <- and here
    enable "mid3";
         # <- and here

    $app; # <- and finally here - this is of course EASY
}

It is probably not as easy as something like,

print STDERR Dumper $dont_know_what->request->headers(); #HTTP::Headers ???
print STDERR Dumper $dont_know_what->respond->headers();

so adding a bounty :) ;)


Solution

  • Middleware

    package ShowMeTheHeaders;
    use parent "Plack::Middleware";
    use Plack::Request;
    use Plack::Response
    require Text::Wrap;
    
    my $_call_back = sub {
        my $response = Plack::Response->new(@{+shift});
        print "* Response Headers:\n",
            Text::Wrap::wrap("\t", "\t", $response->headers->as_string);
        return; # Explicit return suggested by docs.
    };
    
    sub call {
        my $self = shift;
        my $request = Plack::Request->new(shift);
        print "* Request Headers:\n",
            Text::Wrap::wrap("\t", "\t", $request->headers->as_string);
        my $response = $self->app->($request);
        Plack::Util::response_cb($response, $_call_back);
    }
    
    1;
    

    You can do this without the objectification (Plack::Request and Plack::Response) but then you have to deal with raw attributes and keys for the header fields instead of the entirely more pleasant ->as_string. See also the “response callback” section of Plack::Middleware.

    demo psgi

    use warnings;
    use strict;
    use Plack::Builder;
    
    my $app = sub {
        [ 200,
          [ "Content-Type" => "text/plain" ],
          [ "O HAI, PLAK!" ]
        ];
    };
    
    builder {
        enable "+ShowMeTheHeaders";
        mount "/" => $app;
    };