1 /*
   2  * Copyright (c) 2016, 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 import java.io.File;
  25 import java.io.IOException;
  26 import java.io.InputStream;
  27 import java.io.OutputStream;
  28 import java.net.URI;
  29 import java.net.URISyntaxException;
  30 import java.net.http.CustomHttp2Frame;
  31 import java.net.http.Http2Handler;
  32 import java.net.http.Http2TestExchange;
  33 import java.net.http.Http2TestServer;
  34 import java.net.http.HttpClient;
  35 import java.net.http.HttpRequest;
  36 import java.net.http.HttpResponse;
  37 import java.net.http.HttpTimeoutException;
  38 import java.nio.ByteBuffer;
  39 import java.util.concurrent.TimeUnit;
  40 
  41 /*
  42  * @test
  43  * @bug 8157104
  44  * @modules java.httpclient
  45  * @compile/module=java.httpclient java/net/http/Http2Handler.java
  46  * @compile/module=java.httpclient java/net/http/Http2TestExchange.java
  47  * @compile/module=java.httpclient java/net/http/Http2TestServer.java
  48  * @compile/module=java.httpclient java/net/http/CustomHttp2Frame.java
  49  * @run main/othervm SettingsTest
  50  */
  51 public class SettingsTest {
  52 
  53     private static final String KEYSTORE = System.getProperty("test.src")
  54             + File.separator + "keystore.p12";
  55     private static final String PASSWORD = "password";
  56     private static final int TIMEOUT = 3; // in seconds
  57     private static final int INVALID_STREAM_ID = Integer.MAX_VALUE;
  58     private static final int INVALID_PARAMETERS_LENGTH = 16;
  59     private static final int[] INVALID_PARAMETERS = new int[INVALID_PARAMETERS_LENGTH];
  60 
  61     public static void main(String[] args) throws Exception {
  62         System.setProperty("java.net.http.HttpClient.log",
  63                 "ssl,requests,responses,errors");
  64 
  65         System.setProperty("javax.net.ssl.keyStore", KEYSTORE);
  66         System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD);
  67         System.setProperty("javax.net.ssl.trustStore", KEYSTORE);
  68         System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD);
  69 
  70         Handler handler = new Handler();
  71         
  72         try (Http2TestServer server = new Http2TestServer(true, 0, handler)) {
  73             server.start();
  74 
  75             int port = server.getAddress().getPort();
  76             String uriString = "https://127.0.0.1:" + Integer.toString(port);
  77 
  78             boolean success = true;
  79 
  80             success &= expectSuccess(
  81                     "Test #1: run client, expect successful connection",
  82                     () -> connect(uriString));
  83             
  84             CustomSettingsFrame frame = new CustomSettingsFrame();
  85             frame.setStreamId(INVALID_STREAM_ID);
  86             handler.setFrame(frame);
  87             success &= expectFailure(
  88                     "Test #2: run client, "
  89                             + "server sends a frame with wrong stream id, "
  90                             + "expect connection failure",
  91                     () -> connect(uriString));
  92             
  93             frame = new CustomSettingsFrame(INVALID_PARAMETERS);            
  94             handler.setFrame(frame);
  95             success &= expectFailure(
  96                     "Test #3: run client, "
  97                             + "server sends a frame with wrong parameters, "
  98                             + "expect connection failure",
  99                     () -> connect(uriString));
 100 
 101             if (success) {
 102                 System.out.println("Test passed");
 103             } else {
 104                 throw new RuntimeException("At least one test case failed");
 105             }
 106         }
 107     }
 108 
 109     private static interface Test {
 110 
 111         public void run() throws Exception;
 112     }
 113 
 114     private static class Handler implements Http2Handler {
 115 
 116         private static final byte[] BODY = "Test response".getBytes();
 117         
 118         private volatile CustomSettingsFrame frame;
 119 
 120         @Override
 121         public void handle(Http2TestExchange t) throws IOException {
 122             System.out.println("Handler: received request to "
 123                     + t.getRequestURI());
 124 
 125             if (frame != null) {
 126                 System.out.println("Handler: send a frame: " + frame);
 127                 t.sendFrame(frame);
 128             }
 129 
 130             try (InputStream is = t.getRequestBody()) {
 131                 byte[] body = is.readAllBytes();
 132                 System.out.println("Handler: read " + body.length + " bytes of body: ");
 133                 System.out.println(new String(body));
 134             }
 135 
 136             try (OutputStream os = t.getResponseBody()) {
 137                 t.sendResponseHeaders(200, BODY.length);
 138                 os.write(BODY);
 139             }
 140         }
 141         
 142         void setFrame(CustomSettingsFrame frame) {
 143             this.frame = frame;
 144         }
 145     }
 146 
 147     private static class CustomSettingsFrame extends CustomHttp2Frame {
 148 
 149         private final int[] parameters;                
 150         
 151         CustomSettingsFrame() {
 152             this(null);
 153         }
 154         
 155         CustomSettingsFrame(int[] parameters) {
 156             super();
 157             this.parameters = parameters != null 
 158                     ? parameters.clone() : new int[0]; 
 159             setFrameType(SETTING_FRAME_TYPE);
 160         }
 161 
 162         @Override
 163         public int customComputeLength() {
 164             int length = 0;
 165             for (int i : parameters) {
 166                 if (i != -1) {
 167                     length += 6;
 168                 }
 169             }
 170             return length;
 171         }
 172 
 173         @Override
 174         public void customWriteOutgoing(ByteBuffer buf) {
 175             for (int i = 0; i < parameters.length; i++) {
 176                 if (parameters[i] != -1) {
 177                     buf.putShort((short)(i+1));
 178                     buf.putInt(parameters[i]);
 179                 }
 180             }
 181         }
 182 
 183     }
 184 
 185     private static void connect(String uriString)
 186             throws URISyntaxException, IOException, InterruptedException {
 187 
 188         String body = HttpClient.create()
 189                 .version(HttpClient.Version.HTTP_2)
 190                 .build()
 191                 .request(new URI(uriString))
 192                 .timeout(TimeUnit.SECONDS, TIMEOUT)
 193                 .body(HttpRequest.fromString("body"))
 194                 .GET()
 195                 .response()
 196                 .body(HttpResponse.asString());
 197 
 198         System.out.println("Response: " + body);
 199     }
 200 
 201     private static boolean expectSuccess(String message, Test test) {
 202         System.out.println(message);
 203         try {
 204             test.run();
 205             System.out.println("Passed");
 206             return true;
 207         } catch (Exception e) {
 208             System.out.println("Failed: unexpected exception:");
 209             e.printStackTrace(System.out);
 210             return false;
 211         }
 212     }
 213 
 214     private static boolean expectFailure(String message, Test test) {
 215         System.out.println(message);
 216         try {
 217             test.run();
 218             System.out.println("Failed: unexpected successful connection");
 219             return false;
 220         } catch (HttpTimeoutException e) {
 221             System.out.println("Failed: unexpected HttpTimeoutException:");
 222             e.printStackTrace(System.out);
 223             return false;
 224         } catch (Exception e) {
 225             System.out.println("Passed: expected exception: " + e);
 226             e.printStackTrace(System.out);
 227             return true;
 228         }
 229     }
 230 
 231 }