1
18
19 package io.undertow.server.protocol.http;
20
21 import java.io.IOException;
22 import java.nio.ByteBuffer;
23 import java.util.Collections;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentHashMap;
26
27 import org.xnio.ChannelListener;
28 import org.xnio.IoUtils;
29 import org.xnio.OptionMap;
30 import org.xnio.Options;
31 import org.xnio.Pool;
32 import org.xnio.StreamConnection;
33
34 import io.undertow.UndertowLogger;
35 import io.undertow.UndertowMessages;
36 import io.undertow.UndertowOptions;
37 import io.undertow.conduits.BytesReceivedStreamSourceConduit;
38 import io.undertow.conduits.BytesSentStreamSinkConduit;
39 import io.undertow.conduits.IdleTimeoutConduit;
40 import io.undertow.conduits.ReadTimeoutStreamSourceConduit;
41 import io.undertow.conduits.WriteTimeoutStreamSinkConduit;
42 import io.undertow.connector.ByteBufferPool;
43 import io.undertow.connector.PooledByteBuffer;
44 import io.undertow.server.ConnectorStatistics;
45 import io.undertow.server.ConnectorStatisticsImpl;
46 import io.undertow.server.DelegateOpenListener;
47 import io.undertow.server.HttpHandler;
48 import io.undertow.server.ServerConnection;
49 import io.undertow.server.XnioByteBufferPool;
50
51
57 public final class HttpOpenListener implements ChannelListener<StreamConnection>, DelegateOpenListener {
58
59 private final Set<HttpServerConnection> connections = Collections.newSetFromMap(new ConcurrentHashMap<>());
60
61 private final ByteBufferPool bufferPool;
62 private final int bufferSize;
63
64 private volatile HttpHandler rootHandler;
65
66 private volatile OptionMap undertowOptions;
67
68 private volatile HttpRequestParser parser;
69
70 private volatile boolean statisticsEnabled;
71 private final ConnectorStatisticsImpl connectorStatistics;
72
73 @Deprecated
74 public HttpOpenListener(final Pool<ByteBuffer> pool) {
75 this(pool, OptionMap.EMPTY);
76 }
77
78 @Deprecated
79 public HttpOpenListener(final Pool<ByteBuffer> pool, final OptionMap undertowOptions) {
80 this(new XnioByteBufferPool(pool), undertowOptions);
81 }
82
83 public HttpOpenListener(final ByteBufferPool pool) {
84 this(pool, OptionMap.EMPTY);
85 }
86
87 public HttpOpenListener(final ByteBufferPool pool, final OptionMap undertowOptions) {
88 this.undertowOptions = undertowOptions;
89 this.bufferPool = pool;
90 PooledByteBuffer buf = pool.allocate();
91 this.bufferSize = buf.getBuffer().remaining();
92 buf.close();
93 parser = HttpRequestParser.instance(undertowOptions);
94 connectorStatistics = new ConnectorStatisticsImpl();
95 statisticsEnabled = undertowOptions.get(UndertowOptions.ENABLE_CONNECTOR_STATISTICS, false);
96 }
97
98 @Override
99 public void handleEvent(StreamConnection channel) {
100 handleEvent(channel, null);
101 }
102
103 @Override
104 public void handleEvent(final StreamConnection channel, PooledByteBuffer buffer) {
105 if (UndertowLogger.REQUEST_LOGGER.isTraceEnabled()) {
106 UndertowLogger.REQUEST_LOGGER.tracef("Opened connection with %s", channel.getPeerAddress());
107 }
108
109
110 try {
111 Integer readTimeout = channel.getOption(Options.READ_TIMEOUT);
112 Integer idle = undertowOptions.get(UndertowOptions.IDLE_TIMEOUT);
113 if (idle != null) {
114 IdleTimeoutConduit conduit = new IdleTimeoutConduit(channel);
115 channel.getSourceChannel().setConduit(conduit);
116 channel.getSinkChannel().setConduit(conduit);
117 }
118 if (readTimeout != null && readTimeout > 0) {
119 channel.getSourceChannel().setConduit(new ReadTimeoutStreamSourceConduit(channel.getSourceChannel().getConduit(), channel, this));
120 }
121 Integer writeTimeout = channel.getOption(Options.WRITE_TIMEOUT);
122 if (writeTimeout != null && writeTimeout > 0) {
123 channel.getSinkChannel().setConduit(new WriteTimeoutStreamSinkConduit(channel.getSinkChannel().getConduit(), channel, this));
124 }
125 } catch (IOException e) {
126 IoUtils.safeClose(channel);
127 UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
128 } catch (Throwable t) {
129 IoUtils.safeClose(channel);
130 UndertowLogger.REQUEST_IO_LOGGER.handleUnexpectedFailure(t);
131 }
132 if (statisticsEnabled) {
133 channel.getSinkChannel().setConduit(new BytesSentStreamSinkConduit(channel.getSinkChannel().getConduit(), connectorStatistics.sentAccumulator()));
134 channel.getSourceChannel().setConduit(new BytesReceivedStreamSourceConduit(channel.getSourceChannel().getConduit(), connectorStatistics.receivedAccumulator()));
135 }
136
137 HttpServerConnection connection = new HttpServerConnection(channel, bufferPool, rootHandler, undertowOptions, bufferSize, statisticsEnabled ? connectorStatistics : null);
138 HttpReadListener readListener = new HttpReadListener(connection, parser, statisticsEnabled ? connectorStatistics : null);
139
140
141 if (buffer != null) {
142 if (buffer.getBuffer().hasRemaining()) {
143 connection.setExtraBytes(buffer);
144 } else {
145 buffer.close();
146 }
147 }
148 if (connectorStatistics != null && statisticsEnabled) {
149 connectorStatistics.incrementConnectionCount();
150 }
151
152 connections.add(connection);
153 connection.addCloseListener(new ServerConnection.CloseListener() {
154 @Override
155 public void closed(ServerConnection c) {
156 connections.remove(connection);
157 }
158 });
159 connection.setReadListener(readListener);
160 readListener.newRequest();
161 channel.getSourceChannel().setReadListener(readListener);
162 readListener.handleEvent(channel.getSourceChannel());
163 }
164
165 @Override
166 public HttpHandler getRootHandler() {
167 return rootHandler;
168 }
169
170 @Override
171 public void setRootHandler(final HttpHandler rootHandler) {
172 this.rootHandler = rootHandler;
173 }
174
175 @Override
176 public OptionMap getUndertowOptions() {
177 return undertowOptions;
178 }
179
180 @Override
181 public void setUndertowOptions(final OptionMap undertowOptions) {
182 if (undertowOptions == null) {
183 throw UndertowMessages.MESSAGES.argumentCannotBeNull("undertowOptions");
184 }
185 this.undertowOptions = undertowOptions;
186 this.parser = HttpRequestParser.instance(undertowOptions);
187 statisticsEnabled = undertowOptions.get(UndertowOptions.ENABLE_CONNECTOR_STATISTICS, false);
188 }
189
190 @Override
191 public ByteBufferPool getBufferPool() {
192 return bufferPool;
193 }
194
195 @Override
196 public ConnectorStatistics getConnectorStatistics() {
197 if (statisticsEnabled) {
198 return connectorStatistics;
199 }
200 return null;
201 }
202
203 @Override
204 public void closeConnections() {
205 for(HttpServerConnection i : connections) {
206 i.getIoThread().execute(new Runnable() {
207 @Override
208 public void run() {
209 IoUtils.safeClose(i);
210 }
211 });
212 }
213 }
214
215 }
216