@@ -980,6 +980,8 @@ static class HttpsProxyTunnel extends HTTPTestServer
980
980
implements Runnable {
981
981
982
982
final ServerSocket ss ;
983
+ private volatile boolean stop ;
984
+
983
985
public HttpsProxyTunnel (HttpServer server , HTTPTestServer target ,
984
986
HttpHandler delegate )
985
987
throws IOException {
@@ -998,9 +1000,10 @@ final void start() throws IOException {
998
1000
999
1001
@ Override
1000
1002
public void stop () {
1001
- super .stop ();
1002
- try {
1003
- ss .close ();
1003
+ try (var toClose = ss ) {
1004
+ stop = true ;
1005
+ System .out .println ("Server " + ss + " stop requested" );
1006
+ super .stop ();
1004
1007
} catch (IOException ex ) {
1005
1008
if (DEBUG ) ex .printStackTrace (System .out );
1006
1009
}
@@ -1050,6 +1053,9 @@ String readLine(InputStream r) throws IOException {
1050
1053
if (c == '\n' ) break ;
1051
1054
b .appendCodePoint (c );
1052
1055
}
1056
+ if (b .length () == 0 ) {
1057
+ return "" ;
1058
+ }
1053
1059
if (b .codePointAt (b .length () -1 ) == '\r' ) {
1054
1060
b .delete (b .length () -1 , b .length ());
1055
1061
}
@@ -1059,80 +1065,121 @@ String readLine(InputStream r) throws IOException {
1059
1065
@ Override
1060
1066
public void run () {
1061
1067
Socket clientConnection = null ;
1062
- try {
1063
- while (true ) {
1064
- System .out .println ("Tunnel: Waiting for client at: " + ss );
1065
- Socket previous = clientConnection ;
1068
+ while (!stop ) {
1069
+ System .out .println ("Tunnel: Waiting for client at: " + ss );
1070
+ final Socket previous = clientConnection ;
1071
+ try {
1072
+ clientConnection = ss .accept ();
1073
+ } catch (IOException io ) {
1066
1074
try {
1067
- clientConnection = ss .accept ();
1068
- } catch (IOException io ) {
1069
- if (DEBUG ) io .printStackTrace (System .out );
1070
- break ;
1071
- } finally {
1072
- // close the previous connection
1073
- if (previous != null ) previous .close ();
1075
+ ss .close ();
1076
+ } catch (IOException ex ) {
1077
+ if (DEBUG ) {
1078
+ ex .printStackTrace (System .out );
1079
+ }
1074
1080
}
1075
- System .out .println ("Tunnel: Client accepted" );
1076
- Socket targetConnection = null ;
1077
- InputStream ccis = clientConnection .getInputStream ();
1078
- OutputStream ccos = clientConnection .getOutputStream ();
1079
- Writer w = new OutputStreamWriter (
1080
- clientConnection .getOutputStream (), "UTF-8" );
1081
- PrintWriter pw = new PrintWriter (w );
1082
- System .out .println ("Tunnel: Reading request line" );
1083
- String requestLine = readLine (ccis );
1084
- System .out .println ("Tunnel: Request line: " + requestLine );
1085
- if (requestLine .startsWith ("CONNECT " )) {
1086
- // We should probably check that the next word following
1087
- // CONNECT is the host:port of our HTTPS serverImpl.
1088
- // Some improvement for a followup!
1089
-
1090
- // Read all headers until we find the empty line that
1091
- // signals the end of all headers.
1092
- while (!requestLine .equals ("" )) {
1093
- System .out .println ("Tunnel: Reading header: "
1094
- + (requestLine = readLine (ccis )));
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
+ }
1095
1099
}
1096
-
1097
- targetConnection = new Socket (
1098
- serverImpl .getAddress ().getAddress (),
1099
- serverImpl .getAddress ().getPort ());
1100
-
1101
- // Then send the 200 OK response to the client
1102
- System .out .println ("Tunnel: Sending "
1103
- + "HTTP/1.1 200 OK\r \n \r \n " );
1104
- pw .print ("HTTP/1.1 200 OK\r \n Content-Length: 0\r \n \r \n " );
1105
- pw .flush ();
1106
- } else {
1107
- // This should not happen. If it does let our serverImpl
1108
- // deal with it.
1109
- throw new IOException ("Tunnel: Unexpected status line: "
1110
- + requestLine );
1111
1100
}
1112
-
1113
- // Pipe the input stream of the client connection to the
1114
- // output stream of the target connection and conversely.
1115
- // Now the client and target will just talk to each other.
1116
- System .out .println ("Tunnel: Starting tunnel pipes" );
1117
- Thread t1 = pipe (ccis , targetConnection .getOutputStream (), '+' );
1118
- Thread t2 = pipe (targetConnection .getInputStream (), ccos , '-' );
1119
- t1 .start ();
1120
- t2 .start ();
1121
-
1122
- // We have only 1 client... wait until it has finished before
1123
- // accepting a new connection request.
1124
- t1 .join ();
1125
- t2 .join ();
1126
1101
}
1127
- } catch ( Throwable ex ) {
1102
+ System . out . println ( "Tunnel: Client accepted" );
1128
1103
try {
1129
- ss .close ();
1130
- } catch (IOException ex1 ) {
1131
- ex .addSuppressed (ex1 );
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 ();
1112
+ } catch (IOException io ) {
1113
+ // ignore
1114
+ if (DEBUG ) {
1115
+ System .out .println ("Ignoring exception that happened during client" +
1116
+ " connection close:" );
1117
+ io .printStackTrace (System .out );
1118
+ }
1119
+ } finally {
1120
+ clientConnection = null ;
1121
+ }
1122
+ } catch (Throwable t ) {
1123
+ // don't close the client connection for non-IOExceptions, instead
1124
+ // just log it and move on to accept next connection
1125
+ if (!stop ) {
1126
+ t .printStackTrace ();
1127
+ }
1132
1128
}
1133
- ex .printStackTrace (System .err );
1134
1129
}
1135
1130
}
1136
1131
1132
+ private void processRequestAndWaitToComplete (final Socket clientConnection )
1133
+ throws IOException , InterruptedException {
1134
+ final Socket targetConnection ;
1135
+ InputStream ccis = clientConnection .getInputStream ();
1136
+ OutputStream ccos = clientConnection .getOutputStream ();
1137
+ Writer w = new OutputStreamWriter (
1138
+ clientConnection .getOutputStream (), "UTF-8" );
1139
+ PrintWriter pw = new PrintWriter (w );
1140
+ System .out .println ("Tunnel: Reading request line" );
1141
+ String requestLine = readLine (ccis );
1142
+ System .out .println ("Tunnel: Request line: " + requestLine );
1143
+ if (requestLine .startsWith ("CONNECT " )) {
1144
+ // We should probably check that the next word following
1145
+ // CONNECT is the host:port of our HTTPS serverImpl.
1146
+ // Some improvement for a followup!
1147
+
1148
+ // Read all headers until we find the empty line that
1149
+ // signals the end of all headers.
1150
+ while (!requestLine .equals ("" )) {
1151
+ System .out .println ("Tunnel: Reading header: "
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 \n Content-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
+ }
1137
1184
}
1138
1185
}
0 commit comments