1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.tomcat.util.descriptor;
18
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.net.MalformedURLException;
22 import java.net.URI;
23 import java.net.URISyntaxException;
24 import java.net.URL;
25 import java.util.Map;
26
27 import org.apache.tomcat.util.res.StringManager;
28 import org.xml.sax.InputSource;
29 import org.xml.sax.SAXException;
30 import org.xml.sax.ext.EntityResolver2;
31
32 /**
33  * A resolver for locally cached XML resources.
34  */

35 public class LocalResolver implements EntityResolver2 {
36
37     private static final StringManager sm =
38             StringManager.getManager(Constants.PACKAGE_NAME);
39
40     private static final String[] JAVA_EE_NAMESPACES = {
41         XmlIdentifiers.JAVAEE_1_4_NS,
42         XmlIdentifiers.JAVAEE_5_NS,
43         XmlIdentifiers.JAVAEE_7_NS};
44
45
46     private final Map<String,String> publicIds;
47     private final Map<String,String> systemIds;
48     private final boolean blockExternal;
49
50     /**
51      * Constructor providing mappings of public and system identifiers to local
52      * resources. Each map contains a mapping from a well-known identifier to a
53      * URL for a local resource path.
54      *
55      * @param publicIds mapping of well-known public identifiers to local
56      *                  resources
57      * @param systemIds mapping of well-known system identifiers to local
58      *                  resources
59      * @param blockExternal are external resources blocked that are not
60      *                      well-known
61      */

62     public LocalResolver(Map<String,String> publicIds,
63             Map<String,String> systemIds, boolean blockExternal) {
64         this.publicIds = publicIds;
65         this.systemIds = systemIds;
66         this.blockExternal = blockExternal;
67     }
68
69
70     @Override
71     public InputSource resolveEntity(String publicId, String systemId)
72             throws SAXException, IOException {
73         return resolveEntity(null, publicId, null, systemId);
74     }
75
76
77     @Override
78     public InputSource resolveEntity(String name, String publicId,
79             String base, String systemId) throws SAXException, IOException {
80
81         // First try resolving using the publicId
82         String resolved = publicIds.get(publicId);
83         if (resolved != null) {
84             InputSource is = new InputSource(resolved);
85             is.setPublicId(publicId);
86             return is;
87         }
88
89         // If there is no systemId, can't try anything else
90         if (systemId == null) {
91             throw new FileNotFoundException(sm.getString("localResolver.unresolvedEntity",
92                     name, publicId, null, base));
93         }
94
95         // Try resolving with the supplied systemId
96         resolved = systemIds.get(systemId);
97         if (resolved != null) {
98             InputSource is = new InputSource(resolved);
99             is.setPublicId(publicId);
100             return is;
101         }
102
103         // Work-around for XML documents that use just the file name for the
104         // location to refer to a JavaEE schema
105         for (String javaEENamespace : JAVA_EE_NAMESPACES) {
106             String javaEESystemId = javaEENamespace + '/' + systemId;
107             resolved = systemIds.get(javaEESystemId);
108             if (resolved != null) {
109                 InputSource is = new InputSource(resolved);
110                 is.setPublicId(publicId);
111                 return is;
112             }
113         }
114
115         // Resolve the supplied systemId against the base
116         URI systemUri;
117         try {
118             if (base == null) {
119                 systemUri = new URI(systemId);
120             } else {
121                 // Can't use URI.resolve() because "jar:..." URLs are not valid
122                 // hierarchical URIs so resolve() does not work. new URL()
123                 // delegates to the jar: stream handler and it manages to figure
124                 // it out.
125                 URI baseUri = new URI(base);
126                 systemUri = new URL(baseUri.toURL(), systemId).toURI();
127             }
128             systemUri = systemUri.normalize();
129         } catch (URISyntaxException e) {
130             // May be caused by a | being used instead of a : in an absolute
131             // file URI on Windows.
132             if (blockExternal) {
133                 // Absolute paths aren't allowed so block it
134                 throw new MalformedURLException(e.getMessage());
135             } else {
136                 // See if the URLHandler can resolve it
137                 return new InputSource(systemId);
138             }
139         }
140         if (systemUri.isAbsolute()) {
141             // Try the resolved systemId
142             resolved = systemIds.get(systemUri.toString());
143             if (resolved != null) {
144                 InputSource is = new InputSource(resolved);
145                 is.setPublicId(publicId);
146                 return is;
147             }
148             if (!blockExternal) {
149                 InputSource is = new InputSource(systemUri.toString());
150                 is.setPublicId(publicId);
151                 return is;
152             }
153         }
154
155         throw new FileNotFoundException(sm.getString("localResolver.unresolvedEntity",
156                 name, publicId, systemId, base));
157     }
158
159
160     @Override
161     public InputSource getExternalSubset(String name, String baseURI)
162             throws SAXException, IOException {
163         return null;
164     }
165 }
166