View Javadoc

1   /*
2    * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/oac.hc3x/trunk/src/java/org/apache/commons/httpclient/ConnectMethod.java $
3    * $Revision: 1425331 $
4    * $Date: 2012-12-22 19:29:41 +0100 (Sat, 22 Dec 2012) $
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 Gl???ck
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: 1425331 $ $Date: 2012-12-22 19:29:41 +0100 (Sat, 22 Dec 2012) $
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       */
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       */
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       */
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       */
98      public String getName() {
99          return NAME;
100     }
101     
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 
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      */
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      */
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      */
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      */
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      */
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 }