Source Code Cross Referenced for HttpURLConnection.java in  » 6.0-JDK-Modules-sun » net » sun » net » www » protocol » http » 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 » 6.0 JDK Modules sun » net » sun.net.www.protocol.http 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 1995-2007 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package sun.net.www.protocol.http;
0027:
0028:        import java.net.URL;
0029:        import java.net.URLConnection;
0030:        import java.net.ProtocolException;
0031:        import java.net.HttpRetryException;
0032:        import java.net.PasswordAuthentication;
0033:        import java.net.Authenticator;
0034:        import java.net.InetAddress;
0035:        import java.net.UnknownHostException;
0036:        import java.net.SocketTimeoutException;
0037:        import java.net.Proxy;
0038:        import java.net.ProxySelector;
0039:        import java.net.URI;
0040:        import java.net.InetSocketAddress;
0041:        import java.net.CookieHandler;
0042:        import java.net.ResponseCache;
0043:        import java.net.CacheResponse;
0044:        import java.net.SecureCacheResponse;
0045:        import java.net.CacheRequest;
0046:        import java.net.Authenticator.RequestorType;
0047:        import java.io.*;
0048:        import java.util.Date;
0049:        import java.util.Map;
0050:        import java.util.List;
0051:        import java.util.Locale;
0052:        import java.util.StringTokenizer;
0053:        import java.util.Iterator;
0054:        import java.util.Set;
0055:        import java.util.logging.Level;
0056:        import java.util.logging.Logger;
0057:        import sun.net.*;
0058:        import sun.net.www.*;
0059:        import sun.net.www.http.HttpClient;
0060:        import sun.net.www.http.PosterOutputStream;
0061:        import sun.net.www.http.ChunkedInputStream;
0062:        import sun.net.www.http.ChunkedOutputStream;
0063:        import java.text.SimpleDateFormat;
0064:        import java.util.TimeZone;
0065:        import java.net.MalformedURLException;
0066:        import java.nio.ByteBuffer;
0067:        import java.nio.channels.ReadableByteChannel;
0068:        import java.nio.channels.WritableByteChannel;
0069:        import java.nio.channels.Selector;
0070:        import java.nio.channels.SelectionKey;
0071:        import java.nio.channels.SelectableChannel;
0072:        import java.lang.reflect.*;
0073:
0074:        /**
0075:         * A class to represent an HTTP connection to a remote object.
0076:         */
0077:
0078:        public class HttpURLConnection extends java.net.HttpURLConnection {
0079:
0080:            private static Logger logger = Logger
0081:                    .getLogger("sun.net.www.protocol.http.HttpURLConnection");
0082:
0083:            static final String version;
0084:            public static final String userAgent;
0085:
0086:            /* max # of allowed re-directs */
0087:            static final int defaultmaxRedirects = 20;
0088:            static final int maxRedirects;
0089:
0090:            /* Not all servers support the (Proxy)-Authentication-Info headers.
0091:             * By default, we don't require them to be sent
0092:             */
0093:            static final boolean validateProxy;
0094:            static final boolean validateServer;
0095:
0096:            private StreamingOutputStream strOutputStream;
0097:            private final static String RETRY_MSG1 = "cannot retry due to proxy authentication, in streaming mode";
0098:            private final static String RETRY_MSG2 = "cannot retry due to server authentication, in streaming mode";
0099:            private final static String RETRY_MSG3 = "cannot retry due to redirection, in streaming mode";
0100:
0101:            /*
0102:             * System properties related to error stream handling:
0103:             *
0104:             * sun.net.http.errorstream.enableBuffering = <boolean>
0105:             *
0106:             * With the above system property set to true (default is false),
0107:             * when the response code is >=400, the HTTP handler will try to
0108:             * buffer the response body (up to a certain amount and within a
0109:             * time limit). Thus freeing up the underlying socket connection
0110:             * for reuse. The rationale behind this is that usually when the
0111:             * server responds with a >=400 error (client error or server
0112:             * error, such as 404 file not found), the server will send a
0113:             * small response body to explain who to contact and what to do to
0114:             * recover. With this property set to true, even if the
0115:             * application doesn't call getErrorStream(), read the response
0116:             * body, and then call close(), the underlying socket connection
0117:             * can still be kept-alive and reused. The following two system
0118:             * properties provide further control to the error stream
0119:             * buffering behaviour.
0120:             *
0121:             * sun.net.http.errorstream.timeout = <int>
0122:             *     the timeout (in millisec) waiting the error stream
0123:             *     to be buffered; default is 300 ms
0124:             *
0125:             * sun.net.http.errorstream.bufferSize = <int>
0126:             *     the size (in bytes) to use for the buffering the error stream;
0127:             *     default is 4k
0128:             */
0129:
0130:            /* Should we enable buffering of error streams? */
0131:            private static boolean enableESBuffer = false;
0132:
0133:            /* timeout waiting for read for buffered error stream;
0134:             */
0135:            private static int timeout4ESBuffer = 0;
0136:
0137:            /* buffer size for buffered error stream;
0138:             */
0139:            private static int bufSize4ES = 0;
0140:
0141:            static {
0142:                maxRedirects = ((Integer) java.security.AccessController
0143:                        .doPrivileged(new sun.security.action.GetIntegerAction(
0144:                                "http.maxRedirects", defaultmaxRedirects)))
0145:                        .intValue();
0146:                version = (String) java.security.AccessController
0147:                        .doPrivileged(new sun.security.action.GetPropertyAction(
0148:                                "java.version"));
0149:                String agent = (String) java.security.AccessController
0150:                        .doPrivileged(new sun.security.action.GetPropertyAction(
0151:                                "http.agent"));
0152:                if (agent == null) {
0153:                    agent = "Java/" + version;
0154:                } else {
0155:                    agent = agent + " Java/" + version;
0156:                }
0157:                userAgent = agent;
0158:                validateProxy = ((Boolean) java.security.AccessController
0159:                        .doPrivileged(new sun.security.action.GetBooleanAction(
0160:                                "http.auth.digest.validateProxy")))
0161:                        .booleanValue();
0162:                validateServer = ((Boolean) java.security.AccessController
0163:                        .doPrivileged(new sun.security.action.GetBooleanAction(
0164:                                "http.auth.digest.validateServer")))
0165:                        .booleanValue();
0166:
0167:                enableESBuffer = ((Boolean) java.security.AccessController
0168:                        .doPrivileged(new sun.security.action.GetBooleanAction(
0169:                                "sun.net.http.errorstream.enableBuffering")))
0170:                        .booleanValue();
0171:                timeout4ESBuffer = ((Integer) java.security.AccessController
0172:                        .doPrivileged(new sun.security.action.GetIntegerAction(
0173:                                "sun.net.http.errorstream.timeout", 300)))
0174:                        .intValue();
0175:                if (timeout4ESBuffer <= 0) {
0176:                    timeout4ESBuffer = 300; // use the default
0177:                }
0178:
0179:                bufSize4ES = ((Integer) java.security.AccessController
0180:                        .doPrivileged(new sun.security.action.GetIntegerAction(
0181:                                "sun.net.http.errorstream.bufferSize", 4096)))
0182:                        .intValue();
0183:                if (bufSize4ES <= 0) {
0184:                    bufSize4ES = 4096; // use the default
0185:                }
0186:
0187:            }
0188:
0189:            static final String httpVersion = "HTTP/1.1";
0190:            static final String acceptString = "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
0191:
0192:            // the following http request headers should NOT have their values
0193:            // returned for security reasons.
0194:            private static final String[] EXCLUDE_HEADERS = {
0195:                    "Proxy-Authorization", "Authorization" };
0196:            protected HttpClient http;
0197:            protected Handler handler;
0198:            protected Proxy instProxy;
0199:
0200:            private CookieHandler cookieHandler;
0201:            private ResponseCache cacheHandler;
0202:
0203:            // the cached response, and cached response headers and body
0204:            protected CacheResponse cachedResponse;
0205:            private MessageHeader cachedHeaders;
0206:            private InputStream cachedInputStream;
0207:
0208:            /* output stream to server */
0209:            protected PrintStream ps = null;
0210:
0211:            /* buffered error stream */
0212:            private InputStream errorStream = null;
0213:
0214:            /* User set Cookies */
0215:            private boolean setUserCookies = true;
0216:            private String userCookies = null;
0217:
0218:            /* We only have a single static authenticator for now.
0219:             * REMIND:  backwards compatibility with JDK 1.1.  Should be
0220:             * eliminated for JDK 2.0.
0221:             */
0222:            private static HttpAuthenticator defaultAuth;
0223:
0224:            /* all the headers we send 
0225:             * NOTE: do *NOT* dump out the content of 'requests' in the 
0226:             * output or stacktrace since it may contain security-sensitive 
0227:             * headers such as those defined in EXCLUDE_HEADERS.
0228:             */
0229:            private MessageHeader requests;
0230:
0231:            /* The following two fields are only used with Digest Authentication */
0232:            String domain; /* The list of authentication domains */
0233:            DigestAuthentication.Parameters digestparams;
0234:
0235:            /* Current credentials in use */
0236:            AuthenticationInfo currentProxyCredentials = null;
0237:            AuthenticationInfo currentServerCredentials = null;
0238:            boolean needToCheck = true;
0239:            private boolean doingNTLM2ndStage = false; /* doing the 2nd stage of an NTLM server authentication */
0240:            private boolean doingNTLMp2ndStage = false; /* doing the 2nd stage of an NTLM proxy authentication */
0241:            /* try auth without calling Authenticator */
0242:            private boolean tryTransparentNTLMServer = NTLMAuthentication
0243:                    .supportsTransparentAuth();
0244:            private boolean tryTransparentNTLMProxy = NTLMAuthentication
0245:                    .supportsTransparentAuth();
0246:            Object authObj;
0247:
0248:            /* Set if the user is manually setting the Authorization or Proxy-Authorization headers */
0249:            boolean isUserServerAuth;
0250:            boolean isUserProxyAuth;
0251:
0252:            /* Progress source */
0253:            protected ProgressSource pi;
0254:
0255:            /* all the response headers we get back */
0256:            private MessageHeader responses;
0257:            /* the stream _from_ the server */
0258:            private InputStream inputStream = null;
0259:            /* post stream _to_ the server, if any */
0260:            private PosterOutputStream poster = null;
0261:
0262:            /* Indicates if the std. request headers have been set in requests. */
0263:            private boolean setRequests = false;
0264:
0265:            /* Indicates whether a request has already failed or not */
0266:            private boolean failedOnce = false;
0267:
0268:            /* Remembered Exception, we will throw it again if somebody
0269:               calls getInputStream after disconnect */
0270:            private Exception rememberedException = null;
0271:
0272:            /* If we decide we want to reuse a client, we put it here */
0273:            private HttpClient reuseClient = null;
0274:
0275:            /* Redefine timeouts from java.net.URLConnection as we nee -1 to mean
0276:             * not set. This is to ensure backward compatibility.
0277:             */
0278:            private int connectTimeout = -1;
0279:            private int readTimeout = -1;
0280:
0281:            /*
0282:             * privileged request password authentication 
0283:             *
0284:             */
0285:            private static PasswordAuthentication privilegedRequestPasswordAuthentication(
0286:                    final String host, final InetAddress addr, final int port,
0287:                    final String protocol, final String prompt,
0288:                    final String scheme, final URL url,
0289:                    final RequestorType authType) {
0290:                return (PasswordAuthentication) java.security.AccessController
0291:                        .doPrivileged(new java.security.PrivilegedAction() {
0292:                            public Object run() {
0293:                                return Authenticator
0294:                                        .requestPasswordAuthentication(host,
0295:                                                addr, port, protocol, prompt,
0296:                                                scheme, url, authType);
0297:                            }
0298:                        });
0299:            }
0300:
0301:            /* 
0302:             * checks the validity of http message header and throws 
0303:             * IllegalArgumentException if invalid.
0304:             */
0305:            private void checkMessageHeader(String key, String value) {
0306:                char LF = '\n';
0307:                int index = key.indexOf(LF);
0308:                if (index != -1) {
0309:                    throw new IllegalArgumentException(
0310:                            "Illegal character(s) in message header field: "
0311:                                    + key);
0312:                } else {
0313:                    if (value == null) {
0314:                        return;
0315:                    }
0316:
0317:                    index = value.indexOf(LF);
0318:                    while (index != -1) {
0319:                        index++;
0320:                        if (index < value.length()) {
0321:                            char c = value.charAt(index);
0322:                            if ((c == ' ') || (c == '\t')) {
0323:                                // ok, check the next occurrence
0324:                                index = value.indexOf(LF, index);
0325:                                continue;
0326:                            }
0327:                        }
0328:                        throw new IllegalArgumentException(
0329:                                "Illegal character(s) in message header value: "
0330:                                        + value);
0331:                    }
0332:                }
0333:            }
0334:
0335:            /* adds the standard key/val pairs to reqests if necessary & write to
0336:             * given PrintStream
0337:             */
0338:            private void writeRequests() throws IOException {
0339:                /* print all message headers in the MessageHeader 
0340:                 * onto the wire - all the ones we've set and any
0341:                 * others that have been set
0342:                 */
0343:                // send any pre-emptive authentication
0344:                if (http.usingProxy) {
0345:                    setPreemptiveProxyAuthentication(requests);
0346:                }
0347:                if (!setRequests) {
0348:
0349:                    /* We're very particular about the order in which we
0350:                     * set the request headers here.  The order should not
0351:                     * matter, but some careless CGI programs have been
0352:                     * written to expect a very particular order of the
0353:                     * standard headers.  To name names, the order in which
0354:                     * Navigator3.0 sends them.  In particular, we make *sure*
0355:                     * to send Content-type: <> and Content-length:<> second
0356:                     * to last and last, respectively, in the case of a POST
0357:                     * request.
0358:                     */
0359:                    if (!failedOnce)
0360:                        requests.prepend(method + " " + http.getURLFile() + " "
0361:                                + httpVersion, null);
0362:                    if (!getUseCaches()) {
0363:                        requests.setIfNotSet("Cache-Control", "no-cache");
0364:                        requests.setIfNotSet("Pragma", "no-cache");
0365:                    }
0366:                    requests.setIfNotSet("User-Agent", userAgent);
0367:                    int port = url.getPort();
0368:                    String host = url.getHost();
0369:                    if (port != -1 && port != url.getDefaultPort()) {
0370:                        host += ":" + String.valueOf(port);
0371:                    }
0372:                    requests.setIfNotSet("Host", host);
0373:                    requests.setIfNotSet("Accept", acceptString);
0374:
0375:                    /*
0376:                     * For HTTP/1.1 the default behavior is to keep connections alive.
0377:                     * However, we may be talking to a 1.0 server so we should set
0378:                     * keep-alive just in case, except if we have encountered an error
0379:                     * or if keep alive is disabled via a system property
0380:                     */
0381:
0382:                    // Try keep-alive only on first attempt
0383:                    if (!failedOnce && http.getHttpKeepAliveSet()) {
0384:                        if (http.usingProxy) {
0385:                            requests.setIfNotSet("Proxy-Connection",
0386:                                    "keep-alive");
0387:                        } else {
0388:                            requests.setIfNotSet("Connection", "keep-alive");
0389:                        }
0390:                    } else {
0391:                        /*
0392:                         * RFC 2616 HTTP/1.1 section 14.10 says:
0393:                         * HTTP/1.1 applications that do not support persistent
0394:                         * connections MUST include the "close" connection option
0395:                         * in every message
0396:                         */
0397:                        requests.setIfNotSet("Connection", "close");
0398:                    }
0399:                    // Set modified since if necessary
0400:                    long modTime = getIfModifiedSince();
0401:                    if (modTime != 0) {
0402:                        Date date = new Date(modTime);
0403:                        //use the preferred date format according to RFC 2068(HTTP1.1),
0404:                        // RFC 822 and RFC 1123
0405:                        SimpleDateFormat fo = new SimpleDateFormat(
0406:                                "EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
0407:                        fo.setTimeZone(TimeZone.getTimeZone("GMT"));
0408:                        requests.setIfNotSet("If-Modified-Since", fo
0409:                                .format(date));
0410:                    }
0411:                    // check for preemptive authorization
0412:                    AuthenticationInfo sauth = AuthenticationInfo
0413:                            .getServerAuth(url);
0414:                    if (sauth != null
0415:                            && sauth.supportsPreemptiveAuthorization()) {
0416:                        // Sets "Authorization"
0417:                        requests.setIfNotSet(sauth.getHeaderName(), sauth
0418:                                .getHeaderValue(url, method));
0419:                        currentServerCredentials = sauth;
0420:                    }
0421:
0422:                    if (!method.equals("PUT")
0423:                            && (poster != null || streaming())) {
0424:                        requests.setIfNotSet("Content-type",
0425:                                "application/x-www-form-urlencoded");
0426:                    }
0427:
0428:                    if (streaming()) {
0429:                        if (chunkLength != -1) {
0430:                            requests.set("Transfer-Encoding", "chunked");
0431:                        } else {
0432:                            requests.set("Content-Length", String
0433:                                    .valueOf(fixedContentLength));
0434:                        }
0435:                    } else if (poster != null) {
0436:                        /* add Content-Length & POST/PUT data */
0437:                        synchronized (poster) {
0438:                            /* close it, so no more data can be added */
0439:                            poster.close();
0440:                            requests.set("Content-Length", String
0441:                                    .valueOf(poster.size()));
0442:                        }
0443:                    }
0444:
0445:                    // get applicable cookies based on the uri and request headers
0446:                    // add them to the existing request headers
0447:                    setCookieHeader();
0448:
0449:                    setRequests = true;
0450:                }
0451:                if (logger.isLoggable(Level.FINEST)) {
0452:                    logger.fine(requests.toString());
0453:                }
0454:                http.writeRequests(requests, poster);
0455:                if (ps.checkError()) {
0456:                    String proxyHost = http.getProxyHostUsed();
0457:                    int proxyPort = http.getProxyPortUsed();
0458:                    disconnectInternal();
0459:                    if (failedOnce) {
0460:                        throw new IOException("Error writing to server");
0461:                    } else { // try once more
0462:                        failedOnce = true;
0463:                        if (proxyHost != null) {
0464:                            setProxiedClient(url, proxyHost, proxyPort);
0465:                        } else {
0466:                            setNewClient(url);
0467:                        }
0468:                        ps = (PrintStream) http.getOutputStream();
0469:                        connected = true;
0470:                        responses = new MessageHeader();
0471:                        setRequests = false;
0472:                        writeRequests();
0473:                    }
0474:                }
0475:            }
0476:
0477:            /**
0478:             * Create a new HttpClient object, bypassing the cache of
0479:             * HTTP client objects/connections.
0480:             *
0481:             * @param url	the URL being accessed
0482:             */
0483:            protected void setNewClient(URL url) throws IOException {
0484:                setNewClient(url, false);
0485:            }
0486:
0487:            /**
0488:             * Obtain a HttpsClient object. Use the cached copy if specified. 
0489:             *
0490:             * @param url       the URL being accessed
0491:             * @param useCache  whether the cached connection should be used
0492:             *        if present
0493:             */
0494:            protected void setNewClient(URL url, boolean useCache)
0495:                    throws IOException {
0496:                http = HttpClient.New(url, null, -1, useCache, connectTimeout);
0497:                http.setReadTimeout(readTimeout);
0498:            }
0499:
0500:            /**
0501:             * Create a new HttpClient object, set up so that it uses
0502:             * per-instance proxying to the given HTTP proxy.  This
0503:             * bypasses the cache of HTTP client objects/connections.
0504:             *
0505:             * @param url	the URL being accessed
0506:             * @param proxyHost	the proxy host to use
0507:             * @param proxyPort	the proxy port to use
0508:             */
0509:            protected void setProxiedClient(URL url, String proxyHost,
0510:                    int proxyPort) throws IOException {
0511:                setProxiedClient(url, proxyHost, proxyPort, false);
0512:            }
0513:
0514:            /**
0515:             * Obtain a HttpClient object, set up so that it uses per-instance
0516:             * proxying to the given HTTP proxy. Use the cached copy of HTTP
0517:             * client objects/connections if specified.
0518:             *
0519:             * @param url       the URL being accessed
0520:             * @param proxyHost the proxy host to use
0521:             * @param proxyPort the proxy port to use
0522:             * @param useCache  whether the cached connection should be used
0523:             *        if present
0524:             */
0525:            protected void setProxiedClient(URL url, String proxyHost,
0526:                    int proxyPort, boolean useCache) throws IOException {
0527:                proxiedConnect(url, proxyHost, proxyPort, useCache);
0528:            }
0529:
0530:            protected void proxiedConnect(URL url, String proxyHost,
0531:                    int proxyPort, boolean useCache) throws IOException {
0532:                http = HttpClient.New(url, proxyHost, proxyPort, useCache,
0533:                        connectTimeout);
0534:                http.setReadTimeout(readTimeout);
0535:            }
0536:
0537:            protected HttpURLConnection(URL u, Handler handler)
0538:                    throws IOException {
0539:                // we set proxy == null to distinguish this case with the case
0540:                // when per connection proxy is set
0541:                this (u, null, handler);
0542:            }
0543:
0544:            public HttpURLConnection(URL u, String host, int port) {
0545:                this (u, new Proxy(Proxy.Type.HTTP, InetSocketAddress
0546:                        .createUnresolved(host, port)));
0547:            }
0548:
0549:            /** this constructor is used by other protocol handlers such as ftp
0550:                that want to use http to fetch urls on their behalf.*/
0551:            public HttpURLConnection(URL u, Proxy p) {
0552:                this (u, p, new Handler());
0553:            }
0554:
0555:            protected HttpURLConnection(URL u, Proxy p, Handler handler) {
0556:                super (u);
0557:                requests = new MessageHeader();
0558:                responses = new MessageHeader();
0559:                this .handler = handler;
0560:                instProxy = p;
0561:                cookieHandler = (CookieHandler) java.security.AccessController
0562:                        .doPrivileged(new java.security.PrivilegedAction() {
0563:                            public Object run() {
0564:                                return CookieHandler.getDefault();
0565:                            }
0566:                        });
0567:                cacheHandler = (ResponseCache) java.security.AccessController
0568:                        .doPrivileged(new java.security.PrivilegedAction() {
0569:                            public Object run() {
0570:                                return ResponseCache.getDefault();
0571:                            }
0572:                        });
0573:            }
0574:
0575:            /** 
0576:             * @deprecated.  Use java.net.Authenticator.setDefault() instead.
0577:             */
0578:            public static void setDefaultAuthenticator(HttpAuthenticator a) {
0579:                defaultAuth = a;
0580:            }
0581:
0582:            /**
0583:             * opens a stream allowing redirects only to the same host.
0584:             */
0585:            public static InputStream openConnectionCheckRedirects(
0586:                    URLConnection c) throws IOException {
0587:                boolean redir;
0588:                int redirects = 0;
0589:                InputStream in = null;
0590:
0591:                do {
0592:                    if (c instanceof  HttpURLConnection) {
0593:                        ((HttpURLConnection) c)
0594:                                .setInstanceFollowRedirects(false);
0595:                    }
0596:
0597:                    // We want to open the input stream before
0598:                    // getting headers, because getHeaderField()
0599:                    // et al swallow IOExceptions.
0600:                    in = c.getInputStream();
0601:                    redir = false;
0602:
0603:                    if (c instanceof  HttpURLConnection) {
0604:                        HttpURLConnection http = (HttpURLConnection) c;
0605:                        int stat = http.getResponseCode();
0606:                        if (stat >= 300 && stat <= 307 && stat != 306
0607:                                && stat != HttpURLConnection.HTTP_NOT_MODIFIED) {
0608:                            URL base = http.getURL();
0609:                            String loc = http.getHeaderField("Location");
0610:                            URL target = null;
0611:                            if (loc != null) {
0612:                                target = new URL(base, loc);
0613:                            }
0614:                            http.disconnect();
0615:                            if (target == null
0616:                                    || !base.getProtocol().equals(
0617:                                            target.getProtocol())
0618:                                    || base.getPort() != target.getPort()
0619:                                    || !hostsEqual(base, target)
0620:                                    || redirects >= 5) {
0621:                                throw new SecurityException(
0622:                                        "illegal URL redirect");
0623:                            }
0624:                            redir = true;
0625:                            c = target.openConnection();
0626:                            redirects++;
0627:                        }
0628:                    }
0629:                } while (redir);
0630:                return in;
0631:            }
0632:
0633:            //
0634:            // Same as java.net.URL.hostsEqual
0635:            //
0636:            private static boolean hostsEqual(URL u1, URL u2) {
0637:                final String h1 = u1.getHost();
0638:                final String h2 = u2.getHost();
0639:
0640:                if (h1 == null) {
0641:                    return h2 == null;
0642:                } else if (h2 == null) {
0643:                    return false;
0644:                } else if (h1.equalsIgnoreCase(h2)) {
0645:                    return true;
0646:                }
0647:                // Have to resolve addresses before comparing, otherwise
0648:                // names like tachyon and tachyon.eng would compare different
0649:                final boolean result[] = { false };
0650:
0651:                java.security.AccessController
0652:                        .doPrivileged(new java.security.PrivilegedAction() {
0653:                            public Object run() {
0654:                                try {
0655:                                    InetAddress a1 = InetAddress.getByName(h1);
0656:                                    InetAddress a2 = InetAddress.getByName(h2);
0657:                                    result[0] = a1.equals(a2);
0658:                                } catch (UnknownHostException e) {
0659:                                } catch (SecurityException e) {
0660:                                }
0661:                                return null;
0662:                            }
0663:                        });
0664:
0665:                return result[0];
0666:            }
0667:
0668:            // overridden in HTTPS subclass
0669:
0670:            public void connect() throws IOException {
0671:                plainConnect();
0672:            }
0673:
0674:            private boolean checkReuseConnection() {
0675:                if (connected) {
0676:                    return true;
0677:                }
0678:                if (reuseClient != null) {
0679:                    http = reuseClient;
0680:                    http.setReadTimeout(getReadTimeout());
0681:                    http.reuse = false;
0682:                    reuseClient = null;
0683:                    connected = true;
0684:                    return true;
0685:                }
0686:                return false;
0687:            }
0688:
0689:            protected void plainConnect() throws IOException {
0690:                if (connected) {
0691:                    return;
0692:                }
0693:                // try to see if request can be served from local cache
0694:                if (cacheHandler != null && getUseCaches()) {
0695:                    try {
0696:                        URI uri = ParseUtil.toURI(url);
0697:                        if (uri != null) {
0698:                            cachedResponse = cacheHandler.get(uri,
0699:                                    getRequestMethod(), requests
0700:                                            .getHeaders(EXCLUDE_HEADERS));
0701:                            if ("https".equalsIgnoreCase(uri.getScheme())
0702:                                    && !(cachedResponse instanceof  SecureCacheResponse)) {
0703:                                cachedResponse = null;
0704:                            }
0705:                            if (cachedResponse != null) {
0706:                                cachedHeaders = mapToMessageHeader(cachedResponse
0707:                                        .getHeaders());
0708:                                cachedInputStream = cachedResponse.getBody();
0709:                            }
0710:                        }
0711:                    } catch (IOException ioex) {
0712:                        // ignore and commence normal connection
0713:                    }
0714:                    if (cachedHeaders != null && cachedInputStream != null) {
0715:                        connected = true;
0716:                        return;
0717:                    } else {
0718:                        cachedResponse = null;
0719:                    }
0720:                }
0721:                try {
0722:                    /* Try to open connections using the following scheme,
0723:                     * return on the first one that's successful:
0724:                     * 1) if (instProxy != null)
0725:                     *        connect to instProxy; raise exception if failed
0726:                     * 2) else use system default ProxySelector
0727:                     * 3) is 2) fails, make direct connection
0728:                     */
0729:
0730:                    if (instProxy == null) { // no instance Proxy is set
0731:                        /**
0732:                         * Do we have to use a proxy?
0733:                         */
0734:                        ProxySelector sel = (ProxySelector) java.security.AccessController
0735:                                .doPrivileged(new java.security.PrivilegedAction() {
0736:                                    public Object run() {
0737:                                        return ProxySelector.getDefault();
0738:                                    }
0739:                                });
0740:                        Proxy p = null;
0741:                        if (sel != null) {
0742:                            URI uri = sun.net.www.ParseUtil.toURI(url);
0743:                            Iterator<Proxy> it = sel.select(uri).iterator();
0744:                            while (it.hasNext()) {
0745:                                p = it.next();
0746:                                try {
0747:                                    if (!failedOnce) {
0748:                                        http = getNewHttpClient(url, p,
0749:                                                connectTimeout);
0750:                                        http.setReadTimeout(readTimeout);
0751:                                    } else {
0752:                                        // make sure to construct new connection if first
0753:                                        // attempt failed
0754:                                        http = getNewHttpClient(url, p,
0755:                                                connectTimeout, false);
0756:                                        http.setReadTimeout(readTimeout);
0757:                                    }
0758:                                    break;
0759:                                } catch (IOException ioex) {
0760:                                    if (p != Proxy.NO_PROXY) {
0761:                                        sel.connectFailed(uri, p.address(),
0762:                                                ioex);
0763:                                        if (!it.hasNext()) {
0764:                                            // fallback to direct connection
0765:                                            http = getNewHttpClient(url, null,
0766:                                                    connectTimeout, false);
0767:                                            http.setReadTimeout(readTimeout);
0768:                                            break;
0769:                                        }
0770:                                    } else {
0771:                                        throw ioex;
0772:                                    }
0773:                                    continue;
0774:                                }
0775:                            }
0776:                        } else {
0777:                            // No proxy selector, create http client with no proxy
0778:                            if (!failedOnce) {
0779:                                http = getNewHttpClient(url, null,
0780:                                        connectTimeout);
0781:                                http.setReadTimeout(readTimeout);
0782:                            } else {
0783:                                // make sure to construct new connection if first
0784:                                // attempt failed
0785:                                http = getNewHttpClient(url, null,
0786:                                        connectTimeout, false);
0787:                                http.setReadTimeout(readTimeout);
0788:                            }
0789:                        }
0790:                    } else {
0791:                        if (!failedOnce) {
0792:                            http = getNewHttpClient(url, instProxy,
0793:                                    connectTimeout);
0794:                            http.setReadTimeout(readTimeout);
0795:                        } else {
0796:                            // make sure to construct new connection if first
0797:                            // attempt failed
0798:                            http = getNewHttpClient(url, instProxy,
0799:                                    connectTimeout, false);
0800:                            http.setReadTimeout(readTimeout);
0801:                        }
0802:                    }
0803:
0804:                    ps = (PrintStream) http.getOutputStream();
0805:                } catch (IOException e) {
0806:                    throw e;
0807:                }
0808:                // constructor to HTTP client calls openserver
0809:                connected = true;
0810:            }
0811:
0812:            // subclass HttpsClient will overwrite & return an instance of HttpsClient
0813:            protected HttpClient getNewHttpClient(URL url, Proxy p,
0814:                    int connectTimeout) throws IOException {
0815:                return HttpClient.New(url, p, connectTimeout);
0816:            }
0817:
0818:            // subclass HttpsClient will overwrite & return an instance of HttpsClient
0819:            protected HttpClient getNewHttpClient(URL url, Proxy p,
0820:                    int connectTimeout, boolean useCache) throws IOException {
0821:                return HttpClient.New(url, p, connectTimeout, useCache);
0822:            }
0823:
0824:            /*
0825:             * Allowable input/output sequences:
0826:             * [interpreted as POST/PUT]
0827:             * - get output, [write output,] get input, [read input]
0828:             * - get output, [write output]
0829:             * [interpreted as GET]
0830:             * - get input, [read input]
0831:             * Disallowed:
0832:             * - get input, [read input,] get output, [write output]
0833:             */
0834:
0835:            public synchronized OutputStream getOutputStream()
0836:                    throws IOException {
0837:
0838:                try {
0839:                    if (!doOutput) {
0840:                        throw new ProtocolException(
0841:                                "cannot write to a URLConnection"
0842:                                        + " if doOutput=false - call setDoOutput(true)");
0843:                    }
0844:
0845:                    if (method.equals("GET")) {
0846:                        method = "POST"; // Backward compatibility
0847:                    }
0848:                    if (!"POST".equals(method) && !"PUT".equals(method)
0849:                            && "http".equals(url.getProtocol())) {
0850:                        throw new ProtocolException("HTTP method " + method
0851:                                + " doesn't support output");
0852:                    }
0853:
0854:                    // if there's already an input stream open, throw an exception
0855:                    if (inputStream != null) {
0856:                        throw new ProtocolException(
0857:                                "Cannot write output after reading input.");
0858:                    }
0859:
0860:                    if (!checkReuseConnection())
0861:                        connect();
0862:
0863:                    /* REMIND: This exists to fix the HttpsURLConnection subclass.
0864:                     * Hotjava needs to run on JDK1.1FCS.  Do proper fix in subclass
0865:                     * for 1.2 and remove this.
0866:                     */
0867:
0868:                    if (streaming() && strOutputStream == null) {
0869:                        writeRequests();
0870:                    }
0871:                    ps = (PrintStream) http.getOutputStream();
0872:                    if (streaming()) {
0873:                        if (strOutputStream == null) {
0874:                            if (fixedContentLength != -1) {
0875:                                strOutputStream = new StreamingOutputStream(ps,
0876:                                        fixedContentLength);
0877:                            } else if (chunkLength != -1) {
0878:                                strOutputStream = new StreamingOutputStream(
0879:                                        new ChunkedOutputStream(ps, chunkLength),
0880:                                        -1);
0881:                            }
0882:                        }
0883:                        return strOutputStream;
0884:                    } else {
0885:                        if (poster == null) {
0886:                            poster = new PosterOutputStream();
0887:                        }
0888:                        return poster;
0889:                    }
0890:                } catch (RuntimeException e) {
0891:                    disconnectInternal();
0892:                    throw e;
0893:                } catch (IOException e) {
0894:                    disconnectInternal();
0895:                    throw e;
0896:                }
0897:            }
0898:
0899:            private boolean streaming() {
0900:                return (fixedContentLength != -1) || (chunkLength != -1);
0901:            }
0902:
0903:            /*
0904:             * get applicable cookies based on the uri and request headers
0905:             * add them to the existing request headers
0906:             */
0907:            private void setCookieHeader() throws IOException {
0908:                if (cookieHandler != null) {
0909:                    // we only want to capture the user defined Cookies once, as
0910:                    // they cannot be changed by user code after we are connected,
0911:                    // only internally.
0912:                    if (setUserCookies) {
0913:                        int k = requests.getKey("Cookie");
0914:                        if (k != -1)
0915:                            userCookies = requests.getValue(k);
0916:                        setUserCookies = false;
0917:                    }
0918:
0919:                    // remove old Cookie header before setting new one.
0920:                    requests.remove("Cookie");
0921:
0922:                    URI uri = ParseUtil.toURI(url);
0923:                    if (uri != null) {
0924:                        Map cookies = cookieHandler.get(uri, requests
0925:                                .getHeaders(EXCLUDE_HEADERS));
0926:                        if (!cookies.isEmpty()) {
0927:                            Set s = cookies.entrySet();
0928:                            Iterator k_itr = s.iterator();
0929:                            while (k_itr.hasNext()) {
0930:                                Map.Entry entry = (Map.Entry) k_itr.next();
0931:                                String key = (String) entry.getKey();
0932:                                // ignore all entries that don't have "Cookie"
0933:                                // or "Cookie2" as keys
0934:                                if (!"Cookie".equalsIgnoreCase(key)
0935:                                        && !"Cookie2".equalsIgnoreCase(key)) {
0936:                                    continue;
0937:                                }
0938:                                List l = (List) entry.getValue();
0939:                                if (l != null && !l.isEmpty()) {
0940:                                    Iterator v_itr = l.iterator();
0941:                                    StringBuilder cookieValue = new StringBuilder();
0942:                                    while (v_itr.hasNext()) {
0943:                                        String value = (String) v_itr.next();
0944:                                        cookieValue.append(value).append(';');
0945:                                    }
0946:                                    // strip off the ending ;-sign
0947:                                    try {
0948:                                        requests.add(key, cookieValue
0949:                                                .substring(0, cookieValue
0950:                                                        .length() - 1));
0951:                                    } catch (StringIndexOutOfBoundsException ignored) {
0952:                                        // no-op
0953:                                    }
0954:                                }
0955:                            }
0956:                        }
0957:                    }
0958:                    if (userCookies != null) {
0959:                        int k;
0960:                        if ((k = requests.getKey("Cookie")) != -1)
0961:                            requests.set("Cookie", requests.getValue(k) + ";"
0962:                                    + userCookies);
0963:                        else
0964:                            requests.set("Cookie", userCookies);
0965:                    }
0966:
0967:                } // end of getting cookies
0968:            }
0969:
0970:            public synchronized InputStream getInputStream() throws IOException {
0971:
0972:                if (!doInput) {
0973:                    throw new ProtocolException(
0974:                            "Cannot read from URLConnection"
0975:                                    + " if doInput=false (call setDoInput(true))");
0976:                }
0977:
0978:                if (rememberedException != null) {
0979:                    if (rememberedException instanceof  RuntimeException)
0980:                        throw new RuntimeException(rememberedException);
0981:                    else {
0982:                        throw getChainedException((IOException) rememberedException);
0983:                    }
0984:                }
0985:
0986:                if (inputStream != null) {
0987:                    return inputStream;
0988:                }
0989:
0990:                if (streaming()) {
0991:                    if (strOutputStream == null) {
0992:                        getOutputStream();
0993:                    }
0994:                    /* make sure stream is closed */
0995:                    strOutputStream.close();
0996:                    if (!strOutputStream.writtenOK()) {
0997:                        throw new IOException("Incomplete output stream");
0998:                    }
0999:                }
1000:
1001:                int redirects = 0;
1002:                int respCode = 0;
1003:                int cl = -1;
1004:                AuthenticationInfo serverAuthentication = null;
1005:                AuthenticationInfo proxyAuthentication = null;
1006:                AuthenticationHeader srvHdr = null;
1007:
1008:                // If the user has set either of these headers then do not remove them
1009:                isUserServerAuth = requests.getKey("Authorization") != -1;
1010:                isUserProxyAuth = requests.getKey("Proxy-Authorization") != -1;
1011:
1012:                try {
1013:                    do {
1014:                        if (!checkReuseConnection())
1015:                            connect();
1016:
1017:                        if (cachedInputStream != null) {
1018:                            return cachedInputStream;
1019:                        }
1020:
1021:                        // Check if URL should be metered
1022:                        boolean meteredInput = ProgressMonitor.getDefault()
1023:                                .shouldMeterInput(url, method);
1024:
1025:                        if (meteredInput) {
1026:                            pi = new ProgressSource(url, method);
1027:                            pi.beginTracking();
1028:                        }
1029:
1030:                        /* REMIND: This exists to fix the HttpsURLConnection subclass.
1031:                         * Hotjava needs to run on JDK1.1FCS.  Do proper fix once a
1032:                         * proper solution for SSL can be found.
1033:                         */
1034:                        ps = (PrintStream) http.getOutputStream();
1035:
1036:                        if (!streaming()) {
1037:                            writeRequests();
1038:                        }
1039:                        http.parseHTTP(responses, pi, this );
1040:                        if (logger.isLoggable(Level.FINEST)) {
1041:                            logger.fine(responses.toString());
1042:                        }
1043:                        inputStream = http.getInputStream();
1044:
1045:                        respCode = getResponseCode();
1046:                        if (respCode == HTTP_PROXY_AUTH) {
1047:                            if (streaming()) {
1048:                                disconnectInternal();
1049:                                throw new HttpRetryException(RETRY_MSG1,
1050:                                        HTTP_PROXY_AUTH);
1051:                            }
1052:
1053:                            // changes: add a 3rd parameter to the constructor of
1054:                            // AuthenticationHeader, so that NegotiateAuthentication.
1055:                            // isSupported can be tested.
1056:                            // The other 2 appearances of "new AuthenticationHeader" is
1057:                            // altered in similar ways.
1058:
1059:                            AuthenticationHeader authhdr = new AuthenticationHeader(
1060:                                    "Proxy-Authenticate", responses, http
1061:                                            .getProxyHostUsed());
1062:
1063:                            if (!doingNTLMp2ndStage) {
1064:                                proxyAuthentication = resetProxyAuthentication(
1065:                                        proxyAuthentication, authhdr);
1066:                                if (proxyAuthentication != null) {
1067:                                    redirects++;
1068:                                    disconnectInternal();
1069:                                    continue;
1070:                                }
1071:                            } else {
1072:                                /* in this case, only one header field will be present */
1073:                                String raw = responses
1074:                                        .findValue("Proxy-Authenticate");
1075:                                reset();
1076:                                if (!proxyAuthentication.setHeaders(this ,
1077:                                        authhdr.headerParser(), raw)) {
1078:                                    disconnectInternal();
1079:                                    throw new IOException(
1080:                                            "Authentication failure");
1081:                                }
1082:                                if (serverAuthentication != null
1083:                                        && srvHdr != null
1084:                                        && !serverAuthentication.setHeaders(
1085:                                                this , srvHdr.headerParser(),
1086:                                                raw)) {
1087:                                    disconnectInternal();
1088:                                    throw new IOException(
1089:                                            "Authentication failure");
1090:                                }
1091:                                authObj = null;
1092:                                doingNTLMp2ndStage = false;
1093:                                continue;
1094:                            }
1095:                        }
1096:
1097:                        // cache proxy authentication info
1098:                        if (proxyAuthentication != null) {
1099:                            // cache auth info on success, domain header not relevant.
1100:                            proxyAuthentication.addToCache();
1101:                        }
1102:
1103:                        if (respCode == HTTP_UNAUTHORIZED) {
1104:                            if (streaming()) {
1105:                                disconnectInternal();
1106:                                throw new HttpRetryException(RETRY_MSG2,
1107:                                        HTTP_UNAUTHORIZED);
1108:                            }
1109:
1110:                            srvHdr = new AuthenticationHeader(
1111:                                    "WWW-Authenticate", responses, url
1112:                                            .getHost().toLowerCase());
1113:
1114:                            String raw = srvHdr.raw();
1115:                            if (!doingNTLM2ndStage) {
1116:                                if ((serverAuthentication != null)
1117:                                        && !(serverAuthentication instanceof  NTLMAuthentication)) {
1118:                                    if (serverAuthentication
1119:                                            .isAuthorizationStale(raw)) {
1120:                                        /* we can retry with the current credentials */
1121:                                        disconnectInternal();
1122:                                        redirects++;
1123:                                        requests.set(serverAuthentication
1124:                                                .getHeaderName(),
1125:                                                serverAuthentication
1126:                                                        .getHeaderValue(url,
1127:                                                                method));
1128:                                        currentServerCredentials = serverAuthentication;
1129:                                        setCookieHeader();
1130:                                        continue;
1131:                                    } else {
1132:                                        serverAuthentication.removeFromCache();
1133:                                    }
1134:                                }
1135:                                serverAuthentication = getServerAuthentication(srvHdr);
1136:                                currentServerCredentials = serverAuthentication;
1137:
1138:                                if (serverAuthentication != null) {
1139:                                    disconnectInternal();
1140:                                    redirects++; // don't let things loop ad nauseum
1141:                                    setCookieHeader();
1142:                                    continue;
1143:                                }
1144:                            } else {
1145:                                reset();
1146:                                /* header not used for ntlm */
1147:                                if (!serverAuthentication.setHeaders(this ,
1148:                                        null, raw)) {
1149:                                    disconnectInternal();
1150:                                    throw new IOException(
1151:                                            "Authentication failure");
1152:                                }
1153:                                doingNTLM2ndStage = false;
1154:                                authObj = null;
1155:                                setCookieHeader();
1156:                                continue;
1157:                            }
1158:                        }
1159:                        // cache server authentication info
1160:                        if (serverAuthentication != null) {
1161:                            // cache auth info on success
1162:                            if (!(serverAuthentication instanceof  DigestAuthentication)
1163:                                    || (domain == null)) {
1164:                                if (serverAuthentication instanceof  BasicAuthentication) {
1165:                                    // check if the path is shorter than the existing entry
1166:                                    String npath = AuthenticationInfo
1167:                                            .reducePath(url.getPath());
1168:                                    String opath = serverAuthentication.path;
1169:                                    if (!opath.startsWith(npath)
1170:                                            || npath.length() >= opath.length()) {
1171:                                        /* npath is longer, there must be a common root */
1172:                                        npath = BasicAuthentication
1173:                                                .getRootPath(opath, npath);
1174:                                    }
1175:                                    // remove the entry and create a new one 
1176:                                    BasicAuthentication a = (BasicAuthentication) serverAuthentication
1177:                                            .clone();
1178:                                    serverAuthentication.removeFromCache();
1179:                                    a.path = npath;
1180:                                    serverAuthentication = a;
1181:                                }
1182:                                serverAuthentication.addToCache();
1183:                            } else {
1184:                                // what we cache is based on the domain list in the request
1185:                                DigestAuthentication srv = (DigestAuthentication) serverAuthentication;
1186:                                StringTokenizer tok = new StringTokenizer(
1187:                                        domain, " ");
1188:                                String realm = srv.realm;
1189:                                PasswordAuthentication pw = srv.pw;
1190:                                digestparams = srv.params;
1191:                                while (tok.hasMoreTokens()) {
1192:                                    String path = tok.nextToken();
1193:                                    try {
1194:                                        /* path could be an abs_path or a complete URI */
1195:                                        URL u = new URL(url, path);
1196:                                        DigestAuthentication d = new DigestAuthentication(
1197:                                                false, u, realm, "Digest", pw,
1198:                                                digestparams);
1199:                                        d.addToCache();
1200:                                    } catch (Exception e) {
1201:                                    }
1202:                                }
1203:                            }
1204:                        }
1205:
1206:                        // some flags should be reset to its initialized form so that
1207:                        // even after a redirect the necessary checks can still be
1208:                        // preformed.
1209:
1210:                        //serverAuthentication = null;
1211:                        doingNTLMp2ndStage = false;
1212:                        doingNTLM2ndStage = false;
1213:                        if (!isUserServerAuth)
1214:                            requests.remove("Authorization");
1215:                        if (!isUserProxyAuth)
1216:                            requests.remove("Proxy-Authorization");
1217:
1218:                        if (respCode == HTTP_OK) {
1219:                            checkResponseCredentials(false);
1220:                        } else {
1221:                            needToCheck = false;
1222:                        }
1223:
1224:                        // a flag need to clean
1225:                        needToCheck = true;
1226:
1227:                        if (followRedirect()) {
1228:                            /* if we should follow a redirect, then the followRedirects()
1229:                             * method will disconnect() and re-connect us to the new
1230:                             * location
1231:                             */
1232:                            redirects++;
1233:
1234:                            // redirecting HTTP response may have set cookie, so
1235:                            // need to re-generate request header
1236:                            setCookieHeader();
1237:
1238:                            continue;
1239:                        }
1240:
1241:                        try {
1242:                            cl = Integer.parseInt(responses
1243:                                    .findValue("content-length"));
1244:                        } catch (Exception exc) {
1245:                        }
1246:                        ;
1247:
1248:                        if (method.equals("HEAD") || cl == 0
1249:                                || respCode == HTTP_NOT_MODIFIED
1250:                                || respCode == HTTP_NO_CONTENT) {
1251:
1252:                            if (pi != null) {
1253:                                pi.finishTracking();
1254:                                pi = null;
1255:                            }
1256:                            http.finished();
1257:                            http = null;
1258:                            inputStream = new EmptyInputStream();
1259:                            connected = false;
1260:                        }
1261:
1262:                        if (respCode == 200 || respCode == 203
1263:                                || respCode == 206 || respCode == 300
1264:                                || respCode == 301 || respCode == 410) {
1265:                            if (cacheHandler != null) {
1266:                                // give cache a chance to save response in cache
1267:                                URI uri = ParseUtil.toURI(url);
1268:                                if (uri != null) {
1269:                                    URLConnection uconn = this ;
1270:                                    if ("https".equalsIgnoreCase(uri
1271:                                            .getScheme())) {
1272:                                        try {
1273:                                            // use reflection to get to the public
1274:                                            // HttpsURLConnection instance saved in 
1275:                                            // DelegateHttpsURLConnection
1276:                                            uconn = (URLConnection) this 
1277:                                                    .getClass()
1278:                                                    .getField(
1279:                                                            "httpsURLConnection")
1280:                                                    .get(this );
1281:                                        } catch (IllegalAccessException iae) {
1282:                                            // ignored; use 'this'
1283:                                        } catch (NoSuchFieldException nsfe) {
1284:                                            // ignored; use 'this'
1285:                                        }
1286:                                    }
1287:                                    CacheRequest cacheRequest = cacheHandler
1288:                                            .put(uri, uconn);
1289:                                    if (cacheRequest != null && http != null) {
1290:                                        http.setCacheRequest(cacheRequest);
1291:                                        inputStream = new HttpInputStream(
1292:                                                inputStream, cacheRequest);
1293:                                    }
1294:                                }
1295:                            }
1296:                        }
1297:
1298:                        if (!(inputStream instanceof  HttpInputStream)) {
1299:                            inputStream = new HttpInputStream(inputStream);
1300:                        }
1301:
1302:                        if (respCode >= 400) {
1303:                            if (respCode == 404 || respCode == 410) {
1304:                                throw new FileNotFoundException(url.toString());
1305:                            } else {
1306:                                throw new java.io.IOException(
1307:                                        "Server returned HTTP"
1308:                                                + " response code: " + respCode
1309:                                                + " for URL: " + url.toString());
1310:                            }
1311:                        }
1312:                        poster = null;
1313:                        strOutputStream = null;
1314:                        return inputStream;
1315:                    } while (redirects < maxRedirects);
1316:
1317:                    throw new ProtocolException("Server redirected too many "
1318:                            + " times (" + redirects + ")");
1319:                } catch (RuntimeException e) {
1320:                    disconnectInternal();
1321:                    rememberedException = e;
1322:                    throw e;
1323:                } catch (IOException e) {
1324:                    rememberedException = e;
1325:
1326:                    // buffer the error stream if bytes < 4k
1327:                    // and it can be buffered within 1 second
1328:                    String te = responses.findValue("Transfer-Encoding");
1329:                    if (http != null
1330:                            && http.isKeepingAlive()
1331:                            && enableESBuffer
1332:                            && (cl > 0 || (te != null && te
1333:                                    .equalsIgnoreCase("chunked")))) {
1334:                        errorStream = ErrorStream.getErrorStream(inputStream,
1335:                                cl, http);
1336:                    }
1337:                    throw e;
1338:                } finally {
1339:                    if (respCode == HTTP_PROXY_AUTH
1340:                            && proxyAuthentication != null) {
1341:                        proxyAuthentication.endAuthRequest();
1342:                    } else if (respCode == HTTP_UNAUTHORIZED
1343:                            && serverAuthentication != null) {
1344:                        serverAuthentication.endAuthRequest();
1345:                    }
1346:                }
1347:            }
1348:
1349:            /*
1350:             * Creates a chained exception that has the same type as 
1351:             * original exception and with the same message. Right now,
1352:             * there is no convenient APIs for doing so.
1353:             */
1354:            private IOException getChainedException(
1355:                    IOException rememberedException) {
1356:                try {
1357:                    final IOException originalException = rememberedException;
1358:                    final Class[] cls = new Class[1];
1359:                    cls[0] = String.class;
1360:                    final String[] args = new String[1];
1361:                    args[0] = originalException.getMessage();
1362:                    IOException chainedException = (IOException) java.security.AccessController
1363:                            .doPrivileged(new java.security.PrivilegedExceptionAction() {
1364:                                public Object run() throws Exception {
1365:                                    Constructor ctr = originalException
1366:                                            .getClass().getConstructor(cls);
1367:                                    return (IOException) ctr
1368:                                            .newInstance((Object[]) args);
1369:                                }
1370:                            });
1371:                    chainedException.initCause(originalException);
1372:                    return chainedException;
1373:                } catch (Exception ignored) {
1374:                    return (IOException) rememberedException;
1375:                }
1376:            }
1377:
1378:            public InputStream getErrorStream() {
1379:                if (connected && responseCode >= 400) {
1380:                    // Client Error 4xx and Server Error 5xx
1381:                    if (errorStream != null) {
1382:                        return errorStream;
1383:                    } else if (inputStream != null) {
1384:                        return inputStream;
1385:                    }
1386:                }
1387:                return null;
1388:            }
1389:
1390:            /**
1391:             * set or reset proxy authentication info in request headers
1392:             * after receiving a 407 error. In the case of NTLM however,
1393:             * receiving a 407 is normal and we just skip the stale check
1394:             * because ntlm does not support this feature.
1395:             */
1396:            private AuthenticationInfo resetProxyAuthentication(
1397:                    AuthenticationInfo proxyAuthentication,
1398:                    AuthenticationHeader auth) {
1399:                if ((proxyAuthentication != null)
1400:                        && !(proxyAuthentication instanceof  NTLMAuthentication)) {
1401:                    String raw = auth.raw();
1402:                    if (proxyAuthentication.isAuthorizationStale(raw)) {
1403:                        /* we can retry with the current credentials */
1404:                        requests
1405:                                .set(proxyAuthentication.getHeaderName(),
1406:                                        proxyAuthentication.getHeaderValue(url,
1407:                                                method));
1408:                        currentProxyCredentials = proxyAuthentication;
1409:                        return proxyAuthentication;
1410:                    } else {
1411:                        proxyAuthentication.removeFromCache();
1412:                    }
1413:                }
1414:                proxyAuthentication = getHttpProxyAuthentication(auth);
1415:                currentProxyCredentials = proxyAuthentication;
1416:                return proxyAuthentication;
1417:            }
1418:
1419:            /**
1420:             * establish a tunnel through proxy server
1421:             */
1422:            public synchronized void doTunneling() throws IOException {
1423:                int retryTunnel = 0;
1424:                String statusLine = "";
1425:                int respCode = 0;
1426:                AuthenticationInfo proxyAuthentication = null;
1427:                String proxyHost = null;
1428:                int proxyPort = -1;
1429:
1430:                // save current requests so that they can be restored after tunnel is setup.
1431:                MessageHeader savedRequests = requests;
1432:                requests = new MessageHeader();
1433:
1434:                try {
1435:                    do {
1436:                        if (!checkReuseConnection()) {
1437:                            proxiedConnect(url, proxyHost, proxyPort, false);
1438:                        }
1439:                        // send the "CONNECT" request to establish a tunnel
1440:                        // through proxy server
1441:                        sendCONNECTRequest();
1442:                        responses.reset();
1443:
1444:                        // There is no need to track progress in HTTP Tunneling,
1445:                        // so ProgressSource is null.
1446:                        http.parseHTTP(responses, null, this );
1447:
1448:                        statusLine = responses.getValue(0);
1449:                        StringTokenizer st = new StringTokenizer(statusLine);
1450:                        st.nextToken();
1451:                        respCode = Integer.parseInt(st.nextToken().trim());
1452:                        if (respCode == HTTP_PROXY_AUTH) {
1453:                            AuthenticationHeader authhdr = new AuthenticationHeader(
1454:                                    "Proxy-Authenticate", responses, http
1455:                                            .getProxyHostUsed());
1456:                            if (!doingNTLMp2ndStage) {
1457:                                proxyAuthentication = resetProxyAuthentication(
1458:                                        proxyAuthentication, authhdr);
1459:                                if (proxyAuthentication != null) {
1460:                                    proxyHost = http.getProxyHostUsed();
1461:                                    proxyPort = http.getProxyPortUsed();
1462:                                    disconnectInternal();
1463:                                    retryTunnel++;
1464:                                    continue;
1465:                                }
1466:                            } else {
1467:                                String raw = responses
1468:                                        .findValue("Proxy-Authenticate");
1469:                                reset();
1470:                                if (!proxyAuthentication.setHeaders(this ,
1471:                                        authhdr.headerParser(), raw)) {
1472:                                    proxyHost = http.getProxyHostUsed();
1473:                                    proxyPort = http.getProxyPortUsed();
1474:                                    disconnectInternal();
1475:                                    throw new IOException(
1476:                                            "Authentication failure");
1477:                                }
1478:                                authObj = null;
1479:                                doingNTLMp2ndStage = false;
1480:                                continue;
1481:                            }
1482:                        }
1483:                        // cache proxy authentication info
1484:                        if (proxyAuthentication != null) {
1485:                            // cache auth info on success, domain header not relevant.
1486:                            proxyAuthentication.addToCache();
1487:                        }
1488:
1489:                        if (respCode == HTTP_OK) {
1490:                            break;
1491:                        }
1492:                        // we don't know how to deal with other response code
1493:                        // so disconnect and report error
1494:                        disconnectInternal();
1495:                        break;
1496:                    } while (retryTunnel < maxRedirects);
1497:
1498:                    if (retryTunnel >= maxRedirects || (respCode != HTTP_OK)) {
1499:                        throw new IOException("Unable to tunnel through proxy."
1500:                                + " Proxy returns \"" + statusLine + "\"");
1501:                    }
1502:                } finally {
1503:                    if (respCode == HTTP_PROXY_AUTH
1504:                            && proxyAuthentication != null) {
1505:                        proxyAuthentication.endAuthRequest();
1506:                    }
1507:                }
1508:
1509:                // restore original request headers
1510:                requests = savedRequests;
1511:
1512:                // reset responses
1513:                responses.reset();
1514:            }
1515:
1516:            /**
1517:             * send a CONNECT request for establishing a tunnel to proxy server
1518:             */
1519:            private void sendCONNECTRequest() throws IOException {
1520:                int port = url.getPort();
1521:
1522:                // setRequests == true indicates the std. request headers
1523:                // have been set in (previous) requests.
1524:                // so the first one must be the http method (GET, etc.).
1525:                // we need to set it to CONNECT soon, remove this one first.
1526:                // otherwise, there may have 2 http methods in headers
1527:                if (setRequests)
1528:                    requests.set(0, null, null);
1529:
1530:                requests.prepend("CONNECT " + url.getHost() + ":"
1531:                        + (port != -1 ? port : url.getDefaultPort()) + " "
1532:                        + httpVersion, null);
1533:                requests.setIfNotSet("User-Agent", userAgent);
1534:
1535:                String host = url.getHost();
1536:                if (port != -1 && port != url.getDefaultPort()) {
1537:                    host += ":" + String.valueOf(port);
1538:                }
1539:                requests.setIfNotSet("Host", host);
1540:
1541:                // Not really necessary for a tunnel, but can't hurt
1542:                requests.setIfNotSet("Accept", acceptString);
1543:
1544:                setPreemptiveProxyAuthentication(requests);
1545:                http.writeRequests(requests, null);
1546:                // remove CONNECT header
1547:                requests.set(0, null, null);
1548:            }
1549:
1550:            /**
1551:             * Sets pre-emptive proxy authentication in header
1552:             */
1553:            private void setPreemptiveProxyAuthentication(MessageHeader requests) {
1554:                AuthenticationInfo pauth = AuthenticationInfo.getProxyAuth(http
1555:                        .getProxyHostUsed(), http.getProxyPortUsed());
1556:                if (pauth != null && pauth.supportsPreemptiveAuthorization()) {
1557:                    // Sets "Proxy-authorization"
1558:                    requests.set(pauth.getHeaderName(), pauth.getHeaderValue(
1559:                            url, method));
1560:                    currentProxyCredentials = pauth;
1561:                }
1562:            }
1563:
1564:            /**
1565:             * Gets the authentication for an HTTP proxy, and applies it to
1566:             * the connection.
1567:             */
1568:            private AuthenticationInfo getHttpProxyAuthentication(
1569:                    AuthenticationHeader authhdr) {
1570:                /* get authorization from authenticator */
1571:                AuthenticationInfo ret = null;
1572:                String raw = authhdr.raw();
1573:                String host = http.getProxyHostUsed();
1574:                int port = http.getProxyPortUsed();
1575:                if (host != null && authhdr.isPresent()) {
1576:                    HeaderParser p = authhdr.headerParser();
1577:                    String realm = p.findValue("realm");
1578:                    String scheme = authhdr.scheme();
1579:                    char schemeID;
1580:                    if ("basic".equalsIgnoreCase(scheme)) {
1581:                        schemeID = BasicAuthentication.BASIC_AUTH;
1582:                    } else if ("digest".equalsIgnoreCase(scheme)) {
1583:                        schemeID = DigestAuthentication.DIGEST_AUTH;
1584:                    } else if ("ntlm".equalsIgnoreCase(scheme)) {
1585:                        schemeID = NTLMAuthentication.NTLM_AUTH;
1586:                        doingNTLMp2ndStage = true;
1587:                    } else if ("Kerberos".equalsIgnoreCase(scheme)) {
1588:                        schemeID = NegotiateAuthentication.KERBEROS_AUTH;
1589:                        doingNTLMp2ndStage = true;
1590:                    } else if ("Negotiate".equalsIgnoreCase(scheme)) {
1591:                        schemeID = NegotiateAuthentication.NEGOTIATE_AUTH;
1592:                        doingNTLMp2ndStage = true;
1593:                    } else {
1594:                        schemeID = 0;
1595:                    }
1596:                    if (realm == null)
1597:                        realm = "";
1598:                    ret = AuthenticationInfo.getProxyAuth(host, port, realm,
1599:                            schemeID);
1600:                    if (ret == null) {
1601:                        if (schemeID == BasicAuthentication.BASIC_AUTH) {
1602:                            InetAddress addr = null;
1603:                            try {
1604:                                final String finalHost = host;
1605:                                addr = (InetAddress) java.security.AccessController
1606:                                        .doPrivileged(new java.security.PrivilegedExceptionAction() {
1607:                                            public Object run()
1608:                                                    throws java.net.UnknownHostException {
1609:                                                return InetAddress
1610:                                                        .getByName(finalHost);
1611:                                            }
1612:                                        });
1613:                            } catch (java.security.PrivilegedActionException ignored) {
1614:                                // User will have an unknown host.
1615:                            }
1616:                            PasswordAuthentication a = privilegedRequestPasswordAuthentication(
1617:                                    host, addr, port, "http", realm, scheme,
1618:                                    url, RequestorType.PROXY);
1619:                            if (a != null) {
1620:                                ret = new BasicAuthentication(true, host, port,
1621:                                        realm, a);
1622:                            }
1623:                        } else if (schemeID == DigestAuthentication.DIGEST_AUTH) {
1624:                            PasswordAuthentication a = privilegedRequestPasswordAuthentication(
1625:                                    host, null, port, url.getProtocol(), realm,
1626:                                    scheme, url, RequestorType.PROXY);
1627:                            if (a != null) {
1628:                                DigestAuthentication.Parameters params = new DigestAuthentication.Parameters();
1629:                                ret = new DigestAuthentication(true, host,
1630:                                        port, realm, scheme, a, params);
1631:                            }
1632:                        } else if (schemeID == NTLMAuthentication.NTLM_AUTH) {
1633:                            PasswordAuthentication a = null;
1634:                            if (!tryTransparentNTLMProxy) {
1635:                                a = privilegedRequestPasswordAuthentication(
1636:                                        host, null, port, url.getProtocol(),
1637:                                        "", scheme, url, RequestorType.PROXY);
1638:                            }
1639:                            /* If we are not trying transparent authentication then
1640:                             * we need to have a PasswordAuthentication instance. For
1641:                             * transparent authentication (Windows only) the username
1642:                             * and password will be picked up from the current logged
1643:                             * on users credentials.
1644:                             */
1645:                            if (tryTransparentNTLMProxy
1646:                                    || (!tryTransparentNTLMProxy && a != null)) {
1647:                                ret = new NTLMAuthentication(true, host, port,
1648:                                        a);
1649:                            }
1650:
1651:                            tryTransparentNTLMProxy = false;
1652:                        } else if (schemeID == NegotiateAuthentication.NEGOTIATE_AUTH) {
1653:                            ret = new NegotiateAuthentication(true, host, port,
1654:                                    null, "Negotiate");
1655:                        } else if (schemeID == NegotiateAuthentication.KERBEROS_AUTH) {
1656:                            ret = new NegotiateAuthentication(true, host, port,
1657:                                    null, "Kerberos");
1658:                        }
1659:                    }
1660:                    // For backwards compatibility, we also try defaultAuth
1661:                    // REMIND:  Get rid of this for JDK2.0.
1662:
1663:                    if (ret == null && defaultAuth != null
1664:                            && defaultAuth.schemeSupported(scheme)) {
1665:                        try {
1666:                            URL u = new URL("http", host, port, "/");
1667:                            String a = defaultAuth.authString(u, scheme, realm);
1668:                            if (a != null) {
1669:                                ret = new BasicAuthentication(true, host, port,
1670:                                        realm, a);
1671:                                // not in cache by default - cache on success
1672:                            }
1673:                        } catch (java.net.MalformedURLException ignored) {
1674:                        }
1675:                    }
1676:                    if (ret != null) {
1677:                        if (!ret.setHeaders(this , p, raw)) {
1678:                            ret = null;
1679:                        }
1680:                    }
1681:                }
1682:                return ret;
1683:            }
1684:
1685:            /**
1686:             * Gets the authentication for an HTTP server, and applies it to
1687:             * the connection.
1688:             * @param authHdr the AuthenticationHeader which tells what auth scheme is 
1689:             * prefered.
1690:             */
1691:            private AuthenticationInfo getServerAuthentication(
1692:                    AuthenticationHeader authhdr) {
1693:                /* get authorization from authenticator */
1694:                AuthenticationInfo ret = null;
1695:                String raw = authhdr.raw();
1696:                /* When we get an NTLM auth from cache, don't set any special headers */
1697:                if (authhdr.isPresent()) {
1698:                    HeaderParser p = authhdr.headerParser();
1699:                    String realm = p.findValue("realm");
1700:                    String scheme = authhdr.scheme();
1701:                    char schemeID;
1702:                    if ("basic".equalsIgnoreCase(scheme)) {
1703:                        schemeID = BasicAuthentication.BASIC_AUTH;
1704:                    } else if ("digest".equalsIgnoreCase(scheme)) {
1705:                        schemeID = DigestAuthentication.DIGEST_AUTH;
1706:                    } else if ("ntlm".equalsIgnoreCase(scheme)) {
1707:                        schemeID = NTLMAuthentication.NTLM_AUTH;
1708:                        doingNTLM2ndStage = true;
1709:                    } else if ("Kerberos".equalsIgnoreCase(scheme)) {
1710:                        schemeID = NegotiateAuthentication.KERBEROS_AUTH;
1711:                        doingNTLM2ndStage = true;
1712:                    } else if ("Negotiate".equalsIgnoreCase(scheme)) {
1713:                        schemeID = NegotiateAuthentication.NEGOTIATE_AUTH;
1714:                        doingNTLM2ndStage = true;
1715:                    } else {
1716:                        schemeID = 0;
1717:                    }
1718:                    domain = p.findValue("domain");
1719:                    if (realm == null)
1720:                        realm = "";
1721:                    ret = AuthenticationInfo
1722:                            .getServerAuth(url, realm, schemeID);
1723:                    InetAddress addr = null;
1724:                    if (ret == null) {
1725:                        try {
1726:                            addr = InetAddress.getByName(url.getHost());
1727:                        } catch (java.net.UnknownHostException ignored) {
1728:                            // User will have addr = null
1729:                        }
1730:                    }
1731:                    // replacing -1 with default port for a protocol
1732:                    int port = url.getPort();
1733:                    if (port == -1) {
1734:                        port = url.getDefaultPort();
1735:                    }
1736:                    if (ret == null) {
1737:                        if (schemeID == NegotiateAuthentication.KERBEROS_AUTH) {
1738:                            URL url1;
1739:                            try {
1740:                                url1 = new URL(url, "/"); /* truncate the path */
1741:                            } catch (Exception e) {
1742:                                url1 = url;
1743:                            }
1744:                            ret = new NegotiateAuthentication(false, url1,
1745:                                    null, "Kerberos");
1746:                        }
1747:                        if (schemeID == NegotiateAuthentication.NEGOTIATE_AUTH) {
1748:                            URL url1;
1749:                            try {
1750:                                url1 = new URL(url, "/"); /* truncate the path */
1751:                            } catch (Exception e) {
1752:                                url1 = url;
1753:                            }
1754:                            ret = new NegotiateAuthentication(false, url1,
1755:                                    null, "Negotiate");
1756:                        }
1757:                        if (schemeID == BasicAuthentication.BASIC_AUTH) {
1758:                            PasswordAuthentication a = privilegedRequestPasswordAuthentication(
1759:                                    url.getHost(), addr, port, url
1760:                                            .getProtocol(), realm, scheme, url,
1761:                                    RequestorType.SERVER);
1762:                            if (a != null) {
1763:                                ret = new BasicAuthentication(false, url,
1764:                                        realm, a);
1765:                            }
1766:                        }
1767:
1768:                        if (schemeID == DigestAuthentication.DIGEST_AUTH) {
1769:                            PasswordAuthentication a = privilegedRequestPasswordAuthentication(
1770:                                    url.getHost(), addr, port, url
1771:                                            .getProtocol(), realm, scheme, url,
1772:                                    RequestorType.SERVER);
1773:                            if (a != null) {
1774:                                digestparams = new DigestAuthentication.Parameters();
1775:                                ret = new DigestAuthentication(false, url,
1776:                                        realm, scheme, a, digestparams);
1777:                            }
1778:                        }
1779:
1780:                        if (schemeID == NTLMAuthentication.NTLM_AUTH) {
1781:                            URL url1;
1782:                            try {
1783:                                url1 = new URL(url, "/"); /* truncate the path */
1784:                            } catch (Exception e) {
1785:                                url1 = url;
1786:                            }
1787:                            PasswordAuthentication a = null;
1788:                            if (!tryTransparentNTLMServer) {
1789:                                a = privilegedRequestPasswordAuthentication(url
1790:                                        .getHost(), addr, port, url
1791:                                        .getProtocol(), "", scheme, url,
1792:                                        RequestorType.SERVER);
1793:                            }
1794:
1795:                            /* If we are not trying transparent authentication then 
1796:                             * we need to have a PasswordAuthentication instance. For
1797:                             * transparent authentication (Windows only) the username 
1798:                             * and password will be picked up from the current logged 
1799:                             * on users credentials.
1800:                             */
1801:                            if (tryTransparentNTLMServer
1802:                                    || (!tryTransparentNTLMServer && a != null)) {
1803:                                ret = new NTLMAuthentication(false, url1, a);
1804:                            }
1805:
1806:                            tryTransparentNTLMServer = false;
1807:                        }
1808:                    }
1809:
1810:                    // For backwards compatibility, we also try defaultAuth
1811:                    // REMIND:  Get rid of this for JDK2.0.
1812:
1813:                    if (ret == null && defaultAuth != null
1814:                            && defaultAuth.schemeSupported(scheme)) {
1815:                        String a = defaultAuth.authString(url, scheme, realm);
1816:                        if (a != null) {
1817:                            ret = new BasicAuthentication(false, url, realm, a);
1818:                            // not in cache by default - cache on success
1819:                        }
1820:                    }
1821:
1822:                    if (ret != null) {
1823:                        if (!ret.setHeaders(this , p, raw)) {
1824:                            ret = null;
1825:                        }
1826:                    }
1827:                }
1828:                return ret;
1829:            }
1830:
1831:            /* inclose will be true if called from close(), in which case we
1832:             * force the call to check because this is the last chance to do so.
1833:             * If not in close(), then the authentication info could arrive in a trailer
1834:             * field, which we have not read yet.
1835:             */
1836:            private void checkResponseCredentials(boolean inClose)
1837:                    throws IOException {
1838:                try {
1839:                    if (!needToCheck)
1840:                        return;
1841:                    if (validateProxy && currentProxyCredentials != null) {
1842:                        String raw = responses
1843:                                .findValue("Proxy-Authentication-Info");
1844:                        if (inClose || (raw != null)) {
1845:                            currentProxyCredentials.checkResponse(raw, method,
1846:                                    url);
1847:                            currentProxyCredentials = null;
1848:                        }
1849:                    }
1850:                    if (validateServer && currentServerCredentials != null) {
1851:                        String raw = responses.findValue("Authentication-Info");
1852:                        if (inClose || (raw != null)) {
1853:                            currentServerCredentials.checkResponse(raw, method,
1854:                                    url);
1855:                            currentServerCredentials = null;
1856:                        }
1857:                    }
1858:                    if ((currentServerCredentials == null)
1859:                            && (currentProxyCredentials == null)) {
1860:                        needToCheck = false;
1861:                    }
1862:                } catch (IOException e) {
1863:                    disconnectInternal();
1864:                    connected = false;
1865:                    throw e;
1866:                }
1867:            }
1868:
1869:            /* Tells us whether to follow a redirect.  If so, it
1870:             * closes the connection (break any keep-alive) and
1871:             * resets the url, re-connects, and resets the request
1872:             * property.
1873:             */
1874:            private boolean followRedirect() throws IOException {
1875:                if (!getInstanceFollowRedirects()) {
1876:                    return false;
1877:                }
1878:
1879:                int stat = getResponseCode();
1880:                if (stat < 300 || stat > 307 || stat == 306
1881:                        || stat == HTTP_NOT_MODIFIED) {
1882:                    return false;
1883:                }
1884:                String loc = getHeaderField("Location");
1885:                if (loc == null) {
1886:                    /* this should be present - if not, we have no choice
1887:                     * but to go forward w/ the response we got
1888:                     */
1889:                    return false;
1890:                }
1891:                URL locUrl;
1892:                try {
1893:                    locUrl = new URL(loc);
1894:                    if (!url.getProtocol().equalsIgnoreCase(
1895:                            locUrl.getProtocol())) {
1896:                        return false;
1897:                    }
1898:
1899:                } catch (MalformedURLException mue) {
1900:                    // treat loc as a relative URI to conform to popular browsers
1901:                    locUrl = new URL(url, loc);
1902:                }
1903:                disconnectInternal();
1904:                if (streaming()) {
1905:                    throw new HttpRetryException(RETRY_MSG3, stat, loc);
1906:                }
1907:
1908:                // clear out old response headers!!!!
1909:                responses = new MessageHeader();
1910:                if (stat == HTTP_USE_PROXY) {
1911:                    /* This means we must re-request the resource through the
1912:                     * proxy denoted in the "Location:" field of the response.
1913:                     * Judging by the spec, the string in the Location header
1914:                     * _should_ denote a URL - let's hope for "http://my.proxy.org"
1915:                     * Make a new HttpClient to the proxy, using HttpClient's
1916:                     * Instance-specific proxy fields, but note we're still fetching
1917:                     * the same URL.
1918:                     */
1919:                    String proxyHost = locUrl.getHost();
1920:                    int proxyPort = locUrl.getPort();
1921:
1922:                    SecurityManager security = System.getSecurityManager();
1923:                    if (security != null) {
1924:                        security.checkConnect(proxyHost, proxyPort);
1925:                    }
1926:
1927:                    setProxiedClient(url, proxyHost, proxyPort);
1928:                    requests.set(0, method + " " + http.getURLFile() + " "
1929:                            + httpVersion, null);
1930:                    connected = true;
1931:                } else {
1932:                    // maintain previous headers, just change the name
1933:                    // of the file we're getting
1934:                    url = locUrl;
1935:                    if (method.equals("POST")
1936:                            && !Boolean.getBoolean("http.strictPostRedirect")
1937:                            && (stat != 307)) {
1938:                        /* The HTTP/1.1 spec says that a redirect from a POST 
1939:                         * *should not* be immediately turned into a GET, and
1940:                         * that some HTTP/1.0 clients incorrectly did this.
1941:                         * Correct behavior redirects a POST to another POST.
1942:                         * Unfortunately, since most browsers have this incorrect
1943:                         * behavior, the web works this way now.  Typical usage
1944:                         * seems to be:
1945:                         *   POST a login code or passwd to a web page.
1946:                         *   after validation, the server redirects to another
1947:                         *     (welcome) page
1948:                         *   The second request is (erroneously) expected to be GET
1949:                         * 
1950:                         * We will do the incorrect thing (POST-->GET) by default.
1951:                         * We will provide the capability to do the "right" thing
1952:                         * (POST-->POST) by a system property, "http.strictPostRedirect=true"
1953:                         */
1954:
1955:                        requests = new MessageHeader();
1956:                        setRequests = false;
1957:                        setRequestMethod("GET");
1958:                        poster = null;
1959:                        if (!checkReuseConnection())
1960:                            connect();
1961:                    } else {
1962:                        if (!checkReuseConnection())
1963:                            connect();
1964:                        /* Even after a connect() call, http variable still can be
1965:                         * null, if a ResponseCache has been installed and it returns
1966:                         * a non-null CacheResponse instance. So check nullity before using it.
1967:                         *
1968:                         * And further, if http is null, there's no need to do anything
1969:                         * about request headers because successive http session will use
1970:                         * cachedInputStream/cachedHeaders anyway, which is returned by
1971:                         * CacheResponse.
1972:                         */
1973:                        if (http != null) {
1974:                            requests.set(0, method + " " + http.getURLFile()
1975:                                    + " " + httpVersion, null);
1976:                            int port = url.getPort();
1977:                            String host = url.getHost();
1978:                            if (port != -1 && port != url.getDefaultPort()) {
1979:                                host += ":" + String.valueOf(port);
1980:                            }
1981:                            requests.set("Host", host);
1982:                        }
1983:                    }
1984:                }
1985:                return true;
1986:            }
1987:
1988:            /* dummy byte buffer for reading off socket prior to closing */
1989:            byte[] cdata = new byte[128];
1990:
1991:            /**
1992:             * Reset (without disconnecting the TCP conn) in order to do another transaction with this instance
1993:             */
1994:            private void reset() throws IOException {
1995:                http.reuse = true;
1996:                /* must save before calling close */
1997:                reuseClient = http;
1998:                InputStream is = http.getInputStream();
1999:                if (!method.equals("HEAD")) {
2000:                    try {
2001:                        /* we want to read the rest of the response without using the
2002:                         * hurry mechanism, because that would close the connection
2003:                         * if everything is not available immediately
2004:                         */
2005:                        if ((is instanceof  ChunkedInputStream)
2006:                                || (is instanceof  MeteredStream)) {
2007:                            /* reading until eof will not block */
2008:                            while (is.read(cdata) > 0) {
2009:                            }
2010:                        } else {
2011:                            /* raw stream, which will block on read, so only read
2012:                             * the expected number of bytes, probably 0
2013:                             */
2014:                            int cl = 0, n = 0;
2015:                            try {
2016:                                cl = Integer.parseInt(responses
2017:                                        .findValue("Content-Length"));
2018:                            } catch (Exception e) {
2019:                            }
2020:                            for (int i = 0; i < cl;) {
2021:                                if ((n = is.read(cdata)) == -1) {
2022:                                    break;
2023:                                } else {
2024:                                    i += n;
2025:                                }
2026:                            }
2027:                        }
2028:                    } catch (IOException e) {
2029:                        http.reuse = false;
2030:                        reuseClient = null;
2031:                        disconnectInternal();
2032:                        return;
2033:                    }
2034:                    try {
2035:                        if (is instanceof  MeteredStream) {
2036:                            is.close();
2037:                        }
2038:                    } catch (IOException e) {
2039:                    }
2040:                }
2041:                responseCode = -1;
2042:                responses = new MessageHeader();
2043:                connected = false;
2044:            }
2045:
2046:            /**
2047:             * Disconnect from the server (for internal use)
2048:             */
2049:            private void disconnectInternal() {
2050:                responseCode = -1;
2051:                if (pi != null) {
2052:                    pi.finishTracking();
2053:                    pi = null;
2054:                }
2055:                if (http != null) {
2056:                    http.closeServer();
2057:                    http = null;
2058:                    connected = false;
2059:                }
2060:            }
2061:
2062:            /**
2063:             * Disconnect from the server (public API)
2064:             */
2065:            public void disconnect() {
2066:
2067:                responseCode = -1;
2068:                if (pi != null) {
2069:                    pi.finishTracking();
2070:                    pi = null;
2071:                }
2072:
2073:                if (http != null) {
2074:                    /*
2075:                     * If we have an input stream this means we received a response
2076:                     * from the server. That stream may have been read to EOF and
2077:                     * dependening on the stream type may already be closed or the
2078:                     * the http client may be returned to the keep-alive cache.
2079:                     * If the http client has been returned to the keep-alive cache
2080:                     * it may be closed (idle timeout) or may be allocated to 
2081:                     * another request.
2082:                     *
2083:                     * In other to avoid timing issues we close the input stream
2084:                     * which will either close the underlying connection or return
2085:                     * the client to the cache. If there's a possibility that the
2086:                     * client has been returned to the cache (ie: stream is a keep
2087:                     * alive stream or a chunked input stream) then we remove an
2088:                     * idle connection to the server. Note that this approach
2089:                     * can be considered an approximation in that we may close a
2090:                     * different idle connection to that used by the request.
2091:                     * Additionally it's possible that we close two connections
2092:                     * - the first becuase it wasn't an EOF (and couldn't be
2093:                     * hurried) - the second, another idle connection to the
2094:                     * same server. The is okay because "disconnect" is an
2095:                     * indication that the application doesn't intend to access
2096:                     * this http server for a while.
2097:                     */
2098:
2099:                    if (inputStream != null) {
2100:                        HttpClient hc = http;
2101:
2102:                        // un-synchronized 
2103:                        boolean ka = hc.isKeepingAlive();
2104:
2105:                        try {
2106:                            inputStream.close();
2107:                        } catch (IOException ioe) {
2108:                        }
2109:
2110:                        // if the connection is persistent it may have been closed
2111:                        // or returned to the keep-alive cache. If it's been returned
2112:                        // to the keep-alive cache then we would like to close it
2113:                        // but it may have been allocated
2114:
2115:                        if (ka) {
2116:                            hc.closeIdleConnection();
2117:                        }
2118:
2119:                    } else {
2120:                        // We are deliberatly being disconnected so HttpClient
2121:                        // should not try to resend the request no matter what stage
2122:                        // of the connection we are in.
2123:                        http.setDoNotRetry(true);
2124:
2125:                        http.closeServer();
2126:                    }
2127:
2128:                    //	    poster = null;
2129:                    http = null;
2130:                    connected = false;
2131:                }
2132:                cachedInputStream = null;
2133:                if (cachedHeaders != null) {
2134:                    cachedHeaders.reset();
2135:                }
2136:            }
2137:
2138:            public boolean usingProxy() {
2139:                if (http != null) {
2140:                    return (http.getProxyHostUsed() != null);
2141:                }
2142:                return false;
2143:            }
2144:
2145:            /**
2146:             * Gets a header field by name. Returns null if not known.
2147:             * @param name the name of the header field
2148:             */
2149:            public String getHeaderField(String name) {
2150:                try {
2151:                    getInputStream();
2152:                } catch (IOException e) {
2153:                }
2154:
2155:                if (cachedHeaders != null) {
2156:                    return cachedHeaders.findValue(name);
2157:                }
2158:
2159:                return responses.findValue(name);
2160:            }
2161:
2162:            /**
2163:             * Returns an unmodifiable Map of the header fields.
2164:             * The Map keys are Strings that represent the
2165:             * response-header field names. Each Map value is an
2166:             * unmodifiable List of Strings that represents 
2167:             * the corresponding field values.
2168:             *
2169:             * @return a Map of header fields
2170:             * @since 1.4
2171:             */
2172:            public Map getHeaderFields() {
2173:                try {
2174:                    getInputStream();
2175:                } catch (IOException e) {
2176:                }
2177:
2178:                if (cachedHeaders != null) {
2179:                    return cachedHeaders.getHeaders();
2180:                }
2181:
2182:                return responses.getHeaders();
2183:            }
2184:
2185:            /**
2186:             * Gets a header field by index. Returns null if not known.
2187:             * @param n the index of the header field
2188:             */
2189:            public String getHeaderField(int n) {
2190:                try {
2191:                    getInputStream();
2192:                } catch (IOException e) {
2193:                }
2194:
2195:                if (cachedHeaders != null) {
2196:                    return cachedHeaders.getValue(n);
2197:                }
2198:                return responses.getValue(n);
2199:            }
2200:
2201:            /**
2202:             * Gets a header field by index. Returns null if not known.
2203:             * @param n the index of the header field
2204:             */
2205:            public String getHeaderFieldKey(int n) {
2206:                try {
2207:                    getInputStream();
2208:                } catch (IOException e) {
2209:                }
2210:
2211:                if (cachedHeaders != null) {
2212:                    return cachedHeaders.getKey(n);
2213:                }
2214:
2215:                return responses.getKey(n);
2216:            }
2217:
2218:            /**
2219:             * Sets request property. If a property with the key already
2220:             * exists, overwrite its value with the new value.
2221:             * @param value the value to be set
2222:             */
2223:            public void setRequestProperty(String key, String value) {
2224:                if (connected)
2225:                    throw new IllegalStateException("Already connected");
2226:                if (key == null)
2227:                    throw new NullPointerException("key is null");
2228:
2229:                checkMessageHeader(key, value);
2230:                requests.set(key, value);
2231:            }
2232:
2233:            /**
2234:             * Adds a general request property specified by a
2235:             * key-value pair.  This method will not overwrite
2236:             * existing values associated with the same key.
2237:             *
2238:             * @param   key     the keyword by which the request is known
2239:             *                  (e.g., "<code>accept</code>").
2240:             * @param   value  the value associated with it.
2241:             * @see #getRequestProperties(java.lang.String)
2242:             * @since 1.4
2243:             */
2244:            public void addRequestProperty(String key, String value) {
2245:                if (connected)
2246:                    throw new IllegalStateException("Already connected");
2247:                if (key == null)
2248:                    throw new NullPointerException("key is null");
2249:
2250:                checkMessageHeader(key, value);
2251:                requests.add(key, value);
2252:            }
2253:
2254:            //
2255:            // Set a property for authentication.  This can safely disregard
2256:            // the connected test.
2257:            //
2258:            void setAuthenticationProperty(String key, String value) {
2259:                checkMessageHeader(key, value);
2260:                requests.set(key, value);
2261:            }
2262:
2263:            public String getRequestProperty(String key) {
2264:                // don't return headers containing security sensitive information
2265:                if (key != null) {
2266:                    for (int i = 0; i < EXCLUDE_HEADERS.length; i++) {
2267:                        if (key.equalsIgnoreCase(EXCLUDE_HEADERS[i])) {
2268:                            return null;
2269:                        }
2270:                    }
2271:                }
2272:                return requests.findValue(key);
2273:            }
2274:
2275:            /**
2276:             * Returns an unmodifiable Map of general request
2277:             * properties for this connection. The Map keys
2278:             * are Strings that represent the request-header
2279:             * field names. Each Map value is a unmodifiable List 
2280:             * of Strings that represents the corresponding 
2281:             * field values.
2282:             *
2283:             * @return  a Map of the general request properties for this connection.
2284:             * @throws IllegalStateException if already connected
2285:             * @since 1.4
2286:             */
2287:            public Map getRequestProperties() {
2288:                if (connected)
2289:                    throw new IllegalStateException("Already connected");
2290:
2291:                // exclude headers containing security-sensitive info
2292:                return requests.getHeaders(EXCLUDE_HEADERS);
2293:            }
2294:
2295:            public void setConnectTimeout(int timeout) {
2296:                if (timeout < 0)
2297:                    throw new IllegalArgumentException(
2298:                            "timeouts can't be negative");
2299:                connectTimeout = timeout;
2300:            }
2301:
2302:            /**
2303:             * Returns setting for connect timeout.
2304:             * <p>
2305:             * 0 return implies that the option is disabled
2306:             * (i.e., timeout of infinity).
2307:             *
2308:             * @return an <code>int</code> that indicates the connect timeout
2309:             *         value in milliseconds
2310:             * @see java.net.URLConnection#setConnectTimeout(int)
2311:             * @see java.net.URLConnection#connect()
2312:             * @since 1.5
2313:             */
2314:            public int getConnectTimeout() {
2315:                return (connectTimeout < 0 ? 0 : connectTimeout);
2316:            }
2317:
2318:            /**
2319:             * Sets the read timeout to a specified timeout, in
2320:             * milliseconds. A non-zero value specifies the timeout when
2321:             * reading from Input stream when a connection is established to a
2322:             * resource. If the timeout expires before there is data available
2323:             * for read, a java.net.SocketTimeoutException is raised. A
2324:             * timeout of zero is interpreted as an infinite timeout.
2325:             *
2326:             * <p> Some non-standard implementation of this method ignores the
2327:             * specified timeout. To see the read timeout set, please call
2328:             * getReadTimeout().
2329:             *
2330:             * @param timeout an <code>int</code> that specifies the timeout
2331:             * value to be used in milliseconds
2332:             * @throws IllegalArgumentException if the timeout parameter is negative
2333:             *
2334:             * @see java.net.URLConnectiongetReadTimeout()
2335:             * @see java.io.InputStream#read()
2336:             * @since 1.5
2337:             */
2338:            public void setReadTimeout(int timeout) {
2339:                if (timeout < 0)
2340:                    throw new IllegalArgumentException(
2341:                            "timeouts can't be negative");
2342:                readTimeout = timeout;
2343:            }
2344:
2345:            /**
2346:             * Returns setting for read timeout. 0 return implies that the
2347:             * option is disabled (i.e., timeout of infinity).
2348:             *
2349:             * @return an <code>int</code> that indicates the read timeout
2350:             *         value in milliseconds
2351:             *
2352:             * @see java.net.URLConnection#setReadTimeout(int)
2353:             * @see java.io.InputStream#read()
2354:             * @since 1.5
2355:             */
2356:            public int getReadTimeout() {
2357:                return readTimeout < 0 ? 0 : readTimeout;
2358:            }
2359:
2360:            protected void finalize() {
2361:                // this should do nothing.  The stream finalizer will close 
2362:                // the fd
2363:            }
2364:
2365:            String getMethod() {
2366:                return method;
2367:            }
2368:
2369:            private MessageHeader mapToMessageHeader(Map map) {
2370:                MessageHeader headers = new MessageHeader();
2371:                if (map == null || map.isEmpty()) {
2372:                    return headers;
2373:                }
2374:                Set entries = map.entrySet();
2375:                Iterator itr1 = entries.iterator();
2376:                while (itr1.hasNext()) {
2377:                    Map.Entry entry = (Map.Entry) itr1.next();
2378:                    String key = (String) entry.getKey();
2379:                    List values = (List) entry.getValue();
2380:                    Iterator itr2 = values.iterator();
2381:                    while (itr2.hasNext()) {
2382:                        String value = (String) itr2.next();
2383:                        if (key == null) {
2384:                            headers.prepend(key, value);
2385:                        } else {
2386:                            headers.add(key, value);
2387:                        }
2388:                    }
2389:                }
2390:                return headers;
2391:            }
2392:
2393:            /* The purpose of this wrapper is just to capture the close() call
2394:             * so we can check authentication information that may have
2395:             * arrived in a Trailer field
2396:             */
2397:            class HttpInputStream extends FilterInputStream {
2398:                private CacheRequest cacheRequest;
2399:                private OutputStream outputStream;
2400:                private boolean marked = false;
2401:                private int inCache = 0;
2402:                private int markCount = 0;
2403:
2404:                public HttpInputStream(InputStream is) {
2405:                    super (is);
2406:                    this .cacheRequest = null;
2407:                    this .outputStream = null;
2408:                }
2409:
2410:                public HttpInputStream(InputStream is, CacheRequest cacheRequest) {
2411:                    super (is);
2412:                    this .cacheRequest = cacheRequest;
2413:                    try {
2414:                        this .outputStream = cacheRequest.getBody();
2415:                    } catch (IOException ioex) {
2416:                        this .cacheRequest.abort();
2417:                        this .cacheRequest = null;
2418:                        this .outputStream = null;
2419:                    }
2420:                }
2421:
2422:                /**
2423:                 * Marks the current position in this input stream. A subsequent 
2424:                 * call to the <code>reset</code> method repositions this stream at 
2425:                 * the last marked position so that subsequent reads re-read the same
2426:                 * bytes.
2427:                 * <p>
2428:                 * The <code>readlimit</code> argument tells this input stream to 
2429:                 * allow that many bytes to be read before the mark position gets 
2430:                 * invalidated. 
2431:                 * <p>
2432:                 * This method simply performs <code>in.mark(readlimit)</code>.
2433:                 *
2434:                 * @param   readlimit   the maximum limit of bytes that can be read before
2435:                 *                      the mark position becomes invalid.
2436:                 * @see     java.io.FilterInputStream#in
2437:                 * @see     java.io.FilterInputStream#reset()
2438:                 */
2439:                public synchronized void mark(int readlimit) {
2440:                    super .mark(readlimit);
2441:                    if (cacheRequest != null) {
2442:                        marked = true;
2443:                        markCount = 0;
2444:                    }
2445:                }
2446:
2447:                /**
2448:                 * Repositions this stream to the position at the time the 
2449:                 * <code>mark</code> method was last called on this input stream. 
2450:                 * <p>
2451:                 * This method
2452:                 * simply performs <code>in.reset()</code>.
2453:                 * <p>
2454:                 * Stream marks are intended to be used in
2455:                 * situations where you need to read ahead a little to see what's in
2456:                 * the stream. Often this is most easily done by invoking some
2457:                 * general parser. If the stream is of the type handled by the
2458:                 * parse, it just chugs along happily. If the stream is not of
2459:                 * that type, the parser should toss an exception when it fails.
2460:                 * If this happens within readlimit bytes, it allows the outer
2461:                 * code to reset the stream and try another parser.
2462:                 *
2463:                 * @exception  IOException  if the stream has not been marked or if the
2464:                 *               mark has been invalidated.
2465:                 * @see        java.io.FilterInputStream#in
2466:                 * @see        java.io.FilterInputStream#mark(int)
2467:                 */
2468:                public synchronized void reset() throws IOException {
2469:                    super .reset();
2470:                    if (cacheRequest != null) {
2471:                        marked = false;
2472:                        inCache += markCount;
2473:                    }
2474:                }
2475:
2476:                public int read() throws IOException {
2477:                    try {
2478:                        byte[] b = new byte[1];
2479:                        int ret = read(b);
2480:                        return (ret == -1 ? ret : (b[0] & 0x00FF));
2481:                    } catch (IOException ioex) {
2482:                        if (cacheRequest != null) {
2483:                            cacheRequest.abort();
2484:                        }
2485:                        throw ioex;
2486:                    }
2487:                }
2488:
2489:                public int read(byte[] b) throws IOException {
2490:                    return read(b, 0, b.length);
2491:                }
2492:
2493:                public int read(byte[] b, int off, int len) throws IOException {
2494:                    try {
2495:                        int newLen = super .read(b, off, len);
2496:                        int nWrite;
2497:                        // write to cache
2498:                        if (inCache > 0) {
2499:                            if (inCache >= newLen) {
2500:                                inCache -= newLen;
2501:                                nWrite = 0;
2502:                            } else {
2503:                                nWrite = newLen - inCache;
2504:                                inCache = 0;
2505:                            }
2506:                        } else {
2507:                            nWrite = newLen;
2508:                        }
2509:                        if (nWrite > 0 && outputStream != null)
2510:                            outputStream.write(b, off + (newLen - nWrite),
2511:                                    nWrite);
2512:                        if (marked) {
2513:                            markCount += newLen;
2514:                        }
2515:                        return newLen;
2516:                    } catch (IOException ioex) {
2517:                        if (cacheRequest != null) {
2518:                            cacheRequest.abort();
2519:                        }
2520:                        throw ioex;
2521:                    }
2522:                }
2523:
2524:                public void close() throws IOException {
2525:                    try {
2526:                        if (outputStream != null) {
2527:                            if (read() != -1) {
2528:                                cacheRequest.abort();
2529:                            } else {
2530:                                outputStream.close();
2531:                            }
2532:                        }
2533:                        super .close();
2534:                    } catch (IOException ioex) {
2535:                        if (cacheRequest != null) {
2536:                            cacheRequest.abort();
2537:                        }
2538:                        throw ioex;
2539:                    } finally {
2540:                        HttpURLConnection.this .http = null;
2541:                        checkResponseCredentials(true);
2542:                    }
2543:                }
2544:            }
2545:
2546:            class StreamingOutputStream extends FilterOutputStream {
2547:
2548:                int expected;
2549:                int written;
2550:                boolean closed;
2551:                boolean error;
2552:                IOException errorExcp;
2553:
2554:                /**
2555:                 * expectedLength == -1 if the stream is chunked
2556:                 * expectedLength > 0 if the stream is fixed content-length
2557:                 *    In the 2nd case, we make sure the expected number of
2558:                 *    of bytes are actually written
2559:                 */
2560:                StreamingOutputStream(OutputStream os, int expectedLength) {
2561:                    super (os);
2562:                    expected = expectedLength;
2563:                    written = 0;
2564:                    closed = false;
2565:                    error = false;
2566:                }
2567:
2568:                public void write(int b) throws IOException {
2569:                    checkError();
2570:                    written++;
2571:                    if (expected != -1 && written > expected) {
2572:                        throw new IOException("too many bytes written");
2573:                    }
2574:                    out.write(b);
2575:                }
2576:
2577:                public void write(byte[] b) throws IOException {
2578:                    write(b, 0, b.length);
2579:                }
2580:
2581:                public void write(byte[] b, int off, int len)
2582:                        throws IOException {
2583:                    checkError();
2584:                    written += len;
2585:                    if (expected != -1 && written > expected) {
2586:                        out.close();
2587:                        throw new IOException("too many bytes written");
2588:                    }
2589:                    out.write(b, off, len);
2590:                }
2591:
2592:                void checkError() throws IOException {
2593:                    if (closed) {
2594:                        throw new IOException("Stream is closed");
2595:                    }
2596:                    if (error) {
2597:                        throw errorExcp;
2598:                    }
2599:                    if (((PrintStream) out).checkError()) {
2600:                        throw new IOException(
2601:                                "Error writing request body to server");
2602:                    }
2603:                }
2604:
2605:                /* this is called to check that all the bytes
2606:                 * that were supposed to be written were written
2607:                 * and that the stream is now closed().
2608:                 */
2609:                boolean writtenOK() {
2610:                    return closed && !error;
2611:                }
2612:
2613:                public void close() throws IOException {
2614:                    if (closed) {
2615:                        return;
2616:                    }
2617:                    closed = true;
2618:                    if (expected != -1) {
2619:                        /* not chunked */
2620:                        if (written != expected) {
2621:                            error = true;
2622:                            errorExcp = new IOException(
2623:                                    "insufficient data written");
2624:                            out.close();
2625:                            throw errorExcp;
2626:                        }
2627:                        super .flush(); /* can't close the socket */
2628:                    } else {
2629:                        /* chunked */
2630:                        super .close(); /* force final chunk to be written */
2631:                        /* trailing \r\n */
2632:                        OutputStream o = http.getOutputStream();
2633:                        o.write('\r');
2634:                        o.write('\n');
2635:                        o.flush();
2636:                    }
2637:                }
2638:            }
2639:
2640:            static class ErrorStream extends InputStream {
2641:                ByteBuffer buffer;
2642:                InputStream is;
2643:
2644:                private ErrorStream(ByteBuffer buf) {
2645:                    buffer = buf;
2646:                    is = null;
2647:                }
2648:
2649:                private ErrorStream(ByteBuffer buf, InputStream is) {
2650:                    buffer = buf;
2651:                    this .is = is;
2652:                }
2653:
2654:                // when this method is called, it's either the case that cl > 0, or
2655:                // if chunk-encoded, cl = -1; in other words, cl can't be 0
2656:                public static InputStream getErrorStream(InputStream is,
2657:                        int cl, HttpClient http) {
2658:
2659:                    // cl can't be 0; this following is here for extra precaution
2660:                    if (cl == 0) {
2661:                        return null;
2662:                    }
2663:
2664:                    try {
2665:                        // set SO_TIMEOUT to 1/5th of the total timeout
2666:                        // remember the old timeout value so that we can restore it
2667:                        int oldTimeout = http.setTimeout(timeout4ESBuffer / 5);
2668:
2669:                        int expected = 0;
2670:                        // the chunked case
2671:                        if (cl < 0) {
2672:                            expected = bufSize4ES;
2673:                        } else {
2674:                            expected = cl;
2675:                        }
2676:                        if (expected <= bufSize4ES) {
2677:                            byte[] buffer = new byte[expected];
2678:                            int count = 0, time = 0, len = 0;
2679:                            do {
2680:                                try {
2681:                                    len = is.read(buffer, count, buffer.length
2682:                                            - count);
2683:                                    if (len < 0) {
2684:                                        if (cl < 0) {
2685:                                            // chunked ended
2686:                                            // if chunked ended prematurely,
2687:                                            // an IOException would be thrown
2688:                                            break;
2689:                                        }
2690:                                        // the server sends less than cl bytes of data
2691:                                        throw new IOException(
2692:                                                "the server closes"
2693:                                                        + " before sending "
2694:                                                        + cl + " bytes of data");
2695:                                    }
2696:                                    count += len;
2697:                                } catch (SocketTimeoutException ex) {
2698:                                    time += timeout4ESBuffer / 5;
2699:                                }
2700:                            } while (count < expected
2701:                                    && time < timeout4ESBuffer);
2702:
2703:                            // reset SO_TIMEOUT to old value
2704:                            http.setTimeout(oldTimeout);
2705:
2706:                            // if count < cl at this point, we will not try to reuse
2707:                            // the connection
2708:                            if (count == 0) {
2709:                                // since we haven't read anything,
2710:                                // we will return the underlying
2711:                                // inputstream back to the application
2712:                                return null;
2713:                            } else if (count == expected || (cl < 0 && len < 0)) {
2714:                                // put the connection into keep-alive cache
2715:                                // the inputstream will try to do the right thing
2716:                                is.close();
2717:                                return new ErrorStream(ByteBuffer.wrap(buffer,
2718:                                        0, count));
2719:                            } else {
2720:                                // we read part of the response body
2721:                                return new ErrorStream(ByteBuffer.wrap(buffer,
2722:                                        0, count), is);
2723:                            }
2724:                        }
2725:                        return null;
2726:                    } catch (IOException ioex) {
2727:                        // ioex.printStackTrace();
2728:                        return null;
2729:                    }
2730:                }
2731:
2732:                public int available() throws IOException {
2733:                    if (is == null) {
2734:                        return buffer.remaining();
2735:                    } else {
2736:                        return buffer.remaining() + is.available();
2737:                    }
2738:                }
2739:
2740:                public int read() throws IOException {
2741:                    byte[] b = new byte[1];
2742:                    int ret = read(b);
2743:                    return (ret == -1 ? ret : (b[0] & 0x00FF));
2744:                }
2745:
2746:                public int read(byte[] b) throws IOException {
2747:                    return read(b, 0, b.length);
2748:                }
2749:
2750:                public int read(byte[] b, int off, int len) throws IOException {
2751:                    int rem = buffer.remaining();
2752:                    if (rem > 0) {
2753:                        int ret = rem < len ? rem : len;
2754:                        buffer.get(b, off, ret);
2755:                        return ret;
2756:                    } else {
2757:                        if (is == null) {
2758:                            return -1;
2759:                        } else {
2760:                            return is.read(b, off, len);
2761:                        }
2762:                    }
2763:                }
2764:
2765:                public void close() throws IOException {
2766:                    buffer = null;
2767:                    if (is != null) {
2768:                        is.close();
2769:                    }
2770:                }
2771:            }
2772:        }
2773:
2774:        /** An input stream that just returns EOF.  This is for
2775:         * HTTP URLConnections that are KeepAlive && use the
2776:         * HEAD method - i.e., stream not dead, but nothing to be read.
2777:         */
2778:
2779:        class EmptyInputStream extends InputStream {
2780:
2781:            public int available() {
2782:                return 0;
2783:            }
2784:
2785:            public int read() {
2786:                return -1;
2787:            }
2788:        }
w_w__w___.j__a___v__a__2__s___.___c___om_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.