0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.net;
0019:
0020: import java.io.IOException;
0021: import java.io.InputStream;
0022: import java.io.OutputStream;
0023: import java.security.AccessController;
0024: import java.security.PrivilegedAction;
0025: import java.util.Collections;
0026: import java.util.Date;
0027: import java.util.Hashtable;
0028: import java.util.List;
0029: import java.util.Map;
0030: import java.util.StringTokenizer;
0031:
0032: import org.apache.harmony.luni.internal.net.www.MimeTable;
0033: import org.apache.harmony.luni.util.Msg;
0034: import org.apache.harmony.luni.util.PriviAction;
0035:
0036: /**
0037: * The URLConnection class is responsible for establishing a connection to an
0038: * URL for a given protocol. The correct URLConnection subclass to call is
0039: * determined by <code>URLStreamHandler.openConnection()</code>.
0040: */
0041: public abstract class URLConnection {
0042:
0043: protected URL url;
0044:
0045: private String contentType;
0046:
0047: private static boolean defaultAllowUserInteraction;
0048:
0049: private static boolean defaultUseCaches = true;
0050:
0051: ContentHandler defaultHandler = new DefaultContentHandler();
0052:
0053: private long lastModified = -1;
0054:
0055: protected long ifModifiedSince;
0056:
0057: protected boolean useCaches = defaultUseCaches;
0058:
0059: protected boolean connected;
0060:
0061: protected boolean doOutput;
0062:
0063: protected boolean doInput = true;
0064:
0065: protected boolean allowUserInteraction = defaultAllowUserInteraction;
0066:
0067: private static ContentHandlerFactory contentHandlerFactory;
0068:
0069: private int readTimeout = 0;
0070:
0071: private int connectTimeout = 0;
0072:
0073: /**
0074: * Cache for storing Content handler
0075: */
0076: static Hashtable<String, Object> contentHandlers = new Hashtable<String, Object>();
0077:
0078: /**
0079: * A hashtable that maps the filename extension (key) to a MIME-type
0080: * (element)
0081: */
0082: private static FileNameMap fileNameMap;
0083:
0084: /**
0085: * Creates a URLConnection pointing to the resource specified by the
0086: * <code>url</code>
0087: */
0088: protected URLConnection(URL url) {
0089: this .url = url;
0090: }
0091:
0092: /**
0093: * Establishes the connection to the resource specified by this
0094: * <code>URL</code> with this <code>method</code>, along with other
0095: * options that can only be set before this connection is made.
0096: *
0097: * @throws IOException
0098: * If an error occurs while connecting
0099: *
0100: * @see java.io.IOException
0101: * @see URLStreamHandler
0102: */
0103: public abstract void connect() throws IOException;
0104:
0105: /**
0106: * Answers the value of <code>allowUserInteraction</code> which indicates
0107: * if this connection allows user interaction
0108: *
0109: * @return the value of the flag
0110: *
0111: * @see #getDefaultRequestProperty
0112: * @see #setDefaultRequestProperty
0113: * @see #allowUserInteraction
0114: */
0115: public boolean getAllowUserInteraction() {
0116: return allowUserInteraction;
0117: }
0118:
0119: /**
0120: * Answers the object pointed to by this <code>URL</code>. It first
0121: * attempts to get the content type from <code>getContentType()</code>,
0122: * which looks for the response header field "Content-Type". If none is
0123: * found, it will guess the content type from the filename extension. If
0124: * that fails, it will guess by inspecting the stream.
0125: *
0126: * @return a non-null object
0127: *
0128: * @throws IOException
0129: * if an IO error occurred
0130: *
0131: * @see ContentHandler
0132: * @see ContentHandlerFactory
0133: * @see IOException
0134: * @see #setContentHandlerFactory
0135: */
0136: public Object getContent() throws java.io.IOException {
0137: if (!connected) {
0138: connect();
0139: }
0140:
0141: if ((contentType = getContentType()) == null) {
0142: if ((contentType = guessContentTypeFromName(url.getFile())) == null) {
0143: contentType = guessContentTypeFromStream(getInputStream());
0144: }
0145: }
0146: if (contentType != null) {
0147: return getContentHandler(contentType).getContent(this );
0148: }
0149: return null;
0150: }
0151:
0152: /**
0153: * Answers the object pointed to by this <code>URL</code>. It first
0154: * attempts to get the content type from <code>getContentType()</code>,
0155: * which looks for the response header field "Content-Type". If none is
0156: * found, it will guess the content type from the filename extension. If
0157: * that fails, it will guess by inspecting the stream.
0158: *
0159: * @param types
0160: * The list of acceptable content types
0161: * @return Object The object of the resource pointed by this URL, or null if
0162: * the content does not match a specified content type.
0163: *
0164: * @throws IOException
0165: * If an error occurred obtaining the content.
0166: */
0167: // Param is not generic in spec
0168: @SuppressWarnings("unchecked")
0169: public Object getContent(Class[] types) throws IOException {
0170: if (!connected) {
0171: connect();
0172: }
0173:
0174: if ((contentType = getContentType()) == null) {
0175: if ((contentType = guessContentTypeFromName(url.getFile())) == null) {
0176: contentType = guessContentTypeFromStream(getInputStream());
0177: }
0178: }
0179: if (contentType != null) {
0180: return getContentHandler(contentType).getContent(this ,
0181: types);
0182: }
0183: return null;
0184: }
0185:
0186: /**
0187: * Answers the Content encoding type of the response body, null if no such
0188: * field is found in the header response.
0189: *
0190: * @return The content encoding type
0191: *
0192: * @see #getContentType
0193: */
0194: public String getContentEncoding() {
0195: return getHeaderField("Content-Encoding"); //$NON-NLS-1$
0196: }
0197:
0198: /**
0199: * Answers the specific ContentHandler that will handle the type
0200: * <code>contentType</code>
0201: *
0202: * @param type
0203: * The type that needs to be handled
0204: * @return An instance of the Content Handler
0205: */
0206: private ContentHandler getContentHandler(String type)
0207: throws IOException {
0208: // Replace all non-alphanumeric character by '_'
0209: final String typeString = parseTypeString(type
0210: .replace('/', '.'));
0211:
0212: // if there's a cached content handler, use it
0213: Object cHandler = contentHandlers.get(type);
0214: if (cHandler != null) {
0215: return (ContentHandler) cHandler;
0216: }
0217:
0218: if (contentHandlerFactory != null) {
0219: cHandler = contentHandlerFactory.createContentHandler(type);
0220: if (!(cHandler instanceof ContentHandler)) {
0221: throw new UnknownServiceException();
0222: }
0223: contentHandlers.put(type, cHandler);
0224: return (ContentHandler) cHandler;
0225: }
0226:
0227: // search through the package list for the right class for the Content
0228: // Type
0229: String packageList = AccessController
0230: .doPrivileged(new PriviAction<String>(
0231: "java.content.handler.pkgs")); //$NON-NLS-1$
0232: if (packageList != null) {
0233: final StringTokenizer st = new StringTokenizer(packageList,
0234: "|"); //$NON-NLS-1$
0235: while (st.countTokens() > 0) {
0236: try {
0237: Class<?> cl = Class.forName(st.nextToken() + "." //$NON-NLS-1$
0238: + typeString, true, ClassLoader
0239: .getSystemClassLoader());
0240: cHandler = cl.newInstance();
0241: } catch (ClassNotFoundException e) {
0242: } catch (IllegalAccessException e) {
0243: } catch (InstantiationException e) {
0244: }
0245: }
0246: }
0247:
0248: if (cHandler == null) {
0249: cHandler = AccessController
0250: .doPrivileged(new PrivilegedAction<Object>() {
0251: public Object run() {
0252: try {
0253: String className = "org.apache.harmony.luni.internal.net.www.content." //$NON-NLS-1$
0254: + typeString;
0255: return Class.forName(className)
0256: .newInstance();
0257: } catch (ClassNotFoundException e) {
0258: } catch (IllegalAccessException e) {
0259: } catch (InstantiationException e) {
0260: }
0261: return null;
0262: }
0263: });
0264: }
0265: if (cHandler != null) {
0266: if (!(cHandler instanceof ContentHandler)) {
0267: throw new UnknownServiceException();
0268: }
0269: contentHandlers.put(type, cHandler); // if we got the handler,
0270: // cache it for next time
0271: return (ContentHandler) cHandler;
0272: }
0273:
0274: return defaultHandler;
0275: }
0276:
0277: /**
0278: * Answers the length of the content or body in the response header in
0279: * bytes. Answer -1 if <code> Content-Length </code> cannot be found in the
0280: * response header.
0281: *
0282: * @return The length of the content
0283: *
0284: * @see #getContentType
0285: */
0286: public int getContentLength() {
0287: return getHeaderFieldInt("Content-Length", -1); //$NON-NLS-1$
0288: }
0289:
0290: /**
0291: * Answers the type of the content. Answers <code> null </code> if there's
0292: * no such field.
0293: *
0294: * @return The type of the content
0295: *
0296: * @see #guessContentTypeFromName
0297: * @see #guessContentTypeFromStream
0298: */
0299: public String getContentType() {
0300: return getHeaderField("Content-Type"); //$NON-NLS-1$
0301: }
0302:
0303: /**
0304: * Answers the date in milliseconds since epoch when this response header
0305: * was created, or 0 if the field <code>Date</code> is not found in the
0306: * header.
0307: *
0308: * @return Date in millisecond since epoch
0309: *
0310: * @see #getExpiration
0311: * @see #getLastModified
0312: * @see java.util.Date
0313: *
0314: */
0315: public long getDate() {
0316: return getHeaderFieldDate("Date", 0); //$NON-NLS-1$
0317: }
0318:
0319: /**
0320: * Answers whether this connection allow user interaction by default.
0321: *
0322: * @return the value of <code>defaultAllowUserInteraction</code>
0323: *
0324: * @see #getAllowUserInteraction
0325: * @see #setDefaultAllowUserInteraction
0326: * @see #setAllowUserInteraction
0327: * @see #allowUserInteraction
0328: */
0329: public static boolean getDefaultAllowUserInteraction() {
0330: return defaultAllowUserInteraction;
0331: }
0332:
0333: /**
0334: * Answers the default value for the field specified by <code>field</code>,
0335: * null if there's no such field.
0336: *
0337: * @param field
0338: * the field to get the request property for
0339: * @return the field to be looked up
0340: *
0341: * @deprecated Use getRequestProperty().
0342: */
0343: @Deprecated
0344: public static String getDefaultRequestProperty(String field) {
0345: return null;
0346: }
0347:
0348: /**
0349: * Answers whether this connection use caches by default.
0350: *
0351: * @return true if this connection use caches by default, false otherwise
0352: *
0353: * @see #getUseCaches
0354: * @see #setDefaultUseCaches
0355: * @see #setUseCaches
0356: * @see #useCaches
0357: */
0358: public boolean getDefaultUseCaches() {
0359: return defaultUseCaches;
0360: }
0361:
0362: /**
0363: * Answers whether this connection supports input.
0364: *
0365: * @return true if this connection supports input, false otherwise
0366: *
0367: * @see #setDoInput
0368: * @see #doInput
0369: */
0370: public boolean getDoInput() {
0371: return doInput;
0372: }
0373:
0374: /**
0375: * Answers whether this connection supports output.
0376: *
0377: * @return true if this connection supports output, false otherwise
0378: *
0379: * @see #setDoOutput
0380: * @see #doOutput
0381: */
0382: public boolean getDoOutput() {
0383: return doOutput;
0384: }
0385:
0386: /**
0387: * Answers the date in milliseconds since epoch when this response header
0388: * expires or 0 if the field <code>Expires</code> is not found in the
0389: * header.
0390: *
0391: * @return Date in milliseconds since epoch
0392: *
0393: * @see #getHeaderField(int)
0394: * @see #getHeaderField(String)
0395: * @see #getHeaderFieldDate(String, long)
0396: * @see #getHeaderFieldInt(String, int)
0397: * @see #getHeaderFieldKey(int)
0398: */
0399: public long getExpiration() {
0400: return getHeaderFieldDate("Expires", 0); //$NON-NLS-1$
0401: }
0402:
0403: /**
0404: * Answers the MIME table of this URL connection.
0405: *
0406: * @return FileNameMap
0407: */
0408: public static FileNameMap getFileNameMap() {
0409: // Must use lazy initialization or there is a bootstrap problem
0410: // trying to load the MimeTable resource from a .jar before
0411: // JarURLConnection has finished initialization.
0412: if (fileNameMap == null) {
0413: fileNameMap = new MimeTable();
0414: }
0415: return fileNameMap;
0416: }
0417:
0418: /**
0419: * Answers the value of the field at position <code>pos<code>.
0420: * Answers <code>null</code> if there are fewer than <code>pos</code> fields
0421: * in the response header.
0422: *
0423: * @param pos the position of the field
0424: * @return The value of the field
0425: *
0426: * @see #getHeaderFieldDate
0427: * @see #getHeaderFieldInt
0428: * @see #getHeaderFieldKey
0429: */
0430: public String getHeaderField(int pos) {
0431: return null;
0432: }
0433:
0434: /**
0435: * Provides an unmodifiable map of the connection header values. The map
0436: * keys are the String header field names. Each map value is a List of the
0437: * header field values associated with that key name.
0438: *
0439: * @return the mapping of header field names to values
0440: *
0441: * @since 1.4
0442: */
0443: public Map<String, List<String>> getHeaderFields() {
0444: return Collections.emptyMap();
0445: }
0446:
0447: /**
0448: * Provides an unmodifiable map of the request properties. The map keys are
0449: * Strings, the map values are each a List of Strings, with each request
0450: * property name mapped to its corresponding property values.
0451: *
0452: * @return the mapping of request property names to values
0453: *
0454: * @since 1.4
0455: */
0456: public Map<String, List<String>> getRequestProperties() {
0457: if (connected) {
0458: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
0459: }
0460: return Collections.emptyMap();
0461: }
0462:
0463: /**
0464: * Adds the given request property. Will not overwrite any existing
0465: * properties associated with the given field name.
0466: *
0467: * @param field
0468: * the request property field name
0469: * @param newValue
0470: * the property value
0471: *
0472: * @throws IllegalStateException -
0473: * if connection already established
0474: * @throws NullPointerException -
0475: * if field is null
0476: *
0477: * @since 1.4
0478: */
0479: public void addRequestProperty(String field, String newValue) {
0480: if (connected) {
0481: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
0482: }
0483: if (field == null) {
0484: throw new NullPointerException(Msg.getString("KA007")); //$NON-NLS-1$
0485: }
0486: }
0487:
0488: /**
0489: * Answers the value of the field corresponding to the <code>key</code>
0490: * Answers <code>null</code> if there is no such field.
0491: *
0492: * @param key
0493: * the name of the header field
0494: * @return The value of the header field
0495: *
0496: * @see #getHeaderFieldDate
0497: * @see #getHeaderFieldInt
0498: * @see #getHeaderFieldKey
0499: */
0500: public String getHeaderField(String key) {
0501: return null;
0502: }
0503:
0504: /**
0505: * Answers the date value in the form of milliseconds since epoch
0506: * corresponding to the field <code>field</code>. Answers
0507: * <code>defaultValue</code> if no such field can be found in the response
0508: * header.
0509: *
0510: * @param field
0511: * the field in question
0512: * @param defaultValue
0513: * the default value if no field is found or the value is invalid
0514: * @return milliseconds since epoch
0515: *
0516: * @see #ifModifiedSince
0517: * @see #setIfModifiedSince
0518: */
0519: @SuppressWarnings("deprecation")
0520: public long getHeaderFieldDate(String field, long defaultValue) {
0521: String date = getHeaderField(field);
0522: if (date == null) {
0523: return defaultValue;
0524: }
0525: try {
0526: return Date.parse(date);
0527: } catch (Exception e) {
0528: return defaultValue;
0529: }
0530: }
0531:
0532: /**
0533: * Answers the integer value of the specified field. Answers default value
0534: * <code>defaultValue</code> if no such field exists.
0535: *
0536: * @param field
0537: * the field to return
0538: * @param defaultValue
0539: * to be returned if <code>field></code> does not exist
0540: * @return value of the field
0541: */
0542: public int getHeaderFieldInt(String field, int defaultValue) {
0543: try {
0544: return Integer.parseInt(getHeaderField(field));
0545: } catch (NumberFormatException e) {
0546: return defaultValue;
0547: }
0548: }
0549:
0550: /**
0551: * Answers the name of the field at position specified by <code>posn</code>,
0552: * null if there are fewer than <code>posn</code> fields.
0553: *
0554: * @param posn
0555: * the position to look for; the first field being 0
0556: * @return the name of the field
0557: *
0558: * @see #getHeaderFieldDate
0559: * @see #getHeaderFieldInt
0560: * @see #getHeaderField(int)
0561: * @see #getHeaderField(String)
0562: * @see #getHeaderFieldDate(String, long)
0563: * @see #getHeaderFieldInt(String, int)
0564: * @see #getHeaderFieldKey(int)
0565: */
0566: public String getHeaderFieldKey(int posn) {
0567: return null;
0568: }
0569:
0570: /**
0571: * Answers the value of <code>ifModifiedSince</code> of this connection in
0572: * milliseconds since epoch
0573: *
0574: * @return the time since epoch
0575: *
0576: * @see #ifModifiedSince
0577: * @see #setIfModifiedSince
0578: */
0579: public long getIfModifiedSince() {
0580: return ifModifiedSince;
0581: }
0582:
0583: /**
0584: * Creates an InputStream for reading from this URL Connection. It throws
0585: * UnknownServiceException by default. This method should be overridden by
0586: * its subclasses
0587: *
0588: * @return The InputStream to read from
0589: *
0590: * @throws IOException
0591: * If an InputStream could not be created
0592: *
0593: * @see #getContent()
0594: * @see #getContent(Class[])
0595: * @see #getOutputStream
0596: * @see java.io.InputStream
0597: * @see java.io.IOException
0598: *
0599: */
0600: public InputStream getInputStream() throws IOException {
0601: throw new UnknownServiceException(Msg.getString("K004d")); //$NON-NLS-1$
0602: }
0603:
0604: /**
0605: * Answers the value of the field <code>Last-Modified</code> in the
0606: * response header, 0 if no such field exists
0607: *
0608: * @return the value of the field last modified
0609: *
0610: * @see java.util.Date
0611: * @see #getDate
0612: * @see #getExpiration
0613: */
0614: public long getLastModified() {
0615: if (lastModified != -1) {
0616: return lastModified;
0617: }
0618: return lastModified = getHeaderFieldDate("Last-Modified", 0); //$NON-NLS-1$
0619: }
0620:
0621: /**
0622: * Creates an OutputStream for writing to this URL Connection. It throws
0623: * UnknownServiceException by default. This method should be overridden by
0624: * subclasses.
0625: *
0626: * @return The OutputStream to write to
0627: *
0628: * @throws IOException
0629: * If an OutputStream could not be created
0630: *
0631: * @see #getContent()
0632: * @see #getContent(Class[])
0633: * @see #getInputStream
0634: * @see java.io.IOException
0635: *
0636: */
0637: public OutputStream getOutputStream() throws IOException {
0638: throw new UnknownServiceException(Msg.getString("K005f")); //$NON-NLS-1$
0639: }
0640:
0641: /**
0642: * Answers the permissions necessary to make the connection. Depending on
0643: * the protocol, this can be any of the permission subclasses. The
0644: * permission returned may also depend on the state of the connection, E.G
0645: * In the case of HTTP, redirection can change the applicable permission if
0646: * the host changed.
0647: *
0648: * <p>
0649: * By default, this methods returns <code>AllPermission</code>.
0650: * Subclasses should override this and return the appropriate permission
0651: * object.
0652: *
0653: * @return the permission object governing the connection
0654: *
0655: * @throws IOException
0656: * if an IO exception occurs during the creation of the
0657: * permission object.
0658: */
0659: public java.security.Permission getPermission() throws IOException {
0660: return new java.security.AllPermission();
0661: }
0662:
0663: /**
0664: * Answers the value corresponding to the field in the request Header, null
0665: * if no such field exists.
0666: *
0667: * @param field
0668: * the field to get the property for
0669: * @return the field to look up
0670: * @throws IllegalStateException -
0671: * if connection already established
0672: *
0673: * @see #getDefaultRequestProperty
0674: * @see #setDefaultRequestProperty
0675: * @see #setRequestProperty
0676: */
0677: public String getRequestProperty(String field) {
0678: if (connected) {
0679: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
0680: }
0681: return null;
0682: }
0683:
0684: /**
0685: * Answers the <code>URL</code> of this connection
0686: *
0687: * @return the URL of this connection
0688: *
0689: * @see URL
0690: * @see #URLConnection(URL)
0691: */
0692: public URL getURL() {
0693: return url;
0694: }
0695:
0696: /**
0697: * Answers whether this connection uses caches
0698: *
0699: * @return the value of the flag
0700: */
0701: public boolean getUseCaches() {
0702: return useCaches;
0703: }
0704:
0705: /**
0706: * Determines the MIME type of the file specified by the
0707: * <code> string </code> URL, using the filename extension. Any fragment
0708: * identifier is removed before processing.
0709: *
0710: * @param url
0711: * the MIME type of the file.
0712: * @return the string representation of an URL
0713: *
0714: * @see FileNameMap
0715: * @see FileNameMap#getContentTypeFor(String)
0716: * @see #getContentType
0717: * @see #guessContentTypeFromStream
0718: *
0719: */
0720: public static String guessContentTypeFromName(String url) {
0721: return getFileNameMap().getContentTypeFor(url);
0722: }
0723:
0724: /**
0725: * Examines the bytes of the input stream and returns the MIME type, null if
0726: * no content type can be deduced.
0727: *
0728: * @param is
0729: * the input stream for the URL
0730: * @return the type of the input stream
0731: *
0732: * @throws IOException
0733: * If an IO error occurs
0734: */
0735: @SuppressWarnings("nls")
0736: public static String guessContentTypeFromStream(InputStream is)
0737: throws IOException {
0738:
0739: if (!is.markSupported()) {
0740: return null;
0741: }
0742: // Look ahead up to 64 bytes for the longest encoded header
0743: is.mark(64);
0744: byte[] bytes = new byte[64];
0745: int length = is.read(bytes);
0746: is.reset();
0747:
0748: // Check for Unicode BOM encoding indicators
0749: String encoding = "ASCII";
0750: int start = 0;
0751: if (length > 1) {
0752: if ((bytes[0] == (byte) 0xFF) && (bytes[1] == (byte) 0xFE)) {
0753: encoding = "UTF-16LE";
0754: start = 2;
0755: length -= length & 1;
0756: }
0757: if ((bytes[0] == (byte) 0xFE) && (bytes[1] == (byte) 0xFF)) {
0758: encoding = "UTF-16BE";
0759: start = 2;
0760: length -= length & 1;
0761: }
0762: if (length > 2) {
0763: if ((bytes[0] == (byte) 0xEF)
0764: && (bytes[1] == (byte) 0xBB)
0765: && (bytes[2] == (byte) 0xBF)) {
0766: encoding = "UTF-8";
0767: start = 3;
0768: }
0769: if (length > 3) {
0770: if ((bytes[0] == (byte) 0x00)
0771: && (bytes[1] == (byte) 0x00)
0772: && (bytes[2] == (byte) 0xFE)
0773: && (bytes[3] == (byte) 0xFF)) {
0774: encoding = "UTF-32BE";
0775: start = 4;
0776: length -= length & 3;
0777: }
0778: if ((bytes[0] == (byte) 0xFF)
0779: && (bytes[1] == (byte) 0xFE)
0780: && (bytes[2] == (byte) 0x00)
0781: && (bytes[3] == (byte) 0x00)) {
0782: encoding = "UTF-32LE";
0783: start = 4;
0784: length -= length & 3;
0785: }
0786: }
0787: }
0788: }
0789:
0790: String header = new String(bytes, start, length - start,
0791: encoding);
0792:
0793: // Check binary types
0794: if (header.startsWith("PK")) {
0795: return "application/zip";
0796: }
0797: if (header.startsWith("GI")) {
0798: return "image/gif";
0799: }
0800:
0801: // Check text types
0802: String textHeader = header.trim().toUpperCase();
0803: if (textHeader.startsWith("<!DOCTYPE HTML")
0804: || textHeader.startsWith("<HTML")
0805: || textHeader.startsWith("<HEAD")
0806: || textHeader.startsWith("<BODY")
0807: || textHeader.startsWith("<HEAD")) {
0808: return "text/html";
0809: }
0810:
0811: if (textHeader.startsWith("<?XML")) {
0812: return "application/xml";
0813: }
0814:
0815: // Give up
0816: return null;
0817: }
0818:
0819: /**
0820: * Performs any necessary string parsing on the input string such as
0821: * converting non-alphanumeric character into underscore.
0822: *
0823: * @param typeString
0824: * the parsed string
0825: * @return the string to be parsed
0826: */
0827: private String parseTypeString(String typeString) {
0828: StringBuffer typeStringBuffer = new StringBuffer(typeString);
0829: for (int i = 0; i < typeStringBuffer.length(); i++) {
0830: // if non-alphanumeric, replace it with '_'
0831: char c = typeStringBuffer.charAt(i);
0832: if (!(Character.isLetter(c) || Character.isDigit(c) || c == '.')) {
0833: typeStringBuffer.setCharAt(i, '_');
0834: }
0835: }
0836: return typeStringBuffer.toString();
0837: }
0838:
0839: /**
0840: * Sets the flag indicating whether this connection allows user interaction
0841: * This can only be called prior to connection establishment.
0842: *
0843: * @param newValue
0844: * the value of the flag to be set
0845: *
0846: * @throws IllegalStateException
0847: * if this method attempts to change the flag after a connection
0848: * has been established
0849: */
0850: public void setAllowUserInteraction(boolean newValue) {
0851: if (connected) {
0852: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
0853: }
0854: this .allowUserInteraction = newValue;
0855: }
0856:
0857: /**
0858: * Sets the current content handler factory to be
0859: * <code>contentFactory</code>. It can only do so with the permission of
0860: * the security manager. The ContentFactory can only be specified once
0861: * during the lifetime of an application.
0862: *
0863: * @param contentFactory
0864: * the factory
0865: *
0866: * @throws Error
0867: * if a ContentFactory has been created before SecurityException
0868: * if the security manager does not allow this action
0869: *
0870: * @see ContentHandler
0871: * @see ContentHandlerFactory
0872: * @see java.lang.SecurityException
0873: * @see java.lang.SecurityManager#checkSetFactory()
0874: */
0875: public static synchronized void setContentHandlerFactory(
0876: ContentHandlerFactory contentFactory) {
0877: if (contentHandlerFactory != null) {
0878: throw new Error(Msg.getString("K004e")); //$NON-NLS-1$
0879: }
0880: SecurityManager sManager = System.getSecurityManager();
0881: if (sManager != null) {
0882: sManager.checkSetFactory();
0883: }
0884: contentHandlerFactory = contentFactory;
0885: }
0886:
0887: /**
0888: * Set whether user interaction is allowed by default. Existing
0889: * URLConnections are unaffected.
0890: *
0891: * @param allows
0892: * allow user interaction
0893: */
0894: public static void setDefaultAllowUserInteraction(boolean allows) {
0895: defaultAllowUserInteraction = allows;
0896: }
0897:
0898: /**
0899: * Sets the <code>field</code> in the default request header with the
0900: * value <code>value</code>
0901: *
0902: * @param field
0903: * the request header field to be set
0904: * @param value
0905: * the new value
0906: *
0907: * @deprecated Use getRequestProperty().
0908: */
0909: @Deprecated
0910: public static void setDefaultRequestProperty(String field,
0911: String value) {
0912: }
0913:
0914: /**
0915: * Set whether caches are used by default. Existing URLConnections are
0916: * unaffected.
0917: *
0918: * @param newValue
0919: * the value of the flag to be set
0920: *
0921: * @see #getDefaultUseCaches
0922: * @see #getUseCaches
0923: * @see #setUseCaches
0924: * @see #useCaches
0925: */
0926: public void setDefaultUseCaches(boolean newValue) {
0927: if (connected) {
0928: throw new IllegalAccessError(Msg.getString("K0037")); //$NON-NLS-1$
0929: }
0930: defaultUseCaches = newValue;
0931: }
0932:
0933: /**
0934: * Sets whether this URLConnection allows input. It cannot be set after the
0935: * connection is made.
0936: *
0937: * @param newValue
0938: * boolean
0939: *
0940: * @throws IllegalAccessError
0941: * Exception thrown when this method attempts to change the
0942: * value after connected
0943: *
0944: * @see #doInput
0945: * @see #getDoInput
0946: * @see #setDoInput
0947: * @see java.lang.IllegalAccessError
0948: */
0949: public void setDoInput(boolean newValue) {
0950: if (connected) {
0951: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
0952: }
0953: this .doInput = newValue;
0954: }
0955:
0956: /**
0957: * Sets whether this URLConnection allows output. It cannot be set after the
0958: * connection is made.
0959: *
0960: * @param newValue
0961: * boolean
0962: *
0963: * @throws IllegalAccessError
0964: * Exception thrown when this method attempts to change the
0965: * value after connected
0966: *
0967: * @see #doOutput
0968: * @see #getDoOutput
0969: * @see #setDoOutput
0970: * @see java.lang.IllegalAccessError
0971: */
0972: public void setDoOutput(boolean newValue) {
0973: if (connected) {
0974: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
0975: }
0976: this .doOutput = newValue;
0977: }
0978:
0979: /**
0980: * With permission from the security manager, this method sets the
0981: * <code>map</code> to be the MIME Table of this URL connection.
0982: *
0983: * @param map
0984: * the MIME table to be set.
0985: */
0986: public static void setFileNameMap(FileNameMap map) {
0987: SecurityManager manager = System.getSecurityManager();
0988: if (manager != null) {
0989: manager.checkSetFactory();
0990: }
0991: fileNameMap = map;
0992: }
0993:
0994: /**
0995: * Sets the header field <code>ifModifiedSince</code>.
0996: *
0997: * @param newValue
0998: * number of milliseconds since epoch
0999: * @throws IllegalStateException
1000: * if already connected.
1001: */
1002: public void setIfModifiedSince(long newValue) {
1003: if (connected) {
1004: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
1005: }
1006: this .ifModifiedSince = newValue;
1007: }
1008:
1009: /**
1010: * Sets the value of the request header field <code> field </code> to
1011: * <code>newValue</code> Only the current URL Connection is affected. It
1012: * can only be called before the connection is made
1013: *
1014: * @param field
1015: * the field
1016: * @param newValue
1017: * the field's new value
1018: *
1019: * @throws IllegalStateException -
1020: * if connection already established
1021: * @throws NullPointerException -
1022: * if field is null
1023: *
1024: * @see #getDefaultRequestProperty
1025: * @see #setDefaultRequestProperty
1026: * @see #getRequestProperty
1027: */
1028: public void setRequestProperty(String field, String newValue) {
1029: if (connected) {
1030: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
1031: }
1032: if (field == null) {
1033: throw new NullPointerException(Msg.getString("KA007")); //$NON-NLS-1$
1034: }
1035: }
1036:
1037: /**
1038: * Sets the flag indicating if this connection uses caches. This value
1039: * cannot be set after the connection is made.
1040: *
1041: * @param newValue
1042: * the value of the flag to be set
1043: *
1044: * @throws IllegalStateException
1045: * Exception thrown when this method attempts to change the
1046: * value after connected
1047: *
1048: * @see #getDefaultUseCaches
1049: * @see #setDefaultUseCaches
1050: * @see #getUseCaches
1051: * @see #useCaches
1052: */
1053: public void setUseCaches(boolean newValue) {
1054: if (connected) {
1055: throw new IllegalStateException(Msg.getString("K0037")); //$NON-NLS-1$
1056: }
1057: this .useCaches = newValue;
1058: }
1059:
1060: /**
1061: * Sets a timeout for connection to perform non-block. Default is zero.
1062: * Timeout of zero means infinite.
1063: *
1064: * @param timeout
1065: * timeout for connection in milliseconds.
1066: * @throws IllegalArgumentException
1067: * if timeout is less than zero.
1068: */
1069: public void setConnectTimeout(int timeout) {
1070: if (0 > timeout) {
1071: throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
1072: }
1073: this .connectTimeout = timeout;
1074: }
1075:
1076: /**
1077: * Returns a timeout of connection by milliseconds
1078: *
1079: * @return timeout of connection by milliseconds
1080: */
1081: public int getConnectTimeout() {
1082: return connectTimeout;
1083: }
1084:
1085: /**
1086: * Sets a timeout for reading to perform non-block. Default is zero. Timeout
1087: * of zero means infinite.
1088: *
1089: * @param timeout
1090: * timeout for reading in milliseconds.
1091: * @throws IllegalArgumentException
1092: * if timeout is less than zero.
1093: */
1094: public void setReadTimeout(int timeout) {
1095: if (0 > timeout) {
1096: throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
1097: }
1098: this .readTimeout = timeout;
1099: }
1100:
1101: /**
1102: * Returns a timeout of reading by milliseconds
1103: *
1104: * @return timeout of reading by milliseconds
1105: */
1106: public int getReadTimeout() {
1107: return readTimeout;
1108: }
1109:
1110: /**
1111: * Answers the name of the class of the <code>URLConnection </code>
1112: *
1113: * @return The string representation of this <code>URLConnection</code>
1114: *
1115: * @see #getURL
1116: * @see #URLConnection(URL)
1117: */
1118: @Override
1119: public String toString() {
1120: return getClass().getName() + ":" + url.toString(); //$NON-NLS-1$
1121: }
1122:
1123: static class DefaultContentHandler extends java.net.ContentHandler {
1124:
1125: /**
1126: * @param u
1127: * the URL connection
1128: *
1129: * @see java.net.ContentHandler#getContent(java.net.URLConnection)
1130: */
1131: @Override
1132: public Object getContent(URLConnection u) throws IOException {
1133: return u.getInputStream();
1134: }
1135: }
1136: }
|