/hg/icedtea-web: Implemented Codebase manifest entry handling wi...
jvanek at icedtea.classpath.org
jvanek at icedtea.classpath.org
Wed Feb 12 02:10:47 PST 2014
changeset 36a76414e08a in /hg/icedtea-web
details: http://icedtea.classpath.org/hg/icedtea-web?cmd=changeset;node=36a76414e08a
author: Jiri Vanek <jvanek at redhat.com>
date: Wed Feb 12 11:10:29 2014 +0100
Implemented Codebase manifest entry handling with testss.
diffstat:
ChangeLog | 28 +
netx/net/sourceforge/jnlp/JNLPFile.java | 116 +-
netx/net/sourceforge/jnlp/resources/Messages.properties | 8 +
netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java | 58 +-
netx/net/sourceforge/jnlp/util/ClasspathMatcher.java | 375 ++++++
tests/netx/unit/net/sourceforge/jnlp/runtime/JNLPFileTest.java | 169 ++-
tests/netx/unit/net/sourceforge/jnlp/util/ClasspathMatcherTest.java | 559 ++++++++++
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/resources/CodeBaseManifestEntrySignedMatching.html | 48 +
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/resources/CodeBaseManifestEntrySignedMatching.jnlp | 56 +
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/resources/CodeBaseManifestEntrySignedMatchingApplet.jnlp | 61 +
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/resources/CodeBaseManifestEntrySignedMatchingJnlp.html | 46 +
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/srcs/CodeBaseManifestEntrySignedMatching.java | 73 +
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/srcs/META-INF/MANIFEST.MF | 3 +
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/testcases/CodeBaseManifestEntrySignedMatching.java | 193 +++
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/testcases/CodeBaseManifestEntrySignedNotMatching.java | 164 ++
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/testcases/CodeBaseManifestEntryUnsignedMatching.java | 159 ++
tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/testcases/CodeBaseManifestEntryUnsignedNotMatching.java | 161 ++
tests/reproducers/signed/CodeBaseManifestEntrySignedNotMatching/resources/CodeBaseManifestEntrySignedNotMatching.html | 48 +
tests/reproducers/signed/CodeBaseManifestEntrySignedNotMatching/resources/CodeBaseManifestEntrySignedNotMatching.jnlp | 56 +
tests/reproducers/signed/CodeBaseManifestEntrySignedNotMatching/resources/CodeBaseManifestEntrySignedNotMatchingApplet.jnlp | 61 +
tests/reproducers/signed/CodeBaseManifestEntrySignedNotMatching/resources/CodeBaseManifestEntrySignedNotMatchingJnlp.html | 46 +
tests/reproducers/signed/CodeBaseManifestEntrySignedNotMatching/srcs/CodeBaseManifestEntrySignedNotMatching.java | 73 +
tests/reproducers/signed/CodeBaseManifestEntrySignedNotMatching/srcs/META-INF/MANIFEST.MF | 3 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedMatching/resources/CodeBaseManifestEntryUnsignedMatching.html | 48 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedMatching/resources/CodeBaseManifestEntryUnsignedMatching.jnlp | 53 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedMatching/resources/CodeBaseManifestEntryUnsignedMatchingApplet.jnlp | 58 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedMatching/resources/CodeBaseManifestEntryUnsignedMatchingJnlp.html | 46 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedMatching/srcs/CodeBaseManifestEntryUnsignedMatching.java | 73 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedMatching/srcs/META-INF/MANIFEST.MF | 3 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedNotMatching/resources/CodeBaseManifestEntryUnsignedNotMatching.html | 48 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedNotMatching/resources/CodeBaseManifestEntryUnsignedNotMatching.jnlp | 53 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedNotMatching/resources/CodeBaseManifestEntryUnsignedNotMatchingApplet.jnlp | 58 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedNotMatching/resources/CodeBaseManifestEntryUnsignedNotMatchingJnlp.html | 46 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedNotMatching/srcs/CodeBaseManifestEntryUnsignedNotMatching.java | 73 +
tests/reproducers/simple/CodeBaseManifestEntryUnsignedNotMatching/srcs/META-INF/MANIFEST.MF | 3 +
tests/test-extensions/net/sourceforge/jnlp/util/FileTestUtils.java | 4 +-
36 files changed, 3089 insertions(+), 41 deletions(-)
diffs (truncated from 3410 to 500 lines):
diff -r 5909bfb3675f -r 36a76414e08a ChangeLog
--- a/ChangeLog Tue Feb 11 09:20:36 2014 -0500
+++ b/ChangeLog Wed Feb 12 11:10:29 2014 +0100
@@ -1,3 +1,31 @@
+2014-02-12 Jiri Vanek <jvanek at redhat.com>
+
+ Implemented Codebase manifest entry handling.
+ * netx/net/sourceforge/jnlp/JNLPFile.java: manifests names constants moved into
+ ManifestsAttributes inner class.(getCallerAllowableCodebase) (getApplicationLibraryAllowableCodebase)
+ (getCodebase) (getCodeBaseMatchersAttribute) (getCodeBaseMatchersAttribute) are
+ now returning (ClasspathMatcher.ClasspathMatchers). added boolean access to (isTrustedOnly)
+ (isTrustedLibrary).
+ * netx/net/sourceforge/jnlp/resources/Messages.properties: added (CBCheckFile)
+ (CBCheckNoEntry) (CBCheckUnsignedPass) (CBCheckUnsignedPass) (CBCheckOkSignedOk)
+ (CBCheckOkSignedOk) (CBCheckOkSignedOk) keys to inform about Classpath validation
+ * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: in Init call new method
+ (checkCodebaseAttribute) which check the codebase manifest entry.
+ * netx/net/sourceforge/jnlp/util/ClasspathMatcher.java: New class, responsible
+ for matching Classpath like pattern with URL
+ * tests/netx/unit/net/sourceforge/jnlp/runtime/JNLPFileTest.java: added tests to
+ cover all newly accessible attributes from JNLPFile.ManifestsAttributes
+ * tests/netx/unit/net/sourceforge/jnlp/util/ClasspathMatcherTest.java: mostly
+ corner and must-fullfill cases tests.
+ * tests/test-extensions/net/sourceforge/jnlp/util/FileTestUtils.java: (assertNoFileLeak)
+ have timeout before actual countings. JVM needs time to propagate cleanup.
+ * tests/reproducers/signed/CodeBaseManifestEntrySignedMatching/:
+ * tests/reproducers/signed/CodeBaseManifestEntrySignedNotMatching/:
+ * tests/reproducers/simple/CodeBaseManifestEntryUnsignedMatching/:
+ *tests/reproducers/simple/CodeBaseManifestEntryUnsignedNotMatching/:
+ New set of reproducers to test Codebases processing. All testcas are in
+ (CodeBaseManifestEntrySignedMatching) so they can share code.
+
2014-02-11 Andrew Azores <aazores at redhat.com>
Partial revert of 7933143a1286, refactoring to move
diff -r 5909bfb3675f -r 36a76414e08a netx/net/sourceforge/jnlp/JNLPFile.java
--- a/netx/net/sourceforge/jnlp/JNLPFile.java Tue Feb 11 09:20:36 2014 -0500
+++ b/netx/net/sourceforge/jnlp/JNLPFile.java Wed Feb 12 11:10:29 2014 +0100
@@ -33,6 +33,7 @@
import net.sourceforge.jnlp.cache.UpdatePolicy;
import net.sourceforge.jnlp.runtime.JNLPClassLoader;
import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.util.ClasspathMatcher;
import net.sourceforge.jnlp.util.logging.OutputController;
/**
@@ -56,13 +57,7 @@
* @version $Revision: 1.21 $
*/
public class JNLPFile {
-
-
- public static final String APP_NAME = "Application-Name";
- public static final String CALLER_ALLOWABLE = "Caller-Allowable-Codebase";
- public static final String APP_LIBRARY_ALLOWABLE = "Application-Library-Allowable-Codebase";
-
-
+
// todo: save the update policy, then if file was not updated
// then do not check resources for being updated.
@@ -876,10 +871,18 @@
}
- public class ManifestsAttributes{
+ public class ManifestsAttributes {
+
+ public static final String APP_NAME = "Application-Name";
+ public static final String CALLER_ALLOWABLE = "Caller-Allowable-Codebase";
+ public static final String APP_LIBRARY_ALLOWABLE = "Application-Library-Allowable-Codebase";
+ public static final String PERMISSIONS = "Permissions";
+ public static final String CODEBASE = "Codebase";
+ public static final String TRUSTED_ONLY = "Trusted-Only";
+ public static final String TRUSTED_LIBRARY = "Trusted-Library";
private JNLPClassLoader loader;
-
-
+
+
public void setLoader(JNLPClassLoader loader) {
this.loader = loader;
}
@@ -912,34 +915,103 @@
/**
* http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#caller_allowable
*/
- public String getCallerAllowableCodebase(){
- return getAttribute(CALLER_ALLOWABLE);
+ public ClasspathMatcher.ClasspathMatchers getCallerAllowableCodebase() {
+ return getCodeBaseMatchersAttribute(CALLER_ALLOWABLE);
}
/**
* http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#app_library
*/
- public String getApplicationLibraryAllowableCodebase(){
- return getAttribute(APP_LIBRARY_ALLOWABLE);
+ public ClasspathMatcher.ClasspathMatchers getApplicationLibraryAllowableCodebase() {
+ return getCodeBaseMatchersAttribute(APP_LIBRARY_ALLOWABLE);
}
-
+
+ /**
+ * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#codebase
+ */
+ public ClasspathMatcher.ClasspathMatchers getCodebase() {
+ return getCodeBaseMatchersAttribute(CODEBASE);
+ }
+
+ /**
+ * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#trusted_only
+ */
+ public Boolean isTrustedOnly() {
+ return processBooleanAttribute(TRUSTED_ONLY);
+
+ }
+
+ /**
+ * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#trusted_library
+ */
+ public Boolean isTrustedLibrary() {
+ return processBooleanAttribute(TRUSTED_LIBRARY);
+
+ }
+
+ /**
+ * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#permissions
+ */
+ public Boolean isSandboxForced() {
+ String s = getAttribute(PERMISSIONS);
+ if (s == null) {
+ return null;
+ } else if (s.trim().equalsIgnoreCase("sandbox")) {
+ return true;
+ } else if (s.trim().equalsIgnoreCase("all-permissions")) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Unknown value of " + PERMISSIONS + " attribute " + s + ". Expected sandbox or all-permissions");
+ }
+
+
+ }
+
/**
* get custom attribute.
*/
- public String getAttribute(String name){
+ public String getAttribute(String name) {
return getAttribute(new Attributes.Name(name));
}
-
+
/**
* get standard attribute
*/
- public String getAttribute(Attributes.Name name){
- if (loader == null) {
- OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Jars not ready to provide attribute "+ name);
- return null;
+ public String getAttribute(Attributes.Name name) {
+ if (loader == null) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Jars not ready to provide attribute " + name);
+ return null;
}
return loader.checkForAttributeInJars(Arrays.asList(getResources().getJARs()), name);
}
+
+ public ClasspathMatcher.ClasspathMatchers getCodeBaseMatchersAttribute(String s) {
+ return getCodeBaseMatchersAttribute(new Attributes.Name(s));
+ }
+
+ public ClasspathMatcher.ClasspathMatchers getCodeBaseMatchersAttribute(Attributes.Name name) {
+ String s = getAttribute(name);
+ if (s == null) {
+ return null;
+ }
+ return ClasspathMatcher.ClasspathMatchers.compile(s);
+ }
+
+ private Boolean processBooleanAttribute(String id) throws IllegalArgumentException {
+ String s = getAttribute(id);
+ if (s == null) {
+ return null;
+ } else {
+ s = s.trim();
+ if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("false")) {
+ //the Boolean is working like below, thats why the condition
+ //return ((name != null) && name.equalsIgnoreCase("true"));
+ return Boolean.parseBoolean(s);
+ } else {
+ throw new IllegalArgumentException("Unknown value of " + id + " attribute " + s + ". Expected true or false");
+ }
+ }
+ }
}
-
}
+
diff -r 5909bfb3675f -r 36a76414e08a netx/net/sourceforge/jnlp/resources/Messages.properties
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties Tue Feb 11 09:20:36 2014 -0500
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties Wed Feb 12 11:10:29 2014 +0100
@@ -569,6 +569,14 @@
SPLASHmissingInformation = Information element is missing, verify source rather
SPLASHchainWas = This is the list of exceptions that occurred launching your applet. Please note, those exceptions can originate from multiple applets. For a helpful bug report, be sure to run only one applet.
+CBCheckFile = The application is a local file. Codebase validation is disabled. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
+CBCheckNoEntry = This application does not specify a Codebase in its manifest. Please verify with the applet's vendor. Continuing. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
+CBCheckUnsignedPass = Codebase matches codebase manifest attribute, but application is unsigned. Continuing. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
+CBCheckUnsignedFail= The application's codebase does NOT match the codebase specified in its manifest, but the application is unsigned. Continuing. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
+CBCheckOkSignedOk = Codebase matches codebase manifest attribute, and application is signed. Continuing. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
+CBCheckSignedAppletDontMatchException = Signed applets are not allowed to run when their actual Codebase does not match the Codebase specified in their manifest. Expected: {0}. Actual: {1}. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
+CBCheckSignedFail = Application Codebase does NOT match the Codebase specified in the application's manifest, and this application is signed. You are strongly discouraged from running this application. See: http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/security/no_redeploy.html for details.
+
APPEXTSECappletSecurityLevelExtraHighId=Disable running of all Java applets
APPEXTSECappletSecurityLevelVeryHighId=Very High Security
APPEXTSECappletSecurityLevelHighId=High Security
diff -r 5909bfb3675f -r 36a76414e08a netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java Tue Feb 11 09:20:36 2014 -0500
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java Wed Feb 12 11:10:29 2014 +0100
@@ -88,6 +88,7 @@
import net.sourceforge.jnlp.security.appletextendedsecurity.AppletStartupSecuritySettings;
import net.sourceforge.jnlp.security.appletextendedsecurity.UnsignedAppletTrustConfirmation;
import net.sourceforge.jnlp.tools.JarCertVerifier;
+import net.sourceforge.jnlp.util.ClasspathMatcher.ClasspathMatchers;
import net.sourceforge.jnlp.util.JarFile;
import net.sourceforge.jnlp.util.StreamUtils;
import net.sourceforge.jnlp.util.logging.OutputController;
@@ -274,6 +275,8 @@
setSecurity();
+ checkCodebaseAttribute();
+
installShutdownHooks();
@@ -299,15 +302,7 @@
private void setSecurity() throws LaunchException {
- URL codebase = null;
-
- if (file.getCodeBase() != null) {
- codebase = file.getCodeBase();
- } else {
- //Fixme: codebase should be the codebase of the Main Jar not
- //the location. Although, it still works in the current state.
- codebase = file.getResources().getMainJAR().getLocation();
- }
+ URL codebase = guessCodeBase();
/**
* When we're trying to load an applet, file.getSecurity() will return
@@ -2278,6 +2273,51 @@
public String getMainClass() {
return mainClass;
}
+
+ private URL guessCodeBase() {
+ if (file.getCodeBase() != null) {
+ return file.getCodeBase();
+ } else {
+ //Fixme: codebase should be the codebase of the Main Jar not
+ //the location. Although, it still works in the current state.
+ return file.getResources().getMainJAR().getLocation();
+ }
+ }
+
+ /**
+ * http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#codebase
+ */
+ private void checkCodebaseAttribute() throws LaunchException {
+ if (file.getCodeBase() == null || file.getCodeBase().getProtocol().equals("file")) {
+ OutputController.getLogger().log(OutputController.Level.WARNING_ALL, Translator.R("CBCheckFile"));
+ return;
+ }
+ final Object securityType = security.getSecurityType();
+ final URL codebase = guessCodeBase();
+ final ClasspathMatchers codebaseAtt = file.getManifestsAttributes().getCodebase();
+ if (codebaseAtt == null) {
+ OutputController.getLogger().log(OutputController.Level.WARNING_ALL, Translator.R("CBCheckNoEntry"));
+ return;
+ }
+ if (securityType.equals(SecurityDesc.SANDBOX_PERMISSIONS)) {
+ if (codebaseAtt.matches(codebase)) {
+ OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("CBCheckUnsignedPass"));
+ } else {
+ OutputController.getLogger().log(OutputController.Level.ERROR_ALL, Translator.R("CBCheckUnsignedFail"));
+ }
+ } else {
+ if (codebaseAtt.matches(codebase)) {
+ OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("CBCheckOkSignedOk"));
+ } else {
+ if (file instanceof PluginBridge) {
+ throw new LaunchException(Translator.R("CBCheckSignedAppletDontMatchException", file.getManifestsAttributes().getCodebase().toString(), codebase));
+ } else {
+ OutputController.getLogger().log(OutputController.Level.ERROR_ALL, Translator.R("CBCheckSignedFail"));
+ }
+ }
+ }
+
+ }
/*
* Helper class to expose protected URLClassLoader methods.
diff -r 5909bfb3675f -r 36a76414e08a netx/net/sourceforge/jnlp/util/ClasspathMatcher.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/util/ClasspathMatcher.java Wed Feb 12 11:10:29 2014 +0100
@@ -0,0 +1,375 @@
+// Copyright (C) 2013 Red Hat, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+package net.sourceforge.jnlp.util;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+
+public class ClasspathMatcher {
+
+ public static class ClasspathMatchers {
+
+ private final ArrayList<ClasspathMatcher> matchers;
+
+ ArrayList<ClasspathMatcher> getMatchers() {
+ return matchers;
+ }
+
+ /**
+ * space separated list of ClasspathMatcher source strings
+ *
+ * @param s
+ * @return
+ */
+ public static ClasspathMatchers compile(String s) {
+ if (s == null) {
+ return new ClasspathMatchers(new ArrayList<ClasspathMatcher>(0));
+ }
+ String[] splitted = s.trim().split("\\s+");
+ ArrayList<ClasspathMatcher> matchers = new ArrayList<ClasspathMatcher>(splitted.length);
+ for (String string : splitted) {
+ matchers.add(ClasspathMatcher.compile(string.trim()));
+ }
+
+ return new ClasspathMatchers(matchers);
+ }
+
+ public ClasspathMatchers(ArrayList<ClasspathMatcher> matchers) {
+ this.matchers = matchers;
+ }
+
+ public boolean matches(URL s) {
+ return or(s);
+ }
+
+ private boolean or(URL s) {
+ for (ClasspathMatcher classpathMatcher : matchers) {
+ if (classpathMatcher.match(s)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean and(URL s) {
+ for (ClasspathMatcher classpathMatcher : matchers) {
+ if (!classpathMatcher.match(s)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (ClasspathMatcher classpathMatcher : matchers) {
+ sb.append(classpathMatcher.toString()).append(" ");
+ }
+ return sb.toString();
+ }
+ }
+ public static final String PROTOCOL_DELIMITER = "://";
+ public static final String PATH_DELIMITER = "/";
+ public static final String PORT_DELIMITER = ":";
+ private final String source;
+ private Parts parts;
+
+ static class Parts {
+
+ String protocol;
+ String domain;
+ String port;
+ String path;
+ Pattern protocolRegEx;
+ Pattern domainRegEx;
+ Pattern portRegEx;
+ Pattern pathRegEx;
+
+ @Override
+ public String toString() {
+ return protocol + PROTOCOL_DELIMITER + domain + PORT_DELIMITER + port + PATH_DELIMITER + path;
+ }
+
+ public void compilePartsToPatterns() {
+ protocolRegEx = ClasspathMatcher.sourceToRegEx(protocol);
+ //the http://docs.oracle.com/javase/7/docs/technotes/guides/jweb/manifest.html#codebase
+ //clearly says: *.example.com matches both
+ //https://example.com, http://example.com
+ //it sounds like bug, but well, who am I...
+ domainRegEx = domainToRegEx(domain);
+ portRegEx = ClasspathMatcher.sourceToRegEx(port);
+ pathRegEx = ClasspathMatcher.sourceToRegEx(path);
+ }
+
+ private boolean matchDomain(String source) {
+ return generalMatch(source, domainRegEx);
+ }
+
+ private boolean matchProtocol(String source) {
+ return generalMatch(source, protocolRegEx);
+ }
+
+ private boolean matchPath(String source) {
+ if (source.startsWith(PATH_DELIMITER)) {
+ source = source.substring(1);
+ }
+ return generalMatch(source, pathRegEx);
+ }
+
+ private boolean matchPort(int port) {
+ return generalMatch(Integer.toString(port), portRegEx);
+ }
+
+ private static boolean generalMatch(String input, Pattern pattern) {
+ return pattern.matcher(input).matches();
+ }
+
+ private static Pattern domainToRegEx(String domain) {
+ // I have conisdered the "dot" as bug i specification
+ // while (domain.startsWith("*.")) {
+ // domain = "*" + domain.substring(2);
+ //}
+ return ClasspathMatcher.sourceToRegEx(domain);
+ }
+ }
+
+ /**
+ * http://www.w3.org/Addressing/URL/url-spec.txt
+ */
+ private ClasspathMatcher(String source) {
+ this.source = source;
+ }
+
+ Parts getParts() {
+ return parts;
+ }
+
+ @Override
+ public String toString() {
+ return source;
+ }
+
+ public static ClasspathMatcher compile(String source) {
+ ClasspathMatcher r = new ClasspathMatcher(source);
+ r.parts = splitToParts(source);
+ r.parts.compilePartsToPatterns();
+ return r;
+ }
+
+ public boolean match(URL url) {
+ //path is not counted in specification
+ return matchWithoutPath(url);
+ }
+
+ private boolean match(URL url, boolean includePath) {
+ String protocol = url.getProtocol();
+ int port = url.getPort(); //negative if not set
+ String domain = url.getHost();
+ String path = url.getPath();
+ boolean always = parts.matchPort(port)
+ && parts.matchProtocol(protocol)
+ && parts.matchDomain(domain);
+
+ if (includePath) {
+ return always && parts.matchPath(path);
+ } else {
More information about the distro-pkg-dev
mailing list