arturobernalg commented on PR #733:
URL:
https://github.com/apache/httpcomponents-core/pull/733#issuecomment-6559726012
Reproducer, run against master 450ef92a4. It sends a POST carrying both
Content-Length and Transfer-Encoding, followed by a pipelined GET, to the
classic and to the async server.
```java
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.Message;
import org.apache.hc.core5.http.URIScheme;
import org.apache.hc.core5.http.impl.bootstrap.AsyncServerBootstrap;
import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
import org.apache.hc.core5.http.nio.support.BasicResponseProducer;
import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.io.CloseMode;
public class PipelinedTeCl {
static final String RAW = "POST /a HTTP/1.1\r\nHost:
localhost\r\nContent-Length: 6\r\n"
+ "Transfer-Encoding: chunked\r\n\r\n5\r\nAAAAA\r\n0\r\n\r\n"
+ "GET /b HTTP/1.1\r\nHost: localhost\r\n\r\n";
static int responses(final int port) throws Exception {
try (Socket s = new Socket("localhost", port)) {
s.setSoTimeout(2000);
s.getOutputStream().write(RAW.getBytes(StandardCharsets.ISO_8859_1));
final StringBuilder sb = new StringBuilder();
final InputStream in = s.getInputStream();
final byte[] b = new byte[1024];
try {
int n;
while ((n = in.read(b)) != -1) {
sb.append(new String(b, 0, n,
StandardCharsets.ISO_8859_1));
}
} catch (final SocketTimeoutException ignore) {
}
return sb.toString().split("HTTP/1.1 200 OK", -1).length - 1;
}
}
public static void main(final String[] args) throws Exception {
final AtomicInteger calls = new AtomicInteger();
final HttpServer classic = ServerBootstrap.bootstrap()
.setCanonicalHostName("localhost")
.register("*", (request, response, context) -> {
calls.incrementAndGet();
response.setEntity(new StringEntity("ok"));
})
.create();
classic.start();
System.out.println("classic server: responses=" +
responses(classic.getLocalPort())
+ " handler calls=" + calls.get());
classic.close(CloseMode.IMMEDIATE);
calls.set(0);
final HttpAsyncServer async = AsyncServerBootstrap.bootstrap()
.setCanonicalHostName("localhost")
.register("*", () -> new BasicServerExchangeHandler<>(
new AsyncServerRequestHandler<Message<HttpRequest,
String>>() {
@Override
public AsyncRequestConsumer<Message<HttpRequest,
String>> prepare(
final HttpRequest request, final
EntityDetails entityDetails,
final HttpContext context) {
return new BasicRequestConsumer<>(new
StringAsyncEntityConsumer());
}
@Override
public void handle(
final Message<HttpRequest, String>
message, final ResponseTrigger trigger,
final HttpContext context) throws
java.io.IOException,
org.apache.hc.core5.http.HttpException {
calls.incrementAndGet();
trigger.submitResponse(new
BasicResponseProducer(200, "ok"), context);
}
}))
.create();
async.start();
final int port = ((InetSocketAddress) async.listen(new
InetSocketAddress(0), URIScheme.HTTP)
.get().getAddress()).getPort();
System.out.println("async server: responses=" + responses(port) +
" handler calls=" + calls.get());
async.close(CloseMode.IMMEDIATE);
}
}
```
Output:
```
classic server: responses=1 handler calls=1
async server: responses=2 handler calls=2
```
Both servers frame the request by Transfer-Encoding, so answering the
pipelined GET is correct under that framing. The difference is that the classic
server closes the connection after the first response, as the reuse strategy
says, while the async server has already read the next request by then and
answers it too. It only matters behind a front end that frames by
Content-Length. I do not claim more than that.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]