blob: 2d23184e6c61847105813d5f2620d905da17dd7f [file] [log] [blame]
/*
* Copyright 2015 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/render_blocking_html_computation.h"
#include "base/logging.h"
#include "net/instaweb/rewriter/public/resource.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/rewriter/public/server_context.h"
#include "pagespeed/kernel/base/function.h"
#include "pagespeed/kernel/base/ref_counted_ptr.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/http/google_url.h"
#include "pagespeed/kernel/thread/queued_worker_pool.h"
namespace net_instaweb {
class RenderBlockingHtmlComputation::ResourceCallback
: public Resource::AsyncCallback {
public:
ResourceCallback(RewriteDriver* parent_driver,
const ResourcePtr& resource,
RenderBlockingHtmlComputation* computation)
: AsyncCallback(resource), parent_driver_(parent_driver),
computation_(computation) {}
virtual void Done(bool lock_failure, bool resource_ok) {
// Shouldn't be enforcing locks on this anyway.
DCHECK(!lock_failure);
if (!resource_ok) {
computation_->ReportResult(false);
delete this;
} else {
parent_driver_->rewrite_worker()->Add(
MakeFunction(this, &ResourceCallback::ParseAndFilter));
}
}
void ParseAndFilter() {
bool ok = false;
scoped_ptr<RewriteDriver> child_driver(
parent_driver_->server_context()->NewUnmanagedRewriteDriver(
NULL /* no pool */,
parent_driver_->options()->Clone(),
parent_driver_->request_context()));
// Keep it alive beyond auto-cleanup so client's Done can get info out of
// filters.
child_driver->set_externally_managed(true);
computation_->SetupFilters(child_driver.get());
if (!child_driver->StartParse(resource()->url())) {
LOG(DFATAL) << "Huh? StartParse doesn't like URL, but resource fetched:"
<< resource()->url();
child_driver->Cleanup();
} else {
child_driver->ParseText(resource()->ExtractUncompressedContents());
child_driver->FinishParse();
ok = true;
}
computation_->ReportResult(ok);
delete this;
}
private:
RewriteDriver* parent_driver_;
RenderBlockingHtmlComputation* computation_;
};
RenderBlockingHtmlComputation::RenderBlockingHtmlComputation(
RewriteDriver* parent_driver) : parent_driver_(parent_driver) {}
void RenderBlockingHtmlComputation::Compute(const GoogleString& url) {
parent_driver_->IncrementRenderBlockingAsyncEventsCount();
GoogleUrl gurl(url);
if (!gurl.IsWebValid()) {
ReportResult(false);
return;
}
bool is_authorized = false;
ResourcePtr resource(
parent_driver_->CreateInputResource(gurl, &is_authorized));
if (resource.get() == NULL) {
ReportResult(false);
return;
}
// Don't cancel us willy-nilly. (Cancellation due to e.g. shutdown
// will just look like failures to us and will be passed on to our
// client).
resource->set_is_background_fetch(false);
ResourceCallback* resource_callback =
new ResourceCallback(parent_driver_, resource, this);
resource->LoadAsync(Resource::kLoadEvenIfNotCacheable,
parent_driver_->request_context(),
resource_callback);
}
RenderBlockingHtmlComputation::~RenderBlockingHtmlComputation() {}
void RenderBlockingHtmlComputation::ReportResult(bool success) {
Done(success);
parent_driver_->DecrementRenderBlockingAsyncEventsCount();
delete this;
}
} // namespace net_instaweb