Skip to content

Commit 5da0ed1

Browse files
naarciniCommit Bot
authored and
Commit Bot
committed
Allow range requests to pass through a service worker
This change implements the following edits to the Fetch spec: whatwg/fetch#560 whatwg/fetch#1076 Existing web tests cover the new functionality. Bug: 847428 Change-Id: Ie63704769e99d4b8d26d8903edf4cc4e3466c124 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2339761 Commit-Queue: Nicolas Arciniega <[email protected]> Reviewed-by: Kinuko Yasuda <[email protected]> Reviewed-by: Matt Falkenhagen <[email protected]> Reviewed-by: Ben Kelly <[email protected]> Reviewed-by: Yutaka Hirano <[email protected]> Reviewed-by: Makoto Shimazu <[email protected]> Cr-Commit-Position: refs/heads/master@{#800663}
1 parent fadc13d commit 5da0ed1

File tree

31 files changed

+198
-44
lines changed

31 files changed

+198
-44
lines changed

content/browser/cache_storage/cache_storage_cache_unittest.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,8 @@ class CacheStorageCacheTest : public testing::Test {
672672
network::mojom::ParsedHeaders::New(),
673673
net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN,
674674
"unknown" /* alpn_negotiated_protocol */,
675-
false /* loaded_with_credentials */, false /* was_fetched_via_spdy */);
675+
false /* loaded_with_credentials */, false /* was_fetched_via_spdy */,
676+
false /* has_range_requested */);
676677
}
677678

678679
void CopySideDataToResponse(const std::string& uuid,

content/browser/cache_storage/cache_storage_manager_unittest.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,8 @@ class CacheStorageManagerTest : public testing::Test {
669669
network::mojom::ParsedHeaders::New(),
670670
net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN,
671671
"unknown" /* alpn_negotiated_protocol */,
672-
false /* loaded_with_credentials */, false /* was_fetched_via_spdy */);
672+
false /* loaded_with_credentials */, false /* was_fetched_via_spdy */,
673+
false /* has_range_requested */);
673674

674675
blink::mojom::BatchOperationPtr operation =
675676
blink::mojom::BatchOperation::New();

content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
#include "net/base/net_errors.h"
5050
#include "net/disk_cache/disk_cache.h"
5151
#include "net/http/http_request_headers.h"
52+
#include "net/http/http_response_headers.h"
53+
#include "net/http/http_status_code.h"
5254
#include "services/network/public/mojom/fetch_api.mojom.h"
5355
#include "storage/browser/blob/blob_storage_context.h"
5456
#include "storage/browser/quota/padding_key.h"
@@ -425,6 +427,10 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
425427
if (metadata.response().has_request_method())
426428
request_method = metadata.response().request_method();
427429

430+
// Note that |has_range_requested| can be safely set to false since it only
431+
// affects HTTP 206 (Partial) responses, which are blocked from cache storage.
432+
// See https://fetch.spec.whatwg.org/#main-fetch for usage of
433+
// |has_range_requested|.
428434
return blink::mojom::FetchAPIResponse::New(
429435
url_list, metadata.response().status_code(),
430436
metadata.response().status_text(),
@@ -443,7 +449,8 @@ blink::mojom::FetchAPIResponsePtr CreateResponse(
443449
static_cast<net::HttpResponseInfo::ConnectionInfo>(
444450
metadata.response().connection_info()),
445451
alpn_negotiated_protocol, metadata.response().loaded_with_credentials(),
446-
metadata.response().was_fetched_via_spdy());
452+
metadata.response().was_fetched_via_spdy(),
453+
/* has_range_requested */ false);
447454
}
448455

449456
// The size of opaque (non-cors) resource responses are padded in order
@@ -1796,6 +1803,7 @@ void LegacyCacheStorageCache::PutDidCreateEntry(
17961803
}
17971804

17981805
proto::CacheResponse* response_metadata = metadata.mutable_response();
1806+
DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT);
17991807
response_metadata->set_status_code(put_context->response->status_code);
18001808
response_metadata->set_status_text(put_context->response->status_text);
18011809
response_metadata->set_response_type(FetchResponseTypeToProtoResponseType(

content/common/background_fetch/background_fetch_types.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ blink::mojom::FetchAPIResponsePtr BackgroundFetchSettledFetch::CloneResponse(
4040
CloneSerializedBlob(response->side_data_blob_for_cache_put),
4141
mojo::Clone(response->parsed_headers), response->connection_info,
4242
response->alpn_negotiated_protocol, response->loaded_with_credentials,
43-
response->was_fetched_via_spdy);
43+
response->was_fetched_via_spdy, response->has_range_requested);
4444
}
4545

4646
// static

content/common/service_worker/service_worker_loader_helpers.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ void ServiceWorkerLoaderHelpers::SaveResponseInfo(
120120
out_head->connection_info = response.connection_info;
121121
out_head->alpn_negotiated_protocol = response.alpn_negotiated_protocol;
122122
out_head->was_fetched_via_spdy = response.was_fetched_via_spdy;
123+
out_head->has_range_requested = response.has_range_requested;
123124
}
124125

125126
// static

content/renderer/loader/web_url_loader_impl.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,7 @@ void WebURLLoaderImpl::PopulateURLResponse(
910910
net::IsCertStatusError(head.cert_status));
911911
response->SetCTPolicyCompliance(head.ct_policy_compliance);
912912
response->SetIsLegacyTLSVersion(head.is_legacy_tls_version);
913+
response->SetHasRangeRequested(head.has_range_requested);
913914
response->SetTimingAllowPassed(head.timing_allow_passed);
914915
response->SetAppCacheID(head.appcache_id);
915916
response->SetAppCacheManifestURL(head.appcache_manifest_url);

services/network/public/cpp/cors/cors.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,14 @@ bool IsNoCorsSafelistedHeaderName(const std::string& name) {
490490
}
491491

492492
bool IsPrivilegedNoCorsHeaderName(const std::string& name) {
493-
return base::ToLowerASCII(name) == "range";
493+
const std::string lower_name = base::ToLowerASCII(name);
494+
const std::vector<std::string> privileged_no_cors_header_names =
495+
PrivilegedNoCorsHeaderNames();
496+
for (const auto& header : privileged_no_cors_header_names) {
497+
if (lower_name == header)
498+
return true;
499+
}
500+
return false;
494501
}
495502

496503
bool IsNoCorsSafelistedHeader(const std::string& name,
@@ -560,6 +567,10 @@ std::vector<std::string> CorsUnsafeNotForbiddenRequestHeaderNames(
560567
return header_names;
561568
}
562569

570+
std::vector<std::string> PrivilegedNoCorsHeaderNames() {
571+
return {"range"};
572+
}
573+
563574
bool IsForbiddenMethod(const std::string& method) {
564575
const std::string upper_method = base::ToUpperASCII(method);
565576
return upper_method == net::HttpRequestHeaders::kConnectMethod ||

services/network/public/cpp/cors/cors.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ std::vector<std::string> CorsUnsafeNotForbiddenRequestHeaderNames(
137137
const net::HttpRequestHeaders::HeaderVector& headers,
138138
bool is_revalidating);
139139

140+
// https://fetch.spec.whatwg.org/#privileged-no-cors-request-header-name
141+
// The returned list is NOT sorted.
142+
// The returned list consists of lower-cased names.
143+
COMPONENT_EXPORT(NETWORK_CPP)
144+
std::vector<std::string> PrivilegedNoCorsHeaderNames();
145+
140146
// Checks forbidden method in the fetch spec.
141147
// See https://fetch.spec.whatwg.org/#forbidden-method.
142148
// TODO(toyoshim): Move Blink FetchUtils::IsForbiddenMethod to cors:: and use

services/network/public/mojom/url_response_head.mojom

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ struct URLResponseHead {
190190
// will be removed in the future.
191191
bool is_legacy_tls_version = false;
192192

193+
// https://fetch.spec.whatwg.org/#concept-response-range-requested-flag
194+
bool has_range_requested = false;
195+
193196
// https://fetch.spec.whatwg.org/#concept-response-timing-allow-passed
194197
bool timing_allow_passed = false;
195198

services/network/url_loader.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ void PopulateResourceResponse(net::URLRequest* request,
131131
response->response_start = base::TimeTicks::Now();
132132
response->encoded_data_length = request->GetTotalReceivedBytes();
133133
response->auth_challenge_info = request->auth_challenge_info();
134+
response->has_range_requested = request->extra_request_headers().HasHeader(
135+
net::HttpRequestHeaders::kRange);
134136
}
135137

136138
// A subclass of net::UploadBytesElementReader which owns

third_party/blink/public/mojom/fetch/fetch_api_response.mojom

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,7 @@ struct FetchAPIResponse {
105105
// True if the response was originally loaded via a request fetched over a
106106
// SPDY channel.
107107
bool was_fetched_via_spdy = false;
108+
109+
// https://fetch.spec.whatwg.org/#concept-response-range-requested-flag
110+
bool has_range_requested = false;
108111
};

third_party/blink/public/platform/web_url_response.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ class WebURLResponse {
219219
BLINK_PLATFORM_EXPORT void SetHasMajorCertificateErrors(bool);
220220
BLINK_PLATFORM_EXPORT void SetCTPolicyCompliance(net::ct::CTPolicyCompliance);
221221
BLINK_PLATFORM_EXPORT void SetIsLegacyTLSVersion(bool);
222+
BLINK_PLATFORM_EXPORT void SetHasRangeRequested(bool);
222223
BLINK_PLATFORM_EXPORT void SetTimingAllowPassed(bool);
223224

224225
BLINK_PLATFORM_EXPORT void SetSecurityStyle(SecurityStyle);

third_party/blink/renderer/core/fetch/fetch_manager.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -714,11 +714,6 @@ void FetchManager::Loader::PerformHTTPFetch() {
714714

715715
request.SetCredentialsMode(fetch_request_data_->Credentials());
716716
for (const auto& header : fetch_request_data_->HeaderList()->List()) {
717-
// Since |fetch_request_data_|'s headers are populated with either of the
718-
// "request" guard or "request-no-cors" guard, we can assume that none of
719-
// the headers have a name listed in the forbidden header names.
720-
DCHECK(!cors::IsForbiddenHeaderName(header.first));
721-
722717
request.AddHttpHeaderField(AtomicString(header.first),
723718
AtomicString(header.second));
724719
}

third_party/blink/renderer/core/fetch/fetch_response_data.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,13 @@ const KURL* FetchResponseData::Url() const {
141141
return &url_list_.back();
142142
}
143143

144+
uint16_t FetchResponseData::InternalStatus() const {
145+
if (internal_response_) {
146+
return internal_response_->Status();
147+
}
148+
return Status();
149+
}
150+
144151
FetchHeaderList* FetchResponseData::InternalHeaderList() const {
145152
if (internal_response_) {
146153
return internal_response_->HeaderList();
@@ -199,6 +206,7 @@ FetchResponseData* FetchResponseData::Clone(ScriptState* script_state,
199206
new_response->alpn_negotiated_protocol_ = alpn_negotiated_protocol_;
200207
new_response->loaded_with_credentials_ = loaded_with_credentials_;
201208
new_response->was_fetched_via_spdy_ = was_fetched_via_spdy_;
209+
new_response->has_range_requested_ = has_range_requested_;
202210

203211
switch (type_) {
204212
case Type::kBasic:
@@ -272,6 +280,7 @@ mojom::blink::FetchAPIResponsePtr FetchResponseData::PopulateFetchAPIResponse(
272280
response->alpn_negotiated_protocol = alpn_negotiated_protocol_;
273281
response->loaded_with_credentials = loaded_with_credentials_;
274282
response->was_fetched_via_spdy = was_fetched_via_spdy_;
283+
response->has_range_requested = has_range_requested_;
275284
for (const auto& header : HeaderList()->List())
276285
response->headers.insert(header.first, header.second);
277286
response->parsed_headers = ParseHeaders(
@@ -336,6 +345,8 @@ void FetchResponseData::InitFromResourceResponse(
336345
request_credentials == network::mojom::CredentialsMode::kInclude ||
337346
(request_credentials == network::mojom::CredentialsMode::kSameOrigin &&
338347
tainting == FetchRequestData::kBasicTainting));
348+
349+
SetHasRangeRequested(response.HasRangeRequested());
339350
}
340351

341352
FetchResponseData::FetchResponseData(Type type,
@@ -351,7 +362,8 @@ FetchResponseData::FetchResponseData(Type type,
351362
connection_info_(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN),
352363
alpn_negotiated_protocol_("unknown"),
353364
loaded_with_credentials_(false),
354-
was_fetched_via_spdy_(false) {}
365+
was_fetched_via_spdy_(false),
366+
has_range_requested_(false) {}
355367

356368
void FetchResponseData::ReplaceBodyStreamBuffer(BodyStreamBuffer* buffer) {
357369
if (type_ == Type::kBasic || type_ == Type::kCors) {

third_party/blink/renderer/core/fetch/fetch_response_data.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class CORE_EXPORT FetchResponseData final
6868
}
6969
const KURL* Url() const;
7070
uint16_t Status() const { return status_; }
71+
uint16_t InternalStatus() const;
7172
AtomicString StatusMessage() const { return status_message_; }
7273
FetchHeaderList* HeaderList() const { return header_list_.Get(); }
7374
FetchHeaderList* InternalHeaderList() const;
@@ -82,6 +83,7 @@ class CORE_EXPORT FetchResponseData final
8283
const HTTPHeaderSet& CorsExposedHeaderNames() const {
8384
return cors_exposed_header_names_;
8485
}
86+
bool HasRangeRequested() const { return has_range_requested_; }
8587

8688
void SetResponseSource(network::mojom::FetchResponseSource response_source) {
8789
response_source_ = response_source;
@@ -120,6 +122,9 @@ class CORE_EXPORT FetchResponseData final
120122
void SetWasFetchedViaSpdy(bool was_fetched_via_spdy) {
121123
was_fetched_via_spdy_ = was_fetched_via_spdy;
122124
}
125+
void SetHasRangeRequested(bool has_range_requested) {
126+
has_range_requested_ = has_range_requested;
127+
}
123128

124129
// If the type is Default, replaces |buffer_|.
125130
// If the type is Basic or CORS, replaces |buffer_| and
@@ -160,6 +165,7 @@ class CORE_EXPORT FetchResponseData final
160165
AtomicString alpn_negotiated_protocol_;
161166
bool loaded_with_credentials_;
162167
bool was_fetched_via_spdy_;
168+
bool has_range_requested_;
163169

164170
DISALLOW_COPY_AND_ASSIGN(FetchResponseData);
165171
};

third_party/blink/renderer/core/fetch/headers.cc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ void Headers::append(const String& name,
126126
}
127127
// "7. Append |name|/|value| to header list."
128128
header_list_->Append(name, normalized_value);
129+
// "8. If this’s guard is |request-no-cors|, then remove privileged no-CORS
130+
// request headers from this."
131+
if (guard_ == kRequestNoCorsGuard)
132+
RemovePrivilegedNoCorsRequestHeaders();
129133
}
130134

131135
void Headers::remove(const String& name, ExceptionState& exception_state) {
@@ -158,8 +162,15 @@ void Headers::remove(const String& name, ExceptionState& exception_state) {
158162
FetchUtils::IsForbiddenResponseHeaderName(name)) {
159163
return;
160164
}
161-
// "6. Delete |name| from header list."
165+
// "6. If this’s header list does not contain |name|, then return."
166+
if (!header_list_->Has(name))
167+
return;
168+
// "7. Delete |name| from header list."
162169
header_list_->Remove(name);
170+
// "8. If this’s guard is |request-no-cors|, then remove privileged no-CORS
171+
// request headers from this."
172+
if (guard_ == kRequestNoCorsGuard)
173+
RemovePrivilegedNoCorsRequestHeaders();
163174
}
164175

165176
String Headers::get(const String& name, ExceptionState& exception_state) {
@@ -228,6 +239,10 @@ void Headers::set(const String& name,
228239
}
229240
// "7. Set |name|/|value| in header list."
230241
header_list_->Set(name, normalized_value);
242+
// "8. If this’s guard is |request-no-cors|, then remove privileged no-CORS
243+
// request headers from this."
244+
if (guard_ == kRequestNoCorsGuard)
245+
RemovePrivilegedNoCorsRequestHeaders();
231246
}
232247

233248
// This overload is not called directly by Web APIs, but rather by other C++
@@ -285,6 +300,13 @@ void Headers::FillWith(const Vector<std::pair<String, String>>& object,
285300
}
286301
}
287302

303+
void Headers::RemovePrivilegedNoCorsRequestHeaders() {
304+
const Vector<String> privileged_no_cors_header_names =
305+
cors::PrivilegedNoCorsHeaderNames();
306+
for (const auto& header : privileged_no_cors_header_names)
307+
header_list_->Remove(header);
308+
}
309+
288310
Headers::Headers()
289311
: header_list_(MakeGarbageCollected<FetchHeaderList>()),
290312
guard_(kNoneGuard) {}

third_party/blink/renderer/core/fetch/headers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ class CORE_EXPORT Headers final : public ScriptWrappable,
5959
void FillWith(const Headers*, ExceptionState&);
6060
void FillWith(const HeadersInit&, ExceptionState&);
6161

62+
// https://fetch.spec.whatwg.org/#concept-headers-remove-privileged-no-cors-request-headers
63+
void RemovePrivilegedNoCorsRequestHeaders();
64+
6265
FetchHeaderList* HeaderList() const { return header_list_; }
6366
void Trace(Visitor*) const override;
6467

third_party/blink/renderer/core/fetch/request.cc

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -564,19 +564,11 @@ Request* Request::CreateRequestWithRequestOrString(
564564
// "Let |r| be a new Request object associated with |request| and a new
565565
// Headers object whose guard is "request"."
566566
Request* r = Request::Create(script_state, request);
567-
// Perform the following steps:
568-
// - "Let |headers| be a copy of |r|'s Headers object."
569-
// - "If |init|'s headers member is present, set |headers| to |init|'s
570-
// headers member."
571-
//
572-
// We don't create a copy of r's Headers object when init's headers member
573-
// is present.
574-
Headers* headers = nullptr;
575-
if (!init->hasHeaders()) {
576-
headers = r->getHeaders()->Clone();
577-
}
578-
// "Empty |r|'s request's header list."
579-
r->request_->HeaderList()->ClearList();
567+
568+
// "If |signal| is not null, then make |r|’s signal follow |signal|."
569+
if (signal)
570+
r->signal_->Follow(signal);
571+
580572
// "If |r|'s request's mode is "no-cors", run these substeps:
581573
if (r->GetRequest()->Mode() == network::mojom::RequestMode::kNoCors) {
582574
// "If |r|'s request's method is not a CORS-safelisted method, throw a
@@ -589,19 +581,32 @@ Request* Request::CreateRequestWithRequestOrString(
589581
// "Set |r|'s Headers object's guard to "request-no-cors"."
590582
r->getHeaders()->SetGuard(Headers::kRequestNoCorsGuard);
591583
}
592-
// "If |signal| is not null, then make |r|’s signal follow |signal|."
593-
if (signal)
594-
r->signal_->Follow(signal);
595584

596-
// "Fill |r|'s Headers object with |headers|. Rethrow any exceptions."
597-
if (init->hasHeaders()) {
598-
r->getHeaders()->FillWith(init->headers(), exception_state);
599-
} else {
600-
DCHECK(headers);
601-
r->getHeaders()->FillWith(headers, exception_state);
585+
if (AreAnyMembersPresent(init)) {
586+
// Perform the following steps:
587+
// - "Let |headers| be a copy of |r|'s Headers object."
588+
// - "If |init|'s headers member is present, set |headers| to |init|'s
589+
// headers member."
590+
//
591+
// We don't create a copy of r's Headers object when init's headers member
592+
// is present.
593+
Headers* headers = nullptr;
594+
if (!init->hasHeaders()) {
595+
headers = r->getHeaders()->Clone();
596+
}
597+
// "Empty |r|'s request's header list."
598+
r->request_->HeaderList()->ClearList();
599+
600+
// "Fill |r|'s Headers object with |headers|. Rethrow any exceptions."
601+
if (init->hasHeaders()) {
602+
r->getHeaders()->FillWith(init->headers(), exception_state);
603+
} else {
604+
DCHECK(headers);
605+
r->getHeaders()->FillWith(headers, exception_state);
606+
}
607+
if (exception_state.HadException())
608+
return nullptr;
602609
}
603-
if (exception_state.HadException())
604-
return nullptr;
605610

606611
// "Let |inputBody| be |input|'s request's body if |input| is a
607612
// Request object, and null otherwise."

third_party/blink/renderer/core/fetch/response.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ FetchResponseData* Response::CreateUnfilteredFetchResponseDataWithoutBody(
389389
response->SetLoadedWithCredentials(
390390
fetch_api_response.loaded_with_credentials);
391391
response->SetWasFetchedViaSpdy(fetch_api_response.was_fetched_via_spdy);
392+
response->SetHasRangeRequested(fetch_api_response.has_range_requested);
392393

393394
for (const auto& header : fetch_api_response.headers)
394395
response->HeaderList()->Append(header.key, header.value);

0 commit comments

Comments
 (0)