blob: 3cee423c4a51eada835d8cfaea4133d112bfa65c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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_server_context.h"
#include <memory>
// http_protocol.h includes httpd.h. We need to include httpd_includes.h, which
// works around a conflicting definition of OK in gRPC.
#include "http_protocol.h" // NOLINT
#include "net/instaweb/rewriter/config/measurement_proxy_rewrite_options_manager.h"
#include "net/instaweb/rewriter/public/measurement_proxy_url_namer.h"
#include "pagespeed/apache/apache_config.h"
#include "pagespeed/apache/apache_httpd_includes.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"
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() == nullptr) {
spdy_config_overlay_ =
std::make_unique<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() == nullptr) {
non_spdy_config_overlay_ =
std::make_unique<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() != nullptr) {
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_ = std::make_unique<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_ = std::make_unique<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