Compare commits

..

1 Commits

Author SHA1 Message Date
Otto van der Schaaf 26a0c37b97 location-header: Only set the location field when the input
Only set headers_out.location when the input also originally did
that.

This still needs a test to prevent regression, but I thought I'd
put this out so people can try this.

Should fix https://github.com/pagespeed/ngx_pagespeed/issues/819
Might help https://github.com/pagespeed/ngx_pagespeed/issues/711
2014-10-21 07:43:04 +02:00
18 changed files with 540 additions and 930 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
test/tmp
psol/
psol-*.tar.gz
*.*.*.*.tar.gz
+3 -3
View File
@@ -27,8 +27,8 @@ if [ "$mod_pagespeed_dir" = "unset" ] ; then
echo " You need to separately download the pagespeed library:"
echo ""
echo " $ cd /path/to/ngx_pagespeed"
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.9.32.4.tar.gz"
echo " $ tar -xzvf 1.9.32.4.tar.gz # expands to psol/"
echo " $ wget https://dl.google.com/dl/page-speed/psol/1.9.32.1.tar.gz"
echo " $ tar -xzvf 1.9.32.1.tar.gz # expands to psol/"
echo ""
echo " Or see the installation instructions:"
echo " https://github.com/pagespeed/ngx_pagespeed#how-to-build"
@@ -205,7 +205,7 @@ if [ $ngx_found = yes ]; then
else
cat << END
$0: error: module ngx_pagespeed requires the pagespeed optimization library.
Look in objs/autoconf.err for more details.
Look in obj/autoconf.err for more details.
END
exit 1
fi
+2 -2
View File
@@ -13,9 +13,9 @@
# Author: vid@zippykid.com (Vid Luther)
# jefftk@google.com (Jeff Kaufman)
URL="https://github.com/pagespeed/mod_pagespeed/raw/master/"
URL="https://modpagespeed.googlecode.com/svn/trunk/src/"
URL+="net/instaweb/genfiles/conf/pagespeed_libraries.conf"
curl -L -s -S "$URL" \
curl -s "$URL" \
| grep ModPagespeedLibrary \
| while read library size hash url ; do
echo " pagespeed Library $size $hash $url;"
+1 -1
View File
@@ -144,7 +144,7 @@ void NgxBaseFetch::HandleHeadersComplete() {
}
}
// For the IPRO lookup, suppress notification of the nginx side here.
// For the IPRO lookup, supress notification of the nginx side here.
// If we send both this event and the one from done, nasty stuff will happen
// if we loose the race with with the nginx side destructing this base fetch
// instance (and thereby clearing the byte and its pending extraneous event.
+466 -806
View File
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -51,13 +51,12 @@ namespace net_instaweb {
typedef bool (*response_handler_pt)(ngx_connection_t* c);
class NgxUrlAsyncFetcher;
class NgxConnection;
class NgxFetch : public PoolElement<NgxFetch> {
public:
NgxFetch(const GoogleString& url,
AsyncFetch* async_fetch,
MessageHandler* message_handler,
ngx_msec_t timeout_ms,
ngx_log_t* log);
~NgxFetch();
@@ -113,19 +112,19 @@ class NgxFetch : public PoolElement<NgxFetch> {
response_handler = handler;
}
// Only the Static functions could be used in callbacks.
static void ResolveDoneHandler(ngx_resolver_ctx_t* ctx);
static void NgxFetchResolveDone(ngx_resolver_ctx_t* ctx);
// Write the request.
static void ConnectionWriteHandler(ngx_event_t* wev);
static void NgxFetchWrite(ngx_event_t* wev);
// Wait for the response.
static void ConnectionReadHandler(ngx_event_t* rev);
static void NgxFetchRead(ngx_event_t* rev);
// Read and parse the first status line.
static bool HandleStatusLine(ngx_connection_t* c);
static bool NgxFetchHandleStatusLine(ngx_connection_t* c);
// Read and parse the HTTP headers.
static bool HandleHeader(ngx_connection_t* c);
static bool NgxFetchHandleHeader(ngx_connection_t* c);
// Read the response body.
static bool HandleBody(ngx_connection_t* c);
static bool NgxFetchHandleBody(ngx_connection_t* c);
// Cancel the fetch when it's timeout.
static void TimeoutHandler(ngx_event_t* tev);
static void NgxFetchTimeout(ngx_event_t* tev);
// Add the pagespeed User-Agent.
void FixUserAgent();
@@ -140,6 +139,7 @@ class NgxFetch : public PoolElement<NgxFetch> {
int64 bytes_received_;
int64 fetch_start_ms_;
int64 fetch_end_ms_;
int64 timeout_ms_;
bool done_;
int64 content_length_;
bool content_length_known_;
@@ -152,7 +152,7 @@ class NgxFetch : public PoolElement<NgxFetch> {
ngx_http_request_t* r_;
ngx_http_status_t* status_;
ngx_event_t* timeout_event_;
NgxConnection* connection_;
ngx_connection_t* connection_;
ngx_resolver_ctx_t* resolver_ctx_;
DISALLOW_COPY_AND_ASSIGN(NgxFetch);
+4 -15
View File
@@ -70,7 +70,7 @@ extern "C" {
}
}
NgxGZipSetter::NgxGZipSetter() : enabled_(false), initialized_(false) { }
NgxGZipSetter::NgxGZipSetter() : enabled_(0) { }
NgxGZipSetter::~NgxGZipSetter() { }
// Helper functions to determine signature.
@@ -95,7 +95,7 @@ bool IsNgxBitmaskCommand(ngx_command_t* command) {
HasLocalConfig(command));
}
// Initialize the NgxGZipSetter.
// Initialize the NgxGzipSetter.
// Find the gzip, gzip_vary, gzip_http_version and gzip_types commands in the
// gzip module. Enable if the signature of the zip command matches with what we
// trust. Also sets up redirects for the configurations. These redirect handle
@@ -105,16 +105,6 @@ void NgxGZipSetter::Init(ngx_conf_t* cf) {
#if (NGX_HTTP_GZIP)
bool gzip_signature_mismatch = false;
bool other_signature_mismatch = false;
// If we initialized already we don't have to scan again.
if (initialized_) {
// Config might have changed, so re-enable if we have gzip.
if (gzip_command_.command_ != NULL) {
enabled_ = true;
} else {
enabled_ = false;
}
return;
}
for (int m = 0; ngx_modules[m] != NULL; m++) {
if (ngx_modules[m]->commands != NULL) {
for (int c = 0; ngx_modules[m]->commands[c].name.len; c++) {
@@ -132,7 +122,7 @@ void NgxGZipSetter::Init(ngx_conf_t* cf) {
current_command->set = ngx_gzip_redirect_conf_set_flag_slot;
gzip_command_.command_ = current_command;
gzip_command_.module_ = ngx_modules[m];
enabled_ = true;
enabled_ = 1;
} else {
ngx_conf_log_error(
NGX_LOG_WARN, cf, 0,
@@ -199,7 +189,6 @@ void NgxGZipSetter::Init(ngx_conf_t* cf) {
}
}
}
initialized_ = true;
if (gzip_signature_mismatch) {
return; // Already logged error.
} else if (!enabled_) {
@@ -392,7 +381,7 @@ void NgxGZipSetter::AddGZipHTTPTypes(ngx_conf_t* cf) {
}
void NgxGZipSetter::RollBackAndDisable(ngx_conf_t* cf) {
ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0,
ngx_conf_log_error(NGX_LOG_INFO, cf, 0,
"pagespeed: rollback gzip, explicit configuration");
for (std::vector<ngx_flag_t*>::iterator i = ngx_flags_set_.begin();
i != ngx_flags_set_.end(); ++i) {
-1
View File
@@ -91,7 +91,6 @@ class NgxGZipSetter {
ngx_command_ctx gzip_vary_command_;
ngx_command_ctx gzip_http_version_command_;
bool enabled_;
bool initialized_;
public:
NgxGZipSetter();
-4
View File
@@ -18,10 +18,6 @@
#define NGX_MESSAGE_HANDLER_H_
extern "C" {
#include <ngx_auto_config.h>
#if (NGX_THREADS)
#include <ngx_thread.h>
#endif
#include <ngx_core.h>
#include <ngx_log.h>
}
+45 -45
View File
@@ -208,6 +208,13 @@ ngx_int_t string_piece_to_buffer_chain(
namespace {
// Get the context for this request. ps_connection_read_handler should already
// have been called to create it.
ps_request_ctx_t* ps_get_request_context(ngx_http_request_t* r) {
return static_cast<ps_request_ctx_t*>(
ngx_http_get_module_ctx(r, ngx_pagespeed));
}
// Setting headers in nginx is tricky because it's not just a matter of adding
// them to a list. You also need to remove them if there's already one there,
// as well as setting the shortcut pointers (both upper case and lower case).
@@ -295,8 +302,7 @@ void copy_response_headers_from_ngx(const ngx_http_request_t* r,
// When we don't have a date header, set one with the current time.
if (headers->Lookup1(HttpAttributes::kDate) == NULL) {
PosixTimer timer;
headers->SetDate(timer.NowMs());
headers->SetDate(ngx_current_msec);
}
// TODO(oschaaf): ComputeCaching should be called in setupforhtml()?
@@ -343,17 +349,10 @@ ngx_int_t copy_response_headers_to_ngx(
ngx_str_t name, value;
// If the gzip module is not configured, we must not rename the header,
// because we will fail to inject the header filter that will rename the
// header back.
bool gzip_enabled = false;
#if (NGX_HTTP_GZIP)
gzip_enabled = true;
#endif
// To prevent the gzip module from clearing weak etags, we output them
// using a different name here. The etag header filter module runs behind
// the gzip compressors header filter, and will rename it to 'ETag'
if (gzip_enabled && StringCaseEqual(name_gs, "etag")
if (StringCaseEqual(name_gs, "etag")
&& StringCaseStartsWith(value_gs, "W/")) {
name.len = strlen(kInternalEtagName);
name.data = reinterpret_cast<u_char*>(
@@ -362,7 +361,6 @@ ngx_int_t copy_response_headers_to_ngx(
name.len = name_gs.length();
name.data = reinterpret_cast<u_char*>(const_cast<char*>(name_gs.data()));
}
value.len = value_gs.length();
value.data = reinterpret_cast<u_char*>(const_cast<char*>(value_gs.data()));
@@ -441,7 +439,10 @@ ngx_int_t copy_response_headers_to_ngx(
} else if (STR_EQ_LITERAL(name, "Last-Modified")) {
headers_out->last_modified = header;
} else if (STR_EQ_LITERAL(name, "Location")) {
headers_out->location = header;
ps_request_ctx_t* ctx = ps_get_request_context(r);
if (ctx->location_field_set) {
headers_out->location = header;
}
} else if (STR_EQ_LITERAL(name, "Server")) {
headers_out->server = header;
} else if (STR_EQ_LITERAL(name, "Content-Length")) {
@@ -1107,13 +1108,6 @@ GoogleString ps_determine_url(ngx_http_request_t* r) {
host, port_string, str_to_string_piece(r->unparsed_uri));
}
// Get the context for this request. ps_connection_read_handler should already
// have been called to create it.
ps_request_ctx_t* ps_get_request_context(ngx_http_request_t* r) {
return static_cast<ps_request_ctx_t*>(
ngx_http_get_module_ctx(r, ngx_pagespeed));
}
void ps_release_base_fetch(ps_request_ctx_t* ctx);
// we are still at pagespeed phase
@@ -1639,8 +1633,7 @@ void ps_release_base_fetch(ps_request_ctx_t* ctx) {
// TODO(chaizhenhua): merge into NgxBaseFetch ctor
ngx_int_t ps_create_base_fetch(ps_request_ctx_t* ctx,
RequestContextPtr request_context,
RequestHeaders* request_headers) {
RequestContextPtr request_context) {
ngx_http_request_t* r = ctx->r;
ps_srv_conf_t* cfg_s = ps_get_srv_config(r);
int file_descriptors[2];
@@ -1683,7 +1676,6 @@ ngx_int_t ps_create_base_fetch(ps_request_ctx_t* ctx,
ctx->base_fetch = new NgxBaseFetch(
r, file_descriptors[1], cfg_s->server_context,
request_context, ctx->preserve_caching_headers);
ctx->base_fetch->SetRequestHeadersTakingOwnership(request_headers);
return NGX_OK;
}
@@ -1819,10 +1811,7 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
GoogleString url_string = ps_determine_url(r);
GoogleUrl url(url_string);
if (!url.IsWebValid()) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid url");
return NGX_DECLINED;
}
CHECK(url.IsWebValid());
scoped_ptr<RequestHeaders> request_headers(new RequestHeaders);
scoped_ptr<ResponseHeaders> response_headers(new ResponseHeaders);
@@ -1900,6 +1889,7 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
ctx->driver = NULL;
ctx->recorder = NULL;
ctx->ipro_response_headers = NULL;
ctx->location_field_set = false;
// See build_context_for_request() in mod_instaweb.cc
// TODO(jefftk): Is this the right place to be modifying caching headers for
@@ -1937,17 +1927,35 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
ngx_http_set_ctx(r, ctx, ngx_pagespeed);
}
if (ps_create_base_fetch(ctx, request_context) != NGX_OK) {
// Do not need to release request context 'ctx'.
// http_pool_cleanup will call ps_release_request_context
return NGX_ERROR;
}
ctx->base_fetch->SetRequestHeadersTakingOwnership(request_headers.release());
bool page_callback_added = false;
scoped_ptr<ProxyFetchPropertyCallbackCollector>
property_callback(
ProxyFetchFactory::InitiatePropertyCacheLookup(
!html_rewrite /* is_resource_fetch */,
url,
cfg_s->server_context,
options,
ctx->base_fetch,
false /* requires_blink_cohort (no longer unused) */,
&page_callback_added));
if (pagespeed_resource) {
// TODO(jefftk): Set using_spdy appropriately. See
// ProxyInterface::ProxyRequestCallback
ps_create_base_fetch(ctx, request_context, request_headers.release());
ResourceFetch::Start(
url,
custom_options.release() /* null if there aren't custom options */,
false /* using_spdy */, cfg_s->server_context, ctx->base_fetch);
return ps_async_wait_response(r);
} else if (is_an_admin_handler) {
ps_create_base_fetch(ctx, request_context, request_headers.release());
QueryParams query_params;
query_params.ParseFromUrl(url);
@@ -1991,7 +1999,6 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
}
if (html_rewrite) {
ps_create_base_fetch(ctx, request_context, request_headers.release());
// Do not store driver in request_context, it's not safe.
RewriteDriver* driver;
@@ -2018,22 +2025,12 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
driver->set_pagespeed_option_cookies(pagespeed_option_cookies);
// TODO(jefftk): FlushEarlyFlow would go here.
bool page_callback_added = false;
ProxyFetchPropertyCallbackCollector* property_callback =
ProxyFetchFactory::InitiatePropertyCacheLookup(
!html_rewrite /* is_resource_fetch */,
url,
cfg_s->server_context,
options,
ctx->base_fetch,
false /* requires_blink_cohort (no longer unused) */,
&page_callback_added);
// Will call StartParse etc. The rewrite driver will take care of deleting
// itself if necessary.
ctx->proxy_fetch = cfg_s->proxy_fetch_factory->CreateNewProxyFetch(
url_string, ctx->base_fetch, driver,
property_callback,
property_callback.release(),
NULL /* original_content_fetch */);
return NGX_OK;
}
@@ -2041,7 +2038,6 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
if (options->in_place_rewriting_enabled() &&
options->enabled() &&
options->IsAllowed(url.Spec())) {
ps_create_base_fetch(ctx, request_context, request_headers.release());
// Do not store driver in request_context, it's not safe.
RewriteDriver* driver;
if (custom_options.get() == NULL) {
@@ -2081,7 +2077,8 @@ ngx_int_t ps_resource_handler(ngx_http_request_t* r,
"Passing on content handling for non-pagespeed resource '%s'",
url_string.c_str());
CHECK(ctx->base_fetch == NULL);
ctx->base_fetch->Done(false);
ps_release_base_fetch(ctx);
// set html_rewrite flag.
ctx->html_rewrite = true;
return NGX_DECLINED;
@@ -2286,13 +2283,14 @@ ngx_int_t ps_html_rewrite_header_filter(ngx_http_request_t* r) {
if (!ps_has_stacked_content_encoding(r)) {
StringPiece content_encoding =
str_to_string_piece(r->headers_out.content_encoding->value);
GzipInflater::InflateType inflate_type = GzipInflater::kGzip;
GzipInflater::InflateType inflate_type;
bool is_encoded = false;
if (StringCaseEqual(content_encoding, "deflate")) {
is_encoded = true;
inflate_type = GzipInflater::kDeflate;
} else if (StringCaseEqual(content_encoding, "gzip")) {
is_encoded = true;
inflate_type = GzipInflater::kGzip;
}
if (is_encoded) {
@@ -2305,6 +2303,8 @@ ngx_int_t ps_html_rewrite_header_filter(ngx_http_request_t* r) {
}
ps_strip_html_headers(r);
// See https://github.com/pagespeed/ngx_pagespeed/issues/819
ctx->location_field_set = r->headers_out.location != NULL;
// TODO(jefftk): is this thread safe?
copy_response_headers_from_ngx(r, ctx->base_fetch->response_headers());
@@ -2705,8 +2705,8 @@ bool ps_request_body_to_string_piece(
if (ret < 0) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"ps_request_body_to_string_piece: "
"error reading post body.");
"ps_request_body_to_string_piece: "
"error reading post body.");
return false;
}
+1
View File
@@ -107,6 +107,7 @@ typedef struct {
// We need to remember the URL here as well since we may modify what NGX
// gets by stripping our special query params and honoring X-Forwarded-Proto.
GoogleString url_string;
bool location_field_set;
} ps_request_ctx_t;
-3
View File
@@ -78,8 +78,6 @@ NgxRewriteDriverFactory::NgxRewriteDriverFactory(
log_(NULL),
resolver_timeout_(NGX_CONF_UNSET_MSEC),
use_native_fetcher_(false),
// 100 Aligns to nginx's server-side default.
native_fetcher_max_keepalive_requests_(100),
ngx_shared_circular_buffer_(NULL),
hostname_(hostname.as_string()),
port_(port),
@@ -114,7 +112,6 @@ UrlAsyncFetcher* NgxRewriteDriverFactory::AllocateFetcher(
resolver_timeout_,
config->blocking_fetch_timeout_ms(),
resolver_,
native_fetcher_max_keepalive_requests_,
thread_system(),
message_handler());
ngx_url_async_fetchers_.push_back(fetcher);
-12
View File
@@ -20,10 +20,6 @@
#define NGX_REWRITE_DRIVER_FACTORY_H_
extern "C" {
#include <ngx_auto_config.h>
#if (NGX_THREADS)
#include <ngx_thread.h>
#endif
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_config.h>
@@ -109,12 +105,6 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
void set_use_native_fetcher(bool x) {
use_native_fetcher_ = x;
}
int native_fetcher_max_keepalive_requests() {
return native_fetcher_max_keepalive_requests_;
}
void set_native_fetcher_max_keepalive_requests(int x) {
native_fetcher_max_keepalive_requests_ = x;
}
bool process_script_variables() {
return process_script_variables_;
}
@@ -150,8 +140,6 @@ class NgxRewriteDriverFactory : public SystemRewriteDriverFactory {
ngx_msec_t resolver_timeout_;
ngx_resolver_t* resolver_;
bool use_native_fetcher_;
int native_fetcher_max_keepalive_requests_;
typedef std::set<NgxMessageHandler*> NgxMessageHandlerSet;
NgxMessageHandlerSet server_context_message_handlers_;
+2 -14
View File
@@ -72,14 +72,12 @@ const char* const server_only_options[] = {
"LoadFromFileMatch",
"LoadFromFileRule",
"LoadFromFileRuleMatch",
"UseNativeFetcher",
"NativeFetcherMaxKeepaliveRequests"
"UseNativeFetcher"
};
// Options that can only be used in the main (http) option scope.
const char* const main_only_options[] = {
"UseNativeFetcher",
"NativeFetcherMaxKeepaliveRequests"
"UseNativeFetcher"
};
} // namespace
@@ -345,16 +343,6 @@ const char* NgxRewriteOptions::ParseAndSetOptions(
result = ParseAndSetOptionHelper<NgxRewriteDriverFactory>(
arg, driver_factory,
&NgxRewriteDriverFactory::set_use_native_fetcher);
} else if (IsDirective(directive, "NativeFetcherMaxKeepaliveRequests")) {
int max_keepalive_requests;
if (StringToInt(arg, &max_keepalive_requests) &&
max_keepalive_requests > 0) {
driver_factory->set_native_fetcher_max_keepalive_requests(
max_keepalive_requests);
result = RewriteOptions::kOptionOk;
} else {
result = RewriteOptions::kOptionValueInvalid;
}
} else if (StringCaseEqual("ProcessScriptVariables", args[0])) {
if (scope == RewriteOptions::kProcessScopeStrict) {
if (StringCaseEqual(arg, "on")) {
+1 -1
View File
@@ -48,7 +48,7 @@ SystemRequestContext* NgxServerContext::NewRequestContext(
ngx_http_request_t* r) {
// Based on ngx_http_variable_server_port.
bool port_set = false;
int local_port = 0;
int local_port;
#if (NGX_HAVE_INET6)
if (r->connection->local_sockaddr->sa_family == AF_INET6) {
local_port = ntohs(reinterpret_cast<struct sockaddr_in6*>(
+2 -4
View File
@@ -55,7 +55,6 @@ namespace net_instaweb {
ngx_msec_t resolver_timeout,
ngx_msec_t fetch_timeout,
ngx_resolver_t* resolver,
int max_keepalive_requests,
ThreadSystem* thread_system,
MessageHandler* handler)
: fetchers_count_(0),
@@ -64,8 +63,7 @@ namespace net_instaweb {
byte_count_(0),
thread_system_(thread_system),
message_handler_(handler),
mutex_(NULL),
max_keepalive_requests_(max_keepalive_requests) {
mutex_(NULL) {
resolver_timeout_ = resolver_timeout;
fetch_timeout_ = fetch_timeout;
ngx_memzero(&proxy_, sizeof(proxy_));
@@ -225,7 +223,7 @@ namespace net_instaweb {
AsyncFetch* async_fetch) {
async_fetch = EnableInflation(async_fetch);
NgxFetch* fetch = new NgxFetch(url, async_fetch,
message_handler, log_);
message_handler, fetch_timeout_, log_);
ScopedMutex lock(mutex_);
pending_fetches_.Add(fetch);
SendCmd('F');
+2 -4
View File
@@ -53,13 +53,12 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
NgxUrlAsyncFetcher(
const char* proxy, ngx_log_t* log, ngx_msec_t resolver_timeout,
ngx_msec_t fetch_timeout, ngx_resolver_t* resolver,
int max_keepalive_requests, ThreadSystem* thread_system,
MessageHandler* handler);
ThreadSystem* thread_system, MessageHandler* handler);
~NgxUrlAsyncFetcher();
// It should be called in the module init_process callback function. Do some
// initializations which can't be done in the master process
// intializations which can't be done in the master process
bool Init();
// shutdown all the fetches.
@@ -140,7 +139,6 @@ class NgxUrlAsyncFetcher : public UrlAsyncFetcher {
ngx_connection_t* command_connection_; // the command pipe
int pipe_fd_; // the write pipe end
ngx_resolver_t* resolver_;
int max_keepalive_requests_;
ngx_msec_t resolver_timeout_;
ngx_msec_t fetch_timeout_;
-4
View File
@@ -38,10 +38,6 @@ http {
pagespeed StaticAssetPrefix /pagespeed_custom_static/;
pagespeed MessageBufferSize 200000;
# Increase the default fetcher timeout to resolve sporadic flakeyness when
# the native fetcher uses 8.8.8.8 to resolve.
pagespeed FetcherTimeoutMs 10000;
pagespeed NativeFetcherMaxKeepaliveRequests 50;
root "@@SERVER_ROOT@@";