File Coverage

blib/lib/Apache2/Mojo.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Apache2::Mojo;
2             our $VERSION = '0.004';
3              
4              
5 1     1   734 use strict;
  1         1  
  1         43  
6 1     1   6 use warnings;
  1         3  
  1         36  
7              
8 1     1   384 use Apache2::Connection;
  0            
  0            
9             use Apache2::Const -compile => qw(OK);
10             use Apache2::RequestIO;
11             use Apache2::RequestRec;
12             use Apache2::RequestUtil;
13             use Apache2::URI;
14             use APR::SockAddr;
15             use APR::Table;
16             use APR::URI;
17              
18             use Mojo::Loader;
19              
20              
21             eval "use Apache2::ModSSL";
22             if ($@) {
23             *_is_https = \&_is_https_fallback;
24             } else {
25             *_is_https = \&_is_https_modssl;
26             }
27              
28             my $_app = undef;
29              
30              
31             sub _app {
32             if ($ENV{MOJO_RELOAD} and $_app) {
33             Mojo::Loader->reload;
34             $_app = undef;
35             }
36             $_app ||= Mojo::Loader->load_build($ENV{MOJO_APP} || 'Mojo::HelloWorld');
37             return $_app;
38             }
39              
40             sub handler {
41             my $r = shift;
42              
43             # call _app() only once (because of MOJO_RELOAD)
44             my $app = _app;
45             my $tx = $app->build_tx;
46              
47             # Transaction
48             _transaction($r, $tx);
49              
50             # Request
51             _request($r, $tx->req);
52              
53             # Handler
54             $app->handler($tx);
55              
56             my $res = $tx->res;
57              
58             # Response
59             _response($r, $res);
60              
61             return Apache2::Const::OK;
62             }
63              
64             sub _transaction {
65             my ($r, $tx) = @_;
66              
67             # local and remote address (needs Mojo 0.9002)
68             if ($tx->can('remote_address')) {
69             my $c = $r->connection;
70             my $local_sa = $c->local_addr;
71             $tx->local_address($local_sa->ip_get);
72             $tx->local_port($local_sa->port);
73             my $remote_sa = $c->remote_addr;
74             $tx->remote_address($remote_sa->ip_get);
75             $tx->remote_port($remote_sa->port);
76             }
77             }
78              
79             sub _request {
80             my ($r, $req) = @_;
81              
82             my $url = $req->url;
83             my $base = $url->base;
84              
85             # headers
86             my $headers = $r->headers_in;
87             foreach my $key (keys %$headers) {
88             $req->headers->header($key, $headers->get($key));
89             }
90              
91             # path
92             if ($r->location eq '/') {
93             # bug in older mod_perl (e. g. 2.0.3 in Ubuntu Hardy LTS)
94             $url->path->parse($r->uri);
95             } else {
96             $url->path->parse($r->path_info);
97             }
98              
99             # query
100             $url->query->parse($r->parsed_uri->query);
101              
102             # method
103             $req->method($r->method);
104              
105             # base path
106             $base->path->parse($r->location);
107              
108             # host/port
109             my $host = $r->get_server_name;
110             my $port = $r->get_server_port;
111             $url->host($host);
112             $url->port($port);
113             $base->host($host);
114             $base->port($port);
115              
116             # scheme
117             my $scheme = _is_https($r) ? 'https' : 'http';
118             $url->scheme($scheme);
119             $base->scheme($scheme);
120              
121             # version
122             if ($r->protocol =~ m|^HTTP/(\d+\.\d+)$|) {
123             $req->version($1);
124             } else {
125             $req->version('0.9');
126             }
127              
128             # body
129             $req->state('content');
130             $req->content->state('body');
131             my $offset = 0;
132             while (!$req->is_finished) {
133             last unless (my $read = $r->read(my $buffer, 4096, $offset));
134             $offset += $read;
135             $req->parse($buffer);
136             }
137             }
138              
139             sub _response {
140             my ($r, $res) = @_;
141              
142             # status
143             $r->status($res->code);
144              
145             # headers
146             $res->fix_headers;
147             my $headers = $res->headers;
148             foreach my $key (@{$headers->names}) {
149             my @value = $headers->header($key);
150             next unless @value;
151              
152             # special treatment for content-type
153             if ($key eq 'Content-Type') {
154             $r->content_type($value[0]);
155             } else {
156             $r->headers_out->set($key => shift @value);
157             $r->headers_out->add($key => $_) foreach (@value);
158             }
159             }
160              
161             # body
162             my $offset = 0;
163             while (1) {
164             my $chunk = $res->get_body_chunk($offset);
165              
166             # No content yet, try again
167             unless (defined $chunk) {
168             sleep 1;
169             next;
170             }
171              
172             # End of content
173             last unless length $chunk;
174              
175             # Content
176             my $written = $r->print($chunk);
177             $offset += $written;
178             }
179             }
180              
181             sub _is_https_modssl {
182             my ($r) = @_;
183              
184             return $r->connection->is_https;
185             }
186              
187             sub _is_https_fallback {
188             my ($r) = @_;
189              
190             return $r->get_server_port == 443;
191             }
192              
193              
194             1;
195              
196             __END__