/*
 * Copyright 2011 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: jmarantz@google.com (Joshua Marantz)

#include "net/instaweb/http/public/inflating_fetch.h"

#include "base/logging.h"
#include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/stack_buffer.h"
#include "pagespeed/kernel/base/string_writer.h"
#include "pagespeed/kernel/http/http_names.h"
#include "pagespeed/kernel/http/request_headers.h"
#include "pagespeed/kernel/http/response_headers.h"

namespace net_instaweb {

InflatingFetch::InflatingFetch(AsyncFetch* fetch)
    : SharedAsyncFetch(fetch) {
  Reset();
}

InflatingFetch::~InflatingFetch() {
  Reset();
}

bool InflatingFetch::IsCompressionAllowedInRequest() {
  if (!request_checked_for_accept_encoding_) {
    request_checked_for_accept_encoding_ = true;
    ConstStringStarVector v;
    if (request_headers()->Lookup(HttpAttributes::kAcceptEncoding, &v)) {
      for (int i = 0, n = v.size(); i < n; ++i) {
        if (v[i] != NULL) {
          StringPiece value = *v[i];
          if (StringCaseEqual(value, HttpAttributes::kGzip) ||
              StringCaseEqual(value, HttpAttributes::kDeflate)) {
            // TODO(jmarantz): what if we want only deflate, but get gzip?
            // What if we want only gzip, but get deflate?  I think this will
            // rarely happen in practice but we could handle it here.
            compression_desired_ = true;
            break;
          }
        }
      }
    }
  }
  return compression_desired_;
}

void InflatingFetch::EnableGzipFromBackend() {
  if (!IsCompressionAllowedInRequest()) {
    request_headers()->Add(HttpAttributes::kAcceptEncoding,
                           HttpAttributes::kGzip);
  }
}

bool InflatingFetch::HandleWrite(const StringPiece& sp,
                                 MessageHandler* handler) {
  if (inflate_failure_) {
    return false;
  }
  if (inflater_.get() == NULL) {
    return SharedAsyncFetch::HandleWrite(sp, handler);
  }

  DCHECK(!inflater_->HasUnconsumedInput());
  bool status = false;
  if (!inflater_->error()) {
    status = inflater_->SetInput(sp.data(), sp.size());
    if (status && !inflater_->error()) {
      char buf[kStackBufferSize];
      while (inflater_->HasUnconsumedInput()) {
        int size = inflater_->InflateBytes(buf, sizeof buf);
        if (inflater_->error() || (size < 0)) {
          handler->Message(kWarning, "inflation failure, size=%d", size);
          inflate_failure_ = true;
          break;
        } else {
          status = SharedAsyncFetch::HandleWrite(
              StringPiece(buf, size), handler);
        }
      }
    } else {
      handler->MessageS(kWarning, "inflation failure SetInput returning false");
      inflate_failure_ = true;
    }
  }
  return status && !inflate_failure_;
}

// Inflate a HTTPValue, if it was gzip compressed.
bool InflatingFetch::UnGzipValueIfCompressed(const HTTPValue& src,
                                             ResponseHeaders* headers,
                                             HTTPValue* dest,
                                             MessageHandler* handler) {
  if (!src.Empty() && headers->IsGzipped()) {
    GoogleString inflated;
    StringWriter inflate_writer(&inflated);
    StringPiece content;
    src.ExtractContents(&content);
    if (GzipInflater::Inflate(content, GzipInflater::kGzip, &inflate_writer)) {
      headers->RemoveAll(HttpAttributes::kTransferEncoding);
      headers->Add(HttpAttributes::HttpAttributes::kVary,
                   HttpAttributes::kAcceptEncoding);
      headers->Remove(HttpAttributes::kContentEncoding, HttpAttributes::kGzip);
      headers->Replace(HttpAttributes::kContentLength,
                       Integer64ToString(inflated.length()));
      content.set(inflated.c_str(), inflated.length());
      dest->Clear();
      dest->Write(content, handler);
      dest->SetHeaders(headers);
      return true;
    }
  }
  return false;
}

bool InflatingFetch::GzipValue(int compression_level,
                               const HTTPValue& http_value,
                               HTTPValue* compressed_value,
                               ResponseHeaders* headers,
                               MessageHandler* handler) {
  StringPiece content;
  GoogleString deflated;
  int64 content_length;
  http_value.ExtractContents(&content);
  StringWriter deflate_writer(&deflated);
  if (!headers->IsGzipped() &&
      GzipInflater::Deflate(content, GzipInflater::kGzip, compression_level,
                            &deflate_writer)) {
    if (!headers->FindContentLength(&content_length)) {
      content_length = content.size();
    }
    headers->RemoveAll(HttpAttributes::kTransferEncoding);
    headers->SetOriginalContentLength(content_length);
    headers->Add(HttpAttributes::kContentEncoding, HttpAttributes::kGzip);
    headers->Replace(HttpAttributes::kContentLength,
                     Integer64ToString(deflated.length()));
    headers->Add(HttpAttributes::HttpAttributes::kVary,
                 HttpAttributes::kAcceptEncoding);
    compressed_value->SetHeaders(headers);
    compressed_value->Write(deflated, NULL);
    return true;
  }
  return false;
}

// If we did not request gzipped/deflated content but the site gave it
// to us anyway, then interpose an inflating Writer.
//
// As of Dec 6, 2011 this URL serves gzipped content to clients that
// don't claim to accept it:
//   http://cache.boston.com/universal/js/bcom_global_scripts.js
// This is referenced from http://boston.com.
void InflatingFetch::HandleHeadersComplete() {
  ConstStringStarVector v;
  if (!IsCompressionAllowedInRequest() &&
      response_headers()->Lookup(HttpAttributes::kContentEncoding, &v)) {
    // Look for an encoding to strip.  We only look at the *last* encoding.
    // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
    for (int i = v.size() - 1; i >= 0; --i) {
      if (v[i] != NULL) {
        const StringPiece& value = *v[i];
        if (!value.empty()) {
          if (StringCaseEqual(value, HttpAttributes::kGzip)) {
            InitInflater(GzipInflater::kGzip, value);
          } else if (StringCaseEqual(value, HttpAttributes::kDeflate)) {
            InitInflater(GzipInflater::kDeflate, value);
          }
          break;  // Stop on the last non-empty value.
        }
      }
    }
  }
  SharedAsyncFetch::HandleHeadersComplete();
}

void InflatingFetch::InitInflater(GzipInflater::InflateType type,
                                  const StringPiece& value) {
  response_headers()->Remove(HttpAttributes::kContentEncoding, value);
  response_headers()->ComputeCaching();

  // TODO(jmarantz): Consider integrating with a free-store of Inflater
  // objects to avoid re-initializing these on every request.
  inflater_.reset(new GzipInflater(type));
  if (!inflater_->Init()) {
    inflate_failure_ = true;
    inflater_.reset(NULL);
  }
}

void InflatingFetch::HandleDone(bool success) {
  SharedAsyncFetch::HandleDone(success && !inflate_failure_);
  delete this;
}

void InflatingFetch::Reset() {
  if (inflater_.get() != NULL) {
    inflater_->ShutDown();
    inflater_.reset(NULL);
  }
  request_checked_for_accept_encoding_ = false;
  compression_desired_ = false;
  inflate_failure_ = false;
  SharedAsyncFetch::Reset();
}

}  // namespace net_instaweb
