1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/child/web_url_request_util.h"
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "net/base/load_flags.h"
10 #include "net/base/net_errors.h"
11 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
12 #include "third_party/WebKit/public/platform/WebString.h"
13 #include "third_party/WebKit/public/platform/WebURL.h"
14 #include "third_party/WebKit/public/platform/WebURLError.h"
15 #include "third_party/WebKit/public/platform/WebURLRequest.h"
17 using blink::WebHTTPBody
;
18 using blink::WebString
;
19 using blink::WebURLRequest
;
25 const char kThrottledErrorDescription
[] =
26 "Request throttled. Visit http://dev.chromium.org/throttling for more "
29 class HeaderFlattener
: public blink::WebHTTPHeaderVisitor
{
31 HeaderFlattener() : has_accept_header_(false) {}
33 virtual void visitHeader(const WebString
& name
, const WebString
& value
) {
34 // Headers are latin1.
35 const std::string
& name_latin1
= name
.latin1();
36 const std::string
& value_latin1
= value
.latin1();
38 // Skip over referrer headers found in the header map because we already
39 // pulled it out as a separate parameter.
40 if (base::LowerCaseEqualsASCII(name_latin1
, "referer"))
43 if (base::LowerCaseEqualsASCII(name_latin1
, "accept"))
44 has_accept_header_
= true;
47 buffer_
.append("\r\n");
48 buffer_
.append(name_latin1
+ ": " + value_latin1
);
51 const std::string
& GetBuffer() {
52 // In some cases, WebKit doesn't add an Accept header, but not having the
53 // header confuses some web servers. See bug 808613.
54 if (!has_accept_header_
) {
56 buffer_
.append("\r\n");
57 buffer_
.append("Accept: */*");
58 has_accept_header_
= true;
65 bool has_accept_header_
;
70 ResourceType
WebURLRequestToResourceType(const WebURLRequest
& request
) {
71 WebURLRequest::RequestContext requestContext
= request
.requestContext();
72 if (request
.frameType() != WebURLRequest::FrameTypeNone
) {
73 DCHECK(requestContext
== WebURLRequest::RequestContextForm
||
74 requestContext
== WebURLRequest::RequestContextFrame
||
75 requestContext
== WebURLRequest::RequestContextHyperlink
||
76 requestContext
== WebURLRequest::RequestContextIframe
||
77 requestContext
== WebURLRequest::RequestContextInternal
||
78 requestContext
== WebURLRequest::RequestContextLocation
);
79 if (request
.frameType() == WebURLRequest::FrameTypeTopLevel
||
80 request
.frameType() == WebURLRequest::FrameTypeAuxiliary
) {
81 return RESOURCE_TYPE_MAIN_FRAME
;
83 if (request
.frameType() == WebURLRequest::FrameTypeNested
)
84 return RESOURCE_TYPE_SUB_FRAME
;
86 return RESOURCE_TYPE_SUB_RESOURCE
;
89 switch (requestContext
) {
91 case WebURLRequest::RequestContextFavicon
:
92 return RESOURCE_TYPE_FAVICON
;
95 case WebURLRequest::RequestContextFont
:
96 return RESOURCE_TYPE_FONT_RESOURCE
;
99 case WebURLRequest::RequestContextImage
:
100 case WebURLRequest::RequestContextImageSet
:
101 return RESOURCE_TYPE_IMAGE
;
104 case WebURLRequest::RequestContextAudio
:
105 case WebURLRequest::RequestContextVideo
:
106 return RESOURCE_TYPE_MEDIA
;
109 case WebURLRequest::RequestContextEmbed
:
110 case WebURLRequest::RequestContextObject
:
111 return RESOURCE_TYPE_OBJECT
;
114 case WebURLRequest::RequestContextBeacon
:
115 case WebURLRequest::RequestContextCSPReport
:
116 case WebURLRequest::RequestContextPing
:
117 return RESOURCE_TYPE_PING
;
120 case WebURLRequest::RequestContextPrefetch
:
121 return RESOURCE_TYPE_PREFETCH
;
124 case WebURLRequest::RequestContextImport
:
125 case WebURLRequest::RequestContextScript
:
126 return RESOURCE_TYPE_SCRIPT
;
129 case WebURLRequest::RequestContextXSLT
:
130 case WebURLRequest::RequestContextStyle
:
131 return RESOURCE_TYPE_STYLESHEET
;
134 case WebURLRequest::RequestContextDownload
:
135 case WebURLRequest::RequestContextManifest
:
136 case WebURLRequest::RequestContextSubresource
:
137 case WebURLRequest::RequestContextPlugin
:
138 return RESOURCE_TYPE_SUB_RESOURCE
;
141 case WebURLRequest::RequestContextTrack
:
142 return RESOURCE_TYPE_MEDIA
;
145 case WebURLRequest::RequestContextServiceWorker
:
146 return RESOURCE_TYPE_SERVICE_WORKER
;
147 case WebURLRequest::RequestContextSharedWorker
:
148 return RESOURCE_TYPE_SHARED_WORKER
;
149 case WebURLRequest::RequestContextWorker
:
150 return RESOURCE_TYPE_WORKER
;
153 case WebURLRequest::RequestContextInternal
:
154 case WebURLRequest::RequestContextUnspecified
:
155 return RESOURCE_TYPE_SUB_RESOURCE
;
158 case WebURLRequest::RequestContextEventSource
:
159 case WebURLRequest::RequestContextFetch
:
160 case WebURLRequest::RequestContextXMLHttpRequest
:
161 return RESOURCE_TYPE_XHR
;
163 // These should be handled by the FrameType checks at the top of the
165 case WebURLRequest::RequestContextForm
:
166 case WebURLRequest::RequestContextHyperlink
:
167 case WebURLRequest::RequestContextLocation
:
168 case WebURLRequest::RequestContextFrame
:
169 case WebURLRequest::RequestContextIframe
:
171 return RESOURCE_TYPE_SUB_RESOURCE
;
175 return RESOURCE_TYPE_SUB_RESOURCE
;
179 std::string
GetWebURLRequestHeaders(const blink::WebURLRequest
& request
) {
180 HeaderFlattener flattener
;
181 request
.visitHTTPHeaderFields(&flattener
);
182 return flattener
.GetBuffer();
185 int GetLoadFlagsForWebURLRequest(const blink::WebURLRequest
& request
) {
186 int load_flags
= net::LOAD_NORMAL
;
187 GURL url
= request
.url();
188 switch (request
.cachePolicy()) {
189 case WebURLRequest::ReloadIgnoringCacheData
:
190 // Required by LayoutTests/http/tests/misc/refresh-headers.php
191 load_flags
|= net::LOAD_VALIDATE_CACHE
;
193 case WebURLRequest::ReloadBypassingCache
:
194 load_flags
|= net::LOAD_BYPASS_CACHE
;
196 case WebURLRequest::ReturnCacheDataElseLoad
:
197 load_flags
|= net::LOAD_PREFERRING_CACHE
;
199 case WebURLRequest::ReturnCacheDataDontLoad
:
200 load_flags
|= net::LOAD_ONLY_FROM_CACHE
;
202 case WebURLRequest::UseProtocolCachePolicy
:
208 if (!request
.allowStoredCredentials()) {
209 load_flags
|= net::LOAD_DO_NOT_SAVE_COOKIES
;
210 load_flags
|= net::LOAD_DO_NOT_SEND_COOKIES
;
213 if (!request
.allowStoredCredentials())
214 load_flags
|= net::LOAD_DO_NOT_SEND_AUTH_DATA
;
219 scoped_refptr
<ResourceRequestBody
> GetRequestBodyForWebURLRequest(
220 const blink::WebURLRequest
& request
) {
221 scoped_refptr
<ResourceRequestBody
> request_body
;
223 if (request
.httpBody().isNull()) {
227 const std::string
& method
= request
.httpMethod().latin1();
228 // GET and HEAD requests shouldn't have http bodies.
229 DCHECK(method
!= "GET" && method
!= "HEAD");
231 const WebHTTPBody
& httpBody
= request
.httpBody();
232 request_body
= new ResourceRequestBody();
234 WebHTTPBody::Element element
;
235 while (httpBody
.elementAt(i
++, element
)) {
236 switch (element
.type
) {
237 case WebHTTPBody::Element::TypeData
:
238 if (!element
.data
.isEmpty()) {
239 // Blink sometimes gives empty data to append. These aren't
240 // necessary so they are just optimized out here.
241 request_body
->AppendBytes(
242 element
.data
.data(), static_cast<int>(element
.data
.size()));
245 case WebHTTPBody::Element::TypeFile
:
246 if (element
.fileLength
== -1) {
247 request_body
->AppendFileRange(
248 base::FilePath::FromUTF16Unsafe(element
.filePath
),
249 0, kuint64max
, base::Time());
251 request_body
->AppendFileRange(
252 base::FilePath::FromUTF16Unsafe(element
.filePath
),
253 static_cast<uint64
>(element
.fileStart
),
254 static_cast<uint64
>(element
.fileLength
),
255 base::Time::FromDoubleT(element
.modificationTime
));
258 case WebHTTPBody::Element::TypeFileSystemURL
: {
259 GURL file_system_url
= element
.fileSystemURL
;
260 DCHECK(file_system_url
.SchemeIsFileSystem());
261 request_body
->AppendFileSystemFileRange(
263 static_cast<uint64
>(element
.fileStart
),
264 static_cast<uint64
>(element
.fileLength
),
265 base::Time::FromDoubleT(element
.modificationTime
));
268 case WebHTTPBody::Element::TypeBlob
:
269 request_body
->AppendBlob(element
.blobUUID
.utf8());
275 request_body
->set_identifier(request
.httpBody().identifier());
279 #define STATIC_ASSERT_MATCHING_ENUMS(content_name, blink_name) \
281 static_cast<int>(content_name) == static_cast<int>(blink_name), \
282 "mismatching enums: " #content_name)
284 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_SAME_ORIGIN
,
285 WebURLRequest::FetchRequestModeSameOrigin
);
286 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_NO_CORS
,
287 WebURLRequest::FetchRequestModeNoCORS
);
288 STATIC_ASSERT_MATCHING_ENUMS(FETCH_REQUEST_MODE_CORS
,
289 WebURLRequest::FetchRequestModeCORS
);
290 STATIC_ASSERT_MATCHING_ENUMS(
291 FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT
,
292 WebURLRequest::FetchRequestModeCORSWithForcedPreflight
);
294 FetchRequestMode
GetFetchRequestModeForWebURLRequest(
295 const blink::WebURLRequest
& request
) {
296 return static_cast<FetchRequestMode
>(request
.fetchRequestMode());
299 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_OMIT
,
300 WebURLRequest::FetchCredentialsModeOmit
);
301 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_SAME_ORIGIN
,
302 WebURLRequest::FetchCredentialsModeSameOrigin
);
303 STATIC_ASSERT_MATCHING_ENUMS(FETCH_CREDENTIALS_MODE_INCLUDE
,
304 WebURLRequest::FetchCredentialsModeInclude
);
306 FetchCredentialsMode
GetFetchCredentialsModeForWebURLRequest(
307 const blink::WebURLRequest
& request
) {
308 return static_cast<FetchCredentialsMode
>(request
.fetchCredentialsMode());
311 STATIC_ASSERT_MATCHING_ENUMS(FetchRedirectMode::FOLLOW_MODE
,
312 WebURLRequest::FetchRedirectModeFollow
);
313 STATIC_ASSERT_MATCHING_ENUMS(FetchRedirectMode::ERROR_MODE
,
314 WebURLRequest::FetchRedirectModeError
);
315 STATIC_ASSERT_MATCHING_ENUMS(FetchRedirectMode::MANUAL_MODE
,
316 WebURLRequest::FetchRedirectModeManual
);
318 FetchRedirectMode
GetFetchRedirectModeForWebURLRequest(
319 const blink::WebURLRequest
& request
) {
320 return static_cast<FetchRedirectMode
>(request
.fetchRedirectMode());
323 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_AUXILIARY
,
324 WebURLRequest::FrameTypeAuxiliary
);
325 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NESTED
,
326 WebURLRequest::FrameTypeNested
);
327 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_NONE
,
328 WebURLRequest::FrameTypeNone
);
329 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL
,
330 WebURLRequest::FrameTypeTopLevel
);
332 RequestContextFrameType
GetRequestContextFrameTypeForWebURLRequest(
333 const blink::WebURLRequest
& request
) {
334 return static_cast<RequestContextFrameType
>(request
.frameType());
337 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_UNSPECIFIED
,
338 WebURLRequest::RequestContextUnspecified
);
339 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_AUDIO
,
340 WebURLRequest::RequestContextAudio
);
341 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_BEACON
,
342 WebURLRequest::RequestContextBeacon
);
343 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_CSP_REPORT
,
344 WebURLRequest::RequestContextCSPReport
);
345 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_DOWNLOAD
,
346 WebURLRequest::RequestContextDownload
);
347 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EMBED
,
348 WebURLRequest::RequestContextEmbed
);
349 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_EVENT_SOURCE
,
350 WebURLRequest::RequestContextEventSource
);
351 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FAVICON
,
352 WebURLRequest::RequestContextFavicon
);
353 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FETCH
,
354 WebURLRequest::RequestContextFetch
);
355 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FONT
,
356 WebURLRequest::RequestContextFont
);
357 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FORM
,
358 WebURLRequest::RequestContextForm
);
359 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_FRAME
,
360 WebURLRequest::RequestContextFrame
);
361 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_HYPERLINK
,
362 WebURLRequest::RequestContextHyperlink
);
363 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IFRAME
,
364 WebURLRequest::RequestContextIframe
);
365 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE
,
366 WebURLRequest::RequestContextImage
);
367 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMAGE_SET
,
368 WebURLRequest::RequestContextImageSet
);
369 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_IMPORT
,
370 WebURLRequest::RequestContextImport
);
371 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_INTERNAL
,
372 WebURLRequest::RequestContextInternal
);
373 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_LOCATION
,
374 WebURLRequest::RequestContextLocation
);
375 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_MANIFEST
,
376 WebURLRequest::RequestContextManifest
);
377 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_OBJECT
,
378 WebURLRequest::RequestContextObject
);
379 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PING
,
380 WebURLRequest::RequestContextPing
);
381 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PLUGIN
,
382 WebURLRequest::RequestContextPlugin
);
383 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_PREFETCH
,
384 WebURLRequest::RequestContextPrefetch
);
385 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SCRIPT
,
386 WebURLRequest::RequestContextScript
);
387 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SERVICE_WORKER
,
388 WebURLRequest::RequestContextServiceWorker
);
389 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SHARED_WORKER
,
390 WebURLRequest::RequestContextSharedWorker
);
391 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_SUBRESOURCE
,
392 WebURLRequest::RequestContextSubresource
);
393 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_STYLE
,
394 WebURLRequest::RequestContextStyle
);
395 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_TRACK
,
396 WebURLRequest::RequestContextTrack
);
397 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_VIDEO
,
398 WebURLRequest::RequestContextVideo
);
399 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_WORKER
,
400 WebURLRequest::RequestContextWorker
);
401 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XML_HTTP_REQUEST
,
402 WebURLRequest::RequestContextXMLHttpRequest
);
403 STATIC_ASSERT_MATCHING_ENUMS(REQUEST_CONTEXT_TYPE_XSLT
,
404 WebURLRequest::RequestContextXSLT
);
406 RequestContextType
GetRequestContextTypeForWebURLRequest(
407 const blink::WebURLRequest
& request
) {
408 return static_cast<RequestContextType
>(request
.requestContext());
411 blink::WebURLError
CreateWebURLError(const blink::WebURL
& unreachable_url
,
412 bool stale_copy_in_cache
,
414 blink::WebURLError error
;
415 error
.domain
= WebString::fromUTF8(net::kErrorDomain
);
416 error
.reason
= reason
;
417 error
.unreachableURL
= unreachable_url
;
418 error
.staleCopyInCache
= stale_copy_in_cache
;
419 if (reason
== net::ERR_ABORTED
) {
420 error
.isCancellation
= true;
421 } else if (reason
== net::ERR_TEMPORARILY_THROTTLED
) {
422 error
.localizedDescription
=
423 WebString::fromUTF8(kThrottledErrorDescription
);
425 error
.localizedDescription
=
426 WebString::fromUTF8(net::ErrorToString(reason
));
431 blink::WebURLError
CreateWebURLError(const blink::WebURL
& unreachable_url
,
432 bool stale_copy_in_cache
,
434 bool was_ignored_by_handler
) {
435 blink::WebURLError error
=
436 CreateWebURLError(unreachable_url
, stale_copy_in_cache
, reason
);
437 error
.wasIgnoredByHandler
= was_ignored_by_handler
;
441 } // namespace content