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