1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.incubator.http.internal.websocket; 25 26 import org.testng.annotations.DataProvider; 27 import org.testng.annotations.Test; 28 29 import java.net.URI; 30 import jdk.incubator.http.HttpClient; 31 import jdk.incubator.http.WebSocket; 32 import java.time.Duration; 33 import java.util.List; 34 import java.util.concurrent.CompletionStage; 35 import java.util.function.Function; 36 import java.util.stream.Collectors; 37 38 import static jdk.incubator.http.internal.websocket.TestSupport.assertCompletesExceptionally; 39 import static jdk.incubator.http.internal.websocket.TestSupport.assertThrows; 40 41 /* 42 * In some places in this class a new String is created out of a string literal. 43 * The idea is to make sure the code under test relies on something better than 44 * the reference equality ( == ) for string equality checks. 45 */ 46 public class BuildingWebSocketTest { 47 48 @Test 49 public void nulls() { 50 HttpClient c = HttpClient.newHttpClient(); 51 URI uri = URI.create("ws://websocket.example.com"); 52 53 assertThrows(NullPointerException.class, 54 () -> c.newWebSocketBuilder(null, listener())); 55 assertThrows(NullPointerException.class, 56 () -> c.newWebSocketBuilder(uri, null)); 57 assertThrows(NullPointerException.class, 58 () -> c.newWebSocketBuilder(null, null)); 59 assertThrows(NullPointerException.class, 60 () -> c.newWebSocketBuilder(uri, listener()) 61 .header(null, "value")); 62 assertThrows(NullPointerException.class, 63 () -> c.newWebSocketBuilder(uri, listener()) 64 .header("name", null)); 65 assertThrows(NullPointerException.class, 66 () -> c.newWebSocketBuilder(uri, listener()) 67 .header(null, null)); 68 assertThrows(NullPointerException.class, 69 () -> c.newWebSocketBuilder(uri, listener()) 70 .subprotocols(null)); 71 assertThrows(NullPointerException.class, 72 () -> c.newWebSocketBuilder(uri, listener()) 73 .subprotocols(null, "sub1")); 74 assertThrows(NullPointerException.class, 75 () -> c.newWebSocketBuilder(uri, listener()) 76 .subprotocols("sub1.example.com", (String) null)); 77 assertThrows(NullPointerException.class, 78 () -> c.newWebSocketBuilder(uri, listener()) 79 .subprotocols("sub1.example.com", (String[]) null)); 80 assertThrows(NullPointerException.class, 81 () -> c.newWebSocketBuilder(uri, listener()) 82 .subprotocols("sub1.example.com", 83 "sub2.example.com", 84 null)); 85 assertThrows(NullPointerException.class, 86 () -> c.newWebSocketBuilder(uri, listener()) 87 .connectTimeout(null)); 88 } 89 90 @Test(dataProvider = "badURIs") 91 void illegalURI(String u) { 92 WebSocket.Builder b = HttpClient.newHttpClient() 93 .newWebSocketBuilder(URI.create(u), listener()); 94 assertCompletesExceptionally(IllegalArgumentException.class, b.buildAsync()); 95 } 96 97 @Test 98 public void illegalHeaders() { 99 List<String> headers = List.of("Authorization", 100 "Connection", 101 "Cookie", 102 "Content-Length", 103 "Date", 104 "Expect", 105 "From", 106 "Host", 107 "Origin", 108 "Proxy-Authorization", 109 "Referer", 110 "User-agent", 111 "Upgrade", 112 "Via", 113 "Warning", 114 "Sec-WebSocket-Accept", 115 "Sec-WebSocket-Extensions", 116 "Sec-WebSocket-Key", 117 "Sec-WebSocket-Protocol", 118 "Sec-WebSocket-Version").stream() 119 .map(String::new).collect(Collectors.toList()); 120 121 Function<String, CompletionStage<?>> f = 122 header -> HttpClient 123 .newHttpClient() 124 .newWebSocketBuilder(URI.create("ws://websocket.example.com"), 125 listener()) 126 .buildAsync(); 127 128 headers.forEach(h -> assertCompletesExceptionally(IllegalArgumentException.class, f.apply(h))); 129 } 130 131 // TODO: test for bad syntax headers 132 // TODO: test for overwrites (subprotocols) and additions (headers) 133 134 @Test(dataProvider = "badSubprotocols") 135 public void illegalSubprotocolsSyntax(String s) { 136 WebSocket.Builder b = HttpClient.newHttpClient() 137 .newWebSocketBuilder(URI.create("ws://websocket.example.com"), 138 listener()); 139 b.subprotocols(s); 140 assertCompletesExceptionally(IllegalArgumentException.class, b.buildAsync()); 141 } 142 143 @Test(dataProvider = "duplicatingSubprotocols") 144 public void illegalSubprotocolsDuplicates(String mostPreferred, 145 String[] lesserPreferred) { 146 WebSocket.Builder b = HttpClient.newHttpClient() 147 .newWebSocketBuilder(URI.create("ws://websocket.example.com"), 148 listener()); 149 b.subprotocols(mostPreferred, lesserPreferred); 150 assertCompletesExceptionally(IllegalArgumentException.class, b.buildAsync()); 151 } 152 153 @Test(dataProvider = "badConnectTimeouts") 154 public void illegalConnectTimeout(Duration d) { 155 WebSocket.Builder b = HttpClient.newHttpClient() 156 .newWebSocketBuilder(URI.create("ws://websocket.example.com"), 157 listener()); 158 b.connectTimeout(d); 159 assertCompletesExceptionally(IllegalArgumentException.class, b.buildAsync()); 160 } 161 162 @DataProvider 163 public Object[][] badURIs() { 164 return new Object[][]{ 165 {"http://example.com"}, 166 {"ftp://example.com"}, 167 {"wss://websocket.example.com/hello#fragment"}, 168 {"ws://websocket.example.com/hello#fragment"}, 169 }; 170 } 171 172 @DataProvider 173 public Object[][] badConnectTimeouts() { 174 return new Object[][]{ 175 {Duration.ofDays ( 0)}, 176 {Duration.ofDays (-1)}, 177 {Duration.ofHours ( 0)}, 178 {Duration.ofHours (-1)}, 179 {Duration.ofMinutes( 0)}, 180 {Duration.ofMinutes(-1)}, 181 {Duration.ofSeconds( 0)}, 182 {Duration.ofSeconds(-1)}, 183 {Duration.ofMillis ( 0)}, 184 {Duration.ofMillis (-1)}, 185 {Duration.ofNanos ( 0)}, 186 {Duration.ofNanos (-1)}, 187 {Duration.ZERO}, 188 }; 189 } 190 191 // https://tools.ietf.org/html/rfc7230#section-3.2.6 192 // https://tools.ietf.org/html/rfc20 193 @DataProvider 194 public static Object[][] badSubprotocols() { 195 return new Object[][]{ 196 {new String("")}, 197 {"round-brackets("}, 198 {"round-brackets)"}, 199 {"comma,"}, 200 {"slash/"}, 201 {"colon:"}, 202 {"semicolon;"}, 203 {"angle-brackets<"}, 204 {"angle-brackets>"}, 205 {"equals="}, 206 {"question-mark?"}, 207 {"at@"}, 208 {"brackets["}, 209 {"backslash\\"}, 210 {"brackets]"}, 211 {"curly-brackets{"}, 212 {"curly-brackets}"}, 213 {"space "}, 214 {"non-printable-character " + Character.toString((char) 31)}, 215 {"non-printable-character " + Character.toString((char) 127)}, 216 }; 217 } 218 219 @DataProvider 220 public static Object[][] duplicatingSubprotocols() { 221 return new Object[][]{ 222 {"a.b.c", new String[]{"a.b.c"}}, 223 {"a.b.c", new String[]{"x.y.z", "p.q.r", "x.y.z"}}, 224 {"a.b.c", new String[]{new String("a.b.c")}}, 225 }; 226 } 227 228 private static WebSocket.Listener listener() { 229 return new WebSocket.Listener() { }; 230 } 231 }