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
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$ $Date$
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
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 }