package Apache2::Mojo; our $VERSION = '0.004'; use strict; use warnings; use Apache2::Connection; use Apache2::Const -compile => qw(OK); use Apache2::RequestIO; use Apache2::RequestRec; use Apache2::RequestUtil; use Apache2::URI; use APR::SockAddr; use APR::Table; use APR::URI; use Mojo::Loader; eval "use Apache2::ModSSL"; if ($@) { *_is_https = \&_is_https_fallback; } else { *_is_https = \&_is_https_modssl; } my $_app = undef; sub _app { if ($ENV{MOJO_RELOAD} and $_app) { Mojo::Loader->reload; $_app = undef; } $_app ||= Mojo::Loader->load_build($ENV{MOJO_APP} || 'Mojo::HelloWorld'); return $_app; } sub handler { my $r = shift; # call _app() only once (because of MOJO_RELOAD) my $app = _app; my $tx = $app->build_tx; # Transaction _transaction($r, $tx); # Request _request($r, $tx->req); # Handler $app->handler($tx); my $res = $tx->res; # Response _response($r, $res); return Apache2::Const::OK; } sub _transaction { my ($r, $tx) = @_; # local and remote address (needs Mojo 0.9002) if ($tx->can('remote_address')) { my $c = $r->connection; my $local_sa = $c->local_addr; $tx->local_address($local_sa->ip_get); $tx->local_port($local_sa->port); my $remote_sa = $c->remote_addr; $tx->remote_address($remote_sa->ip_get); $tx->remote_port($remote_sa->port); } } sub _request { my ($r, $req) = @_; my $url = $req->url; my $base = $url->base; # headers my $headers = $r->headers_in; foreach my $key (keys %$headers) { $req->headers->header($key, $headers->get($key)); } # path if ($r->location eq '/') { # bug in older mod_perl (e. g. 2.0.3 in Ubuntu Hardy LTS) $url->path->parse($r->uri); } else { $url->path->parse($r->path_info); } # query $url->query->parse($r->parsed_uri->query); # method $req->method($r->method); # base path $base->path->parse($r->location); # host/port my $host = $r->get_server_name; my $port = $r->get_server_port; $url->host($host); $url->port($port); $base->host($host); $base->port($port); # scheme my $scheme = _is_https($r) ? 'https' : 'http'; $url->scheme($scheme); $base->scheme($scheme); # version if ($r->protocol =~ m|^HTTP/(\d+\.\d+)$|) { $req->version($1); } else { $req->version('0.9'); } # body $req->state('content'); $req->content->state('body'); my $offset = 0; while (!$req->is_finished) { last unless (my $read = $r->read(my $buffer, 4096, $offset)); $offset += $read; $req->parse($buffer); } } sub _response { my ($r, $res) = @_; # status $r->status($res->code); # headers $res->fix_headers; my $headers = $res->headers; foreach my $key (@{$headers->names}) { my @value = $headers->header($key); next unless @value; # special treatment for content-type if ($key eq 'Content-Type') { $r->content_type($value[0]); } else { $r->headers_out->set($key => shift @value); $r->headers_out->add($key => $_) foreach (@value); } } # body my $offset = 0; while (1) { my $chunk = $res->get_body_chunk($offset); # No content yet, try again unless (defined $chunk) { sleep 1; next; } # End of content last unless length $chunk; # Content my $written = $r->print($chunk); $offset += $written; } } sub _is_https_modssl { my ($r) = @_; return $r->connection->is_https; } sub _is_https_fallback { my ($r) = @_; return $r->get_server_port == 443; } 1; __END__ =pod =head1 NAME Apache2::Mojo - mod_perl2 handler for Mojo =head1 VERSION version 0.004 =head1 SYNOPSIS in httpd.conf: use lib '...'; use Apache2::Mojo; use TestApp; SetHandler perl-script PerlSetEnv MOJO_APP TestApp PerlHandler Apache2::Mojo =head1 DESCRIPTION This is a mod_perl2 handler for L/L. Set the application class with the environment variable C. C is also supported (e. g. C). =head1 SEE ALSO L, L, L. =head1 AUTHOR Uwe Voelker, =cut