Failed to read HTTP message:ion: JSON parse error: Unexpected end-of-input in VALUE_STRING : Unexpected EOF read on the socket - rest

When a client is sending an image to one of the rest endpoints, only part of the data is being received.
To be sure what is happening I made a trace with Wireshark and analyzed it. The application is indeed not receiving the last part of the message. This is because the application is not able to receive all the data within the 900ms timeout that is specified on the Client side. Its buffers are full halfway through the reception.
I get application warning
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
[http-nio-0.0.0.0-9999-exec-35] Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException:
I/O error while reading input message; nested exception is
java.io.EOFException: Unexpected EOF read on the socket
And the client gets Connection timeout.

I have got a solution to my problem. I have increased the socket buffer size in my application. I have added following code to my Application class.
#Bean
public EmbeddedServletContainerFactory embeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory = new TomcatEmbeddedServletContainerFactory();
tomcatEmbeddedServletContainerFactory.setProtocol("org.apache.coyote.http11.Http11Nio2Protocol");
tomcatEmbeddedServletContainerFactory.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
connector.setProperty("socket.rxBufSize", "5000000");
});
return tomcatEmbeddedServletContainerFactory;
}

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

TCP Socket connection- Unable to read data sent from external client even after serializing through ByteArrayLengthHeaderSerializer

I have implemented TCP socket server which accepts incoming XML messages from client. I could send messages through telnet.
But when I am trying to establish connection and send message through python script, I was getting IOException:CRLF not found before max message length: 2048.So I have added ByteArrayLengthHeaderSerializer to serialize and deserialize, but now I am getting below error.
IOException:Message length 1014132591 exceeds max message length: 2048
Though I am increasing the max message length I am getting IOException:Stream closed after 46 of 1014132591
Could someone let me know how to fix the issue.
final AbstractServerConnectionFactory crLfServer = context.getBean(AbstractServerConnectionFactory.class);
ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer();
serializer.setMaxMessageSize(1000 * 1024);
crLfServer.setSerializer(serializer);
crLfServer.setDeserializer(serializer);
I have implemented using Spring Integration.Below is the snippet for my inbound adapter
#Bean
public TcpReceivingChannelAdapter inboundAdapter(AbstractServerConnectionFactory connectionFactory) {
System.out.println("Creating inbound adapter");
TcpReceivingChannelAdapter inbound = new TcpReceivingChannelAdapter();
inbound.setConnectionFactory(connectionFactory);
//inbound.
inbound.setOutputChannel(fromTcp());
return inbound;
}
I think might be better to send exactly that CRLF in your script after the message. That will be exactly delimiter for the messages to deserialize. This is one what is used by the mentioned Telnet. However you need to come back to the default deserializer in the connection factory configuration.

NETTY 4.1.4: TCP Socket Server which replies back towards clients after processing requests

i'm new to Netty and intend to create a tcp socket server which reads the info of each client and replies back towards client before processing requests immediately ,i.e. sort of an acknowledgement towards client as and when the message enters overriden channelRead method of ChannelInboundHandlerAdapter class.
Please guide me in the above specified objective.
i'm currently trying the basic netty 4.1.4 echo server example however i wanted server to send back acknowledgement to the client so i updated channelread method as follows :
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg);
ChannelFuture cf = ctx.channel().write("FROM SERVER");
System.out.println("Channelfuture is "+cf);
}
and the output obtained was as follows:
Channelfuture is DefaultChannelPromise#3f4ee9dd(failure: java.lang.UnsupportedOperationException: unsupported message type: String (expected: ByteBuf, FileRegion))
I understand the error that it is expecting bytebuf but how do i achieve it? also, whether this method would be able to send out acknowledgement towards client
You can use String.getBytes(Charset) and Unpooled.wrappedBuffer(byte[]) to convert to ByteBuf.
ChannelFuture cf = ctx.channel()
.write(Unpooled.wrappedBuffer("FROM SERVER".getBytes(CharsetUtil.UTF_8)));
Also note that ctx.channel().write(...); may not be what you want. Consider ctx.write(...); instead. The difference is that if your handler is a ChannelDuplexHandler it would receive a write event when you do channel().write(). Using ctx instead of channel will send the write out from your handlers point in the pipeline instead of from the end of the pipeline, which is usually what you want.

(Winsock TCP programming) How to determine if there is a message to be received?

I've made a TCP Server and a client but I got stuck on a probably very simple thing.
There are two functions, "recv()" and "send()". "recv()" can return different values like "SOCKET_ERROR" (and others) that signs that connection was lost or something else.
In the server (which is threaded), a message "Connecting..." is sent when a client connects and then either "Connection successful" or "Connection failed" followed by the error. In short it can either be:
send(...) //Connecting...
...
send(...) //Connection successful
or:
send(...) //Connecting...
...
send(...) //Connection failed
...
send(...) //The error
How can I check if there is a message waiting to be received?
You can use select(...) API on socket to wait for N milliseconds to check if message is ready to be received or if send API can be executed without blocking.