Changeset 7719
- Timestamp:
- 06/10/10 13:57:33 (2 years ago)
- Location:
- trunk/core/lib/Foswiki
- Files:
-
- 4 edited
-
Engine.pm (modified) (8 diffs)
-
Response.pm (modified) (15 diffs)
-
UI.pm (modified) (2 diffs)
-
UI/Statistics.pm (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/core/lib/Foswiki/Engine.pm
r7453 r7719 46 46 sub run { 47 47 my $this = shift; 48 my $req = $this->prepare ;48 my $req = $this->prepare(); 49 49 if ( defined $req ) { 50 50 my $res = Foswiki::UI::handleRequest($req); … … 88 88 $res->print($html); 89 89 } 90 $this->finalizeError($res );90 $this->finalizeError($res, $req); 91 91 return $e->{status}; 92 92 } … … 115 115 $res->print($text); 116 116 } 117 $this->finalizeError($res );117 $this->finalizeError($res, $req); 118 118 return 500; # Internal server error 119 119 }; … … 268 268 sub finalize { 269 269 my ( $this, $res, $req ) = @_; 270 $this->finalizeUploads( $res, $req ); 271 $this->finalizeHeaders( $res, $req ); 272 $this->finalizeBody($res); 270 if ($res->outputHasStarted()) { 271 $this->flush($res, $req); 272 } else { 273 $this->finalizeUploads( $res, $req ); 274 $this->finalizeHeaders( $res, $req ); 275 $this->finalizeBody($res); 276 } 273 277 } 274 278 … … 289 293 =begin TML 290 294 291 ---++ ObjectMethod finalizeError( $res )295 ---++ ObjectMethod finalizeError( $res, $req ) 292 296 293 297 Called if some engine especific error happens. 294 298 295 299 * =$res= - Foswiki::Response object to get data from 300 * =$req= - Foswiki::Request object to get data from 296 301 297 302 =cut 298 303 299 304 sub finalizeError { 300 my ( $this, $res ) = @_;301 $this->finalizeHeaders($res );302 $this->finalizeBody($res );305 my ( $this, $res, $req ) = @_; 306 $this->finalizeHeaders($res, $req); 307 $this->finalizeBody($res, $req); 303 308 } 304 309 … … 351 356 =begin TML 352 357 353 ---++ ObjectMethod finalizeBody( $res )358 ---++ ObjectMethod finalizeBody( $res, $req ) 354 359 355 360 * =$res= - Foswiki::Response object to get data from 361 * =$req= - Foswiki::Request object to get data from 356 362 357 363 Should send $res' body to client. This method calls =write()= … … 361 367 362 368 sub finalizeBody { 363 my ( $this, $res ) = @_;369 my ( $this, $res, $req ) = @_; 364 370 my $body = $res->body; 365 371 return unless $body; … … 381 387 =begin TML 382 388 389 ---++ flush($res, $req) 390 391 Forces the response headers to be emitted if they haven't already been sent 392 (note that this may in some circumstances result in cookies being missed) 393 before flushing what is in the body so far. 394 395 Before headers are sent, any Content-length is removed, as a call to 396 flush is a statement that there's more to follow, but we don't know 397 how much at this point. 398 399 This function should be used with great care! It requires that the output 400 headers are fully complete before it is first called. Once it *has* been 401 called, the response object will refuse any modifications that would alter 402 the header. 403 404 =cut 405 406 sub flush { 407 my ($this, $res, $req) = @_; 408 409 unless ($res->outputHasStarted()) { 410 $res->deleteHeader('Content-Length'); 411 $this->finalizeUploads( $res, $req ); 412 $this->finalizeHeaders( $res, $req ); 413 $this->prepareWrite($res); 414 $res->outputHasStarted(1); 415 } 416 417 my $body = $res->body(); 418 419 if ( Scalar::Util::blessed($body) || ref( $body ) eq 'GLOB' ) { 420 throw Foswiki::EngineException('Cannot flush non-text response body'); 421 } 422 423 $this->write($body); 424 $res->body(''); 425 } 426 427 =begin TML 428 383 429 ---++ ObjectMethod prepareWrite( $res ) 384 430 385 Abstract method, m ustbe defined by inherited classes.431 Abstract method, may be defined by inherited classes. 386 432 * =$res= - Foswiki::Response object to get data from 387 433 388 Sho ld perform any task needed before writing.434 Should perform any task needed before writing. 389 435 That's ok if none needed ;-) 390 436 -
trunk/core/lib/Foswiki/Response.pm
r7709 r7719 16 16 17 17 package Foswiki::Response; 18 18 19 use strict; 19 20 use warnings; 20 21 use Assert; 21 use CGI::Util qw(rearrange expires); 22 23 use CGI::Util (); 22 24 23 25 =begin TML … … 28 30 29 31 =cut 30 31 # NOTE: CHECK_ORDER is used to indicate when the body assembly has started.32 # By associating an assert with this action we can ensure that headers are33 # fully assembled before the body print starts - an essential precondition34 # for early flushing of output.35 sub CHECK_ORDER {36 ASSERT( !$_[0]->{startedPrinting} ) if DEBUG;37 }38 32 39 33 sub new { … … 41 35 my $class = ref($proto) || $proto; 42 36 my $this = { 43 status => undef,44 headers => {},45 body => undef,46 charset => 'ISO-8859-1',47 cookies => [],48 startedPrinting=> 0,37 status => undef, 38 headers => {}, 39 body => undef, 40 charset => 'ISO-8859-1', 41 cookies => [], 42 outputHasStarted => 0, 49 43 }; 50 44 … … 67 61 my ( $this, $status ) = @_; 68 62 if ($status) { 69 CHECK_ORDER() if DEBUG; 63 ASSERT(!$this->{outputHasStarted}, 'Too late to change status') 64 if DEBUG; 70 65 $this->{status} = $status =~ /^\d{3}/ ? $status : undef; 71 66 } … … 105 100 my (@header); 106 101 107 CHECK_ORDER;102 ASSERT(!$this->{outputHasStarted}, 'Too late to change headers') if DEBUG; 108 103 109 104 # Ugly hack to avoid html escape in CGI::Util::rearrange 110 105 local $CGI::Q = { escape => 0 }; 111 106 my ( $type, $status, $cookie, $charset, $expires, $attachment, @other ) = 112 rearrange(107 CGI::Util::rearrange( 113 108 [ 114 109 [ 'TYPE', 'CONTENT_TYPE', 'CONTENT-TYPE' ], 'STATUS', … … 163 158 $this->cookies( \@cookies ); 164 159 } 165 $this->{headers}->{Expires} = expires( $expires, 'http' )160 $this->{headers}->{Expires} = CGI::Util::expires( $expires, 'http' ) 166 161 if ( defined $expires ); 167 $this->{headers}->{Date} = expires( 0, 'http' )162 $this->{headers}->{Date} = CGI::Util::expires( 0, 'http' ) 168 163 if defined $expires || $cookie; 169 164 $this->{headers}->{'Content-Disposition'} = … … 186 181 my ( $this, $hdr ) = @_; 187 182 if ($hdr) { 188 CHECK_ORDER; 183 ASSERT(!$this->{outputHasStarted}, 'Too late to change headers') 184 if DEBUG; 189 185 my %headers = (); 190 186 while ( my ( $key, $value ) = each %$hdr ) { … … 192 188 $headers{$key} = $value; 193 189 } 194 $headers{Expires} = expires( $headers{Expires}, 'http' )190 $headers{Expires} = CGI::Util::expires( $headers{Expires}, 'http' ) 195 191 if defined $headers{Expires}; 196 $headers{Date} = expires( 0, 'http' )192 $headers{Date} = CGI::Util::expires( 0, 'http' ) 197 193 if defined $headers{'Set-Cookie'} || defined $headers{Expires}; 198 194 if ( defined $headers{'Set-Cookie'} ) { … … 253 249 } 254 250 elsif ( $hdr eq 'Expires' ) { 255 $value = expires( $value, 'http' );251 $value = CGI::Util::expires( $value, 'http' ); 256 252 } 257 253 elsif ( $hdr eq 'Set-Cookie' ) { … … 262 258 } 263 259 } 264 $this->{headers}{Date} = expires( 0, 'http' )260 $this->{headers}{Date} = CGI::Util::expires( 0, 'http' ) 265 261 if !exists $this->{headers}{Date} 266 262 && ( defined $this->{headers}{Expires} … … 302 298 my $this = shift; 303 299 304 CHECK_ORDER;300 ASSERT(!$this->{outputHasStarted}, 'Too late to change headers') if DEBUG; 305 301 306 302 foreach (@_) { … … 321 317 my ( $this, $hdr, $value ) = @_; 322 318 323 CHECK_ORDER;319 ASSERT(!$this->{outputHasStarted}, 'Too late to change headers') if DEBUG; 324 320 325 321 $hdr =~ s/(?:^|(?<=-))(.)([^-]*)/\u$1\L$2\E/g; … … 398 394 sub redirect { 399 395 my ( $this, @p ) = @_; 396 ASSERT(!$this->{outputHasStarted}, 'Too late to redirect') if DEBUG; 400 397 my ( $url, $status, $cookies ) = 401 rearrange( [ [qw(LOCATION URL URI)], 'STATUS', [qw(COOKIE COOKIES)], ], 402 @p ); 398 CGI::Util::rearrange( 399 [ [qw(LOCATION URL URI)], 'STATUS', [qw(COOKIE COOKIES)], ], 400 @p ); 403 401 404 402 return unless $url; … … 415 413 ---++ ObjectMethod print(...) 416 414 417 Add content to the end of the body. The print may not be flushed until the 418 body is complete. 415 Add content to the end of the body. 419 416 420 417 =cut … … 422 419 sub print { 423 420 my $this = shift; 424 $this->{startedPrinting} = 1;425 421 $this->body( ( $this->{body} || '' ) . join( '', @_ ) ); 422 } 423 424 =begin TML 425 426 ---++ ObjectMethod outputHasStarted([$boolean]) 427 428 Get/set the output-has-started flag. This is used by the Foswiki::Engine 429 to separate header and body output. Once output has started, the headers 430 cannot be changed (though the body can be modified) 431 432 =cut 433 434 sub outputHasStarted { 435 my ($this, $flag ) = @_; 436 $this->{outputHasStarted} = $flag if defined $flag; 437 return $this->{outputHasStarted}; 426 438 } 427 439 -
trunk/core/lib/Foswiki/UI.pm
r7682 r7719 385 385 $res->print($html); 386 386 } 387 $Foswiki::engine->finalizeError($res );387 $Foswiki::engine->finalizeError($res, $session->{request}); 388 388 return $e->{status}; 389 389 } … … 397 397 $res ||= new Foswiki::Response(); 398 398 399 $res->header( -type => 'text/plain' ); 399 $res->header( -type => 'text/plain' ) 400 unless $res->outputHasStarted(); 400 401 if (DEBUG) { 401 402 -
trunk/core/lib/Foswiki/UI/Statistics.pm
r7682 r7719 496 496 } 497 497 $session->{response}->print( $msg . "\n" ) if $msg; 498 $Foswiki::engine->flush($session->{response}, $session->{request}); 498 499 } 499 500
Note: See TracChangeset
for help on using the changeset viewer.
