blob: 09320bf7700897b4f8e63d50acfb2eae13c014e4 [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.
//
// Author: jefftk@google.com (Jeff Kaufman)
#ifndef PAGESPEED_SYSTEM_SYSTEM_SERVER_CONTEXT_H_
#define PAGESPEED_SYSTEM_SYSTEM_SERVER_CONTEXT_H_
#include "net/instaweb/rewriter/public/server_context.h"
#include "net/instaweb/http/public/request_context.h"
#include "pagespeed/system/admin_site.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/util/copy_on_write.h"
namespace net_instaweb {
class AbstractMutex;
class AsyncFetch;
class GoogleUrl;
class Histogram;
class QueryParams;
class PurgeSet;
class RewriteDriver;
class RewriteDriverFactory;
class RewriteOptions;
class RewriteStats;
class SharedMemStatistics;
class Statistics;
class SystemCachePath;
class SystemCaches;
class SystemRewriteDriverFactory;
class SystemRewriteOptions;
class UpDownCounter;
class UrlAsyncFetcherStats;
class Variable;
class Writer;
// A server context with features specific to a PSOL port on a unix system.
class SystemServerContext : public ServerContext {
public:
// Identifies whether the user arrived at an admin page from a
// /pagespeed_admin handler or a /*_pagespeed_statistics handler.
// The main difference between these is that the _admin site might in the
// future grant more privileges than the statistics site did, such as flushing
// cache. But it also affects the syntax of the links created to sub-pages
// in the top navigation bar.
SystemServerContext(RewriteDriverFactory* factory,
StringPiece hostname, int port);
virtual ~SystemServerContext();
void SetCachePath(SystemCachePath* cache_path);
// Implementations should call this method on every request, both for html and
// resources, to avoid serving stale resources.
//
// TODO(jmarantz): allow a URL-based mechanism to flush cache, even if
// we implement it by simply writing the cache.flush file so other
// servers can see it. Note that using shared-memory is not a great
// plan because we need the cache-invalidation to persist across server
// restart.
void FlushCacheIfNecessary();
SystemRewriteOptions* global_system_rewrite_options();
GoogleString hostname_identifier() { return hostname_identifier_; }
// Updates the PurgeSet with a new version. This is called when the system
// picks up (by polling or API) a new version of the cache.purge file.
void UpdateCachePurgeSet(const CopyOnWrite<PurgeSet>& purge_set);
// Initialize this SystemServerContext to set up its admin site.
virtual void PostInitHook();
static void InitStats(Statistics* statistics);
// Called by SystemRewriteDriverFactory::ChildInit. See documentation there.
virtual void ChildInit(SystemRewriteDriverFactory* factory);
// Initialize this ServerContext to have its own statistics domain. Must be
// called after global_statistics has been created and had ::InitStats called
// on it.
void CreateLocalStatistics(Statistics* global_statistics,
SystemRewriteDriverFactory* factory);
// Whether ChildInit() has been called yet. Exposed so debugging code can
// verify initialization proceeded properly.
bool initialized() const { return initialized_; }
// Normally we just fetch with the default UrlAsyncFetcher, generally serf,
// but there are some cases where we need to do something more complex:
// - Local requests: requests for resources on this host should go directly
// to the local IP.
// - Fetches directly from other modules: in Apache we have an experimental
// pathway where we can make fetches directly from mod_spdy without going
// out to the network.
// - Custom fetch headers: before continuing with the fetch we want to add
// request headers.
// Session fetchers allow us to make these decisions. Here we may update
// driver->async_fetcher() to be a special fetcher just for this request.
virtual void ApplySessionFetchers(const RequestContextPtr& req,
RewriteDriver* driver);
// Accumulate in a histogram the amount of time spent rewriting HTML.
// TODO(sligocki): Remove in favor of RewriteStats::rewrite_latency_histogram.
void AddHtmlRewriteTimeUs(int64 rewrite_time_us);
SystemCachePath* cache_path() { return cache_path_; }
// Hook called after all configuration parsing is done to support implementers
// like ApacheServerContext that need to collapse configuration inside the
// config overlays into actual RewriteOptions objects. It will also compute
// signatures when done, and by default that's the only thing it does.
virtual void CollapseConfigOverlaysAndComputeSignatures();
// Returns the spdy-specific configuration, or NULL if there is none
// specified.
virtual const SystemRewriteOptions* SpdyGlobalConfig() const;
// Handler which serves PSOL console.
// Note: ConsoleHandler always succeeds.
void ConsoleHandler(const SystemRewriteOptions& options,
AdminSite::AdminSource source,
const QueryParams& query_params, AsyncFetch* fetch);
// Displays recent Info/Warning/Error messages.
void MessageHistoryHandler(const RewriteOptions& options,
AdminSite::AdminSource source,
AsyncFetch* fetch);
// Deprecated handler for graphs in the PSOL console.
void StatisticsGraphsHandler(Writer* writer);
// Handle a request for /pagespeed_admin/*, which is a launching
// point for all the administrator pages including stats,
// message-histogram, console, etc.
void AdminPage(bool is_global, const GoogleUrl& stripped_gurl,
const QueryParams& query_params, const RewriteOptions* options,
AsyncFetch* fetch);
// Handle a request for the legacy /*_pagespeed_statistics page, which also
// serves as a launching point for a subset of the admin pages. Because the
// admin pages are not uniformly sensitive, an existing PageSpeed user might
// have granted public access to /mod_pagespeed_statistics, but we don't
// want that to automatically imply access to the server cache.
void StatisticsPage(bool is_global, const QueryParams& query_params,
const RewriteOptions* options,
AsyncFetch* fetch);
AdminSite* admin_site() { return admin_site_.get(); }
protected:
// Flush the cache by updating the cache flush timestamp in the global
// options. This will change its signature, which is part of the cache key,
// and so all previously cached entries will be unreachable.
//
// Returns true if it actually updated the timestamp, false if the existing
// cache flush timestamp was newer or the same as the one provided.
//
// Subclasses which add additional configurations need to override this method
// to additionally update the cache flush timestamp in those other
// configurations. See ApacheServerContext::UpdateCacheFlushTimestampMs where
// the separate SpdyConfig that mod_pagespeed uses when using SPDY also needs
// to have it's timestamp bumped.
virtual bool UpdateCacheFlushTimestampMs(int64 timestamp_ms);
// Hook for implementations to support fetching directly from the spdy module.
virtual void MaybeApplySpdySessionFetcher(const RequestContextPtr& request,
RewriteDriver* driver) {}
// Returns JSON used by the PageSpeed Console JavaScript.
void ConsoleJsonHandler(const QueryParams& params, AsyncFetch* fetch);
// Handler for /mod_pagespeed_statistics and
// /ngx_pagespeed_statistics, as well as
// /...pagespeed__global_statistics. If the latter,
// is_global_request should be true.
//
// Returns NULL on success, otherwise the returned error string
// should be passed along to the user and the contents of writer and
// content_type should be ignored.
//
// In systems without a spdy-specific config, spdy_config should be
// null.
void StatisticsHandler(const RewriteOptions& options, bool is_global_request,
AdminSite::AdminSource source, AsyncFetch* fetch);
// Print details fo the SPDY configuration.
void PrintSpdyConfig(AdminSite::AdminSource source, AsyncFetch* fetch);
// Print details fo the non-SPDY configuration.
void PrintNormalConfig(AdminSite::AdminSource source, AsyncFetch* fetch);
// Print statistics about the caches. In the future this will also
// be a launching point for examining cache entries and purging them.
void PrintCaches(bool is_global, AdminSite::AdminSource source,
const GoogleUrl& stripped_gurl,
const QueryParams& query_params,
const RewriteOptions* options,
AsyncFetch* fetch);
// Print histograms showing the dynamics of server activity.
void PrintHistograms(bool is_global_request,
AdminSite::AdminSource source,
AsyncFetch* fetch);
Variable* statistics_404_count();
private:
// Checks the timestamp of cache.flush, updating the purge context as
// needed.
//
// TODO(jmarantz): Consider removing this if we decide to turn
// enable_cache_purge always-on. If we do that, "touch cache.flush"
// will no longer work, and that will force users to use the new purge API
// instead. We could consider checking both cache.flush and cache.purge,
// but it would be confusing what our semantics should be if both are
// present.
void CheckLegacyGlobalCacheFlushFile();
scoped_ptr<AdminSite> admin_site_;
bool initialized_;
bool use_per_vhost_statistics_;
// State used to implement periodic polling of $FILE_PREFIX/cache.flush.
// last_cache_flush_check_sec_ is ctor-initialized to 0 so the first
// time we Poll we will read the file.
scoped_ptr<AbstractMutex> cache_flush_mutex_;
int64 last_cache_flush_check_sec_; // seconds since 1970
Variable* cache_flush_count_;
UpDownCounter* cache_flush_timestamp_ms_;
Histogram* html_rewrite_time_us_histogram_;
// Non-NULL if we have per-vhost stats.
scoped_ptr<Statistics> split_statistics_;
// May be NULL. Owned by *split_statistics_.
SharedMemStatistics* local_statistics_;
// These are non-NULL if we have per-vhost stats.
scoped_ptr<RewriteStats> local_rewrite_stats_;
scoped_ptr<UrlAsyncFetcherStats> stats_fetcher_;
// hostname_identifier_ equals to "server_hostname:port" of the server. It's
// used to distinguish the name of shared memory so that each vhost has its
// own SharedCircularBuffer.
GoogleString hostname_identifier_;
SystemCaches* system_caches_;
SystemCachePath* cache_path_;
DISALLOW_COPY_AND_ASSIGN(SystemServerContext);
};
} // namespace net_instaweb
#endif // PAGESPEED_SYSTEM_SYSTEM_SERVER_CONTEXT_H_