Path: blob/master/test/jdk/sun/net/www/protocol/https/ChunkedOutputStream.java
66646 views
/*1* Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 502674526* @library /test/lib27* @run main/othervm ChunkedOutputStream28* @run main/othervm -Djava.net.preferIPv6Addresses=true ChunkedOutputStream29*30* SunJSSE does not support dynamic system properties, no way to re-use31* system properties in samevm/agentvm mode.32* @summary Cannot flush output stream when writing to an HttpUrlConnection33*/3435import java.io.FileInputStream;36import java.io.IOException;37import java.io.InputStream;38import java.io.OutputStream;39import java.net.HttpRetryException;40import java.net.HttpURLConnection;41import java.net.InetAddress;42import java.net.InetSocketAddress;43import java.net.Proxy;44import java.net.SocketException;45import java.net.URL;46import java.nio.charset.Charset;47import java.security.KeyStore;48import java.util.concurrent.Executors;49import java.util.concurrent.atomic.AtomicInteger;5051import javax.net.ssl.HostnameVerifier;52import javax.net.ssl.HttpsURLConnection;53import javax.net.ssl.KeyManagerFactory;54import javax.net.ssl.SSLContext;55import javax.net.ssl.SSLSession;56import javax.net.ssl.TrustManagerFactory;5758import com.sun.net.httpserver.HttpExchange;59import com.sun.net.httpserver.HttpHandler;60import com.sun.net.httpserver.HttpsConfigurator;61import com.sun.net.httpserver.HttpsServer;6263public class ChunkedOutputStream implements HttpHandler {64/*65* Where do we find the keystores for ssl?66*/67static String pathToStores = "../../../../../javax/net/ssl/etc";68static String keyStoreFile = "keystore";69static String trustStoreFile = "truststore";70static String passwd = "passphrase";71static int count = 0;72static final AtomicInteger rogueCount = new AtomicInteger();7374static final String str1 = "Helloworld1234567890abcdefghijklmnopqrstuvwxyz"+75"1234567890abcdefkjsdlkjflkjsldkfjlsdkjflkj"+76"1434567890abcdefkjsdlkjflkjsldkfjlsdkjflkj";7778static final String str2 = "Helloworld1234567890abcdefghijklmnopqrstuvwxyz"+79"1234567890";8081private static String getAuthority() {82InetAddress address = server.getAddress().getAddress();83String hostaddr = address.getHostAddress();84if (address.isAnyLocalAddress()) hostaddr = "localhost";85if (hostaddr.indexOf(':') > -1) hostaddr = "[" + hostaddr + "]";86return hostaddr + ":" + server.getAddress().getPort();87}8889public void handle(HttpExchange req) throws IOException {90// this is needed (count++ doesn't work), 'cause we91// are doing concurrent tests92System.out.println("Request Received");93String path = req.getRequestURI().getPath();94if (path.equals("/d0")) {95count = 0;96} else if (path.equals("/d01")) {97count = 1;98} else if (path.equals("/d3")) {99count = 2;100} else if (path.equals("/d4") || path.equals("/d5")) {101count = 3;102} else if (path.equals("/d6")) {103count = 3;104} else if (path.equals("/d7")) {105count = 4;106} else if (path.equals("/d8")) {107count = 5;108}109110switch (count) {111case 0: /* test1 -- keeps conn alive */112case 1: /* test2 -- closes conn */113114String reqbody = "";115try(InputStream inputStream = req.getRequestBody()) {116reqbody = new String(inputStream.readAllBytes(), Charset.forName("ISO8859_1"));117}118if (!reqbody.equals(str1)) {119req.sendResponseHeaders(500, -1);120break;121}122String chunk = req.getRequestHeaders().getFirst("Transfer-encoding");123if (!"chunked".equals(chunk)) {124req.sendResponseHeaders(501, -1);125break;126}127if (count == 1) {128req.getResponseHeaders().set("Connection", "close");129}130req.sendResponseHeaders(200, 0);131try (OutputStream os = req.getResponseBody()) {132os.write(reqbody.getBytes(Charset.forName("ISO8859_1")));133}134break;135case 2: /* test 3 */136reqbody = new String(req.getRequestBody().readAllBytes(), Charset.forName("ISO8859_1"));137if (!reqbody.equals(str2)) {138req.sendResponseHeaders(500, -1);139break;140}141int clen = Integer.parseInt (req.getRequestHeaders().getFirst("Content-length"));142if (clen != str2.length()) {143req.sendResponseHeaders(501, -1);144break;145}146req.getResponseHeaders().set("Connection", "close");147req.sendResponseHeaders(200, 0);148try (OutputStream os = req.getResponseBody()) {149os.write(reqbody.getBytes(Charset.forName("ISO8859_1")));150}151break;152case 3: /* test 6 */153if (path.equals("/d6")) {154reqbody = new String(req.getRequestBody().readAllBytes(), Charset.forName("ISO8859_1"));155}156req.getResponseHeaders().set("Location", "https://foo.bar/");157req.getResponseHeaders().set("Connection", "close");158req.sendResponseHeaders(307, -1);159break;160case 4: /* test 7 */161case 5: /* test 8 */162reqbody = new String(req.getRequestBody().readAllBytes(), Charset.forName("ISO8859_1"));163if (reqbody != null && !"".equals(reqbody)) {164req.sendResponseHeaders(501, -1);165break;166}167req.getResponseHeaders().set("Connection", "close");168req.sendResponseHeaders(200, -1);169break;170default:171req.sendResponseHeaders(404, -1);172break;173}174req.close();175}176177static void readAndCompare(InputStream is, String cmp) throws IOException {178int c;179byte buf[] = new byte[1024];180int off = 0;181int len = 1024;182while ((c=is.read(buf, off, len)) != -1) {183off += c;184len -= c;185}186String s1 = new String(buf, 0, off, "ISO8859_1");187if (!cmp.equals(s1)) {188throw new IOException("strings not same");189}190}191192/* basic smoke test: verify that server drops plain connections */193static void testPlainText(String authority) throws Exception {194URL url = new URL("http://" + authority + "/Donauschiffsgesellschaftskapitaenskajuete");195System.out.println("client opening connection to: " + url);196HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);197int rogue = rogueCount.get();198try {199int code = urlc.getResponseCode();200System.out.println("Unexpected response: " + code);201throw new AssertionError("Unexpected response: " + code);202} catch (SocketException x) {203// we expect that the server will drop the connection and204// close the accepted socket, so we should get a SocketException205System.out.println("Got expected exception: " + x);206}207}208209/* basic chunked test (runs twice) */210211static void test1(String u) throws Exception {212URL url = new URL(u);213System.out.println("client opening connection to: " + u);214HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);215urlc.setChunkedStreamingMode(20);216urlc.setDoOutput(true);217urlc.setRequestMethod("POST");218OutputStream os = urlc.getOutputStream();219os.write(str1.getBytes(Charset.forName("ISO8859_1")));220os.close();221InputStream is = urlc.getInputStream();222readAndCompare(is, str1);223is.close();224}225226/* basic fixed length test */227228static void test3(String u) throws Exception {229URL url = new URL(u);230System.out.println("client opening connection to: " + u);231HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);232urlc.setFixedLengthStreamingMode(str2.length());233urlc.setDoOutput(true);234urlc.setRequestMethod("POST");235OutputStream os = urlc.getOutputStream();236os.write (str2.getBytes(Charset.forName("ISO8859_1")));237os.close();238InputStream is = urlc.getInputStream();239readAndCompare(is, str2);240is.close();241}242243/* write too few bytes */244245static void test4(String u) throws Exception {246URL url = new URL(u);247System.out.println("client opening connection to: " + u);248HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);249urlc.setFixedLengthStreamingMode(str2.length()+1);250urlc.setDoOutput(true);251urlc.setRequestMethod("POST");252OutputStream os = urlc.getOutputStream();253os.write(str2.getBytes(Charset.forName("ISO8859_1")));254try {255os.close();256throw new Exception("should have thrown IOException");257} catch (IOException e) {}258}259260/* write too many bytes */261262static void test5(String u) throws Exception {263URL url = new URL(u);264System.out.println("client opening connection to: " + u);265HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);266urlc.setFixedLengthStreamingMode(str2.length()-1);267urlc.setDoOutput(true);268urlc.setRequestMethod("POST");269OutputStream os = urlc.getOutputStream();270try {271os.write(str2.getBytes(Charset.forName("ISO8859_1")));272throw new Exception("should have thrown IOException");273} catch (IOException e) {}274}275276/* check for HttpRetryException on redirection */277278static void test6(String u) throws Exception {279URL url = new URL(u);280System.out.println("client opening connection to: " + u);281HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);282urlc.setChunkedStreamingMode(20);283urlc.setDoOutput(true);284urlc.setRequestMethod("POST");285OutputStream os = urlc.getOutputStream();286os.write(str1.getBytes(Charset.forName("ISO8859_1")));287os.close();288try {289InputStream is = urlc.getInputStream();290throw new Exception("should have gotten HttpRetryException");291} catch (HttpRetryException e) {292if (e.responseCode() != 307) {293throw new Exception("Wrong response code " + e.responseCode());294}295if (!e.getLocation().equals("https://foo.bar/")) {296throw new Exception("Wrong location " + e.getLocation());297}298}299}300301/* next two tests send zero length posts */302303static void test7(String u) throws Exception {304URL url = new URL(u);305System.out.println("client opening connection to: " + u);306HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);307urlc.setChunkedStreamingMode(20);308urlc.setDoOutput(true);309urlc.setRequestMethod("POST");310OutputStream os = urlc.getOutputStream();311os.close();312int ret = urlc.getResponseCode();313if (ret != 200) {314throw new Exception("Expected 200: got " + ret);315}316}317318static void test8(String u) throws Exception {319URL url = new URL(u);320System.out.println("client opening connection to: " + u);321HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);322urlc.setFixedLengthStreamingMode(0);323urlc.setDoOutput(true);324urlc.setRequestMethod("POST");325OutputStream os = urlc.getOutputStream();326os.close();327int ret = urlc.getResponseCode();328if (ret != 200) {329throw new Exception("Expected 200: got " + ret);330}331}332333static HttpsServer server;334335public static void main(String[] args) throws Exception {336ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream();337// setup properties to do ssl338String keyFilename =339System.getProperty("test.src", "./") + "/" + pathToStores +340"/" + keyStoreFile;341String trustFilename =342System.getProperty("test.src", "./") + "/" + pathToStores +343"/" + trustStoreFile;344345InetAddress loopback = InetAddress.getLoopbackAddress();346347HostnameVerifier reservedHV =348HttpsURLConnection.getDefaultHostnameVerifier();349try {350System.setProperty("javax.net.ssl.keyStore", keyFilename);351System.setProperty("javax.net.ssl.keyStorePassword", passwd);352System.setProperty("javax.net.ssl.trustStore", trustFilename);353System.setProperty("javax.net.ssl.trustStorePassword", passwd);354HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());355356try {357// create and initialize a SSLContext358KeyStore ks = KeyStore.getInstance("JKS");359KeyStore ts = KeyStore.getInstance("JKS");360char[] passphrase = "passphrase".toCharArray();361362ks.load(new FileInputStream(System.getProperty("javax.net.ssl.keyStore")), passphrase);363ts.load(new FileInputStream(System.getProperty("javax.net.ssl.trustStore")), passphrase);364365KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");366kmf.init(ks, passphrase);367368TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");369tmf.init(ts);370371SSLContext sslCtx = SSLContext.getInstance("TLS");372373sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);374375server = HttpsServer.create(new InetSocketAddress(loopback, 0), 10);376server.setHttpsConfigurator(new HttpsConfigurator(sslCtx));377server.createContext("/", chunkedOutputStream);378server.setExecutor(Executors.newSingleThreadExecutor());379server.start();380381System.out.println("Server started: listening on: " + getAuthority());382testPlainText(getAuthority());383// the test server doesn't support keep-alive yet384// test1("http://" + server.getAuthority() + "/d0");385test1("https://" + getAuthority() + "/d01");386test3("https://" + getAuthority() + "/d3");387test4("https://" + getAuthority() + "/d4");388test5("https://" + getAuthority() + "/d5");389test6("https://" + getAuthority() + "/d6");390test7("https://" + getAuthority() + "/d7");391test8("https://" + getAuthority() + "/d8");392} catch (Exception e) {393if (server != null) {394server.stop(1);395}396throw e;397}398server.stop(1);399} finally {400HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);401}402}403404static class NameVerifier implements HostnameVerifier {405public boolean verify(String hostname, SSLSession session) {406return true;407}408}409410public static void except(String s) {411server.stop(1);412throw new RuntimeException(s);413}414}415416417