/* * Copyright 2001 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ /** * * @bug 4333920 * @bug 4394548 * @summary Check that chunked encoding response doesn't cause * getInputStream to block until last chunk arrives. * Also regression against NPE in ChunkedInputStream. */ import java.net.*; import java.io.*; import java.util.Random; public class ChunkedEncoding implements Runnable { ServerSocket ss; /* * Our "http" server to return a chunked response */ public void run() { try { Socket s = ss.accept(); PrintStream out = new PrintStream( new BufferedOutputStream( s.getOutputStream() )); /* send the header */ out.print("HTTP/1.1 200\r\n"); out.print("Transfer-Encoding: chunked\r\n"); out.print("Content-Type: text/html\r\n"); out.print("\r\n"); out.flush(); /* delay the server before first chunk */ Thread.sleep(5000); /* * Our response will be of random length * but > 32k */ Random rand = new Random(); int len; do { len = rand.nextInt(128*1024); } while (len < 32*1024); /* * Our chunk size will be 2-32k */ int chunkSize; do { chunkSize = rand.nextInt(len / 3); } while (chunkSize < 2*1024); /* * Generate random content and check sum it */ byte buf[] = new byte[len]; int cs = 0; for (int i=0; i<len; i++) { buf[i] = (byte)('a' + rand.nextInt(26)); cs = (cs + buf[i]) % 65536; } /* * Stream the chunks to the client */ int remaining = len; int pos = 0; while (remaining > 0) { int size = Math.min(remaining, chunkSize); out.print( Integer.toHexString(size) ); out.print("\r\n"); out.write( buf, pos, size ); pos += size; remaining -= size; out.print("\r\n"); out.flush(); } /* send EOF chunk */ out.print("0\r\n"); out.flush(); /* * Send trailer with checksum */ String trailer = "Checksum:" + cs + "\r\n"; out.print(trailer); out.print("\r\n"); out.flush(); s.close(); ss.close(); } catch (Exception e) { e.printStackTrace(); } } ChunkedEncoding() throws Exception { /* start the server */ ss = new ServerSocket(0); (new Thread(this)).start(); /* establish http connection to server */ String uri = "http://localhost:" + Integer.toString(ss.getLocalPort()) + "/foo"; URL url = new URL(uri); HttpURLConnection http = (HttpURLConnection)url.openConnection(); /* * Server should only send headers if TE:trailers * specified - see updated HTTP 1.1 spec. */ http.setRequestProperty("TE", "trailers"); /* Time how long the getInputStream takes */ long ts = System.currentTimeMillis(); InputStream in = http.getInputStream(); long te = System.currentTimeMillis(); /* * If getInputStream takes >2 seconds it probably means * that the implementation is waiting for the chunks to * arrive. */ if ( (te-ts) > 2000) { throw new Exception("getInputStream didn't return immediately"); } /* * Read the stream and checksum it as it arrives */ int nread; int cs = 0; byte b[] = new byte[1024]; do { nread = in.read(b); if (nread > 0) { for (int i=0; i<nread; i++) { cs = (cs + b[i]) % 65536; } } } while (nread > 0); /* * Verify that the checksums match */ String trailer = http.getHeaderField("Checksum"); if (trailer == null) { throw new Exception("Checksum trailer missing from response"); } int rcvd_cs = Integer.parseInt(trailer); if (rcvd_cs != cs) { throw new Exception("Trailer checksum doesn't equal calculated checksum"); } http.disconnect(); } public static void main(String args[]) throws Exception { new ChunkedEncoding(); } }