perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From André Warnier ...@ice-sa.com>
Subject Re: question on sub-requests
Date Tue, 13 Nov 2012 18:17:49 GMT
Torsten Förtsch wrote:
> On 11/12/2012 06:19 PM, André Warnier wrote:
>> In response to some request URLs, I have to compose a response
>> structured as follows :
>>
>> - a html frameset document with two frames
>> - in the 1st frame, the result of another HTTP request to the same
>> Apache server.
>>   This URI of this HTTP request is created by "mangling" the original
>> request URL somewhat.
>> - in the 2d frame, the content of the HTML file corresponding to the
>> original request URI.
>>
>> For example, if the original request URI was something like :
>> "/abc/def/ghi.html", then
>>   - the top frame should contain the (html) output of a request to
>> "/cgi-bin/mangle.pl?arg=ghi"
>>   - the bottom frame should contain the content of the
>> originally-requested "/abc/def/ghi.html" URI (which is a static file).
>>
>> I am thinking of doing this by :
>> - creating a mod_perl ResponseHandler
>> - having this response handler make a first sub-request to the
>> "/cgi-bin/mangle.pl?arg=ghi" URI, grabbing the content of the response
>> to that sub-request, and insert it into the first <frame> of the output
>> <frameset> document.
>> - having the response handler do a lookup_uri of the original URI, get
>> the resulting filename, reading the file and insert its content into the
>> second <frame> of the output <frameset> document.
>>
>> My 1st question is : is the above a valid plan, or is there something
>> fundamentally wrong with this approach ?
>>
>> My 2d question is : looking at the Apache2::SubRequest documentation, I
>> do not see a clear way of getting the response content of a subrequest. 
>> For example, the run() method explanation seems to indicate that the
>> response content is sent directly to the client.
>> Am I missing something ?
> 
> I don't really understand what you want to achieve. But if you just want
> to insert a header on top of each page, this can be done without a
> frameset (you know, they are utterly deprecated).
> 
> Use a PerlOutputFilterHandler to insert a <div> or perhaps even an
> <iframe> just after the opening <body> tag.
> 
> Once you have found the <body> tag in the output stream, you pass it
> further down the filter chain and add perhaps the opening <div>. Then
> you create and run the subrequest. Then you put out the rest of the
> brigade, remove the filter and return. Thus, the filter will probably be
> called only once because the <body> tag tends to appear within the first
> few kbytes of the document.
> 
> If that is the case, you can even adjust the Content-Length header
> properly to include the additional stuff. Otherwise you should remove
> the Content-Length header.
> 
> Things you have to consider:
> 
> - filtering data costs CPU cylces
> This is especially true if you served just plain files before by
> sendfile(2).
> 
> - on the other hand, you can put mod_cache in front of those requests
> (even in the same apache) and they will be served even faster than the
> plain files before
> 
> - deleting the Content-Length header is to be avoided if possible. It
> increases the overall transfer time considerably
> 
> - if you have used precompressed plain files before they are now
> useless. Instead you'll have to use the DEFLATE filter. This costs
> additional CPU cycles. But again mod_cache helps a lot.
> 
> 
> One other idea comes to mind. If you want to stick with your frameset
> but prevent multiple requests perhaps you can use "data:" URLs as src.
> This probably requires much more complicated filtering.
> 
> Torsten
> 

Hi.
I didn't want to take too much time of anyone before, which is why I somewhat 
oversimplified the issue.  But considering the traffic on the lis os low, maybe you want 
to hear the whole story after all.

The basic case is this : a bit aside from our usual professional activities and for a 
friend, we run a website which is basically a shop with hundreds of individual items which

people can view and buy.  (I will provide the URL privately to anyone who is more 
interested. It's a cute shop.)

The pages corresponding to these individual items, at the moment, are individual static 
pages in multiple sub-directories, and there are quite a lot of them.  The friend creates

and maintains these static pages herself; she is an artist rather than a programmer, so 
she can handle an html editor (which she does rather well) to edit static pages and test 
them on her PC before copying them to the server, but we cannot ask her to handle any kind

of "template" pages or the like.
Add to this that the basic logic of the website and the design and techniques used date 
back from some 10 years ago, have been patched and repatched several times over several 
years, and are rather bad.

Now there is a requirement that, instead of being just static pages, each of these pages 
should in addition contain a <form> with some specific item-related information, allowing

to buy these items on-line (so it cannot be done just with an include or a stylesheet).

What I am trying to achieve, without having to edit each of these individual hundreds of 
pages, or changing the links to these pages, or change the basic design of the application

(because there is no budget for that), is to find a clever way on the server side
to respond to a normal "/Shop_xxx/def/xyz.html" URL of one of these pages, to combine into

one response both the required <form>, and the content of the existing unmodified static

page.  I also do not want to parse the html on-the-fly and insert a <form> right into
it, 
because the html that she creates with her (T-online) editor is rather bad to start with,

and I have no guarantee that the result would be pleasing.

So that was the reason to think of the <frameset> solution, whereby in response to the

initial request for "/Shop_xxx/def/xyz.html", I would respond with a first <frame> 
containing the form (generated by a back-end application, and depending on the item), and

a second <frame> containing her artfully-crafted static page describing that item in
all 
its glory.

The static pages in question are in several subdirectories of DocumentRoot, and at 
different levels.  Fortunately, all the top sub-directories names start with "/Shop_" 
(after which there can be "Quilts" or "Babydecken" and things like that, and a variable 
hierarchy of sub-directories containing html files and jpg images and the like.

So I have this configured :
<LocationMatch "^/Shop_">
   sethandler modperl
   PerlResponseHandler My::ShopResponse
   ...
</LocationMatch>

As a result in part of the previous communications on this list, this PerlResponseHandler
does more or less what I want, except one remaining problem which I am trying to resolve 
right now :
In response to an initial request for "/Shop_xxx/def/xyz.html", the handler generates a
<frameset> document as such :
<html>
<frameset rows="100,*">
   <frame name="top_frame" src="..the URI which generates the form.." />  (1)
   <frame name="bottom_frame" src="/Shop_xxx/def/xyz.html.shop" />  (2)
</frameset>
</html>

(1) for the dynamically-generated html <form> document
(2) for the static existing page

Because the second frame's URI also starts with "/Shop_", when the browser requests this 
frame, the same ResponseHandler is called.
The handler examines the URL and sees that it ends in ".shop" (instead of ".html").
So it knows that this time, it should not send another frameset, but instead it should 
strip the trailing ".shop" and deliver, as is, the content of the static document 
"/Shop_xxx/def/xyz.html".

But, how do I tell it to do that ?
I have tried :
   my $uri = $r->uri();
   if ($uri =~ m!\/([^/]+\.htm[l]?\.shop)$!i) {
	$uri =~ s/\.shop$//; # strip the trailing ".shop"
	$r->internal_redirect($uri);
     	return Apache2::Const::OK ;
   }

and also :

   my $uri = $r->uri();
   if ($uri =~ m!\/([^/]+\.htm[l]?\.shop)$!i) {
	$uri =~ s/\.shop$//; # strip the trailing ".shop"
	my $subr = $r->lookup_uri($uri);
	$subr->run();
     	return Apache2::Const::OK ;
   }

but both of those result in a loop : they end up requesting "/Shop_xxx/def/xyz.html", 
which hits the same Location, which runs the same handler, which then produces the 
frameset, and so on.

So how do I tell Apache/mod_perl that this time "I mean it", and that it should directly 
deliver the requested file, without re-running the whole cycle ?

I can of course request the corresponding filename() and deliver it myself (perhaps with 
sendfile()), but that does not seem to be the most elegant way of doing this. Or is it ?

Oh, and I'd like it elegant, but I would prefer not having to introduce a PerlFixupHandler

or a PerlOutputFilter or Javascript, and do it all within this ResponseHandler.  That's 
because I have colleagues who know even less about mod_perl than I do, and I'd like to 
leave them something simple to deal with in support and maintenance for another 10 years.

...

Aside : I just tried

   my $uri = $r->uri();
   if ($uri =~ m!\/([^/]+\.htm[l]?\.shop)$!i) {
	$uri =~ s/\.shop$//; # strip the trailing ".shop"
	my $subr = $r->lookup_uri($uri);
	$r->sendfile($subr->filename());
     	return Apache2::Const::OK ;
   }

and that works.  So I guess that /is/ the right solution here.



Mime
View raw message