Flutter/Dart + gRPC Stream error: Stream was terminated by peer (errorCode: 2) - flutter

I'm having this intermittent error come up when making a call from a Dart gRPC client to a Go gRPC server. The exact error message is:
gRPC Error (code: 2, codeName: UNKNOWN, message: HTTP/2 error: Stream
error: Stream was terminated by peer (errorCode: 2)
This seems to occur frequently on creating the client stub with the channel and making a call to the server. Subsequent calls seems to work fine with a response returned correctly to the client. Then this error intermittently pops up again every n-th call (could be after 5 calls, 10 calls sometimes no errors until the 20th call).
When I use a different client (eg: BloomRPC or Java app I wrote), this does not happen no matter how hard or fast I spam the calls to the server. This kind of implies the server is probably not the issue.
Can anyone shine a light on what might be happening? Or provide some hints as to where to start looking/debugging? I've tried stepping through the code, but not really able to follow what is happening when the gRPC call is made/returned.
Steps in the client code:
create ClientChannel with ip, ports
final cc = ClientChannel(serverIP,
port: serverPort,
options:
const ChannelOptions(credentials: ChannelCredentials.insecure()
));
created a stub based on above channel
_userQueryStub = UserQueryGRPCClient(cc,
options: CallOptions(timeout: Duration(seconds: 30)));
call function from stub (repeatedly)
GetUserInformationRequest request = GetUserInformationRequest(userId: userId);
GetUserInformationResponse response = await _userQueryStub.getUserInformation(request);
Any help will be greatly appreciated!

Related

Bidirectional communication of Unix sockets

I'm trying to create a server that sets up a Unix socket and listens for clients which send/receive data. I've made a small repository to recreate the problem.
The server runs and it can receive data from the clients that connect, but I can't get the server response to be read from the client without an error on the server.
I have commented out the offending code on the client and server. Uncomment both to recreate the problem.
When the code to respond to the client is uncommented, I get this error on the server:
thread '' panicked at 'called Result::unwrap() on an Err value: Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }', src/main.rs:77:42
MRE Link
Your code calls set_read_timeout to set the timeout on the socket. Its documentation states that on Unix it results in a WouldBlock error in case of timeout, which is precisely what happens to you.
As to why your client times out, the likely reason is that the server calls stream.read_to_string(&mut response), which reads the stream until end-of-file. On the other hand, your client calls write_all() followed by flush(), and (after uncommenting the offending code) attempts to read the response. But the attempt to read the response means that the stream is not closed, so the server will wait for EOF, and you have a deadlock on your hands. Note that none of this is specific to Rust; you would have the exact same issue in C++ or Python.
To fix the issue, you need to use a protocol in your communication. A very simple protocol could consist of first sending the message size (in a fixed format, perhaps 4 bytes in length) and only then the actual message. The code that reads from the stream would do the same: first read the message size and then the message itself. Even better than inventing your own protocol would be to use an existing one, e.g. to exchange messages using serde.

Vertx request does not end on sendFile throwing

I'm new to vert.x and I'm trying to create a simple download service.
I used Request#sendFile(fileName) and it works well, but if I pass a directory path to Request#sendFile(fileName) it throws an exception, which is totally fine.
The problem is that, even if I catch that exception with an handler, I can't send any data nor end the request, an that leaves the http client (the browser) stuck on an endless spinning progress.
That is an example that reproduces the problem:
VertxOptions options = new VertxOptions();
options.setBlockedThreadCheckInterval(1000*60*60);
Vertx vertx = Vertx.vertx(options);
HttpServer server = vertx.createHttpServer();
Router router = Router.router(vertx);
router
.route(HttpMethod.GET,"/foo")
.handler(ctx->{
// this path exist but is not a file, is a directory.
ctx.response().sendFile("docs/pdf",asr->{
if(asr.failed()) {
ctx.response()
.setStatusCode(404)
// I can't end the connection the only thing I can do is close it
// I've commented out this lambda because is not what I want to happen.
// It's just an hack to end the request all the same.
.end("File not found: "+"docs/pdf" /*, (x)->{ctx.response().close();}*/ );
}
});
});
server
.requestHandler(router)
.listen(3000);
I can this problem by checking first if the path references to a file which both exsist and is not a directory (which in fact I did in the real code), but that leaves me with doubt about what would happen if the IOException was something different (like reading a broken file, or an unauthorized file ...).
When this error happens no data is sent through the wire, I've both checked form the browser and sniffing packets TCP packets (0 bytes send from the server to the browser).
The only things that works is closing the connection with Response#close(), which at least closes the keep-alive http connection, and ends the browser request.
What I want to achieve is to send some information back to the client to tell something went wrong, possibly setting the status code to an appropriate 4** error and possibly adding some details to it (either in status text or in the response body).
You should add failureHandler to your router:
route.failureHandler(frc-> {
frc.response().setStatusCode( 400 ).end("Sorry! Not today");
});
see https://vertx.io/docs/vertx-web/java/#_error_handling

Route SockJS connection at variable URL?

Let's say I have a bunch of clients who all have their own numeric IDs. Each of them connect to my server through SockJS, with something like:
var sock = new SockJS("localhost:8080/sock/100");
In this case, 100 is that client's numeric ID, but it could be any number with any number of digits. How can I set up a SockJS router in my server-side code that allows for the client to set up a SockJS connection through a URL that varies based on what the user's ID is? Here's a simplified version of what I have on the server-side right now:
public void start() {
HttpServer server = vertx.createHttpServer();
SockJSHandler sockHandler = SockJSHandler.create(vertx);
router.route("/sock/*").handler(sockHandler);
server.requestHandler(router::accept).listen(8080);
}
This works fine if the client connects through localhost:8080/sock, but it doesn't seem to work if I add "/100" to the end of the URL. Instead of getting the default "Welcome to SockJS!" message, I just get "Not Found." I tried setting a path regex and I got an error saying that sub-routers can't use pattern URLs. So is there some way to allow for the client to connect through a variable URL, whether it's /sock/100, /sock/15, or /sock/1123123?
Ideally, I'd be able to capture the numeric ID that the client uses (like with routing REST API calls, when you could add "/:ID" to the routing path and then capture the value that the client uses), but I can't find anything that works for SockJS connections.
Since it seems that SockJS connections are considered to be the same as sub-routers, and sub-routers can't have pattern URLs, is there some work-around for this? Or is it not possible?
Edit
Just to add to what I said above, I've tried a couple different things which haven't seemed to work yet.
I tried setting up an initial, generic main router, which then re-directs to the SockJS handler. Here's the idea I had:
router.routeWithRegex("/sock/\\d+").handler(context -> {
context.reroute("/final");
});
router.route("/final").handler(SockJSHandler.create(vertx));
With this, if I access localhost:8080/sock/100 directly through the browser, it takes me to the "Welcome to SockJS!" page, and the Chrome network tab shows that a websocket connection has been created when I test it through my client.
However, I still get an error because the websocket shows a 200 status code rather than 101, and I'm not 100% sure as to why that is happening, but I would guess that it has to do with the response that the initial handler produces. If I try to set the initial handler's status code to 101, I still get an error, because then the initial handler fails.
If there's some way to work around these status codes (it seems like the websocket is expecting 101 but the initial handler is expecting 200, and I think I can only pick one), then that could potentially solve this. Any ideas?

Nodejs Websocket Close Event Called...Eventually

I've been having some problems with the below code that I've pieced together. All the events work as advertised however, when a client drops off-line without first disconnecting the close event doesn't get call right away. If you give it a minute or so it will eventually get called. Also, I find if I continue to send data to the client it picks up a close event faster but never right away. Lastly, if the client gracefully disconnects, the end event is called just fine.
I understand this is related to the other listen events like upgrade and ondata.
I should also state that the client is an embedded device.
client http request:
GET /demo HTTP/1.1\r\n
Host: example.com\r\n
Upgrade: Websocket\r\n
Connection: Upgrade\r\n\r\n
//nodejs server (I'm using version 6.6)
var http = require('http');
var net = require('net');
var sys = require("util");
var srv = http.createServer(function (req, res){
});
srv.on('upgrade', function(req, socket, upgradeHead) {
socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n\r\n');
sys.puts('upgraded');
socket.ondata = function(data, start, end) {
socket.write(data.toString('utf8', start, end), 'utf8'); // echo back
};
socket.addListener('end', function () {
sys.puts('end'); //works fine
});
socket.addListener('close', function () {
sys.puts('close'); //eventually gets here
});
});
srv.listen(3400);
Can anyone suggest a solution to pickup an immediate close event? I am trying to keep this simple without use of modules. Thanks in advance.
close event will be called once TCP socket connection is closed by one or another end with few complications of rare cases when system "not realising" that socket been already closed, but this are rare cases. As WebSockets start from HTTP request server might just keep-alive till it timeouts the socket. That involves the delay.
In your case you are trying to perform handshake and then send data back and forth, but WebSockets are a bit more complex process than that.
The handshake process requires some security procedure to validate both ends (server and client) and it is HTTP compatible headers. But different draft versions supported by different platforms and browsers do implement it in a different manner so your implementation should take this in account as well and follow official documentation on WebSockets specification based on versions you need to support.
Then sending and receiving data via WebSockets is not pure string. Actual data sent over WebSockets protocol has data-framing layer, which involves adding header to each message you send. This header has details over message you sending, masking (from client to server), length and many other things. data-framing depends on version of WebSockets again, so implementations will vary slightly.
I would encourage to use existing libraries as they already implement everything you need in nice and clean manner, and have been used extensively across commercial projects.
As your client is embedded platform, and server I assume is node.js as well, it is easy to use same library on both ends.
Best suit here would be ws - actual pure WebSockets.
Socket.IO is not good for your case, as it is much more complex and heavy library that has multiple list of protocols support with fallbacks and have some abstraction that might be not what you are looking for.

Exception Handling in REST

I have created a REST service using WCF for communicating with BLL/DAL from UI. Now, I would like to implement Exception Handling through some globalize way in REST. I am using HTTPClient to communicate with REST from client. The following are the ways, I have implemented exception handling:
Approach 1:
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = System.Net.HttpStatusCode.Unauthorized;
response.StatusDescription = ex.Message;
success = false;
Approach 2:
throw new WebProtocolException(HttpStatusCode.NotFound, ex.Message, null);
but somehow I am not able to catch them in the client side. Kindly suggest some pointers in order to handle exceptions raised by service globally.
I am throwing WebProtocolException (Approach 2) along with error code and error message from the service to UI in order to notify users about the exception. I am able to receive the error code in UI side but not getting error message or detail.
Then I created another service (having .svc extension) and added following line to the service's markup: "Factory='Microsoft.ServiceModel.Web.WebServiceHost2Factory'". Now, I am able to receive the error message along with error code on client side (UI).
Can anybody let me know how to use the WebServiceHost2Factory method in my existing service which is a class file instead of .svc file?
Any suggestions will be highly appreciated. Thanks
HttpClient does not throw exceptions when a response comes back that is not "successful". If you really want exceptions to be thrown on the client side, then call
response.EnsureResponseIsSuccessful();
Otherwise, just check the status code on the client and decide what to do based on that value.
You cannot throw exceptions on the server and expect the exceptions to be propagated to the client. HTTP does not have any notion of exception.