Contact: fumanchu@aminus.org

Log in as guest/misc to create tickets

root/urilib.js

Revision 146 (checked in by fumanchu, 2 years ago)

urilib.js: More URI functions.

  • Property svn:eol-style set to native
Line 
1 // This module provides URI parsing and joining as described
2 // in RFC 2396.
3 //
4 // Usage:
5 //   <script src="urilib.js"></script>
6 //   <script type="text/javascript">
7 //     base = urilib.parse('http://www.site.example/path/to/app');
8 //     ref = new urilib.URI('', '', 'thing/5', 'a=1');
9 //     full = urilib.join(base, url);
10 //     alert(full);     // "http://www.site.example/path/to/thing/5?a=1"
11 //   </script>
12
13 var urilib = {};
14
15 urilib.parse_regex = new RegExp(
16     // Scheme
17     "^(?:([a-zA-Z][a-zA-Z0-9+\\-.]*)[:])?" +
18     // Authority
19     "(?://([^/]+))?" +
20     // Path
21     "([^?]+)?" +
22     // Query
23     "([?](.*))?");
24
25 urilib.AbsoluteURIError = function (message) {
26     // Error thrown when relativeURI functions are called on an absoluteURI.
27     this.message = message || "relativeURI functions cannot be called on an absoluteURI";
28 }
29 urilib.AbsoluteURIError.prototype.toString = function () {
30     return 'AbsoluteURIError: "' + this.message + '"';
31 }
32
33 urilib.RelativeURIError = function (message) {
34     // Error thrown when absoluteURI functions are called on a relativeURI.
35     this.message = message || "absoluteURI functions cannot be called on a relativeURI";
36 }
37 urilib.RelativeURIError.prototype.toString = function () {
38     return 'RelativeURIError: "' + this.message + '"';
39 }
40
41 urilib.URI = function (scheme, authority, path, query) {
42     this.scheme = scheme || "";
43     this.authority = authority || "";
44     this.path = path || "";
45     this.query = query || "";
46     return this;
47 };
48
49 urilib.URI.prototype.toString = function () {
50     // 7) The resulting URI components, including any inherited from the
51     // base URI, are recombined to give the absolute form of the URI
52     // reference.
53     var result = "";
54     if (this.scheme != '') result = this.scheme + ":";
55     if (this.authority != '') result = result + "//" + this.authority;
56     result = result + this.path;
57     if (this.query != '') result = result + "?" + this.query;
58     return result;
59 };
60
61 urilib.URI.prototype.is_relative = function () {
62     return (this.path.length > 0 && this.path.charAt(0) != '/');
63 }
64
65 urilib.URI.prototype.net_path = function () {
66     // Return the 'net_path' ("//" authority [ abs_path ]) of this URI.
67     if (this.is_relative()) throw urilib.RelativeURIError();
68     return "//" + this.authority + this.path;
69 };
70
71 urilib.URI.prototype.abs_path = function () {
72     // Return the 'abs_path' ("/" path_segments) of this URI.
73     if (this.is_relative()) throw urilib.RelativeURIError();
74     return this.path;
75 };
76
77 urilib.URI.prototype.rel_path = function () {
78     // Return the 'rel_path' (rel_segment [ abs_path ]) of this URI.
79     if (!this.is_relative()) throw urilib.AbsoluteURIError();
80     return this.path;
81 };
82
83 urilib.URI.prototype.hier_part = function (include_authority) {
84     // Return the 'hier_part' ( net_path | abs_path ) [ "?" query ] of this URI.
85     //
86     // If 'include_authority' is false (the default), returns the
87     // abs_path [+ query] by omitting the authority component.
88     // Otherwise, returns the net_path [+ query] by including the
89     // authority component.
90     if (this.is_relative()) throw urilib.RelativeURIError();
91     var result = include_authority ? this.net_path() : this.path;
92     if (this.query != '') result = result + "?" + this.query;
93     return result;
94 };
95
96 urilib.URI.prototype.server_relative = function () {
97     // Return the 'server relative' ( abs_path | rel_path ) [ "?" query ] form of this URI.
98     var result = this.path;
99     if (this.query != '') result = result + "?" + this.query;
100     return result;
101 };
102
103 urilib.parse = function (uri) {
104     // Return a URI object populated by parsing the given uri string.
105     uri = uri || "";
106     var atoms = urilib.parse_regex.exec(uri);
107     return new urilib.URI(atoms[1], atoms[2], atoms[3], atoms[4]);
108 };
109
110 urilib.normalize = function (path) {
111     // Return 'path', normalized to remove '.' and '<segment>/..' segments.
112     //
113     // 'path' may be either a string or an Array.
114     // The return type will match the input type.
115     var typ = typeof(path);
116     if (typ == 'string') path = path.split("/");
117    
118     // 5c) All occurrences of "./", where "." is a complete path segment,
119     // are removed from the buffer string.
120     // 5d) If the buffer string ends with "." as a complete path segment,
121     // that "." is removed.
122     var pos = 0;
123     while (pos < path.length) {
124         if (path[pos] == '.') {
125             path.splice(pos, 1);
126         } else {
127             pos++;
128         }
129     }
130    
131     // 5e) All occurrences of "<segment>/../", where <segment> is a
132     // complete path segment not equal to "..", are removed from the
133     // buffer string.  Removal of these path segments is performed
134     // iteratively, removing the leftmost matching pattern on each
135     // iteration, until no matching pattern remains.
136     // 5f) If the buffer string ends with "<segment>/..", where <segment>
137     // is a complete path segment not equal to "..", that
138     // "<segment>/.." is removed.
139     pos = 1;
140     while (pos < path.length) {
141         if (pos > 0 && path[pos] == '..' && path[pos - 1] != '..') {
142             path.splice(pos - 1, 2);
143             pos--;
144         } else {
145             pos++;
146         }
147     }
148    
149     // g) If the resulting buffer string still begins with one or more
150     // complete path segments of "..", then the reference is
151     // considered to be in error.
152     if (path.length > 0 && path[0] == '..')
153         throw ("Could not normalize. URI begins with illegal '..' segment." +
154                path.join('/'));
155    
156     if (typ == 'string') path = path.join("/");
157     return path;
158 };
159
160 urilib.join = function (base, ref) {
161     // Return a URI object which combines the two given URI objects.
162     
163     // 1) The URI reference is parsed into the potential four components
164     // and fragment identifier, as described in Section 4.3.
165     if (base.constructor != urilib.URI) base = urilib.parse(base);
166     if (ref.constructor != urilib.URI) ref = urilib.parse(ref);
167    
168     // 2) If the path component is empty and the scheme, authority, and
169     // query components are undefined, then it is a reference to the
170     // current document and we are done.
171     if (ref.path == '' && ref.scheme == '' &&
172         ref.authority == '' && ref.query == '') return base;
173    
174     // 3) If the scheme component is defined, indicating that the reference
175     // starts with a scheme name, then the reference is interpreted as an
176     // absolute URI and we are done.
177     if (ref.scheme != '') return ref;
178    
179     // 2b) Otherwise, the reference URI's
180     // query and fragment components are defined as found (or not found)
181     // within the URI reference and not inherited from the base URI.
182     // 3b) Otherwise, the reference URI's
183     // scheme is inherited from the base URI's scheme component.
184     var newUri = new urilib.URI(base.scheme, "", "", ref.query);
185    
186     // 4) If the authority component is defined, then the reference is a
187     // network-path and we skip to step 7.
188     if (ref.authority == '') {
189         // Otherwise, the reference
190         // URI's authority is inherited from the base URI's authority
191         // component, which will also be undefined if the URI scheme does not
192         // use an authority component.
193         newUri.authority = base.authority;
194        
195         // 5) If the path component begins with a slash character ("/"), then
196         // the reference is an absolute-path and we skip to step 7.
197         if (ref.path.indexOf('/') != 0) {
198             // 6) If this step is reached, then we are resolving a relative-path
199             // reference.  The relative path needs to be merged with the base
200             // URI's path.
201             //
202             // a) All but the last segment of the base URI's path component is
203             // copied to the buffer.  In other words, any characters after the
204             // last (right-most) slash character, if any, are excluded.
205             var buf = base.path;
206             var last_slash = buf.lastIndexOf('/');
207             if (last_slash >= 0) buf = buf.substring(0, last_slash + 1);
208            
209             // b) The reference's path component is appended to the buffer string.
210             buf = buf + ref.path;
211            
212             // c) through g) -- see normalize()
213             // h) The remaining buffer string is the reference URI's new path
214             // component.
215             newUri.path = urilib.normalize(buf);
216         }
217     }
218     return newUri;
219 }
220
Note: See TracBrowser for help on using the browser.