I'm new user of envoy proxy, maybe someone can help me
I have 2 upstream hosts (UH1 and UH2), and configured envoy proxy to proxy (round robin) websocket connections from a client (frontend) to them.
Let's say UH1 has an active websocket connection (WC1) and UH1 becomes down (closes all its connections) I would like to keep the connection WC1 alive with a client and move the connection to UH2. Could anyone say if it is possible?
Thank you in advance!
I asked this question in the official google group of envoy-dev team and got an answer from Stephan:
This isn’t currently supported.
My sense is that one might be able to write an HTTP filter that takes
the place of the router filter to support this behavior in conjunction
with upgrade configs[1], but it’s probably a lot of work. That filter
would probably need to buffer the original HTTP request to be able
form a new websocket to a different upstream, and it would need to
decode websocket frames to avoid forwarding partial frames. Further if
the messages on the websocket are request/response oriented the filter
would have buffer websocket frames and have knowledge of their content
to avoid dropping requests.
In my experience, optimizing reconnect from the client and just
forming a new websocket connection is simpler to implement and also
provides benefits when the connection between the client and Envoy is
severed.
Stephan
https://groups.google.com/g/envoy-dev/c/3yCTqLx5ePE
Related
I have a process that runs in California that wants to talk to a process in New York, using Stomp over Websockets.
Also note that my process is not a web app, but I implemented a stomp over websocket client in C++, in order to connect things up to my backend. Maybe this was or wasn't a good idea. So, I want my client to talk to the server and subscribe, where their client pushed messages.
I was implementing my own server when I saw that ApacheMQ supported Stomp over Websockets. So, I started reading the docs.
It says with the last line under 'configuration' at
http://activemq.apache.org/websockets :
One thing worth noting is that web sockets (just as Ajax) implements ? > the same origin policy, so you can access only brokers running on the > same host as the web application running the client.
it says it again in several related searches such as http://sensatic.net/activemq/activemq-54-stomp-over-web-sockets.html
Is this a limitation of the server or the web client?
With that limitation, if I understand right, the server is not going to accept websocket connections from a client, of any kind, that is not on the same machine?
I am not sure I see the point of that...
If that is indeed its meaning, then how do I get around it in order to implement my scenario?
I've not found that bit of documentation you are referring to but from what I know of the STOMP implementation on the broker this seems incorrect. There shouldn't be any limit to the transport connector accepting connect requests from an outside host by default and I don't think the browser treats the websocket requests the same as it does other things like an Ajax case in terms of the same origin policy.
This probably a case that is best checked by actually trying it to see if it works, I've connected just fine from outside the same host using AMQP over websockets on ActiveMQ so I'd guess the STOMP stack should also work fine.
The point of my question is about "TCP connections flow" between my application server and Google Firebase Cloud Messaging (FCM) server.
I plan that my application disconnect a TCP connection every time for each
HTTP request
and response. (This behavior is like HTTP/1.0).
However, I can't find related mentions about it on FCM's web pages.
(FCM web page (relating legacy HTTP Protocol) has a illustration about communication flow, but I want one about HTTP Protocol).
This is outside of the scope of FCM specifications, for an example,
Apple Notification Service (APNs) specification request that a tcp
connection
must not disconnect while the connection is fine. (If I eagerly want to disconnect, I have been requested once a day by ANPs specification).
Can I disconnect the connection for every HTTP communication with FCM ?
I am worried about that FCM will guess that this behavior is DDoS attack.
However, my application does not repeat connection fast like DDoS attack.
Please excuse my poor English.
Best regards,
The Firebase Cloud Messaging legacy HTTP API is a connectionless protocol. You can either establish a new connection for each request, or reuse an existing connection, as you see fit.
That said, I'd recommend re-using the connection where possible, especially if you expect a high number of requests. This both optimizes throughput, and prevents current or future misclassification as malware.
I have an API running on a server, which handle users connection and a messaging system.
Beside that, I launched a websocket on that same server, waiting for connections and stuff.
And let's say we can get access to this by an Android app.
I'm having troubles to figure out what I should do now, here are my thoughts:
1 - When a user connect to the app, the API connect to the websocket. We allow the Android app only to listen on this socket to get new messages. When the user want to answer, the Android app send a message to the API. The API writes itself the received message to the socket, which will be read back by the Android app used by another user.
This way, the API can store the message in database before writing it in the socket.
2- The API does not connect to the websocket in any way. The Android app listen and write to the websocket when needed, and should, when writing to the websocket, also send a request to the API so it can store the message in DB.
May be none of the above is correct, please let me know
EDIT
I already understood why I should use a websocket, seems like it's the best way to have this "real time" system (when getting a new message for example) instead of forcing the client to make an HTTP request every x seconds to check if there are new messages.
What I still don't understand, is how it is suppose to communicate with my database. Sorry if my example is not clear, but I'll try to keep going with it :
My messaging system need to store all messages in my API database, to have some kind of historic of the conversation.
But it seems like a websocket must be running separately from the API, I mean it's another program right? Because it's not for HTTP requests
So should the API also listen to this websocket to catch new messages and store them?
You really have not described what the requirements are for your application so it's hard for us to directly advise what your app should do. You really shouldn't start out your analysis by saying that you have a webSocket and you're trying to figure out what to do with it. Instead, lay out the requirements of your app and figure out what technology will best meet those requirements.
Since your requirements are not clear, I'll talk about what a webSocket is best used for and what more traditional http requests are best used for.
Here are some characteristics of a webSocket:
It's designed to be continuously connected over some longer duration of time (much longer than the duration of one exchange between client and server).
The connection is typically made from a client to a server.
Once the connection is established, then data can be sent in either direction from client to server or from server to client at any time. This is a huge difference from a typical http request where data can only be requested by the client - with an http request the server can not initiate the sending of data to the client.
A webSocket is not a request/response architecture by default. In fact to make it work like request/response requires building a layer on top of the webSocket protocol so you can tell which response goes with which request. http is natively request/response.
Because a webSocket is designed to be continuously connected (or at least connected for some duration of time), it works very well (and with lower overhead) for situations where there is frequent communication between the two endpoints. The connection is already established and data can just be sent without any connection establishment overhead. In addition, the overhead per message is typically smaller with a webSocket than with http.
So, here are a couple typical reasons why you might choose one over the other.
If you need to be able to send data from server to client without having the client regular poll for new data, then a webSocket is very well designed for that and http cannot do that.
If you are frequently sending lots of small bits of data (for example, a temperature probe sending the current temperature every 10 seconds), then a webSocket will incur less network and server overhead than initiating a new http request for every new piece of data.
If you don't have either of the above situations, then you may not have any real need for a webSocket and an http request/response model may just be simpler.
If you really need request/response where a specific response is tied to a specific request, then that is built into http and is not a built-in feature of webSockets.
You may also find these other posts useful:
What are the pitfalls of using Websockets in place of RESTful HTTP?
What's the difference between WebSocket and plain socket communication?
Push notification | is websocket mandatory?
How does WebSockets server architecture work?
Response to Your Edit
But it seems like a websocket must be running separately from the API,
I mean it's another program right? Because it's not for HTTP requests
The same process that supports your API can also be serving the webSocket connections. Thus, when you get incoming data on the webSocket, you can just write it directly to the database the same way the API would access the database. So, NO the webSocket server does not have to be a separate program or process.
So should the API also listen to this websocket to catch new messages
and store them?
No, I don't think so. Only one process can be listening to a set of incoming webSocket connections.
I am trying to tunnel websockets over TCP. I know how to tunnel HTTPS - "Connect URL:port" is where I start. From there, one opens a socket to the target and then just pipe between the client and the target. Where do I start with websockets? is there something similar to a "Connect url:port" to begin with, which I can catch in my http server and then do some upgrade processing?
You sure you want to tunnel WebSocket over TCP? WebSocket runs over TCP.
I think you mean you want to tunnel TCP traffic with WebSocket, i.e., take an existing, traditional Socket-based application and make it work over the web. If that's what you mean, you essentially put your TCP data in a WebSocket frame and on the receiving end you read the WebSocket frame and extract the data. Of course this is easier said than done. You have to make sure you create the WebSocket frame correctly on the sender side (also handling the TCP data stream, which also may be tricky), encrypt the data (its going over the web, right?) and on the receiving side read the WebSocket frame, extract the data from the right parts of the frame. And also you need to check to see if all the data is in one WebSocket frame or multiple frames.
As I said, its not dead simple.
There are several WebSocket libraries out there that may (or may) not handle all of this for you (many do not handle the multiple WebSocket frame situation).
Websocket example in netty (examples) has a http request handler which:
performs hand shaking (at first)
(then) handles different types of WebSocket frames, eventually "TextWebSocketFrame"s.
There is only one url for websocket connections in this example.
The problem is, when TextWebSocketFrame based actual websocket communication starts, there is no direct way to determine websocket url from TextWebSocketFrames themselves (correct me if I am wrong).
So, how to handle different (url) websocket connections in netty?
One solution can be registering channels and their "websocket connection urls" during handshaking process.
The other is having only one websocket connection url and resolving different contexts by adding extra information to websocket messages (TextWebSocketFrames).
I don't find these solutions elegant, so any ideas?
It is my understanding that when you perform a web socket handshake, it is to a specific URL. That is specified in the web socket standard. See RFC 6455. Hence, there is no URL information in the TextWebSocketFrame because the assumption is that the frame will be sent to the URL to which the socket is bound.
To handle different URLs, you will have to either:
Setup a different pipeline and bind to a different IP and/or port for each URL, or
Like you stated, customise the hand shake and store the URL with the channel.
Personally, I've just used JSON in a TextWebSocketFrame. In my JSON, I have a field that states the intended action. This field is used for routing to the appropriate message handler.
I think it comes down to a design decision. WebSockets are intended for long lived connections where a request message can have 0, 1 or > 1 responses. This contrasts the REST style 1 request and 1 responses model.
Hope this helps.
The question "how to handle different (url) websocket connections in netty" does not make sense, I presume that the author meant to ask "how to serve multiple different websocket paths on a single port:host".
The question is valid because the HTTP protocol, (at least version 1.1,) WebSockets, and web browsers all support this scenario:
Client connects to server and the two start exchanging HTTP request/response pairs.
Client sends the HTTP request to upgrade to WebSocket, server honors it, and now a WebSocket is established between client and server.
The original HTTP connection remains open, so client and server can continue exchanging HTTP request/response pairs in parallel to the WebSocket. (In light of this, the term "upgrade" is a misnomer, because the connection is not upgraded at all; instead, a new connection is established for the WebSocket.)
Since the HTTP connection is still available, the client can send another HTTP upgrade request, thus creating another WebSocket. On the client side, it would look like this:
socket1 = new WebSocket( "https://acme.com:8443/alpha" );
socket2 = new WebSocket( "https://acme.com:8443/bravo" );
However, you can't have that, because Netty in all its magnificent glory and terrifying complexity does not exactly support that, and this is true even now, 10 years after the question was asked.
That's because:
Only one ServerBootstrap can bind to a given port on a given host.
(That's how the socket layer works.)
A ServerBootstrap can only have one "Child Handler".
(ServerBootstrap.childHandler() silently fails to report an error if you invoke it twice, but only the last invocation takes effect.)
A ChannelPipeline can only have one WebSocketServerProtocolHandler.
(Only the first WebSocketServerProtocolHandler that you add works, and Netty silently fails to issue an error if you add more.)
A WebSocketServerProtocolHandler accepts one and only one webSocketPath.
So, there you have it, a port:host can only have one webSocketPath, and that's a Netty limitation.
It might be possible to overcome this limitation by rewriting WebSocketServerProtocolHandler, but #aintNoBodyGotNoTimeFoDat.
Luckily, Netty does support another feature which makes it possible to achieve a similar thing. The constructor of WebSocketServerProtocolHandler supports a poorly documented and poorly named checkStartsWith parameter which, if set to true, will cause the handler to honor websocket negotiation requests not only on the given webSocketPath but also for any webSocket path that starts with the given webSocketpath and continues with a '?' or a '/' followed by other stuff. So, the code on the client would then look like this:
socket1 = new WebSocket( "https://acme.com:8443/allWebSocketsHere/alpha" );
socket2 = new WebSocket( "https://acme.com:8443/allWebSocketsHere/bravo" );
If you decide to build your netty server to handle this, the next problem you will face is how to obtain the "/allWebSocketsHere/alpha" and "allWebSocketsHere/bravo" parts. Luckily, someone else has already figured that out, see "Netty: How to use query string with websocket?" https://stackoverflow.com/a/47897963/773113