1 /*
   2  * Copyright (c) 2009, 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  * @bug 6726695
  27  * @summary HttpURLConnection shoul support 'Expect: 100-contimue' headers for PUT
  28 */
  29 
  30 import java.net.*;
  31 import java.io.*;
  32 
  33 public class B6726695 extends Thread {
  34     private ServerSocket server = null;
  35     private int port = 0;
  36     private byte[] data = new byte[512];
  37     private String boundary = "----------------7774563516523621";
  38 
  39     public static void main(String[] args) throws Exception {
  40         B6726695 test = new B6726695();
  41         // Exit even if server is still running
  42         test.setDaemon(true);
  43         // start server
  44         test.start();
  45         // run test
  46         test.test();
  47     }
  48 
  49     public B6726695() {
  50         try {
  51             server = new ServerSocket(0);
  52             port = server.getLocalPort();
  53         } catch (IOException e) {
  54             e.printStackTrace();
  55         }
  56     }
  57 
  58     public void test() throws Exception {
  59         /**
  60          * This is a hardcoded test. The server side expects 3 requests with a
  61          * Expect: 100-continue header. It will reject the 1st one and accept
  62          * the second one. Thus allowing us to test both scenarios.
  63          * The 3rd case is the simulation of a server that just plains ignore
  64          * the Expect: 100-Continue header. So the POST should proceed after
  65          * a timeout.
  66          */
  67         URL url = new URL("http://localhost:" + port + "/foo");
  68 
  69         // 1st Connection. Should be rejected. I.E. get a ProtocolException
  70         URLConnection con = url.openConnection();
  71         HttpURLConnection http = (HttpURLConnection) con;
  72         http.setRequestMethod("POST");
  73         http.setRequestProperty("Expect", "100-Continue");
  74         http.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
  75         http.setDoOutput(true);
  76         http.setFixedLengthStreamingMode(512);
  77         OutputStream out = null;
  78         int errorCode = -1;
  79         try {
  80             out = http.getOutputStream();
  81         } catch (ProtocolException e) {
  82             errorCode = http.getResponseCode();
  83         }
  84         if (errorCode != 417) {
  85             throw new RuntimeException("Didn't get the ProtocolException");
  86         }
  87 
  88         // 2nd connection. Should be accepted by server.
  89         http = (HttpURLConnection) url.openConnection();
  90         http.setRequestMethod("POST");
  91         http.setRequestProperty("Expect", "100-Continue");
  92         http.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
  93         http.setDoOutput(true);
  94         http.setFixedLengthStreamingMode(data.length);
  95         out = null;
  96         try {
  97             out = http.getOutputStream();
  98         } catch (ProtocolException e) {
  99         }
 100         if (out == null) {
 101             throw new RuntimeException("Didn't get an OutputStream");
 102         }
 103         out.write(data);
 104         out.flush();
 105         errorCode = http.getResponseCode();
 106         if (errorCode != 200) {
 107             throw new RuntimeException("Response code is " + errorCode);
 108         }
 109         out.close();
 110 
 111         // 3rd connection. Simulate a server that doesn't implement 100-continue
 112         http = (HttpURLConnection) url.openConnection();
 113         http.setRequestMethod("POST");
 114         http.setRequestProperty("Expect", "100-Continue");
 115         http.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
 116         http.setDoOutput(true);
 117         http.setFixedLengthStreamingMode(data.length);
 118         out = null;
 119         try {
 120             out = http.getOutputStream();
 121         } catch (ProtocolException e) {
 122         }
 123         if (out == null) {
 124             throw new RuntimeException("Didn't get an OutputStream");
 125         }
 126         out.write(data);
 127         out.flush();
 128         out.close();
 129         errorCode = http.getResponseCode();
 130         if (errorCode != 200) {
 131             throw new RuntimeException("Response code is " + errorCode);
 132         }
 133     }
 134 
 135 
 136     @Override
 137     public void run() {
 138         try {
 139             // Fist connection: don't accetpt the request
 140             Socket s = server.accept();
 141             serverReject(s);
 142             // Second connection: accept the request (send 100-continue)
 143             s = server.accept();
 144             serverAccept(s);
 145             // 3rd connection: just ignore the 'Expect:' header
 146             s = server.accept();
 147             serverIgnore(s);
 148         } catch (IOException e) {
 149             e.printStackTrace();
 150         } finally {
 151             try { server.close(); } catch (IOException unused) {}
 152         }
 153     }
 154 
 155     public void serverReject(Socket s) throws IOException {
 156         BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
 157         PrintStream out = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
 158         String line = null;
 159         do {
 160             line = in.readLine();
 161         } while (line != null && line.length() != 0);
 162 
 163         out.print("HTTP/1.1 417 Expectation Failed\r\n");
 164         out.print("Server: Sun-Java-System-Web-Server/7.0\r\n");
 165         out.print("Connection: close\r\n");
 166         out.print("Content-Length: 0\r\n");
 167         out.print("\r\n");
 168         out.flush();
 169         out.close();
 170         in.close();
 171     }
 172 
 173     public void serverAccept(Socket s) throws IOException {
 174         BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
 175         PrintStream out = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
 176         String line = null;
 177         do {
 178             line = in.readLine();
 179         } while (line != null && line.length() != 0);
 180 
 181         // Send 100-Continue
 182         out.print("HTTP/1.1 100 Continue\r\n");
 183         out.print("\r\n");
 184         out.flush();
 185         // Then read the body
 186         char[] cbuf = new char[512];
 187         int l = in.read(cbuf);
 188         // finally send the 200 OK
 189         out.print("HTTP/1.1 200 OK");
 190         out.print("Server: Sun-Java-System-Web-Server/7.0\r\n");
 191         out.print("Connection: close\r\n");
 192         out.print("Content-Length: 0\r\n");
 193         out.print("\r\n");
 194         out.flush();
 195         out.close();
 196         in.close();
 197     }
 198 
 199     public void serverIgnore(Socket s) throws IOException {
 200         BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
 201         PrintStream out = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
 202         String line = null;
 203         do {
 204             line = in.readLine();
 205         } while (line != null && line.length() != 0);
 206 
 207         // Then read the body
 208         char[] cbuf = new char[512];
 209         int l = in.read(cbuf);
 210         // finally send the 200 OK
 211         out.print("HTTP/1.1 200 OK");
 212         out.print("Server: Sun-Java-System-Web-Server/7.0\r\n");
 213         out.print("Content-Length: 0\r\n");
 214         out.print("Connection: close\r\n");
 215         out.print("\r\n");
 216         out.flush();
 217         out.close();
 218         in.close();
 219     }
 220 }