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


001:        /*
002:         * @(#)HttpClient.java	1.124 06/10/10
003:         *
004:         * Copyright  1990-2006 Sun Microsystems, Inc. All Rights Reserved.  
005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER  
006:         *   
007:         * This program is free software; you can redistribute it and/or  
008:         * modify it under the terms of the GNU General Public License version  
009:         * 2 only, as published by the Free Software Foundation.   
010:         *   
011:         * This program is distributed in the hope that it will be useful, but  
012:         * WITHOUT ANY WARRANTY; without even the implied warranty of  
013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  
014:         * General Public License version 2 for more details (a copy is  
015:         * included at /legal/license.txt).   
016:         *   
017:         * You should have received a copy of the GNU General Public License  
018:         * version 2 along with this work; if not, write to the Free Software  
019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  
020:         * 02110-1301 USA   
021:         *   
022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa  
023:         * Clara, CA 95054 or visit www.sun.com if you need additional  
024:         * information or have any questions. 
025:         *
026:         */
027:
028:        package sun.net.www.http;
029:
030:        import java.io.*;
031:        import java.net.*;
032:        import java.util.*;
033:        import sun.net.NetworkClient;
034:        import sun.net.ProgressEntry;
035:        import sun.net.ProgressData;
036:        import sun.net.www.MessageHeader;
037:        import sun.net.www.HeaderParser;
038:        import sun.net.www.MeteredStream;
039:        import sun.misc.RegexpPool;
040:
041:        import java.security.*;
042:
043:        /**
044:         * @version 1.115, 08/30/01
045:         * @author Herb Jellinek
046:         * @author Dave Brown
047:         */
048:        public class HttpClient extends NetworkClient {
049:            // whether this httpclient comes from the cache
050:            protected boolean cachedHttpClient = false;
051:
052:            private boolean inCache;
053:
054:            // Http requests we send
055:            MessageHeader requests;
056:
057:            // Http data we send with the headers
058:            PosterOutputStream poster = null;
059:
060:            // if we've had one io error
061:            boolean failedOnce = false;
062:
063:            /** regexp pool of hosts for which we should connect directly, not Proxy
064:             *  these are intialized from a property.
065:             */
066:            private static RegexpPool nonProxyHostsPool = null;
067:
068:            /** The string source of nonProxyHostsPool
069:             */
070:            private static String nonProxyHostsSource = null;
071:
072:            /** Response code for CONTINUE */
073:            private static final int HTTP_CONTINUE = 100;
074:
075:            /** Default port number for http daemons. TODO: make these private */
076:            static final int httpPortNumber = 80;
077:
078:            /** return default port number (subclasses may override) */
079:            protected int getDefaultPort() {
080:                return httpPortNumber;
081:            }
082:
083:            /* The following three data members are left in for binary */
084:            /* backwards-compatibility.  Unfortunately, HotJava sets them directly */
085:            /* when it wants to change the settings.  The new design has us not */
086:            /* cache these, so this is unnecessary, but eliminating the data members */
087:            /* would break HJB 1.1 under JDK 1.2. */
088:            /* */
089:            /* These data members are not used, and their values are meaningless. */
090:            /* TODO:  Take them out for JDK 2.0! */
091:            /**
092:             * @deprecated
093:             */
094:            public static String proxyHost = null;
095:            /**
096:             * @deprecated
097:             */
098:            public static int proxyPort = 80;
099:
100:            /* instance-specific proxy fields override the static fields if set.
101:             * Used by FTP.  These are set to the true proxy host/port if
102:             * usingProxy is true.
103:             */
104:            private String instProxy = null;
105:            private int instProxyPort = -1;
106:
107:            /* All proxying (generic as well as instance-specific) may be
108:             * disabled through use of this flag
109:             */
110:            protected boolean proxyDisabled;
111:
112:            // are we using proxy in this instance?
113:            public boolean usingProxy = false;
114:            // target host, port for the URL
115:            protected String host;
116:            protected int port;
117:
118:            /* where we cache currently open, persistent connections */
119:            protected static KeepAliveCache kac = new KeepAliveCache();
120:
121:            private static boolean keepAliveProp = true;
122:
123:            volatile boolean keepingAlive = false; /* this is a keep-alive connection */
124:            int keepAliveConnections = -1; /* number of keep-alives left */
125:
126:            /**Idle timeout value, in milliseconds. Zero means infinity,
127:             * iff keepingAlive=true.
128:             * Unfortunately, we can't always believe this one.  If I'm connected
129:             * through a Netscape proxy to a server that sent me a keep-alive
130:             * time of 15 sec, the proxy unilaterally terminates my connection
131:             * after 5 sec.  So we have to hard code our effective timeout to
132:             * 4 sec for the case where we're using a proxy. *SIGH*
133:             */
134:            int keepAliveTimeout = 0;
135:
136:            /** Url being fetched. */
137:            protected URL url;
138:
139:            /* if set, the client will be reused and must not be put in cache */
140:            public boolean reuse = false;
141:
142:            /**
143:             * A NOP method kept for backwards binary compatibility
144:             * @deprecated -- system properties are no longer cached.
145:             */
146:            public static synchronized void resetProperties() {
147:            }
148:
149:            int getKeepAliveTimeout() {
150:                return keepAliveTimeout;
151:            }
152:
153:            /**
154:             * @return the proxy host to use, as defined by system properties.
155:             */
156:            private String getProxyHost() {
157:                String host = (String) java.security.AccessController
158:                        .doPrivileged(new sun.security.action.GetPropertyAction(
159:                                "http.proxyHost"));
160:                if (host == null) {
161:                    /* maintain compatibility with 1.0.2, before
162:                     * the properties namespace was so polluted
163:                     * and these properties were called, respectively,
164:                     * "proxyHost" "proxyPort".  Hopefully there won't
165:                     * be any conflicts.
166:                     */
167:                    host = (String) java.security.AccessController
168:                            .doPrivileged(new sun.security.action.GetPropertyAction(
169:                                    "proxyHost"));
170:                }
171:                if (host != null && host.length() == 0) {
172:                    /* System.getProp() will give us an empty String, ""
173:                     * for a defined but "empty" property.
174:                     */
175:                    host = null;
176:                }
177:                return host;
178:            }
179:
180:            /**
181:             * @return the proxy port to use, as defined by system properties
182:             */
183:            private int getProxyPort() {
184:                final int port[] = { 0 };
185:                java.security.AccessController
186:                        .doPrivileged(new java.security.PrivilegedAction() {
187:                            public Object run() {
188:                                if (System.getProperty("http.proxyHost") != null) {
189:                                    port[0] = Integer.getInteger(
190:                                            "http.proxyPort", 80).intValue();
191:                                } else {
192:                                    /* maintain compatibility with 1.0.2, before
193:                                     * the properties namespace was so polluted
194:                                     * and these properties were called, respectively,
195:                                     * "proxyHost" "proxyPort".  Hopefully there won't
196:                                     * be any conflicts.
197:                                     */
198:                                    port[0] = Integer.getInteger("proxyPort",
199:                                            80).intValue();
200:                                }
201:                                return null;
202:                            }
203:                        });
204:                return port[0];
205:            }
206:
207:            static {
208:                String keepAlive = (String) java.security.AccessController
209:                        .doPrivileged(new java.security.PrivilegedAction() {
210:                            public Object run() {
211:                                return System.getProperty("http.keepAlive");
212:                            }
213:                        });
214:                if (keepAlive != null) {
215:                    keepAliveProp = Boolean.valueOf(keepAlive).booleanValue();
216:                } else {
217:                    keepAliveProp = true;
218:                }
219:            }
220:
221:            /**
222:             * @return true iff http keep alive is set (i.e. enabled).  Defaults
223:             *		to true if the system property http.keepAlive isn't set.
224:             */
225:            public boolean getHttpKeepAliveSet() {
226:                return keepAliveProp;
227:            }
228:
229:            /** 
230:             * @return true if host matches a host specified via
231:             * the http.nonProxyHosts property
232:             */
233:            private boolean matchNonProxyHosts(String host) {
234:                synchronized (getClass()) {
235:                    String rawList = (String) java.security.AccessController
236:                            .doPrivileged(new sun.security.action.GetPropertyAction(
237:                                    "http.nonProxyHosts"));
238:                    if (rawList == null) {
239:                        nonProxyHostsPool = null;
240:                    } else {
241:                        if (!rawList.equals(nonProxyHostsSource)) {
242:                            RegexpPool pool = new RegexpPool();
243:                            StringTokenizer st = new StringTokenizer(rawList,
244:                                    "|", false);
245:                            try {
246:                                while (st.hasMoreTokens()) {
247:                                    pool.add(st.nextToken().toLowerCase(),
248:                                            Boolean.TRUE);
249:                                }
250:                            } catch (sun.misc.REException ex) {
251:                                System.err
252:                                        .println("Error in http.nonProxyHosts system property:  "
253:                                                + ex);
254:                            }
255:                            nonProxyHostsPool = pool;
256:                        }
257:                    }
258:                    nonProxyHostsSource = rawList;
259:                }
260:
261:                /*
262:                 * Match against non-proxy hosts
263:                 */
264:                if (nonProxyHostsPool == null) {
265:                    return false;
266:                }
267:                if (nonProxyHostsPool.match(host) != null) {
268:                    return true;
269:                } else {
270:                    return false;
271:                }
272:            }
273:
274:            protected HttpClient() {
275:            }
276:
277:            private HttpClient(URL url) throws IOException {
278:                this (url, (String) null, -1, false);
279:            }
280:
281:            protected HttpClient(URL url, boolean proxyDisabled)
282:                    throws IOException {
283:                this (url, null, -1, proxyDisabled);
284:            }
285:
286:            /* This package-only CTOR should only be used for FTP piggy-backed on HTTP
287:             * HTTP URL's that use this won't take advantage of keep-alive.
288:             * Additionally, this constructor may be used as a last resort when the
289:             * first HttpClient gotten through New() failed (probably b/c of a
290:             * Keep-Alive mismatch).
291:             *
292:             * NOTE: That documentation is wrong ... it's not package-private any more
293:             */
294:            public HttpClient(URL url, String proxy, int proxyPort)
295:                    throws IOException {
296:                this (url, proxy, proxyPort, false);
297:            }
298:
299:            /*
300:             * This constructor gives "ultimate" flexibility, including the ability
301:             * to bypass implicit proxying.  Sometimes we need to be using tunneling
302:             * (transport or network level) instead of proxying (application level),
303:             * for example when we don't want the application level data to become
304:             * visible to third parties.
305:             *
306:             * @param url		the URL to which we're connecting
307:             * @param proxy		proxy to use for this URL (e.g. forwarding)
308:             * @param proxyPort		proxy port to use for this URL
309:             * @param proxyDisabled	true to disable default proxying
310:             */
311:            private HttpClient(URL url, String proxy, int proxyPort,
312:                    boolean proxyDisabled) throws IOException {
313:
314:                this .proxyDisabled = proxyDisabled;
315:                if (!proxyDisabled) {
316:                    this .instProxy = proxy;
317:                    this .instProxyPort = (proxyPort < 0) ? getDefaultPort()
318:                            : proxyPort;
319:                }
320:                /* try to set host to "%d.%d.%d.%d" string if
321:                 * visible - Sprint bug - brown */
322:                try {
323:                    InetAddress addr = InetAddress.getByName(url.getHost());
324:                    this .host = addr.getHostAddress();
325:                } catch (UnknownHostException ignored) {
326:                    this .host = url.getHost();
327:                }
328:                this .url = url;
329:                port = url.getPort();
330:                if (port == -1) {
331:                    port = getDefaultPort();
332:                }
333:                openServer();
334:            }
335:
336:            /* This class has no public constructor for HTTP.  This method is used to
337:             * get an HttpClient to the specifed URL.  If there's currently an
338:             * active HttpClient to that server/port, you'll get that one.
339:             */
340:            public static HttpClient New(URL url) throws IOException {
341:                return HttpClient.New(url, true);
342:            }
343:
344:            public static HttpClient New(URL url, boolean useCache)
345:                    throws IOException {
346:                return HttpClient.New(url, (String) null, -1, useCache);
347:            }
348:
349:            public static HttpClient New(URL url, String proxy, int proxyPort,
350:                    boolean useCache) throws IOException {
351:                HttpClient ret = null;
352:                if (useCache) {
353:                    /* see if one's already around */
354:                    ret = (HttpClient) kac.get(url, null);
355:                    if (ret != null) {
356:                        synchronized (ret) {
357:                            ret.cachedHttpClient = true;
358:                            // Uncomment this line if assertions are always
359:                            //    turned on for libraries
360:                            //assert ret.inCache;
361:                            ret.inCache = false;
362:                        }
363:                    }
364:                }
365:                if (ret == null) {
366:                    ret = new HttpClient(url, proxy, proxyPort);
367:                } else {
368:                    SecurityManager security = System.getSecurityManager();
369:                    if (security != null) {
370:                        security.checkConnect(url.getHost(), url.getPort());
371:                    }
372:                    ret.url = url;
373:                }
374:
375:                return ret;
376:            }
377:
378:            /* return it to the cache as still usable, if:
379:             * 1) It's keeping alive, AND
380:             * 2) It still has some connections left, AND
381:             * 3) It hasn't had a error (PrintStream.checkError())
382:             * 4) It hasn't timed out
383:             *
384:             * If this client is not keepingAlive, it should have been
385:             * removed from the cache in the parseHeaders() method.
386:             */
387:
388:            public void finished() {
389:                if (reuse) /* will be reused */
390:                    return;
391:                keepAliveConnections--;
392:                if (keepAliveConnections > 0 && isKeepingAlive()
393:                        && !(serverOutput.checkError())) {
394:                    /* This connection is keepingAlive && still valid.
395:                     * Return it to the cache.
396:                     */
397:                    putInKeepAliveCache();
398:                } else {
399:                    closeServer();
400:                }
401:            }
402:
403:            protected synchronized void putInKeepAliveCache() {
404:                if (inCache) {
405:                    // Uncomment this line if assertions are always
406:                    //    turned on for libraries
407:                    //assert false : "Duplicate put to keep alive cache";
408:                    return;
409:                }
410:                inCache = true;
411:                kac.put(url, null, this );
412:            }
413:
414:            /*
415:             * Close an idle connection to this URL (if it exists in the
416:             * cache).
417:             */
418:            public void closeIdleConnection() {
419:                HttpClient http = (HttpClient) kac.get(url, null);
420:                if (http != null) {
421:                    http.closeServer();
422:                }
423:            }
424:
425:            /* We're very particular here about what our InputStream to the server
426:             * looks like for reasons that are apparent if you can decipher the
427:             * method parseHTTP().  That's why this method is overidden from the
428:             * superclass.
429:             */
430:            public void openServer(String server, int port) throws IOException {
431:                serverSocket = doConnect(server, port);
432:                try {
433:                    serverOutput = new PrintStream(new BufferedOutputStream(
434:                            serverSocket.getOutputStream()), false, encoding);
435:                } catch (UnsupportedEncodingException e) {
436:                    throw new InternalError(encoding + " encoding not found");
437:                }
438:                serverSocket.setTcpNoDelay(true);
439:            }
440:
441:            /*
442:             * Returns true if the http request should be tunneled through proxy.
443:             * An example where this is the case is Https.
444:             */
445:            public boolean needsTunneling() {
446:                return false;
447:            }
448:
449:            /*
450:             * Returns true if this httpclient is from cache
451:             */
452:            public boolean isCachedConnection() {
453:                return cachedHttpClient;
454:            }
455:
456:            /*
457:             * Finish any work left after the socket connection is
458:             * established.  In the normal http case, it's a NO-OP. Subclass
459:             * may need to override this. An example is Https, where for
460:             * direct connection to the origin server, ssl handshake needs to
461:             * be done; for proxy tunneling, the socket needs to be converted
462:             * into an SSL socket before ssl handshake can take place.
463:             */
464:            public void afterConnect() throws IOException, UnknownHostException {
465:                // NO-OP. Needs to be overwritten by HttpsClient
466:            }
467:
468:            /*
469:             * call openServer in a privileged block
470:             */
471:            private synchronized void privilegedOpenServer(
472:                    final String proxyHost, final int proxyPort)
473:                    throws IOException {
474:                try {
475:                    java.security.AccessController
476:                            .doPrivileged(new java.security.PrivilegedExceptionAction() {
477:                                public Object run() throws IOException {
478:                                    openServer(proxyHost, proxyPort);
479:                                    return null;
480:                                }
481:                            });
482:                } catch (java.security.PrivilegedActionException pae) {
483:                    throw (IOException) pae.getException();
484:                }
485:            }
486:
487:            /*
488:             * call super.openServer
489:             */
490:            private void super OpenServer(final String proxyHost,
491:                    final int proxyPort) throws IOException,
492:                    UnknownHostException {
493:                super .openServer(proxyHost, proxyPort);
494:            }
495:
496:            /*
497:             * call super.openServer in a privileged block
498:             */
499:            private synchronized void privilegedSuperOpenServer(
500:                    final String proxyHost, final int proxyPort)
501:                    throws IOException {
502:                try {
503:                    java.security.AccessController
504:                            .doPrivileged(new java.security.PrivilegedExceptionAction() {
505:                                public Object run() throws IOException {
506:                                    super OpenServer(proxyHost, proxyPort);
507:                                    return null;
508:                                }
509:                            });
510:                } catch (java.security.PrivilegedActionException pae) {
511:                    throw (IOException) pae.getException();
512:                }
513:            }
514:
515:            /**
516:             * Determines if the given host address is a loopback address or
517:             * not. Any IP address starting with 127 is a loopback address
518:             * although typically this is set to 127.0.0.1. A request for
519:             * the address "localhost" will also be treated as loopback.
520:             */
521:            private boolean isLoopback(String host) {
522:
523:                if (host == null || host.length() == 0)
524:                    return false;
525:
526:                if (host.equalsIgnoreCase("localhost"))
527:                    return true;
528:
529:                if (!Character.isDigit(host.charAt(0))) {
530:                    return false;
531:                } else {
532:                    /* The string (probably) represents a numerical IP address.
533:                     * Parse it into int's. Compare the first int
534:                     * component to 127 and return if it is not
535:                     * 127. Otherwise, just make sure the rest of the
536:                     * address is a valid address.
537:                     */
538:
539:                    boolean firstInt = true;
540:
541:                    int hitDots = 0;
542:                    char[] data = host.toCharArray();
543:
544:                    for (int i = 0; i < data.length; i++) {
545:                        char c = data[i];
546:                        if (c < 48 || c > 57) { // !digit
547:                            return false;
548:                        }
549:                        int b = 0x00; // the value of one integer component
550:                        while (c != '.') {
551:                            if (c < 48 || c > 57) { // !digit
552:                                return false;
553:                            }
554:                            b = b * 10 + c - '0';
555:
556:                            if (++i >= data.length)
557:                                break;
558:                            c = data[i];
559:                        }
560:                        if (b > 0xFF) { /* invalid - bigger than a byte */
561:                            return false;
562:                        }
563:
564:                        /* 
565:                         * If the first integer component is not 127 we may
566:                         * as well stop.
567:                         */
568:                        if (firstInt) {
569:                            firstInt = false;
570:                            if (b != 0x7F)
571:                                return false;
572:                        }
573:
574:                        hitDots++;
575:                    }
576:
577:                    if (hitDots != 4 || host.endsWith(".")) {
578:                        return false;
579:                    }
580:                }
581:
582:                return true;
583:            }
584:
585:            /*
586:             */
587:            protected synchronized void openServer() throws IOException {
588:
589:                SecurityManager security = System.getSecurityManager();
590:                if (security != null) {
591:                    security.checkConnect(host, port);
592:                }
593:
594:                if (keepingAlive) { // already opened
595:                    return;
596:                }
597:
598:                /* Try to open connections in this order, return on the
599:                 * first one that's successful:
600:                 * 1) if (instProxy != null)
601:                 *        connect to instProxy
602:                 *        _raise_exception_ if failure
603:                 *        usingProxy=true
604:                 * 2) if (proxyHost != null) and !(proxyDisabled || host is on dontProxy list)
605:                 *        connect to proxyHost;
606:                 *        usingProxy=true;
607:                 * 3) connect locally
608:                 *    usingProxy = false;
609:                 */
610:
611:                String urlHost = url.getHost().toLowerCase();
612:                boolean loopback = isLoopback(urlHost);
613:
614:                if (url.getProtocol().equals("http")
615:                        || url.getProtocol().equals("https")) {
616:
617:                    if ((instProxy != null) && !loopback) {
618:                        privilegedOpenServer(instProxy, instProxyPort);
619:                        usingProxy = true;
620:                        return;
621:                    }
622:
623:                    String proxyHost = getProxyHost();
624:                    if ((proxyHost != null)
625:                            && (!(proxyDisabled || loopback
626:                                    || matchNonProxyHosts(urlHost) || matchNonProxyHosts(host)))) {
627:                        try {
628:                            int proxyPort = getProxyPort();
629:                            privilegedOpenServer(proxyHost, proxyPort);
630:                            instProxy = proxyHost;
631:                            instProxyPort = proxyPort;
632:                            usingProxy = true;
633:                            return;
634:                        } catch (IOException e) {
635:                            // continue in this case - try locally
636:                        }
637:                    }
638:                    // try locally - let Exception get raised
639:                    openServer(host, port);
640:                    usingProxy = false;
641:                    return;
642:
643:                } else {
644:                    /* we're opening some other kind of url, most likely an
645:                     * ftp url. In this case:
646:                     * 1) try instProxy (== FTP proxy)
647:                     * 2) try HttpProxy
648:                     * 3) directly
649:                     */
650:                    if ((instProxy != null) && !loopback) {
651:                        privilegedSuperOpenServer(instProxy, instProxyPort);
652:                        usingProxy = true;
653:                        return;
654:                    }
655:
656:                    String proxyHost = getProxyHost();
657:                    if ((proxyHost != null)
658:                            && (!(proxyDisabled || loopback
659:                                    || matchNonProxyHosts(urlHost) || matchNonProxyHosts(host)))) {
660:                        try {
661:                            int proxyPort = getProxyPort();
662:                            privilegedSuperOpenServer(proxyHost, proxyPort);
663:                            instProxy = proxyHost;
664:                            instProxyPort = proxyPort;
665:                            usingProxy = true;
666:                            return;
667:                        } catch (IOException e) {
668:                            // continue in this case - try locally
669:                        }
670:                    }
671:                    // try locally
672:                    super .openServer(host, port);
673:                    usingProxy = false;
674:                    return;
675:                }
676:            }
677:
678:            public String getURLFile() throws IOException {
679:
680:                String fileName = url.getFile();
681:                if ((fileName == null) || (fileName.length() == 0))
682:                    fileName = "/";
683:
684:                if (usingProxy) {
685:                    fileName = url.toExternalForm();
686:                }
687:                if (fileName.indexOf('\n') == -1)
688:                    return fileName;
689:                else
690:                    throw new java.net.MalformedURLException(
691:                            "Illegal character in URL");
692:            }
693:
694:            /**
695:             * @deprecated 
696:             */
697:
698:            public void writeRequests(MessageHeader head) {
699:                requests = head;
700:                requests.print(serverOutput);
701:                serverOutput.flush();
702:            }
703:
704:            public void writeRequests(MessageHeader head, PosterOutputStream pos)
705:                    throws IOException {
706:                requests = head;
707:                requests.print(serverOutput);
708:                poster = pos;
709:                if (poster != null)
710:                    poster.writeTo(serverOutput);
711:                serverOutput.flush();
712:            }
713:
714:            /** Parse the first line of the HTTP request.  It usually looks
715:            something like: "HTTP/1.0 <number> comment\r\n". */
716:
717:            public boolean parseHTTP(MessageHeader responses, ProgressEntry pe)
718:                    throws IOException {
719:                /* If "HTTP/*" is found in the beginning, return true.  Let
720:                 * HttpURLConnection parse the mime header itself.
721:                 *
722:                 * If this isn't valid HTTP, then we don't try to parse a header
723:                 * out of the beginning of the response into the responses,
724:                 * and instead just queue up the output stream to it's very beginning.
725:                 * This seems most reasonable, and is what the NN browser does.
726:                 */
727:
728:                try {
729:                    serverInput = serverSocket.getInputStream();
730:                    serverInput = new BufferedInputStream(serverInput);
731:                    return (parseHTTPHeader(responses, pe));
732:                } catch (IOException e) {
733:                    closeServer();
734:                    if (!failedOnce && requests != null) {
735:                        // try once more
736:                        failedOnce = true;
737:                        openServer();
738:                        writeRequests(requests, poster);
739:                        return parseHTTP(responses, pe);
740:                    } else {
741:                        throw e;
742:                    }
743:                }
744:
745:            }
746:
747:            public int setTimeout(int timeout) throws SocketException {
748:                int old = serverSocket.getSoTimeout();
749:                serverSocket.setSoTimeout(timeout);
750:                return old;
751:            }
752:
753:            private boolean parseHTTPHeader(MessageHeader responses,
754:                    ProgressEntry pe) throws IOException {
755:                /* If "HTTP/*" is found in the beginning, return true.  Let
756:                 * HttpURLConnection parse the mime header itself.
757:                 *
758:                 * If this isn't valid HTTP, then we don't try to parse a header
759:                 * out of the beginning of the response into the responses,
760:                 * and instead just queue up the output stream to it's very beginning.
761:                 * This seems most reasonable, and is what the NN browser does.
762:                 */
763:
764:                keepAliveConnections = -1;
765:                keepAliveTimeout = 0;
766:
767:                boolean ret = false;
768:                byte[] b = new byte[8];
769:
770:                try {
771:                    int nread = 0;
772:                    serverInput.mark(10);
773:                    while (nread < 8) {
774:                        int r = serverInput.read(b, nread, 8 - nread);
775:                        if (r < 0) {
776:                            break;
777:                        }
778:                        nread += r;
779:                    }
780:                    String keep = null;
781:                    ret = b[0] == 'H' && b[1] == 'T' && b[2] == 'T'
782:                            && b[3] == 'P' && b[4] == '/' && b[5] == '1'
783:                            && b[6] == '.';
784:                    serverInput.reset();
785:                    if (ret) { // is valid HTTP - response started w/ "HTTP/1."
786:                        responses.parseHeader(serverInput);
787:                        /* decide if we're keeping alive:
788:                         * Note:  There's a spec, but most current
789:                         * servers (10/1/96) that support this differ in dialects.
790:                         * If the server/client misunderstand each other, the
791:                         * protocol should fall back onto HTTP/1.0, no keep-alive.
792:                         */
793:                        if (usingProxy) { // not likely a proxy will return this
794:                            keep = responses.findValue("Proxy-Connection");
795:                        }
796:                        if (keep == null) {
797:                            keep = responses.findValue("Connection");
798:                        }
799:                        if (keep != null
800:                                && keep.toLowerCase().equals("keep-alive")) {
801:                            /* some servers, notably Apache1.1, send something like:
802:                             * "Keep-Alive: timeout=15, max=1" which we should respect.
803:                             */
804:                            HeaderParser p = new HeaderParser(responses
805:                                    .findValue("Keep-Alive"));
806:                            if (p != null) {
807:                                /* default should be larger in case of proxy */
808:                                keepAliveConnections = p.findInt("max",
809:                                        usingProxy ? 50 : 5);
810:                                keepAliveTimeout = p.findInt("timeout",
811:                                        usingProxy ? 60 : 5);
812:                            }
813:                        } else if (b[7] != '0') {
814:                            /*
815:                             * We're talking 1.1 or later. Keep persistent until
816:                             * the server says to close.
817:                             */
818:                            if (keep != null) {
819:                                /*
820:                                 * The only Connection token we understand is close.
821:                                 * Paranoia: if there is any Connection header then
822:                                 * treat as non-persistent.
823:                                 */
824:                                keepAliveConnections = 1;
825:                            } else {
826:                                keepAliveConnections = 5;
827:                            }
828:                        }
829:                    } else if (nread != 8) {
830:                        if (!failedOnce && requests != null) {
831:                            failedOnce = true;
832:                            closeServer();
833:                            openServer();
834:                            writeRequests(requests, poster);
835:                            return parseHTTP(responses, pe);
836:                        }
837:                        throw new SocketException(
838:                                "Unexpected end of file from server");
839:                    } else {
840:                        // we can't vouche for what this is....
841:                        responses.set("Content-type", "unknown/unknown");
842:                    }
843:                } catch (IOException e) {
844:                    throw e;
845:                }
846:
847:                int code = -1;
848:                try {
849:                    String resp;
850:                    resp = responses.getValue(0);
851:                    /* should have no leading/trailing LWS
852:                     * expedite the typical case by assuming it has
853:                     * form "HTTP/1.x <WS> 2XX <mumble>"
854:                     */
855:                    int ind;
856:                    ind = resp.indexOf(' ');
857:                    while (resp.charAt(ind) == ' ')
858:                        ind++;
859:                    code = Integer.parseInt(resp.substring(ind, ind + 3));
860:                } catch (Exception e) {
861:                }
862:
863:                if (code == HTTP_CONTINUE) {
864:                    responses.reset();
865:                    return parseHTTPHeader(responses, pe);
866:                }
867:
868:                int cl = -1;
869:
870:                /*
871:                 * Set things up to parse the entity body of the reply.
872:                 * We should be smarter about avoid pointless work when
873:                 * the HTTP method and response code indicate there will be
874:                 * no entity body to parse.
875:                 */
876:                String te = null;
877:                try {
878:                    te = responses.findValue("Transfer-Encoding");
879:                } catch (Exception e) {
880:                }
881:                if (te != null && te.equalsIgnoreCase("chunked")) {
882:                    serverInput = new ChunkedInputStream(serverInput, this ,
883:                            responses);
884:
885:                    /*
886:                     * If keep alive not specified then close after the stream
887:                     * has completed.
888:                     */
889:                    if (keepAliveConnections < 0) {
890:                        keepAliveConnections = 1;
891:                    }
892:                    keepingAlive = true;
893:                    failedOnce = false;
894:                } else {
895:
896:                    /* 
897:                     * If it's a keep alive connection then we will keep 
898:                     * (alive if :-
899:                     * 1. content-length is specified, or 
900:                     * 2. "Not-Modified" or "No-Content" responses - RFC 2616 states that  
901:                     *    204 or 304 response must not include a message body. 
902:                     */
903:                    try {
904:                        cl = Integer.parseInt(responses
905:                                .findValue("content-length"));
906:                    } catch (Exception e) {
907:                    }
908:
909:                    if (keepAliveConnections > 1
910:                            && (cl >= 0
911:                                    || code == HttpURLConnection.HTTP_NOT_MODIFIED || code == HttpURLConnection.HTTP_NO_CONTENT)) {
912:                        keepingAlive = true;
913:                    } else if (keepingAlive) {
914:                        /* Previously we were keeping alive, and now we're not.  Remove
915:                         * this from the cache (but only here, once) - otherwise we get
916:                         * multiple removes and the cache count gets messed up.
917:                         */
918:                        keepingAlive = false;
919:                    }
920:                }
921:
922:                /* finally wrap a KeepAlive/MeteredStream around it if appropriate */
923:                if (cl > 0) {
924:                    pe.setType(url.getFile(), responses
925:                            .findValue("content-type"));
926:                    pe.update(0, cl);
927:                    if (isKeepingAlive()) {
928:                        serverInput = new KeepAliveStream(serverInput, pe, this );
929:                        failedOnce = false;
930:                    } else {
931:                        serverInput = new MeteredStream(serverInput, pe);
932:                    }
933:                } else {
934:                    ProgressData.pdata.unregister(pe);
935:                }
936:                return ret;
937:            }
938:
939:            public synchronized InputStream getInputStream() {
940:                return serverInput;
941:            }
942:
943:            public OutputStream getOutputStream() {
944:                return serverOutput;
945:            }
946:
947:            public String toString() {
948:                return getClass().getName() + "(" + url + ")";
949:            }
950:
951:            public final boolean isKeepingAlive() {
952:                return getHttpKeepAliveSet() && keepingAlive;
953:            }
954:
955:            protected void finalize() throws Throwable {
956:                // This should do nothing.  The stream finalizer will
957:                // close the fd.
958:            }
959:
960:            /* Use only on connections in error. */
961:            public void closeServer() {
962:                try {
963:                    keepingAlive = false;
964:                    serverSocket.close();
965:                } catch (Exception e) {
966:                }
967:            }
968:
969:            /**
970:             * @return the proxy host being used for this client, or null
971:             *		if we're not going through a proxy
972:             */
973:            public String getProxyHostUsed() {
974:                if (!usingProxy) {
975:                    return null;
976:                } else {
977:                    return instProxy;
978:                }
979:            }
980:
981:            /**
982:             * @return the proxy port being used for this client.  Meaningless
983:             *		if getProxyHostUsed() gives null.
984:             */
985:            public int getProxyPortUsed() {
986:                return instProxyPort;
987:            }
988:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.