blob: 748af784874767272e9fdb1c3e67ae84160f6783 [file] [log] [blame]
/*
* Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
* (http://www.torchmobile.com/)
* Copyright (C) 2009 Adam Barth. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/loader/http_refresh_scheduler.h"
#include <memory>
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/core/events/current_input_event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
static constexpr base::TimeDelta kMaxScheduledDelay =
base::TimeDelta::FromSeconds(INT32_MAX / 1000);
namespace blink {
static ClientNavigationReason ToReason(
Document::HttpRefreshType http_refresh_type) {
switch (http_refresh_type) {
case Document::HttpRefreshType::kHttpRefreshFromHeader:
return ClientNavigationReason::kHttpHeaderRefresh;
case Document::HttpRefreshType::kHttpRefreshFromMetaTag:
return ClientNavigationReason::kMetaTagRefresh;
default:
break;
}
NOTREACHED();
return ClientNavigationReason::kMetaTagRefresh;
}
HttpRefreshScheduler::HttpRefreshScheduler(Document* document)
: document_(document) {}
bool HttpRefreshScheduler::IsScheduledWithin(base::TimeDelta interval) const {
return refresh_ && refresh_->delay <= interval;
}
void HttpRefreshScheduler::Schedule(
base::TimeDelta delay,
const KURL& url,
Document::HttpRefreshType http_refresh_type) {
DCHECK(document_->GetFrame());
if (!document_->GetFrame()->IsNavigationAllowed())
return;
if (delay < base::TimeDelta() || delay > kMaxScheduledDelay)
return;
if (url.IsEmpty())
return;
if (refresh_ && refresh_->delay < delay)
return;
base::TimeTicks timestamp;
if (const WebInputEvent* input_event = CurrentInputEvent::Get())
timestamp = input_event->TimeStamp();
Cancel();
refresh_ = std::make_unique<ScheduledHttpRefresh>(
delay, url, ToReason(http_refresh_type), timestamp);
MaybeStartTimer();
}
void HttpRefreshScheduler::NavigateTask() {
TRACE_EVENT2("navigation", "HttpRefreshScheduler::NavigateTask",
"document_url", document_->Url().GetString().Utf8(),
"refresh_url", refresh_->url.GetString().Utf8());
DCHECK(document_->GetFrame());
std::unique_ptr<ScheduledHttpRefresh> refresh(refresh_.release());
FrameLoadRequest request(document_->domWindow(),
ResourceRequest(refresh->url));
request.SetInputStartTime(refresh->input_timestamp);
request.SetClientRedirectReason(refresh->reason);
WebFrameLoadType load_type = WebFrameLoadType::kStandard;
// If the urls match, process the refresh as a reload. However, if an initial
// empty document has its url modified via document.open() and the refresh is
// to that url, it will confuse the browser process to report it as a reload
// in a frame where there hasn't actually been a navigation yet. Therefore,
// don't treat as a reload if all this frame has ever seen is empty documents.
if (EqualIgnoringFragmentIdentifier(document_->Url(), refresh->url) &&
document_->GetFrame()->Loader().HasLoadedNonEmptyDocument()) {
request.GetResourceRequest().SetCacheMode(
mojom::FetchCacheMode::kValidateCache);
load_type = WebFrameLoadType::kReload;
} else if (refresh->delay <= base::TimeDelta::FromSeconds(1)) {
load_type = WebFrameLoadType::kReplaceCurrentItem;
}
document_->GetFrame()->Loader().StartNavigation(request, load_type);
probe::FrameClearedScheduledNavigation(document_->GetFrame());
}
void HttpRefreshScheduler::MaybeStartTimer() {
if (!refresh_)
return;
if (navigate_task_handle_.IsActive())
return;
if (!document_->LoadEventFinished())
return;
// wrapWeakPersistent(this) is safe because a posted task is canceled when the
// task handle is destroyed on the dtor of this HttpRefreshScheduler.
navigate_task_handle_ = PostDelayedCancellableTask(
*document_->GetTaskRunner(TaskType::kInternalLoading), FROM_HERE,
WTF::Bind(&HttpRefreshScheduler::NavigateTask, WrapWeakPersistent(this)),
refresh_->delay);
probe::FrameScheduledNavigation(document_->GetFrame(), refresh_->url,
refresh_->delay, refresh_->reason);
}
void HttpRefreshScheduler::Cancel() {
if (navigate_task_handle_.IsActive()) {
probe::FrameClearedScheduledNavigation(document_->GetFrame());
}
navigate_task_handle_.Cancel();
refresh_.reset();
}
void HttpRefreshScheduler::Trace(Visitor* visitor) const {
visitor->Trace(document_);
}
} // namespace blink