corgrath
corgrath

Reputation: 12295

Is there a way to make Dart server websocket implementation compatible with Phantom 1.9.7 headless browser (another websocket standard that is)?

According to the WebSocketTransformer docs, it says it tries to upgrade HttpRequests according to the RFC6455 web socket standard:

This transformer strives to implement web sockets as specified by RFC6455.

And provides this Dart example code:

HttpServer server;
server.listen((request) {
  if (...) {
    WebSocketTransformer.upgrade(request).then((websocket) {
      ...
    });
  } else {
    // Do normal HTTP request processing.
  }
});

Now if you search through PhantomJS' issue tracker you can find issue:

11018 Update to final websocket standard

Which basically says that the latest PhantomJS (1.9.7) uses an old web socket standard (I still haven't figured out what version sends out the Sec-WebSocket-Key1 information, but I assume its not the RFC6455 version).

So basically, my problem is that when I run PhantomJS headless browser towards my site that uses Dart 1.3.3, websocket server implementation (basically some upgrade code as I pasted above), it says:

Headers from PhantomJS:

sec-websocket-key1: 327J w6iS/b!43 L2j5}2 2
connection: Upgrade
origin: http://mydomain.com
upgrade: WebSocket
sec-websocket-key2: 42 d 7 64 84622
host: mydomain.com

Dart:

WebSocketTransformer.isUpgradeRequest(request) = false

WebSocketException: Invalid WebSocket upgrade request

The upgrade of the request failed (I assume it because of the mis match of versions).

My question is, until Phantom JS gets updated with 2.0, is there a way I can fix my Dart back-end so it would handle PhantomJS websockets as well?

According to the docs of WebSocketTransformer, the upgrade function has two arguments, one HttpRequest mandatory, and a second optional argument:

static Future<WebSocket> upgrade(HttpRequest request, {Function protocolSelector(List<String> protocols)})

Could this maybe help me some how?

Upvotes: 2

Views: 772

Answers (3)

Matthias247
Matthias247

Reputation: 10426

The protocols won't help you. These allow to agree on a special protocol that is used after the handshake for communication. But you can't modify the handshake and the exchanged fields themselves.

What you could do is make a complete own websocket implementation (directly based on Dart HTTP and TCP) that matches the the old implementation that PhantomJS uses. But that won't work with newer clients. By that way you also might be able to make an implementation that supports several versions (by checking the headers when you receive the handshake HTTP request and depending on the handshake forward to another implementation.

You would have to do at least your own WebSocketTransformer implementation. For this you could start by copying Darts interface and implementation and modify it on all places you need (check Licenses). If the actual WebSocket behavior after the handshake is compatible in the two RFCs you could reuse Darts WebSocket class. If this is not the case (other framing, etc.) then you would also have to do your own WebSocket class.

Some pseudo code based on yours:

HttpServer server;
server.listen((request) {
  if (...) { // websocket condition
    if (request.headers.value("Sec-WebSocket-Key1") != null) {
      YourWebSocketTransformer.upgrade(request).then((websocket) {
        ... // websocket might need to be a different type than Dart's WebSocket
      });
    } 
    else {
      WebSocketTransformer.upgrade(request).then((websocket) {
        ...
      });
    }
  }
  else {
    // Do normal HTTP request processing.
  }
});

I don't know your application, but it's probably not worth the effort. Bringing the old websocket implementation into Dart is probably the same effort as bringing the official implementation to PhantomJS. Therefore I think fixing PhantomJS should be preferred.

Upvotes: 2

Vink
Vink

Reputation: 1277

Maybe it's possible to do that through inheritance. It's impossible in dart to avoid overriding. If you have the time and you really need this, you can re-implement some method to patch the websocket for PhatomJS

class MyWebSocket extends WebSocket {
    MyWebSocket(/* ... */) : super(/* ... */);

    methodYouNeedToOverride(/* ... */) {
        super.methodYouNeedToOverride(/* ... */)
        // Your patch
    }
}

This way will allow you to access to "protected" variable or method, may be useful for a patching

But be careful, WebSocket are just the visible part, all the implementation is in websocket_impl.dart

Upvotes: 0

ALW
ALW

Reputation: 1017

"No."

HttpRequest.headers is immutable, so you can't massage the request headers into a format that Dart is willing to accept. You can't do any Ruby-style monkey-patching, because Dart does not allow dynamic evaluation.

You can, should you choose a path of insanity, implement a compatible version of WebSockets by handling the raw HttpRequest yourself when you see a request coming in with the expected headers. I believe you can re-implement the WebSocket class if necessary. The source for the WebSocket is here.

Upvotes: 0

Related Questions