Skip to content

Conversation

@LRFLEW
Copy link
Contributor

@LRFLEW LRFLEW commented Dec 27, 2025

Checklist

  • I read and understood the Contributing Guidelines.
  • This is not a duplicate of an existing merge request.
  • I believe this falls into the scope of the project and should be part of the built-in functionality.
  • My code follows the code style of this project.
  • I have added tests to cover my changes, wherever they are necessary.
  • All new and existing tests pass.

Changes

This fixes an issue I encountered with the log in the IPC API. When I switched the Kestrel config from HTTP to HTTPS, the live log stopped working in the web-ui. After significant troubleshooting, I discovered the issue was actually with using a WebSocket over HTTP/2 (which browsers only enable when using HTTPS). Microsoft's documentation for WebSockets in ASP.NET has this note about HTTP/2 compatibility:

.NET 7 introduced WebSockets over HTTP/2 support for Kestrel, the SignalR JavaScript client, and SignalR with Blazor WebAssembly. HTTP/2 WebSockets use CONNECT requests rather than GET. If you previously used [HttpGet("/path")] on your controller action method for Websocket requests, update it to use [Route("/path")] instead.

The /Api/NLog had a [HttpGet] attribute, which was breaking compatibility with HTTP/2. Since the class has the Route attribute, I was able to simply remove the HttpGet attribute to get it working with HTTP/2. Since this function already has an explicit check for whether the request is a WebSocket, this shouldn't meaningfully impact the correctness of this route.

Additional info

I saw the checklist includes an entry for adding a test for the change. While a test for this would probably be useful to have, I don't see any existing tests for the IPC API, and I'm not sure how to implement one that isn't just an integration test (i.e. spinning up a full ASF server and sending requests). I think this should be fine to merge without a test, but I left the checkbox unchecked for now.

@JustArchi
Copy link
Member

Hmm, very interesting, I guess nobody stumbled upon it before because everybody even remotely interested in accessing that endpoint over secure protocol was doing that through a reverse proxy, where this issue is non-existent. Alternatively, using HTTP 1.1, which would also work.

But indeed, if you're attempting to access that endpoint using HTTP/2, it might be different as per the docs you linked - thanks for that. I don't see any problem with this PR - have you tested that this indeed resolves your issue, but also if the endpoint shows up properly in /swagger and that you can still access it using also HTTP/1.1, and not only HTTP/2? I assume it should work, but I don't want to introduce regression for existing, and much more popular setups, so we need to be sure.

@JustArchi JustArchi added the ✨ Enhancement Issues marked with this label indicate further enhancements to the program, such as new features. label Dec 27, 2025
@JustArchi JustArchi added 🐛 Bug Issues marked with this label indicate unintended program behaviour that needs correction. and removed ✨ Enhancement Issues marked with this label indicate further enhancements to the program, such as new features. labels Dec 27, 2025
@LRFLEW
Copy link
Contributor Author

LRFLEW commented Dec 27, 2025

I have this patch running on my server currently (technically as a backport for V6.3.1.5 because of how I have the build system setup), and I tested that both HTTP/1.1 and HTTP/2 (over TLS) works. I had forgotten about /swagger when I made this PR, and when I went to check it, it seems that the entry for this disappeared. The entry for /Api/NLog/File is still there, but not /Api/NLog. I can look into bringing it back (for documentation), though I can also see an argument in favor of leaving it out of swagger (namely, that the test requests and example schemas didn't work properly for WebSockets).

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes WebSocket compatibility over HTTP/2 for the NLog IPC endpoint by removing the [HttpGet] attribute. When using HTTPS, browsers enable HTTP/2 by default, which requires WebSocket endpoints to use CONNECT requests instead of GET requests. The fix aligns with Microsoft's ASP.NET Core documentation recommendations for HTTP/2 WebSocket support.

  • Removes the [HttpGet] attribute from the NLog WebSocket endpoint
  • Maintains existing WebSocket validation logic in the method
  • Ensures compatibility with HTTP/2 WebSocket connections

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@JustArchi
Copy link
Member

JustArchi commented Dec 27, 2025

Try to add [Route("/")] in the place of removed HttpGet - that might do the trick for swagger without breaking your HTTP/2.

@JustArchi
Copy link
Member

JustArchi commented Dec 27, 2025

Or try [Route("Api/NLog")] if / won't work.

@JustArchi
Copy link
Member

Ok, I tested and neither works, but that's for me to fix since it might involve deeper digging. For now, thanks a lot, this PR does more good than harm, so it's appropriate candidate for merging if HTTP/1.1 works properly. Thanks!

@JustArchi JustArchi merged commit 255537f into JustArchiNET:main Dec 27, 2025
32 checks passed
@LRFLEW
Copy link
Contributor Author

LRFLEW commented Dec 27, 2025

To comment on the /swagger thing, it seems that Scalar is planning on implementing more direct support for WebSockets at some point. scalar/scalar#2670. It might just be a matter of waiting for it to be supported.

@JustArchi
Copy link
Member

Nah, we can wait for the next decade this way. I manually extended the schema with limited information - just enough to notify visitors about existence of that endpoint.

obraz

@LRFLEW LRFLEW deleted the wss-route branch December 28, 2025 04:34
@fazelukario
Copy link
Contributor

fazelukario commented Jan 1, 2026

Hmm, very interesting, I guess nobody stumbled upon it before because everybody even remotely interested in accessing that endpoint over secure protocol was doing that through a reverse proxy, where this issue is non-existent. Alternatively, using HTTP 1.1, which would also work.

But indeed, if you're attempting to access that endpoint using HTTP/2, it might be different as per the docs you linked - thanks for that. I don't see any problem with this PR - have you tested that this indeed resolves your issue, but also if the endpoint shows up properly in /swagger and that you can still access it using also HTTP/1.1, and not only HTTP/2? I assume it should work, but I don't want to introduce regression for existing, and much more popular setups, so we need to be sure.

Actually, I've encountered this error before, you even tried to fix it
https://discord.com/channels/267292556709068800/267292556709068800/1059455187229614171
9c9a8d0

Btw, bug fixed, kudos for @LRFLEW

@JustArchi
Copy link
Member

JustArchi commented Jan 1, 2026

Hmm, very interesting, I guess nobody stumbled upon it before because everybody even remotely interested in accessing that endpoint over secure protocol was doing that through a reverse proxy, where this issue is non-existent. Alternatively, using HTTP 1.1, which would also work.
But indeed, if you're attempting to access that endpoint using HTTP/2, it might be different as per the docs you linked - thanks for that. I don't see any problem with this PR - have you tested that this indeed resolves your issue, but also if the endpoint shows up properly in /swagger and that you can still access it using also HTTP/1.1, and not only HTTP/2? I assume it should work, but I don't want to introduce regression for existing, and much more popular setups, so we need to be sure.

Actually, I've encountered this error before, you even tried to fix it https://discord.com/channels/267292556709068800/267292556709068800/1059455187229614171 9c9a8d0

Btw, error fixed, kudos for @LRFLEW

Could be the same issue indeed, I'm not denying it - the difference is, here @LRFLEW pointed to the precise issue and also submitted fix for it which I could analyze. It's totally different compared to me looking for issue reported by somebody, only to find out I can't reproduce it. And yes, if it works on Firefox but doesn't on Chrome, that's a hint towards browser-specific problem. If you digged more and pointed out that it's not due to web browsers but due to Chrome using HTTP/2 for websocket and Firefox not, and that's why it doesn't work - I could test that theory and confirm it as well.

I'm not a wizard, sometimes the issue is more complex and it's not enough to just point it out, fixing the issue first and foremost requires understanding the culprit, and the culprit back then was not discovered properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 Bug Issues marked with this label indicate unintended program behaviour that needs correction.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants