WebSocket is not in the OPEN state - asp.net-core

I'm trying SignalR on ASP.NET Core. It works fine running from VisaulStudio debugger.
However it does not work in deployed code, showing the error message "WebSocket is not in the OPEN state" and "Handshake was canceled". What is the possible cause of the problem?
Microsoft.AspNetCore.Mvc 2.2.0
Microsoft.AspNetCore.SignalR 1.1.0
#aspnet/signalr 1.1.2
Bootstrap4
jQuery v3.1.0
Kestrel
No HTTPS SSL
Tried with Windows 7 and Ubuntu 18.4
Network Console on Google Chrome
WebSocket is not in the OPEN state (kms-event-exit.js:12)
Uncaught Error: Seerver returned handshake error: Handshake was canceled. (signalr.min.js:16)
at HubConnection.processHandshakeResponse (signalr.min.js:16)
at HubConnection.processIncomingData (signalr.min.js:16)
at WebSocketTransport.HubConnection.connection.onreceive (signalr.min.js:16)
at WebSocket.webSocket.onmessag (signalr.min.js:16)
[2019-04-06T01:06:41.965Z] Error: Connection disconnected with error 'Error: Server returned handshake error: Handshake was canceled.'. signalr.min.js:16
Uncaught (in promise) Server returned handshake error: Handshake was canceled. (signalr.min.js:16)
Startup functions.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddRazorOptions(options => options.AllowRecompilingViewsOnFileChange = true);
services.AddSignalR(options => options.EnableDetailedErrors = true);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
if (!env.IsDevelopment())
{
//app.UseExceptionHandler("/Home/Main");
app.UseHsts();
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseSignalR(routes =>
{
routes.MapHub<Hubs.KmsHub>("/KmsHub");
routes.MapHub<Hubs.AllResetHub>("/AllResetHub");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areaDefault",
template: "{area:exists}/{controller=Home}/{action=Main}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Main}/{id?}/{exit?}");
});
}
Logs
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionDispatcher[4]
Establishing new connection.
dbug: Microsoft.AspNetCore.SignalR.HubConnectionHandler[5]
OnConnectedAsync started.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[1]
Socket opened using Sub-Protocol: '(null)'.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/favicon.ico
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
Sending file. Request path: '/favicon.ico'. Physical path: 'D:\K4\KMS\KMS\bin\Release\netcoreapp2.2\publish\wwwroot\favicon.ico'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 6.664ms 200 image/x-icon
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/lib/Popper/popper.min.js.map
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 3.4573ms 404
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/lib/bootstrap/dist/js/bootstrap.min.js.map
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/lib/signalr/dist/browser/signalr.min.js.map
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 2.3443ms 404
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
Sending file. Request path: '/lib/bootstrap/dist/js/bootstrap.min.js.map'. Physical path: 'D:\K4\KMS\KMS\bin\Release\netcoreapp2.2\publish\wwwroot\lib\boo
tstrap\dist\js\bootstrap.min.js.map'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 114.858ms 200 text/plain
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://localhost:5000/lib/bootstrap/dist/css/bootstrap.min.css.map
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[2]
Sending file. Request path: '/lib/bootstrap/dist/css/bootstrap.min.css.map'. Physical path: 'D:\K4\KMS\KMS\bin\Release\netcoreapp2.2\publish\wwwroot\lib\b
ootstrap\dist\css\bootstrap.min.css.map'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 18.0356ms 200 text/plain
dbug: Microsoft.AspNetCore.SignalR.HubConnectionContext[2]
Handshake was canceled.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[7]
Waiting for the client to close the socket.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport[2]
Socket closed.
dbug: Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager[2]
Removing connection 8K2CDgDs6jWXM7DPMWk_Dg from the list of connections.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 15047.5227ms 101
JavaScript code which caught the exception.
function kmsEventExit(url) {
var exitButton = document.getElementById("exitButton");
var connection = new signalR.HubConnectionBuilder().withUrl(url + "/KmsHub").build();
//Disable send button until connection is established
exitButton.disabled = true;
//Wait until connection finishes.
connection.start().then(function () {
exitButton.disabled = false;
}).catch(function (err) {
return console.error(err.toString()); //WebSocket is not in the OPEN state
});
//Call ExitKms on clicking the button.
exitButton.addEventListener("click", function (event) {
connection.invoke("ExitKms").catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
//Catch the result.
connection.on("ExitKmsResult", function (isAlert, options) {
if (isAlert) {
swal(JSON.parse(options));
}
});
}

There has been an workaround posted in a GitHub Issue that has worked for me.
Before connecting, add:
Object.defineProperty(WebSocket, 'OPEN', { value: 1, });
Using this method, there's no need to remove pace.js.
Important note: if you are using Blazor Server, you will face the same issue. Remove pace.js then, as it's quite useless in this case.

I have identified the problem!
It did not work because pace.js was not compatible with signalr.js. WebSocket variable was duplicated in these two plugins. SignalR works fine after removing pace.js.
SignalR on VisualStudio worked with pace.js because it uses SSE and IIS Express, instead of WebSocket and Kestrel, thus pace.js and signalr.js can be compatible with this particular configuration.
Reference:
https://github.com/aspnet/SignalR/issues/2389

As Identified above, pace and signalr are not directly compatible, however putting the script below before loading pace.js will resolve the problem instead of outrightly remove pace.js
<script>
window.paceOptions = { ajax: { ignoreURLs: ['mainHub', '__browserLink', 'browserLinkSignalR'], trackWebSockets: false } }
</script>
Reference to above answer: https://stackoverflow.com/questions/54770354/how-to-use-asp-net-core-signalr-with-pace-js
The value of 'mainHub' is the signalR hub in your C# application you are connecting to.

Related

Blazor WebAssembly MQTT over websockets not working

I'm trying to implement an mqtt over websocket client subscriber in Blazor using Paho. The problem is it insists on using wss instead of ws and throws an ERR_SSL_PROTOCOL_ERROR error upon connection.
Here's a simplified code block:
var mqtt;
var host = "api.mydomainexample.com";
var port = 1884;
function onConnect(){
console.log("connected ! Now listening for messages ..");
mqtt.subscribe("someTopic");
}
function onFailure(message){
console.log("connection to host failed: " + message);
}
function onMessageArrived(msg){
var message = "Message received on topic '"+ msg.destinationName +"': "+ msg.payloadString;
console.log(message);
}
function mqttConnect() {
console.log("connecting to " + host + " ..");
mqtt = new Paho.MQTT.Client(host, port, clientid);
var options = {
timeout: 3,
onSuccess: onConnect,
onFailure: onFailure,
useSSL: false
};
mqtt.onMessageArrived = onMessageArrived;
mqtt.connect(options);
}
I copied this code into an html page created in notepad, called the function from the html body and ran the file in browser. It worked and subscribed well.
Also I added useSSL: false in the connection options although I didnt have it before but still didnt work.
here's the error I'm having from console:
WebSocket connection to 'wss://api.mydomainexample:1884/mqtt' failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR
I also changed my projects launch settings so that it launches as http and not https because based on this answer, I cannot use a ws from a page loaded through https.
Any ideas ? Can't I just connect to a websocket without certificate in blazor?
Ok it turns out that when creating the blazor application, there is an option to 'configure on https' where this option causes requests redirection from http to https and consequently asks for secure wss instead of ws.
Hope this helps someone!

VueJS - Localhost API requests not working on Android Chromium

I am running a vue-project on Chromium 72 on Android v4.4.4 and an API is also running on localhost:8225.
So with the click of a button, I am making a post request using Axios to this localhost API in the project.
var axiosConfig = {
method: "post",
url: "http://localhost:8225/info/update",
data: {},
timeout: 3000,
contentType: "application/json",
headers: {
Authorization: "Basic " + btoa(apiUser + ":" + apiPassword),
},
};
return new Promise(function (resolve, reject) {
axios(axiosConfig)
.then(function (response) {
var result = response;
resolve(result);
console.log("Response", response);
})
.catch(function (error) {
console.log("Error", error);
reject(error);
});
});
But the problem is when I click the button it doesn't hit the API method. It gives Error: timeout of 3000ms exceeded and when I removed the timeout and checked the network tab the request remains in a pending state.
I don't think there is a structural error in the code because the same request works from another application running on the device. When the button is clicked the information gets updated.
Also, I tried all the chromium version till v80 same issue exists. So is there any setting that needs to be changed or enabled on Chromium to handle API requests?
UPDATE:
The API gets hit but when I checked the value of the User(username and password) on HttpListenerContext object, it shows null. I have cross-checked multiple times and I believe the request structure is correct. I am not sure if Chromium is putting some restrictions while sending the requests or the problem is with the backend like CORS issue or maybe something else.

Infinispan java.lang.SecurityException: ISPN006017: Unauthorized 'PUT' operation

I am trying to put a value in Infinispan cache using Hotrod nodeJS client. The code runs fine if the server is installed locally. However, when I run the same code with Infinispan server hosted on docker container I get the following error
java.lang.SecurityException: ISPN006017: Unauthorized 'PUT' operation
try {
client = await infinispan.client({
port: 11222,
host: '127.0.0.1'
}, {
cacheName: 'testcache'
});
console.log(`Connected to cache`);
await client.put('test', 'hello 1');
await client.disconnect();
} catch (e) {
console.log(e);
await client.disconnect();
}
I have tried setting CORS Allow all option on the server as well
Need to provide custom config.yaml to docker with following configurations
endpoints:
hotrod:
auth: false
enabled: false
qop: auth
serverName: infinispan
Unfortunately the nodejs client doesn't support authentication yet. The issue to implement this is https://issues.redhat.com/projects/HRJS/issues/HRJS-36

Socket.io will not accept connection

Working on socket.io for the first time and trying to get it up and going, I can make the request and I have the server up and going, here is the server in node.
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
app.get("/",function (req,res){
res.send("Hello you socket loving bastard!");
});
io.on('connection', socket => {
console.log('user connection', socket);
io.emit('You got someone!', {user: "me"});
});
io.on('close', socket => {
console.log(socket);
});
http.listen(9090, () => {
console.log("Node starting on 9090 for websockets!")
});
Using vue-native-websocket I have this ...
Vue.use(Socket, 'ws://localhost:9090/', {
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 1500
});
The console in the browser says:
build.js?b408:1 WebSocket connection to 'ws://localhost:9090/' failed: Connection closed before receiving a handshake response
The server says nothing in the console at all, however, it will serve the get request
Well... the issue is that I'm using vue-native-websocket Socket.io is NOT a native websocket handler and adds extra header information which was lacking apparently. I switches to just using ws in node and it works fine.
From the Socket.io docs.
Socket.IO is NOT a WebSocket implementation. Although Socket.IO indeed uses WebSocket as a transport when possible, it adds some metadata to each packet: the packet type, the namespace and the packet id when a message acknowledgement is needed. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a WebSocket server either.

webpack dev-server: Avoid proxy errors on HTTP errors returned from proxy target

I have a Vue.js project where I have configured a webpack dev-server to proxy all requests to the UI to my backend server. Here is the relevant part of vue.config.js:
devServer: {
contentBase: PATHS.build,
port: 9000,
https: false,
hot: true,
progress: true,
inline: true,
watchContentBase: true,
proxy: {
'^/': {
target: 'http://127.0.0.1:8089',
secure: false
},
}
},
I've noticed that if the HTTP response code from http://127.0.0.1:8089 is anything other than 2xx then the proxy fails with the following error:
Proxy error: Could not proxy request /api/test from localhost:9000 to http://127.0.0.1:8089.
See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (HPE_INVALID_CHUNK_SIZE).
This also causes the HTTP response code from the request to localhost:9000 to be 500 for any error and all the information about what went wrong on the server side is lost. This is problematic as I want to be able to extract information from error responses to display to the user.
I know it's possible to do because I had it working on an older Angular project which I think was using Webpack 3 (am now using Webpack 4). I tried copying all the dev-server config from this project but it just doesn't seem to work here!
EDIT: I was wrong. The Proxy error does not occur on every bad response but only for one of the requests which is a multipart file upload. Still unable to reproduce this in a smaller example to put on github though so struggling to pinpoint the cause.
This error message comes from node_modules/#vue/cli-service/lib/util/prepareProxy.js, which define a onError callback for node-http-proxy;
So I did some experiment, make back-end api generate 400 404 500 response, but I didn't got this error.
After I happen to close back-end api, error arise:
Proxy error: Could not proxy request /hello from localhost:8080 to http://localhost:8081 (ECONNREFUSED).
I search in the doc and find these:
The error event is emitted if the request to the target fail. We do not do any error handling of messages passed between client and proxy, and messages passed between proxy and target, so it is recommended that you listen on errors and handle them
So the onError do not handle error code, is called only when request fail (500 response is still treated as a complete request, connection refuse is not)
Go back to your error message, [HPE_INVALID_CHUNK_SIZE] means bad request to the back-end api. In this issue, it gives an solution: add a keep-alive header:
devServer: {
publicPath: 'http://localhost:9090/front/static-dev/build/',
port: 9090,
proxy: {
'/**': {
target: 'http://localhost:8080',
secure: false,
changeOrigin: true,
headers: {
Connection: 'keep-alive'
}
},
open: true
}
I have finally found the problem, and I apologise, it was a lot more of a specific issue than I originally thought when I wrote the question.
Issue was to do with a request which was proxied to another server using the Spring RestTemplate:
e.g.
#PostMapping("/upload")
public ResponseEntity upload(#RequestParam("file") MultipartFile file)
throws Exception {
String baseUrl = serviceProperties.getAddress();
HttpEntity<MultiValueMap<String, Object>> request = createMultipartRequest(file.getBytes());
return restTemplate.postForEntity(baseUrl + "/api/upload", filterRequest, String.class);
}
The ResponseEntity returning from the rest template proxy contained the header "Connection: close" when the response was anything other than 200 which cause the connection to close and caused this request to fail to return anything which subsequently made the dev-server proxy fail on the UI.
Fixed this by not passing the response headers from the rest template proxy to the response:
#PostMapping("/upload")
public ResponseEntity upload(#RequestParam("file") MultipartFile file)
throws Exception {
String baseUrl = serviceProperties.getAddress();
HttpEntity<MultiValueMap<String, Object>> request = createMultipartRequest(file.getBytes());
ResponseEntity response = restTemplate.postForEntity(baseUrl + "/api/upload", filterRequest, String.class);
return new ResponseEntity<>(response.getBody(), response.getStatusCode());
}