.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "LUA-URI 3" .TH LUA-URI 3 "2012-00-00" "1.1" "Lua uri module" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "Name" .IX Header "Name" lua-uri \- Lua module for manipulating URIs .SH "Loading the module" .IX Header "Loading the module" The \s-1URI\s0 module doesn't alter any global variables when it loads, so you can decide what name you want to use to access it. You will probably want to load it like this: .PP .Vb 1 \& local URI = require "uri" .Ve .PP You can use a variable called something other than \f(CW\*(C`URI\*(C'\fR if you'd like, or you could assign the table returned by \f(CW\*(C`require\*(C'\fR to a global variable. In this documentation we'll assume you're using a variable called \f(CW\*(C`URI\*(C'\fR. .SH "Parsing, validating and normalizing URIs" .IX Header "Parsing, validating and normalizing URIs" When you create a \s-1URI\s0 object, the string you supply is checked to make sure it conforms to the appropriate standards. If everything is \s-1OK,\s0 the new object will be returned, otherwise nil and an error message will be returned. You can convert any errors into Lua exceptions using the \f(CW\*(C`assert\*(C'\fR function. .PP .Vb 1 \& local URI = require "URI" \& \& local uri = assert(URI:new("http://example.com/foo")) \& \& \-\- In this case, these will print the original string. \& \-\- They are both the same. \& print(tostring(uri)) \& print(uri:uri()) .Ve .PP You can extract individual parts of the \s-1URI\s0 with various accessor methods: .PP .Vb 3 \& print(uri:scheme()) \-\- http \& print(uri:host()) \-\- example.com \& print(uri:path()) \-\- /foo .Ve .PP Some URIs will be 'normalized' automatically to produce an equivalent canonical version. Nothing will be changed which would affect how the \&\s-1URI\s0 will be interpreted. For example: .PP .Vb 2 \& local uri = assert(URI:new("HTTP://EXAMPLE.COM:80/FOO")) \& print(tostring(uri)) \-\- http://example.com/FOO .Ve .PP In this case the scheme and hostname were both converted to lowercase (but not the path part, because that's case sensitive). The port number was also removed because port\ 80 is the default anyway for \s-1HTTP\s0 URIs. .PP If you just want to make sure a \s-1URI\s0 is correct, but without throwing an exception, use code like this: .PP .Vb 1 \& local uri, err = URI:new(uri_to_test) \& \& if uri then \& print("valid, normalized to " .. tostring(uri)) \& else \& print("invalid, error message is " .. err) \& end .Ve .PP (Note that many invalid URIs will get processed as relative \s-1URI\s0 references, so if you're expecting an absolute \s-1URI\s0 it's also a good idea to check that the \f(CW\*(C`is_relative\*(C'\fR method returns false.) .SH "Cloning URIs" .IX Header "Cloning URIs" To make a copy of a \s-1URI\s0 object, pass it to the constructor: .PP .Vb 2 \& local original = URI:new("http://www/foo") \& local copy = URI:new(original) .Ve .PP The two objects will contain the same information, but can be changed independently. .SH "Relative URIs" .IX Header "Relative URIs" A relative \s-1URI\s0 reference is not a complete \s-1URI.\s0 It doesn't have a scheme, so it doesn't really mean anything until it is resolved against an absolute \&\s-1URI.\s0 For this reason, when you create a \s-1URI\s0 object from a relative \s-1URI,\s0 it will belong to the special class \f(CW\*(C`uri._relative\*(C'\fR. There is very little you can do with a relative \s-1URI\s0 object other than get and set its path, query string, and fragment identifier. .PP Relative \s-1URI\s0 objects can be created in the same way as absolute ones: .PP .Vb 3 \& local uri = assert(URI:new("../path?query#fragment")) \& print(uri:is_relative()) \-\- true \& print(uri._NAME) \-\- uri._relative .Ve .PP There are two ways to resolve a relative \s-1URI\s0 reference against an absolute \&\s-1URI\s0 to get another absolute \s-1URI.\s0 One is to create a new \s-1URI\s0 object, passing the base \s-1URI\s0 as a second argument to the constructor: .PP .Vb 4 \& local rel = assert(URI:new("../quux.html")) \& local base = assert(URI:new("http://example.com/foo/bar/")) \& local abs = assert(URI:new(rel, base)) \& print(tostring(abs)) \-\- http://example.com/foo/quux.html .Ve .PP You can also do this by passing strings to \f(CW\*(C`new\*(C'\fR, instead of objects: .PP .Vb 3 \& local abs = assert(URI:new("../quux.html", \& "http://example.com/foo/bar/")) \& print(tostring(abs)) \-\- http://example.com/foo/quux.html .Ve .PP Alternatively, a \s-1URI\s0 object containing a relative \s-1URI\s0 can be made absolute without creating a new object using the \f(CW\*(C`resolve\*(C'\fR method: .PP .Vb 4 \& local uri = assert(URI:new("../quux.html")) \& local base = assert(URI:new("http://example.com/foo/bar/")) \& uri:resolve(base) \& print(tostring(uri)) \-\- http://example.com/foo/quux.html .Ve .PP The reverse process can be carried out with the \f(CW\*(C`relativize\*(C'\fR method, creating a relative \s-1URI\s0 from an absolute one, where the relative \s-1URI\s0 can be later resolved against a particular base \s-1URI:\s0 .PP .Vb 4 \& local uri = assert(URI:new("http://example.com/foo/quux.html")) \& local base = assert(URI:new("http://example.com/foo/bar/")) \& uri:relativize(base) \& print(tostring(uri)) \-\- ../quux.html .Ve .PP It is possible for a relative \s-1URI\s0 to have an authority part, although this is very rare in practice. It is unlikely that you'll ever need to do this, but you can create a \s-1URI\s0 like this: .PP .Vb 1 \& local uri = assert(URI:new("//example.com/path")) .Ve .SH "Methods" .IX Header "Methods" This is a complete list of the methods you can call on a generic \f(CW\*(C`URI\*(C'\fR object once created by calling \f(CW\*(C`new\*(C'\fR. Some URIs are created in more specific classes (listed in the \fI\s-1URI\s0 schemes\fR section), which may have additional methods. Arguments shown in square brackets below are optional. .PP Note that all the accessor methods, like \f(CW\*(C`path\*(C'\fR and \f(CW\*(C`uri\*(C'\fR, can be used just to return the current value (if they are called without an argument), or can set a new value while returning the old value. Passing nil as the argument is generally different from not passing an argument at all, or to passing an empty string. .IP "\fBuri:default_port()\fR" 4 .IX Item "uri:default_port()" Returns the default port used for this type of \s-1URI\s0 when no port number is supplied in the authority part. This will be nil if the standard for the \&\s-1URI\s0's current scheme doesn't specify a default port, or if the scheme is one which this library doesn't have any special understanding of. .Sp .Vb 2 \& local uri = assert(URI:new("http://example.com:123/")) \& print(uri:default_port()) \-\- 80 .Ve .IP "uri:eq(other)" 4 .IX Item "uri:eq(other)" Returns true if the two \s-1URI\s0 objects contain the same \s-1URI.\s0 \f(CW\*(C`other\*(C'\fR can also be a string, which will be converted to a \s-1URI\s0 object (in order for the normalization to be done). .Sp This can also be called as a stand-alone function if you don't know whether either \s-1URI\s0 is an object or a string. For example: .Sp .Vb 2 \& print(URI.eq("http://example.com", \& "HTTP://EXAMPLE.COM/")) .Ve .Sp If either value is a string which isn't a valid \s-1URI,\s0 this will throw an exception. It will however accept relative URIs, and they will be compared as normal. A relative \s-1URI\s0 is never equal to an absolute one. .Sp There is no less-than comparison function, as URIs don't have any particular ordering. If you want to sort \s-1URI\s0 objects you're best bet is probably just to compare the string versions: .Sp .Vb 3 \& function urisort (a, b) \& return a:uri() < b:uri() \& end \& \& table.sort(t, urisort) .Ve .IP "uri:fragment([newvalue])" 4 .IX Item "uri:fragment([newvalue])" Returns the current fragment part of the \s-1URI\s0 (the part after the \f(CW\*(C`#\*(C'\fR character), or nil if the \s-1URI\s0 has no fragment part. Note that an empty fragment (zero characters long) is different from one which is completely missing. .Sp If \f(CW\*(C`newvalue\*(C'\fR is supplied, changes the fragment to the new value, percent encoding any characters which would not be valid in a fragment part. Any percent encoding already done on the string will be left in place (not double encoded). If \f(CW\*(C`newvalue\*(C'\fR is nil then any existing fragment will be removed. .Sp The syntax of fragments are meaningful only for particular media types of resources, so there is no special behaviour for different \s-1URI\s0 schemes. .IP "uri:host([newvalue])" 4 .IX Item "uri:host([newvalue])" Get and set the host part of the authority in a \s-1URI.\s0 This can be a domain name, an IPv4 address (four numbers separated by dots), or an IPv6 address (which must include the enclosing square brackets used in URIs). .Sp When setting a new host, the value is normalized to lowercase. An invalid value will cause an exception to be thrown. The value can be an empty string to indicate the default host. .Sp Setting the value to nil will cause the host to be removed altogether, leaving the \s-1URI\s0 with no authority component. This will throw an exception if there is a userinfo or port component in the \s-1URI,\s0 because it is impossible to represent a \s-1URI\s0 with no host when there is an authority component. .Sp Some \s-1URI\s0 schemes may throw an exception when setting the host to nil or the empty string, and others when setting it to anything other than nil, if those schemes require or disallow authority components. .IP "\fBuri:init()\fR" 4 .IX Item "uri:init()" This method is called internally to make a \s-1URI\s0 object belong to the right class and do any scheme-specific validation an normalization. It is only of interest if you want to write a new \f(CW\*(C`uri\*(C'\fR subclass for particular types of URIs. .Sp The implementation in the \f(CW\*(C`uri\*(C'\fR class itself changes the class of the object to the one appropriate to the scheme (if there is a more specific class available). It also removes the port number from the authority component if it is unnecessary because the scheme defines it as the default port. Finally, if there is a more specific class available it calls the \f(CW\*(C`init\*(C'\fR method in that. .Sp \&\f(CW\*(C`init\*(C'\fR is called after the \s-1URI\s0 has been split into components according to the generic syntax, so it can use the accessor methods to get at them. It should return the same values as \f(CW\*(C`new\*(C'\fR, either the new \s-1URI\s0 object (the object it was called on), or nil and an error message. .IP "\fBuri:is_relative()\fR" 4 .IX Item "uri:is_relative()" Returns true if this is a relative \s-1URI\s0 reference, false otherwise. All relative URIs belong to the class \f(CW\*(C`uri._relative\*(C'\fR. All the other \s-1URI\s0 classes are for absolute URIs. .IP "uri:path([newvalue])" 4 .IX Item "uri:path([newvalue])" Get or set the path component of the \s-1URI.\s0 Throws an exception if the new value is not valid in the context of the rest of the \s-1URI.\s0 .Sp .Vb 4 \& local uri = assert(URI:new("http://example.com/foo")) \& local old = uri:path("/bar/") \& print(old) \-\- /foo \& print(uri:path()) \-\- /bar/ .Ve .Sp When a new path value is supplied, it can already be percent encoded, but any characters which aren't allowed are encoded as well. Percent characters are not encoded themselves, because they are assumed to be part of the existing encoding. The existing percent encoding is normalized, and any invalid encoding will cause an exception. .Sp There are certain paths which cannot be expressed in the \s-1URI\s0 syntax. A path which does not start with a \f(CW\*(C`/\*(C'\fR character (unless it's completely empty) cannot be represented when there is an authority component, so this will cause an exception to be thrown. A path which starts with \f(CW\*(C`//\*(C'\fR when there is no authority component would be misinterpreted, so the second slash is percent encoded. .Sp Some \s-1URI\s0 schemes may impose further restrictions on what is allowed in a path, so other path values may cause exceptions in certain cases. .IP "uri:port([newvalue])" 4 .IX Item "uri:port([newvalue])" Get or set the port number in a \s-1URI.\s0 The value returned is always an integer number or nil. .Sp If \f(CW\*(C`newvalue\*(C'\fR is supplied it should be a non-negative integer number, or a string containing only digits, or nil to remove any existing port number. An exception is thrown if it is an invalid value, or if the \s-1URI\s0 scheme doesn't allow port numbers to be specified. If there is currently no authority part in the \s-1URI,\s0 then an empty host will be added to create one. .Sp If the port number is the default for a \s-1URI\s0 scheme (the same as the number returned from the \f(CW\*(C`default_port\*(C'\fR method), then the \f(CW\*(C`port\*(C'\fR method will return that number, but the number won't actually be shown in the \s-1URI\s0 when it is represented as a string, because it would be redundant. Setting the port number to nil has the same effect as setting it to the default port number. .IP "uri:query([newvalue])" 4 .IX Item "uri:query([newvalue])" Get or set the query part of a \s-1URI.\s0 .Sp If \f(CW\*(C`newvalue\*(C'\fR is supplied it should be the new string, or nil to remove any existing query part. The query part can be an empty string, which is different from it not being present at all (the \f(CW\*(C`?\*(C'\fR character will still be included to indicate that there is a query part, even if it is not followed by anything else). Any characters which would not be valid in a query part will be percent encoded, but any percent encoding already done on the string will be left in place (not double encoded). .Sp The base-class implementation of this method never throws exceptions, but some scheme-specific classes may throw exceptions if they impose constraints on the syntax of query parts. .IP "uri:resolve(base)" 4 .IX Item "uri:resolve(base)" Given an object representing a relative \s-1URI,\s0 resolve it against the base \&\s-1URI\s0 \f(CW\*(C`base\*(C'\fR (which can be a \s-1URI\s0 object or string) and update the \f(CW\*(C`uri\*(C'\fR object to contain an absolute \s-1URI.\s0 .Sp Has no effect if \f(CW\*(C`uri\*(C'\fR is already an absolute \s-1URI.\s0 Throws an exception if \f(CW\*(C`base\*(C'\fR is not an absolute \s-1URI,\s0 or if the new \s-1URI\s0 formed by combining them would be invalid for the given scheme. .Sp See also the section \fIRelative URIs\fR and the \f(CW\*(C`uri:relativize(base)\*(C'\fR method. .IP "uri:scheme([newvalue])" 4 .IX Item "uri:scheme([newvalue])" Get and set the scheme of the \s-1URI.\s0 Altering the scheme of an existing \s-1URI\s0 is very unlikely to be useful. .Sp Throws an exception if \f(CW\*(C`newvalue\*(C'\fR is nil or not a valid scheme, or if the rest of the \s-1URI\s0 is not valid when interpreted with the new scheme. After calling this method the class of the object may have been changed, if the old class is not appropriate for the new value. .IP "uri:relativize(base)" 4 .IX Item "uri:relativize(base)" If possible, update the absolute \s-1URI\s0 \f(CW\*(C`uri\*(C'\fR to contain a relative \s-1URI\s0 which, when resolved again against \f(CW\*(C`base\*(C'\fR, will yield the original \s-1URI\s0 value. This doesn't return anything, just modifies the object. .Sp Has no effect if \f(CW\*(C`uri\*(C'\fR is already relative, or if there is no way to create an appropriate relative \s-1URI\s0 (so the \s-1URI\s0 will remain absolute for example if \&\f(CW\*(C`base\*(C'\fR has a different scheme from \f(CW\*(C`uri\*(C'\fR). Throws an exception if \f(CW\*(C`base\*(C'\fR is not absolute. .Sp This method will never result in a network-path reference (a relative \s-1URI\s0 which includes an authority part). In cases where that would be possible the value in \f(CW\*(C`uri\*(C'\fR will be left as an absolute \s-1URI,\s0 which is less likely to cause problems. .Sp See also the section \fIRelative URIs\fR and the \f(CW\*(C`uri:resolve(base)\*(C'\fR method. .IP "uri:uri([newvalue])" 4 .IX Item "uri:uri([newvalue])" Returns the \s-1URI\s0 value as a string. The return value is the same as you'll get from \f(CW\*(C`tostring(uri)\*(C'\fR. .Sp If an argument is supplied, this replaces the \s-1URI\s0 in the \f(CW\*(C`uri\*(C'\fR object with a different one. \f(CW\*(C`newvalue\*(C'\fR must be a complete new \s-1URI\s0 or relative \s-1URI\s0 reference in a string, or a \s-1URI\s0 object. .Sp This is equivalent to creating a new \s-1URI\s0 object by calling \f(CW\*(C`URI:new\*(C'\fR, except that instead of creating a new object the existing object is updated with the new information. It is also not possible to pass a base \s-1URI\s0 to the \f(CW\*(C`uri\*(C'\fR method. .Sp Throws an exception if \f(CW\*(C`newvalue\*(C'\fR is nil or if there is any error in parsing the new \s-1URI\s0 string. After calling this method the class of the object may have been changed, if the old class is not appropriate for the new value. .IP "uri:userinfo([newvalue])" 4 .IX Item "uri:userinfo([newvalue])" Get or set the userinfo part of the \s-1URI.\s0 If \f(CW\*(C`newvalue\*(C'\fR is supplied then it is expected to be percent encoded already. Percent encoding is normalized. An exception will be thrown if the new value is invalid, or if the \s-1URI\s0 scheme does not allow a userinfo part (for example if it is an \s-1HTTP URI\s0). If there is currently no authority part in the \s-1URI,\s0 then an empty host will be added to create one. .Sp If \f(CW\*(C`newvalue\*(C'\fR is nil then any existing userinfo part is removed. .SH "URI schemes" .IX Header "URI schemes" The following Lua modules provide classes which implement extra validation and normalization, or provide extra methods, for URIs which specific schemes: .IP "uri.data" 4 .IX Item "uri.data" .PD 0 .IP "uri.file" 4 .IX Item "uri.file" .IP "uri.ftp" 4 .IX Item "uri.ftp" .IP "uri.http and uri.https" 4 .IX Item "uri.http and uri.https" .IP "uri.pop" 4 .IX Item "uri.pop" .IP "uri.rtsp and uri.rtspu" 4 .IX Item "uri.rtsp and uri.rtspu" .IP "uri.telnet" 4 .IX Item "uri.telnet" .IP "uri.urn" 4 .IX Item "uri.urn" .PD .SH "Other modules" .IX Header "Other modules" Other Lua modules provide additional functionality used in the library, or act as base classes for the scheme-specific classes: .IP "uri._login" 4 .IX Item "uri._login" Baseclass for \s-1URI\s0 schemes which use a username and password in their userinfo part, separated by a colon (for example \s-1FTP\s0). .IP "uri._util" 4 .IX Item "uri._util" Utility functions used by the rest of the library. Contains useful \&\f(CW\*(C`uri_encode\*(C'\fR and \f(CW\*(C`uri_decode\*(C'\fR functions which might be useful elsewhere. .SH "References" .IX Header "References" The parsing of \s-1URI\s0 syntax is based primarily on \*(L"\s-1RFC 3986\*(R"\s0. .SH "Copyright" .IX Header "Copyright" This software and documentation is Copyright (c) 2007 Geoff Richards . It is free software; you can redistribute it and/or modify it under the terms of the Lua\ 5.0 license. The full terms are given in the file \fI\s-1COPYRIGHT\s0\fR supplied with the source code package, and are also available here: .PP An older unreleased version of this library was created as a direct port of the Perl \s-1URI\s0 library, by Gisle Aas and others. It has since been rewritten with a somewhat different design.