KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > HTTPClient > HTTPConnection


1 /*
2  * @(#)HTTPConnection.java 0.3-2 18/06/1999
3  *
4  * This file is part of the HTTPClient package
5  * Copyright (C) 1996-1999 Ronald Tschalär
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307, USA
21  *
22  * For questions, suggestions, bug-reports, enhancement-requests etc.
23  * I may be contacted at:
24  *
25  * ronald@innovation.ch
26  *
27  */

28
29 package HTTPClient;
30
31
32 import java.io.OutputStream JavaDoc;
33 import java.io.DataOutputStream JavaDoc;
34 import java.io.FilterOutputStream JavaDoc;
35 import java.io.ByteArrayOutputStream JavaDoc;
36 import java.io.IOException JavaDoc;
37 import java.io.InterruptedIOException JavaDoc;
38 import java.net.URL JavaDoc;
39 import java.net.Socket JavaDoc;
40 import java.net.InetAddress JavaDoc;
41 import java.net.SocketException JavaDoc;
42 import java.net.UnknownHostException JavaDoc;
43 import java.util.Vector JavaDoc;
44 import java.util.Hashtable JavaDoc;
45 import java.applet.Applet JavaDoc;
46
47
48 /**
49  * This class implements http protocol requests; it contains most of HTTP/1.1
50  * and ought to be unconditionally compliant.
51  * Redirections are automatically handled, and authorizations requests are
52  * recognized and dealt with via an authorization handler.
53  * Only full HTTP/1.0 and HTTP/1.1 requests are generated. HTTP/1.1, HTTP/1.0
54  * and HTTP/0.9 responses are recognized.
55  *
56  * <P>Using the HTTPClient should be quite simple. First add the import
57  * statement '<code>import HTTPClient.*;</code>' to your file(s). Request
58  * can then be sent using one of the methods <var>Head()</var>,
59  * <var>Get()</var>, <var>Post()</var>, etc in <var>HTTPConnection</var>.
60  * These methods all return an instance of <var>HTTPResponse</var> which
61  * has methods for accessing the response headers (<var>getHeader()</var>,
62  * <var>getHeaderAsInt()</var>, etc), various response info
63  * (<var>getStatusCode()</var>, <var>getReasonLine()</var>, etc) and the
64  * reponse data (<var>getData()</var> and <var>getInputStream()</var>).
65  * Following are some examples.
66  *
67  * <P>If this is in an applet you can retrieve files from your server
68  * as follows:
69  *
70  * <PRE>
71  * try
72  * {
73  * HTTPConnection con = new HTTPConnection(this);
74  * HTTPResponse rsp = con.Get("/my_file");
75  * if (rsp.getStatusCode() >= 300)
76  * {
77  * System.err.println("Received Error: "+rsp.getReasonLine());
78  * System.err.println(new String(rsp.getData()));
79  * }
80  * else
81  * data = rsp.getData();
82  *
83  * rsp = con.Get("/another_file");
84  * if (rsp.getStatusCode() >= 300)
85  * {
86  * System.err.println("Received Error: "+rsp.getReasonLine());
87  * System.err.println(new String(rsp.getData()));
88  * }
89  * else
90  * other_data = rsp.getData();
91  * }
92  * catch (IOException ioe)
93  * {
94  * System.err.println(ioe.toString());
95  * }
96  * catch (ModuleException me)
97  * {
98  * System.err.println("Error handling request: " + me.getMessage());
99  * }
100  * </PRE>
101  *
102  * This will get the files "/my_file" and "/another_file" and put their
103  * contents into byte[]s accessible via <code>getData()</code>. Note that
104  * you need to only create a new <var>HTTPConnection</var> when sending a
105  * request to a new server (different host or port); although you may create
106  * a new <var>HTTPConnection</var> for every request to the same server this
107  * <strong>not</strong> recommended, as various information about the server
108  * is cached after the first request (to optimize subsequent requests) and
109  * persistent connections are used whenever possible.
110  *
111  * <P>To POST form data you would use something like this (assuming you
112  * have two fields called <var>name</var> and <var>e-mail</var>, whose
113  * contents are stored in the variables <var>name</var> and <var>email</var>):
114  *
115  * <PRE>
116  * try
117  * {
118  * NVPair form_data[] = new NVPair[2];
119  * form_data[0] = new NVPair("name", name);
120  * form_data[1] = new NVPair("e-mail", email);
121  *
122  * HTTPConnection con = new HTTPConnection(this);
123  * HTTPResponse rsp = con.Post("/cgi-bin/my_script", form_data);
124  * if (rsp.getStatusCode() >= 300)
125  * {
126  * System.err.println("Received Error: "+rsp.getReasonLine());
127  * System.err.println(new String(rsp.getData()));
128  * }
129  * else
130  * stream = rsp.getInputStream();
131  * }
132  * catch (IOException ioe)
133  * {
134  * System.err.println(ioe.toString());
135  * }
136  * catch (ModuleException me)
137  * {
138  * System.err.println("Error handling request: " + me.getMessage());
139  * }
140  * </PRE>
141  *
142  * Here the response data is read at leasure via an <var>InputStream</var>
143  * instead of all at once into a <var>byte[]</var>.
144  *
145  * <P>As another example, if you have a URL you're trying to send a request
146  * to you would do something like the following:
147  *
148  * <PRE>
149  * try
150  * {
151  * URL url = new URL("http://www.mydomain.us/test/my_file");
152  * HTTPConnection con = new HTTPConnection(url);
153  * HTTPResponse rsp = con.Put(url.getFile(), "Hello World");
154  * if (rsp.getStatusCode() >= 300)
155  * {
156  * System.err.println("Received Error: "+rsp.getReasonLine());
157  * System.err.println(new String(rsp.getData()));
158  * }
159  * else
160  * data = rsp.getData();
161  * }
162  * catch (IOException ioe)
163  * {
164  * System.err.println(ioe.toString());
165  * }
166  * catch (ModuleException me)
167  * {
168  * System.err.println("Error handling request: " + me.getMessage());
169  * }
170  * </PRE>
171  *
172  * <P>There are a whole number of methods for each request type; however the
173  * general forms are ([...] means that the enclosed is optional):
174  * <ul>
175  * <li> Head ( file [, form-data [, headers ] ] )
176  * <li> Head ( file [, query [, headers ] ] )
177  * <li> Get ( file [, form-data [, headers ] ] )
178  * <li> Get ( file [, query [, headers ] ] )
179  * <li> Post ( file [, form-data [, headers ] ] )
180  * <li> Post ( file [, data [, headers ] ] )
181  * <li> Post ( file [, stream [, headers ] ] )
182  * <li> Put ( file , data [, headers ] )
183  * <li> Put ( file , stream [, headers ] )
184  * <li> Delete ( file [, headers ] )
185  * <li> Options ( file [, headers [, data] ] )
186  * <li> Options ( file [, headers [, stream] ] )
187  * <li> Trace ( file [, headers ] )
188  * </ul>
189  *
190  * @version 0.3-2 18/06/1999
191  * @author Ronald Tschalär
192  */

193
194 public class HTTPConnection
195     implements GlobalConstants, HTTPClientModuleConstants
196 {
197     /** The current version of this package. */
198     public final static String JavaDoc version = "RPT-HTTPClient/0.3-2";
199
200     /** The default context */
201     private final static Object JavaDoc dflt_context = new Object JavaDoc();
202
203     /** The current context */
204     private Object JavaDoc Context = null;
205
206     /** The protocol used on this connection */
207     private int Protocol;
208
209     /** The server's protocol version; M.m stored as (M<<16 | m) */
210             int ServerProtocolVersion;
211
212     /** Have we gotten the server's protocol version yet? */
213             boolean ServProtVersKnown;
214
215     /** The protocol version we send in a request; this is always HTTP/1.1
216     unless we're talking to a broken server in which case it's HTTP/1.0 */

217     private String JavaDoc RequestProtocolVersion;
218
219     /** hack to force buffering of data instead of using chunked T-E */
220     private static boolean no_chunked = false;
221
222     /** hack to force HTTP/1.0 requests */
223     private static boolean force_1_0 = false;
224
225     /** The remote host this connection is associated with */
226     private String JavaDoc Host;
227
228     /** The remote port this connection is attached to */
229     private int Port;
230
231     /** The current proxy host to use (if any) */
232     private String JavaDoc Proxy_Host = null;
233
234     /** The current proxy port */
235     private int Proxy_Port;
236
237     /** The default proxy host to use (if any) */
238     private static String JavaDoc Default_Proxy_Host = null;
239
240     /** The default proxy port */
241     private static int Default_Proxy_Port;
242
243     /** The list of hosts for which no proxy is to be used */
244     private static CIHashtable non_proxy_host_list = new CIHashtable();
245     private static Vector JavaDoc non_proxy_dom_list = new Vector JavaDoc();
246     private static Vector JavaDoc non_proxy_addr_list = new Vector JavaDoc();
247     private static Vector JavaDoc non_proxy_mask_list = new Vector JavaDoc();
248
249     /** The socks server to use */
250     private SocksClient Socks_client = null;
251
252     /** The default socks server to use */
253     private static SocksClient Default_Socks_client = null;
254
255     /** the current stream demultiplexor */
256     private StreamDemultiplexor input_demux = null;
257
258     /** a list of active stream demultiplexors */
259         LinkedList DemuxList = new LinkedList();
260
261     /** a list of active requests */
262     private LinkedList RequestList = new LinkedList();
263
264     /** does the server support keep-alive's? */
265     private boolean DoesKeepAlive = false;
266
267     /** have we been able to determine the above yet? */
268     private boolean KeepAliveUnknown = true;
269
270     /** the maximum number of requests over a HTTP/1.0 keep-alive connection */
271     private int KeepAliveReqMax = -1;
272
273     /** the number of requests over a HTTP/1.0 keep-alive connection left */
274     private int KeepAliveReqLeft;
275
276     /** hack to be able to disable pipelining */
277     private static boolean NeverPipeline = false;
278
279     /** hack to be able to disable keep-alives */
280     private static boolean NoKeepAlives = false;
281
282     /** hack to work around M$ bug */
283     private static boolean haveMSLargeWritesBug = false;
284
285     /** the default timeout to use for new connections */
286     private static int DefaultTimeout = 0;
287
288     /** the timeout to use for reading responses */
289     private int Timeout;
290
291     /** The list of default http headers */
292     private NVPair[] DefaultHeaders = new NVPair[0];
293
294     /** The default list of modules (as a Vector of Class objects) */
295     private static Vector JavaDoc DefaultModuleList;
296
297     /** The list of modules (as a Vector of Class objects) */
298     private Vector JavaDoc ModuleList;
299
300     /** controls whether modules are allowed to interact with user */
301     private static boolean DefaultAllowUI = true;
302
303     /** controls whether modules are allowed to interact with user */
304     private boolean AllowUI;
305
306
307     static
308     {
309     /*
310      * Let's try and see if we can figure out whether any proxies are
311      * being used.
312      */

313
314     try // JDK 1.1 naming
315
{
316         String JavaDoc host = System.getProperty("http.proxyHost");
317         if (host == null)
318         throw new Exception JavaDoc(); // try JDK 1.0.x naming
319
int port = Integer.getInteger("http.proxyPort", -1).intValue();
320
321         if (DebugConn)
322         System.err.println("Conn: using proxy " + host + ":" + port);
323         setProxyServer(host, port);
324     }
325     catch (Exception JavaDoc e)
326     {
327         try // JDK 1.0.x naming
328
{
329         if (Boolean.getBoolean("proxySet"))
330         {
331             String JavaDoc host = System.getProperty("proxyHost");
332             int port = Integer.getInteger("proxyPort", -1).intValue();
333             if (DebugConn)
334             System.err.println("Conn: using proxy " + host + ":" + port);
335             setProxyServer(host, port);
336         }
337         }
338         catch (Exception JavaDoc ee)
339         { Default_Proxy_Host = null; }
340     }
341
342
343     /*
344      * now check for the non-proxy list
345      */

346     //try
347
//{
348
String JavaDoc hosts = System.getProperty("HTTPClient.nonProxyHosts");
349         if (hosts == null)
350         hosts = System.getProperty("http.nonProxyHosts");
351
352         String JavaDoc[] _list = Util.splitProperty(hosts);
353         dontProxyFor(_list);
354             /*
355               }
356               catch (Exception e)
357               { }
358             */

359
360     /*
361      * we can't turn the JDK SOCKS handling off, so we don't use the
362      * properties 'socksProxyHost' and 'socksProxyPort'. Instead we
363      * define 'HTTPClient.socksHost', 'HTTPClient.socksPort' and
364      * 'HTTPClient.socksVersion'.
365      */

366     try
367     {
368         String JavaDoc host = System.getProperty("HTTPClient.socksHost");
369         if (host != null && host.length() > 0)
370         {
371         int port = Integer.getInteger("HTTPClient.socksPort", -1).intValue();
372         int version = Integer.getInteger("HTTPClient.socksVersion", -1).intValue();
373         if (DebugConn)
374             System.err.println("Conn: using SOCKS " + host + ":" + port);
375         if (version == -1)
376             setSocksServer(host, port);
377         else
378             setSocksServer(host, port, version);
379         }
380     }
381     catch (Exception JavaDoc e)
382         { Default_Socks_client = null; }
383
384
385     // Set up module list
386

387     String JavaDoc modules = "HTTPClient.RetryModule|" +
388              "HTTPClient.CookieModule|" +
389              "HTTPClient.RedirectionModule|" +
390              "HTTPClient.AuthorizationModule|" +
391              "HTTPClient.DefaultModule|" +
392              "HTTPClient.TransferEncodingModule|" +
393              "HTTPClient.ContentMD5Module|" +
394              "HTTPClient.ContentEncodingModule";
395
396     boolean in_applet = false;
397     try
398         { modules = System.getProperty("HTTPClient.Modules", modules); }
399     catch (SecurityException JavaDoc se)
400         { in_applet = true; }
401
402     DefaultModuleList = new Vector JavaDoc();
403     String JavaDoc[] list = Util.splitProperty(modules);
404     for (int idx=0; idx<list.length; idx++)
405     {
406         try
407         {
408         DefaultModuleList.addElement(Class.forName(list[idx]));
409         if (DebugConn)
410             System.err.println("Conn: added module " + list[idx]);
411         }
412         catch (ClassNotFoundException JavaDoc cnfe)
413         {
414         if (!in_applet)
415             throw new NoClassDefFoundError JavaDoc(cnfe.getMessage());
416
417         /* Just ignore it. This allows for example applets to just
418          * load the necessary modules - if you don't need a module
419          * then don't provide it, and it won't be added to the
420          * list. The disadvantage is that if you accidently misstype
421          * a module name this will lead to a "silent" error.
422          */

423         }
424     }
425
426
427     /*
428      * Hack: disable pipelining
429      */

430     try
431     {
432         NeverPipeline = Boolean.getBoolean("HTTPClient.disable_pipelining");
433         if (DebugConn)
434         if (NeverPipeline) System.err.println("Conn: disabling pipelining");
435     }
436     catch (Exception JavaDoc e)
437         { }
438
439     /*
440      * Hack: disable keep-alives
441      */

442     try
443     {
444         NoKeepAlives = Boolean.getBoolean("HTTPClient.disableKeepAlives");
445         if (DebugConn)
446         if (NoKeepAlives) System.err.println("Conn: disabling keep-alives");
447     }
448     catch (Exception JavaDoc e)
449         { }
450
451     /*
452      * Hack: force HTTP/1.0 requests
453      */

454     try
455     {
456         force_1_0 = Boolean.getBoolean("HTTPClient.forceHTTP_1.0");
457         if (DebugConn)
458         if (force_1_0) System.err.println("Conn: forcing HTTP/1.0 requests");
459     }
460     catch (Exception JavaDoc e)
461         { }
462
463     /*
464      * Hack: prevent chunking of request data
465      */

466     try
467     {
468         no_chunked = Boolean.getBoolean("HTTPClient.dontChunkRequests");
469         if (DebugConn)
470         if (no_chunked) System.err.println("Conn: never chunking requests");
471     }
472     catch (Exception JavaDoc e)
473         { }
474
475     /*
476      * M$ bug: large writes hang the stuff
477      */

478     try
479     {
480         if (System.getProperty("os.name").indexOf("Windows") >= 0 &&
481         System.getProperty("java.version").startsWith("1.1"))
482             haveMSLargeWritesBug = true;
483         if (DebugConn)
484         if (haveMSLargeWritesBug)
485             System.err.println("Conn: splitting large writes into 20K chunks (M$ bug)");
486     }
487     catch (Exception JavaDoc e)
488         { }
489     }
490
491
492     // Constructors
493

494     /**
495      * Constructs a connection to the host from where the applet was loaded.
496      * Note that current security policies only let applets connect home.
497      *
498      * @param applet the current applet
499      */

500     public HTTPConnection(Applet JavaDoc applet) throws ProtocolNotSuppException
501     {
502     this(applet.getCodeBase().getProtocol(),
503          applet.getCodeBase().getHost(),
504          applet.getCodeBase().getPort());
505     }
506
507     /**
508      * Constructs a connection to the specified host on port 80
509      *
510      * @param host the host
511      */

512     public HTTPConnection(String JavaDoc host)
513     {
514     Setup(HTTP, host, 80);
515     }
516
517     /**
518      * Constructs a connection to the specified host on the specified port
519      *
520      * @param host the host
521      * @param port the port
522      */

523     public HTTPConnection(String JavaDoc host, int port)
524     {
525     Setup(HTTP, host, port);
526     }
527
528     /**
529      * Constructs a connection to the specified host on the specified port,
530      * using the specified protocol (currently only "http" is supported).
531      *
532      * @param prot the protocol
533      * @param host the host
534      * @param port the port, or -1 for the default port
535      * @exception ProtocolNotSuppException if the protocol is not HTTP
536      */

537     public HTTPConnection(String JavaDoc prot, String JavaDoc host, int port) throws
538     ProtocolNotSuppException
539     {
540     prot = prot.trim().toLowerCase();
541
542     //if (!prot.equals("http") && !prot.equals("https"))
543
if (!prot.equals("http"))
544         throw new ProtocolNotSuppException("Unsupported protocol '" + prot + "'");
545
546     if (prot.equals("http"))
547         Setup(HTTP, host, port);
548     else if (prot.equals("https"))
549         Setup(HTTPS, host, port);
550     else if (prot.equals("shttp"))
551         Setup(SHTTP, host, port);
552     else if (prot.equals("http-ng"))
553         Setup(HTTP_NG, host, port);
554     }
555
556     /**
557      * Constructs a connection to the host (port) as given in the url.
558      *
559      * @param url the url
560      * @exception ProtocolNotSuppException if the protocol is not HTTP
561      */

562     public HTTPConnection(URL JavaDoc url) throws ProtocolNotSuppException
563     {
564     this(url.getProtocol(), url.getHost(), url.getPort());
565     }
566
567     /**
568      * Sets the class variables. Must not be public.
569      *
570      * @param prot the protocol
571      * @param host the host
572      * @param port the port
573      */

574     private void Setup(int prot, String JavaDoc host, int port)
575     {
576     Protocol = prot;
577     Host = host.trim().toLowerCase();
578     Port = port;
579
580     if (Port == -1)
581         Port = URI.defaultPort(getProtocol());
582
583     if (Default_Proxy_Host != null && !matchNonProxy(Host))
584         setCurrentProxy(Default_Proxy_Host, Default_Proxy_Port);
585     else
586         setCurrentProxy(null, 0);
587
588     Socks_client = Default_Socks_client;
589     Timeout = DefaultTimeout;
590     ModuleList = (Vector JavaDoc) DefaultModuleList.clone();
591     AllowUI = DefaultAllowUI;
592     if (NoKeepAlives)
593         setDefaultHeaders(new NVPair[] { new NVPair("Connection", "close") });
594     }
595
596
597     /**
598      * Determines if the given host matches any entry in the non-proxy list.
599      *
600      * @param host the host to match - must be trim()'d and lowercase
601      * @return true if a match is found, false otherwise
602      * @see #dontProxyFor(java.lang.String)
603      */

604     private boolean matchNonProxy(String JavaDoc host)
605     {
606     // Check host name list
607

608     if (non_proxy_host_list.get(host) != null)
609         return true;
610
611
612     // Check domain name list
613

614     for (int idx=0; idx<non_proxy_dom_list.size(); idx++)
615         if (host.endsWith((String JavaDoc) non_proxy_dom_list.elementAt(idx)))
616         return true;
617
618
619     // Check IP-address and subnet list
620

621     if (non_proxy_addr_list.size() == 0)
622         return false;
623
624     InetAddress JavaDoc[] host_addr;
625     try
626         { host_addr = InetAddress.getAllByName(host); }
627     catch (UnknownHostException JavaDoc uhe)
628         { return false; } // maybe the proxy has better luck
629

630     for (int idx=0; idx<non_proxy_addr_list.size(); idx++)
631     {
632         byte[] addr = (byte[]) non_proxy_addr_list.elementAt(idx);
633         byte[] mask = (byte[]) non_proxy_mask_list.elementAt(idx);
634
635         ip_loop: for (int idx2=0; idx2<host_addr.length; idx2++)
636         {
637         byte[] raw_addr = host_addr[idx2].getAddress();
638         if (raw_addr.length != addr.length) continue;
639
640         for (int idx3=0; idx3<raw_addr.length; idx3++)
641         {
642             if ((raw_addr[idx3] & mask[idx3]) != (addr[idx3] & mask[idx3]))
643             continue ip_loop;
644         }
645         return true;
646         }
647     }
648
649     return false;
650     }
651
652
653     // Methods
654

655     /**
656      * Sends the HEAD request. This request is just like the corresponding
657      * GET except that it only returns the headers and no data.
658      *
659      * @see #Get(java.lang.String)
660      * @param file the absolute path of the file
661      * @return an HTTPResponse structure containing the response
662      * @exception java.io.IOException when an exception is returned from
663      * the socket.
664      * @exception ModuleException if an exception is encountered in any module.
665      */

666     public HTTPResponse Head(String JavaDoc file) throws IOException JavaDoc, ModuleException
667     {
668     return Head(file, (String JavaDoc) null, null);
669     }
670
671     /**
672      * Sends the HEAD request. This request is just like the corresponding
673      * GET except that it only returns the headers and no data.
674      *
675      * @see #Get(java.lang.String, HTTPClient.NVPair[])
676      * @param file the absolute path of the file
677      * @param form_data an array of Name/Value pairs
678      * @return an HTTPResponse structure containing the response
679      * @exception java.io.IOException when an exception is returned from
680      * the socket.
681      * @exception ModuleException if an exception is encountered in any module.
682      */

683     public HTTPResponse Head(String JavaDoc file, NVPair form_data[])
684         throws IOException JavaDoc, ModuleException
685     {
686     return Head(file, form_data, null);
687     }
688
689     /**
690      * Sends the HEAD request. This request is just like the corresponding
691      * GET except that it only returns the headers and no data.
692      *
693      * @see #Get(java.lang.String, HTTPClient.NVPair[], HTTPClient.NVPair[])
694      * @param file the absolute path of the file
695      * @param form_data an array of Name/Value pairs
696      * @param headers additional headers
697      * @return an HTTPResponse structure containing the response
698      * @exception java.io.IOException when an exception is returned from
699      * the socket.
700      * @exception ModuleException if an exception is encountered in any module.
701      */

702     public HTTPResponse Head(String JavaDoc file, NVPair[] form_data, NVPair[] headers)
703         throws IOException JavaDoc, ModuleException
704     {
705     String JavaDoc File = stripRef(file),
706            query = Codecs.nv2query(form_data);
707     if (query != null && query.length() > 0)
708         File += "?" + query;
709
710     return setupRequest("HEAD", File, headers, null, null);
711     }
712
713     /**
714      * Sends the HEAD request. This request is just like the corresponding
715      * GET except that it only returns the headers and no data.
716      *
717      * @see #Get(java.lang.String, java.lang.String)
718      * @param file the absolute path of the file
719      * @param query the query string; it will be urlencoded
720      * @return an HTTPResponse structure containing the response
721      * @exception java.io.IOException when an exception is returned from
722      * the socket.
723      * @exception ModuleException if an exception is encountered in any module.
724      */

725     public HTTPResponse Head(String JavaDoc file, String JavaDoc query)
726         throws IOException JavaDoc, ModuleException
727     {
728     return Head(file, query, null);
729     }
730
731
732     /**
733      * Sends the HEAD request. This request is just like the corresponding
734      * GET except that it only returns the headers and no data.
735      *
736      * @see #Get(java.lang.String, java.lang.String, HTTPClient.NVPair[])
737      * @param file the absolute path of the file
738      * @param query the query string; it will be urlencoded
739      * @param headers additional headers
740      * @return an HTTPResponse structure containing the response
741      * @exception java.io.IOException when an exception is returned from
742      * the socket.
743      * @exception ModuleException if an exception is encountered in any module.
744      */

745     public HTTPResponse Head(String JavaDoc file, String JavaDoc query, NVPair[] headers)
746         throws IOException JavaDoc, ModuleException
747     {
748     String JavaDoc File = stripRef(file);
749     if (query != null && query.length() > 0)
750         File += "?" + Codecs.URLEncode(query);
751
752     return setupRequest("HEAD", File, headers, null, null);
753     }
754
755
756     /**
757      * GETs the file.
758      *
759      * @param file the absolute path of the file
760      * @return an HTTPResponse structure containing the response
761      * @exception java.io.IOException when an exception is returned from
762      * the socket.
763      * @exception ModuleException if an exception is encountered in any module.
764      */

765     public HTTPResponse Get(String JavaDoc file) throws IOException JavaDoc, ModuleException
766     {
767     return Get(file, (String JavaDoc) null, null);
768     }
769
770     /**
771      * GETs the file with a query consisting of the specified form-data.
772      * The data is urlencoded, turned into a string of the form
773      * "name1=value1&name2=value2" and then sent as a query string.
774      *
775      * @param file the absolute path of the file
776      * @param form_data an array of Name/Value pairs
777      * @return an HTTPResponse structure containing the response
778      * @exception java.io.IOException when an exception is returned from
779      * the socket.
780      * @exception ModuleException if an exception is encountered in any module.
781      */

782     public HTTPResponse Get(String JavaDoc file, NVPair form_data[])
783         throws IOException JavaDoc, ModuleException
784     {
785     return Get(file, form_data, null);
786     }
787
788     /**
789      * GETs the file with a query consisting of the specified form-data.
790      * The data is urlencoded, turned into a string of the form
791      * "name1=value1&name2=value2" and then sent as a query string.
792      *
793      * @param file the absolute path of the file
794      * @param form_data an array of Name/Value pairs
795      * @param headers additional headers
796      * @return an HTTPResponse structure containing the response
797      * @exception java.io.IOException when an exception is returned from
798      * the socket.
799      * @exception ModuleException if an exception is encountered in any module.
800      */

801     public HTTPResponse Get(String JavaDoc file, NVPair[] form_data, NVPair[] headers)
802         throws IOException JavaDoc, ModuleException
803     {
804     String JavaDoc File = stripRef(file),
805            query = Codecs.nv2query(form_data);
806     if (query != null && query.length() > 0)
807         File += "?" + query;
808
809     return setupRequest("GET", File, headers, null, null);
810     }
811
812     /**
813      * GETs the file using the specified query string. The query string
814      * is first urlencoded.
815      *
816      * @param file the absolute path of the file
817      * @param query the query
818      * @return an HTTPResponse structure containing the response
819      * @exception java.io.IOException when an exception is returned from
820      * the socket.
821      * @exception ModuleException if an exception is encountered in any module.
822      */

823     public HTTPResponse Get(String JavaDoc file, String JavaDoc query)
824         throws IOException JavaDoc, ModuleException
825     {
826     return Get(file, query, null);
827     }
828
829     /**
830      * GETs the file using the specified query string. The query string
831      * is first urlencoded.
832      *
833      * @param file the absolute path of the file
834      * @param query the query string
835      * @param headers additional headers
836      * @return an HTTPResponse structure containing the response
837      * @exception java.io.IOException when an exception is returned from
838      * the socket.
839      * @exception ModuleException if an exception is encountered in any module.
840      */

841     public HTTPResponse Get(String JavaDoc file, String JavaDoc query, NVPair[] headers)
842         throws IOException JavaDoc, ModuleException
843     {
844     String JavaDoc File = stripRef(file);
845     if (query != null && query.length() > 0)
846         File += "?" + Codecs.URLEncode(query);
847
848     return setupRequest("GET", File, headers, null, null);
849     }
850
851
852     /**
853      * POSTs to the specified file. No data is sent.
854      *
855      * @param file the absolute path of the file
856      * @return an HTTPResponse structure containing the response
857      * @exception java.io.IOException when an exception is returned from
858      * the socket.
859      * @exception ModuleException if an exception is encountered in any module.
860      */

861     public HTTPResponse Post(String JavaDoc file) throws IOException JavaDoc, ModuleException
862     {
863     return Post(file, (byte []) null, null);
864     }
865
866     /**
867      * POSTs form-data to the specified file. The data is first urlencoded
868      * and then turned into a string of the form "name1=value1&name2=value2".
869      * A <var>Content-type</var> header with the value
870      * <var>application/x-www-form-urlencoded</var> is added.
871      *
872      * @param file the absolute path of the file
873      * @param form_data an array of Name/Value pairs
874      * @return an HTTPResponse structure containing the response
875      * @exception java.io.IOException when an exception is returned from
876      * the socket.
877      * @exception ModuleException if an exception is encountered in any module.
878      */

879     public HTTPResponse Post(String JavaDoc file, NVPair form_data[])
880         throws IOException JavaDoc, ModuleException
881     {
882     NVPair[] headers =
883         { new NVPair("Content-type", "application/x-www-form-urlencoded") };
884
885     return Post(file, Codecs.nv2query(form_data), headers);
886     }
887
888     /**
889      * POST's form-data to the specified file using the specified headers.
890      * The data is first urlencoded and then turned into a string of the
891      * form "name1=value1&name2=value2". If no <var>Content-type</var> header
892      * is given then one is added with a value of
893      * <var>application/x-www-form-urlencoded</var>.
894      *
895      * @param file the absolute path of the file
896      * @param form_data an array of Name/Value pairs
897      * @param headers additional headers
898      * @return a HTTPResponse structure containing the response
899      * @exception java.io.IOException when an exception is returned from
900      * the socket.
901      * @exception ModuleException if an exception is encountered in any module.
902      */

903     public HTTPResponse Post(String JavaDoc file, NVPair form_data[], NVPair headers[])
904                 throws IOException JavaDoc, ModuleException
905     {
906     int idx;
907     for (idx=0; idx<headers.length; idx++)
908         if (headers[idx].getName().equalsIgnoreCase("Content-type")) break;
909     if (idx == headers.length)
910     {
911         headers = Util.resizeArray(headers, idx+1);
912         headers[idx] =
913         new NVPair("Content-type", "application/x-www-form-urlencoded");
914     }
915
916     return Post(file, Codecs.nv2query(form_data), headers);
917     }
918
919     /**
920      * POSTs the data to the specified file. The data is converted to an
921      * array of bytes using the lower byte of each character.
922      * The request is sent using the content-type "application/octet-stream".
923      *
924      * @see java.lang.String#getBytes(int, int, byte[], int)
925      * @param file the absolute path of the file
926      * @param data the data
927      * @return an HTTPResponse structure containing the response
928      * @exception java.io.IOException when an exception is returned from
929      * the socket.
930      * @exception ModuleException if an exception is encountered in any module.
931      */

932     public HTTPResponse Post(String JavaDoc file, String JavaDoc data)
933         throws IOException JavaDoc, ModuleException
934     {
935     return Post(file, data, null);
936     }
937
938     /**
939      * POSTs the data to the specified file using the specified headers.
940      *
941      * @param file the absolute path of the file
942      * @param data the data
943      * @param headers additional headers
944      * @return an HTTPResponse structure containing the response
945      * @exception java.io.IOException when an exception is returned from
946      * the socket.
947      * @exception ModuleException if an exception is encountered in any module.
948      */

949     public HTTPResponse Post(String JavaDoc file, String JavaDoc data, NVPair[] headers)
950         throws IOException JavaDoc, ModuleException
951     {
952     byte tmp[] = null;
953
954     if (data != null && data.length() > 0)
955     {
956         tmp = new byte[data.length()];
957         data.getBytes(0, data.length(), tmp, 0);