<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[199590] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/199590">199590</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-04-15 09:39:00 -0700 (Fri, 15 Apr 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Refactor WebSockets handshake to use StringView instead of String for header validation.
https://bugs.webkit.org/show_bug.cgi?id=155602
Patch by John Wilander <wilander@apple.com> on 2016-04-15
Reviewed by Darin Adler.
Source/WebCore:
No new tests. Existing test have been augmented.
* Modules/websockets/WebSocketHandshake.cpp:
(WebCore::WebSocketHandshake::readServerHandshake):
Made sure failure reason was set consistently with makeString().
(WebCore::headerHasValidHTTPVersion):
Now operates on the HTTP status line with StringView.
(WebCore::WebSocketHandshake::readStatusLine):
Now operates on the HTTP status line with StringView.
(WebCore::WebSocketHandshake::readHTTPHeaders):
Now operates on header names with StringView.
Made sure failure reason was set consistently with makeString() and ASCIILiteral().
(WebCore::WebSocketHandshake::checkResponseHeaders):
Made sure failure reason was set consistently with ASCIILiteral().
* platform/network/HTTPParsers.cpp:
(WebCore::parseHTTPRequestLine):
Made sure failure reason was set consistently with ASCIILiteral().
(WebCore::isValidHeaderNameCharacter):
Inlined function to check if a character is allowed in an HTTP header name according to RFC 7230.
https://tools.ietf.org/html/rfc7230 (June 2014)
(WebCore::parseHTTPHeader):
* platform/network/HTTPParsers.h:
Now receives the HTTP header name as a StringView.
Checks that header names only contain valid characters according to RFC 7230 (see above).
* platform/network/ResourceRequestBase.cpp:
(WebCore::ResourceRequestBase::addHTTPHeaderField):
* platform/network/ResourceRequestBase.h:
Now has an overloaded function which receives the HTTP header name as an HTTPHeaderName enum value.
* platform/network/ResourceResponseBase.cpp:
(WebCore::ResourceResponseBase::addHTTPHeaderField):
* platform/network/ResourceResponseBase.h:
Now has an overloaded function which receives the HTTP header name as an HTTPHeaderName enum value.
Source/WebKit2:
* UIProcess/InspectorServer/HTTPRequest.cpp:
(WebKit::HTTPRequest::parseHeaders):
Now declares the HTTP header name as a StringView to match the change in WebCore::parseHTTPHeader.
LayoutTests:
* http/tests/websocket/tests/hybi/bad-handshake-crash-expected.txt:
Fixed so that new error output is expected.
* http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1-expected.txt:
* http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1.html:
* http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1_wsh.py:
Now tests HTTP versions that are higher than 1.1, are lower than 1.1, have bad characters, and are empty.
* http/tests/websocket/tests/hybi/long-invalid-header-expected.txt:
Fixed so that slightly refined error output is expected.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybibadhandshakecrashexpectedtxt">trunk/LayoutTests/http/tests/websocket/tests/hybi/bad-handshake-crash-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybihandshakeokwithhttpversionbeyond1_1expectedtxt">trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybihandshakeokwithhttpversionbeyond1_1html">trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1.html</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybihandshakeokwithhttpversionbeyond1_1_wshpy">trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1_wsh.py</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybilonginvalidheaderexpectedtxt">trunk/LayoutTests/http/tests/websocket/tests/hybi/long-invalid-header-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModuleswebsocketsWebSocketHandshakecpp">trunk/Source/WebCore/Modules/websockets/WebSocketHandshake.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkHTTPParserscpp">trunk/Source/WebCore/platform/network/HTTPParsers.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkHTTPParsersh">trunk/Source/WebCore/platform/network/HTTPParsers.h</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkResourceRequestBasecpp">trunk/Source/WebCore/platform/network/ResourceRequestBase.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkResourceRequestBaseh">trunk/Source/WebCore/platform/network/ResourceRequestBase.h</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkResourceResponseBasecpp">trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformnetworkResourceResponseBaseh">trunk/Source/WebCore/platform/network/ResourceResponseBase.h</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessInspectorServerHTTPRequestcpp">trunk/Source/WebKit2/UIProcess/InspectorServer/HTTPRequest.cpp</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/LayoutTests/ChangeLog        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2016-04-15 John Wilander <wilander@apple.com>
+
+ Refactor WebSockets handshake to use StringView instead of String for header validation.
+ https://bugs.webkit.org/show_bug.cgi?id=155602
+
+ Reviewed by Darin Adler.
+
+ * http/tests/websocket/tests/hybi/bad-handshake-crash-expected.txt:
+ Fixed so that new error output is expected.
+ * http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1-expected.txt:
+ * http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1.html:
+ * http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1_wsh.py:
+ Now tests HTTP versions that are higher than 1.1, are lower than 1.1, have bad characters, and are empty.
+ * http/tests/websocket/tests/hybi/long-invalid-header-expected.txt:
+ Fixed so that slightly refined error output is expected.
+
</ins><span class="cx"> 2016-04-15 Joanmarie Diggs <jdiggs@igalia.com>
</span><span class="cx">
</span><span class="cx"> AX: Presentational role on SVG elements is trumped by child 'title' and 'desc' elements
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybibadhandshakecrashexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/bad-handshake-crash-expected.txt (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/bad-handshake-crash-expected.txt        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/bad-handshake-crash-expected.txt        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-CONSOLE MESSAGE: WebSocket connection to 'ws://127.0.0.1:8880/websocket/tests/hybi/bad-handshake-crash' failed: Invalid UTF-8 sequence in header name
</del><ins>+CONSOLE MESSAGE: WebSocket connection to 'ws://127.0.0.1:8880/websocket/tests/hybi/bad-handshake-crash' failed: Unexpected start character in header name
</ins><span class="cx"> Make sure WebSocket doesn't crash with bad handshake message.
</span><span class="cx">
</span><span class="cx"> On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybihandshakeokwithhttpversionbeyond1_1expectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1-expected.txt (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1-expected.txt        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1-expected.txt        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -1,8 +1,16 @@
</span><del>-Test whether WebSocket handshake is OK with if server sends status line with http version beyond 1.1.
</del><ins>+CONSOLE MESSAGE: WebSocket connection to 'ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?01.00' failed: Invalid HTTP version string: HTTP/01.00
+CONSOLE MESSAGE: WebSocket connection to 'ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?000.99' failed: Invalid HTTP version string: HTTP/000.99
+CONSOLE MESSAGE: WebSocket connection to 'ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?0.00' failed: Invalid HTTP version string: HTTP/0.00
+CONSOLE MESSAGE: WebSocket connection to 'ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?-11.9' failed: Invalid HTTP version string: HTTP/-11.9
+CONSOLE MESSAGE: WebSocket connection to 'ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?0x1.0x00' failed: Invalid HTTP version string: HTTP/0x1.0x00
+CONSOLE MESSAGE: WebSocket connection to 'ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?%EF%A3%BF.1' failed: Invalid HTTP version string: HTTP/%EF%A3%BF.1
+CONSOLE MESSAGE: WebSocket connection to 'ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?' failed: Invalid HTTP version string: HTTP/
+CONSOLE MESSAGE: WebSocket connection to 'ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?1.1%EF%A3%BF' failed: Invalid HTTP version string: HTTP/1.1%EF%A3%BF
+Test http version parsing and validation. HTTP version 1.1 and above should be accepted for WebSockets.
</ins><span class="cx">
</span><span class="cx"> On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
</span><span class="cx">
</span><del>-PASS handshake_success is true
</del><ins>+PASS for all URLs.
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx">
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybihandshakeokwithhttpversionbeyond1_1html"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1.html (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1.html        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1.html        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -7,31 +7,64 @@
</span><span class="cx"> <div id="description"></div>
</span><span class="cx"> <div id="console"></div>
</span><span class="cx"> <script>
</span><del>- description("Test whether WebSocket handshake is OK with if server sends status line with http version beyond 1.1.");
</del><ins>+ description("Test http version parsing and validation. HTTP version 1.1 and above should be accepted for WebSockets.");
</ins><span class="cx">
</span><span class="cx"> window.jsTestIsAsync = true;
</span><span class="cx">
</span><del>- var url = "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1";
- var handshake_success = false;
- var ws = new WebSocket(url);
- var closeEvent;
</del><ins>+ var testCases = [
+ { url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?1.11", shouldSucceed : true }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?11.0", shouldSucceed : true }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?001.01", shouldSucceed : true }
</ins><span class="cx">
</span><del>- function endTest() {
- clearTimeout(timeoutID);
- shouldBeTrue("handshake_success");
- finishJSTest();
</del><ins>+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?01.00", shouldSucceed : false }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?000.99", shouldSucceed : false }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?0.00", shouldSucceed : false }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?-11.9", shouldSucceed : false }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?0x1.0x00", shouldSucceed : false }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?.1", shouldSucceed : false }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?", shouldSucceed : false }
+ ,{ url : "ws://localhost:8880/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1?1.1", shouldSucceed : false }
+ ];
+
+ var currentTest = 0;
+ var allTestsPassed = true;
+
+ function runATest () {
+ if (currentTest === testCases.length) {
+ if (!allTestsPassed) {
+ testFailed("At least one test failed.");
+ } else {
+ debug("PASS for all URLs.");
+ }
+ finishJSTest();
+ } else {
+ var testCase = testCases[currentTest++];
+ var ws = new WebSocket(testCase.url);
+
+ ws.onopen = (function(shouldSucceed, url) {
+ return function () {
+ if (!shouldSucceed) {
+ debug("FAIL The following URL should have caused an error: " + url);
+ allTestsPassed = false;
+ }
+ runATest();
+ };
+ })(testCase.shouldSucceed, testCase.url);
+
+ ws.onerror = (function(shouldSucceed, url) {
+ return function () {
+ if (shouldSucceed) {
+ debug("FAIL The following URL should have been allowed to be opened: " + url);
+ allTestsPassed = false;
+ }
+ runATest();
+ };
+ })(testCase.shouldSucceed, testCase.url);
+ }
</ins><span class="cx"> }
</span><del>- ws.onopen = function() {
- handshake_success = true;
- ws.close();
- };
</del><span class="cx">
</span><del>- ws.onclose = function () {
- endTest();
- };
-
- var timeoutID = setTimeout("endTest()", 2000);
</del><ins>+ runATest();
</ins><span class="cx"> </script>
</span><span class="cx"> <script src="../../../../js-test-resources/js-test-post.js"></script>
</span><span class="cx"> </body>
</span><del>-</html>
</del><span class="cx">\ No newline at end of file
</span><ins>+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybihandshakeokwithhttpversionbeyond1_1_wshpy"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1_wsh.py (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1_wsh.py        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/handshake-ok-with-http-version-beyond-1_1_wsh.py        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -4,7 +4,14 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def web_socket_do_extra_handshake(request):
</span><del>- message = 'HTTP/3.0 101 Switching Protocols\r\n'
</del><ins>+
+ resources = request.ws_resource.split('?', 1)
+ parameter = None
+ if len(resources) == 2:
+ parameter = resources[1]
+ message = 'HTTP/'
+ message += parameter
+ message += ' 101 Switching Protocols\r\n'
</ins><span class="cx"> message += 'Upgrade: websocket\r\n'
</span><span class="cx"> message += 'Connection: Upgrade\r\n'
</span><span class="cx"> message += 'Sec-WebSocket-Accept: %s\r\n' % compute_accept(request.headers_in['Sec-WebSocket-Key'])[0]
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybilonginvalidheaderexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/long-invalid-header-expected.txt (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/long-invalid-header-expected.txt        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/long-invalid-header-expected.txt        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-CONSOLE MESSAGE: WebSocket connection to 'ws://127.0.0.1:8880/websocket/tests/hybi/long-invalid-header' failed: Unexpected CR in name at pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp…
</del><ins>+CONSOLE MESSAGE: WebSocket connection to 'ws://127.0.0.1:8880/websocket/tests/hybi/long-invalid-header' failed: Unexpected CR in header name at pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp…
</ins><span class="cx"> Make sure WebSocket gives errors on long invalid upgrade header.
</span><span class="cx">
</span><span class="cx"> On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebCore/ChangeLog        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -1,3 +1,43 @@
</span><ins>+2016-04-15 John Wilander <wilander@apple.com>
+
+ Refactor WebSockets handshake to use StringView instead of String for header validation.
+ https://bugs.webkit.org/show_bug.cgi?id=155602
+
+ Reviewed by Darin Adler.
+
+ No new tests. Existing test have been augmented.
+
+ * Modules/websockets/WebSocketHandshake.cpp:
+ (WebCore::WebSocketHandshake::readServerHandshake):
+ Made sure failure reason was set consistently with makeString().
+ (WebCore::headerHasValidHTTPVersion):
+ Now operates on the HTTP status line with StringView.
+ (WebCore::WebSocketHandshake::readStatusLine):
+ Now operates on the HTTP status line with StringView.
+ (WebCore::WebSocketHandshake::readHTTPHeaders):
+ Now operates on header names with StringView.
+ Made sure failure reason was set consistently with makeString() and ASCIILiteral().
+ (WebCore::WebSocketHandshake::checkResponseHeaders):
+ Made sure failure reason was set consistently with ASCIILiteral().
+ * platform/network/HTTPParsers.cpp:
+ (WebCore::parseHTTPRequestLine):
+ Made sure failure reason was set consistently with ASCIILiteral().
+ (WebCore::isValidHeaderNameCharacter):
+ Inlined function to check if a character is allowed in an HTTP header name according to RFC 7230.
+ https://tools.ietf.org/html/rfc7230 (June 2014)
+ (WebCore::parseHTTPHeader):
+ * platform/network/HTTPParsers.h:
+ Now receives the HTTP header name as a StringView.
+ Checks that header names only contain valid characters according to RFC 7230 (see above).
+ * platform/network/ResourceRequestBase.cpp:
+ (WebCore::ResourceRequestBase::addHTTPHeaderField):
+ * platform/network/ResourceRequestBase.h:
+ Now has an overloaded function which receives the HTTP header name as an HTTPHeaderName enum value.
+ * platform/network/ResourceResponseBase.cpp:
+ (WebCore::ResourceResponseBase::addHTTPHeaderField):
+ * platform/network/ResourceResponseBase.h:
+ Now has an overloaded function which receives the HTTP header name as an HTTPHeaderName enum value.
+
</ins><span class="cx"> 2016-04-15 Joanmarie Diggs <jdiggs@igalia.com>
</span><span class="cx">
</span><span class="cx"> AX: Presentational role on SVG elements is trumped by child 'title' and 'desc' elements
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebsocketsWebSocketHandshakecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/websockets/WebSocketHandshake.cpp (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/websockets/WebSocketHandshake.cpp        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebCore/Modules/websockets/WebSocketHandshake.cpp        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx"> #include <wtf/ASCIICType.h>
</span><span class="cx"> #include <wtf/CryptographicallyRandomNumber.h>
</span><span class="cx"> #include <wtf/MD5.h>
</span><ins>+#include <wtf/NeverDestroyed.h>
</ins><span class="cx"> #include <wtf/SHA1.h>
</span><span class="cx"> #include <wtf/StdLibExtras.h>
</span><span class="cx"> #include <wtf/StringExtras.h>
</span><span class="lines">@@ -304,7 +305,7 @@
</span><span class="cx">
</span><span class="cx"> if (statusCode != 101) {
</span><span class="cx"> m_mode = Failed;
</span><del>- m_failureReason = "Unexpected response code: " + String::number(statusCode);
</del><ins>+ m_failureReason = makeString("Unexpected response code: ", String::number(statusCode));
</ins><span class="cx"> return len;
</span><span class="cx"> }
</span><span class="cx"> m_mode = Normal;
</span><span class="lines">@@ -394,27 +395,39 @@
</span><span class="cx">
</span><span class="cx"> // https://tools.ietf.org/html/rfc6455#section-4.1
</span><span class="cx"> // "The HTTP version MUST be at least 1.1."
</span><del>-static inline bool headerHasValidHTTPVersion(const String& httpVersionString, const size_t headerLength)
</del><ins>+static inline bool headerHasValidHTTPVersion(StringView httpStatusLine)
</ins><span class="cx"> {
</span><del>- const size_t posOfHttp = httpVersionString.find("HTTP/");
- if (posOfHttp == notFound)
</del><ins>+ const char* httpVersionStaticPreambleLiteral = "HTTP/";
+ StringView httpVersionStaticPreamble(reinterpret_cast<const LChar*>(httpVersionStaticPreambleLiteral), strlen(httpVersionStaticPreambleLiteral));
+ if (!httpStatusLine.startsWith(httpVersionStaticPreamble))
</ins><span class="cx"> return false;
</span><span class="cx">
</span><del>- // Check that there is a version number which should be three characters after "HTTP/"
- const size_t posOfHttpVersionNumberString = posOfHttp + 5;
- if (posOfHttpVersionNumberString + 3 >= headerLength)
</del><ins>+ // Check that there is a version number which should be at least three characters after "HTTP/"
+ unsigned preambleLength = httpVersionStaticPreamble.length();
+ if (httpStatusLine.length() < preambleLength + 3)
</ins><span class="cx"> return false;
</span><span class="cx">
</span><del>- // Check that the version number is 1.1 or above
- bool versionNumberIsOneDotOneOrAbove = false;
- if (httpVersionString.characterAt(posOfHttpVersionNumberString + 1) == '.') {
- UChar majorVersion = httpVersionString.characterAt(posOfHttpVersionNumberString);
- UChar minorVersion = httpVersionString.characterAt(posOfHttpVersionNumberString + 2);
- if ((majorVersion == '1' && minorVersion >= '1' && minorVersion <= '9')
- || (majorVersion > '1' && majorVersion <= '9' && minorVersion >= '0' && minorVersion <= '9'))
- versionNumberIsOneDotOneOrAbove = true;
</del><ins>+ auto dotPosition = httpStatusLine.find('.', preambleLength);
+ if (dotPosition == notFound)
+ return false;
+
+ StringView majorVersionView = httpStatusLine.substring(preambleLength, dotPosition - preambleLength);
+ bool isValid;
+ int majorVersion = majorVersionView.toIntStrict(isValid);
+ if (!isValid)
+ return false;
+
+ unsigned minorVersionLength;
+ unsigned charactersLeftAfterDotPosition = httpStatusLine.length() - dotPosition;
+ for (minorVersionLength = 1; minorVersionLength < charactersLeftAfterDotPosition; minorVersionLength++) {
+ if (!isASCIIDigit(httpStatusLine[dotPosition + minorVersionLength]))
+ break;
</ins><span class="cx"> }
</span><del>- return versionNumberIsOneDotOneOrAbove;
</del><ins>+ int minorVersion = (httpStatusLine.substring(dotPosition + 1, minorVersionLength)).toIntStrict(isValid);
+ if (!isValid)
+ return false;
+
+ return (majorVersion >= 1 && minorVersion >= 1) || majorVersion >= 2;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Returns the header length (including "\r\n"), or -1 if we have not received enough data yet.
</span><span class="lines">@@ -444,10 +457,10 @@
</span><span class="cx"> // The caller isn't prepared to deal with null bytes in status
</span><span class="cx"> // line. WebSockets specification doesn't prohibit this, but HTTP
</span><span class="cx"> // does, so we'll just treat this as an error.
</span><del>- m_failureReason = "Status line contains embedded null";
</del><ins>+ m_failureReason = ASCIILiteral("Status line contains embedded null");
</ins><span class="cx"> return p + 1 - header;
</span><span class="cx"> } else if (!isASCII(*p)) {
</span><del>- m_failureReason = "Status line contains non-ASCII character";
</del><ins>+ m_failureReason = ASCIILiteral("Status line contains non-ASCII character");
</ins><span class="cx"> return p + 1 - header;
</span><span class="cx"> } else if (*p == '\n')
</span><span class="cx"> break;
</span><span class="lines">@@ -458,38 +471,38 @@
</span><span class="cx"> const char* end = p + 1;
</span><span class="cx"> int lineLength = end - header;
</span><span class="cx"> if (lineLength > maximumLength) {
</span><del>- m_failureReason = "Status line is too long";
</del><ins>+ m_failureReason = ASCIILiteral("Status line is too long");
</ins><span class="cx"> return maximumLength;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // The line must end with "\r\n".
</span><span class="cx"> if (lineLength < 2 || *(end - 2) != '\r') {
</span><del>- m_failureReason = "Status line does not end with CRLF";
</del><ins>+ m_failureReason = ASCIILiteral("Status line does not end with CRLF");
</ins><span class="cx"> return lineLength;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (!space1 || !space2) {
</span><del>- m_failureReason = "No response code found: " + trimInputSample(header, lineLength - 2);
</del><ins>+ m_failureReason = makeString("No response code found: ", trimInputSample(header, lineLength - 2));
</ins><span class="cx"> return lineLength;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- String httpVersionString(header, space1 - header);
- if (!headerHasValidHTTPVersion(httpVersionString, headerLength)) {
- m_failureReason = "Invalid HTTP version string: " + httpVersionString;
</del><ins>+ StringView httpStatusLine(reinterpret_cast<const LChar*>(header), space1 - header);
+ if (!headerHasValidHTTPVersion(httpStatusLine)) {
+ m_failureReason = makeString("Invalid HTTP version string: ", httpStatusLine);
</ins><span class="cx"> return lineLength;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- String statusCodeString(space1 + 1, space2 - space1 - 1);
</del><ins>+ StringView statusCodeString(reinterpret_cast<const LChar*>(space1 + 1), space2 - space1 - 1);
</ins><span class="cx"> if (statusCodeString.length() != 3) // Status code must consist of three digits.
</span><span class="cx"> return lineLength;
</span><span class="cx"> for (int i = 0; i < 3; ++i)
</span><span class="cx"> if (statusCodeString[i] < '0' || statusCodeString[i] > '9') {
</span><del>- m_failureReason = "Invalid status code: " + statusCodeString;
</del><ins>+ m_failureReason = makeString("Invalid status code: ", statusCodeString);
</ins><span class="cx"> return lineLength;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> bool ok = false;
</span><del>- statusCode = statusCodeString.toInt(&ok);
</del><ins>+ statusCode = statusCodeString.toIntStrict(ok);
</ins><span class="cx"> ASSERT(ok);
</span><span class="cx">
</span><span class="cx"> statusText = String(space2 + 1, end - space2 - 3); // Exclude "\r\n".
</span><span class="lines">@@ -498,7 +511,7 @@
</span><span class="cx">
</span><span class="cx"> const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* end)
</span><span class="cx"> {
</span><del>- String name;
</del><ins>+ StringView name;
</ins><span class="cx"> String value;
</span><span class="cx"> bool sawSecWebSocketExtensionsHeaderField = false;
</span><span class="cx"> bool sawSecWebSocketAcceptHeaderField = false;
</span><span class="lines">@@ -514,19 +527,25 @@
</span><span class="cx"> if (name.isEmpty())
</span><span class="cx"> break;
</span><span class="cx">
</span><ins>+ HTTPHeaderName headerName;
+ if (!findHTTPHeaderName(name, headerName)) {
+ m_failureReason = makeString("Unknown header name ", name, " in HTTP response");
+ return nullptr;
+ }
+
</ins><span class="cx"> // https://tools.ietf.org/html/rfc7230#section-3.2.4
</span><span class="cx"> // "Newly defined header fields SHOULD limit their field values to US-ASCII octets."
</span><del>- if ((equalLettersIgnoringASCIICase(name, "sec-websocket-extensions")
- || equalLettersIgnoringASCIICase(name, "sec-websocket-accept")
- || equalLettersIgnoringASCIICase(name, "sec-websocket-protocol"))
</del><ins>+ if ((headerName == HTTPHeaderName::SecWebSocketExtensions
+ || headerName == HTTPHeaderName::SecWebSocketAccept
+ || headerName == HTTPHeaderName::SecWebSocketProtocol)
</ins><span class="cx"> && !value.containsOnlyASCII()) {
</span><del>- m_failureReason = name + " header value should only contain ASCII characters";
</del><ins>+ m_failureReason = makeString(name, " header value should only contain ASCII characters");
</ins><span class="cx"> return nullptr;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (equalLettersIgnoringASCIICase(name, "sec-websocket-extensions")) {
</del><ins>+ if (headerName == HTTPHeaderName::SecWebSocketExtensions) {
</ins><span class="cx"> if (sawSecWebSocketExtensionsHeaderField) {
</span><del>- m_failureReason = "The Sec-WebSocket-Extensions header must not appear more than once in an HTTP response";
</del><ins>+ m_failureReason = ASCIILiteral("The Sec-WebSocket-Extensions header must not appear more than once in an HTTP response");
</ins><span class="cx"> return nullptr;
</span><span class="cx"> }
</span><span class="cx"> if (!m_extensionDispatcher.processHeaderValue(value)) {
</span><span class="lines">@@ -534,22 +553,23 @@
</span><span class="cx"> return nullptr;
</span><span class="cx"> }
</span><span class="cx"> sawSecWebSocketExtensionsHeaderField = true;
</span><del>- } else if (equalLettersIgnoringASCIICase(name, "sec-websocket-accept")) {
- if (sawSecWebSocketAcceptHeaderField) {
- m_failureReason = "The Sec-WebSocket-Accept header must not appear more than once in an HTTP response";
- return nullptr;
</del><ins>+ } else {
+ if (headerName == HTTPHeaderName::SecWebSocketAccept) {
+ if (sawSecWebSocketAcceptHeaderField) {
+ m_failureReason = ASCIILiteral("The Sec-WebSocket-Accept header must not appear more than once in an HTTP response");
+ return nullptr;
+ }
+ sawSecWebSocketAcceptHeaderField = true;
+ } else if (headerName == HTTPHeaderName::SecWebSocketProtocol) {
+ if (sawSecWebSocketProtocolHeaderField) {
+ m_failureReason = ASCIILiteral("The Sec-WebSocket-Protocol header must not appear more than once in an HTTP response");
+ return nullptr;
+ }
+ sawSecWebSocketProtocolHeaderField = true;
</ins><span class="cx"> }
</span><del>- m_serverHandshakeResponse.addHTTPHeaderField(name, value);
- sawSecWebSocketAcceptHeaderField = true;
- } else if (equalLettersIgnoringASCIICase(name, "sec-websocket-protocol")) {
- if (sawSecWebSocketProtocolHeaderField) {
- m_failureReason = "The Sec-WebSocket-Protocol header must not appear more than once in an HTTP response";
- return nullptr;
- }
- m_serverHandshakeResponse.addHTTPHeaderField(name, value);
- sawSecWebSocketProtocolHeaderField = true;
- } else
- m_serverHandshakeResponse.addHTTPHeaderField(name, value);
</del><ins>+
+ m_serverHandshakeResponse.addHTTPHeaderField(headerName, value);
+ }
</ins><span class="cx"> }
</span><span class="cx"> return p;
</span><span class="cx"> }
</span><span class="lines">@@ -562,40 +582,40 @@
</span><span class="cx"> const String& serverWebSocketAccept = this->serverWebSocketAccept();
</span><span class="cx">
</span><span class="cx"> if (serverUpgrade.isNull()) {
</span><del>- m_failureReason = "Error during WebSocket handshake: 'Upgrade' header is missing";
</del><ins>+ m_failureReason = ASCIILiteral("Error during WebSocket handshake: 'Upgrade' header is missing");
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx"> if (serverConnection.isNull()) {
</span><del>- m_failureReason = "Error during WebSocket handshake: 'Connection' header is missing";
</del><ins>+ m_failureReason = ASCIILiteral("Error during WebSocket handshake: 'Connection' header is missing");
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx"> if (serverWebSocketAccept.isNull()) {
</span><del>- m_failureReason = "Error during WebSocket handshake: 'Sec-WebSocket-Accept' header is missing";
</del><ins>+ m_failureReason = ASCIILiteral("Error during WebSocket handshake: 'Sec-WebSocket-Accept' header is missing");
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (!equalLettersIgnoringASCIICase(serverUpgrade, "websocket")) {
</span><del>- m_failureReason = "Error during WebSocket handshake: 'Upgrade' header value is not 'WebSocket'";
</del><ins>+ m_failureReason = ASCIILiteral("Error during WebSocket handshake: 'Upgrade' header value is not 'WebSocket'");
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx"> if (!equalLettersIgnoringASCIICase(serverConnection, "upgrade")) {
</span><del>- m_failureReason = "Error during WebSocket handshake: 'Connection' header value is not 'Upgrade'";
</del><ins>+ m_failureReason = ASCIILiteral("Error during WebSocket handshake: 'Connection' header value is not 'Upgrade'");
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (serverWebSocketAccept != m_expectedAccept) {
</span><del>- m_failureReason = "Error during WebSocket handshake: Sec-WebSocket-Accept mismatch";
</del><ins>+ m_failureReason = ASCIILiteral("Error during WebSocket handshake: Sec-WebSocket-Accept mismatch");
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx"> if (!serverWebSocketProtocol.isNull()) {
</span><span class="cx"> if (m_clientProtocol.isEmpty()) {
</span><del>- m_failureReason = "Error during WebSocket handshake: Sec-WebSocket-Protocol mismatch";
</del><ins>+ m_failureReason = ASCIILiteral("Error during WebSocket handshake: Sec-WebSocket-Protocol mismatch");
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx"> Vector<String> result;
</span><span class="cx"> m_clientProtocol.split(String(WebSocket::subProtocolSeperator()), result);
</span><span class="cx"> if (!result.contains(serverWebSocketProtocol)) {
</span><del>- m_failureReason = "Error during WebSocket handshake: Sec-WebSocket-Protocol mismatch";
</del><ins>+ m_failureReason = ASCIILiteral("Error during WebSocket handshake: Sec-WebSocket-Protocol mismatch");
</ins><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkHTTPParserscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/HTTPParsers.cpp (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/HTTPParsers.cpp        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebCore/platform/network/HTTPParsers.cpp        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -582,20 +582,20 @@
</span><span class="cx">
</span><span class="cx"> // Haven't finished header line.
</span><span class="cx"> if (consumedLength == length) {
</span><del>- failureReason = "Incomplete Request Line";
</del><ins>+ failureReason = ASCIILiteral("Incomplete Request Line");
</ins><span class="cx"> return 0;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // RequestLine does not contain 3 parts.
</span><span class="cx"> if (!space1 || !space2) {
</span><del>- failureReason = "Request Line does not appear to contain: <Method> <Url> <HTTPVersion>.";
</del><ins>+ failureReason = ASCIILiteral("Request Line does not appear to contain: <Method> <Url> <HTTPVersion>.");
</ins><span class="cx"> return 0;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // The line must end with "\r\n".
</span><span class="cx"> const char* end = p + 1;
</span><span class="cx"> if (*(end - 2) != '\r') {
</span><del>- failureReason = "Request line does not end with CRLF";
</del><ins>+ failureReason = ASCIILiteral("Request line does not end with CRLF");
</ins><span class="cx"> return 0;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -619,14 +619,48 @@
</span><span class="cx"> return end - data;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-size_t parseHTTPHeader(const char* start, size_t length, String& failureReason, String& nameStr, String& valueStr, bool strict)
</del><ins>+static inline bool isValidHeaderNameCharacter(const char* character)
</ins><span class="cx"> {
</span><ins>+ // https://tools.ietf.org/html/rfc7230#section-3.2
+ // A header name should only contain one or more of
+ // alphanumeric or ! # $ % & ' * + - . ^ _ ` | ~
+ if (isASCIIAlphanumeric(*character))
+ return true;
+ switch (*character) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ return true;
+ default:
+ return false;
+ }
+}
+
+size_t parseHTTPHeader(const char* start, size_t length, String& failureReason, StringView& nameStr, String& valueStr, bool strict)
+{
</ins><span class="cx"> const char* p = start;
</span><span class="cx"> const char* end = start + length;
</span><span class="cx">
</span><span class="cx"> Vector<char> name;
</span><span class="cx"> Vector<char> value;
</span><del>- nameStr = String();
</del><ins>+
+ bool foundFirstNameChar = false;
+ const char* namePtr;
+ size_t nameSize = 0;
+
+ nameStr = StringView();
</ins><span class="cx"> valueStr = String();
</span><span class="cx">
</span><span class="cx"> for (; p < end; p++) {
</span><span class="lines">@@ -635,18 +669,29 @@
</span><span class="cx"> if (name.isEmpty()) {
</span><span class="cx"> if (p + 1 < end && *(p + 1) == '\n')
</span><span class="cx"> return (p + 2) - start;
</span><del>- failureReason = "CR doesn't follow LF at " + trimInputSample(p, end - p);
</del><ins>+ failureReason = makeString("CR doesn't follow LF in header name at ", trimInputSample(p, end - p));
</ins><span class="cx"> return 0;
</span><span class="cx"> }
</span><del>- failureReason = "Unexpected CR in name at " + trimInputSample(name.data(), name.size());
</del><ins>+ failureReason = makeString("Unexpected CR in header name at ", trimInputSample(name.data(), name.size()));
</ins><span class="cx"> return 0;
</span><span class="cx"> case '\n':
</span><del>- failureReason = "Unexpected LF in name at " + trimInputSample(name.data(), name.size());
</del><ins>+ failureReason = makeString("Unexpected LF in header name at ", trimInputSample(name.data(), name.size()));
</ins><span class="cx"> return 0;
</span><span class="cx"> case ':':
</span><span class="cx"> break;
</span><span class="cx"> default:
</span><ins>+ if (!isValidHeaderNameCharacter(p)) {
+ if (name.size() < 1)
+ failureReason = "Unexpected start character in header name";
+ else
+ failureReason = makeString("Unexpected character in header name at ", trimInputSample(name.data(), name.size()));
+ return 0;
+ }
</ins><span class="cx"> name.append(*p);
</span><ins>+ if (!foundFirstNameChar) {
+ namePtr = p;
+ foundFirstNameChar = true;
+ }
</ins><span class="cx"> continue;
</span><span class="cx"> }
</span><span class="cx"> if (*p == ':') {
</span><span class="lines">@@ -655,6 +700,9 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ nameSize = name.size();
+ nameStr = StringView(reinterpret_cast<const LChar*>(namePtr), nameSize);
+
</ins><span class="cx"> for (; p < end && *p == 0x20; p++) { }
</span><span class="cx">
</span><span class="cx"> for (; p < end; p++) {
</span><span class="lines">@@ -663,7 +711,7 @@
</span><span class="cx"> break;
</span><span class="cx"> case '\n':
</span><span class="cx"> if (strict) {
</span><del>- failureReason = "Unexpected LF in value at " + trimInputSample(value.data(), value.size());
</del><ins>+ failureReason = makeString("Unexpected LF in header value at ", trimInputSample(value.data(), value.size()));
</ins><span class="cx"> return 0;
</span><span class="cx"> }
</span><span class="cx"> break;
</span><span class="lines">@@ -676,17 +724,12 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> if (p >= end || (strict && *p != '\n')) {
</span><del>- failureReason = "CR doesn't follow LF after value at " + trimInputSample(p, end - p);
</del><ins>+ failureReason = makeString("CR doesn't follow LF after header value at ", trimInputSample(p, end - p));
</ins><span class="cx"> return 0;
</span><span class="cx"> }
</span><del>- nameStr = String::fromUTF8(name.data(), name.size());
</del><span class="cx"> valueStr = String::fromUTF8(value.data(), value.size());
</span><del>- if (nameStr.isNull()) {
- failureReason = "Invalid UTF-8 sequence in header name";
- return 0;
- }
</del><span class="cx"> if (valueStr.isNull()) {
</span><del>- failureReason = "Invalid UTF-8 sequence in header value";
</del><ins>+ failureReason = ASCIILiteral("Invalid UTF-8 sequence in header value");
</ins><span class="cx"> return 0;
</span><span class="cx"> }
</span><span class="cx"> return p - start;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkHTTPParsersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/HTTPParsers.h (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/HTTPParsers.h        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebCore/platform/network/HTTPParsers.h        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -91,7 +91,7 @@
</span><span class="cx"> // Parsing Complete HTTP Messages.
</span><span class="cx"> enum HTTPVersion { Unknown, HTTP_1_0, HTTP_1_1 };
</span><span class="cx"> size_t parseHTTPRequestLine(const char* data, size_t length, String& failureReason, String& method, String& url, HTTPVersion&);
</span><del>-size_t parseHTTPHeader(const char* data, size_t length, String& failureReason, String& nameStr, String& valueStr, bool strict = true);
</del><ins>+size_t parseHTTPHeader(const char* data, size_t length, String& failureReason, StringView& nameStr, String& valueStr, bool strict = true);
</ins><span class="cx"> size_t parseHTTPRequestBody(const char* data, size_t length, Vector<unsigned char>& body);
</span><span class="cx">
</span><span class="cx"> inline bool isHTTPSpace(UChar character)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkResourceRequestBasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/ResourceRequestBase.cpp (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/ResourceRequestBase.cpp        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebCore/platform/network/ResourceRequestBase.cpp        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -465,7 +465,7 @@
</span><span class="cx"> m_platformRequestUpdated = false;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void ResourceRequestBase::addHTTPHeaderField(const String& name, const String& value)
</del><ins>+void ResourceRequestBase::addHTTPHeaderField(HTTPHeaderName name, const String& value)
</ins><span class="cx"> {
</span><span class="cx"> updateResourceRequest();
</span><span class="cx">
</span><span class="lines">@@ -475,6 +475,16 @@
</span><span class="cx"> m_platformRequestUpdated = false;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void ResourceRequestBase::addHTTPHeaderField(const String& name, const String& value)
+{
+ updateResourceRequest();
+
+ m_httpHeaderFields.add(name, value);
+
+ if (url().protocolIsInHTTPFamily())
+ m_platformRequestUpdated = false;
+}
+
</ins><span class="cx"> void ResourceRequestBase::setHTTPHeaderFields(HTTPHeaderMap headerFields)
</span><span class="cx"> {
</span><span class="cx"> updateResourceRequest();
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkResourceRequestBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/ResourceRequestBase.h (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/ResourceRequestBase.h        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebCore/platform/network/ResourceRequestBase.h        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -86,6 +86,7 @@
</span><span class="cx"> WEBCORE_EXPORT String httpHeaderField(HTTPHeaderName) const;
</span><span class="cx"> WEBCORE_EXPORT void setHTTPHeaderField(const String& name, const String& value);
</span><span class="cx"> WEBCORE_EXPORT void setHTTPHeaderField(HTTPHeaderName, const String& value);
</span><ins>+ void addHTTPHeaderField(HTTPHeaderName, const String& value);
</ins><span class="cx"> void addHTTPHeaderField(const String& name, const String& value);
</span><span class="cx">
</span><span class="cx"> // Instead of passing a string literal to any of these functions, just use a HTTPHeaderName instead.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkResourceResponseBasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebCore/platform/network/ResourceResponseBase.cpp        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -334,15 +334,22 @@
</span><span class="cx"> // FIXME: Should invalidate or update platform response if present.
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void ResourceResponseBase::addHTTPHeaderField(const String& name, const String& value)
</del><ins>+void ResourceResponseBase::addHTTPHeaderField(HTTPHeaderName name, const String& value)
</ins><span class="cx"> {
</span><span class="cx"> lazyInit(AllFields);
</span><ins>+ updateHeaderParsedState(name);
+ m_httpHeaderFields.add(name, value);
+}
</ins><span class="cx">
</span><ins>+void ResourceResponseBase::addHTTPHeaderField(const String& name, const String& value)
+{
</ins><span class="cx"> HTTPHeaderName headerName;
</span><span class="cx"> if (findHTTPHeaderName(name, headerName))
</span><del>- updateHeaderParsedState(headerName);
-
- m_httpHeaderFields.add(name, value);
</del><ins>+ addHTTPHeaderField(headerName, value);
+ else {
+ lazyInit(AllFields);
+ m_httpHeaderFields.add(name, value);
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> const HTTPHeaderMap& ResourceResponseBase::httpHeaderFields() const
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformnetworkResourceResponseBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/network/ResourceResponseBase.h (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/network/ResourceResponseBase.h        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebCore/platform/network/ResourceResponseBase.h        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -84,6 +84,7 @@
</span><span class="cx"> WEBCORE_EXPORT void setHTTPHeaderField(const String& name, const String& value);
</span><span class="cx"> void setHTTPHeaderField(HTTPHeaderName, const String& value);
</span><span class="cx">
</span><ins>+ void addHTTPHeaderField(HTTPHeaderName, const String& value);
</ins><span class="cx"> void addHTTPHeaderField(const String& name, const String& value);
</span><span class="cx">
</span><span class="cx"> // Instead of passing a string literal to any of these functions, just use a HTTPHeaderName instead.
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebKit2/ChangeLog        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-04-15 John Wilander <wilander@apple.com>
+
+ Refactor WebSockets handshake to use StringView instead of String for header validation.
+ https://bugs.webkit.org/show_bug.cgi?id=155602
+
+ Reviewed by Darin Adler.
+
+ * UIProcess/InspectorServer/HTTPRequest.cpp:
+ (WebKit::HTTPRequest::parseHeaders):
+ Now declares the HTTP header name as a StringView to match the change in WebCore::parseHTTPHeader.
+
</ins><span class="cx"> 2016-04-15 Alex Christensen <achristensen@webkit.org>
</span><span class="cx">
</span><span class="cx"> Don't copy entire NSURLSessionConfiguration just to test for credentials
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessInspectorServerHTTPRequestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/InspectorServer/HTTPRequest.cpp (199589 => 199590)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/InspectorServer/HTTPRequest.cpp        2016-04-15 16:18:37 UTC (rev 199589)
+++ trunk/Source/WebKit2/UIProcess/InspectorServer/HTTPRequest.cpp        2016-04-15 16:39:00 UTC (rev 199590)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #include "HTTPRequest.h"
</span><span class="cx">
</span><span class="cx"> #include <wtf/text/CString.h>
</span><ins>+#include <wtf/text/StringView.h>
</ins><span class="cx">
</span><span class="cx"> using namespace WebCore;
</span><span class="cx">
</span><span class="lines">@@ -82,7 +83,7 @@
</span><span class="cx"> {
</span><span class="cx"> const char* p = data;
</span><span class="cx"> const char* end = data + length;
</span><del>- String name;
</del><ins>+ StringView name;
</ins><span class="cx"> String value;
</span><span class="cx"> for (; p < data + length; p++) {
</span><span class="cx"> size_t consumedLength = parseHTTPHeader(p, end - p, failureReason, name, value);
</span><span class="lines">@@ -91,7 +92,7 @@
</span><span class="cx"> p += consumedLength;
</span><span class="cx"> if (name.isEmpty())
</span><span class="cx"> break;
</span><del>- m_headerFields.add(name, value);
</del><ins>+ m_headerFields.add(name.toString(), value);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // If we got here and "name" is empty, it means the headers are valid and ended with a
</span></span></pre>
</div>
</div>
</body>
</html>