home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / solaris2 / jdk / src / java / net / urlconne.jav < prev    next >
Encoding:
Text File  |  1995-10-30  |  19.2 KB  |  571 lines

  1. /*
  2.  * @(#)URLConnection.java    1.16 95/10/24
  3.  * 
  4.  * Copyright (c) 1994-1995 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for NON-COMMERCIAL purposes and without fee is hereby
  8.  * granted provided that this copyright notice appears in all copies. Please
  9.  * refer to the file "copyright.html" for further important copyright and
  10.  * licensing information.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  15.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  16.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  17.  * ITS DERIVATIVES.
  18.  */
  19.  
  20. package java.net;
  21.  
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.OutputStream;
  25. import java.util.Hashtable;
  26. import java.util.Date;
  27.  
  28. /**
  29.  * A class to represent an active connection to an object
  30.  * represented by a URL. It is an abstract class that must be
  31.  * subclassed to provide implementation of connect.
  32.  *
  33.  * @version     1.16, 10/24/95
  34.  * @author  James Gosling
  35.  */
  36. abstract public class URLConnection {
  37.     protected URL url;
  38.  
  39.     protected boolean doInput = true;
  40.     protected boolean doOutput = false;
  41.     private static boolean defaultAllowUserInteraction = false;
  42.     protected boolean allowUserInteraction = defaultAllowUserInteraction;
  43.     private static boolean defaultUseCaches = true;
  44.     protected boolean useCaches = defaultUseCaches;
  45.     protected long ifModifiedSince = 0;
  46.  
  47.     protected boolean connected = false;
  48.  
  49.     /**
  50.      * URLConnection objects go through two phases: first they are created,
  51.      * then they are connected.  After being created, and before being connected,
  52.      * various option can be specified (eg. doInput, UseCaches, ...).  After connecting,
  53.      * it is an Error to try to set them.  Operations that depend on being connected,
  54.      * like getContentLength, will implicitly perform the connection if necessary.
  55.      * Connecting when already connected does nothing.
  56.      */
  57.     abstract public void connect() throws IOException;
  58.  
  59.     /**
  60.      * Constructs a URL connection to the specified URL.
  61.      * @param url the specified URL
  62.      */
  63.     protected URLConnection (URL url) {
  64.     this.url = url;
  65.     }
  66.  
  67.     /**
  68.      * Gets the URL for this connection.
  69.      */
  70.     public URL getURL() {
  71.     return url;
  72.     }
  73.  
  74.     /**
  75.      * Gets the content length. Returns -1 if not known.
  76.      */
  77.     public int getContentLength() {
  78.     return getHeaderFieldInt("content-length", -1);
  79.     }
  80.  
  81.     /**
  82.      * Gets the content type. Returns null if not known.
  83.      */
  84.     public String getContentType() {
  85.     return getHeaderField("content-type");
  86.     }
  87.  
  88.     /**
  89.      * Gets the content encoding. Returns null if not known.
  90.      */
  91.     public String getContentEncoding() {
  92.     return getHeaderField("content-encoding");
  93.     }
  94.  
  95.     /**
  96.      * Gets the expriation date of the object. Returns 0 if not known.
  97.      */
  98.     public long getExpiration() {
  99.     return getHeaderFieldDate("expires", 0);
  100.     }
  101.  
  102.     /**
  103.      * Gets the sending date of the object. Returns 0 if not known.
  104.      */
  105.     public long getDate() {
  106.     return getHeaderFieldDate("date", 0);
  107.     }
  108.  
  109.     /**
  110.      * Gets the last modified date of the object. Returns 0 if not known.
  111.      */
  112.     public long getLastModified() {
  113.     return getHeaderFieldDate("last-modified", 0);
  114.     }
  115.  
  116.     /**
  117.      * Gets a header field by name. Returns null if not known.
  118.      * @param name the name of the header field
  119.      */
  120.     public String getHeaderField(String name) {
  121.     return null;
  122.     }
  123.  
  124.     /**
  125.      * Gets a header field by name. Returns null if not known.
  126.      * The field will be parsed as an integer.  This form of
  127.      * getHeaderField exists because some connection types
  128.      * (eg. http-ng) have pre-parsed headers & this allows them
  129.      * to override this method and short-circuit the parsing.
  130.      * @param name the name of the header field
  131.      * @param Default the value to return if the field is missing
  132.      *    or malformed.
  133.      */
  134.     public int getHeaderFieldInt(String name, int Default) {
  135.     try {
  136.         return Integer.parseInt(getHeaderField(name));
  137.     } catch(Throwable t) {}
  138.     return Default;
  139.     }
  140.  
  141.     /**
  142.      * Gets a header field by name. Returns null if not known.
  143.      * The field will be parsed as a date.  This form of
  144.      * getHeaderField exists because some connection types
  145.      * (eg. http-ng) have pre-parsed headers & this allows them
  146.      * to override this method and short-circuit the parsing.
  147.      * @param name the name of the header field
  148.      * @param Default the value to return if the field is missing
  149.      *    or malformed.
  150.      */
  151.     public long getHeaderFieldDate(String name, long Default) {
  152.     try {
  153.         return Date.parse(getHeaderField(name));
  154.     } catch(Throwable t) {}
  155.     return Default;
  156.     }
  157.  
  158.     /**
  159.      * Return the key for the nth header field. Returns null if
  160.      * there are fewer than n fields.  This can be used to iterate
  161.      * through all the headers in the message.
  162.      */
  163.     public String getHeaderFieldKey(int n) {
  164.     return null;
  165.     }
  166.  
  167.     /**
  168.      * Return the value for the nth header field. Returns null if
  169.      * there are fewer than n fields.  This can be used in conjunction
  170.      * with getHeaderFieldKey to iterate through all the headers in the message.
  171.      */
  172.     public String getHeaderField(int n) {
  173.     return null;
  174.     }
  175.  
  176.     /**
  177.      * Gets the object referred to by this URL.  For example, if it
  178.      * refers to an image the object will be some subclass of
  179.      * Image.  The instanceof operator should be used to determine
  180.      * what kind of object was returned.
  181.      * @return    the object that was fetched.
  182.      * @exception UnknownServiceException If the protocol does not
  183.      * support content.
  184.      */
  185.     public Object getContent() throws IOException {
  186.     return getContentHandler().getContent(this);
  187.     }
  188.  
  189.     /**
  190.      * Calls this routine to get an InputStream that reads from the object.
  191.      * Protocol implementors should implement this if appropriate.
  192.      * @exception UnknownServiceException If the protocol does not
  193.      * support input.
  194.      */
  195.     public InputStream getInputStream() throws IOException {
  196.     throw new UnknownServiceException("protocol doesn't support input");
  197.     }
  198.  
  199.     /**
  200.      * Calls this routine to get an OutputStream that writes to the object.
  201.      * Protocol implementors should implement this if appropriate.
  202.      * @exception UnknownServiceException If the protocol does not
  203.      * support output.
  204.      */
  205.     public OutputStream getOutputStream() throws IOException {
  206.     throw new UnknownServiceException("protocol doesn't support output");
  207.     }
  208.  
  209.     /**
  210.      * Returns the String representation of the URL connection.
  211.      */
  212.     public String toString() {
  213.     return this.getClass().getName() + ":" + url;
  214.     }
  215.  
  216.  
  217.     /** A URL connection can be used for input and/or output.  Set the DoInput
  218.         flag to true if you intend to use the URL connection for input,
  219.         false if not.  The default is true unless DoOutput is explicitly
  220.         set to true, in which case DoInput defaults to false.  */
  221.     public void setDoInput(boolean doinput) {
  222.     if (connected)
  223.         throw new IllegalAccessError("Already connected");
  224.     doInput = doinput;
  225.     }
  226.     public boolean getDoInput() {
  227.     return doInput;
  228.     }
  229.  
  230.     /** A URL connection can be used for input and/or output.  Set the DoOutput
  231.         flag to true if you intend to use the URL connection for output,
  232.         false if not.  The default is false. */
  233.     public void setDoOutput(boolean dooutput) {
  234.     if (connected)
  235.         throw new IllegalAccessError("Already connected");
  236.     doOutput = dooutput;
  237.     }
  238.     public boolean getDoOutput() {
  239.     return doOutput;
  240.     }
  241.  
  242.     /** Some URL connections occasionally need to to interactions with the
  243.         user.  For example, the http protocol may need to pop up an authentication
  244.         dialog.  But this is only appropriate if the application is running
  245.         in a situation where there <i>is</i> a user.  The allowUserInteraction
  246.         flag allows these interactions when true.  When it is false, they are
  247.         not allowed an exception is tossed. The default value can be
  248.         set/gotten using setDefaultAllowUserInteraction, which defaults to false. */
  249.     public void setAllowUserInteraction(boolean allowuserinteraction) {
  250.     if (connected)
  251.         throw new IllegalAccessError("Already connected");
  252.     allowUserInteraction = allowuserinteraction;
  253.     }
  254.     public boolean getAllowUserInteraction() {
  255.     return allowUserInteraction;
  256.     }
  257.  
  258.     /** Set/get the default value of the allowUserInteraction flag.  This default
  259.         is "sticky", being a part of the static state of all URLConnections.  This
  260.         flag applies to the next, and all following, URLConnections that are created. */
  261.     public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
  262.     defaultAllowUserInteraction = defaultallowuserinteraction;
  263.     }
  264.     public static boolean getDefaultAllowUserInteraction() {
  265.     return defaultAllowUserInteraction;
  266.     }
  267.  
  268.     /** Some protocols do caching of documents.  Occasionally, it is important to be
  269.         able to "tunnel through" and ignore the caches (eg. the "reload" button in
  270.         a browser).  If the UseCaches flag on a connection is true, the connection is
  271.         allowed to use whatever caches it can.  If false, caches are to be ignored.
  272.         The default value comes from DefaultUseCaches, which defaults to true. */
  273.     public void setUseCaches(boolean usecaches) {
  274.     if (connected)
  275.         throw new IllegalAccessError("Already connected");
  276.     useCaches = usecaches;
  277.     }
  278.     public boolean getUseCaches() {
  279.     return useCaches;
  280.     }
  281.  
  282.     /** Some protocols support skipping fetching unless the object is newer than some time.
  283.     The ifModifiedSince field may be set/gotten to define this time. */
  284.     public void setIfModifiedSince(long ifmodifiedsince) {
  285.     if (connected)
  286.         throw new IllegalAccessError("Already connected");
  287.     ifModifiedSince = ifmodifiedsince;
  288.     }
  289.     public long getIfModifiedSince() {
  290.     return ifModifiedSince;
  291.     }
  292.  
  293.     /** Set/get the default value of the UseCaches flag.  This default
  294.         is "sticky", being a part of the static state of all URLConnections.  This
  295.         flag applies to the next, and all following, URLConnections that are created. */
  296.     public boolean getDefaultUseCaches() {
  297.     return defaultUseCaches;
  298.     }
  299.     public void setDefaultUseCaches(boolean defaultusecaches) {
  300.     defaultUseCaches = defaultusecaches;
  301.     }
  302.  
  303.     /**
  304.      * Set/get a general request property.
  305.      * @param key The keyword by which the request is known (eg "accept")
  306.      * @param value The value associated with it.
  307.      */
  308.     public void setRequestProperty(String key, String value) {
  309.     if (connected)
  310.         throw new IllegalAccessError("Already connected");
  311.     }
  312.     public String getRequestProperty(String key) {
  313.     if (connected)
  314.         throw new IllegalAccessError("Already connected");
  315.     return null;
  316.     }
  317.  
  318.     /**
  319.      * Set/get the default value of a general request property. When a
  320.      * URLConnection is created, it gets initialized with these properties.
  321.      * @param key The keyword by which the request is known (eg "accept")
  322.      * @param value The value associated with it.
  323.      */
  324.     public static void setDefaultRequestProperty(String key, String value) {
  325.     }
  326.     public static String getDefaultRequestProperty(String key) {
  327.     return null;
  328.     }
  329.  
  330.     /**
  331.      * The ContentHandler factory.
  332.      */
  333.     static ContentHandlerFactory factory;
  334.  
  335.     /**
  336.      * Sets the ContentHandler factory.
  337.      * @param fac the desired factory
  338.      * @exception Exception If the factory has already been defined.
  339.      */
  340.     public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
  341.     if (factory != null) {
  342.         throw new Error("factory already defined");
  343.     }
  344.     SecurityManager security = System.getSecurityManager();
  345.     if (security != null) {
  346.         security.checkSetFactory();
  347.     }
  348.     factory = fac;
  349.     }
  350.  
  351.     private static Hashtable handlers = new Hashtable();
  352.     private static ContentHandler UnknownContentHandlerP = new UnknownContentHandler();
  353.     private static String content_class_prefix = "sun.net.www.content.";
  354.  
  355.     /**
  356.      * Gets the Content Handler appropriate for this connection.
  357.      * @param connection the connection to use.
  358.      */
  359.     synchronized ContentHandler getContentHandler()
  360.     throws UnknownServiceException
  361.     {
  362.     String contentType = getContentType();
  363.     ContentHandler handler = null;
  364.     if (contentType == null)
  365.         throw new UnknownServiceException("no content-type");
  366.     try {
  367.         handler = (ContentHandler) handlers.get(contentType);
  368.         if (handler != null)
  369.         return handler;
  370.     } catch(Exception e) {
  371.     }
  372.     if (factory != null)
  373.         handler = factory.createContentHandler(contentType);
  374.     if (handler == null) {
  375.         try {
  376.         int i = content_class_prefix.length();
  377.         int j = contentType.length();
  378.         char nm[] = new char[i + j];
  379.         content_class_prefix.getChars(0, i, nm, 0);
  380.         contentType.getChars(0, j, nm, i);
  381.         while (--j >= 0) {
  382.             char c = nm[i];
  383.             if (c == '/')
  384.             nm[i] = '.';
  385.             else if (!('A' <= c && c <= 'Z' ||
  386.                    'a' <= c && c <= 'z' ||
  387.                    '0' <= c && c <= '9'))
  388.             nm[i] = '_';
  389.             i++;
  390.         }
  391.         String name = new String(nm);
  392.         try {
  393.             handler = (ContentHandler) Class.forName(name).newInstance();
  394.         } catch(Exception e) {
  395.             e.printStackTrace();
  396.             handler = UnknownContentHandlerP;
  397.         }
  398.         } catch(Exception e) {
  399.         e.printStackTrace();
  400.         handler = UnknownContentHandlerP;
  401.         }
  402.         handlers.put(contentType, handler);
  403.     }
  404.     return handler;
  405.     }
  406.  
  407.     /**
  408.      * A useful utility routine that tries to guess the content-type
  409.      * of an object based upon its extension.
  410.      */
  411.     protected static String guessContentTypeFromName(String fname) {
  412.     String ext = "";
  413.     int i = fname.lastIndexOf('#');
  414.  
  415.     if (i != -1)
  416.         fname = fname.substring(0, i - 1);
  417.     i = fname.lastIndexOf('.');
  418.     i = Math.max(i, fname.lastIndexOf('/'));
  419.     i = Math.max(i, fname.lastIndexOf('?'));
  420.  
  421.     if (i != -1 && fname.charAt(i) == '.') {
  422.         ext = fname.substring(i).toLowerCase();
  423.     }
  424.     return (String) extension_map.get(ext);
  425.     }
  426.  
  427.     static Hashtable extension_map = new Hashtable();
  428.  
  429.     static {
  430.     setSuffix("", "content/unknown");
  431.     setSuffix(".uu", "application/octet-stream");
  432.     setSuffix(".saveme", "application/octet-stream");
  433.     setSuffix(".dump", "application/octet-stream");
  434.     setSuffix(".hqx", "application/octet-stream");
  435.     setSuffix(".arc", "application/octet-stream");
  436.     setSuffix(".o", "application/octet-stream");
  437.     setSuffix(".a", "application/octet-stream");
  438.     setSuffix(".bin", "application/octet-stream");
  439.     setSuffix(".exe", "application/octet-stream");
  440.     /* Temporary only. */
  441.     setSuffix(".z", "application/octet-stream");
  442.     setSuffix(".gz", "application/octet-stream");
  443.  
  444.     setSuffix(".oda", "application/oda");
  445.     setSuffix(".pdf", "application/pdf");
  446.     setSuffix(".eps", "application/postscript");
  447.     setSuffix(".ai", "application/postscript");
  448.     setSuffix(".ps", "application/postscript");
  449.     setSuffix(".rtf", "application/rtf");
  450.     setSuffix(".dvi", "application/x-dvi");
  451.     setSuffix(".hdf", "application/x-hdf");
  452.     setSuffix(".latex", "application/x-latex");
  453.     setSuffix(".cdf", "application/x-netcdf");
  454.     setSuffix(".nc", "application/x-netcdf");
  455.     setSuffix(".tex", "application/x-tex");
  456.     setSuffix(".texinfo", "application/x-texinfo");
  457.     setSuffix(".texi", "application/x-texinfo");
  458.     setSuffix(".t", "application/x-troff");
  459.     setSuffix(".tr", "application/x-troff");
  460.     setSuffix(".roff", "application/x-troff");
  461.     setSuffix(".man", "application/x-troff-man");
  462.     setSuffix(".me", "application/x-troff-me");
  463.     setSuffix(".ms", "application/x-troff-ms");
  464.     setSuffix(".src", "application/x-wais-source");
  465.     setSuffix(".wsrc", "application/x-wais-source");
  466.     setSuffix(".zip", "application/zip");
  467.     setSuffix(".bcpio", "application/x-bcpio");
  468.     setSuffix(".cpio", "application/x-cpio");
  469.     setSuffix(".gtar", "application/x-gtar");
  470.     setSuffix(".shar", "application/x-shar");
  471.     setSuffix(".sh", "application/x-shar");
  472.     setSuffix(".sv4cpio", "application/x-sv4cpio");
  473.     setSuffix(".sv4crc", "application/x-sv4crc");
  474.     setSuffix(".tar", "application/x-tar");
  475.     setSuffix(".ustar", "application/x-ustar");
  476.     setSuffix(".snd", "audio/basic");
  477.     setSuffix(".au", "audio/basic");
  478.     setSuffix(".aifc", "audio/x-aiff");
  479.     setSuffix(".aif", "audio/x-aiff");
  480.     setSuffix(".aiff", "audio/x-aiff");
  481.     setSuffix(".wav", "audio/x-wav");
  482.     setSuffix(".gif", "image/gif");
  483.     setSuffix(".ief", "image/ief");
  484.     setSuffix(".jfif", "image/jpeg");
  485.     setSuffix(".jfif-tbnl", "image/jpeg");
  486.     setSuffix(".jpe", "image/jpeg");
  487.     setSuffix(".jpg", "image/jpeg");
  488.     setSuffix(".jpeg", "image/jpeg");
  489.     setSuffix(".tif", "image/tiff");
  490.     setSuffix(".tiff", "image/tiff");
  491.     setSuffix(".ras", "image/x-cmu-rast");
  492.     setSuffix(".pnm", "image/x-portable-anymap");
  493.     setSuffix(".pbm", "image/x-portable-bitmap");
  494.     setSuffix(".pgm", "image/x-portable-graymap");
  495.     setSuffix(".ppm", "image/x-portable-pixmap");
  496.     setSuffix(".rgb", "image/x-rgb");
  497.     setSuffix(".xbm", "image/x-xbitmap");
  498.     setSuffix(".xpm", "image/x-xpixmap");
  499.     setSuffix(".xwd", "image/x-xwindowdump");
  500.     setSuffix(".htm", "text/html");
  501.     setSuffix(".html", "text/html");
  502.     setSuffix(".text", "text/plain");
  503.     setSuffix(".c", "text/plain");
  504.     setSuffix(".cc", "text/plain");
  505.     setSuffix(".c++", "text/plain");
  506.     setSuffix(".h", "text/plain");
  507.     setSuffix(".pl", "text/plain");
  508.     setSuffix(".txt", "text/plain");
  509.     setSuffix(".java", "text/plain");
  510.     setSuffix(".rtx", "application/rtf");
  511.     setSuffix(".tsv", "text/tab-separated-values");
  512.     setSuffix(".etx", "text/x-setext");
  513.     setSuffix(".mpg", "video/mpeg");
  514.     setSuffix(".mpe", "video/mpeg");
  515.     setSuffix(".mpeg", "video/mpeg");
  516.     setSuffix(".mov", "video/quicktime");
  517.     setSuffix(".qt", "video/quicktime");
  518.     setSuffix(".avi", "application/x-troff-msvideo");
  519.     setSuffix(".movie", "video/x-sgi-movie");
  520.     setSuffix(".mv", "video/x-sgi-movie");
  521.     setSuffix(".mime", "message/rfc822");
  522.     }
  523.  
  524.     static private void setSuffix(String ext, String ct) {
  525.     extension_map.put(ext, ct);
  526.     }
  527.  
  528.     /**
  529.      * This disgusting hack is used to check for files have some type
  530.      * that can be determined by inspection.  The bytes at the beginning
  531.      * of the file are examined loosely.  In an ideal world, this routine
  532.      * would not be needed, but in a world where http servers lie
  533.      * about content-types and extensions are often non-standard,
  534.      * direct inspection of the bytes can make the system more robust.
  535.      * The stream must support marks (eg. have a BufferedInputStream
  536.      * somewhere).
  537.      */
  538.     static protected String guessContentTypeFromStream(InputStream is) throws IOException
  539.     {
  540.     is.mark(10);
  541.     int c1 = is.read();
  542.     int c2 = is.read();
  543.     int c3 = is.read();
  544.     int c4 = is.read();
  545.     int c5 = is.read();
  546.     int c6 = is.read();
  547.     is.reset();
  548.     if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8')
  549.         return "image/gif";
  550.     if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f')
  551.         return "image/x-bitmap";
  552.     if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && c5 == 'M' && c6 == '2')
  553.         return "image/x-pixmap";
  554.     if (c1 == '<')
  555.         if (c2 == '!'
  556.             || (c6 == '>'
  557.             && (c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
  558.                       c3 == 'e' && c4 == 'a' && c5 == 'd')
  559.               || c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y')))
  560.         return "text/html";
  561.     return null;
  562.     }
  563.  
  564. }
  565.  
  566. class UnknownContentHandler extends ContentHandler {
  567.     public Object getContent(URLConnection uc) throws IOException {
  568.     return uc.getInputStream();
  569.     }
  570. }
  571.