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 package org.apache.http.nio.client.methods;
28
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.FileNotFoundException;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.net.URI;
35 import java.nio.charset.Charset;
36 import java.util.concurrent.Future;
37
38 import org.apache.commons.io.FileUtils;
39 import org.apache.commons.io.IOUtils;
40 import org.apache.commons.io.LineIterator;
41 import org.apache.commons.io.output.FileWriterWithEncoding;
42 import org.apache.http.Consts;
43 import org.apache.http.localserver.HttpAsyncTestBase;
44 import org.apache.http.HttpEntity;
45 import org.apache.http.HttpEntityEnclosingRequest;
46 import org.apache.http.HttpException;
47 import org.apache.http.HttpHost;
48 import org.apache.http.HttpRequest;
49 import org.apache.http.HttpResponse;
50 import org.apache.http.HttpStatus;
51 import org.apache.http.client.methods.HttpPost;
52 import org.apache.http.entity.BasicHttpEntity;
53 import org.apache.http.entity.ContentType;
54 import org.apache.http.nio.entity.NFileEntity;
55 import org.apache.http.nio.entity.NStringEntity;
56 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
57 import org.apache.http.protocol.HttpContext;
58 import org.apache.http.protocol.HttpRequestHandler;
59 import org.junit.After;
60 import org.junit.AfterClass;
61 import org.junit.Assert;
62 import org.junit.BeforeClass;
63 import org.junit.Test;
64
65 public class TestZeroCopy extends HttpAsyncTestBase {
66
67 private static final String[] TEXT = {
68 "blah blah blah blah blah blah blah blah blah blah blah blah blah blah",
69 "yada yada yada yada yada yada yada yada yada yada yada yada yada yada",
70 "da da da da da da da da da da da da da da da da da da da da da da da da",
71 "nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet nyet"
72 };
73
74 private static final Charset ASCII = Charset.forName("ascii");
75 private static File TEST_FILE;
76 private File tmpfile;
77
78 @BeforeClass
79 public static void createSrcFile() throws Exception {
80 final File tmpdir = FileUtils.getTempDirectory();
81 TEST_FILE = new File(tmpdir, "src.test");
82 final FileWriterWithEncoding out = new FileWriterWithEncoding(TEST_FILE, ASCII);
83 try {
84 for (int i = 0; i < 500; i++) {
85 for (final String line: TEXT) {
86 out.write(line);
87 out.write("\r\n");
88 }
89 }
90 } finally {
91 out.close();
92 }
93 }
94
95 @AfterClass
96 public static void deleteSrcFile() throws Exception {
97 if (TEST_FILE != null) {
98 TEST_FILE.delete();
99 TEST_FILE = null;
100 }
101 }
102
103 @After
104 public void cleanUp() throws Exception {
105 if (this.tmpfile != null && this.tmpfile.exists()) {
106 this.tmpfile.delete();
107 }
108 }
109
110 static class TestZeroCopyPost extends BaseZeroCopyRequestProducer {
111
112 private final boolean forceChunking;
113
114 protected TestZeroCopyPost(
115 final String requestURI,
116 final boolean forceChunking) throws FileNotFoundException {
117 super(URI.create(requestURI), TEST_FILE, ContentType.create("text/plain"));
118 this.forceChunking = forceChunking;
119 }
120
121 @Override
122 protected HttpEntityEnclosingRequest createRequest(final URI requestURI, final HttpEntity entity) {
123 final HttpPost httppost = new HttpPost(requestURI);
124 if (this.forceChunking) {
125 final BasicHttpEntity chunkedEntity = new BasicHttpEntity();
126 chunkedEntity.setChunked(true);
127 httppost.setEntity(chunkedEntity);
128 } else {
129 httppost.setEntity(entity);
130 }
131 return httppost;
132 }
133
134 }
135
136 static class TestZeroCopyConsumer extends ZeroCopyConsumer<Integer> {
137
138 public TestZeroCopyConsumer(final File file) throws FileNotFoundException {
139 super(file);
140 }
141
142 @Override
143 protected Integer process(
144 final HttpResponse response,
145 final File file,
146 final ContentType contentType) {
147 return response.getStatusLine().getStatusCode();
148 }
149
150 }
151
152 static class TestHandler implements HttpRequestHandler {
153
154 private final boolean forceChunking;
155
156 TestHandler(final boolean forceChunking) {
157 super();
158 this.forceChunking = forceChunking;
159 }
160
161 @Override
162 public void handle(
163 final HttpRequest request,
164 final HttpResponse response,
165 final HttpContext context) throws HttpException, IOException {
166 HttpEntity requestEntity = null;
167 if (request instanceof HttpEntityEnclosingRequest) {
168 requestEntity = ((HttpEntityEnclosingRequest) request).getEntity();
169 }
170 if (requestEntity == null) {
171 response.setEntity(new NStringEntity("Empty content"));
172 return;
173 }
174
175 boolean ok = true;
176
177 final InputStream instream = requestEntity.getContent();
178 try {
179 final ContentType contentType = ContentType.getOrDefault(requestEntity);
180 Charset charset = contentType.getCharset();
181 if (charset == null) {
182 charset = Consts.ISO_8859_1;
183 }
184 final LineIterator it = IOUtils.lineIterator(instream, charset.name());
185 int count = 0;
186 while (it.hasNext()) {
187 final String line = it.next();
188 final int i = count % TEXT.length;
189 final String expected = TEXT[i];
190 if (!line.equals(expected)) {
191 ok = false;
192 break;
193 }
194 count++;
195 }
196 } finally {
197 instream.close();
198 }
199 if (ok) {
200 final NFileEntity responseEntity = new NFileEntity(TEST_FILE,
201 ContentType.create("text/plian"));
202 if (this.forceChunking) {
203 responseEntity.setChunked(true);
204 }
205 response.setEntity(responseEntity);
206 } else {
207 response.setEntity(new NStringEntity("Invalid content"));
208 }
209 }
210 }
211
212 @Test
213 public void testTwoWayZeroCopy() throws Exception {
214 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new TestHandler(false)));
215 final HttpHost target = start();
216
217 final File tmpdir = FileUtils.getTempDirectory();
218 this.tmpfile = new File(tmpdir, "dst.test");
219 final TestZeroCopyPost httppost = new TestZeroCopyPost(target.toURI() + "/bounce", false);
220 final TestZeroCopyConsumer consumer = new TestZeroCopyConsumer(this.tmpfile);
221 final Future<Integer> future = this.httpclient.execute(httppost, consumer, null);
222 final Integer status = future.get();
223 Assert.assertNotNull(status);
224 Assert.assertEquals(HttpStatus.SC_OK, status.intValue());
225 final InputStream instream = new FileInputStream(this.tmpfile);
226 try {
227 final LineIterator it = IOUtils.lineIterator(instream, ASCII.name());
228 int count = 0;
229 while (it.hasNext()) {
230 final String line = it.next();
231 final int i = count % TEXT.length;
232 final String expected = TEXT[i];
233 Assert.assertEquals(expected, line);
234 count++;
235 }
236 } finally {
237 instream.close();
238 }
239 }
240
241 @Test
242 public void testZeroCopyFallback() throws Exception {
243 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new TestHandler(true)));
244 final HttpHost target = start();
245 final File tmpdir = FileUtils.getTempDirectory();
246 this.tmpfile = new File(tmpdir, "dst.test");
247 final TestZeroCopyPost httppost = new TestZeroCopyPost(target.toURI() + "/bounce", true);
248 final TestZeroCopyConsumer consumer = new TestZeroCopyConsumer(this.tmpfile);
249 final Future<Integer> future = this.httpclient.execute(httppost, consumer, null);
250 final Integer status = future.get();
251 Assert.assertNotNull(status);
252 Assert.assertEquals(HttpStatus.SC_OK, status.intValue());
253 final InputStream instream = new FileInputStream(this.tmpfile);
254 try {
255 final LineIterator it = IOUtils.lineIterator(instream, ASCII.name());
256 int count = 0;
257 while (it.hasNext()) {
258 final String line = it.next();
259 final int i = count % TEXT.length;
260 final String expected = TEXT[i];
261 Assert.assertEquals(expected, line);
262 count++;
263 }
264 } finally {
265 instream.close();
266 }
267 }
268
269 }