~ubuntu-branches/ubuntu/lucid/commons-httpclient/lucid

« back to all changes in this revision

Viewing changes to src/java/org/apache/commons/httpclient/ConnectMethod.java

  • Committer: Bazaar Package Importer
  • Author(s): Barry Hawkins
  • Date: 2005-11-25 13:12:23 UTC
  • Revision ID: james.westby@ubuntu.com-20051125131223-2g7eyo21pqgrohpo
Tags: upstream-2.0.2
ImportĀ upstreamĀ versionĀ 2.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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 $
 
5
 *
 
6
 * ====================================================================
 
7
 *
 
8
 *  Copyright 1999-2004 The Apache Software Foundation
 
9
 *
 
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
 
13
 *
 
14
 *      http://www.apache.org/licenses/LICENSE-2.0
 
15
 *
 
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
 * ====================================================================
 
22
 *
 
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/>.
 
27
 *
 
28
 * [Additional notices, if required by prior licensing conditions]
 
29
 *
 
30
 */
 
31
 
 
32
package org.apache.commons.httpclient;
 
33
 
 
34
import java.io.IOException;
 
35
 
 
36
import org.apache.commons.logging.Log;
 
37
import org.apache.commons.logging.LogFactory;
 
38
 
 
39
/**
 
40
 * <p>Wraps another method to tunnel through a proxy.</p>
 
41
 *
 
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>
 
46
 * @since 2.0
 
47
 * @version $Revision: 1.18.2.3 $ $Date: 2004/06/25 03:27:40 $
 
48
 */
 
49
public class ConnectMethod extends HttpMethodBase {
 
50
    /** the name of this method */
 
51
    public static final String NAME = "CONNECT";
 
52
 
 
53
    /**
 
54
     * Create a connect method wrapping the existing method
 
55
     *
 
56
     * @param method the {@link HttpMethod method} to execute after connecting
 
57
     *      to the server
 
58
     */
 
59
    public ConnectMethod(HttpMethod method) {
 
60
        LOG.trace("enter ConnectMethod(HttpMethod)");
 
61
        this.method = method;
 
62
    }
 
63
 
 
64
    /**
 
65
     * Provide the {@link #NAME name} of this method.
 
66
     *
 
67
     * @return the String "CONNECT"
 
68
     */
 
69
    public String getName() {
 
70
        return NAME;
 
71
    }
 
72
 
 
73
 
 
74
    /**
 
75
     * This method does nothing. <tt>CONNECT</tt> request is not supposed 
 
76
     * to contain <tt>Authorization</tt> request header.
 
77
     *
 
78
     * @param state current state of http requests
 
79
     * @param conn the connection to use for I/O
 
80
     *
 
81
     * @throws IOException when errors occur reading or writing to/from the
 
82
     *         connection
 
83
     * @throws HttpException when a recoverable error occurs
 
84
     *  
 
85
     * @see HttpMethodBase#addAuthorizationRequestHeader(HttpState, HttpConnection)
 
86
     */
 
87
    protected void addAuthorizationRequestHeader(HttpState state, HttpConnection conn)
 
88
        throws IOException, HttpException {
 
89
        // Do nothing. Not applicable to CONNECT method
 
90
    }
 
91
 
 
92
    /**
 
93
     * This method does nothing. <tt>CONNECT</tt> request is not supposed 
 
94
     * to contain <tt>Content-Length</tt> request header.
 
95
     *
 
96
     * @param state current state of http requests
 
97
     * @param conn the connection to use for I/O
 
98
     *
 
99
     * @throws IOException when errors occur reading or writing to/from the
 
100
     *         connection
 
101
     * @throws HttpException when a recoverable error occurs
 
102
     *  
 
103
     * @see HttpMethodBase#addContentLengthRequestHeader(HttpState, HttpConnection)
 
104
     */
 
105
    protected void addContentLengthRequestHeader(HttpState state, HttpConnection conn)
 
106
        throws IOException, HttpException {
 
107
        // Do nothing. Not applicable to CONNECT method
 
108
    }
 
109
 
 
110
    /**
 
111
     * This method does nothing. <tt>CONNECT</tt> request is not supposed 
 
112
     * to contain <tt>Cookie</tt> request header.
 
113
     *
 
114
     * @param state current state of http requests
 
115
     * @param conn the connection to use for I/O
 
116
     *
 
117
     * @throws IOException when errors occur reading or writing to/from the
 
118
     *         connection
 
119
     * @throws HttpException when a recoverable error occurs
 
120
     *  
 
121
     * @see HttpMethodBase#addCookieRequestHeader(HttpState, HttpConnection)
 
122
     */
 
123
    protected void addCookieRequestHeader(HttpState state, HttpConnection conn)
 
124
        throws IOException, HttpException {
 
125
        // Do nothing. Not applicable to CONNECT method
 
126
    }
 
127
 
 
128
 
 
129
    /**
 
130
     * Populates the request headers map to with additional {@link Header
 
131
     * headers} to be submitted to the given {@link HttpConnection}.
 
132
     *
 
133
     * <p>
 
134
     * This implementation adds <tt>User-Agent</tt>, <tt>Host</tt>,
 
135
     * and <tt>Proxy-Authorization</tt> headers, when appropriate.
 
136
     * </p>
 
137
     *
 
138
     * @param state the client state
 
139
     * @param conn the {@link HttpConnection} the headers will eventually be
 
140
     *        written to
 
141
     * @throws IOException when an error occurs writing the request
 
142
     * @throws HttpException when a HTTP protocol error occurs
 
143
     *
 
144
     * @see #writeRequestHeaders
 
145
     */
 
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);
 
154
    }
 
155
 
 
156
    /**
 
157
     * Execute this method by tunnelling and then executing the wrapped method.
 
158
     *
 
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
 
164
     */
 
165
    public int execute(HttpState state, HttpConnection conn) 
 
166
    throws IOException, HttpException {
 
167
 
 
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);
 
174
        } else {
 
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 & 
 
185
            // response body.
 
186
            
 
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
 
190
                // method.
 
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(
 
197
                    getStatusLine(), 
 
198
                    getResponseHeaderGroup(),
 
199
                    getResponseStream()
 
200
                );
 
201
            } else {
 
202
                releaseConnection();
 
203
            }
 
204
        }
 
205
        return code;
 
206
    }
 
207
 
 
208
    /**
 
209
     * Special Connect request.
 
210
     *
 
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
 
215
     */
 
216
    protected void writeRequestLine(HttpState state, HttpConnection conn)
 
217
    throws IOException, HttpException {
 
218
        int port = conn.getPort();
 
219
        if (port == -1) {
 
220
            port = conn.getProtocol().getDefaultPort();  
 
221
        }
 
222
        StringBuffer buffer = new StringBuffer();
 
223
        buffer.append(getName()); 
 
224
        buffer.append(' '); 
 
225
        buffer.append(conn.getHost()); 
 
226
        if (port > -1) {
 
227
            buffer.append(':'); 
 
228
            buffer.append(port); 
 
229
        }
 
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);
 
235
        }
 
236
    }
 
237
 
 
238
    /**
 
239
     * Returns <code>true</code> if the status code is anything other than
 
240
     * SC_OK, <code>false</code> otherwise.
 
241
     * 
 
242
     * @param conn the connection to test
 
243
     * 
 
244
     * @return <code>true</code> if the connection should be closed
 
245
     * 
 
246
     * @see HttpMethodBase#shouldCloseConnection(HttpConnection)
 
247
     * @see HttpStatus#SC_OK
 
248
     */
 
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");
 
254
            }
 
255
            if (connectionHeader == null) {
 
256
                connectionHeader = getResponseHeader("connection");
 
257
            }
 
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());
 
263
                    }
 
264
                }
 
265
            }
 
266
            return false;
 
267
        } else {
 
268
            return super.shouldCloseConnection(conn);
 
269
        }
 
270
    }
 
271
    
 
272
    /** Log object for this class. */
 
273
    private static final Log LOG = LogFactory.getLog(ConnectMethod.class);
 
274
 
 
275
    /** The wrapped method */
 
276
    private HttpMethod method;
 
277
 
 
278
}