/*
 * 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
