- Revision
- 105076
- Author
- [email protected]
- Date
- 2012-01-16 10:42:03 -0800 (Mon, 16 Jan 2012)
Log Message
https://bugs.webkit.org/show_bug.cgi?id=41210
Cross Origin XMLHttpRequest can not expose headers indicated in Access-Control-Expose-Headers HTTP Response Header
Source/WebCore:
Parsing the "Access-Control-Expose-Headers" in the XMLHTTPRequest response header.
If the custom response-header is part of Access-Control-Expose-Headers, then consider that custom response-header as a valid one.
Patch by Joe Thomas <[email protected]> on 2012-01-16
Reviewed by Alexey Proskuryakov.
Test: http/tests/xmlhttprequest/access-control-response-with-expose-headers.html
* loader/CrossOriginAccessControl.cpp:
(WebCore::parseAccessControlExposeHeadersAllowList): parsing logic of Access-Control-Expose-Headers
* loader/CrossOriginAccessControl.h:
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::getAllResponseHeaders): checking whether the custom response-header is part of "Access-Control-Expose-Headers"
(WebCore::XMLHttpRequest::getResponseHeader): checking whether the custom response-header is part of "Access-Control-Expose-Headers"
LayoutTests:
Added test cases for Access-Control-Expose-Headers
Patch by Joe Thomas <[email protected]> on 2012-01-16
Reviewed by Alexey Proskuryakov.
* http/tests/xmlhttprequest/access-control-response-with-expose-headers-expected.txt: Added.
* http/tests/xmlhttprequest/access-control-response-with-expose-headers.html: Added.
* http/tests/xmlhttprequest/resources/access-control-response-with-expose-headers.php: Added.
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (105075 => 105076)
--- trunk/LayoutTests/ChangeLog 2012-01-16 18:40:21 UTC (rev 105075)
+++ trunk/LayoutTests/ChangeLog 2012-01-16 18:42:03 UTC (rev 105076)
@@ -1,3 +1,16 @@
+2012-01-16 Joe Thomas <[email protected]>
+
+ https://bugs.webkit.org/show_bug.cgi?id=41210
+ Cross Origin XMLHttpRequest can not expose headers indicated in Access-Control-Expose-Headers HTTP Response Header
+
+ Added test cases for Access-Control-Expose-Headers
+
+ Reviewed by Alexey Proskuryakov.
+
+ * http/tests/xmlhttprequest/access-control-response-with-expose-headers-expected.txt: Added.
+ * http/tests/xmlhttprequest/access-control-response-with-expose-headers.html: Added.
+ * http/tests/xmlhttprequest/resources/access-control-response-with-expose-headers.php: Added.
+
2012-01-16 Alexander Pavlov <[email protected]>
[Chromium] Unreviewed, rebaseline SVG tests after r105061.
Added: trunk/LayoutTests/http/tests/xmlhttprequest/access-control-response-with-expose-headers-expected.txt (0 => 105076)
--- trunk/LayoutTests/http/tests/xmlhttprequest/access-control-response-with-expose-headers-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/xmlhttprequest/access-control-response-with-expose-headers-expected.txt 2012-01-16 18:42:03 UTC (rev 105076)
@@ -0,0 +1,13 @@
+CONSOLE MESSAGE: Refused to get unsafe header "X-TEST"
+Test for bug 41210: Cross Origin XMLHttpRequest can not expose headers indicated in Access-Control-Expose-Headers HTTP Response Header.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS xhr.getResponseHeader("X-FOO") is 'BAR'
+PASS xhr.getResponseHeader("x-foo") is 'BAR'
+PASS xhr.getResponseHeader("X-TEST") is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/http/tests/xmlhttprequest/access-control-response-with-expose-headers.html (0 => 105076)
--- trunk/LayoutTests/http/tests/xmlhttprequest/access-control-response-with-expose-headers.html (rev 0)
+++ trunk/LayoutTests/http/tests/xmlhttprequest/access-control-response-with-expose-headers.html 2012-01-16 18:42:03 UTC (rev 105076)
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script type="text/_javascript_">
+window.jsTestIsAsync = true;
+description('Test for bug 41210: Cross Origin XMLHttpRequest can not expose headers indicated in Access-Control-Expose-Headers HTTP Response Header.');
+var xhr = new XMLHttpRequest();
+xhr._onreadystatechange_=function() {
+ if (xhr.readyState==4) {
+ shouldBe("xhr.getResponseHeader(\"X-FOO\")","'BAR'");
+ shouldBe("xhr.getResponseHeader(\"x-foo\")","'BAR'");
+ shouldBeNull("xhr.getResponseHeader(\"X-TEST\")");
+ finishJSTest();
+ }
+}
+var url = ""
+xhr.open("GET",url);
+xhr.send(null);
+</script>
+<script src=""
+</body>
+</html>
\ No newline at end of file
Added: trunk/LayoutTests/http/tests/xmlhttprequest/resources/access-control-response-with-expose-headers.php (0 => 105076)
--- trunk/LayoutTests/http/tests/xmlhttprequest/resources/access-control-response-with-expose-headers.php (rev 0)
+++ trunk/LayoutTests/http/tests/xmlhttprequest/resources/access-control-response-with-expose-headers.php 2012-01-16 18:42:03 UTC (rev 105076)
@@ -0,0 +1,10 @@
+<?php
+ header("Access-control-max-age: 0");
+ header("Access-control-allow-origin: *");
+ header("X-foo: BAR");
+ header("X-TEST: TEST");
+ header("Access-Control-Expose-Headers: x-Foo");
+ header("Content-Type: text/html");
+
+ print "echo"
+?>
Modified: trunk/Source/WebCore/ChangeLog (105075 => 105076)
--- trunk/Source/WebCore/ChangeLog 2012-01-16 18:40:21 UTC (rev 105075)
+++ trunk/Source/WebCore/ChangeLog 2012-01-16 18:42:03 UTC (rev 105076)
@@ -1,3 +1,22 @@
+2012-01-16 Joe Thomas <[email protected]>
+
+ https://bugs.webkit.org/show_bug.cgi?id=41210
+ Cross Origin XMLHttpRequest can not expose headers indicated in Access-Control-Expose-Headers HTTP Response Header
+
+ Parsing the "Access-Control-Expose-Headers" in the XMLHTTPRequest response header.
+ If the custom response-header is part of Access-Control-Expose-Headers, then consider that custom response-header as a valid one.
+
+ Reviewed by Alexey Proskuryakov.
+
+ Test: http/tests/xmlhttprequest/access-control-response-with-expose-headers.html
+
+ * loader/CrossOriginAccessControl.cpp:
+ (WebCore::parseAccessControlExposeHeadersAllowList): parsing logic of Access-Control-Expose-Headers
+ * loader/CrossOriginAccessControl.h:
+ * xml/XMLHttpRequest.cpp:
+ (WebCore::XMLHttpRequest::getAllResponseHeaders): checking whether the custom response-header is part of "Access-Control-Expose-Headers"
+ (WebCore::XMLHttpRequest::getResponseHeader): checking whether the custom response-header is part of "Access-Control-Expose-Headers"
+
2012-01-16 Pavel Feldman <[email protected]>
Web Inspector: timeline record bars may overlap with the records column
Modified: trunk/Source/WebCore/loader/CrossOriginAccessControl.cpp (105075 => 105076)
--- trunk/Source/WebCore/loader/CrossOriginAccessControl.cpp 2012-01-16 18:40:21 UTC (rev 105075)
+++ trunk/Source/WebCore/loader/CrossOriginAccessControl.cpp 2012-01-16 18:42:03 UTC (rev 105076)
@@ -30,7 +30,6 @@
#include "HTTPParsers.h"
#include "ResourceResponse.h"
#include "SecurityOrigin.h"
-#include <wtf/HashSet.h>
#include <wtf/Threading.h>
#include <wtf/text/AtomicString.h>
#include <wtf/text/StringBuilder.h>
@@ -76,7 +75,6 @@
return true;
}
-typedef HashSet<String, CaseFoldingHash> HTTPHeaderSet;
static PassOwnPtr<HTTPHeaderSet> createAllowedCrossOriginResponseHeadersSet()
{
OwnPtr<HTTPHeaderSet> headerSet = adoptPtr(new HashSet<String, CaseFoldingHash>);
@@ -171,4 +169,15 @@
return true;
}
+void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHeaderSet& headerSet)
+{
+ Vector<String> headers;
+ headerValue.split(',', false, headers);
+ for (unsigned headerCount = 0; headerCount < headers.size(); headerCount++) {
+ String strippedHeader = headers[headerCount].stripWhiteSpace();
+ if (!strippedHeader.isEmpty())
+ headerSet.add(strippedHeader);
+ }
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/loader/CrossOriginAccessControl.h (105075 => 105076)
--- trunk/Source/WebCore/loader/CrossOriginAccessControl.h 2012-01-16 18:40:21 UTC (rev 105075)
+++ trunk/Source/WebCore/loader/CrossOriginAccessControl.h 2012-01-16 18:42:03 UTC (rev 105076)
@@ -30,9 +30,12 @@
#include "ResourceHandle.h"
#include "ResourceRequest.h"
#include <wtf/Forward.h>
+#include <wtf/HashSet.h>
namespace WebCore {
+typedef HashSet<String, CaseFoldingHash> HTTPHeaderSet;
+
class HTTPHeaderMap;
class ResourceResponse;
class SecurityOrigin;
@@ -46,6 +49,7 @@
ResourceRequest createAccessControlPreflightRequest(const ResourceRequest&, SecurityOrigin*, StoredCredentials);
bool passesAccessControlCheck(const ResourceResponse&, StoredCredentials, SecurityOrigin*, String& errorDescription);
+void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHeaderSet&);
} // namespace WebCore
Modified: trunk/Source/WebCore/xml/XMLHttpRequest.cpp (105075 => 105076)
--- trunk/Source/WebCore/xml/XMLHttpRequest.cpp 2012-01-16 18:40:21 UTC (rev 105075)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.cpp 2012-01-16 18:42:03 UTC (rev 105076)
@@ -892,6 +892,8 @@
StringBuilder stringBuilder;
+ HTTPHeaderSet accessControlExposeHeaderSet;
+ parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access-Control-Expose-Headers"), accessControlExposeHeaderSet);
HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it!= end; ++it) {
// Hide Set-Cookie header fields from the XMLHttpRequest client for these reasons:
@@ -903,7 +905,7 @@
if (isSetCookieHeader(it->first) && !securityOrigin()->canLoadLocalResources())
continue;
- if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->first))
+ if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->first) && !accessControlExposeHeaderSet.contains(it->first))
continue;
stringBuilder.append(it->first);
@@ -929,8 +931,11 @@
logConsoleError(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
return String();
}
+
+ HTTPHeaderSet accessControlExposeHeaderSet;
+ parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access-Control-Expose-Headers"), accessControlExposeHeaderSet);
- if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name)) {
+ if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name) && !accessControlExposeHeaderSet.contains(name)) {
logConsoleError(scriptExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
return String();
}