1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.impl.async;
29
30 import java.io.IOException;
31 import java.util.Iterator;
32 import java.util.List;
33
34 import org.apache.hc.client5.http.impl.DefaultClientConnectionReuseStrategy;
35 import org.apache.hc.core5.http.ConnectionReuseStrategy;
36 import org.apache.hc.core5.http.Header;
37 import org.apache.hc.core5.http.HttpConnection;
38 import org.apache.hc.core5.http.HttpRequest;
39 import org.apache.hc.core5.http.HttpResponse;
40 import org.apache.hc.core5.http.config.CharCodingConfig;
41 import org.apache.hc.core5.http.config.Http1Config;
42 import org.apache.hc.core5.http.impl.Http1StreamListener;
43 import org.apache.hc.core5.http.impl.nio.ClientHttp1StreamDuplexerFactory;
44 import org.apache.hc.core5.http.impl.nio.DefaultHttpRequestWriterFactory;
45 import org.apache.hc.core5.http.impl.nio.DefaultHttpResponseParserFactory;
46 import org.apache.hc.core5.http.message.RequestLine;
47 import org.apache.hc.core5.http.message.StatusLine;
48 import org.apache.hc.core5.http.nio.AsyncPushConsumer;
49 import org.apache.hc.core5.http.nio.HandlerFactory;
50 import org.apache.hc.core5.http.nio.NHttpMessageParserFactory;
51 import org.apache.hc.core5.http.nio.NHttpMessageWriterFactory;
52 import org.apache.hc.core5.http.protocol.HttpProcessor;
53 import org.apache.hc.core5.http2.HttpVersionPolicy;
54 import org.apache.hc.core5.http2.config.H2Config;
55 import org.apache.hc.core5.http2.frame.FramePrinter;
56 import org.apache.hc.core5.http2.frame.RawFrame;
57 import org.apache.hc.core5.http2.impl.nio.ClientH2StreamMultiplexerFactory;
58 import org.apache.hc.core5.http2.impl.nio.ClientHttpProtocolNegotiator;
59 import org.apache.hc.core5.http2.impl.nio.H2StreamListener;
60 import org.apache.hc.core5.reactor.IOEventHandler;
61 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
62 import org.apache.hc.core5.reactor.ProtocolIOSession;
63 import org.apache.hc.core5.util.Args;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 class HttpAsyncClientEventHandlerFactory implements IOEventHandlerFactory {
68
69 private static final Logger STREAM_LOG = LoggerFactory.getLogger(InternalHttpAsyncClient.class);
70 private static final Logger HEADER_LOG = LoggerFactory.getLogger("org.apache.hc.client5.http.headers");
71 private static final Logger FRAME_LOG = LoggerFactory.getLogger("org.apache.hc.client5.http2.frame");
72 private static final Logger FRAME_PAYLOAD_LOG = LoggerFactory.getLogger("org.apache.hc.client5.http2.frame.payload");
73 private static final Logger FLOW_CTRL_LOG = LoggerFactory.getLogger("org.apache.hc.client5.http2.flow");
74
75 private final HttpProcessor httpProcessor;
76 private final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory;
77 private final HttpVersionPolicy versionPolicy;
78 private final H2Config h2Config;
79 private final Http1Config h1Config;
80 private final CharCodingConfig charCodingConfig;
81 private final ConnectionReuseStrategy http1ConnectionReuseStrategy;
82 private final NHttpMessageParserFactory<HttpResponse> http1ResponseParserFactory;
83 private final NHttpMessageWriterFactory<HttpRequest> http1RequestWriterFactory;
84
85 HttpAsyncClientEventHandlerFactory(
86 final HttpProcessor httpProcessor,
87 final HandlerFactory<AsyncPushConsumer> exchangeHandlerFactory,
88 final HttpVersionPolicy versionPolicy,
89 final H2Config h2Config,
90 final Http1Config h1Config,
91 final CharCodingConfig charCodingConfig,
92 final ConnectionReuseStrategy connectionReuseStrategy) {
93 this.httpProcessor = Args.notNull(httpProcessor, "HTTP processor");
94 this.exchangeHandlerFactory = exchangeHandlerFactory;
95 this.versionPolicy = versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE;
96 this.h2Config = h2Config != null ? h2Config : H2Config.DEFAULT;
97 this.h1Config = h1Config != null ? h1Config : Http1Config.DEFAULT;
98 this.charCodingConfig = charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT;
99 this.http1ConnectionReuseStrategy = connectionReuseStrategy != null ? connectionReuseStrategy : DefaultClientConnectionReuseStrategy.INSTANCE;
100 this.http1ResponseParserFactory = new DefaultHttpResponseParserFactory(h1Config);
101 this.http1RequestWriterFactory = DefaultHttpRequestWriterFactory.INSTANCE;
102 }
103
104 @Override
105 public IOEventHandler createHandler(final ProtocolIOSession ioSession, final Object attachment) {
106 if (STREAM_LOG.isDebugEnabled()
107 || HEADER_LOG.isDebugEnabled()
108 || FRAME_LOG.isDebugEnabled()
109 || FRAME_PAYLOAD_LOG.isDebugEnabled()
110 || FLOW_CTRL_LOG.isDebugEnabled()) {
111 final String id = ioSession.getId();
112 final ClientHttp1StreamDuplexerFactory http1StreamHandlerFactory = new ClientHttp1StreamDuplexerFactory(
113 httpProcessor,
114 h1Config,
115 charCodingConfig,
116 http1ConnectionReuseStrategy,
117 http1ResponseParserFactory,
118 http1RequestWriterFactory,
119 new Http1StreamListener() {
120
121 @Override
122 public void onRequestHead(final HttpConnection connection, final HttpRequest request) {
123 if (HEADER_LOG.isDebugEnabled()) {
124 HEADER_LOG.debug("{} >> {}", id, new RequestLine(request));
125 for (final Iterator<Header> it = request.headerIterator(); it.hasNext(); ) {
126 HEADER_LOG.debug("{} >> {}", id, it.next());
127 }
128 }
129 }
130
131 @Override
132 public void onResponseHead(final HttpConnection connection, final HttpResponse response) {
133 if (HEADER_LOG.isDebugEnabled()) {
134 HEADER_LOG.debug("{} << {}", id, new StatusLine(response));
135 for (final Iterator<Header> it = response.headerIterator(); it.hasNext(); ) {
136 HEADER_LOG.debug("{} << {}", id, it.next());
137 }
138 }
139 }
140
141 @Override
142 public void onExchangeComplete(final HttpConnection connection, final boolean keepAlive) {
143 if (STREAM_LOG.isDebugEnabled()) {
144 if (keepAlive) {
145 STREAM_LOG.debug("{} Connection is kept alive", id);
146 } else {
147 STREAM_LOG.debug("{} Connection is not kept alive", id);
148 }
149 }
150 }
151
152 });
153 final ClientH2StreamMultiplexerFactory http2StreamHandlerFactory = new ClientH2StreamMultiplexerFactory(
154 httpProcessor,
155 exchangeHandlerFactory,
156 h2Config,
157 charCodingConfig,
158 new H2StreamListener() {
159
160 final FramePrinter framePrinter = new FramePrinter();
161
162 private void logFrameInfo(final String prefix, final RawFrame frame) {
163 try {
164 final LogAppendablesync/LogAppendable.html#LogAppendable">LogAppendable logAppendable = new LogAppendable(FRAME_LOG, prefix);
165 framePrinter.printFrameInfo(frame, logAppendable);
166 logAppendable.flush();
167 } catch (final IOException ignore) {
168 }
169 }
170
171 private void logFramePayload(final String prefix, final RawFrame frame) {
172 try {
173 final LogAppendablesync/LogAppendable.html#LogAppendable">LogAppendable logAppendable = new LogAppendable(FRAME_PAYLOAD_LOG, prefix);
174 framePrinter.printPayload(frame, logAppendable);
175 logAppendable.flush();
176 } catch (final IOException ignore) {
177 }
178 }
179
180 private void logFlowControl(final String prefix, final int streamId, final int delta, final int actualSize) {
181 FLOW_CTRL_LOG.debug("{} stream {} flow control {} -> {}", prefix, streamId, delta, actualSize);
182 }
183
184 @Override
185 public void onHeaderInput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
186 if (HEADER_LOG.isDebugEnabled()) {
187 for (int i = 0; i < headers.size(); i++) {
188 HEADER_LOG.debug("{} << {}", id, headers.get(i));
189 }
190 }
191 }
192
193 @Override
194 public void onHeaderOutput(final HttpConnection connection, final int streamId, final List<? extends Header> headers) {
195 if (HEADER_LOG.isDebugEnabled()) {
196 for (int i = 0; i < headers.size(); i++) {
197 HEADER_LOG.debug("{} >> {}", id, headers.get(i));
198 }
199 }
200 }
201
202 @Override
203 public void onFrameInput(final HttpConnection connection, final int streamId, final RawFrame frame) {
204 if (FRAME_LOG.isDebugEnabled()) {
205 logFrameInfo(id + " <<", frame);
206 }
207 if (FRAME_PAYLOAD_LOG.isDebugEnabled()) {
208 logFramePayload(id + " <<", frame);
209 }
210 }
211
212 @Override
213 public void onFrameOutput(final HttpConnection connection, final int streamId, final RawFrame frame) {
214 if (FRAME_LOG.isDebugEnabled()) {
215 logFrameInfo(id + " >>", frame);
216 }
217 if (FRAME_PAYLOAD_LOG.isDebugEnabled()) {
218 logFramePayload(id + " >>", frame);
219 }
220 }
221
222 @Override
223 public void onInputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
224 if (FLOW_CTRL_LOG.isDebugEnabled()) {
225 logFlowControl(id + " <<", streamId, delta, actualSize);
226 }
227 }
228
229 @Override
230 public void onOutputFlowControl(final HttpConnection connection, final int streamId, final int delta, final int actualSize) {
231 if (FLOW_CTRL_LOG.isDebugEnabled()) {
232 logFlowControl(id + " >>", streamId, delta, actualSize);
233 }
234 }
235
236 });
237 return new ClientHttpProtocolNegotiator(
238 ioSession,
239 http1StreamHandlerFactory,
240 http2StreamHandlerFactory,
241 attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : versionPolicy);
242 }
243 final ClientHttp1StreamDuplexerFactory http1StreamHandlerFactory = new ClientHttp1StreamDuplexerFactory(
244 httpProcessor,
245 h1Config,
246 charCodingConfig,
247 http1ConnectionReuseStrategy,
248 http1ResponseParserFactory,
249 http1RequestWriterFactory,
250 null);
251 final ClientH2StreamMultiplexerFactory http2StreamHandlerFactory = new ClientH2StreamMultiplexerFactory(
252 httpProcessor,
253 exchangeHandlerFactory,
254 h2Config,
255 charCodingConfig,
256 null);
257 return new ClientHttpProtocolNegotiator(
258 ioSession,
259 http1StreamHandlerFactory,
260 http2StreamHandlerFactory,
261 attachment instanceof HttpVersionPolicy ? (HttpVersionPolicy) attachment : versionPolicy);
262 }
263
264 }