View Javadoc
1   /*
2    * Copyright (C) 2006 The Android Open Source Project
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.exoplatform.utils;
18  
19  import static android.util.Patterns.GOOD_IRI_CHAR;
20  
21  import java.util.Locale;
22  import java.util.regex.Matcher;
23  import java.util.regex.Pattern;
24  
25  /**
26   *
27   * Web Address Parser
28   *
29   * This is called WebAddress, rather than URL or URI, because it
30   * attempts to parse the stuff that a user will actually type into a
31   * browser address widget.
32   *
33   * Unlike java.net.uri, this parser will not choke on URIs missing
34   * schemes.  It will only throw a ParseException if the input is
35   * really hosed.
36   *
37   * If given an https scheme but no port, fills in port
38   * 
39   * cf https://github.com/android/platform_frameworks_base/blob/master/core/java/android/net/WebAddress.java
40   *
41   */
42  public class ExoWebAddress {
43    
44    public static class ParseException extends Exception {
45      private static final long serialVersionUID = 1L;
46      
47      public ParseException(String message) {
48        super(message);
49      }
50      
51      public ParseException(String message, Throwable source) {
52        super(message, source);
53      }
54    }
55  
56      private String mScheme;
57      private String mHost;
58      private int mPort;
59      private String mPath;
60      private String mAuthInfo;
61  
62      static final int MATCH_GROUP_SCHEME = 1;
63      static final int MATCH_GROUP_AUTHORITY = 2;
64      static final int MATCH_GROUP_HOST = 3;
65      static final int MATCH_GROUP_PORT = 4;
66      static final int MATCH_GROUP_PATH = 5;
67  
68      static Pattern sAddressPattern = Pattern.compile(
69              /* scheme    */ "(?:(" + ExoConstants.HTTP_PROTOCOL + "|" + ExoConstants.HTTPS_PROTOCOL + ")\\:\\/\\/)?" +
70              /* authority */ "(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
71              /* host      */ "([" + GOOD_IRI_CHAR + "%_-][" + GOOD_IRI_CHAR + "%_\\.-]*|\\[[0-9a-fA-F:\\.]+\\])?" +
72              /* port      */ "(?:\\:([0-9]*))?" +
73              /* path      */ "(\\/?[^#]*)?" +
74              /* anchor    */ ".*", Pattern.CASE_INSENSITIVE);
75  
76      /** parses given uriString. 
77       * @throws ParseException */
78      public ExoWebAddress(String address) throws ParseException {
79          if (address == null) {
80              throw new ParseException("Cannot create ExoWebAddress from null address parameter");
81          }
82  
83          mScheme = "";
84          mHost = "";
85          mPort = -1;
86          mPath = "/";
87          mAuthInfo = "";
88  
89          Matcher m = sAddressPattern.matcher(address);
90          String t;
91          if (m.matches()) {
92              t = m.group(MATCH_GROUP_SCHEME);
93              if (t != null) mScheme = t.toLowerCase(Locale.ROOT);
94              t = m.group(MATCH_GROUP_AUTHORITY);
95              if (t != null) mAuthInfo = t;
96              t = m.group(MATCH_GROUP_HOST);
97              if (t != null) mHost = t;
98              t = m.group(MATCH_GROUP_PORT);
99              if (t != null && t.length() > 0) {
100                 // The ':' character is not returned by the regex.
101                 try {
102                     mPort = Integer.parseInt(t);
103                 } catch (NumberFormatException ex) {
104                     throw new ParseException("Incorrect port number", ex);
105                 }
106             }
107             t = m.group(MATCH_GROUP_PATH);
108             if (t != null && t.length() > 0) {
109                 /* handle busted myspace frontpage redirect with
110                    missing initial "/" */
111                 if (t.charAt(0) == '/') {
112                     mPath = t;
113                 } else {
114                     mPath = "/" + t;
115                 }
116             }
117 
118         } else {
119             // nothing found... outa here
120             throw new ParseException("Incorrect address");
121         }
122 
123         if ("".equals(mScheme)) mScheme = ExoConstants.HTTP_PROTOCOL;
124     }
125 
126     @Override
127     public String toString() {
128         String port = "";
129 
130         if (mPort != -1 &&
131             ((mPort != 443 && mScheme.equals(ExoConstants.HTTPS_PROTOCOL)) ||
132              (mPort != 80 && mScheme.equals(ExoConstants.HTTP_PROTOCOL))
133             )) {
134             port = ":" + Integer.toString(mPort);
135         }
136         String authInfo = "";
137         if (mAuthInfo.length() > 0) {
138             authInfo = mAuthInfo + "@";
139         }
140 
141         return mScheme + "://" + authInfo + mHost + port + mPath;
142     }
143 
144     public void setScheme(String scheme) {
145       mScheme = scheme;
146     }
147 
148     public String getScheme() {
149       return mScheme;
150     }
151 
152     public void setHost(String host) {
153       mHost = host;
154     }
155 
156     public String getHost() {
157       return mHost;
158     }
159 
160     public void setPort(int port) {
161       mPort = port;
162     }
163 
164     public int getPort() {
165       return mPort;
166     }
167 
168     public void setPath(String path) {
169       mPath = path;
170     }
171 
172     public String getPath() {
173       return mPath;
174     }
175 
176     public void setAuthInfo(String authInfo) {
177       mAuthInfo = authInfo;
178     }
179 
180     public String getAuthInfo() {
181       return mAuthInfo;
182     }
183     
184     /**
185      * @return true if this address has an empty host, false otherwise
186      */
187     public boolean isRelativeURL() {
188       return "".equals(mHost);
189     }
190 }