4

I'm building a react application that uses atmosphere library to listen to a SpringBoot websocket, when the client tries to connect to the server, it throws an error in the console saying Some cookies are misusing the recommended “sameSite“ attribute. I added some attributes to the request object to fix the issue as recommended (SameSite cookies). but I'm still getting the same error.

ReactJS code:

import React from 'react';
import * as atmosphere from 'atmosphere.js';

//import $ from 'jquery';
var transport = 'websocket';
//var req = new atmosphere.AtmosphereRequest();

// We are now ready to cut the request
var request = {
    url:'http://localhost:8080/stream',
    contentType: "application/json",
    trackMessageLength: true,
    shared: true,
    enableXDR: true,
    headers: { 'Access-Control-Allow-Origin': '*',
                'sameSite': ' None; Secure'
    },
    //sameSite: 'None; Secure',
    rewriteURL:true,
    transport: transport,
    fallbackTransport: 'long-polling',
    onOpen: function(response:any) {
        console.log('Atmosphere connected using ' , response.transport);
        transport = response.transport;
    },
    onTransportFailure: function(errorMsg: Atmosphere.Response, request: Atmosphere.Request) {
        console.log('Atmosphere Chat. Default transport is WebSocket, fallback is ' ,request.fallbackTransport );
    },
    onMessage: function (response:Atmosphere.Response) {

        var message = response.responseBody;
        try {
            console.log('message: ', message);
        } catch (e) {
            console.log('This doesn\'t look like a valid JSON: ', message);
            return;
        }
    },
    onClose : function(response: Atmosphere.Response) {
        console.log("Close connection !!!");
    }
    
};

const socket = atmosphere;
// Connect to the server, hook up to the request handler.
console.log('socket : ', socket.subscribe);
socket.subscribe && socket.subscribe(request);

const AtmosphereWebSocket = () => {
    return ( <div> </div> );
}

export default AtmosphereWebSocket;

SpringBoot Code:

@Component
@CrossOrigin(origins = "http://localhost:3000")
@WebSocketHandlerService(path = "/stream", broadcaster = SimpleBroadcaster.class,
        atmosphereConfig = {"org.atmosphere.websocket.WebSocketProtocol=" +
                "org.atmosphere.websocket.protocol.StreamingHttpProtocol"})
public class WebSocketStream extends WebSocketStreamingHandlerAdapter {

    private final Logger logger = LoggerFactory.getLogger(WebSocketStream.class);

    public WebSocketStream() {
        System.out.println(" ** WebSocketStream ** ");
    }

    // A thread which sends a stream of data out of a websocket. Create when the class
    // is instantiated, inject the websocket when open.
    private class Stream extends Thread {
        protected WebSocket socket;
        protected final ObjectMapper mapper = new ObjectMapper();
        protected boolean stop = false;

        public Stream(WebSocket socket) {
            this.socket = socket;
        }

        public void run() {
            int count = 0;
            try {
                while (!stop) {
                    Map<String, Object> message = new HashMap<String, Object>();
                    message.put("time", new Date().toString());
                    message.put("count", count++);
                    String string = mapper.writeValueAsString(message);
                    socket.write(string);
                    System.out.println("tick: " + string);
                    Thread.sleep(1000);
                }
            } catch (Exception x) {
                // break.
            }
        }
    }

    int clients = 0;

    @Override
    public void onOpen(WebSocket webSocket) throws IOException {
        // Hook up the stream.
        final Stream stream = new Stream(webSocket);
        stream.start();
        logger.info(" on open was called !!!");
        webSocket.broadcast("client " + clients++ + " connected");
        webSocket.resource().addEventListener(new WebSocketEventListenerAdapter() {
            @Override
            public void onDisconnect(AtmosphereResourceEvent event) {
                if (event.isCancelled()) {
                    logger.info("Browser {} unexpectedly disconnected", event.getResource().uuid());
                } else if (event.isClosedByClient()) {
                    logger.info("Browser {} closed the connection", event.getResource().uuid());
                }
                stream.stop = true;
            }
        });
    }
}

Error Message:

Websocket failed on first connection attempt. Downgrading to long-        polling and resending 1.chunk.js:3632:18
Atmosphere Chat. Default transport is WebSocket, fallback is  long-polling atmosphere.tsx:27
The development server has disconnected.
Refresh the page if necessary. 1.chunk.js:7419:13
Sat Jul 11 2020 15:52:07 GMT-0500 (Central Daylight Time) Atmosphere: unload event 1.chunk.js:3632:18
[HMR] Waiting for update signal from WDS... log.js:24
Download the React DevTools for a better development experience: react-dom.development.js:24994
socket :  
function subscribe(url, callback, request)
atmosphere.tsx:47
Firefox can’t establish a connection to the server at ws://localhost:8080/stream?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=3.0.5-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&Content-Type=application/json&X-atmo-protocol=true&Access-Control-Allow-Origin=*&sameSite=%20None%3B%20Secure. atmosphere.js:1201
Websocket closed, reason: Connection was closed abnormally (that is, with no close frame being sent). - wasClean: false atmosphere.js:3302
Close connection !!! atmosphere.tsx:40
Websocket failed on first connection attempt. Downgrading to long-polling and resending atmosphere.js:3302
Atmosphere Chat. Default transport is WebSocket, fallback is  long-polling
Arar
  • 1,926
  • 5
  • 29
  • 47
  • Why are you trying to set the cookie inside of request? The cookie has to be originally set by the server (using Set-Cookie response header) together with all necessary attributes like SameSite, Secure, Expires, etc. – mangusta Jul 12 '20 at 12:28
  • The cookie will be attached to request by browser afterwards – mangusta Jul 12 '20 at 12:29
  • 1
    Also, "sameSite" is not a valid header key. The cookie is attached to request using `Cookie` header key, with value `cookie_key=cookie_value;SameSite=None;Secure` – mangusta Jul 12 '20 at 12:33
  • Thanks for your feedback, can you please point out where this `cookie_key=cookie_value;SameSite=None;Secure` needs to be set in the code above? – Arar Jul 12 '20 at 17:20
  • You're expecting cookies from server, so somewhere within your Spring Boot app. Another issue is how to actually get those cookies from the response and store it in browser. In case of AJAX request, it is better to refer to this question: https://stackoverflow.com/questions/12840410/how-to-get-a-cookie-from-an-ajax-response. But probably ReactJS or Atmosphere have their own ways of retrieving a cookie from response – mangusta Jul 13 '20 at 00:22

0 Answers0