Java tutorial
// Copyright (C) king.com Ltd 2015 // https://github.com/king/king-http-client // Author: Magnus Gustafsson // License: Apache 2.0, https://raw.github.com/king/king-http-client/LICENSE-APACHE package com.king.platform.net.http.integration; import com.king.platform.net.http.ConfKeys; import com.king.platform.net.http.FileResponseConsumer; import com.king.platform.net.http.FutureResult; import com.king.platform.net.http.netty.NettyHttpClient; import io.netty.util.ResourceLeakDetector; import org.eclipse.jetty.server.HttpOutput; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.WriteListener; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; public class HttpGetFile { @Rule public TemporaryFolder folder = new TemporaryFolder(); IntegrationServer integrationServer; private NettyHttpClient httpClient; private int port; private TemporaryFile temporaryFile; @Before public void setUp() throws Exception { temporaryFile = new TemporaryFile(folder); ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.PARANOID); integrationServer = new JettyIntegrationServer(); integrationServer.start(); port = integrationServer.getPort(); httpClient = new TestingHttpClientFactory().create(); httpClient.setConf(ConfKeys.TOTAL_REQUEST_TIMEOUT_MILLIS, 0); httpClient.setConf(ConfKeys.IDLE_TIMEOUT_MILLIS, 100); httpClient.start(); } @Test public void get32MBFile() throws Exception { temporaryFile.generateContent(32 * 1024); integrationServer.addServlet(new FileServingHttpServlet(1024 * 8, temporaryFile), "/getFile"); BlockingMD5CalculatingHttpCallback httpCallback = new BlockingMD5CalculatingHttpCallback(); httpClient.createGet("http://localhost:" + port + "/getFile").build().execute(httpCallback); httpCallback.waitForCompletion(); byte[] clientMd5 = httpCallback.getBody(); assertEquals(hexStringFromBytes(temporaryFile.getFileMd5()), hexStringFromBytes(clientMd5)); } @Test public void get64MBFile() throws Exception { temporaryFile.generateContent(64 * 1024); integrationServer.addServlet(new AsyncFileServingHttpServlet(1024 * 1024, temporaryFile), "/getFile"); BlockingMD5CalculatingHttpCallback httpCallback = new BlockingMD5CalculatingHttpCallback(); httpClient.createGet("http://localhost:" + port + "/getFile").build().execute(httpCallback); httpCallback.waitForCompletion(); byte[] clientMd5 = httpCallback.getBody(); assertEquals(hexStringFromBytes(temporaryFile.getFileMd5()), hexStringFromBytes(clientMd5)); } @Test public void get64MBFileToLocalFile() throws Exception { temporaryFile.generateContent(64 * 1024); integrationServer.addServlet(new AsyncFileServingHttpServlet(1024 * 1024, temporaryFile), "/getFile"); File tempFile = temporaryFile.getTempFile(); Future<FutureResult<File>> execute = httpClient.createGet("http://localhost:" + port + "/getFile").build() .execute(new FileResponseConsumer(tempFile)); FutureResult<File> result = execute.get(1000, TimeUnit.MILLISECONDS); File body = result.getHttpResponse().getBody(); assertEquals(64 * 1024 * 1024, body.length()); } @Test public void get1KbFile() throws Exception { temporaryFile.generateContent(1); integrationServer.addServlet(new FileServingHttpServlet(1024 * 8, temporaryFile), "/getFile"); BlockingMD5CalculatingHttpCallback httpCallback = new BlockingMD5CalculatingHttpCallback(); httpClient.createGet("http://localhost:" + port + "/getFile").build().execute(httpCallback); httpCallback.waitForCompletion(); byte[] clientMd5 = httpCallback.getBody(); assertEquals(hexStringFromBytes(temporaryFile.getFileMd5()), hexStringFromBytes(clientMd5)); } @Test public void get1KbFileTwice() throws Exception { temporaryFile.generateContent(1); integrationServer.addServlet(new FileServingHttpServlet(1024 * 8, temporaryFile), "/getFile"); BlockingMD5CalculatingHttpCallback httpCallback = new BlockingMD5CalculatingHttpCallback(); httpClient.createGet("http://localhost:" + port + "/getFile").build().execute(httpCallback); httpCallback.waitForCompletion(); httpCallback = new BlockingMD5CalculatingHttpCallback(); httpClient.createGet("http://localhost:" + port + "/getFile").build().execute(httpCallback); httpCallback.waitForCompletion(); byte[] clientMd5 = httpCallback.getBody(); assertEquals(hexStringFromBytes(temporaryFile.getFileMd5()), hexStringFromBytes(clientMd5)); } @Test public void get16KbFile() throws Exception { temporaryFile.generateContent(16); integrationServer.addServlet(new FileServingHttpServlet(1024, temporaryFile), "/getFile"); BlockingMD5CalculatingHttpCallback httpCallback = new BlockingMD5CalculatingHttpCallback(); httpClient.createGet("http://localhost:" + port + "/getFile").build().execute(httpCallback); httpCallback.waitForCompletion(); byte[] clientMd5 = httpCallback.getBody(); assertEquals(hexStringFromBytes(temporaryFile.getFileMd5()), hexStringFromBytes(clientMd5)); } private String hexStringFromBytes(byte[] b) { return String.format("%0" + b.length * 2 + "x", new BigInteger(1, b)); } @After public void tearDown() throws Exception { integrationServer.shutdown(); httpClient.shutdown(); } private static class FileServingHttpServlet extends HttpServlet { private final int bufferSize; private final File serverBinaryBlob; public FileServingHttpServlet(int bufferSize, TemporaryFile serverBinaryBlob) { this.bufferSize = bufferSize; this.serverBinaryBlob = serverBinaryBlob.getFile(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setBufferSize(bufferSize); resp.setContentType("application/octet-stream"); resp.setHeader("Content-Disposition", "filename=\"serverBinary.blob\""); resp.setContentLength((int) serverBinaryBlob.length()); byte[] buffer = new byte[bufferSize]; try (FileInputStream fis = new FileInputStream(serverBinaryBlob); OutputStream os = resp.getOutputStream()) { int byteRead = 0; while ((byteRead = fis.read(buffer)) != -1) { os.write(buffer, 0, byteRead); } os.flush(); resp.setStatus(200); } catch (Exception excp) { resp.setStatus(500); } } } private static class AsyncFileServingHttpServlet extends HttpServlet { private final int bufferSize; private final File serverBinaryBlob; private final ConcurrentHashMap fileCache = new ConcurrentHashMap(); public AsyncFileServingHttpServlet(int bufferSize, TemporaryFile serverBinaryBlob) { this.bufferSize = bufferSize; this.serverBinaryBlob = serverBinaryBlob.getFile(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try (RandomAccessFile raf = new RandomAccessFile(serverBinaryBlob, "r")) { ByteBuffer buf = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, raf.length()); final ByteBuffer content = buf.asReadOnlyBuffer(); final HttpOutput out = (HttpOutput) resp.getOutputStream(); final AsyncContext async = req.startAsync(); out.setWriteListener(new WriteListener() { public void onWritePossible() throws IOException { while (out.isReady()) { if (!content.hasRemaining()) { async.complete(); return; } out.write(content); } } public void onError(Throwable t) { getServletContext().log("Async Error", t); async.complete(); } }); } } } }