Jetty 8.1.1 Websocket client handshake
I am using Jetty 8.1.1 Websocket client api.
I need to use ("Sec-WebSocket-Protocol", "xsCrossfire")
and update the title("Authorization", "Basic TLVWQMZqRr2hasYnZoI=")
WebSocketClientFactory factory = new WebSocketClientFactory();
factory.start();
client = factory.newWebSocketClient();
client.getCookies().put("Sec-WebSocket-Protocol", "xsCrossfire");
client.getCookies().put("Authorization", "Basic TLVWQMZqRr2hasYnZoI=");
Future<Connection> conn = client.open(uri, (WebSocket) this);
System.out.printf("Connecting to : %s%n", uri);
The requirement looks like:
Host: iltlvl262:8000\r\n
Upgrade: websocket\r\n
Connection: Upgrade\r\n
Sec-WebSocket-Version: 13\r\n
Sec-WebSocket-Key: FHKTsICO2vqGCxXVwLkH4Q==\r\n
Cookie: Sec-WebSocket-Protocol=xsCrossfire\r\n
Cookie: Authorization="Basic TLVWQMZqRr2hasYnZoI="\r\n
Expected requirements:
Host: iltlvl262:8000\r\n
Upgrade: websocket\r\n
Connection: Upgrade\r\n
Sec-WebSocket-Version: 13\r\n
Sec-WebSocket-Key: FHKTsICO2vqGCxXVwLkH4Q==\r\n
Sec-WebSocket-Protocol: xsCrossfire\r\n
Authorization: "Basic TLVWQMZqRr2hasYnZoI="\r\n
How to properly implement handshake in version 8.1.1?
Some good news and some bad news.
One, the good news:
To set Sec-WebSocket-Protocol
the title, use the following.
client.setProtocol("xsCrossfire");
before useclient.open()
Next, the bad news:
With Jetty 8.x, you cannot set arbitrary non-websocket headers. This is due to how early experimental drafts of WebSocket were written. You are simply not allowed to set arbitrary headers as per the earlier spec draft, so the Jetty 8.x-era implementation just doesn't allow it.
However, things changed with the finalization of RFC6455 (the official WebSocket specification) , all of which were incorporated into the Jetty 9.x codebase. 100% RFC6455 compliant . (Note: Jetty 8 is 100% RFC6455 compliant on the server side. Jetty8 is also 100% compliant on the RFC6455 protocol used by the server and client. However, functionally, Jetty 8 is only partially compliant on the client and API point of view. )
The decision for Jetty 7 and Jetty 8 is to keep old experimental drafts for those early adopters and older browsers (Safari 5.x) who are still using them. This decision prevents us from allowing behavior that was expressly prohibited in the old experimental draft.
Starting with Jetty 9.x, all old experimental drafts of websockets have been removed, leaving only support for RFC6455 , which allows Jetty to open up more features that were previously not allowed. This includes arbitrary headers on WebSocketClient.
Jetty 9.1 WebSocket Client Example
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.Future;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
public class ExampleClient
{
public static class ExampleSocket extends WebSocketAdapter
{
@Override
public void onWebSocketText(String message)
{
try
{
// echo the message
getRemote().sendString(message);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
try
{
new ExampleClient().demo();
}
catch (Throwable t)
{
t.printStackTrace(System.err);
}
}
public void demo() throws Exception
{
WebSocketClient client = new WebSocketClient();
try
{
client.start();
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setSubProtocols("xsCrossfire");
request.setHeader("Authorization","Basic TLVWQMZqRr2hasYnZoI=");
URI wsUri = URI.create("ws://iltlvl262:8000/echo");
ExampleSocket socket = new ExampleSocket();
Future<Session> future = client.connect(socket,wsUri,request);
future.get(); // wait for connect
socket.getRemote().sendString("hello"); // send message
}
finally
{
client.stop();
}
}
}
Also note that as of Jetty 9.1, the (JSR-356) API is even fully supported.javax.websocket
Same example using javax.websocket on Jetty 9.1
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.websocket.ClientEndpoint;
import javax.websocket.ContainerProvider;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
public class ExampleClient
{
@ClientEndpoint(subprotocols = { "xsCrossfire" },
configurator = ExampleClient.Configurator.class)
public static class ExampleSocket
{
@OnMessage
public String onMessage(String msg)
{
return msg; // echo
}
}
public static class Configurator
extends javax.websocket.ClientEndpointConfig.Configurator
{
@Override
public void beforeRequest(Map<String, List<String>> headers)
{
List<String> authvalues = new ArrayList<>();
authvalues.add("Basic TLVWQMZqRr2hasYnZoI=");
headers.put("Authorization", authvalues);
super.beforeRequest(headers);
}
}
public static void main(String[] args)
{
try
{
new ExampleClient().demo();
}
catch (Throwable t)
{
t.printStackTrace(System.err);
}
}
public void demo() throws Exception
{
WebSocketContainer client = ContainerProvider.getWebSocketContainer();
ExampleSocket socket = new ExampleSocket();
URI wsUri = URI.create("ws://iltlvl262:8000/echo");
Session session = client.connectToServer(socket,wsUri);
session.getAsyncRemote().sendText("Hello");
}
}