[TYRUS-180] Impossible to override Origin header using the Java Client Created: 10/May/13  Updated: 04/Jun/13  Resolved: 04/Jun/13

Status: Resolved
Project: tyrus
Component/s: None
Affects Version/s: 1.0-rc3, 1.0
Fix Version/s: 1.1

Type: Bug Priority: Critical
Reporter: sebster Assignee: Pavel Bucek
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

I have the following code to connect to a WebSocket server:

		ClientManager client = ClientManager.createClient();
		TickerEndpoint endpoint = new TickerEndpoint();
		ClientEndpointConfig config = ClientEndpointConfig.Builder.create().configurator(new Configurator() {
			@Override
			public void beforeRequest(Map<String, List<String>> headers) {
				headers.put("Origin", Arrays.asList("http://websocket.mtgox.com"));
			}
		}).preferredSubprotocols(Arrays.asList("mtgox")).build();
		Session session = client.connectToServer(endpoint, config, URI.create("ws://websocket.mtgox.com/mtgox"));

However, the generated request does not honor the overriden Origin header and looks like this:

                GET /mtgox HTTP/1.1
                Connection: Upgrade
                Host: websocket.mtgox.com
                Origin: websocket.mtgox.com
                Sec-WebSocket-Key: 6omOcZl7/BelBTW0PIM8xQ==
                Sec-WebSocket-Protocol: mtgox
                Sec-WebSocket-Version: 13
                Upgrade: websocket

Unfortunately MtGox returns "400 Bad Request" if the Origin is not exactly "http://websocket.mtgox.com", which I'm setting in the custom Configurator.

The reason the bug occurs is as follows. The origin in the Handshake instance is initially set to the host by the following code:

    protected HandShake(WebSocketRequest webSocketRequest, boolean client) {
        /* irrelevant code removed */
        origin = appendPort(new StringBuilder(uri.getHost())).toString();
        /* irrelevant code removed */
    }

Later GrizzlyClientSocket calls the callback to the Configurator:

    private void prepareHandshake(HandShake handshake) {
        /* irrelevant code removed */
        configuration.getConfigurator().beforeRequest(handshake.getRequest().getHeaders());
    }

The getRequest method from Handshake initializes the request header map and sets the Origin header to the value of the origin field:

   /* Handshake17.getRequest(), super.getRequest calls Handshake06.getRequest() below */
   public WebSocketRequest getRequest() {
        WebSocketRequest request = super.getRequest();
        final String headerValue = request.getFirstHeaderValue(WebSocketEngine.SEC_WS_ORIGIN_HEADER);
        request.getHeaders().remove(WebSocketEngine.SEC_WS_ORIGIN_HEADER);
        request.putSingleHeader(WebSocketEngine.ORIGIN_HEADER, headerValue);
        return request;
    }

    /* Handshake06.getRequest() */
    public WebSocketRequest getRequest() {
        final WebSocketRequest webSocketRequest = super.getRequest();
        /* irrelevant code removed */
        webSocketRequest.putSingleHeader(WebSocketEngine.SEC_WS_ORIGIN_HEADER, getOrigin());
        /* irrelevant code removed */
        return webSocketRequest;
    }

Thus the configurator receives a map with a default Origin header value "websocket.mtgox.com", which is then overridden by the custom Configurator.

Finally, when the connection is made by the WebSocketFilter, the following code gets executed:

    public NextAction handleConnect(FilterChainContext ctx) throws IOException {
        /* irrelevant code removed */
        WebSocketRequest webSocketRequest = webSocketHolder.handshake.initiate();
        /* irrelevant code removed */
    }

Unfortunately, handshake.initiate() calls getRequest() again, which clobbers the customized header values:

    public WebSocketRequest initiate(/*FilterChainContext ctx*/) {
        return getRequest();
    }

Thus it is impossible to override the Origin header.


Generated at Sun Sep 25 05:53:42 UTC 2016 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.