Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id D0107200C80 for ; Thu, 11 May 2017 08:12:44 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id CEAB6160BB4; Thu, 11 May 2017 06:12:44 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 7AB4C160B9C for ; Thu, 11 May 2017 08:12:42 +0200 (CEST) Received: (qmail 80131 invoked by uid 500); 11 May 2017 06:12:41 -0000 Mailing-List: contact dev-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list dev@hc.apache.org Received: (qmail 80116 invoked by uid 99); 11 May 2017 06:12:41 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd2-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 11 May 2017 06:12:41 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd2-us-west.apache.org (ASF Mail Server at spamd2-us-west.apache.org) with ESMTP id 7F86A1A0077 for ; Thu, 11 May 2017 06:12:40 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd2-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 0.765 X-Spam-Level: X-Spam-Status: No, score=0.765 tagged_above=-999 required=6.31 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=2, HTML_OBFUSCATE_10_20=1.162, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-2.796, RCVD_IN_SORBS_SPAM=0.5, SPF_PASS=-0.001] autolearn=disabled Authentication-Results: spamd2-us-west.apache.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd2-us-west.apache.org [10.40.0.9]) (amavisd-new, port 10024) with ESMTP id KZNECpLsi3X6 for ; Thu, 11 May 2017 06:12:18 +0000 (UTC) Received: from mail-oi0-f44.google.com (mail-oi0-f44.google.com [209.85.218.44]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with ESMTPS id 384205FC84 for ; Thu, 11 May 2017 06:12:17 +0000 (UTC) Received: by mail-oi0-f44.google.com with SMTP id b204so18978371oii.1 for ; Wed, 10 May 2017 23:12:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=PTOh5S4Gfc6cHe16StIkaYMeN2tqYrhxgbm13WzLVo0=; b=iR7i8pgmKNQc4QTzGCzo/leRsP1kYR+GzZZ4JKrPNmi5250Njed5s1QjSVSD32h4Hv ReEv9Exp+lbHBHlcZao8PMnU4uN9d15w7vStO+B0DEdRt06DUeMJqGVA0M513Ex+UoRE OJJv8l1V4XIm8S3lyiSPkNgRjMB99tKOuNIHQ+lOfZ/EnvtLoyVL8rwZyiHQS/g+cdgf VYCTQJkYZxBRrsN8VxlcE62gXvb2BxnkRK+pD+n0GlArLTuMPvtoj6C2Nq9SABGaW2ZH Oz0qgSS/mc+9yFo1H1HfjKNZHvszoHTuv7fP3kznb2TER9cvtBZhbEznTDpAqoWIFqWb hARA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=PTOh5S4Gfc6cHe16StIkaYMeN2tqYrhxgbm13WzLVo0=; b=Xdhwf0y50mhN3NMsNLqkVv/L2Y2QCHkcpm0rxIwxAsiZieaBVGWkTSWu4xIe10m4Lh JrX0c1W7RFmTwlHuVwNmyxg3g5548eUACbUIeDDiGW98KIvPjEcIDlyLBLhiNDznYnL4 GDMLJRV4e+DJrK7JrkIjyjdMvRBw1+5Yqr9e38Kh5EWASd/Ntw/1iPb0EatUZwe/2HKy pi3wrVI3uAkf9NlyHq8qNCg8mw26k+A/1IFGXQSxRo5jzelfV0seKVt8nRJb0iqBd2mL R9Wu6IUkwf+GCupoOgyaVqnXSKvY0mneS12nmnF59iBpZ+AY2zxOfvRWJvezb7bhkqzV DLPw== X-Gm-Message-State: AODbwcByQUn9cXhr67/NDLWvVQZU8PSITaeHoOY6e1JKAwuUjuxVwvJ/ zCI25vgk8WWmVtapGldqPprmWKQ9r7BO9Tw= X-Received: by 10.157.82.25 with SMTP id e25mr4975478oth.153.1494483135239; Wed, 10 May 2017 23:12:15 -0700 (PDT) MIME-Version: 1.0 Received: by 10.157.56.18 with HTTP; Wed, 10 May 2017 23:12:14 -0700 (PDT) In-Reply-To: References: <609700be729c4eeeb6fc76bb33d907a4@git.apache.org> From: Gary Gregory Date: Wed, 10 May 2017 23:12:14 -0700 Message-ID: Subject: Re: httpcomponents-core git commit: Remove unused ctor from this example. To: HttpComponents Project Content-Type: multipart/alternative; boundary=f40304354dd4662054054f3978a8 archived-at: Thu, 11 May 2017 06:12:45 -0000 --f40304354dd4662054054f3978a8 Content-Type: text/plain; charset=UTF-8 Running 'git config core.autocrlf' returns 'true'. What next? Gary On Wed, May 10, 2017 at 7:33 PM, Gary Gregory wrote: > Oh crud, this must be some EOL issue again. Tips? > > Gary > > ---------- Forwarded message ---------- > From: > Date: Wed, May 10, 2017 at 6:52 PM > Subject: httpcomponents-core git commit: Remove unused ctor from this > example. > To: commits@hc.apache.org > > > Repository: httpcomponents-core > Updated Branches: > refs/heads/4.4.x 5b29a6e4a -> 0be867829 > > > Remove unused ctor from this example. > > Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/repo > Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/c > ommit/0be86782 > Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/t > ree/0be86782 > Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-core/d > iff/0be86782 > > Branch: refs/heads/4.4.x > Commit: 0be8678299f1cb7c9da34e2db90b737f13d40048 > Parents: 5b29a6e > Author: Gary Gregory > Authored: Wed May 10 18:52:13 2017 -0700 > Committer: Gary Gregory > Committed: Wed May 10 18:52:13 2017 -0700 > > ---------------------------------------------------------------------- > .../http/examples/nio/NHttpReverseProxy.java | 1794 +++++++++--------- > 1 file changed, 894 insertions(+), 900 deletions(-) > ---------------------------------------------------------------------- > > > http://git-wip-us.apache.org/repos/asf/httpcomponents-core/b > lob/0be86782/httpcore-nio/src/examples/org/apache/http/examp > les/nio/NHttpReverseProxy.java > ---------------------------------------------------------------------- > diff --git a/httpcore-nio/src/examples/org/apache/http/examples/nio/NHttpReverseProxy.java > b/httpcore-nio/src/examples/org/apache/http/examples/nio/NHt > tpReverseProxy.java > index 82dfa23..632bd2c 100644 > --- a/httpcore-nio/src/examples/org/apache/http/examples/nio/NHt > tpReverseProxy.java > +++ b/httpcore-nio/src/examples/org/apache/http/examples/nio/NHt > tpReverseProxy.java > @@ -1,900 +1,894 @@ > -/* > - * ==================================================================== > - * Licensed to the Apache Software Foundation (ASF) under one > - * or more contributor license agreements. See the NOTICE file > - * distributed with this work for additional information > - * regarding copyright ownership. The ASF licenses this file > - * to you under the Apache License, Version 2.0 (the > - * "License"); you may not use this file except in compliance > - * with the License. You may obtain a copy of the License at > - * > - * http://www.apache.org/licenses/LICENSE-2.0 > - * > - * Unless required by applicable law or agreed to in writing, > - * software distributed under the License is distributed on an > - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > - * KIND, either express or implied. See the License for the > - * specific language governing permissions and limitations > - * under the License. > - * ==================================================================== > - * > - * This software consists of voluntary contributions made by many > - * individuals on behalf of the Apache Software Foundation. For more > - * information on the Apache Software Foundation, please see > - * . > - * > - */ > -package org.apache.http.examples.nio; > - > -import java.io.IOException; > -import java.io.InterruptedIOException; > -import java.net.InetSocketAddress; > -import java.net.URI; > -import java.nio.ByteBuffer; > -import java.security.cert.CertificateException; > -import java.security.cert.X509Certificate; > -import java.util.Locale; > -import java.util.concurrent.atomic.AtomicLong; > - > -import javax.net.ssl.SSLContext; > - > -import org.apache.http.ConnectionReuseStrategy; > -import org.apache.http.HttpEntityEnclosingRequest; > -import org.apache.http.HttpException; > -import org.apache.http.HttpHost; > -import org.apache.http.HttpRequest; > -import org.apache.http.HttpRequestInterceptor; > -import org.apache.http.HttpResponse; > -import org.apache.http.HttpResponseInterceptor; > -import org.apache.http.HttpStatus; > -import org.apache.http.HttpVersion; > -import org.apache.http.config.ConnectionConfig; > -import org.apache.http.entity.ContentType; > -import org.apache.http.impl.DefaultConnectionReuseStrategy; > -import org.apache.http.impl.EnglishReasonPhraseCatalog; > -import org.apache.http.impl.nio.DefaultHttpClientIODispatch; > -import org.apache.http.impl.nio.DefaultHttpServerIODispatch; > -import org.apache.http.impl.nio.DefaultNHttpClientConnectionFactory; > -import org.apache.http.impl.nio.SSLNHttpClientConnectionFactory; > -import org.apache.http.impl.nio.pool.BasicNIOConnFactory; > -import org.apache.http.impl.nio.pool.BasicNIOConnPool; > -import org.apache.http.impl.nio.pool.BasicNIOPoolEntry; > -import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; > -import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor; > -import org.apache.http.impl.nio.reactor.IOReactorConfig; > -import org.apache.http.message.BasicHttpEntityEnclosingRequest; > -import org.apache.http.message.BasicHttpRequest; > -import org.apache.http.message.BasicHttpResponse; > -import org.apache.http.nio.ContentDecoder; > -import org.apache.http.nio.ContentEncoder; > -import org.apache.http.nio.IOControl; > -import org.apache.http.nio.NHttpClientConnection; > -import org.apache.http.nio.NHttpConnection; > -import org.apache.http.nio.NHttpServerConnection; > -import org.apache.http.nio.entity.NStringEntity; > -import org.apache.http.nio.pool.NIOConnFactory; > -import org.apache.http.nio.protocol.BasicAsyncResponseProducer; > -import org.apache.http.nio.protocol.HttpAsyncExchange; > -import org.apache.http.nio.protocol.HttpAsyncRequestConsumer; > -import org.apache.http.nio.protocol.HttpAsyncRequestExecutor; > -import org.apache.http.nio.protocol.HttpAsyncRequestHandler; > -import org.apache.http.nio.protocol.HttpAsyncRequestHandlerMapper; > -import org.apache.http.nio.protocol.HttpAsyncRequestProducer; > -import org.apache.http.nio.protocol.HttpAsyncRequester; > -import org.apache.http.nio.protocol.HttpAsyncResponseConsumer; > -import org.apache.http.nio.protocol.HttpAsyncResponseProducer; > -import org.apache.http.nio.protocol.HttpAsyncService; > -import org.apache.http.nio.protocol.UriHttpAsyncRequestHandlerMapper; > -import org.apache.http.nio.reactor.ConnectingIOReactor; > -import org.apache.http.nio.reactor.IOEventDispatch; > -import org.apache.http.nio.reactor.ListeningIOReactor; > -import org.apache.http.pool.PoolStats; > -import org.apache.http.protocol.HttpContext; > -import org.apache.http.protocol.HttpCoreContext; > -import org.apache.http.protocol.HttpProcessor; > -import org.apache.http.protocol.ImmutableHttpProcessor; > -import org.apache.http.protocol.RequestConnControl; > -import org.apache.http.protocol.RequestContent; > -import org.apache.http.protocol.RequestExpectContinue; > -import org.apache.http.protocol.RequestTargetHost; > -import org.apache.http.protocol.RequestUserAgent; > -import org.apache.http.protocol.ResponseConnControl; > -import org.apache.http.protocol.ResponseContent; > -import org.apache.http.protocol.ResponseDate; > -import org.apache.http.protocol.ResponseServer; > -import org.apache.http.ssl.SSLContextBuilder; > -import org.apache.http.ssl.TrustStrategy; > - > -/** > - * Asynchronous, fully streaming HTTP/1.1 reverse proxy. > - *

> - * Supports SSL to origin servers which use self-signed certificates. > - *

> - */ > -public class NHttpReverseProxy { > - > - public static void main(String[] args) throws Exception { > - if (args.length < 2) { > - System.out.println("Usage: NHttpReverseProxy > [\"TrustSelfSignedStrategy\"]"); > - System.exit(1); > - } > - // Extract command line arguments > - URI uri = new URI(args[0]); > - int port = Integer.parseInt(args[1]); > - SSLContext sslContext = null; > - if (args.length > 2 && args[2].equals("TrustSelfSignedStrategy")) > { > - System.out.println("Using TrustSelfSignedStrategy (not for > production)"); > - sslContext = SSLContextBuilder.create().loadTrustMaterial(new > TrustStrategy() { > - > - @Override > - public boolean isTrusted( > - final X509Certificate[] chain, final String authType) > throws CertificateException { > - return chain.length == 1; > - } > - > - }).build(); > - } > - > - // Target host > - HttpHost targetHost = new HttpHost( > - uri.getHost(), > - uri.getPort() > 0 ? uri.getPort() : 80, > - uri.getScheme() != null ? uri.getScheme() : "http"); > - > - System.out.println("Reverse proxy to " + targetHost); > - > - IOReactorConfig config = IOReactorConfig.custom() > - .setIoThreadCount(1) > - .setSoTimeout(3000) > - .setConnectTimeout(3000) > - .build(); > - final ConnectingIOReactor connectingIOReactor = new > DefaultConnectingIOReactor(config); > - final ListeningIOReactor listeningIOReactor = new > DefaultListeningIOReactor(config); > - > - // Set up HTTP protocol processor for incoming connections > - HttpProcessor inhttpproc = new ImmutableHttpProcessor( > - new HttpResponseInterceptor[] { > - new ResponseDate(), > - new ResponseServer("Test/1.1"), > - new ResponseContent(), > - new ResponseConnControl() > - }); > - > - // Set up HTTP protocol processor for outgoing connections > - HttpProcessor outhttpproc = new ImmutableHttpProcessor( > - new HttpRequestInterceptor[] { > - new RequestContent(), > - new RequestTargetHost(), > - new RequestConnControl(), > - new RequestUserAgent("Test/1.1"), > - new RequestExpectContinue(true) > - }); > - > - ProxyClientProtocolHandler clientHandler = new > ProxyClientProtocolHandler(); > - HttpAsyncRequester executor = new HttpAsyncRequester( > - outhttpproc, new ProxyOutgoingConnectionReuseStrategy()); > - > - // Without SSL: ProxyConnPool connPool = new > ProxyConnPool(connectingIOReactor, ConnectionConfig.DEFAULT); > - ProxyConnPool connPool = new ProxyConnPool(connectingIOReactor, > - new BasicNIOConnFactory(new DefaultNHttpClientConnectionFa > ctory(ConnectionConfig.DEFAULT), > - new SSLNHttpClientConnectionFactory(sslContext, > null, ConnectionConfig.DEFAULT)), > - 0); > - connPool.setMaxTotal(100); > - connPool.setDefaultMaxPerRoute(20); > - > - UriHttpAsyncRequestHandlerMapper handlerRegistry = new > UriHttpAsyncRequestHandlerMapper(); > - handlerRegistry.register("*", new ProxyRequestHandler(targetHost, > executor, connPool)); > - > - ProxyServiceHandler serviceHandler = new ProxyServiceHandler( > - inhttpproc, > - new ProxyIncomingConnectionReuseStrategy(), > - handlerRegistry); > - > - final IOEventDispatch connectingEventDispatch = > DefaultHttpClientIODispatch.create( > - clientHandler, sslContext, ConnectionConfig.DEFAULT); > - > - final IOEventDispatch listeningEventDispatch = new > DefaultHttpServerIODispatch( > - serviceHandler, ConnectionConfig.DEFAULT); > - > - Thread t = new Thread(new Runnable() { > - > - public void run() { > - try { > - connectingIOReactor.execute(connectingEventDispatch); > - } catch (InterruptedIOException ex) { > - System.err.println("Interrupted"); > - } catch (IOException ex) { > - ex.printStackTrace(); > - } finally { > - try { > - listeningIOReactor.shutdown(); > - } catch (IOException ex2) { > - ex2.printStackTrace(); > - } > - } > - } > - > - }); > - t.start(); > - try { > - listeningIOReactor.listen(new InetSocketAddress(port)); > - listeningIOReactor.execute(listeningEventDispatch); > - } catch (InterruptedIOException ex) { > - System.err.println("Interrupted"); > - } catch (IOException ex) { > - ex.printStackTrace(); > - } finally { > - try { > - connectingIOReactor.shutdown(); > - } catch (IOException ex2) { > - ex2.printStackTrace(); > - } > - } > - } > - > - static class ProxyHttpExchange { > - > - private final ByteBuffer inBuffer; > - private final ByteBuffer outBuffer; > - > - private volatile String id; > - private volatile HttpHost target; > - private volatile HttpAsyncExchange responseTrigger; > - private volatile IOControl originIOControl; > - private volatile IOControl clientIOControl; > - private volatile HttpRequest request; > - private volatile boolean requestReceived; > - private volatile HttpResponse response; > - private volatile boolean responseReceived; > - private volatile Exception ex; > - > - public ProxyHttpExchange() { > - super(); > - this.inBuffer = ByteBuffer.allocateDirect(10240); > - this.outBuffer = ByteBuffer.allocateDirect(10240); > - } > - > - public ByteBuffer getInBuffer() { > - return this.inBuffer; > - } > - > - public ByteBuffer getOutBuffer() { > - return this.outBuffer; > - } > - > - public String getId() { > - return this.id; > - } > - > - public void setId(final String id) { > - this.id = id; > - } > - > - public HttpHost getTarget() { > - return this.target; > - } > - > - public void setTarget(final HttpHost target) { > - this.target = target; > - } > - > - public HttpRequest getRequest() { > - return this.request; > - } > - > - public void setRequest(final HttpRequest request) { > - this.request = request; > - } > - > - public HttpResponse getResponse() { > - return this.response; > - } > - > - public void setResponse(final HttpResponse response) { > - this.response = response; > - } > - > - public HttpAsyncExchange getResponseTrigger() { > - return this.responseTrigger; > - } > - > - public void setResponseTrigger(final HttpAsyncExchange > responseTrigger) { > - this.responseTrigger = responseTrigger; > - } > - > - public IOControl getClientIOControl() { > - return this.clientIOControl; > - } > - > - public void setClientIOControl(final IOControl clientIOControl) { > - this.clientIOControl = clientIOControl; > - } > - > - public IOControl getOriginIOControl() { > - return this.originIOControl; > - } > - > - public void setOriginIOControl(final IOControl originIOControl) { > - this.originIOControl = originIOControl; > - } > - > - public boolean isRequestReceived() { > - return this.requestReceived; > - } > - > - public void setRequestReceived() { > - this.requestReceived = true; > - } > - > - public boolean isResponseReceived() { > - return this.responseReceived; > - } > - > - public void setResponseReceived() { > - this.responseReceived = true; > - } > - > - public Exception getException() { > - return this.ex; > - } > - > - public void setException(final Exception ex) { > - this.ex = ex; > - } > - > - public void reset() { > - this.inBuffer.clear(); > - this.outBuffer.clear(); > - this.target = null; > - this.id = null; > - this.responseTrigger = null; > - this.clientIOControl = null; > - this.originIOControl = null; > - this.request = null; > - this.requestReceived = false; > - this.response = null; > - this.responseReceived = false; > - this.ex = null; > - } > - > - } > - > - static class ProxyRequestHandler implements > HttpAsyncRequestHandler { > - > - private final HttpHost target; > - private final HttpAsyncRequester executor; > - private final BasicNIOConnPool connPool; > - private final AtomicLong counter; > - > - public ProxyRequestHandler( > - final HttpHost target, > - final HttpAsyncRequester executor, > - final BasicNIOConnPool connPool) { > - super(); > - this.target = target; > - this.executor = executor; > - this.connPool = connPool; > - this.counter = new AtomicLong(1); > - } > - > - public HttpAsyncRequestConsumer > processRequest( > - final HttpRequest request, > - final HttpContext context) { > - ProxyHttpExchange httpExchange = (ProxyHttpExchange) > context.getAttribute("http-exchange"); > - if (httpExchange == null) { > - httpExchange = new ProxyHttpExchange(); > - context.setAttribute("http-exchange", httpExchange); > - } > - synchronized (httpExchange) { > - httpExchange.reset(); > - String id = String.format("%08X", > this.counter.getAndIncrement()); > - httpExchange.setId(id); > - httpExchange.setTarget(this.target); > - return new ProxyRequestConsumer(httpExchange, > this.executor, this.connPool); > - } > - } > - > - public void handle( > - final ProxyHttpExchange httpExchange, > - final HttpAsyncExchange responseTrigger, > - final HttpContext context) throws HttpException, > IOException { > - synchronized (httpExchange) { > - Exception ex = httpExchange.getException(); > - if (ex != null) { > - System.out.println("[client<-proxy] " + > httpExchange.getId() + " " + ex); > - int status = HttpStatus.SC_INTERNAL_SERVER_ERROR; > - HttpResponse response = new > BasicHttpResponse(HttpVersion.HTTP_1_0, status, > - EnglishReasonPhraseCatalog.INSTANCE.getReason(status, > Locale.US)); > - String message = ex.getMessage(); > - if (message == null) { > - message = "Unexpected error"; > - } > - response.setEntity(new NStringEntity(message, > ContentType.DEFAULT_TEXT)); > - responseTrigger.submitResponse(new > BasicAsyncResponseProducer(response)); > - System.out.println("[client<-proxy] " + > httpExchange.getId() + " error response triggered"); > - } > - HttpResponse response = httpExchange.getResponse(); > - if (response != null) { > - responseTrigger.submitResponse(new > ProxyResponseProducer(httpExchange)); > - System.out.println("[client<-proxy] " + > httpExchange.getId() + " response triggered"); > - } > - // No response yet. > - httpExchange.setResponseTrigger(responseTrigger); > - } > - } > - > - } > - > - static class ProxyRequestConsumer implements > HttpAsyncRequestConsumer { > - > - private final ProxyHttpExchange httpExchange; > - private final HttpAsyncRequester executor; > - private final BasicNIOConnPool connPool; > - > - private volatile boolean completed; > - > - public ProxyRequestConsumer( > - final ProxyHttpExchange httpExchange, > - final HttpAsyncRequester executor, > - final BasicNIOConnPool connPool) { > - super(); > - this.httpExchange = httpExchange; > - this.executor = executor; > - this.connPool = connPool; > - } > - > - public void close() throws IOException { > - } > - > - public void requestReceived(final HttpRequest request) { > - synchronized (this.httpExchange) { > - System.out.println("[client->proxy] " + > this.httpExchange.getId() + " " + request.getRequestLine()); > - this.httpExchange.setRequest(request); > - this.executor.execute( > - new ProxyRequestProducer(this.httpExchange), > - new ProxyResponseConsumer(this.httpExchange), > - this.connPool); > - } > - } > - > - public void consumeContent( > - final ContentDecoder decoder, final IOControl ioctrl) > throws IOException { > - synchronized (this.httpExchange) { > - this.httpExchange.setClientIOControl(ioctrl); > - // Receive data from the client > - ByteBuffer buf = this.httpExchange.getInBuffer(); > - int n = decoder.read(buf); > - System.out.println("[client->proxy] " + > this.httpExchange.getId() + " " + n + " bytes read"); > - if (decoder.isCompleted()) { > - System.out.println("[client->proxy] " + > this.httpExchange.getId() + " content fully read"); > - } > - // If the buffer is full, suspend client input until > there is free > - // space in the buffer > - if (!buf.hasRemaining()) { > - ioctrl.suspendInput(); > - System.out.println("[client->proxy] " + > this.httpExchange.getId() + " suspend client input"); > - } > - // If there is some content in the input buffer make sure > origin > - // output is active > - if (buf.position() > 0) { > - if (this.httpExchange.getOriginIOControl() != null) { > - this.httpExchange.getOriginIOC > ontrol().requestOutput(); > - System.out.println("[client->proxy] " + > this.httpExchange.getId() + " request origin output"); > - } > - } > - } > - } > - > - public void requestCompleted(final HttpContext context) { > - synchronized (this.httpExchange) { > - this.completed = true;; > - System.out.println("[client->proxy] " + > this.httpExchange.getId() + " request completed"); > - this.httpExchange.setRequestReceived(); > - if (this.httpExchange.getOriginIOControl() != null) { > - this.httpExchange.getOriginIOC > ontrol().requestOutput(); > - System.out.println("[client->proxy] " + > this.httpExchange.getId() + " request origin output"); > - } > - } > - } > - > - public Exception getException() { > - return null; > - } > - > - public ProxyHttpExchange getResult() { > - return this.httpExchange; > - } > - > - public boolean isDone() { > - return this.completed; > - } > - > - public void failed(final Exception ex) { > - System.out.println("[client->proxy] " + ex.toString()); > - } > - > - } > - > - static class ProxyRequestProducer implements HttpAsyncRequestProducer > { > - > - private final ProxyHttpExchange httpExchange; > - > - public ProxyRequestProducer(final ProxyHttpExchange httpExchange) > { > - super(); > - this.httpExchange = httpExchange; > - } > - > - public void close() throws IOException { > - } > - > - public HttpHost getTarget() { > - synchronized (this.httpExchange) { > - return this.httpExchange.getTarget(); > - } > - } > - > - public HttpRequest generateRequest() { > - synchronized (this.httpExchange) { > - HttpRequest request = this.httpExchange.getRequest(); > - System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " " + request.getRequestLine()); > - // Rewrite request!!!! > - if (request instanceof HttpEntityEnclosingRequest) { > - BasicHttpEntityEnclosingRequest r = new > BasicHttpEntityEnclosingRequest( > - request.getRequestLine()); > - r.setEntity(((HttpEntityEnclosingRequest) > request).getEntity()); > - return r; > - } else { > - return new BasicHttpRequest(request.getRe > questLine()); > - } > - } > - } > - > - public void produceContent( > - final ContentEncoder encoder, final IOControl ioctrl) > throws IOException { > - synchronized (this.httpExchange) { > - this.httpExchange.setOriginIOControl(ioctrl); > - // Send data to the origin server > - ByteBuffer buf = this.httpExchange.getInBuffer(); > - buf.flip(); > - int n = encoder.write(buf); > - buf.compact(); > - System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " " + n + " bytes written"); > - // If there is space in the buffer and the message has > not been > - // transferred, make sure the client is sending more data > - if (buf.hasRemaining() && !this.httpExchange.isRequestReceived()) > { > - if (this.httpExchange.getClientIOControl() != null) { > - this.httpExchange.getClientIOC > ontrol().requestInput(); > - System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " request client input"); > - } > - } > - if (buf.position() == 0) { > - if (this.httpExchange.isRequestReceived()) { > - encoder.complete(); > - System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " content fully written"); > - } else { > - // Input buffer is empty. Wait until the client > fills up > - // the buffer > - ioctrl.suspendOutput(); > - System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " suspend origin output"); > - } > - } > - } > - } > - > - public void requestCompleted(final HttpContext context) { > - synchronized (this.httpExchange) { > - System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " request completed"); > - } > - } > - > - public boolean isRepeatable() { > - return false; > - } > - > - public void resetRequest() { > - } > - > - public void failed(final Exception ex) { > - System.out.println("[proxy->origin] " + ex.toString()); > - } > - > - } > - > - static class ProxyResponseConsumer implements > HttpAsyncResponseConsumer { > - > - private final ProxyHttpExchange httpExchange; > - > - private volatile boolean completed; > - > - public ProxyResponseConsumer(final ProxyHttpExchange > httpExchange) { > - super(); > - this.httpExchange = httpExchange; > - } > - > - public void close() throws IOException { > - } > - > - public void responseReceived(final HttpResponse response) { > - synchronized (this.httpExchange) { > - System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " " + response.getStatusLine()); > - this.httpExchange.setResponse(response); > - HttpAsyncExchange responseTrigger = > this.httpExchange.getResponseTrigger(); > - if (responseTrigger != null && > !responseTrigger.isCompleted()) { > - System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " response triggered"); > - responseTrigger.submitResponse(new > ProxyResponseProducer(this.httpExchange)); > - } > - } > - } > - > - public void consumeContent( > - final ContentDecoder decoder, final IOControl ioctrl) > throws IOException { > - synchronized (this.httpExchange) { > - this.httpExchange.setOriginIOControl(ioctrl); > - // Receive data from the origin > - ByteBuffer buf = this.httpExchange.getOutBuffer(); > - int n = decoder.read(buf); > - System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " " + n + " bytes read"); > - if (decoder.isCompleted()) { > - System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " content fully read"); > - } > - // If the buffer is full, suspend origin input until > there is free > - // space in the buffer > - if (!buf.hasRemaining()) { > - ioctrl.suspendInput(); > - System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " suspend origin input"); > - } > - // If there is some content in the input buffer make sure > client > - // output is active > - if (buf.position() > 0) { > - if (this.httpExchange.getClientIOControl() != null) { > - this.httpExchange.getClientIOC > ontrol().requestOutput(); > - System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " request client output"); > - } > - } > - } > - } > - > - public void responseCompleted(final HttpContext context) { > - synchronized (this.httpExchange) { > - if (this.completed) { > - return; > - } > - this.completed = true; > - System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " response completed"); > - this.httpExchange.setResponseReceived(); > - if (this.httpExchange.getClientIOControl() != null) { > - this.httpExchange.getClientIOC > ontrol().requestOutput(); > - System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " request client output"); > - } > - } > - } > - > - public void failed(final Exception ex) { > - synchronized (this.httpExchange) { > - if (this.completed) { > - return; > - } > - this.completed = true; > - this.httpExchange.setException(ex); > - HttpAsyncExchange responseTrigger = > this.httpExchange.getResponseTrigger(); > - if (responseTrigger != null && > !responseTrigger.isCompleted()) { > - System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " " + ex); > - int status = HttpStatus.SC_INTERNAL_SERVER_ERROR; > - HttpResponse response = new > BasicHttpResponse(HttpVersion.HTTP_1_0, status, > - EnglishReasonPhraseCatalog.INSTANCE.getReason(status, > Locale.US)); > - String message = ex.getMessage(); > - if (message == null) { > - message = "Unexpected error"; > - } > - response.setEntity(new NStringEntity(message, > ContentType.DEFAULT_TEXT)); > - responseTrigger.submitResponse(new > BasicAsyncResponseProducer(response)); > - } > - } > - } > - > - public boolean cancel() { > - synchronized (this.httpExchange) { > - if (this.completed) { > - return false; > - } > - failed(new InterruptedIOException("Cancelled")); > - return true; > - } > - } > - > - public ProxyHttpExchange getResult() { > - return this.httpExchange; > - } > - > - public Exception getException() { > - return null; > - } > - > - public boolean isDone() { > - return this.completed; > - } > - > - } > - > - static class ProxyResponseProducer implements > HttpAsyncResponseProducer { > - > - private final ProxyHttpExchange httpExchange; > - > - public ProxyResponseProducer(final ProxyHttpExchange > httpExchange) { > - super(); > - this.httpExchange = httpExchange; > - } > - > - public void close() throws IOException { > - this.httpExchange.reset(); > - } > - > - public HttpResponse generateResponse() { > - synchronized (this.httpExchange) { > - HttpResponse response = this.httpExchange.getResponse(); > - System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " " + response.getStatusLine()); > - // Rewrite response!!!! > - BasicHttpResponse r = new BasicHttpResponse(response.get > StatusLine()); > - r.setEntity(response.getEntity()); > - return r; > - } > - } > - > - public void produceContent( > - final ContentEncoder encoder, final IOControl ioctrl) > throws IOException { > - synchronized (this.httpExchange) { > - this.httpExchange.setClientIOControl(ioctrl); > - // Send data to the client > - ByteBuffer buf = this.httpExchange.getOutBuffer(); > - buf.flip(); > - int n = encoder.write(buf); > - buf.compact(); > - System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " " + n + " bytes written"); > - // If there is space in the buffer and the message has > not been > - // transferred, make sure the origin is sending more data > - if (buf.hasRemaining() && !this.httpExchange.isResponseReceived()) > { > - if (this.httpExchange.getOriginIOControl() != null) { > - this.httpExchange.getOriginIOC > ontrol().requestInput(); > - System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " request origin input"); > - } > - } > - if (buf.position() == 0) { > - if (this.httpExchange.isResponseReceived()) { > - encoder.complete(); > - System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " content fully written"); > - } else { > - // Input buffer is empty. Wait until the origin > fills up > - // the buffer > - ioctrl.suspendOutput(); > - System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " suspend client output"); > - } > - } > - } > - } > - > - public void responseCompleted(final HttpContext context) { > - synchronized (this.httpExchange) { > - System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " response completed"); > - } > - } > - > - public void failed(final Exception ex) { > - System.out.println("[client<-proxy] " + ex.toString()); > - } > - > - } > - > - static class ProxyIncomingConnectionReuseStrategy extends > DefaultConnectionReuseStrategy { > - > - @Override > - public boolean keepAlive(final HttpResponse response, final > HttpContext context) { > - NHttpConnection conn = (NHttpConnection) context.getAttribute( > - HttpCoreContext.HTTP_CONNECTION); > - boolean keepAlive = super.keepAlive(response, context); > - if (keepAlive) { > - System.out.println("[client->proxy] connection kept > alive " + conn); > - } > - return keepAlive; > - } > - > - }; > - > - static class ProxyOutgoingConnectionReuseStrategy extends > DefaultConnectionReuseStrategy { > - > - @Override > - public boolean keepAlive(final HttpResponse response, final > HttpContext context) { > - NHttpConnection conn = (NHttpConnection) context.getAttribute( > - HttpCoreContext.HTTP_CONNECTION); > - boolean keepAlive = super.keepAlive(response, context); > - if (keepAlive) { > - System.out.println("[proxy->origin] connection kept > alive " + conn); > - } > - return keepAlive; > - } > - > - }; > - > - static class ProxyServiceHandler extends HttpAsyncService { > - > - public ProxyServiceHandler( > - final HttpProcessor httpProcessor, > - final ConnectionReuseStrategy reuseStrategy, > - final HttpAsyncRequestHandlerMapper handlerResolver) { > - super(httpProcessor, reuseStrategy, null, handlerResolver, > null); > - } > - > - @Override > - protected void log(final Exception ex) { > - ex.printStackTrace(); > - } > - > - @Override > - public void connected(final NHttpServerConnection conn) { > - System.out.println("[client->proxy] connection open " + > conn); > - super.connected(conn); > - } > - > - @Override > - public void closed(final NHttpServerConnection conn) { > - System.out.println("[client->proxy] connection closed " + > conn); > - super.closed(conn); > - } > - > - } > - > - static class ProxyClientProtocolHandler extends > HttpAsyncRequestExecutor { > - > - public ProxyClientProtocolHandler() { > - super(); > - } > - > - @Override > - protected void log(final Exception ex) { > - ex.printStackTrace(); > - } > - > - @Override > - public void connected(final NHttpClientConnection conn, > - final Object attachment) throws IOException, > HttpException { > - System.out.println("[proxy->origin] connection open " + > conn); > - super.connected(conn, attachment); > - } > - > - @Override > - public void closed(final NHttpClientConnection conn) { > - System.out.println("[proxy->origin] connection closed " + > conn); > - super.closed(conn); > - } > - > - } > - > - static class ProxyConnPool extends BasicNIOConnPool { > - > - public ProxyConnPool( > - final ConnectingIOReactor ioreactor, > - final ConnectionConfig config) { > - super(ioreactor, config); > - } > - > - public ProxyConnPool( > - final ConnectingIOReactor ioreactor, > - final NIOConnFactory > connFactory, > - final int connectTimeout) { > - super(ioreactor, connFactory, connectTimeout); > - } > - > - @Override > - public void release(final BasicNIOPoolEntry entry, boolean > reusable) { > - System.out.println("[proxy->origin] connection released " + > entry.getConnection()); > - super.release(entry, reusable); > - StringBuilder buf = new StringBuilder(); > - PoolStats totals = getTotalStats(); > - buf.append("[total kept alive: ").append(totals.getAvailable()).append("; > "); > - buf.append("total allocated: ").append(totals.getLeased() + > totals.getAvailable()); > - buf.append(" of ").append(totals.getMax()).append("]"); > - System.out.println("[proxy->origin] " + buf.toString()); > - } > - > - } > - > -} > +/* > + * ==================================================================== > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + * ==================================================================== > + * > + * This software consists of voluntary contributions made by many > + * individuals on behalf of the Apache Software Foundation. For more > + * information on the Apache Software Foundation, please see > + * . > + * > + */ > +package org.apache.http.examples.nio; > + > +import java.io.IOException; > +import java.io.InterruptedIOException; > +import java.net.InetSocketAddress; > +import java.net.URI; > +import java.nio.ByteBuffer; > +import java.security.cert.CertificateException; > +import java.security.cert.X509Certificate; > +import java.util.Locale; > +import java.util.concurrent.atomic.AtomicLong; > + > +import javax.net.ssl.SSLContext; > + > +import org.apache.http.ConnectionReuseStrategy; > +import org.apache.http.HttpEntityEnclosingRequest; > +import org.apache.http.HttpException; > +import org.apache.http.HttpHost; > +import org.apache.http.HttpRequest; > +import org.apache.http.HttpRequestInterceptor; > +import org.apache.http.HttpResponse; > +import org.apache.http.HttpResponseInterceptor; > +import org.apache.http.HttpStatus; > +import org.apache.http.HttpVersion; > +import org.apache.http.config.ConnectionConfig; > +import org.apache.http.entity.ContentType; > +import org.apache.http.impl.DefaultConnectionReuseStrategy; > +import org.apache.http.impl.EnglishReasonPhraseCatalog; > +import org.apache.http.impl.nio.DefaultHttpClientIODispatch; > +import org.apache.http.impl.nio.DefaultHttpServerIODispatch; > +import org.apache.http.impl.nio.DefaultNHttpClientConnectionFactory; > +import org.apache.http.impl.nio.SSLNHttpClientConnectionFactory; > +import org.apache.http.impl.nio.pool.BasicNIOConnFactory; > +import org.apache.http.impl.nio.pool.BasicNIOConnPool; > +import org.apache.http.impl.nio.pool.BasicNIOPoolEntry; > +import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; > +import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor; > +import org.apache.http.impl.nio.reactor.IOReactorConfig; > +import org.apache.http.message.BasicHttpEntityEnclosingRequest; > +import org.apache.http.message.BasicHttpRequest; > +import org.apache.http.message.BasicHttpResponse; > +import org.apache.http.nio.ContentDecoder; > +import org.apache.http.nio.ContentEncoder; > +import org.apache.http.nio.IOControl; > +import org.apache.http.nio.NHttpClientConnection; > +import org.apache.http.nio.NHttpConnection; > +import org.apache.http.nio.NHttpServerConnection; > +import org.apache.http.nio.entity.NStringEntity; > +import org.apache.http.nio.pool.NIOConnFactory; > +import org.apache.http.nio.protocol.BasicAsyncResponseProducer; > +import org.apache.http.nio.protocol.HttpAsyncExchange; > +import org.apache.http.nio.protocol.HttpAsyncRequestConsumer; > +import org.apache.http.nio.protocol.HttpAsyncRequestExecutor; > +import org.apache.http.nio.protocol.HttpAsyncRequestHandler; > +import org.apache.http.nio.protocol.HttpAsyncRequestHandlerMapper; > +import org.apache.http.nio.protocol.HttpAsyncRequestProducer; > +import org.apache.http.nio.protocol.HttpAsyncRequester; > +import org.apache.http.nio.protocol.HttpAsyncResponseConsumer; > +import org.apache.http.nio.protocol.HttpAsyncResponseProducer; > +import org.apache.http.nio.protocol.HttpAsyncService; > +import org.apache.http.nio.protocol.UriHttpAsyncRequestHandlerMapper; > +import org.apache.http.nio.reactor.ConnectingIOReactor; > +import org.apache.http.nio.reactor.IOEventDispatch; > +import org.apache.http.nio.reactor.ListeningIOReactor; > +import org.apache.http.pool.PoolStats; > +import org.apache.http.protocol.HttpContext; > +import org.apache.http.protocol.HttpCoreContext; > +import org.apache.http.protocol.HttpProcessor; > +import org.apache.http.protocol.ImmutableHttpProcessor; > +import org.apache.http.protocol.RequestConnControl; > +import org.apache.http.protocol.RequestContent; > +import org.apache.http.protocol.RequestExpectContinue; > +import org.apache.http.protocol.RequestTargetHost; > +import org.apache.http.protocol.RequestUserAgent; > +import org.apache.http.protocol.ResponseConnControl; > +import org.apache.http.protocol.ResponseContent; > +import org.apache.http.protocol.ResponseDate; > +import org.apache.http.protocol.ResponseServer; > +import org.apache.http.ssl.SSLContextBuilder; > +import org.apache.http.ssl.TrustStrategy; > + > +/** > + * Asynchronous, fully streaming HTTP/1.1 reverse proxy. > + *

> + * Supports SSL to origin servers which use self-signed certificates. > + *

> + */ > +public class NHttpReverseProxy { > + > + public static void main(String[] args) throws Exception { > + if (args.length < 2) { > + System.out.println("Usage: NHttpReverseProxy > [\"TrustSelfSignedStrategy\"]"); > + System.exit(1); > + } > + // Extract command line arguments > + URI uri = new URI(args[0]); > + int port = Integer.parseInt(args[1]); > + SSLContext sslContext = null; > + if (args.length > 2 && args[2].equals("TrustSelfSignedStrategy")) > { > + System.out.println("Using TrustSelfSignedStrategy (not for > production)"); > + sslContext = SSLContextBuilder.create().loadTrustMaterial(new > TrustStrategy() { > + > + @Override > + public boolean isTrusted( > + final X509Certificate[] chain, final String authType) > throws CertificateException { > + return chain.length == 1; > + } > + > + }).build(); > + } > + > + // Target host > + HttpHost targetHost = new HttpHost( > + uri.getHost(), > + uri.getPort() > 0 ? uri.getPort() : 80, > + uri.getScheme() != null ? uri.getScheme() : "http"); > + > + System.out.println("Reverse proxy to " + targetHost); > + > + IOReactorConfig config = IOReactorConfig.custom() > + .setIoThreadCount(1) > + .setSoTimeout(3000) > + .setConnectTimeout(3000) > + .build(); > + final ConnectingIOReactor connectingIOReactor = new > DefaultConnectingIOReactor(config); > + final ListeningIOReactor listeningIOReactor = new > DefaultListeningIOReactor(config); > + > + // Set up HTTP protocol processor for incoming connections > + HttpProcessor inhttpproc = new ImmutableHttpProcessor( > + new HttpResponseInterceptor[] { > + new ResponseDate(), > + new ResponseServer("Test/1.1"), > + new ResponseContent(), > + new ResponseConnControl() > + }); > + > + // Set up HTTP protocol processor for outgoing connections > + HttpProcessor outhttpproc = new ImmutableHttpProcessor( > + new HttpRequestInterceptor[] { > + new RequestContent(), > + new RequestTargetHost(), > + new RequestConnControl(), > + new RequestUserAgent("Test/1.1"), > + new RequestExpectContinue(true) > + }); > + > + ProxyClientProtocolHandler clientHandler = new > ProxyClientProtocolHandler(); > + HttpAsyncRequester executor = new HttpAsyncRequester( > + outhttpproc, new ProxyOutgoingConnectionReuseStrategy()); > + > + // Without SSL: ProxyConnPool connPool = new > ProxyConnPool(connectingIOReactor, ConnectionConfig.DEFAULT); > + ProxyConnPool connPool = new ProxyConnPool(connectingIOReactor, > + new BasicNIOConnFactory(new DefaultNHttpClientConnectionFa > ctory(ConnectionConfig.DEFAULT), > + new SSLNHttpClientConnectionFactory(sslContext, > null, ConnectionConfig.DEFAULT)), > + 0); > + connPool.setMaxTotal(100); > + connPool.setDefaultMaxPerRoute(20); > + > + UriHttpAsyncRequestHandlerMapper handlerRegistry = new > UriHttpAsyncRequestHandlerMapper(); > + handlerRegistry.register("*", new ProxyRequestHandler(targetHost, > executor, connPool)); > + > + ProxyServiceHandler serviceHandler = new ProxyServiceHandler( > + inhttpproc, > + new ProxyIncomingConnectionReuseStrategy(), > + handlerRegistry); > + > + final IOEventDispatch connectingEventDispatch = > DefaultHttpClientIODispatch.create( > + clientHandler, sslContext, ConnectionConfig.DEFAULT); > + > + final IOEventDispatch listeningEventDispatch = new > DefaultHttpServerIODispatch( > + serviceHandler, ConnectionConfig.DEFAULT); > + > + Thread t = new Thread(new Runnable() { > + > + public void run() { > + try { > + connectingIOReactor.execute(connectingEventDispatch); > + } catch (InterruptedIOException ex) { > + System.err.println("Interrupted"); > + } catch (IOException ex) { > + ex.printStackTrace(); > + } finally { > + try { > + listeningIOReactor.shutdown(); > + } catch (IOException ex2) { > + ex2.printStackTrace(); > + } > + } > + } > + > + }); > + t.start(); > + try { > + listeningIOReactor.listen(new InetSocketAddress(port)); > + listeningIOReactor.execute(listeningEventDispatch); > + } catch (InterruptedIOException ex) { > + System.err.println("Interrupted"); > + } catch (IOException ex) { > + ex.printStackTrace(); > + } finally { > + try { > + connectingIOReactor.shutdown(); > + } catch (IOException ex2) { > + ex2.printStackTrace(); > + } > + } > + } > + > + static class ProxyHttpExchange { > + > + private final ByteBuffer inBuffer; > + private final ByteBuffer outBuffer; > + > + private volatile String id; > + private volatile HttpHost target; > + private volatile HttpAsyncExchange responseTrigger; > + private volatile IOControl originIOControl; > + private volatile IOControl clientIOControl; > + private volatile HttpRequest request; > + private volatile boolean requestReceived; > + private volatile HttpResponse response; > + private volatile boolean responseReceived; > + private volatile Exception ex; > + > + public ProxyHttpExchange() { > + super(); > + this.inBuffer = ByteBuffer.allocateDirect(10240); > + this.outBuffer = ByteBuffer.allocateDirect(10240); > + } > + > + public ByteBuffer getInBuffer() { > + return this.inBuffer; > + } > + > + public ByteBuffer getOutBuffer() { > + return this.outBuffer; > + } > + > + public String getId() { > + return this.id; > + } > + > + public void setId(final String id) { > + this.id = id; > + } > + > + public HttpHost getTarget() { > + return this.target; > + } > + > + public void setTarget(final HttpHost target) { > + this.target = target; > + } > + > + public HttpRequest getRequest() { > + return this.request; > + } > + > + public void setRequest(final HttpRequest request) { > + this.request = request; > + } > + > + public HttpResponse getResponse() { > + return this.response; > + } > + > + public void setResponse(final HttpResponse response) { > + this.response = response; > + } > + > + public HttpAsyncExchange getResponseTrigger() { > + return this.responseTrigger; > + } > + > + public void setResponseTrigger(final HttpAsyncExchange > responseTrigger) { > + this.responseTrigger = responseTrigger; > + } > + > + public IOControl getClientIOControl() { > + return this.clientIOControl; > + } > + > + public void setClientIOControl(final IOControl clientIOControl) { > + this.clientIOControl = clientIOControl; > + } > + > + public IOControl getOriginIOControl() { > + return this.originIOControl; > + } > + > + public void setOriginIOControl(final IOControl originIOControl) { > + this.originIOControl = originIOControl; > + } > + > + public boolean isRequestReceived() { > + return this.requestReceived; > + } > + > + public void setRequestReceived() { > + this.requestReceived = true; > + } > + > + public boolean isResponseReceived() { > + return this.responseReceived; > + } > + > + public void setResponseReceived() { > + this.responseReceived = true; > + } > + > + public Exception getException() { > + return this.ex; > + } > + > + public void setException(final Exception ex) { > + this.ex = ex; > + } > + > + public void reset() { > + this.inBuffer.clear(); > + this.outBuffer.clear(); > + this.target = null; > + this.id = null; > + this.responseTrigger = null; > + this.clientIOControl = null; > + this.originIOControl = null; > + this.request = null; > + this.requestReceived = false; > + this.response = null; > + this.responseReceived = false; > + this.ex = null; > + } > + > + } > + > + static class ProxyRequestHandler implements > HttpAsyncRequestHandler { > + > + private final HttpHost target; > + private final HttpAsyncRequester executor; > + private final BasicNIOConnPool connPool; > + private final AtomicLong counter; > + > + public ProxyRequestHandler( > + final HttpHost target, > + final HttpAsyncRequester executor, > + final BasicNIOConnPool connPool) { > + super(); > + this.target = target; > + this.executor = executor; > + this.connPool = connPool; > + this.counter = new AtomicLong(1); > + } > + > + public HttpAsyncRequestConsumer > processRequest( > + final HttpRequest request, > + final HttpContext context) { > + ProxyHttpExchange httpExchange = (ProxyHttpExchange) > context.getAttribute("http-exchange"); > + if (httpExchange == null) { > + httpExchange = new ProxyHttpExchange(); > + context.setAttribute("http-exchange", httpExchange); > + } > + synchronized (httpExchange) { > + httpExchange.reset(); > + String id = String.format("%08X", > this.counter.getAndIncrement()); > + httpExchange.setId(id); > + httpExchange.setTarget(this.target); > + return new ProxyRequestConsumer(httpExchange, > this.executor, this.connPool); > + } > + } > + > + public void handle( > + final ProxyHttpExchange httpExchange, > + final HttpAsyncExchange responseTrigger, > + final HttpContext context) throws HttpException, > IOException { > + synchronized (httpExchange) { > + Exception ex = httpExchange.getException(); > + if (ex != null) { > + System.out.println("[client<-proxy] " + > httpExchange.getId() + " " + ex); > + int status = HttpStatus.SC_INTERNAL_SERVER_ERROR; > + HttpResponse response = new > BasicHttpResponse(HttpVersion.HTTP_1_0, status, > + EnglishReasonPhraseCatalog.INSTANCE.getReason(status, > Locale.US)); > + String message = ex.getMessage(); > + if (message == null) { > + message = "Unexpected error"; > + } > + response.setEntity(new NStringEntity(message, > ContentType.DEFAULT_TEXT)); > + responseTrigger.submitResponse(new > BasicAsyncResponseProducer(response)); > + System.out.println("[client<-proxy] " + > httpExchange.getId() + " error response triggered"); > + } > + HttpResponse response = httpExchange.getResponse(); > + if (response != null) { > + responseTrigger.submitResponse(new > ProxyResponseProducer(httpExchange)); > + System.out.println("[client<-proxy] " + > httpExchange.getId() + " response triggered"); > + } > + // No response yet. > + httpExchange.setResponseTrigger(responseTrigger); > + } > + } > + > + } > + > + static class ProxyRequestConsumer implements > HttpAsyncRequestConsumer { > + > + private final ProxyHttpExchange httpExchange; > + private final HttpAsyncRequester executor; > + private final BasicNIOConnPool connPool; > + > + private volatile boolean completed; > + > + public ProxyRequestConsumer( > + final ProxyHttpExchange httpExchange, > + final HttpAsyncRequester executor, > + final BasicNIOConnPool connPool) { > + super(); > + this.httpExchange = httpExchange; > + this.executor = executor; > + this.connPool = connPool; > + } > + > + public void close() throws IOException { > + } > + > + public void requestReceived(final HttpRequest request) { > + synchronized (this.httpExchange) { > + System.out.println("[client->proxy] " + > this.httpExchange.getId() + " " + request.getRequestLine()); > + this.httpExchange.setRequest(request); > + this.executor.execute( > + new ProxyRequestProducer(this.httpExchange), > + new ProxyResponseConsumer(this.httpExchange), > + this.connPool); > + } > + } > + > + public void consumeContent( > + final ContentDecoder decoder, final IOControl ioctrl) > throws IOException { > + synchronized (this.httpExchange) { > + this.httpExchange.setClientIOControl(ioctrl); > + // Receive data from the client > + ByteBuffer buf = this.httpExchange.getInBuffer(); > + int n = decoder.read(buf); > + System.out.println("[client->proxy] " + > this.httpExchange.getId() + " " + n + " bytes read"); > + if (decoder.isCompleted()) { > + System.out.println("[client->proxy] " + > this.httpExchange.getId() + " content fully read"); > + } > + // If the buffer is full, suspend client input until > there is free > + // space in the buffer > + if (!buf.hasRemaining()) { > + ioctrl.suspendInput(); > + System.out.println("[client->proxy] " + > this.httpExchange.getId() + " suspend client input"); > + } > + // If there is some content in the input buffer make sure > origin > + // output is active > + if (buf.position() > 0) { > + if (this.httpExchange.getOriginIOControl() != null) { > + this.httpExchange.getOriginIOC > ontrol().requestOutput(); > + System.out.println("[client->proxy] " + > this.httpExchange.getId() + " request origin output"); > + } > + } > + } > + } > + > + public void requestCompleted(final HttpContext context) { > + synchronized (this.httpExchange) { > + this.completed = true;; > + System.out.println("[client->proxy] " + > this.httpExchange.getId() + " request completed"); > + this.httpExchange.setRequestReceived(); > + if (this.httpExchange.getOriginIOControl() != null) { > + this.httpExchange.getOriginIOC > ontrol().requestOutput(); > + System.out.println("[client->proxy] " + > this.httpExchange.getId() + " request origin output"); > + } > + } > + } > + > + public Exception getException() { > + return null; > + } > + > + public ProxyHttpExchange getResult() { > + return this.httpExchange; > + } > + > + public boolean isDone() { > + return this.completed; > + } > + > + public void failed(final Exception ex) { > + System.out.println("[client->proxy] " + ex.toString()); > + } > + > + } > + > + static class ProxyRequestProducer implements HttpAsyncRequestProducer > { > + > + private final ProxyHttpExchange httpExchange; > + > + public ProxyRequestProducer(final ProxyHttpExchange httpExchange) > { > + super(); > + this.httpExchange = httpExchange; > + } > + > + public void close() throws IOException { > + } > + > + public HttpHost getTarget() { > + synchronized (this.httpExchange) { > + return this.httpExchange.getTarget(); > + } > + } > + > + public HttpRequest generateRequest() { > + synchronized (this.httpExchange) { > + HttpRequest request = this.httpExchange.getRequest(); > + System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " " + request.getRequestLine()); > + // Rewrite request!!!! > + if (request instanceof HttpEntityEnclosingRequest) { > + BasicHttpEntityEnclosingRequest r = new > BasicHttpEntityEnclosingRequest( > + request.getRequestLine()); > + r.setEntity(((HttpEntityEnclosingRequest) > request).getEntity()); > + return r; > + } else { > + return new BasicHttpRequest(request.getRe > questLine()); > + } > + } > + } > + > + public void produceContent( > + final ContentEncoder encoder, final IOControl ioctrl) > throws IOException { > + synchronized (this.httpExchange) { > + this.httpExchange.setOriginIOControl(ioctrl); > + // Send data to the origin server > + ByteBuffer buf = this.httpExchange.getInBuffer(); > + buf.flip(); > + int n = encoder.write(buf); > + buf.compact(); > + System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " " + n + " bytes written"); > + // If there is space in the buffer and the message has > not been > + // transferred, make sure the client is sending more data > + if (buf.hasRemaining() && !this.httpExchange.isRequestReceived()) > { > + if (this.httpExchange.getClientIOControl() != null) { > + this.httpExchange.getClientIOC > ontrol().requestInput(); > + System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " request client input"); > + } > + } > + if (buf.position() == 0) { > + if (this.httpExchange.isRequestReceived()) { > + encoder.complete(); > + System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " content fully written"); > + } else { > + // Input buffer is empty. Wait until the client > fills up > + // the buffer > + ioctrl.suspendOutput(); > + System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " suspend origin output"); > + } > + } > + } > + } > + > + public void requestCompleted(final HttpContext context) { > + synchronized (this.httpExchange) { > + System.out.println("[proxy->origin] " + > this.httpExchange.getId() + " request completed"); > + } > + } > + > + public boolean isRepeatable() { > + return false; > + } > + > + public void resetRequest() { > + } > + > + public void failed(final Exception ex) { > + System.out.println("[proxy->origin] " + ex.toString()); > + } > + > + } > + > + static class ProxyResponseConsumer implements > HttpAsyncResponseConsumer { > + > + private final ProxyHttpExchange httpExchange; > + > + private volatile boolean completed; > + > + public ProxyResponseConsumer(final ProxyHttpExchange > httpExchange) { > + super(); > + this.httpExchange = httpExchange; > + } > + > + public void close() throws IOException { > + } > + > + public void responseReceived(final HttpResponse response) { > + synchronized (this.httpExchange) { > + System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " " + response.getStatusLine()); > + this.httpExchange.setResponse(response); > + HttpAsyncExchange responseTrigger = > this.httpExchange.getResponseTrigger(); > + if (responseTrigger != null && > !responseTrigger.isCompleted()) { > + System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " response triggered"); > + responseTrigger.submitResponse(new > ProxyResponseProducer(this.httpExchange)); > + } > + } > + } > + > + public void consumeContent( > + final ContentDecoder decoder, final IOControl ioctrl) > throws IOException { > + synchronized (this.httpExchange) { > + this.httpExchange.setOriginIOControl(ioctrl); > + // Receive data from the origin > + ByteBuffer buf = this.httpExchange.getOutBuffer(); > + int n = decoder.read(buf); > + System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " " + n + " bytes read"); > + if (decoder.isCompleted()) { > + System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " content fully read"); > + } > + // If the buffer is full, suspend origin input until > there is free > + // space in the buffer > + if (!buf.hasRemaining()) { > + ioctrl.suspendInput(); > + System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " suspend origin input"); > + } > + // If there is some content in the input buffer make sure > client > + // output is active > + if (buf.position() > 0) { > + if (this.httpExchange.getClientIOControl() != null) { > + this.httpExchange.getClientIOC > ontrol().requestOutput(); > + System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " request client output"); > + } > + } > + } > + } > + > + public void responseCompleted(final HttpContext context) { > + synchronized (this.httpExchange) { > + if (this.completed) { > + return; > + } > + this.completed = true; > + System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " response completed"); > + this.httpExchange.setResponseReceived(); > + if (this.httpExchange.getClientIOControl() != null) { > + this.httpExchange.getClientIOC > ontrol().requestOutput(); > + System.out.println("[proxy<-origin] " + > this.httpExchange.getId() + " request client output"); > + } > + } > + } > + > + public void failed(final Exception ex) { > + synchronized (this.httpExchange) { > + if (this.completed) { > + return; > + } > + this.completed = true; > + this.httpExchange.setException(ex); > + HttpAsyncExchange responseTrigger = > this.httpExchange.getResponseTrigger(); > + if (responseTrigger != null && > !responseTrigger.isCompleted()) { > + System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " " + ex); > + int status = HttpStatus.SC_INTERNAL_SERVER_ERROR; > + HttpResponse response = new > BasicHttpResponse(HttpVersion.HTTP_1_0, status, > + EnglishReasonPhraseCatalog.INSTANCE.getReason(status, > Locale.US)); > + String message = ex.getMessage(); > + if (message == null) { > + message = "Unexpected error"; > + } > + response.setEntity(new NStringEntity(message, > ContentType.DEFAULT_TEXT)); > + responseTrigger.submitResponse(new > BasicAsyncResponseProducer(response)); > + } > + } > + } > + > + public boolean cancel() { > + synchronized (this.httpExchange) { > + if (this.completed) { > + return false; > + } > + failed(new InterruptedIOException("Cancelled")); > + return true; > + } > + } > + > + public ProxyHttpExchange getResult() { > + return this.httpExchange; > + } > + > + public Exception getException() { > + return null; > + } > + > + public boolean isDone() { > + return this.completed; > + } > + > + } > + > + static class ProxyResponseProducer implements > HttpAsyncResponseProducer { > + > + private final ProxyHttpExchange httpExchange; > + > + public ProxyResponseProducer(final ProxyHttpExchange > httpExchange) { > + super(); > + this.httpExchange = httpExchange; > + } > + > + public void close() throws IOException { > + this.httpExchange.reset(); > + } > + > + public HttpResponse generateResponse() { > + synchronized (this.httpExchange) { > + HttpResponse response = this.httpExchange.getResponse(); > + System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " " + response.getStatusLine()); > + // Rewrite response!!!! > + BasicHttpResponse r = new BasicHttpResponse(response.get > StatusLine()); > + r.setEntity(response.getEntity()); > + return r; > + } > + } > + > + public void produceContent( > + final ContentEncoder encoder, final IOControl ioctrl) > throws IOException { > + synchronized (this.httpExchange) { > + this.httpExchange.setClientIOControl(ioctrl); > + // Send data to the client > + ByteBuffer buf = this.httpExchange.getOutBuffer(); > + buf.flip(); > + int n = encoder.write(buf); > + buf.compact(); > + System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " " + n + " bytes written"); > + // If there is space in the buffer and the message has > not been > + // transferred, make sure the origin is sending more data > + if (buf.hasRemaining() && !this.httpExchange.isResponseReceived()) > { > + if (this.httpExchange.getOriginIOControl() != null) { > + this.httpExchange.getOriginIOC > ontrol().requestInput(); > + System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " request origin input"); > + } > + } > + if (buf.position() == 0) { > + if (this.httpExchange.isResponseReceived()) { > + encoder.complete(); > + System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " content fully written"); > + } else { > + // Input buffer is empty. Wait until the origin > fills up > + // the buffer > + ioctrl.suspendOutput(); > + System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " suspend client output"); > + } > + } > + } > + } > + > + public void responseCompleted(final HttpContext context) { > + synchronized (this.httpExchange) { > + System.out.println("[client<-proxy] " + > this.httpExchange.getId() + " response completed"); > + } > + } > + > + public void failed(final Exception ex) { > + System.out.println("[client<-proxy] " + ex.toString()); > + } > + > + } > + > + static class ProxyIncomingConnectionReuseStrategy extends > DefaultConnectionReuseStrategy { > + > + @Override > + public boolean keepAlive(final HttpResponse response, final > HttpContext context) { > + NHttpConnection conn = (NHttpConnection) context.getAttribute( > + HttpCoreContext.HTTP_CONNECTION); > + boolean keepAlive = super.keepAlive(response, context); > + if (keepAlive) { > + System.out.println("[client->proxy] connection kept > alive " + conn); > + } > + return keepAlive; > + } > + > + }; > + > + static class ProxyOutgoingConnectionReuseStrategy extends > DefaultConnectionReuseStrategy { > + > + @Override > + public boolean keepAlive(final HttpResponse response, final > HttpContext context) { > + NHttpConnection conn = (NHttpConnection) context.getAttribute( > + HttpCoreContext.HTTP_CONNECTION); > + boolean keepAlive = super.keepAlive(response, context); > + if (keepAlive) { > + System.out.println("[proxy->origin] connection kept > alive " + conn); > + } > + return keepAlive; > + } > + > + }; > + > + static class ProxyServiceHandler extends HttpAsyncService { > + > + public ProxyServiceHandler( > + final HttpProcessor httpProcessor, > + final ConnectionReuseStrategy reuseStrategy, > + final HttpAsyncRequestHandlerMapper handlerResolver) { > + super(httpProcessor, reuseStrategy, null, handlerResolver, > null); > + } > + > + @Override > + protected void log(final Exception ex) { > + ex.printStackTrace(); > + } > + > + @Override > + public void connected(final NHttpServerConnection conn) { > + System.out.println("[client->proxy] connection open " + > conn); > + super.connected(conn); > + } > + > + @Override > + public void closed(final NHttpServerConnection conn) { > + System.out.println("[client->proxy] connection closed " + > conn); > + super.closed(conn); > + } > + > + } > + > + static class ProxyClientProtocolHandler extends > HttpAsyncRequestExecutor { > + > + public ProxyClientProtocolHandler() { > + super(); > + } > + > + @Override > + protected void log(final Exception ex) { > + ex.printStackTrace(); > + } > + > + @Override > + public void connected(final NHttpClientConnection conn, > + final Object attachment) throws IOException, > HttpException { > + System.out.println("[proxy->origin] connection open " + > conn); > + super.connected(conn, attachment); > + } > + > + @Override > + public void closed(final NHttpClientConnection conn) { > + System.out.println("[proxy->origin] connection closed " + > conn); > + super.closed(conn); > + } > + > + } > + > + static class ProxyConnPool extends BasicNIOConnPool { > + > + public ProxyConnPool( > + final ConnectingIOReactor ioreactor, > + final NIOConnFactory > connFactory, > + final int connectTimeout) { > + super(ioreactor, connFactory, connectTimeout); > + } > + > + @Override > + public void release(final BasicNIOPoolEntry entry, boolean > reusable) { > + System.out.println("[proxy->origin] connection released " + > entry.getConnection()); > + super.release(entry, reusable); > + StringBuilder buf = new StringBuilder(); > + PoolStats totals = getTotalStats(); > + buf.append("[total kept alive: ").append(totals.getAvailable()).append("; > "); > + buf.append("total allocated: ").append(totals.getLeased() + > totals.getAvailable()); > + buf.append(" of ").append(totals.getMax()).append("]"); > + System.out.println("[proxy->origin] " + buf.toString()); > + } > + > + } > + > +} > > > > > -- > E-Mail: garydgregory@gmail.com | ggregory@apache.org > Java Persistence with Hibernate, Second Edition > > > > JUnit in Action, Second Edition > > > > Spring Batch in Action > > > Blog: http://garygregory.wordpress.com > Home: http://garygregory.com/ > Tweet! http://twitter.com/GaryGregory > -- E-Mail: garydgregory@gmail.com | ggregory@apache.org Java Persistence with Hibernate, Second Edition JUnit in Action, Second Edition Spring Batch in Action Blog: http://garygregory.wordpress.com Home: http://garygregory.com/ Tweet! http://twitter.com/GaryGregory --f40304354dd4662054054f3978a8--