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