1
18
19 package io.undertow.server.handlers;
20
21 import java.io.IOException;
22 import java.nio.ByteBuffer;
23 import java.nio.channels.FileChannel;
24 import java.util.concurrent.TimeUnit;
25
26 import org.xnio.channels.StreamSinkChannel;
27 import org.xnio.conduits.AbstractStreamSourceConduit;
28 import org.xnio.conduits.StreamSourceConduit;
29
30 import io.undertow.server.ConduitWrapper;
31 import io.undertow.server.Connectors;
32 import io.undertow.server.HttpHandler;
33 import io.undertow.server.HttpServerExchange;
34 import io.undertow.server.ResponseCommitListener;
35 import io.undertow.server.protocol.http.HttpContinue;
36 import io.undertow.util.ConduitFactory;
37 import io.undertow.util.StatusCodes;
38
39
45 public class HttpContinueReadHandler implements HttpHandler {
46
47 private static final ConduitWrapper<StreamSourceConduit> WRAPPER = new ConduitWrapper<StreamSourceConduit>() {
48 @Override
49 public StreamSourceConduit wrap(final ConduitFactory<StreamSourceConduit> factory, final HttpServerExchange exchange) {
50 if (exchange.isRequestChannelAvailable() && !exchange.isResponseStarted()) {
51 return new ContinueConduit(factory.create(), exchange);
52 }
53 return factory.create();
54 }
55 };
56
57 private final HttpHandler handler;
58
59 public HttpContinueReadHandler(final HttpHandler handler) {
60 this.handler = handler;
61 }
62
63 @Override
64 public void handleRequest(final HttpServerExchange exchange) throws Exception {
65 if (HttpContinue.requiresContinueResponse(exchange)) {
66 exchange.addRequestWrapper(WRAPPER);
67 exchange.addResponseCommitListener(new ResponseCommitListener() {
68 @Override
69 public void beforeCommit(HttpServerExchange exchange) {
70
71 if (!HttpContinue.isContinueResponseSent(exchange)) {
72 exchange.setPersistent(false);
73
74 exchange.getConnection().terminateRequestChannel(exchange);
75 }
76 }
77 });
78 }
79 handler.handleRequest(exchange);
80 }
81
82 private static final class ContinueConduit extends AbstractStreamSourceConduit<StreamSourceConduit> implements StreamSourceConduit {
83
84 private boolean sent = false;
85 private HttpContinue.ContinueResponseSender response = null;
86 private final HttpServerExchange exchange;
87
88
89 protected ContinueConduit(final StreamSourceConduit next, final HttpServerExchange exchange) {
90 super(next);
91 this.exchange = exchange;
92 }
93
94 @Override
95 public long transferTo(final long position, final long count, final FileChannel target) throws IOException {
96 if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
97
98 Connectors.terminateRequest(exchange);
99 return -1;
100 }
101 if (!sent) {
102 sent = true;
103 response = HttpContinue.createResponseSender(exchange);
104 }
105 if (response != null) {
106 if (!response.send()) {
107 return 0;
108 }
109 response = null;
110 }
111 return super.transferTo(position, count, target);
112 }
113
114 @Override
115 public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException {
116 if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
117
118 Connectors.terminateRequest(exchange);
119 return -1;
120 }
121 if (!sent) {
122 sent = true;
123 response = HttpContinue.createResponseSender(exchange);
124 }
125 if (response != null) {
126 if (!response.send()) {
127 return 0;
128 }
129 response = null;
130 }
131 return super.transferTo(count, throughBuffer, target);
132 }
133
134 @Override
135 public int read(final ByteBuffer dst) throws IOException {
136 if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
137
138 Connectors.terminateRequest(exchange);
139 return -1;
140 }
141 if (!sent) {
142 sent = true;
143 response = HttpContinue.createResponseSender(exchange);
144 }
145 if (response != null) {
146 if (!response.send()) {
147 return 0;
148 }
149 response = null;
150 }
151 return super.read(dst);
152 }
153
154 @Override
155 public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException {
156 if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
157
158 Connectors.terminateRequest(exchange);
159 return -1;
160 }
161 if (!sent) {
162 sent = true;
163 response = HttpContinue.createResponseSender(exchange);
164 }
165 if (response != null) {
166 if (!response.send()) {
167 return 0;
168 }
169 response = null;
170 }
171 return super.read(dsts, offs, len);
172 }
173
174 @Override
175 public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException {
176 if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
177
178 return;
179 }
180 if (!sent) {
181 sent = true;
182 response = HttpContinue.createResponseSender(exchange);
183 }
184 long exitTime = System.currentTimeMillis() + timeUnit.toMillis(time);
185 if (response != null) {
186 while (!response.send()) {
187 long currentTime = System.currentTimeMillis();
188 if (currentTime > exitTime) {
189 return;
190 }
191 response.awaitWritable(exitTime - currentTime, TimeUnit.MILLISECONDS);
192 }
193 response = null;
194 }
195
196 long currentTime = System.currentTimeMillis();
197 super.awaitReadable(exitTime - currentTime, TimeUnit.MILLISECONDS);
198 }
199
200 @Override
201 public void awaitReadable() throws IOException {
202 if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
203
204 return;
205 }
206 if (!sent) {
207 sent = true;
208 response = HttpContinue.createResponseSender(exchange);
209 }
210 if (response != null) {
211 while (!response.send()) {
212 response.awaitWritable();
213 }
214 response = null;
215 }
216 super.awaitReadable();
217 }
218 }
219 }
220