jdk/src/solaris/classes/sun/nio/fs/MimeTypesFileTypeDetector.java
changeset 14702 111342b28e67
equal deleted inserted replaced
14701:0c0578b802b1 14702:111342b28e67
       
     1 /*
       
     2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.nio.fs;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.nio.charset.Charset;
       
    30 import java.nio.file.Files;
       
    31 import java.nio.file.Path;
       
    32 import java.security.AccessController;
       
    33 import java.security.PrivilegedAction;
       
    34 import java.util.Collections;
       
    35 import java.util.HashMap;
       
    36 import java.util.List;
       
    37 import java.util.Map;
       
    38 import java.util.regex.Matcher;
       
    39 import java.util.regex.Pattern;
       
    40 
       
    41 /**
       
    42  * File type detector that uses a file extension to look up its MIME type
       
    43  * based on a mime.types file.
       
    44  */
       
    45 
       
    46 class MimeTypesFileTypeDetector extends AbstractFileTypeDetector {
       
    47 
       
    48     // path to mime.types file
       
    49     private final Path mimeTypesFile;
       
    50 
       
    51     // map of extension to MIME type
       
    52     private Map<String,String> mimeTypeMap;
       
    53 
       
    54     // set to true when file loaded
       
    55     private volatile boolean loaded = false;
       
    56 
       
    57     public MimeTypesFileTypeDetector(Path filePath) {
       
    58         mimeTypesFile = filePath;
       
    59     }
       
    60 
       
    61     @Override
       
    62     protected String implProbeContentType(Path path) {
       
    63         Path fn = path.getFileName();
       
    64         if (fn == null)
       
    65             return null;  // no file name
       
    66 
       
    67         String ext = getExtension(fn.toString());
       
    68         if (ext.isEmpty())
       
    69             return null;  // no extension
       
    70 
       
    71         loadMimeTypes();
       
    72         if (mimeTypeMap == null || mimeTypeMap.isEmpty())
       
    73             return null;
       
    74 
       
    75         // Case-sensitive search
       
    76         String mimeType;
       
    77         do {
       
    78             mimeType = mimeTypeMap.get(ext);
       
    79             if (mimeType == null)
       
    80                 ext = getExtension(ext);
       
    81         } while (mimeType == null && !ext.isEmpty());
       
    82 
       
    83         return mimeType;
       
    84     }
       
    85 
       
    86     // Get the extension of a file name.
       
    87     private static String getExtension(String name) {
       
    88         String ext = "";
       
    89         if (name != null && !name.isEmpty()) {
       
    90             int dot = name.indexOf('.');
       
    91             if ((dot >= 0) && (dot < name.length() - 1)) {
       
    92                 ext = name.substring(dot + 1);
       
    93             }
       
    94         }
       
    95         return ext;
       
    96     }
       
    97 
       
    98     /**
       
    99      * Parse the mime types file, and store the type-extension mappings into
       
   100      * mimeTypeMap. The mime types file is not loaded until the first probe
       
   101      * to achieve the lazy initialization. It adopts double-checked locking
       
   102      * optimization to reduce the locking overhead.
       
   103      */
       
   104     private void loadMimeTypes() {
       
   105         if (!loaded) {
       
   106             synchronized (this) {
       
   107                 if (!loaded) {
       
   108                     List<String> lines = AccessController.doPrivileged(
       
   109                         new PrivilegedAction<List<String>>() {
       
   110                             @Override
       
   111                             public List<String> run() {
       
   112                                 try {
       
   113                                     return Files.readAllLines(mimeTypesFile,
       
   114                                                               Charset.defaultCharset());
       
   115                                 } catch (IOException ignore) {
       
   116                                     return Collections.emptyList();
       
   117                                 }
       
   118                             }
       
   119                         });
       
   120 
       
   121                     mimeTypeMap = new HashMap<>(lines.size());
       
   122                     String entry = "";
       
   123                     for (String line : lines) {
       
   124                         entry += line;
       
   125                         if (entry.endsWith("\\")) {
       
   126                             entry = entry.substring(0, entry.length() - 1);
       
   127                             continue;
       
   128                         }
       
   129                         parseMimeEntry(entry);
       
   130                         entry = "";
       
   131                     }
       
   132                     if (!entry.isEmpty()) {
       
   133                         parseMimeEntry(entry);
       
   134                     }
       
   135                     loaded = true;
       
   136                 }
       
   137             }
       
   138         }
       
   139     }
       
   140 
       
   141     /**
       
   142      * Parse a mime-types entry, which can have the following formats.
       
   143      * 1) Simple space-delimited format
       
   144      * image/jpeg   jpeg jpg jpe JPG
       
   145      *
       
   146      * 2) Netscape key-value pair format
       
   147      * type=application/x-java-jnlp-file desc="Java Web Start" exts="jnlp"
       
   148      * or
       
   149      * type=text/html exts=htm,html
       
   150      */
       
   151     private void parseMimeEntry(String entry) {
       
   152         entry = entry.trim();
       
   153         if (entry.isEmpty() || entry.charAt(0) == '#')
       
   154             return;
       
   155 
       
   156         entry = entry.replaceAll("\\s*#.*", "");
       
   157         int equalIdx = entry.indexOf('=');
       
   158         if (equalIdx > 0) {
       
   159             // Parse a mime-types command having the key-value pair format
       
   160             final String TYPEEQUAL = "type=";
       
   161             String typeRegex = "\\b" + TYPEEQUAL +
       
   162                     "(\"\\p{Graph}+?/\\p{Graph}+?\"|\\p{Graph}+/\\p{Graph}+\\b)";
       
   163             Pattern typePattern = Pattern.compile(typeRegex);
       
   164             Matcher typeMatcher = typePattern.matcher(entry);
       
   165 
       
   166             if (typeMatcher.find()) {
       
   167                 String type = typeMatcher.group().substring(TYPEEQUAL.length());
       
   168                 if (type.charAt(0) == '"') {
       
   169                     type = type.substring(1, type.length() - 1);
       
   170                 }
       
   171 
       
   172                 final String EXTEQUAL = "exts=";
       
   173                 String extRegex = "\\b" + EXTEQUAL +
       
   174                         "(\"[\\p{Graph}|\\p{Blank}]+?\"|\\p{Graph}+\\b)";
       
   175                 Pattern extPattern = Pattern.compile(extRegex);
       
   176                 Matcher extMatcher = extPattern.matcher(entry);
       
   177 
       
   178                 if (extMatcher.find()) {
       
   179                     String exts =
       
   180                             extMatcher.group().substring(EXTEQUAL.length());
       
   181                     if (exts.charAt(0) == '"') {
       
   182                         exts = exts.substring(1, exts.length() - 1);
       
   183                     }
       
   184                     String[] extList = exts.split("[\\p{Blank}|\\p{Punct}]+");
       
   185                     for (String ext : extList) {
       
   186                         putIfAbsent(ext, type);
       
   187                     }
       
   188                 }
       
   189             }
       
   190         } else {
       
   191             // Parse a mime-types command having the space-delimited format
       
   192             String[] elements = entry.split("\\s+");
       
   193             int i = 1;
       
   194             while (i < elements.length) {
       
   195                 putIfAbsent(elements[i++], elements[0]);
       
   196             }
       
   197         }
       
   198     }
       
   199 
       
   200     private void putIfAbsent(String key, String value) {
       
   201         if (key != null && !key.isEmpty() &&
       
   202             value != null && !value.isEmpty() &&
       
   203             !mimeTypeMap.containsKey(key))
       
   204         {
       
   205             mimeTypeMap.put(key, value);
       
   206         }
       
   207     }
       
   208 }