Trying to implement a basic WebSockets channel with a JavScript client and an ASP.NET server. The client code goes:
function Connect()
{
var ws = new WebSocket("ws://" + window.location.host + "/callback.aspx");
ws.onmessage = function (a) { alert("Message"); };
ws.onopen = function (a) { alert("Open"); };
ws.onerror = function (a) { alert("Error"); };
}
Callback.aspx is a basic ASP.NET web page, and it goes:
protected void Page_Load(object sender, EventArgs e)
{
if (HttpContext.Current.IsWebSocketRequest)
{
HttpContext.Current.AcceptWebSocketRequest(SocketProc);
}
}
private static async Task SocketProc(AspNetWebSocketContext a)
{
try
{
ArraySegment<byte> Buffer = new ArraySegment<byte>(new Byte[1024]);
while (true)
{
WebSocketReceiveResult res = await a.WebSocket.ReceiveAsync(Buffer, CancellationToken.None);
if (a.WebSocket.State != WebSocketState.Open)
return;
}
}
catch (Exception exc)
{
Debug.WriteLine(exc);
}
}
When I try to connect from the client, the Page_Load is invoked, then SocketProc is invoked, but then ReceiveAsync immediately throws the following exception:
System.Net.WebSockets.WebSocketException (0x800703E3): The I/O operation has been aborted because of either a thread exit or an application request
at System.Web.WebSockets.WebSocketPipe.<>c__DisplayClass9_0.<ReadFragmentAsync>b__0(Int32 hrError, Int32 cbIO, Boolean fUtf8Encoded, Boolean fFinalFragment, Boolean fClose)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.WebSockets.AspNetWebSocket.<DoWork>d__45`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.WebSockets.AspNetWebSocket.<>c__DisplayClass36_0.<<ReceiveAsyncImpl>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at CleanProxy.callback.<SocketProc>d__2.MoveNext() in C:\dev\CleanModel\CleanProxy\callback.aspx.cs:line 37
On the client, OnOpen fires, then OnError.
If I catch the exception immediately around ReceiveAsync, the WebSocket object comes out of it closed.
What am I missing here? Testing on Windows Server 2016, both in IIS Express and IIS proper.
EDIT: I've been testing with built-in IE, but I've now tried with Chrome and got a different error. This time, there's no exception, ReceiveAsync returns an object with MessageType=Close, CloseStatus=ProtocolError. On the client, there's an error in Chrome console:
WebSocket connection to 'ws://localhost:53329/callback.aspx' failed: Invalid frame header
EDIT2: it somehow worked with an HTTP handler instead of an ASPX page. Freaky. There's no requirement to use classic ASP.NET, so this'll do for now, but the issue will probably remain unsolved.
Related
i have one question about SSEEmitter in Java Spring Boot.
I have following code to etablish connection between client and server in Java Spring Boot. I have set the timeout of the SseEmitter - object to max value of long.
Now following scenary occurrs: I close the tab in the browser and the sseemitter object on the server don't close. So many objects are on the server. This leads to memory issues.
#RequestMapping(value = "/subscribe", consumes = MediaType.ALL_VALUE)
public SseEmitter subscribe() {
System.out.println("SUBSCRIBE CALLED!");
System.out.println(emitters.size());
SseEmitter x = new SseEmitter(Long.MAX_VALUE);
try {
x.send(SseEmitter.event().name("INIT"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
x.onCompletion(()->{
System.out.println("ON COMPLETION CALLED!");
emitters.remove(x);
});
x.onTimeout(()->{
System.out.println("ON TIMEOUT CALLED!");
emitters.remove(x);
});
emitters.add(x);
return x;
}
How can I say the client to close the object?
Kind regards
I assume you are using "emitters" to send future updates. Try to complete the emitter and remove it from "emimtter" in the catch (IOException) block where you send the emitter update:
I'm starting with WebSockets and, to try things off, I built a minuscule WebSocket server in C# (using WebSocketSharp) and an html as a client to connect to it.
On the client I have this code:
const webSocket = new WebSocket("ws://localhost:51036/test");
webSocket.onopen = e => {
webSocket.send("hello :D");
console.log("Socket connection opened!");
}
This send() call never works — it sometimes result in an exception in the C# server, most other times it is just ignored as if nothing was ever received on the server's end. However, any send() I call afterwards (e.g. with a button) works fine, and send() inside onopen also works fine if I place it inside a timeout of just 200ms. If I don't call any send() onopen, and just call it later via a button, it always works fine (so it's not a 'first call always fails' issue).
On the C# side, the code is very simple:
public class TestWS : WebSocketBehavior {
protected override void OnMessage (MessageEventArgs e) {
System.Diagnostics.Debug.WriteLine($"Client message: {e.Data}");
Send($"String length: {e.Data.Length} [msg received: {e.Data}]");
}
}
public static class Sockets {
public const string SERVER_ROUTE = "ws://localhost:51036";
private static WebSocketServer socket;
public static void Start () {
socket = new WebSocketServer(SERVER_ROUTE);
socket.AddWebSocketService<TestWS>("/test");
socket.Start();
System.Diagnostics.Debug.WriteLine($"Server started on {SERVER_ROUTE}");
}
public static void Stop () {
socket.Stop();
}
}
The exception in question is this one:
2021-09-06 19:59:06|Fatal|WebSocket.<startReceiving>b__175_2:0|WebSocketSharp.WebSocketException: The header of a frame cannot be read from the stream.
at WebSocketSharp.WebSocketFrame.processHeader(Byte[] header)
at WebSocketSharp.WebSocketFrame.<>c__DisplayClass73_0.<readHeaderAsync>b__0(Byte[] bytes)
at WebSocketSharp.Ext.<>c__DisplayClass55_0.<ReadBytesAsync>b__0(IAsyncResult ar)
I am developing websocket server with netty frame work version 4.1.6.
I am using the sample code from netty example site
This is my server source code:
public class WebSocketServer
{
static final int PORT = 4466;
public static void main(String[] args)
{
final SslContext sslCtx;
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new WebSocketServerInitializer(sslCtx));
Channel ch = b.bind(PORT).sync().channel();
System.out.println("Open your web browser and navigate to " +
"http://127.0.0.1:" + PORT + '/');
ch.closeFuture().sync();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
An WebSocketServerInitializer source code:
public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel>
{
private static final String WEBSOCKET_PATH = "/websocket";
private final SslContext sslCtx;
public WebSocketServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(sslCtx.newHandler(ch.alloc()));
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WebSocketServerCompressionHandler());
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
// pipeline.addLast(new WebSocketIndexPageHandler(WEBSOCKET_PATH));
pipeline.addLast(new WebSocketFrameHandler());
}
}
This is my Html code:
<html>
<head>
<script type="text/javascript">
// Let us open a web socket
var ws = null;
function WebSocketTest()
{
if ("WebSocket" in window)
{
alert("WebSocket is supported by your Browser!");
// Let us open a web socket
ws = new WebSocket("wss://localhost:4466/websocket");
ws.onopen = function()
{
// Web Socket is connected, send data using send()
ws.send("Message to send");
alert("Message is sent...");
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
alert(received_msg);
//alert("Message is received...");
};
ws.onclose = function()
{
// websocket is closed.
alert("Connection is closed...");
};
window.onbeforeunload = function(event) {
socket.close();
};
}
else
{
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
}
}
</script>
</head>
<body>
<div id="sse">
Run WebSocket
</div>
</body>
</html>
I browse the page using Chrome browser and got the following message when I click on the link in the web page.
WebSocket connection to 'wss://localhost:4466/websocket' failed: Error in connection establishment: net::ERR_INSECURE_RESPONSE
According to some discussions here, and the netty websocket sample code, wss must be forwarded by HTTPS. However, when I change the following javascript statement in my web page:
ws = new WebSocket("wss://localhost:4466/websocket");
to
ws = new WebSocket("wss://echo.websocket.org");
It works fine. It make me confusing, Why the site echo.websocket.org can working without https? Why my server cannot? are there something missing in my server source code?
PS: the echo.websocket.org example found in the following url:
http://jsbin.com/muqamiqimu/edit?js,console
Your browser is failing to connect to your websocket server, because it detected it is insecure.
This happens because when the browser tries to connect to your server, it will check the SSL certificate. This certificate is basically a proof that says your server is claiming to be the authoritative server for localhost.
Your server claims this by its certificate, what in your case is signed by itself, that's basically the SelfSignedCertificate class, and it's claiming to be "example.com".
This creates 2 issues:
Your browser connects to localhost, but instead of getting a certificate for localhost, it gets 1 for example.com
Your browser does not trust the signer of the certificate to have the authority to make certificates, causing it to be rejected.
There are multiple ways to solve this:
Getting a valid certificate and hosting your application on a server
This would be the recommended solution for production, depending where you get your valid certificate, it may or may not cost money.
Bypass the certificate warning
By manually going to http://localhost:4466/ you can skip past the certificate warning, and basically this adds a 1 time exception for the certificate rule, till you restart your browser
Configuring google chrome to accept invalid certificates for localhost
While this can be insecure (but not as insecure as turning off all certificate validation), it can be a great way to test ssl on development machines.
You can turn ssl validation of for localhost by going to chrome://flags/#allow-insecure-localhost and turning that option on. Notice that you might be required to set the domain of your certificate to localhost when using this option by calling the new SelfSignedCertificate("localhost"); contructor.
I'm attempting to write a C# WebSocket server for an application that interacts upon browser input.
This is the code:
class Program {
static void Main(string[] args) {
var listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 42001);
listener.Start();
using(var client = listener.AcceptTcpClient())
using(var stream = client.GetStream())
using(var reader = new StreamReader(stream))
using(var writer = new StreamWriter(stream)) {
while (!reader.EndOfStream) {
String line = reader.ReadLine();
if (new Regex("^GET").IsMatch(line)) {
line = reader.ReadLine();
if (new Regex("^Sec-WebSocket-Key: ").IsMatch(line)) {
String key = new Regex("(^Sec-WebSocket-Key\\: |\\r\\n)").Replace(line, "");
key = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")));
writer.WriteLine("HTTP/1.1 101 Switching Protocols");
writer.WriteLine("Upgrade: websocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("Sec-WebSocket-Accept: " + key);
writer.WriteLine("Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits");
writer.WriteLine("WebSocket-Origin: http://127.0.0.1");
writer.WriteLine("WebSocket-Location: ws://localhost:42001/websocket");
writer.WriteLine("");
}
}
}
}
listener.Stop();
}
}
... and:
var ws = new WebSocket('ws://localhost:42001/websocket');
ws.onopen = function() {
console.log('connected');
};
ws.onmessage = function(e) {
console.log(e.data);
};
ws.onerror = function(e) {
console.log(e);
};
ws.onclose = function() {
console.log("closed");
};
On execution, the TPCListener successfully accepts the TCPClient and reads the incoming HTTP request. It parses the Key, generates the correct Accept token, but the JS - window native - WebSocket seems to have gone flat out bonkers: it does not answer no matter what it receives.
I would expect it throwing an error upon sending a HTTP/1.1 400 Bad Request, but nothing at all happens. It just goes mute.
Checking out Chrome Dev Tools' Networking tab, I do only see the websocket outgoing GET request, but no incoming packets - is that supposed to happen?
If I forcefully close the application, WebSocket throws this exception:
WebSocket connection to 'ws://localhost:42001/websocket' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET.
What am I missing here? Thank you all in advance.
Also, I'm not using Net.WebSockets because it is available since .NET 4.5, and my application targets systems from Windows 7 to the current build of Windows 10.
well... how far does your C# code get? My first bet would be on buffering - you don't flush the writer or stream, so I would expect them to be holding onto data while stuck in the top of the while loop, but frankly it shouldn't be a while loop in the first place - you only get one handshake per socket, not many. You could try adding flushes after the blank line, and you should make sure the Socket itself has buffering disabled (NoDelay = true;) - but: fundamentally this isn't a good way to write a web-socket server. Apart from anything else, the data will cease to be text if the handshake succeeds, so having a TextReader is a very bad thing. Frankly, you should be dealing with raw Socket / byte[] data here, IMO (having implemented this very thing several times).
I have a report in BIRT that has non-trivial JavaScript (scripted data source). The JavaScript is all a bit wobbly, and suspect to regress. For that reason and others I have written a JUnit test that populates the data, runs the report (createRunAndRenderTask and run that task) and do some validation on the resulting report.
Obviously this test will fail when the BIRT engine throws any exceptions. However, upon JavaScript errors in the report, no exceptions are thrown. And that does not feel good. Can I change this somehow to have the BIRT engine throw exceptions upon JavaScript errors?
I tried this by having a host of JavaScript errors during development of the report. Think of typos in the scripted data source. They are spit out in the console, but no exceptions.
E.g.:
<method name="open"><![CDATA[count = 0;
this should break]]></method>
This shows in the console:
... Fail to execute script in function __bm_OPEN(). Source:
------
" + count = 0;
this should break + "
-----
A BIRT exception occurred. See next exception for more information.
ReferenceError: "this should break" is not defined. (/report/data-sets/script-data-set[#id="9"]/method[#name="open"]#3)
Thank you for your suggestions!
I ended up doing this and pretty okay with it:
IRunAndRenderTask task = ...
...
task.setErrorHandlingOption(IEngineTask.CANCEL_ON_ERROR);
...
task.run();
evaluateStatus(task, reportName);
task.close();
And:
private void evaluateStatus(IRunAndRenderTask task, String reportName) {
if (task.getStatus() == IEngineTask.STATUS_CANCELLED) {
String message = "report failed: " + reportName;
List<Throwable> errors = task.getErrors();
if (!errors.isEmpty()) {
throw new RuntimeException(message, errors.get(errors.size() - 1));
}
throw new RuntimeException(message);
}
}
Depending on javascript errors, the BIRT engine will catch them and still try to display the report.
I think you could override this by wrapping your javascript code (Rhino script) in a try...catch expression, and explicitely throw a BirtException if something wrong happens:
try{
//your javascript stuff
var test=null;
test.toString();
}catch(e){
var exception=new org.eclipse.birt.core.exception.BirtException("Custom exception:"+e);
throw exception;
}