The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Plack::Middleware::Debugger::Injector - Middleware for injecting content into a web request

VERSION

version 0.02

DESCRIPTION

This middleware is used to inject some content into the body of a given web request right before the closing <body> tag. Its primary use-case is to inject a <script> tag which will then create the Plack::Debugger debugging UI.

Since this middleware will run on every request it has to decide if injection is sensible or not. It does this by checking the HTTP status code, some HTTP headers and finally the content-type of the response.

Status codes

Most status codes not in the 2xx range are ignored since they rarely contain a body that is of consequence to this module. The only exception being 204 - No Content, which will not have a body and so is ignored.

Headers

Currently we only handle one header, X-Plack-Debugger-Parent-Request-UID, which is a custom header that we add into AJAX requests that are associated with a given request. If we see this header, we will not bother injecting content since we can assume that it is meant to be debugged via the parent page.

Content-Types

The following content-types are handled in the following order:

No content-type specified

This currently throws an exception, perhaps this is not sensible, but then again not specifying your content-type is not very sensible either.

text/html, application/xhtml, etc.

Given a content-type that looks like HTML, this will PSGI responses in the most sensible way possible.

If we detect a PSGI response which is an array of strings, we will process it (in reverse) looking for the closing <body> tag and inject the content accordingly.

All other PSGI responses will be handled as if they are streaming responses, in which case we simple return a CODE reference that will process the stream and if a closing <body> tag is found, inject accordingly.

application/json

While we have a specific handler for this content-type, we do not do anything but just let it pass through. This is handled in this way specifically in case someone decides it is sensible to inject some kind of data into a JSON response.

It is left as an exercise to the reader to decide if this is sensible or not.

application/*, text/*, image/*

These three content types are fairly common, but there is no obvious way to inject content into them. So instead of guessing, we just let them pass through without modification. If there is any need to inject data into these response types it is simply a matter of overriding the pass_through_content_type method in a subclass and then doing your own content-type dispatching.

Unknown content-type

If none of these content-types match then we throw an exception and complain that we are not use what to actually do. Again, as with the lack of a content-type, this may not be sensible, if you disagree please give me a use case.

METHODS

new (%args)

This expects a content key in %args which is either a string or a CODE reference that will accept a PSGI $env as its only argument.

call ($env)

This is just overriding the Plack::Middleware call method.

get_content_to_insert ($env)

This will return the content specified in new and will just do the appropriate thing depending on if the content was a string or a CODE reference.

HTTP Request predicates

The remaining methods deal with processing the HTTP request to determine if we should inject the content or not.

should_ignore_status ($env, $resp)

This filters based on the HTTP status code, see the "Status Codes" section above for more details.

has_parent_request_uid ($env, $resp)

If the request has the HTTP header that indicates it is a sub-request (typically an AJAX call from the browser) then it should be injected into, this method determines this. See the Headers section above for more details.

Content-Type handlers

It only makes sense to inject the debugger content into certain types of responses, these methods determine how and when to do this. See the Content-Types section above for more details.

handle_no_content_type ($env, $resp)
pass_through_content_type ($env, $resp)
handle_json_content_type ($env, $resp)
handle_html_content_type ($env, $resp)
handle_unknown_content_type ($env, $resp)

TODO

The following is a list of things this module might want to try and do, but which currently are not important to me. If one or more of these features would be useful to you, please feel free to send patches.

Detect User-Agents where injection is not sensible.

Injecting Javascript code into pages being viewed by browsers like Lynx or tools like c<cURL> or wget would not make any sense.

ACKNOWLEDGMENT

This module was originally developed for Booking.com. With approval from Booking.com, this module was generalized and published on CPAN, for which the authors would like to express their gratitude.

AUTHOR

Stevan Little <stevan@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Stevan Little.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.