Skip to content

Commit

Permalink
Fix problems with cross-origin redirects
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=116075

Reviewed by Daniel Bates.

LayoutTests/imported/w3c:

Rebasing test expectations.
These tests cannot work as expected as WTR/DRT block access to www2.localhost and example.not.

* web-platform-tests/XMLHttpRequest/send-redirect-bogus-expected.txt:
* web-platform-tests/XMLHttpRequest/send-redirect-to-cors-expected.txt:
* web-platform-tests/XMLHttpRequest/send-redirect-to-non-cors-expected.txt:

Source/WebCore:

Merging https://chromium.googlesource.com/chromium/blink/+/7ea774e478f84f355748108d2aaabca15355d512 by Ken Russell
Same origin redirect responses leading to cross-origin requests were checked as cross-origin redirect responses.
Introduced ClientRequestedCredentials to manage whether credentials are needed or not in the cross-origin request.

In addition to Blink patch, it was needed to update some loaders with the newly introduced ClientRequestedCredentials parameter.
Added the clearing of "Accept-Encoding" header from cross-origin requests as Mac HTTP network layer is adding it for same-origin requests.

Test: http/tests/xmlhttprequest/access-control-and-redirects-async-same-origin.html

* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::startLoadingMainResource): Added new security parameter (from Blink patch).
* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::redirectReceived): Updated checks so that same origin redirections are not treated as cross origin redirections (from Blink patch).
* loader/MediaResourceLoader.cpp:
(WebCore::MediaResourceLoader::start):
* loader/NetscapePlugInStreamLoader.cpp:
(WebCore::NetscapePlugInStreamLoader::NetscapePlugInStreamLoader): Added new security parameter.
* loader/ResourceLoaderOptions.h:
(WebCore::ResourceLoaderOptions::ResourceLoaderOptions): Added new security parameter (from Blink patch).
(WebCore::ResourceLoaderOptions::credentialRequest):
(WebCore::ResourceLoaderOptions::setCredentialRequest):
* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::requestUserCSSStyleSheet): Ditto.
(WebCore::CachedResourceLoader::defaultCachedResourceOptions): Ditto.
* loader/icon/IconLoader.cpp:
(WebCore::IconLoader::startLoading): Added new security parameter.
* page/EventSource.cpp:
(WebCore::EventSource::connect): Added new security parameter (from Blink patch).
* platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.cpp:
(WebCore::WebCoreAVCFResourceLoader::startLoading): Added new security parameter.
* platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm:
(WebCore::WebCoreAVFResourceLoader::startLoading): Ditto.
* platform/network/ResourceHandleTypes.h: Added new security parameter constants (from Blink patch).
* platform/network/ResourceRequestBase.cpp:
(WebCore::ResourceRequestBase::clearHTTPAcceptEncoding): Function to remove "Accept-Encoding" header.
* platform/network/ResourceRequestBase.h: Ditto.
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::createRequest): Added new security parameter.

LayoutTests:

Merging https://chromium.googlesource.com/chromium/blink/+/7ea774e478f84f355748108d2aaabca15355d512 by Ken Russell
This merge adds tests for cross origin requests triggered from same origin redirection responses with and without credentials).
Rebaseline of some tests due to console error messages generated from newly hit CORS checks.

* TestExpectations: Disabled WPT tests that require access to non localhost URLs which are currently blocked by DTR/WTR.
* http/tests/xmlhttprequest/access-control-and-redirects-async-expected.txt:
* http/tests/xmlhttprequest/access-control-and-redirects-async-same-origin-expected.txt: Added.
* http/tests/xmlhttprequest/access-control-and-redirects-async-same-origin.html: Added.
* http/tests/xmlhttprequest/access-control-and-redirects-async.html:
* http/tests/xmlhttprequest/access-control-and-redirects-expected.txt:
* http/tests/xmlhttprequest/access-control-and-redirects.html:
* http/tests/xmlhttprequest/redirect-cross-origin-2-expected.txt:
* http/tests/xmlhttprequest/redirect-cross-origin-expected.txt:
* http/tests/xmlhttprequest/redirect-cross-origin-post-expected.txt:
* http/tests/xmlhttprequest/redirect-cross-origin-tripmine-expected.txt:
* http/tests/xmlhttprequest/resources/access-control-basic-allow-no-credentials.cgi: Added.
* http/tests/xmlhttprequest/xmlhttprequest-unsafe-redirect-expected.txt:


Canonical link: https://commits.webkit.org/171180@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@195010 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
youennf committed Jan 14, 2016
1 parent 281d0d7 commit de3f2c9
Show file tree
Hide file tree
Showing 31 changed files with 310 additions and 69 deletions.
25 changes: 25 additions & 0 deletions LayoutTests/ChangeLog
@@ -1,3 +1,28 @@
2016-01-14 Youenn Fablet <youenn.fablet@crf.canon.fr>

Fix problems with cross-origin redirects
https://bugs.webkit.org/show_bug.cgi?id=116075

Reviewed by Daniel Bates.

Merging https://chromium.googlesource.com/chromium/blink/+/7ea774e478f84f355748108d2aaabca15355d512 by Ken Russell
This merge adds tests for cross origin requests triggered from same origin redirection responses with and without credentials).
Rebaseline of some tests due to console error messages generated from newly hit CORS checks.

* TestExpectations: Disabled WPT tests that require access to non localhost URLs which are currently blocked by DTR/WTR.
* http/tests/xmlhttprequest/access-control-and-redirects-async-expected.txt:
* http/tests/xmlhttprequest/access-control-and-redirects-async-same-origin-expected.txt: Added.
* http/tests/xmlhttprequest/access-control-and-redirects-async-same-origin.html: Added.
* http/tests/xmlhttprequest/access-control-and-redirects-async.html:
* http/tests/xmlhttprequest/access-control-and-redirects-expected.txt:
* http/tests/xmlhttprequest/access-control-and-redirects.html:
* http/tests/xmlhttprequest/redirect-cross-origin-2-expected.txt:
* http/tests/xmlhttprequest/redirect-cross-origin-expected.txt:
* http/tests/xmlhttprequest/redirect-cross-origin-post-expected.txt:
* http/tests/xmlhttprequest/redirect-cross-origin-tripmine-expected.txt:
* http/tests/xmlhttprequest/resources/access-control-basic-allow-no-credentials.cgi: Added.
* http/tests/xmlhttprequest/xmlhttprequest-unsafe-redirect-expected.txt:

2016-01-13 Ryan Haddad <ryanhaddad@apple.com>

Marking test as flaky: sputnik/Conformance/15_Native_Objects/15.1_The_Global_Object/15.1.3/15.1.3.3_encodeURI/S15.1.3.3_A2.4_T2.html
Expand Down
5 changes: 5 additions & 0 deletions LayoutTests/TestExpectations
Expand Up @@ -299,6 +299,11 @@ imported/w3c/web-platform-tests/XMLHttpRequest/xmlhttprequest-timeout-worker-ove
imported/w3c/web-platform-tests/XMLHttpRequest/xmlhttprequest-timeout-worker-simple.html [ Slow ]
imported/w3c/web-platform-tests/XMLHttpRequest/xmlhttprequest-timeout-worker-synconworker.html [ Slow ]
imported/w3c/web-platform-tests/XMLHttpRequest/xmlhttprequest-timeout-worker-twice.html [ Slow ]
# XMLHttpRequest tests requiring DTR/WTR to allow other URLs than localhost to not be blocked and be reachable (www2.localhost)
imported/w3c/web-platform-tests/XMLHttpRequest/send-redirect-bogus.htm [ Skip ]
imported/w3c/web-platform-tests/XMLHttpRequest/send-redirect-to-cors.htm [ Skip ]
imported/w3c/web-platform-tests/XMLHttpRequest/send-redirect-to-non-cors.htm [ Skip ]


# New W3C ref tests that are failing.
webkit.org/b/148856 imported/w3c/web-platform-tests/html/semantics/embedded-content/the-video-element/video_initially_paused.html [ ImageOnlyFailure ]
Expand Down
@@ -1,33 +1,24 @@
Tests that asynchronous XMLHttpRequests handle redirects according to the CORS standard.

Testing resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi without credentials
Expecting success: false
PASS: 0
Testing resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=http://localhost:8000& access-control-allow-credentials=true
Expecting success: false
PASS: 0
Testing resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi& access-control-allow-origin=http://localhost:8000& access-control-allow-credentials=true
Expecting success: false
PASS: 0
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi
Expecting success: false
PASS: 0
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=http://localhost:8000
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=http://localhost:8000 without credentials
Expecting success: true
FAIL: 0
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=http://localhost:8000
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=http://localhost:8000 without credentials
Expecting success: false
PASS: 0
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi& access-control-allow-origin=http://localhost:8000
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi& access-control-allow-origin=http://localhost:8000 without credentials
Expecting success: false
PASS: 0
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=true& url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=*
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=true& url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=* without credentials
Expecting success: false
PASS: 0
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=false& url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=*& access-control-allow-headers=x-webkit
Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=false& url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi& access-control-allow-origin=*& access-control-allow-headers=x-webkit without credentials
Expecting success: false
PASS: 0
Testing resources/redirect-cors.php?url=http://127.0.0.1:8000/xmlhttprequest/resources/get.txt
Testing resources/redirect-cors.php?url=http://127.0.0.1:8000/xmlhttprequest/resources/get.txt without credentials
Expecting success: true
PASS: PASS

@@ -0,0 +1,27 @@
CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi. Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.
CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-no-credentials.cgi. Credentials flag is true, but Access-Control-Allow-Credentials is not "true".
Tests that asynchronous XMLHttpRequests handle redirects according to the CORS standard.

Testing ../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi without credentials
Expecting success: true
PASS: PASS: Cross-domain access allowed.

Testing ../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi with credentials
Expecting success: false
PASS: 0
Testing ../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi without credentials
Expecting success: true
PASS: PASS: Cross-domain access allowed.

Testing ../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi with credentials
Expecting success: true
PASS: PASS: Cross-domain access allowed.

Testing ../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-no-credentials.cgi without credentials
Expecting success: true
PASS: PASS: Cross-domain access allowed.

Testing ../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-no-credentials.cgi with credentials
Expecting success: false
PASS: 0

@@ -0,0 +1,88 @@
<p>Tests that asynchronous XMLHttpRequests handle redirects according to the CORS standard.</p>

<pre id="console"></pre>
<script>
if (window.testRunner) {
testRunner.dumpAsText();
testRunner.waitUntilDone();
}

function log(message)
{
document.getElementById('console').appendChild(document.createTextNode(message + '\n'));
}

function runTestAsync(url, credentials, addCustomHeader, expectSuccess) {
log("Testing " + url + (credentials ? " with " : " without ") + "credentials");
log("Expecting success: " + expectSuccess);

xhr = new XMLHttpRequest();
xhr.withCredentials = credentials;
xhr.open("GET", url, true);
if (addCustomHeader)
xhr.setRequestHeader("x-webkit", "foo");

xhr.onload = function() {
log((expectSuccess ? "PASS" : "FAIL") + ": " + xhr.responseText);
nextTest();
}
xhr.onerror = function() {
log((expectSuccess ? "FAIL" : "PASS") + ": " + xhr.status);
nextTest();
}
xhr.send(null);
}

var withoutCredentials = false;
var withCredentials = true;
var noCustomHeader = false;
var addCustomHeader = true;
var succeeds = true;
var fails = false;

var tests = [
// Test simple same origin requests that receive cross origin redirects.

// Request without credentials is redirected to a cross-origin response with Access-Control-Allow-Origin=*.
// The redirect response passes the access check.
["../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi",
withoutCredentials, noCustomHeader, succeeds],

// Request with credentials is redirected to a cross-origin response with Access-Control-Allow-Origin=*.
// The redirect response fails the access check because credentials were sent.
["../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi",
withCredentials, noCustomHeader, fails],

// Request without credentials is redirected to a cross-origin response with a specific Access-Control-Allow-Origin.
// The redirect response passes the access check.
["../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi",
withoutCredentials, noCustomHeader, succeeds],

// Request with credentials is redirected to a cross-origin response with a specific Access-Control-Allow-Origin.
// The redirect response passes the access check.
["../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi",
withCredentials, noCustomHeader, succeeds],

// Request without credentials is redirected to a cross-origin response with a specific Access-Control-Allow-Origin
// forbidding credentials. The redirect response passes the access check.
["../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-no-credentials.cgi",
withoutCredentials, noCustomHeader, succeeds],

// Request with credentials is redirected to a cross-origin response with a specific Access-Control-Allow-Origin
// forbidding credentials. The redirect response fails the access check.
["../resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-no-credentials.cgi",
withCredentials, noCustomHeader, fails],

]

var currentTest = 0;

function nextTest() {
if (currentTest < tests.length)
runTestAsync.apply(null, tests[currentTest++]);
else if (window.testRunner)
testRunner.notifyDone();
}

nextTest();
</script>
Expand Up @@ -12,11 +12,12 @@
document.getElementById('console').appendChild(document.createTextNode(message + '\n'));
}

function runTestAsync(url, addCustomHeader, expectSuccess) {
log("Testing " + url);
function runTestAsync(url, credentials, addCustomHeader, expectSuccess) {
log("Testing " + url + (credentials ? " with " : " without ") + "credentials");
log("Expecting success: " + expectSuccess);

xhr = new XMLHttpRequest();
xhr.withCredentials = credentials;
xhr.open("GET", url, true);
if (addCustomHeader)
xhr.setRequestHeader("x-webkit", "foo");
Expand All @@ -32,72 +33,57 @@
xhr.send(null);
}

var withoutCredentials = false;
var withCredentials = true;
var noCustomHeader = false;
var addCustomHeader = true;
var succeeds = true;
var fails = false;

var tests = [
// 1) Test simple same origin requests that receive cross origin redirects.

// Request receives a cross-origin redirect response without CORS headers. The redirect response fails the access check.
["resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi",
noCustomHeader, fails],

// Request receives a cross-origin redirect response with CORS headers. The redirect response passes the access check,
// but the resource response fails its access check because the security origin is a globally unique identifier after
// the redirect and the same origin XHR has 'allowCredentials' true.
["resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&\
access-control-allow-origin=http://localhost:8000&\
access-control-allow-credentials=true",
noCustomHeader, fails],

// Same as above, but to a less permissive resource that only allows the requesting origin.
["resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi&\
access-control-allow-origin=http://localhost:8000&\
access-control-allow-credentials=true",
noCustomHeader, fails],

// 2) Test simple cross origin requests that receive redirects.
// 1) Test simple cross origin requests that receive redirects.

// Receives a redirect response without CORS headers. The redirect response fails the access check.
["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi",
noCustomHeader, fails],
withoutCredentials, noCustomHeader, fails],

// Receives a redirect response with CORS headers. The redirect response passes the access check and the resource response
// passes the access check.
// FIXME: this test fails because the redirect is vetoed. There are continued bugs with redirects when the original
// request was cross-origin.
["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&\
access-control-allow-origin=http://localhost:8000",
noCustomHeader, succeeds],
withoutCredentials, noCustomHeader, succeeds],

// Receives a redirect response with a URL containing the userinfo production.
["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&\
access-control-allow-origin=http://localhost:8000",
noCustomHeader, fails],
withoutCredentials, noCustomHeader, fails],

// Receives a redirect response with a URL with an unsupported scheme.
["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi&\
access-control-allow-origin=http://localhost:8000",
noCustomHeader, fails],
withoutCredentials, noCustomHeader, fails],

// 3) Test preflighted cross origin requests that receive redirects.
// 2) Test preflighted cross origin requests that receive redirects.

// Receives a redirect response to the preflight request and fails.
["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=true&\
url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&\
access-control-allow-origin=*",
addCustomHeader, fails],
withoutCredentials, addCustomHeader, fails],

// Successful preflight and receives a redirect response to the actual request and fails.
["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=false&\
url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&\
access-control-allow-origin=*&\
access-control-allow-headers=x-webkit",
addCustomHeader, fails],
withoutCredentials, addCustomHeader, fails],

// 4) Test same origin requests with a custom header that receive a same origin redirect.
// 3) Test same origin requests with a custom header that receive a same origin redirect.
["resources/redirect-cors.php?url=http://127.0.0.1:8000/xmlhttprequest/resources/get.txt",
addCustomHeader, succeeds],
withoutCredentials, addCustomHeader, succeeds],

]

var currentTest = 0;
Expand Down
Expand Up @@ -6,8 +6,9 @@ Testing /resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resourc
Expecting success: false
PASS: Error: NETWORK_ERR: XMLHttpRequest Exception 101
Testing /resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi(async)
Expecting success: false
PASS: 0
Expecting success: true
PASS: PASS: Cross-domain access allowed.

Testing http://localhost:8000/resources/redirect.php?url=http://127.0.0.1:8000/xmlhttprequest/resources/access-control-basic-allow.cgi (sync)
Expecting success: false
PASS: Error: NETWORK_ERR: XMLHttpRequest Exception 101
Expand Down
Expand Up @@ -45,7 +45,7 @@
}

var tests = [
["/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi", false, false],
["/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi", false, true],
["http://localhost:8000/resources/redirect.php?url=http://127.0.0.1:8000/xmlhttprequest/resources/access-control-basic-allow.cgi", false, false],
["http://localhost:8000/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow.cgi", false, false]
]
Expand Down
@@ -1,3 +1,4 @@
CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/reply.xml. Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
Test that a cross-origin redirect to a server that responds is indistinguishable from one that does not. Should say PASS:

PASS
Expand Down
@@ -1,3 +1,4 @@
CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/reply.xml. Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
Test that a cross-origin redirect to a server that responds is indistinguishable from one that does not. Should say PASS:

PASS
Expand Down
@@ -1,3 +1,4 @@
CONSOLE MESSAGE: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/reply.xml. Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
Test that a cross-origin redirect to a server that responds is indistinguishable from one that does not. Should say PASS:

PASS
Expand Down

0 comments on commit de3f2c9

Please sign in to comment.