Atmosphere / wasync

WebSockets with fallback transports client library for Node.js, Android and Java
http://async-io.org
161 stars 47 forks source link

Issue with QueryParams - string becomes too long after a number of reconnect attempts #157

Open Jpickles89 opened 6 years ago

Jpickles89 commented 6 years ago

I have some code I've created to create a client connection via wasync (2.1.5) to my deployed war instance of Atmosphere . When using websockets, as the number of reconnect attempts increases, my HTTP header continually increases in size, due to the connect string being appended to with the query parameters and then it won't connect because the HTTP header size is too large. I was able also to reproduce this via the wasync sample for wAsyncChat. It seems to be related to the requestBuilder.build() that is done on reconnect in WebSocketTransport.java: ListenableFuture webSocketListenableFuture = options.runtime().executeRequest(requestBuilder.build(), WebSocketTransport.this);

Here's how you can reproduce it: Using wAsyncChat via https://github.com/Atmosphere/atmosphere-samples/tree/master/wasync-samples/chat/src/main/java/org/atmosphere/wasync/samples, connect via websockets. If I drop the connection to the server by undeploying the war file and wait a few minutes, you can see upon each reconnect string the connect string increases in size by continually adding the query params.

First connection string: NettyConnectListener - Using non-cached Channel [id: 0xf6bba11d, /192.168.1.2:51336 => uri=ws://192.168.146.10:10005/atmoapp-1/webdatabus?X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=2.3.0&X-atmo-protocol=true&X-Atmosphere-tracking-id=0

After undeploying the war to simulate the connection dropping, the next connection string is: uri=ws://192.168.146.10:10005/atmoapp-1/webdatabus/chat?X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=2.3.0&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=2.3.0&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&X-Atmosphere-tracking-id=0

After a few more attempts: uri=ws://192.168.146.10:10005/atmoapp-1/webdatabus/chat?X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=2.3.0&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=2.3.0&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=2.3.0&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=2.3.0&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&X-Atmosphere-tracking-id=0&X-Atmosphere-Transport=websocket&X-Atmosphere-Framework=2.3.0&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&X-Atmosphere-tracking-id=0

This will keep repeating until I blow out the HTTP header.

DEBUG c.n.h.c.p.n.r.NettyRequestSender - HTTP header is larger than 8192 bytes. org.jboss.netty.handler.codec.frame.TooLongFrameException: HTTP header is larger than 8192bytes.``

Any ideas on how to resolve this?

Below is the exact code used when I attempt this.

`/*

import com.fasterxml.jackson.databind.ObjectMapper; import org.atmosphere.wasync.ClientFactory; import org.atmosphere.wasync.Decoder; import org.atmosphere.wasync.Encoder; import org.atmosphere.wasync.Event; import org.atmosphere.wasync.Function; import org.atmosphere.wasync.Request; import org.atmosphere.wasync.RequestBuilder; import org.atmosphere.wasync.Socket; import org.atmosphere.wasync.impl.AtmosphereClient;

import org.atmosphere.wasync.impl.DefaultOptionsBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Date;

public class wAsyncChat {

private final static Logger logger = LoggerFactory.getLogger(wAsyncChat.class);
private final static ObjectMapper mapper = new ObjectMapper();

public static void main(String[] args) throws IOException {

    if (args.length == 0) {
        args = new String[]{"http://192.168.1.10:xxx/atmosphere/databus"};
    }

    AtmosphereClient client = ClientFactory.getDefault().newClient(AtmosphereClient.class);

    RequestBuilder request = client.newRequestBuilder()
            .method(Request.METHOD.GET)
            .uri(args[0] + "/chat")
            .trackMessageLength(true)
            .encoder(new Encoder<Message, String>() {
                @Override
                public String encode(Message data) {
                    try {
                        return mapper.writeValueAsString(data);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            })
            .decoder(new Decoder<String, Message>() {
                @Override
                public Message decode(Event type, String data) {

                    data = data.trim();

                    // Padding
                    if (data.length() == 0) {
                        return null;
                    }

                    if (type.equals(Event.MESSAGE)) {
                        try {
                            return mapper.readValue(data, Message.class);
                        } catch (IOException e) {
                            logger.debug("Invalid message {}", data);
                            return null;
                        }
                    } else {
                        return null;
                    }
                }
            })
            .transport(Request.TRANSPORT.WEBSOCKET);

    DefaultOptionsBuilder optBuilder = client.newOptionsBuilder()
            .reconnect(true)
            .pauseBeforeReconnectInSeconds(4)
            .reconnectAttempts(1000);

    Socket socket = client.create(optBuilder.build());
    socket.on("message", new Function<Message>() {
        @Override
        public void on(Message t) {
            Date d = new Date(t.getTime());
            logger.info("Author {}: {}", t.getAuthor() + "@ " + d.getHours() + ":" + d.getMinutes(), t.getMessage());
        }
    }).on(new Function<Throwable>() {

        @Override
        public void on(Throwable t) {
            t.printStackTrace();
        }

    }).on(Event.CLOSE.name(), new Function<String>() {
        @Override
        public void on(String t) {
            logger.info("Connection closed");
        }
    }).on(Event.OPEN.name(), new Function<String>() {
        @Override
        public void on(String t) {
            logger.info("Connection opened");
        }
    })
            .open(request.build());

    logger.info("Choose Name: ");
    String name = null;
    String a = "";
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    while (!(a.equals("quit"))) {
        a = br.readLine();
        if (name == null) {
            name = a;
        }
        socket.fire(new Message(name, a));
    }
    socket.close();
}

}`

jfarcand commented 6 years ago

@Jpickles89 Apologies for the delay. Have you found a solution of the lib still need a fix?

Jpickles89 commented 6 years ago

Hi Jeanfrancois,

I still have this issue, but changed my retry timeout to workaround the issue for now. I would still love a fix, because setting a long retry timeout is not ideal. Thanks for the followup.

mephee commented 6 years ago

Hi @jfarcand

Same problem for me, are there any plans to solve this?

kind regards

jfarcand commented 6 years ago

@mephee Contribution welcomed! Once I have a patch I can release a new version pretty fast.