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.


Reply via email to