tyrus
  1. tyrus
  2. TYRUS-180

Impossible to override Origin header using the Java Client

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: 1.0-rc3, 1.0
    • Fix Version/s: 1.1
    • Component/s: None
    • Labels:
      None

      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.

        Activity

        There are no comments yet on this issue.

          People

          • Assignee:
            Pavel Bucek
            Reporter:
            sebster
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: