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 "ResourceRequest.h" 31#include <wtf/PassOwnPtr.h> 32 33namespace WebCore { 34 35#if !USE(SOUP) && (!PLATFORM(COCOA) || USE(CFNETWORK)) 36double ResourceRequestBase::s_defaultTimeoutInterval = INT_MAX; 37#else 38// Will use NSURLRequest default timeout unless set to a non-zero value with setDefaultTimeoutInterval(). 39// For libsoup the timeout enabled with integer milliseconds. We set 0 as the default value to avoid integer overflow. 40double ResourceRequestBase::s_defaultTimeoutInterval = 0; 41#endif 42 43#if PLATFORM(IOS) 44bool ResourceRequestBase::s_defaultAllowCookies = true; 45#endif 46 47inline const ResourceRequest& ResourceRequestBase::asResourceRequest() const 48{ 49 return *static_cast<const ResourceRequest*>(this); 50} 51 52PassOwnPtr<ResourceRequest> ResourceRequestBase::adopt(PassOwnPtr<CrossThreadResourceRequestData> data) 53{ 54 OwnPtr<ResourceRequest> request = adoptPtr(new ResourceRequest()); 55 request->setURL(data->m_url); 56 request->setCachePolicy(data->m_cachePolicy); 57 request->setTimeoutInterval(data->m_timeoutInterval); 58 request->setFirstPartyForCookies(data->m_firstPartyForCookies); 59 request->setHTTPMethod(data->m_httpMethod); 60 request->setPriority(data->m_priority); 61 62 request->updateResourceRequest(); 63 request->m_httpHeaderFields.adopt(WTF::move(data->m_httpHeaders)); 64 65 size_t encodingCount = data->m_responseContentDispositionEncodingFallbackArray.size(); 66 if (encodingCount > 0) { 67 String encoding1 = data->m_responseContentDispositionEncodingFallbackArray[0]; 68 String encoding2; 69 String encoding3; 70 if (encodingCount > 1) { 71 encoding2 = data->m_responseContentDispositionEncodingFallbackArray[1]; 72 if (encodingCount > 2) 73 encoding3 = data->m_responseContentDispositionEncodingFallbackArray[2]; 74 } 75 ASSERT(encodingCount <= 3); 76 request->setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3); 77 } 78 request->setHTTPBody(data->m_httpBody); 79 request->setAllowCookies(data->m_allowCookies); 80 request->doPlatformAdopt(data); 81 return request.release(); 82} 83 84PassOwnPtr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const 85{ 86 OwnPtr<CrossThreadResourceRequestData> data = adoptPtr(new CrossThreadResourceRequestData()); 87 data->m_url = url().copy(); 88 data->m_cachePolicy = cachePolicy(); 89 data->m_timeoutInterval = timeoutInterval(); 90 data->m_firstPartyForCookies = firstPartyForCookies().copy(); 91 data->m_httpMethod = httpMethod().isolatedCopy(); 92 data->m_httpHeaders = httpHeaderFields().copyData(); 93 data->m_priority = priority(); 94 95 data->m_responseContentDispositionEncodingFallbackArray.reserveInitialCapacity(m_responseContentDispositionEncodingFallbackArray.size()); 96 size_t encodingArraySize = m_responseContentDispositionEncodingFallbackArray.size(); 97 for (size_t index = 0; index < encodingArraySize; ++index) { 98 data->m_responseContentDispositionEncodingFallbackArray.append(m_responseContentDispositionEncodingFallbackArray[index].isolatedCopy()); 99 } 100 if (m_httpBody) 101 data->m_httpBody = m_httpBody->deepCopy(); 102 data->m_allowCookies = m_allowCookies; 103 return asResourceRequest().doPlatformCopyData(data.release()); 104} 105 106bool ResourceRequestBase::isEmpty() const 107{ 108 updateResourceRequest(); 109 110 return m_url.isEmpty(); 111} 112 113bool ResourceRequestBase::isNull() const 114{ 115 updateResourceRequest(); 116 117 return m_url.isNull(); 118} 119 120const URL& ResourceRequestBase::url() const 121{ 122 updateResourceRequest(); 123 124 return m_url; 125} 126 127void ResourceRequestBase::setURL(const URL& url) 128{ 129 updateResourceRequest(); 130 131 m_url = url; 132 133 m_platformRequestUpdated = false; 134} 135 136void ResourceRequestBase::removeCredentials() 137{ 138 updateResourceRequest(); 139 140 if (m_url.user().isEmpty() && m_url.pass().isEmpty()) 141 return; 142 143 m_url.setUser(String()); 144 m_url.setPass(String()); 145 146 m_platformRequestUpdated = false; 147} 148 149ResourceRequestCachePolicy ResourceRequestBase::cachePolicy() const 150{ 151 updateResourceRequest(); 152 153 return static_cast<ResourceRequestCachePolicy>(m_cachePolicy); 154} 155 156void ResourceRequestBase::setCachePolicy(ResourceRequestCachePolicy cachePolicy) 157{ 158 updateResourceRequest(); 159 160 if (m_cachePolicy == cachePolicy) 161 return; 162 163 m_cachePolicy = cachePolicy; 164 165 if (url().protocolIsInHTTPFamily()) 166 m_platformRequestUpdated = false; 167} 168 169double ResourceRequestBase::timeoutInterval() const 170{ 171 updateResourceRequest(); 172 173 return m_timeoutInterval; 174} 175 176void ResourceRequestBase::setTimeoutInterval(double timeoutInterval) 177{ 178 updateResourceRequest(); 179 180 if (m_timeoutInterval == timeoutInterval) 181 return; 182 183 m_timeoutInterval = timeoutInterval; 184 185 if (url().protocolIsInHTTPFamily()) 186 m_platformRequestUpdated = false; 187} 188 189const URL& ResourceRequestBase::firstPartyForCookies() const 190{ 191 updateResourceRequest(); 192 193 return m_firstPartyForCookies; 194} 195 196void ResourceRequestBase::setFirstPartyForCookies(const URL& firstPartyForCookies) 197{ 198 updateResourceRequest(); 199 200 if (m_firstPartyForCookies == firstPartyForCookies) 201 return; 202 203 m_firstPartyForCookies = firstPartyForCookies; 204 205 m_platformRequestUpdated = false; 206} 207 208const String& ResourceRequestBase::httpMethod() const 209{ 210 updateResourceRequest(); 211 212 return m_httpMethod; 213} 214 215void ResourceRequestBase::setHTTPMethod(const String& httpMethod) 216{ 217 updateResourceRequest(); 218 219 if (m_httpMethod == httpMethod) 220 return; 221 222 m_httpMethod = httpMethod; 223 224 if (url().protocolIsInHTTPFamily()) 225 m_platformRequestUpdated = false; 226} 227 228const HTTPHeaderMap& ResourceRequestBase::httpHeaderFields() const 229{ 230 updateResourceRequest(); 231 232 return m_httpHeaderFields; 233} 234 235String ResourceRequestBase::httpHeaderField(const String& name) const 236{ 237 updateResourceRequest(); 238 239 return m_httpHeaderFields.get(name); 240} 241 242String ResourceRequestBase::httpHeaderField(HTTPHeaderName name) const 243{ 244 updateResourceRequest(); 245 246 return m_httpHeaderFields.get(name); 247} 248 249void ResourceRequestBase::setHTTPHeaderField(const String& name, const String& value) 250{ 251 updateResourceRequest(); 252 253 m_httpHeaderFields.set(name, value); 254 255 if (url().protocolIsInHTTPFamily()) 256 m_platformRequestUpdated = false; 257} 258 259void ResourceRequestBase::setHTTPHeaderField(HTTPHeaderName name, const String& value) 260{ 261 updateResourceRequest(); 262 263 m_httpHeaderFields.set(name, value); 264 265 if (url().protocolIsInHTTPFamily()) 266 m_platformRequestUpdated = false; 267} 268 269void ResourceRequestBase::clearHTTPAuthorization() 270{ 271 updateResourceRequest(); 272 273 if (!m_httpHeaderFields.remove(HTTPHeaderName::Authorization)) 274 return; 275 276 if (url().protocolIsInHTTPFamily()) 277 m_platformRequestUpdated = false; 278} 279 280String ResourceRequestBase::httpContentType() const 281{ 282 return httpHeaderField(HTTPHeaderName::ContentType); 283} 284 285void ResourceRequestBase::setHTTPContentType(const String& httpContentType) 286{ 287 setHTTPHeaderField(HTTPHeaderName::ContentType, httpContentType); 288} 289 290void ResourceRequestBase::clearHTTPContentType() 291{ 292 updateResourceRequest(); 293 294 m_httpHeaderFields.remove(HTTPHeaderName::ContentType); 295 296 if (url().protocolIsInHTTPFamily()) 297 m_platformRequestUpdated = false; 298} 299 300String ResourceRequestBase::httpReferrer() const 301{ 302 return httpHeaderField(HTTPHeaderName::Referer); 303} 304 305void ResourceRequestBase::setHTTPReferrer(const String& httpReferrer) 306{ 307 setHTTPHeaderField(HTTPHeaderName::Referer, httpReferrer); 308} 309 310void ResourceRequestBase::clearHTTPReferrer() 311{ 312 updateResourceRequest(); 313 314 m_httpHeaderFields.remove(HTTPHeaderName::Referer); 315 316 if (url().protocolIsInHTTPFamily()) 317 m_platformRequestUpdated = false; 318} 319 320String ResourceRequestBase::httpOrigin() const 321{ 322 return httpHeaderField(HTTPHeaderName::Origin); 323} 324 325void ResourceRequestBase::setHTTPOrigin(const String& httpOrigin) 326{ 327 setHTTPHeaderField(HTTPHeaderName::Origin, httpOrigin); 328} 329 330void ResourceRequestBase::clearHTTPOrigin() 331{ 332 updateResourceRequest(); 333 334 m_httpHeaderFields.remove(HTTPHeaderName::Origin); 335 336 if (url().protocolIsInHTTPFamily()) 337 m_platformRequestUpdated = false; 338} 339 340String ResourceRequestBase::httpUserAgent() const 341{ 342 return httpHeaderField(HTTPHeaderName::UserAgent); 343} 344 345void ResourceRequestBase::setHTTPUserAgent(const String& httpUserAgent) 346{ 347 setHTTPHeaderField(HTTPHeaderName::UserAgent, httpUserAgent); 348} 349 350void ResourceRequestBase::clearHTTPUserAgent() 351{ 352 updateResourceRequest(); 353 354 m_httpHeaderFields.remove(HTTPHeaderName::UserAgent); 355 356 if (url().protocolIsInHTTPFamily()) 357 m_platformRequestUpdated = false; 358} 359 360String ResourceRequestBase::httpAccept() const 361{ 362 return httpHeaderField(HTTPHeaderName::Accept); 363} 364 365void ResourceRequestBase::setHTTPAccept(const String& httpAccept) 366{ 367 setHTTPHeaderField(HTTPHeaderName::Accept, httpAccept); 368} 369 370void ResourceRequestBase::clearHTTPAccept() 371{ 372 updateResourceRequest(); 373 374 m_httpHeaderFields.remove(HTTPHeaderName::Accept); 375 376 if (url().protocolIsInHTTPFamily()) 377 m_platformRequestUpdated = false; 378} 379 380void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3) 381{ 382 updateResourceRequest(); 383 384 m_responseContentDispositionEncodingFallbackArray.clear(); 385 m_responseContentDispositionEncodingFallbackArray.reserveInitialCapacity(!encoding1.isNull() + !encoding2.isNull() + !encoding3.isNull()); 386 if (!encoding1.isNull()) 387 m_responseContentDispositionEncodingFallbackArray.uncheckedAppend(encoding1); 388 if (!encoding2.isNull()) 389 m_responseContentDispositionEncodingFallbackArray.uncheckedAppend(encoding2); 390 if (!encoding3.isNull()) 391 m_responseContentDispositionEncodingFallbackArray.uncheckedAppend(encoding3); 392 393 if (url().protocolIsInHTTPFamily()) 394 m_platformRequestUpdated = false; 395} 396 397FormData* ResourceRequestBase::httpBody() const 398{ 399 updateResourceRequest(UpdateHTTPBody); 400 401 return m_httpBody.get(); 402} 403 404void ResourceRequestBase::setHTTPBody(PassRefPtr<FormData> httpBody) 405{ 406 updateResourceRequest(); 407 408 m_httpBody = httpBody; 409 410 m_resourceRequestBodyUpdated = true; 411 412 if (url().protocolIsInHTTPFamily()) 413 m_platformRequestBodyUpdated = false; 414} 415 416bool ResourceRequestBase::allowCookies() const 417{ 418 updateResourceRequest(); 419 420 return m_allowCookies; 421} 422 423void ResourceRequestBase::setAllowCookies(bool allowCookies) 424{ 425 updateResourceRequest(); 426 427 if (m_allowCookies == allowCookies) 428 return; 429 430 m_allowCookies = allowCookies; 431 432 if (url().protocolIsInHTTPFamily()) 433 m_platformRequestUpdated = false; 434} 435 436ResourceLoadPriority ResourceRequestBase::priority() const 437{ 438 updateResourceRequest(); 439 440 return m_priority; 441} 442 443void ResourceRequestBase::setPriority(ResourceLoadPriority priority) 444{ 445 updateResourceRequest(); 446 447 if (m_priority == priority) 448 return; 449 450 m_priority = priority; 451 452 if (url().protocolIsInHTTPFamily()) 453 m_platformRequestUpdated = false; 454} 455 456void ResourceRequestBase::addHTTPHeaderField(const String& name, const String& value) 457{ 458 updateResourceRequest(); 459 460 m_httpHeaderFields.add(name, value); 461 462 if (url().protocolIsInHTTPFamily()) 463 m_platformRequestUpdated = false; 464} 465 466void ResourceRequestBase::setHTTPHeaderFields(HTTPHeaderMap headerFields) 467{ 468 updateResourceRequest(); 469 470 m_httpHeaderFields = WTF::move(headerFields); 471 472 if (url().protocolIsInHTTPFamily()) 473 m_platformRequestUpdated = false; 474} 475 476bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceRequestBase& b) 477{ 478 if (a.url() != b.url()) 479 return false; 480 481 if (a.cachePolicy() != b.cachePolicy()) 482 return false; 483 484 if (a.timeoutInterval() != b.timeoutInterval()) 485 return false; 486 487 if (a.firstPartyForCookies() != b.firstPartyForCookies()) 488 return false; 489 490 if (a.httpMethod() != b.httpMethod()) 491 return false; 492 493 if (a.allowCookies() != b.allowCookies()) 494 return false; 495 496 if (a.priority() != b.priority()) 497 return false; 498 499 FormData* formDataA = a.httpBody(); 500 FormData* formDataB = b.httpBody(); 501 502 if (!formDataA) 503 return !formDataB; 504 if (!formDataB) 505 return !formDataA; 506 507 if (*formDataA != *formDataB) 508 return false; 509 510 return true; 511} 512 513bool ResourceRequestBase::compare(const ResourceRequest& a, const ResourceRequest& b) 514{ 515 if (!equalIgnoringHeaderFields(a, b)) 516 return false; 517 518 if (a.httpHeaderFields() != b.httpHeaderFields()) 519 return false; 520 521 return ResourceRequest::platformCompare(a, b); 522} 523 524static const HTTPHeaderName conditionalHeaderNames[] = { 525 HTTPHeaderName::IfMatch, 526 HTTPHeaderName::IfModifiedSince, 527 HTTPHeaderName::IfNoneMatch, 528 HTTPHeaderName::IfRange, 529 HTTPHeaderName::IfUnmodifiedSince 530}; 531 532bool ResourceRequestBase::isConditional() const 533{ 534 for (auto headerName : conditionalHeaderNames) { 535 if (m_httpHeaderFields.contains(headerName)) 536 return true; 537 } 538 539 return false; 540} 541 542void ResourceRequestBase::makeUnconditional() 543{ 544 for (auto headerName : conditionalHeaderNames) 545 m_httpHeaderFields.remove(headerName); 546} 547 548double ResourceRequestBase::defaultTimeoutInterval() 549{ 550 return s_defaultTimeoutInterval; 551} 552 553void ResourceRequestBase::setDefaultTimeoutInterval(double timeoutInterval) 554{ 555 s_defaultTimeoutInterval = timeoutInterval; 556} 557 558void ResourceRequestBase::updatePlatformRequest(HTTPBodyUpdatePolicy bodyPolicy) const 559{ 560 if (!m_platformRequestUpdated) { 561 ASSERT(m_resourceRequestUpdated); 562 const_cast<ResourceRequest&>(asResourceRequest()).doUpdatePlatformRequest(); 563 m_platformRequestUpdated = true; 564 } 565 566 if (!m_platformRequestBodyUpdated && bodyPolicy == UpdateHTTPBody) { 567 ASSERT(m_resourceRequestBodyUpdated); 568 const_cast<ResourceRequest&>(asResourceRequest()).doUpdatePlatformHTTPBody(); 569 m_platformRequestBodyUpdated = true; 570 } 571} 572 573void ResourceRequestBase::updateResourceRequest(HTTPBodyUpdatePolicy bodyPolicy) const 574{ 575 if (!m_resourceRequestUpdated) { 576 ASSERT(m_platformRequestUpdated); 577 const_cast<ResourceRequest&>(asResourceRequest()).doUpdateResourceRequest(); 578 m_resourceRequestUpdated = true; 579 } 580 581 if (!m_resourceRequestBodyUpdated && bodyPolicy == UpdateHTTPBody) { 582 ASSERT(m_platformRequestBodyUpdated); 583 const_cast<ResourceRequest&>(asResourceRequest()).doUpdateResourceHTTPBody(); 584 m_resourceRequestBodyUpdated = true; 585 } 586} 587 588#if !PLATFORM(COCOA) && !USE(CFNETWORK) && !USE(SOUP) 589unsigned initializeMaximumHTTPConnectionCountPerHost() 590{ 591 // This is used by the loader to control the number of issued parallel load requests. 592 // Four seems to be a common default in HTTP frameworks. 593 return 4; 594} 595#endif 596 597#if PLATFORM(IOS) 598void ResourceRequestBase::setDefaultAllowCookies(bool allowCookies) 599{ 600 s_defaultAllowCookies = allowCookies; 601} 602 603bool ResourceRequestBase::defaultAllowCookies() 604{ 605 return s_defaultAllowCookies; 606} 607#endif 608 609} 610