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  * @modules java.net.http
 28  *          jdk.httpserver
 29  * @library /test/lib
 30  * @build jdk.test.lib.net.SimpleSSLContext
 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.HttpsConfigurator;
 38 import com.sun.net.httpserver.HttpsServer;
 39 import java.io.IOException;
 40 import java.io.InputStream;
 41 import java.io.OutputStream;
 42 import java.net.InetAddress;
 43 import java.net.InetSocketAddress;
 44 import java.net.URI;
 45 import java.net.http.HttpClient;
 46 import java.net.http.HttpRequest;
 47 import java.net.http.HttpRequest.BodyPublishers;
 48 import java.net.http.HttpResponse;
 49 import java.net.http.HttpResponse.BodyHandlers;
 50 import java.util.List;
 51 import javax.net.ssl.SSLContext;
 52 import jdk.test.lib.net.SimpleSSLContext;
 53 import org.testng.annotations.AfterTest;
 54 import org.testng.annotations.BeforeTest;
 55 import org.testng.annotations.DataProvider;
 56 import org.testng.annotations.Test;
 57 import static java.lang.System.out;
 58 import static org.testng.Assert.assertEquals;
 59 
 60 public class ExpectContinue {
 61 
 62     SSLContext sslContext;
 63     HttpServer httpTestServer;         // HTTP/1.1    [ 2 servers ]
 64     HttpsServer httpsTestServer;       // HTTPS/1.1
 65     String httpURI;
 66     String httpsURI;
 67 
 68     @DataProvider(name = "positive")
 69     public Object[][] positive() {
 70         return new Object[][] {
 71                 { httpURI,  false, "Billy" },
 72                 { httpURI,  false, "Bob"   },
 73                 { httpURI,  true,  "Jimmy" },
 74                 { httpsURI, true,  "Jack"  },
 75         };
 76     }
 77 
 78     @Test(dataProvider = "positive")
 79     void test(String uriString, boolean expectedContinue, String data)
 80         throws Exception
 81     {
 82         out.printf("test(%s, %s, %s): starting%n", uriString, expectedContinue, data);
 83         HttpClient client = HttpClient.newBuilder()
 84                 .sslContext(sslContext)
 85                 .build();
 86 
 87         URI uri = URI.create(uriString);
 88         HttpRequest request = HttpRequest.newBuilder(uri)
 89                 .expectContinue(expectedContinue)
 90                 .POST(BodyPublishers.ofString(data))
 91                 .build();
 92 
 93         HttpResponse<String> response = client.send(request,
 94                                                     BodyHandlers.ofString());
 95         System.out.println("First response: " + response);
 96         assertEquals(response.statusCode(), 200);
 97         assertEquals(response.body(), data);
 98 
 99         // again with the same request, to ensure no Expect header duplication
100         response = client.send(request, BodyHandlers.ofString());
101         System.out.println("Second response: " + response);
102         assertEquals(response.statusCode(), 200);
103         assertEquals(response.body(), data);
104     }
105 
106     @Test(dataProvider = "positive")
107     void testAsync(String uriString, boolean expectedContinue, String data) {
108         out.printf("test(%s, %s, %s): starting%n", uriString, expectedContinue, data);
109         HttpClient client = HttpClient.newBuilder()
110                 .sslContext(sslContext)
111                 .build();
112 
113         URI uri = URI.create(uriString);
114         HttpRequest request = HttpRequest.newBuilder(uri)
115                 .expectContinue(expectedContinue)
116                 .POST(BodyPublishers.ofString(data))
117                 .build();
118 
119         HttpResponse<String> response = client.sendAsync(request,
120                 BodyHandlers.ofString()).join();
121         System.out.println("First response: " + response);
122         assertEquals(response.statusCode(), 200);
123         assertEquals(response.body(), data);
124 
125         // again with the same request, to ensure no Expect header duplication
126         response = client.sendAsync(request, BodyHandlers.ofString()).join();
127         System.out.println("Second response: " + response);
128         assertEquals(response.statusCode(), 200);
129         assertEquals(response.body(), data);
130     }
131 
132     // -- Infrastructure
133 
134     static String serverAuthority(HttpServer server) {
135         return InetAddress.getLoopbackAddress().getHostName() + ":"
136                 + server.getAddress().getPort();
137     }
138 
139     @BeforeTest
140     public void setup() throws Exception {
141         sslContext = new SimpleSSLContext().get();
142         if (sslContext == null)
143             throw new AssertionError("Unexpected null sslContext");
144 
145         InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
146         httpTestServer = HttpServer.create(sa, 0);
147         httpTestServer.createContext("/http1/ec", new Http1ExpectContinueHandler());
148         httpURI = "http://" + serverAuthority(httpTestServer) + "/http1/ec";
149 
150         httpsTestServer = HttpsServer.create(sa, 0);
151         httpsTestServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
152         httpsTestServer.createContext("/https1/ec", new Http1ExpectContinueHandler());
153         httpsURI = "https://" + serverAuthority(httpsTestServer) + "/https1/ec";
154 
155         httpTestServer.start();
156         httpsTestServer.start();
157     }
158 
159     @AfterTest
160     public void teardown() throws Exception {
161         httpTestServer.stop(0);
162         httpsTestServer.stop(0);
163     }
164 
165     static class Http1ExpectContinueHandler implements HttpHandler {
166         @Override
167         public void handle(HttpExchange t) throws IOException {
168             try (InputStream is = t.getRequestBody();
169                  OutputStream os = t.getResponseBody()) {
170                 byte[] bytes = is.readAllBytes();
171 
172                 List<String> expect = t.getRequestHeaders().get("Expect");
173                 if (expect != null && expect.size() != 1) {
174                     System.out.println("Server: Expect: " + expect);
175                     Throwable ex = new AssertionError("Expect: " + expect);
176                     ex.printStackTrace();
177                     t.sendResponseHeaders(500, 0);
178                 } else {
179                     t.sendResponseHeaders(200, bytes.length);
180                     os.write(bytes);
181                 }
182             }
183         }
184     }
185 }