test/jdk/java/net/HttpURLConnection/SetAuthenticator/HTTPTestServer.java
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
parent 54086 ccb4a50bee06
child 58679 9c3209ff7550
equal deleted inserted replaced
58677:13588c901957 58678:9cf78a70fa4f
   163             final List<B> toClose = new ArrayList<>();
   163             final List<B> toClose = new ArrayList<>();
   164             try {
   164             try {
   165                 for (int i = 1; i <= max; i++) {
   165                 for (int i = 1; i <= max; i++) {
   166                     B bindable = createBindable();
   166                     B bindable = createBindable();
   167                     SocketAddress address = getAddress(bindable);
   167                     SocketAddress address = getAddress(bindable);
   168                     String key = address.toString();
   168                     String key = toString(address);
   169                     if (addresses.addIfAbsent(key)) {
   169                     if (addresses.addIfAbsent(key)) {
   170                        System.out.println("Socket bound to: " + key
   170                        System.out.println("Socket bound to: " + key
   171                                           + " after " + i + " attempt(s)");
   171                                           + " after " + i + " attempt(s)");
   172                        return bindable;
   172                        return bindable;
   173                     }
   173                     }
   184                   try { close(b); } catch (Exception x) { /* ignore */ }
   184                   try { close(b); } catch (Exception x) { /* ignore */ }
   185                 }
   185                 }
   186             }
   186             }
   187             throw new IOException("Couldn't bind socket after " + max + " attempts: "
   187             throw new IOException("Couldn't bind socket after " + max + " attempts: "
   188                                   + "addresses used before: " + addresses);
   188                                   + "addresses used before: " + addresses);
       
   189         }
       
   190 
       
   191         private static String toString(SocketAddress address) {
       
   192             // We don't rely on address.toString(): sometimes it can be
       
   193             // "/127.0.0.1:port", sometimes it can be "localhost/127.0.0.1:port"
       
   194             // Instead we compose our own string representation:
       
   195             InetSocketAddress candidate = (InetSocketAddress) address;
       
   196             String hostAddr = candidate.getAddress().getHostAddress();
       
   197             if (hostAddr.contains(":")) hostAddr = "[" + hostAddr + "]";
       
   198             return hostAddr + ":" + candidate.getPort();
   189         }
   199         }
   190 
   200 
   191         protected abstract B createBindable() throws IOException;
   201         protected abstract B createBindable() throws IOException;
   192 
   202 
   193         protected abstract SocketAddress getAddress(B bindable);
   203         protected abstract SocketAddress getAddress(B bindable);
   386         impl.start();
   396         impl.start();
   387         return redirectingServer;
   397         return redirectingServer;
   388     }
   398     }
   389 
   399 
   390     public InetSocketAddress getAddress() {
   400     public InetSocketAddress getAddress() {
       
   401         return serverImpl.getAddress();
       
   402     }
       
   403 
       
   404     public InetSocketAddress getProxyAddress() {
   391         return serverImpl.getAddress();
   405         return serverImpl.getAddress();
   392     }
   406     }
   393 
   407 
   394     public void stop() {
   408     public void stop() {
   395         serverImpl.stop(0);
   409         serverImpl.stop(0);
   964     // CONNECT and then redirect streams to the real server.
   978     // CONNECT and then redirect streams to the real server.
   965     static class HttpsProxyTunnel extends HTTPTestServer
   979     static class HttpsProxyTunnel extends HTTPTestServer
   966             implements Runnable {
   980             implements Runnable {
   967 
   981 
   968         final ServerSocket ss;
   982         final ServerSocket ss;
       
   983         private volatile boolean stop;
       
   984 
   969         public HttpsProxyTunnel(HttpServer server, HTTPTestServer target,
   985         public HttpsProxyTunnel(HttpServer server, HTTPTestServer target,
   970                                HttpHandler delegate)
   986                                HttpHandler delegate)
   971                 throws IOException {
   987                 throws IOException {
   972             super(server, target, delegate);
   988             super(server, target, delegate);
   973             System.out.flush();
   989             System.out.flush();
   982             t.start();
   998             t.start();
   983         }
   999         }
   984 
  1000 
   985         @Override
  1001         @Override
   986         public void stop() {
  1002         public void stop() {
   987             super.stop();
  1003             try (var toClose = ss) {
   988             try {
  1004                 stop = true;
   989                 ss.close();
  1005                 System.out.println("Server " + ss + " stop requested");
       
  1006                 super.stop();
   990             } catch (IOException ex) {
  1007             } catch (IOException ex) {
   991                 if (DEBUG) ex.printStackTrace(System.out);
  1008                 if (DEBUG) ex.printStackTrace(System.out);
   992             }
  1009             }
   993         }
  1010         }
   994 
  1011 
  1017                 }
  1034                 }
  1018             };
  1035             };
  1019         }
  1036         }
  1020 
  1037 
  1021         @Override
  1038         @Override
  1022         public InetSocketAddress getAddress() {
  1039         public InetSocketAddress getProxyAddress() {
  1023             return new InetSocketAddress(ss.getInetAddress(), ss.getLocalPort());
  1040             return new InetSocketAddress(ss.getInetAddress(), ss.getLocalPort());
  1024         }
  1041         }
  1025 
  1042 
  1026         // This is a bit shaky. It doesn't handle continuation
  1043         // This is a bit shaky. It doesn't handle continuation
  1027         // lines, but our client shouldn't send any.
  1044         // lines, but our client shouldn't send any.
  1034             int c;
  1051             int c;
  1035             while ((c = r.read()) != -1) {
  1052             while ((c = r.read()) != -1) {
  1036                 if (c == '\n') break;
  1053                 if (c == '\n') break;
  1037                 b.appendCodePoint(c);
  1054                 b.appendCodePoint(c);
  1038             }
  1055             }
       
  1056             if (b.length() == 0) {
       
  1057                 return "";
       
  1058             }
  1039             if (b.codePointAt(b.length() -1) == '\r') {
  1059             if (b.codePointAt(b.length() -1) == '\r') {
  1040                 b.delete(b.length() -1, b.length());
  1060                 b.delete(b.length() -1, b.length());
  1041             }
  1061             }
  1042             return b.toString();
  1062             return b.toString();
  1043         }
  1063         }
  1044 
  1064 
  1045         @Override
  1065         @Override
  1046         public void run() {
  1066         public void run() {
  1047             Socket clientConnection = null;
  1067             Socket clientConnection = null;
  1048             try {
  1068             while (!stop) {
  1049                 while (true) {
  1069                 System.out.println("Tunnel: Waiting for client at: " + ss);
  1050                     System.out.println("Tunnel: Waiting for client");
  1070                 final Socket previous = clientConnection;
  1051                     Socket previous = clientConnection;
  1071                 try {
       
  1072                     clientConnection = ss.accept();
       
  1073                 } catch (IOException io) {
  1052                     try {
  1074                     try {
  1053                         clientConnection = ss.accept();
  1075                         ss.close();
       
  1076                     } catch (IOException ex) {
       
  1077                         if (DEBUG) {
       
  1078                             ex.printStackTrace(System.out);
       
  1079                         }
       
  1080                     }
       
  1081                     // log the reason that caused the server to stop accepting connections
       
  1082                     if (!stop) {
       
  1083                         System.err.println("Server will stop accepting connections due to an exception:");
       
  1084                         io.printStackTrace();
       
  1085                     }
       
  1086                     break;
       
  1087                 } finally {
       
  1088                     // close the previous connection
       
  1089                     if (previous != null) {
       
  1090                         try {
       
  1091                             previous.close();
       
  1092                         } catch (IOException e) {
       
  1093                             // ignore
       
  1094                             if (DEBUG) {
       
  1095                                 System.out.println("Ignoring exception that happened while closing " +
       
  1096                                         "an older connection:");
       
  1097                                 e.printStackTrace(System.out);
       
  1098                             }
       
  1099                         }
       
  1100                     }
       
  1101                 }
       
  1102                 System.out.println("Tunnel: Client accepted");
       
  1103                 try {
       
  1104                     // We have only 1 client... process the current client
       
  1105                     // request and wait until it has finished before
       
  1106                     // accepting a new connection request.
       
  1107                     processRequestAndWaitToComplete(clientConnection);
       
  1108                 } catch (IOException ioe) {
       
  1109                     // close the client connection
       
  1110                     try {
       
  1111                         clientConnection.close();
  1054                     } catch (IOException io) {
  1112                     } catch (IOException io) {
  1055                         if (DEBUG) io.printStackTrace(System.out);
  1113                         // ignore
  1056                         break;
  1114                         if (DEBUG) {
       
  1115                             System.out.println("Ignoring exception that happened during client" +
       
  1116                                     " connection close:");
       
  1117                             io.printStackTrace(System.out);
       
  1118                         }
  1057                     } finally {
  1119                     } finally {
  1058                         // close the previous connection
  1120                         clientConnection = null;
  1059                         if (previous != null) previous.close();
       
  1060                     }
  1121                     }
  1061                     System.out.println("Tunnel: Client accepted");
  1122                 } catch (Throwable t) {
  1062                     Socket targetConnection = null;
  1123                     // don't close the client connection for non-IOExceptions, instead
  1063                     InputStream  ccis = clientConnection.getInputStream();
  1124                     // just log it and move on to accept next connection
  1064                     OutputStream ccos = clientConnection.getOutputStream();
  1125                     if (!stop) {
  1065                     Writer w = new OutputStreamWriter(
  1126                         t.printStackTrace();
  1066                                    clientConnection.getOutputStream(), "UTF-8");
       
  1067                     PrintWriter pw = new PrintWriter(w);
       
  1068                     System.out.println("Tunnel: Reading request line");
       
  1069                     String requestLine = readLine(ccis);
       
  1070                     System.out.println("Tunnel: Request line: " + requestLine);
       
  1071                     if (requestLine.startsWith("CONNECT ")) {
       
  1072                         // We should probably check that the next word following
       
  1073                         // CONNECT is the host:port of our HTTPS serverImpl.
       
  1074                         // Some improvement for a followup!
       
  1075 
       
  1076                         // Read all headers until we find the empty line that
       
  1077                         // signals the end of all headers.
       
  1078                         while(!requestLine.equals("")) {
       
  1079                             System.out.println("Tunnel: Reading header: "
       
  1080                                                + (requestLine = readLine(ccis)));
       
  1081                         }
       
  1082 
       
  1083                         targetConnection = new Socket(
       
  1084                                 serverImpl.getAddress().getAddress(),
       
  1085                                 serverImpl.getAddress().getPort());
       
  1086 
       
  1087                         // Then send the 200 OK response to the client
       
  1088                         System.out.println("Tunnel: Sending "
       
  1089                                            + "HTTP/1.1 200 OK\r\n\r\n");
       
  1090                         pw.print("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
       
  1091                         pw.flush();
       
  1092                     } else {
       
  1093                         // This should not happen. If it does let our serverImpl
       
  1094                         // deal with it.
       
  1095                         throw new IOException("Tunnel: Unexpected status line: "
       
  1096                                              + requestLine);
       
  1097                     }
  1127                     }
  1098 
  1128                 }
  1099                     // Pipe the input stream of the client connection to the
  1129             }
  1100                     // output stream of the target connection and conversely.
  1130         }
  1101                     // Now the client and target will just talk to each other.
  1131 
  1102                     System.out.println("Tunnel: Starting tunnel pipes");
  1132         private void processRequestAndWaitToComplete(final Socket clientConnection)
  1103                     Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+');
  1133                 throws IOException, InterruptedException {
  1104                     Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-');
  1134             final Socket targetConnection;
  1105                     t1.start();
  1135             InputStream  ccis = clientConnection.getInputStream();
  1106                     t2.start();
  1136             OutputStream ccos = clientConnection.getOutputStream();
  1107 
  1137             Writer w = new OutputStreamWriter(
  1108                     // We have only 1 client... wait until it has finished before
  1138                     clientConnection.getOutputStream(), "UTF-8");
  1109                     // accepting a new connection request.
  1139             PrintWriter pw = new PrintWriter(w);
  1110                     t1.join();
  1140             System.out.println("Tunnel: Reading request line");
  1111                     t2.join();
  1141             String requestLine = readLine(ccis);
  1112                 }
  1142             System.out.println("Tunnel: Request line: " + requestLine);
  1113             } catch (Throwable ex) {
  1143             if (requestLine.startsWith("CONNECT ")) {
  1114                 try {
  1144                 // We should probably check that the next word following
  1115                     ss.close();
  1145                 // CONNECT is the host:port of our HTTPS serverImpl.
  1116                 } catch (IOException ex1) {
  1146                 // Some improvement for a followup!
  1117                     ex.addSuppressed(ex1);
  1147 
  1118                 }
  1148                 // Read all headers until we find the empty line that
  1119                 ex.printStackTrace(System.err);
  1149                 // signals the end of all headers.
  1120             }
  1150                 while(!requestLine.equals("")) {
  1121         }
  1151                     System.out.println("Tunnel: Reading header: "
  1122 
  1152                             + (requestLine = readLine(ccis)));
       
  1153                 }
       
  1154 
       
  1155                 targetConnection = new Socket(
       
  1156                         serverImpl.getAddress().getAddress(),
       
  1157                         serverImpl.getAddress().getPort());
       
  1158 
       
  1159                 // Then send the 200 OK response to the client
       
  1160                 System.out.println("Tunnel: Sending "
       
  1161                         + "HTTP/1.1 200 OK\r\n\r\n");
       
  1162                 pw.print("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
       
  1163                 pw.flush();
       
  1164             } else {
       
  1165                 // This should not happen. If it does then consider it a
       
  1166                 // client error and throw an IOException
       
  1167                 System.out.println("Tunnel: Throwing an IOException due to unexpected" +
       
  1168                         " request line: " + requestLine);
       
  1169                 throw new IOException("Client request error - Unexpected request line");
       
  1170             }
       
  1171 
       
  1172             // Pipe the input stream of the client connection to the
       
  1173             // output stream of the target connection and conversely.
       
  1174             // Now the client and target will just talk to each other.
       
  1175             System.out.println("Tunnel: Starting tunnel pipes");
       
  1176             Thread t1 = pipe(ccis, targetConnection.getOutputStream(), '+');
       
  1177             Thread t2 = pipe(targetConnection.getInputStream(), ccos, '-');
       
  1178             t1.start();
       
  1179             t2.start();
       
  1180             // wait for the request to complete
       
  1181             t1.join();
       
  1182             t2.join();
       
  1183         }
  1123     }
  1184     }
  1124 }
  1185 }