Apache2-CondProxy

 view release on metacpan or  search on metacpan

lib/Apache2/CondProxy.pm  view on Meta::CPAN

        }
        else {
            my $uri = $r->unparsed_uri;
            $r->log->debug("Attempting lookup on $uri");
            my $subr = _make_subreq($r, $uri);

            # set the content-type and content-length in the subrequest
            my $ct = $r->headers_in->get('Content-Type');
            $subr->headers_in->set('Content-Type', $ct) if $ct;
            my $cl = $r->headers_in->get('Content-Length');
            $subr->headers_in->set('Content-Length', $cl) if $cl;

            # remove Accept-Encoding headers for proxy
            my $ae = $r->headers_in->get('Accept-Encoding');
            $r->headers_in->unset('Accept-Encoding');

            if ($subr->status == 404) {
                $r->log->debug('Proxying before subrequest is run');
                return _do_proxy($r);
            }

            $r->log->debug(
                sprintf 'Results inconclusive: %d; running subrequest',
                $subr->status);

            $subr->add_input_filter(\&_input_filter_tee);
            $subr->add_output_filter(\&_output_filter_hold);
            my $rv = $subr->run;

            # we only care about 404
            my $st = $subr->status;
            if (grep { $rv == $_ || $st == $_ } (403, 404)) {
                $r->log->debug("Proxying $uri after subrequest is run");
                return _do_proxy($r);
            }
            else {
                # override the subrequest status
                $subr->status($rv) if $subr->status != $rv && $rv != 0;
                $r->status($subr->status);

                # replace Accept-Encoding header
                $r->headers_in->set('Accept-Encoding', $ae) if $ae;

                $r->log->debug(
                    sprintf 'Subrequest returned %d; serving content for %s',
                    $subr->status, $uri);

                # copy headers from subreq
                $r->headers_out->overlap
                    ($subr->headers_out, APR::Const::OVERLAP_TABLES_SET);
                $r->err_headers_out->overlap
                    ($subr->err_headers_out, APR::Const::OVERLAP_TABLES_SET);

                # apparently content_type has to be done separately
                #$r->log->debug($subr->content_type);
                $r->content_type($subr->content_type) if $subr->content_type;
                $r->content_encoding($subr->content_encoding)
                    if $subr->content_encoding;
                $r->set_last_modified($subr->mtime) if $subr->mtime;

                $r->SUPER::handler('modperl');
                $r->set_handlers(PerlResponseHandler => \&_response_handler);
                $r->push_handlers(PerlCleanupHandler => \&_cleanup_handler);
                $r->add_output_filter(\&_output_filter_release);

                return Apache2::Const::OK;
            }
        }
    }

    Apache2::Const::OK;
}

sub _make_subreq {
    my ($r, $uri) = @_;

    $uri = $r->unparsed_uri unless defined $uri;

    my $subr = $r->lookup_method_uri($r->method, $uri);

    # set the content-type and content-length in the subrequest
    my $ct = $r->headers_in->get('Content-Type');
    $subr->headers_in->set('Content-Type', $ct) if $ct;
    my $cl = $r->headers_in->get('Content-Length');
    $subr->headers_in->set('Content-Length', $cl) if $cl;

    # remove this so no gzip filter etc happens
    $subr->headers_in->unset('Accept-Encoding');

    $subr;
}

sub _do_proxy {
    my ($r, $first) = @_;
    my $c = $r->connection;

    my $base  = URI->new($r->dir_config('ProxyTarget'))->canonical;
    my $match = $r->dir_config('MatchScheme') || '';
    $match = scalar($match =~ $TRUE);
    if ($match) {
        $c->is_https ? $base->scheme('https') : $base->scheme('http');
    }

    # just do this.
    $base = URI->new_abs(substr($r->unparsed_uri, 1), $base);
    # for some reason mod_proxy mysteriously started double-escaping
    # URIs. AHA: MAGIC.
    $r->notes->set('proxy-nocanon', 1);

    $r->filename(sprintf 'proxy:%s', $base);
    $r->proxyreq(Apache2::Const::PROXYREQ_REVERSE);
    $r->SUPER::handler('proxy-server');

    $r->add_output_filter(\&_output_filter_fix_location);
    if ($first) {
        $r->push_handlers(PerlCleanupHandler => \&_cleanup_handler);
        $r->add_input_filter(\&_input_filter_tee);
        $r->add_output_filter(\&_output_filter_local);
    }
    else {
        $r->add_input_filter(\&_input_filter_replay);
    }

    return Apache2::Const::OK;
}

sub _do_local {
    my ($r, $subr) = @_;
}


# XXX this is the only way I could think of to get at the Location
# header after mod_proxy took over. Could be problematic if another
# filter in the stack flushes output before this one gets run.
sub _output_filter_fix_location {
    my ($f, $bb) = @_;
    my $c = $f->c;
    my $r = $f->r;

    #my $mainr = $r->main || $r;
    unless ($f->ctx) {
        _fix_location($r, $c);
        $f->ctx(1);
    }

    Apache2::Const::DECLINED;
}

sub _fix_location {
    my $r = shift;
    my $c = shift || $r->connection;

    my $loc  = $r->headers_out->get('Location');
    if ($loc) {
        my $match = $r->dir_config('MatchScheme') || '';
        $match = scalar($match =~ $TRUE);

        # get the hostname of the request, failing that, the server name
        my $host = $r->headers_in->get('Host')
            || $r->server->server_hostname;
        $host = ($c->is_https ? 'https://' : 'http://') . $host;
        $host = URI->new($host)->canonical;

        # get the proxy base
        my $base = URI->new($r->dir_config('ProxyTarget'))->canonical;
        if ($match) {
            $c->is_https ? $base->scheme('https') : $base->scheme('http');
        }

        # fix for malformed (i.e. relative) Location header
        $loc = URI->new_abs($loc, $base);
        $loc = $loc->canonical;



( run in 0.390 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )