Disable client extension if server does not accept extensions - websocket

I have a WebSocket client that uses the netty WebSocketClientCompressionHandler to support compression extension. For this extension to work properly I need to set the allowExtensions value to true when creating a newHandshaker using the WebSocketClientHandshakerFactory.
At times when the server does not support these extensions it responds without a Sec-WebSocket-Extensions. If that is the case if reserved (RSV) bits are used, the client should terminate the connection immediately.
Since I am creating the WebSocketClientHandshaker before I could get any response from the server I am unable to set the value of allowExtensions to false afterwards when I come to know that the server does not support extensions.
Is it in anyway possible to set the value of allowExtensions to false after I receive the response from server (or inform netty) so that netty will close the connection if RSV bit is set due to protocol violation?
(For the server implementation I do check the client request headers for Sec-WebSocket-Extensions before creating the handshaker which is fine.)

The only solution I had was to replace the WebSocketFrameDecoder after finishing the handshake and set the allowExtensions value to false if the handshake response does not have the extension header:
handshaker.finishHandshake(ctx.channel(), handshakeResponse);
Channel channel = ctx.channel();
String extensionsHeader = handshakeResponse.headers().getAsString(HttpHeaderNames.SEC_WEBSOCKET_EXTENSIONS);
if (extensionsHeader == null) {
// This replaces the frame decoder to make sure the rsv bits are not allowed
channel.pipeline().replace(WebSocketFrameDecoder.class, "ws-decoder",
new WebSocket13FrameDecoder(false, false, handshaker.maxFramePayloadLength(),
false));
}

Related

lighttpd/mod_wstunnel concatenates JSON messages

I'm trying to use lighttpd (v1.4.49) with mod_wstunnel.
$HTTP["url"] =~ "^/websocket" {
wstunnel.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "50007" ) ) )
wstunnel.frame-type = "text"
wstunnel.ping-interval = 30
}
The backend TCP-Server sends single line JSON-Messages that should be received by the WebSocket-Clients onmessage handler.
However, sometimes two successive messages are concatenated by mod_wstunnel and received (and passed to onmessage) as one message.
Is there any "end-of-message" token I could send to explicitly "tell" mod_wstunnel that the message is complete?
Thanks,
Sam
You should probably fix your application if your application depends on framing at the websockets layer. See https://www.rfc-editor.org/rfc/rfc6455#section-5.4
Unless specified otherwise by an extension, frames have no semantic
meaning. An intermediary might coalesce and/or split frames, if no
extensions were negotiated by the client and the server or if some
extensions were negotiated, but the intermediary understood all the
extensions negotiated and knows how to coalesce and/or split frames
in the presence of these extensions. One implication of this is that
in absence of extensions, senders and receivers must not depend on
the presence of specific frame boundaries.
Your backend is sending JSON and knows nothing about websockets, and therefore can not specify how mod_wstunnel should send websocket frames. Your client app should not depend on the websocket framing, but if you wanted to try to mitigate this on the server-side, your backend could pause between sending each JSON message. It would be better to fix your app to process complete JSON messages, one at a time.

Handling an MSXML timeout [duplicate]

This question already has answers here:
VBScript -- Using error handling
(5 answers)
Closed 3 years ago.
One of our websites has a glitch which occasionally takes it down - the back end needs to be restarted. The replacement is not yet ready for production, so I've created a VBS script which polls the server and restarts the server if:
a) The HTTP status code <> 200, or
b) The page loads but a substring is not found on the page.
The HTTP status check times out if the tomcat service fails to respond; I would like to call a function if that occurs. Is it possible to capture and handle a timeout? This is a snippet of my relevant code pieces.
xmlhttp.setOption 2, 13056
xmlhttp.open "get", "https://www.mywebsite.com/thisurl", false
xmlhttp.send
if xmlhttp.status <> 200 then
call restartTomcat()
call emailAlert()
end if
Thank you in advance.
Unfortunately you can't create object event handlers in VBScript.
Perhaps you can use the .setTimeouts resolveTimeout, connectTimeout, sendTimeout, receiveTimeout method of the HTTP Request object. Add this before your call to the send method. Here's the description of the parameters:
resolveTimeout
A long integer. The value is applied to mapping host names (such as "www.microsoft.com") to IP addresses; the default value is infinite, meaning no timeout.
connectTimeout
A long integer. The value is applied to establishing a communication socket with the target server, with a default timeout value of 60 seconds.
sendTimeout
A long integer. The value applies to sending an individual packet of request data (if any) on the communication socket to the target server. A large request sent to a server will normally be broken up into multiple packets; the send timeout applies to sending each packet individually. The default value is 30 seconds.
receiveTimeout
A long integer. The value applies to receiving a packet of response data from the target server. Large responses will be broken up into multiple packets; the receive timeout applies to fetching each packet of data off the socket. The default value is 30 seconds.
You can check the Status as you are currently doing after the send call. This should help you handle an unresponsive server.

Is there any way to run Tungstenite on the same port as hyper?

I'm trying to make a web server in Rust for a simple browser game. I want the server to be able to deliver pages through HTTPS, but also be able to communicate through WebSockets. I'm planning to put this server on Heroku, but since they only allow one port per application I have to make the WebSocket server operate on the same port as the other HTTPS code.
It seems like this is possible with crates like rust-websocket, but that crate uses an outdated version of hyper and seems to be no longer maintained. The crate tokio_tungstenite is much more up to date.
The problem is that both hyper and tungstenite have their own implementation of the HTTP protocol that WebSockets operate over with no way to convert between the two. This means that once an HTTPS request has been parsed by either hyper or tungstenite there is no way to continue the processing by the other part, so you can't really try to connect the WebSocket and match on an error in tungstenite and process it by hyper, nor can you parse the request by hyper and check if it's a WebSocket request and send it over to tungstenite. Is there any way to resolve this problem?
I think it should be possible to do that, the tungstenite and tokio-tungstenite allow you to specify custom headers (there are helpers functions for that, prefixed with hdr), so depending on the hyper version you use, if you can convert a request to some form, when the headers can be extracted, you can pass them to tungstenite.
You might also want to try warp crate, it's built on top of hyper and it uses tungstenite under the hood for the websocket support, so if you want to write your own version of warp, you can take a look at the source code (the source code may contain hints on how to use hyper and tungstenite together).
You can do it, but it's quite fiddly. You'll have to use tokio-tungstenite, do the handshake yourself (check header, set response headers) and spawn a new future on the runtime that will handle the websockets connection. The new future can be created by calling on_upgrade() on the request body with the latest version of hyper, and the connection can then be passed to tokio_tungstenite::WebSocketStream::from_raw_socket to turn it into a websockets connection.
Example handler (note that this doesn't fully check the request headers and assumes we want an upgrade):
fn websocket(req: Request<Body>) -> Result<Response<Body>, &'static str> {
// TODO check other header
let key = match req.headers().typed_get::<headers::SecWebsocketKey>() {
Some(key) => key,
None => return Err("failed to read ws key from headers"),
};
let websocket_future = req
.into_body()
.on_upgrade()
.map_err(|err| eprintln!("Error on upgrade: {}", err))
.and_then(|upgraded| {
let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket(
upgraded,
tokio_tungstenite::tungstenite::protocol::Role::Server,
None,
);
let (sink, stream) = ws_stream.split();
sink.send_all(stream)
.map(|_| ())
.map_err(|err| error!("{}", err))
});
hyper::rt::spawn(websocket_future);
let mut upgrade_rsp = Response::builder()
.status(StatusCode::SWITCHING_PROTOCOLS)
.body(Body::empty())
.unwrap();
upgrade_rsp
.headers_mut()
.typed_insert(headers::Upgrade::websocket());
upgrade_rsp
.headers_mut()
.typed_insert(headers::Connection::upgrade());
upgrade_rsp
.headers_mut()
.typed_insert(headers::SecWebsocketAccept::from(key));
Ok(upgrade_rsp)
}

Does WP background transfers support re-uploading and how it actually works?

I'm trying to implement http handler for handling file upload by wp background transfers. I've tried this:
var request = new BackgroundTransferRequest(#"http://computerName/test.ashx")
{
Method = "POST",
TransferPreferences = TransferPreferences.None,
UploadLocation = new Uri(#"shared/transfers/testfile.txt", UriKind.RelativeOrAbsolute)
};
In this case my phone always sends Range:0- . ContentLength equals actual source file size. And request stream contains all data... I did not know how to make it sending data partially.
And, I can not find any actual info about how uploading works, what headers it uses and so on. There is no any specification for server!
Sadly, BackgroundTransferRequests do not support range for upload or download. If you don't need to allow transfers when your app is not running, I would suggest writing your own transfer code. Then you can support RANGE and you can control the number of concurrent transfers(and you can get around the 2 transfer limit for the phone) and you don't have to deal with the various file size/network type limitations.
Below is the documentation explaining this from the following link:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202955%28v=vs.105%29.aspx#BKMK_BackgroundTransferPolicies
The Headers property of the BackgroundTransferRequest object is used to set the HTTP headers for a transfer request. The following headers are reserved for use by the system and cannot be used by calling applications. Adding one of the following headers to the Headers collection will cause a NotSupportedException to be thrown when the Add(BackgroundTransferRequest) method is used to queue the transfer request:
•
If-Modified-Since
•
If-None-Match
•
If-Range
•
Range
•
Unless-Modified-Since

Netty https ( TLS ) Session duration: why is renegotiation needed?

I have a 100% https web server that does TLS renegotiation. This is very useful so that users can come to the site and get some nice pages before clicking the login button and being asked for their client certificate. Below is the part of the code that does renegotiation line 213-236 of X509Cert class
import org.jboss.netty.handler.ssl.SslHandler
val sslh = r.underlying.context.getPipeline.get(classOf[SslHandler])
trySome(sslh.getEngine.getSession.getPeerCertificates.toIndexedSeq) orElse {
if (!fetch) None
else {
sslh.setEnableRenegotiation(true) // todo: does this have to be done on every request?
r match {
case UserAgent(agent) if needAuth(agent) => sslh.getEngine.setNeedClientAuth(true)
case _ => sslh.getEngine.setWantClientAuth(true)
}
val future = sslh.handshake()
future.await(30000) //that's certainly way too long.
if (future.isDone && future.isSuccess)
trySome(sslh.getEngine.getSession.getPeerCertificates.toIndexedSeq)
else
None
}
}
Now I was expecting that once someone authenticates with an X509 Client certificate the session would last a little while and remember that certificate chain - say 10 minutes or more, and in any case at the very least 1 minute. Indeed that is why I have the option of calling the above method with the variable "fetch" set to false. I am hoping that if someone authenticated the connection does not need to be renegotiated.
But I noticed on my that with most browsers it looks like I need to call sslh.handshake() every time if I want to get the session and return the X509 Certificates. If "fetch" is set to false, then I mostly get returned None.
Is this normal, or is there something I am doing wrong?
PS.
the code above is part of an implementation of the WebID protocol
This is using netty 3.2.5Final. I also tried with 3.2.7Final without more luck.
So I had to change the code of the current service running the above code so that it always forces a handshake (see the commit) But this does not give me as much flexibility as I hoped to have.
It turns out I was having a problem with unfiltered's use of netty. I found this when implementing the same on Play 2.0.
See bug report 215 on Play2.0, and on unfiltered bug 111: secure netty creates new TLS contexts on each connection

Resources