| /* |
| * 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: jkarlin@google.com (Josh Karlin) |
| |
| #include "net/instaweb/rewriter/public/fake_filter.h" |
| #include <memory> |
| |
| #include "net/instaweb/rewriter/cached_result.pb.h" |
| #include "net/instaweb/rewriter/public/image_url_encoder.h" |
| #include "net/instaweb/rewriter/public/resource.h" |
| #include "net/instaweb/rewriter/public/resource_slot.h" |
| #include "net/instaweb/rewriter/public/resource_tag_scanner.h" |
| #include "net/instaweb/rewriter/public/rewrite_context.h" |
| #include "net/instaweb/rewriter/public/rewrite_driver.h" |
| #include "net/instaweb/rewriter/public/rewrite_result.h" |
| #include "net/instaweb/rewriter/public/server_context.h" |
| #include "pagespeed/kernel/base/function.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/base/timer.h" |
| #include "pagespeed/kernel/html/html_element.h" |
| #include "pagespeed/kernel/http/content_type.h" |
| #include "pagespeed/kernel/thread/scheduler.h" |
| |
| namespace net_instaweb { |
| |
| FakeFilter::Context::~Context() {} |
| |
| void FakeFilter::Context::RewriteSingle(const ResourcePtr& input, |
| const OutputResourcePtr& output) { |
| if (filter_->exceed_deadline()) { |
| // Wake up 1us past the deadline. |
| int64 wakeup_us = Driver()->scheduler()->timer()->NowUs() + |
| (Timer::kMsUs * GetRewriteDeadlineAlarmMs() + 1); |
| Function* closure = |
| MakeFunction(this, &Context::DoRewriteSingle, input, output); |
| Driver()->scheduler()->AddAlarmAtUs(wakeup_us, closure); |
| } else { |
| DoRewriteSingle(input, output); |
| } |
| } |
| |
| void FakeFilter::Context::DoRewriteSingle(const ResourcePtr input, |
| OutputResourcePtr output) { |
| RewriteResult result = kRewriteFailed; |
| GoogleString rewritten; |
| |
| if (filter_->enabled()) { |
| // TODO(jkarlin): Writing to the filter from a context is not thread |
| // safe. |
| filter_->IncRewrites(); |
| StrAppend(&rewritten, input->ExtractUncompressedContents(), ":", |
| filter_->id()); |
| |
| // Set the output type here to make sure that the CachedResult url |
| // field has the correct extension for the type. |
| const ContentType* output_type = &kContentTypeText; |
| if (filter_->output_content_type() != NULL) { |
| output_type = filter_->output_content_type(); |
| } else if (input->type() != NULL) { |
| output_type = input->type(); |
| } |
| ResourceVector rv = ResourceVector(1, input); |
| if (Driver()->Write(rv, rewritten, output_type, input->charset(), |
| output.get())) { |
| result = kRewriteOk; |
| } |
| } |
| |
| RewriteDone(result, 0); |
| } |
| |
| GoogleString FakeFilter::Context::UserAgentCacheKey( |
| const ResourceContext* resource_context) const { |
| if (resource_context != NULL) { |
| return ImageUrlEncoder::CacheKeyFromResourceContext(*resource_context); |
| } |
| return ""; |
| } |
| |
| FakeFilter::~FakeFilter() {} |
| |
| void FakeFilter::StartElementImpl(HtmlElement* element) { |
| resource_tag_scanner::UrlCategoryVector attributes; |
| resource_tag_scanner::ScanElement(element, rewrite_options(), &attributes); |
| for (int i = 0, n = attributes.size(); i < n; ++i) { |
| if (attributes[i].category == category_) { |
| ResourcePtr input_resource(CreateInputResourceOrInsertDebugComment( |
| attributes[i].url->DecodedValueOrNull(), element)); |
| if (input_resource.get() == NULL) { |
| return; |
| } |
| ResourceSlotPtr slot( |
| driver()->GetSlot(input_resource, element, attributes[i].url)); |
| RewriteContext* context = MakeRewriteContext(); |
| context->AddSlot(slot); |
| driver()->InitiateRewrite(context); |
| } |
| } |
| } |
| |
| RewriteContext* FakeFilter::MakeNestedRewriteContext( |
| RewriteContext* parent, const ResourceSlotPtr& slot) { |
| ResourceContext* resource_context = new ResourceContext; |
| if (parent != NULL && parent->resource_context() != NULL) { |
| resource_context->CopyFrom(*parent->resource_context()); |
| } |
| RewriteContext* context = |
| MakeFakeContext(NULL, parent, resource_context); |
| context->AddSlot(slot); |
| return context; |
| } |
| |
| void FakeFilter::ClearStats() { |
| num_rewrites_ = 0; |
| num_calls_to_encode_user_agent_ = 0; |
| } |
| |
| void FakeFilter::EncodeUserAgentIntoResourceContext( |
| ResourceContext* context) const { |
| ImageUrlEncoder::SetWebpAndMobileUserAgent(*driver(), context); |
| ++num_calls_to_encode_user_agent_; |
| } |
| |
| } // namespace net_instaweb |