| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org> | 3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org> |
| 4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org> | 4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org> |
| 5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved. | 5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved. |
| 6 * Copyright (C) 2012 Intel Corporation | 6 * Copyright (C) 2012 Intel Corporation |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Lesser General Public | 9 * modify it under the terms of the GNU Lesser General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 #include "wtf/ArrayBufferView.h" | 59 #include "wtf/ArrayBufferView.h" |
| 60 #include "wtf/Assertions.h" | 60 #include "wtf/Assertions.h" |
| 61 #include "wtf/RefCountedLeakCounter.h" | 61 #include "wtf/RefCountedLeakCounter.h" |
| 62 #include "wtf/StdLibExtras.h" | 62 #include "wtf/StdLibExtras.h" |
| 63 #include "wtf/text/CString.h" | 63 #include "wtf/text/CString.h" |
| 64 | 64 |
| 65 namespace WebCore { | 65 namespace WebCore { |
| 66 | 66 |
| 67 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XM
LHttpRequest")); | 67 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XM
LHttpRequest")); |
| 68 | 68 |
| 69 struct XMLHttpRequestStaticData { | |
| 70 WTF_MAKE_NONCOPYABLE(XMLHttpRequestStaticData); WTF_MAKE_FAST_ALLOCATED; | |
| 71 public: | |
| 72 XMLHttpRequestStaticData(); | |
| 73 String m_proxyHeaderPrefix; | |
| 74 String m_secHeaderPrefix; | |
| 75 HashSet<String, CaseFoldingHash> m_forbiddenRequestHeaders; | |
| 76 }; | |
| 77 | |
| 78 XMLHttpRequestStaticData::XMLHttpRequestStaticData() | |
| 79 : m_proxyHeaderPrefix("proxy-") | |
| 80 , m_secHeaderPrefix("sec-") | |
| 81 { | |
| 82 m_forbiddenRequestHeaders.add("accept-charset"); | |
| 83 m_forbiddenRequestHeaders.add("accept-encoding"); | |
| 84 m_forbiddenRequestHeaders.add("access-control-request-headers"); | |
| 85 m_forbiddenRequestHeaders.add("access-control-request-method"); | |
| 86 m_forbiddenRequestHeaders.add("connection"); | |
| 87 m_forbiddenRequestHeaders.add("content-length"); | |
| 88 m_forbiddenRequestHeaders.add("cookie"); | |
| 89 m_forbiddenRequestHeaders.add("cookie2"); | |
| 90 m_forbiddenRequestHeaders.add("date"); | |
| 91 m_forbiddenRequestHeaders.add("dnt"); | |
| 92 m_forbiddenRequestHeaders.add("expect"); | |
| 93 m_forbiddenRequestHeaders.add("host"); | |
| 94 m_forbiddenRequestHeaders.add("keep-alive"); | |
| 95 m_forbiddenRequestHeaders.add("origin"); | |
| 96 m_forbiddenRequestHeaders.add("referer"); | |
| 97 m_forbiddenRequestHeaders.add("te"); | |
| 98 m_forbiddenRequestHeaders.add("trailer"); | |
| 99 m_forbiddenRequestHeaders.add("transfer-encoding"); | |
| 100 m_forbiddenRequestHeaders.add("upgrade"); | |
| 101 m_forbiddenRequestHeaders.add("user-agent"); | |
| 102 m_forbiddenRequestHeaders.add("via"); | |
| 103 } | |
| 104 | |
| 105 static bool isSetCookieHeader(const AtomicString& name) | 69 static bool isSetCookieHeader(const AtomicString& name) |
| 106 { | 70 { |
| 107 return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set
-cookie2"); | 71 return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set
-cookie2"); |
| 108 } | 72 } |
| 109 | 73 |
| 110 static void replaceCharsetInMediaType(String& mediaType, const String& charsetVa
lue) | 74 static void replaceCharsetInMediaType(String& mediaType, const String& charsetVa
lue) |
| 111 { | 75 { |
| 112 unsigned pos = 0, len = 0; | 76 unsigned pos = 0, len = 0; |
| 113 | 77 |
| 114 findCharsetInMediaType(mediaType, pos, len); | 78 findCharsetInMediaType(mediaType, pos, len); |
| 115 | 79 |
| 116 if (!len) { | 80 if (!len) { |
| 117 // When no charset found, do nothing. | 81 // When no charset found, do nothing. |
| 118 return; | 82 return; |
| 119 } | 83 } |
| 120 | 84 |
| 121 // Found at least one existing charset, replace all occurrences with new cha
rset. | 85 // Found at least one existing charset, replace all occurrences with new cha
rset. |
| 122 while (len) { | 86 while (len) { |
| 123 mediaType.replace(pos, len, charsetValue); | 87 mediaType.replace(pos, len, charsetValue); |
| 124 unsigned start = pos + charsetValue.length(); | 88 unsigned start = pos + charsetValue.length(); |
| 125 findCharsetInMediaType(mediaType, pos, len, start); | 89 findCharsetInMediaType(mediaType, pos, len, start); |
| 126 } | 90 } |
| 127 } | 91 } |
| 128 | 92 |
| 129 static const XMLHttpRequestStaticData* staticData = 0; | |
| 130 | |
| 131 static const XMLHttpRequestStaticData* createXMLHttpRequestStaticData() | |
| 132 { | |
| 133 staticData = new XMLHttpRequestStaticData; | |
| 134 return staticData; | |
| 135 } | |
| 136 | |
| 137 static const XMLHttpRequestStaticData* initializeXMLHttpRequestStaticData() | |
| 138 { | |
| 139 // Uses dummy to avoid warnings about an unused variable. | |
| 140 AtomicallyInitializedStatic(const XMLHttpRequestStaticData*, dummy = createX
MLHttpRequestStaticData()); | |
| 141 return dummy; | |
| 142 } | |
| 143 | |
| 144 static void logConsoleError(ExecutionContext* context, const String& message) | 93 static void logConsoleError(ExecutionContext* context, const String& message) |
| 145 { | 94 { |
| 146 if (!context) | 95 if (!context) |
| 147 return; | 96 return; |
| 148 // FIXME: It's not good to report the bad usage without indicating what sour
ce line it came from. | 97 // FIXME: It's not good to report the bad usage without indicating what sour
ce line it came from. |
| 149 // We should pass additional parameters so we can tell the console where the
mistake occurred. | 98 // We should pass additional parameters so we can tell the console where the
mistake occurred. |
| 150 context->addConsoleMessage(JSMessageSource, ErrorMessageLevel, message); | 99 context->addConsoleMessage(JSMessageSource, ErrorMessageLevel, message); |
| 151 } | 100 } |
| 152 | 101 |
| 153 PassRefPtrWillBeRawPtr<XMLHttpRequest> XMLHttpRequest::create(ExecutionContext*
context, PassRefPtr<SecurityOrigin> securityOrigin) | 102 PassRefPtrWillBeRawPtr<XMLHttpRequest> XMLHttpRequest::create(ExecutionContext*
context, PassRefPtr<SecurityOrigin> securityOrigin) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 170 , m_responseTypeCode(ResponseTypeDefault) | 119 , m_responseTypeCode(ResponseTypeDefault) |
| 171 , m_securityOrigin(securityOrigin) | 120 , m_securityOrigin(securityOrigin) |
| 172 , m_async(true) | 121 , m_async(true) |
| 173 , m_includeCredentials(false) | 122 , m_includeCredentials(false) |
| 174 , m_createdDocument(false) | 123 , m_createdDocument(false) |
| 175 , m_error(false) | 124 , m_error(false) |
| 176 , m_uploadEventsAllowed(true) | 125 , m_uploadEventsAllowed(true) |
| 177 , m_uploadComplete(false) | 126 , m_uploadComplete(false) |
| 178 , m_sameOriginRequest(true) | 127 , m_sameOriginRequest(true) |
| 179 { | 128 { |
| 180 initializeXMLHttpRequestStaticData(); | |
| 181 #ifndef NDEBUG | 129 #ifndef NDEBUG |
| 182 xmlHttpRequestCounter.increment(); | 130 xmlHttpRequestCounter.increment(); |
| 183 #endif | 131 #endif |
| 184 ScriptWrappable::init(this); | 132 ScriptWrappable::init(this); |
| 185 } | 133 } |
| 186 | 134 |
| 187 XMLHttpRequest::~XMLHttpRequest() | 135 XMLHttpRequest::~XMLHttpRequest() |
| 188 { | 136 { |
| 189 #ifndef NDEBUG | 137 #ifndef NDEBUG |
| 190 xmlHttpRequestCounter.decrement(); | 138 xmlHttpRequestCounter.decrement(); |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 } | 428 } |
| 481 | 429 |
| 482 // FIXME: According to XMLHttpRequest Level 2 we should throw InvalidAccessE
rror exception here. | 430 // FIXME: According to XMLHttpRequest Level 2 we should throw InvalidAccessE
rror exception here. |
| 483 // However for time being only print warning message to warn web developers. | 431 // However for time being only print warning message to warn web developers. |
| 484 if (!m_async) | 432 if (!m_async) |
| 485 UseCounter::countDeprecation(executionContext(), UseCounter::SyncXHRWith
Credentials); | 433 UseCounter::countDeprecation(executionContext(), UseCounter::SyncXHRWith
Credentials); |
| 486 | 434 |
| 487 m_includeCredentials = value; | 435 m_includeCredentials = value; |
| 488 } | 436 } |
| 489 | 437 |
| 490 bool XMLHttpRequest::isAllowedHTTPMethod(const String& method) | |
| 491 { | |
| 492 return !equalIgnoringCase(method, "TRACE") | |
| 493 && !equalIgnoringCase(method, "TRACK") | |
| 494 && !equalIgnoringCase(method, "CONNECT"); | |
| 495 } | |
| 496 | |
| 497 AtomicString XMLHttpRequest::uppercaseKnownHTTPMethod(const AtomicString& method
) | 438 AtomicString XMLHttpRequest::uppercaseKnownHTTPMethod(const AtomicString& method
) |
| 498 { | 439 { |
| 499 // Valid methods per step-5 of http://xhr.spec.whatwg.org/#the-open()-method
. | 440 // Valid methods per step-5 of http://xhr.spec.whatwg.org/#the-open()-method
. |
| 500 const char* const methods[] = { | 441 const char* const methods[] = { |
| 501 "DELETE", | 442 "DELETE", |
| 502 "GET", | 443 "GET", |
| 503 "HEAD", | 444 "HEAD", |
| 504 "OPTIONS", | 445 "OPTIONS", |
| 505 "POST", | 446 "POST", |
| 506 "PUT" }; | 447 "PUT" }; |
| 507 | 448 |
| 508 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(methods); ++i) { | 449 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(methods); ++i) { |
| 509 if (equalIgnoringCase(method, methods[i])) { | 450 if (equalIgnoringCase(method, methods[i])) { |
| 510 // Don't bother allocating a new string if it's already all uppercas
e. | 451 // Don't bother allocating a new string if it's already all uppercas
e. |
| 511 if (method == methods[i]) | 452 if (method == methods[i]) |
| 512 return method; | 453 return method; |
| 513 return methods[i]; | 454 return methods[i]; |
| 514 } | 455 } |
| 515 } | 456 } |
| 516 return method; | 457 return method; |
| 517 } | 458 } |
| 518 | 459 |
| 519 bool XMLHttpRequest::isAllowedHTTPHeader(const String& name) | |
| 520 { | |
| 521 initializeXMLHttpRequestStaticData(); | |
| 522 return !staticData->m_forbiddenRequestHeaders.contains(name) && !name.starts
With(staticData->m_proxyHeaderPrefix, false) | |
| 523 && !name.startsWith(staticData->m_secHeaderPrefix, false); | |
| 524 } | |
| 525 | |
| 526 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, Exception
State& exceptionState) | 460 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, Exception
State& exceptionState) |
| 527 { | 461 { |
| 528 open(method, url, true, exceptionState); | 462 open(method, url, true, exceptionState); |
| 529 } | 463 } |
| 530 | 464 |
| 531 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool asyn
c, ExceptionState& exceptionState) | 465 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool asyn
c, ExceptionState& exceptionState) |
| 532 { | 466 { |
| 533 WTF_LOG(Network, "XMLHttpRequest %p open('%s', '%s', %d)", this, method.utf8
().data(), url.elidedString().utf8().data(), async); | 467 WTF_LOG(Network, "XMLHttpRequest %p open('%s', '%s', %d)", this, method.utf8
().data(), url.elidedString().utf8().data(), async); |
| 534 | 468 |
| 535 if (!internalAbort()) | 469 if (!internalAbort()) |
| 536 return; | 470 return; |
| 537 | 471 |
| 538 State previousState = m_state; | 472 State previousState = m_state; |
| 539 m_state = UNSENT; | 473 m_state = UNSENT; |
| 540 m_error = false; | 474 m_error = false; |
| 541 m_uploadComplete = false; | 475 m_uploadComplete = false; |
| 542 | 476 |
| 543 // clear stuff from possible previous load | 477 // clear stuff from possible previous load |
| 544 clearResponse(); | 478 clearResponse(); |
| 545 clearRequest(); | 479 clearRequest(); |
| 546 | 480 |
| 547 ASSERT(m_state == UNSENT); | 481 ASSERT(m_state == UNSENT); |
| 548 | 482 |
| 549 if (!isValidHTTPToken(method)) { | 483 if (!isValidHTTPToken(method)) { |
| 550 exceptionState.throwDOMException(SyntaxError, "'" + method + "' is not a
valid HTTP method."); | 484 exceptionState.throwDOMException(SyntaxError, "'" + method + "' is not a
valid HTTP method."); |
| 551 return; | 485 return; |
| 552 } | 486 } |
| 553 | 487 |
| 554 if (!isAllowedHTTPMethod(method)) { | 488 if (CrossOriginAccessControl::isForbiddenMethod(method)) { |
| 555 exceptionState.throwSecurityError("'" + method + "' HTTP method is unsup
ported."); | 489 exceptionState.throwSecurityError("'" + method + "' HTTP method is unsup
ported."); |
| 556 return; | 490 return; |
| 557 } | 491 } |
| 558 | 492 |
| 559 if (!ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) && !ex
ecutionContext()->contentSecurityPolicy()->allowConnectToSource(url)) { | 493 if (!ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) && !ex
ecutionContext()->contentSecurityPolicy()->allowConnectToSource(url)) { |
| 560 // We can safely expose the URL to JavaScript, as these checks happen sy
nchronously before redirection. JavaScript receives no new information. | 494 // We can safely expose the URL to JavaScript, as these checks happen sy
nchronously before redirection. JavaScript receives no new information. |
| 561 exceptionState.throwSecurityError("Refused to connect to '" + url.elided
String() + "' because it violates the document's Content Security Policy."); | 495 exceptionState.throwSecurityError("Refused to connect to '" + url.elided
String() + "' because it violates the document's Content Security Policy."); |
| 562 return; | 496 return; |
| 563 } | 497 } |
| 564 | 498 |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 808 if (httpBody && m_upload) { | 742 if (httpBody && m_upload) { |
| 809 uploadEvents = m_upload->hasEventListeners(); | 743 uploadEvents = m_upload->hasEventListeners(); |
| 810 m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(EventTyp
eNames::loadstart)); | 744 m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(EventTyp
eNames::loadstart)); |
| 811 } | 745 } |
| 812 } | 746 } |
| 813 | 747 |
| 814 m_sameOriginRequest = securityOrigin()->canRequest(m_url); | 748 m_sameOriginRequest = securityOrigin()->canRequest(m_url); |
| 815 | 749 |
| 816 // We also remember whether upload events should be allowed for this request
in case the upload listeners are | 750 // We also remember whether upload events should be allowed for this request
in case the upload listeners are |
| 817 // added after the request is started. | 751 // added after the request is started. |
| 818 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCros
sOriginAccessRequest(m_method, m_requestHeaders); | 752 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !CrossOriginA
ccessControl::isSimpleRequest(m_method, m_requestHeaders); |
| 819 | 753 |
| 820 ASSERT(executionContext()); | 754 ASSERT(executionContext()); |
| 821 ExecutionContext& executionContext = *this->executionContext(); | 755 ExecutionContext& executionContext = *this->executionContext(); |
| 822 | 756 |
| 823 ResourceRequest request(m_url); | 757 ResourceRequest request(m_url); |
| 824 request.setHTTPMethod(m_method); | 758 request.setHTTPMethod(m_method); |
| 825 request.setRequestContext(blink::WebURLRequest::RequestContextXMLHttpRequest
); | 759 request.setRequestContext(blink::WebURLRequest::RequestContextXMLHttpRequest
); |
| 826 | 760 |
| 827 InspectorInstrumentation::willLoadXHR(&executionContext, this, this, m_metho
d, m_url, m_async, httpBody ? httpBody->deepCopy() : nullptr, m_requestHeaders,
m_includeCredentials); | 761 InspectorInstrumentation::willLoadXHR(&executionContext, this, this, m_metho
d, m_url, m_async, httpBody ? httpBody->deepCopy() : nullptr, m_requestHeaders,
m_includeCredentials); |
| 828 | 762 |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1074 exceptionState.throwDOMException(SyntaxError, "'" + name + "' is not a v
alid HTTP header field name."); | 1008 exceptionState.throwDOMException(SyntaxError, "'" + name + "' is not a v
alid HTTP header field name."); |
| 1075 return; | 1009 return; |
| 1076 } | 1010 } |
| 1077 | 1011 |
| 1078 if (!isValidHTTPHeaderValue(value)) { | 1012 if (!isValidHTTPHeaderValue(value)) { |
| 1079 exceptionState.throwDOMException(SyntaxError, "'" + value + "' is not a
valid HTTP header field value."); | 1013 exceptionState.throwDOMException(SyntaxError, "'" + value + "' is not a
valid HTTP header field value."); |
| 1080 return; | 1014 return; |
| 1081 } | 1015 } |
| 1082 | 1016 |
| 1083 // No script (privileged or not) can set unsafe headers. | 1017 // No script (privileged or not) can set unsafe headers. |
| 1084 if (!isAllowedHTTPHeader(name)) { | 1018 if (CrossOriginAccessControl::isForbiddenHeaderName(name)) { |
| 1085 logConsoleError(executionContext(), "Refused to set unsafe header \"" +
name + "\""); | 1019 logConsoleError(executionContext(), "Refused to set unsafe header \"" +
name + "\""); |
| 1086 return; | 1020 return; |
| 1087 } | 1021 } |
| 1088 | 1022 |
| 1089 setRequestHeaderInternal(name, value); | 1023 setRequestHeaderInternal(name, value); |
| 1090 } | 1024 } |
| 1091 | 1025 |
| 1092 void XMLHttpRequest::setRequestHeaderInternal(const AtomicString& name, const At
omicString& value) | 1026 void XMLHttpRequest::setRequestHeaderInternal(const AtomicString& name, const At
omicString& value) |
| 1093 { | 1027 { |
| 1094 HTTPHeaderMap::AddResult result = m_requestHeaders.add(name, value); | 1028 HTTPHeaderMap::AddResult result = m_requestHeaders.add(name, value); |
| (...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1424 { | 1358 { |
| 1425 visitor->trace(m_responseBlob); | 1359 visitor->trace(m_responseBlob); |
| 1426 visitor->trace(m_responseStream); | 1360 visitor->trace(m_responseStream); |
| 1427 visitor->trace(m_responseDocument); | 1361 visitor->trace(m_responseDocument); |
| 1428 visitor->trace(m_progressEventThrottle); | 1362 visitor->trace(m_progressEventThrottle); |
| 1429 visitor->trace(m_upload); | 1363 visitor->trace(m_upload); |
| 1430 XMLHttpRequestEventTarget::trace(visitor); | 1364 XMLHttpRequestEventTarget::trace(visitor); |
| 1431 } | 1365 } |
| 1432 | 1366 |
| 1433 } // namespace WebCore | 1367 } // namespace WebCore |
| OLD | NEW |