National Geographic Expeditions

Back to NationalGeographic.com 1-888-966-8687
Your participation in a National Geographic Expedition provides support to National Geographic's mission of increasing global understanding through exploration, geography education, and research.
Error in Include(/www/htdocs/nge/privatesafaris/kenyaandtanzania/detail/index.html):
Headers already sent. at /www/CPAN/lib/site_perl/5.8.8/Mungo/Response.pm line 184.

[    1]    1: package Mungo::Response;
[    2]    2: 
[    3]    3: # Copyright (c) 2007 OmniTI Computer Consulting, Inc. All rights reserved.
[    4]    4: # For information on licensing see:
[    5]    5: #   https://labs.omniti.com/zetaback/trunk/LICENSE
[    6]    6: 
[    7]    7: =head1 NAME
[    8]    8: 
[    9]    9: Mungo::Response - Represent response side of HTTP request cycle
[   10]   10: 
[   11]   11: =head1 SYNOPSIS
[   12]   12: 
[   13]   13:   <!-- You get a Response object for free when you use Mungo -->
[   14]   14:   <% if ($Response) { ... } %>
[   15]   15: 
[   16]   16:   <!-- Read and Mungo-process other files -->
[   17]   17:   <%
[   18]   18:      # Prints to browser
[   19]   19:      $Response->Include('/some/file.html', $arg1);
[   20]   20: 
[   21]   21:      # Caputured
[   22]   22:      my $output = $Response->TrapInclude('/some/file.html');
[   23]   23: 
[   24]   24:      # Can also print to browser via Response
[   25]   25:      print $Response "Hello world!";
[   26]   26:   %>
[   27]   27: 
[   28]   28:   <!-- May also set headers -->
[   29]   29:   <%
[   30]   30:      $Response->AddHeader('header_name' => $value);
[   31]   31:   %>
[   32]   32: 
[   33]   33:   <!-- Halt processing and jump out of the handler -->
[   34]   34:   <%
[   35]   35:      # With a 302
[   36]   36:      $Response->Redirect('/new/url/');
[   37]   37: 
[   38]   38:      # Just end
[   39]   39:      $Response->End();
[   40]   40:   %>
[   41]   41: 
[   42]   42:   <!-- Cookie facility -->
[   43]   43:   <%
[   44]   44:      # Single valued cookies
[   45]   45:      $Response->Cookies($cookie_name, $cookie_value);
[   46]   46: 
[   47]   47:      # Multivalued cookies
[   48]   48:      $Response->Cookies($cookie_name, $key, $value);
[   49]   49: 
[   50]   50:      # Cookie options
[   51]   51:      $Response->Cookies($cookie_name, 'Domain', $value);
[   52]   52:      $Response->Cookies($cookie_name, 'Expires', $value);
[   53]   53:      $Response->Cookies($cookie_name, 'Path', $value);
[   54]   54:      $Response->Cookies($cookie_name, 'Secure', $value);
[   55]   55:   %>
[   56]   56: 
[   57]   57: =head1 DESCRIPTION
[   58]   58: 
[   59]   59: Represents the response side of the Mungo request cycle.
[   60]   60: 
[   61]   61: =cut
[   62]   62: 
[   63]   63: 
[   64]   64: use strict;
[   65]   65: use IO::Handle;
[   66]   66: use Mungo::Arbiter::Response;
[   67]   67: use Mungo::Response::Trap;
[   68]   68: use Mungo::Cookie;
[   69]   69: use Mungo::Utils;
[   70]   70: use HTML::Entities;
[   71]   71: our $AUTOLOAD;
[   72]   72: 
[   73]   73: my $one_true_buffer = '';
[   74]   74: 
[   75]   75: sub new {
[   76]   76:   my $class = shift;
[   77]   77:   my $parent = shift;
[   78]   78:   my $r = $parent->{'Apache::Request'};
[   79]   79:   my $singleton = $r->pnotes(__PACKAGE__);
[   80]   80:   return $singleton if ($singleton);
[   81]   81:   my %core_data = (
[   82]   82:     'Apache::Request' => $r,
[   83]   83:     'ContentType' => $r->dir_config('MungoContentType') || $r->content_type || 'text/html',
[   84]   84:     # We don't set buffer here, we set it after it has been tied.
[   85]   85:     # 'Buffer' => $r->dir_config('MungoBuffer') || 0,
[   86]   86:     'Buffer' => 0,
[   87]   87:     'CacheControl' => $r->dir_config('MungoCacheControl') || 'private',
[   88]   88:     'Charset' => $r->dir_config('MungoCharset') || undef,
[   89]   89:     'Status' => 200,
[   90]   90:     'Mungo' => $parent,
[   91]   91:     'CookieClass' => $r->dir_config('MungoCookieClass') || 'Mungo::Cookie',
[   92]   92:     'Cookies' => undef, # placeholder for visibility
[   93]   93:   );
[   94]   94:   my %data;
[   95]   95:   $singleton = bless \%data, $class;
[   96]   96:   tie %data, 'Mungo::Arbiter::Response', $singleton, \%core_data;
[   97]   97:   $singleton->{Buffer} = $r->dir_config('MungoBuffer') || 0;
[   98]   98:   $r->pnotes(__PACKAGE__, $singleton);
[   99]   99:   return $singleton;
[  100]  100: }
[  101]  101: 
[  102]  102: sub DESTROY {
[  103]  103:   my $self = shift;
[  104]  104:   $self->cleanse();
[  105]  105: }
[  106]  106: 
[  107]  107: sub cleanse {
[  108]  108:   my $self = shift;
[  109]  109:   my $_r = tied %$self;
[  110]  110:   if(ref $_r->{data}->{'IO_stack'} eq 'ARRAY') {
[  111]  111:     while (@{$_r->{data}->{'IO_stack'}}) {
[  112]  112:       my $fh = pop @{$_r->{data}->{'IO_stack'}};
[  113]  113:       close(select($fh));
[  114]  114:     }
[  115]  115:   }
[  116]  116:   delete $_r->{data}->{$_} for keys %$self;
[  117]  117:   untie %$self if tied %$self;
[  118]  118: }
[  119]  119: 
[  120]  120: sub send_http_header {
[  121]  121:   my $self = shift;
[  122]  122:   my $_r = tied %$self;
[  123]  123:   my $r = $_r->{data}->{'Apache::Request'};
[  124]  124:   return if($_r->{data}->{'__HEADERS_SENT__'});
[  125]  125:   $_r->{data}->{'__HEADERS_SENT__'} = 1;
[  126]  126:   if($_r->{data}->{CacheControl} eq 'no-cache') {
[  127]  127:     $r->no_cache(1);
[  128]  128:   }
[  129]  129:   else {
[  130]  130:     if($r->can('headers_out')) {
[  131]  131:       $r->err_headers_out->set('Cache-Control' => $_r->{data}->{CacheControl});
[  132]  132:     }
[  133]  133:     else {
[  134]  134:       $r->err_header_out('Cache-Control' => $_r->{data}->{CacheControl});
[  135]  135:     }
[  136]  136:   }
[  137]  137:   # Must use Internal as the tiehash is magic for cookies
[  138]  138:   $_r->{'__Internal__'}->{Cookies}->inject_headers($r);
[  139]  139:   $r->status($_r->{data}->{Status});
[  140]  140:   $r->can('send_http_header') ?
[  141]  141:     $r->send_http_header($_r->{data}->{ContentType}) :
[  142]  142:     $r->content_type($_r->{data}->{ContentType});;
[  143]  143: }
[  144]  144: 
[  145]  145: sub start {
[  146]  146:   my $self = shift;
[  147]  147:   my $_r = tied %$self;
[  148]  148:   return if(exists $_r->{data}->{'IO_stack'} &&
[  149]  149:             scalar(@{$_r->{data}->{'IO_stack'}}) > 0);
[  150]  150:   $_r->{data}->{'IO_stack'} = [];
[  151]  151:   tie *DIRECT, ref $self, $self;
[  152]  152:   push @{$_r->{data}->{'IO_stack'}}, select(DIRECT);
[  153]  153: }
[  154]  154: 
[  155]  155: sub finish {
[  156]  156:   my $self = shift;
[  157]  157:   my $_r = tied %$self;
[  158]  158:   # Unbuffer outselves, this will actually induce a flush (must go through tiehash)
[  159]  159:   $_r->{'__Internal__'}->{Buffer} = 0;
[  160]  160:   untie *DIRECT if tied *DIRECT;
[  161]  161:   return unless(exists $_r->{data}->{'IO_stack'});
[  162]  162:   my $fh = $_r->{data}->{'IO_stack'}->[0];
[  163]  163:   die __PACKAGE__." IO stack of wrong depth" if(scalar(@{$_r->{data}->{'IO_stack'}}) != 1);
[  164]  164: }
[  165]  165: 
[  166]  166: =head2 $Response->AddHeader('header_name' => 'header_value');
[  167]  167: 
[  168]  168: Adds an HTTP header to the response.
[  169]  169: 
[  170]  170: Dies if headers (or any other output) has already been sent.
[  171]  171: 
[  172]  172: =cut
[  173]  173: 
[  174]  174: sub AddHeader {
[  175]  175:   my $self = shift;
[  176]  176:   my $_r = tied %$self;
[  177]  177:   my $r = $_r->{data}->{'Apache::Request'};
[  178]  178:   die "Headers already sent." if($_r->{data}->{'__HEADERS_SENT__'});
[  179]  179:   $r->can('headers_out') ? $r->err_headers_out->set(@_) : $r->err_header_out(@_);
[  180]  180: }
[  181]  181: sub Cookies {
[  182]  182:   my $self = shift;
[  183]  183:   my $_r = tied %$self;
[* 184]  184:   die "Headers already sent." if($_r->{data}->{'__HEADERS_SENT__'});
[  185]  185:   # Must use Internal as the tiehash is magic for cookies
[  186]  186:   my $cookie = $_r->{'__Internal__'}->{'Cookies'};
[  187]  187:   $cookie->__set(@_);
[  188]  188: }
[  189]  189: 
[  190]  190: =head2 $Response->Redirect($url);
[  191]  191: 
[  192]  192: Issues a 302 redirect with the new location as $url.
[  193]  193: 
[  194]  194: Dies if headers (or any other output) has already been sent.
[  195]  195: 
[  196]  196: =cut
[  197]  197: 
[  198]  198: sub Redirect {
[  199]  199:   my $self = shift;
[  200]  200:   my $url = shift;
[  201]  201:   my $_r = tied %$self;
[  202]  202:   die "Cannot redirect, headers already sent\n" if($_r->{data}->{'__HEADERS_SENT__'});
[  203]  203:   $_r->{data}->{Status} = shift || 302;
[  204]  204:   my $r = $_r->{data}->{'Apache::Request'};
[  205]  205:   $r->can('headers_out') ? $r->err_headers_out->set('Location', $url) :
[  206]  206:                            $r->err_header_out('Location', $url);
[  207]  207:   $self->send_http_header();
[  208]  208:   $self->End();
[  209]  209: }
[  210]  210: 
[  211]  211: 
[  212]  212: =head2 $res->Include($filename, $arg1, $arg2, ...);
[  213]  213: 
[  214]  214: =head2 $res->Include(\$string, $arg1, $arg2, ...);
[  215]  215: 
[  216]  216: Reads the given filename or string and interprets it as Mungo ASP code.
[  217]  217: 
[  218]  218: Any passed arguments are available in the @_ array within the ASP code.
[  219]  219: 
[  220]  220: The results of evaluating the code is printed to STDOUT.
[  221]  221: 
[  222]  222: =cut
[  223]  223: 
[  224]  224: sub Include {
[  225]  225:   my $self = shift;
[  226]  226:   my $subject = shift;
[  227]  227:   my $_r = tied %$self;
[  228]  228:   my $rv;
[  229]  229:   eval {
[  230]  230:     local $SIG{__DIE__} = \&Mungo::MungoDie;
[  231]  231:     if(ref $subject) {
[  232]  232:       $rv = $_r->{data}->{Mungo}->include_mem($subject, @_);
[  233]  233:     }
[  234]  234:     else {
[  235]  235:       $rv = $_r->{data}->{Mungo}->include_file($subject, @_);
[  236]  236:     }
[  237]  237:   };
[  238]  238:   if($@) {
[  239]  239:     # If we have more than 1 item in the IO stack, we should just re-raise.
[  240]  240:     if (scalar(@{$_r->{data}->{'IO_stack'} || []}) > 1) {
[  241]  241:       local $SIG{__DIE__} = undef;
[  242]  242:       die $@;
[  243]  243:     }
[  244]  244:     my $hashref = $@;
[  245]  245:     eval {
[  246]  246:       if($_r->{data}->{OnError}) {
[  247]  247:         $_r->{data}->{OnError}->($self, $hashref, $subject);
[  248]  248:       }
[  249]  249:       else {
[  250]  250:         $self->defaultErrorHandler($hashref, $subject);
[  251]  251:       }
[  252]  252:     };
[  253]  253:     if($@) {
[  254]  254:       # Oh, dear lord this is bad.  We'd died trying to print out death.
[  255]  255:       print STDERR "Mungo::Response -> die in error renderer\n";
[  256]  256:       print STDERR $hashref;
[  257]  257:       print STDERR $@;
[  258]  258:     }
[  259]  259:     return undef;
[  260]  260:   }
[  261]  261:   return $rv;
[  262]  262: }
[  263]  263: 
[  264]  264: sub defaultErrorHandler {
[  265]  265:   use Data::Dumper;
[  266]  266:   my $self = shift;
[  267]  267:   my $href = shift; # Our Error
[  268]  268:   my $subject = shift;
[  269]  269:   my $_r = tied %$self;
[  270]  270:   print "Error in Include($subject):<br />\n";
[  271]  271:   my $pkg = $href->{callstack}->[0]->[0];
[  272]  272:   my $preamble = eval "\$${pkg}::Mungo_preamble;";
[  273]  273:   my $postamble = eval "\$${pkg}::Mungo_postamble;";
[  274]  274:   my $contents = eval "\$${pkg}::Mungo_contents;";
[  275]  275:   print "<pre class=\"error\">$href->{error}</pre><br />\n";
[  276]  276: 
[  277]  277:   unless($contents) {
[  278]  278:     my $filename = $href->{callstack}->[0]->[1];
[  279]  279:     if(open(FILE, "<$filename")) {
[  280]  280:       local $/ = undef;
[  281]  281:       $$contents = <FILE>;
[  282]  282:       close(FILE);
[  283]  283:     }
[  284]  284:   }
[  285]  285: 
[  286]  286:   if($contents) {
[  287]  287:     if($_r->{data}->{'Apache::Request'}->dir_config('Debug')) {
[  288]  288:       print Mungo::Utils::pretty_print_code($preamble, $contents, $postamble, $href->{callstack}->[0]->[2]);
[  289]  289:     }
[  290]  290:   } else {
[  291]  291:     print '<pre>'.Dumper($@).'</pre>';
[  292]  292:   }
[  293]  293: }
[  294]  294: 
[  295]  295: =head2 $output = $Response->TrapInclude($filename, @args);
[  296]  296: 
[  297]  297: Like Include(), but results are returned as a string, instead of being printed.
[  298]  298: 
[  299]  299: =cut
[  300]  300: 
[  301]  301: sub TrapInclude {
[  302]  302:   my $self = shift;
[  303]  303:   my $_r = tied %$self;
[  304]  304:   my $output;
[  305]  305:   my $handle = \do { local *HANDLE };
[  306]  306:   tie *{$handle}, 'Mungo::Response::Trap', \$output;
[  307]  307:   push @{$_r->{data}->{'IO_stack'}}, select(*{$handle});
[  308]  308:   eval {
[  309]  309:     $self->Include(@_);
[  310]  310:   };
[  311]  311:   untie *{$handle} if tied *{$handle};
[  312]  312:   select(pop @{$_r->{data}->{'IO_stack'}});
[  313]  313:   if($@) {
[  314]  314:     local $SIG{__DIE__} = undef;
[  315]  315:     die $@;
[  316]  316:   }
[  317]  317:   return $output;
[  318]  318: }
[  319]  319: 
[  320]  320: =head2 $Response->End()
[  321]  321: 
[  322]  322: Stops processing the current response, shuts down the 
[  323]  323: output handle, and jumps out of the response handler.  
[  324]  324: No further processing will occur.
[  325]  325: 
[  326]  326: =cut
[  327]  327: 
[  328]  328: sub End {
[  329]  329:   my $self = shift;
[  330]  330:   my $_r = tied %$self;
[  331]  331:   while(scalar(@{$_r->{data}->{'IO_stack'} || []}) > 1) {
[  332]  332:     my $oldfh = select(pop @{$_r->{data}->{'IO_stack'}});
[  333]  333:     if(my $obj = tied *{$oldfh}) {
[  334]  334:       untie *{$oldfh};
[  335]  335:       print $$obj;
[  336]  336:     }
[  337]  337:   }
[  338]  338:   $self->Flush();
[  339]  339:   eval { goto  MUNGO_HANDLER_FINISH; }; # Jump back to Mungo::handler()
[  340]  340: }
[  341]  341: 
[  342]  342: sub Flush {
[  343]  343:   my $self = shift;
[  344]  344:   my $_r = tied %$self;
[  345]  345:   # Flush doesn't apply unless we're immediately above STDOUT
[  346]  346:   return if(scalar(@{$_r->{data}->{'IO_stack'} || []}) > 1);
[  347]  347:   unless($_r->{data}->{'__OUTPUT_STARTED__'}) {
[  348]  348:     $self->send_http_header;
[  349]  349:     $_r->{data}->{'__OUTPUT_STARTED__'} = 1;
[  350]  350:   }
[  351]  351:   if (@{$_r->{data}->{'IO_stack'} || []}) {
[  352]  352:       $_r->{data}->{'IO_stack'}->[-1]->print($one_true_buffer);
[  353]  353:   } else {
[  354]  354:       print $one_true_buffer;
[  355]  355:   }
[  356]  356: 
[  357]  357:   $one_true_buffer = '';
[  358]  358: }
[  359]  359: 
[  360]  360: sub AUTOLOAD {
[  361]  361:   my $self = shift;
[  362]  362:   my $name = $AUTOLOAD;
[  363]  363:   $name =~ s/.*://;   # strip fully-qualified portion
[  364]  364:   die __PACKAGE__." does not implement $name";
[  365]  365: }
[  366]  366: 
[  367]  367: sub TIEHANDLE {
[  368]  368:   my $class = shift;
[  369]  369:   my $self = shift;
[  370]  370:   return $self;
[  371]  371: }
[  372]  372: sub PRINT {
[  373]  373:   my $self = shift;
[  374]  374:   my $output = shift;
[  375]  375:   my $_r = tied %$self;
[  376]  376:   if(scalar(@{$_r->{data}->{'IO_stack'} || []}) == 1) {
[  377]  377:     # Buffering a just-in-time headers only applies if we
[  378]  378:     # immediately above STDOUT
[  379]  379:     if($_r->{data}->{Buffer}) {
[  380]  380:       $one_true_buffer .= $output;
[  381]  381:       return;
[  382]  382:     }
[  383]  383:     unless($_r->{data}->{'__OUTPUT_STARTED__'}) {
[  384]  384:       $_r->{data}->{'__OUTPUT_STARTED__'} = 1;
[  385]  385:       $self->send_http_header;
[  386]  386:     }
[  387]  387:   }
[  388]  388:   if (@{$_r->{data}->{'IO_stack'} || []}) {
[  389]  389:       $_r->{data}->{'IO_stack'}->[-1]->print($output);
[  390]  390:   } else {
[  391]  391:       print $output;
[  392]  392:   }
[  393]  393: }
[  394]  394: sub PRINTF {
[  395]  395:   my $self = shift;
[  396]  396:   my $_r = tied %$self;
[  397]  397:   if(scalar(@{$_r->{data}->{'IO_stack'} || []}) == 1) {
[  398]  398:     # Buffering a just-in-time headers only applies if we
[  399]  399:     # immediately above STDOUT
[  400]  400:     if($_r->{data}->{Buffer}) {
[  401]  401:       $one_true_buffer .= sprintf(@_);
[  402]  402:       return;
[  403]  403:     }
[  404]  404:     unless($_r->{data}->{'__OUTPUT_STARTED__'}) {
[  405]  405:       $_r->{data}->{'__OUTPUT_STARTED__'} = 1;
[  406]  406:       $self->send_http_header;
[  407]  407:     }
[  408]  408:   }
[  409]  409:   if (@{$_r->{data}->{'IO_stack'} || []}) {
[  410]  410:       $_r->{data}->{'IO_stack'}->[-1]->printf(@_);
[  411]  411:   } else {
[  412]  412:       printf(@_);
[  413]  413:   }
[  414]  414: }
[  415]  415: sub CLOSE {
[  416]  416:   my $self = shift;
[  417]  417:   my $_r = tied %$self;
[  418]  418:   # Unbuffer outselves, this will actually induce a flush (must go through tiehash)
[  419]  419:   $_r->{data}->{Buffer} = 0;
[  420]  420: }
[  421]  421: sub UNTIE { }
[  422]  422: 
[  423]  423: =head1 AUTHOR
[  424]  424: 
[  425]  425: Theo Schlossnagle
[  426]  426: 
[  427]  427: Clinton Wolfe (docs)
[  428]  428: 
[  429]  429: =cut
[  430]  430: 
[  431]  431: 1;