1
18
19 package io.undertow.server.protocol.http;
20
21 import io.undertow.UndertowMessages;
22 import io.undertow.conduits.ReadDataStreamSourceConduit;
23 import io.undertow.server.AbstractServerConnection;
24 import io.undertow.server.ConduitWrapper;
25 import io.undertow.server.ConnectionSSLSessionInfo;
26 import io.undertow.server.ConnectorStatisticsImpl;
27 import io.undertow.server.Connectors;
28 import io.undertow.server.ExchangeCompletionListener;
29 import io.undertow.server.HttpHandler;
30 import io.undertow.server.HttpServerExchange;
31 import io.undertow.server.HttpUpgradeListener;
32 import io.undertow.server.SSLSessionInfo;
33 import io.undertow.server.ServerConnection;
34 import io.undertow.util.ConduitFactory;
35 import io.undertow.util.Headers;
36 import io.undertow.util.HttpString;
37 import io.undertow.util.ImmediatePooledByteBuffer;
38 import io.undertow.util.Methods;
39
40 import org.xnio.IoUtils;
41 import org.xnio.OptionMap;
42 import io.undertow.connector.ByteBufferPool;
43 import io.undertow.connector.PooledByteBuffer;
44 import org.xnio.StreamConnection;
45 import org.xnio.channels.SslChannel;
46 import org.xnio.conduits.StreamSinkConduit;
47
48 import javax.net.ssl.SSLSession;
49 import java.nio.ByteBuffer;
50
51
59 public final class HttpServerConnection extends AbstractServerConnection {
60
61 private SSLSessionInfo sslSessionInfo;
62 private HttpReadListener readListener;
63 private PipeliningBufferingStreamSinkConduit pipelineBuffer;
64 private HttpResponseConduit responseConduit;
65 private ServerFixedLengthStreamSinkConduit fixedLengthStreamSinkConduit;
66 private ReadDataStreamSourceConduit readDataStreamSourceConduit;
67
68 private HttpUpgradeListener upgradeListener;
69 private boolean connectHandled;
70
71 public HttpServerConnection(StreamConnection channel, final ByteBufferPool bufferPool, final HttpHandler rootHandler, final OptionMap undertowOptions, final int bufferSize, final ConnectorStatisticsImpl connectorStatistics) {
72 super(channel, bufferPool, rootHandler, undertowOptions, bufferSize);
73 if (channel instanceof SslChannel) {
74 sslSessionInfo = new ConnectionSSLSessionInfo(((SslChannel) channel), this);
75 }
76 this.responseConduit = new HttpResponseConduit(channel.getSinkChannel().getConduit(), bufferPool, this);
77
78 fixedLengthStreamSinkConduit = new ServerFixedLengthStreamSinkConduit(responseConduit, false, false);
79 readDataStreamSourceConduit = new ReadDataStreamSourceConduit(channel.getSourceChannel().getConduit(), this);
80
81 addCloseListener(new CloseListener() {
82 @Override
83 public void closed(ServerConnection connection) {
84 if(connectorStatistics != null) {
85 connectorStatistics.decrementConnectionCount();
86 }
87 responseConduit.freeBuffers();
88 }
89 });
90 }
91
92 @Override
93 public HttpServerExchange sendOutOfBandResponse(HttpServerExchange exchange) {
94 if (exchange == null || !HttpContinue.requiresContinueResponse(exchange)) {
95 throw UndertowMessages.MESSAGES.outOfBandResponseOnlyAllowedFor100Continue();
96 }
97 final ConduitState state = resetChannel();
98 HttpServerExchange newExchange = new HttpServerExchange(this);
99 for (HttpString header : exchange.getRequestHeaders().getHeaderNames()) {
100 newExchange.getRequestHeaders().putAll(header, exchange.getRequestHeaders().get(header));
101 }
102 newExchange.setProtocol(exchange.getProtocol());
103 newExchange.setRequestMethod(exchange.getRequestMethod());
104 exchange.setRequestURI(exchange.getRequestURI(), exchange.isHostIncludedInRequestURI());
105 exchange.setRequestPath(exchange.getRequestPath());
106 exchange.setRelativePath(exchange.getRelativePath());
107 newExchange.getRequestHeaders().put(Headers.CONNECTION, Headers.KEEP_ALIVE.toString());
108 newExchange.getRequestHeaders().put(Headers.CONTENT_LENGTH, 0);
109 newExchange.setPersistent(true);
110
111 Connectors.terminateRequest(newExchange);
112 newExchange.addResponseWrapper(new ConduitWrapper<StreamSinkConduit>() {
113 @Override
114 public StreamSinkConduit wrap(ConduitFactory<StreamSinkConduit> factory, HttpServerExchange exchange) {
115
116 HttpResponseConduit httpResponseConduit = new HttpResponseConduit(getSinkChannel().getConduit(), getByteBufferPool(), HttpServerConnection.this, exchange);
117 exchange.addExchangeCompleteListener(new ExchangeCompletionListener() {
118 @Override
119 public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) {
120 httpResponseConduit.freeContinueResponse();
121 nextListener.proceed();
122 }
123 });
124 ServerFixedLengthStreamSinkConduit fixed = new ServerFixedLengthStreamSinkConduit(httpResponseConduit, false, false);
125 fixed.reset(0, exchange);
126 return fixed;
127 }
128 });
129
130
131 channel.getSourceChannel().setConduit(source(state));
132 newExchange.addExchangeCompleteListener(new ExchangeCompletionListener() {
133 @Override
134 public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) {
135 restoreChannel(state);
136 }
137 });
138 return newExchange;
139 }
140
141 @Override
142 public boolean isContinueResponseSupported() {
143 return true;
144 }
145
146 @Override
147 public void terminateRequestChannel(HttpServerExchange exchange) {
148 if (!exchange.isPersistent()) {
149 IoUtils.safeClose(getChannel().getSourceChannel());
150 }
151 }
152
153
159 public void ungetRequestBytes(final PooledByteBuffer unget) {
160 if (getExtraBytes() == null) {
161 setExtraBytes(unget);
162 } else {
163 PooledByteBuffer eb = getExtraBytes();
164 ByteBuffer buf = eb.getBuffer();
165 final ByteBuffer ugBuffer = unget.getBuffer();
166
167 if (ugBuffer.limit() - ugBuffer.remaining() > buf.remaining()) {
168
169 ugBuffer.compact();
170 ugBuffer.put(buf);
171 ugBuffer.flip();
172 eb.close();
173 setExtraBytes(unget);
174 } else {
175
176 final byte[] data = new byte[ugBuffer.remaining() + buf.remaining()];
177 int first = ugBuffer.remaining();
178 ugBuffer.get(data, 0, ugBuffer.remaining());
179 buf.get(data, first, buf.remaining());
180 eb.close();
181 unget.close();
182 final ByteBuffer newBuffer = ByteBuffer.wrap(data);
183 setExtraBytes(new ImmediatePooledByteBuffer(newBuffer));
184 }
185 }
186 }
187
188 @Override
189 public SSLSessionInfo getSslSessionInfo() {
190 return sslSessionInfo;
191 }
192
193 @Override
194 public void setSslSessionInfo(SSLSessionInfo sessionInfo) {
195 this.sslSessionInfo = sessionInfo;
196 }
197
198 public SSLSession getSslSession() {
199 if (channel instanceof SslChannel) {
200 return ((SslChannel) channel).getSslSession();
201 }
202 return null;
203 }
204
205 @Override
206 protected StreamConnection upgradeChannel() {
207 clearChannel();
208 if (extraBytes != null) {
209 channel.getSourceChannel().setConduit(new ReadDataStreamSourceConduit(channel.getSourceChannel().getConduit(), this));
210 }
211 return channel;
212 }
213
214 @Override
215 protected StreamSinkConduit getSinkConduit(HttpServerExchange exchange, StreamSinkConduit conduit) {
216 if(exchange.getRequestMethod().equals(Methods.CONNECT) && !connectHandled) {
217
218 exchange.setPersistent(false);
219 exchange.getResponseHeaders().put(Headers.CONNECTION, "close");
220 }
221 return HttpTransferEncoding.createSinkConduit(exchange);
222 }
223
224 @Override
225 protected boolean isUpgradeSupported() {
226 return true;
227 }
228
229 @Override
230 protected boolean isConnectSupported() {
231 return true;
232 }
233
234 void setReadListener(HttpReadListener readListener) {
235 this.readListener = readListener;
236 }
237
238 @Override
239 protected void exchangeComplete(HttpServerExchange exchange) {
240 if(fixedLengthStreamSinkConduit != null) {
241 fixedLengthStreamSinkConduit.clearExchange();
242 }
243 if (pipelineBuffer == null) {
244 readListener.exchangeComplete(exchange);
245 } else {
246 pipelineBuffer.exchangeComplete(exchange);
247 }
248 }
249
250 HttpReadListener getReadListener() {
251 return readListener;
252 }
253
254 ReadDataStreamSourceConduit getReadDataStreamSourceConduit() {
255 return readDataStreamSourceConduit;
256 }
257
258 public PipeliningBufferingStreamSinkConduit getPipelineBuffer() {
259 return pipelineBuffer;
260 }
261
262 public HttpResponseConduit getResponseConduit() {
263 return responseConduit;
264 }
265
266 ServerFixedLengthStreamSinkConduit getFixedLengthStreamSinkConduit() {
267 return fixedLengthStreamSinkConduit;
268 }
269
270 protected HttpUpgradeListener getUpgradeListener() {
271 return upgradeListener;
272 }
273
274 @Override
275 protected void setUpgradeListener(HttpUpgradeListener upgradeListener) {
276 this.upgradeListener = upgradeListener;
277 }
278
279 @Override
280 protected void setConnectListener(HttpUpgradeListener connectListener) {
281 this.upgradeListener = connectListener;
282 connectHandled = true;
283 }
284
285 void setCurrentExchange(HttpServerExchange exchange) {
286 this.current = exchange;
287 }
288
289 public void setPipelineBuffer(PipeliningBufferingStreamSinkConduit pipelineBuffer) {
290 this.pipelineBuffer = pipelineBuffer;
291 this.responseConduit = new HttpResponseConduit(pipelineBuffer, bufferPool, this);
292 this.fixedLengthStreamSinkConduit = new ServerFixedLengthStreamSinkConduit(responseConduit, false, false);
293 }
294
295 @Override
296 public String getTransportProtocol() {
297 return "http/1.1";
298 }
299
300 @Override
301 public boolean isRequestTrailerFieldsSupported() {
302 if(current == null) {
303 return false;
304 }
305
306 String te = current.getRequestHeaders().getFirst(Headers.TRANSFER_ENCODING);
307 if(te == null) {
308 return false;
309 }
310 return te.equalsIgnoreCase(Headers.CHUNKED.toString());
311 }
312
313 boolean isConnectHandled() {
314 return connectHandled;
315 }
316 }
317