use of org.jocean.http.client.HttpClient.HttpInitiator in project jocean-http by isdom.
the class DefaultHttpClientTestCase method testInitiatorInteractionStillActiveAsHttps10ConnectionClose.
@Test(timeout = 5000)
public void testInitiatorInteractionStillActiveAsHttps10ConnectionClose() throws Exception {
// 配置 池化分配器 为 取消缓存,使用 Heap
configDefaultAllocator();
final PooledByteBufAllocator allocator = defaultAllocator();
final BlockingQueue<HttpTrade> trades = new ArrayBlockingQueue<>(1);
final String addr = UUID.randomUUID().toString();
final Subscription server = TestHttpUtil.createTestServerWith(addr, trades, enableSSL4ServerWithSelfSigned(), Feature.ENABLE_LOGGING_OVER_SSL);
final DefaultHttpClient client = new DefaultHttpClient(new TestChannelCreator(), enableSSL4Client(), Feature.ENABLE_LOGGING_OVER_SSL);
try {
final HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/");
request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
startInteraction(client.initiator().remoteAddress(new LocalAddress(addr)), Observable.just(request), new Interaction() {
@Override
public void interact(final HttpInitiator initiator, final Observable<DisposableWrapper<FullHttpResponse>> getresp) throws Exception {
final Observable<DisposableWrapper<FullHttpResponse>> cached = getresp.cache();
cached.subscribe();
// server side recv req
final HttpTrade trade = trades.take();
// recv all request
trade.inbound().toCompletable().await();
final ByteBuf svrRespContent = allocator.buffer(CONTENT.length).writeBytes(CONTENT);
// for HTTP 1.0 Connection: Close response behavior
final FullHttpResponse fullrespfromsvr = new DefaultFullHttpResponse(HttpVersion.HTTP_1_0, HttpResponseStatus.OK, svrRespContent);
fullrespfromsvr.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
// missing Content-Length
// response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
fullrespfromsvr.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
trade.outbound(Observable.just(fullrespfromsvr));
// wait for recv all resp at client side
cached.toCompletable().await();
svrRespContent.release();
TerminateAware.Util.awaitTerminated(trade);
final Channel channel = (Channel) initiator.transport();
assertTrue(!channel.isActive());
assertTrue(initiator.isActive());
assertTrue(Arrays.equals(dumpResponseContentAsBytes(cached), CONTENT));
}
});
} finally {
assertEquals(0, allActiveAllocationsCount(allocator));
client.close();
server.unsubscribe();
}
}
use of org.jocean.http.client.HttpClient.HttpInitiator in project jocean-http by isdom.
the class DefaultHttpClientTestCase method testInitiatorInteractionUnsubscribedAlreadyAsHttp.
@Test(timeout = 5000)
public void testInitiatorInteractionUnsubscribedAlreadyAsHttp() throws Exception {
// 配置 池化分配器 为 取消缓存,使用 Heap
configDefaultAllocator();
final PooledByteBufAllocator allocator = defaultAllocator();
final String addr = UUID.randomUUID().toString();
final BlockingQueue<HttpTrade> trades = new ArrayBlockingQueue<>(1);
final Subscription server = TestHttpUtil.createTestServerWith(addr, trades, Feature.ENABLE_LOGGING);
final DefaultHttpClient client = new DefaultHttpClient(new TestChannelCreator(), Feature.ENABLE_LOGGING);
assertEquals(0, allActiveAllocationsCount(allocator));
try {
startInteraction(client.initiator().remoteAddress(new LocalAddress(addr)), Observable.just(fullHttpRequest()), new Interaction() {
@Override
public void interact(final HttpInitiator initiator, final Observable<DisposableWrapper<FullHttpResponse>> getresp) throws Exception {
final TestSubscriber<DisposableWrapper<FullHttpResponse>> subscriber = new TestSubscriber<>();
subscriber.unsubscribe();
final Subscription subscription = getresp.subscribe(subscriber);
assertTrue(subscription.isUnsubscribed());
subscriber.assertNoTerminalEvent();
subscriber.assertNoValues();
}
});
assertEquals(0, allActiveAllocationsCount(allocator));
} finally {
client.close();
server.unsubscribe();
}
}
use of org.jocean.http.client.HttpClient.HttpInitiator in project jocean-http by isdom.
the class DefaultHttpServerBuilderTestCase method testTradeReadControl.
/* // TODO using initiator
@Test
public void testHttpHappyPathOnce() throws Exception {
final String testAddr = UUID.randomUUID().toString();
final HttpServerBuilder server = new DefaultHttpServerBuilder(
new AbstractBootstrapCreator(
new DefaultEventLoopGroup(1), new DefaultEventLoopGroup()) {
@Override
protected void initializeBootstrap(final ServerBootstrap bootstrap) {
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
bootstrap.channel(LocalServerChannel.class);
}});
final Subscription testServer =
server.defineServer(new LocalAddress(testAddr),
Feature.ENABLE_LOGGING,
Feature.ENABLE_COMPRESSOR)
.subscribe(echoReactor(null));
final DefaultHttpClient client = new DefaultHttpClient(new TestChannelCreator());
try {
final Iterator<HttpObject> itr =
client.defineInteraction(
new LocalAddress(testAddr),
Observable.just(buildFullRequest(CONTENT)),
Feature.ENABLE_LOGGING)
.map(RxNettys.<HttpObject>retainer())
.toBlocking().toIterable().iterator();
final byte[] bytes = RxNettys.httpObjectsAsBytes(itr);
assertTrue(Arrays.equals(bytes, CONTENT));
} finally {
client.close();
testServer.unsubscribe();
server.close();
}
}
@Test
public void testHttpHappyPathTwice() throws Exception {
final String testAddr = UUID.randomUUID().toString();
final HttpServerBuilder server = new DefaultHttpServerBuilder(
new AbstractBootstrapCreator(
new DefaultEventLoopGroup(1), new DefaultEventLoopGroup()) {
@Override
protected void initializeBootstrap(final ServerBootstrap bootstrap) {
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
bootstrap.channel(LocalServerChannel.class);
}});
final AtomicReference<Object> transportRef = new AtomicReference<Object>();
final Subscription testServer =
server.defineServer(new LocalAddress(testAddr),
Feature.ENABLE_LOGGING,
Feature.ENABLE_COMPRESSOR)
.subscribe(echoReactor(transportRef));
final TestChannelPool pool = new TestChannelPool(1);
final DefaultHttpClient client = new DefaultHttpClient(new TestChannelCreator(), pool);
try {
final CountDownLatch unsubscribed = new CountDownLatch(1);
final Iterator<HttpObject> itr =
client.defineInteraction(
new LocalAddress(testAddr),
Observable.just(buildFullRequest(CONTENT)),
Feature.ENABLE_LOGGING)
.compose(RxFunctions.<HttpObject>countDownOnUnsubscribe(unsubscribed))
.map(RxNettys.<HttpObject>retainer())
.toBlocking().toIterable().iterator();
final byte[] bytes = RxNettys.httpObjectsAsBytes(itr);
assertTrue(Arrays.equals(bytes, CONTENT));
final Object channel1 = transportRef.get();
unsubscribed.await();
// await for 1 second
pool.awaitRecycleChannels(1);
// TODO
// TOBE fix, client maybe not reused, so server channel not reused,
// so ensure client channel will be reused
final Iterator<HttpObject> itr2 =
client.defineInteraction(
new LocalAddress(testAddr),
Observable.just(buildFullRequest(CONTENT)),
Feature.ENABLE_LOGGING)
.map(RxNettys.<HttpObject>retainer())
.toBlocking().toIterable().iterator();
final byte[] bytes2 = RxNettys.httpObjectsAsBytes(itr2);
assertTrue(Arrays.equals(bytes2, CONTENT));
final Object channel2 = transportRef.get();
assertTrue(channel1 == channel2);
} finally {
client.close();
testServer.unsubscribe();
server.close();
}
}
*/
@Test
public void testTradeReadControl() throws Exception {
final String testAddr = UUID.randomUUID().toString();
final HttpServerBuilder server = new DefaultHttpServerBuilder(new AbstractBootstrapCreator(new DefaultEventLoopGroup(1), new DefaultEventLoopGroup()) {
@Override
protected void initializeBootstrap(final ServerBootstrap bootstrap) {
bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
bootstrap.channel(LocalServerChannel.class);
}
});
final BlockingQueue<HttpTrade> trades = new ArrayBlockingQueue<>(2);
final Subscription testServer = server.defineServer(new LocalAddress(testAddr), Feature.ENABLE_LOGGING, Feature.ENABLE_COMPRESSOR).subscribe(new Action1<HttpTrade>() {
@Override
public void call(final HttpTrade trade) {
LOG.debug("on trade {}", trade);
try {
trades.put(trade);
LOG.debug("after offer trade {}", trade);
} catch (InterruptedException e) {
LOG.warn("exception when put trade, detail: {}", ExceptionUtils.exception2detail(e));
}
}
});
final TestChannelPool pool = new TestChannelPool(1);
final DefaultHttpClient client = new DefaultHttpClient(new TestChannelCreator(), pool);
try (final HttpInitiator initiator = client.initiator().remoteAddress(new LocalAddress(testAddr)).build().toBlocking().single()) {
final FullHttpRequest reqToSend1 = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
initiator.defineInteraction(Observable.just(reqToSend1)).subscribe();
final HttpTrade trade1 = trades.take();
// trade receive all inbound msg
// trade1.obsrequest().toCompletable().await();
final FullHttpRequest reqReceived1 = trade1.inbound().compose(RxNettys.message2fullreq(trade1)).toBlocking().single().unwrap();
assertEquals(reqToSend1, reqReceived1);
final Channel channel = (Channel) initiator.transport();
final FullHttpRequest reqToSend2 = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/2nd");
channel.writeAndFlush(reqToSend2).sync();
assertTrue(null == trades.poll(1L, TimeUnit.SECONDS));
// after send other interaction req, then first trade send response
final FullHttpResponse responseToSend1 = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(CONTENT));
trade1.outbound(Observable.<HttpObject>just(responseToSend1));
// initiator.inbound().message().toCompletable().await();
// final FullHttpResponse resp = initiator.inbound().messageHolder().
// httpMessageBuilder(RxNettys.BUILD_FULL_RESPONSE).call();
// assertEquals(responseToSend1, resp);
final HttpTrade trade2 = trades.take();
// receive all inbound msg
// trade2.obsrequest().toCompletable().await();
final FullHttpRequest reqReceived2 = trade2.inbound().compose(RxNettys.message2fullreq(trade2)).toBlocking().single().unwrap();
assertEquals(reqToSend2, reqReceived2);
} finally {
client.close();
testServer.unsubscribe();
server.close();
}
}
use of org.jocean.http.client.HttpClient.HttpInitiator in project jocean-http by isdom.
the class DefaultSignalClient method defineInteraction.
private <RESP> Observable<RESP> defineInteraction(final Object signalBean, final Feature... features) {
final Feature[] fullfeatures = Feature.Util.union(RosaProfiles._DEFAULT_PROFILE, features);
final URI uri = req2uri(signalBean, fullfeatures);
return _httpClient.initiator().remoteAddress(safeGetAddress(signalBean, uri)).feature(genFeatures4HttpClient(signalBean, fullfeatures)).build().flatMap(new Func1<HttpInitiator, Observable<RESP>>() {
@Override
public Observable<RESP> call(final HttpInitiator initiator) {
return initiator.defineInteraction(outboundMessageOf(signalBean, initRequestOf(uri), fullfeatures, initiator.onTerminate())).compose(RxNettys.message2fullresp(initiator, true)).map(new Func1<DisposableWrapper<FullHttpResponse>, RESP>() {
@Override
public RESP call(final DisposableWrapper<FullHttpResponse> dwresp) {
try {
return toRESP(dwresp.unwrap(), safeGetResponseType(fullfeatures), safeGetResponseBodyType(signalBean, fullfeatures));
} finally {
dwresp.dispose();
}
}
}).doOnUnsubscribe(initiator.closer());
}
}).retryWhen(_RETRY);
}
use of org.jocean.http.client.HttpClient.HttpInitiator in project jocean-http by isdom.
the class MessageUtil method interact.
public static Interact interact(final HttpClient client) {
final InitiatorBuilder _initiatorBuilder = client.initiator();
final AtomicBoolean _isSSLEnabled = new AtomicBoolean(false);
final AtomicReference<Observable<Object>> _obsreqRef = new AtomicReference<>(fullRequestWithoutBody(HttpVersion.HTTP_1_1, HttpMethod.GET));
final List<String> _nvs = new ArrayList<>();
final AtomicReference<URI> _uriRef = new AtomicReference<>();
return new Interact() {
private void updateObsRequest(final Action1<Object> action) {
_obsreqRef.set(_obsreqRef.get().doOnNext(action));
}
private void addQueryParams() {
if (!_nvs.isEmpty()) {
updateObsRequest(MessageUtil.addQueryParam(_nvs.toArray(new String[0])));
}
}
private void extractUriWithHost(final Object... reqbeans) {
if (null == _uriRef.get()) {
for (Object bean : reqbeans) {
try {
final Path path = bean.getClass().getAnnotation(Path.class);
if (null != path) {
final URI uri = new URI(path.value());
if (null != uri.getHost()) {
uri(path.value());
return;
}
}
} catch (Exception e) {
LOG.warn("exception when extract uri from bean {}, detail: {}", bean, ExceptionUtils.exception2detail(e));
}
}
}
}
private void checkAddr() {
if (null == _uriRef.get()) {
throw new RuntimeException("remote address not set.");
}
}
private InitiatorBuilder addSSLFeatureIfNeed(final InitiatorBuilder builder) {
if (_isSSLEnabled.get()) {
return builder;
} else if ("https".equals(_uriRef.get().getScheme())) {
return builder.feature(F_SSL);
} else {
return builder;
}
}
@Override
public Interact method(final HttpMethod method) {
updateObsRequest(MessageUtil.setMethod(method));
return this;
}
@Override
public Interact uri(final String uriAsString) {
try {
final URI uri = new URI(uriAsString);
_uriRef.set(uri);
_initiatorBuilder.remoteAddress(uri2addr(uri));
updateObsRequest(MessageUtil.setHost(uri));
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
return this;
}
@Override
public Interact path(final String path) {
updateObsRequest(MessageUtil.setPath(path));
return this;
}
@Override
public Interact paramAsQuery(final String name, final String value) {
_nvs.add(name);
_nvs.add(value);
return this;
}
@Override
public Interact reqbean(final Object... reqbeans) {
updateObsRequest(MessageUtil.toRequest(reqbeans));
extractUriWithHost(reqbeans);
return this;
}
@Override
public Interact body(final Observable<? extends MessageBody> body) {
_obsreqRef.set(_obsreqRef.get().compose(MessageUtil.addBody(body)));
return this;
}
@Override
public Interact body(final Object bean, final ContentEncoder contentEncoder) {
return body(toBody(bean, contentEncoder.contentType(), contentEncoder.encoder()));
}
// @Override
// public Interact disposeBodyOnTerminate(final boolean doDispose) {
// _doDisposeBody.set(doDispose);
// return this;
// }
@Override
public Interact onrequest(final Action1<Object> action) {
updateObsRequest(action);
return this;
}
@Override
public Interact feature(final Feature... features) {
_initiatorBuilder.feature(features);
if (isSSLEnabled(features)) {
_isSSLEnabled.set(true);
}
return this;
}
private boolean isSSLEnabled(final Feature... features) {
for (Feature f : features) {
if (f instanceof Feature.ENABLE_SSL) {
return true;
}
}
return false;
}
private Observable<? extends Object> hookDisposeBody(final Observable<Object> obsreq, final HttpInitiator initiator) {
return obsreq.doOnNext(DisposableWrapperUtil.disposeOnForAny(initiator));
}
private Observable<? extends DisposableWrapper<HttpObject>> defineInteraction(final HttpInitiator initiator) {
return initiator.defineInteraction(hookDisposeBody(_obsreqRef.get(), initiator));
}
@Override
public Observable<? extends Interaction> execution() {
checkAddr();
addQueryParams();
return addSSLFeatureIfNeed(_initiatorBuilder).build().map(new Func1<HttpInitiator, Interaction>() {
@Override
public Interaction call(final HttpInitiator initiator) {
final Observable<? extends DisposableWrapper<HttpObject>> interaction = defineInteraction(initiator);
return new Interaction() {
@Override
public HttpInitiator initiator() {
return initiator;
}
@Override
public Observable<? extends DisposableWrapper<HttpObject>> execute() {
return interaction;
}
};
}
});
}
};
}
Aggregations