[Rt-devel] reliably serving images from inside the standalone server

Nicholas Clark nick at ccl4.org
Wed Jun 6 12:39:47 EDT 2007


I'm using the standalone server for development. It's attempting to server
image files from inside html/NoAuth/images verbatim by using an autohandler.
But Mason always wants to pass the files first as Mason components, so if they
happen to have '<&' (or a couple of other strings) Mason chokes.

I can't see a great way to override Mason. The best I can manage is to subvert
Mason as appended, by sniffing the file on the way in, and if it appears to
be anything recognisable, wrap the Mason source object to return a faked-up
Mason component that has the real content as a large literal '' string.

There is rather too much copying of the literal data here for my liking.
But I can't see a way to get the real absolute filename of the component
early enough to feed into File::Type, I can't see an official way to override
the Mason component compiler (which would avoid the need for the <%'$source'%>
hack, and I can't see a way to cleanly wrap the code callback used in the
upstream comp_source_ref() method.

Yes, it works.
Yes, it's small.
Yes, it's non-invasive.

That's about all it has going for it.

Nicholas Clark

--- lib/RT/Interface/Web/Standalone.pm~	Mon May 21 14:38:41 2007
+++ lib/RT/Interface/Web/Standalone.pm	Wed Jun  6 14:39:56 2007
@@ -49,6 +49,7 @@
 use base 'HTTP::Server::Simple::Mason';
 use RT::Interface::Web::Handler;
 use RT::Interface::Web;
+use MasonX::SimplisticServer;
 
 sub handler_class { "RT::Interface::Web::Handler" }
 
@@ -62,7 +63,7 @@
 } 
 
 sub default_mason_config {
-    return @RT::MasonParameters;
+    return interp_class => 'MasonX::SimplisticServer', @RT::MasonParameters;
 } 
 
 sub handle_request {
--- /dev/null	Wed Jun  6 16:33:00 2007
+++ lib/MasonX/SimplisticServer.pm	Wed Jun  6 16:24:34 2007
@@ -0,0 +1,58 @@
+package MasonX::SimplisticServer;
+use strict;
+use warnings;
+use vars qw($VERSION @ISA);
+$VERSION = '0.01';
+
+require HTML::Mason::Interp;
+
+ at ISA = 'HTML::Mason::Interp';
+
+require File::Type;
+
+sub resolve_comp_path_to_source {
+    my $self = shift;
+    my $source_obj = $self->SUPER::resolve_comp_path_to_source(@_);
+
+    return unless $source_obj;
+
+    if ($source_obj) {
+	my $source = $source_obj->comp_source();
+	my $type = File::Type->new()->checktype_contents($source);
+	if (defined $type and $type !~ m!^text/!
+	    and $type ne 'application/octet-stream') {
+	    # application/octet-stream is the fallback default, and rather a
+	    # lot of Mason components end up there, as File::Type is looking
+	    # for an <html> tag before it says text/html
+	    # In fact, File::Type is 100% reluctant to say text/*
+	    bless $source_obj, 'MasonX::SimplisticServer::LiteralSource';
+	}
+    }
+
+    $source_obj;
+}
+
+package MasonX::SimplisticServer::LiteralSource;
+
+use strict;
+use warnings;
+use vars qw($VERSION @ISA);
+$VERSION = '0.01';
+
+require HTML::Mason::ComponentSource;
+
+ at ISA = 'HTML::Mason::ComponentSource';
+
+sub comp_source_ref {
+    my $self = shift;
+    my $ref = $self->SUPER::comp_source_ref();
+    my $source = $$ref;
+    # Escape all the single quotes and backslashes
+    $source =~ s/([\\\'])/\\$1/g;
+    # So that we can make this a valid '' string literal that encodes the
+    # file contents, and return a reference to a page that has that '' string
+    \"<%'$source'%>";
+}
+
+1;


More information about the Rt-devel mailing list