Embedded Jetty - use WebSocketUpgradeFilter together with AsyncProxyServlet - jetty

I've got a class that extends AsyncProxyServlet to do proxying with Jetty:
Server httpProxy = new Server();
ServletHolder servletHolder = new ServletHolder(TunnelProxyServlet.class);
HandlerCollection handlers = new HandlerCollection();
httpProxy.setHandler(handlers);
ServletContextHandler contextHandler = new ServletContextHandler(handlers, "/", ServletContextHandler.SESSIONS);
contextHandler.addServlet(servletHolder, "/*");
Now I'd like to add WebSocket support to this.
I tried this:
try {
WebSocketUpgradeFilter.configure(contextHandler);
NativeWebSocketServletContainerInitializer.configure(contextHandler, ((context, container) ->
{
container.addMapping("/*", (req, resp) -> new WebSocketProxy().getWebSocketConnectionListener());
}));
} catch (ServletException ex) {
Logger.getLogger(HttpProxy.class.getName()).log(Level.SEVERE, ex.getMessage());
}
But the code never reaches this point.
How can I do proxying with WebSockets?

WebSocket Proxy is a very large and complicated topic.
First, let me start by saying that WebSocket proxying is possible starting with Jetty 10.
The basic support for WebSocket proxy was added to Jetty 10 in https://github.com/eclipse/jetty.project/pull/3365
Sadly, Jetty 9 has no support for WebSocket Proxy.
Either built into Jetty itself, or with enough core features within Jetty's WebSocket layer to allow you to implement it yourself.
Next, Jetty's AsyncProxyServlet is not capable of handling upgraded connections (like WebSocket). That class can only handle HTTP requests (be it HTTP/1.0, HTTP/1.1, or HTTP/2. With HTTP/3 support in the near future).
Some advice, when you do WebSocket proxying, you'll need to decide how you do it.
Are you going to proxy the frames as-is? (easiest, and most recommended approach).
Are you going to want to read the frame content? (requires complicated extension manipulation, extension preservation, frame preservation, and the ability to read partial messages from the frame level, etc)
Are you going to want to read the whole message (1..n frames) content? (this quadruples your memory requirements for websocket as its : remote websocket client -> websocket proxy server -> your proxy interested in messages -> websocket proxy client -> websocket backend server)

Related

Is it possible to have Filters on a ConnectHandler?

I used the original jetty-proxy in Jetty 9, when the embedded start proxy server, after modifying the browser's proxy port, all access can be through the proxy server, I added my own filter in proxy server, add the way is:
ServletHandler handler = new ServletHandler();
FilterHolder fh = handler.addFilterWithMapping((Class<? extends Filter>) TLFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
context.addFilter(fh, "/*", EnumSet.of(DispatcherType.REQUEST));
But my filter can only filter HTTP requests, but I can't filter HTTPS .
The development maintainers at jetty gave the results:
It is possible to deliver a CONNECT request to a Servlet service method, but it is ultimately futile to do so because it is impossible to handle a CONNECT inside a servlet. You don't really have access to the raw IO streams, only the HTTP content of the request/response. You can almost make his work, but never efficiently (no async IO etc.) So ultimately you will end up falling back to Jetty APIs anyway.
Also, why not just build on the support already provided by Jetty:
http://download.eclipse.org/jetty/stable-9/xref/org/eclipse/jetty/proxy/ConnectHandler.html http://download.eclipse.org/jetty/stable-9/xref/org/eclipse/jetty/proxy/ProxyServlet.html

How to make Qt Websocket and QNetworkRequest (HTTP) to use the same connection?

Is it possible with Qt to upgrade a HTTP connection that handles the normal HTTP requests to a Websocket with the same connection?
I'm thinking about something like this with Poco libraries, but all done in Qt similar to QtWebApp.
The simple answer is no and that is mostly because of specifics of the server side. And Qt just follows the protocol available and exposed by the server (HTTP/WebSocket) as mostly the client-side development framework and AFAIK won't be able to do the kind of transformation you want of going from HTTP to Websocket that are two different protocols. But of course, theoretically that can be done as long as both protocols able to use IP port 80. But that implies new unique sever and new unique client implementations.
We use both WebSocket and REST in our app. And WebSocket is for triggering the client by the server to do something. Client gets the "poke" from the server and starts normal JSON HTTP-based exchange with the server.
Somewhat relative link: https://softwareengineering.stackexchange.com/questions/276253/mixing-rest-and-websocket-in-the-same-api

How to get a WebSocket server run on aws

I'm developing an iOS app that requires realtime dual-way server/client messaging.
I'm trying to use WebSocket++ to develop a WebSocket server app on an AWS EC2. Have to use C++ because that's the only language I know on the server side.
The problem is I'm a fresh guy on server side development. I have 2 very basic questions:
1, Do I need have to setup an HTTP server like apache/nginx in order to get websocket running?
That is, can websocket app live independently alone?
2, I have now setup an nginx server in case it is a must have, is there any resource that I can refer to to make nginx & websocket work together well?
No, you don't need a Web server, a (reverse) Web proxy or anything to have your C++ WebSocket server talk to WebSocket clients.
Nginx (as HAproxy) supports reverse proxying WebSocket. This can make sense in certain situations, like you want to terminate TLS at the proxy and forward plain WebSocket to your backend server, or you want to load-balance incoming WebSocket connections to multiple backend nodes. However, as said, this isn't required.
No you don't, websocket and socket for an HTTP server are two diffent things.
HTTP server is for the HTTP protocol while there is not protocol defined for websocket, you have to define it yourself typically by the mean of sending/receiving Json message (a stream of character which each side (the server and the client) knows how to read/write).
The goal of websocket is to offer to javascript through HTML5 an easy, light and quick way to communicate through a socket, without websocket you have to do that with web services and in that case you need a http server.
With websocket you can create an html file leveraging html tag and javascript, javascript use client side of websocket to communicate with a C++/websocket server program, and you do not need even a web server, in this scenario you have a "desktop web app" ! (here web term is only because you use html tags)
Same question, same answer, no again ;-)
Good luck, and welcome in the wonderful world of asio !

Jetty 9.0 embeded config with SPDY but without SSL/NPN

SSL/NPN will be handled via our loadbalancer (Haproxy), so I don't really need Jetty to do this for us.
But all the examples I can see on the web only show how to do this with SSL/NPN, not without.
Here's what I've attempted so far:
Server server = new Server();
HTTPConfiguration httpConfig = .... // set up some additional http config here
PushStrategey push = new ReferrerPushStrategy();
List<ConnectionFactory> factories = new ArrayList<>();
factories.add(new HTTPSPDYServerConnectionFactory(SPDY.V3, httpConfig, push));
factories.add(new HTTPSPDYServerConnectionFactory(SPDY.V2, httpConfig, push));
factories.add(new HTTPConnectionFactory(httpConfig));
ServerConnector connector = new ServerConnector(server, factories.toArray(new ConnectionFactory[factories.size()]));
connector.setPort(port);
server.addConnector(connector);
connector.start();
....
Unfortunately, it seems something is wrong, when I try to access the server via clients like curl or my browser they hang indefinitely. What am I doing wrong?
Thanks
When you configure a ServerConnector to speak clear-text SPDY, your clients must also speak clear-text SPDY.
If you use clients like curl or the browser, they don't speak clear-text SPDY. The clients will send a HTTP request which is not understood (the server expects SPDY), and that's why your connection "hangs".
Only Chromium/Chrome has a mode where you can make it speak clear-text SPDY, using the --use-spdy=no-ssl parameter as described here.
Therefore, if you're using clear-text SPDY there is no point in configuring multiple ServerConnectionFactory because there is no way to select one based on the protocol being negotiated, because there is no protocol negotiation.
The protocol negotiation only happens when using SSL+NPN.
Your code is basically correct (apart the unnecessary multiple ServerConnectionFactory) if you really want to setup a clear-text SPDY ServerConnector; this is an example of how the same is setup in the Jetty SPDY test suite.
Finally, see also the reference documentation about SPDY.

node.js webserver and C++ game server

This question may be too broad, but I think it's a decent question to ask, and I'm not sure how to handle it.
I'm currently hosting a website at example.com. I'm doing this using 100% node.js, at the moment. I'm also hosting a networked HTML5 game (at game.example.com) that uses socket.io, which is fantastic, but I have decided that I would rather handle the game server using C++ (or, potentially, Java) and am planning on translating the server logic from JavaScript.
My biggest problem at the moment is that I simply don't know how I would connect the WebSocket. I still plan on serving the full client (HTML and JavaScript) using node.js, but I would like the client to connect to the C++ server rather than the node.js server.
The way that I'm currently connecting to the server is simply using a socket gained from socket.io's io.connect();. I think this can remain, I just need to pass the socket on the server-side from node.js to my C++ program, and I have absolutely no idea how to do this.
Can anyone help me?
Assuming I understand you correctly, you want Node to handle regular HTTP requests, but you want to pass Websocket requests to your C++ server? Try using a proxy in Node for the upgrade requests:
var http = require('http'),
httpProxy = require('http-proxy');
//have your c++ server for websockets operating on port 1333
var proxy = new httpProxy.HttpProxy({
target: {
host: 'localhost',
port: 1333
}
});
var server = http.createServer(function (req, res) {
//handle normal requests in here
});
server.on('upgrade', function (req, socket, head) {
// Proxy websocket requests...
proxy.proxyWebSocketRequest(req, socket, head);
});
server.listen(80);
First, there's the option of connecting your clients directly to your C++ server. If your socket.io transport is websockets, for example, you can use http://libwebsockets.org (a C++ websockets library for the server-side).
Otherwise, you could let your clients connect the socket.io to your node.js server, and establish some simple communication between your C++ server and node.js server. Don't try to "handle off the socket.io to the C++ server": simply have the C++ server and the node.js server communicate between themselves, passing messages back and forth, about players' states: the C++ would handle the logic, and the node.js would do the actual sending and receiving. You can do that, for example, with a simple TCP socket.