Source Code Cross Referenced for HTTPConnection.java in  » Net » SkunkDAV » HTTPClient » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /*
0002:         * @(#)HTTPConnection.java				0.3-2 18/06/1999
0003:         *
0004:         *  This file is part of the HTTPClient package
0005:         *  Copyright (C) 1996-1999  Ronald Tschalär
0006:         *
0007:         *  This library is free software; you can redistribute it and/or
0008:         *  modify it under the terms of the GNU Lesser General Public
0009:         *  License as published by the Free Software Foundation; either
0010:         *  version 2 of the License, or (at your option) any later version.
0011:         *
0012:         *  This library is distributed in the hope that it will be useful,
0013:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015:         *  Lesser General Public License for more details.
0016:         *
0017:         *  You should have received a copy of the GNU Lesser General Public
0018:         *  License along with this library; if not, write to the Free
0019:         *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
0020:         *  MA 02111-1307, USA
0021:         *
0022:         *  For questions, suggestions, bug-reports, enhancement-requests etc.
0023:         *  I may be contacted at:
0024:         *
0025:         *  ronald@innovation.ch
0026:         *
0027:         */
0028:
0029:        package HTTPClient;
0030:
0031:        import java.io.OutputStream;
0032:        import java.io.DataOutputStream;
0033:        import java.io.FilterOutputStream;
0034:        import java.io.ByteArrayOutputStream;
0035:        import java.io.IOException;
0036:        import java.io.InterruptedIOException;
0037:        import java.net.URL;
0038:        import java.net.Socket;
0039:        import java.net.InetAddress;
0040:        import java.net.SocketException;
0041:        import java.net.UnknownHostException;
0042:        import java.util.Vector;
0043:        import java.util.Hashtable;
0044:        import java.applet.Applet;
0045:
0046:        /**
0047:         * This class implements http protocol requests; it contains most of HTTP/1.1
0048:         * and ought to be unconditionally compliant.
0049:         * Redirections are automatically handled, and authorizations requests are
0050:         * recognized and dealt with via an authorization handler.
0051:         * Only full HTTP/1.0 and HTTP/1.1 requests are generated. HTTP/1.1, HTTP/1.0
0052:         * and HTTP/0.9 responses are recognized.
0053:         *
0054:         * <P>Using the HTTPClient should be quite simple. First add the import
0055:         * statement '<code>import HTTPClient.*;</code>' to your file(s). Request
0056:         * can then be sent using one of the methods <var>Head()</var>,
0057:         * <var>Get()</var>, <var>Post()</var>, etc in <var>HTTPConnection</var>.
0058:         * These methods all return an instance of <var>HTTPResponse</var> which
0059:         * has methods for accessing the response headers (<var>getHeader()</var>,
0060:         * <var>getHeaderAsInt()</var>, etc), various response info
0061:         * (<var>getStatusCode()</var>, <var>getReasonLine()</var>, etc) and the
0062:         * reponse data (<var>getData()</var> and <var>getInputStream()</var>).
0063:         * Following are some examples.
0064:         *
0065:         * <P>If this is in an applet you can retrieve files from your server
0066:         * as follows:
0067:         *
0068:         * <PRE>
0069:         *     try
0070:         *     {
0071:         *         HTTPConnection con = new HTTPConnection(this);
0072:         *         HTTPResponse   rsp = con.Get("/my_file");
0073:         *         if (rsp.getStatusCode() >= 300)
0074:         *         {
0075:         *             System.err.println("Received Error: "+rsp.getReasonLine());
0076:         *             System.err.println(new String(rsp.getData()));
0077:         *         }
0078:         *         else
0079:         *             data = rsp.getData();
0080:         *
0081:         *         rsp = con.Get("/another_file");
0082:         *         if (rsp.getStatusCode() >= 300)
0083:         *         {
0084:         *             System.err.println("Received Error: "+rsp.getReasonLine());
0085:         *             System.err.println(new String(rsp.getData()));
0086:         *         }
0087:         *         else
0088:         *             other_data = rsp.getData();
0089:         *     }
0090:         *     catch (IOException ioe)
0091:         *     {
0092:         *         System.err.println(ioe.toString());
0093:         *     }
0094:         *     catch (ModuleException me)
0095:         *     {
0096:         *         System.err.println("Error handling request: " + me.getMessage());
0097:         *     }
0098:         * </PRE>
0099:         *
0100:         * This will get the files "/my_file" and "/another_file" and put their
0101:         * contents into byte[]s accessible via <code>getData()</code>. Note that
0102:         * you need to only create a new <var>HTTPConnection</var> when sending a
0103:         * request to a new server (different host or port); although you may create
0104:         * a new <var>HTTPConnection</var> for every request to the same server this
0105:         * <strong>not</strong> recommended, as various information about the server
0106:         * is cached after the first request (to optimize subsequent requests) and
0107:         * persistent connections are used whenever possible.
0108:         *
0109:         * <P>To POST form data you would use something like this (assuming you
0110:         * have two fields called <var>name</var> and <var>e-mail</var>, whose
0111:         * contents are stored in the variables <var>name</var> and <var>email</var>):
0112:         *
0113:         * <PRE>
0114:         *     try
0115:         *     {
0116:         *         NVPair form_data[] = new NVPair[2];
0117:         *         form_data[0] = new NVPair("name", name);
0118:         *         form_data[1] = new NVPair("e-mail", email);
0119:         *
0120:         *         HTTPConnection con = new HTTPConnection(this);
0121:         *         HTTPResponse   rsp = con.Post("/cgi-bin/my_script", form_data);
0122:         *         if (rsp.getStatusCode() >= 300)
0123:         *         {
0124:         *             System.err.println("Received Error: "+rsp.getReasonLine());
0125:         *             System.err.println(new String(rsp.getData()));
0126:         *         }
0127:         *         else
0128:         *             stream = rsp.getInputStream();
0129:         *     }
0130:         *     catch (IOException ioe)
0131:         *     {
0132:         *         System.err.println(ioe.toString());
0133:         *     }
0134:         *     catch (ModuleException me)
0135:         *     {
0136:         *         System.err.println("Error handling request: " + me.getMessage());
0137:         *     }
0138:         * </PRE>
0139:         *
0140:         * Here the response data is read at leasure via an <var>InputStream</var>
0141:         * instead of all at once into a <var>byte[]</var>.
0142:         *
0143:         * <P>As another example, if you have a URL you're trying to send a request
0144:         * to you would do something like the following:
0145:         *
0146:         * <PRE>
0147:         *     try
0148:         *     {
0149:         *         URL url = new URL("http://www.mydomain.us/test/my_file");
0150:         *         HTTPConnection con = new HTTPConnection(url);
0151:         *         HTTPResponse   rsp = con.Put(url.getFile(), "Hello World");
0152:         *         if (rsp.getStatusCode() >= 300)
0153:         *         {
0154:         *             System.err.println("Received Error: "+rsp.getReasonLine());
0155:         *             System.err.println(new String(rsp.getData()));
0156:         *         }
0157:         *         else
0158:         *             data = rsp.getData();
0159:         *     }
0160:         *     catch (IOException ioe)
0161:         *     {
0162:         *         System.err.println(ioe.toString());
0163:         *     }
0164:         *     catch (ModuleException me)
0165:         *     {
0166:         *         System.err.println("Error handling request: " + me.getMessage());
0167:         *     }
0168:         * </PRE>
0169:         *
0170:         * <P>There are a whole number of methods for each request type; however the
0171:         * general forms are ([...] means that the enclosed is optional):
0172:         * <ul>
0173:         * <li> Head ( file [, form-data [, headers ] ] )
0174:         * <li> Head ( file [, query [, headers ] ] )
0175:         * <li> Get ( file [, form-data [, headers ] ] )
0176:         * <li> Get ( file [, query [, headers ] ] )
0177:         * <li> Post ( file [, form-data [, headers ] ] )
0178:         * <li> Post ( file [, data [, headers ] ] )
0179:         * <li> Post ( file [, stream [, headers ] ] )
0180:         * <li> Put ( file , data [, headers ] )
0181:         * <li> Put ( file , stream [, headers ] )
0182:         * <li> Delete ( file [, headers ] )
0183:         * <li> Options ( file [, headers [, data] ] )
0184:         * <li> Options ( file [, headers [, stream] ] )
0185:         * <li> Trace ( file [, headers ] )
0186:         * </ul>
0187:         *
0188:         * @version	0.3-2  18/06/1999
0189:         * @author	Ronald Tschalär
0190:         */
0191:
0192:        public class HTTPConnection implements  GlobalConstants,
0193:                HTTPClientModuleConstants {
0194:            /** The current version of this package. */
0195:            public final static String version = "RPT-HTTPClient/0.3-2";
0196:
0197:            /** The default context */
0198:            private final static Object dflt_context = new Object();
0199:
0200:            /** The current context */
0201:            private Object Context = null;
0202:
0203:            /** The protocol used on this connection */
0204:            private int Protocol;
0205:
0206:            /** The server's protocol version; M.m stored as (M<<16 | m) */
0207:            int ServerProtocolVersion;
0208:
0209:            /** Have we gotten the server's protocol version yet? */
0210:            boolean ServProtVersKnown;
0211:
0212:            /** The protocol version we send in a request; this is always HTTP/1.1
0213:            unless we're talking to a broken server in which case it's HTTP/1.0 */
0214:            private String RequestProtocolVersion;
0215:
0216:            /** hack to force buffering of data instead of using chunked T-E */
0217:            private static boolean no_chunked = false;
0218:
0219:            /** hack to force HTTP/1.0 requests */
0220:            private static boolean force_1_0 = false;
0221:
0222:            /** The remote host this connection is associated with */
0223:            private String Host;
0224:
0225:            /** The remote port this connection is attached to */
0226:            private int Port;
0227:
0228:            /** The current proxy host to use (if any) */
0229:            private String Proxy_Host = null;
0230:
0231:            /** The current proxy port */
0232:            private int Proxy_Port;
0233:
0234:            /** The default proxy host to use (if any) */
0235:            private static String Default_Proxy_Host = null;
0236:
0237:            /** The default proxy port */
0238:            private static int Default_Proxy_Port;
0239:
0240:            /** The list of hosts for which no proxy is to be used */
0241:            private static CIHashtable non_proxy_host_list = new CIHashtable();
0242:            private static Vector non_proxy_dom_list = new Vector();
0243:            private static Vector non_proxy_addr_list = new Vector();
0244:            private static Vector non_proxy_mask_list = new Vector();
0245:
0246:            /** The socks server to use */
0247:            private SocksClient Socks_client = null;
0248:
0249:            /** The default socks server to use */
0250:            private static SocksClient Default_Socks_client = null;
0251:
0252:            /** the current stream demultiplexor */
0253:            private StreamDemultiplexor input_demux = null;
0254:
0255:            /** a list of active stream demultiplexors */
0256:            LinkedList DemuxList = new LinkedList();
0257:
0258:            /** a list of active requests */
0259:            private LinkedList RequestList = new LinkedList();
0260:
0261:            /** does the server support keep-alive's? */
0262:            private boolean DoesKeepAlive = false;
0263:
0264:            /** have we been able to determine the above yet? */
0265:            private boolean KeepAliveUnknown = true;
0266:
0267:            /** the maximum number of requests over a HTTP/1.0 keep-alive connection */
0268:            private int KeepAliveReqMax = -1;
0269:
0270:            /** the number of requests over a HTTP/1.0 keep-alive connection left */
0271:            private int KeepAliveReqLeft;
0272:
0273:            /** hack to be able to disable pipelining */
0274:            private static boolean NeverPipeline = false;
0275:
0276:            /** hack to be able to disable keep-alives */
0277:            private static boolean NoKeepAlives = false;
0278:
0279:            /** hack to work around M$ bug */
0280:            private static boolean haveMSLargeWritesBug = false;
0281:
0282:            /** the default timeout to use for new connections */
0283:            private static int DefaultTimeout = 0;
0284:
0285:            /** the timeout to use for reading responses */
0286:            private int Timeout;
0287:
0288:            /** The list of default http headers */
0289:            private NVPair[] DefaultHeaders = new NVPair[0];
0290:
0291:            /** The default list of modules (as a Vector of Class objects) */
0292:            private static Vector DefaultModuleList;
0293:
0294:            /** The list of modules (as a Vector of Class objects) */
0295:            private Vector ModuleList;
0296:
0297:            /** controls whether modules are allowed to interact with user */
0298:            private static boolean DefaultAllowUI = true;
0299:
0300:            /** controls whether modules are allowed to interact with user */
0301:            private boolean AllowUI;
0302:
0303:            static {
0304:                /*
0305:                 * Let's try and see if we can figure out whether any proxies are
0306:                 * being used.
0307:                 */
0308:
0309:                try // JDK 1.1 naming
0310:                {
0311:                    String host = System.getProperty("http.proxyHost");
0312:                    if (host == null)
0313:                        throw new Exception(); // try JDK 1.0.x naming
0314:                    int port = Integer.getInteger("http.proxyPort", -1)
0315:                            .intValue();
0316:
0317:                    if (DebugConn)
0318:                        System.err.println("Conn:  using proxy " + host + ":"
0319:                                + port);
0320:                    setProxyServer(host, port);
0321:                } catch (Exception e) {
0322:                    try // JDK 1.0.x naming
0323:                    {
0324:                        if (Boolean.getBoolean("proxySet")) {
0325:                            String host = System.getProperty("proxyHost");
0326:                            int port = Integer.getInteger("proxyPort", -1)
0327:                                    .intValue();
0328:                            if (DebugConn)
0329:                                System.err.println("Conn:  using proxy " + host
0330:                                        + ":" + port);
0331:                            setProxyServer(host, port);
0332:                        }
0333:                    } catch (Exception ee) {
0334:                        Default_Proxy_Host = null;
0335:                    }
0336:                }
0337:
0338:                /*
0339:                 * now check for the non-proxy list
0340:                 */
0341:                try {
0342:                    String hosts = System
0343:                            .getProperty("HTTPClient.nonProxyHosts");
0344:                    if (hosts == null)
0345:                        hosts = System.getProperty("http.nonProxyHosts");
0346:
0347:                    String[] list = Util.splitProperty(hosts);
0348:                    dontProxyFor(list);
0349:                } catch (RuntimeException e) {
0350:                }
0351:
0352:                /*
0353:                 * we can't turn the JDK SOCKS handling off, so we don't use the
0354:                 * properties 'socksProxyHost' and 'socksProxyPort'. Instead we
0355:                 * define 'HTTPClient.socksHost', 'HTTPClient.socksPort' and
0356:                 * 'HTTPClient.socksVersion'.
0357:                 */
0358:                try {
0359:                    String host = System.getProperty("HTTPClient.socksHost");
0360:                    if (host != null && host.length() > 0) {
0361:                        int port = Integer.getInteger("HTTPClient.socksPort",
0362:                                -1).intValue();
0363:                        int version = Integer.getInteger(
0364:                                "HTTPClient.socksVersion", -1).intValue();
0365:                        if (DebugConn)
0366:                            System.err.println("Conn:  using SOCKS " + host
0367:                                    + ":" + port);
0368:                        if (version == -1)
0369:                            setSocksServer(host, port);
0370:                        else
0371:                            setSocksServer(host, port, version);
0372:                    }
0373:                } catch (Exception e) {
0374:                    Default_Socks_client = null;
0375:                }
0376:
0377:                // Set up module list
0378:
0379:                String modules = "HTTPClient.RetryModule|"
0380:                        + "HTTPClient.CookieModule|"
0381:                        + "HTTPClient.RedirectionModule|"
0382:                        + "HTTPClient.AuthorizationModule|"
0383:                        + "HTTPClient.DefaultModule|"
0384:                        + "HTTPClient.TransferEncodingModule|"
0385:                        + "HTTPClient.ContentMD5Module|"
0386:                        + "HTTPClient.ContentEncodingModule";
0387:
0388:                boolean in_applet = false;
0389:                try {
0390:                    modules = System.getProperty("HTTPClient.Modules", modules);
0391:                } catch (SecurityException se) {
0392:                    in_applet = true;
0393:                }
0394:
0395:                DefaultModuleList = new Vector();
0396:                String[] list = Util.splitProperty(modules);
0397:                for (int idx = 0; idx < list.length; idx++) {
0398:                    try {
0399:                        DefaultModuleList.addElement(Class.forName(list[idx]));
0400:                        if (DebugConn)
0401:                            System.err.println("Conn:  added module "
0402:                                    + list[idx]);
0403:                    } catch (ClassNotFoundException cnfe) {
0404:                        if (!in_applet)
0405:                            throw new NoClassDefFoundError(cnfe.getMessage());
0406:
0407:                        /* Just ignore it. This allows for example applets to just
0408:                         * load the necessary modules - if you don't need a module
0409:                         * then don't provide it, and it won't be added to the
0410:                         * list. The disadvantage is that if you accidently misstype
0411:                         * a module name this will lead to a "silent" error.
0412:                         */
0413:                    }
0414:                }
0415:
0416:                /*
0417:                 * Hack: disable pipelining
0418:                 */
0419:                try {
0420:                    NeverPipeline = Boolean
0421:                            .getBoolean("HTTPClient.disable_pipelining");
0422:                    if (DebugConn)
0423:                        if (NeverPipeline)
0424:                            System.err.println("Conn:  disabling pipelining");
0425:                } catch (Exception e) {
0426:                }
0427:
0428:                /*
0429:                 * Hack: disable keep-alives
0430:                 */
0431:                try {
0432:                    NoKeepAlives = Boolean
0433:                            .getBoolean("HTTPClient.disableKeepAlives");
0434:                    if (DebugConn)
0435:                        if (NoKeepAlives)
0436:                            System.err.println("Conn:  disabling keep-alives");
0437:                } catch (Exception e) {
0438:                }
0439:
0440:                /*
0441:                 * Hack: force HTTP/1.0 requests
0442:                 */
0443:                try {
0444:                    force_1_0 = Boolean.getBoolean("HTTPClient.forceHTTP_1.0");
0445:                    if (DebugConn)
0446:                        if (force_1_0)
0447:                            System.err
0448:                                    .println("Conn:  forcing HTTP/1.0 requests");
0449:                } catch (Exception e) {
0450:                }
0451:
0452:                /*
0453:                 * Hack: prevent chunking of request data
0454:                 */
0455:                try {
0456:                    no_chunked = Boolean
0457:                            .getBoolean("HTTPClient.dontChunkRequests");
0458:                    if (DebugConn)
0459:                        if (no_chunked)
0460:                            System.err
0461:                                    .println("Conn:  never chunking requests");
0462:                } catch (Exception e) {
0463:                }
0464:
0465:                /*
0466:                 * M$ bug: large writes hang the stuff
0467:                 */
0468:                try {
0469:                    if (System.getProperty("os.name").indexOf("Windows") >= 0
0470:                            && System.getProperty("java.version").startsWith(
0471:                                    "1.1"))
0472:                        haveMSLargeWritesBug = true;
0473:                    if (DebugConn)
0474:                        if (haveMSLargeWritesBug)
0475:                            System.err
0476:                                    .println("Conn:  splitting large writes into 20K chunks (M$ bug)");
0477:                } catch (Exception e) {
0478:                }
0479:            }
0480:
0481:            // Constructors
0482:
0483:            /**
0484:             * Constructs a connection to the host from where the applet was loaded.
0485:             * Note that current security policies only let applets connect home.
0486:             *
0487:             * @param applet the current applet
0488:             */
0489:            public HTTPConnection(Applet applet)
0490:                    throws ProtocolNotSuppException {
0491:                this (applet.getCodeBase().getProtocol(), applet.getCodeBase()
0492:                        .getHost(), applet.getCodeBase().getPort());
0493:            }
0494:
0495:            /**
0496:             * Constructs a connection to the specified host on port 80
0497:             *
0498:             * @param host the host
0499:             */
0500:            public HTTPConnection(String host) {
0501:                Setup(HTTP, host, 80);
0502:            }
0503:
0504:            /**
0505:             * Constructs a connection to the specified host on the specified port
0506:             *
0507:             * @param host the host
0508:             * @param port the port
0509:             */
0510:            public HTTPConnection(String host, int port) {
0511:                Setup(HTTP, host, port);
0512:            }
0513:
0514:            /**
0515:             * Constructs a connection to the specified host on the specified port,
0516:             * using the specified protocol (currently only "http" is supported).
0517:             *
0518:             * @param prot the protocol
0519:             * @param host the host
0520:             * @param port the port, or -1 for the default port
0521:             * @exception ProtocolNotSuppException if the protocol is not HTTP
0522:             */
0523:            public HTTPConnection(String prot, String host, int port)
0524:                    throws ProtocolNotSuppException {
0525:                prot = prot.trim().toLowerCase();
0526:
0527:                if (!prot.equals("http") && !prot.equals("https"))
0528:                    //if (!prot.equals("http"))
0529:                    throw new ProtocolNotSuppException("Unsupported protocol '"
0530:                            + prot + "'");
0531:
0532:                if (prot.equals("http"))
0533:                    Setup(HTTP, host, port);
0534:                else if (prot.equals("https"))
0535:                    Setup(HTTPS, host, port);
0536:                else if (prot.equals("shttp"))
0537:                    Setup(SHTTP, host, port);
0538:                else if (prot.equals("http-ng"))
0539:                    Setup(HTTP_NG, host, port);
0540:            }
0541:
0542:            /**
0543:             * Constructs a connection to the host (port) as given in the url.
0544:             *
0545:             * @param     url the url
0546:             * @exception ProtocolNotSuppException if the protocol is not HTTP
0547:             */
0548:            public HTTPConnection(URL url) throws ProtocolNotSuppException {
0549:                this (url.getProtocol(), url.getHost(), url.getPort());
0550:            }
0551:
0552:            /**
0553:             * Sets the class variables. Must not be public.
0554:             *
0555:             * @param prot the protocol
0556:             * @param host the host
0557:             * @param port the port
0558:             */
0559:            private void Setup(int prot, String host, int port) {
0560:                Protocol = prot;
0561:                Host = host.trim().toLowerCase();
0562:                Port = port;
0563:
0564:                if (Port == -1)
0565:                    Port = URI.defaultPort(getProtocol());
0566:
0567:                if (Default_Proxy_Host != null && !matchNonProxy(Host))
0568:                    setCurrentProxy(Default_Proxy_Host, Default_Proxy_Port);
0569:                else
0570:                    setCurrentProxy(null, 0);
0571:
0572:                Socks_client = Default_Socks_client;
0573:                Timeout = DefaultTimeout;
0574:                ModuleList = (Vector) DefaultModuleList.clone();
0575:                AllowUI = DefaultAllowUI;
0576:                if (NoKeepAlives)
0577:                    setDefaultHeaders(new NVPair[] { new NVPair("Connection",
0578:                            "close") });
0579:            }
0580:
0581:            /**
0582:             * Determines if the given host matches any entry in the non-proxy list.
0583:             *
0584:             * @param host the host to match - must be trim()'d and lowercase
0585:             * @return true if a match is found, false otherwise
0586:             * @see #dontProxyFor(java.lang.String)
0587:             */
0588:            private boolean matchNonProxy(String host) {
0589:                // Check host name list
0590:
0591:                if (non_proxy_host_list.get(host) != null)
0592:                    return true;
0593:
0594:                // Check domain name list
0595:
0596:                for (int idx = 0; idx < non_proxy_dom_list.size(); idx++)
0597:                    if (host.endsWith((String) non_proxy_dom_list
0598:                            .elementAt(idx)))
0599:                        return true;
0600:
0601:                // Check IP-address and subnet list
0602:
0603:                if (non_proxy_addr_list.size() == 0)
0604:                    return false;
0605:
0606:                InetAddress[] host_addr;
0607:                try {
0608:                    host_addr = InetAddress.getAllByName(host);
0609:                } catch (UnknownHostException uhe) {
0610:                    return false;
0611:                } // maybe the proxy has better luck
0612:
0613:                for (int idx = 0; idx < non_proxy_addr_list.size(); idx++) {
0614:                    byte[] addr = (byte[]) non_proxy_addr_list.elementAt(idx);
0615:                    byte[] mask = (byte[]) non_proxy_mask_list.elementAt(idx);
0616:
0617:                    ip_loop: for (int idx2 = 0; idx2 < host_addr.length; idx2++) {
0618:                        byte[] raw_addr = host_addr[idx2].getAddress();
0619:                        if (raw_addr.length != addr.length)
0620:                            continue;
0621:
0622:                        for (int idx3 = 0; idx3 < raw_addr.length; idx3++) {
0623:                            if ((raw_addr[idx3] & mask[idx3]) != (addr[idx3] & mask[idx3]))
0624:                                continue ip_loop;
0625:                        }
0626:                        return true;
0627:                    }
0628:                }
0629:
0630:                return false;
0631:            }
0632:
0633:            // Methods
0634:
0635:            /**
0636:             * Sends the HEAD request. This request is just like the corresponding
0637:             * GET except that it only returns the headers and no data.
0638:             *
0639:             * @see #Get(java.lang.String)
0640:             * @param     file the absolute path of the file
0641:             * @return    an HTTPResponse structure containing the response
0642:             * @exception java.io.IOException when an exception is returned from
0643:             *                                the socket.
0644:             * @exception ModuleException if an exception is encountered in any module.
0645:             */
0646:            public HTTPResponse Head(String file) throws IOException,
0647:                    ModuleException {
0648:                return Head(file, (String) null, null);
0649:            }
0650:
0651:            /**
0652:             * Sends the HEAD request. This request is just like the corresponding
0653:             * GET except that it only returns the headers and no data.
0654:             *
0655:             * @see #Get(java.lang.String, HTTPClient.NVPair[])
0656:             * @param     file      the absolute path of the file
0657:             * @param     form_data an array of Name/Value pairs
0658:             * @return    an HTTPResponse structure containing the response
0659:             * @exception java.io.IOException when an exception is returned from
0660:             *                                the socket.
0661:             * @exception ModuleException if an exception is encountered in any module.
0662:             */
0663:            public HTTPResponse Head(String file, NVPair form_data[])
0664:                    throws IOException, ModuleException {
0665:                return Head(file, form_data, null);
0666:            }
0667:
0668:            /**
0669:             * Sends the HEAD request. This request is just like the corresponding
0670:             * GET except that it only returns the headers and no data.
0671:             *
0672:             * @see #Get(java.lang.String, HTTPClient.NVPair[], HTTPClient.NVPair[])
0673:             * @param     file      the absolute path of the file
0674:             * @param     form_data an array of Name/Value pairs
0675:             * @param     headers   additional headers
0676:             * @return    an HTTPResponse structure containing the response
0677:             * @exception java.io.IOException when an exception is returned from
0678:             *                                the socket.
0679:             * @exception ModuleException if an exception is encountered in any module.
0680:             */
0681:            public HTTPResponse Head(String file, NVPair[] form_data,
0682:                    NVPair[] headers) throws IOException, ModuleException {
0683:                String File = stripRef(file), query = Codecs
0684:                        .nv2query(form_data);
0685:                if (query != null && query.length() > 0)
0686:                    File += "?" + query;
0687:
0688:                return setupRequest("HEAD", File, headers, null, null);
0689:            }
0690:
0691:            /**
0692:             * Sends the HEAD request. This request is just like the corresponding
0693:             * GET except that it only returns the headers and no data.
0694:             *
0695:             * @see #Get(java.lang.String, java.lang.String)
0696:             * @param     file   the absolute path of the file
0697:             * @param     query   the query string; it will be urlencoded
0698:             * @return    an HTTPResponse structure containing the response
0699:             * @exception java.io.IOException when an exception is returned from
0700:             *                                the socket.
0701:             * @exception ModuleException if an exception is encountered in any module.
0702:             */
0703:            public HTTPResponse Head(String file, String query)
0704:                    throws IOException, ModuleException {
0705:                return Head(file, query, null);
0706:            }
0707:
0708:            /**
0709:             * Sends the HEAD request. This request is just like the corresponding
0710:             * GET except that it only returns the headers and no data.
0711:             *
0712:             * @see #Get(java.lang.String, java.lang.String, HTTPClient.NVPair[])
0713:             * @param     file    the absolute path of the file
0714:             * @param     query   the query string; it will be urlencoded
0715:             * @param     headers additional headers
0716:             * @return    an HTTPResponse structure containing the response
0717:             * @exception java.io.IOException when an exception is returned from
0718:             *                                the socket.
0719:             * @exception ModuleException if an exception is encountered in any module.
0720:             */
0721:            public HTTPResponse Head(String file, String query, NVPair[] headers)
0722:                    throws IOException, ModuleException {
0723:                String File = stripRef(file);
0724:                if (query != null && query.length() > 0)
0725:                    File += "?" + Codecs.URLEncode(query);
0726:
0727:                return setupRequest("HEAD", File, headers, null, null);
0728:            }
0729:
0730:            /**
0731:             * GETs the file.
0732:             *
0733:             * @param     file the absolute path of the file
0734:             * @return    an HTTPResponse structure containing the response
0735:             * @exception java.io.IOException when an exception is returned from
0736:             *                                the socket.
0737:             * @exception ModuleException if an exception is encountered in any module.
0738:             */
0739:            public HTTPResponse Get(String file) throws IOException,
0740:                    ModuleException {
0741:                return Get(file, (String) null, null);
0742:            }
0743:
0744:            /**
0745:             * GETs the file with a query consisting of the specified form-data.
0746:             * The data is urlencoded, turned into a string of the form
0747:             * "name1=value1&name2=value2" and then sent as a query string.
0748:             *
0749:             * @param     file       the absolute path of the file
0750:             * @param     form_data  an array of Name/Value pairs
0751:             * @return    an HTTPResponse structure containing the response
0752:             * @exception java.io.IOException when an exception is returned from
0753:             *                                the socket.
0754:             * @exception ModuleException if an exception is encountered in any module.
0755:             */
0756:            public HTTPResponse Get(String file, NVPair form_data[])
0757:                    throws IOException, ModuleException {
0758:                return Get(file, form_data, null);
0759:            }
0760:
0761:            /**
0762:             * GETs the file with a query consisting of the specified form-data.
0763:             * The data is urlencoded, turned into a string of the form
0764:             * "name1=value1&name2=value2" and then sent as a query string.
0765:             *
0766:             * @param     file       the absolute path of the file
0767:             * @param     form_data  an array of Name/Value pairs
0768:             * @param     headers    additional headers
0769:             * @return    an HTTPResponse structure containing the response
0770:             * @exception java.io.IOException when an exception is returned from
0771:             *                                the socket.
0772:             * @exception ModuleException if an exception is encountered in any module.
0773:             */
0774:            public HTTPResponse Get(String file, NVPair[] form_data,
0775:                    NVPair[] headers) throws IOException, ModuleException {
0776:                String File = stripRef(file), query = Codecs
0777:                        .nv2query(form_data);
0778:                if (query != null && query.length() > 0)
0779:                    File += "?" + query;
0780:
0781:                return setupRequest("GET", File, headers, null, null);
0782:            }
0783:
0784:            /**
0785:             * GETs the file using the specified query string. The query string
0786:             * is first urlencoded.
0787:             *
0788:             * @param     file  the absolute path of the file
0789:             * @param     query the query
0790:             * @return    an HTTPResponse structure containing the response
0791:             * @exception java.io.IOException when an exception is returned from
0792:             *                                the socket.
0793:             * @exception ModuleException if an exception is encountered in any module.
0794:             */
0795:            public HTTPResponse Get(String file, String query)
0796:                    throws IOException, ModuleException {
0797:                return Get(file, query, null);
0798:            }
0799:
0800:            /**
0801:             * GETs the file using the specified query string. The query string
0802:             * is first urlencoded.
0803:             *
0804:             * @param     file     the absolute path of the file
0805:             * @param     query    the query string
0806:             * @param     headers  additional headers
0807:             * @return    an HTTPResponse structure containing the response
0808:             * @exception java.io.IOException when an exception is returned from
0809:             *                                the socket.
0810:             * @exception ModuleException if an exception is encountered in any module.
0811:             */
0812:            public HTTPResponse Get(String file, String query, NVPair[] headers)
0813:                    throws IOException, ModuleException {
0814:                String File = stripRef(file);
0815:                if (query != null && query.length() > 0)
0816:                    File += "?" + Codecs.URLEncode(query);
0817:
0818:                return setupRequest("GET", File, headers, null, null);
0819:            }
0820:
0821:            /**
0822:             * POSTs to the specified file. No data is sent.
0823:             *
0824:             * @param     file the absolute path of the file
0825:             * @return    an HTTPResponse structure containing the response
0826:             * @exception java.io.IOException when an exception is returned from
0827:             *                                the socket.
0828:             * @exception ModuleException if an exception is encountered in any module.
0829:             */
0830:            public HTTPResponse Post(String file) throws IOException,
0831:                    ModuleException {
0832:                return Post(file, (byte[]) null, null);
0833:            }
0834:
0835:            /**
0836:             * POSTs form-data to the specified file. The data is first urlencoded
0837:             * and then turned into a string of the form "name1=value1&name2=value2".
0838:             * A <var>Content-type</var> header with the value
0839:             * <var>application/x-www-form-urlencoded</var> is added.
0840:             *
0841:             * @param     file      the absolute path of the file
0842:             * @param     form_data an array of Name/Value pairs
0843:             * @return    an HTTPResponse structure containing the response
0844:             * @exception java.io.IOException when an exception is returned from
0845:             *                                the socket.
0846:             * @exception ModuleException if an exception is encountered in any module.
0847:             */
0848:            public HTTPResponse Post(String file, NVPair form_data[])
0849:                    throws IOException, ModuleException {
0850:                NVPair[] headers = { new NVPair("Content-type",
0851:                        "application/x-www-form-urlencoded") };
0852:
0853:                return Post(file, Codecs.nv2query(form_data), headers);
0854:            }
0855:
0856:            /**
0857:             * POST's form-data to the specified file using the specified headers.
0858:             * The data is first urlencoded and then turned into a string of the
0859:             * form "name1=value1&name2=value2". If no <var>Content-type</var> header
0860:             * is given then one is added with a value of
0861:             * <var>application/x-www-form-urlencoded</var>.
0862:             *
0863:             * @param     file      the absolute path of the file
0864:             * @param     form_data an array of Name/Value pairs
0865:             * @param     headers   additional headers
0866:             * @return    a HTTPResponse structure containing the response
0867:             * @exception java.io.IOException when an exception is returned from
0868:             *                                the socket.
0869:             * @exception ModuleException if an exception is encountered in any module.
0870:             */
0871:            public HTTPResponse Post(String file, NVPair form_data[],
0872:                    NVPair headers[]) throws IOException, ModuleException {
0873:                int idx;
0874:                for (idx = 0; idx < headers.length; idx++)
0875:                    if (headers[idx].getName().equalsIgnoreCase("Content-type"))
0876:                        break;
0877:                if (idx == headers.length) {
0878:                    headers = Util.resizeArray(headers, idx + 1);
0879:                    headers[idx] = new NVPair("Content-type",
0880:                            "application/x-www-form-urlencoded");
0881:                }
0882:
0883:                return Post(file, Codecs.nv2query(form_data), headers);
0884:            }
0885:
0886:            /**
0887:             * POSTs the data to the specified file. The data is converted to an
0888:             * array of bytes using the lower byte of each character.
0889:             * The request is sent using the content-type "application/octet-stream".
0890:             *
0891:             * @see java.lang.String#getBytes(int, int, byte[], int)
0892:             * @param     file the absolute path of the file
0893:             * @param     data the data
0894:             * @return    an HTTPResponse structure containing the response
0895:             * @exception java.io.IOException when an exception is returned from
0896:             *                                the socket.
0897:             * @exception ModuleException if an exception is encountered in any module.
0898:             */
0899:            public HTTPResponse Post(String file, String data)
0900:                    throws IOException, ModuleException {
0901:                return Post(file, data, null);
0902:            }
0903:
0904:            /**
0905:             * POSTs the data to the specified file using the specified headers.
0906:             *
0907:             * @param     file     the absolute path of the file
0908:             * @param     data     the data
0909:             * @param     headers  additional headers
0910:             * @return    an HTTPResponse structure containing the response
0911:             * @exception java.io.IOException when an exception is returned from
0912:             *                                the socket.
0913:             * @exception ModuleException if an exception is encountered in any module.
0914:             */
0915:            public HTTPResponse Post(String file, String data, NVPair[] headers)
0916:                    throws IOException, ModuleException {
0917:                byte tmp[] = null;
0918:
0919:                if (data != null && data.length() > 0) {
0920:                    tmp = new byte[data.length()];
0921:                    data.getBytes(0, data.length(), tmp, 0);
0922:                }
0923:
0924:                return Post(file, tmp, headers);
0925:            }
0926:
0927:            /**
0928:             * POSTs the raw data to the specified file.
0929:             * The request is sent using the content-type "application/octet-stream"
0930:             *
0931:             * @param     file the absolute path of the file
0932:             * @param     data the data
0933:             * @return    an HTTPResponse structure containing the response
0934:             * @exception java.io.IOException when an exception is returned from
0935:             *                                the socket.
0936:             * @exception ModuleException if an exception is encountered in any module.
0937:             */
0938:            public HTTPResponse Post(String file, byte data[])
0939:                    throws IOException, ModuleException {
0940:                return Post(file, data, null);
0941:            }
0942:
0943:            /**
0944:             * POSTs the raw data to the specified file using the specified headers.
0945:             *
0946:             * @param     file     the absolute path of the file
0947:             * @param     data     the data
0948:             * @param     headers  additional headers
0949:             * @return    an HTTPResponse structure containing the response
0950:             * @exception java.io.IOException when an exception is returned from
0951:             *                                the socket.
0952:             * @exception ModuleException if an exception is encountered in any module.
0953:             */
0954:            public HTTPResponse Post(String file, byte data[], NVPair[] headers)
0955:                    throws IOException, ModuleException {
0956:                if (data == null)
0957:                    data = new byte[0]; // POST must always have a CL
0958:                return setupRequest("POST", stripRef(file), headers, data, null);
0959:            }
0960:
0961:            /**
0962:             * POSTs the data written to the output stream to the specified file.
0963:             * The request is sent using the content-type "application/octet-stream"
0964:             *
0965:             * @param     file   the absolute path of the file
0966:             * @param     stream the output stream on which the data is written
0967:             * @return    an HTTPResponse structure containing the response
0968:             * @exception java.io.IOException when an exception is returned from
0969:             *                                the socket.
0970:             * @exception ModuleException if an exception is encountered in any module.
0971:             */
0972:            public HTTPResponse Post(String file, HttpOutputStream stream)
0973:                    throws IOException, ModuleException {
0974:                return Post(file, stream, null);
0975:            }
0976:
0977:            /**
0978:             * POSTs the data written to the output stream to the specified file
0979:             * using the specified headers.
0980:             *
0981:             * @param     file     the absolute path of the file
0982:             * @param     stream   the output stream on which the data is written
0983:             * @param     headers  additional headers
0984:             * @return    an HTTPResponse structure containing the response
0985:             * @exception java.io.IOException when an exception is returned from
0986:             *                                the socket.
0987:             * @exception ModuleException if an exception is encountered in any module.
0988:             */
0989:            public HTTPResponse Post(String file, HttpOutputStream stream,
0990:                    NVPair[] headers) throws IOException, ModuleException {
0991:                return setupRequest("POST", stripRef(file), headers, null,
0992:                        stream);
0993:            }
0994:
0995:            /**
0996:             * PUTs the data into the specified file. The data is converted to an
0997:             * array of bytes using the lower byte of each character.
0998:             * The request ist sent using the content-type "application/octet-stream".
0999:             *
1000:             * @see java.lang.String#getBytes(int, int, byte[], int)
1001:             * @param     file the absolute path of the file
1002:             * @param     data the data
1003:             * @return    an HTTPResponse structure containing the response
1004:             * @exception java.io.IOException when an exception is returned from
1005:             *                                the socket.
1006:             * @exception ModuleException if an exception is encountered in any module.
1007:             */
1008:            public HTTPResponse Put(String file, String data)
1009:                    throws IOException, ModuleException {
1010:                return Put(file, data, null);
1011:            }
1012:
1013:            /**
1014:             * PUTs the data into the specified file using the additional headers
1015:             * for the request.
1016:             *
1017:             * @param     file     the absolute path of the file
1018:             * @param     data     the data
1019:             * @param     headers  additional headers
1020:             * @return    an HTTPResponse structure containing the response
1021:             * @exception java.io.IOException when an exception is returned from
1022:             *                                the socket.
1023:             * @exception ModuleException if an exception is encountered in any module.
1024:             */
1025:            public HTTPResponse Put(String file, String data, NVPair[] headers)
1026:                    throws IOException, ModuleException {
1027:                byte tmp[] = null;
1028:
1029:                if (data != null) {
1030:                    tmp = new byte[data.length()];
1031:                    data.getBytes(0, data.length(), tmp, 0);
1032:                }
1033:
1034:                return Put(file, tmp, headers);
1035:            }
1036:
1037:            /**
1038:             * PUTs the raw data into the specified file.
1039:             * The request is sent using the content-type "application/octet-stream".
1040:             *
1041:             * @param     file     the absolute path of the file
1042:             * @param     data     the data
1043:             * @return    an HTTPResponse structure containing the response
1044:             * @exception java.io.IOException when an exception is returned from
1045:             *                                the socket.
1046:             * @exception ModuleException if an exception is encountered in any module.
1047:             */
1048:            public HTTPResponse Put(String file, byte data[])
1049:                    throws IOException, ModuleException {
1050:                return Put(file, data, null);
1051:            }
1052:
1053:            /**
1054:             * PUTs the raw data into the specified file using the additional
1055:             * headers.
1056:             *
1057:             * @param     file     the absolute path of the file
1058:             * @param     data     the data
1059:             * @param     headers  any additional headers
1060:             * @return    an HTTPResponse structure containing the response
1061:             * @exception java.io.IOException when an exception is returned from
1062:             *                                the socket.
1063:             * @exception ModuleException if an exception is encountered in any module.
1064:             */
1065:            public HTTPResponse Put(String file, byte data[], NVPair[] headers)
1066:                    throws IOException, ModuleException {
1067:                if (data == null)
1068:                    data = new byte[0]; // PUT must always have a CL
1069:                return setupRequest("PUT", stripRef(file), headers, data, null);
1070:            }
1071:
1072:            /**
1073:             * PUTs the data written to the output stream into the specified file.
1074:             * The request is sent using the content-type "application/octet-stream".
1075:             *
1076:             * @param     file     the absolute path of the file
1077:             * @param     stream   the output stream on which the data is written
1078:             * @return    an HTTPResponse structure containing the response
1079:             * @exception java.io.IOException when an exception is returned from
1080:             *                                the socket.
1081:             * @exception ModuleException if an exception is encountered in any module.
1082:             */
1083:            public HTTPResponse Put(String file, HttpOutputStream stream)
1084:                    throws IOException, ModuleException {
1085:                return Put(file, stream, null);
1086:            }
1087:
1088:            /**
1089:             * PUTs the data written to the output stream into the specified file
1090:             * using the additional headers.
1091:             *
1092:             * @param     file     the absolute path of the file
1093:             * @param     stream   the output stream on which the data is written
1094:             * @param     headers  any additional headers
1095:             * @return    an HTTPResponse structure containing the response
1096:             * @exception java.io.IOException when an exception is returned from
1097:             *                                the socket.
1098:             * @exception ModuleException if an exception is encountered in any module.
1099:             */
1100:            public HTTPResponse Put(String file, HttpOutputStream stream,
1101:                    NVPair[] headers) throws IOException, ModuleException {
1102:                return setupRequest("PUT", stripRef(file), headers, null,
1103:                        stream);
1104:            }
1105:
1106:            /**
1107:             * Request OPTIONS from the server. If <var>file</var> is "*" then
1108:             * the request applies to the server as a whole; otherwise it applies
1109:             * only to that resource.
1110:             *
1111:             * @param     file     the absolute path of the resource, or "*"
1112:             * @return    an HTTPResponse structure containing the response
1113:             * @exception java.io.IOException when an exception is returned from
1114:             *                                the socket.
1115:             * @exception ModuleException if an exception is encountered in any module.
1116:             */
1117:            public HTTPResponse Options(String file) throws IOException,
1118:                    ModuleException {
1119:                return Options(file, null, (byte[]) null);
1120:            }
1121:
1122:            /**
1123:             * Request OPTIONS from the server. If <var>file</var> is "*" then
1124:             * the request applies to the server as a whole; otherwise it applies
1125:             * only to that resource.
1126:             *
1127:             * @param     file     the absolute path of the resource, or "*"
1128:             * @param     headers  the headers containing optional info.
1129:             * @return    an HTTPResponse structure containing the response
1130:             * @exception java.io.IOException when an exception is returned from
1131:             *                                the socket.
1132:             * @exception ModuleException if an exception is encountered in any module.
1133:             */
1134:            public HTTPResponse Options(String file, NVPair[] headers)
1135:                    throws IOException, ModuleException {
1136:                return Options(file, headers, (byte[]) null);
1137:            }
1138:
1139:            /**
1140:             * Request OPTIONS from the server. If <var>file</var> is "*" then
1141:             * the request applies to the server as a whole; otherwise it applies
1142:             * only to that resource.
1143:             *
1144:             * @param     file     the absolute path of the resource, or "*"
1145:             * @param     headers  the headers containing optional info.
1146:             * @param     data     any data to be sent in the optional body
1147:             * @return    an HTTPResponse structure containing the response
1148:             * @exception java.io.IOException when an exception is returned from
1149:             *                                the socket.
1150:             * @exception ModuleException if an exception is encountered in any module.
1151:             */
1152:            public HTTPResponse Options(String file, NVPair[] headers,
1153:                    byte[] data) throws IOException, ModuleException {
1154:                return setupRequest("OPTIONS", stripRef(file), headers, data,
1155:                        null);
1156:            }
1157:
1158:            /**
1159:             * Request OPTIONS from the server. If <var>file</var> is "*" then
1160:             * the request applies to the server as a whole; otherwise it applies
1161:             * only to that resource.
1162:             *
1163:             * @param     file     the absolute path of the resource, or "*"
1164:             * @param     headers  the headers containing optional info.
1165:             * @param     stream   an output stream for sending the optional body
1166:             * @return    an HTTPResponse structure containing the response
1167:             * @exception java.io.IOException when an exception is returned from
1168:             *                                the socket.
1169:             * @exception ModuleException if an exception is encountered in any module.
1170:             */
1171:            public HTTPResponse Options(String file, NVPair[] headers,
1172:                    HttpOutputStream stream) throws IOException,
1173:                    ModuleException {
1174:                return setupRequest("OPTIONS", stripRef(file), headers, null,
1175:                        stream);
1176:            }
1177:
1178:            /**
1179:             * Requests that <var>file</var> be DELETEd from the server.
1180:             *
1181:             * @param     file     the absolute path of the resource
1182:             * @return    an HTTPResponse structure containing the response
1183:             * @exception java.io.IOException when an exception is returned from
1184:             *                                the socket.
1185:             * @exception ModuleException if an exception is encountered in any module.
1186:             */
1187:            public HTTPResponse Delete(String file) throws IOException,
1188:                    ModuleException {
1189:                return Delete(file, null);
1190:            }
1191:
1192:            /**
1193:             * Requests that <var>file</var> be DELETEd from the server.
1194:             *
1195:             * @param     file     the absolute path of the resource
1196:             * @param     headers  additional headers
1197:             * @return    an HTTPResponse structure containing the response
1198:             * @exception java.io.IOException when an exception is returned from
1199:             *                                the socket.
1200:             * @exception ModuleException if an exception is encountered in any module.
1201:             */
1202:            public HTTPResponse Delete(String file, NVPair[] headers)
1203:                    throws IOException, ModuleException {
1204:                return setupRequest("DELETE", stripRef(file), headers, null,
1205:                        null);
1206:            }
1207:
1208:            /**
1209:             * Requests a TRACE. Headers of particular interest here are "Via"
1210:             * and "Max-Forwards".
1211:             *
1212:             * @param     file     the absolute path of the resource
1213:             * @param     headers  additional headers
1214:             * @return    an HTTPResponse structure containing the response
1215:             * @exception java.io.IOException when an exception is returned from
1216:             *                                the socket.
1217:             * @exception ModuleException if an exception is encountered in any module.
1218:             */
1219:            public HTTPResponse Trace(String file, NVPair[] headers)
1220:                    throws IOException, ModuleException {
1221:                return setupRequest("TRACE", stripRef(file), headers, null,
1222:                        null);
1223:            }
1224:
1225:            /**
1226:             * Requests a TRACE.
1227:             *
1228:             * @param     file     the absolute path of the resource
1229:             * @return    an HTTPResponse structure containing the response
1230:             * @exception java.io.IOException when an exception is returned from
1231:             *                                the socket.
1232:             * @exception ModuleException if an exception is encountered in any module.
1233:             */
1234:            public HTTPResponse Trace(String file) throws IOException,
1235:                    ModuleException {
1236:                return Trace(file, null);
1237:            }
1238:
1239:            /**
1240:             * This is here to allow an arbitrary, non-standard request to be sent.
1241:             * I'm assuming you know what you are doing...
1242:             *
1243:             * @param     method   the extension method
1244:             * @param     file     the absolute path of the resource, or null
1245:             * @param     data     optional data, or null
1246:             * @param     headers  optional headers, or null
1247:             * @return    an HTTPResponse structure containing the response
1248:             * @exception java.io.IOException when an exception is returned from
1249:             *                                the socket.
1250:             * @exception ModuleException if an exception is encountered in any module.
1251:             */
1252:            public HTTPResponse ExtensionMethod(String method, String file,
1253:                    byte[] data, NVPair[] headers) throws IOException,
1254:                    ModuleException {
1255:                return setupRequest(method.trim(), stripRef(file), headers,
1256:                        data, null);
1257:            }
1258:
1259:            /**
1260:             * This is here to allow an arbitrary, non-standard request to be sent.
1261:             * I'm assuming you know what you are doing...
1262:             *
1263:             * @param     method   the extension method
1264:             * @param     file     the absolute path of the resource, or null
1265:             * @param     stream   optional output stream, or null
1266:             * @param     headers  optional headers, or null
1267:             * @return    an HTTPResponse structure containing the response
1268:             * @exception java.io.IOException when an exception is returned from
1269:             *                                the socket.
1270:             * @exception ModuleException if an exception is encountered in any module.
1271:             */
1272:            public HTTPResponse ExtensionMethod(String method, String file,
1273:                    HttpOutputStream os, NVPair[] headers) throws IOException,
1274:                    ModuleException {
1275:                return setupRequest(method.trim(), stripRef(file), headers,
1276:                        null, os);
1277:            }
1278:
1279:            /**
1280:             * Aborts all the requests currently in progress on this connection and
1281:             * closes all associated sockets.
1282:             *
1283:             * <P>Note: there is a small window where a request method such as
1284:             * <code>Get()</code> may have been invoked but the request has not
1285:             * been built and added to the list. Any request in this window will
1286:             * not be aborted.
1287:             *
1288:             * @since V0.2-3
1289:             */
1290:            public void stop() {
1291:                for (Request req = (Request) RequestList.enumerate(); req != null; req = (Request) RequestList
1292:                        .next())
1293:                    req.aborted = true;
1294:
1295:                for (StreamDemultiplexor demux = (StreamDemultiplexor) DemuxList
1296:                        .enumerate(); demux != null; demux = (StreamDemultiplexor) DemuxList
1297:                        .next())
1298:                    demux.abort();
1299:            }
1300:
1301:            /**
1302:             * Sets the default http headers to be sent with each request. The
1303:             * actual headers sent are determined as follows: for each header
1304:             * specified in multiple places a value given as part of the request
1305:             * takes priority over any default values set by this method, which
1306:             * in turn takes priority over any built-in default values. A different
1307:             * way of looking at it is that we start off with a list of all headers
1308:             * specified with the request, then add any default headers set by this
1309:             * method which aren't already in our list, and finally add any built-in
1310:             * headers which aren't yet in the list. There are two exceptions to this
1311:             * rule: "Content-length" and "Host" headers are always ignored; and when
1312:             * posting form-data any default "Content-type" is ignored in favor of
1313:             * the built-in "application/x-www-form-urlencoded" (however it will be
1314:             * overriden by any content-type header specified as part of the request).
1315:             *
1316:             * <P>Typical headers you might want to set here are "Accept" and its
1317:             * "Accept-*" relatives, "Connection", "From", "User-Agent", etc.
1318:             *
1319:             * @param headers an array of header-name/value pairs (do not give the
1320:             *                separating ':').
1321:             */
1322:            public void setDefaultHeaders(NVPair[] headers) {
1323:                int length = (headers == null ? 0 : headers.length);
1324:                NVPair[] def_hdrs = new NVPair[length];
1325:
1326:                // weed out undesired headers
1327:                int sidx, didx;
1328:                for (sidx = 0, didx = 0; sidx < length; sidx++) {
1329:                    String name = headers[sidx].getName().trim();
1330:                    if (name.equalsIgnoreCase("Content-length")
1331:                            || name.equalsIgnoreCase("Host"))
1332:                        continue;
1333:
1334:                    def_hdrs[didx++] = headers[sidx];
1335:                }
1336:
1337:                if (didx < length)
1338:                    def_hdrs = Util.resizeArray(DefaultHeaders, didx);
1339:
1340:                synchronized (DefaultHeaders) {
1341:                    DefaultHeaders = def_hdrs;
1342:                }
1343:            }
1344:
1345:            /**
1346:             * Gets the current list of default http headers.
1347:             *
1348:             * @return an array of header/value pairs.
1349:             */
1350:            public NVPair[] getDefaultHeaders() {
1351:                //return (NVPair[]) DefaultHeaders.clone();  JDK 1.1 Only
1352:
1353:                synchronized (DefaultHeaders) {
1354:                    NVPair[] headers = new NVPair[DefaultHeaders.length];
1355:                    System.arraycopy(DefaultHeaders, 0, headers, 0,
1356:                            headers.length);
1357:                    return headers;
1358:                }
1359:            }
1360:
1361:            /**
1362:             * Returns the protocol this connection is talking.
1363:             *
1364:             * @return a string containing the (lowercased) protocol
1365:             */
1366:            public String getProtocol() {
1367:                switch (Protocol) {
1368:                case HTTP:
1369:                    return "http";
1370:                case HTTPS:
1371:                    return "https";
1372:                case SHTTP:
1373:                    return "shttp";
1374:                case HTTP_NG:
1375:                    return "http-ng";
1376:                default:
1377:                    throw new Error(
1378:                            "HTTPClient Internal Error: invalid protocol "
1379:                                    + Protocol);
1380:                }
1381:            }
1382:
1383:            /**
1384:             * Returns the host this connection is talking to.
1385:             *
1386:             * @return a string containing the (lowercased) host name.
1387:             */
1388:            public String getHost() {
1389:                return Host;
1390:            }
1391:
1392:            /**
1393:             * Returns the port this connection connects to. This is always the
1394:             * actual port number, never -1.
1395:             *
1396:             * @return the port number
1397:             */
1398:            public int getPort() {
1399:                return Port;
1400:            }
1401:
1402:            /**
1403:             * Returns the host of the proxy this connection is using.
1404:             *
1405:             * @return a string containing the (lowercased) host name.
1406:             */
1407:            public String getProxyHost() {
1408:                return Proxy_Host;
1409:            }
1410:
1411:            /**
1412:             * Returns the port of the proxy this connection is using.
1413:             *
1414:             * @return the port number
1415:             */
1416:            public int getProxyPort() {
1417:                return Proxy_Port;
1418:            }
1419:
1420:            /**
1421:             * See if the given uri is compatible with this connection. Compatible
1422:             * means that the given uri can be retrieved using this connection
1423:             * object.
1424:             *
1425:             * @param uri  the URI to check
1426:             * @return true if they're compatible, false otherwise
1427:             * @since V0.3-2
1428:             */
1429:            public boolean isCompatibleWith(URI uri) {
1430:                if (!uri.getScheme().equals(getProtocol())
1431:                        || !uri.getHost().equalsIgnoreCase(Host))
1432:                    return false;
1433:
1434:                int port = uri.getPort();
1435:                if (port == -1)
1436:                    port = URI.defaultPort(uri.getScheme());
1437:                return port == Port;
1438:            }
1439:
1440:            /**
1441:             * Sets/Resets raw mode. In raw mode all modules are bypassed, meaning
1442:             * the automatic handling of authorization requests, redirections,
1443:             * cookies, etc. is turned off.
1444:             *
1445:             * <P>The default is false.
1446:             *
1447:             * @deprecated This is not really needed anymore; in V0.2 request were
1448:             *             synchronous and therefore to do pipelining you needed
1449:             *             to disable the processing of responses.
1450:             * @see #removeModule(java.lang.Class)
1451:             *
1452:             * @param raw if true removes all modules (except for the retry module)
1453:             */
1454:            public void setRawMode(boolean raw) {
1455:                // Don't remove the retry module
1456:                String[] modules = { "HTTPClient.CookieModule",
1457:                        "HTTPClient.RedirectionModule",
1458:                        "HTTPClient.AuthorizationModule",
1459:                        "HTTPClient.DefaultModule",
1460:                        "HTTPClient.TransferEncodingModule",
1461:                        "HTTPClient.ContentMD5Module",
1462:                        "HTTPClient.ContentEncodingModule" };
1463:
1464:                for (int idx = 0; idx < modules.length; idx++) {
1465:                    try {
1466:                        if (raw)
1467:                            removeModule(Class.forName(modules[idx]));
1468:                        else
1469:                            addModule(Class.forName(modules[idx]), -1);
1470:                    } catch (ClassNotFoundException cnfe) {
1471:                    }
1472:                }
1473:            }
1474:
1475:            /**
1476:             * Sets the default timeout value to be used for each new HTTPConnection.
1477:             * The default is 0.
1478:             *
1479:             * @param time the timeout in milliseconds.
1480:             * @see #setTimeout(int)
1481:             */
1482:            public static void setDefaultTimeout(int time) {
1483:                DefaultTimeout = time;
1484:            }
1485:
1486:            /**
1487:             * Gets the default timeout value to be used for each new HTTPConnection.
1488:             *
1489:             * @return the timeout in milliseconds.
1490:             * @see #setTimeout(int)
1491:             */
1492:            public static int getDefaultTimeout() {
1493:                return DefaultTimeout;
1494:            }
1495:
1496:            /**
1497:             * Sets the timeout to be used for creating connections and reading
1498:             * responses. When a timeout expires the operation will throw an
1499:             * InterruptedIOException. The operation may be restarted again
1500:             * afterwards. If the operation is not restarted and it is a read
1501:             * operation (i.e HTTPResponse.xxxx()) then <code>stop()</code>
1502:             * <strong>should</strong> be invoked.
1503:             *
1504:             * <P>When creating new sockets the timeout will limit the time spent
1505:             * doing the host name translation and establishing the connection with
1506:             * the server.
1507:             *
1508:             * <P>The timeout also influences the reading of the response headers.
1509:             * However, it does not specify a how long, for example, getStatusCode()
1510:             * may take, as might be assumed. Instead it specifies how long a read
1511:             * on the socket may take. If the response dribbles in slowly with
1512:             * packets arriving quicker than the timeout then the method will
1513:             * complete normally. I.e. the exception is only thrown if nothing
1514:             * arrives on the socket for the specified time. Furthermore, the
1515:             * timeout only influences the reading of the headers, not the reading
1516:             * of the body.
1517:             *
1518:             * <P>Read Timeouts are associated with responses, so that you may change
1519:             * this value before each request and it won't affect the reading of
1520:             * responses to previous requests.
1521:             *
1522:             * <P><em>Note:</em> The read timeout only works with JDK 1.1 or later.
1523:             * Using this method with JDK 1.0.2 or earlier will only influence the
1524:             * connection creation.
1525:             *
1526:             * @param time the time in milliseconds. A time of 0 means wait
1527:             *             indefinitely.
1528:             * @see #stop()
1529:             */
1530:            public void setTimeout(int time) {
1531:                Timeout = time;
1532:            }
1533:
1534:            /**
1535:             * Gets the timeout used for reading response data.
1536:             *
1537:             * @return the current timeout value
1538:             * @see #setTimeout(int)
1539:             */
1540:            public int getTimeout() {
1541:                return Timeout;
1542:            }
1543:
1544:            /**
1545:             * Controls whether modules are allowed to prompt the user or pop up
1546:             * dialogs if neccessary.
1547:             *
1548:             * @param allow if true allows modules to interact with user.
1549:             */
1550:            public void setAllowUserInteraction(boolean allow) {
1551:                AllowUI = allow;
1552:            }
1553:
1554:            /**
1555:             * returns whether modules are allowed to prompt or popup dialogs
1556:             * if neccessary.
1557:             *
1558:             * @return true if modules are allowed to interact with user.
1559:             */
1560:            public boolean getAllowUserInteraction() {
1561:                return AllowUI;
1562:            }
1563:
1564:            /**
1565:             * Sets the default allow-user-action.
1566:             *
1567:             * @param allow if true allows modules to interact with user.
1568:             */
1569:            public static void setDefaultAllowUserInteraction(boolean allow) {
1570:                DefaultAllowUI = allow;
1571:            }
1572:
1573:            /**
1574:             * Gets the default allow-user-action.
1575:             *
1576:             * @return true if modules are allowed to interact with user.
1577:             */
1578:            public static boolean getDefaultAllowUserInteraction() {
1579:                return DefaultAllowUI;
1580:            }
1581:
1582:            /**
1583:             * Returns the default list of modules.
1584:             *
1585:             * @return an array of classes
1586:             */
1587:            public static Class[] getDefaultModules() {
1588:                synchronized (DefaultModuleList) {
1589:                    Class[] modules = new Class[DefaultModuleList.size()];
1590:                    DefaultModuleList.copyInto(modules);
1591:                    return modules;
1592:                }
1593:            }
1594:
1595:            /**
1596:             * Adds a module to the default list. It must implement the
1597:             * <var>HTTPClientModule</var> interface. If the module is already in
1598:             * the list then this method does nothing.
1599:             *
1600:             * <P>Example:
1601:             * <PRE>
1602:             * HTTPConnection.addDefaultModule(Class.forName("HTTPClient.CookieModule"), 1);
1603:             * </PRE>
1604:             * adds the cookie module as the second module in the list.
1605:             *
1606:             * <P>The default list is created at class initialization time from the
1607:             * property <var>HTTPClient.Modules</var>. This must contain a "|"
1608:             * separated list of classes in the order they're to be invoked. If this
1609:             * property is not set it defaults to:
1610:             *
1611:             * "HTTPClient.RetryModule | HTTPClient.CookieModule |
1612:             *  HTTPClient.RedirectionModule | HTTPClient.AuthorizationModule |
1613:             *  HTTPClient.DefaultModule | HTTPClient.TransferEncodingModule |
1614:             *  HTTPClient.ContentMD5Module | HTTPClient.ContentEncodingModule"
1615:             *
1616:             * @see HTTPClientModule
1617:             * @param module the module's Class object
1618:             * @param pos    the position of this module in the list; if <var>pos</var>
1619:             *               >= 0 then this is the absolute position in the list (0 is
1620:             *               the first position); if <var>pos</var> < 0 then this is
1621:             *               the position relative to the end of the list (-1 means
1622:             *               the last element, -2 the second to last element, etc).
1623:             * @return       true if module was successfully added; false if the
1624:             *               module is already in the list.
1625:             * @exception    ArrayIndexOutOfBoundsException if <var>pos</var> >
1626:             *               list-size or if <var>pos</var> < -(list-size).
1627:             * @exception    ClassCastException if <var>module</var> does not
1628:             *               implement the <var>HTTPClientModule</var> interface.
1629:             * @exception    RuntimeException if <var>module</var> cannot be
1630:             *               instantiated.
1631:             */
1632:            public static boolean addDefaultModule(Class module, int pos) {
1633:                // check if module implements HTTPClientModule
1634:                try {
1635:                    HTTPClientModule tmp = (HTTPClientModule) module
1636:                            .newInstance();
1637:                } catch (RuntimeException re) {
1638:                    throw re;
1639:                } catch (Exception e) {
1640:                    throw new RuntimeException(e.toString());
1641:                }
1642:
1643:                synchronized (DefaultModuleList) {
1644:                    // check if module already in list
1645:                    if (DefaultModuleList.contains(module))
1646:                        return false;
1647:
1648:                    // add module to list
1649:                    if (pos < 0)
1650:                        DefaultModuleList.insertElementAt(module,
1651:                                DefaultModuleList.size() + pos + 1);
1652:                    else
1653:                        DefaultModuleList.insertElementAt(module, pos);
1654:                }
1655:
1656:                if (DebugConn)
1657:                    System.err.println("Conn:  Added module "
1658:                            + module.getName() + " to default list");
1659:
1660:                return true;
1661:            }
1662:
1663:            /**
1664:             * Removes a module from the default list. If the module is not in the
1665:             * list it does nothing.
1666:             *
1667:             * @param module the module's Class object
1668:             * @return true if module was successfully removed; false otherwise
1669:             */
1670:            public static boolean removeDefaultModule(Class module) {
1671:                boolean removed = DefaultModuleList.removeElement(module);
1672:
1673:                if (DebugConn)
1674:                    if (removed)
1675:                        System.err.println("Conn:  Removed module "
1676:                                + module.getName() + " from default list");
1677:
1678:                return removed;
1679:            }
1680:
1681:            /**
1682:             * Returns the list of modules used currently.
1683:             *
1684:             * @return an array of classes
1685:             */
1686:            public Class[] getModules() {
1687:                synchronized (ModuleList) {
1688:                    Class[] modules = new Class[ModuleList.size()];
1689:                    ModuleList.copyInto(modules);
1690:                    return modules;
1691:                }
1692:            }
1693:
1694:            /**
1695:             * Adds a module to the current list. It must implement the
1696:             * <var>HTTPClientModule</var> interface. If the module is already in
1697:             * the list then this method does nothing.
1698:             *
1699:             * @see HTTPClientModule
1700:             * @param module the module's Class object
1701:             * @param pos    the position of this module in the list; if <var>pos</var>
1702:             *               >= 0 then this is the absolute position in the list (0 is
1703:             *               the first position); if <var>pos</var> < 0 then this is
1704:             *               the position relative to the end of the list (-1 means
1705:             *               the last element, -2 the second to last element, etc).
1706:             * @return       true if module was successfully added; false if the
1707:             *               module is already in the list.
1708:             * @exception    ArrayIndexOutOfBoundsException if <var>pos</var> >
1709:             *               list-size or if <var>pos</var> < -(list-size).
1710:             * @exception    ClassCastException if <var>module</var> does not
1711:             *               implement the <var>HTTPClientModule</var> interface.
1712:             * @exception    RuntimeException if <var>module</var> cannot be
1713:             *               instantiated.
1714:             */
1715:            public boolean addModule(Class module, int pos) {
1716:                // check if module implements HTTPClientModule
1717:                try {
1718:                    HTTPClientModule tmp = (HTTPClientModule) module
1719:                            .newInstance();
1720:                } catch (RuntimeException re) {
1721:                    throw re;
1722:                } catch (Exception e) {
1723:                    throw new RuntimeException(e.toString());
1724:                }
1725:
1726:                synchronized (ModuleList) {
1727:                    // check if module already in list
1728:                    if (ModuleList.contains(module))
1729:                        return false;
1730:
1731:                    // add module to list
1732:                    if (pos < 0)
1733:                        ModuleList.insertElementAt(module, ModuleList.size()
1734:                                + pos + 1);
1735:                    else
1736:                        ModuleList.insertElementAt(module, pos);
1737:                }
1738:
1739:                return true;
1740:            }
1741:
1742:            /**
1743:             * Removes a module from the current list. If the module is not in the
1744:             * list it does nothing.
1745:             *
1746:             * @param module the module's Class object
1747:             * @return true if module was successfully removed; false otherwise
1748:             */
1749:            public boolean removeModule(Class module) {
1750:                if (module == null)
1751:                    return false;
1752:                return ModuleList.removeElement(module);
1753:            }
1754:
1755:            /**
1756:             * Sets the current context. The context is used by modules such as
1757:             * the AuthorizationModule and the CookieModule which keep lists of
1758:             * info that is normally shared between all instances of HTTPConnection.
1759:             * This is usually the desired behaviour. However, in some cases one
1760:             * would like to simulate multiple independent clients within the
1761:             * same application and hence the sharing of such info should be
1762:             * restricted. This is where the context comes in. Modules will only
1763:             * share their info between requests using the same context (i.e. they
1764:             * keep multiple lists, one for each context).
1765:             *
1766:             * <P>The context may be any object. Contexts are considered equal
1767:             * if <code>equals()</code> returns true. Examples of useful context
1768:             * objects are threads (e.g. if you are running multiple clients, one
1769:             * per thread) and sockets (e.g. if you are implementing a gateway).
1770:             *
1771:             * <P>When a new HTTPConnection is created it is initialized with a
1772:             * default context which is the same for all instances. This method
1773:             * must be invoked immediately after a new HTTPConnection is created
1774:             * and before any request method is invoked. Furthermore, this method
1775:             * may only be called once (i.e. the context is "sticky").
1776:             *
1777:             * @param context the new context; must be non-null
1778:             * @exception IllegalArgumentException if <var>context</var> is null
1779:             * @exception RuntimeException if the context has already been set
1780:             */
1781:            public void setContext(Object context) {
1782:                if (context == null)
1783:                    throw new IllegalArgumentException(
1784:                            "Context must be non-null");
1785:                if (Context != null)
1786:                    throw new RuntimeException("Context already set");
1787:
1788:                Context = context;
1789:            }
1790:
1791:            /**
1792:             * Returns the current context.
1793:             *
1794:             * @see #setContext(java.lang.Object)
1795:             * @return the current context, or the default context if
1796:             *         <code>setContext()</code> hasn't been invoked
1797:             */
1798:            public Object getContext() {
1799:                if (Context != null)
1800:                    return Context;
1801:                else
1802:                    return dflt_context;
1803:            }
1804:
1805:            /**
1806:             * Returns the default context.
1807:             *
1808:             * @see #setContext(java.lang.Object)
1809:             * @return the default context
1810:             */
1811:            static Object getDefaultContext() {
1812:                return dflt_context;
1813:            }
1814:
1815:            /**
1816:             * Adds an authorization entry for the "digest" authorization scheme to
1817:             * the list. If an entry already exists for the "digest" scheme and the
1818:             * specified realm then it is overwritten.
1819:             *
1820:             * <P>This is a convenience method and just invokes the corresponding
1821:             * method in AuthorizationInfo.
1822:             *
1823:             * @param realm the realm
1824:             * @param user  the username
1825:             * @param passw the password
1826:             * @see AuthorizationInfo#addDigestAuthorization(java.lang.String, int, java.lang.String, java.lang.String, java.lang.String)
1827:             */
1828:            public void addDigestAuthorization(String realm, String user,
1829:                    String passwd) {
1830:                AuthorizationInfo.addDigestAuthorization(Host, Port, realm,
1831:                        user, passwd, getContext());
1832:            }
1833:
1834:            /**
1835:             * Adds an authorization entry for the "basic" authorization scheme to
1836:             * the list. If an entry already exists for the "basic" scheme and the
1837:             * specified realm then it is overwritten.
1838:             *
1839:             * <P>This is a convenience method and just invokes the corresponding
1840:             * method in AuthorizationInfo.
1841:             *
1842:             * @param realm the realm
1843:             * @param user  the username
1844:             * @param passw the password
1845:             * @see AuthorizationInfo#addBasicAuthorization(java.lang.String, int, java.lang.String, java.lang.String, java.lang.String)
1846:             */
1847:            public void addBasicAuthorization(String realm, String user,
1848:                    String passwd) {
1849:                AuthorizationInfo.addBasicAuthorization(Host, Port, realm,
1850:                        user, passwd, getContext());
1851:            }
1852:
1853:            /**
1854:             * Sets the default proxy server to use. The proxy will only be used
1855:             * for new <var>HTTPConnection</var>s created after this call and will
1856:             * not affect currrent instances of <var>HTTPConnection</var>. A null
1857:             * or empty string <var>host</var> parameter disables the proxy.
1858:             *
1859:             * <P>In an application or using the Appletviewer an alternative to
1860:             * this method is to set the following properties (either in the
1861:             * properties file or on the command line):
1862:             * <var>http.proxyHost</var> and <var>http.proxyPort</var>. Whether
1863:             * <var>http.proxyHost</var> is set or not determines whether a proxy
1864:             * server is used.
1865:             *
1866:             * <P>If the proxy server requires authorization and you wish to set
1867:             * this authorization information in the code, then you may use any
1868:             * of the <var>AuthorizationInfo.addXXXAuthorization()</var> methods to
1869:             * do so. Specify the same <var>host</var> and <var>port</var> as in
1870:             * this method. If you have not given any authorization info and the
1871:             * proxy server requires authorization then you will be prompted for
1872:             * the necessary info via a popup the first time you do a request.
1873:             *
1874:             * @see #setCurrentProxy(java.lang.String,int)
1875:             * @param  host    the host on which the proxy server resides.
1876:             * @param  port    the port the proxy server is listening on.
1877:             */
1878:            public static void setProxyServer(String host, int port) {
1879:                if (host == null || host.trim().length() == 0)
1880:                    Default_Proxy_Host = null;
1881:                else {
1882:                    Default_Proxy_Host = host.trim().toLowerCase();
1883:                    Default_Proxy_Port = port;
1884:                }
1885:            }
1886:
1887:            /**
1888:             * Sets the proxy used by this instance. This can be used to override
1889:             * the proxy setting inherited from the default proxy setting. A null
1890:             * or empty string <var>host</var> parameter disables the proxy.
1891:             *
1892:             * <P>Note that if you set a proxy for the connection using this
1893:             * method, and a request made over this connection is redirected
1894:             * to a different server, then the connection used for new server
1895:             * will <em>not</em> pick this proxy setting, but instead will use
1896:             * the default proxy settings.
1897:             *
1898:             * @see #setProxyServer(java.lang.String,int)
1899:             * @param host the host the proxy runs on
1900:             * @param port the port the proxy is listening on
1901:             */
1902:            public synchronized void setCurrentProxy(String host, int port) {
1903:                if (host == null || host.trim().length() == 0)
1904:                    Proxy_Host = null;
1905:                else {
1906:                    Proxy_Host = host.trim().toLowerCase();
1907:                    if (port <= 0)
1908:                        Proxy_Port = 80;
1909:                    else
1910:                        Proxy_Port = port;
1911:                }
1912:
1913:                // the proxy might be talking a different version, so renegotiate
1914:                switch (Protocol) {
1915:                case HTTP:
1916:                case HTTPS:
1917:                    if (force_1_0) {
1918:                        ServerProtocolVersion = HTTP_1_0;
1919:                        ServProtVersKnown = true;
1920:                        RequestProtocolVersion = "HTTP/1.0";
1921:                    } else {
1922:                        ServerProtocolVersion = HTTP_1_1;
1923:                        ServProtVersKnown = false;
1924:                        RequestProtocolVersion = "HTTP/1.1";
1925:                    }
1926:                    break;
1927:                case HTTP_NG:
1928:                    ServerProtocolVersion = -1; /* Unknown */
1929:                    ServProtVersKnown = false;
1930:                    RequestProtocolVersion = "";
1931:                    break;
1932:                case SHTTP:
1933:                    ServerProtocolVersion = -1; /* Unknown */
1934:                    ServProtVersKnown = false;
1935:                    RequestProtocolVersion = "Secure-HTTP/1.3";
1936:                    break;
1937:                default:
1938:                    throw new Error(
1939:                            "HTTPClient Internal Error: invalid protocol "
1940:                                    + Protocol);
1941:                }
1942:
1943:                KeepAliveUnknown = true;
1944:                DoesKeepAlive = false;
1945:
1946:                input_demux = null;
1947:                early_stall = null;
1948:                late_stall = null;
1949:                prev_resp = null;
1950:            }
1951:
1952:            /**
1953:             * Add <var>host</var> to the list of hosts which should be accessed
1954:             * directly, not via any proxy set by <code>setProxyServer()</code>.
1955:             *
1956:             * <P>The <var>host</var> may be any of:
1957:             * <UL>
1958:             * <LI>a complete host name (e.g. "www.disney.com")
1959:             * <LI>a domain name; domain names must begin with a dot (e.g.
1960:             *     ".disney.com")
1961:             * <LI>an IP-address (e.g. "12.34.56.78")
1962:             * <LI>an IP-subnet, specified as an IP-address and a netmask separated
1963:             *     by a "/" (e.g. "34.56.78/255.255.255.192"); a 0 bit in the netmask
1964:             *     means that that bit won't be used in the comparison (i.e. the
1965:             *     addresses are AND'ed with the netmask before comparison).
1966:             * </UL>
1967:             *
1968:             * <P>The two properties <var>HTTPClient.nonProxyHosts</var> and
1969:             * <var>http.nonProxyHosts</var> are used when this class is loaded to
1970:             * initialize the list of non-proxy hosts. The second property is only
1971:             * read if the first one is not set; the second property is also used
1972:             * the JDK's URLConnection. These properties must contain a "|"
1973:             * separated list of entries which conform to the above rules for the
1974:             * <var>host</var> parameter (e.g. "11.22.33.44|.disney.com").
1975:             *
1976:             * @param host a host name, domain name, IP-address or IP-subnet.
1977:             * @exception ParseException if the length of the netmask does not match
1978:             *                           the length of the IP-address
1979:             */
1980:            public static void dontProxyFor(String host) throws ParseException {
1981:                host = host.trim().toLowerCase();
1982:
1983:                // check for domain name
1984:
1985:                if (host.charAt(0) == '.') {
1986:                    if (!non_proxy_dom_list.contains(host))
1987:                        non_proxy_dom_list.addElement(host);
1988:                    return;
1989:                }
1990:
1991:                // check for host name
1992:
1993:                for (int idx = 0; idx < host.length(); idx++) {
1994:                    if (!Character.isDigit(host.charAt(idx))
1995:                            && host.charAt(idx) != '.'
1996:                            && host.charAt(idx) != '/') {
1997:                        non_proxy_host_list.put(host, "");
1998:                        return;
1999:                    }
2000:                }
2001:
2002:                // must be an IP-address
2003:
2004:                byte[] ip_addr;
2005:                byte[] ip_mask;
2006:                int slash;
2007:                if ((slash = host.indexOf('/')) != -1) // IP subnet
2008:                {
2009:                    ip_addr = string2arr(host.substring(0, slash));
2010:                    ip_mask = string2arr(host.substring(slash + 1));
2011:                    if (ip_addr.length != ip_mask.length)
2012:                        throw new ParseException("length of IP-address ("
2013:                                + ip_addr.length + ") != length of netmask ("
2014:                                + ip_mask.length + ")");
2015:                } else {
2016:                    ip_addr = string2arr(host);
2017:                    ip_mask = new byte[ip_addr.length];
2018:                    for (int idx = 0; idx < ip_mask.length; idx++)
2019:                        ip_mask[idx] = (byte) 255;
2020:                }
2021:
2022:                // check if addr or subnet already exists
2023:
2024:                ip_loop: for (int idx = 0; idx < non_proxy_addr_list.size(); idx++) {
2025:                    byte[] addr = (byte[]) non_proxy_addr_list.elementAt(idx);
2026:                    byte[] mask = (byte[]) non_proxy_mask_list.elementAt(idx);
2027:                    if (addr.length != ip_addr.length)
2028:                        continue;
2029:
2030:                    for (int idx2 = 0; idx2 < addr.length; idx2++) {
2031:                        if ((ip_addr[idx2] & mask[idx2]) != (addr[idx2] & mask[idx2])
2032:                                || (mask[idx2] != ip_mask[idx2]))
2033:                            continue ip_loop;
2034:                    }
2035:
2036:                    return; // already exists
2037:                }
2038:                non_proxy_addr_list.addElement(ip_addr);
2039:                non_proxy_mask_list.addElement(ip_mask);
2040:            }
2041:
2042:            /**
2043:             * Convenience method to add a number of hosts at once. If any one
2044:             * host is null or cannot be parsed it is ignored.
2045:             *
2046:             * @param hosts The list of hosts to set
2047:             * @see #dontProxyFor(java.lang.String)
2048:             * @since V0.3-2
2049:             */
2050:            public static void dontProxyFor(String[] hosts) {
2051:                if (hosts == null || hosts.length == 0)
2052:                    return;
2053:
2054:                for (int idx = 0; idx < hosts.length; idx++) {
2055:                    try {
2056:                        if (hosts[idx] != null)
2057:                            dontProxyFor(hosts[idx]);
2058:                    } catch (ParseException pe) {
2059:                        // ignore it
2060:                    }
2061:                }
2062:            }
2063:
2064:            /**
2065:             * Remove <var>host</var> from the list of hosts for which the proxy
2066:             * should not be used. The syntax for <var>host</var> is specified in
2067:             * <code>dontProxyFor()</code>.
2068:             *
2069:             * @param host a host name, domain name, IP-address or IP-subnet.
2070:             * @return true if the remove was sucessful, false otherwise
2071:             * @exception ParseException if the length of the netmask does not match
2072:             *                           the length of the IP-address
2073:             * @see #dontProxyFor(java.lang.String)
2074:             */
2075:            public static boolean doProxyFor(String host) throws ParseException {
2076:                host = host.trim().toLowerCase();
2077:
2078:                // check for domain name
2079:
2080:                if (host.charAt(0) == '.')
2081:                    return non_proxy_dom_list.removeElement(host);
2082:
2083:                // check for host name
2084:
2085:                for (int idx = 0; idx < host.length(); idx++) {
2086:                    if (!Character.isDigit(host.charAt(idx))
2087:                            && host.charAt(idx) != '.'
2088:                            && host.charAt(idx) != '/')
2089:                        return (non_proxy_host_list.remove(host) != null);
2090:                }
2091:
2092:                // must be an IP-address
2093:
2094:                byte[] ip_addr;
2095:                byte[] ip_mask;
2096:                int slash;
2097:                if ((slash = host.indexOf('/')) != -1) // IP subnet
2098:                {
2099:                    ip_addr = string2arr(host.substring(0, slash));
2100:                    ip_mask = string2arr(host.substring(slash + 1));
2101:                    if (ip_addr.length != ip_mask.length)
2102:                        throw new ParseException("length of IP-address ("
2103:                                + ip_addr.length + ") != length of netmask ("
2104:                                + ip_mask.length + ")");
2105:                } else {
2106:                    ip_addr = string2arr(host);
2107:                    ip_mask = new byte[ip_addr.length];
2108:                    for (int idx = 0; idx < ip_mask.length; idx++)
2109:                        ip_mask[idx] = (byte) 255;
2110:                }
2111:
2112:                ip_loop: for (int idx = 0; idx < non_proxy_addr_list.size(); idx++) {
2113:                    byte[] addr = (byte[]) non_proxy_addr_list.elementAt(idx);
2114:                    byte[] mask = (byte[]) non_proxy_mask_list.elementAt(idx);
2115:                    if (addr.length != ip_addr.length)
2116:                        continue;
2117:
2118:                    for (int idx2 = 0; idx2 < addr.length; idx2++) {
2119:                        if ((ip_addr[idx2] & mask[idx2]) != (addr[idx2] & mask[idx2])
2120:                                || (mask[idx2] != ip_mask[idx2]))
2121:                            continue ip_loop;
2122:                    }
2123:
2124:                    non_proxy_addr_list.removeElementAt(idx);
2125:                    non_proxy_mask_list.removeElementAt(idx);
2126:                    return true;
2127:                }
2128:                return false;
2129:            }
2130:
2131:            /**
2132:             * Turn an IP-address string into an array (e.g. "12.34.56.78" into
2133:             * { 12, 34, 56, 78 }).
2134:             *
2135:             * @param ip IP-address
2136:             * @return IP-address in network byte order
2137:             */
2138:            private static byte[] string2arr(String ip) {
2139:                byte[] arr;
2140:                char[] ip_char = new char[ip.length()];
2141:                ip.getChars(0, ip_char.length, ip_char, 0);
2142:
2143:                int cnt = 0;
2144:                for (int idx = 0; idx < ip_char.length; idx++)
2145:                    if (ip_char[idx] == '.')
2146:                        cnt++;
2147:                arr = new byte[cnt + 1];
2148:
2149:                cnt = 0;
2150:                int pos = 0;
2151:                for (int idx = 0; idx < ip_char.length; idx++)
2152:                    if (ip_char[idx] == '.') {
2153:                        arr[cnt] = (byte) Integer.parseInt(ip.substring(pos,
2154:                                idx));
2155:                        cnt++;
2156:                        pos = idx + 1;
2157:                    }
2158:                arr[cnt] = (byte) Integer.parseInt(ip.substring(pos));
2159:
2160:                return arr;
2161:            }
2162:
2163:            /**
2164:             * Sets the SOCKS server to use. The server will only be used
2165:             * for new HTTPConnections created after this call and will not affect
2166:             * currrent instances of HTTPConnection. A null or empty string host
2167:             * parameter disables SOCKS.
2168:             * <P>The code will try to determine the SOCKS version to use at
2169:             * connection time. This might fail for a number of reasons, however,
2170:             * in which case you must specify the version explicitly.
2171:             *
2172:             * @see #setSocksServer(java.lang.String, int, int)
2173:             * @param  host    the host on which the proxy server resides. The port
2174:             *                 used is the default port 1080.
2175:             */
2176:            public static void setSocksServer(String host) {
2177:                setSocksServer(host, 1080);
2178:            }
2179:
2180:            /**
2181:             * Sets the SOCKS server to use. The server will only be used
2182:             * for new HTTPConnections created after this call and will not affect
2183:             * currrent instances of HTTPConnection. A null or empty string host
2184:             * parameter disables SOCKS.
2185:             * <P>The code will try to determine the SOCKS version to use at
2186:             * connection time. This might fail for a number of reasons, however,
2187:             * in which case you must specify the version explicitly.
2188:             *
2189:             * @see #setSocksServer(java.lang.String, int, int)
2190:             * @param  host    the host on which the proxy server resides.
2191:             * @param  port    the port the proxy server is listening on.
2192:             */
2193:            public static void setSocksServer(String host, int port) {
2194:                if (port <= 0)
2195:                    port = 1080;
2196:
2197:                if (host == null || host.length() == 0)
2198:                    Default_Socks_client = null;
2199:                else
2200:                    Default_Socks_client = new SocksClient(host, port);
2201:            }
2202:
2203:            /**
2204:             * Sets the SOCKS server to use. The server will only be used
2205:             * for new HTTPConnections created after this call and will not affect
2206:             * currrent instances of HTTPConnection. A null or empty string host
2207:             * parameter disables SOCKS.
2208:             *
2209:             * <P>In an application or using the Appletviewer an alternative to
2210:             * this method is to set the following properties (either in the
2211:             * properties file or on the command line):
2212:             * <var>HTTPClient.socksHost</var>, <var>HTTPClient.socksPort</var>
2213:             * and <var>HTTPClient.socksVersion</var>. Whether
2214:             * <var>HTTPClient.socksHost</var> is set or not determines whether a
2215:             * SOCKS server is used; if <var>HTTPClient.socksPort</var> is not set
2216:             * it defaults to 1080; if <var>HTTPClient.socksVersion</var> is not
2217:             * set an attempt will be made to automatically determine the version
2218:             * used by the server.
2219:             *
2220:             * <P>Note: If you have also set a proxy server then a connection
2221:             * will be made to the SOCKS server, which in turn then makes a
2222:             * connection to the proxy server (possibly via other SOCKS servers),
2223:             * which in turn makes the final connection.
2224:             *
2225:             * <P>If the proxy server is running SOCKS version 5 and requires
2226:             * username/password authorization, and you wish to set
2227:             * this authorization information in the code, then you may use the
2228:             * <var>AuthorizationInfo.addAuthorization()</var> method to do so.
2229:             * Specify the same <var>host</var> and <var>port</var> as in this
2230:             * method, give the <var>scheme</var> "SOCKS5" and the <var>realm</var>
2231:             * "USER/PASS", set the <var>cookie</var> to null and the
2232:             * <var>params</var> to an array containing a single <var>NVPair</var>
2233:             * in turn containing the username and password. Example:
2234:             * <PRE>
2235:             *     NVPair[] up = { new NVPair(username, password) };
2236:             *     AuthorizationInfo.addAuthorization(host, port, "SOCKS5", "USER/PASS",
2237:             *                                        null, up);
2238:             * </PRE>
2239:             * If you have not given any authorization info and the proxy server
2240:             * requires authorization then you will be prompted for the necessary
2241:             * info via a popup the first time you do a request.
2242:             *
2243:             * @param  host    the host on which the proxy server resides.
2244:             * @param  port    the port the proxy server is listening on.
2245:             * @param  version the SOCKS version the server is running. Currently
2246:             *                 this must be '4' or '5'.
2247:             * @exception SocksException If <var>version</var> is not '4' or '5'.
2248:             */
2249:            public static void setSocksServer(String host, int port, int version)
2250:                    throws SocksException {
2251:                if (port <= 0)
2252:                    port = 1080;
2253:
2254:                if (host == null || host.length() == 0)
2255:                    Default_Socks_client = null;
2256:                else
2257:                    Default_Socks_client = new SocksClient(host, port, version);
2258:            }
2259:
2260:            /**
2261:             * Removes the #... part. Returns the stripped name, or "" if either
2262:             * the <var>file</var> is null or is the empty string (after stripping).
2263:             *
2264:             * @param file the name to strip
2265:             * @return the stripped name
2266:             */
2267:            private final String stripRef(String file) {
2268:                if (file == null)
2269:                    return "";
2270:
2271:                int hash = file.indexOf('#');
2272:                if (hash != -1)
2273:                    file = file.substring(0, hash);
2274:
2275:                return file.trim();
2276:            }
2277:
2278:            // private helper methods
2279:
2280:            /**
2281:             * Sets up the request, creating the list of headers to send and
2282:             * creating instances of the modules.
2283:             *
2284:             * @param  method   GET, POST, etc.
2285:             * @param  resource the resource
2286:             * @param  headers  an array of headers to be used
2287:             * @param  entity   the entity (or null)
2288:             * @return the response.
2289:             * @exception java.io.IOException when an exception is returned from
2290:             *                                the socket.
2291:             * @exception ModuleException if an exception is encountered in any module.
2292:             */
2293:            private HTTPResponse setupRequest(String method, String resource,
2294:                    NVPair[] headers, byte[] entity, HttpOutputStream stream)
2295:                    throws IOException, ModuleException {
2296:                Request req = new Request(this , method, resource,
2297:                        mergedHeaders(headers), entity, stream, AllowUI);
2298:                RequestList.addToEnd(req);
2299:
2300:                try {
2301:                    HTTPResponse resp = new HTTPResponse(gen_mod_insts(),
2302:                            Timeout, req);
2303:                    handleRequest(req, resp, null, true);
2304:                    return resp;
2305:                } finally {
2306:                    RequestList.remove(req);
2307:                }
2308:            }
2309:
2310:            /**
2311:             * This merges built-in default headers, user-specified default headers,
2312:             * and method-specified headers. Method-specified take precedence over
2313:             * user defaults, which take precedence over built-in defaults.
2314:             *
2315:             * The following headers are removed if found: "Host" and
2316:             * "Content-length".
2317:             *
2318:             * @param  spec   the headers specified in the call to the method
2319:             * @return an array consisting of merged headers.
2320:             */
2321:            private NVPair[] mergedHeaders(NVPair[] spec) {
2322:                int spec_len = (spec != null ? spec.length : 0), defs_len;
2323:                NVPair[] merged;
2324:
2325:                synchronized (DefaultHeaders) {
2326:                    defs_len = (DefaultHeaders != null ? DefaultHeaders.length
2327:                            : 0);
2328:                    merged = new NVPair[spec_len + defs_len];
2329:
2330:                    // copy default headers
2331:                    System.arraycopy(DefaultHeaders, 0, merged, 0, defs_len);
2332:                }
2333:
2334:                // merge in selected headers
2335:                int sidx, didx = defs_len;
2336:                for (sidx = 0; sidx < spec_len; sidx++) {
2337:                    String s_name = spec[sidx].getName().trim();
2338:                    if (s_name.equalsIgnoreCase("Content-length")
2339:                            || s_name.equalsIgnoreCase("Host"))
2340:                        continue;
2341:
2342:                    int search;
2343:                    for (search = 0; search < didx; search++) {
2344:                        if (merged[search].getName().trim().equalsIgnoreCase(
2345:                                s_name))
2346:                            break;
2347:                    }
2348:
2349:                    merged[search] = spec[sidx];
2350:                    if (search == didx)
2351:                        didx++;
2352:                }
2353:
2354:                if (didx < merged.length)
2355:                    merged = Util.resizeArray(merged, didx);
2356:
2357:                return merged;
2358:            }
2359:
2360:            /**
2361:             * Generate an array of instances of the current modules.
2362:             */
2363:            private HTTPClientModule[] gen_mod_insts() {
2364:                synchronized (ModuleList) {
2365:                    HTTPClientModule[] mod_insts = new HTTPClientModule[ModuleList
2366:                            .size()];
2367:
2368:                    for (int idx = 0; idx < ModuleList.size(); idx++) {
2369:                        Class mod = (Class) ModuleList.elementAt(idx);
2370:                        try {
2371:                            mod_insts[idx] = (HTTPClientModule) mod
2372:                                    .newInstance();
2373:                        } catch (Exception e) {
2374:                            throw new Error(
2375:                                    "HTTPClient Internal Error: could not "
2376:                                            + "create instance of "
2377:                                            + mod.getName() + " -\n" + e);
2378:                        }
2379:                    }
2380:
2381:                    return mod_insts;
2382:                }
2383:            }
2384:
2385:            /**
2386:             * handles the Request. First the request handler for each module is
2387:             * is invoked, and then if no response was generated the request is
2388:             * sent.
2389:             *
2390:             * @param  req        the Request
2391:             * @param  http_resp  the HTTPResponse
2392:             * @param  resp       the Response
2393:             * @param  usemodules if false then skip module loop
2394:             * @exception IOException if any module or sendRequest throws it
2395:             * @exception ModuleException if any module throws it
2396:             */
2397:            void handleRequest(Request req, HTTPResponse http_resp,
2398:                    Response resp, boolean usemodules) throws IOException,
2399:                    ModuleException {
2400:                Response[] rsp_arr = { resp };
2401:                HTTPClientModule[] modules = http_resp.getModules();
2402:
2403:                // invoke requestHandler for each module
2404:
2405:                if (usemodules)
2406:                    doModules: for (int idx = 0; idx < modules.length; idx++) {
2407:                        int sts = modules[idx].requestHandler(req, rsp_arr);
2408:                        switch (sts) {
2409:                        case REQ_CONTINUE: // continue processing
2410:                            break;
2411:
2412:                        case REQ_RESTART: // restart processing with first module
2413:                            idx = -1;
2414:                            continue doModules;
2415:
2416:                        case REQ_SHORTCIRC: // stop processing and send
2417:                            break doModules;
2418:
2419:                        case REQ_RESPONSE: // go to phase 2
2420:                        case REQ_RETURN: // return response immediately
2421:                            if (rsp_arr[0] == null)
2422:                                throw new Error(
2423:                                        "HTTPClient Internal Error: no "
2424:                                                + "response returned by module "
2425:                                                + modules[idx].getClass()
2426:                                                        .getName());
2427:                            http_resp.set(req, rsp_arr[0]);
2428:                            if (req.getStream() != null)
2429:                                req.getStream().ignoreData(req);
2430:                            if (req.internal_subrequest)
2431:                                return;
2432:                            if (sts == REQ_RESPONSE)
2433:                                http_resp.handleResponse();
2434:                            else
2435:                                http_resp.init(rsp_arr[0]);
2436:                            return;
2437:
2438:                        case REQ_NEWCON_RST: // new connection
2439:                            if (req.internal_subrequest)
2440:                                return;
2441:                            req.getConnection().handleRequest(req, http_resp,
2442:                                    rsp_arr[0], true);
2443:                            return;
2444:
2445:                        case REQ_NEWCON_SND: // new connection, send immediately
2446:                            if (req.internal_subrequest)
2447:                                return;
2448:                            req.getConnection().handleRequest(req, http_resp,
2449:                                    rsp_arr[0], false);
2450:                            return;
2451:
2452:                        default: // not valid
2453:                            throw new Error(
2454:                                    "HTTPClient Internal Error: invalid status"
2455:                                            + " " + sts
2456:                                            + " returned by module "
2457:                                            + modules[idx].getClass().getName());
2458:                        }
2459:                    }
2460:
2461:                if (req.internal_subrequest)
2462:                    return;
2463:
2464:                // Send the request across the wire
2465:
2466:                if (req.getStream() != null
2467:                        && req.getStream().getLength() == -1) {
2468:                    if (!ServProtVersKnown || ServerProtocolVersion < HTTP_1_1
2469:                            || no_chunked) {
2470:                        req.getStream().goAhead(req, null,
2471:                                http_resp.getTimeout());
2472:                        http_resp.set(req, req.getStream());
2473:                    } else {
2474:                        // add Transfer-Encoding header if necessary
2475:                        int idx;
2476:                        NVPair[] hdrs = req.getHeaders();
2477:                        for (idx = 0; idx < hdrs.length; idx++)
2478:                            if (hdrs[idx].getName().equalsIgnoreCase(
2479:                                    "Transfer-Encoding"))
2480:                                break;
2481:
2482:                        if (idx == hdrs.length) {
2483:                            hdrs = Util.resizeArray(hdrs, idx + 1);
2484:                            hdrs[idx] = new NVPair("Transfer-Encoding",
2485:                                    "chunked");
2486:                            req.setHeaders(hdrs);
2487:                        } else {
2488:                            String v = hdrs[idx].getValue();
2489:                            try {
2490:                                if (!Util.hasToken(v, "chunked"))
2491:                                    hdrs[idx] = new NVPair("Transfer-Encoding",
2492:                                            v + ", chunked");
2493:                            } catch (ParseException pe) {
2494:                                throw new IOException(pe.toString());
2495:                            }
2496:                        }
2497:
2498:                        http_resp.set(req, sendRequest(req, http_resp
2499:                                .getTimeout()));
2500:                    }
2501:                } else
2502:                    http_resp
2503:                            .set(req, sendRequest(req, http_resp.getTimeout()));
2504:
2505:                if (req.aborted)
2506:                    throw new IOException("Request aborted by user");
2507:            }
2508:
2509:            /** These mark the response to stall the next request on, if any */
2510:            private Response early_stall = null;
2511:            private Response late_stall = null;
2512:            private Response prev_resp = null;
2513:            /** This marks the socket output stream as still being used */
2514:            private boolean output_finished = true;
2515:
2516:            /**
2517:             * sends the request over the line.
2518:             *
2519:             * @param  req         the request
2520:             * @param  con_timeout the timeout to use when establishing a socket
2521:             *                     connection; an InterruptedIOException is thrown
2522:             *                     if the procedure times out.
2523:             * @return the response.
2524:             * @exception IOException     if thrown by the socket
2525:             * @exception InterruptedIOException if the connection is not established
2526:             *                                   within the specified timeout
2527:             * @exception ModuleException if any module throws it during the SSL-
2528:             *                            tunneling handshake
2529:             */
2530:            Response sendRequest(Request req, int con_timeout)
2531:                    throws IOException, ModuleException {
2532:                ByteArrayOutputStream hdr_buf = new ByteArrayOutputStream(600);
2533:                Response resp = null;
2534:                boolean keep_alive;
2535:
2536:                // The very first request is special in that we need its response
2537:                // before any further requests may be made. This is to set things
2538:                // like the server version.
2539:
2540:                if (early_stall != null) {
2541:                    try {
2542:                        if (DebugConn)
2543:                            System.err
2544:                                    .println("Conn:  Early-stalling Request: "
2545:                                            + req.getMethod() + " "
2546:                                            + req.getRequestURI());
2547:
2548:                        synchronized (early_stall) {
2549:                            // wait till the response is received
2550:                            try {
2551:                                early_stall.getVersion();
2552:                            } catch (IOException ioe) {
2553:                            }
2554:                            early_stall = null;
2555:                        }
2556:                    } catch (NullPointerException npe) {
2557:                    }
2558:                }
2559:
2560:                String[] con_hdrs = assembleHeaders(req, hdr_buf);
2561:
2562:                // determine if the connection should be kept alive after this
2563:                // request
2564:
2565:                try {
2566:                    if (ServerProtocolVersion >= HTTP_1_1
2567:                            && !Util.hasToken(con_hdrs[0], "close")
2568:                            || ServerProtocolVersion == HTTP_1_0
2569:                            && Util.hasToken(con_hdrs[0], "keep-alive"))
2570:                        keep_alive = true;
2571:                    else
2572:                        keep_alive = false;
2573:                } catch (ParseException pe) {
2574:                    throw new IOException(pe.toString());
2575:                }
2576:
2577:                synchronized (this ) {
2578:                    // Sometimes we must stall the pipeline until the previous request
2579:                    // has been answered. However, if we are going to open up a new
2580:                    // connection anyway we don't really need to stall.
2581:
2582:                    if (late_stall != null) {
2583:                        if (input_demux != null || KeepAliveUnknown) {
2584:                            if (DebugConn)
2585:                                System.err.println("Conn:  Stalling Request: "
2586:                                        + req.getMethod() + " "
2587:                                        + req.getRequestURI());
2588:
2589:                            try // wait till the response is received
2590:                            {
2591:                                late_stall.getVersion();
2592:                                if (KeepAliveUnknown)
2593:                                    determineKeepAlive(late_stall);
2594:                            } catch (IOException ioe) {
2595:                            }
2596:                        }
2597:
2598:                        late_stall = null;
2599:                    }
2600:
2601:                    /* POSTs must not be pipelined because of problems if the connection
2602:                     * is aborted. Since it is generally impossible to know what urls
2603:                     * POST will influence it is impossible to determine if a sequence
2604:                     * of requests containing a POST is idempotent.
2605:                     * Also, for retried requests we don't want to pipeline either.
2606:                     */
2607:                    if ((req.getMethod().equals("POST") || req.dont_pipeline)
2608:                            && prev_resp != null && input_demux != null) {
2609:                        if (DebugConn)
2610:                            System.err.println("Conn:  Stalling Request: "
2611:                                    + req.getMethod() + " "
2612:                                    + req.getRequestURI());
2613:
2614:                        try // wait till the response is received
2615:                        {
2616:                            prev_resp.getVersion();
2617:                        } catch (IOException ioe) {
2618:                        }
2619:                    }
2620:
2621:                    // If the previous request used an output stream, then wait till
2622:                    // all the data has been written
2623:
2624:                    if (!output_finished) {
2625:                        try {
2626:                            wait();
2627:                        } catch (InterruptedException ie) {
2628:                            throw new IOException(ie.toString());
2629:                        }
2630:                    }
2631:
2632:                    if (req.aborted)
2633:                        throw new IOException("Request aborted by user");
2634:
2635:                    int try_count = 3;
2636:                    /* what a hack! This is to handle the case where the server closes
2637:                     * the connection but we don't realize it until we try to send
2638:                     * something. The problem is that we only get IOException, but
2639:                     * we need a finer specification (i.e. whether it's an EPIPE or
2640:                     * something else); I don't trust relying on the message part
2641:                     * of IOException (which on SunOS/Solaris gives 'Broken pipe',
2642:                     * but what on Windoze/Mac?).
2643:                     */
2644:
2645:                    while (try_count-- > 0) {
2646:                        try {
2647:                            // get a client socket
2648:
2649:                            Socket sock;
2650:                            if (input_demux == null
2651:                                    || (sock = input_demux.getSocket()) == null) {
2652:                                sock = getSocket(con_timeout);
2653:
2654:                                if (Protocol == HTTPS) {
2655:                                    if (Proxy_Host != null) {
2656:                                        Socket[] sarr = { sock };
2657:                                        resp = enableSSLTunneling(sarr, req,
2658:                                                con_timeout);
2659:                                        if (resp != null) {
2660:                                            resp.final_resp = true;
2661:                                            return resp;
2662:                                        }
2663:                                        sock = sarr[0];
2664:                                    }
2665:                                    SSLSupport support = SSLSupport
2666:                                            .getDefault();
2667:                                    if (support != null)
2668:                                        sock = support.createSocket(sock, Host,
2669:                                                Port);
2670:                                    //sock = new SSLSocket(sock);
2671:                                }
2672:
2673:                                input_demux = new StreamDemultiplexor(Protocol,
2674:                                        sock, this );
2675:                                DemuxList.addToEnd(input_demux);
2676:                                KeepAliveReqLeft = KeepAliveReqMax;
2677:                            }
2678:
2679:                            if (req.aborted)
2680:                                throw new IOException("Request aborted by user");
2681:
2682:                            if (DebugConn) {
2683:                                System.err.println("Conn:  Sending Request: ");
2684:                                System.err.println();
2685:                                hdr_buf.writeTo(System.err);
2686:                            }
2687:
2688:                            // Send headers
2689:
2690:                            OutputStream sock_out = sock.getOutputStream();
2691:                            if (haveMSLargeWritesBug)
2692:                                sock_out = new MSLargeWritesBugStream(sock_out);
2693:
2694:                            hdr_buf.writeTo(sock_out);
2695:
2696:                            // Wait for "100 Continue" status if necessary
2697:
2698:                            try {
2699:                                if (ServProtVersKnown
2700:                                        && ServerProtocolVersion >= HTTP_1_1
2701:                                        && Util.hasToken(con_hdrs[1],
2702:                                                "100-continue")) {
2703:                                    resp = new Response(
2704:                                            req,
2705:                                            (Proxy_Host != null && Protocol != HTTPS),
2706:                                            input_demux);
2707:                                    resp.timeout = 60;
2708:                                    if (resp.getContinue() != 100)
2709:                                        break;
2710:                                }
2711:                            } catch (ParseException pe) {
2712:                                throw new IOException(pe.toString());
2713:                            } catch (InterruptedIOException iioe) {
2714:                            } finally {
2715:                                if (resp != null)
2716:                                    resp.timeout = 0;
2717:                            }
2718:
2719:                            // POST/PUT data
2720:
2721:                            if (req.getData() != null
2722:                                    && req.getData().length > 0) {
2723:                                if (req.delay_entity > 0) {
2724:                                    // wait for something on the network; check available()
2725:                                    // roughly every 100 ms
2726:
2727:                                    long num_units = req.delay_entity / 100;
2728:                                    long one_unit = req.delay_entity
2729:                                            / num_units;
2730:
2731:                                    for (int idx = 0; idx < num_units; idx++) {
2732:                                        if (input_demux.available(null) != 0)
2733:                                            break;
2734:                                        try {
2735:                                            Thread.sleep(one_unit);
2736:                                        } catch (InterruptedException ie) {
2737:                                        }
2738:                                    }
2739:
2740:                                    if (input_demux.available(null) == 0)
2741:                                        sock_out.write(req.getData()); // he's still waiting
2742:                                    else
2743:                                        keep_alive = false; // Uh oh!
2744:                                } else
2745:                                    sock_out.write(req.getData());
2746:                            }
2747:
2748:                            if (req.getStream() != null)
2749:                                req.getStream().goAhead(req, sock_out, 0);
2750:                            else
2751:                                sock_out.flush();
2752:
2753:                            // get a new response.
2754:                            // Note: this does not do a read on the socket.
2755:
2756:                            if (resp == null)
2757:                                resp = new Response(
2758:                                        req,
2759:                                        (Proxy_Host != null && Protocol != HTTPS),
2760:                                        input_demux);
2761:                        } catch (IOException ioe) {
2762:                            if (DebugConn) {
2763:                                System.err.print("Conn:  ");
2764:                                ioe.printStackTrace();
2765:                            }
2766:
2767:                            closeDemux(ioe, true);
2768:
2769:                            if (try_count == 0
2770:                                    || ioe instanceof  UnknownHostException
2771:                                    || ioe instanceof  InterruptedIOException
2772:                                    || req.aborted)
2773:                                throw ioe;
2774:
2775:                            if (DebugConn)
2776:                                System.err.println("Conn:  Retrying request");
2777:                            continue;
2778:                        }
2779:
2780:                        break;
2781:                    }
2782:
2783:                    prev_resp = resp;
2784:
2785:                    // close the stream after this response if necessary
2786:
2787:                    if ((!KeepAliveUnknown && !DoesKeepAlive)
2788:                            || !keep_alive
2789:                            || (KeepAliveReqMax != -1 && KeepAliveReqLeft-- == 0)) {
2790:                        input_demux.markForClose(resp);
2791:                        input_demux = null;
2792:                    } else
2793:                        input_demux.restartTimer();
2794:
2795:                    if (DebugConn) {
2796:                        if (KeepAliveReqMax != -1)
2797:                            System.err
2798:                                    .println("Conn:  Number of requests left: "
2799:                                            + KeepAliveReqLeft);
2800:                    }
2801:
2802:                    /* We don't pipeline the first request, as we need some info
2803:                     * about the server (such as which http version it complies with)
2804:                     */
2805:                    if (!ServProtVersKnown) {
2806:                        early_stall = resp;
2807:                        resp.markAsFirstResponse(req);
2808:                    }
2809:
2810:                    /* Also don't pipeline until we know if the server supports
2811:                     * keep-alive's or not.
2812:                     * Note: strictly speaking, HTTP/1.0 keep-alives don't mean we can
2813:                     *       pipeline requests. I seem to remember some (beta?) version
2814:                     *       of Netscape's Enterprise server which barfed if you tried
2815:                     *       push requests down it's throat w/o waiting for the previous
2816:                     *       response first. However, I've not been able to find such a
2817:                     *       server lately, and so I'm taking the risk and assuming we
2818:                     *       can in fact pipeline requests to HTTP/1.0 servers.
2819:                     */
2820:                    if (KeepAliveUnknown ||
2821:                    // We don't pipeline POST's ...
2822:                            !IdempotentSequence.methodIsIdempotent(req
2823:                                    .getMethod()) || req.dont_pipeline || // Retries disable pipelining too
2824:                            NeverPipeline) // Emergency measure: prevent all pipelining
2825:                    {
2826:                        late_stall = resp;
2827:                    }
2828:
2829:                    /* If there is an output stream then just tell the other threads to
2830:                     * wait; the stream will notify() when it's done. If there isn't any
2831:                     * stream then wake up a waiting thread (if any).
2832:                     */
2833:                    if (req.getStream() != null)
2834:                        output_finished = false;
2835:                    else {
2836:                        output_finished = true;
2837:                        notify();
2838:                    }
2839:
2840:                    // Looks like were finally done
2841:
2842:                    if (DebugConn)
2843:                        System.err.println("Conn:  Request sent");
2844:                }
2845:
2846:                return resp;
2847:            }
2848:
2849:            /**
2850:             * Gets a socket. Creates a socket to the proxy if set, or else to the
2851:             * actual destination.
2852:             *
2853:             * @param con_timeout if not 0 then start a new thread to establish the
2854:             *                    the connection and join(con_timeout) it. If the
2855:             *                    join() times out an InteruptedIOException is thrown.
2856:             */
2857:            private Socket getSocket(int con_timeout) throws IOException {
2858:                Socket sock = null;
2859:
2860:                String actual_host;
2861:                int actual_port;
2862:
2863:                if (Proxy_Host != null) {
2864:                    actual_host = Proxy_Host;
2865:                    actual_port = Proxy_Port;
2866:                } else {
2867:                    actual_host = Host;
2868:                    actual_port = Port;
2869:                }
2870:
2871:                if (DebugConn)
2872:                    System.err.println("Conn:  Creating Socket: " + actual_host
2873:                            + ":" + actual_port);
2874:
2875:                if (con_timeout == 0) // normal connection establishment
2876:                {
2877:                    if (Socks_client != null)
2878:                        sock = Socks_client.getSocket(actual_host, actual_port);
2879:                    else {
2880:                        // try all A records
2881:                        InetAddress[] addr_list = InetAddress
2882:                                .getAllByName(actual_host);
2883:                        for (int idx = 0; idx < addr_list.length; idx++) {
2884:                            try {
2885:                                sock = new Socket(addr_list[idx], actual_port);
2886:                                break; // success
2887:                            } catch (SocketException se) // should be NoRouteToHostException
2888:                            {
2889:                                if (idx == addr_list.length - 1)
2890:                                    throw se; // we tried them all
2891:                            }
2892:                        }
2893:                    }
2894:                } else {
2895:                    EstablishConnection con = new EstablishConnection(
2896:                            actual_host, actual_port, Socks_client);
2897:                    con.start();
2898:                    try {
2899:                        con.join((long) con_timeout);
2900:                    } catch (InterruptedException ie) {
2901:                    }
2902:
2903:                    if (con.getException() != null)
2904:                        throw con.getException();
2905:                    if ((sock = con.getSocket()) == null) {
2906:                        con.forget();
2907:                        if ((sock = con.getSocket()) == null)
2908:                            throw new InterruptedIOException(
2909:                                    "Connection establishment timed out");
2910:                    }
2911:                }
2912:
2913:                return sock;
2914:            }
2915:
2916:            /**
2917:             * Enable SSL Tunneling if we're talking to a proxy. See ietf draft
2918:             * draft-luotonen-ssl-tunneling-03 for more info.
2919:             *
2920:             * @param sock    the socket
2921:             * @param req     the request initiating this connection
2922:             * @param timeout the timeout
2923:             * @return the proxy's last response if unsuccessful, or null if
2924:             *         tunnel successfuly established
2925:             * @exception IOException
2926:             * @exception ModuleException
2927:             */
2928:            private Response enableSSLTunneling(Socket[] sock, Request req,
2929:                    int timeout) throws IOException, ModuleException {
2930:                // copy User-Agent and Proxy-Auth headers from request
2931:
2932:                Vector hdrs = new Vector();
2933:                for (int idx = 0; idx < req.getHeaders().length; idx++) {
2934:                    String name = req.getHeaders()[idx].getName();
2935:                    if (name.equalsIgnoreCase("User-Agent")
2936:                            || name.equalsIgnoreCase("Proxy-Authorization"))
2937:                        hdrs.addElement(req.getHeaders()[idx]);
2938:                }
2939:
2940:                // create initial CONNECT subrequest
2941:
2942:                NVPair[] h = new NVPair[hdrs.size()];
2943:                hdrs.copyInto(h);
2944:                Request connect = new Request(this , "CONNECT", Host + ":"
2945:                        + Port, h, null, null, req.allowUI());
2946:                connect.internal_subrequest = true;
2947:
2948:                ByteArrayOutputStream hdr_buf = new ByteArrayOutputStream(600);
2949:                HTTPResponse r = new HTTPResponse(gen_mod_insts(), timeout,
2950:                        connect);
2951:
2952:                // send and handle CONNECT request until successful or tired
2953:
2954:                Response resp = null;
2955:
2956:                while (true) {
2957:                    handleRequest(connect, r, resp, true);
2958:
2959:                    hdr_buf.reset();
2960:                    assembleHeaders(connect, hdr_buf);
2961:
2962:                    if (DebugConn) {
2963:                        System.err
2964:                                .println("Conn:  Sending SSL-Tunneling Subrequest: ");
2965:                        System.err.println();
2966:                        hdr_buf.writeTo(System.err);
2967:                    }
2968:
2969:                    // send CONNECT
2970:
2971:                    hdr_buf.writeTo(sock[0].getOutputStream());
2972:
2973:                    // return if successful
2974:
2975:                    resp = new Response(connect, sock[0].getInputStream());
2976:                    if (resp.getStatusCode() == 200)
2977:                        return null;
2978:
2979:                    // failed!
2980:
2981:                    // make life easy: read data and close socket
2982:
2983:                    try {
2984:                        resp.getData();
2985:                    } catch (IOException ioe) {
2986:                    }
2987:                    try {
2988:                        sock[0].close();
2989:                    } catch (IOException ioe) {
2990:                    }
2991:
2992:                    // handle response
2993:
2994:                    r.set(connect, resp);
2995:                    if (!r.handleResponse())
2996:                        return resp;
2997:
2998:                    sock[0] = getSocket(timeout);
2999:                }
3000:            }
3001:
3002:            /**
3003:             * This writes out the headers on the <var>hdr_buf</var>. It takes
3004:             * special precautions for the following headers:
3005:             * <DL>
3006:             * <DT>Content-type<DI>This is only written if the request has an entity.
3007:             *                     If the request has an entity and no content-type
3008:             *                     header was given for the request it defaults to
3009:             *                     "application/octet-stream"
3010:             * <DT>Content-length<DI>This header is generated if the request has an
3011:             *                     entity and the entity isn't being sent with the
3012:             *                     Transfer-Encoding "chunked".
3013:             * <DT>User-Agent  <DI>If not present it will be generated with the current
3014:             *                     HTTPClient version strings. Otherwise the version
3015:             *                     string is appended to the given User-Agent string.
3016:             * <DT>Connection  <DI>This header is only written if no proxy is used.
3017:             *                     If no connection header is specified and the server
3018:             *                     is not known to understand HTTP/1.1 or later then
3019:             *                     a "Connection: keep-alive" header is generated.
3020:             * <DT>Proxy-Connection<DI>This header is only written if a proxy is used.
3021:             *                     If no connection header is specified and the proxy
3022:             *                     is not known to understand HTTP/1.1 or later then
3023:             *                     a "Proxy-Connection: keep-alive" header is generated.
3024:             * <DT>Keep-Alive  <DI>This header is only written if the Connection or
3025:             *                     Proxy-Connection header contains the Keep-Alive
3026:             *                     token.
3027:             * <DT>Expect      <DI>If there is no entity and this header contains the
3028:             *                     "100-continue" token then this token is removed.
3029:             *                     before writing the header.
3030:             * <DT>TE          <DI>If this header does not exist, it is created; else
3031:             *                     if the "trailers" token is not specified this token
3032:             *                     is added; else the header is not touched.
3033:             * </DL>
3034:             *
3035:             * Furthermore, it escapes various characters in request-URI.
3036:             *
3037:             * @param req     the Request
3038:             * @param hdr_buf the buffer onto which to write the headers
3039:             * @return        an array of headers; the first element contains the
3040:             *                the value of the Connection or Proxy-Connectin header,
3041:             *                the second element the value of the Expect header.
3042:             * @exception IOException if writing on <var>hdr_buf</var> generates an
3043:             *                        an IOException, or if an error occurs during
3044:             *                        parsing of a header
3045:             */
3046:            private String[] assembleHeaders(Request req,
3047:                    ByteArrayOutputStream hdr_buf) throws IOException {
3048:                DataOutputStream dataout = new DataOutputStream(hdr_buf);
3049:                String[] con_hdrs = { "", "" };
3050:                NVPair[] hdrs = req.getHeaders();
3051:
3052:                // Generate request line and Host header
3053:
3054:                String file = Util.escapeUnsafeChars(req.getRequestURI());
3055:                if (Proxy_Host != null && Protocol != HTTPS
3056:                        && !file.equals("*"))
3057:                    dataout.writeBytes(req.getMethod() + " http://" + Host
3058:                            + ":" + Port + file + " " + RequestProtocolVersion
3059:                            + "\r\n");
3060:                else
3061:                    dataout.writeBytes(req.getMethod() + " " + file + " "
3062:                            + RequestProtocolVersion + "\r\n");
3063:
3064:                if (Port != 80)
3065:                    dataout.writeBytes("Host: " + Host + ":" + Port + "\r\n");
3066:                else
3067:                    // Netscape-Enterprise has some bugs...
3068:                    dataout.writeBytes("Host: " + Host + "\r\n");
3069:
3070:                // remember various headers
3071:
3072:                int ct_idx = -1, ua_idx = -1, co_idx = -1, pc_idx = -1, ka_idx = -1, ex_idx = -1, te_idx = -1, tc_idx = -1, ug_idx = -1;
3073:                for (int idx = 0; idx < hdrs.length; idx++) {
3074:                    String name = hdrs[idx].getName().trim();
3075:                    if (name.equalsIgnoreCase("Content-Type"))
3076:                        ct_idx = idx;
3077:                    else if (name.equalsIgnoreCase("User-Agent"))
3078:                        ua_idx = idx;
3079:                    else if (name.equalsIgnoreCase("Connection"))
3080:                        co_idx = idx;
3081:                    else if (name.equalsIgnoreCase("Proxy-Connection"))
3082:                        pc_idx = idx;
3083:                    else if (name.equalsIgnoreCase("Keep-Alive"))
3084:                        ka_idx = idx;
3085:                    else if (name.equalsIgnoreCase("Expect"))
3086:                        ex_idx = idx;
3087:                    else if (name.equalsIgnoreCase("TE"))
3088:                        te_idx = idx;
3089:                    else if (name.equalsIgnoreCase("Transfer-Encoding"))
3090:                        tc_idx = idx;
3091:                    else if (name.equalsIgnoreCase("Upgrade"))
3092:                        ug_idx = idx;
3093:                }
3094:
3095:                /*
3096:                 * What follows is the setup for persistent connections. We default
3097:                 * to doing persistent connections for both HTTP/1.0 and HTTP/1.1,
3098:                 * unless we're using a proxy server and HTTP/1.0 in which case we
3099:                 * must make sure we don't do persistence (because of the problem of
3100:                 * 1.0 proxies blindly passing the Connection header on).
3101:                 *
3102:                 * Note: there is a "Proxy-Connection" header for use with proxies.
3103:                 * This however is only understood by Netscape and Netapp caches.
3104:                 * Furthermore, it suffers from the same problem as the Connection
3105:                 * header in HTTP/1.0 except that at least two proxies must be
3106:                 * involved. But I've taken the risk now and decided to send the
3107:                 * Proxy-Connection header. If I get complaints I'll remove it again.
3108:                 *
3109:                 * In any case, with this header we can now modify the above to send
3110:                 * the Proxy-Connection header whenever we wouldn't send the normal
3111:                 * Connection header.
3112:                 */
3113:
3114:                String co_hdr = null;
3115:                if (!(ServProtVersKnown && ServerProtocolVersion >= HTTP_1_1 && co_idx == -1)) {
3116:                    if (co_idx == -1) { // no connection header given by user
3117:                        co_hdr = "Keep-Alive";
3118:                        con_hdrs[0] = "Keep-Alive";
3119:                    } else {
3120:                        con_hdrs[0] = hdrs[co_idx].getValue().trim();
3121:                        co_hdr = con_hdrs[0];
3122:                    }
3123:
3124:                    try {
3125:                        if (ka_idx != -1
3126:                                && Util.hasToken(con_hdrs[0], "keep-alive"))
3127:                            dataout.writeBytes("Keep-Alive: "
3128:                                    + hdrs[ka_idx].getValue().trim() + "\r\n");
3129:                    } catch (ParseException pe) {
3130:                        throw new IOException(pe.toString());
3131:                    }
3132:                }
3133:
3134:                if ((Proxy_Host != null && Protocol != HTTPS)
3135:                        && !(ServProtVersKnown && ServerProtocolVersion >= HTTP_1_1)) {
3136:                    if (co_hdr != null) {
3137:                        dataout.writeBytes("Proxy-Connection: ");
3138:                        dataout.writeBytes(co_hdr);
3139:                        dataout.writeBytes("\r\n");
3140:                        co_hdr = null;
3141:                    }
3142:                }
3143:
3144:                if (co_hdr != null) {
3145:                    try {
3146:                        if (!Util.hasToken(co_hdr, "TE"))
3147:                            co_hdr += ", TE";
3148:                    } catch (ParseException pe) {
3149:                        throw new IOException(pe.toString());
3150:                    }
3151:                } else
3152:                    co_hdr = "TE";
3153:
3154:                if (ug_idx != -1)
3155:                    co_hdr += ", Upgrade";
3156:
3157:                if (co_hdr != null) {
3158:                    dataout.writeBytes("Connection: ");
3159:                    dataout.writeBytes(co_hdr);
3160:                    dataout.writeBytes("\r\n");
3161:                }
3162:
3163:                // handle TE header
3164:
3165:                if (te_idx != -1) {
3166:                    dataout.writeBytes("TE: ");
3167:                    Vector pte;
3168:                    try {
3169:                        pte = Util.parseHeader(hdrs[te_idx].getValue());
3170:                    } catch (ParseException pe) {
3171:                        throw new IOException(pe.toString());
3172:                    }
3173:
3174:                    if (!pte.contains(new HttpHeaderElement("trailers")))
3175:                        dataout.writeBytes("trailers, ");
3176:
3177:                    dataout.writeBytes(hdrs[te_idx].getValue().trim() + "\r\n");
3178:                } else
3179:                    dataout.writeBytes("TE: trailers\r\n");
3180:
3181:                // User-Agent
3182:
3183:                if (ua_idx != -1)
3184:                    dataout.writeBytes("User-Agent: "
3185:                            + hdrs[ua_idx].getValue().trim() + " " + version
3186:                            + "\r\n");
3187:                else
3188:                    dataout.writeBytes("User-Agent: " + version + "\r\n");
3189:
3190:                // Write out any headers left
3191:
3192:                for (int idx = 0; idx < hdrs.length; idx++) {
3193:                    if (idx != ct_idx && idx != ua_idx && idx != co_idx
3194:                            && idx != pc_idx && idx != ka_idx && idx != ex_idx
3195:                            && idx != te_idx)
3196:                        dataout.writeBytes(hdrs[idx].getName().trim() + ": "
3197:                                + hdrs[idx].getValue().trim() + "\r\n");
3198:                }
3199:
3200:                // Handle Content-type, Content-length and Expect headers
3201:
3202:                if (req.getData() != null || req.getStream() != null) {
3203:                    dataout.writeBytes("Content-type: ");
3204:                    if (ct_idx != -1)
3205:                        dataout.writeBytes(hdrs[ct_idx].getValue().trim());
3206:                    else
3207:                        dataout.writeBytes("application/octet-stream");
3208:                    dataout.writeBytes("\r\n");
3209:
3210:                    if (req.getData() != null)
3211:                        dataout.writeBytes("Content-length: "
3212:                                + req.getData().length + "\r\n");
3213:                    else if (req.getStream().getLength() != -1 && tc_idx == -1)
3214:                        dataout.writeBytes("Content-length: "
3215:                                + req.getStream().getLength() + "\r\n");
3216:
3217:                    if (ex_idx != -1) {
3218:                        con_hdrs[1] = hdrs[ex_idx].getValue().trim();
3219:                        dataout.writeBytes("Expect: " + con_hdrs[1] + "\r\n");
3220:                    }
3221:                } else if (ex_idx != -1) {
3222:                    Vector expect_tokens;
3223:                    try {
3224:                        expect_tokens = Util.parseHeader(hdrs[ex_idx]
3225:                                .getValue());
3226:                    } catch (ParseException pe) {
3227:                        throw new IOException(pe.toString());
3228:                    }
3229:
3230:                    // remove any 100-continue tokens
3231:
3232:                    HttpHeaderElement cont = new HttpHeaderElement(
3233:                            "100-continue");
3234:                    while (expect_tokens.removeElement(cont))
3235:                        ;
3236:
3237:                    // write out header if any tokens left
3238:
3239:                    if (!expect_tokens.isEmpty()) {
3240:                        con_hdrs[1] = Util.assembleHeader(expect_tokens);
3241:                        dataout.writeBytes("Expect: " + con_hdrs[1] + "\r\n");
3242:                    }
3243:                }
3244:
3245:                dataout.writeBytes("\r\n"); // end of header
3246:
3247:                return con_hdrs;
3248:            }
3249:
3250:            /**
3251:             * The very first request is special in that we use it to figure out the
3252:             * protocol version the server (or proxy) is compliant with.
3253:             *
3254:             * @return true if all went fine, false if the request needs to be resent
3255:             * @exception IOException if any exception is thrown by the response
3256:             */
3257:            boolean handleFirstRequest(Request req, Response resp)
3258:                    throws IOException {
3259:                // read response headers to get protocol version used by
3260:                // the server.
3261:
3262:                ServerProtocolVersion = String2ProtVers(resp.getVersion());
3263:                ServProtVersKnown = true;
3264:
3265:                /* We need to treat connections through proxies specially, because
3266:                 * many HTTP/1.0 proxies do not downgrade an HTTP/1.1 response
3267:                 * version to HTTP/1.0 (i.e. when we are talking to an HTTP/1.1
3268:                 * server through an HTTP/1.0 proxy we are mislead to thinking we're
3269:                 * talking to an HTTP/1.1 proxy). We use the absence of the Via
3270:                 * header to detect whether we're talking to an HTTP/1.0 proxy.
3271:                 * However, this only works when the chain contains only HTTP/1.0
3272:                 * proxies; if you have <client - 1.0 proxy - 1.1 proxy - server>
3273:                 * then this will fail too. Unfortunately there seems to be no way
3274:                 * to reliably detect broken HTTP/1.0 proxies...
3275:                 */
3276:                if ((Proxy_Host != null && Protocol != HTTPS)
3277:                        && resp.getHeader("Via") == null)
3278:                    ServerProtocolVersion = HTTP_1_0;
3279:
3280:                if (DebugConn)
3281:                    System.err.println("Conn:  Protocol Version established: "
3282:                            + ProtVers2String(ServerProtocolVersion));
3283:
3284:                // some (buggy) servers return an error status if they get a
3285:                // version they don't comprehend
3286:
3287:                if (ServerProtocolVersion == HTTP_1_0
3288:                        && (resp.getStatusCode() == 400 || resp.getStatusCode() == 500)) {
3289:                    input_demux.markForClose(resp);
3290:                    input_demux = null;
3291:                    RequestProtocolVersion = "HTTP/1.0";
3292:                    return false;
3293:                }
3294:
3295:                return true;
3296:            }
3297:
3298:            private void determineKeepAlive(Response resp) throws IOException {
3299:                // try and determine if this server does keep-alives
3300:
3301:                String con;
3302:
3303:                try {
3304:                    if (ServerProtocolVersion >= HTTP_1_1
3305:                            || ((((Proxy_Host == null || Protocol == HTTPS) && (con = resp
3306:                                    .getHeader("Connection")) != null) || ((Proxy_Host != null && Protocol != HTTPS) && (con = resp
3307:                                    .getHeader("Proxy-Connection")) != null)) && Util
3308:                                    .hasToken(con, "keep-alive"))) {
3309:                        DoesKeepAlive = true;
3310:
3311:                        if (DebugConn)
3312:                            System.err.println("Conn:  Keep-Alive enabled");
3313:
3314:                        KeepAliveUnknown = false;
3315:                    } else if (resp.getStatusCode() < 400)
3316:                        KeepAliveUnknown = false;
3317:
3318:                    // get maximum number of requests
3319:
3320:                    if (DoesKeepAlive && ServerProtocolVersion == HTTP_1_0
3321:                            && (con = resp.getHeader("Keep-Alive")) != null) {
3322:                        HttpHeaderElement max = Util.getElement(Util
3323:                                .parseHeader(con), "max");
3324:                        if (max != null && max.getValue() != null) {
3325:                            KeepAliveReqMax = Integer.parseInt(max.getValue());
3326:                            KeepAliveReqLeft = KeepAliveReqMax;
3327:
3328:                            if (DebugConn)
3329:                                System.err
3330:                                        .println("Conn:  Max Keep-Alive requests: "
3331:                                                + KeepAliveReqMax);
3332:                        }
3333:                    }
3334:                } catch (ParseException pe) {
3335:                } catch (NumberFormatException nfe) {
3336:                } catch (ClassCastException cce) {
3337:                }
3338:            }
3339:
3340:            synchronized void outputFinished() {
3341:                output_finished = true;
3342:                notify();
3343:            }
3344:
3345:            synchronized void closeDemux(IOException ioe, boolean was_reset) {
3346:                if (input_demux != null)
3347:                    input_demux.close(ioe, was_reset);
3348:
3349:                early_stall = null;
3350:                late_stall = null;
3351:                prev_resp = null;
3352:            }
3353:
3354:            final static String ProtVers2String(int prot_vers) {
3355:                return "HTTP/" + (prot_vers >>> 16) + "."
3356:                        + (prot_vers & 0xFFFF);
3357:            }
3358:
3359:            final static int String2ProtVers(String prot_vers) {
3360:                String vers = prot_vers.substring(5);
3361:                int dot = vers.indexOf('.');
3362:                return Integer.parseInt(vers.substring(0, dot)) << 16
3363:                        | Integer.parseInt(vers.substring(dot + 1));
3364:            }
3365:
3366:            /**
3367:             * Generates a string of the form protocol://host.domain:port .
3368:             *
3369:             * @return the string
3370:             */
3371:            public String toString() {
3372:                return getProtocol()
3373:                        + "://"
3374:                        + getHost()
3375:                        + (getPort() != URI.defaultPort(getProtocol()) ? ":"
3376:                                + getPort() : "");
3377:            }
3378:
3379:            private class EstablishConnection extends Thread {
3380:                String actual_host;
3381:                int actual_port;
3382:                IOException exception;
3383:                Socket sock;
3384:                SocksClient Socks_client;
3385:                boolean close;
3386:
3387:                EstablishConnection(String host, int port, SocksClient socks) {
3388:                    super ("EstablishConnection (" + host + ":" + port + ")");
3389:                    try {
3390:                        setDaemon(true);
3391:                    } catch (SecurityException se) {
3392:                    } // Oh well...
3393:
3394:                    actual_host = host;
3395:                    actual_port = port;
3396:                    Socks_client = socks;
3397:
3398:                    exception = null;
3399:                    sock = null;
3400:                    close = false;
3401:                }
3402:
3403:                public void run() {
3404:                    try {
3405:                        if (Socks_client != null)
3406:                            sock = Socks_client.getSocket(actual_host,
3407:                                    actual_port);
3408:                        else {
3409:                            // try all A records
3410:                            InetAddress[] addr_list = InetAddress
3411:                                    .getAllByName(actual_host);
3412:                            for (int idx = 0; idx < addr_list.length; idx++) {
3413:                                try {
3414:                                    sock = new Socket(addr_list[idx],
3415:                                            actual_port);
3416:                                    break; // success
3417:                                } catch (SocketException se) // should be NoRouteToHostException
3418:                                {
3419:                                    if (idx == addr_list.length - 1 || close)
3420:                                        throw se; // we tried them all
3421:                                }
3422:                            }
3423:                        }
3424:                    } catch (IOException ioe) {
3425:                        exception = ioe;
3426:                    }
3427:
3428:                    if (close && sock != null) {
3429:                        try {
3430:                            sock.close();
3431:                        } catch (IOException ioe) {
3432:                        }
3433:                        sock = null;
3434:                    }
3435:                }
3436:
3437:                IOException getException() {
3438:                    return exception;
3439:                }
3440:
3441:                Socket getSocket() {
3442:                    return sock;
3443:                }
3444:
3445:                void forget() {
3446:                    close = true;
3447:                }
3448:            }
3449:
3450:            /**
3451:             * M$ has yet another bug in their WinSock: if you try to write too much
3452:             * data at once it'll hang itself. This filter therefore splits big writes
3453:             * up into multiple writes of at most 20K.
3454:             */
3455:            private class MSLargeWritesBugStream extends FilterOutputStream {
3456:                private final int CHUNK_SIZE = 20000;
3457:
3458:                MSLargeWritesBugStream(OutputStream os) {
3459:                    super (os);
3460:                }
3461:
3462:                public void write(byte[] b, int off, int len)
3463:                        throws IOException {
3464:                    while (len > CHUNK_SIZE) {
3465:                        out.write(b, off, CHUNK_SIZE);
3466:                        off += CHUNK_SIZE;
3467:                        len -= CHUNK_SIZE;
3468:                    }
3469:                    out.write(b, off, len);
3470:                }
3471:            }
3472:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.