blob: 51c0d56ff040985c953e878bef67c16940f7f4a3 [file] [log] [blame]
// Copyright 2011 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.
//
// Author: jmarantz@google.com (Joshua Marantz)
#include "pagespeed/apache/apache_server_context.h"
// http_protocol.h includes httpd.h. We need to include httpd_includes.h, which
// works around a conflicting definition of OK in gRPC.
#include "pagespeed/apache/apache_httpd_includes.h"
#include "http_protocol.h" // NOLINT
#include "pagespeed/apache/apache_config.h"
#include "pagespeed/apache/apache_request_context.h"
#include "pagespeed/apache/apache_rewrite_driver_factory.h"
#include "pagespeed/automatic/proxy_fetch.h"
#include "pagespeed/automatic/proxy_interface.h"
#include "pagespeed/kernel/base/file_system.h"
#include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/statistics.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/thread_system.h"
#include "pagespeed/kernel/http/http_names.h"
#include "net/instaweb/config/measurement_proxy_rewrite_options_manager.h"
#include "net/instaweb/rewriter/public/measurement_proxy_url_namer.h"
namespace net_instaweb {
const char ApacheServerContext::kProxyInterfaceStatsPrefix[] =
"proxy-all-mode-";
ApacheServerContext::ApacheServerContext(
ApacheRewriteDriverFactory* factory,
server_rec* server,
const StringPiece& version)
: SystemServerContext(factory, server->server_hostname, server->port),
apache_factory_(factory),
server_rec_(server),
version_(version.data(), version.size()) {
// We may need the message handler for error messages very early, before
// we get to InitServerContext in ChildInit().
set_message_handler(apache_factory_->message_handler());
// Currently, mod_pagespeed always runs upstream of mod_headers when used as
// an origin server. Note that in a proxy application, this might not be the
// case. I'm not sure how we can detect this on a per-request basis so
// that might require a small refactor.
//
// TODO(jmarantz): We'd like to change this for various reasons but are unsure
// of the impact.
set_response_headers_finalized(false);
}
ApacheServerContext::~ApacheServerContext() {
}
void ApacheServerContext::InitStats(Statistics* statistics) {
ProxyInterface::InitStats(kProxyInterfaceStatsPrefix, statistics);
SystemServerContext::InitStats(statistics);
}
bool ApacheServerContext::InitPath(const GoogleString& path) {
if (file_system()->IsDir(path.c_str(), message_handler()).is_true()) {
return true;
}
bool ok = file_system()->RecursivelyMakeDir(path, message_handler());
if (ok) {
apache_factory_->AddCreatedDirectory(path);
}
return ok;
}
ApacheConfig* ApacheServerContext::global_config() {
return ApacheConfig::DynamicCast(global_options());
}
const ApacheConfig* ApacheServerContext::global_config() const {
return ApacheConfig::DynamicCast(global_options());
}
ApacheConfig* ApacheServerContext::SpdyConfigOverlay() {
// While we no longer actually use the spdy config overlay, it's still
// useful for backwards compatibility during parsing.
if (spdy_config_overlay_.get() == NULL) {
spdy_config_overlay_.reset(new ApacheConfig(
"spdy_overlay", thread_system()));
// We want to copy any implicit rewrite level from the parent,
// so we don't end up overriding it with passthrough. It's also OK
// to forward explicit one to an implicit one here, since an implicit
// will never override an explicit one (even if its different).
spdy_config_overlay_->SetDefaultRewriteLevel(global_config()->level());
}
return spdy_config_overlay_.get();
}
ApacheConfig* ApacheServerContext::NonSpdyConfigOverlay() {
if (non_spdy_config_overlay_.get() == NULL) {
non_spdy_config_overlay_.reset(new ApacheConfig(
"non_spdy_overlay", thread_system()));
// See ::SpdyConfigOverlay for explanation.
non_spdy_config_overlay_->SetDefaultRewriteLevel(global_config()->level());
}
return non_spdy_config_overlay_.get();
}
void ApacheServerContext::CollapseConfigOverlaysAndComputeSignatures() {
// These days we ignore the spdy overlay and merge-in the non-spdy one
// unconditionally.
if (non_spdy_config_overlay_.get() != NULL) {
global_config()->Merge(*non_spdy_config_overlay_);
}
SystemServerContext::CollapseConfigOverlaysAndComputeSignatures();
spdy_config_overlay_.reset();
non_spdy_config_overlay_.reset();
}
bool ApacheServerContext::PoolDestroyed() {
DCHECK_EQ(num_active_rewrite_drivers(), 0);
return apache_factory_->PoolDestroyed(this);
}
void ApacheServerContext::InitProxyFetchFactory() {
proxy_fetch_factory_.reset(new ProxyFetchFactory(this));
}
ApacheRequestContext* ApacheServerContext::NewApacheRequestContext(
request_rec* request) {
return new ApacheRequestContext(
thread_system()->NewMutex(),
timer(),
request);
}
void ApacheServerContext::ReportNotFoundHelper(MessageType message_type,
StringPiece error_message,
request_rec* request,
Variable* error_count) {
error_count->Add(1);
request->status = HttpStatus::kNotFound;
ap_send_error_response(request, 0);
message_handler()->Message(message_type, "%s %s: not found (404)",
(error_message.empty() ? "(null)" :
error_message.as_string().c_str()),
error_count->GetName().as_string().c_str());
}
GoogleString ApacheServerContext::FormatOption(StringPiece option_name,
StringPiece args) {
return StrCat("ModPagespeed", option_name, " ", args);
}
void ApacheServerContext::ChildInit(SystemRewriteDriverFactory* f) {
if (global_config()->proxy_all_requests_mode()) {
apache_factory_->SetNeedSchedulerThread();
if (global_config()->measurement_proxy_mode()) {
measurement_url_namer_.reset(new MeasurementProxyUrlNamer(
global_config()->measurement_proxy_root(),
global_config()->measurement_proxy_password()));
set_url_namer(measurement_url_namer_.get());
SetRewriteOptionsManager(new MeasurementProxyRewriteOptionsManager(
this,
global_config()->measurement_proxy_root(),
global_config()->measurement_proxy_password()));
}
}
SystemServerContext::ChildInit(f);
}
} // namespace net_instaweb