2f60c65f9d0b0127ea9fcf27c1610590e31a5687
[WebKit-https.git] / Source / WebCore / platform / network / ResourceRequestBase.cpp
1 /*
2  * Copyright (C) 2003, 2006 Apple Inc.  All rights reserved.
3  * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26 #include "config.h"
27 #include "ResourceRequestBase.h"
28
29 #include "HTTPHeaderNames.h"
30 #include "PublicSuffix.h"
31 #include "ResourceRequest.h"
32 #include "SecurityPolicy.h"
33 #include <wtf/PointerComparison.h>
34
35 namespace WebCore {
36
37 #if PLATFORM(IOS) || USE(CFURLCONNECTION)
38 double ResourceRequestBase::s_defaultTimeoutInterval = INT_MAX;
39 #else
40 // Will use NSURLRequest default timeout unless set to a non-zero value with setDefaultTimeoutInterval().
41 // For libsoup the timeout enabled with integer milliseconds. We set 0 as the default value to avoid integer overflow.
42 double ResourceRequestBase::s_defaultTimeoutInterval = 0;
43 #endif
44
45 inline const ResourceRequest& ResourceRequestBase::asResourceRequest() const
46 {
47     return *static_cast<const ResourceRequest*>(this);
48 }
49
50 ResourceRequest ResourceRequestBase::isolatedCopy() const
51 {
52     ResourceRequest request;
53     request.setAsIsolatedCopy(asResourceRequest());
54     return request;
55 }
56
57 void ResourceRequestBase::setAsIsolatedCopy(const ResourceRequest& other)
58 {
59     setURL(other.url().isolatedCopy());
60     setCachePolicy(other.cachePolicy());
61     setTimeoutInterval(other.timeoutInterval());
62     setFirstPartyForCookies(other.firstPartyForCookies().isolatedCopy());
63     setHTTPMethod(other.httpMethod().isolatedCopy());
64     setPriority(other.priority());
65     setRequester(other.requester());
66     setInitiatorIdentifier(other.initiatorIdentifier().isolatedCopy());
67     setCachePartition(other.cachePartition().isolatedCopy());
68
69     updateResourceRequest();
70     m_httpHeaderFields = other.httpHeaderFields().isolatedCopy();
71
72     size_t encodingCount = other.m_responseContentDispositionEncodingFallbackArray.size();
73     if (encodingCount > 0) {
74         String encoding1 = other.m_responseContentDispositionEncodingFallbackArray[0].isolatedCopy();
75         String encoding2;
76         String encoding3;
77         if (encodingCount > 1) {
78             encoding2 = other.m_responseContentDispositionEncodingFallbackArray[1].isolatedCopy();
79             if (encodingCount > 2)
80                 encoding3 = other.m_responseContentDispositionEncodingFallbackArray[2].isolatedCopy();
81         }
82         ASSERT(encodingCount <= 3);
83         setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3);
84     }
85     if (other.m_httpBody)
86         setHTTPBody(other.m_httpBody->isolatedCopy());
87     setAllowCookies(other.m_allowCookies);
88 }
89
90 bool ResourceRequestBase::isEmpty() const
91 {
92     updateResourceRequest(); 
93     
94     return m_url.isEmpty(); 
95 }
96
97 bool ResourceRequestBase::isNull() const
98 {
99     updateResourceRequest(); 
100     
101     return m_url.isNull();
102 }
103
104 const URL& ResourceRequestBase::url() const 
105 {
106     updateResourceRequest(); 
107     
108     return m_url;
109 }
110
111 void ResourceRequestBase::setURL(const URL& url)
112
113     updateResourceRequest(); 
114
115     m_url = url; 
116     
117     m_platformRequestUpdated = false;
118 }
119
120 static bool shouldUseGet(const ResourceRequestBase& request, const ResourceResponse& redirectResponse)
121 {
122     if (redirectResponse.httpStatusCode() == 301 || redirectResponse.httpStatusCode() == 302)
123         return equalLettersIgnoringASCIICase(request.httpMethod(), "post");
124     return redirectResponse.httpStatusCode() == 303;
125 }
126
127 ResourceRequest ResourceRequestBase::redirectedRequest(const ResourceResponse& redirectResponse, bool shouldClearReferrerOnHTTPSToHTTPRedirect) const
128 {
129     ASSERT(redirectResponse.isRedirection());
130     // This method is based on https://fetch.spec.whatwg.org/#http-redirect-fetch.
131     // It also implements additional processing like done by CFNetwork layer.
132
133     auto request = asResourceRequest();
134     auto location = redirectResponse.httpHeaderField(HTTPHeaderName::Location);
135
136     request.setURL(location.isEmpty() ? URL { } : URL { redirectResponse.url(), location });
137
138     if (shouldUseGet(*this, redirectResponse)) {
139         request.setHTTPMethod(ASCIILiteral("GET"));
140         request.setHTTPBody(nullptr);
141         request.clearHTTPContentType();
142         request.m_httpHeaderFields.remove(HTTPHeaderName::ContentLength);
143     }
144
145     if (shouldClearReferrerOnHTTPSToHTTPRedirect && !request.url().protocolIs("https") && WebCore::protocolIs(request.httpReferrer(), "https"))
146         request.clearHTTPReferrer();
147
148     if (!protocolHostAndPortAreEqual(request.url(), redirectResponse.url()))
149         request.clearHTTPOrigin();
150     request.clearHTTPAuthorization();
151     request.m_httpHeaderFields.remove(HTTPHeaderName::ProxyAuthorization);
152
153     return request;
154 }
155
156 void ResourceRequestBase::removeCredentials()
157 {
158     updateResourceRequest(); 
159
160     if (m_url.user().isEmpty() && m_url.pass().isEmpty())
161         return;
162
163     m_url.setUser(String());
164     m_url.setPass(String());
165
166     m_platformRequestUpdated = false;
167 }
168
169 ResourceRequestCachePolicy ResourceRequestBase::cachePolicy() const
170 {
171     updateResourceRequest(); 
172     
173     return m_cachePolicy;
174 }
175
176 void ResourceRequestBase::setCachePolicy(ResourceRequestCachePolicy cachePolicy)
177 {
178     updateResourceRequest(); 
179
180     if (m_cachePolicy == cachePolicy)
181         return;
182     
183     m_cachePolicy = cachePolicy;
184     
185     m_platformRequestUpdated = false;
186 }
187
188 double ResourceRequestBase::timeoutInterval() const
189 {
190     updateResourceRequest(); 
191     
192     return m_timeoutInterval; 
193 }
194
195 void ResourceRequestBase::setTimeoutInterval(double timeoutInterval) 
196 {
197     updateResourceRequest(); 
198     
199     if (m_timeoutInterval == timeoutInterval)
200         return;
201
202     m_timeoutInterval = timeoutInterval;
203     
204     m_platformRequestUpdated = false;
205 }
206
207 const URL& ResourceRequestBase::firstPartyForCookies() const
208 {
209     updateResourceRequest(); 
210     
211     return m_firstPartyForCookies;
212 }
213
214 void ResourceRequestBase::setFirstPartyForCookies(const URL& firstPartyForCookies)
215
216     updateResourceRequest(); 
217
218     if (m_firstPartyForCookies == firstPartyForCookies)
219         return;
220
221     m_firstPartyForCookies = firstPartyForCookies;
222     
223     m_platformRequestUpdated = false;
224 }
225
226 const String& ResourceRequestBase::httpMethod() const
227 {
228     updateResourceRequest(); 
229     
230     return m_httpMethod; 
231 }
232
233 void ResourceRequestBase::setHTTPMethod(const String& httpMethod) 
234 {
235     updateResourceRequest(); 
236
237     if (m_httpMethod == httpMethod)
238         return;
239
240     m_httpMethod = httpMethod;
241     
242     m_platformRequestUpdated = false;
243 }
244
245 const HTTPHeaderMap& ResourceRequestBase::httpHeaderFields() const
246 {
247     updateResourceRequest(); 
248
249     return m_httpHeaderFields; 
250 }
251
252 String ResourceRequestBase::httpHeaderField(const String& name) const
253 {
254     updateResourceRequest(); 
255     
256     return m_httpHeaderFields.get(name);
257 }
258
259 String ResourceRequestBase::httpHeaderField(HTTPHeaderName name) const
260 {
261     updateResourceRequest(); 
262     
263     return m_httpHeaderFields.get(name);
264 }
265
266 void ResourceRequestBase::setHTTPHeaderField(const String& name, const String& value)
267 {
268     updateResourceRequest();
269
270     m_httpHeaderFields.set(name, value);
271     
272     m_platformRequestUpdated = false;
273 }
274
275 void ResourceRequestBase::setHTTPHeaderField(HTTPHeaderName name, const String& value)
276 {
277     updateResourceRequest();
278
279     m_httpHeaderFields.set(name, value);
280
281     m_platformRequestUpdated = false;
282 }
283
284 void ResourceRequestBase::clearHTTPAuthorization()
285 {
286     updateResourceRequest(); 
287
288     if (!m_httpHeaderFields.remove(HTTPHeaderName::Authorization))
289         return;
290
291     m_platformRequestUpdated = false;
292 }
293
294 String ResourceRequestBase::httpContentType() const
295 {
296     return httpHeaderField(HTTPHeaderName::ContentType);
297 }
298
299 void ResourceRequestBase::setHTTPContentType(const String& httpContentType)
300 {
301     setHTTPHeaderField(HTTPHeaderName::ContentType, httpContentType);
302 }
303
304 void ResourceRequestBase::clearHTTPContentType()
305 {
306     updateResourceRequest(); 
307
308     m_httpHeaderFields.remove(HTTPHeaderName::ContentType);
309
310     m_platformRequestUpdated = false;
311 }
312
313 String ResourceRequestBase::httpReferrer() const
314 {
315     return httpHeaderField(HTTPHeaderName::Referer);
316 }
317
318 bool ResourceRequestBase::hasHTTPReferrer() const
319 {
320     return m_httpHeaderFields.contains(HTTPHeaderName::Referer);
321 }
322
323 void ResourceRequestBase::setHTTPReferrer(const String& httpReferrer)
324 {
325     setHTTPHeaderField(HTTPHeaderName::Referer, httpReferrer);
326 }
327
328 void ResourceRequestBase::setExistingHTTPReferrerToOriginString()
329 {
330     if (!hasHTTPReferrer())
331         return;
332
333     setHTTPHeaderField(HTTPHeaderName::Referer, SecurityPolicy::referrerToOriginString(httpReferrer()));
334 }
335     
336 void ResourceRequestBase::clearHTTPReferrer()
337 {
338     updateResourceRequest(); 
339
340     m_httpHeaderFields.remove(HTTPHeaderName::Referer);
341
342     m_platformRequestUpdated = false;
343 }
344
345 String ResourceRequestBase::httpOrigin() const
346 {
347     return httpHeaderField(HTTPHeaderName::Origin);
348 }
349
350 void ResourceRequestBase::setHTTPOrigin(const String& httpOrigin)
351 {
352     setHTTPHeaderField(HTTPHeaderName::Origin, httpOrigin);
353 }
354
355 bool ResourceRequestBase::hasHTTPOrigin() const
356 {
357     return m_httpHeaderFields.contains(HTTPHeaderName::Origin);
358 }
359
360 void ResourceRequestBase::clearHTTPOrigin()
361 {
362     updateResourceRequest();
363
364     m_httpHeaderFields.remove(HTTPHeaderName::Origin);
365
366     m_platformRequestUpdated = false;
367 }
368
369 bool ResourceRequestBase::hasHTTPHeader(HTTPHeaderName name) const
370 {
371     return m_httpHeaderFields.contains(name);
372 }
373
374 String ResourceRequestBase::httpUserAgent() const
375 {
376     return httpHeaderField(HTTPHeaderName::UserAgent);
377 }
378
379 void ResourceRequestBase::setHTTPUserAgent(const String& httpUserAgent)
380 {
381     setHTTPHeaderField(HTTPHeaderName::UserAgent, httpUserAgent);
382 }
383
384 void ResourceRequestBase::clearHTTPUserAgent()
385 {
386     updateResourceRequest(); 
387
388     m_httpHeaderFields.remove(HTTPHeaderName::UserAgent);
389
390     m_platformRequestUpdated = false;
391 }
392
393 String ResourceRequestBase::httpAccept() const
394 {
395     return httpHeaderField(HTTPHeaderName::Accept);
396 }
397
398 void ResourceRequestBase::setHTTPAccept(const String& httpAccept)
399 {
400     setHTTPHeaderField(HTTPHeaderName::Accept, httpAccept);
401 }
402
403 void ResourceRequestBase::clearHTTPAccept()
404 {
405     updateResourceRequest(); 
406
407     m_httpHeaderFields.remove(HTTPHeaderName::Accept);
408
409     m_platformRequestUpdated = false;
410 }
411
412 void ResourceRequestBase::clearHTTPAcceptEncoding()
413 {
414     updateResourceRequest();
415
416     m_httpHeaderFields.remove(HTTPHeaderName::AcceptEncoding);
417
418     m_platformRequestUpdated = false;
419 }
420
421 void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3)
422 {
423     updateResourceRequest(); 
424     
425     m_responseContentDispositionEncodingFallbackArray.clear();
426     m_responseContentDispositionEncodingFallbackArray.reserveInitialCapacity(!encoding1.isNull() + !encoding2.isNull() + !encoding3.isNull());
427     if (!encoding1.isNull())
428         m_responseContentDispositionEncodingFallbackArray.uncheckedAppend(encoding1);
429     if (!encoding2.isNull())
430         m_responseContentDispositionEncodingFallbackArray.uncheckedAppend(encoding2);
431     if (!encoding3.isNull())
432         m_responseContentDispositionEncodingFallbackArray.uncheckedAppend(encoding3);
433     
434     m_platformRequestUpdated = false;
435 }
436
437 FormData* ResourceRequestBase::httpBody() const
438 {
439     updateResourceRequest(UpdateHTTPBody);
440
441     return m_httpBody.get();
442 }
443
444 void ResourceRequestBase::setHTTPBody(RefPtr<FormData>&& httpBody)
445 {
446     updateResourceRequest();
447
448     m_httpBody = WTFMove(httpBody);
449
450     m_resourceRequestBodyUpdated = true;
451
452     m_platformRequestBodyUpdated = false;
453 }
454
455 bool ResourceRequestBase::allowCookies() const
456 {
457     updateResourceRequest(); 
458     
459     return m_allowCookies;
460 }
461
462 void ResourceRequestBase::setAllowCookies(bool allowCookies)
463 {
464     updateResourceRequest(); 
465
466     if (m_allowCookies == allowCookies)
467         return;
468
469     m_allowCookies = allowCookies;
470     
471     m_platformRequestUpdated = false;
472 }
473
474 ResourceLoadPriority ResourceRequestBase::priority() const
475 {
476     updateResourceRequest();
477
478     return m_priority;
479 }
480
481 void ResourceRequestBase::setPriority(ResourceLoadPriority priority)
482 {
483     updateResourceRequest();
484
485     if (m_priority == priority)
486         return;
487
488     m_priority = priority;
489
490     m_platformRequestUpdated = false;
491 }
492
493 void ResourceRequestBase::addHTTPHeaderFieldIfNotPresent(HTTPHeaderName name, const String& value)
494 {
495     updateResourceRequest();
496
497     if (!m_httpHeaderFields.addIfNotPresent(name, value))
498         return;
499
500     m_platformRequestUpdated = false;
501 }
502
503 void ResourceRequestBase::addHTTPHeaderField(HTTPHeaderName name, const String& value)
504 {
505     updateResourceRequest();
506
507     m_httpHeaderFields.add(name, value);
508
509     m_platformRequestUpdated = false;
510 }
511
512 void ResourceRequestBase::addHTTPHeaderField(const String& name, const String& value)
513 {
514     updateResourceRequest();
515
516     m_httpHeaderFields.add(name, value);
517
518     m_platformRequestUpdated = false;
519 }
520
521 bool ResourceRequestBase::hasHTTPHeaderField(HTTPHeaderName headerName) const
522 {
523     return m_httpHeaderFields.contains(headerName);
524 }
525
526 void ResourceRequestBase::setHTTPHeaderFields(HTTPHeaderMap headerFields)
527 {
528     updateResourceRequest();
529
530     m_httpHeaderFields = WTFMove(headerFields);
531
532     m_platformRequestUpdated = false;
533 }
534
535 bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceRequestBase& b)
536 {
537     if (a.url() != b.url())
538         return false;
539     
540     if (a.cachePolicy() != b.cachePolicy())
541         return false;
542     
543     if (a.timeoutInterval() != b.timeoutInterval())
544         return false;
545     
546     if (a.firstPartyForCookies() != b.firstPartyForCookies())
547         return false;
548     
549     if (a.httpMethod() != b.httpMethod())
550         return false;
551     
552     if (a.allowCookies() != b.allowCookies())
553         return false;
554     
555     if (a.priority() != b.priority())
556         return false;
557
558     if (a.requester() != b.requester())
559         return false;
560
561     return arePointingToEqualData(a.httpBody(), b.httpBody());
562 }
563
564 bool ResourceRequestBase::equal(const ResourceRequest& a, const ResourceRequest& b)
565 {
566     if (!equalIgnoringHeaderFields(a, b))
567         return false;
568     
569     if (a.httpHeaderFields() != b.httpHeaderFields())
570         return false;
571         
572     return ResourceRequest::platformCompare(a, b);
573 }
574
575 static const HTTPHeaderName conditionalHeaderNames[] = {
576     HTTPHeaderName::IfMatch,
577     HTTPHeaderName::IfModifiedSince,
578     HTTPHeaderName::IfNoneMatch,
579     HTTPHeaderName::IfRange,
580     HTTPHeaderName::IfUnmodifiedSince
581 };
582
583 bool ResourceRequestBase::isConditional() const
584 {
585     updateResourceRequest();
586
587     for (auto headerName : conditionalHeaderNames) {
588         if (m_httpHeaderFields.contains(headerName))
589             return true;
590     }
591
592     return false;
593 }
594
595 void ResourceRequestBase::makeUnconditional()
596 {
597     updateResourceRequest();
598
599     for (auto headerName : conditionalHeaderNames)
600         m_httpHeaderFields.remove(headerName);
601 }
602
603 double ResourceRequestBase::defaultTimeoutInterval()
604 {
605     return s_defaultTimeoutInterval;
606 }
607
608 void ResourceRequestBase::setDefaultTimeoutInterval(double timeoutInterval)
609 {
610     s_defaultTimeoutInterval = timeoutInterval;
611 }
612
613 void ResourceRequestBase::updatePlatformRequest(HTTPBodyUpdatePolicy bodyPolicy) const
614 {
615     if (!m_platformRequestUpdated) {
616         ASSERT(m_resourceRequestUpdated);
617         const_cast<ResourceRequest&>(asResourceRequest()).doUpdatePlatformRequest();
618         m_platformRequestUpdated = true;
619     }
620
621     if (!m_platformRequestBodyUpdated && bodyPolicy == UpdateHTTPBody) {
622         ASSERT(m_resourceRequestBodyUpdated);
623         const_cast<ResourceRequest&>(asResourceRequest()).doUpdatePlatformHTTPBody();
624         m_platformRequestBodyUpdated = true;
625     }
626 }
627
628 void ResourceRequestBase::updateResourceRequest(HTTPBodyUpdatePolicy bodyPolicy) const
629 {
630     if (!m_resourceRequestUpdated) {
631         ASSERT(m_platformRequestUpdated);
632         const_cast<ResourceRequest&>(asResourceRequest()).doUpdateResourceRequest();
633         m_resourceRequestUpdated = true;
634     }
635
636     if (!m_resourceRequestBodyUpdated && bodyPolicy == UpdateHTTPBody) {
637         ASSERT(m_platformRequestBodyUpdated);
638         const_cast<ResourceRequest&>(asResourceRequest()).doUpdateResourceHTTPBody();
639         m_resourceRequestBodyUpdated = true;
640     }
641 }
642
643 #if !PLATFORM(COCOA) && !USE(CFURLCONNECTION) && !USE(SOUP)
644 unsigned initializeMaximumHTTPConnectionCountPerHost()
645 {
646     // This is used by the loader to control the number of issued parallel load requests. 
647     // Four seems to be a common default in HTTP frameworks.
648     return 4;
649 }
650 #endif
651
652 void ResourceRequestBase::setCachePartition(const String& cachePartition)
653 {
654 #if ENABLE(CACHE_PARTITIONING)
655     ASSERT(!cachePartition.isNull());
656     ASSERT(cachePartition == partitionName(cachePartition));
657     m_cachePartition = cachePartition;
658 #else
659     UNUSED_PARAM(cachePartition);
660 #endif
661 }
662
663 String ResourceRequestBase::partitionName(const String& domain)
664 {
665 #if ENABLE(PUBLIC_SUFFIX_LIST)
666     if (domain.isNull())
667         return emptyString();
668     String highLevel = topPrivatelyControlledDomain(domain);
669     if (highLevel.isNull())
670         return emptyString();
671     return highLevel;
672 #else
673     UNUSED_PARAM(domain);
674 #if ENABLE(CACHE_PARTITIONING)
675 #error Cache partitioning requires PUBLIC_SUFFIX_LIST
676 #endif
677     return emptyString();
678 #endif
679 }
680
681 }