blob: 52c9e86c635761d3ea4a247ff9534145f4f88ab4 [file] [log] [blame]
/*
* Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2009, 2012 Google Inc. 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR
* 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 "platform/loader/fetch/ResourceRequest.h"
#include <memory>
#include "platform/HTTPNames.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/network/NetworkUtils.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "platform/wtf/PtrUtil.h"
#include "public/platform/WebAddressSpace.h"
#include "public/platform/WebCachePolicy.h"
#include "public/platform/WebURLRequest.h"
namespace blink {
double ResourceRequest::default_timeout_interval_ = INT_MAX;
ResourceRequest::ResourceRequest() : ResourceRequest(KURL()) {}
ResourceRequest::ResourceRequest(const String& url_string)
: ResourceRequest(KURL(kParsedURLString, url_string)) {}
ResourceRequest::ResourceRequest(const KURL& url)
: url_(url),
cache_policy_(WebCachePolicy::kUseProtocolCachePolicy),
timeout_interval_(default_timeout_interval_),
requestor_origin_(SecurityOrigin::CreateUnique()),
http_method_(HTTPNames::GET),
allow_stored_credentials_(true),
report_upload_progress_(false),
report_raw_headers_(false),
has_user_gesture_(false),
download_to_file_(false),
use_stream_on_response_(false),
keepalive_(false),
should_reset_app_cache_(false),
service_worker_mode_(WebURLRequest::ServiceWorkerMode::kAll),
priority_(kResourceLoadPriorityLowest),
intra_priority_value_(0),
requestor_id_(0),
requestor_process_id_(0),
app_cache_host_id_(0),
request_context_(WebURLRequest::kRequestContextUnspecified),
frame_type_(WebURLRequest::kFrameTypeNone),
fetch_request_mode_(WebURLRequest::kFetchRequestModeNoCORS),
fetch_credentials_mode_(WebURLRequest::kFetchCredentialsModeInclude),
fetch_redirect_mode_(WebURLRequest::kFetchRedirectModeFollow),
previews_state_(WebURLRequest::kPreviewsUnspecified),
referrer_policy_(kReferrerPolicyDefault),
did_set_http_referrer_(false),
check_for_browser_side_navigation_(true),
ui_start_time_(0),
is_external_request_(false),
loading_ipc_type_(RuntimeEnabledFeatures::loadingWithMojoEnabled()
? WebURLRequest::LoadingIPCType::kMojo
: WebURLRequest::LoadingIPCType::kChromeIPC),
is_same_document_navigation_(false),
input_perf_metric_report_policy_(
InputToLoadPerfMetricReportPolicy::kNoReport),
redirect_status_(RedirectStatus::kNoRedirect) {}
ResourceRequest::ResourceRequest(CrossThreadResourceRequestData* data)
: ResourceRequest(data->url_) {
SetCachePolicy(data->cache_policy_);
SetTimeoutInterval(data->timeout_interval_);
SetFirstPartyForCookies(data->first_party_for_cookies_);
SetRequestorOrigin(data->requestor_origin_);
SetHTTPMethod(AtomicString(data->http_method_));
SetPriority(data->priority_, data->intra_priority_value_);
http_header_fields_.Adopt(std::move(data->http_headers_));
SetHTTPBody(data->http_body_);
SetAttachedCredential(data->attached_credential_);
SetAllowStoredCredentials(data->allow_stored_credentials_);
SetReportUploadProgress(data->report_upload_progress_);
SetHasUserGesture(data->has_user_gesture_);
SetDownloadToFile(data->download_to_file_);
SetUseStreamOnResponse(data->use_stream_on_response_);
SetKeepalive(data->keepalive_);
SetServiceWorkerMode(data->service_worker_mode_);
SetShouldResetAppCache(data->should_reset_app_cache_);
SetRequestorID(data->requestor_id_);
SetRequestorProcessID(data->requestor_process_id_);
SetAppCacheHostID(data->app_cache_host_id_);
SetRequestContext(data->request_context_);
SetFrameType(data->frame_type_);
SetFetchRequestMode(data->fetch_request_mode_);
SetFetchCredentialsMode(data->fetch_credentials_mode_);
SetFetchRedirectMode(data->fetch_redirect_mode_);
SetPreviewsState(data->previews_state_);
referrer_policy_ = data->referrer_policy_;
did_set_http_referrer_ = data->did_set_http_referrer_;
check_for_browser_side_navigation_ = data->check_for_browser_side_navigation_;
ui_start_time_ = data->ui_start_time_;
is_external_request_ = data->is_external_request_;
loading_ipc_type_ = data->loading_ipc_type_;
input_perf_metric_report_policy_ = data->input_perf_metric_report_policy_;
redirect_status_ = data->redirect_status_;
}
ResourceRequest::ResourceRequest(const ResourceRequest&) = default;
ResourceRequest& ResourceRequest::operator=(const ResourceRequest&) = default;
std::unique_ptr<CrossThreadResourceRequestData> ResourceRequest::CopyData()
const {
std::unique_ptr<CrossThreadResourceRequestData> data =
WTF::MakeUnique<CrossThreadResourceRequestData>();
data->url_ = Url().Copy();
data->cache_policy_ = GetCachePolicy();
data->timeout_interval_ = TimeoutInterval();
data->first_party_for_cookies_ = FirstPartyForCookies().Copy();
data->requestor_origin_ =
RequestorOrigin() ? RequestorOrigin()->IsolatedCopy() : nullptr;
data->http_method_ = HttpMethod().GetString().IsolatedCopy();
data->http_headers_ = HttpHeaderFields().CopyData();
data->priority_ = Priority();
data->intra_priority_value_ = intra_priority_value_;
if (http_body_)
data->http_body_ = http_body_->DeepCopy();
if (attached_credential_)
data->attached_credential_ = attached_credential_->DeepCopy();
data->allow_stored_credentials_ = allow_stored_credentials_;
data->report_upload_progress_ = report_upload_progress_;
data->has_user_gesture_ = has_user_gesture_;
data->download_to_file_ = download_to_file_;
data->use_stream_on_response_ = use_stream_on_response_;
data->keepalive_ = keepalive_;
data->service_worker_mode_ = service_worker_mode_;
data->should_reset_app_cache_ = should_reset_app_cache_;
data->requestor_id_ = requestor_id_;
data->requestor_process_id_ = requestor_process_id_;
data->app_cache_host_id_ = app_cache_host_id_;
data->request_context_ = request_context_;
data->frame_type_ = frame_type_;
data->fetch_request_mode_ = fetch_request_mode_;
data->fetch_credentials_mode_ = fetch_credentials_mode_;
data->fetch_redirect_mode_ = fetch_redirect_mode_;
data->previews_state_ = previews_state_;
data->referrer_policy_ = referrer_policy_;
data->did_set_http_referrer_ = did_set_http_referrer_;
data->check_for_browser_side_navigation_ = check_for_browser_side_navigation_;
data->ui_start_time_ = ui_start_time_;
data->is_external_request_ = is_external_request_;
data->loading_ipc_type_ = loading_ipc_type_;
data->input_perf_metric_report_policy_ = input_perf_metric_report_policy_;
data->redirect_status_ = redirect_status_;
return data;
}
bool ResourceRequest::IsEmpty() const {
return url_.IsEmpty();
}
bool ResourceRequest::IsNull() const {
return url_.IsNull();
}
const KURL& ResourceRequest::Url() const {
return url_;
}
void ResourceRequest::SetURL(const KURL& url) {
url_ = url;
}
void ResourceRequest::RemoveUserAndPassFromURL() {
if (url_.User().IsEmpty() && url_.Pass().IsEmpty())
return;
url_.SetUser(String());
url_.SetPass(String());
}
WebCachePolicy ResourceRequest::GetCachePolicy() const {
return cache_policy_;
}
void ResourceRequest::SetCachePolicy(WebCachePolicy cache_policy) {
cache_policy_ = cache_policy;
}
double ResourceRequest::TimeoutInterval() const {
return timeout_interval_;
}
void ResourceRequest::SetTimeoutInterval(double timout_interval_seconds) {
timeout_interval_ = timout_interval_seconds;
}
const KURL& ResourceRequest::FirstPartyForCookies() const {
return first_party_for_cookies_;
}
void ResourceRequest::SetFirstPartyForCookies(
const KURL& first_party_for_cookies) {
first_party_for_cookies_ = first_party_for_cookies;
}
PassRefPtr<SecurityOrigin> ResourceRequest::RequestorOrigin() const {
return requestor_origin_;
}
void ResourceRequest::SetRequestorOrigin(
PassRefPtr<SecurityOrigin> requestor_origin) {
requestor_origin_ = std::move(requestor_origin);
}
const AtomicString& ResourceRequest::HttpMethod() const {
return http_method_;
}
void ResourceRequest::SetHTTPMethod(const AtomicString& http_method) {
http_method_ = http_method;
}
const HTTPHeaderMap& ResourceRequest::HttpHeaderFields() const {
return http_header_fields_;
}
const AtomicString& ResourceRequest::HttpHeaderField(
const AtomicString& name) const {
return http_header_fields_.Get(name);
}
void ResourceRequest::SetHTTPHeaderField(const AtomicString& name,
const AtomicString& value) {
http_header_fields_.Set(name, value);
}
void ResourceRequest::SetHTTPReferrer(const Referrer& referrer) {
if (referrer.referrer.IsEmpty())
http_header_fields_.Remove(HTTPNames::Referer);
else
SetHTTPHeaderField(HTTPNames::Referer, referrer.referrer);
referrer_policy_ = referrer.referrer_policy;
did_set_http_referrer_ = true;
}
void ResourceRequest::ClearHTTPReferrer() {
http_header_fields_.Remove(HTTPNames::Referer);
referrer_policy_ = kReferrerPolicyDefault;
did_set_http_referrer_ = false;
}
void ResourceRequest::SetHTTPOrigin(const SecurityOrigin* origin) {
SetHTTPHeaderField(HTTPNames::Origin, origin->ToAtomicString());
if (origin->HasSuborigin()) {
SetHTTPHeaderField(HTTPNames::Suborigin,
AtomicString(origin->GetSuborigin()->GetName()));
}
}
void ResourceRequest::ClearHTTPOrigin() {
http_header_fields_.Remove(HTTPNames::Origin);
http_header_fields_.Remove(HTTPNames::Suborigin);
}
void ResourceRequest::AddHTTPOriginIfNeeded(const SecurityOrigin* origin) {
if (NeedsHTTPOrigin())
SetHTTPOrigin(origin);
}
void ResourceRequest::AddHTTPOriginIfNeeded(const String& origin_string) {
if (NeedsHTTPOrigin())
SetHTTPOrigin(SecurityOrigin::CreateFromString(origin_string).Get());
}
void ResourceRequest::ClearHTTPUserAgent() {
http_header_fields_.Remove(HTTPNames::User_Agent);
}
EncodedFormData* ResourceRequest::HttpBody() const {
return http_body_.Get();
}
void ResourceRequest::SetHTTPBody(PassRefPtr<EncodedFormData> http_body) {
http_body_ = std::move(http_body);
}
EncodedFormData* ResourceRequest::AttachedCredential() const {
return attached_credential_.Get();
}
void ResourceRequest::SetAttachedCredential(
PassRefPtr<EncodedFormData> attached_credential) {
attached_credential_ = std::move(attached_credential);
}
bool ResourceRequest::AllowStoredCredentials() const {
return allow_stored_credentials_;
}
void ResourceRequest::SetAllowStoredCredentials(bool allow_credentials) {
allow_stored_credentials_ = allow_credentials;
}
ResourceLoadPriority ResourceRequest::Priority() const {
return priority_;
}
void ResourceRequest::SetPriority(ResourceLoadPriority priority,
int intra_priority_value) {
priority_ = priority;
intra_priority_value_ = intra_priority_value;
}
void ResourceRequest::AddHTTPHeaderField(const AtomicString& name,
const AtomicString& value) {
HTTPHeaderMap::AddResult result = http_header_fields_.Add(name, value);
if (!result.is_new_entry)
result.stored_value->value = result.stored_value->value + ", " + value;
}
void ResourceRequest::AddHTTPHeaderFields(const HTTPHeaderMap& header_fields) {
HTTPHeaderMap::const_iterator end = header_fields.end();
for (HTTPHeaderMap::const_iterator it = header_fields.begin(); it != end;
++it)
AddHTTPHeaderField(it->key, it->value);
}
void ResourceRequest::ClearHTTPHeaderField(const AtomicString& name) {
http_header_fields_.Remove(name);
}
void ResourceRequest::SetExternalRequestStateFromRequestorAddressSpace(
WebAddressSpace requestor_space) {
static_assert(kWebAddressSpaceLocal < kWebAddressSpacePrivate,
"Local is inside Private");
static_assert(kWebAddressSpaceLocal < kWebAddressSpacePublic,
"Local is inside Public");
static_assert(kWebAddressSpacePrivate < kWebAddressSpacePublic,
"Private is inside Public");
// TODO(mkwst): This only checks explicit IP addresses. We'll have to move all
// this up to //net and //content in order to have any real impact on gateway
// attacks. That turns out to be a TON of work. https://crbug.com/378566
if (!RuntimeEnabledFeatures::corsRFC1918Enabled()) {
is_external_request_ = false;
return;
}
WebAddressSpace target_space = kWebAddressSpacePublic;
if (NetworkUtils::IsReservedIPAddress(url_.Host()))
target_space = kWebAddressSpacePrivate;
if (SecurityOrigin::Create(url_)->IsLocalhost())
target_space = kWebAddressSpaceLocal;
is_external_request_ = requestor_space > target_space;
}
void ResourceRequest::SetNavigationStartTime(double navigation_start) {
navigation_start_ = navigation_start;
}
bool ResourceRequest::IsConditional() const {
return (http_header_fields_.Contains(HTTPNames::If_Match) ||
http_header_fields_.Contains(HTTPNames::If_Modified_Since) ||
http_header_fields_.Contains(HTTPNames::If_None_Match) ||
http_header_fields_.Contains(HTTPNames::If_Range) ||
http_header_fields_.Contains(HTTPNames::If_Unmodified_Since));
}
void ResourceRequest::SetHasUserGesture(bool has_user_gesture) {
has_user_gesture_ |= has_user_gesture;
}
const CacheControlHeader& ResourceRequest::GetCacheControlHeader() const {
if (!cache_control_header_cache_.parsed) {
cache_control_header_cache_ = ParseCacheControlDirectives(
http_header_fields_.Get(HTTPNames::Cache_Control),
http_header_fields_.Get(HTTPNames::Pragma));
}
return cache_control_header_cache_;
}
bool ResourceRequest::CacheControlContainsNoCache() const {
return GetCacheControlHeader().contains_no_cache;
}
bool ResourceRequest::CacheControlContainsNoStore() const {
return GetCacheControlHeader().contains_no_store;
}
bool ResourceRequest::HasCacheValidatorFields() const {
return !http_header_fields_.Get(HTTPNames::Last_Modified).IsEmpty() ||
!http_header_fields_.Get(HTTPNames::ETag).IsEmpty();
}
bool ResourceRequest::NeedsHTTPOrigin() const {
if (!HttpOrigin().IsEmpty())
return false; // Request already has an Origin header.
// Don't send an Origin header for GET or HEAD to avoid privacy issues.
// For example, if an intranet page has a hyperlink to an external web
// site, we don't want to include the Origin of the request because it
// will leak the internal host name. Similar privacy concerns have lead
// to the widespread suppression of the Referer header at the network
// layer.
if (HttpMethod() == HTTPNames::GET || HttpMethod() == HTTPNames::HEAD)
return false;
// For non-GET and non-HEAD methods, always send an Origin header so the
// server knows we support this feature.
return true;
}
} // namespace blink