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.net.SocketAddress;
32 import java.nio.ByteBuffer;
33 import java.nio.channels.ByteChannel;
34 import java.nio.channels.SelectionKey;
35 import java.util.concurrent.locks.Lock;
36
37 import org.apache.hc.core5.http.Chars;
38 import org.apache.hc.core5.io.CloseMode;
39 import org.apache.hc.core5.reactor.Command;
40 import org.apache.hc.core5.reactor.IOEventHandler;
41 import org.apache.hc.core5.reactor.IOSession;
42 import org.apache.hc.core5.util.Args;
43 import org.apache.hc.core5.util.Timeout;
44 import org.slf4j.Logger;
45
46 class LoggingIOSession implements IOSession {
47
48 private final Logger log;
49 private final Logger wireLog;
50 private final IOSession session;
51
52 public LoggingIOSession(final IOSession session, final Logger log, final Logger wireLog) {
53 super();
54 this.session = session;
55 this.log = log;
56 this.wireLog = wireLog;
57 }
58
59 @Override
60 public String getId() {
61 return session.getId();
62 }
63
64 @Override
65 public Lock getLock() {
66 return session.getLock();
67 }
68
69 @Override
70 public boolean hasCommands() {
71 return session.hasCommands();
72 }
73
74 @Override
75 public Command poll() {
76 return session.poll();
77 }
78
79 @Override
80 public void enqueue(final Command command, final Command.Priority priority) {
81 session.enqueue(command, priority);
82 if (log.isDebugEnabled()) {
83 log.debug("{} Enqueued {} with priority {}", session, command.getClass().getSimpleName(), priority);
84 }
85 }
86
87 @Override
88 public ByteChannel channel() {
89 return session.channel();
90 }
91
92 @Override
93 public SocketAddress getLocalAddress() {
94 return session.getLocalAddress();
95 }
96
97 @Override
98 public SocketAddress getRemoteAddress() {
99 return session.getRemoteAddress();
100 }
101
102 @Override
103 public int getEventMask() {
104 return session.getEventMask();
105 }
106
107 private static String formatOps(final int ops) {
108 final StringBuilder buffer = new StringBuilder(6);
109 buffer.append('[');
110 if ((ops & SelectionKey.OP_READ) > 0) {
111 buffer.append('r');
112 }
113 if ((ops & SelectionKey.OP_WRITE) > 0) {
114 buffer.append('w');
115 }
116 if ((ops & SelectionKey.OP_ACCEPT) > 0) {
117 buffer.append('a');
118 }
119 if ((ops & SelectionKey.OP_CONNECT) > 0) {
120 buffer.append('c');
121 }
122 buffer.append(']');
123 return buffer.toString();
124 }
125
126 @Override
127 public void setEventMask(final int ops) {
128 session.setEventMask(ops);
129 if (log.isDebugEnabled()) {
130 log.debug("{} Event mask set {}", session, formatOps(ops));
131 }
132 }
133
134 @Override
135 public void setEvent(final int op) {
136 session.setEvent(op);
137 if (log.isDebugEnabled()) {
138 log.debug("{} Event set {}", session, formatOps(op));
139 }
140 }
141
142 @Override
143 public void clearEvent(final int op) {
144 session.clearEvent(op);
145 if (log.isDebugEnabled()) {
146 log.debug("{} Event cleared {}", session, formatOps(op));
147 }
148 }
149
150 @Override
151 public boolean isOpen() {
152 return session.isOpen();
153 }
154
155 @Override
156 public void close() {
157 if (log.isDebugEnabled()) {
158 log.debug("{} Close", session);
159 }
160 session.close();
161 }
162
163 @Override
164 public Status getStatus() {
165 return session.getStatus();
166 }
167
168 @Override
169 public void close(final CloseMode closeMode) {
170 if (log.isDebugEnabled()) {
171 log.debug("{} Close {}", session, closeMode);
172 }
173 session.close(closeMode);
174 }
175
176 @Override
177 public Timeout getSocketTimeout() {
178 return session.getSocketTimeout();
179 }
180
181 @Override
182 public void setSocketTimeout(final Timeout timeout) {
183 if (log.isDebugEnabled()) {
184 log.debug("{} Set timeout {}", session, timeout);
185 }
186 session.setSocketTimeout(timeout);
187 }
188
189 @Override
190 public long getLastReadTime() {
191 return session.getLastReadTime();
192 }
193
194 @Override
195 public long getLastWriteTime() {
196 return session.getLastWriteTime();
197 }
198
199 @Override
200 public void updateReadTime() {
201 session.updateReadTime();
202 }
203
204 @Override
205 public void updateWriteTime() {
206 session.updateWriteTime();
207 }
208
209 @Override
210 public long getLastEventTime() {
211 return session.getLastEventTime();
212 }
213
214 @Override
215 public IOEventHandler getHandler() {
216 return session.getHandler();
217 }
218
219 @Override
220 public void upgrade(final IOEventHandler handler) {
221 Args.notNull(handler, "Protocol handler");
222 if (log.isDebugEnabled()) {
223 log.debug("{} protocol upgrade {}", session, handler.getClass());
224 }
225 session.upgrade(new IOEventHandler() {
226
227 @Override
228 public void connected(final IOSession protocolSession) throws IOException {
229 handler.connected(protocolSession);
230 }
231
232 @Override
233 public void inputReady(final IOSession protocolSession, final ByteBuffer src) throws IOException {
234 if (src != null && wireLog.isDebugEnabled()) {
235 final ByteBuffer b = src.duplicate();
236 logData(b, "<< ");
237 }
238 handler.inputReady(protocolSession, src);
239 }
240
241 @Override
242 public void outputReady(final IOSession protocolSession) throws IOException {
243 handler.outputReady(protocolSession);
244 }
245
246 @Override
247 public void timeout(final IOSession protocolSession, final Timeout timeout) throws IOException {
248 handler.timeout(protocolSession, timeout);
249 }
250
251 @Override
252 public void exception(final IOSession protocolSession, final Exception cause) {
253 handler.exception(protocolSession, cause);
254 }
255
256 @Override
257 public void disconnected(final IOSession protocolSession) {
258 handler.disconnected(protocolSession);
259 }
260
261 });
262
263 }
264
265 private void logData(final ByteBuffer data, final String prefix) throws IOException {
266 final byte[] line = new byte[16];
267 final StringBuilder buf = new StringBuilder();
268 while (data.hasRemaining()) {
269 buf.setLength(0);
270 buf.append(session).append(" ").append(prefix);
271 final int chunk = Math.min(data.remaining(), line.length);
272 data.get(line, 0, chunk);
273
274 for (int i = 0; i < chunk; i++) {
275 final char ch = (char) line[i];
276 if (ch > Chars.SP && ch <= Chars.DEL) {
277 buf.append(ch);
278 } else if (Character.isWhitespace(ch)) {
279 buf.append(' ');
280 } else {
281 buf.append('.');
282 }
283 }
284 for (int i = chunk; i < 17; i++) {
285 buf.append(' ');
286 }
287
288 for (int i = 0; i < chunk; i++) {
289 buf.append(' ');
290 final int b = line[i] & 0xff;
291 final String s = Integer.toHexString(b);
292 if (s.length() == 1) {
293 buf.append("0");
294 }
295 buf.append(s);
296 }
297 wireLog.debug(buf.toString());
298 }
299 }
300
301 @Override
302 public int read(final ByteBuffer dst) throws IOException {
303 final int bytesRead = session.read(dst);
304 if (log.isDebugEnabled()) {
305 log.debug("{} {} bytes read", session, bytesRead);
306 }
307 if (bytesRead > 0 && wireLog.isDebugEnabled()) {
308 final ByteBuffer b = dst.duplicate();
309 final int p = b.position();
310 b.limit(p);
311 b.position(p - bytesRead);
312 logData(b, "<< ");
313 }
314 return bytesRead;
315 }
316
317 @Override
318 public int write(final ByteBuffer src) throws IOException {
319 final int byteWritten = session.write(src);
320 if (log.isDebugEnabled()) {
321 log.debug("{} {} bytes written", session, byteWritten);
322 }
323 if (byteWritten > 0 && wireLog.isDebugEnabled()) {
324 final ByteBuffer b = src.duplicate();
325 final int p = b.position();
326 b.limit(p);
327 b.position(p - byteWritten);
328 logData(b, ">> ");
329 }
330 return byteWritten;
331 }
332
333 @Override
334 public String toString() {
335 return session.toString();
336 }
337
338 }