1 /* 2 * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/ConnectMethod.java,v 1.29 2004/06/24 21:39:52 mbecke Exp $ 3 * $Revision: 483949 $ 4 * $Date: 2006-12-08 12:34:50 +0100 (Fri, 08 Dec 2006) $ 5 * 6 * ==================================================================== 7 * 8 * Licensed to the Apache Software Foundation (ASF) under one or more 9 * contributor license agreements. See the NOTICE file distributed with 10 * this work for additional information regarding copyright ownership. 11 * The ASF licenses this file to You under the Apache License, Version 2.0 12 * (the "License"); you may not use this file except in compliance with 13 * the License. You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * ==================================================================== 23 * 24 * This software consists of voluntary contributions made by many 25 * individuals on behalf of the Apache Software Foundation. For more 26 * information on the Apache Software Foundation, please see 27 * <http://www.apache.org/>. 28 * 29 */ 30 31 package org.apache.commons.httpclient; 32 33 import java.io.IOException; 34 35 import org.apache.commons.logging.Log; 36 import org.apache.commons.logging.LogFactory; 37 38 /** 39 * Establishes a tunneled HTTP connection via the CONNECT method. 40 * 41 * @author Ortwin Glueck 42 * @author dIon Gillard 43 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> 44 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> 45 * @since 2.0 46 * @version $Revision: 483949 $ $Date: 2006-12-08 12:34:50 +0100 (Fri, 08 Dec 2006) $ 47 */ 48 public class ConnectMethod extends HttpMethodBase { 49 50 /** the name of this method */ 51 public static final String NAME = "CONNECT"; 52 53 private final HostConfiguration targethost; 54 55 /** 56 * @deprecated use #ConnectMethod(HttpHost); 57 * 58 * Create a connect method. 59 * 60 * @since 3.0 61 */ ConnectMethod()62 public ConnectMethod() { 63 super(); 64 this.targethost = null; 65 } 66 67 /** 68 * @deprecated the wrapped method is no longer used 69 * 70 * Create a connect method wrapping the existing method 71 * 72 * @param method the {@link HttpMethod method} to execute after connecting 73 * to the server 74 */ ConnectMethod(HttpMethod method)75 public ConnectMethod(HttpMethod method) { 76 super(); 77 this.targethost = null; 78 } 79 80 /** 81 * Create a connect method. 82 * 83 * @since 3.0 84 */ ConnectMethod(final HostConfiguration targethost)85 public ConnectMethod(final HostConfiguration targethost) { 86 super(); 87 if (targethost == null) { 88 throw new IllegalArgumentException("Target host may not be null"); 89 } 90 this.targethost = targethost; 91 } 92 93 /** 94 * Provide the {@link #NAME name} of this method. 95 * 96 * @return the String "CONNECT" 97 */ getName()98 public String getName() { 99 return NAME; 100 } 101 getPath()102 public String getPath() { 103 if (this.targethost != null) { 104 StringBuffer buffer = new StringBuffer(); 105 buffer.append(this.targethost.getHost()); 106 int port = this.targethost.getPort(); 107 if (port == -1) { 108 port = this.targethost.getProtocol().getDefaultPort(); 109 } 110 buffer.append(':'); 111 buffer.append(port); 112 return buffer.toString(); 113 } else { 114 return "/"; 115 } 116 } 117 getURI()118 public URI getURI() throws URIException { 119 String charset = getParams().getUriCharset(); 120 return new URI(getPath(), true, charset); 121 } 122 123 /** 124 * This method does nothing. <tt>CONNECT</tt> request is not supposed 125 * to contain <tt>Cookie</tt> request header. 126 * 127 * @param state current state of http requests 128 * @param conn the connection to use for I/O 129 * 130 * @throws IOException when errors occur reading or writing to/from the 131 * connection 132 * @throws HttpException when a recoverable error occurs 133 * 134 * @see HttpMethodBase#addCookieRequestHeader(HttpState, HttpConnection) 135 */ addCookieRequestHeader(HttpState state, HttpConnection conn)136 protected void addCookieRequestHeader(HttpState state, HttpConnection conn) 137 throws IOException, HttpException { 138 // Do nothing. Not applicable to CONNECT method 139 } 140 141 142 /** 143 * Populates the request headers map to with additional {@link Header 144 * headers} to be submitted to the given {@link HttpConnection}. 145 * 146 * <p> 147 * This implementation adds <tt>User-Agent</tt>, <tt>Host</tt>, 148 * and <tt>Proxy-Authorization</tt> headers, when appropriate. 149 * </p> 150 * 151 * @param state the client state 152 * @param conn the {@link HttpConnection} the headers will eventually be 153 * written to 154 * @throws IOException when an error occurs writing the request 155 * @throws HttpException when a HTTP protocol error occurs 156 * 157 * @see #writeRequestHeaders 158 */ addRequestHeaders(HttpState state, HttpConnection conn)159 protected void addRequestHeaders(HttpState state, HttpConnection conn) 160 throws IOException, HttpException { 161 LOG.trace("enter ConnectMethod.addRequestHeaders(HttpState, " 162 + "HttpConnection)"); 163 addUserAgentRequestHeader(state, conn); 164 addHostRequestHeader(state, conn); 165 addProxyConnectionHeader(state, conn); 166 } 167 168 /** 169 * Execute this method and create a tunneled HttpConnection. If the method 170 * is successful (i.e. the status is a 2xx) tunnelCreated() will be called 171 * on the connection. 172 * 173 * @param state the current http state 174 * @param conn the connection to write to 175 * @return the http status code from execution 176 * @throws HttpException when an error occurs writing the headers 177 * @throws IOException when an error occurs writing the headers 178 * 179 * @see HttpConnection#tunnelCreated() 180 */ execute(HttpState state, HttpConnection conn)181 public int execute(HttpState state, HttpConnection conn) 182 throws IOException, HttpException { 183 184 LOG.trace("enter ConnectMethod.execute(HttpState, HttpConnection)"); 185 int code = super.execute(state, conn); 186 if (LOG.isDebugEnabled()) { 187 LOG.debug("CONNECT status code " + code); 188 } 189 return code; 190 } 191 192 /** 193 * Special Connect request. 194 * 195 * @param state the current http state 196 * @param conn the connection to write to 197 * @throws IOException when an error occurs writing the request 198 * @throws HttpException when an error occurs writing the request 199 */ writeRequestLine(HttpState state, HttpConnection conn)200 protected void writeRequestLine(HttpState state, HttpConnection conn) 201 throws IOException, HttpException { 202 StringBuffer buffer = new StringBuffer(); 203 buffer.append(getName()); 204 buffer.append(' '); 205 if (this.targethost != null) { 206 buffer.append(getPath()); 207 } else { 208 int port = conn.getPort(); 209 if (port == -1) { 210 port = conn.getProtocol().getDefaultPort(); 211 } 212 buffer.append(conn.getHost()); 213 buffer.append(':'); 214 buffer.append(port); 215 } 216 buffer.append(" "); 217 buffer.append(getEffectiveVersion()); 218 String line = buffer.toString(); 219 conn.printLine(line, getParams().getHttpElementCharset()); 220 if (Wire.HEADER_WIRE.enabled()) { 221 Wire.HEADER_WIRE.output(line); 222 } 223 } 224 225 /** 226 * Returns <code>true</code> if the status code is anything other than 227 * SC_OK, <code>false</code> otherwise. 228 * 229 * @see HttpMethodBase#shouldCloseConnection(HttpConnection) 230 * @see HttpStatus#SC_OK 231 * 232 * @return <code>true</code> if the connection should be closed 233 */ shouldCloseConnection(HttpConnection conn)234 protected boolean shouldCloseConnection(HttpConnection conn) { 235 if (getStatusCode() == HttpStatus.SC_OK) { 236 Header connectionHeader = null; 237 if (!conn.isTransparent()) { 238 connectionHeader = getResponseHeader("proxy-connection"); 239 } 240 if (connectionHeader == null) { 241 connectionHeader = getResponseHeader("connection"); 242 } 243 if (connectionHeader != null) { 244 if (connectionHeader.getValue().equalsIgnoreCase("close")) { 245 if (LOG.isWarnEnabled()) { 246 LOG.warn("Invalid header encountered '" + connectionHeader.toExternalForm() 247 + "' in response " + getStatusLine().toString()); 248 } 249 } 250 } 251 return false; 252 } else { 253 return super.shouldCloseConnection(conn); 254 } 255 } 256 257 /** Log object for this class. */ 258 private static final Log LOG = LogFactory.getLog(ConnectMethod.class); 259 260 } 261