1 /* 2 * Copyright (c) 2015, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package java.net.http; 26 27 import java.io.IOException; 28 import java.net.ProtocolException; 29 import java.net.URI; 30 import java.nio.ByteBuffer; 31 import java.time.Duration; 32 import java.util.Map; 33 import java.util.Optional; 34 import java.util.concurrent.CompletableFuture; 35 import java.util.concurrent.CompletionStage; 36 37 /** 38 * A WebSocket client conforming to RFC 6455. 39 * 40 * <p> A {@code WebSocket} provides full-duplex communication over a TCP 41 * connection. 42 * 43 * <p> To create a {@code WebSocket} use a {@linkplain #newBuilder(URI, Listener) 44 * builder}. Once a {@code WebSocket} is obtained, it's ready to send and 45 * receive messages. When the {@code WebSocket} is no longer 46 * needed it must be closed: a Close message must both be {@linkplain 47 * #sendClose() sent} and {@linkplain Listener#onClose(WebSocket, Optional, 48 * String) received}. Otherwise, invoke {@link #abort() abort} to close abruptly. 49 * 50 * <p> Once closed the {@code WebSocket} remains closed and cannot be reopened. 51 * 52 * <p> Messages of type {@code X} are sent through the {@code WebSocket.sendX} 53 * methods and received through {@link WebSocket.Listener}{@code .onX} methods 54 * asynchronously. Each of the methods returns a {@link CompletionStage} which 55 * completes when the operation has completed. 56 * 57 * <p> Messages are received only if {@linkplain #request(long) requested}. 58 * 59 * <p> One outstanding send operation is permitted: if another send operation is 60 * initiated before the previous one has completed, an {@link 61 * IllegalStateException IllegalStateException} will be thrown. When sending, a 62 * message should not be modified until the returned {@code CompletableFuture} 63 * completes (either normally or exceptionally). 64 * 65 * <p> Messages can be sent and received as a whole or in parts. A whole message 66 * is a sequence of one or more messages in which the last message is marked 67 * when it is sent or received. 68 * 69 * <p> If the message is contained in a {@link ByteBuffer}, bytes are considered 70 * arranged from the {@code buffer}'s {@link ByteBuffer#position() position} to 71 * the {@code buffer}'s {@link ByteBuffer#limit() limit}. 72 * 73 * <p> Unless otherwise noted, passing a {@code null} argument to a constructor 74 * or method of this type will cause a {@link NullPointerException 75 * NullPointerException} to be thrown. 76 * 77 * @implNote The default implementation's methods do not block before returning 78 * a {@code CompletableFuture}. 79 * 80 * @since 9 81 */ 82 public interface WebSocket { 83 84 /** 85 * Creates a builder of {@code WebSocket}s connected to the given URI and 86 * receiving events with the given {@code Listener}. 87 * 88 * <p> Equivalent to: 89 * <pre>{@code 90 * WebSocket.newBuilder(uri, HttpClient.getDefault()) 91 * }</pre> 92 * 93 * @param uri 94 * the WebSocket URI as defined in the WebSocket Protocol 95 * (with "ws" or "wss" scheme) 96 * 97 * @param listener 98 * the listener 99 * 100 * @throws IllegalArgumentException 101 * if the {@code uri} is not a WebSocket URI 102 * @throws SecurityException 103 * if running under a security manager and the caller does 104 * not have permission to access the 105 * {@linkplain HttpClient#getDefault() default HttpClient} 106 * 107 * @return a builder 108 */ 109 static Builder newBuilder(URI uri, Listener listener) { 110 return newBuilder(uri, HttpClient.getDefault(), listener); 111 } 112 113 /** 114 * Creates a builder of {@code WebSocket}s connected to the given URI and 115 * receiving events with the given {@code Listener}. 116 * 117 * <p> Providing a custom {@code client} allows for finer control over the 118 * opening handshake. 119 * 120 * <p> <b>Example</b> 121 * <pre>{@code 122 * HttpClient client = HttpClient.create() 123 * .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80))) 124 * .build(); 125 * ... 126 * WebSocket.newBuilder(URI.create("ws://websocket.example.com"), client, listener)... 127 * }</pre> 128 * 129 * @param uri 130 * the WebSocket URI as defined in the WebSocket Protocol 131 * (with "ws" or "wss" scheme) 132 * 133 * @param client 134 * the HttpClient 135 * @param listener 136 * the listener 137 * 138 * @throws IllegalArgumentException 139 * if the uri is not a WebSocket URI 140 * 141 * @return a builder 142 */ 143 static Builder newBuilder(URI uri, HttpClient client, Listener listener) { 144 return new WSBuilder(uri, client, listener); 145 } 146 147 /** 148 * A builder for creating {@code WebSocket} instances. 149 * 150 * <p> To build a {@code WebSocket}, instantiate a builder, configure it 151 * as required by calling intermediate methods (the ones that return the 152 * builder itself), then finally call {@link #buildAsync()} to get a {@link 153 * CompletableFuture} with resulting {@code WebSocket}. 154 * 155 * <p> If an intermediate method has not been called, an appropriate 156 * default value (or behavior) will be used. Unless otherwise noted, a 157 * repeated call to an intermediate method overwrites the previous value (or 158 * overrides the previous behaviour), if no exception is thrown. 159 * 160 * <p> Instances of {@code Builder} may not be safe for use by multiple 161 * threads. 162 * 163 * @since 9 164 */ 165 interface Builder { 166 167 /** 168 * Adds the given name-value pair to the list of additional headers for 169 * the opening handshake. 170 * 171 * <p> Headers defined in WebSocket Protocol are not allowed to be added. 172 * 173 * @param name 174 * the header name 175 * @param value 176 * the header value 177 * 178 * @return this builder 179 * 180 * @throws IllegalArgumentException 181 * if the {@code name} is a WebSocket defined header name 182 */ 183 Builder header(String name, String value); 184 185 /** 186 * Includes a request for the given subprotocols during the opening 187 * handshake. 188 * 189 * <p> Among the requested subprotocols at most one will be chosen by 190 * the server. When the {@code WebSocket} is connected, the subprotocol 191 * in use is available from {@link WebSocket#getSubprotocol}. 192 * Subprotocols may be specified in the order of preference. 193 * 194 * <p> Each of the given subprotocols must conform to the relevant 195 * rules defined in the WebSocket Protocol. 196 * 197 * @param mostPreferred 198 * the most preferred subprotocol 199 * @param lesserPreferred 200 * the lesser preferred subprotocols, with the least preferred 201 * at the end 202 * 203 * @return this builder 204 * 205 * @throws IllegalArgumentException 206 * if any of the WebSocket Protocol rules relevant to 207 * subprotocols are violated 208 */ 209 Builder subprotocols(String mostPreferred, String... lesserPreferred); 210 211 /** 212 * Sets a timeout for the opening handshake. 213 * 214 * <p> If the opening handshake is not finished within the specified 215 * amount of time then {@link #buildAsync()} completes exceptionally 216 * with a {@code HttpTimeoutException}. 217 * 218 * <p> If this method is not invoked then the timeout is deemed infinite. 219 * 220 * @param timeout 221 * the timeout 222 * 223 * @return this builder 224 */ 225 Builder connectTimeout(Duration timeout); 226 227 /** 228 * Builds a {@code WebSocket}. 229 * 230 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 231 * normally with the {@code WebSocket} when it is connected or completes 232 * exceptionally if an error occurs. 233 * 234 * <p> {@code CompletableFuture} may complete exceptionally with the 235 * following errors: 236 * <ul> 237 * <li> {@link IOException} 238 * if an I/O error occurs 239 * <li> {@link InterruptedException} 240 * if the operation was interrupted 241 * <li> {@link SecurityException} 242 * if a security manager is set, and the caller does not 243 * have a {@link java.net.URLPermission} for the WebSocket URI 244 * <li> {@link WebSocketHandshakeException} 245 * if the opening handshake fails 246 * </ul> 247 * 248 * @return a {@code CompletableFuture} with the {@code WebSocket} 249 */ 250 CompletableFuture<WebSocket> buildAsync(); 251 } 252 253 /** 254 * A listener for events and messages on a {@code WebSocket}. 255 * 256 * <p> Each method below corresponds to a type of event. 257 * <ul> 258 * <li> {@link #onOpen onOpen} <br> 259 * This method is always the first to be invoked. 260 * <li> {@link #onText(WebSocket, CharSequence, WebSocket.MessagePart) 261 * onText}, {@link #onBinary(WebSocket, ByteBuffer, WebSocket.MessagePart) 262 * onBinary}, {@link #onPing(WebSocket, ByteBuffer) onPing} and {@link 263 * #onPong(WebSocket, ByteBuffer) onPong} <br> 264 * These methods are invoked zero or more times after {@code onOpen}. 265 * <li> {@link #onClose(WebSocket, Optional, String) onClose}, {@link 266 * #onError(WebSocket, Throwable) onError} <br> 267 * Only one of these methods is invoked, and that method is invoked last and 268 * at most once. 269 * </ul> 270 * 271 * <pre><code> 272 * onOpen (onText|onBinary|onPing|onPong)* (onClose|onError)? 273 * </code></pre> 274 * 275 * <p> Messages received by the {@code Listener} conform to the WebSocket 276 * Protocol, otherwise {@code onError} with a {@link ProtocolException} is 277 * invoked. 278 * 279 * <p> If a whole message is received, then the corresponding method 280 * ({@code onText} or {@code onBinary}) will be invoked with {@link 281 * WebSocket.MessagePart#WHOLE WHOLE} marker. Otherwise the method will be 282 * invoked with {@link WebSocket.MessagePart#FIRST FIRST}, zero or more 283 * times with {@link WebSocket.MessagePart#FIRST PART} and, finally, with 284 * {@link WebSocket.MessagePart#LAST LAST} markers. 285 * 286 * <pre><code> 287 * WHOLE|(FIRST PART* LAST) 288 * </code></pre> 289 * 290 * <p> All methods are invoked in a sequential (and 291 * <a href="../../../java/util/concurrent/package-summary.html#MemoryVisibility"> 292 * happens-before</a>) order, one after another, possibly by different 293 * threads. If any of the methods above throws an exception, {@code onError} 294 * is then invoked with that exception. Exceptions thrown from {@code 295 * onError} or {@code onClose} are ignored. 296 * 297 * <p> When the method returns, the message is deemed received. After this 298 * another messages may be received. 299 * 300 * <p> These invocations begin asynchronous processing which might not end 301 * with the invocation. To provide coordination, methods of {@code 302 * Listener} return a {@link CompletionStage CompletionStage}. The {@code 303 * CompletionStage} signals the {@code WebSocket} that the 304 * processing of a message has ended. For 305 * convenience, methods may return {@code null}, which means 306 * the same as returning an already completed {@code CompletionStage}. If 307 * the returned {@code CompletionStage} completes exceptionally, then {@link 308 * #onError(WebSocket, Throwable) onError} will be invoked with the 309 * exception. 310 * 311 * <p> Control of the message passes to the {@code Listener} with the 312 * invocation of the method. Control of the message returns to the {@code 313 * WebSocket} at the earliest of, either returning {@code null} from the 314 * method, or the completion of the {@code CompletionStage} returned from 315 * the method. The {@code WebSocket} does not access the message while it's 316 * not in its control. The {@code Listener} must not access the message 317 * after its control has been returned to the {@code WebSocket}. 318 * 319 * <p> It is the responsibility of the listener to make additional 320 * {@linkplain WebSocket#request(long) message requests}, when ready, so 321 * that messages are received eventually. 322 * 323 * <p> Methods above are never invoked with {@code null}s as their 324 * arguments. 325 * 326 * @since 9 327 */ 328 interface Listener { 329 330 /** 331 * Notifies the {@code Listener} that it is connected to the provided 332 * {@code WebSocket}. 333 * 334 * <p> The {@code onOpen} method does not correspond to any message 335 * from the WebSocket Protocol. It is a synthetic event. It is the first 336 * {@code Listener}'s method to be invoked. No other {@code Listener}'s 337 * methods are invoked before this one. The method is usually used to 338 * make an initial {@linkplain WebSocket#request(long) request} for 339 * messages. 340 * 341 * <p> If an exception is thrown from this method then {@link 342 * #onError(WebSocket, Throwable) onError} will be invoked with the 343 * exception. 344 * 345 * @implSpec The default implementation {@linkplain WebSocket#request(long) 346 * requests one message}. 347 * 348 * @param webSocket 349 * the WebSocket 350 */ 351 default void onOpen(WebSocket webSocket) { webSocket.request(1); } 352 353 /** 354 * Receives a Text message. 355 * 356 * <p> The {@code onText} method is invoked zero or more times between 357 * {@code onOpen} and ({@code onClose} or {@code onError}). 358 * 359 * <p> This message may be a partial UTF-16 sequence. However, the 360 * concatenation of all messages through the last will be a whole UTF-16 361 * sequence. 362 * 363 * <p> If an exception is thrown from this method or the returned {@code 364 * CompletionStage} completes exceptionally, then {@link 365 * #onError(WebSocket, Throwable) onError} will be invoked with the 366 * exception. 367 * 368 * @implSpec The default implementation {@linkplain WebSocket#request(long) 369 * requests one more message}. 370 * 371 * @implNote This implementation passes only complete UTF-16 sequences 372 * to the {@code onText} method. 373 * 374 * @param webSocket 375 * the WebSocket 376 * @param message 377 * the message 378 * @param part 379 * the part 380 * 381 * @return a CompletionStage that completes when the message processing 382 * is done; or {@code null} if already done 383 */ 384 default CompletionStage<?> onText(WebSocket webSocket, 385 CharSequence message, 386 MessagePart part) { 387 webSocket.request(1); 388 return null; 389 } 390 391 /** 392 * Receives a Binary message. 393 * 394 * <p> The {@code onBinary} method is invoked zero or more times 395 * between {@code onOpen} and ({@code onClose} or {@code onError}). 396 * 397 * <p> If an exception is thrown from this method or the returned {@code 398 * CompletionStage} completes exceptionally, then {@link 399 * #onError(WebSocket, Throwable) onError} will be invoked with this 400 * exception. 401 * 402 * @implSpec The default implementation {@linkplain WebSocket#request(long) 403 * requests one more message}. 404 * 405 * @param webSocket 406 * the WebSocket 407 * @param message 408 * the message 409 * @param part 410 * the part 411 * 412 * @return a CompletionStage that completes when the message processing 413 * is done; or {@code null} if already done 414 */ 415 default CompletionStage<?> onBinary(WebSocket webSocket, 416 ByteBuffer message, 417 MessagePart part) { 418 webSocket.request(1); 419 return null; 420 } 421 422 /** 423 * Receives a Ping message. 424 * 425 * <p> A Ping message may be sent or received by either client or 426 * server. It may serve either as a keepalive or as a means to verify 427 * that the remote endpoint is still responsive. 428 * 429 * <p> The message will consist of not more than {@code 125} bytes: 430 * {@code message.remaining() <= 125}. 431 * 432 * <p> The {@code onPing} is invoked zero or more times in between 433 * {@code onOpen} and ({@code onClose} or {@code onError}). 434 * 435 * <p> If an exception is thrown from this method or the returned {@code 436 * CompletionStage} completes exceptionally, then {@link 437 * #onError(WebSocket, Throwable) onError} will be invoked with this 438 * exception. 439 * 440 * @implNote 441 * 442 * <p> Replies with a Pong message and requests one more message when 443 * the Pong has been sent. 444 * 445 * @param webSocket 446 * the WebSocket 447 * @param message 448 * the message 449 * 450 * @return a CompletionStage that completes when the message processing 451 * is done; or {@code null} if already done 452 */ 453 default CompletionStage<?> onPing(WebSocket webSocket, 454 ByteBuffer message) { 455 return webSocket.sendPong(message).thenRun(() -> webSocket.request(1)); 456 } 457 458 /** 459 * Receives a Pong message. 460 * 461 * <p> A Pong message may be unsolicited or may be received in response 462 * to a previously sent Ping. In the latter case, the contents of the 463 * Pong is identical to the originating Ping. 464 * 465 * <p> The message will consist of not more than {@code 125} bytes: 466 * {@code message.remaining() <= 125}. 467 * 468 * <p> The {@code onPong} method is invoked zero or more times in 469 * between {@code onOpen} and ({@code onClose} or {@code onError}). 470 * 471 * <p> If an exception is thrown from this method or the returned {@code 472 * CompletionStage} completes exceptionally, then {@link 473 * #onError(WebSocket, Throwable) onError} will be invoked with this 474 * exception. 475 * 476 * @implSpec The default implementation {@linkplain WebSocket#request(long) 477 * requests one more message}. 478 * 479 * @param webSocket 480 * the WebSocket 481 * @param message 482 * the message 483 * 484 * @return a CompletionStage that completes when the message processing 485 * is done; or {@code null} if already done 486 */ 487 default CompletionStage<?> onPong(WebSocket webSocket, 488 ByteBuffer message) { 489 webSocket.request(1); 490 return null; 491 } 492 493 /** 494 * Receives a Close message. 495 * 496 * <p> Once a Close message is received, the server will not send any 497 * more messages. 498 * 499 * <p> A Close message may consist of a status code and a reason for 500 * closing. The reason will have a UTF-8 representation not longer than 501 * {@code 123} bytes. The reason may be useful for debugging or passing 502 * information relevant to the connection but is not necessarily human 503 * readable. 504 * 505 * <p> {@code onClose} is the last invocation on the {@code Listener}. 506 * It is invoked at most once, but after {@code onOpen}. If an exception 507 * is thrown from this method, it is ignored. 508 * 509 * @implSpec The default implementation does nothing. 510 * 511 * @param webSocket 512 * the WebSocket 513 * @param code 514 * an {@code Optional} describing the close code, or 515 * an empty {@code Optional} if the message doesn't contain it 516 * @param reason 517 * the reason of close; can be empty 518 */ 519 default void onClose(WebSocket webSocket, Optional<CloseCode> code, 520 String reason) { } 521 522 /** 523 * Notifies an I/O or protocol error has occurred on the {@code 524 * WebSocket}. 525 * 526 * <p> The {@code onError} method does not correspond to any message 527 * from the WebSocket Protocol. It is a synthetic event. {@code onError} 528 * is the last invocation on the {@code Listener}. It is invoked at most 529 * once but after {@code onOpen}. If an exception is thrown from this 530 * method, it is ignored. 531 * 532 * <p> The WebSocket Protocol requires some errors occurs in the 533 * incoming destination must be fatal to the connection. In such cases 534 * the implementation takes care of closing the {@code WebSocket}. By 535 * the time {@code onError} is invoked, no more messages can be sent on 536 * this {@code WebSocket}. 537 * 538 * @apiNote Errors associated with {@code sendX} methods are reported to 539 * the {@code CompletableFuture} these methods return. 540 * 541 * @implSpec The default implementation does nothing. 542 * 543 * @param webSocket 544 * the WebSocket 545 * @param error 546 * the error 547 */ 548 default void onError(WebSocket webSocket, Throwable error) { } 549 } 550 551 /** 552 * A marker used by {@link WebSocket.Listener} in cases where a partial 553 * message may be received. 554 * 555 * @since 9 556 */ 557 enum MessagePart { 558 559 /** 560 * The first part of a message in a sequence. 561 */ 562 FIRST, 563 564 /** 565 * A middle part of a message in a sequence. 566 */ 567 PART, 568 569 /** 570 * The last part of a message in a sequence. 571 */ 572 LAST, 573 574 /** 575 * A whole message consisting of a single part. 576 */ 577 WHOLE 578 } 579 580 /** 581 * Sends a Text message with characters from the given {@code CharSequence}. 582 * 583 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 584 * normally when the message has been sent or completes exceptionally if an 585 * error occurs. 586 * 587 * <p> The {@code CharSequence} should not be modified until the returned 588 * {@code CompletableFuture} completes (either normally or exceptionally). 589 * 590 * <p> The returned {@code CompletableFuture} can complete exceptionally 591 * with: 592 * <ul> 593 * <li> {@link IOException} 594 * if an I/O error occurs during this operation 595 * <li> {@link IllegalStateException} 596 * if the {@code WebSocket} closes while this operation is in progress; 597 * or if a Close message has been sent already; 598 * or if there is an outstanding send operation; 599 * or if a previous Binary message was not sent with {@code isLast == true} 600 * </ul> 601 * 602 * @implNote This implementation does not accept partial UTF-16 603 * sequences. In case such a sequence is passed, a returned {@code 604 * CompletableFuture} completes exceptionally. 605 * 606 * @param message 607 * the message 608 * @param isLast 609 * {@code true} if this is the last part of the message, 610 * {@code false} otherwise 611 * 612 * @return a CompletableFuture with this WebSocket 613 * 614 * @throws IllegalArgumentException 615 * if {@code message} is a malformed (or an incomplete) UTF-16 sequence 616 */ 617 CompletableFuture<WebSocket> sendText(CharSequence message, boolean isLast); 618 619 /** 620 * Sends a whole Text message with characters from the given {@code 621 * CharSequence}. 622 * 623 * <p> This is a convenience method. For the general case, use {@link 624 * #sendText(CharSequence, boolean)}. 625 * 626 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 627 * normally when the message has been sent or completes exceptionally if an 628 * error occurs. 629 * 630 * <p> The {@code CharSequence} should not be modified until the returned 631 * {@code CompletableFuture} completes (either normally or exceptionally). 632 * 633 * <p> The returned {@code CompletableFuture} can complete exceptionally 634 * with: 635 * <ul> 636 * <li> {@link IOException} 637 * if an I/O error occurs during this operation 638 * <li> {@link IllegalStateException} 639 * if the {@code WebSocket} closes while this operation is in progress; 640 * or if a Close message has been sent already; 641 * or if there is an outstanding send operation; 642 * or if a previous Binary message was not sent with {@code isLast == true} 643 * </ul> 644 * 645 * @param message 646 * the message 647 * 648 * @return a CompletableFuture with this WebSocket 649 * 650 * @throws IllegalArgumentException 651 * if {@code message} is a malformed (or an incomplete) UTF-16 sequence 652 */ 653 default CompletableFuture<WebSocket> sendText(CharSequence message) { 654 return sendText(message, true); 655 } 656 657 /** 658 * Sends a Binary message with bytes from the given {@code ByteBuffer}. 659 * 660 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 661 * normally when the message has been sent or completes exceptionally if an 662 * error occurs. 663 * 664 * <p> The returned {@code CompletableFuture} can complete exceptionally 665 * with: 666 * <ul> 667 * <li> {@link IOException} 668 * if an I/O error occurs during this operation 669 * <li> {@link IllegalStateException} 670 * if the {@code WebSocket} closes while this operation is in progress; 671 * or if a Close message has been sent already; 672 * or if there is an outstanding send operation; 673 * or if a previous Text message was not sent with {@code isLast == true} 674 * </ul> 675 * 676 * @param message 677 * the message 678 * @param isLast 679 * {@code true} if this is the last part of the message, 680 * {@code false} otherwise 681 * 682 * @return a CompletableFuture with this WebSocket 683 */ 684 CompletableFuture<WebSocket> sendBinary(ByteBuffer message, boolean isLast); 685 686 /** 687 * Sends a Ping message. 688 * 689 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 690 * normally when the message has been sent or completes exceptionally if an 691 * error occurs. 692 * 693 * <p> A Ping message may be sent or received by either client or server. 694 * It may serve either as a keepalive or as a means to verify that the 695 * remote endpoint is still responsive. 696 * 697 * <p> The message must consist of not more than {@code 125} bytes: {@code 698 * message.remaining() <= 125}. 699 * 700 * <p> The returned {@code CompletableFuture} can complete exceptionally 701 * with: 702 * <ul> 703 * <li> {@link IOException} 704 * if an I/O error occurs during this operation 705 * <li> {@link IllegalStateException} 706 * if the {@code WebSocket} closes while this operation is in progress; 707 * or if a Close message has been sent already; 708 * or if there is an outstanding send operation 709 * </ul> 710 * 711 * @param message 712 * the message 713 * 714 * @return a CompletableFuture with this WebSocket 715 * 716 * @throws IllegalArgumentException 717 * if {@code message.remaining() > 125} 718 */ 719 CompletableFuture<WebSocket> sendPing(ByteBuffer message); 720 721 /** 722 * Sends a Pong message. 723 * 724 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 725 * normally when the message has been sent or completes exceptionally if an 726 * error occurs. 727 * 728 * <p> A Pong message may be unsolicited or may be sent in response to a 729 * previously received Ping. In latter case the contents of the Pong is 730 * identical to the originating Ping. 731 * 732 * <p> The message must consist of not more than {@code 125} bytes: {@code 733 * message.remaining() <= 125}. 734 * 735 * <p> The returned {@code CompletableFuture} can complete exceptionally 736 * with: 737 * <ul> 738 * <li> {@link IOException} 739 * if an I/O error occurs during this operation 740 * <li> {@link IllegalStateException} 741 * if the {@code WebSocket} closes while this operation is in progress; 742 * or if a Close message has been sent already; 743 * or if there is an outstanding send operation 744 * </ul> 745 * 746 * @param message 747 * the message 748 * 749 * @return a CompletableFuture with this WebSocket 750 * 751 * @throws IllegalArgumentException 752 * if {@code message.remaining() > 125} 753 */ 754 CompletableFuture<WebSocket> sendPong(ByteBuffer message); 755 756 /** 757 * Sends a Close message with the given close code and the reason. 758 * 759 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 760 * normally when the message has been sent or completes exceptionally if an 761 * error occurs. 762 * 763 * <p> A Close message may consist of a status code and a reason for 764 * closing. The reason must have a UTF-8 representation not longer than 765 * {@code 123} bytes. The reason may be useful for debugging or passing 766 * information relevant to the connection but is not necessarily human 767 * readable. 768 * 769 * <p> The returned {@code CompletableFuture} can complete exceptionally 770 * with: 771 * <ul> 772 * <li> {@link IOException} 773 * if an I/O error occurs during this operation 774 * <li> {@link IllegalStateException} 775 * if the {@code WebSocket} closes while this operation is in progress; 776 * or if a Close message has been sent already; 777 * or if there is an outstanding send operation 778 * </ul> 779 * 780 * @param code 781 * the close code 782 * @param reason 783 * the reason; can be empty 784 * 785 * @return a CompletableFuture with this WebSocket 786 * 787 * @throws IllegalArgumentException 788 * if {@code reason} doesn't have an UTF-8 representation not longer 789 * than {@code 123} bytes 790 */ 791 CompletableFuture<WebSocket> sendClose(CloseCode code, CharSequence reason); 792 793 /** 794 * Sends an empty Close message. 795 * 796 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes 797 * normally when the message has been sent or completes exceptionally if an 798 * error occurs. 799 * 800 * <p> The returned {@code CompletableFuture} can complete exceptionally 801 * with: 802 * <ul> 803 * <li> {@link IOException} 804 * if an I/O error occurs during this operation 805 * <li> {@link IllegalStateException} 806 * if the {@code WebSocket} closes while this operation is in progress; 807 * or if a Close message has been sent already; 808 * or if there is an outstanding send operation 809 * </ul> 810 * 811 * @return a CompletableFuture with this WebSocket 812 */ 813 CompletableFuture<WebSocket> sendClose(); 814 815 /** 816 * Allows {@code n} more messages to be received by the {@link Listener 817 * Listener}. 818 * 819 * <p> The actual number of received messages might be fewer if a Close 820 * message is received, the connection closes or an error occurs. 821 * 822 * <p> A {@code WebSocket} that has just been created, hasn't requested 823 * anything yet. Usually the initial request for messages is done in {@link 824 * Listener#onOpen(java.net.http.WebSocket) Listener.onOpen}. 825 * 826 * @implNote This implementation does not distinguish between partial and 827 * whole messages, because it's not known beforehand how a message will be 828 * received. 829 * 830 * <p> If a server sends more messages than requested, this implementation 831 * queues up these messages on the TCP connection and may eventually force 832 * the sender to stop sending through TCP flow control. 833 * 834 * @param n 835 * the number of messages 836 * 837 * @throws IllegalArgumentException 838 * if {@code n < 0} 839 */ 840 void request(long n); 841 842 /** 843 * Returns a {@linkplain Builder#subprotocols(String, String...) subprotocol} 844 * in use. 845 * 846 * @return a subprotocol, or {@code null} if there is none 847 */ 848 String getSubprotocol(); 849 850 /** 851 * Tells whether the {@code WebSocket} is closed. 852 * 853 * <p> A {@code WebSocket} deemed closed when either the underlying socket 854 * is closed or the closing handshake is completed. 855 * 856 * @return {@code true} if the {@code WebSocket} is closed, 857 * {@code false} otherwise 858 */ 859 boolean isClosed(); 860 861 /** 862 * Closes the {@code WebSocket} abruptly. 863 * 864 * <p> This method closes the underlying TCP connection. If the {@code 865 * WebSocket} is already closed then invoking this method has no effect. 866 * 867 * @throws IOException 868 * if an I/O error occurs 869 */ 870 void abort() throws IOException; 871 872 /** 873 * A {@code WebSocket} close status code. 874 * 875 * <p> Some codes <a href="https://tools.ietf.org/html/rfc6455#section-7.4"> 876 * specified</a> in the WebSocket Protocol are defined as named constants 877 * here. Others can be {@linkplain #of(int) retrieved on demand}. 878 * 879 * <p> This is a 880 * <a href="../../lang/doc-files/ValueBased.html">value-based</a> class; 881 * use of identity-sensitive operations (including reference equality 882 * ({@code ==}), identity hash code, or synchronization) on instances of 883 * {@code CloseCode} may have unpredictable results and should be avoided. 884 * 885 * @since 9 886 */ 887 final class CloseCode { 888 889 /** 890 * Indicates a normal close, meaning that the purpose for which the 891 * connection was established has been fulfilled. 892 * 893 * <p> Numerical representation: {@code 1000} 894 */ 895 public static final CloseCode NORMAL_CLOSURE 896 = new CloseCode(1000, "NORMAL_CLOSURE"); 897 898 /** 899 * Indicates that an endpoint is "going away", such as a server going 900 * down or a browser having navigated away from a page. 901 * 902 * <p> Numerical representation: {@code 1001} 903 */ 904 public static final CloseCode GOING_AWAY 905 = new CloseCode(1001, "GOING_AWAY"); 906 907 /** 908 * Indicates that an endpoint is terminating the connection due to a 909 * protocol error. 910 * 911 * <p> Numerical representation: {@code 1002} 912 */ 913 public static final CloseCode PROTOCOL_ERROR 914 = new CloseCode(1002, "PROTOCOL_ERROR"); 915 916 /** 917 * Indicates that an endpoint is terminating the connection because it 918 * has received a type of data it cannot accept (e.g., an endpoint that 919 * understands only text data MAY send this if it receives a binary 920 * message). 921 * 922 * <p> Numerical representation: {@code 1003} 923 */ 924 public static final CloseCode CANNOT_ACCEPT 925 = new CloseCode(1003, "CANNOT_ACCEPT"); 926 927 /** 928 * Indicates that an endpoint is terminating the connection because it 929 * has received data within a message that was not consistent with the 930 * type of the message (e.g., non-UTF-8 [RFC3629] data within a text 931 * message). 932 * 933 * <p> Numerical representation: {@code 1007} 934 */ 935 public static final CloseCode NOT_CONSISTENT 936 = new CloseCode(1007, "NOT_CONSISTENT"); 937 938 /** 939 * Indicates that an endpoint is terminating the connection because it 940 * has received a message that violates its policy. This is a generic 941 * status code that can be returned when there is no other more suitable 942 * status code (e.g., {@link #CANNOT_ACCEPT} or {@link #TOO_BIG}) or if 943 * there is a need to hide specific details about the policy. 944 * 945 * <p> Numerical representation: {@code 1008} 946 */ 947 public static final CloseCode VIOLATED_POLICY 948 = new CloseCode(1008, "VIOLATED_POLICY"); 949 950 /** 951 * Indicates that an endpoint is terminating the connection because it 952 * has received a message that is too big for it to process. 953 * 954 * <p> Numerical representation: {@code 1009} 955 */ 956 public static final CloseCode TOO_BIG 957 = new CloseCode(1009, "TOO_BIG"); 958 959 /** 960 * Indicates that an endpoint is terminating the connection because it 961 * encountered an unexpected condition that prevented it from fulfilling 962 * the request. 963 * 964 * <p> Numerical representation: {@code 1011} 965 */ 966 public static final CloseCode UNEXPECTED_CONDITION 967 = new CloseCode(1011, "UNEXPECTED_CONDITION"); 968 969 private static final Map<Integer, CloseCode> cached = Map.ofEntries( 970 entry(NORMAL_CLOSURE), 971 entry(GOING_AWAY), 972 entry(PROTOCOL_ERROR), 973 entry(CANNOT_ACCEPT), 974 entry(NOT_CONSISTENT), 975 entry(VIOLATED_POLICY), 976 entry(TOO_BIG), 977 entry(UNEXPECTED_CONDITION) 978 ); 979 980 /** 981 * Returns a {@code CloseCode} from its numerical representation. 982 * 983 * <p> The given {@code code} should be in the range {@code 1000 <= code 984 * <= 4999}, and should not be equal to any of the following codes: 985 * {@code 1004}, {@code 1005}, {@code 1006} and {@code 1015}. 986 * 987 * @param code 988 * numerical representation 989 * 990 * @return a close code corresponding to the provided numerical value 991 * 992 * @throws IllegalArgumentException 993 * if {@code code} violates any of the requirements above 994 */ 995 public static CloseCode of(int code) { 996 if (code < 1000 || code > 4999) { 997 throw new IllegalArgumentException("Out of range: " + code); 998 } 999 if (code == 1004 || code == 1005 || code == 1006 || code == 1015) { 1000 throw new IllegalArgumentException("Reserved: " + code); 1001 } 1002 CloseCode closeCode = cached.get(code); 1003 return closeCode != null ? closeCode : new CloseCode(code, ""); 1004 } 1005 1006 private final int code; 1007 private final String description; 1008 1009 private CloseCode(int code, String description) { 1010 assert description != null; 1011 this.code = code; 1012 this.description = description; 1013 } 1014 1015 /** 1016 * Returns a numerical representation of this close code. 1017 * 1018 * @return a numerical representation 1019 */ 1020 public int getCode() { 1021 return code; 1022 } 1023 1024 /** 1025 * Compares this close code to the specified object. 1026 * 1027 * @param o 1028 * the object to compare this {@code CloseCode} against 1029 * 1030 * @return {@code true} iff the argument is a close code with the same 1031 * {@linkplain #getCode() numerical representation} as this one 1032 */ 1033 @Override 1034 public boolean equals(Object o) { 1035 if (this == o) { 1036 return true; 1037 } 1038 if (!(o instanceof CloseCode)) { 1039 return false; 1040 } 1041 CloseCode that = (CloseCode) o; 1042 return code == that.code; 1043 } 1044 1045 @Override 1046 public int hashCode() { 1047 return code; 1048 } 1049 1050 /** 1051 * Returns a human-readable representation of this close code. 1052 * 1053 * @apiNote The representation is not designed to be parsed; the format 1054 * may change unexpectedly. 1055 * 1056 * @return a string representation 1057 */ 1058 @Override 1059 public String toString() { 1060 return code + (description.isEmpty() ? "" : (": " + description)); 1061 } 1062 1063 private static Map.Entry<Integer, CloseCode> entry(CloseCode cc) { 1064 return Map.entry(cc.getCode(), cc); 1065 } 1066 } 1067 }