| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Hub::Webapp::Response; | 
| 2 | 1 |  |  | 1 |  | 9 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 47 |  | 
| 3 | 1 |  |  | 1 |  | 7 | use Hub qw/:lib/; | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 8 |  | 
| 4 |  |  |  |  |  |  | our $VERSION = '4.00043'; | 
| 5 |  |  |  |  |  |  | our @EXPORT = qw//; | 
| 6 |  |  |  |  |  |  | our @EXPORT_OK = qw/ | 
| 7 |  |  |  |  |  |  | respond | 
| 8 |  |  |  |  |  |  | /; | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | # ------------------------------------------------------------------------------ | 
| 11 |  |  |  |  |  |  | # respond - Print response to STDOUT | 
| 12 |  |  |  |  |  |  | # ------------------------------------------------------------------------------ | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | sub respond { | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | # Request object | 
| 17 | 0 |  |  | 0 | 1 |  | my $reqrec = shift; | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | # Munge /cgi data to protect from XSS attacks | 
| 20 | 0 |  |  |  |  |  | foreach my $k (keys %{$$Hub{'/cgi'}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | } | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | # Merge templates with values | 
| 24 | 0 |  |  |  |  |  | my $contents = ''; | 
| 25 | 0 |  |  |  |  |  | my $response_template = Hub::getaddr($$Hub{'/sys/response/template'}); | 
| 26 | 0 | 0 |  |  |  |  | return unless defined $response_template; | 
| 27 | 0 |  |  |  |  |  | my $file = $$Hub{$response_template}; | 
| 28 | 0 | 0 |  |  |  |  | if (can($file, 'get_content')) { | 
| 29 | 0 |  |  |  |  |  | $contents = $file->get_content(); | 
| 30 |  |  |  |  |  |  | } | 
| 31 | 0 |  |  |  |  |  | my $parser = Hub::mkinst('HtmlParser', -template => \$contents); | 
| 32 | 0 |  | 0 |  |  |  | my $output = $parser->populate($Hub) || ''; | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | # Glean headers from registry | 
| 35 | 0 |  |  |  |  |  | my $headers = {}; | 
| 36 | 0 |  |  |  |  |  | my $rh = $$Hub{'/sys/response/headers'}; | 
| 37 | 0 | 0 |  |  |  |  | if (isa($rh, 'ARRAY')) { | 
| 38 | 0 |  |  |  |  |  | for (@$rh) { | 
| 39 | 0 |  |  |  |  |  | my ($k, $v) = /([^:]+)\s*:\s*(.*)/; | 
| 40 | 0 |  |  |  |  |  | $headers->{lc($k)} = $v; | 
| 41 |  |  |  |  |  |  | } | 
| 42 |  |  |  |  |  |  | } | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | # Parse headers from output | 
| 45 | 0 |  |  |  |  |  | my $crown = substr($$output, 0, 500); | 
| 46 | 0 |  |  |  |  |  | my $crop = 0; | 
| 47 | 0 |  |  |  |  |  | for (split /[\r\n]+/, $crown) { | 
| 48 | 0 |  |  |  |  |  | my @fields = /^([a-z\-_]+)\s*:\s*(.*)/i; | 
| 49 | 0 | 0 |  |  |  |  | if (@fields) { | 
| 50 | 0 |  |  |  |  |  | $headers->{lc($fields[0])} = $fields[1]; | 
| 51 | 0 |  |  |  |  |  | $crop = Hub::indexmatch($crown, '[\r\n]+', $crop, -after); | 
| 52 | 0 | 0 |  |  |  |  | $crop = length($crown) if $crop < 0; | 
| 53 |  |  |  |  |  |  | } else { | 
| 54 | 0 |  |  |  |  |  | last; | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  | } | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | # Oputput headers | 
| 59 | 0 | 0 |  |  |  |  | unless ($$headers{'content-type'}) { | 
| 60 | 0 |  |  |  |  |  | my ($encoding,$type,$header) = | 
| 61 |  |  |  |  |  |  | _get_content_headers(Hub::getext($response_template)); | 
| 62 | 0 |  |  |  |  |  | $headers->{'content-type'} = $type; | 
| 63 |  |  |  |  |  |  | } | 
| 64 | 0 |  |  |  |  |  | my $output_headers = ''; | 
| 65 | 0 |  |  |  |  |  | for (keys %$headers) { | 
| 66 | 0 | 0 |  |  |  |  | /content-type/ and next; | 
| 67 | 0 |  |  |  |  |  | $output_headers .= ucfirst($_) . ": $$headers{$_}\n" | 
| 68 |  |  |  |  |  |  | } | 
| 69 | 0 |  |  |  |  |  | $output_headers .= "Content-Type: $$headers{'content-type'}\n\n"; | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | # Send output | 
| 72 | 0 | 0 |  |  |  |  | if (can($reqrec, 'print')) { | 
| 73 | 0 | 0 |  |  |  |  | $output_headers and $reqrec->print($output_headers); | 
| 74 | 0 | 0 |  |  |  |  | $reqrec->print($crop > 0 ? substr($$output, $crop) : $$output); | 
| 75 |  |  |  |  |  |  | } else { | 
| 76 | 0 | 0 |  |  |  |  | $output_headers and print STDOUT $output_headers; | 
| 77 | 0 | 0 |  |  |  |  | print STDOUT $crop > 0 ? substr($$output, $crop) : $$output; | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | # | 
| 81 |  |  |  |  |  |  | # # Echo the response to file (debugging headers) | 
| 82 |  |  |  |  |  |  | # if ($$Hub{'/sys/ENV/DEBUG'}) { | 
| 83 |  |  |  |  |  |  | #   if (defined $$Hub{'/session'}) { | 
| 84 |  |  |  |  |  |  | #     my $dir = $$Hub{'/session/directory'}; | 
| 85 |  |  |  |  |  |  | #     if (-d $dir) { | 
| 86 |  |  |  |  |  |  | #       my $fn = $dir . '/' . Hub::getname($response_template); | 
| 87 |  |  |  |  |  |  | #       Hub::writefile($fn, $output_headers . $$output); | 
| 88 |  |  |  |  |  |  | #     } | 
| 89 |  |  |  |  |  |  | #   } | 
| 90 |  |  |  |  |  |  | # } | 
| 91 |  |  |  |  |  |  | # | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | # ------------------------------------------------------------------------------ | 
| 96 |  |  |  |  |  |  | # _get_content_headers - Standard HTTP headers by file extension | 
| 97 |  |  |  |  |  |  | # _get_content_headers $ext | 
| 98 |  |  |  |  |  |  | # Return an array of headers ($content_encoding, $content_type, [other..]) | 
| 99 |  |  |  |  |  |  | # ------------------------------------------------------------------------------ | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | sub _get_content_headers { | 
| 102 | 0 |  | 0 | 0 |  |  | my $ext = lc(shift) || ''; | 
| 103 |  |  |  |  |  |  | # Create the map | 
| 104 | 0 |  | 0 |  |  |  | $$Hub{"/conf/content_types"} ||= { | 
| 105 |  |  |  |  |  |  | htm => { | 
| 106 |  |  |  |  |  |  | type => 'text/html', | 
| 107 |  |  |  |  |  |  | }, | 
| 108 |  |  |  |  |  |  | html => { | 
| 109 |  |  |  |  |  |  | type => 'text/html', | 
| 110 |  |  |  |  |  |  | }, | 
| 111 |  |  |  |  |  |  | js => { | 
| 112 |  |  |  |  |  |  | type => 'text/javascript', | 
| 113 |  |  |  |  |  |  | }, | 
| 114 |  |  |  |  |  |  | css => { | 
| 115 |  |  |  |  |  |  | type => 'text/css', | 
| 116 |  |  |  |  |  |  | }, | 
| 117 |  |  |  |  |  |  | txt => { | 
| 118 |  |  |  |  |  |  | type => 'text/plain', | 
| 119 |  |  |  |  |  |  | }, | 
| 120 |  |  |  |  |  |  | }; | 
| 121 |  |  |  |  |  |  | # Lookup by file extension | 
| 122 | 0 |  | 0 |  |  |  | my $content_types = $$Hub{"/conf/content_types/$ext"} || {}; | 
| 123 | 0 |  | 0 |  |  |  | my $e = $content_types->{'encoding'} || ""; | 
| 124 | 0 |  | 0 |  |  |  | my $t = $content_types->{'type'} || "text/html"; | 
| 125 | 0 |  | 0 |  |  |  | my $h = $content_types->{'header'} || ""; | 
| 126 | 0 |  |  |  |  |  | return ($e,$t,$h); | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | #------------------------------------------------------------------------------- | 
| 130 |  |  |  |  |  |  | 1; | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | __END__ |