blob: bbad2586710718464f7e79e8c6d575486722e06a [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pagespeed/apache/apache_request_context.h"
#include "base/logging.h"
#include "pagespeed/apache/interface_mod_spdy.h"
#include "pagespeed/apache/mod_spdy_fetcher.h"
#include "net/instaweb/http/public/request_context.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/http/http_names.h"
#include "httpd.h" // NOLINT
namespace net_instaweb {
ApacheRequestContext::ApacheRequestContext(
AbstractMutex* logging_mutex, Timer* timer, request_rec* req)
: SystemRequestContext(
logging_mutex,
timer,
req->hostname,
req->connection->local_addr->port,
req->connection->local_ip),
use_spdy_fetcher_(ModSpdyFetcher::ShouldUseOn(req)),
spdy_connection_factory_(NULL) {
// Note that at the time we create a RequestContext we have full
// access to the Apache request_rec. However, due to Cloning and (I
// believe) Detaching, we can initiate fetches after the Apache
// request_rec* has been retired. So deep-copy the bits we need
// from the request_rec at the time we create our RequestContext.
// This includes the local port (for loopback fetches) and the
// entire connection subobject, for backdoor mod_spdy fetches. To
// avoid temptation we do not keep a pointer to the request_rec.
// Determines whether we should handle request as SPDY.
// This happens in two cases:
// 1) It's actually a SPDY request using mod_spdy
// 2) The header X-PSA-Optimize-For-SPDY is present, with any value.
if (mod_spdy_get_spdy_version(req->connection) != 0) {
set_using_spdy(true);
} else {
const char* value = apr_table_get(req->headers_in,
HttpAttributes::kXPsaOptimizeForSpdy);
set_using_spdy(value != NULL);
}
}
ApacheRequestContext::~ApacheRequestContext() {
if (spdy_connection_factory_ != NULL) {
mod_spdy_destroy_slave_connection_factory(spdy_connection_factory_);
}
}
void ApacheRequestContext::SetupSpdyConnectionIfNeeded(request_rec* req) {
// Independent of whether we are serving a SPDY request, we will want
// to be able to do back door mod_spdy fetches if configured to do so.
if (use_spdy_fetcher_) {
// TODO(jmarantz): mdsteele indicates this is not overly expensive to
// do per-request. Verify this with profiling.
spdy_connection_factory_ =
mod_spdy_create_slave_connection_factory(req->connection);
}
}
ApacheRequestContext* ApacheRequestContext::DynamicCast(RequestContext* rc) {
if (rc == NULL) {
return NULL;
}
ApacheRequestContext* out = dynamic_cast<ApacheRequestContext*>(rc);
DCHECK(out != NULL) << "Invalid request conversion. Do not rely on RTTI for "
<< "functional behavior. Apache handling flows must use "
<< "ApacheRequestContexts.";
return out;
}
} // namespace net_instaweb