1+ package org .grails .plugin .resource ;
2+
3+ import java .io .UnsupportedEncodingException ;
4+ import java .net .URI ;
5+ import java .net .URISyntaxException ;
6+ import java .net .URLDecoder ;
7+ import java .util .regex .Pattern ;
8+
9+ /**
10+ * @author Marc Palmer (marc@grailsrocks.com)
11+ */
12+ class URLUtils {
13+
14+ public static Pattern externalURLPattern = Pattern .compile ("^((https?:?)?//).*" );
15+ private static final int MAX_NORMALIZE_ITERATIONS = 3 ;
16+
17+ /**
18+ * Take a base URI and a target URI and resolve target against the base
19+ * using the normal rules e.g. "../x", "./x" "x" results in a link relative to the base's folder
20+ * and / is app-absolute, and anything with a protocol // is absolute
21+ *
22+ * Please note, I take full responsibility for the nastiness of this code. I could not
23+ * find a nice way to do this, and I wanted to find an existing lib to do it. Its
24+ * certainly not my finest moment. Sorry. Rely on the MenuTagTests.
25+ *
26+ * It's quite ugly in there.
27+ */
28+ public static String relativeURI (String base , String target ) {
29+ try {
30+ return new URI (base ).resolve (new URI (target )).normalize ().toString ();
31+ }
32+ catch (URISyntaxException e ) {
33+ throw new RuntimeException (e );
34+ }
35+ }
36+
37+ /**
38+ * Works out if url is relative, such that it would need to be corrected if
39+ * the file containing the url is moved
40+ */
41+ public static Boolean isRelativeURL (String url ) {
42+ return !url .startsWith ("data:" ) &&
43+ !url .startsWith ("#" ) &&
44+ !(url .indexOf ("//" ) >= 0 );
45+ }
46+
47+ public static Boolean isExternalURL (String url ){
48+ if (url == null ) return false ;
49+ return externalURLPattern .matcher (url ).matches ();
50+ }
51+
52+ /**
53+ * Normalizes and decodes uri once.
54+ * Check if result contains \ , /../ , /./ or // after decoding and throws IllegalArgumentException in that case
55+ *
56+ * @param uri
57+ * @return
58+ */
59+ public static String normalizeUri (String uri ) {
60+ String current = uri ;
61+ int counter =0 ;
62+ boolean changed = true ;
63+ // handle double-encoding
64+ while (changed ) {
65+ if (counter ++ > MAX_NORMALIZE_ITERATIONS ) {
66+ throw new IllegalArgumentException ("unable to normalize input uri " + uri );
67+ }
68+ String normalized = doNormalizeUri (current );
69+ changed = (!current .equals (normalized ));
70+ current = normalized ;
71+ }
72+ return current ;
73+ }
74+
75+ private static String doNormalizeUri (String uri ) {
76+ if (uri == null ) return null ;
77+
78+ String normalized = RequestUtil .normalize (uri );
79+ if (normalized == null ) {
80+ throw new IllegalArgumentException ("illegal uri " + uri );
81+ }
82+
83+ String decoded ;
84+ try {
85+ decoded = URLDecoder .decode (normalized , "UTF-8" );
86+ }
87+ catch (UnsupportedEncodingException e ) {
88+ throw new RuntimeException (e );
89+ }
90+ if (decoded .contains ("\\ " ) || decoded .contains ("/./" ) || decoded .contains ("/../" ) || decoded .contains ("//" )) {
91+ throw new IllegalArgumentException ("illegal uri " + uri );
92+ }
93+
94+ return decoded ;
95+ }
96+ }
0 commit comments