001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027 028package org.apache.http.impl.conn; 029 030import java.net.InetSocketAddress; 031import java.net.Proxy; 032import java.net.ProxySelector; 033import java.net.URI; 034import java.net.URISyntaxException; 035import java.util.List; 036 037import org.apache.http.HttpException; 038import org.apache.http.HttpHost; 039import org.apache.http.HttpRequest; 040import org.apache.http.annotation.Contract; 041import org.apache.http.annotation.ThreadingBehavior; 042import org.apache.http.conn.SchemePortResolver; 043import org.apache.http.protocol.HttpContext; 044 045/** 046 * {@link org.apache.http.conn.routing.HttpRoutePlanner} implementation 047 * based on {@link ProxySelector}. By default, this class will pick up 048 * the proxy settings of the JVM, either from system properties 049 * or from the browser running the application. 050 * 051 * @since 4.3 052 */ 053@Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL) 054public class SystemDefaultRoutePlanner extends DefaultRoutePlanner { 055 056 private final ProxySelector proxySelector; 057 058 /** 059 * @param proxySelector the proxy selector, or {@code null} for the system default 060 */ 061 public SystemDefaultRoutePlanner( 062 final SchemePortResolver schemePortResolver, 063 final ProxySelector proxySelector) { 064 super(schemePortResolver); 065 this.proxySelector = proxySelector; 066 } 067 068 /** 069 * @param proxySelector the proxy selector, or {@code null} for the system default 070 */ 071 public SystemDefaultRoutePlanner(final ProxySelector proxySelector) { 072 this(null, proxySelector); 073 } 074 075 @Override 076 protected HttpHost determineProxy( 077 final HttpHost target, 078 final HttpRequest request, 079 final HttpContext context) throws HttpException { 080 final URI targetURI; 081 try { 082 targetURI = new URI(target.toURI()); 083 } catch (final URISyntaxException ex) { 084 throw new HttpException("Cannot convert host to URI: " + target, ex); 085 } 086 ProxySelector proxySelectorInstance = this.proxySelector; 087 if (proxySelectorInstance == null) { 088 proxySelectorInstance = ProxySelector.getDefault(); 089 } 090 if (proxySelectorInstance == null) { 091 //The proxy selector can be "unset", so we must be able to deal with a null selector 092 return null; 093 } 094 final List<Proxy> proxies = proxySelectorInstance.select(targetURI); 095 final Proxy p = chooseProxy(proxies); 096 HttpHost result = null; 097 if (p.type() == Proxy.Type.HTTP) { 098 // convert the socket address to an HttpHost 099 if (!(p.address() instanceof InetSocketAddress)) { 100 throw new HttpException("Unable to handle non-Inet proxy address: " + p.address()); 101 } 102 final InetSocketAddress isa = (InetSocketAddress) p.address(); 103 // assume default scheme (http) 104 result = new HttpHost(getHost(isa), isa.getPort()); 105 } 106 107 return result; 108 } 109 110 private String getHost(final InetSocketAddress isa) { 111 112 //@@@ Will this work with literal IPv6 addresses, or do we 113 //@@@ need to wrap these in [] for the string representation? 114 //@@@ Having it in this method at least allows for easy workarounds. 115 return isa.isUnresolved() ? 116 isa.getHostName() : isa.getAddress().getHostAddress(); 117 118 } 119 120 private Proxy chooseProxy(final List<Proxy> proxies) { 121 Proxy result = null; 122 // check the list for one we can use 123 for (int i=0; (result == null) && (i < proxies.size()); i++) { 124 final Proxy p = proxies.get(i); 125 switch (p.type()) { 126 127 case DIRECT: 128 case HTTP: 129 result = p; 130 break; 131 132 case SOCKS: 133 // SOCKS hosts are not handled on the route level. 134 // The socket may make use of the SOCKS host though. 135 break; 136 } 137 } 138 if (result == null) { 139 //@@@ log as warning or info that only a socks proxy is available? 140 // result can only be null if all proxies are socks proxies 141 // socks proxies are not handled on the route planning level 142 result = Proxy.NO_PROXY; 143 } 144 return result; 145 } 146 147}