1 /* 2 * Copyright (c) 2016, 2017, 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 import java.util.stream.Stream; 38 39 import static jdk.incubator.http.internal.websocket.TestSupport.assertCompletesExceptionally; 40 import static jdk.incubator.http.internal.websocket.TestSupport.assertThrows; 41 42 /* 43 * In some places in this class a new String is created out of a string literal. 44 * The idea is to make sure the code under test relies on something better than 45 * the reference equality ( == ) for string equality checks. 46 */ 47 public class BuildingWebSocketTest { 48 49 private final static URI VALID_URI = URI.create("ws://websocket.example.com"); 50 51 @Test 52 public void nullArguments() { 53 HttpClient c = HttpClient.newHttpClient(); 54 55 assertThrows(NullPointerException.class, 56 () -> c.newWebSocketBuilder() 57 .buildAsync(null, listener())); 58 assertThrows(NullPointerException.class, 59 () -> c.newWebSocketBuilder() 60 .buildAsync(VALID_URI, null)); 61 assertThrows(NullPointerException.class, 62 () -> c.newWebSocketBuilder() 63 .buildAsync(null, null)); 64 assertThrows(NullPointerException.class, 65 () -> c.newWebSocketBuilder() 66 .header(null, "value")); 67 assertThrows(NullPointerException.class, 68 () -> c.newWebSocketBuilder() 69 .header("name", null)); 70 assertThrows(NullPointerException.class, 71 () -> c.newWebSocketBuilder() 72 .header(null, null)); 73 assertThrows(NullPointerException.class, 74 () -> c.newWebSocketBuilder() 75 .subprotocols(null)); 76 assertThrows(NullPointerException.class, 77 () -> c.newWebSocketBuilder() 78 .subprotocols(null, "sub2.example.com")); 79 assertThrows(NullPointerException.class, 80 () -> c.newWebSocketBuilder() 81 .subprotocols("sub1.example.com", (String) null)); 82 assertThrows(NullPointerException.class, 83 () -> c.newWebSocketBuilder() 84 .subprotocols("sub1.example.com", (String[]) null)); 85 assertThrows(NullPointerException.class, 86 () -> c.newWebSocketBuilder() 87 .subprotocols("sub1.example.com", "sub2.example.com", null)); 88 assertThrows(NullPointerException.class, 89 () -> c.newWebSocketBuilder() 90 .subprotocols("sub1.example.com", null, "sub3.example.com")); 91 assertThrows(NullPointerException.class, 92 () -> c.newWebSocketBuilder() 93 .connectTimeout(null)); 94 } 95 96 @Test(dataProvider = "badURIs") 97 void illegalURI(URI uri) { 98 WebSocket.Builder b = HttpClient.newHttpClient().newWebSocketBuilder(); 99 assertCompletesExceptionally(IllegalArgumentException.class, 100 b.buildAsync(uri, listener())); 101 } 102 103 @Test 104 public void illegalHeaders() { 105 List<String> headers = 106 List.of("Sec-WebSocket-Accept", 107 "Sec-WebSocket-Extensions", 108 "Sec-WebSocket-Key", 109 "Sec-WebSocket-Protocol", 110 "Sec-WebSocket-Version") 111 .stream() 112 .flatMap(s -> Stream.of(s, new String(s))) // a string and a copy of it 113 .collect(Collectors.toList()); 114 115 Function<String, CompletionStage<?>> f = 116 header -> HttpClient.newHttpClient() 117 .newWebSocketBuilder() 118 .header(header, "value") 119 .buildAsync(VALID_URI, listener()); 120 121 headers.forEach(h -> assertCompletesExceptionally(IllegalArgumentException.class, f.apply(h))); 122 } 123 124 // TODO: test for bad syntax headers 125 // TODO: test for overwrites (subprotocols) and additions (headers) 126 127 @Test(dataProvider = "badSubprotocols") 128 public void illegalSubprotocolsSyntax(String s) { 129 WebSocket.Builder b = HttpClient.newHttpClient() 130 .newWebSocketBuilder() 131 .subprotocols(s); 132 assertCompletesExceptionally(IllegalArgumentException.class, 133 b.buildAsync(VALID_URI, listener())); 134 } 135 136 @Test(dataProvider = "duplicatingSubprotocols") 137 public void illegalSubprotocolsDuplicates(String mostPreferred, 138 String[] lesserPreferred) { 139 WebSocket.Builder b = HttpClient.newHttpClient() 140 .newWebSocketBuilder() 141 .subprotocols(mostPreferred, lesserPreferred); 142 assertCompletesExceptionally(IllegalArgumentException.class, 143 b.buildAsync(VALID_URI, listener())); 144 } 145 146 @Test(dataProvider = "badConnectTimeouts") 147 public void illegalConnectTimeout(Duration d) { 148 WebSocket.Builder b = HttpClient.newHttpClient() 149 .newWebSocketBuilder() 150 .connectTimeout(d); 151 assertCompletesExceptionally(IllegalArgumentException.class, 152 b.buildAsync(VALID_URI, listener())); 153 } 154 155 @DataProvider 156 public Object[][] badURIs() { 157 return new Object[][]{ 158 {URI.create("http://example.com")}, 159 {URI.create("ftp://example.com")}, 160 {URI.create("wss://websocket.example.com/hello#fragment")}, 161 {URI.create("ws://websocket.example.com/hello#fragment")}, 162 }; 163 } 164 165 @DataProvider 166 public Object[][] badConnectTimeouts() { 167 return new Object[][]{ 168 {Duration.ofDays ( 0)}, 169 {Duration.ofDays (-1)}, 170 {Duration.ofHours ( 0)}, 171 {Duration.ofHours (-1)}, 172 {Duration.ofMinutes( 0)}, 173 {Duration.ofMinutes(-1)}, 174 {Duration.ofSeconds( 0)}, 175 {Duration.ofSeconds(-1)}, 176 {Duration.ofMillis ( 0)}, 177 {Duration.ofMillis (-1)}, 178 {Duration.ofNanos ( 0)}, 179 {Duration.ofNanos (-1)}, 180 {Duration.ZERO}, 181 }; 182 } 183 184 // https://tools.ietf.org/html/rfc7230#section-3.2.6 185 // https://tools.ietf.org/html/rfc20 186 @DataProvider 187 public static Object[][] badSubprotocols() { 188 return new Object[][]{ 189 {""}, 190 {new String("")}, 191 {"round-brackets("}, 192 {"round-brackets)"}, 193 {"comma,"}, 194 {"slash/"}, 195 {"colon:"}, 196 {"semicolon;"}, 197 {"angle-brackets<"}, 198 {"angle-brackets>"}, 199 {"equals="}, 200 {"question-mark?"}, 201 {"at@"}, 202 {"brackets["}, 203 {"backslash\\"}, 204 {"brackets]"}, 205 {"curly-brackets{"}, 206 {"curly-brackets}"}, 207 {"space "}, 208 {"non-printable-character " + Character.toString((char) 31)}, 209 {"non-printable-character " + Character.toString((char) 127)}, 210 }; 211 } 212 213 @DataProvider 214 public static Object[][] duplicatingSubprotocols() { 215 return new Object[][]{ 216 {"a.b.c", new String[]{"a.b.c"}}, 217 {"a.b.c", new String[]{"x.y.z", "p.q.r", "x.y.z"}}, 218 {"a.b.c", new String[]{new String("a.b.c")}}, 219 }; 220 } 221 222 private static WebSocket.Listener listener() { 223 return new WebSocket.Listener() { }; 224 } 225 }