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


0001:        /*
0002:         * @(#)HttpURLConnection.java	1.86 06/10/10
0003:         *
0004:         * Copyright  1990-2006 Sun Microsystems, Inc. All Rights Reserved.  
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER  
0006:         *   
0007:         * This program is free software; you can redistribute it and/or  
0008:         * modify it under the terms of the GNU General Public License version  
0009:         * 2 only, as published by the Free Software Foundation.   
0010:         *   
0011:         * This program is distributed in the hope that it will be useful, but  
0012:         * WITHOUT ANY WARRANTY; without even the implied warranty of  
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  
0014:         * General Public License version 2 for more details (a copy is  
0015:         * included at /legal/license.txt).   
0016:         *   
0017:         * You should have received a copy of the GNU General Public License  
0018:         * version 2 along with this work; if not, write to the Free Software  
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  
0020:         * 02110-1301 USA   
0021:         *   
0022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa  
0023:         * Clara, CA 95054 or visit www.sun.com if you need additional  
0024:         * information or have any questions. 
0025:         *
0026:         */
0027:
0028:        package sun.net.www.protocol.http;
0029:
0030:        import java.net.URL;
0031:        import java.net.URLConnection;
0032:        import java.net.ProtocolException;
0033:        import java.net.PasswordAuthentication;
0034:        import java.net.Authenticator;
0035:        import java.net.InetAddress;
0036:        import java.net.UnknownHostException;
0037:        import java.net.SocketTimeoutException;
0038:        import java.io.*;
0039:        import java.util.Date;
0040:        import java.util.Map;
0041:        import java.util.Locale;
0042:        import java.util.StringTokenizer;
0043:        import sun.net.*;
0044:        import sun.net.www.*;
0045:        import sun.net.www.http.HttpClient;
0046:        import sun.net.www.http.PosterOutputStream;
0047:        import sun.net.www.http.ChunkedInputStream;
0048:        import java.text.SimpleDateFormat;
0049:        import java.util.TimeZone;
0050:        import java.net.MalformedURLException;
0051:
0052:        /**
0053:         * A class to represent an HTTP connection to a remote object.
0054:         */
0055:
0056:        public class HttpURLConnection extends java.net.HttpURLConnection {
0057:
0058:            static final String version;
0059:            public static final String userAgent;
0060:
0061:            /* max # of allowed re-directs */
0062:            static final int defaultmaxRedirects = 20;
0063:            static final int maxRedirects;
0064:
0065:            /* Not all servers support the (Proxy)-Authentication-Info headers.
0066:             * By default, we don't require them to be sent
0067:             */
0068:            static final boolean validateProxy;
0069:            static final boolean validateServer;
0070:
0071:            static {
0072:                maxRedirects = ((Integer) java.security.AccessController
0073:                        .doPrivileged(new sun.security.action.GetIntegerAction(
0074:                                "http.maxRedirects", defaultmaxRedirects)))
0075:                        .intValue();
0076:                version = (String) java.security.AccessController
0077:                        .doPrivileged(new sun.security.action.GetPropertyAction(
0078:                                "java.version"));
0079:                String agent = (String) java.security.AccessController
0080:                        .doPrivileged(new sun.security.action.GetPropertyAction(
0081:                                "http.agent"));
0082:                if (agent == null) {
0083:                    agent = "Java/" + version;
0084:                } else {
0085:                    agent = agent + " Java/" + version;
0086:                }
0087:                userAgent = agent;
0088:                validateProxy = ((Boolean) java.security.AccessController
0089:                        .doPrivileged(new sun.security.action.GetBooleanAction(
0090:                                "http.auth.digest.validateProxy")))
0091:                        .booleanValue();
0092:                validateServer = ((Boolean) java.security.AccessController
0093:                        .doPrivileged(new sun.security.action.GetBooleanAction(
0094:                                "http.auth.digest.validateServer")))
0095:                        .booleanValue();
0096:            }
0097:
0098:            static final String httpVersion = "HTTP/1.1";
0099:            static final String acceptString = "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
0100:
0101:            // the following http request headers should NOT have their values
0102:            // returned for security reasons.
0103:            private static final String[] EXCLUDE_HEADERS = {
0104:                    "Proxy-Authorization", "Authorization" };
0105:            protected HttpClient http;
0106:            protected Handler handler;
0107:
0108:            /* output stream to server */
0109:            protected PrintStream ps = null;
0110:
0111:            /* We only have a single static authenticator for now.
0112:             * For backwards compatibility with JDK 1.1.  Should be
0113:             * eliminated for JDK 2.0.
0114:             */
0115:            private static HttpAuthenticator defaultAuth;
0116:
0117:            /* all the headers we send 
0118:             * NOTE: do *NOT* dump out the content of 'requests' in the 
0119:             * output or stacktrace since it may contain security-sensitive 
0120:             * headers such as those defined in EXCLUDE_HEADERS.
0121:             */
0122:            private MessageHeader requests;
0123:
0124:            /* The following two fields are only used with Digest Authentication */
0125:            String domain; /* The list of authentication domains */
0126:            DigestAuthentication.Parameters digestparams;
0127:
0128:            /* Current credentials in use */
0129:            AuthenticationInfo currentProxyCredentials = null;
0130:            AuthenticationInfo currentServerCredentials = null;
0131:            boolean needToCheck = true;
0132:            private boolean doingNTLM2ndStage = false; /* doing the 2nd stage of an NTLM server authentication */
0133:            private boolean doingNTLMp2ndStage = false; /* doing the 2nd stage of an NTLM proxy authentication */
0134:            Object authObj;
0135:
0136:            /* Progress entry */
0137:            protected ProgressEntry pe;
0138:
0139:            /* all the response headers we get back */
0140:            private MessageHeader responses;
0141:            /* the stream _from_ the server */
0142:            private InputStream inputStream = null;
0143:            /* post stream _to_ the server, if any */
0144:            private PosterOutputStream poster = null;
0145:
0146:            /* Indicates if the std. request headers have been set in requests. */
0147:            private boolean setRequests = false;
0148:
0149:            /* Indicates whether a request has already failed or not */
0150:            private boolean failedOnce = false;
0151:
0152:            /* Remembered Exception, we will throw it again if somebody
0153:               calls getInputStream after disconnect */
0154:            private Exception rememberedException = null;
0155:
0156:            /* If we decide we want to reuse a client, we put it here */
0157:            private HttpClient reuseClient = null;
0158:
0159:            /*
0160:             * privileged request password authentication 
0161:             *
0162:             */
0163:            private static PasswordAuthentication privilegedRequestPasswordAuthentication(
0164:                    final String host, final InetAddress addr, final int port,
0165:                    final String protocol, final String prompt,
0166:                    final String scheme) {
0167:                return (PasswordAuthentication) java.security.AccessController
0168:                        .doPrivileged(new java.security.PrivilegedAction() {
0169:                            public Object run() {
0170:                                return Authenticator
0171:                                        .requestPasswordAuthentication(host,
0172:                                                addr, port, protocol, prompt,
0173:                                                scheme);
0174:                            }
0175:                        });
0176:            }
0177:
0178:            /* 
0179:             * checks the validity of http message header and throws 
0180:             * IllegalArgumentException if invalid.
0181:             */
0182:            private void checkMessageHeader(String key, String value) {
0183:                char LF = '\n';
0184:                int index = key.indexOf(LF);
0185:                if (index != -1) {
0186:                    throw new IllegalArgumentException(
0187:                            "Illegal character(s) in message header field: "
0188:                                    + key);
0189:                } else {
0190:                    if (value == null) {
0191:                        return;
0192:                    }
0193:
0194:                    index = value.indexOf(LF);
0195:                    while (index != -1) {
0196:                        index++;
0197:                        if (index < value.length()) {
0198:                            char c = value.charAt(index);
0199:                            if ((c == ' ') || (c == '\t')) {
0200:                                // ok, check the next occurrence
0201:                                index = value.indexOf(LF, index);
0202:                                continue;
0203:                            }
0204:                        }
0205:                        throw new IllegalArgumentException(
0206:                                "Illegal character(s) in message header value: "
0207:                                        + value);
0208:                    }
0209:                }
0210:            }
0211:
0212:            /* adds the standard key/val pairs to reqests if necessary & write to
0213:             * given PrintStream
0214:             */
0215:            private void writeRequests() throws IOException {
0216:
0217:                /* print all message headers in the MessageHeader 
0218:                 * onto the wire - all the ones we've set and any
0219:                 * others that have been set
0220:                 */
0221:                if (!setRequests) {
0222:
0223:                    /* We're very particular about the order in which we
0224:                     * set the request headers here.  The order should not
0225:                     * matter, but some careless CGI programs have been
0226:                     * written to expect a very particular order of the
0227:                     * standard headers.  To name names, the order in which
0228:                     * Navigator3.0 sends them.  In particular, we make *sure*
0229:                     * to send Content-type: <> and Content-length:<> second
0230:                     * to last and last, respectively, in the case of a POST
0231:                     * request.
0232:                     */
0233:                    if (!failedOnce)
0234:                        requests.prepend(method + " " + http.getURLFile() + " "
0235:                                + httpVersion, null);
0236:                    if (!getUseCaches()) {
0237:                        requests.setIfNotSet("Cache-Control", "no-cache");
0238:                        requests.setIfNotSet("Pragma", "no-cache");
0239:                    }
0240:                    requests.setIfNotSet("User-Agent", userAgent);
0241:                    int port = url.getPort();
0242:                    String host = url.getHost();
0243:                    if (port != -1 && port != 80) {
0244:                        host += ":" + String.valueOf(port);
0245:                    }
0246:                    requests.setIfNotSet("Host", host);
0247:                    requests.setIfNotSet("Accept", acceptString);
0248:
0249:                    /*
0250:                     * For HTTP/1.1 the default behavior is to keep connections alive.
0251:                     * However, we may be talking to a 1.0 server so we should set
0252:                     * keep-alive just in case, except if we have encountered an error
0253:                     * or if keep alive is disabled via a system property
0254:                     */
0255:
0256:                    // Try keep-alive only on first attempt
0257:                    if (!failedOnce && http.getHttpKeepAliveSet()) {
0258:                        if (http.usingProxy) {
0259:                            requests.setIfNotSet("Proxy-Connection",
0260:                                    "keep-alive");
0261:                        } else {
0262:                            requests.setIfNotSet("Connection", "keep-alive");
0263:                        }
0264:                    }
0265:                    // send any pre-emptive authentication
0266:                    if (http.usingProxy) {
0267:                        setPreemptiveProxyAuthentication(requests);
0268:                    }
0269:                    // Set modified since if necessary
0270:                    long modTime = getIfModifiedSince();
0271:                    if (modTime != 0) {
0272:                        Date date = new Date(modTime);
0273:                        //use the preferred date format according to RFC 2068(HTTP1.1),
0274:                        // RFC 822 and RFC 1123
0275:                        SimpleDateFormat fo = new SimpleDateFormat(
0276:                                "EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
0277:                        fo.setTimeZone(TimeZone.getTimeZone("GMT"));
0278:                        requests.setIfNotSet("If-Modified-Since", fo
0279:                                .format(date));
0280:                    }
0281:                    // check for preemptive authorization
0282:                    AuthenticationInfo sauth = AuthenticationInfo
0283:                            .getServerAuth(url);
0284:                    if (sauth != null
0285:                            && sauth.supportsPreemptiveAuthorization()) {
0286:                        // Sets "Authorization"
0287:                        requests.setIfNotSet(sauth.getHeaderName(), sauth
0288:                                .getHeaderValue(url, method));
0289:                        currentServerCredentials = sauth;
0290:                    }
0291:
0292:                    if (poster != null) {
0293:                        /* add Content-Length & POST/PUT data */
0294:                        synchronized (poster) {
0295:                            /* close it, so no more data can be added */
0296:                            poster.close();
0297:                            if (!method.equals("PUT")) {
0298:                                String type = "application/x-www-form-urlencoded";
0299:                                requests.setIfNotSet("Content-Type", type);
0300:                            }
0301:                            requests.set("Content-Length", String
0302:                                    .valueOf(poster.size()));
0303:                        }
0304:                    }
0305:                    setRequests = true;
0306:                }
0307:                http.writeRequests(requests, poster);
0308:                if (ps.checkError()) {
0309:                    String proxyHost = http.getProxyHostUsed();
0310:                    int proxyPort = http.getProxyPortUsed();
0311:                    disconnectInternal();
0312:                    if (failedOnce) {
0313:                        throw new IOException("Error writing to server");
0314:                    } else { // try once more
0315:                        failedOnce = true;
0316:                        if (proxyHost != null) {
0317:                            setProxiedClient(url, proxyHost, proxyPort);
0318:                        } else {
0319:                            setNewClient(url);
0320:                        }
0321:                        ps = (PrintStream) http.getOutputStream();
0322:                        connected = true;
0323:                        responses = new MessageHeader();
0324:                        setRequests = false;
0325:                        writeRequests();
0326:                    }
0327:                }
0328:            }
0329:
0330:            /**
0331:             * Create a new HttpClient object, bypassing the cache of
0332:             * HTTP client objects/connections.
0333:             *
0334:             * @param url	the URL being accessed
0335:             */
0336:            protected void setNewClient(URL url) throws IOException {
0337:                setNewClient(url, false);
0338:            }
0339:
0340:            /**
0341:             * Obtain a HttpsClient object. Use the cached copy if specified. 
0342:             *
0343:             * @param url       the URL being accessed
0344:             * @param useCache  whether the cached connection should be used
0345:             *        if present
0346:             */
0347:            protected void setNewClient(URL url, boolean useCache)
0348:                    throws IOException {
0349:                http = HttpClient.New(url, useCache);
0350:            }
0351:
0352:            /**
0353:             * Create a new HttpClient object, set up so that it uses
0354:             * per-instance proxying to the given HTTP proxy.  This
0355:             * bypasses the cache of HTTP client objects/connections.
0356:             *
0357:             * @param url	the URL being accessed
0358:             * @param proxyHost	the proxy host to use
0359:             * @param proxyPort	the proxy port to use
0360:             */
0361:            protected void setProxiedClient(URL url, String proxyHost,
0362:                    int proxyPort) throws IOException {
0363:                setProxiedClient(url, proxyHost, proxyPort, false);
0364:            }
0365:
0366:            /**
0367:             * Obtain a HttpClient object, set up so that it uses per-instance
0368:             * proxying to the given HTTP proxy. Use the cached copy of HTTP
0369:             * client objects/connections if specified.
0370:             *
0371:             * @param url       the URL being accessed
0372:             * @param proxyHost the proxy host to use
0373:             * @param proxyPort the proxy port to use
0374:             * @param useCache  whether the cached connection should be used
0375:             *        if present
0376:             */
0377:            protected void setProxiedClient(URL url, String proxyHost,
0378:                    int proxyPort, boolean useCache) throws IOException {
0379:                proxiedConnect(url, proxyHost, proxyPort, useCache);
0380:            }
0381:
0382:            protected void proxiedConnect(URL url, String proxyHost,
0383:                    int proxyPort, boolean useCache) throws IOException {
0384:                SecurityManager security = System.getSecurityManager();
0385:                if (security != null) {
0386:                    security.checkConnect(proxyHost, proxyPort);
0387:                }
0388:                http = HttpClient.New(url, proxyHost, proxyPort, useCache);
0389:            }
0390:
0391:            protected HttpURLConnection(URL u, Handler handler)
0392:                    throws IOException {
0393:                super (u);
0394:                requests = new MessageHeader();
0395:                responses = new MessageHeader();
0396:                this .handler = handler;
0397:            }
0398:
0399:            /** this constructor is used by other protocol handlers such as ftp
0400:                that want to use http to fetch urls on their behalf. */
0401:            public HttpURLConnection(URL u, String host, int port)
0402:                    throws IOException {
0403:                this (u, new Handler(host, port));
0404:            }
0405:
0406:            /** 
0407:             * @deprecated.  Use java.net.Authenticator.setDefault() instead.
0408:             */
0409:            public static void setDefaultAuthenticator(HttpAuthenticator a) {
0410:                defaultAuth = a;
0411:            }
0412:
0413:            /**
0414:             * opens a stream allowing redirects only to the same host.
0415:             */
0416:            public static InputStream openConnectionCheckRedirects(
0417:                    URLConnection c) throws IOException {
0418:                boolean redir;
0419:                int redirects = 0;
0420:                InputStream in = null;
0421:
0422:                do {
0423:                    if (c instanceof  HttpURLConnection) {
0424:                        ((HttpURLConnection) c)
0425:                                .setInstanceFollowRedirects(false);
0426:                    }
0427:
0428:                    // We want to open the input stream before
0429:                    // getting headers, because getHeaderField()
0430:                    // et al swallow IOExceptions.
0431:                    in = c.getInputStream();
0432:                    redir = false;
0433:
0434:                    if (c instanceof  HttpURLConnection) {
0435:                        HttpURLConnection http = (HttpURLConnection) c;
0436:                        int stat = http.getResponseCode();
0437:                        if (stat >= 300 && stat <= 307 && stat != 306
0438:                                && stat != HttpURLConnection.HTTP_NOT_MODIFIED) {
0439:                            URL base = http.getURL();
0440:                            String loc = http.getHeaderField("Location");
0441:                            URL target = null;
0442:                            if (loc != null) {
0443:                                target = new URL(base, loc);
0444:                            }
0445:                            http.disconnect();
0446:                            if (target == null
0447:                                    || !base.getProtocol().equals(
0448:                                            target.getProtocol())
0449:                                    || base.getPort() != target.getPort()
0450:                                    || !hostsEqual(base, target)
0451:                                    || redirects >= 5) {
0452:                                throw new SecurityException(
0453:                                        "illegal URL redirect");
0454:                            }
0455:                            redir = true;
0456:                            c = target.openConnection();
0457:                            redirects++;
0458:                        }
0459:                    }
0460:                } while (redir);
0461:                return in;
0462:            }
0463:
0464:            //
0465:            // Same as java.net.URL.hostsEqual
0466:            //
0467:            private static boolean hostsEqual(URL u1, URL u2) {
0468:                final String h1 = u1.getHost();
0469:                final String h2 = u2.getHost();
0470:
0471:                if (h1 == null) {
0472:                    return h2 == null;
0473:                } else if (h2 == null) {
0474:                    return false;
0475:                } else if (h1.equalsIgnoreCase(h2)) {
0476:                    return true;
0477:                }
0478:                // Have to resolve addresses before comparing, otherwise
0479:                // names like tachyon and tachyon.eng would compare different
0480:                final boolean result[] = { false };
0481:
0482:                java.security.AccessController
0483:                        .doPrivileged(new java.security.PrivilegedAction() {
0484:                            public Object run() {
0485:                                try {
0486:                                    InetAddress a1 = InetAddress.getByName(h1);
0487:                                    InetAddress a2 = InetAddress.getByName(h2);
0488:                                    result[0] = a1.equals(a2);
0489:                                } catch (UnknownHostException e) {
0490:                                } catch (SecurityException e) {
0491:                                }
0492:                                return null;
0493:                            }
0494:                        });
0495:
0496:                return result[0];
0497:            }
0498:
0499:            // overridden in HTTPS subclass
0500:
0501:            public void connect() throws IOException {
0502:                plainConnect();
0503:            }
0504:
0505:            private boolean checkReuseConnection() {
0506:                if (connected) {
0507:                    return true;
0508:                }
0509:                if (reuseClient != null) {
0510:                    http = reuseClient;
0511:                    http.reuse = false;
0512:                    reuseClient = null;
0513:                    connected = true;
0514:                    return true;
0515:                }
0516:                return false;
0517:            }
0518:
0519:            protected void plainConnect() throws IOException {
0520:                if (connected) {
0521:                    return;
0522:                }
0523:                try {
0524:                    if ("http".equals(url.getProtocol()) && !failedOnce) {
0525:                        http = HttpClient.New(url);
0526:                    } else {
0527:                        // make sure to construct new connection if first
0528:                        // attempt failed
0529:                        http = new HttpClient(url, handler.proxy,
0530:                                handler.proxyPort);
0531:                    }
0532:                    ps = (PrintStream) http.getOutputStream();
0533:                } catch (IOException e) {
0534:                    throw e;
0535:                }
0536:                // constructor to HTTP client calls openserver
0537:                connected = true;
0538:            }
0539:
0540:            /*
0541:             * Allowable input/output sequences:
0542:             * [interpreted as POST/PUT]
0543:             * - get output, [write output,] get input, [read input]
0544:             * - get output, [write output]
0545:             * [interpreted as GET]
0546:             * - get input, [read input]
0547:             * Disallowed:
0548:             * - get input, [read input,] get output, [write output]
0549:             */
0550:
0551:            public synchronized OutputStream getOutputStream()
0552:                    throws IOException {
0553:
0554:                try {
0555:                    if (!doOutput) {
0556:                        throw new ProtocolException(
0557:                                "cannot write to a URLConnection"
0558:                                        + " if doOutput=false - call setDoOutput(true)");
0559:                    }
0560:
0561:                    if (method.equals("GET")) {
0562:                        method = "POST"; // Backward compatibility
0563:                    }
0564:                    if (!"POST".equals(method) && !"PUT".equals(method)
0565:                            && "http".equals(url.getProtocol())) {
0566:                        throw new ProtocolException("HTTP method " + method
0567:                                + " doesn't support output");
0568:                    }
0569:
0570:                    // if there's already an input stream open, throw an exception
0571:                    if (inputStream != null) {
0572:                        throw new ProtocolException(
0573:                                "Cannot write output after reading input.");
0574:                    }
0575:
0576:                    if (!checkReuseConnection())
0577:                        connect();
0578:
0579:                    /* This exists to fix the HttpsURLConnection subclass.
0580:                     * Hotjava needs to run on JDK1.1.  Do proper fix in subclass
0581:                     * for 1.2 and remove this.
0582:                     */
0583:                    ps = (PrintStream) http.getOutputStream();
0584:
0585:                    if (poster == null)
0586:                        poster = new PosterOutputStream();
0587:                    return poster;
0588:                } catch (RuntimeException e) {
0589:                    disconnectInternal();
0590:                    throw e;
0591:                } catch (IOException e) {
0592:                    disconnectInternal();
0593:                    throw e;
0594:                }
0595:            }
0596:
0597:            public synchronized InputStream getInputStream() throws IOException {
0598:
0599:                if (!doInput) {
0600:                    throw new ProtocolException(
0601:                            "Cannot read from URLConnection"
0602:                                    + " if doInput=false (call setDoInput(true))");
0603:                }
0604:
0605:                if (rememberedException != null) {
0606:                    if (rememberedException instanceof  RuntimeException)
0607:                        throw new RuntimeException(rememberedException);
0608:                    else {
0609:                        IOException exception;
0610:                        try {
0611:                            exception = new IOException();
0612:                            exception.initCause(rememberedException);
0613:                        } catch (Exception t) {
0614:                            exception = (IOException) rememberedException;
0615:                        }
0616:                        throw exception;
0617:                    }
0618:                }
0619:
0620:                if (inputStream != null) {
0621:                    return inputStream;
0622:                }
0623:
0624:                int redirects = 0;
0625:                int respCode = 0;
0626:                AuthenticationInfo serverAuthentication = null;
0627:                AuthenticationInfo proxyAuthentication = null;
0628:                AuthenticationHeader srvHdr = null;
0629:                try {
0630:                    do {
0631:
0632:                        pe = new ProgressEntry(url.getFile(), null);
0633:                        ProgressData.pdata.register(pe);
0634:                        if (!checkReuseConnection())
0635:                            connect();
0636:
0637:                        /* This exists to fix the HttpsURLConnection subclass.
0638:                         * Hotjava needs to run on JDK1.1.  Do proper fix once a
0639:                         * proper solution for SSL can be found.
0640:                         */
0641:                        ps = (PrintStream) http.getOutputStream();
0642:
0643:                        writeRequests();
0644:                        http.parseHTTP(responses, pe);
0645:                        inputStream = new HttpInputStream(http.getInputStream());
0646:
0647:                        respCode = getResponseCode();
0648:                        if (respCode == HTTP_PROXY_AUTH) {
0649:                            AuthenticationHeader authhdr = new AuthenticationHeader(
0650:                                    "Proxy-Authenticate", responses);
0651:                            if (!doingNTLMp2ndStage) {
0652:                                proxyAuthentication = resetProxyAuthentication(
0653:                                        proxyAuthentication, authhdr);
0654:                                if (proxyAuthentication != null) {
0655:                                    redirects++;
0656:                                    disconnectInternal();
0657:                                    continue;
0658:                                }
0659:                            } else {
0660:                                /* in this case, only one header field will be present */
0661:                                String raw = responses
0662:                                        .findValue("Proxy-Authenticate");
0663:                                reset();
0664:                                if (!proxyAuthentication.setHeaders(this ,
0665:                                        authhdr.headerParser(), raw)) {
0666:                                    disconnectInternal();
0667:                                    throw new IOException(
0668:                                            "Authentication failure");
0669:                                }
0670:                                if (serverAuthentication != null
0671:                                        && srvHdr != null
0672:                                        && !serverAuthentication.setHeaders(
0673:                                                this , srvHdr.headerParser(),
0674:                                                raw)) {
0675:                                    disconnectInternal();
0676:                                    throw new IOException(
0677:                                            "Authentication failure");
0678:                                }
0679:                                authObj = null;
0680:                                doingNTLMp2ndStage = false;
0681:                                continue;
0682:                            }
0683:                        }
0684:
0685:                        // cache proxy authentication info
0686:                        if (proxyAuthentication != null) {
0687:                            // cache auth info on success, domain header not relevant.
0688:                            proxyAuthentication.addToCache();
0689:                        }
0690:
0691:                        if (respCode == HTTP_UNAUTHORIZED) {
0692:                            srvHdr = new AuthenticationHeader(
0693:                                    "WWW-Authenticate", responses);
0694:                            String raw = srvHdr.raw();
0695:                            if (!doingNTLM2ndStage) {
0696:                                if (serverAuthentication != null) {
0697:                                    if (serverAuthentication
0698:                                            .isAuthorizationStale(raw)) {
0699:                                        /* we can retry with the current credentials */
0700:                                        disconnectInternal();
0701:                                        redirects++;
0702:                                        requests.set(serverAuthentication
0703:                                                .getHeaderName(),
0704:                                                serverAuthentication
0705:                                                        .getHeaderValue(url,
0706:                                                                method));
0707:                                        currentServerCredentials = serverAuthentication;
0708:                                        continue;
0709:                                    } else {
0710:                                        serverAuthentication.removeFromCache();
0711:                                    }
0712:                                }
0713:                                serverAuthentication = getServerAuthentication(srvHdr);
0714:                                currentServerCredentials = serverAuthentication;
0715:
0716:                                if (serverAuthentication != null) {
0717:                                    disconnectInternal();
0718:                                    redirects++; // don't let things loop ad nauseum
0719:                                    continue;
0720:                                }
0721:                            } else {
0722:                                reset();
0723:                                /* header not used for ntlm */
0724:                                if (!serverAuthentication.setHeaders(this ,
0725:                                        null, raw)) {
0726:                                    disconnectInternal();
0727:                                    throw new IOException(
0728:                                            "Authentication failure");
0729:                                }
0730:                                doingNTLM2ndStage = false;
0731:                                authObj = null;
0732:                                continue;
0733:                            }
0734:                        }
0735:                        // cache server authentication info
0736:                        if (serverAuthentication != null) {
0737:                            // cache auth info on success
0738:                            if (!(serverAuthentication instanceof  DigestAuthentication)
0739:                                    || (domain == null)) {
0740:                                if (serverAuthentication instanceof  BasicAuthentication) {
0741:                                    // check if the path is shorter than the existing entry
0742:                                    String npath = AuthenticationInfo
0743:                                            .reducePath(url.getPath());
0744:                                    String opath = serverAuthentication.path;
0745:                                    if (!opath.startsWith(npath)
0746:                                            || npath.length() >= opath.length()) {
0747:                                        /* npath is longer, there must be a common root */
0748:                                        npath = BasicAuthentication
0749:                                                .getRootPath(opath, npath);
0750:                                    }
0751:                                    // remove the entry and create a new one 
0752:                                    BasicAuthentication a = (BasicAuthentication) serverAuthentication
0753:                                            .clone();
0754:                                    serverAuthentication.removeFromCache();
0755:                                    a.path = npath;
0756:                                    serverAuthentication = a;
0757:                                }
0758:                                serverAuthentication.addToCache();
0759:                            } else {
0760:                                // what we cache is based on the domain list in the request
0761:                                DigestAuthentication srv = (DigestAuthentication) serverAuthentication;
0762:                                StringTokenizer tok = new StringTokenizer(
0763:                                        domain, " ");
0764:                                String realm = srv.realm;
0765:                                PasswordAuthentication pw = srv.pw;
0766:                                digestparams = srv.params;
0767:                                while (tok.hasMoreTokens()) {
0768:                                    String path = tok.nextToken();
0769:                                    try {
0770:                                        /* path could be an abs_path or a complete URI */
0771:                                        URL u = new URL(url, path);
0772:                                        DigestAuthentication d = new DigestAuthentication(
0773:                                                false, u, realm, "Digest", pw,
0774:                                                digestparams);
0775:                                        d.addToCache();
0776:                                    } catch (Exception e) {
0777:                                    }
0778:                                }
0779:                            }
0780:                        }
0781:
0782:                        if (respCode == HTTP_OK) {
0783:                            checkResponseCredentials(false);
0784:                        } else {
0785:                            needToCheck = false;
0786:                        }
0787:
0788:                        if (followRedirect()) {
0789:                            /* if we should follow a redirect, then the followRedirects()
0790:                             * method will disconnect() and re-connect us to the new
0791:                             * location
0792:                             */
0793:                            redirects++;
0794:                            continue;
0795:                        }
0796:
0797:                        int cl = -1;
0798:                        try {
0799:                            cl = Integer.parseInt(responses
0800:                                    .findValue("content-length"));
0801:                        } catch (Exception exc) {
0802:                        }
0803:                        ;
0804:
0805:                        if (method.equals("HEAD") || method.equals("TRACE")
0806:                                || cl == 0 || respCode == HTTP_NOT_MODIFIED
0807:                                || respCode == HTTP_NO_CONTENT) {
0808:
0809:                            if (pe != null) {
0810:                                ProgressData.pdata.unregister(pe);
0811:                            }
0812:                            http.finished();
0813:                            http = null;
0814:                            inputStream = new EmptyInputStream();
0815:                            if (respCode < 400) {
0816:                                connected = false;
0817:                                return inputStream;
0818:                            }
0819:                        }
0820:
0821:                        if (respCode >= 400) {
0822:                            if (respCode == 404 || respCode == 410) {
0823:                                throw new FileNotFoundException(url.toString());
0824:                            } else {
0825:                                throw new java.io.IOException(
0826:                                        "Server returned HTTP"
0827:                                                + " response code: " + respCode
0828:                                                + " for URL: " + url.toString());
0829:                            }
0830:                        }
0831:
0832:                        return inputStream;
0833:                    } while (redirects < maxRedirects);
0834:
0835:                    throw new ProtocolException("Server redirected too many "
0836:                            + " times (" + redirects + ")");
0837:                } catch (RuntimeException e) {
0838:                    disconnectInternal();
0839:                    rememberedException = e;
0840:                    throw e;
0841:                } catch (IOException e) {
0842:                    rememberedException = e;
0843:                    throw e;
0844:                } finally {
0845:                    if (respCode == HTTP_PROXY_AUTH
0846:                            && proxyAuthentication != null) {
0847:                        proxyAuthentication.endAuthRequest();
0848:                    } else if (respCode == HTTP_UNAUTHORIZED
0849:                            && serverAuthentication != null) {
0850:                        serverAuthentication.endAuthRequest();
0851:                    }
0852:                }
0853:            }
0854:
0855:            public InputStream getErrorStream() {
0856:                if (connected && responseCode >= 400) {
0857:                    // Client Error 4xx and Server Error 5xx
0858:                    if (inputStream != null) {
0859:                        return inputStream;
0860:                    }
0861:                }
0862:                return null;
0863:            }
0864:
0865:            /**
0866:             * set or reset proxy authentication info in request headers
0867:             * after receiving a 407 error. In the case of NTLM however,
0868:             * receiving a 407 is normal and we just skip the stale check
0869:             * because ntlm does not support this feature.
0870:             */
0871:            private AuthenticationInfo resetProxyAuthentication(
0872:                    AuthenticationInfo proxyAuthentication,
0873:                    AuthenticationHeader auth) {
0874:                if (proxyAuthentication != null) {
0875:                    String raw = auth.raw();
0876:                    if (proxyAuthentication.isAuthorizationStale(raw)) {
0877:                        /* we can retry with the current credentials */
0878:                        requests
0879:                                .set(proxyAuthentication.getHeaderName(),
0880:                                        proxyAuthentication.getHeaderValue(url,
0881:                                                method));
0882:                        currentProxyCredentials = proxyAuthentication;
0883:                        return proxyAuthentication;
0884:                    } else {
0885:                        proxyAuthentication.removeFromCache();
0886:                    }
0887:                }
0888:                proxyAuthentication = getHttpProxyAuthentication(auth);
0889:                currentProxyCredentials = proxyAuthentication;
0890:                return proxyAuthentication;
0891:            }
0892:
0893:            /**
0894:             * establish a tunnel through proxy server
0895:             */
0896:            protected synchronized void doTunneling() throws IOException {
0897:                int retryTunnel = 0;
0898:                String statusLine = "";
0899:                int respCode = 0;
0900:                AuthenticationInfo proxyAuthentication = null;
0901:                String proxyHost = null;
0902:                int proxyPort = -1;
0903:                try {
0904:                    do {
0905:                        if (!checkReuseConnection()) {
0906:                            proxiedConnect(url, proxyHost, proxyPort, false);
0907:                        }
0908:                        // send the "CONNECT" request to establish a tunnel
0909:                        // through proxy server
0910:                        sendCONNECTRequest();
0911:                        responses.reset();
0912:                        http.parseHTTP(responses, new ProgressEntry(url
0913:                                .getFile(), null));
0914:                        statusLine = responses.getValue(0);
0915:                        StringTokenizer st = new StringTokenizer(statusLine);
0916:                        st.nextToken();
0917:                        respCode = Integer.parseInt(st.nextToken().trim());
0918:                        if (respCode == HTTP_PROXY_AUTH) {
0919:                            AuthenticationHeader authhdr = new AuthenticationHeader(
0920:                                    "Proxy-Authenticate", responses);
0921:                            if (!doingNTLMp2ndStage) {
0922:                                proxyAuthentication = resetProxyAuthentication(
0923:                                        proxyAuthentication, authhdr);
0924:                                if (proxyAuthentication != null) {
0925:                                    proxyHost = http.getProxyHostUsed();
0926:                                    proxyPort = http.getProxyPortUsed();
0927:                                    disconnectInternal();
0928:                                    retryTunnel++;
0929:                                    continue;
0930:                                }
0931:                            } else {
0932:                                String raw = responses
0933:                                        .findValue("Proxy-Authenticate");
0934:                                reset();
0935:                                if (!proxyAuthentication.setHeaders(this ,
0936:                                        authhdr.headerParser(), raw)) {
0937:                                    proxyHost = http.getProxyHostUsed();
0938:                                    proxyPort = http.getProxyPortUsed();
0939:                                    disconnectInternal();
0940:                                    throw new IOException(
0941:                                            "Authentication failure");
0942:                                }
0943:                                authObj = null;
0944:                                doingNTLMp2ndStage = false;
0945:                                continue;
0946:                            }
0947:                        }
0948:                        // cache proxy authentication info
0949:                        if (proxyAuthentication != null) {
0950:                            // cache auth info on success, domain header not relevant.
0951:                            proxyAuthentication.addToCache();
0952:                        }
0953:
0954:                        if (respCode == HTTP_OK) {
0955:                            break;
0956:                        }
0957:                        // we don't know how to deal with other response code
0958:                        // so disconnect and report error
0959:                        disconnectInternal();
0960:                        break;
0961:                    } while (retryTunnel < maxRedirects);
0962:
0963:                    if (retryTunnel >= maxRedirects || (respCode != HTTP_OK)) {
0964:                        throw new IOException("Unable to tunnel through proxy."
0965:                                + " Proxy returns \"" + statusLine + "\"");
0966:                    }
0967:                } finally {
0968:                    if (respCode == HTTP_PROXY_AUTH
0969:                            && proxyAuthentication != null) {
0970:                        proxyAuthentication.endAuthRequest();
0971:                    }
0972:                }
0973:                // remove tunneling related requests
0974:                int i;
0975:                if ((i = requests.getKey("Proxy-authorization")) >= 0)
0976:                    requests.set(i, null, null);
0977:
0978:                // reset responses
0979:                responses.reset();
0980:            }
0981:
0982:            /**
0983:             * send a CONNECT request for establishing a tunnel to proxy server
0984:             */
0985:            private void sendCONNECTRequest() throws IOException {
0986:                int port = url.getPort();
0987:                if (port == -1) {
0988:                    port = url.getDefaultPort();
0989:                }
0990:                requests.prepend("CONNECT " + url.getHost() + ":" + port + " "
0991:                        + httpVersion, null);
0992:                requests.setIfNotSet("User-Agent", userAgent);
0993:
0994:                String host = url.getHost();
0995:                if (port != -1 && port != 80) {
0996:                    host += ":" + String.valueOf(port);
0997:                }
0998:                requests.setIfNotSet("Host", host);
0999:
1000:                // Not really necessary for a tunnel, but can't hurt
1001:                requests.setIfNotSet("Accept", acceptString);
1002:
1003:                setPreemptiveProxyAuthentication(requests);
1004:                http.writeRequests(requests, null);
1005:                // remove CONNECT header
1006:                requests.set(0, null, null);
1007:            }
1008:
1009:            /**
1010:             * Sets pre-emptive proxy authentication in header
1011:             */
1012:            private void setPreemptiveProxyAuthentication(MessageHeader requests) {
1013:                AuthenticationInfo pauth = AuthenticationInfo.getProxyAuth(http
1014:                        .getProxyHostUsed(), http.getProxyPortUsed());
1015:                if (pauth != null && pauth.supportsPreemptiveAuthorization()) {
1016:                    // Sets "Proxy-authorization"
1017:                    requests.setIfNotSet(pauth.getHeaderName(), pauth
1018:                            .getHeaderValue(url, method));
1019:                    currentProxyCredentials = pauth;
1020:                }
1021:            }
1022:
1023:            /**
1024:             * Gets the authentication for an HTTP proxy, and applies it to
1025:             * the connection.
1026:             */
1027:            private AuthenticationInfo getHttpProxyAuthentication(
1028:                    AuthenticationHeader authhdr) {
1029:                /* get authorization from authenticator */
1030:                AuthenticationInfo ret = null;
1031:                String raw = authhdr.raw();
1032:                String host = http.getProxyHostUsed();
1033:                int port = http.getProxyPortUsed();
1034:                if (host != null && authhdr.isPresent()) {
1035:                    HeaderParser p = authhdr.headerParser();
1036:                    String realm = p.findValue("realm");
1037:                    String scheme = authhdr.scheme();
1038:                    char schemeID;
1039:                    if ("basic".equalsIgnoreCase(scheme)) {
1040:                        schemeID = BasicAuthentication.BASIC_AUTH;
1041:                    } else if ("digest".equalsIgnoreCase(scheme)) {
1042:                        schemeID = DigestAuthentication.DIGEST_AUTH;
1043:
1044:                    } else {
1045:                        schemeID = 0;
1046:                    }
1047:                    if (realm == null)
1048:                        realm = "";
1049:                    ret = AuthenticationInfo.getProxyAuth(host, port, realm,
1050:                            schemeID);
1051:                    if (ret == null) {
1052:                        if (schemeID == BasicAuthentication.BASIC_AUTH) {
1053:                            InetAddress addr = null;
1054:                            try {
1055:                                final String finalHost = host;
1056:                                addr = (InetAddress) java.security.AccessController
1057:                                        .doPrivileged(new java.security.PrivilegedExceptionAction() {
1058:                                            public Object run()
1059:                                                    throws java.net.UnknownHostException {
1060:                                                return InetAddress
1061:                                                        .getByName(finalHost);
1062:                                            }
1063:                                        });
1064:                            } catch (java.security.PrivilegedActionException ignored) {
1065:                                // User will have an unknown host.
1066:                            }
1067:                            PasswordAuthentication a = privilegedRequestPasswordAuthentication(
1068:                                    host, addr, port, "http", realm, scheme);
1069:                            if (a != null) {
1070:                                ret = new BasicAuthentication(true, host, port,
1071:                                        realm, a);
1072:                            }
1073:                        } else if (schemeID == DigestAuthentication.DIGEST_AUTH) {
1074:                            PasswordAuthentication a = privilegedRequestPasswordAuthentication(
1075:                                    host, null, port, url.getProtocol(), realm,
1076:                                    scheme);
1077:                            if (a != null) {
1078:                                DigestAuthentication.Parameters params = new DigestAuthentication.Parameters();
1079:                                ret = new DigestAuthentication(true, host,
1080:                                        port, realm, scheme, a, params);
1081:                            }
1082:                        }
1083:                    }
1084:                    // For backwards compatibility, we also try defaultAuth
1085:
1086:                    if (ret == null && defaultAuth != null
1087:                            && defaultAuth.schemeSupported(scheme)) {
1088:                        try {
1089:                            URL u = new URL("http", host, port, "/");
1090:                            String a = defaultAuth.authString(u, scheme, realm);
1091:                            if (a != null) {
1092:                                ret = new BasicAuthentication(true, host, port,
1093:                                        realm, a);
1094:                                // not in cache by default - cache on success
1095:                            }
1096:                        } catch (java.net.MalformedURLException ignored) {
1097:                        }
1098:                    }
1099:                    if (ret != null) {
1100:                        if (!ret.setHeaders(this , p, raw)) {
1101:                            ret = null;
1102:                        }
1103:                    }
1104:                }
1105:                return ret;
1106:            }
1107:
1108:            /**
1109:             * Gets the authentication for an HTTP server, and applies it to
1110:             * the connection.
1111:             */
1112:            private AuthenticationInfo getServerAuthentication(
1113:                    AuthenticationHeader authhdr) {
1114:                /* get authorization from authenticator */
1115:                AuthenticationInfo ret = null;
1116:                String raw = authhdr.raw();
1117:                /* When we get an NTLM auth from cache, don't set any special headers */
1118:                if (authhdr.isPresent()) {
1119:                    HeaderParser p = authhdr.headerParser();
1120:                    String realm = p.findValue("realm");
1121:                    String scheme = authhdr.scheme();
1122:                    char schemeID;
1123:                    if ("basic".equalsIgnoreCase(scheme)) {
1124:                        schemeID = BasicAuthentication.BASIC_AUTH;
1125:                    } else if ("digest".equalsIgnoreCase(scheme)) {
1126:                        schemeID = DigestAuthentication.DIGEST_AUTH;
1127:
1128:                    } else {
1129:                        schemeID = 0;
1130:                    }
1131:                    domain = p.findValue("domain");
1132:                    if (realm == null)
1133:                        realm = "";
1134:                    ret = AuthenticationInfo
1135:                            .getServerAuth(url, realm, schemeID);
1136:                    InetAddress addr = null;
1137:                    if (ret == null) {
1138:                        try {
1139:                            addr = InetAddress.getByName(url.getHost());
1140:                        } catch (java.net.UnknownHostException ignored) {
1141:                            // User will have addr = null
1142:                        }
1143:                    }
1144:                    // replacing -1 with default port for a protocol
1145:                    int port = url.getPort();
1146:                    if (port == -1) {
1147:                        port = url.getDefaultPort();
1148:                    }
1149:                    if (ret == null) {
1150:                        if (schemeID == BasicAuthentication.BASIC_AUTH) {
1151:                            PasswordAuthentication a = privilegedRequestPasswordAuthentication(
1152:                                    url.getHost(), addr, port, url
1153:                                            .getProtocol(), realm, scheme);
1154:                            if (a != null) {
1155:                                ret = new BasicAuthentication(false, url,
1156:                                        realm, a);
1157:                            }
1158:                        }
1159:
1160:                        if (schemeID == DigestAuthentication.DIGEST_AUTH) {
1161:                            PasswordAuthentication a = privilegedRequestPasswordAuthentication(
1162:                                    url.getHost(), addr, port, url
1163:                                            .getProtocol(), realm, scheme);
1164:                            if (a != null) {
1165:                                digestparams = new DigestAuthentication.Parameters();
1166:                                ret = new DigestAuthentication(false, url,
1167:                                        realm, scheme, a, digestparams);
1168:                            }
1169:                        }
1170:                    }
1171:
1172:                    // For backwards compatibility, we also try defaultAuth
1173:
1174:                    if (ret == null && defaultAuth != null
1175:                            && defaultAuth.schemeSupported(scheme)) {
1176:                        String a = defaultAuth.authString(url, scheme, realm);
1177:                        if (a != null) {
1178:                            ret = new BasicAuthentication(false, url, realm, a);
1179:                            // not in cache by default - cache on success
1180:                        }
1181:                    }
1182:
1183:                    if (ret != null) {
1184:                        if (!ret.setHeaders(this , p, raw)) {
1185:                            ret = null;
1186:                        }
1187:                    }
1188:                }
1189:                return ret;
1190:            }
1191:
1192:            /* inclose will be true if called from close(), in which case we
1193:             * force the call to check because this is the last chance to do so.
1194:             * If not in close(), then the authentication info could arrive in a trailer
1195:             * field, which we have not read yet.
1196:             */
1197:            private void checkResponseCredentials(boolean inClose)
1198:                    throws IOException {
1199:                try {
1200:                    if (!needToCheck)
1201:                        return;
1202:                    if (validateProxy && currentProxyCredentials != null) {
1203:                        String raw = responses
1204:                                .findValue("Proxy-Authentication-Info");
1205:                        if (inClose || (raw != null)) {
1206:                            currentProxyCredentials.checkResponse(raw, method,
1207:                                    url);
1208:                            currentProxyCredentials = null;
1209:                        }
1210:                    }
1211:                    if (validateServer && currentServerCredentials != null) {
1212:                        String raw = responses.findValue("Authentication-Info");
1213:                        if (inClose || (raw != null)) {
1214:                            currentServerCredentials.checkResponse(raw, method,
1215:                                    url);
1216:                            currentServerCredentials = null;
1217:                        }
1218:                    }
1219:                    if ((currentServerCredentials == null)
1220:                            && (currentProxyCredentials == null)) {
1221:                        needToCheck = false;
1222:                    }
1223:                } catch (IOException e) {
1224:                    disconnectInternal();
1225:                    connected = false;
1226:                    throw e;
1227:                }
1228:            }
1229:
1230:            /* Tells us whether to follow a redirect.  If so, it
1231:             * closes the connection (break any keep-alive) and
1232:             * resets the url, re-connects, and resets the request
1233:             * property.
1234:             */
1235:            private boolean followRedirect() throws IOException {
1236:                if (!getInstanceFollowRedirects()) {
1237:                    return false;
1238:                }
1239:
1240:                int stat = getResponseCode();
1241:                if (stat < 300 || stat > 307 || stat == 306
1242:                        || stat == HTTP_NOT_MODIFIED) {
1243:                    return false;
1244:                }
1245:                String loc = getHeaderField("Location");
1246:                if (loc == null) {
1247:                    /* this should be present - if not, we have no choice
1248:                     * but to go forward w/ the response we got
1249:                     */
1250:                    return false;
1251:                }
1252:                URL locUrl;
1253:                try {
1254:                    locUrl = new URL(loc);
1255:                    if (!url.getProtocol().equalsIgnoreCase(
1256:                            locUrl.getProtocol())) {
1257:                        return false;
1258:                    }
1259:
1260:                } catch (MalformedURLException mue) {
1261:                    // treat loc as a relative URI to conform to popular browsers
1262:                    locUrl = new URL(url, loc);
1263:                }
1264:                disconnectInternal();
1265:                // clear out old response headers!!!!
1266:                responses = new MessageHeader();
1267:                if (stat == HTTP_USE_PROXY) {
1268:                    /* This means we must re-request the resource through the
1269:                     * proxy denoted in the "Location:" field of the response.
1270:                     * Judging by the spec, the string in the Location header
1271:                     * _should_ denote a URL - let's hope for "http://my.proxy.org"
1272:                     * Make a new HttpClient to the proxy, using HttpClient's
1273:                     * Instance-specific proxy fields, but note we're still fetching
1274:                     * the same URL.
1275:                     */
1276:                    setProxiedClient(url, locUrl.getHost(), locUrl.getPort());
1277:                    requests.set(0, method + " " + http.getURLFile() + " "
1278:                            + httpVersion, null);
1279:                    connected = true;
1280:                } else {
1281:                    // maintain previous headers, just change the name
1282:                    // of the file we're getting
1283:                    url = locUrl;
1284:                    if (method.equals("POST")
1285:                            && !Boolean.getBoolean("http.strictPostRedirect")
1286:                            && (stat != 307)) {
1287:                        /* The HTTP/1.1 spec says that a redirect from a POST 
1288:                         * *should not* be immediately turned into a GET, and
1289:                         * that some HTTP/1.0 clients incorrectly did this.
1290:                         * Correct behavior redirects a POST to another POST.
1291:                         * Unfortunately, since most browsers have this incorrect
1292:                         * behavior, the web works this way now.  Typical usage
1293:                         * seems to be:
1294:                         *   POST a login code or passwd to a web page.
1295:                         *   after validation, the server redirects to another
1296:                         *     (welcome) page
1297:                         *   The second request is (erroneously) expected to be GET
1298:                         * 
1299:                         * We will do the incorrect thing (POST-->GET) by default.
1300:                         * We will provide the capability to do the "right" thing
1301:                         * (POST-->POST) by a system property, "http.strictPostRedirect=true"
1302:                         */
1303:
1304:                        requests = new MessageHeader();
1305:                        setRequests = false;
1306:                        setRequestMethod("GET");
1307:                        poster = null;
1308:                        if (!checkReuseConnection())
1309:                            connect();
1310:                    } else {
1311:                        if (!checkReuseConnection())
1312:                            connect();
1313:                        requests.set(0, method + " " + http.getURLFile() + " "
1314:                                + httpVersion, null);
1315:                        requests
1316:                                .set(
1317:                                        "Host",
1318:                                        url.getHost()
1319:                                                + ((url.getPort() == -1 || url
1320:                                                        .getPort() == 80) ? ""
1321:                                                        : ":"
1322:                                                                + String
1323:                                                                        .valueOf(url
1324:                                                                                .getPort())));
1325:                    }
1326:                }
1327:                return true;
1328:            }
1329:
1330:            /* dummy byte buffer for reading off socket prior to closing */
1331:            byte[] cdata = new byte[128];
1332:
1333:            /**
1334:             * Reset (without disconnecting the TCP conn) in order to do another transaction with this instance
1335:             */
1336:            private void reset() throws IOException {
1337:                http.reuse = true;
1338:                /* must save before calling close */
1339:                reuseClient = http;
1340:                InputStream is = http.getInputStream();
1341:                try {
1342:                    /* we want to read the rest of the response without using the
1343:                     * hurry mechanism, because that would close the connection
1344:                     * if everything is not available immediately
1345:                     */
1346:                    if ((is instanceof  ChunkedInputStream)
1347:                            || (is instanceof  MeteredStream)) {
1348:                        /* reading until eof will not block */
1349:                        while (is.read(cdata) > 0) {
1350:                        }
1351:                    } else {
1352:                        /* raw stream, which will block on read, so only read
1353:                         * the expected number of bytes, probably 0
1354:                         */
1355:                        int cl = 0, n = 0;
1356:                        try {
1357:                            cl = Integer.parseInt(responses
1358:                                    .findValue("Content-Length"));
1359:                        } catch (Exception e) {
1360:                        }
1361:                        for (int i = 0; i < cl;) {
1362:                            if ((n = is.read(cdata)) == -1) {
1363:                                break;
1364:                            } else {
1365:                                i += n;
1366:                            }
1367:                        }
1368:                    }
1369:                } catch (IOException e) {
1370:                    http.reuse = false;
1371:                    reuseClient = null;
1372:                    disconnectInternal();
1373:                    return;
1374:                }
1375:                try {
1376:                    if (is instanceof  MeteredStream) {
1377:                        is.close();
1378:                    }
1379:                } catch (IOException e) {
1380:                }
1381:                responseCode = -1;
1382:                responses = new MessageHeader();
1383:                connected = false;
1384:            }
1385:
1386:            /**
1387:             * Disconnect from the server (for internal use)
1388:             */
1389:            private void disconnectInternal() {
1390:                responseCode = -1;
1391:                if (pe != null) {
1392:                    ProgressData.pdata.unregister(pe);
1393:                }
1394:                if (http != null) {
1395:                    http.closeServer();
1396:                    http = null;
1397:                    connected = false;
1398:                }
1399:            }
1400:
1401:            /**
1402:             * Disconnect from the server (public API)
1403:             */
1404:            public void disconnect() {
1405:
1406:                responseCode = -1;
1407:                if (pe != null) {
1408:                    ProgressData.pdata.unregister(pe);
1409:                }
1410:                if (http != null) {
1411:                    /*
1412:                     * If we have an input stream this means we received a response
1413:                     * from the server. That stream may have been read to EOF and
1414:                     * dependening on the stream type may already be closed or the
1415:                     * the http client may be returned to the keep-alive cache.
1416:                     * If the http client has been returned to the keep-alive cache
1417:                     * it may be closed (idle timeout) or may be allocated to 
1418:                     * another request.
1419:                     *
1420:                     * In other to avoid timing issues we close the input stream
1421:                     * which will either close the underlying connection or return
1422:                     * the client to the cache. If there's a possibility that the
1423:                     * client has been returned to the cache (ie: stream is a keep
1424:                     * alive stream or a chunked input stream) then we remove an
1425:                     * idle connection to the server. Note that this approach
1426:                     * can be considered an approximation in that we may close a
1427:                     * different idle connection to that used by the request.
1428:                     * Additionally it's possible that we close two connections
1429:                     * - the first becuase it wasn't an EOF (and couldn't be
1430:                     * hurried) - the second, another idle connection to the
1431:                     * same server. The is okay because "disconnect" is an
1432:                     * indication that the application doesn't intend to access
1433:                     * this http server for a while.
1434:                     */
1435:
1436:                    if (inputStream != null) {
1437:                        HttpClient hc = http;
1438:
1439:                        // un-synchronized 
1440:                        boolean ka = hc.isKeepingAlive();
1441:
1442:                        try {
1443:                            inputStream.close();
1444:                        } catch (IOException ioe) {
1445:                        }
1446:
1447:                        // if the connection is persistent it may have been closed
1448:                        // or returned to the keep-alive cache. If it's been returned
1449:                        // to the keep-alive cache then we would like to close it
1450:                        // but it may have been allocated
1451:
1452:                        if (ka) {
1453:                            hc.closeIdleConnection();
1454:                        }
1455:
1456:                    } else {
1457:                        http.closeServer();
1458:                    }
1459:
1460:                    //	    poster = null;
1461:                    http = null;
1462:                    connected = false;
1463:                }
1464:            }
1465:
1466:            public boolean usingProxy() {
1467:                if (http != null) {
1468:                    return (http.getProxyHostUsed() != null);
1469:                }
1470:                return false;
1471:            }
1472:
1473:            /**
1474:             * Gets a header field by name. Returns null if not known.
1475:             * @param name the name of the header field
1476:             */
1477:            public String getHeaderField(String name) {
1478:                try {
1479:                    getInputStream();
1480:                } catch (IOException e) {
1481:                }
1482:                return responses.findValue(name);
1483:            }
1484:
1485:            /**
1486:             * Returns an unmodifiable Map of the header fields.
1487:             * The Map keys are Strings that represent the
1488:             * response-header field names. Each Map value is an
1489:             * unmodifiable List of Strings that represents 
1490:             * the corresponding field values.
1491:             *
1492:             * @return a Map of header fields
1493:             * @since 1.4
1494:             */
1495:            public Map getHeaderFields() {
1496:                try {
1497:                    getInputStream();
1498:                } catch (IOException e) {
1499:                }
1500:                return responses.getHeaders();
1501:            }
1502:
1503:            /**
1504:             * Gets a header field by index. Returns null if not known.
1505:             * @param n the index of the header field
1506:             */
1507:            public String getHeaderField(int n) {
1508:                try {
1509:                    getInputStream();
1510:                } catch (IOException e) {
1511:                }
1512:                return responses.getValue(n);
1513:            }
1514:
1515:            /**
1516:             * Gets a header field by index. Returns null if not known.
1517:             * @param n the index of the header field
1518:             */
1519:            public String getHeaderFieldKey(int n) {
1520:                try {
1521:                    getInputStream();
1522:                } catch (IOException e) {
1523:                }
1524:                return responses.getKey(n);
1525:            }
1526:
1527:            /**
1528:             * Sets request property. If a property with the key already
1529:             * exists, overwrite its value with the new value.
1530:             * @param value the value to be set
1531:             */
1532:            public void setRequestProperty(String key, String value) {
1533:                super .setRequestProperty(key, value);
1534:                checkMessageHeader(key, value);
1535:                requests.set(key, value);
1536:            }
1537:
1538:            /**
1539:             * Adds a general request property specified by a
1540:             * key-value pair.  This method will not overwrite
1541:             * existing values associated with the same key.
1542:             *
1543:             * @param   key     the keyword by which the request is known
1544:             *                  (e.g., "<code>accept</code>").
1545:             * @param   value  the value associated with it.
1546:             * @see #getRequestProperties(java.lang.String)
1547:             * @since 1.4
1548:             */
1549:            public void addRequestProperty(String key, String value) {
1550:                super .addRequestProperty(key, value);
1551:                checkMessageHeader(key, value);
1552:                requests.add(key, value);
1553:            }
1554:
1555:            //
1556:            // Set a property for authentication.  This can safely disregard
1557:            // the connected test.
1558:            //
1559:            void setAuthenticationProperty(String key, String value) {
1560:                checkMessageHeader(key, value);
1561:                requests.set(key, value);
1562:            }
1563:
1564:            public String getRequestProperty(String key) {
1565:                // don't return headers containing security sensitive information
1566:                if (key != null) {
1567:                    for (int i = 0; i < EXCLUDE_HEADERS.length; i++) {
1568:                        if (key.equalsIgnoreCase(EXCLUDE_HEADERS[i])) {
1569:                            return null;
1570:                        }
1571:                    }
1572:                }
1573:                return requests.findValue(key);
1574:            }
1575:
1576:            /**
1577:             * Returns an unmodifiable Map of general request
1578:             * properties for this connection. The Map keys
1579:             * are Strings that represent the request-header
1580:             * field names. Each Map value is a unmodifiable List 
1581:             * of Strings that represents the corresponding 
1582:             * field values.
1583:             *
1584:             * @return  a Map of the general request properties for this connection.
1585:             * @throws IllegalStateException if already connected
1586:             * @since 1.4
1587:             */
1588:            public Map getRequestProperties() {
1589:                if (connected)
1590:                    throw new IllegalStateException("Already connected");
1591:
1592:                // exclude headers containing security-sensitive info
1593:                return requests.getHeaders(EXCLUDE_HEADERS);
1594:            }
1595:
1596:            public void finalize() {
1597:                // this should do nothing.  The stream finalizer will close 
1598:                // the fd
1599:            }
1600:
1601:            String getMethod() {
1602:                return method;
1603:            }
1604:
1605:            /* The purpose of this wrapper is just to capture the close() call
1606:             * so we can check authentication information that may have
1607:             * arrived in a Trailer field
1608:             */
1609:            class HttpInputStream extends FilterInputStream {
1610:
1611:                public HttpInputStream(InputStream is) {
1612:                    super (is);
1613:                }
1614:
1615:                public void close() throws IOException {
1616:                    try {
1617:                        super .close();
1618:                    } finally {
1619:                        HttpURLConnection.this .http = null;
1620:                        checkResponseCredentials(true);
1621:                    }
1622:                }
1623:            }
1624:        }
1625:
1626:        /** An input stream that just returns EOF.  This is for
1627:         * HTTP URLConnections that are KeepAlive && use the
1628:         * HEAD method - i.e., stream not dead, but nothing to be read.
1629:         */
1630:
1631:        class EmptyInputStream extends InputStream {
1632:
1633:            public int available() {
1634:                return 0;
1635:            }
1636:
1637:            public int read() {
1638:                return -1;
1639:            }
1640:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.