import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import com.minamp.net.Http; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; /** * Http.abort on a response that was already read to the end must not close its connection: by then it's back in * the pool and may be carrying the next request. (The stream proxy aborts every response it served once done; * that used to cut the read-ahead of the next track short with "Unexpected end of stream".) * Run: test/run_pool_abort.sh */ public class PoolAbortTest { static int fails; static void check(boolean ok, String what) { System.out.println((ok ? "PASS " : "FAIL ") + what); if (!ok) fails++; } public static void main(String[] a) throws Exception { HttpServer srv = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0); srv.createContext("/", new HttpHandler() { public void handle(HttpExchange x) throws java.io.IOException { int size = x.getRequestURI().getPath().startsWith("/big") ? 2 * 1024 * 1024 : 1000; x.sendResponseHeaders(200, size); OutputStream o = x.getResponseBody(); byte[] chunk = new byte[16384]; for (int sent = 0; sent < size; sent += chunk.length) { o.write(chunk, 0, Math.min(chunk.length, size - sent)); o.flush(); if (size > 1000) try { Thread.sleep(2); } catch (InterruptedException ignored) {} } o.close(); } }); srv.start(); String base = "http://127.0.0.1:" + srv.getAddress().getPort(); // 1. the player's response, read to the end: its connection goes back to the pool Http.Response first = Http.get(base + "/small", null, 5000); check(first.readAll().length == 1000, "first response read whole"); // 2. the read-ahead's request takes that pooled connection Http.Response second = Http.get(base + "/big", null, 5000); InputStream in = second.body; byte[] buf = new byte[16384]; long got = 0; int n = in.read(buf); got += n; // 3. the proxy cleans up the first response Http.abort(first); String err = ""; try { while ((n = in.read(buf)) > 0) got += n; } catch (java.io.IOException e) { err = " (" + e.getMessage() + ")"; } check(got == 2 * 1024 * 1024, "aborting a finished response leaves the next request alone: " + got + " bytes" + err); // an unfinished response is still cut off Http.Response third = Http.get(base + "/big", null, 5000); third.body.read(buf); Http.abort(third); boolean cut = false; try { long left = 2 * 1024 * 1024; while ((n = third.body.read(buf)) > 0) left -= n; cut = left > 0; } catch (java.io.IOException e) { cut = true; } check(cut, "aborting a response still being read cuts it off"); srv.stop(0); System.out.println(fails == 0 ? "all passed" : fails + " failed"); System.exit(fails == 0 ? 0 : 1); } }