<http://webkit.org/b/53192> Add experimental support for HTTP pipelining in CFNetwork
[WebKit-https.git] / Source / WebCore / platform / network / ResourceRequestBase.cpp
1 /*
2  * Copyright (C) 2003, 2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2009 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 COMPUTER, 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 COMPUTER, 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
28 #include "ResourceRequestBase.h"
29 #include "ResourceRequest.h"
30
31 using namespace std;
32
33 namespace WebCore {
34
35 inline const ResourceRequest& ResourceRequestBase::asResourceRequest() const
36 {
37     return *static_cast<const ResourceRequest*>(this);
38 }
39
40 PassOwnPtr<ResourceRequest> ResourceRequestBase::adopt(PassOwnPtr<CrossThreadResourceRequestData> data)
41 {
42     OwnPtr<ResourceRequest> request(new ResourceRequest());
43     request->setURL(data->m_url);
44     request->setCachePolicy(data->m_cachePolicy);
45     request->setTimeoutInterval(data->m_timeoutInterval);
46     request->setFirstPartyForCookies(data->m_firstPartyForCookies);
47     request->setHTTPMethod(data->m_httpMethod);
48     request->setPriority(data->m_priority);
49     request->setTargetType(data->m_targetType);
50
51     request->updateResourceRequest();
52     request->m_httpHeaderFields.adopt(data->m_httpHeaders.release());
53
54     size_t encodingCount = data->m_responseContentDispositionEncodingFallbackArray.size();
55     if (encodingCount > 0) {
56         String encoding1 = data->m_responseContentDispositionEncodingFallbackArray[0];
57         String encoding2;
58         String encoding3;
59         if (encodingCount > 1) {
60             encoding2 = data->m_responseContentDispositionEncodingFallbackArray[1];
61             if (encodingCount > 2)
62                 encoding3 = data->m_responseContentDispositionEncodingFallbackArray[2];
63         }
64         ASSERT(encodingCount <= 3);
65         request->setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3);
66     }
67     request->setHTTPBody(data->m_httpBody);
68     request->setAllowCookies(data->m_allowCookies);
69     request->doPlatformAdopt(data);
70     return request.release();
71 }
72
73 PassOwnPtr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const
74 {
75     OwnPtr<CrossThreadResourceRequestData> data(new CrossThreadResourceRequestData());
76     data->m_url = url().copy();
77     data->m_cachePolicy = cachePolicy();
78     data->m_timeoutInterval = timeoutInterval();
79     data->m_firstPartyForCookies = firstPartyForCookies().copy();
80     data->m_httpMethod = httpMethod().crossThreadString();
81     data->m_httpHeaders = httpHeaderFields().copyData();
82     data->m_priority = priority();
83     data->m_targetType = m_targetType;
84
85     data->m_responseContentDispositionEncodingFallbackArray.reserveInitialCapacity(m_responseContentDispositionEncodingFallbackArray.size());
86     size_t encodingArraySize = m_responseContentDispositionEncodingFallbackArray.size();
87     for (size_t index = 0; index < encodingArraySize; ++index) {
88         data->m_responseContentDispositionEncodingFallbackArray.append(m_responseContentDispositionEncodingFallbackArray[index].crossThreadString());
89     }
90     if (m_httpBody)
91         data->m_httpBody = m_httpBody->deepCopy();
92     data->m_allowCookies = m_allowCookies;
93     return asResourceRequest().doPlatformCopyData(data.release());
94 }
95
96 bool ResourceRequestBase::isEmpty() const
97 {
98     updateResourceRequest(); 
99     
100     return m_url.isEmpty(); 
101 }
102
103 bool ResourceRequestBase::isNull() const
104 {
105     updateResourceRequest(); 
106     
107     return m_url.isNull();
108 }
109
110 const KURL& ResourceRequestBase::url() const 
111 {
112     updateResourceRequest(); 
113     
114     return m_url;
115 }
116
117 void ResourceRequestBase::setURL(const KURL& url)
118
119     updateResourceRequest(); 
120
121     m_url = url; 
122     
123     m_platformRequestUpdated = false;
124 }
125
126 void ResourceRequestBase::removeCredentials()
127 {
128     updateResourceRequest(); 
129
130     m_url.setUser(String());
131     m_url.setPass(String());
132
133     m_platformRequestUpdated = false;
134 }
135
136 ResourceRequestCachePolicy ResourceRequestBase::cachePolicy() const
137 {
138     updateResourceRequest(); 
139     
140     return m_cachePolicy; 
141 }
142
143 void ResourceRequestBase::setCachePolicy(ResourceRequestCachePolicy cachePolicy)
144 {
145     updateResourceRequest(); 
146     
147     m_cachePolicy = cachePolicy;
148     
149     if (url().protocolInHTTPFamily())
150         m_platformRequestUpdated = false;
151 }
152
153 double ResourceRequestBase::timeoutInterval() const
154 {
155     updateResourceRequest(); 
156     
157     return m_timeoutInterval; 
158 }
159
160 void ResourceRequestBase::setTimeoutInterval(double timeoutInterval) 
161 {
162     updateResourceRequest(); 
163     
164     m_timeoutInterval = timeoutInterval; 
165     
166     if (url().protocolInHTTPFamily())
167         m_platformRequestUpdated = false;
168 }
169
170 const KURL& ResourceRequestBase::firstPartyForCookies() const
171 {
172     updateResourceRequest(); 
173     
174     return m_firstPartyForCookies;
175 }
176
177 void ResourceRequestBase::setFirstPartyForCookies(const KURL& firstPartyForCookies)
178
179     updateResourceRequest(); 
180     
181     m_firstPartyForCookies = firstPartyForCookies;
182     
183     m_platformRequestUpdated = false;
184 }
185
186 const String& ResourceRequestBase::httpMethod() const
187 {
188     updateResourceRequest(); 
189     
190     return m_httpMethod; 
191 }
192
193 void ResourceRequestBase::setHTTPMethod(const String& httpMethod) 
194 {
195     updateResourceRequest(); 
196
197     m_httpMethod = httpMethod;
198     
199     if (url().protocolInHTTPFamily())
200         m_platformRequestUpdated = false;
201 }
202
203 const HTTPHeaderMap& ResourceRequestBase::httpHeaderFields() const
204 {
205     updateResourceRequest(); 
206
207     return m_httpHeaderFields; 
208 }
209
210 String ResourceRequestBase::httpHeaderField(const AtomicString& name) const
211 {
212     updateResourceRequest(); 
213     
214     return m_httpHeaderFields.get(name);
215 }
216
217 String ResourceRequestBase::httpHeaderField(const char* name) const
218 {
219     updateResourceRequest(); 
220     
221     return m_httpHeaderFields.get(name);
222 }
223
224 void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const String& value)
225 {
226     updateResourceRequest(); 
227     
228     m_httpHeaderFields.set(name, value); 
229     
230     if (url().protocolInHTTPFamily())
231         m_platformRequestUpdated = false;
232 }
233
234 void ResourceRequestBase::setHTTPHeaderField(const char* name, const String& value)
235 {
236     setHTTPHeaderField(AtomicString(name), value);
237 }
238
239 void ResourceRequestBase::clearHTTPAuthorization()
240 {
241     updateResourceRequest(); 
242
243     m_httpHeaderFields.remove("Authorization");
244
245     if (url().protocolInHTTPFamily())
246         m_platformRequestUpdated = false;
247 }
248
249 void ResourceRequestBase::clearHTTPReferrer()
250 {
251     updateResourceRequest(); 
252
253     m_httpHeaderFields.remove("Referer");
254
255     if (url().protocolInHTTPFamily())
256         m_platformRequestUpdated = false;
257 }
258
259 void ResourceRequestBase::clearHTTPOrigin()
260 {
261     updateResourceRequest(); 
262
263     m_httpHeaderFields.remove("Origin");
264
265     if (url().protocolInHTTPFamily())
266         m_platformRequestUpdated = false;
267 }
268
269 void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3)
270 {
271     updateResourceRequest(); 
272     
273     m_responseContentDispositionEncodingFallbackArray.clear();
274     if (!encoding1.isNull())
275         m_responseContentDispositionEncodingFallbackArray.append(encoding1);
276     if (!encoding2.isNull())
277         m_responseContentDispositionEncodingFallbackArray.append(encoding2);
278     if (!encoding3.isNull())
279         m_responseContentDispositionEncodingFallbackArray.append(encoding3);
280     
281     if (url().protocolInHTTPFamily())
282         m_platformRequestUpdated = false;
283 }
284
285 FormData* ResourceRequestBase::httpBody() const 
286
287     updateResourceRequest(); 
288     
289     return m_httpBody.get(); 
290 }
291
292 void ResourceRequestBase::setHTTPBody(PassRefPtr<FormData> httpBody)
293 {
294     updateResourceRequest(); 
295     
296     m_httpBody = httpBody; 
297     
298     if (url().protocolInHTTPFamily())
299         m_platformRequestUpdated = false;
300
301
302 bool ResourceRequestBase::allowCookies() const
303 {
304     updateResourceRequest(); 
305     
306     return m_allowCookies;
307 }
308
309 void ResourceRequestBase::setAllowCookies(bool allowCookies)
310 {
311     updateResourceRequest(); 
312     
313     m_allowCookies = allowCookies;
314     
315     if (url().protocolInHTTPFamily())
316         m_platformRequestUpdated = false;
317 }
318
319 ResourceLoadPriority ResourceRequestBase::priority() const
320 {
321     updateResourceRequest();
322
323     return m_priority;
324 }
325
326 void ResourceRequestBase::setPriority(ResourceLoadPriority priority)
327 {
328     updateResourceRequest();
329
330     m_priority = priority;
331
332     if (url().protocolInHTTPFamily())
333         m_platformRequestUpdated = false;
334 }
335
336 void ResourceRequestBase::addHTTPHeaderField(const AtomicString& name, const String& value) 
337 {
338     updateResourceRequest();
339     pair<HTTPHeaderMap::iterator, bool> result = m_httpHeaderFields.add(name, value); 
340     if (!result.second)
341         result.first->second += "," + value;
342
343     if (url().protocolInHTTPFamily())
344         m_platformRequestUpdated = false;
345 }
346
347 void ResourceRequestBase::addHTTPHeaderFields(const HTTPHeaderMap& headerFields)
348 {
349     HTTPHeaderMap::const_iterator end = headerFields.end();
350     for (HTTPHeaderMap::const_iterator it = headerFields.begin(); it != end; ++it)
351         addHTTPHeaderField(it->first, it->second);
352 }
353
354 bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceRequestBase& b)
355 {
356     if (a.url() != b.url())
357         return false;
358     
359     if (a.cachePolicy() != b.cachePolicy())
360         return false;
361     
362     if (a.timeoutInterval() != b.timeoutInterval())
363         return false;
364     
365     if (a.firstPartyForCookies() != b.firstPartyForCookies())
366         return false;
367     
368     if (a.httpMethod() != b.httpMethod())
369         return false;
370     
371     if (a.allowCookies() != b.allowCookies())
372         return false;
373     
374     if (a.priority() != b.priority())
375         return false;
376
377     FormData* formDataA = a.httpBody();
378     FormData* formDataB = b.httpBody();
379     
380     if (!formDataA)
381         return !formDataB;
382     if (!formDataB)
383         return !formDataA;
384     
385     if (*formDataA != *formDataB)
386         return false;
387     
388     return true;
389 }
390
391 bool ResourceRequestBase::compare(const ResourceRequest& a, const ResourceRequest& b)
392 {
393     if (!equalIgnoringHeaderFields(a, b))
394         return false;
395     
396     if (a.httpHeaderFields() != b.httpHeaderFields())
397         return false;
398         
399     return ResourceRequest::platformCompare(a, b);
400 }
401
402 bool ResourceRequestBase::isConditional() const
403 {
404     return (m_httpHeaderFields.contains("If-Match") ||
405             m_httpHeaderFields.contains("If-Modified-Since") ||
406             m_httpHeaderFields.contains("If-None-Match") ||
407             m_httpHeaderFields.contains("If-Range") ||
408             m_httpHeaderFields.contains("If-Unmodified-Since"));
409 }
410
411 void ResourceRequestBase::updatePlatformRequest() const
412 {
413     if (m_platformRequestUpdated)
414         return;
415     
416     const_cast<ResourceRequest&>(asResourceRequest()).doUpdatePlatformRequest();
417     m_platformRequestUpdated = true;
418 }
419
420 void ResourceRequestBase::updateResourceRequest() const
421 {
422     if (m_resourceRequestUpdated)
423         return;
424
425     const_cast<ResourceRequest&>(asResourceRequest()).doUpdateResourceRequest();
426     m_resourceRequestUpdated = true;
427 }
428
429 #if !PLATFORM(MAC) && !USE(CFNETWORK) && !USE(SOUP) && !PLATFORM(CHROMIUM) && !PLATFORM(ANDROID) && !PLATFORM(QT)
430 unsigned initializeMaximumHTTPConnectionCountPerHost()
431 {
432     // This is used by the loader to control the number of issued parallel load requests. 
433     // Four seems to be a common default in HTTP frameworks.
434     return 4;
435 }
436 #endif
437
438 }