1 /*
  2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @summary Basic test for Expect 100-Continue ( HTTP/1.1 only )
 27  * @library /test/lib /test/jdk/java/net/httpclient/lib
 28  * @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.common.TestServerConfigurator
 29  * @modules java.net.http/jdk.internal.net.http.common
 30  *          jdk.httpserver
 31  * @run testng/othervm ExpectContinue
 32  */
 33 
 34 import com.sun.net.httpserver.HttpExchange;
 35 import com.sun.net.httpserver.HttpHandler;
 36 import com.sun.net.httpserver.HttpServer;
 37 import com.sun.net.httpserver.HttpsServer;
 38 import java.io.IOException;
 39 import java.io.InputStream;
 40 import java.io.OutputStream;
 41 import java.net.InetAddress;
 42 import java.net.InetSocketAddress;
 43 import java.net.URI;
 44 import java.net.http.HttpClient;
 45 import java.net.http.HttpRequest;
 46 import java.net.http.HttpRequest.BodyPublishers;
 47 import java.net.http.HttpResponse;
 48 import java.net.http.HttpResponse.BodyHandlers;
 49 import java.util.List;
 50 import javax.net.ssl.SSLContext;
 51 
 52 import jdk.httpclient.test.lib.common.TestServerConfigurator;
 53 import jdk.test.lib.net.SimpleSSLContext;
 54 import org.testng.annotations.AfterTest;
 55 import org.testng.annotations.BeforeTest;
 56 import org.testng.annotations.DataProvider;
 57 import org.testng.annotations.Test;
 58 import static java.lang.System.out;
 59 import static org.testng.Assert.assertEquals;
 60 
 61 public class ExpectContinue {
 62 
 63     SSLContext sslContext;
 64     HttpServer httpTestServer;         // HTTP/1.1    [ 2 servers ]
 65     HttpsServer httpsTestServer;       // HTTPS/1.1
 66     String httpURI;
 67     String httpsURI;
 68 
 69     @DataProvider(name = "positive")
 70     public Object[][] positive() {
 71         return new Object[][] {
 72                 { httpURI,  false, "Billy" },
 73                 { httpURI,  false, "Bob"   },
 74                 { httpURI,  true,  "Jimmy" },
 75                 { httpsURI, true,  "Jack"  },
 76         };
 77     }
 78 
 79     @Test(dataProvider = "positive")
 80     void test(String uriString, boolean expectedContinue, String data)
 81         throws Exception
 82     {
 83         out.printf("test(%s, %s, %s): starting%n", uriString, expectedContinue, data);
 84         HttpClient client = HttpClient.newBuilder()
 85                 .sslContext(sslContext)
 86                 .build();
 87 
 88         URI uri = URI.create(uriString);
 89         HttpRequest request = HttpRequest.newBuilder(uri)
 90                 .expectContinue(expectedContinue)
 91                 .POST(BodyPublishers.ofString(data))
 92                 .build();
 93 
 94         HttpResponse<String> response = client.send(request,
 95                                                     BodyHandlers.ofString());
 96         System.out.println("First response: " + response);
 97         assertEquals(response.statusCode(), 200);
 98         assertEquals(response.body(), data);
 99 
100         // again with the same request, to ensure no Expect header duplication
101         response = client.send(request, BodyHandlers.ofString());
102         System.out.println("Second response: " + response);
103         assertEquals(response.statusCode(), 200);
104         assertEquals(response.body(), data);
105     }
106 
107     @Test(dataProvider = "positive")
108     void testAsync(String uriString, boolean expectedContinue, String data) {
109         out.printf("test(%s, %s, %s): starting%n", uriString, expectedContinue, data);
110         HttpClient client = HttpClient.newBuilder()
111                 .sslContext(sslContext)
112                 .build();
113 
114         URI uri = URI.create(uriString);
115         HttpRequest request = HttpRequest.newBuilder(uri)
116                 .expectContinue(expectedContinue)
117                 .POST(BodyPublishers.ofString(data))
118                 .build();
119 
120         HttpResponse<String> response = client.sendAsync(request,
121                 BodyHandlers.ofString()).join();
122         System.out.println("First response: " + response);
123         assertEquals(response.statusCode(), 200);
124         assertEquals(response.body(), data);
125 
126         // again with the same request, to ensure no Expect header duplication
127         response = client.sendAsync(request, BodyHandlers.ofString()).join();
128         System.out.println("Second response: " + response);
129         assertEquals(response.statusCode(), 200);
130         assertEquals(response.body(), data);
131     }
132 
133     // -- Infrastructure
134 
135     static String serverAuthority(HttpServer server) {
136         return InetAddress.getLoopbackAddress().getHostName() + ":"
137                 + server.getAddress().getPort();
138     }
139 
140     @BeforeTest
141     public void setup() throws Exception {
142         sslContext = new SimpleSSLContext().get();
143         if (sslContext == null)
144             throw new AssertionError("Unexpected null sslContext");
145 
146         InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
147         httpTestServer = HttpServer.create(sa, 0);
148         httpTestServer.createContext("/http1/ec", new Http1ExpectContinueHandler());
149         httpURI = "http://" + serverAuthority(httpTestServer) + "/http1/ec";
150 
151         httpsTestServer = HttpsServer.create(sa, 0);
152         httpsTestServer.setHttpsConfigurator(new TestServerConfigurator(sa.getAddress(), sslContext));
153         httpsTestServer.createContext("/https1/ec", new Http1ExpectContinueHandler());
154         httpsURI = "https://" + serverAuthority(httpsTestServer) + "/https1/ec";
155 
156         httpTestServer.start();
157         httpsTestServer.start();
158     }
159 
160     @AfterTest
161     public void teardown() throws Exception {
162         httpTestServer.stop(0);
163         httpsTestServer.stop(0);
164     }
165 
166     static class Http1ExpectContinueHandler implements HttpHandler {
167         @Override
168         public void handle(HttpExchange t) throws IOException {
169             try (InputStream is = t.getRequestBody();
170                  OutputStream os = t.getResponseBody()) {
171                 byte[] bytes = is.readAllBytes();
172 
173                 List<String> expect = t.getRequestHeaders().get("Expect");
174                 if (expect != null && expect.size() != 1) {
175                     System.out.println("Server: Expect: " + expect);
176                     Throwable ex = new AssertionError("Expect: " + expect);
177                     ex.printStackTrace();
178                     t.sendResponseHeaders(500, 0);
179                 } else {
180                     t.sendResponseHeaders(200, bytes.length);
181                     os.write(bytes);
182                 }
183             }
184         }
185     }
186 }