2
* $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ConnectMethod.java,v 1.18.2.3 2004/06/25 03:27:40 mbecke Exp $
3
* $Revision: 1.18.2.3 $
4
* $Date: 2004/06/25 03:27:40 $
6
* ====================================================================
8
* Copyright 1999-2004 The Apache Software Foundation
10
* Licensed under the Apache License, Version 2.0 (the "License");
11
* you may not use this file except in compliance with the License.
12
* You may obtain a copy of the License at
14
* http://www.apache.org/licenses/LICENSE-2.0
16
* Unless required by applicable law or agreed to in writing, software
17
* distributed under the License is distributed on an "AS IS" BASIS,
18
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
* See the License for the specific language governing permissions and
20
* limitations under the License.
21
* ====================================================================
23
* This software consists of voluntary contributions made by many
24
* individuals on behalf of the Apache Software Foundation. For more
25
* information on the Apache Software Foundation, please see
26
* <http://www.apache.org/>.
28
* [Additional notices, if required by prior licensing conditions]
32
package org.apache.commons.httpclient;
34
import java.io.IOException;
36
import org.apache.commons.logging.Log;
37
import org.apache.commons.logging.LogFactory;
40
* <p>Wraps another method to tunnel through a proxy.</p>
42
* @author Ortwin Glļæ½ck
43
* @author dIon Gillard
44
* @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
45
* @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
47
* @version $Revision: 1.18.2.3 $ $Date: 2004/06/25 03:27:40 $
49
public class ConnectMethod extends HttpMethodBase {
50
/** the name of this method */
51
public static final String NAME = "CONNECT";
54
* Create a connect method wrapping the existing method
56
* @param method the {@link HttpMethod method} to execute after connecting
59
public ConnectMethod(HttpMethod method) {
60
LOG.trace("enter ConnectMethod(HttpMethod)");
65
* Provide the {@link #NAME name} of this method.
67
* @return the String "CONNECT"
69
public String getName() {
75
* This method does nothing. <tt>CONNECT</tt> request is not supposed
76
* to contain <tt>Authorization</tt> request header.
78
* @param state current state of http requests
79
* @param conn the connection to use for I/O
81
* @throws IOException when errors occur reading or writing to/from the
83
* @throws HttpException when a recoverable error occurs
85
* @see HttpMethodBase#addAuthorizationRequestHeader(HttpState, HttpConnection)
87
protected void addAuthorizationRequestHeader(HttpState state, HttpConnection conn)
88
throws IOException, HttpException {
89
// Do nothing. Not applicable to CONNECT method
93
* This method does nothing. <tt>CONNECT</tt> request is not supposed
94
* to contain <tt>Content-Length</tt> request header.
96
* @param state current state of http requests
97
* @param conn the connection to use for I/O
99
* @throws IOException when errors occur reading or writing to/from the
101
* @throws HttpException when a recoverable error occurs
103
* @see HttpMethodBase#addContentLengthRequestHeader(HttpState, HttpConnection)
105
protected void addContentLengthRequestHeader(HttpState state, HttpConnection conn)
106
throws IOException, HttpException {
107
// Do nothing. Not applicable to CONNECT method
111
* This method does nothing. <tt>CONNECT</tt> request is not supposed
112
* to contain <tt>Cookie</tt> request header.
114
* @param state current state of http requests
115
* @param conn the connection to use for I/O
117
* @throws IOException when errors occur reading or writing to/from the
119
* @throws HttpException when a recoverable error occurs
121
* @see HttpMethodBase#addCookieRequestHeader(HttpState, HttpConnection)
123
protected void addCookieRequestHeader(HttpState state, HttpConnection conn)
124
throws IOException, HttpException {
125
// Do nothing. Not applicable to CONNECT method
130
* Populates the request headers map to with additional {@link Header
131
* headers} to be submitted to the given {@link HttpConnection}.
134
* This implementation adds <tt>User-Agent</tt>, <tt>Host</tt>,
135
* and <tt>Proxy-Authorization</tt> headers, when appropriate.
138
* @param state the client state
139
* @param conn the {@link HttpConnection} the headers will eventually be
141
* @throws IOException when an error occurs writing the request
142
* @throws HttpException when a HTTP protocol error occurs
144
* @see #writeRequestHeaders
146
protected void addRequestHeaders(HttpState state, HttpConnection conn)
147
throws IOException, HttpException {
148
LOG.trace("enter ConnectMethod.addRequestHeaders(HttpState, "
149
+ "HttpConnection)");
150
addUserAgentRequestHeader(state, conn);
151
addHostRequestHeader(state, conn);
152
addProxyAuthorizationRequestHeader(state, conn);
153
addProxyConnectionHeader(state, conn);
157
* Execute this method by tunnelling and then executing the wrapped method.
159
* @param state the current http state
160
* @param conn the connection to write to
161
* @return the http status code from execution
162
* @throws HttpException when an error occurs writing the headers
163
* @throws IOException when an error occurs writing the headers
165
public int execute(HttpState state, HttpConnection conn)
166
throws IOException, HttpException {
168
LOG.trace("enter ConnectMethod.execute(HttpState, HttpConnection)");
169
int code = super.execute(state, conn);
170
LOG.debug("CONNECT status code " + code);
171
if ((code >= 200) && (code < 300)) {
172
conn.tunnelCreated();
173
code = method.execute(state, conn);
175
// What is to follow is an ugly hack.
176
// I REALLY hate having to resort to such
177
// an appalling trick
178
// TODO: Connect method must be redesigned.
179
// The only feasible solution is to split monolithic
180
// HttpMethod into HttpRequest/HttpResponse pair.
181
// That would allow to execute CONNECT method
182
// behind the scene and return CONNECT HttpResponse
183
// object in response to the original request that
184
// contains the correct status line, headers &
187
LOG.debug("CONNECT failed, fake the response for the original method");
188
if (method instanceof HttpMethodBase) {
189
// Pass the status, headers and response stream to the wrapped
191
// To ensure that the connection is not released more than once
192
// this method is still responsible for releasing the connection.
193
// This will happen when the response body is consumed, or when
194
// the wrapped method closes the response connection in
195
// releaseConnection().
196
((HttpMethodBase) method).fakeResponse(
198
getResponseHeaderGroup(),
209
* Special Connect request.
211
* @param state the current http state
212
* @param conn the connection to write to
213
* @throws IOException when an error occurs writing the request
214
* @throws HttpException when an error occurs writing the request
216
protected void writeRequestLine(HttpState state, HttpConnection conn)
217
throws IOException, HttpException {
218
int port = conn.getPort();
220
port = conn.getProtocol().getDefaultPort();
222
StringBuffer buffer = new StringBuffer();
223
buffer.append(getName());
225
buffer.append(conn.getHost());
230
buffer.append(" HTTP/1.1");
231
String line = buffer.toString();
232
conn.printLine(line);
233
if (Wire.HEADER_WIRE.enabled()) {
234
Wire.HEADER_WIRE.output(line);
239
* Returns <code>true</code> if the status code is anything other than
240
* SC_OK, <code>false</code> otherwise.
242
* @param conn the connection to test
244
* @return <code>true</code> if the connection should be closed
246
* @see HttpMethodBase#shouldCloseConnection(HttpConnection)
247
* @see HttpStatus#SC_OK
249
protected boolean shouldCloseConnection(HttpConnection conn) {
250
if (getStatusCode() == HttpStatus.SC_OK) {
251
Header connectionHeader = null;
252
if (!conn.isTransparent()) {
253
connectionHeader = getResponseHeader("proxy-connection");
255
if (connectionHeader == null) {
256
connectionHeader = getResponseHeader("connection");
258
if (connectionHeader != null) {
259
if (connectionHeader.getValue().equalsIgnoreCase("close")) {
260
if (LOG.isWarnEnabled()) {
261
LOG.warn("Invalid header encountered '" + connectionHeader.toExternalForm()
262
+ "' in response " + getStatusLine().toString());
268
return super.shouldCloseConnection(conn);
272
/** Log object for this class. */
273
private static final Log LOG = LogFactory.getLog(ConnectMethod.class);
275
/** The wrapped method */
276
private HttpMethod method;