blob: 7612e36cd950cea882a3b7d5f08fcdfbed0afa61 [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: morlovich@google.com (Maksim Orlovich)
#include "net/instaweb/rewriter/public/google_font_service_input_resource.h"
#include <vector>
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_driver_factory.h"
#include "net/instaweb/rewriter/public/server_context.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/statistics.h"
#include "pagespeed/kernel/http/content_type.h"
#include "pagespeed/kernel/http/google_url.h"
#include "pagespeed/kernel/http/http_names.h"
#include "pagespeed/kernel/http/request_headers.h"
#include "pagespeed/kernel/http/response_headers.h"
#include "pagespeed/kernel/http/user_agent_normalizer.h"
namespace net_instaweb {
namespace {
const char kFontApiHost[] = "fonts.googleapis.com";
} // namespace
GoogleFontServiceInputResource::GoogleFontServiceInputResource(
RewriteDriver* rewrite_driver,
bool is_https,
const StringPiece& url,
const StringPiece& cache_key,
const GoogleString& user_agent)
: CacheableResourceBase("font_service_input_resource",
url, cache_key, &kContentTypeCss, rewrite_driver),
user_agent_(user_agent),
is_https_(is_https) {
}
GoogleFontServiceInputResource::~GoogleFontServiceInputResource() {
}
bool GoogleFontServiceInputResource::IsFontServiceUrl(const GoogleUrl& url) {
return url.IsWebValid() && url.Host() == kFontApiHost;
}
GoogleFontServiceInputResource* GoogleFontServiceInputResource::Make(
const GoogleUrl& parsed_url, RewriteDriver* rewrite_driver) {
if (!IsFontServiceUrl(parsed_url)) {
return NULL;
}
// Compute cache key, incorporating the UA string --- but normalize it first,
// to cut down on irrelevant noise.
const std::vector<const UserAgentNormalizer*>& ua_normalizers =
rewrite_driver->server_context()->factory()->user_agent_normalizers();
GoogleString ua = UserAgentNormalizer::NormalizeWithAll(
ua_normalizers, rewrite_driver->user_agent());
StringPiece url_plus_ua_spec;
scoped_ptr<GoogleUrl> url_plus_ua(
parsed_url.CopyAndAddQueryParam("X-PS-UA", ua));
url_plus_ua_spec = url_plus_ua->Spec();
GoogleString cache_key;
bool is_https = false;
if (StringCaseStartsWith(url_plus_ua_spec, "http://")) {
url_plus_ua_spec.remove_prefix(STATIC_STRLEN("http://"));
cache_key = StrCat("gfnt://", url_plus_ua_spec);
is_https = false;
} else if (StringCaseStartsWith(url_plus_ua_spec, "https://")) {
url_plus_ua_spec.remove_prefix(STATIC_STRLEN("https://"));
cache_key = StrCat("gfnts://", url_plus_ua_spec);
is_https = true;
} else {
// Huh?
return NULL;
}
return new GoogleFontServiceInputResource(
rewrite_driver, is_https, parsed_url.Spec(), cache_key,
rewrite_driver->user_agent());
}
void GoogleFontServiceInputResource::InitStats(Statistics* stats) {
CacheableResourceBase::InitStats("font_service_input_resource", stats);
}
void GoogleFontServiceInputResource::PrepareRequest(
const RequestContextPtr& request_context, RequestHeaders* headers) {
// We want to give the font service the UA the client used, so that it can
// optimize for the visitor's browser, and not something like Serf/1.1
// mod_pagespeed/x.y
headers->Replace(HttpAttributes::kUserAgent, user_agent_);
request_context->AddSessionAuthorizedFetchOrigin(
is_https_ ?
"https://fonts.googleapis.com" : "http://fonts.googleapis.com");
}
void GoogleFontServiceInputResource::PrepareResponseHeaders(
ResponseHeaders* headers) {
// Refuse to deal with anything but CSS.
const ContentType* content_type = headers->DetermineContentType();
if (content_type == NULL || !content_type->IsCss()) {
headers->set_status_code(HttpStatus::kNotAcceptable);
}
// The resource is served with cache-control: private; we need to swizzle
// that in order to save it in the cache.
headers->Remove(HttpAttributes::kCacheControl, "private");
// Remove cookies just in case.
headers->Sanitize();
}
} // namespace net_instaweb