Preliminary RFR JDK-8159053: Improve onPing/onClose behavior

Pavel Rappo pavel.rappo at oracle.com
Wed Jun 22 12:39:22 UTC 2016


Hi,

Here's the updated wording. Could you please have a look at it once again so we
fully agree on it?

What has changed?

1. "WebSocket implementation"/"WebSocket connection" -> {@code WebSocket}
2. "Automatically" added to make it clear no user actions needed
3. Fixed typos mentioned by Chris.
4. Added "@see" cross-references between both versions of sendClose()

*. Please notice the difference between range of status codes accepted in
`sendClose` and passed to `onClose`.
So basically WebSocket will allow to receive status codes up to 65535
(inclusive), but will not allow to send them if they are greater than 4999.

The reason I'm proposing this is that (in contrast to [0, 999]) RFC 6455 does
not actually contain explicit prohibition for using codes from the range [5000, 65535]:

https://tools.ietf.org/html/rfc6455#section-7.4.2

Some might say it's an undefined behaviour. For example, Autobahn|Testsuite sees
it as such:

http://autobahn.ws/testsuite/reports_20131013/clients/ie11_preview_case_7_13_1.html
http://autobahn.ws/testsuite/reports_20131013/clients/ie11_preview_case_7_13_2.html

I think in this case it would be fine to rely on famous "Robustness principle"
an allow such an asymmetry:

    ...be conservative in what you do, be liberal in what you accept from others
    
And since RFC 6455 says WebSocket SHOULD echo back the received close code:

   If an endpoint receives a Close frame and did not previously send a
   Close frame, the endpoint MUST send a Close frame in response.  (When
   sending a Close frame in response, the endpoint typically echos the
   status code it received.)  It SHOULD do so as soon as practical.

WebSocket should normally send back the same code it received. Even if it's
outside the "normal range": [1000, 4999]

What would you say? Thanks.

--------------------------------------------------------------------------------

/**
 * Receives a Close message.
 *
 * <p> Once a Close message is received, the server will not send any
 * more messages.
 *
 * <p> When a Close message has been received, the WebSocket Protocol
 * mandates it is handled in a certain way.
 *
 * <p> After a Close message has been received, the {@code WebSocket}
 * will close automatically. However, the client may finish sending the
 * current sequence of message parts, if any. To facilitate this, the
 * {@code WebSocket} will only attempt to close at the earliest of,
 * either the completion of the returned {@code CompletionStage} or the
 * last part of the current message has been sent.
 *
 * <p> A Close message consists of a status code and a reason for
 * closing. The status code is an integer in the range {@code 1000 <=
 * code <= 65535}. The {@code reason} is a short string that has an
 * UTF-8 representation not longer than {@code 123} bytes. For more
 * details on Close message, status codes and reason see
 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">Close</a>
 * and
 * <a href="https://tools.ietf.org/html/rfc6455#section-7.4">Status Codes</a>.
 *
 * <p> {@code onClose} is the last invocation on the {@code Listener}.
 * It is invoked at most once, but after {@code onOpen}. If an exception
 * is thrown from this method, it is ignored.
 *
 * @implSpec The default implementation behaves as if:
 *
 * <pre>{@code
 *     return CompletableFuture.completedStage(null);
 * }</pre>
 *
 * @param webSocket
 *         the WebSocket
 * @param statusCode
 *         the status code
 * @param reason
 *         the reason
 *
 * @return a CompletionStage that when completed will trigger closing of
 * the WebSocket
 */
default CompletionStage<?> onClose(WebSocket webSocket,
                                   int statusCode,
                                   String reason) {
    return null;
}

/**
 * Sends a Close message with the given status code and the reason.
 *
 * <p> Returns a {@code CompletableFuture<WebSocket>} which completes
 * normally when the message has been sent or completes exceptionally if an
 * error occurs.
 *
 * <p> The {@code statusCode} is an integer in the range {@code 1000 <= code
 * <= 4999}, except for {@code 1004}, {@code 1005}, {@code 1006} and {@code
 * 1015} and some others that can be only set by the {@code WebSocket}.
 * The {@code reason} is a short string that must have an UTF-8
 * representation not longer than {@code 123} bytes. For more details on
 * Close message, status codes and reason see
 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">Close</a>
 * and
 * <a href="https://tools.ietf.org/html/rfc6455#section-7.4">Status Codes</a>.
 *
 * <p> If a Close message has been already sent or the {@code WebSocket} is
 * closed, then invoking this method has no effect and returned {@code
 * CompletableFuture} completes normally.
 *
 * <p> The returned {@code CompletableFuture} can complete exceptionally
 * with:
 * <ul>
 * <li> {@link IOException}
 *          if an I/O error occurs during this operation
 * </ul>
 *
 * @param statusCode
 *         the status code
 * @param reason
 *         the reason
 *
 * @return a CompletableFuture with this WebSocket
 *
 * @throws IllegalArgumentException
 *         if the {@code statusCode} has an illegal value, or
 *         {@code reason} doesn't have an UTF-8 representation not longer
 *         than {@code 123} bytes
 *
 * @see #sendClose()
 */
CompletableFuture<WebSocket> sendClose(int statusCode, String reason);

/**
 * Receives a Ping message.
 *
 * <p> A Ping message may be sent or received by either client or
 * server. It may serve either as a keepalive or as a means to verify
 * that the remote endpoint is still responsive.
 *
 * <p> When a Ping message has been received, the WebSocket Protocol
 * mandates it is handled in a certain way.
 *
 * <p> {@code WebSocket} handles a Ping message automatically using a
 * strategy of its choice, but within the boundaries of the WebSocket
 * Protocol. It may call this method to notify the {@code Listener}
 * after handling the Ping message or before doing so. In other words no
 * particular ordering is guaranteed. If an error occurs while
 * implementation handles this Ping message, then {@code onError} will
 * be invoked with this error. For more details on handling Ping
 * messages see
 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">Ping</a>
 * and
 * <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">Pong</a>.
 *
 * <p> The message will consist of not more than {@code 125} bytes:
 * {@code message.remaining() <= 125}.
 *
 * <p> The {@code onPing} is invoked zero or more times in between
 * {@code onOpen} and ({@code onClose} or {@code onError}).
 *
 * <p> If an exception is thrown from this method or the returned {@code
 * CompletionStage} completes exceptionally, then {@link
 * #onError(WebSocket, Throwable) onError} will be invoked with this
 * exception.
 *
 * @implSpec The default implementation behaves as if:
 *
 * <pre>{@code
 *     webSocket.request(1);
 *     return CompletableFuture.completedStage(null);
 * }</pre>
 *
 * @param webSocket
 *         the WebSocket
 * @param message
 *         the message
 *
 * @return a CompletionStage that completes when the message processing
 * is done; or {@code null} if already done
 */
default CompletionStage<?> onPing(WebSocket webSocket,
                                  ByteBuffer message) {
    webSocket.request(1);
    return null;
}





More information about the net-dev mailing list