View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package javax.mail;
21  
22  import java.io.ByteArrayOutputStream;
23  import java.net.MalformedURLException;
24  import java.net.URI;
25  import java.net.URISyntaxException;
26  import java.net.URL;
27  
28  /**
29   * @version $Rev: 593290 $ $Date: 2007-11-08 15:18:29 -0500 (Thu, 08 Nov 2007) $
30   */
31  public class URLName {
32      private static final String nonEncodedChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-.*";
33      
34      private String file;
35      private String host;
36      private String password;
37      private int port;
38      private String protocol;
39      private String ref;
40      private String username;
41      protected String fullURL;
42      private int hashCode;
43  
44      public URLName(String url) {
45          parseString(url);
46      }
47  
48      protected void parseString(String url) {
49          URI uri;
50          try {
51              if (url == null) {
52                  uri = null;
53              } else {
54                  uri = new URI(url);
55              }
56          } catch (URISyntaxException e) {
57              uri = null;
58          }
59          if (uri == null) {
60              protocol = null;
61              host = null;
62              port = -1;
63              file = null;
64              ref = null;
65              username = null;
66              password = null;
67              return;
68          }
69  
70          protocol = checkBlank(uri.getScheme());
71          host = checkBlank(uri.getHost());
72          port = uri.getPort();
73          file = checkBlank(uri.getPath());
74          // if the file starts with "/", we need to strip that off. 
75          // URL and URLName do not have the same behavior when it comes 
76          // to keeping that there. 
77          if (file != null && file.length() > 1 && file.startsWith("/")) {
78              file = checkBlank(file.substring(1)); 
79          }
80          
81          ref = checkBlank(uri.getFragment());
82          String userInfo = checkBlank(uri.getUserInfo());
83          if (userInfo == null) {
84              username = null;
85              password = null;
86          } else {
87              int pos = userInfo.indexOf(':');
88              if (pos == -1) {
89                  username = userInfo;
90                  password = null;
91              } else {
92                  username = userInfo.substring(0, pos);
93                  password = userInfo.substring(pos + 1);
94              }
95          }
96          updateFullURL();
97      }
98  
99      public URLName(String protocol, String host, int port, String file, String username, String password) {
100         this.protocol = checkBlank(protocol);
101         this.host = checkBlank(host);
102         this.port = port;
103         if (file == null || file.length() == 0) {
104             this.file = null;
105             ref = null;
106         } else {
107             int pos = file.indexOf('#');
108             if (pos == -1) {
109                 this.file = file;
110                 ref = null;
111             } else {
112                 this.file = file.substring(0, pos);
113                 ref = file.substring(pos + 1);
114             }
115         }
116         this.username = checkBlank(username);
117         if (this.username != null) {
118             this.password = checkBlank(password);
119         } else {
120             this.password = null;
121         }
122         username = encode(username); 
123         password = encode(password); 
124         updateFullURL();
125     }
126 
127     public URLName(URL url) {
128         protocol = checkBlank(url.getProtocol());
129         host = checkBlank(url.getHost());
130         port = url.getPort();
131         file = checkBlank(url.getFile());
132         ref = checkBlank(url.getRef());
133         String userInfo = checkBlank(url.getUserInfo());
134         if (userInfo == null) {
135             username = null;
136             password = null;
137         } else {
138             int pos = userInfo.indexOf(':');
139             if (pos == -1) {
140                 username = userInfo;
141                 password = null;
142             } else {
143                 username = userInfo.substring(0, pos);
144                 password = userInfo.substring(pos + 1);
145             }
146         }
147         updateFullURL();
148     }
149 
150     private static String checkBlank(String target) {
151         if (target == null || target.length() == 0) {
152             return null;
153         } else {
154             return target;
155         }
156     }
157 
158     private void updateFullURL() {
159         hashCode = 0;
160         StringBuffer buf = new StringBuffer(100);
161         if (protocol != null) {
162             buf.append(protocol).append(':');
163             if (host != null) {
164                 buf.append("//");
165                 if (username != null) {
166                     buf.append(encode(username));
167                     if (password != null) {
168                         buf.append(':').append(encode(password));
169                     }
170                     buf.append('@');
171                 }
172                 buf.append(host);
173                 if (port != -1) {
174                     buf.append(':').append(port);
175                 }
176                 if (file != null) {
177                     buf.append('/').append(file);
178                 }
179                 hashCode = buf.toString().hashCode();
180                 if (ref != null) {
181                     buf.append('#').append(ref);
182                 }
183             }
184         }
185         fullURL = buf.toString();
186     }
187 
188     public boolean equals(Object o) {
189         if (o instanceof URLName == false) {
190             return false;
191         }
192         URLName other = (URLName) o;
193         // check same protocol - false if either is null
194         if (protocol == null || other.protocol == null || !protocol.equals(other.protocol)) {
195             return false;
196         }
197 
198         if (port != other.port) {
199             return false;
200         }
201 
202         // check host - false if not (both null or both equal)
203         return areSame(host, other.host) && areSame(file, other.file) && areSame(username, other.username) && areSame(password, other.password);
204     }
205 
206     private static boolean areSame(String s1, String s2) {
207         if (s1 == null) {
208             return s2 == null;
209         } else {
210             return s1.equals(s2);
211         }
212     }
213 
214     public int hashCode() {
215         return hashCode;
216     }
217 
218     public String toString() {
219         return fullURL;
220     }
221 
222     public String getFile() {
223         return file;
224     }
225 
226     public String getHost() {
227         return host;
228     }
229 
230     public String getPassword() {
231         return password;
232     }
233 
234     public int getPort() {
235         return port;
236     }
237 
238     public String getProtocol() {
239         return protocol;
240     }
241 
242     public String getRef() {
243         return ref;
244     }
245 
246     public URL getURL() throws MalformedURLException {
247         return new URL(fullURL);
248     }
249 
250     public String getUsername() {
251         return username;
252     }
253     
254     /**
255      * Perform an HTTP encoding to the username and 
256      * password elements of the URLName.  
257      * 
258      * @param v      The input (uncoded) string.
259      * 
260      * @return The HTTP encoded version of the string. 
261      */
262     private static String encode(String v) {
263         // make sure we don't operate on a null string
264         if (v == null) {
265             return null; 
266         }
267         boolean needsEncoding = false; 
268         for (int i = 0; i < v.length(); i++) {
269             // not in the list of things that don't need encoding?
270             if (nonEncodedChars.indexOf(v.charAt(i)) == -1) {
271                 // got to do this the hard way
272                 needsEncoding = true; 
273                 break; 
274             }
275         }
276         // just fine the way it is. 
277         if (!needsEncoding) {
278             return v; 
279         }
280         
281         // we know we're going to be larger, but not sure by how much.  
282         // just give a little extra
283         StringBuffer encoded = new StringBuffer(v.length() + 10);
284             
285         // we get the bytes so that we can have the default encoding applied to 
286         // this string.  This will flag the ones we need to give special processing to. 
287         byte[] data = v.getBytes(); 
288         
289         for (int i = 0; i < data.length; i++) {
290             // pick this up as a one-byte character The 7-bit ascii ones will be fine 
291             // here. 
292             char ch = (char)(data[i] & 0xff); 
293             // blanks get special treatment 
294             if (ch == ' ') {
295                 encoded.append('+'); 
296             }
297             // not in the list of things that don't need encoding?
298             else if (nonEncodedChars.indexOf(ch) == -1) {
299                 // forDigit() uses the lowercase letters for the radix.  The HTML specifications 
300                 // require the uppercase letters. 
301                 char firstChar = Character.toUpperCase(Character.forDigit((ch >> 4) & 0xf, 16)); 
302                 char secondChar = Character.toUpperCase(Character.forDigit(ch & 0xf, 16)); 
303                 
304                 // now append the encoded triplet. 
305                 encoded.append('%'); 
306                 encoded.append(firstChar); 
307                 encoded.append(secondChar); 
308             }
309             else {
310                 // just add this one to the buffer 
311                 encoded.append(ch); 
312             }
313         }
314         // convert to string form. 
315         return encoded.toString(); 
316     }
317 }