Source Code Cross Referenced for HttpMethodBase.java in  » Web-Crawler » heritrix » org » apache » commons » httpclient » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Crawler » heritrix » org.apache.commons.httpclient 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Header$
0003:         * $Revision: 4946 $
0004:         * $Date: 2007-02-28 23:35:32 +0000 (Wed, 28 Feb 2007) $
0005:         *
0006:         * ====================================================================
0007:         *
0008:         *  Copyright 1999-2004 The Apache Software Foundation
0009:         *
0010:         *  Licensed under the Apache License, Version 2.0 (the "License");
0011:         *  you may not use this file except in compliance with the License.
0012:         *  You may obtain a copy of the License at
0013:         *
0014:         *      http://www.apache.org/licenses/LICENSE-2.0
0015:         *
0016:         *  Unless required by applicable law or agreed to in writing, software
0017:         *  distributed under the License is distributed on an "AS IS" BASIS,
0018:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0019:         *  See the License for the specific language governing permissions and
0020:         *  limitations under the License.
0021:         * ====================================================================
0022:         *
0023:         * This software consists of voluntary contributions made by many
0024:         * individuals on behalf of the Apache Software Foundation.  For more
0025:         * information on the Apache Software Foundation, please see
0026:         * <http://www.apache.org/>.
0027:         *
0028:         */
0029:
0030:        package org.apache.commons.httpclient;
0031:
0032:        import java.io.ByteArrayInputStream;
0033:        import java.io.ByteArrayOutputStream;
0034:        import java.io.IOException;
0035:        import java.io.InputStream;
0036:        import java.io.InterruptedIOException;
0037:        import java.util.Collection;
0038:
0039:        import org.apache.commons.httpclient.auth.AuthState;
0040:        import org.apache.commons.httpclient.cookie.CookiePolicy;
0041:        import org.apache.commons.httpclient.cookie.CookieSpec;
0042:        import org.apache.commons.httpclient.cookie.MalformedCookieException;
0043:        import org.apache.commons.httpclient.params.HttpMethodParams;
0044:        import org.apache.commons.httpclient.protocol.Protocol;
0045:        import org.apache.commons.httpclient.util.EncodingUtil;
0046:        import org.apache.commons.httpclient.util.ExceptionUtil;
0047:        import org.apache.commons.logging.Log;
0048:        import org.apache.commons.logging.LogFactory;
0049:
0050:        /**
0051:         * An abstract base implementation of HttpMethod.
0052:         * <p>
0053:         * At minimum, subclasses will need to override:
0054:         * <ul>
0055:         *   <li>{@link #getName} to return the approriate name for this method
0056:         *   </li>
0057:         * </ul>
0058:         * </p>
0059:         *
0060:         * <p>
0061:         * When a method requires additional request headers, subclasses will typically
0062:         * want to override:
0063:         * <ul>
0064:         *   <li>{@link #addRequestHeaders addRequestHeaders(HttpState,HttpConnection)}
0065:         *      to write those headers
0066:         *   </li>
0067:         * </ul>
0068:         * </p>
0069:         *
0070:         * <p>
0071:         * When a method expects specific response headers, subclasses may want to
0072:         * override:
0073:         * <ul>
0074:         *   <li>{@link #processResponseHeaders processResponseHeaders(HttpState,HttpConnection)}
0075:         *     to handle those headers
0076:         *   </li>
0077:         * </ul>
0078:         * </p>
0079:         *
0080:         *
0081:         * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
0082:         * @author Rodney Waldhoff
0083:         * @author Sean C. Sullivan
0084:         * @author <a href="mailto:dion@apache.org">dIon Gillard</a>
0085:         * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
0086:         * @author <a href="mailto:dims@apache.org">Davanum Srinivas</a>
0087:         * @author Ortwin Glueck
0088:         * @author Eric Johnson
0089:         * @author Michael Becke
0090:         * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
0091:         * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
0092:         * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
0093:         * @author Christian Kohlschuetter
0094:         *
0095:         * @version $Revision: 4946 $ $Date: 2007-02-28 23:35:32 +0000 (Wed, 28 Feb 2007) $
0096:         */
0097:        @SuppressWarnings("deprecation")
0098:        public abstract class HttpMethodBase implements  HttpMethod {
0099:
0100:            // -------------------------------------------------------------- Constants
0101:
0102:            /** Log object for this class. */
0103:            private static final Log LOG = LogFactory
0104:                    .getLog(HttpMethodBase.class);
0105:
0106:            // ----------------------------------------------------- Instance variables 
0107:
0108:            /** Request headers, if any. */
0109:            private HeaderGroup requestHeaders = new HeaderGroup();
0110:
0111:            /** The Status-Line from the response. */
0112:            private StatusLine statusLine = null;
0113:
0114:            /** Response headers, if any. */
0115:            private HeaderGroup responseHeaders = new HeaderGroup();
0116:
0117:            /** Response trailer headers, if any. */
0118:            private HeaderGroup responseTrailerHeaders = new HeaderGroup();
0119:
0120:            /** Path of the HTTP method. */
0121:            private String path = null;
0122:
0123:            /** Query string of the HTTP method, if any. */
0124:            private String queryString = null;
0125:
0126:            /** The response body of the HTTP method, assuming it has not be 
0127:             * intercepted by a sub-class. */
0128:            private InputStream responseStream = null;
0129:
0130:            /** The connection that the response stream was read from. */
0131:            private HttpConnection responseConnection = null;
0132:
0133:            /** Buffer for the response */
0134:            private byte[] responseBody = null;
0135:
0136:            /** True if the HTTP method should automatically follow HTTP redirects.*/
0137:            private boolean followRedirects = false;
0138:
0139:            /** True if the HTTP method should automatically handle
0140:             *  HTTP authentication challenges. */
0141:            private boolean doAuthentication = true;
0142:
0143:            /** HTTP protocol parameters. */
0144:            private HttpMethodParams params = new HttpMethodParams();
0145:
0146:            /** Host authentication state */
0147:            private AuthState hostAuthState = new AuthState();
0148:
0149:            /** Proxy authentication state */
0150:            private AuthState proxyAuthState = new AuthState();
0151:
0152:            /** True if this method has already been executed. */
0153:            private boolean used = false;
0154:
0155:            /** Count of how many times did this HTTP method transparently handle 
0156:             * a recoverable exception. */
0157:            private int recoverableExceptionCount = 0;
0158:
0159:            /** the host for this HTTP method, can be null */
0160:            private HttpHost httphost = null;
0161:
0162:            /**
0163:             * Handles method retries
0164:             * 
0165:             * @deprecated no loner used
0166:             */
0167:            private MethodRetryHandler methodRetryHandler;
0168:
0169:            /** True if the connection must be closed when no longer needed */
0170:            private boolean connectionCloseForced = false;
0171:
0172:            /** Number of milliseconds to wait for 100-contunue response. */
0173:            private static final int RESPONSE_WAIT_TIME_MS = 3000;
0174:
0175:            /** HTTP protocol version used for execution of this method. */
0176:            private HttpVersion effectiveVersion = null;
0177:
0178:            /** Whether the execution of this method has been aborted */
0179:            private transient boolean aborted = false;
0180:
0181:            /** Whether the HTTP request has been transmitted to the target
0182:             * server it its entirety */
0183:            private boolean requestSent = false;
0184:
0185:            /** Actual cookie policy */
0186:            private CookieSpec cookiespec = null;
0187:
0188:            /** Default initial size of the response buffer if content length is unknown. */
0189:            private static final int DEFAULT_INITIAL_BUFFER_SIZE = 4 * 1024; // 4 kB
0190:
0191:            // ----------------------------------------------------------- Constructors
0192:
0193:            /**
0194:             * No-arg constructor.
0195:             */
0196:            public HttpMethodBase() {
0197:            }
0198:
0199:            /**
0200:             * Constructor specifying a URI.
0201:             * It is responsibility of the caller to ensure that URI elements
0202:             * (path & query parameters) are properly encoded (URL safe).
0203:             *
0204:             * @param uri either an absolute or relative URI. The URI is expected
0205:             *            to be URL-encoded
0206:             * 
0207:             * @throws IllegalArgumentException when URI is invalid
0208:             * @throws IllegalStateException when protocol of the absolute URI is not recognised
0209:             */
0210:            public HttpMethodBase(String uri) throws IllegalArgumentException,
0211:                    IllegalStateException {
0212:
0213:                try {
0214:
0215:                    // create a URI and allow for null/empty uri values
0216:                    if (uri == null || uri.equals("")) {
0217:                        uri = "/";
0218:                    }
0219:                    // BEGIN IA CHANGES
0220:                    //        setURI(new URI(uri, true));
0221:                    setURI(new org.archive.net.LaxURI(uri, true));
0222:                    // END IA CHANGES
0223:                } catch (URIException e) {
0224:                    throw new IllegalArgumentException("Invalid uri '" + uri
0225:                            + "': " + e.getMessage());
0226:                }
0227:            }
0228:
0229:            // ------------------------------------------- Property Setters and Getters
0230:
0231:            /**
0232:             * Obtains the name of the HTTP method as used in the HTTP request line,
0233:             * for example <tt>"GET"</tt> or <tt>"POST"</tt>.
0234:             * 
0235:             * @return the name of this method
0236:             */
0237:            public abstract String getName();
0238:
0239:            /**
0240:             * Returns the URI of the HTTP method
0241:             * 
0242:             * @return The URI
0243:             * 
0244:             * @throws URIException If the URI cannot be created.
0245:             * 
0246:             * @see org.apache.commons.httpclient.HttpMethod#getURI()
0247:             */
0248:            public URI getURI() throws URIException {
0249:                StringBuffer buffer = new StringBuffer();
0250:                if (this .httphost != null) {
0251:                    buffer.append(this .httphost.getProtocol().getScheme());
0252:                    buffer.append("://");
0253:                    buffer.append(this .httphost.getHostName());
0254:                    int port = this .httphost.getPort();
0255:                    if (port != -1
0256:                            && port != this .httphost.getProtocol()
0257:                                    .getDefaultPort()) {
0258:                        buffer.append(":");
0259:                        buffer.append(port);
0260:                    }
0261:                }
0262:                buffer.append(this .path);
0263:                if (this .queryString != null) {
0264:                    buffer.append('?');
0265:                    buffer.append(this .queryString);
0266:                }
0267:                //      BEGIN IA CHANGES
0268:                //      return new URI(buffer.toString(), true);
0269:                return new org.archive.net.LaxURI(buffer.toString(), true);
0270:                //      END IA CHANGES
0271:            }
0272:
0273:            /**
0274:             * Sets the URI for this method. 
0275:             * 
0276:             * @param uri URI to be set 
0277:             * 
0278:             * @throws URIException if a URI cannot be set
0279:             * 
0280:             * @since 3.0
0281:             */
0282:            public void setURI(URI uri) throws URIException {
0283:                // only set the host if specified by the URI
0284:                if (uri.isAbsoluteURI()) {
0285:                    this .httphost = new HttpHost(uri);
0286:                }
0287:                // set the path, defaulting to root
0288:                setPath(uri.getPath() == null ? "/" : uri.getEscapedPath());
0289:                setQueryString(uri.getEscapedQuery());
0290:            }
0291:
0292:            /**
0293:             * Sets whether or not the HTTP method should automatically follow HTTP redirects 
0294:             * (status code 302, etc.)
0295:             * 
0296:             * @param followRedirects <tt>true</tt> if the method will automatically follow redirects,
0297:             * <tt>false</tt> otherwise.
0298:             */
0299:            public void setFollowRedirects(boolean followRedirects) {
0300:                this .followRedirects = followRedirects;
0301:            }
0302:
0303:            /**
0304:             * Returns <tt>true</tt> if the HTTP method should automatically follow HTTP redirects 
0305:             * (status code 302, etc.), <tt>false</tt> otherwise.
0306:             * 
0307:             * @return <tt>true</tt> if the method will automatically follow HTTP redirects, 
0308:             * <tt>false</tt> otherwise.
0309:             */
0310:            public boolean getFollowRedirects() {
0311:                return this .followRedirects;
0312:            }
0313:
0314:            /** Sets whether version 1.1 of the HTTP protocol should be used per default.
0315:             *
0316:             * @param http11 <tt>true</tt> to use HTTP/1.1, <tt>false</tt> to use 1.0
0317:             * 
0318:             * @deprecated Use {@link HttpMethodParams#setVersion(HttpVersion)}
0319:             */
0320:            public void setHttp11(boolean http11) {
0321:                if (http11) {
0322:                    this .params.setVersion(HttpVersion.HTTP_1_1);
0323:                } else {
0324:                    this .params.setVersion(HttpVersion.HTTP_1_0);
0325:                }
0326:            }
0327:
0328:            /**
0329:             * Returns <tt>true</tt> if the HTTP method should automatically handle HTTP 
0330:             * authentication challenges (status code 401, etc.), <tt>false</tt> otherwise
0331:             *
0332:             * @return <tt>true</tt> if authentication challenges will be processed 
0333:             * automatically, <tt>false</tt> otherwise.
0334:             * 
0335:             * @since 2.0
0336:             */
0337:            public boolean getDoAuthentication() {
0338:                return doAuthentication;
0339:            }
0340:
0341:            /**
0342:             * Sets whether or not the HTTP method should automatically handle HTTP 
0343:             * authentication challenges (status code 401, etc.)
0344:             *
0345:             * @param doAuthentication <tt>true</tt> to process authentication challenges
0346:             * authomatically, <tt>false</tt> otherwise.
0347:             * 
0348:             * @since 2.0
0349:             */
0350:            public void setDoAuthentication(boolean doAuthentication) {
0351:                this .doAuthentication = doAuthentication;
0352:            }
0353:
0354:            // ---------------------------------------------- Protected Utility Methods
0355:
0356:            /**
0357:             * Returns <tt>true</tt> if version 1.1 of the HTTP protocol should be 
0358:             * used per default, <tt>false</tt> if version 1.0 should be used.
0359:             *
0360:             * @return <tt>true</tt> to use HTTP/1.1, <tt>false</tt> to use 1.0
0361:             * 
0362:             * @deprecated Use {@link HttpMethodParams#getVersion()}
0363:             */
0364:            public boolean isHttp11() {
0365:                return this .params.getVersion().equals(HttpVersion.HTTP_1_1);
0366:            }
0367:
0368:            /**
0369:             * Sets the path of the HTTP method.
0370:             * It is responsibility of the caller to ensure that the path is
0371:             * properly encoded (URL safe).
0372:             *
0373:             * @param path the path of the HTTP method. The path is expected
0374:             *        to be URL-encoded
0375:             */
0376:            public void setPath(String path) {
0377:                this .path = path;
0378:            }
0379:
0380:            /**
0381:             * Adds the specified request header, NOT overwriting any previous value.
0382:             * Note that header-name matching is case insensitive.
0383:             *
0384:             * @param header the header to add to the request
0385:             */
0386:            public void addRequestHeader(Header header) {
0387:                LOG.trace("HttpMethodBase.addRequestHeader(Header)");
0388:
0389:                if (header == null) {
0390:                    LOG.debug("null header value ignored");
0391:                } else {
0392:                    getRequestHeaderGroup().addHeader(header);
0393:                }
0394:            }
0395:
0396:            /**
0397:             * Use this method internally to add footers.
0398:             * 
0399:             * @param footer The footer to add.
0400:             */
0401:            public void addResponseFooter(Header footer) {
0402:                getResponseTrailerHeaderGroup().addHeader(footer);
0403:            }
0404:
0405:            /**
0406:             * Gets the path of this HTTP method.
0407:             * Calling this method <em>after</em> the request has been executed will 
0408:             * return the <em>actual</em> path, following any redirects automatically
0409:             * handled by this HTTP method.
0410:             *
0411:             * @return the path to request or "/" if the path is blank.
0412:             */
0413:            public String getPath() {
0414:                return (path == null || path.equals("")) ? "/" : path;
0415:            }
0416:
0417:            /**
0418:             * Sets the query string of this HTTP method. The caller must ensure that the string 
0419:             * is properly URL encoded. The query string should not start with the question 
0420:             * mark character.
0421:             *
0422:             * @param queryString the query string
0423:             * 
0424:             * @see EncodingUtil#formUrlEncode(NameValuePair[], String)
0425:             */
0426:            public void setQueryString(String queryString) {
0427:                this .queryString = queryString;
0428:            }
0429:
0430:            /**
0431:             * Sets the query string of this HTTP method.  The pairs are encoded as UTF-8 characters.  
0432:             * To use a different charset the parameters can be encoded manually using EncodingUtil 
0433:             * and set as a single String.
0434:             *
0435:             * @param params an array of {@link NameValuePair}s to add as query string
0436:             *        parameters. The name/value pairs will be automcatically 
0437:             *        URL encoded
0438:             * 
0439:             * @see EncodingUtil#formUrlEncode(NameValuePair[], String)
0440:             * @see #setQueryString(String)
0441:             */
0442:            public void setQueryString(NameValuePair[] params) {
0443:                LOG
0444:                        .trace("enter HttpMethodBase.setQueryString(NameValuePair[])");
0445:                queryString = EncodingUtil.formUrlEncode(params, "UTF-8");
0446:            }
0447:
0448:            /**
0449:             * Gets the query string of this HTTP method.
0450:             *
0451:             * @return The query string
0452:             */
0453:            public String getQueryString() {
0454:                return queryString;
0455:            }
0456:
0457:            /**
0458:             * Set the specified request header, overwriting any previous value. Note
0459:             * that header-name matching is case-insensitive.
0460:             *
0461:             * @param headerName the header's name
0462:             * @param headerValue the header's value
0463:             */
0464:            public void setRequestHeader(String headerName, String headerValue) {
0465:                Header header = new Header(headerName, headerValue);
0466:                setRequestHeader(header);
0467:            }
0468:
0469:            /**
0470:             * Sets the specified request header, overwriting any previous value.
0471:             * Note that header-name matching is case insensitive.
0472:             * 
0473:             * @param header the header
0474:             */
0475:            public void setRequestHeader(Header header) {
0476:
0477:                Header[] headers = getRequestHeaderGroup().getHeaders(
0478:                        header.getName());
0479:
0480:                for (int i = 0; i < headers.length; i++) {
0481:                    getRequestHeaderGroup().removeHeader(headers[i]);
0482:                }
0483:
0484:                getRequestHeaderGroup().addHeader(header);
0485:
0486:            }
0487:
0488:            /**
0489:             * Returns the specified request header. Note that header-name matching is
0490:             * case insensitive. <tt>null</tt> will be returned if either
0491:             * <i>headerName</i> is <tt>null</tt> or there is no matching header for
0492:             * <i>headerName</i>.
0493:             * 
0494:             * @param headerName The name of the header to be returned.
0495:             *
0496:             * @return The specified request header.
0497:             * 
0498:             * @since 3.0
0499:             */
0500:            public Header getRequestHeader(String headerName) {
0501:                if (headerName == null) {
0502:                    return null;
0503:                } else {
0504:                    return getRequestHeaderGroup().getCondensedHeader(
0505:                            headerName);
0506:                }
0507:            }
0508:
0509:            /**
0510:             * Returns an array of the requests headers that the HTTP method currently has
0511:             *
0512:             * @return an array of my request headers.
0513:             */
0514:            public Header[] getRequestHeaders() {
0515:                return getRequestHeaderGroup().getAllHeaders();
0516:            }
0517:
0518:            /**
0519:             * @see org.apache.commons.httpclient.HttpMethod#getRequestHeaders(java.lang.String)
0520:             */
0521:            public Header[] getRequestHeaders(String headerName) {
0522:                return getRequestHeaderGroup().getHeaders(headerName);
0523:            }
0524:
0525:            /**
0526:             * Gets the {@link HeaderGroup header group} storing the request headers.
0527:             * 
0528:             * @return a HeaderGroup
0529:             * 
0530:             * @since 2.0beta1
0531:             */
0532:            protected HeaderGroup getRequestHeaderGroup() {
0533:                return requestHeaders;
0534:            }
0535:
0536:            /**
0537:             * Gets the {@link HeaderGroup header group} storing the response trailer headers 
0538:             * as per RFC 2616 section 3.6.1.
0539:             * 
0540:             * @return a HeaderGroup
0541:             * 
0542:             * @since 2.0beta1
0543:             */
0544:            protected HeaderGroup getResponseTrailerHeaderGroup() {
0545:                return responseTrailerHeaders;
0546:            }
0547:
0548:            /**
0549:             * Gets the {@link HeaderGroup header group} storing the response headers.
0550:             * 
0551:             * @return a HeaderGroup
0552:             * 
0553:             * @since 2.0beta1
0554:             */
0555:            protected HeaderGroup getResponseHeaderGroup() {
0556:                return responseHeaders;
0557:            }
0558:
0559:            /**
0560:             * @see org.apache.commons.httpclient.HttpMethod#getResponseHeaders(java.lang.String)
0561:             * 
0562:             * @since 3.0
0563:             */
0564:            public Header[] getResponseHeaders(String headerName) {
0565:                return getResponseHeaderGroup().getHeaders(headerName);
0566:            }
0567:
0568:            /**
0569:             * Returns the response status code.
0570:             *
0571:             * @return the status code associated with the latest response.
0572:             */
0573:            public int getStatusCode() {
0574:                return statusLine.getStatusCode();
0575:            }
0576:
0577:            /**
0578:             * Provides access to the response status line.
0579:             *
0580:             * @return the status line object from the latest response.
0581:             * @since 2.0
0582:             */
0583:            public StatusLine getStatusLine() {
0584:                return statusLine;
0585:            }
0586:
0587:            /**
0588:             * Checks if response data is available.
0589:             * @return <tt>true</tt> if response data is available, <tt>false</tt> otherwise.
0590:             */
0591:            private boolean responseAvailable() {
0592:                return (responseBody != null) || (responseStream != null);
0593:            }
0594:
0595:            /**
0596:             * Returns an array of the response headers that the HTTP method currently has
0597:             * in the order in which they were read.
0598:             *
0599:             * @return an array of response headers.
0600:             */
0601:            public Header[] getResponseHeaders() {
0602:                return getResponseHeaderGroup().getAllHeaders();
0603:            }
0604:
0605:            /**
0606:             * Gets the response header associated with the given name. Header name
0607:             * matching is case insensitive. <tt>null</tt> will be returned if either
0608:             * <i>headerName</i> is <tt>null</tt> or there is no matching header for
0609:             * <i>headerName</i>.
0610:             *
0611:             * @param headerName the header name to match
0612:             *
0613:             * @return the matching header
0614:             */
0615:            public Header getResponseHeader(String headerName) {
0616:                if (headerName == null) {
0617:                    return null;
0618:                } else {
0619:                    return getResponseHeaderGroup().getCondensedHeader(
0620:                            headerName);
0621:                }
0622:            }
0623:
0624:            /**
0625:             * Return the length (in bytes) of the response body, as specified in a
0626:             * <tt>Content-Length</tt> header.
0627:             *
0628:             * <p>
0629:             * Return <tt>-1</tt> when the content-length is unknown.
0630:             * </p>
0631:             *
0632:             * @return content length, if <tt>Content-Length</tt> header is available. 
0633:             *          <tt>0</tt> indicates that the request has no body.
0634:             *          If <tt>Content-Length</tt> header is not present, the method 
0635:             *          returns  <tt>-1</tt>.
0636:             */
0637:            public long getResponseContentLength() {
0638:                Header[] headers = getResponseHeaderGroup().getHeaders(
0639:                        "Content-Length");
0640:                if (headers.length == 0) {
0641:                    return -1;
0642:                }
0643:                if (headers.length > 1) {
0644:                    LOG.warn("Multiple content-length headers detected");
0645:                }
0646:                for (int i = headers.length - 1; i >= 0; i--) {
0647:                    Header header = headers[i];
0648:                    try {
0649:                        return Long.parseLong(header.getValue());
0650:                    } catch (NumberFormatException e) {
0651:                        if (LOG.isWarnEnabled()) {
0652:                            LOG.warn("Invalid content-length value: "
0653:                                    + e.getMessage());
0654:                        }
0655:                    }
0656:                    // See if we can have better luck with another header, if present
0657:                }
0658:                return -1;
0659:            }
0660:
0661:            /**
0662:             * Returns the response body of the HTTP method, if any, as an array of bytes.
0663:             * If response body is not available or cannot be read, returns <tt>null</tt>
0664:             * 
0665:             * Note: This will cause the entire response body to be buffered in memory. A
0666:             * malicious server may easily exhaust all the VM memory. It is strongly
0667:             * recommended, to use getResponseAsStream if the content length of the response
0668:             * is unknown or resonably large.
0669:             *  
0670:             * @return The response body.
0671:             * 
0672:             * @throws IOException If an I/O (transport) problem occurs while obtaining the 
0673:             * response body.
0674:             */
0675:            public byte[] getResponseBody() throws IOException {
0676:                if (this .responseBody == null) {
0677:                    InputStream instream = getResponseBodyAsStream();
0678:                    if (instream != null) {
0679:                        long contentLength = getResponseContentLength();
0680:                        if (contentLength > Integer.MAX_VALUE) { //guard below cast from overflow
0681:                            throw new IOException(
0682:                                    "Content too large to be buffered: "
0683:                                            + contentLength + " bytes");
0684:                        }
0685:                        int limit = getParams().getIntParameter(
0686:                                HttpMethodParams.BUFFER_WARN_TRIGGER_LIMIT,
0687:                                1024 * 1024);
0688:                        if ((contentLength == -1) || (contentLength > limit)) {
0689:                            LOG
0690:                                    .warn("Going to buffer response body of large or unknown size. "
0691:                                            + "Using getResponseAsStream instead is recommended.");
0692:                        }
0693:                        LOG.debug("Buffering response body");
0694:                        ByteArrayOutputStream outstream = new ByteArrayOutputStream(
0695:                                contentLength > 0 ? (int) contentLength
0696:                                        : DEFAULT_INITIAL_BUFFER_SIZE);
0697:                        byte[] buffer = new byte[4096];
0698:                        int len;
0699:                        while ((len = instream.read(buffer)) > 0) {
0700:                            outstream.write(buffer, 0, len);
0701:                        }
0702:                        outstream.close();
0703:                        setResponseStream(null);
0704:                        this .responseBody = outstream.toByteArray();
0705:                    }
0706:                }
0707:                return this .responseBody;
0708:            }
0709:
0710:            /**
0711:             * Returns the response body of the HTTP method, if any, as an {@link InputStream}. 
0712:             * If response body is not available, returns <tt>null</tt>
0713:             * 
0714:             * @return The response body
0715:             * 
0716:             * @throws IOException If an I/O (transport) problem occurs while obtaining the 
0717:             * response body.
0718:             */
0719:            public InputStream getResponseBodyAsStream() throws IOException {
0720:                if (responseStream != null) {
0721:                    return responseStream;
0722:                }
0723:                if (responseBody != null) {
0724:                    InputStream byteResponseStream = new ByteArrayInputStream(
0725:                            responseBody);
0726:                    LOG.debug("re-creating response stream from byte array");
0727:                    return byteResponseStream;
0728:                }
0729:                return null;
0730:            }
0731:
0732:            /**
0733:             * Returns the response body of the HTTP method, if any, as a {@link String}. 
0734:             * If response body is not available or cannot be read, returns <tt>null</tt>
0735:             * The string conversion on the data is done using the character encoding specified
0736:             * in <tt>Content-Type</tt> header.
0737:             * 
0738:             * Note: This will cause the entire response body to be buffered in memory. A
0739:             * malicious server may easily exhaust all the VM memory. It is strongly
0740:             * recommended, to use getResponseAsStream if the content length of the response
0741:             * is unknown or resonably large.
0742:             * 
0743:             * @return The response body.
0744:             * 
0745:             * @throws IOException If an I/O (transport) problem occurs while obtaining the 
0746:             * response body.
0747:             */
0748:            public String getResponseBodyAsString() throws IOException {
0749:                byte[] rawdata = null;
0750:                if (responseAvailable()) {
0751:                    rawdata = getResponseBody();
0752:                }
0753:                if (rawdata != null) {
0754:                    return EncodingUtil
0755:                            .getString(rawdata, getResponseCharSet());
0756:                } else {
0757:                    return null;
0758:                }
0759:            }
0760:
0761:            /**
0762:             * Returns an array of the response footers that the HTTP method currently has
0763:             * in the order in which they were read.
0764:             *
0765:             * @return an array of footers
0766:             */
0767:            public Header[] getResponseFooters() {
0768:                return getResponseTrailerHeaderGroup().getAllHeaders();
0769:            }
0770:
0771:            /**
0772:             * Gets the response footer associated with the given name.
0773:             * Footer name matching is case insensitive.
0774:             * <tt>null</tt> will be returned if either <i>footerName</i> is
0775:             * <tt>null</tt> or there is no matching footer for <i>footerName</i>
0776:             * or there are no footers available.  If there are multiple footers
0777:             * with the same name, there values will be combined with the ',' separator
0778:             * as specified by RFC2616.
0779:             * 
0780:             * @param footerName the footer name to match
0781:             * @return the matching footer
0782:             */
0783:            public Header getResponseFooter(String footerName) {
0784:                if (footerName == null) {
0785:                    return null;
0786:                } else {
0787:                    return getResponseTrailerHeaderGroup().getCondensedHeader(
0788:                            footerName);
0789:                }
0790:            }
0791:
0792:            /**
0793:             * Sets the response stream.
0794:             * @param responseStream The new response stream.
0795:             */
0796:            protected void setResponseStream(InputStream responseStream) {
0797:                this .responseStream = responseStream;
0798:            }
0799:
0800:            /**
0801:             * Returns a stream from which the body of the current response may be read.
0802:             * If the method has not yet been executed, if <code>responseBodyConsumed</code>
0803:             * has been called, or if the stream returned by a previous call has been closed,
0804:             * <code>null</code> will be returned.
0805:             *
0806:             * @return the current response stream
0807:             */
0808:            protected InputStream getResponseStream() {
0809:                return responseStream;
0810:            }
0811:
0812:            /**
0813:             * Returns the status text (or "reason phrase") associated with the latest
0814:             * response.
0815:             * 
0816:             * @return The status text.
0817:             */
0818:            public String getStatusText() {
0819:                return statusLine.getReasonPhrase();
0820:            }
0821:
0822:            /**
0823:             * Defines how strictly HttpClient follows the HTTP protocol specification  
0824:             * (RFC 2616 and other relevant RFCs). In the strict mode HttpClient precisely
0825:             * implements the requirements of the specification, whereas in non-strict mode 
0826:             * it attempts to mimic the exact behaviour of commonly used HTTP agents, 
0827:             * which many HTTP servers expect.
0828:             * 
0829:             * @param strictMode <tt>true</tt> for strict mode, <tt>false</tt> otherwise
0830:             * 
0831:             * @deprecated Use {@link org.apache.commons.httpclient.params.HttpParams#setParameter(String, Object)}
0832:             * to exercise a more granular control over HTTP protocol strictness.
0833:             */
0834:            public void setStrictMode(boolean strictMode) {
0835:                if (strictMode) {
0836:                    this .params.makeStrict();
0837:                } else {
0838:                    this .params.makeLenient();
0839:                }
0840:            }
0841:
0842:            /**
0843:             * @deprecated Use {@link org.apache.commons.httpclient.params.HttpParams#setParameter(String, Object)}
0844:             * to exercise a more granular control over HTTP protocol strictness.
0845:             *
0846:             * @return <tt>false</tt>
0847:             */
0848:            public boolean isStrictMode() {
0849:                return false;
0850:            }
0851:
0852:            /**
0853:             * Adds the specified request header, NOT overwriting any previous value.
0854:             * Note that header-name matching is case insensitive.
0855:             *
0856:             * @param headerName the header's name
0857:             * @param headerValue the header's value
0858:             */
0859:            public void addRequestHeader(String headerName, String headerValue) {
0860:                addRequestHeader(new Header(headerName, headerValue));
0861:            }
0862:
0863:            /**
0864:             * Tests if the connection should be force-closed when no longer needed.
0865:             * 
0866:             * @return <code>true</code> if the connection must be closed
0867:             */
0868:            protected boolean isConnectionCloseForced() {
0869:                return this .connectionCloseForced;
0870:            }
0871:
0872:            /**
0873:             * Sets whether or not the connection should be force-closed when no longer 
0874:             * needed. This value should only be set to <code>true</code> in abnormal 
0875:             * circumstances, such as HTTP protocol violations. 
0876:             * 
0877:             * @param b <code>true</code> if the connection must be closed, <code>false</code>
0878:             * otherwise.
0879:             */
0880:            protected void setConnectionCloseForced(boolean b) {
0881:                if (LOG.isDebugEnabled()) {
0882:                    LOG.debug("Force-close connection: " + b);
0883:                }
0884:                this .connectionCloseForced = b;
0885:            }
0886:
0887:            /**
0888:             * Tests if the connection should be closed after the method has been executed.
0889:             * The connection will be left open when using HTTP/1.1 or if <tt>Connection: 
0890:             * keep-alive</tt> header was sent.
0891:             * 
0892:             * @param conn the connection in question
0893:             * 
0894:             * @return boolean true if we should close the connection.
0895:             */
0896:            protected boolean shouldCloseConnection(HttpConnection conn) {
0897:                // Connection must be closed due to an abnormal circumstance 
0898:                if (isConnectionCloseForced()) {
0899:                    LOG.debug("Should force-close connection.");
0900:                    return true;
0901:                }
0902:
0903:                Header connectionHeader = null;
0904:                // In case being connected via a proxy server
0905:                if (!conn.isTransparent()) {
0906:                    // Check for 'proxy-connection' directive
0907:                    connectionHeader = responseHeaders
0908:                            .getFirstHeader("proxy-connection");
0909:                }
0910:                // In all cases Check for 'connection' directive
0911:                // some non-complaint proxy servers send it instread of
0912:                // expected 'proxy-connection' directive
0913:                if (connectionHeader == null) {
0914:                    connectionHeader = responseHeaders
0915:                            .getFirstHeader("connection");
0916:                }
0917:                // In case the response does not contain any explict connection
0918:                // directives, check whether the request does
0919:                if (connectionHeader == null) {
0920:                    connectionHeader = requestHeaders
0921:                            .getFirstHeader("connection");
0922:                }
0923:                if (connectionHeader != null) {
0924:                    if (connectionHeader.getValue().equalsIgnoreCase("close")) {
0925:                        if (LOG.isDebugEnabled()) {
0926:                            LOG
0927:                                    .debug("Should close connection in response to directive: "
0928:                                            + connectionHeader.getValue());
0929:                        }
0930:                        return true;
0931:                    } else if (connectionHeader.getValue().equalsIgnoreCase(
0932:                            "keep-alive")) {
0933:                        if (LOG.isDebugEnabled()) {
0934:                            LOG
0935:                                    .debug("Should NOT close connection in response to directive: "
0936:                                            + connectionHeader.getValue());
0937:                        }
0938:                        return false;
0939:                    } else {
0940:                        if (LOG.isDebugEnabled()) {
0941:                            LOG.debug("Unknown directive: "
0942:                                    + connectionHeader.toExternalForm());
0943:                        }
0944:                    }
0945:                }
0946:                LOG
0947:                        .debug("Resorting to protocol version default close connection policy");
0948:                // missing or invalid connection header, do the default
0949:                if (this .effectiveVersion.greaterEquals(HttpVersion.HTTP_1_1)) {
0950:                    if (LOG.isDebugEnabled()) {
0951:                        LOG.debug("Should NOT close connection, using "
0952:                                + this .effectiveVersion.toString());
0953:                    }
0954:                } else {
0955:                    if (LOG.isDebugEnabled()) {
0956:                        LOG.debug("Should close connection, using "
0957:                                + this .effectiveVersion.toString());
0958:                    }
0959:                }
0960:                return this .effectiveVersion.lessEquals(HttpVersion.HTTP_1_0);
0961:            }
0962:
0963:            /**
0964:             * Tests if the this method is ready to be executed.
0965:             * 
0966:             * @param state the {@link HttpState state} information associated with this method
0967:             * @param conn the {@link HttpConnection connection} to be used
0968:             * @throws HttpException If the method is in invalid state.
0969:             */
0970:            private void checkExecuteConditions(HttpState state,
0971:                    HttpConnection conn) throws HttpException {
0972:
0973:                if (state == null) {
0974:                    throw new IllegalArgumentException(
0975:                            "HttpState parameter may not be null");
0976:                }
0977:                if (conn == null) {
0978:                    throw new IllegalArgumentException(
0979:                            "HttpConnection parameter may not be null");
0980:                }
0981:                if (this .aborted) {
0982:                    throw new IllegalStateException("Method has been aborted");
0983:                }
0984:                if (!validate()) {
0985:                    throw new ProtocolException(
0986:                            "HttpMethodBase object not valid");
0987:                }
0988:            }
0989:
0990:            /**
0991:             * Executes this method using the specified <code>HttpConnection</code> and
0992:             * <code>HttpState</code>. 
0993:             *
0994:             * @param state {@link HttpState state} information to associate with this
0995:             *        request. Must be non-null.
0996:             * @param conn the {@link HttpConnection connection} to used to execute
0997:             *        this HTTP method. Must be non-null.
0998:             *
0999:             * @return the integer status code if one was obtained, or <tt>-1</tt>
1000:             *
1001:             * @throws IOException if an I/O (transport) error occurs
1002:             * @throws HttpException  if a protocol exception occurs.
1003:             */
1004:            public int execute(HttpState state, HttpConnection conn)
1005:                    throws HttpException, IOException {
1006:
1007:                LOG
1008:                        .trace("enter HttpMethodBase.execute(HttpState, HttpConnection)");
1009:
1010:                // this is our connection now, assign it to a local variable so 
1011:                // that it can be released later
1012:                this .responseConnection = conn;
1013:
1014:                checkExecuteConditions(state, conn);
1015:                this .statusLine = null;
1016:                this .connectionCloseForced = false;
1017:
1018:                conn.setLastResponseInputStream(null);
1019:
1020:                // determine the effective protocol version
1021:                if (this .effectiveVersion == null) {
1022:                    this .effectiveVersion = this .params.getVersion();
1023:                }
1024:
1025:                writeRequest(state, conn);
1026:                this .requestSent = true;
1027:                readResponse(state, conn);
1028:                // the method has successfully executed
1029:                used = true;
1030:
1031:                return statusLine.getStatusCode();
1032:            }
1033:
1034:            /**
1035:             * Aborts the execution of this method.
1036:             * 
1037:             * @since 3.0
1038:             */
1039:            public void abort() {
1040:                if (this .aborted) {
1041:                    return;
1042:                }
1043:                this .aborted = true;
1044:                HttpConnection conn = this .responseConnection;
1045:                if (conn != null) {
1046:                    conn.close();
1047:                }
1048:            }
1049:
1050:            /**
1051:             * Returns <tt>true</tt> if the HTTP method has been already {@link #execute executed},
1052:             * but not {@link #recycle recycled}.
1053:             * 
1054:             * @return <tt>true</tt> if the method has been executed, <tt>false</tt> otherwise
1055:             */
1056:            public boolean hasBeenUsed() {
1057:                return used;
1058:            }
1059:
1060:            /**
1061:             * Recycles the HTTP method so that it can be used again.
1062:             * Note that all of the instance variables will be reset
1063:             * once this method has been called. This method will also
1064:             * release the connection being used by this HTTP method.
1065:             * 
1066:             * @see #releaseConnection()
1067:             * 
1068:             * @deprecated no longer supported and will be removed in the future
1069:             *             version of HttpClient
1070:             */
1071:            public void recycle() {
1072:                LOG.trace("enter HttpMethodBase.recycle()");
1073:
1074:                releaseConnection();
1075:
1076:                path = null;
1077:                followRedirects = false;
1078:                doAuthentication = true;
1079:                queryString = null;
1080:                getRequestHeaderGroup().clear();
1081:                getResponseHeaderGroup().clear();
1082:                getResponseTrailerHeaderGroup().clear();
1083:                statusLine = null;
1084:                effectiveVersion = null;
1085:                aborted = false;
1086:                used = false;
1087:                params = new HttpMethodParams();
1088:                responseBody = null;
1089:                recoverableExceptionCount = 0;
1090:                connectionCloseForced = false;
1091:                hostAuthState.invalidate();
1092:                proxyAuthState.invalidate();
1093:                cookiespec = null;
1094:                requestSent = false;
1095:            }
1096:
1097:            /**
1098:             * Releases the connection being used by this HTTP method. In particular the
1099:             * connection is used to read the response(if there is one) and will be held
1100:             * until the response has been read. If the connection can be reused by other 
1101:             * HTTP methods it is NOT closed at this point.
1102:             *
1103:             * @since 2.0
1104:             */
1105:            public void releaseConnection() {
1106:
1107:                if (responseStream != null) {
1108:                    try {
1109:                        // FYI - this may indirectly invoke responseBodyConsumed.
1110:                        responseStream.close();
1111:                    } catch (IOException e) {
1112:                        // the connection may not have been released, let's make sure
1113:                        ensureConnectionRelease();
1114:                    }
1115:                } else {
1116:                    // Make sure the connection has been released. If the response 
1117:                    // stream has not been set, this is the only way to release the 
1118:                    // connection. 
1119:                    ensureConnectionRelease();
1120:                }
1121:            }
1122:
1123:            /**
1124:             * Remove the request header associated with the given name. Note that
1125:             * header-name matching is case insensitive.
1126:             *
1127:             * @param headerName the header name
1128:             */
1129:            public void removeRequestHeader(String headerName) {
1130:
1131:                Header[] headers = getRequestHeaderGroup().getHeaders(
1132:                        headerName);
1133:                for (int i = 0; i < headers.length; i++) {
1134:                    getRequestHeaderGroup().removeHeader(headers[i]);
1135:                }
1136:
1137:            }
1138:
1139:            /**
1140:             * Removes the given request header.
1141:             * 
1142:             * @param header the header
1143:             */
1144:            public void removeRequestHeader(final Header header) {
1145:                if (header == null) {
1146:                    return;
1147:                }
1148:                getRequestHeaderGroup().removeHeader(header);
1149:            }
1150:
1151:            // ---------------------------------------------------------------- Queries
1152:
1153:            /**
1154:             * Returns <tt>true</tt> the method is ready to execute, <tt>false</tt> otherwise.
1155:             * 
1156:             * @return This implementation always returns <tt>true</tt>.
1157:             */
1158:            public boolean validate() {
1159:                return true;
1160:            }
1161:
1162:            /** 
1163:             * Returns the actual cookie policy
1164:             * 
1165:             * @param state HTTP state. TODO: to be removed in the future
1166:             * 
1167:             * @return cookie spec
1168:             */
1169:            private CookieSpec getCookieSpec(final HttpState state) {
1170:                if (this .cookiespec == null) {
1171:                    int i = state.getCookiePolicy();
1172:                    if (i == -1) {
1173:                        this .cookiespec = CookiePolicy
1174:                                .getCookieSpec(this .params.getCookiePolicy());
1175:                    } else {
1176:                        this .cookiespec = CookiePolicy.getSpecByPolicy(i);
1177:                    }
1178:                    this .cookiespec
1179:                            .setValidDateFormats((Collection) this .params
1180:                                    .getParameter(HttpMethodParams.DATE_PATTERNS));
1181:                }
1182:                return this .cookiespec;
1183:            }
1184:
1185:            /**
1186:             * Generates <tt>Cookie</tt> request headers for those {@link Cookie cookie}s
1187:             * that match the given host, port and path.
1188:             *
1189:             * @param state the {@link HttpState state} information associated with this method
1190:             * @param conn the {@link HttpConnection connection} used to execute
1191:             *        this HTTP method
1192:             *
1193:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1194:             *                     can be recovered from.
1195:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1196:             *                    cannot be recovered from.
1197:             */
1198:            protected void addCookieRequestHeader(HttpState state,
1199:                    HttpConnection conn) throws IOException, HttpException {
1200:
1201:                LOG
1202:                        .trace("enter HttpMethodBase.addCookieRequestHeader(HttpState, "
1203:                                + "HttpConnection)");
1204:
1205:                Header[] cookieheaders = getRequestHeaderGroup().getHeaders(
1206:                        "Cookie");
1207:                for (int i = 0; i < cookieheaders.length; i++) {
1208:                    Header cookieheader = cookieheaders[i];
1209:                    if (cookieheader.isAutogenerated()) {
1210:                        getRequestHeaderGroup().removeHeader(cookieheader);
1211:                    }
1212:                }
1213:
1214:                CookieSpec matcher = getCookieSpec(state);
1215:                // BEGIN IA CHANGES
1216:                //      PRIOR IMPL & COMPARISON HARNESS LEFT COMMENTED OUT FOR TEMPORARY REFERENCE
1217:                //        Cookie[] arrayListAnswer;
1218:                Cookie[] cookies;
1219:                synchronized (state) {
1220:                    //            arrayListAnswer = matcher.match(conn.getHost(), conn.getPort(),
1221:                    //                getPath(), conn.isSecure(), state.getCookies());
1222:                    cookies = matcher.match(conn.getHost(), conn.getPort(),
1223:                            getPath(), conn.isSecure(), state.getCookiesMap());
1224:
1225:                    //            if(! (new HashSet(Arrays.asList(arrayListAnswer)).equals(new HashSet(Arrays.asList(cookies))))) {
1226:                    //                System.out.println("discrepancy");
1227:                    //                arrayListAnswer = matcher.match(conn.getHost(), conn.getPort(),
1228:                    //                        getPath(), conn.isSecure(), state.getCookies());
1229:                    //                cookies = matcher.match(conn.getHost(), conn.getPort(),
1230:                    //                            getPath(), conn.isSecure(), state.getCookiesMap());
1231:                    //            }
1232:                    // END IA CHANGES
1233:                }
1234:                if ((cookies != null) && (cookies.length > 0)) {
1235:                    if (getParams().isParameterTrue(
1236:                            HttpMethodParams.SINGLE_COOKIE_HEADER)) {
1237:                        // In strict mode put all cookies on the same header
1238:                        String s = matcher.formatCookies(cookies);
1239:                        getRequestHeaderGroup().addHeader(
1240:                                new Header("Cookie", s, true));
1241:                    } else {
1242:                        // In non-strict mode put each cookie on a separate header
1243:                        for (int i = 0; i < cookies.length; i++) {
1244:                            String s = matcher.formatCookie(cookies[i]);
1245:                            getRequestHeaderGroup().addHeader(
1246:                                    new Header("Cookie", s, true));
1247:                        }
1248:                    }
1249:                }
1250:            }
1251:
1252:            /**
1253:             * Generates <tt>Host</tt> request header, as long as no <tt>Host</tt> request
1254:             * header already exists.
1255:             *
1256:             * @param state the {@link HttpState state} information associated with this method
1257:             * @param conn the {@link HttpConnection connection} used to execute
1258:             *        this HTTP method
1259:             *
1260:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1261:             *                     can be recovered from.
1262:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1263:             *                    cannot be recovered from.
1264:             */
1265:            protected void addHostRequestHeader(HttpState state,
1266:                    HttpConnection conn) throws IOException, HttpException {
1267:                LOG
1268:                        .trace("enter HttpMethodBase.addHostRequestHeader(HttpState, "
1269:                                + "HttpConnection)");
1270:
1271:                // Per 19.6.1.1 of RFC 2616, it is legal for HTTP/1.0 based
1272:                // applications to send the Host request-header.
1273:                // TODO: Add the ability to disable the sending of this header for
1274:                //       HTTP/1.0 requests.
1275:                String host = this .params.getVirtualHost();
1276:                if (host != null) {
1277:                    LOG.debug("Using virtual host name: " + host);
1278:                } else {
1279:                    host = conn.getHost();
1280:                }
1281:                int port = conn.getPort();
1282:
1283:                // Note: RFC 2616 uses the term "internet host name" for what goes on the
1284:                // host line.  It would seem to imply that host should be blank if the
1285:                // host is a number instead of an name.  Based on the behavior of web
1286:                // browsers, and the fact that RFC 2616 never defines the phrase "internet
1287:                // host name", and the bad behavior of HttpClient that follows if we
1288:                // send blank, I interpret this as a small misstatement in the RFC, where
1289:                // they meant to say "internet host".  So IP numbers get sent as host
1290:                // entries too. -- Eric Johnson 12/13/2002
1291:                if (LOG.isDebugEnabled()) {
1292:                    LOG.debug("Adding Host request header");
1293:                }
1294:
1295:                //appends the port only if not using the default port for the protocol
1296:                if (conn.getProtocol().getDefaultPort() != port) {
1297:                    host += (":" + port);
1298:                }
1299:
1300:                setRequestHeader("Host", host);
1301:            }
1302:
1303:            /**
1304:             * Generates <tt>Proxy-Connection: Keep-Alive</tt> request header when 
1305:             * communicating via a proxy server.
1306:             *
1307:             * @param state the {@link HttpState state} information associated with this method
1308:             * @param conn the {@link HttpConnection connection} used to execute
1309:             *        this HTTP method
1310:             *
1311:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1312:             *                     can be recovered from.
1313:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1314:             *                    cannot be recovered from.
1315:             */
1316:            protected void addProxyConnectionHeader(HttpState state,
1317:                    HttpConnection conn) throws IOException, HttpException {
1318:                LOG.trace("enter HttpMethodBase.addProxyConnectionHeader("
1319:                        + "HttpState, HttpConnection)");
1320:                if (!conn.isTransparent()) {
1321:                    setRequestHeader("Proxy-Connection", "Keep-Alive");
1322:                }
1323:            }
1324:
1325:            /**
1326:             * Generates all the required request {@link Header header}s 
1327:             * to be submitted via the given {@link HttpConnection connection}.
1328:             *
1329:             * <p>
1330:             * This implementation adds <tt>User-Agent</tt>, <tt>Host</tt>,
1331:             * <tt>Cookie</tt>, <tt>Authorization</tt>, <tt>Proxy-Authorization</tt>
1332:             * and <tt>Proxy-Connection</tt> headers, when appropriate.
1333:             * </p>
1334:             *
1335:             * <p>
1336:             * Subclasses may want to override this method to to add additional
1337:             * headers, and may choose to invoke this implementation (via
1338:             * <tt>super</tt>) to add the "standard" headers.
1339:             * </p>
1340:             *
1341:             * @param state the {@link HttpState state} information associated with this method
1342:             * @param conn the {@link HttpConnection connection} used to execute
1343:             *        this HTTP method
1344:             *
1345:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1346:             *                     can be recovered from.
1347:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1348:             *                    cannot be recovered from.
1349:             *
1350:             * @see #writeRequestHeaders
1351:             */
1352:            protected void addRequestHeaders(HttpState state,
1353:                    HttpConnection conn) throws IOException, HttpException {
1354:                LOG.trace("enter HttpMethodBase.addRequestHeaders(HttpState, "
1355:                        + "HttpConnection)");
1356:
1357:                addUserAgentRequestHeader(state, conn);
1358:                addHostRequestHeader(state, conn);
1359:                addCookieRequestHeader(state, conn);
1360:                addProxyConnectionHeader(state, conn);
1361:            }
1362:
1363:            /**
1364:             * Generates default <tt>User-Agent</tt> request header, as long as no
1365:             * <tt>User-Agent</tt> request header already exists.
1366:             *
1367:             * @param state the {@link HttpState state} information associated with this method
1368:             * @param conn the {@link HttpConnection connection} used to execute
1369:             *        this HTTP method
1370:             *
1371:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1372:             *                     can be recovered from.
1373:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1374:             *                    cannot be recovered from.
1375:             */
1376:            protected void addUserAgentRequestHeader(HttpState state,
1377:                    HttpConnection conn) throws IOException, HttpException {
1378:                LOG
1379:                        .trace("enter HttpMethodBase.addUserAgentRequestHeaders(HttpState, "
1380:                                + "HttpConnection)");
1381:
1382:                if (getRequestHeader("User-Agent") == null) {
1383:                    String agent = (String) getParams().getParameter(
1384:                            HttpMethodParams.USER_AGENT);
1385:                    if (agent == null) {
1386:                        agent = "Jakarta Commons-HttpClient";
1387:                    }
1388:                    setRequestHeader("User-Agent", agent);
1389:                }
1390:            }
1391:
1392:            /**
1393:             * Throws an {@link IllegalStateException} if the HTTP method has been already
1394:             * {@link #execute executed}, but not {@link #recycle recycled}.
1395:             *
1396:             * @throws IllegalStateException if the method has been used and not
1397:             *      recycled
1398:             */
1399:            protected void checkNotUsed() throws IllegalStateException {
1400:                if (used) {
1401:                    throw new IllegalStateException("Already used.");
1402:                }
1403:            }
1404:
1405:            /**
1406:             * Throws an {@link IllegalStateException} if the HTTP method has not been
1407:             * {@link #execute executed} since last {@link #recycle recycle}.
1408:             *
1409:             *
1410:             * @throws IllegalStateException if not used
1411:             */
1412:            protected void checkUsed() throws IllegalStateException {
1413:                if (!used) {
1414:                    throw new IllegalStateException("Not Used.");
1415:                }
1416:            }
1417:
1418:            // ------------------------------------------------- Static Utility Methods
1419:
1420:            /**
1421:             * Generates HTTP request line according to the specified attributes.
1422:             *
1423:             * @param connection the {@link HttpConnection connection} used to execute
1424:             *        this HTTP method
1425:             * @param name the method name generate a request for
1426:             * @param requestPath the path string for the request
1427:             * @param query the query string for the request
1428:             * @param version the protocol version to use (e.g. HTTP/1.0)
1429:             *
1430:             * @return HTTP request line
1431:             */
1432:            protected static String generateRequestLine(
1433:                    HttpConnection connection, String name, String requestPath,
1434:                    String query, String version) {
1435:                LOG
1436:                        .trace("enter HttpMethodBase.generateRequestLine(HttpConnection, "
1437:                                + "String, String, String, String)");
1438:
1439:                StringBuffer buf = new StringBuffer();
1440:                // Append method name
1441:                buf.append(name);
1442:                buf.append(" ");
1443:                // Absolute or relative URL?
1444:                if (!connection.isTransparent()) {
1445:                    Protocol protocol = connection.getProtocol();
1446:                    buf.append(protocol.getScheme().toLowerCase());
1447:                    buf.append("://");
1448:                    buf.append(connection.getHost());
1449:                    if ((connection.getPort() != -1)
1450:                            && (connection.getPort() != protocol
1451:                                    .getDefaultPort())) {
1452:                        buf.append(":");
1453:                        buf.append(connection.getPort());
1454:                    }
1455:                }
1456:                // Append path, if any
1457:                if (requestPath == null) {
1458:                    buf.append("/");
1459:                } else {
1460:                    if (!connection.isTransparent()
1461:                            && !requestPath.startsWith("/")) {
1462:                        buf.append("/");
1463:                    }
1464:                    buf.append(requestPath);
1465:                }
1466:                // Append query, if any
1467:                if (query != null) {
1468:                    if (query.indexOf("?") != 0) {
1469:                        buf.append("?");
1470:                    }
1471:                    buf.append(query);
1472:                }
1473:                // Append protocol
1474:                buf.append(" ");
1475:                buf.append(version);
1476:                buf.append("\r\n");
1477:
1478:                return buf.toString();
1479:            }
1480:
1481:            /**
1482:             * This method is invoked immediately after 
1483:             * {@link #readResponseBody(HttpState,HttpConnection)} and can be overridden by
1484:             * sub-classes in order to provide custom body processing.
1485:             *
1486:             * <p>
1487:             * This implementation does nothing.
1488:             * </p>
1489:             *
1490:             * @param state the {@link HttpState state} information associated with this method
1491:             * @param conn the {@link HttpConnection connection} used to execute
1492:             *        this HTTP method
1493:             *
1494:             * @see #readResponse
1495:             * @see #readResponseBody
1496:             */
1497:            protected void processResponseBody(HttpState state,
1498:                    HttpConnection conn) {
1499:            }
1500:
1501:            /**
1502:             * This method is invoked immediately after 
1503:             * {@link #readResponseHeaders(HttpState,HttpConnection)} and can be overridden by
1504:             * sub-classes in order to provide custom response headers processing.
1505:
1506:             * <p>
1507:             * This implementation will handle the <tt>Set-Cookie</tt> and
1508:             * <tt>Set-Cookie2</tt> headers, if any, adding the relevant cookies to
1509:             * the given {@link HttpState}.
1510:             * </p>
1511:             *
1512:             * @param state the {@link HttpState state} information associated with this method
1513:             * @param conn the {@link HttpConnection connection} used to execute
1514:             *        this HTTP method
1515:             *
1516:             * @see #readResponse
1517:             * @see #readResponseHeaders
1518:             */
1519:            protected void processResponseHeaders(HttpState state,
1520:                    HttpConnection conn) {
1521:                LOG
1522:                        .trace("enter HttpMethodBase.processResponseHeaders(HttpState, "
1523:                                + "HttpConnection)");
1524:
1525:                Header[] headers = getResponseHeaderGroup().getHeaders(
1526:                        "set-cookie2");
1527:                //Only process old style set-cookie headers if new style headres
1528:                //are not present
1529:                if (headers.length == 0) {
1530:                    headers = getResponseHeaderGroup().getHeaders("set-cookie");
1531:                }
1532:
1533:                CookieSpec parser = getCookieSpec(state);
1534:                String host = this .params.getVirtualHost();
1535:                if (host == null) {
1536:                    host = conn.getHost();
1537:                }
1538:                for (int i = 0; i < headers.length; i++) {
1539:                    Header header = headers[i];
1540:                    Cookie[] cookies = null;
1541:                    try {
1542:                        cookies = parser.parse(host, conn.getPort(), getPath(),
1543:                                conn.isSecure(), header);
1544:                    } catch (MalformedCookieException e) {
1545:                        if (LOG.isWarnEnabled()) {
1546:                            LOG.warn("Invalid cookie header: \""
1547:                                    + header.getValue() + "\". "
1548:                                    + e.getMessage());
1549:                        }
1550:                    }
1551:                    if (cookies != null) {
1552:                        for (int j = 0; j < cookies.length; j++) {
1553:                            Cookie cookie = cookies[j];
1554:                            try {
1555:                                parser.validate(host, conn.getPort(),
1556:                                        getPath(), conn.isSecure(), cookie);
1557:                                state.addCookie(cookie);
1558:                                if (LOG.isDebugEnabled()) {
1559:                                    LOG.debug("Cookie accepted: \""
1560:                                            + parser.formatCookie(cookie)
1561:                                            + "\"");
1562:                                }
1563:                            } catch (MalformedCookieException e) {
1564:                                if (LOG.isWarnEnabled()) {
1565:                                    LOG.warn("Cookie rejected: \""
1566:                                            + parser.formatCookie(cookie)
1567:                                            + "\". " + e.getMessage());
1568:                                }
1569:                            }
1570:                        }
1571:                    }
1572:                }
1573:            }
1574:
1575:            /**
1576:             * This method is invoked immediately after 
1577:             * {@link #readStatusLine(HttpState,HttpConnection)} and can be overridden by
1578:             * sub-classes in order to provide custom response status line processing.
1579:             *
1580:             * @param state the {@link HttpState state} information associated with this method
1581:             * @param conn the {@link HttpConnection connection} used to execute
1582:             *        this HTTP method
1583:             *
1584:             * @see #readResponse
1585:             * @see #readStatusLine
1586:             */
1587:            protected void processStatusLine(HttpState state,
1588:                    HttpConnection conn) {
1589:            }
1590:
1591:            /**
1592:             * Reads the response from the given {@link HttpConnection connection}.
1593:             *
1594:             * <p>
1595:             * The response is processed as the following sequence of actions:
1596:             *
1597:             * <ol>
1598:             * <li>
1599:             * {@link #readStatusLine(HttpState,HttpConnection)} is
1600:             * invoked to read the request line.
1601:             * </li>
1602:             * <li>
1603:             * {@link #processStatusLine(HttpState,HttpConnection)}
1604:             * is invoked, allowing the method to process the status line if
1605:             * desired.
1606:             * </li>
1607:             * <li>
1608:             * {@link #readResponseHeaders(HttpState,HttpConnection)} is invoked to read
1609:             * the associated headers.
1610:             * </li>
1611:             * <li>
1612:             * {@link #processResponseHeaders(HttpState,HttpConnection)} is invoked, allowing
1613:             * the method to process the headers if desired.
1614:             * </li>
1615:             * <li>
1616:             * {@link #readResponseBody(HttpState,HttpConnection)} is
1617:             * invoked to read the associated body (if any).
1618:             * </li>
1619:             * <li>
1620:             * {@link #processResponseBody(HttpState,HttpConnection)} is invoked, allowing the
1621:             * method to process the response body if desired.
1622:             * </li>
1623:             * </ol>
1624:             *
1625:             * Subclasses may want to override one or more of the above methods to to
1626:             * customize the processing. (Or they may choose to override this method
1627:             * if dramatically different processing is required.)
1628:             * </p>
1629:             *
1630:             * @param state the {@link HttpState state} information associated with this method
1631:             * @param conn the {@link HttpConnection connection} used to execute
1632:             *        this HTTP method
1633:             *
1634:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1635:             *                     can be recovered from.
1636:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1637:             *                    cannot be recovered from.
1638:             */
1639:            protected void readResponse(HttpState state, HttpConnection conn)
1640:                    throws IOException, HttpException {
1641:                LOG
1642:                        .trace("enter HttpMethodBase.readResponse(HttpState, HttpConnection)");
1643:                // Status line & line may have already been received
1644:                // if 'expect - continue' handshake has been used
1645:                while (this .statusLine == null) {
1646:                    readStatusLine(state, conn);
1647:                    processStatusLine(state, conn);
1648:                    readResponseHeaders(state, conn);
1649:                    processResponseHeaders(state, conn);
1650:
1651:                    int status = this .statusLine.getStatusCode();
1652:                    if ((status >= 100) && (status < 200)) {
1653:                        if (LOG.isInfoEnabled()) {
1654:                            LOG.info("Discarding unexpected response: "
1655:                                    + this .statusLine.toString());
1656:                        }
1657:                        this .statusLine = null;
1658:                    }
1659:                }
1660:                readResponseBody(state, conn);
1661:                processResponseBody(state, conn);
1662:            }
1663:
1664:            /**
1665:             * Read the response body from the given {@link HttpConnection}.
1666:             *
1667:             * <p>
1668:             * The current implementation wraps the socket level stream with
1669:             * an appropriate stream for the type of response (chunked, content-length,
1670:             * or auto-close).  If there is no response body, the connection associated
1671:             * with the request will be returned to the connection manager.
1672:             * </p>
1673:             *
1674:             * <p>
1675:             * Subclasses may want to override this method to to customize the
1676:             * processing.
1677:             * </p>
1678:             *
1679:             * @param state the {@link HttpState state} information associated with this method
1680:             * @param conn the {@link HttpConnection connection} used to execute
1681:             *        this HTTP method
1682:             *
1683:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1684:             *                     can be recovered from.
1685:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1686:             *                    cannot be recovered from.
1687:             *
1688:             * @see #readResponse
1689:             * @see #processResponseBody
1690:             */
1691:            protected void readResponseBody(HttpState state, HttpConnection conn)
1692:                    throws IOException, HttpException {
1693:                LOG
1694:                        .trace("enter HttpMethodBase.readResponseBody(HttpState, HttpConnection)");
1695:
1696:                // assume we are not done with the connection if we get a stream
1697:                InputStream stream = readResponseBody(conn);
1698:                if (stream == null) {
1699:                    // done using the connection!
1700:                    responseBodyConsumed();
1701:                } else {
1702:                    conn.setLastResponseInputStream(stream);
1703:                    setResponseStream(stream);
1704:                }
1705:            }
1706:
1707:            /**
1708:             * Returns the response body as an {@link InputStream input stream}
1709:             * corresponding to the values of the <tt>Content-Length</tt> and 
1710:             * <tt>Transfer-Encoding</tt> headers. If no response body is available
1711:             * returns <tt>null</tt>.
1712:             * <p>
1713:             *
1714:             * @see #readResponse
1715:             * @see #processResponseBody
1716:             *
1717:             * @param conn the {@link HttpConnection connection} used to execute
1718:             *        this HTTP method
1719:             *
1720:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1721:             *                     can be recovered from.
1722:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1723:             *                    cannot be recovered from.
1724:             */
1725:            private InputStream readResponseBody(HttpConnection conn)
1726:                    throws HttpException, IOException {
1727:
1728:                LOG
1729:                        .trace("enter HttpMethodBase.readResponseBody(HttpConnection)");
1730:
1731:                responseBody = null;
1732:                InputStream is = conn.getResponseInputStream();
1733:                if (Wire.CONTENT_WIRE.enabled()) {
1734:                    is = new WireLogInputStream(is, Wire.CONTENT_WIRE);
1735:                }
1736:                InputStream result = null;
1737:                Header transferEncodingHeader = responseHeaders
1738:                        .getFirstHeader("Transfer-Encoding");
1739:                // We use Transfer-Encoding if present and ignore Content-Length.
1740:                // RFC2616, 4.4 item number 3
1741:                if (transferEncodingHeader != null) {
1742:
1743:                    String transferEncoding = transferEncodingHeader.getValue();
1744:                    if (!"chunked".equalsIgnoreCase(transferEncoding)
1745:                            && !"identity".equalsIgnoreCase(transferEncoding)) {
1746:                        if (LOG.isWarnEnabled()) {
1747:                            LOG.warn("Unsupported transfer encoding: "
1748:                                    + transferEncoding);
1749:                        }
1750:                    }
1751:                    HeaderElement[] encodings = transferEncodingHeader
1752:                            .getElements();
1753:                    // The chunked encoding must be the last one applied
1754:                    // RFC2616, 14.41
1755:                    int len = encodings.length;
1756:                    if ((len > 0)
1757:                            && ("chunked".equalsIgnoreCase(encodings[len - 1]
1758:                                    .getName()))) {
1759:                        // if response body is empty
1760:                        if (conn.isResponseAvailable(conn.getParams()
1761:                                .getSoTimeout())) {
1762:                            result = new ChunkedInputStream(is, this );
1763:                        } else {
1764:                            if (getParams().isParameterTrue(
1765:                                    HttpMethodParams.STRICT_TRANSFER_ENCODING)) {
1766:                                throw new ProtocolException(
1767:                                        "Chunk-encoded body declared but not sent");
1768:                            } else {
1769:                                LOG.warn("Chunk-encoded body missing");
1770:                            }
1771:                        }
1772:                    } else {
1773:                        LOG.info("Response content is not chunk-encoded");
1774:                        // The connection must be terminated by closing 
1775:                        // the socket as per RFC 2616, 3.6
1776:                        setConnectionCloseForced(true);
1777:                        result = is;
1778:                    }
1779:                } else {
1780:                    long expectedLength = getResponseContentLength();
1781:                    if (expectedLength == -1) {
1782:                        Header connectionHeader = responseHeaders
1783:                                .getFirstHeader("Connection");
1784:                        String connectionDirective = null;
1785:                        if (connectionHeader != null) {
1786:                            connectionDirective = connectionHeader.getValue();
1787:                        }
1788:                        if (this .effectiveVersion
1789:                                .greaterEquals(HttpVersion.HTTP_1_1)
1790:                                && !"close"
1791:                                        .equalsIgnoreCase(connectionDirective)) {
1792:                            LOG.info("Response content length is not known");
1793:                            setConnectionCloseForced(true);
1794:                        }
1795:                        result = is;
1796:                    } else {
1797:                        result = new ContentLengthInputStream(is,
1798:                                expectedLength);
1799:                    }
1800:                }
1801:
1802:                // See if the response is supposed to have a response body
1803:                if (!canResponseHaveBody(statusLine.getStatusCode())) {
1804:                    result = null;
1805:                }
1806:                // if there is a result - ALWAYS wrap it in an observer which will
1807:                // close the underlying stream as soon as it is consumed, and notify
1808:                // the watcher that the stream has been consumed.
1809:                if (result != null) {
1810:
1811:                    result = new AutoCloseInputStream(result,
1812:                            new ResponseConsumedWatcher() {
1813:                                public void responseConsumed() {
1814:                                    responseBodyConsumed();
1815:                                }
1816:                            });
1817:                }
1818:
1819:                return result;
1820:            }
1821:
1822:            /**
1823:             * Reads the response headers from the given {@link HttpConnection connection}.
1824:             *
1825:             * <p>
1826:             * Subclasses may want to override this method to to customize the
1827:             * processing.
1828:             * </p>
1829:             *
1830:             * <p>
1831:             * "It must be possible to combine the multiple header fields into one
1832:             * "field-name: field-value" pair, without changing the semantics of the
1833:             * message, by appending each subsequent field-value to the first, each
1834:             * separated by a comma." - HTTP/1.0 (4.3)
1835:             * </p>
1836:             *
1837:             * @param state the {@link HttpState state} information associated with this method
1838:             * @param conn the {@link HttpConnection connection} used to execute
1839:             *        this HTTP method
1840:             *
1841:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1842:             *                     can be recovered from.
1843:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1844:             *                    cannot be recovered from.
1845:             *
1846:             * @see #readResponse
1847:             * @see #processResponseHeaders
1848:             */
1849:            protected void readResponseHeaders(HttpState state,
1850:                    HttpConnection conn) throws IOException, HttpException {
1851:                LOG.trace("enter HttpMethodBase.readResponseHeaders(HttpState,"
1852:                        + "HttpConnection)");
1853:
1854:                getResponseHeaderGroup().clear();
1855:
1856:                Header[] headers = HttpParser.parseHeaders(conn
1857:                        .getResponseInputStream(), getParams()
1858:                        .getHttpElementCharset());
1859:                if (Wire.HEADER_WIRE.enabled()) {
1860:                    for (int i = 0; i < headers.length; i++) {
1861:                        Wire.HEADER_WIRE.input(headers[i].toExternalForm());
1862:                    }
1863:                }
1864:                getResponseHeaderGroup().setHeaders(headers);
1865:            }
1866:
1867:            /**
1868:             * Read the status line from the given {@link HttpConnection}, setting my
1869:             * {@link #getStatusCode status code} and {@link #getStatusText status
1870:             * text}.
1871:             *
1872:             * <p>
1873:             * Subclasses may want to override this method to to customize the
1874:             * processing.
1875:             * </p>
1876:             *
1877:             * @param state the {@link HttpState state} information associated with this method
1878:             * @param conn the {@link HttpConnection connection} used to execute
1879:             *        this HTTP method
1880:             *
1881:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1882:             *                     can be recovered from.
1883:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1884:             *                    cannot be recovered from.
1885:             *
1886:             * @see StatusLine
1887:             */
1888:            protected void readStatusLine(HttpState state, HttpConnection conn)
1889:                    throws IOException, HttpException {
1890:                LOG
1891:                        .trace("enter HttpMethodBase.readStatusLine(HttpState, HttpConnection)");
1892:
1893:                final int maxGarbageLines = getParams().getIntParameter(
1894:                        HttpMethodParams.STATUS_LINE_GARBAGE_LIMIT,
1895:                        Integer.MAX_VALUE);
1896:
1897:                //read out the HTTP status string
1898:                int count = 0;
1899:                String s;
1900:                do {
1901:                    s = conn.readLine(getParams().getHttpElementCharset());
1902:                    if (s == null && count == 0) {
1903:                        // The server just dropped connection on us
1904:                        throw new NoHttpResponseException("The server "
1905:                                + conn.getHost() + " failed to respond");
1906:                    }
1907:                    if (Wire.HEADER_WIRE.enabled()) {
1908:                        Wire.HEADER_WIRE.input(s + "\r\n");
1909:                    }
1910:                    if (s != null && StatusLine.startsWithHTTP(s)) {
1911:                        // Got one
1912:                        break;
1913:                    } else if (s == null || count >= maxGarbageLines) {
1914:                        // Giving up
1915:                        throw new ProtocolException(
1916:                                "The server "
1917:                                        + conn.getHost()
1918:                                        + " failed to respond with a valid HTTP response");
1919:                    }
1920:                    count++;
1921:                } while (true);
1922:
1923:                //create the status line from the status string
1924:                statusLine = new StatusLine(s);
1925:
1926:                //check for a valid HTTP-Version
1927:                String versionStr = statusLine.getHttpVersion();
1928:                if (getParams().isParameterFalse(
1929:                        HttpMethodParams.UNAMBIGUOUS_STATUS_LINE)
1930:                        && versionStr.equals("HTTP")) {
1931:                    getParams().setVersion(HttpVersion.HTTP_1_0);
1932:                    if (LOG.isWarnEnabled()) {
1933:                        LOG
1934:                                .warn("Ambiguous status line (HTTP protocol version missing):"
1935:                                        + statusLine.toString());
1936:                    }
1937:                } else {
1938:                    this .effectiveVersion = HttpVersion.parse(versionStr);
1939:                }
1940:
1941:            }
1942:
1943:            // ------------------------------------------------------ Protected Methods
1944:
1945:            /**
1946:             * <p>
1947:             * Sends the request via the given {@link HttpConnection connection}.
1948:             * </p>
1949:             *
1950:             * <p>
1951:             * The request is written as the following sequence of actions:
1952:             * </p>
1953:             *
1954:             * <ol>
1955:             * <li>
1956:             * {@link #writeRequestLine(HttpState, HttpConnection)} is invoked to 
1957:             * write the request line.
1958:             * </li>
1959:             * <li>
1960:             * {@link #writeRequestHeaders(HttpState, HttpConnection)} is invoked 
1961:             * to write the associated headers.
1962:             * </li>
1963:             * <li>
1964:             * <tt>\r\n</tt> is sent to close the head part of the request.
1965:             * </li>
1966:             * <li>
1967:             * {@link #writeRequestBody(HttpState, HttpConnection)} is invoked to 
1968:             * write the body part of the request.
1969:             * </li>
1970:             * </ol>
1971:             *
1972:             * <p>
1973:             * Subclasses may want to override one or more of the above methods to to
1974:             * customize the processing. (Or they may choose to override this method
1975:             * if dramatically different processing is required.)
1976:             * </p>
1977:             *
1978:             * @param state the {@link HttpState state} information associated with this method
1979:             * @param conn the {@link HttpConnection connection} used to execute
1980:             *        this HTTP method
1981:             *
1982:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
1983:             *                     can be recovered from.
1984:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
1985:             *                    cannot be recovered from.
1986:             */
1987:            protected void writeRequest(HttpState state, HttpConnection conn)
1988:                    throws IOException, HttpException {
1989:                LOG
1990:                        .trace("enter HttpMethodBase.writeRequest(HttpState, HttpConnection)");
1991:                writeRequestLine(state, conn);
1992:                writeRequestHeaders(state, conn);
1993:                conn.writeLine(); // close head
1994:                if (Wire.HEADER_WIRE.enabled()) {
1995:                    Wire.HEADER_WIRE.output("\r\n");
1996:                }
1997:
1998:                HttpVersion ver = getParams().getVersion();
1999:                Header expectheader = getRequestHeader("Expect");
2000:                String expectvalue = null;
2001:                if (expectheader != null) {
2002:                    expectvalue = expectheader.getValue();
2003:                }
2004:                if ((expectvalue != null)
2005:                        && (expectvalue.compareToIgnoreCase("100-continue") == 0)) {
2006:                    if (ver.greaterEquals(HttpVersion.HTTP_1_1)) {
2007:
2008:                        // make sure the status line and headers have been sent
2009:                        conn.flushRequestOutputStream();
2010:
2011:                        int readTimeout = conn.getParams().getSoTimeout();
2012:                        try {
2013:                            conn.setSocketTimeout(RESPONSE_WAIT_TIME_MS);
2014:                            readStatusLine(state, conn);
2015:                            processStatusLine(state, conn);
2016:                            readResponseHeaders(state, conn);
2017:                            processResponseHeaders(state, conn);
2018:
2019:                            if (this .statusLine.getStatusCode() == HttpStatus.SC_CONTINUE) {
2020:                                // Discard status line
2021:                                this .statusLine = null;
2022:                                LOG.debug("OK to continue received");
2023:                            } else {
2024:                                return;
2025:                            }
2026:                        } catch (InterruptedIOException e) {
2027:                            if (!ExceptionUtil.isSocketTimeoutException(e)) {
2028:                                throw e;
2029:                            }
2030:                            // Most probably Expect header is not recongnized
2031:                            // Remove the header to signal the method 
2032:                            // that it's okay to go ahead with sending data
2033:                            removeRequestHeader("Expect");
2034:                            LOG
2035:                                    .info("100 (continue) read timeout. Resume sending the request");
2036:                        } finally {
2037:                            conn.setSocketTimeout(readTimeout);
2038:                        }
2039:
2040:                    } else {
2041:                        removeRequestHeader("Expect");
2042:                        LOG
2043:                                .info("'Expect: 100-continue' handshake is only supported by "
2044:                                        + "HTTP/1.1 or higher");
2045:                    }
2046:                }
2047:
2048:                writeRequestBody(state, conn);
2049:                // make sure the entire request body has been sent
2050:                conn.flushRequestOutputStream();
2051:            }
2052:
2053:            /**
2054:             * Writes the request body to the given {@link HttpConnection connection}.
2055:             *
2056:             * <p>
2057:             * This method should return <tt>true</tt> if the request body was actually
2058:             * sent (or is empty), or <tt>false</tt> if it could not be sent for some
2059:             * reason.
2060:             * </p>
2061:             *
2062:             * <p>
2063:             * This implementation writes nothing and returns <tt>true</tt>.
2064:             * </p>
2065:             *
2066:             * @param state the {@link HttpState state} information associated with this method
2067:             * @param conn the {@link HttpConnection connection} used to execute
2068:             *        this HTTP method
2069:             *
2070:             * @return <tt>true</tt>
2071:             *
2072:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
2073:             *                     can be recovered from.
2074:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
2075:             *                    cannot be recovered from.
2076:             */
2077:            protected boolean writeRequestBody(HttpState state,
2078:                    HttpConnection conn) throws IOException, HttpException {
2079:                return true;
2080:            }
2081:
2082:            /**
2083:             * Writes the request headers to the given {@link HttpConnection connection}.
2084:             *
2085:             * <p>
2086:             * This implementation invokes {@link #addRequestHeaders(HttpState,HttpConnection)},
2087:             * and then writes each header to the request stream.
2088:             * </p>
2089:             *
2090:             * <p>
2091:             * Subclasses may want to override this method to to customize the
2092:             * processing.
2093:             * </p>
2094:             *
2095:             * @param state the {@link HttpState state} information associated with this method
2096:             * @param conn the {@link HttpConnection connection} used to execute
2097:             *        this HTTP method
2098:             *
2099:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
2100:             *                     can be recovered from.
2101:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
2102:             *                    cannot be recovered from.
2103:             *
2104:             * @see #addRequestHeaders
2105:             * @see #getRequestHeaders
2106:             */
2107:            protected void writeRequestHeaders(HttpState state,
2108:                    HttpConnection conn) throws IOException, HttpException {
2109:                LOG.trace("enter HttpMethodBase.writeRequestHeaders(HttpState,"
2110:                        + "HttpConnection)");
2111:                addRequestHeaders(state, conn);
2112:
2113:                String charset = getParams().getHttpElementCharset();
2114:
2115:                Header[] headers = getRequestHeaders();
2116:                for (int i = 0; i < headers.length; i++) {
2117:                    String s = headers[i].toExternalForm();
2118:                    if (Wire.HEADER_WIRE.enabled()) {
2119:                        Wire.HEADER_WIRE.output(s);
2120:                    }
2121:                    conn.print(s, charset);
2122:                }
2123:            }
2124:
2125:            /**
2126:             * Writes the request line to the given {@link HttpConnection connection}.
2127:             *
2128:             * <p>
2129:             * Subclasses may want to override this method to to customize the
2130:             * processing.
2131:             * </p>
2132:             *
2133:             * @param state the {@link HttpState state} information associated with this method
2134:             * @param conn the {@link HttpConnection connection} used to execute
2135:             *        this HTTP method
2136:             *
2137:             * @throws IOException if an I/O (transport) error occurs. Some transport exceptions
2138:             *                     can be recovered from.
2139:             * @throws HttpException  if a protocol exception occurs. Usually protocol exceptions 
2140:             *                    cannot be recovered from.
2141:             *
2142:             * @see #generateRequestLine
2143:             */
2144:            protected void writeRequestLine(HttpState state, HttpConnection conn)
2145:                    throws IOException, HttpException {
2146:                LOG
2147:                        .trace("enter HttpMethodBase.writeRequestLine(HttpState, HttpConnection)");
2148:                String requestLine = getRequestLine(conn);
2149:                if (Wire.HEADER_WIRE.enabled()) {
2150:                    Wire.HEADER_WIRE.output(requestLine);
2151:                }
2152:                conn.print(requestLine, getParams().getHttpElementCharset());
2153:            }
2154:
2155:            /**
2156:             * Returns the request line.
2157:             * 
2158:             * @param conn the {@link HttpConnection connection} used to execute
2159:             *        this HTTP method
2160:             * 
2161:             * @return The request line.
2162:             */
2163:            private String getRequestLine(HttpConnection conn) {
2164:                return HttpMethodBase.generateRequestLine(conn, getName(),
2165:                        getPath(), getQueryString(), this .effectiveVersion
2166:                                .toString());
2167:            }
2168:
2169:            /**
2170:             * Returns {@link HttpMethodParams HTTP protocol parameters} associated with this method.
2171:             *
2172:             * @return HTTP parameters.
2173:             *
2174:             * @since 3.0
2175:             */
2176:            public HttpMethodParams getParams() {
2177:                return this .params;
2178:            }
2179:
2180:            /**
2181:             * Assigns {@link HttpMethodParams HTTP protocol parameters} for this method.
2182:             * 
2183:             * @since 3.0
2184:             * 
2185:             * @see HttpMethodParams
2186:             */
2187:            public void setParams(final HttpMethodParams params) {
2188:                if (params == null) {
2189:                    throw new IllegalArgumentException(
2190:                            "Parameters may not be null");
2191:                }
2192:                this .params = params;
2193:            }
2194:
2195:            /**
2196:             * Returns the HTTP version used with this method (may be <tt>null</tt>
2197:             * if undefined, that is, the method has not been executed)
2198:             *
2199:             * @return HTTP version.
2200:             *
2201:             * @since 3.0
2202:             */
2203:            public HttpVersion getEffectiveVersion() {
2204:                return this .effectiveVersion;
2205:            }
2206:
2207:            /**
2208:             * Per RFC 2616 section 4.3, some response can never contain a message
2209:             * body.
2210:             *
2211:             * @param status - the HTTP status code
2212:             *
2213:             * @return <tt>true</tt> if the message may contain a body, <tt>false</tt> if it can not
2214:             *         contain a message body
2215:             */
2216:            private static boolean canResponseHaveBody(int status) {
2217:                LOG.trace("enter HttpMethodBase.canResponseHaveBody(int)");
2218:
2219:                boolean result = true;
2220:
2221:                if ((status >= 100 && status <= 199) || (status == 204)
2222:                        || (status == 304)) { // NOT MODIFIED
2223:                    result = false;
2224:                }
2225:
2226:                return result;
2227:            }
2228:
2229:            /**
2230:             * Returns proxy authentication realm, if it has been used during authentication process. 
2231:             * Otherwise returns <tt>null</tt>.
2232:             * 
2233:             * @return proxy authentication realm
2234:             * 
2235:             * @deprecated use #getProxyAuthState()
2236:             */
2237:            public String getProxyAuthenticationRealm() {
2238:                return this .proxyAuthState.getRealm();
2239:            }
2240:
2241:            /**
2242:             * Returns authentication realm, if it has been used during authentication process. 
2243:             * Otherwise returns <tt>null</tt>.
2244:             * 
2245:             * @return authentication realm
2246:             * 
2247:             * @deprecated use #getHostAuthState()
2248:             */
2249:            public String getAuthenticationRealm() {
2250:                return this .hostAuthState.getRealm();
2251:            }
2252:
2253:            /**
2254:             * Returns the character set from the <tt>Content-Type</tt> header.
2255:             * 
2256:             * @param contentheader The content header.
2257:             * @return String The character set.
2258:             */
2259:            protected String getContentCharSet(Header contentheader) {
2260:                LOG.trace("enter getContentCharSet( Header contentheader )");
2261:                String charset = null;
2262:                if (contentheader != null) {
2263:                    HeaderElement values[] = contentheader.getElements();
2264:                    // I expect only one header element to be there
2265:                    // No more. no less
2266:                    if (values.length == 1) {
2267:                        NameValuePair param = values[0]
2268:                                .getParameterByName("charset");
2269:                        if (param != null) {
2270:                            // If I get anything "funny" 
2271:                            // UnsupportedEncondingException will result
2272:                            charset = param.getValue();
2273:                        }
2274:                    }
2275:                }
2276:                if (charset == null) {
2277:                    charset = getParams().getContentCharset();
2278:                    if (LOG.isDebugEnabled()) {
2279:                        LOG.debug("Default charset used: " + charset);
2280:                    }
2281:                }
2282:                return charset;
2283:            }
2284:
2285:            /**
2286:             * Returns the character encoding of the request from the <tt>Content-Type</tt> header.
2287:             * 
2288:             * @return String The character set.
2289:             */
2290:            public String getRequestCharSet() {
2291:                return getContentCharSet(getRequestHeader("Content-Type"));
2292:            }
2293:
2294:            /**  
2295:             * Returns the character encoding of the response from the <tt>Content-Type</tt> header.
2296:             * 
2297:             * @return String The character set.
2298:             */
2299:            public String getResponseCharSet() {
2300:                return getContentCharSet(getResponseHeader("Content-Type"));
2301:            }
2302:
2303:            /**
2304:             * @deprecated no longer used
2305:             * 
2306:             * Returns the number of "recoverable" exceptions thrown and handled, to
2307:             * allow for monitoring the quality of the connection.
2308:             *
2309:             * @return The number of recoverable exceptions handled by the method.
2310:             */
2311:            public int getRecoverableExceptionCount() {
2312:                return recoverableExceptionCount;
2313:            }
2314:
2315:            /**
2316:             * A response has been consumed.
2317:             *
2318:             * <p>The default behavior for this class is to check to see if the connection
2319:             * should be closed, and close if need be, and to ensure that the connection
2320:             * is returned to the connection manager - if and only if we are not still
2321:             * inside the execute call.</p>
2322:             *
2323:             */
2324:            protected void responseBodyConsumed() {
2325:
2326:                // make sure this is the initial invocation of the notification,
2327:                // ignore subsequent ones.
2328:                responseStream = null;
2329:                if (responseConnection != null) {
2330:                    responseConnection.setLastResponseInputStream(null);
2331:
2332:                    // At this point, no response data should be available.
2333:                    // If there is data available, regard the connection as being
2334:                    // unreliable and close it.
2335:
2336:                    if (shouldCloseConnection(responseConnection)) {
2337:                        responseConnection.close();
2338:                    } else {
2339:                        try {
2340:                            if (responseConnection.isResponseAvailable()) {
2341:                                boolean logExtraInput = getParams()
2342:                                        .isParameterTrue(
2343:                                                HttpMethodParams.WARN_EXTRA_INPUT);
2344:
2345:                                if (logExtraInput) {
2346:                                    LOG
2347:                                            .warn("Extra response data detected - closing connection");
2348:                                }
2349:                                responseConnection.close();
2350:                            }
2351:                        } catch (IOException e) {
2352:                            LOG.warn(e.getMessage());
2353:                            responseConnection.close();
2354:                        }
2355:                    }
2356:                }
2357:                this .connectionCloseForced = false;
2358:                ensureConnectionRelease();
2359:            }
2360:
2361:            /**
2362:             * Insure that the connection is released back to the pool.
2363:             */
2364:            private void ensureConnectionRelease() {
2365:                if (responseConnection != null) {
2366:                    responseConnection.releaseConnection();
2367:                    responseConnection = null;
2368:                }
2369:            }
2370:
2371:            /**
2372:             * Returns the {@link HostConfiguration host configuration}.
2373:             * 
2374:             * @return the host configuration
2375:             * 
2376:             * @deprecated no longer applicable
2377:             */
2378:            public HostConfiguration getHostConfiguration() {
2379:                HostConfiguration hostconfig = new HostConfiguration();
2380:                hostconfig.setHost(this .httphost);
2381:                return hostconfig;
2382:            }
2383:
2384:            /**
2385:             * Sets the {@link HostConfiguration host configuration}.
2386:             * 
2387:             * @param hostconfig The hostConfiguration to set
2388:             * 
2389:             * @deprecated no longer applicable
2390:             */
2391:            public void setHostConfiguration(final HostConfiguration hostconfig) {
2392:                if (hostconfig != null) {
2393:                    this .httphost = new HttpHost(hostconfig.getHost(),
2394:                            hostconfig.getPort(), hostconfig.getProtocol());
2395:                } else {
2396:                    this .httphost = null;
2397:                }
2398:            }
2399:
2400:            /**
2401:             * Returns the {@link MethodRetryHandler retry handler} for this HTTP method
2402:             * 
2403:             * @return the methodRetryHandler
2404:             * 
2405:             * @deprecated use {@link HttpMethodParams}
2406:             */
2407:            public MethodRetryHandler getMethodRetryHandler() {
2408:                return methodRetryHandler;
2409:            }
2410:
2411:            /**
2412:             * Sets the {@link MethodRetryHandler retry handler} for this HTTP method
2413:             * 
2414:             * @param handler the methodRetryHandler to use when this method executed
2415:             * 
2416:             * @deprecated use {@link HttpMethodParams}
2417:             */
2418:            public void setMethodRetryHandler(MethodRetryHandler handler) {
2419:                methodRetryHandler = handler;
2420:            }
2421:
2422:            /**
2423:             * This method is a dirty hack intended to work around 
2424:             * current (2.0) design flaw that prevents the user from
2425:             * obtaining correct status code, headers and response body from the 
2426:             * preceding HTTP CONNECT method.
2427:             * 
2428:             * TODO: Remove this crap as soon as possible
2429:             */
2430:            void fakeResponse(StatusLine statusline,
2431:                    HeaderGroup responseheaders, InputStream responseStream) {
2432:                // set used so that the response can be read
2433:                this .used = true;
2434:                this .statusLine = statusline;
2435:                this .responseHeaders = responseheaders;
2436:                this .responseBody = null;
2437:                this .responseStream = responseStream;
2438:            }
2439:
2440:            /**
2441:             * Returns the target host {@link AuthState authentication state}
2442:             * 
2443:             * @return host authentication state
2444:             * 
2445:             * @since 3.0
2446:             */
2447:            public AuthState getHostAuthState() {
2448:                return this .hostAuthState;
2449:            }
2450:
2451:            /**
2452:             * Returns the proxy {@link AuthState authentication state}
2453:             * 
2454:             * @return host authentication state
2455:             * 
2456:             * @since 3.0
2457:             */
2458:            public AuthState getProxyAuthState() {
2459:                return this .proxyAuthState;
2460:            }
2461:
2462:            /**
2463:             * Tests whether the execution of this method has been aborted
2464:             * 
2465:             * @return <tt>true</tt> if the execution of this method has been aborted,
2466:             *  <tt>false</tt> otherwise
2467:             * 
2468:             * @since 3.0
2469:             */
2470:            public boolean isAborted() {
2471:                return this .aborted;
2472:            }
2473:
2474:            /**
2475:             * Returns <tt>true</tt> if the HTTP has been transmitted to the target
2476:             * server in its entirety, <tt>false</tt> otherwise. This flag can be useful 
2477:             * for recovery logic. If the request has not been transmitted in its entirety,
2478:             * it is safe to retry the failed method.
2479:             * 
2480:             * @return <tt>true</tt> if the request has been sent, <tt>false</tt> otherwise
2481:             */
2482:            public boolean isRequestSent() {
2483:                return this.requestSent;
2484:            }
2485:
2486:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.