I take it and I don't want you to leave the discussion ;) I've been repeating with Rani the same point every time he brought it up: redirection should be done ASAP and before sending any data to the stdout. I maintain that for any "sensible" page (most web pages size is well < 1000000) data are sent when mod_rivet calls Tcl_Flush, therefore redirection can occur before that point, but it's not true every case. Rivet_ExecuteAndCheck calls Tcl_Flush which in turn causes Rivet channel's output procedure to be called by Tcl. And this happens also when the ::rivet::parse command is called (which calls Rivet_ParseExecFile and then Rivet_ExecuteAndCheck)
That's why redirection in most cases (my websites are always running nested parsing) doesn't work if called during page generation and that's why I perform most data generation within the BeforeScript, well before the top level template is parsed. I think we could easily fix this collapsing every Tcl_Flush call into a single call just before Rivet_SendContent exits. Can we do any better? For example treating a 'headers redirect' call likewise a ::rivet::abort_page call, maybe with it's specific code? After all if you're redirecting what's the point of keep going with the page generation? (As a matter of fact we could also empty the buffer and invalidate any data produced) I'm very conscious the channel is an ordinary Tcl channel and as such it can be manipulated, but it doesn't exploit all the flexibility the Tcl channel model offers. More specifically: only the output method is implemented, but also the flush method could turn out useful in this case. On Sat, Dec 13, 2014 at 7:50 PM, Damon Courtney <[email protected]> wrote: > > The channel mechanism is actually quite flexible out of the box. Anything > Tcl lets you do, you can do with the stdout channel in Rivet. For example: > > fconfigure stdout -buffersize 1000000 -buffering full > > And you have almost a megabyte of output before the channel will flush > (unless you [flush stdout] yourself). > > I know that having to output the headers before any data can be annoying > sometimes, but it’s really the proper way to do it. If you’re going to > redirect to another page, you should have done so LONG before you output > any data. In my case, I’m using a pretty standard MVC model where the > controller determines that a redirect is required before the view is ever > rendered. > > If we wanted to try and support his proposal, we could alter the [headers > redirect] command, and if headers have already been sent, then we output > the <meta> tag, but this has its problems as well. Though most browsers > would probably let it slide, the meta tag should really be inside the > <head> of the page. So, once again, you have a limitation. > > Just my thoughts, take ‘em or leave ‘em. :) > > D > > > On Dec 13, 2014, at 4:50 AM, Massimo Manghi <[email protected]> wrote: > > Rani Ahmad gave me permission to forward to rivet-dev his proposal for an > alternate way to force redirection to a different URL using the <meta ....> > tag. Rani claims this approach could attain the same effect while > preventing the scripts from failing with the "headers already sent" error. > It still makes sense that a script which could issue a redirect has in > principle to determine whether to divert to a different URL *before* any > output is sent to the channel. admittedly this is rigid because forces a > certain design (though a sane one), it's largely undocumented and in the > end there should be a better more flexible way to do this > > We obtain redirection with the 301 HTTP code and when the headers command > is called the code checks for the headers_sent flag > > TCL_CMD_HEADER( Rivet_Headers ) > { > ... > if (globals->req->headers_printed != 0) > { > Tcl_AddObjErrorInfo(interp ,"Cannot manipulate headers - already > sent", -1); > return TCL_ERROR; > } > > globals->req->headers_printed is set when the Rivet channel output > procedure is called by Tcl I/O subsystem and I wonder if there are > different ways to do it, for example making the channel implementation more > flexible about buffering. Of course this doesn't rule out the possibility > of exploiting other ways (like in Rani's proposal), but it seems to me the > HTTP protocol has to be supported in the best possible way > > -- Massimo > > ---------- Forwarded message ---------- > From: Rani Ahmed <[email protected]> > Date: Thu, Dec 11, 2014 at 8:37 PM > Subject: Hi. A suggestion. > To: Massimo Manghi <[email protected]> > > Hi Massimo. > > Well I suggest that you add a better redirect function/procedure other > than the *[headers* redirect $url *]* . This one always makes many people > go into the annoying error message of > > *headers already sent .* > The procedur*e* will be the following, I found it on Stackoverflow. I > understand that I can put it for my own, but this little thing - I think - > can be the key that makes Rivet attractive. > > *proc* http_redirect *{* url *} {* > > > *?>* <meta http-equiv="refresh" content="0;url='*<?=*$url;*?>*'"> > *<?* > > *}* > > >
