1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17package org.apache.harmony.luni.internal.net.www.protocol.https; 18 19import java.io.IOException; 20import java.io.InputStream; 21import java.io.OutputStream; 22import java.net.ProtocolException; 23import java.net.Proxy; 24import java.net.URL; 25import java.security.Permission; 26import java.security.Principal; 27import java.security.cert.Certificate; 28import java.util.List; 29import java.util.Map; 30 31import javax.net.ssl.HttpsURLConnection; 32import javax.net.ssl.SSLPeerUnverifiedException; 33import javax.net.ssl.SSLSocket; 34 35import org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl; 36import org.apache.harmony.luni.internal.nls.Messages; 37 38/** 39 * HttpsURLConnection implementation. 40 */ 41public class HttpsURLConnectionImpl extends HttpsURLConnection { 42 43 // Https engine to be wrapped 44 private final HttpsEngine httpsEngine; 45 46 // SSLSocket to be used for connection 47 private SSLSocket sslSocket; 48 49 protected HttpsURLConnectionImpl(URL url, int port) { 50 super(url); 51 httpsEngine = new HttpsEngine(url, port); 52 } 53 54 protected HttpsURLConnectionImpl(URL url, int port, Proxy proxy) { 55 super(url); 56 httpsEngine = new HttpsEngine(url, port, proxy); 57 } 58 59 @Override 60 public String getCipherSuite() { 61 if (sslSocket == null) { 62 throw new IllegalStateException(Messages.getString("luni.00")); //$NON-NLS-1$ 63 } 64 return sslSocket.getSession().getCipherSuite(); 65 } 66 67 @Override 68 public Certificate[] getLocalCertificates() { 69 if (sslSocket == null) { 70 throw new IllegalStateException(Messages.getString("luni.00")); //$NON-NLS-1$ 71 } 72 return sslSocket.getSession().getLocalCertificates(); 73 } 74 75 @Override 76 public Certificate[] getServerCertificates() 77 throws SSLPeerUnverifiedException { 78 if (sslSocket == null) { 79 throw new IllegalStateException(Messages.getString("luni.00")); //$NON-NLS-1$ 80 } 81 return sslSocket.getSession().getPeerCertificates(); 82 } 83 84 @Override 85 public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { 86 if (sslSocket == null) { 87 throw new IllegalStateException(Messages.getString("luni.00")); //$NON-NLS-1$ 88 } 89 return sslSocket.getSession().getPeerPrincipal(); 90 } 91 92 @Override 93 public Principal getLocalPrincipal() { 94 if (sslSocket == null) { 95 throw new IllegalStateException(Messages.getString("luni.00")); //$NON-NLS-1$ 96 } 97 return sslSocket.getSession().getLocalPrincipal(); 98 } 99 100 @Override 101 public void disconnect() { 102 httpsEngine.disconnect(); 103 } 104 105 @Override 106 public InputStream getErrorStream() { 107 return httpsEngine.getErrorStream(); 108 } 109 110 @Override 111 public String getRequestMethod() { 112 return httpsEngine.getRequestMethod(); 113 } 114 115 @Override 116 public int getResponseCode() throws IOException { 117 return httpsEngine.getResponseCode(); 118 } 119 120 @Override 121 public String getResponseMessage() throws IOException { 122 return httpsEngine.getResponseMessage(); 123 } 124 125 @Override 126 public void setRequestMethod(String method) throws ProtocolException { 127 httpsEngine.setRequestMethod(method); 128 } 129 130 @Override 131 public boolean usingProxy() { 132 return httpsEngine.usingProxy(); 133 } 134 135 @Override 136 public boolean getInstanceFollowRedirects() { 137 return httpsEngine.getInstanceFollowRedirects(); 138 } 139 140 @Override 141 public void setInstanceFollowRedirects(boolean followRedirects) { 142 httpsEngine.setInstanceFollowRedirects(followRedirects); 143 } 144 145 @Override 146 public void connect() throws IOException { 147 httpsEngine.connect(); 148 } 149 150 @Override 151 public boolean getAllowUserInteraction() { 152 return httpsEngine.getAllowUserInteraction(); 153 } 154 155 @Override 156 public Object getContent() throws IOException { 157 return httpsEngine.getContent(); 158 } 159 160 @SuppressWarnings("unchecked") // Spec does not generify 161 @Override 162 public Object getContent(Class[] types) throws IOException { 163 return httpsEngine.getContent(types); 164 } 165 166 @Override 167 public String getContentEncoding() { 168 return httpsEngine.getContentEncoding(); 169 } 170 171 @Override 172 public int getContentLength() { 173 return httpsEngine.getContentLength(); 174 } 175 176 @Override 177 public String getContentType() { 178 return httpsEngine.getContentType(); 179 } 180 181 @Override 182 public long getDate() { 183 return httpsEngine.getDate(); 184 } 185 186 @Override 187 public boolean getDefaultUseCaches() { 188 return httpsEngine.getDefaultUseCaches(); 189 } 190 191 @Override 192 public boolean getDoInput() { 193 return httpsEngine.getDoInput(); 194 } 195 196 @Override 197 public boolean getDoOutput() { 198 return httpsEngine.getDoOutput(); 199 } 200 201 @Override 202 public long getExpiration() { 203 return httpsEngine.getExpiration(); 204 } 205 206 @Override 207 public String getHeaderField(int pos) { 208 return httpsEngine.getHeaderField(pos); 209 } 210 211 @Override 212 public Map<String, List<String>> getHeaderFields() { 213 return httpsEngine.getHeaderFields(); 214 } 215 216 @Override 217 public Map<String, List<String>> getRequestProperties() { 218 return httpsEngine.getRequestProperties(); 219 } 220 221 @Override 222 public void addRequestProperty(String field, String newValue) { 223 httpsEngine.addRequestProperty(field, newValue); 224 } 225 226 @Override 227 public String getHeaderField(String key) { 228 return httpsEngine.getHeaderField(key); 229 } 230 231 @Override 232 public long getHeaderFieldDate(String field, long defaultValue) { 233 return httpsEngine.getHeaderFieldDate(field, defaultValue); 234 } 235 236 @Override 237 public int getHeaderFieldInt(String field, int defaultValue) { 238 return httpsEngine.getHeaderFieldInt(field, defaultValue); 239 } 240 241 @Override 242 public String getHeaderFieldKey(int posn) { 243 return httpsEngine.getHeaderFieldKey(posn); 244 } 245 246 @Override 247 public long getIfModifiedSince() { 248 return httpsEngine.getIfModifiedSince(); 249 } 250 251 @Override 252 public InputStream getInputStream() throws IOException { 253 return httpsEngine.getInputStream(); 254 } 255 256 @Override 257 public long getLastModified() { 258 return httpsEngine.getLastModified(); 259 } 260 261 @Override 262 public OutputStream getOutputStream() throws IOException { 263 return httpsEngine.getOutputStream(); 264 } 265 266 @Override 267 public Permission getPermission() throws IOException { 268 return httpsEngine.getPermission(); 269 } 270 271 @Override 272 public String getRequestProperty(String field) { 273 return httpsEngine.getRequestProperty(field); 274 } 275 276 @Override 277 public URL getURL() { 278 return httpsEngine.getURL(); 279 } 280 281 @Override 282 public boolean getUseCaches() { 283 return httpsEngine.getUseCaches(); 284 } 285 286 @Override 287 public void setAllowUserInteraction(boolean newValue) { 288 httpsEngine.setAllowUserInteraction(newValue); 289 } 290 291 @Override 292 public void setDefaultUseCaches(boolean newValue) { 293 httpsEngine.setDefaultUseCaches(newValue); 294 } 295 296 @Override 297 public void setDoInput(boolean newValue) { 298 httpsEngine.setDoInput(newValue); 299 } 300 301 @Override 302 public void setDoOutput(boolean newValue) { 303 httpsEngine.setDoOutput(newValue); 304 } 305 306 @Override 307 public void setIfModifiedSince(long newValue) { 308 httpsEngine.setIfModifiedSince(newValue); 309 } 310 311 @Override 312 public void setRequestProperty(String field, String newValue) { 313 httpsEngine.setRequestProperty(field, newValue); 314 } 315 316 @Override 317 public void setUseCaches(boolean newValue) { 318 httpsEngine.setUseCaches(newValue); 319 } 320 321 @Override 322 public void setConnectTimeout(int timeout) { 323 httpsEngine.setConnectTimeout(timeout); 324 } 325 326 @Override 327 public int getConnectTimeout() { 328 return httpsEngine.getConnectTimeout(); 329 } 330 331 @Override 332 public void setReadTimeout(int timeout) { 333 httpsEngine.setReadTimeout(timeout); 334 } 335 336 @Override 337 public int getReadTimeout() { 338 return httpsEngine.getReadTimeout(); 339 } 340 341 @Override 342 public String toString() { 343 return httpsEngine.toString(); 344 } 345 346 /** 347 * HttpsEngine 348 */ 349 private class HttpsEngine extends HttpURLConnectionImpl { 350 351 // In case of using proxy this field indicates 352 // if it is a SSL Tunnel establishing stage 353 private boolean makingSSLTunnel; 354 355 protected HttpsEngine(URL url, int port) { 356 super(url, port); 357 } 358 359 protected HttpsEngine(URL url, int port, Proxy proxy) { 360 super(url, port, proxy); 361 } 362 363 @Override 364 public void connect() throws IOException { 365 if (connected) { 366 return; 367 } 368 if (super.usingProxy() && !makingSSLTunnel) { 369 // SSL Tunnel through the proxy was not established yet, do so 370 makingSSLTunnel = true; 371 // first - make the connection 372 super.connect(); 373 // keep request method 374 String save_meth = method; 375 // make SSL Tunnel 376 method = "CONNECT"; //$NON-NLS-1$ 377 try { 378 doRequest(); 379 endRequest(); 380 } finally { 381 // restore initial request method 382 method = save_meth; 383 } 384 if (!connected) { 385 throw new IOException(Messages.getString("luni.01", //$NON-NLS-1$ 386 responseMessage, responseCode)); 387 } 388 // if there are some remaining data in the stream - read it out 389 InputStream is = connection.getInputStream(); 390 while (is.available() != 0) { 391 is.read(); 392 } 393 makingSSLTunnel = false; 394 } else { 395 // no need in SSL tunnel 396 super.connect(); 397 } 398 if (!makingSSLTunnel) { 399 sslSocket = connection.getSecureSocket(getSSLSocketFactory(), getHostnameVerifier()); 400 setUpTransportIO(connection); 401 } 402 } 403 404 @Override 405 protected String requestString() { 406 if (super.usingProxy()) { 407 if (makingSSLTunnel) { 408 // we are making the SSL Tunneling, return remotehost:port 409 int port = url.getPort(); 410 return (port > 0) ? url.getHost() + ":" + port //$NON-NLS-1$ 411 : url.getHost(); 412 } 413 // we has made SSL Tunneling, return /requested.data 414 String file = url.getFile(); 415 if (file == null || file.length() == 0) { 416 file = "/"; //$NON-NLS-1$ 417 } 418 return file; 419 } 420 return super.requestString(); 421 } 422 423 } 424} 425