-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
No proper way to specify subprotocol in WebSocket client without breaking install(Auth) #940
Comments
@e5l I have some interesting follow-up information. Apparently, if the username and password that are manually encoded in the "request" lambda passed on to the "client.wss" are incorrect, the WebSocket client will then immediately retry to authenticate, this time using the credentials specified in the "install(Auth)" block. It will keep retrying (with the credentials in "install(Auth)") until the (default?) max send count of 20 is reached:
Apparently, it preserves the "Sec-WebSocket-Protocol" header value of the initial request in the retries, but switches back to "install(Auth)" for the credentials. Hopefully this detail is useful to you. |
Hi @volkert-fastned, thanks for the report. |
Sorry for the delay. |
No need to apologize. 🙂 I appreciate the hard work you're all doing on constantly improving this amazing framework. I'm not nearly as well-versed in the internals of Ktor as you are, but if you think I can help you with this in any way, let me know. |
Hi @volkert-fastned, could you try to use |
@e5l I'll be able to test this on Friday. Is that okay? |
Sure |
@e5l Hi, sorry for the late reply. I just tried it with Ktor By the way, I noticed that in newer versions of Ktor, nesting
Installing the providers outside of each other, like this, causes WebSocket upgrades to work again: private val client = HttpClient().config {
install(WebSockets)
install(HttpSend)
// NOTE: install(Auth) doesn't actually work when passing on a custom request argument to client.wss().
install(Auth) {
basic {
username = httpBasicAuthName
password = httpBasicPassword
// The line below does not seem to solve the issue.
this.sendWithoutRequest = true
}
}
} By the way, does the order in which you install these providers matter in any way? Thanks again. |
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks. |
I cannot reproduce this problem with Ktor 1.6.1 when having |
Ktor Version
1.1.2
Ktor Engine Used(client or server and name)
CIO (currently the only available WebSocket client provided by Ktor)
JVM Version, Operating System and Relevant Context
Java 11, Linux
Feedback
Currently, as far as I could find, there is apparently no convenient way in the Ktor WebSocket client API to specify the subprotocol(s) to connect with. I'm talking about the value of the "Sec-WebSocket-Protocol" header. Ktor provides a way to specify this when you set up a WebSocket server, through the protocol argument in Route.webSocket(). On the client side however, there is no such argument. I would expect HttpClient.ws and HttpClient.wss to have a similar "protocol" argument as well, but they don't.
As a workaround you can explicitly pass on an HttpRequestBuilder instance to those functions as the "request" argument, in which you then explicitly set the "Sec-WebSocket-Protocol" header (available as the value HttpHeaders.SecWebSocketProtocol in the Ktor API), but as soon as you do so, this overrides any HTTP authentication that you installed in the HttpClient by invoking install(Auth). So subsequently, you then also have to manually encode the username and password in the case of basic authentication. I expect that you'd have to jump through even more hoops in the case of HTTP Digest authentication.
Ideally, I would like to see an optional protocol (String?) argument added to the HttpClient.ws and HttpClient.wss functions to take the "Sec-WebSocket-Protocol" stuff out of our hands, while still being compatible with the install(Auth) function when configuring the HttpClient.
Below is code that reproduces the issue I'm describing here. If you comment out the "header(HttpHeaders.Authorization, ...)" part, you'll see that the "install(Auth) { basic { ... } }" stuff will be ignored when performing a WebSocket upgrade. Be sure to change the "host" and "path" argument to point to some actually running WebSocket server (and if necessary change "client.wss" to "client.ws") to run this code.
The text was updated successfully, but these errors were encountered: