From 5f84beebb796bd2459c04d1192ad948324cef79b Mon Sep 17 00:00:00 2001 From: michaelm Date: Tue, 28 Sep 2010 11:59:57 +0100 Subject: [PATCH] 6550798: Using InputStream.skip with ResponseCache will cause partial data to be cached Reviewed-by: chegar --- .../www/protocol/http/HttpURLConnection.java | 32 +++++ .../www/protocol/http/6550798/TestCache.java | 133 ++++++++++++++++++ .../net/www/protocol/http/6550798/test.java | 90 ++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 test/sun/net/www/protocol/http/6550798/TestCache.java create mode 100644 test/sun/net/www/protocol/http/6550798/test.java diff --git a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index a9caf5949..ad45c983f 100644 --- a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -2825,6 +2825,38 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } } + /* skip() calls read() in order to ensure that entire response gets + * cached. same implementation as InputStream.skip */ + + private byte[] skipBuffer; + private static final int SKIP_BUFFER_SIZE = 8096; + + @Override + public long skip (long n) throws IOException { + + long remaining = n; + int nr; + if (skipBuffer == null) + skipBuffer = new byte[SKIP_BUFFER_SIZE]; + + byte[] localSkipBuffer = skipBuffer; + + if (n <= 0) { + return 0; + } + + while (remaining > 0) { + nr = read(localSkipBuffer, 0, + (int) Math.min(SKIP_BUFFER_SIZE, remaining)); + if (nr < 0) { + break; + } + remaining -= nr; + } + + return n - remaining; + } + @Override public void close () throws IOException { try { diff --git a/test/sun/net/www/protocol/http/6550798/TestCache.java b/test/sun/net/www/protocol/http/6550798/TestCache.java new file mode 100644 index 000000000..c90f3f5a0 --- /dev/null +++ b/test/sun/net/www/protocol/http/6550798/TestCache.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.net.*; +import java.io.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.PrintStream; +import java.io.InputStream; +import java.io.File; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.ResponseCache; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import java.util.Iterator; +import java.util.StringTokenizer; +import java.util.jar.JarInputStream; +import java.util.jar.JarFile; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; +import java.security.Principal; +import java.security.cert.Certificate; +import javax.net.ssl.SSLPeerUnverifiedException; + +public class TestCache extends java.net.ResponseCache { + private boolean inCacheHandler = false; + private boolean _downloading = false; + + public static volatile boolean fail = false; + + public static void reset() { + // Set system wide cache handler + System.out.println("install deploy cache handler"); + ResponseCache.setDefault(new TestCache()); + } + + public synchronized CacheResponse get(final URI uri, String rqstMethod, + Map requestHeaders) throws IOException { + System.out.println("get: " + uri); + Thread.currentThread().dumpStack(); + return null; + } + + public synchronized CacheRequest put(URI uri, URLConnection conn) + throws IOException { + System.out.println("put: " + uri); + Thread.currentThread().dumpStack(); + URL url = uri.toURL(); + return new DeployCacheRequest(url, conn); + + } +} + +class DeployByteArrayOutputStream extends java.io.ByteArrayOutputStream { + + private URL _url; + private URLConnection _conn; + + DeployByteArrayOutputStream(URL url, URLConnection conn) { + _url = url; + _conn = conn; + } + + + public void close() throws IOException { + + System.out.println("contentLength: " + _conn.getContentLength()); + System.out.println("byte array size: " + size()); + if ( _conn.getContentLength() == size()) { + System.out.println("correct content length"); + } else { + System.out.println("wrong content length"); + System.out.println("TEST FAILED"); + TestCache.fail = true; + } + super.close(); + } +} + +class DeployCacheRequest extends java.net.CacheRequest { + + private URL _url; + private URLConnection _conn; + private boolean _downloading = false; + + DeployCacheRequest(URL url, URLConnection conn) { + System.out.println("DeployCacheRequest ctor for: " + url); + _url = url; + _conn = conn; + } + + public void abort() { + System.out.println("abort called"); + } + + public OutputStream getBody() throws IOException { + System.out.println("getBody called"); + return new DeployByteArrayOutputStream(_url, _conn); + } +} diff --git a/test/sun/net/www/protocol/http/6550798/test.java b/test/sun/net/www/protocol/http/6550798/test.java new file mode 100644 index 000000000..9bcf5f915 --- /dev/null +++ b/test/sun/net/www/protocol/http/6550798/test.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 6550798 + * @summary Using InputStream.skip with ResponseCache will cause partial data to be cached + * @run main/othervm test + */ + +import java.net.*; +import com.sun.net.httpserver.*; +import java.io.*; + +public class test { + + final static int LEN = 16 * 1024; + + public static void main(String[] args) throws Exception { + + TestCache.reset(); + HttpServer s = HttpServer.create (new InetSocketAddress(0), 10); + s.createContext ("/", new HttpHandler () { + public void handle (HttpExchange e) { + try { + byte[] buf = new byte [LEN]; + OutputStream o = e.getResponseBody(); + e.sendResponseHeaders(200, LEN); + o.write (buf); + e.close(); + } catch (IOException ex) { + ex.printStackTrace(); + TestCache.fail = true; + } + } + }); + s.start(); + + System.out.println("http request with cache hander"); + URL u = new URL("http://127.0.0.1:"+s.getAddress().getPort()+"/f"); + URLConnection conn = u.openConnection(); + + InputStream is = null; + try { + // this calls into TestCache.get + byte[] buf = new byte[8192]; + is = new BufferedInputStream(conn.getInputStream()); + + is.skip(1000); + + while (is.read(buf) != -1) { + } + } finally { + if (is != null) { + // this calls into TestCache.put + // TestCache.put will check if the resource + // should be cached + is.close(); + } + s.stop(0); + } + + if (TestCache.fail) { + System.out.println ("TEST FAILED"); + throw new RuntimeException (); + } else { + System.out.println ("TEST OK"); + } + } +} -- GitLab