lua-uri-mainline/0000755000175000017500000000000012221047713013257 5ustar vsevavsevalua-uri-mainline/Changes0000644000175000017500000000030412002272735014550 0ustar vsevavseva1.1 2012-00-00 * Fix accidental setting of global variable 'err' in 'uri.ftp' and 'uri.telnet'. * Switch test suite from Lunit 0.3 to Lunit 0.5. 1.0 2007-11-30 * Initial release. lua-uri-mainline/uri.lua0000644000175000017500000003620312002272735014566 0ustar vsevavsevalocal M = { _NAME = "uri", VERSION = "1.0" } M.__index = M local Util = require "uri._util" local _UNRESERVED = "A-Za-z0-9%-._~" local _GEN_DELIMS = ":/?#%[%]@" local _SUB_DELIMS = "!$&'()*+,;=" local _RESERVED = _GEN_DELIMS .. _SUB_DELIMS local _USERINFO = "^[" .. _UNRESERVED .. "%%" .. _SUB_DELIMS .. ":]*$" local _REG_NAME = "^[" .. _UNRESERVED .. "%%" .. _SUB_DELIMS .. "]*$" local _IP_FUTURE_LITERAL = "^v[0-9A-Fa-f]+%." .. "[" .. _UNRESERVED .. _SUB_DELIMS .. "]+$" local _QUERY_OR_FRAG = "^[" .. _UNRESERVED .. "%%" .. _SUB_DELIMS .. ":@/?]*$" local _PATH_CHARS = "^[" .. _UNRESERVED .. "%%" .. _SUB_DELIMS .. ":@/]*$" local function _normalize_percent_encoding (s) if s:find("%%$") or s:find("%%.$") then error("unfinished percent encoding at end of URI '" .. s .. "'", 3) end return s:gsub("%%(..)", function (hex) if not hex:find("^[0-9A-Fa-f][0-9A-Fa-f]$") then error("invalid percent encoding '%" .. hex .. "' in URI '" .. s .. "'", 5) end -- Never percent-encode unreserved characters, and always use uppercase -- hexadecimal for percent encoding. RFC 3986 section 6.2.2.2. local char = string.char(tonumber("0x" .. hex)) return char:find("^[" .. _UNRESERVED .. "]") and char or "%" .. hex:upper() end) end local function _is_ip4_literal (s) if not s:find("^[0-9]+%.[0-9]+%.[0-9]+%.[0-9]+$") then return false end for dec_octet in s:gmatch("[0-9]+") do if dec_octet:len() > 3 or dec_octet:find("^0.") or tonumber(dec_octet) > 255 then return false end end return true end local function _is_ip6_literal (s) local had_elipsis = false -- true when '::' found local num_chunks = 0 while s ~= "" do num_chunks = num_chunks + 1 local p1, p2 = s:find("::?") local chunk if p1 then chunk = s:sub(1, p1 - 1) s = s:sub(p2 + 1) if p2 ~= p1 then -- found '::' if had_elipsis then return false end -- two of '::' had_elipsis = true if chunk == "" then num_chunks = num_chunks - 1 end else if chunk == "" then return false end -- ':' at start if s == "" then return false end -- ':' at end end else chunk = s s = "" end -- Chunk is neither 4-digit hex num, nor IPv4address in last chunk. if (not chunk:find("^[0-9a-f]+$") or chunk:len() > 4) and (s ~= "" or not _is_ip4_literal(chunk)) and chunk ~= "" then return false end -- IPv4address in last position counts for two chunks of hex digits. if chunk:len() > 4 then num_chunks = num_chunks + 1 end end if had_elipsis then if num_chunks > 7 then return false end else if num_chunks ~= 8 then return false end end return true end local function _is_valid_host (host) if host:find("^%[.*%]$") then local ip_literal = host:sub(2, -2) if ip_literal:find("^v") then if not ip_literal:find(_IP_FUTURE_LITERAL) then return "invalid IPvFuture literal '" .. ip_literal .. "'" end else if not _is_ip6_literal(ip_literal) then return "invalid IPv6 address '" .. ip_literal .. "'" end end elseif not _is_ip4_literal(host) and not host:find(_REG_NAME) then return "invalid host value '" .. host .. "'" end return nil end local function _normalize_and_check_path (s, normalize) if not s:find(_PATH_CHARS) then return false end if not normalize then return s end -- Remove unnecessary percent encoding for path values. -- TODO - I think this should be HTTP-specific (probably file also). --s = Util.uri_decode(s, _SUB_DELIMS .. ":@") return Util.remove_dot_segments(s) end function M.new (class, uri, base) if not class or not uri then error("usage: URI:new(uristring, [baseuri])", 2) end if type(uri) ~= "string" then uri = tostring(uri) end if base then local uri, err = M.new(class, uri) if not uri then return nil, err end if type(base) ~= "table" then base, err = M.new(class, base) if not base then return nil, "error parsing base URI: " .. err end end if base:is_relative() then return nil, "base URI must be absolute" end local ok, err = pcall(uri.resolve, uri, base) if not ok then return nil, err end return uri end local s = _normalize_percent_encoding(uri) local _, p local scheme, authority, userinfo, host, port, path, query, fragment _, p, scheme = s:find("^([a-zA-Z][-+.a-zA-Z0-9]*):") if scheme then scheme = scheme:lower() s = s:sub(p + 1) end _, p, authority = s:find("^//([^/?#]*)") if authority then s = s:sub(p + 1) _, p, userinfo = authority:find("^([^@]*)@") if userinfo then if not userinfo:find(_USERINFO) then return nil, "invalid userinfo value '" .. userinfo .. "'" end authority = authority:sub(p + 1) end p, _, port = authority:find(":([0-9]*)$") if port then port = (port ~= "") and tonumber(port) or nil authority = authority:sub(1, p - 1) end host = authority:lower() local err = _is_valid_host(host) if err then return nil, err end end _, p, path = s:find("^([^?#]*)") if path ~= "" then local normpath = _normalize_and_check_path(path, scheme) if not normpath then return nil, "invalid path '" .. path .. "'" end path = normpath s = s:sub(p + 1) end _, p, query = s:find("^%?([^#]*)") if query then s = s:sub(p + 1) if not query:find(_QUERY_OR_FRAG) then return nil, "invalid query value '?" .. query .. "'" end end _, p, fragment = s:find("^#(.*)") if fragment then if not fragment:find(_QUERY_OR_FRAG) then return nil, "invalid fragment value '#" .. fragment .. "'" end end local o = { _scheme = scheme, _userinfo = userinfo, _host = host, _port = port, _path = path, _query = query, _fragment = fragment, } setmetatable(o, scheme and class or (require "uri._relative")) return o:init() end function M.uri (self, ...) local uri = self._uri if not uri then local scheme = self:scheme() if scheme then uri = scheme .. ":" else uri = "" end local host, port, userinfo = self:host(), self._port, self:userinfo() if host or port or userinfo then uri = uri .. "//" if userinfo then uri = uri .. userinfo .. "@" end if host then uri = uri .. host end if port then uri = uri .. ":" .. port end end local path = self:path() if uri == "" and path:find("^[^/]*:") then path = "./" .. path end uri = uri .. path if self:query() then uri = uri .. "?" .. self:query() end if self:fragment() then uri = uri .. "#" .. self:fragment() end self._uri = uri -- cache end if select("#", ...) > 0 then local new = ... if not new then error("URI can't be set to nil", 2) end local newuri, err = M:new(new) if not newuri then error("new URI string is invalid (" .. err .. ")", 2) end setmetatable(self, getmetatable(newuri)) for k in pairs(self) do self[k] = nil end for k, v in pairs(newuri) do self[k] = v end end return uri end function M.__tostring (self) return self:uri() end function M.eq (a, b) if type(a) == "string" then a = assert(M:new(a)) end if type(b) == "string" then b = assert(M:new(b)) end return a:uri() == b:uri() end function M.scheme (self, ...) local old = self._scheme if select("#", ...) > 0 then local new = ... if not new then error("can't remove scheme from absolute URI", 2) end if type(new) ~= "string" then new = tostring(new) end if not new:find("^[a-zA-Z][-+.a-zA-Z0-9]*$") then error("invalid scheme '" .. new .. "'", 2) end Util.do_class_changing_change(self, M, "scheme", new, function (uri, new) uri._scheme = new end) end return old end function M.userinfo (self, ...) local old = self._userinfo if select("#", ...) > 0 then local new = ... if new then if not new:find(_USERINFO) then error("invalid userinfo value '" .. new .. "'", 2) end new = _normalize_percent_encoding(new) end self._userinfo = new if new and not self._host then self._host = "" end self._uri = nil end return old end function M.host (self, ...) local old = self._host if select("#", ...) > 0 then local new = ... if new then new = tostring(new):lower() local err = _is_valid_host(new) if err then error(err, 2) end else if self._userinfo or self._port then error("there must be a host if there is a userinfo or port," .. " although it can be the empty string", 2) end end self._host = new self._uri = nil end return old end function M.port (self, ...) local old = self._port or self:default_port() if select("#", ...) > 0 then local new = ... if new then if type(new) == "string" then new = tonumber(new) end if not new then error("port number must be a number", 2) end if new < 0 then error("port number must not be negative", 2) end local newint = new - new % 1 if newint ~= new then error("port number not integer", 2) end if new == self:default_port() then new = nil end end self._port = new if new and not self._host then self._host = "" end self._uri = nil end return old end function M.path (self, ...) local old = self._path if select("#", ...) > 0 then local new = ... or "" new = _normalize_percent_encoding(new) new = Util.uri_encode(new, "^A-Za-z0-9%-._~%%!$&'()*+,;=:@/") if self._host then if new ~= "" and not new:find("^/") then error("path must begin with '/' when there is an authority", 2) end else if new:find("^//") then new = "/%2F" .. new:sub(3) end end self._path = new self._uri = nil end return old end function M.query (self, ...) local old = self._query if select("#", ...) > 0 then local new = ... if new then new = Util.uri_encode(new, "^" .. _UNRESERVED .. "%%" .. _SUB_DELIMS .. ":@/?") end self._query = new self._uri = nil end return old end function M.fragment (self, ...) local old = self._fragment if select("#", ...) > 0 then local new = ... if new then new = Util.uri_encode(new, "^" .. _UNRESERVED .. "%%" .. _SUB_DELIMS .. ":@/?") end self._fragment = new self._uri = nil end return old end function M.init (self) local scheme_class = Util.attempt_require("uri." .. self._scheme:gsub("[-+.]", "_")) if scheme_class then setmetatable(self, scheme_class) if self._port and self._port == self:default_port() then self._port = nil end -- Call the subclass 'init' method, if it has its own. if scheme_class ~= M and self.init ~= M.init then return self:init() end end return self end function M.default_port () return nil end function M.is_relative () return false end function M.resolve () end -- only does anything in uri._relative -- TODO - there should probably be an option or something allowing you to -- choose between making a link relative whenever possible (always using a -- relative path if the scheme and authority are the same as the base URI) or -- just using a relative reference to make the link as small as possible, which -- might meaning using a path of '/' instead if '../../../' or whatever. -- This method's algorithm is loosely based on the one described here: -- http://lists.w3.org/Archives/Public/uri/2007Sep/0003.html function M.relativize (self, base) if type(base) == "string" then base = assert(M:new(base)) end -- Leave it alone if we can't a relative URI, or if it would be a network -- path reference. if self._scheme ~= base._scheme or self._host ~= base._host or self._port ~= base._port or self._userinfo ~= base._userinfo then return end local basepath = base._path local oldpath = self._path -- This is to avoid trying to make a URN or something relative, which -- is likely to lead to grief. if not basepath:find("^/") or not oldpath:find("^/") then return end -- Turn it into a relative reference. self._uri = nil self._scheme = nil self._host = nil self._port = nil self._userinfo = nil setmetatable(self, require "uri._relative") -- Use empty path if the path in the base URI is already correct. if oldpath == basepath then if self._query or not base._query then self._path = "" else -- An empty URI reference leaves the query string in the base URI -- unchanged, so to get a result with no query part we have to -- have something in the relative path. local _, _, lastseg = oldpath:find("/([^/]+)$") if lastseg and lastseg:find(":") then lastseg = "./" .. lastseg end self._path = lastseg or "." end return end if oldpath == "/" or basepath == "/" then return end local basesegs = Util.split("/", basepath:sub(2)) local oldsegs = Util.split("/", oldpath:sub(2)) if oldsegs[1] ~= basesegs[1] then return end table.remove(basesegs) while #oldsegs > 1 and #basesegs > 0 and oldsegs[1] == basesegs[1] do table.remove(oldsegs, 1) table.remove(basesegs, 1) end local path_naked = true local newpath = "" while #basesegs > 0 do table.remove(basesegs, 1) newpath = newpath .. "../" path_naked = false end if path_naked and #oldsegs == 1 and oldsegs[1] == "" then newpath = "./" table.remove(oldsegs) end while #oldsegs > 0 do if path_naked then if oldsegs[1]:find(":") then newpath = newpath .. "./" elseif #oldsegs > 1 and oldsegs[1] == "" and oldsegs[2] == "" then newpath = newpath .. "/." end end newpath = newpath .. oldsegs[1] path_naked = false table.remove(oldsegs, 1) if #oldsegs > 0 then newpath = newpath .. "/" end end self._path = newpath end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/TODO0000644000175000017500000000357612002272735013763 0ustar vsevavsevaPerhaps incorporate Mozilla test suite for data: URIs: http://www.mozilla.org/quality/networking/testing/datatests.html also validate the mediatype part and normalize it by omitting things which will be the same by default. Check for compliance with latest RFC: http://tools.ietf.org/html/rfc3986 (uri_encode might use the wrong default for 'patn') Try to integrate support for IRIs: http://tools.ietf.org/html/rfc3987 Other schemes: complete IANA list: http://www.iana.org/assignments/uri-schemes.html opaquelocktoken - http://www.rfc-editor.org/rfc/rfc4918.txt (Appendix C) svn mailto - http://tools.ietf.org/html/rfc2368 info - http://tools.ietf.org/html/rfc4452 prospero - http://tools.ietf.org/html/rfc4157 wais - http://tools.ietf.org/html/rfc4156 tel - http://tools.ietf.org/html/rfc3966 sip and sips - http://tools.ietf.org/html/rfc3261 gopher - http://tools.ietf.org/html/rfc4266 tag - http://tools.ietf.org/html/rfc4151 new IMAP URI RFC: http://www.rfc-editor.org/rfc/rfc5092.txt Other NIDs for URNs, some of which are shown here: http://en.wikipedia.org/wiki/Uniform_Resource_Name Other NIDs which have RFCs: ietf - http://tools.ietf.org/html/rfc2648 publicid - http://tools.ietf.org/html/rfc3151 uuid - http://tools.ietf.org/html/rfc4122 sici - http://tools.ietf.org/html/rfc2288 (not really standardised there, but is there a proper RFC?) service - http://tools.ietf.org/html/rfc5031 epc - http://tools.ietf.org/html/rfc5134 check these CPAN bugs against URI module: mailto encoding: http://rt.cpan.org/Public/Bug/Display.html?id=24934 encode: http://rt.cpan.org/Public/Bug/Display.html?id=21640 gopher URI found in the wild, use for testing: Once again provide the stripping of '' and such like. See if this API has any good ideas: http://addressable.rubyforge.org/api/ lua-uri-mainline/doc/0000755000175000017500000000000012002272735014025 5ustar vsevavsevalua-uri-mainline/doc/lua-uri-telnet.pod0000644000175000017500000000132212002272735017376 0ustar vsevavseva=head1 Name lua-uri-telnet - Telnet URI support for Lua URI library =head1 Description The class C is used for URIs with the C scheme. It inherits from the L class. Telnet URIs are not allowed to have any information in their path part, because there isn't any specification defining what it would mean. An empty path or a path of '/' is acceptable, and normalized to '/'. Any other path is considered invalid. The default port for telnet URIs S. There are no extra methods defined for telnet URIs, only those described in L and L. =head1 References This class is based on L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-data.pod0000644000175000017500000000453012002272735017020 0ustar vsevavseva=head1 Name lua-uri-data - data URI support for Lua URI library =head1 Description The class C is used for URIs with the C scheme. It inherits from the L class. Some of the features of this module require the L library to be installed, but URI objects can still be created from C URIs even if it isn't available. Any C URI containing an authority part is considered to be invalid, as is one whose path does not contain a comma. If the URI has the C<;base64> parameter, then the data must consist only of characters allowed in base64 encoded data (upper and lowercase ASCII letters, digits, and the forward slash and plus characters). =head1 Methods All the methods defined in L are supported. The C, C, and C methods will always return nil, and will throw an exception when passed anything other than nil. The C method will throw an exception if given a new path which is nil or not valid for the C scheme. The following additional methods are supported: =over =item uri:data_bytes(...) Get or set the data stored in the URI. The existing data is decoded and returned. If a new value is supplied it must be a string, and will cause the path of the URI to be changed to encode the new data. The method will choose the encoding which will result in the smallest URI, unless the datafilter module is not installed, in which case it will always use percent encoding. An exception is thrown if the datafilter module is not installed and the data in the URI is encoded as base64, although a data URI using percent encoding will not cause an exception. The data passed in and returned should not be encoded in any special way, that is taken care of by the library. =item uri:data_media_type(...) Get or set the media type (MIME type) stored in the URI's path before the comma. This should not include the C<;base64> parameter, which will be included in the path automatically when appropriate. If there is no media type given in the URI then the default value of C will be returned, and if there is no C parameter given then the default C<;charset=US-ASCII> will be included. The media type is encoded and decoded automatically by this method. =back =head1 References This class is based on L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri.pod0000644000175000017500000004204612002272735016115 0ustar vsevavseva=head1 Name lua-uri - Lua module for manipulating URIs =head1 Loading the module The URI 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: =for syntax-highlight lua local URI = require "uri" You can use a variable called something other than C if you'd like, or you could assign the table returned by C to a global variable. In this documentation we'll assume you're using a variable called C. =head1 Parsing, validating and normalizing URIs When you create a URI object, the string you supply is checked to make sure it conforms to the appropriate standards. If everything is OK, 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 C function. =for syntax-highlight lua 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()) You can extract individual parts of the URI with various accessor methods: =for syntax-highlight lua print(uri:scheme()) -- http print(uri:host()) -- example.com print(uri:path()) -- /foo Some URIs will be 'normalized' automatically to produce an equivalent canonical version. Nothing will be changed which would affect how the URI will be interpreted. For example: =for syntax-highlight lua local uri = assert(URI:new("HTTP://EXAMPLE.COM:80/FOO")) print(tostring(uri)) -- http://example.com/FOO 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 S is the default anyway for HTTP URIs. If you just want to make sure a URI is correct, but without throwing an exception, use code like this: =for syntax-highlight lua 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 (Note that many invalid URIs will get processed as relative URI references, so if you're expecting an absolute URI it's also a good idea to check that the C method returns false.) =head1 Cloning URIs To make a copy of a URI object, pass it to the constructor: =for syntax-highlight lua local original = URI:new("http://www/foo") local copy = URI:new(original) The two objects will contain the same information, but can be changed independently. =head1 Relative URIs A relative URI reference is not a complete URI. It doesn't have a scheme, so it doesn't really mean anything until it is resolved against an absolute URI. For this reason, when you create a URI object from a relative URI, it will belong to the special class C. There is very little you can do with a relative URI object other than get and set its path, query string, and fragment identifier. Relative URI objects can be created in the same way as absolute ones: =for syntax-highlight lua local uri = assert(URI:new("../path?query#fragment")) print(uri:is_relative()) -- true print(uri._NAME) -- uri._relative There are two ways to resolve a relative URI reference against an absolute URI to get another absolute URI. One is to create a new URI object, passing the base URI as a second argument to the constructor: =for syntax-highlight lua 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 You can also do this by passing strings to C, instead of objects: =for syntax-highlight lua local abs = assert(URI:new("../quux.html", "http://example.com/foo/bar/")) print(tostring(abs)) -- http://example.com/foo/quux.html Alternatively, a URI object containing a relative URI can be made absolute without creating a new object using the C method: =for syntax-highlight lua 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 The reverse process can be carried out with the C method, creating a relative URI from an absolute one, where the relative URI can be later resolved against a particular base URI: =for syntax-highlight lua 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 It is possible for a relative URI 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 URI like this: =for syntax-highlight lua local uri = assert(URI:new("//example.com/path")) =head1 Methods This is a complete list of the methods you can call on a generic C object once created by calling C. Some URIs are created in more specific classes (listed in the I section), which may have additional methods. Arguments shown in square brackets below are optional. Note that all the accessor methods, like C and C, 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. =over =item uri:default_port() Returns the default port used for this type of URI when no port number is supplied in the authority part. This will be nil if the standard for the URI'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. =for syntax-highlight lua local uri = assert(URI:new("http://example.com:123/")) print(uri:default_port()) -- 80 =item uri:eq(other) Returns true if the two URI objects contain the same URI. C can also be a string, which will be converted to a URI object (in order for the normalization to be done). This can also be called as a stand-alone function if you don't know whether either URI is an object or a string. For example: =for syntax-highlight lua print(URI.eq("http://example.com", "HTTP://EXAMPLE.COM/")) If either value is a string which isn't a valid URI, this will throw an exception. It will however accept relative URIs, and they will be compared as normal. A relative URI is never equal to an absolute one. There is no less-than comparison function, as URIs don't have any particular ordering. If you want to sort URI objects you're best bet is probably just to compare the string versions: =for syntax-highlight lua function urisort (a, b) return a:uri() < b:uri() end table.sort(t, urisort) =item uri:fragment([newvalue]) Returns the current fragment part of the URI (the part after the C<#> character), or nil if the URI has no fragment part. Note that an empty fragment (zero characters long) is different from one which is completely missing. If C 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 C is nil then any existing fragment will be removed. The syntax of fragments are meaningful only for particular media types of resources, so there is no special behaviour for different URI schemes. =item uri:host([newvalue]) Get and set the host part of the authority in a URI. 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). 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. Setting the value to nil will cause the host to be removed altogether, leaving the URI with no authority component. This will throw an exception if there is a userinfo or port component in the URI, because it is impossible to represent a URI with no host when there is an authority component. Some URI 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. =item uri:init() This method is called internally to make a URI 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 C subclass for particular types of URIs. The implementation in the C 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 C method in that. C is called after the URI 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 C, either the new URI object (the object it was called on), or nil and an error message. =item uri:is_relative() Returns true if this is a relative URI reference, false otherwise. All relative URIs belong to the class C. All the other URI classes are for absolute URIs. =item uri:path([newvalue]) Get or set the path component of the URI. Throws an exception if the new value is not valid in the context of the rest of the URI. =for syntax-highlight lua local uri = assert(URI:new("http://example.com/foo")) local old = uri:path("/bar/") print(old) -- /foo print(uri:path()) -- /bar/ 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. There are certain paths which cannot be expressed in the URI syntax. A path which does not start with a C 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 C when there is no authority component would be misinterpreted, so the second slash is percent encoded. Some URI schemes may impose further restrictions on what is allowed in a path, so other path values may cause exceptions in certain cases. =item uri:port([newvalue]) Get or set the port number in a URI. The value returned is always an integer number or nil. If C 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 URI scheme doesn't allow port numbers to be specified. If there is currently no authority part in the URI, then an empty host will be added to create one. If the port number is the default for a URI scheme (the same as the number returned from the C method), then the C method will return that number, but the number won't actually be shown in the URI 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. =item uri:query([newvalue]) Get or set the query part of a URI. If C 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 C 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). 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. =item uri:resolve(base) Given an object representing a relative URI, resolve it against the base URI C (which can be a URI object or string) and update the C object to contain an absolute URI. Has no effect if C is already an absolute URI. Throws an exception if C is not an absolute URI, or if the new URI formed by combining them would be invalid for the given scheme. See also the section I and the C method. =item uri:scheme([newvalue]) Get and set the scheme of the URI. Altering the scheme of an existing URI is very unlikely to be useful. Throws an exception if C is nil or not a valid scheme, or if the rest of the URI 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. =item uri:relativize(base) If possible, update the absolute URI C to contain a relative URI which, when resolved again against C, will yield the original URI value. This doesn't return anything, just modifies the object. Has no effect if C is already relative, or if there is no way to create an appropriate relative URI (so the URI will remain absolute for example if C has a different scheme from C). Throws an exception if C is not absolute. This method will never result in a network-path reference (a relative URI which includes an authority part). In cases where that would be possible the value in C will be left as an absolute URI, which is less likely to cause problems. See also the section I and the C method. =item uri:uri([newvalue]) Returns the URI value as a string. The return value is the same as you'll get from C. If an argument is supplied, this replaces the URI in the C object with a different one. C must be a complete new URI or relative URI reference in a string, or a URI object. This is equivalent to creating a new URI object by calling C, 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 URI to the C method. Throws an exception if C is nil or if there is any error in parsing the new URI 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. =item uri:userinfo([newvalue]) Get or set the userinfo part of the URI. If C 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 URI scheme does not allow a userinfo part (for example if it is an HTTP URI). If there is currently no authority part in the URI, then an empty host will be added to create one. If C is nil then any existing userinfo part is removed. =back =head1 URI schemes The following Lua modules provide classes which implement extra validation and normalization, or provide extra methods, for URIs which specific schemes: =over =item L =item L =item L =item L and uri.https =item L =item L and uri.rtspu =item L =item L =back =head1 Other modules Other Lua modules provide additional functionality used in the library, or act as base classes for the scheme-specific classes: =over =item L Baseclass for URI schemes which use a username and password in their userinfo part, separated by a colon (for example FTP). =item L Utility functions used by the rest of the library. Contains useful C and C functions which might be useful elsewhere. =back =head1 References The parsing of URI syntax is based primarily on L. =head1 Copyright This software and documentation is Copyright E 2007 Geoff Richards Egeoff@geoffrichards.co.ukE. It is free software; you can redistribute it and/or modify it under the terms of the S license. The full terms are given in the file F supplied with the source code package, and are also available here: L An older unreleased version of this library was created as a direct port of the Perl URI library, by Gisle Aas and others. It has since been rewritten with a somewhat different design. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-pop.pod0000644000175000017500000000370212002272735016705 0ustar vsevavseva=head1 Name lua-uri-pop - POP URI support for Lua URI library =head1 Description The class C is used for URIs with the C scheme. It inherits from the L class. POP URIs with a non-empty path part are considered invalid. There are also invalid if there is a userinfo part which has an empty POP username or an empty POP 'auth' type. The ';auth=' part of a POP URI is normalized so that the word 'auth' is in lowercase, and if the auth type is the default '*' value then it is removed altogether, leaving just the username. The default port S. =head1 Methods All the methods defined in L are supported. The C method will throw an exception if the new userinfo would form an invalid POP URI, and will normalize the auth type part if appropriate. The C method will always return empty strings for POP URIs, and will throw an exception if given a new value which is not the empty string. The following additional methods are provided: =over =item uri:pop_user(...) Get or set the POP username, which is stored in the userinfo part of the authority. The return value will be nil if there is no user information in the URI, or a fully decoded string if there is. If the new value is empty, and exception is thrown. The user can be set to nil to remove the userinfo part from the URI, but this will also throw an exception if there is an 'auth' type specified. =item uri:pop_auth(...) Get or set the POP authentication type, which is stored in the userinfo part of the authority after the string ';auth='. The value returned is just the auth type, not the ';auth=' part, and will be fully decoded. The value returned will never be nil. If there is no auth type specified then the default value of '*' will be returned. Setting a new value of nil or the empty string will cause an exception to be thrown. =back =head1 References This class is based on L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-_util.pod0000644000175000017500000001006512002272735017223 0ustar vsevavseva=head1 Name lua-uri-_util - Utility functions for Lua URI library =head1 Description This module contains various utility functions used by the rest of the library. They are mostly intended only for internal use, and are subject to change in future versions, but the URI encoding and decoding functions may be more widely useful. On loading, the module returns a table containing the functions, but like all the modules in this library it does not install itself into any global variables. =for syntax-highlight lua local Util = require "uri._util" =head1 Functions The following functions can be found in the table returned from C: =over =item uri_encode(text, pattern) Use URI encoding (or 'percent encoding') to encode any unsafe characters in C. If C is specified then it should be part of a Lua pattern which can be enclosed in square brackets to make a character class. Usually it will start with C<^> so that the rest of the characters will be considered the 'safe' ones, not to be encoded. Any character matched by the pattern will be encoded. =for syntax-highlight lua print(Util.uri_encode("foo bar!")) ---> foo%20bar! print(Util.uri_encode("foo bar!", "^A-Za-z0-9")) ---> foo%20bar%21 The default pattern is: C<^A-Za-z0-9%-_.!~*'()> =item uri_decode(text, pattern) Decode any URI encoding in C. If C is nil then all encoded characters will be decoded. If a pattern is supplied then it should be in the same form as for C. Any character not matched by the pattern will be left encoded as it was. =for syntax-highlight lua print(Util.uri_decode("foo%20bar%21")) ---> foo bar! print(Util.uri_decode("foo%20bar%21", "^!")) ---> foo bar%21 =item remove_dot_segments(path) Removes single and double dot segments from a URI path. This is the 'remove_dot_segments' algorithm from L. The value of C is used as the input buffer, and the contents of the output buffer are returned. =item split(pattern, str, max) Split the string C wherever C matches it, returning the pieces as individual strings in an array. If C is not nil, then stop splitting after that many pieces have been created. =item attempt_require(name) Calling this function is the same as calling Lua's built in C function, except that if a module called C cannot be found, it returns nil instead of throwing an exception. If loading the module is successful then the result of C is returned. An exception is thrown if any error occurs loading the module other than it not being found. =item subclass_of(class, baseclass) Sets up the metatable and a few other things for the table C so that it will be a subclass of C. This is used by the classes in this library to implement inheritance. =item do_class_changing_change(uri, baseclass, changedesc, newvalue, changefunc) This is used when a mutator method changes something about a URI which leads it to need to belong to a different class. C is the URI object to change, C is the class to reset it to before making the change, C is a description to be included in an error message if necessary, C is the new value to be set (which must be a string, as it is also included in error messages), and C is a function which is called with a temporary URI object it should adjust and C. =item uri_part_not_allowed (class, method) This should be called in scheme-specific classes where certain parts of URIs are not allowed to be present (e.g., the 'host' part in a URN). It will override the named method in the class with one which throws an exception if an attempt is made to set the part to anything other than nil. If the rest of the code for the scheme keeps objects internally consistent then the new method should always return nil, although when a URI is being validated during the C method's execution, it may return other things, which can be used to detect disallowed parts in a URI being parsed. =back =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-file.pod0000644000175000017500000001264412002272735017033 0ustar vsevavseva=head1 Name lua-uri-file - File URI support for Lua URI library =head1 Description The class C is used for URIs with the C scheme. It inherits from the L class. A file URI without an authority doesn't have a well defined meaning. This library considers such URIs to be invalid when they have a path which does not start with '/' (for example C). It is likely that any such URI should really be a relative URI reference. If the path does start with a slash then this library will attempt to 'repair' the URI by adding an empty authority part, so that C will be changed automatically to C. A host value of C is normalized to an empty host, so that C will become C. An empty path is normalized to '/'. The path part is always considered to be case sensitive, so no case folding is done even when converting to a filesystem path for Windows. Query parts and fragments are left alone by this library, but are not used in converting URIs to filesystem paths. =head1 Converting between URIs and filesystem paths A C object can be converted into an absolute path suitable for use on a particular operating system by calling the C method: =for syntax-highlight lua local uri = assert(URI:new("file:///foo/bar")) print(uri:filesystem_path("unix")) -- /foo/bar print(uri:filesystem_path("win32")) -- \foo\bar This method will throw an exception if the path cannot be converted. For example, a file URI containing a host name cannot be represented on a Unix filesystem, but on a Win32 system it will be converted to a UNC path: =for syntax-highlight lua local uri = assert(URI:new("file://server/path")) print(uri:filesystem_path("unix")) -- error print(uri:filesystem_path("win32")) -- \\server\path To convert a filesystem path into a URI, call the class method C: =for syntax-highlight lua local FileURI = require "uri.file" local uri = FileURI.make_file_uri("/foo/bar", "unix") print(uri) -- file:///foo/bar uri = FileURI.make_file_uri("C:\foo\bar", "win32") print(uri) -- file:///C:/foo/bar To convert a relative URI reference (a L object) into a filesystem path you should first resolve it against an appropriate C URI, and then call the C method on that. =head1 Methods All the methods defined in L are supported. The C, and C methods will always return nil, and will throw an exception when passed anything other than nil. The C method will normalize C to an empty host name, and will throw an exception if given a new value of nil. The C method will normalize an empty path or nil value to '/'. In addition to the standard methods, file URIs support the C method, and the C class contains the C function, both of which are described above. =head1 Operating systems supported The conversion between a file URI and a path suitable for use on a particular operating system are defined in additional classes, which are loaded automatically based on the operating system name supplied to the two conversion functions. For example, passing the string C to the functions will invoke the implementation in the class C. An exception will be thrown if no class exists to support a given operating system. The following operating system classes are provided: =over =item C A URI containing a host name will cause an exception to be thrown, as there is no obvious way for these to be represented in Unix paths. If the path contains an encoded null byte (C<%00>) or encoded slash (C<%2F>) then an exception will be thrown. Attempting to convert a relative path to a URI will cause an exception. =item C Forward slashes ('/') in URIs will be converted to backslashes ('\') in paths, and vice versa. URIs containing host names will be converted to UNC paths, starting with a '\\' followed by the hostname and then the path part. If the path part of a URI appears to begin with a drive letter, then the first slash will be removed so that the resulting path starts with the letter. Encoded pipe characters ('%7C') will be recognized as equivalent to colons for the purpose of identifying drive letters, since they have been historically used in that way, but I believe they are not allowed to occur in the path unencoded in a URI nowadays. =back The operating system names are case insensitive, and are folded to lowercase before being converted into a Lua module name. Currently there is no way for this library to recognise the operating system it is running on, since Lua has no built-in way of providing that information. =head1 References The most up to date IETF standard for the C URI scheme is still L, but this does not specify exactly how to convert between URIs and filesystem paths on particular platforms. It does however specify the equivalence between 'localhost' and an empty host. The correct form of file URI to represent a Windows filesystem path is described in a blog article: L There is a standard of sorts describing the conversion between Unix paths and file URIs: L =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-urn.pod0000644000175000017500000000425712002272735016721 0ustar vsevavseva=head1 Name lua-uri-urn - URN support for Lua URI library =head1 Description The class C is used for URNs, that is, URIs with the C scheme. It inherits from the L class. Any URN containing an authority part or query part is considered to be invalid, as is one which does not have a valid NID. URNs must be of the form C, where the NSS part has a syntax specific to the NID. The scheme and NID part are both normalized to lowercase. Some NIDs have subclasses which enforce further syntax constraints, do NID-specific normalization, or provide additional methods. =head1 Methods All the methods defined in L are supported. The C, C, C, and C methods will always return nil, and will throw an exception when passed anything other than nil. The C method will throw an exception if given a new path which is nil or not valid for the C scheme. The following additional methods are supported: =over =item uri:nid(...) Get or set the NID (Namespace Identifier) of the URN (the part of the path before the first colon). If a new value is supplied then the URI's path will be changed to have the new NID but with the same NSS value. An exception will be thrown if the new NID is invalid, or if the existing NSS value is invalid in the context of the new NID. Note that the value 'urn' is an invalid NID. This can cause the class of the URI object to change, if a different class is appropriate for the new NID. =item uri:nss(...) Get or set the NSS (Namespace Specific String) part of the URN (the part of the path after the first colon). If a new value is supplied then the URI's path will be changed to use the new NSS, but the NID will be unchanged. This will throw an exception if the new value is invalid for the current NID. =back =head1 Subclasses The following subclasses are used for URNs with certain NIDs. URNs with other NIDs just use the generic C class. =over =item L =item L =item L =back =head1 References This class is based on L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-rtsp.pod0000644000175000017500000000121512002272735017074 0ustar vsevavseva=head1 Name lua-uri-rtsp - RTSP URI support for Lua URI library =head1 Description The classes C and C are used for URIs with the C and C schemes respectively. C inherits from the L class, and C inherits from C. There is no special validation or normalization applied to these URIs beyond that done for HTTP URIs. The default port for both schemes S. There are no extra methods defined for telnet URIs, only those described in L. =head1 References This class is based on L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-urn-isbn.pod0000644000175000017500000000344212002272735017645 0ustar vsevavseva=head1 Name lua-uri-urn-isbn - ISBN URN support for Lua URI library =head1 Description The class C is used for URNs with the NID 'isbn', that is, URIs which begin C. It inherits from the L class. Some of the functionality of this class depends on the L module being installed, although it can be used without that. In particular, if the module is installed then full checksum validation of the ISBN is performed, whereas without it the ISBN is only checked for invalid characters. The ISBN value is normalized to include hyphens in the conventional places if the lua-isbn module is installed (the exact hyphen positions depend on the number), but without it all hyphens are removed instead. If the ISBN ends in a checksum of 'x', then it folded to uppercase. =head1 Methods All the methods defined in L and L are supported, as well as the following: =over =item uri:isbn(...) Get or set the ISBN value as an object of the type provided by the C class in the L library. This method will throw an exception if this library is not installed, or if the object supplied is not a valid ISBN object (it will currently accept a string, but you shouldn't rely on this). =item uri:isbn_digits(...) Get or set the ISBN value as a string containing just the numbers (and possibly an 'X' as the last digit). There will be no hyphens in this value, and it should be exactly 10 or 13 characters long. If a new value is provided then it must not be nil, and will be validated in the normal way, causing an exception if it is invalid. =back =head1 References This implements the 'isbn' NID defined in L, and is consistent with the same NID suggested in L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-_login.pod0000644000175000017500000000425512002272735017362 0ustar vsevavseva=head1 Name lua-uri-_login - Lua URI library support for URIs containing usernames and passwords =head1 Description The C class is used as a base class by classes implementing URI schemes which can have a username and password in the userinfo part, separated by a colon. A URI of this type where the userinfo part contains more than one colon is considered invalid. They must also have a non-empty host part. The username and password are each optional. The current implementation requires subclasses to call this class's C method within their C method to do the extra validation. This may change if I think of a better way of doing it. =head1 Methods All the methods defined in L are supported, in addition to the following: =over =item uri:username(...) Mutator for the username in the userinfo part. Returns an optionally sets the first part of the userinfo, before the colon. If there is no password then the username will be the whole of the userinfo part, and no colon will be present. =for syntax-highlight lua local uri = assert(URI:new("ftp://host/path")) uri:username("fred") -- ftp://fred@host/path uri:username(nil) -- ftp://host/path Passing nil as the new username will also remove any password in the userinfo, since the password is expected to be meaningless without the username. The username is appropriately percent encoded and decoded by this method. =item uri:password(...) Mutator for the password part of the userinfo. This will appear after a colon, whether or not there is a username. The password is appropriately percent encoded and decoded by this method. =for syntax-highlight lua local password = uri:password() uri:password("secret") =back =head1 References The main RFC for URIs (L) does not specify a syntax for the userinfo part of the authority, which is why the C and C methods are not provided in the generic C class. The use of the colon to separate these parts, and the escaping conventions, are instead derived from the older L, and the up to date telnet URI specification in L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/.gitignore0000644000175000017500000000002612002272735016013 0ustar vsevavsevalua-uri.3 lua-uri-*.3 lua-uri-mainline/doc/lua-uri-ftp.pod0000644000175000017500000000245612002272735016705 0ustar vsevavseva=head1 Name lua-uri-ftp - FTP URI support for Lua URI library =head1 Description The class C is used for URIs with the C scheme. It inherits from the L class. FTP URIs with a missing authority part or an empty host part are considered to be invalid. An empty path is always normalized to '/'. The default port S. =head1 Methods All the methods defined in L and L are supported, in addition to the following: =over =item uri:ftp_typecode(...) Mutator for the 'type' parameter at the end of the path. If the optional argument is supplied then a new type is set, replacing the existing one, or causing the type parameter to be added to the path if it isn't there already. =for syntax-highlight lua local uri = assert(URI:new("ftp://host/path")) uri:ftp_typecode("a") -- ftp://host/path;type=a uri:ftp_typecode(nil) -- ftp://host/path Passing in an empty string has the same effect as nil, removing the parameter. An empty type parameter will be returned as nil, the same as if the parameter was missing. =back =head1 References This class is based on L. Unfortunately there isn't currently an RFC for FTP URIs based on the more up to date L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-urn-oid.pod0000644000175000017500000000260312002272735017463 0ustar vsevavseva=head1 Name lua-uri-urn-oid - OID URN support for Lua URI library =head1 Description The class C is used for URNs with the NID 'oid', that is, URIs which begin C. It inherits from the L class. The URI is considered invalid if its NSS doesn't consist only of non-negative integers separated by full stop characters. Numbers with leading zeroes are not allowed (although the number '0' on its own is). There must be at least one number. There is no normalization performed beyound that performed by the C class. =head1 Methods All the methods defined in L and L as supported, as well as the following: =over =item uri:oid_numbers(...) Get or set the OID as an array of Lua number values. If a new value is provided then it must be a table containing an array of at least one number. All the values in the table must be non-negative numbers. Non-integer numbers are rounded down to an integer value. Strings containing only decimal digits are also allowed. =for syntax-highlight lua local uri = assert(URI:new("urn:oid:1.0.23")) local nums = uri:oid_numbers() for i, v in ipairs(nums) do print(i, v) end uri:oid_numbers({ 5, 4, 3, 2, 1 }) print(uri) -- urn:oid:5.4.3.2.1 =back =head1 References This implements the 'oid' NID defined in L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-urn-issn.pod0000644000175000017500000000224112002272735017662 0ustar vsevavseva=head1 Name lua-uri-urn-issn - ISSN URN support for Lua URI library =head1 Description The class C is used for URNs with the NID 'issn', that is, URIs which begin C. It inherits from the L class. The URI is considered invalid if it doesn't have 8 digits, if there is anything extra in the NSS other than the digits and optional single hyphen, or if the checksum digit is wrong. As specified, the check digit is canonicalized to uppercase. The canonical form has a single hyphen in the middle of the digits. =head1 Methods All the methods defined in L and L as supported, as well as the following: =over =item uri:issn_digits(...) Get or set the ISSN value as a string containing just the numbers. There will be no hyphens in this value, and it should be exactly 8 characters long. If a new value is provided then it must not be nil, and will be validated in the normal way, causing an exception if it is invalid. =back =head1 References This implements the 'issn' NID defined in L, and is consistent with the same NID suggested in L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/doc/lua-uri-http.pod0000644000175000017500000000161212002272735017064 0ustar vsevavseva=head1 Name lua-uri-http - HTTP URI support for Lua URI library =head1 Description The classes C and C are used for URIs with the C and C schemes respectively. C inherits from the generic L class, and C inherits from C. An HTTP or HTTPS URI containing any userinfo part is considered to be invalid. An empty path is normalized to '/', since browsers usually do that, and an empty path cannot be used in an HTTP GET request. The default port for the C scheme S, and for C S. There are no extra methods defined for telnet URIs, only those described in L. =head1 References As far as I can tell there is no up to date specification of the syntax of HTTP URIs, so this class is based on L and L. =for comment vi:ts=4 sw=4 expandtab lua-uri-mainline/README0000644000175000017500000000126312002272735014142 0ustar vsevavsevaThis library allows you to normalize and validate URIs, and provides methods for manipulating them in various ways. The Lua-URI library is written in pure Lua. No C compilation is required to install it. When you unpack the source code everything should already be ready for installation. Doing "make install" as root will install the Lua source files and the man pages containing the documentation. See lua-uri(3) for information about how to use the library. The same documentation is available on the website, where you can also get the latest packages: http://www.geoffrichards.co.uk/lua/uri/ Send bug reports, suggestions, etc. to Geoff Richards lua-uri-mainline/lunit.lua0000644000175000017500000004213412002272735015122 0ustar vsevavseva --[[-------------------------------------------------------------------------- This file is part of lunit 0.5. For Details about lunit look at: http://www.mroth.net/lunit/ Author: Michael Roth Copyright (c) 2004, 2006-2009 Michael Roth Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]]-------------------------------------------------------------------------- local orig_assert = assert local pairs = pairs local ipairs = ipairs local next = next local type = type local error = error local tostring = tostring local string_sub = string.sub local string_format = string.format module("lunit", package.seeall) -- FIXME: Remove package.seeall local lunit = _M local __failure__ = {} -- Type tag for failed assertions local typenames = { "nil", "boolean", "number", "string", "table", "function", "thread", "userdata" } local traceback_hide -- Traceback function which hides lunit internals local mypcall -- Protected call to a function with own traceback do local _tb_hide = setmetatable( {}, {__mode="k"} ) function traceback_hide(func) _tb_hide[func] = true end local function my_traceback(errobj) if is_table(errobj) and errobj.type == __failure__ then local info = debug.getinfo(5, "Sl") -- FIXME: Hardcoded integers are bad... errobj.where = string_format( "%s:%d", info.short_src, info.currentline) else errobj = { msg = tostring(errobj) } errobj.tb = {} local i = 2 while true do local info = debug.getinfo(i, "Snlf") if not is_table(info) then break end if not _tb_hide[info.func] then local line = {} -- Ripped from ldblib.c... line[#line+1] = string_format("%s:", info.short_src) if info.currentline > 0 then line[#line+1] = string_format("%d:", info.currentline) end if info.namewhat ~= "" then line[#line+1] = string_format(" in function '%s'", info.name) else if info.what == "main" then line[#line+1] = " in main chunk" elseif info.what == "C" or info.what == "tail" then line[#line+1] = " ?" else line[#line+1] = string_format(" in function <%s:%d>", info.short_src, info.linedefined) end end errobj.tb[#errobj.tb+1] = table.concat(line) end i = i + 1 end end return errobj end function mypcall(func) orig_assert( is_function(func) ) local ok, errobj = xpcall(func, my_traceback) if not ok then return errobj end end traceback_hide(mypcall) end -- Type check functions for _, typename in ipairs(typenames) do lunit["is_"..typename] = function(x) return type(x) == typename end end local is_nil = is_nil local is_boolean = is_boolean local is_number = is_number local is_string = is_string local is_table = is_table local is_function = is_function local is_thread = is_thread local is_userdata = is_userdata local function failure(name, usermsg, defaultmsg, ...) local errobj = { type = __failure__, name = name, msg = string_format(defaultmsg,...), usermsg = usermsg } error(errobj, 0) end traceback_hide( failure ) local function format_arg(arg) local argtype = type(arg) if argtype == "string" then return "'"..arg.."'" elseif argtype == "number" or argtype == "boolean" or argtype == "nil" then return tostring(arg) else return "["..tostring(arg).."]" end end function fail(msg) stats.assertions = stats.assertions + 1 failure( "fail", msg, "failure" ) end traceback_hide( fail ) function assert(assertion, msg) stats.assertions = stats.assertions + 1 if not assertion then failure( "assert", msg, "assertion failed" ) end return assertion end traceback_hide( assert ) function assert_true(actual, msg) stats.assertions = stats.assertions + 1 local actualtype = type(actual) if actualtype ~= "boolean" then failure( "assert_true", msg, "true expected but was a "..actualtype ) end if actual ~= true then failure( "assert_true", msg, "true expected but was false" ) end return actual end traceback_hide( assert_true ) function assert_false(actual, msg) stats.assertions = stats.assertions + 1 local actualtype = type(actual) if actualtype ~= "boolean" then failure( "assert_false", msg, "false expected but was a "..actualtype ) end if actual ~= false then failure( "assert_false", msg, "false expected but was true" ) end return actual end traceback_hide( assert_false ) function assert_equal(expected, actual, msg) stats.assertions = stats.assertions + 1 if expected ~= actual then failure( "assert_equal", msg, "expected %s but was %s", format_arg(expected), format_arg(actual) ) end return actual end traceback_hide( assert_equal ) function assert_not_equal(unexpected, actual, msg) stats.assertions = stats.assertions + 1 if unexpected == actual then failure( "assert_not_equal", msg, "%s not expected but was one", format_arg(unexpected) ) end return actual end traceback_hide( assert_not_equal ) function assert_match(pattern, actual, msg) stats.assertions = stats.assertions + 1 local patterntype = type(pattern) if patterntype ~= "string" then failure( "assert_match", msg, "expected the pattern as a string but was a "..patterntype ) end local actualtype = type(actual) if actualtype ~= "string" then failure( "assert_match", msg, "expected a string to match pattern '%s' but was a %s", pattern, actualtype ) end if not string.find(actual, pattern) then failure( "assert_match", msg, "expected '%s' to match pattern '%s' but doesn't", actual, pattern ) end return actual end traceback_hide( assert_match ) function assert_not_match(pattern, actual, msg) stats.assertions = stats.assertions + 1 local patterntype = type(pattern) if patterntype ~= "string" then failure( "assert_not_match", msg, "expected the pattern as a string but was a "..patterntype ) end local actualtype = type(actual) if actualtype ~= "string" then failure( "assert_not_match", msg, "expected a string to not match pattern '%s' but was a %s", pattern, actualtype ) end if string.find(actual, pattern) then failure( "assert_not_match", msg, "expected '%s' to not match pattern '%s' but it does", actual, pattern ) end return actual end traceback_hide( assert_not_match ) function assert_error(msg, func) stats.assertions = stats.assertions + 1 if func == nil then func, msg = msg, nil end local functype = type(func) if functype ~= "function" then failure( "assert_error", msg, "expected a function as last argument but was a "..functype ) end local ok, errmsg = pcall(func) if ok then failure( "assert_error", msg, "error expected but no error occurred" ) end end traceback_hide( assert_error ) function assert_error_match(msg, pattern, func) stats.assertions = stats.assertions + 1 if func == nil then msg, pattern, func = nil, msg, pattern end local patterntype = type(pattern) if patterntype ~= "string" then failure( "assert_error_match", msg, "expected the pattern as a string but was a "..patterntype ) end local functype = type(func) if functype ~= "function" then failure( "assert_error_match", msg, "expected a function as last argument but was a "..functype ) end local ok, errmsg = pcall(func) if ok then failure( "assert_error_match", msg, "error expected but no error occurred" ) end local errmsgtype = type(errmsg) if errmsgtype ~= "string" then failure( "assert_error_match", msg, "error as string expected but was a "..errmsgtype ) end if not string.find(errmsg, pattern) then failure( "assert_error_match", msg, "expected error '%s' to match pattern '%s' but doesn't", errmsg, pattern ) end end traceback_hide( assert_error_match ) function assert_pass(msg, func) stats.assertions = stats.assertions + 1 if func == nil then func, msg = msg, nil end local functype = type(func) if functype ~= "function" then failure( "assert_pass", msg, "expected a function as last argument but was a %s", functype ) end local ok, errmsg = pcall(func) if not ok then failure( "assert_pass", msg, "no error expected but error was: '%s'", errmsg ) end end traceback_hide( assert_pass ) -- lunit.assert_typename functions for _, typename in ipairs(typenames) do local assert_typename = "assert_"..typename lunit[assert_typename] = function(actual, msg) stats.assertions = stats.assertions + 1 local actualtype = type(actual) if actualtype ~= typename then failure( assert_typename, msg, typename.." expected but was a "..actualtype ) end return actual end traceback_hide( lunit[assert_typename] ) end -- lunit.assert_not_typename functions for _, typename in ipairs(typenames) do local assert_not_typename = "assert_not_"..typename lunit[assert_not_typename] = function(actual, msg) stats.assertions = stats.assertions + 1 if type(actual) == typename then failure( assert_not_typename, msg, typename.." not expected but was one" ) end end traceback_hide( lunit[assert_not_typename] ) end function lunit.clearstats() stats = { assertions = 0; passed = 0; failed = 0; errors = 0; } end local report, reporterrobj do local testrunner function lunit.setrunner(newrunner) if not ( is_table(newrunner) or is_nil(newrunner) ) then return error("lunit.setrunner: Invalid argument", 0) end local oldrunner = testrunner testrunner = newrunner return oldrunner end function lunit.loadrunner(name) if not is_string(name) then return error("lunit.loadrunner: Invalid argument", 0) end local ok, runner = pcall( require, name ) if not ok then return error("lunit.loadrunner: Can't load test runner: "..runner, 0) end return setrunner(runner) end function report(event, ...) local f = testrunner and testrunner[event] if is_function(f) then pcall(f, ...) end end function reporterrobj(context, tcname, testname, errobj) local fullname = tcname .. "." .. testname if context == "setup" then fullname = fullname .. ":" .. setupname(tcname, testname) elseif context == "teardown" then fullname = fullname .. ":" .. teardownname(tcname, testname) end if errobj.type == __failure__ then stats.failed = stats.failed + 1 report("fail", fullname, errobj.where, errobj.msg, errobj.usermsg) else stats.errors = stats.errors + 1 report("err", fullname, errobj.msg, errobj.tb) end end end local function key_iter(t, k) return (next(t,k)) end local testcase do -- Array with all registered testcases local _testcases = {} -- Marks a module as a testcase. -- Applied over a module from module("xyz", lunit.testcase). function lunit.testcase(m) orig_assert( is_table(m) ) --orig_assert( m._M == m ) orig_assert( is_string(m._NAME) ) --orig_assert( is_string(m._PACKAGE) ) -- Register the module as a testcase _testcases[m._NAME] = m -- Import lunit, fail, assert* and is_* function to the module/testcase m.lunit = lunit m.fail = lunit.fail for funcname, func in pairs(lunit) do if "assert" == string_sub(funcname, 1, 6) or "is_" == string_sub(funcname, 1, 3) then m[funcname] = func end end end -- Iterator (testcasename) over all Testcases function lunit.testcases() -- Make a copy of testcases to prevent confusing the iterator when -- new testcase are defined local _testcases2 = {} for k,v in pairs(_testcases) do _testcases2[k] = true end return key_iter, _testcases2, nil end function testcase(tcname) return _testcases[tcname] end end do -- Finds a function in a testcase case insensitive local function findfuncname(tcname, name) for key, value in pairs(testcase(tcname)) do if is_string(key) and is_function(value) and string.lower(key) == name then return key end end end function lunit.setupname(tcname) return findfuncname(tcname, "setup") end function lunit.teardownname(tcname) return findfuncname(tcname, "teardown") end -- Iterator over all test names in a testcase. -- Have to collect the names first in case one of the test -- functions creates a new global and throws off the iteration. function lunit.tests(tcname) local testnames = {} for key, value in pairs(testcase(tcname)) do if is_string(key) and is_function(value) then local lfn = string.lower(key) if string.sub(lfn, 1, 4) == "test" or string.sub(lfn, -4) == "test" then testnames[key] = true end end end return key_iter, testnames, nil end end function lunit.runtest(tcname, testname) orig_assert( is_string(tcname) ) orig_assert( is_string(testname) ) local function callit(context, func) if func then local err = mypcall(func) if err then reporterrobj(context, tcname, testname, err) return false end end return true end traceback_hide(callit) report("run", tcname, testname) local tc = testcase(tcname) local setup = tc[setupname(tcname)] local test = tc[testname] local teardown = tc[teardownname(tcname)] local setup_ok = callit( "setup", setup ) local test_ok = setup_ok and callit( "test", test ) local teardown_ok = setup_ok and callit( "teardown", teardown ) if setup_ok and test_ok and teardown_ok then stats.passed = stats.passed + 1 report("pass", tcname, testname) end end traceback_hide(runtest) function lunit.run() clearstats() report("begin") for testcasename in lunit.testcases() do -- Run tests in the testcases for testname in lunit.tests(testcasename) do runtest(testcasename, testname) end end report("done") return stats end traceback_hide(run) function lunit.loadonly() clearstats() report("begin") report("done") return stats end local lunitpat2luapat do local conv = { ["^"] = "%^", ["$"] = "%$", ["("] = "%(", [")"] = "%)", ["%"] = "%%", ["."] = "%.", ["["] = "%[", ["]"] = "%]", ["+"] = "%+", ["-"] = "%-", ["?"] = ".", ["*"] = ".*" } function lunitpat2luapat(str) return "^" .. string.gsub(str, "%W", conv) .. "$" end end local function in_patternmap(map, name) if map[name] == true then return true else for _, pat in ipairs(map) do if string.find(name, pat) then return true end end end return false end -- Called from 'lunit' shell script. function main(argv) argv = argv or {} -- FIXME: Error handling and error messages aren't nice. local function checkarg(optname, arg) if not is_string(arg) then return error("lunit.main: option "..optname..": argument missing.", 0) end end local function loadtestcase(filename) if not is_string(filename) then return error("lunit.main: invalid argument") end local chunk, err = loadfile(filename) if err then return error(err) else chunk() end end local testpatterns = nil local doloadonly = false local runner = nil local i = 0 while i < #argv do i = i + 1 local arg = argv[i] if arg == "--loadonly" then doloadonly = true elseif arg == "--runner" or arg == "-r" then local optname = arg; i = i + 1; arg = argv[i] checkarg(optname, arg) runner = arg elseif arg == "--test" or arg == "-t" then local optname = arg; i = i + 1; arg = argv[i] checkarg(optname, arg) testpatterns = testpatterns or {} testpatterns[#testpatterns+1] = arg elseif arg == "--" then while i < #argv do i = i + 1; arg = argv[i] loadtestcase(arg) end else loadtestcase(arg) end end loadrunner(runner or "lunit-console") if doloadonly then return loadonly() else return run(testpatterns) end end clearstats() lua-uri-mainline/MANIFEST0000644000175000017500000000246112002272735014414 0ustar vsevavsevaCOPYRIGHT Changes MANIFEST Makefile README TODO debian/Makefile.Debian.conf debian/changelog debian/compat debian/control debian/copyright debian/liblua5.1-uri-dev.manpages debian/rules doc/lua-uri-_login.3 doc/lua-uri-_login.pod doc/lua-uri-_util.3 doc/lua-uri-_util.pod doc/lua-uri-data.3 doc/lua-uri-data.pod doc/lua-uri-file.3 doc/lua-uri-file.pod doc/lua-uri-ftp.3 doc/lua-uri-ftp.pod doc/lua-uri-http.3 doc/lua-uri-http.pod doc/lua-uri-pop.3 doc/lua-uri-pop.pod doc/lua-uri-rtsp.3 doc/lua-uri-rtsp.pod doc/lua-uri-telnet.3 doc/lua-uri-telnet.pod doc/lua-uri-urn-isbn.3 doc/lua-uri-urn-isbn.pod doc/lua-uri-urn-issn.3 doc/lua-uri-urn-issn.pod doc/lua-uri-urn-oid.3 doc/lua-uri-urn-oid.pod doc/lua-uri-urn.3 doc/lua-uri-urn.pod doc/lua-uri.3 doc/lua-uri.pod lunit-console.lua lunit.lua test/_generic.lua test/_pristine.lua test/_relative.lua test/_resolve.lua test/_util.lua test/data.lua test/file.lua test/ftp.lua test/http.lua test/pop.lua test/rtsp.lua test/telnet.lua test/urn-isbn.lua test/urn-issn.lua test/urn-oid.lua test/urn.lua uri-test.lua uri.lua uri/_login.lua uri/_relative.lua uri/_util.lua uri/data.lua uri/file.lua uri/file/unix.lua uri/file/win32.lua uri/ftp.lua uri/http.lua uri/https.lua uri/pop.lua uri/rtsp.lua uri/rtspu.lua uri/telnet.lua uri/urn.lua uri/urn/isbn.lua uri/urn/issn.lua uri/urn/oid.lua lua-uri-mainline/uri/0000755000175000017500000000000012002272735014057 5ustar vsevavsevalua-uri-mainline/uri/data.lua0000644000175000017500000000647712002272735015511 0ustar vsevavsevalocal M = { _NAME = "uri.data" } local Util = require "uri._util" local URI = require "uri" Util.subclass_of(M, URI) -- This implements the 'data' scheme defined in RFC 2397. local Filter = Util.attempt_require("datafilter") local function _valid_base64 (data) return data:find("^[0-9a-zA-Z/+]*$") end local function _split_path (path) local _, _, mediatype, data = path:find("^([^,]*),(.*)") if not mediatype then return "must have comma in path" end local base64 = false if mediatype:find(";base64$") then base64 = true mediatype = mediatype:sub(1, -8) end if base64 and not _valid_base64(data) then return "illegal character in base64 encoding" end return nil, mediatype, base64, data end function M.init (self) if M._SUPER.host(self) then return nil, "data URIs may not have authority parts" end local err, mediatype, base64, data = _split_path(M._SUPER.path(self)) if err then return nil, "invalid data URI (" .. err .. ")" end return self end function M.data_media_type (self, ...) local _, old, base64, data = _split_path(M._SUPER.path(self)) if select('#', ...) > 0 then local new = ... or "" new = Util.uri_encode(new, "^A-Za-z0-9%-._~!$&'()*+;=:@/") if base64 then new = new .. ";base64" end M._SUPER.path(self, new .. "," .. data) end if old ~= "" then if old:find("^;") then old = "text/plain" .. old end return Util.uri_decode(old) else return "text/plain;charset=US-ASCII" -- default type end end local function _urienc_len (s) local num_unsafe_chars = s:gsub("[A-Za-z0-9%-._~!$&'()*+,;=:@/]", ""):len() local num_safe_chars = s:len() - num_unsafe_chars return num_safe_chars + num_unsafe_chars * 3 end local function _base64_len (s) local num_blocks = (s:len() + 2) / 3 num_blocks = num_blocks - num_blocks % 1 return num_blocks * 4 + 7 -- because of ";base64" marker end local function _do_filter (algorithm, input) return Filter[algorithm](input) end function M.data_bytes (self, ...) local _, mediatype, base64, old = _split_path(M._SUPER.path(self)) if base64 then if not Filter then error("'datafilter' Lua module required to decode base64 data", 2) end old = _do_filter("base64_decode", old) else old = Util.uri_decode(old) end if select('#', ...) > 0 then local new = ... or "" local urienc_len = _urienc_len(new) local base64_len = _base64_len(new) if base64_len < urienc_len and Filter then mediatype = mediatype .. ";base64" new = _do_filter("base64_encode", new) else new = new:gsub("%%", "%%25") end M._SUPER.path(self, mediatype .. "," .. new) end return old end function M.path (self, ...) local old = M._SUPER.path(self) if select('#', ...) > 0 then local new = ... if not new then error("there must be a path in a data URI") end local err = _split_path(new) if err then error("invalid data URI (" .. err .. ")") end M._SUPER.path(self, new) end return old end Util.uri_part_not_allowed(M, "userinfo") Util.uri_part_not_allowed(M, "host") Util.uri_part_not_allowed(M, "port") return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/ftp.lua0000644000175000017500000000252712002272735015361 0ustar vsevavsevalocal M = { _NAME = "uri.ftp" } local Util = require "uri._util" local LoginURI = require "uri._login" Util.subclass_of(M, LoginURI) function M.default_port () return 21 end function M.init (self) local err self, err = M._SUPER.init_base(self) if not self then return nil, err end local host = self:host() if not host or host == "" then return nil, "FTP URIs must have a hostname" end -- I don't think there's any distinction in FTP URIs between empty path -- and the root directory, so probably best to normalize as we do for HTTP. if self:path() == "" then self:path("/") end return self end function M.path (self, ...) local old = M._SUPER.path(self) if select("#", ...) > 0 then local new = ... if not new or new == "" then new = "/" end M._SUPER.path(self, new) end return old end function M.ftp_typecode (self, ...) local path = M._SUPER.path(self) local _, _, withouttype, old = path:find("^(.*);type=(.*)$") if not withouttype then withouttype = path end if old == "" then old = nil end if select("#", ...) > 0 then local new = ... if not new then new = "" end if new ~= "" then new = ";type=" .. new end M._SUPER.path(self, withouttype .. new) end return old end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/_relative.lua0000644000175000017500000000506012002272735016535 0ustar vsevavsevalocal M = { _NAME = "uri._relative" } local Util = require "uri._util" local URI = require "uri" Util.subclass_of(M, URI) -- There needs to be an 'init' method in this class, to because the base-class -- one expects there to be a 'scheme' value. function M.init (self) return self end function M.scheme (self, ...) if select("#", ...) > 0 then error("relative URI references can't have a scheme, perhaps you" .. " need to resolve this against an absolute URI instead", 2) end return nil end function M.is_relative () return true end -- This implements the algorithm from RFC 3986 section 5.2.3 -- Note that this takes an additional argument which appears to be required -- by the algorithm, but isn't shown when it is used in the RFC. local function _merge_paths (base, r, base_has_auth) if base_has_auth and base == "" then return "/" .. r end return base:gsub("[^/]+$", "", 1) .. r end local function _do_resolve (self, base) if type(base) == "string" then base = assert(URI:new(base)) end setmetatable(self, URI) if self:host() or self:userinfo() or self:port() then -- network path reference, just needs a scheme self:path(Util.remove_dot_segments(self:path())) self:scheme(base:scheme()) return end local path = self:path() if path == "" then self:path(base:path()) if not self:query() then self:query(base:query()) end else if path:find("^/") then self:path(Util.remove_dot_segments(path)) else local base_has_auth = base:host() or base:userinfo() or base:port() local merged = _merge_paths(base:path(), path, base_has_auth) self:path(Util.remove_dot_segments(merged)) end end self:host(base:host()) self:userinfo(base:userinfo()) self:port(base:port()) self:scheme(base:scheme()) end function M.resolve (self, base) local orig = tostring(self) local ok, result = pcall(_do_resolve, self, base) if ok then return end -- If the resolving causes an exception, it means that the resulting URI -- would be invalid, so we restore self to its original state and rethrow -- the exception. local restored = assert(URI:new(orig)) for k in pairs(self) do self[k] = nil end for k, v in pairs(restored) do self[k] = v end setmetatable(self, getmetatable(restored)) error("resolved URI reference would be invalid: " .. result, 2) end function M.relativize (self, base) end -- already relative return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/rtsp.lua0000644000175000017500000000032112002272735015546 0ustar vsevavsevalocal M = { _NAME = "uri.rtsp" } local Util = require "uri._util" local HttpURI = require "uri.http" Util.subclass_of(M, HttpURI) function M.default_port () return 554 end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/file.lua0000644000175000017500000000330712002272735015504 0ustar vsevavsevalocal M = { _NAME = "uri.file" } local Util = require "uri._util" local URI = require "uri" Util.subclass_of(M, URI) function M.init (self) if self:userinfo() or self:port() then return nil, "usernames and passwords are not allowed in HTTP URIs" end local host = self:host() local path = self:path() if host then if host:lower() == "localhost" then self:host("") end else if not path:find("^/") then return nil, "file URIs must contain a host, even if it's empty" end self:host("") end if path == "" then self:path("/") end return self end function M.host (self, ...) local old = M._SUPER.host(self) if select('#', ...) > 0 then local new = ... if not new then error("file URIs must have an authority part", 2) end if new:lower() == "localhost" then new = "" end M._SUPER.host(self, new) end return old end function M.path (self, ...) local old = M._SUPER.path(self) if select('#', ...) > 0 then local new = ... if not new or new == "" then new = "/" end M._SUPER.path(self, new) end return old end local function _os_implementation (os) local FileImpl = Util.attempt_require("uri.file." .. os:lower(), 3) if not FileImpl then error("no file URI implementation for operating system " .. os) end return FileImpl end function M.filesystem_path (self, os) return _os_implementation(os).filesystem_path(self) end function M.make_file_uri (path, os) return _os_implementation(os).make_file_uri(path) end Util.uri_part_not_allowed(M, "userinfo") Util.uri_part_not_allowed(M, "port") return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/urn.lua0000644000175000017500000000755712002272735015404 0ustar vsevavsevalocal M = { _NAME = "uri.urn" } local Util = require "uri._util" local URI = require "uri" Util.subclass_of(M, URI) -- This implements RFC 2141, and attempts to change the class of the URI object -- to one of its subclasses for further validation and normalization of the -- namespace-specific string. -- Check NID syntax matches RFC 2141 section 2.1. local function _valid_nid (nid) if nid == "" then return nil, "missing completely" end if nid:len() > 32 then return nil, "too long" end if not nid:find("^[A-Za-z0-9][-A-Za-z0-9]*$") then return nil, "contains illegal character" end if nid:lower() == "urn" then return nil, "'urn' is reserved" end return true end -- Check NSS syntax matches RFC 2141 section 2.2. local function _valid_nss (nss) if nss == "" then return nil, "can't be empty" end if nss:find("[^A-Za-z0-9()+,%-.:=@;$_!*'/%%]") then return nil, "contains illegal character" end return true end local function _validate_and_normalize_path (path) local _, _, nid, nss = path:find("^([^:]+):(.*)$") if not nid then return nil, "illegal path syntax for URN" end local ok, msg = _valid_nid(nid) if not ok then return nil, "invalid namespace identifier (" .. msg .. ")" end ok, msg = _valid_nss(nss) if not ok then return nil, "invalid namespace specific string (" .. msg .. ")" end return nid:lower() .. ":" .. nss end -- TODO - this should check that percent-encoded bytes are valid UTF-8 function M.init (self) if M._SUPER.query(self) then return nil, "URNs may not have query parts" end if M._SUPER.host(self) then return nil, "URNs may not have authority parts" end local path, msg = _validate_and_normalize_path(self:path()) if not path then return nil, msg end M._SUPER.path(self, path) local nid_class = Util.attempt_require("uri.urn." .. self:nid():gsub("%-", "_")) if nid_class then setmetatable(self, nid_class) if self.init ~= M.init then return self:init() end end return self end function M.nid (self, new) local _, _, old = self:path():find("^([^:]+)") if new then new = new:lower() if new ~= old then local ok, msg = _valid_nid(new) if not ok then error("invalid namespace identifier (" .. msg .. ")", 2) end end Util.do_class_changing_change(self, M, "NID", new, function (uri, new) M._SUPER.path(uri, new .. ":" .. uri:nss()) end) end return old end function M.nss (self, new) local _, _, old = self:path():find(":(.*)") if new and new ~= old then local ok, msg = _valid_nss(new) if not ok then error("invalid namespace specific string (" .. msg .. ")", 2) end M._SUPER.path(self, self:nid() .. ":" .. new) end return old end function M.path (self, new) local old = M._SUPER.path(self) if new and new ~= old then local path, msg = _validate_and_normalize_path(new) if not path then error("invalid path for URN '" .. new .. "' (" ..msg .. ")", 2) end local _, _, newnid, newnss = path:find("^([^:]+):(.*)") if not newnid then error("bad path for URN, no NID part found", 2) end local ok, msg = _valid_nid(newnid) if not ok then error("invalid namespace identifier (" .. msg .. ")", 2) end if newnid:lower() == self:nid() then self:nss(newnss) else Util.do_class_changing_change(self, M, "path", path, function (uri, new) M._SUPER.path(uri, new) end) end end return old end Util.uri_part_not_allowed(M, "userinfo") Util.uri_part_not_allowed(M, "host") Util.uri_part_not_allowed(M, "port") Util.uri_part_not_allowed(M, "query") return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/https.lua0000644000175000017500000000031412002272735015722 0ustar vsevavsevalocal M = { _NAME = "uri.https" } local Util = require "uri._util" local Http = require "uri.http" Util.subclass_of(M, Http) function M.default_port () return 443 end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/rtspu.lua0000644000175000017500000000024712002272735015742 0ustar vsevavsevalocal M = { _NAME = "uri.rtspu" } local Util = require "uri._util" local RtspURI = require "uri.rtsp" Util.subclass_of(M, RtspURI) return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/urn/0000755000175000017500000000000012002272735014663 5ustar vsevavsevalua-uri-mainline/uri/urn/isbn.lua0000644000175000017500000000324612002272735016326 0ustar vsevavsevalocal M = { _NAME = "uri.urn.isbn" } local Util = require "uri._util" local URN = require "uri.urn" Util.subclass_of(M, URN) -- This implements the 'isbn' NID defined in RFC 3187, and is consistent -- with the same NID suggested in RFC 2288. local function _valid_isbn (isbn) if not isbn:find("^[-%d]+[%dXx]$") then return nil, "invalid character" end local ISBN = Util.attempt_require("isbn") if ISBN then return ISBN:new(isbn) end return isbn end local function _normalize_isbn (isbn) isbn = isbn:gsub("%-", ""):upper() local ISBN = Util.attempt_require("isbn") if ISBN then return tostring(ISBN:new(isbn)) end return isbn end function M.init (self) local nss = self:nss() local ok, msg = _valid_isbn(nss) if not ok then return nil, "invalid ISBN value (" .. msg .. ")" end self:nss(_normalize_isbn(nss)) return self end function M.nss (self, new) local old = M._SUPER.nss(self) if new then local ok, msg = _valid_isbn(new) if not ok then error("bad ISBN value '" .. new .. "' (" .. msg .. ")", 2) end M._SUPER.nss(self, _normalize_isbn(new)) end return old end function M.isbn_digits (self, new) local old = self:nss():gsub("%-", "") if new then local ok, msg = _valid_isbn(new) if not ok then error("bad ISBN value '" .. new .. "' (" .. msg .. ")", 2) end self._SUPER.nss(self, _normalize_isbn(new)) end return old end function M.isbn (self, new) local ISBN = require "isbn" local old = ISBN:new(self:nss()) if new then self:nss(tostring(new)) end return old end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/urn/issn.lua0000644000175000017500000000346012002272735016345 0ustar vsevavsevalocal M = { _NAME = "uri.urn.issn" } local Util = require "uri._util" local URN = require "uri.urn" Util.subclass_of(M, URN) local function _parse_issn (issn) local _, _, nums1, nums2, checksum = issn:find("^(%d%d%d%d)-?(%d%d%d)([%dxX])$") if checksum == "x" then checksum = "X" end return nums1, nums2, checksum end local function _valid_issn (issn) local nums1, nums2, actual_checksum = _parse_issn(issn) if not nums1 then return nil, "invalid ISSN syntax" end local nums = nums1 .. nums2 local expected_checksum = 0 for i = 1, 7 do expected_checksum = expected_checksum + tonumber(nums:sub(i, i)) * (9 - i) end expected_checksum = (11 - expected_checksum % 11) % 11 expected_checksum = (expected_checksum == 10) and "X" or tostring(expected_checksum) if actual_checksum ~= expected_checksum then return nil, "wrong checksum, expected " .. expected_checksum end return true end local function _normalize_issn (issn) local nums1, nums2, checksum = _parse_issn(issn) return nums1 .. "-" .. nums2 .. checksum end function M.init (self) local nss = self:nss() local ok, msg = _valid_issn(nss) if not ok then return nil, "bad NSS value for ISSN URI (" .. msg .. ")" end M._SUPER.nss(self, _normalize_issn(nss)) return self end function M.nss (self, new) local old = M._SUPER.nss(self) if new then local ok, msg = _valid_issn(new) if not ok then error("bad ISSN value '" .. new .. "' (" .. msg .. ")", 2) end M._SUPER.nss(self, _normalize_issn(new)) end return old end function M.issn_digits (self, new) local old = self:nss(new) return old:sub(1, 4) .. old:sub(6, 9) end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/urn/oid.lua0000644000175000017500000000346312002272735016147 0ustar vsevavsevalocal M = { _NAME = "uri.urn.oid" } local Util = require "uri._util" local URN = require "uri.urn" Util.subclass_of(M, URN) -- This implements RFC 3061. local function _valid_oid (oid) if oid == "" then return nil, "OID can't be zero-length" end if not oid:find("^[.0-9]*$") then return nil, "bad character in OID" end if oid:find("%.%.") then return nil, "missing number in OID" end if oid:find("^0[^.]") or oid:find("%.0[^.]") then return nil, "OID numbers shouldn't have leading zeros" end return true end function M.init (self) local nss = self:nss() local ok, msg = _valid_oid(nss) if not ok then return nil, "bad NSS value for OID URI (" .. msg .. ")" end return self end function M.nss (self, new) local old = M._SUPER.nss(self) if new then local ok, msg = _valid_oid(new) if not ok then error("bad OID value '" .. new .. "' (" .. msg .. ")", 2) end M._SUPER.nss(self, new) end return old end function M.oid_numbers (self, new) local old = Util.split("%.", self:nss()) for i = 1, #old do old[i] = tonumber(old[i]) end if new then if type(new) ~= "table" then error("expected array of numbers", 2) end local nss = "" for _, n in ipairs(new) do if type(n) == "string" and n:find("^%d+$") then n = tonumber(n) end if type(n) ~= "number" then error("bad type for number in OID", 2) end n = n - n % 1 if n < 0 then error("negative numbers not allowed in OID", 2) end if nss ~= "" then nss = nss .. "." end nss = nss .. n end if nss == "" then error("no numbers in new OID value", 2) end self:nss(nss) end return old end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/file/0000755000175000017500000000000012002272735014776 5ustar vsevavsevalua-uri-mainline/uri/file/win32.lua0000644000175000017500000000213112002272735016440 0ustar vsevavsevalocal M = { _NAME = "uri.file.win32" } local URI = require "uri" local Util = require "uri._util" function M.filesystem_path (uri) local host = uri:host() local path = Util.uri_decode(uri:path()) if host ~= "" then path = "//" .. host .. path end if path:find("^/[A-Za-z]|/") or path:find("^/[A-Za-z]|$") then path = path:gsub("|", ":", 1) end if path:find("^/[A-Za-z]:/") then path = path:sub(2) elseif path:find("^/[A-Za-z]:$") then path = path:sub(2) .. "/" end path = path:gsub("/", "\\") return path end function M.make_file_uri (path) if path:find("^[A-Za-z]:$") then path = path .. "\\" end local _, _, host, hostpath = path:find("^\\\\([A-Za-z.]+)\\(.*)$") host = host or "" hostpath = hostpath or path hostpath = hostpath:gsub("\\", "/") :gsub("//+", "/") hostpath = Util.uri_encode(hostpath, "^A-Za-z0-9%-._~!$&'()*+,;=:@/") if not hostpath:find("^/") then hostpath = "/" .. hostpath end return assert(URI:new("file://" .. host .. hostpath)) end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/file/unix.lua0000644000175000017500000000143212002272735016464 0ustar vsevavsevalocal M = { _NAME = "uri.file.unix" } local URI = require "uri" local Util = require "uri._util" function M.filesystem_path (uri) if uri:host() ~= "" then error("a file URI with a host name can't be converted to a Unix path", 2) end local path = uri:path() if path:find("%%00") or path:find("%%2F") then error("Unix paths cannot contain encoded null bytes or slashes", 2) end return Util.uri_decode(path) end function M.make_file_uri (path) if not path:find("^/") then error("Unix relative paths can't be converted to file URIs", 2) end path = path:gsub("//+", "/") path = Util.uri_encode(path, "^A-Za-z0-9%-._~!$&'()*+,;=:@/") return assert(URI:new("file://" .. path)) end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/telnet.lua0000644000175000017500000000236612002272735016064 0ustar vsevavsevalocal M = { _NAME = "uri.telnet" } local Util = require "uri._util" local LoginURI = require "uri._login" Util.subclass_of(M, LoginURI) function M.default_port () return 23 end function M.init (self) local err self, err = M._SUPER.init_base(self) if not self then return nil, err end -- RFC 4248 does not discuss what a path longer than '/' might mean, and -- there are no examples with anything significant in the path, so I'm -- assuming that extra information in the path is not allowed. local path = M._SUPER.path(self) if path ~= "" and path ~= "/" then return nil, "superfluous information in path of telnet URI" end -- RFC 4248 section 2 says that the '/' can be omitted. I chose to -- normalize to having it there, since the example shown in the RFC has -- it, and this is consistent with the way I treat HTTP URIs. if path == "" then self:path("/") end return self end -- The path is always '/', so setting it won't do anything, but we do throw -- an exception on an attempt to set it to anything invalid. function M.path (self, new) if new and new ~= "" and new ~= "/" then error("invalid path for telnet URI", 2) end return "/" end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/_util.lua0000644000175000017500000000744512002272735015710 0ustar vsevavsevalocal M = { _NAME = "uri._util" } local string_char, string_format = string.char, string.format -- Build a char->hex map local escapes = {} for i = 0, 255 do escapes[string_char(i)] = string_format("%%%02X", i) end local function _encode_char (chr) return escapes[chr] end function M.uri_encode (text, patn) if not text then return end if not patn then -- Default unsafe characters. RFC 2732 ^(uric - reserved) -- TODO - this should be updated to the latest RFC. patn = "^A-Za-z0-9%-_.!~*'()" end return (text:gsub("([" .. patn .. "])", _encode_char)) end function M.uri_decode (str, patn) -- Note from RFC1630: "Sequences which start with a percent sign -- but are not followed by two hexadecimal characters are reserved -- for future extension" if not str then return end if patn then patn = "[" .. patn .. "]" end return (str:gsub("%%(%x%x)", function (hex) local char = string_char(tonumber(hex, 16)) return (patn and not char:find(patn)) and "%" .. hex or char end)) end -- This is the remove_dot_segments algorithm from RFC 3986 section 5.2.4. -- The input buffer is 's', the output buffer 'path'. function M.remove_dot_segments (s) local path = "" while s ~= "" do if s:find("^%.%.?/") then -- A s = s:gsub("^%.%.?/", "", 1) elseif s:find("^/%./") or s == "/." then -- B s = s:gsub("^/%./?", "/", 1) elseif s:find("^/%.%./") or s == "/.." then -- C s = s:gsub("^/%.%./?", "/", 1) if path:find("/") then path = path:gsub("/[^/]*$", "", 1) else path = "" end elseif s == "." or s == ".." then -- D s = "" else -- E local _, p, seg = s:find("^(/?[^/]*)") s = s:sub(p + 1) path = path .. seg end end return path end -- TODO - wouldn't this be better as a method on string? s:split(patn) function M.split (patn, s, max) if s == "" then return {} end local i, j = 1, string.find(s, patn) if not j then return { s } end local list = {} while true do if #list + 1 == max then list[max] = s:sub(i); return list end list[#list + 1] = s:sub(i, j - 1) i = j + 1 j = string.find(s, patn, i) if not j then list[#list + 1] = s:sub(i) break end end return list end function M.attempt_require (modname) local ok, result = pcall(require, modname) if ok then return result elseif type(result) == "string" and result:find("module '.*' not found") then return nil else error(result) end end function M.subclass_of (class, baseclass) class.__index = class class.__tostring = baseclass.__tostring class._SUPER = baseclass setmetatable(class, baseclass) end function M.do_class_changing_change (uri, baseclass, changedesc, newvalue, changefunc) local tmpuri = {} setmetatable(tmpuri, baseclass) for k, v in pairs(uri) do tmpuri[k] = v end changefunc(tmpuri, newvalue) tmpuri._uri = nil local foo, err = tmpuri:init() if not foo then error("URI not valid after " .. changedesc .. " changed to '" .. newvalue .. "': " .. err, 3) end setmetatable(uri, getmetatable(tmpuri)) for k in pairs(uri) do uri[k] = nil end for k, v in pairs(tmpuri) do uri[k] = v end end function M.uri_part_not_allowed (class, method) class[method] = function (self, new) if new then error(method .. " not allowed on this kind of URI") end return self["_" .. method] end end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/pop.lua0000644000175000017500000000631112002272735015361 0ustar vsevavsevalocal M = { _NAME = "uri.pop" } local URI = require "uri" local Util = require "uri._util" Util.subclass_of(M, URI) -- This is the set of characters must be encoded in a POP userinfo, which -- unlike for other schemes includes the ';' character. local _POP_USERINFO_ENCODE = "^A-Za-z0-9%-._~%%!$&'()*+,=:" function M.default_port () return 110 end local function _update_userinfo (self, old, new) if new then local _, _, user, auth = new:find("^(.*);[Aa][Uu][Tt][Hh]=(.*)$") if not user then user = new end if user == "" then return "pop user name must not be empty" end user = Util.uri_encode(user, _POP_USERINFO_ENCODE) if auth then if auth == "" then return "pop auth type must not be empty" end if auth == "*" then auth = nil end auth = Util.uri_encode(auth, _POP_USERINFO_ENCODE) end new = user .. (auth and ";auth=" .. auth or "") end if new ~= old then M._SUPER.userinfo(self, new) end return nil end function M.init (self) if M._SUPER.path(self) ~= "" then return nil, "pop URIs must have an empty path" end local userinfo = M._SUPER.userinfo(self) local err = _update_userinfo(self, userinfo, userinfo) if err then return nil, err end return self end function M.userinfo (self, ...) local old = M._SUPER.userinfo(self) if select('#', ...) > 0 then local new = ... local err = _update_userinfo(self, old, new) if err then error(err, 2) end end return old end function M.path (self, new) if new and new ~= "" then error("POP URIs must have an empty path", 2) end return "" end local function _decode_userinfo (self) local old = M._SUPER.userinfo(self) if not old then return nil, nil end local _, _, old_user, old_auth = old:find("^(.*);auth=(.*)$") if not old_user then old_user = old end return old_user, old_auth end function M.pop_user (self, ...) local old_user, old_auth = _decode_userinfo(self) if select('#', ...) > 0 then local new = ... if new == "" then error("pop user name must not be empty", 2) end if not new and old_auth then error("pop user name required when an auth type is specified", 2) end if new then new = Util.uri_encode(new, _POP_USERINFO_ENCODE) if old_auth then new = new .. ";auth=" .. old_auth end end M._SUPER.userinfo(self, new) end return Util.uri_decode(old_user) end function M.pop_auth (self, ...) local old_user, old_auth = _decode_userinfo(self) if select('#', ...) > 0 then local new = ... if not new or new == "" then error("pop auth type must not be empty", 2) end if new == "*" then new = nil end if new and not old_user then error("pop auth type can't be specified without user name", 2) end if new then new = old_user .. ";auth=" .. Util.uri_encode(new, _POP_USERINFO_ENCODE) else new = old_user end M._SUPER.userinfo(self, new) end return old_auth and Util.uri_decode(old_auth) or "*" end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/http.lua0000644000175000017500000000173712002272735015551 0ustar vsevavsevalocal M = { _NAME = "uri.http" } local Util = require "uri._util" local URI = require "uri" Util.subclass_of(M, URI) -- This implementation is based on RFC 2616 section 3.2 and RFC 1738 -- section 3.3. -- -- An HTTP URI with a 'userinfo' field is considered invalid, because it isn't -- shown in the syntax given in RFC 2616, and is explicitly disallowed by -- RFC 1738. function M.default_port () return 80 end function M.init (self) if self:userinfo() then return nil, "usernames and passwords are not allowed in HTTP URIs" end -- RFC 2616 section 3.2.3 says that this is OK, but not that using the -- redundant slash is canonical. I'm adding it because browsers tend to -- treat the version with the extra slash as the normalized form, and -- the initial slash is always present in an HTTP GET request. if self:path() == "" then self:path("/") end return self end Util.uri_part_not_allowed(M, "userinfo") return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri/_login.lua0000644000175000017500000000551112002272735016033 0ustar vsevavsevalocal M = { _NAME = "uri._login" } local Util = require "uri._util" local URI = require "uri" Util.subclass_of(M, URI) -- Generic terminal logins. This is used as a base class for 'telnet' and -- 'ftp' URL schemes. local function _valid_userinfo (userinfo) if userinfo then local colon = userinfo:find(":") if colon and userinfo:find(":", colon + 1) then return nil, "only one colon allowed in userinfo" end end return true end -- TODO - this is a bit of a hack because currently subclasses are required -- to know whether their superclass has one of these that needs calling. -- It should be called from 'init' before anything more specific is done, -- and it has the same calling convention. -- According to RFC 1738 there should be at most one colon in the userinfo. -- I apply that restriction for schemes where it's used for a username/password -- pair. function M.init_base (self) local host = self:host() if not host or host == "" then return nil, "host missing from login URI" end local ok, err = _valid_userinfo(self:userinfo()) if not ok then return nil, err end return self end function M.userinfo (self, ...) if select("#", ...) > 0 then local ok, err = _valid_userinfo(...) if not ok then error("invalid userinfo value (" .. err .. ")", 2) end end return M._SUPER.userinfo(self, ...) end function M.username (self, ...) local info = M._SUPER.userinfo(self) local old, colon if info then local colon = info and info:find(":") old = colon and info:sub(1, colon - 1) or info old = Util.uri_decode(old) end if select('#', ...) > 0 then local pass = colon and info:sub(colon) or "" -- includes colon local new = ... if not new then M._SUPER.userinfo(self, nil) else -- Escape anything that's not allowed in a userinfo, and also -- colon, because that indicates the end of the username. new = Util.uri_encode(new, "^A-Za-z0-9%-._~!$&'()*+,;=") M._SUPER.userinfo(self, new .. pass) end end return old end function M.password (self, ...) local info = M._SUPER.userinfo(self) local old, colon if info then colon = info and info:find(":") old = colon and info:sub(colon + 1) or nil if old then old = Util.uri_decode(old) end end if select('#', ...) > 0 then local new = ... local user = colon and info:sub(1, colon - 1) or info if not new then M._SUPER.userinfo(self, user) else if not user then user = "" end new = Util.uri_encode(new, "^A-Za-z0-9%-._~!$&'()*+,;=") M._SUPER.userinfo(self, user .. ":" .. new) end end return old end return M -- vi:ts=4 sw=4 expandtab lua-uri-mainline/.gitignore0000644000175000017500000000006112002272735015245 0ustar vsevavsevalua-uri-*.tar.bz2 lua-uri-*.tar.gz lua-uri-*.zip lua-uri-mainline/Makefile0000644000175000017500000000434312002272735014724 0ustar vsevavsevaPACKAGE=lua-uri VERSION=$(shell head -1 Changes | sed 's/ .*//') RELEASEDATE=$(shell head -1 Changes | sed 's/.* //') PREFIX=/usr/local DISTNAME=$(PACKAGE)-$(VERSION) # The path to where the module's source files should be installed. LUA_SPATH:=$(shell pkg-config lua5.1 --define-variable=prefix=$(PREFIX) \ --variable=INSTALL_LMOD) MANPAGES = doc/lua-uri.3 doc/lua-uri-_login.3 doc/lua-uri-_util.3 doc/lua-uri-data.3 doc/lua-uri-file.3 doc/lua-uri-ftp.3 doc/lua-uri-http.3 doc/lua-uri-pop.3 doc/lua-uri-rtsp.3 doc/lua-uri-telnet.3 doc/lua-uri-urn.3 doc/lua-uri-urn-isbn.3 doc/lua-uri-urn-issn.3 doc/lua-uri-urn-oid.3 all: $(MANPAGES) doc/lua-%.3: doc/lua-%.pod Changes sed 's/E/(c)/g' <$< | sed 's/E/-/g' | \ pod2man --center="Lua $(shell echo $< | sed 's/^doc\/lua-//' | sed 's/\.pod$$//' | sed 's/-/./g') module" \ --name="$(shell echo $< | sed 's/^doc\///' | sed 's/\.pod$$//' | tr a-z A-Z)" --section=3 \ --release="$(VERSION)" --date="$(RELEASEDATE)" >$@ test: all echo 'lunit.main({...})' | $(VALGRIND) lua -llunit - test/*.lua install: all mkdir -p $(LUA_SPATH)/uri/{file,urn} mkdir -p $(PREFIX)/share/man/man3 install --mode=644 uri.lua $(LUA_SPATH)/ for module in _login _relative _util data file ftp http https pop rtsp rtspu telnet urn; do \ install --mode=644 uri/$$module.lua $(LUA_SPATH)/uri/; \ done for module in unix win32; do \ install --mode=644 uri/file/$$module.lua $(LUA_SPATH)/uri/file/; \ done for module in isbn issn oid; do \ install --mode=644 uri/urn/$$module.lua $(LUA_SPATH)/uri/urn/; \ done for manpage in $(MANPAGES); do \ gzip -c $$manpage >$(PREFIX)/share/man/man3/$$(echo $$manpage | sed -e 's/^doc\///').gz; \ done checktmp: @if [ -e tmp ]; then \ echo "Can't proceed if file 'tmp' exists"; \ false; \ fi dist: all checktmp mkdir -p tmp/$(DISTNAME) tar cf - --files-from MANIFEST | (cd tmp/$(DISTNAME) && tar xf -) cd tmp && tar cf - $(DISTNAME) | gzip -9 >../$(DISTNAME).tar.gz cd tmp && tar cf - $(DISTNAME) | bzip2 -9 >../$(DISTNAME).tar.bz2 rm -f $(DISTNAME).zip cd tmp && zip -q -r -9 ../$(DISTNAME).zip $(DISTNAME) rm -rf tmp clean: rm -f $(MANPAGES) .PHONY: all test install checktmp dist clean lua-uri-mainline/COPYRIGHT0000644000175000017500000000227212002272735014556 0ustar vsevavsevaThis software and documentation is distributed under the same terms as Lua version 5.0, the MIT/X Consortium license. The full terms are as follows: Copyright (C) 2007 Geoff Richards Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. lua-uri-mainline/lunit-console.lua0000644000175000017500000000657112002272735016567 0ustar vsevavseva --[[-------------------------------------------------------------------------- This file is part of lunit 0.5. For Details about lunit look at: http://www.mroth.net/lunit/ Author: Michael Roth Copyright (c) 2006-2008 Michael Roth Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]]-------------------------------------------------------------------------- --[[ begin() run(testcasename, testname) err(fullname, message, traceback) fail(fullname, where, message, usermessage) pass(testcasename, testname) done() Fullname: testcase.testname testcase.testname:setupname testcase.testname:teardownname --]] require "lunit" module( "lunit-console", package.seeall ) local function printformat(format, ...) io.write( string.format(format, ...) ) end local columns_printed = 0 local function writestatus(char) if columns_printed == 0 then io.write(" ") end if columns_printed == 60 then io.write("\n ") columns_printed = 0 end io.write(char) io.flush() columns_printed = columns_printed + 1 end local msgs = {} function begin() local total_tc = 0 local total_tests = 0 for tcname in lunit.testcases() do total_tc = total_tc + 1 for testname, test in lunit.tests(tcname) do total_tests = total_tests + 1 end end printformat("Loaded testsuite with %d tests in %d testcases.\n\n", total_tests, total_tc) end function run(testcasename, testname) -- NOP end function err(fullname, message, traceback) writestatus("E") msgs[#msgs+1] = "Error! ("..fullname.."):\n"..message.."\n\t"..table.concat(traceback, "\n\t") .. "\n" end function fail(fullname, where, message, usermessage) writestatus("F") local text = "Failure ("..fullname.."):\n".. where..": "..message.."\n" if usermessage then text = text .. where..": "..usermessage.."\n" end msgs[#msgs+1] = text end function pass(testcasename, testname) writestatus(".") end function done() printformat("\n\n%d Assertions checked.\n", lunit.stats.assertions ) print() for i, msg in ipairs(msgs) do printformat( "%3d) %s\n", i, msg ) end printformat("Testsuite finished (%d passed, %d failed, %d errors).\n", lunit.stats.passed, lunit.stats.failed, lunit.stats.errors ) end lua-uri-mainline/test/0000755000175000017500000000000012002272735014237 5ustar vsevavsevalua-uri-mainline/test/data.lua0000644000175000017500000001043212002272735015653 0ustar vsevavsevarequire "uri-test" local URI = require "uri" local Util = require "uri._util" local Filter = Util.attempt_require("datafilter") module("test.data", lunit.testcase, package.seeall) function test_data_uri_encoded () local uri = assert(URI:new("data:,A%20brief%20note")) is("uri.data", uri._NAME) is(",A%20brief%20note", uri:path()) is("data", uri:scheme()) is("text/plain;charset=US-ASCII", uri:data_media_type()) is("A brief note", uri:data_bytes()) local old = uri:data_bytes("F\229r-i-k\229l er tingen!") is("A brief note", old) is("data:,F%E5r-i-k%E5l%20er%20tingen!", tostring(uri)) old = uri:data_media_type("text/plain;charset=iso-8859-1") is("text/plain;charset=US-ASCII", old) is("data:text/plain;charset=iso-8859-1,F%E5r-i-k%E5l%20er%20tingen!", tostring(uri)) end function test_data_big_base64_chunk () local imgdata = "R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7" local uri = assert(URI:new("data:image/gif;base64," .. imgdata)) is("image/gif", uri:data_media_type()) if Filter then local gotdata = uri:data_bytes() is(273, gotdata:len()) is(imgdata, Filter.base64_encode(gotdata)) end end function test_data_containing_commas () local uri = assert(URI:new("data:application/vnd-xxx-query,select_vcount,fcol_from_fieldtable/local")) is("application/vnd-xxx-query", uri:data_media_type()) is("select_vcount,fcol_from_fieldtable/local", uri:data_bytes()) uri:data_bytes("") is("data:application/vnd-xxx-query,", tostring(uri)) uri:data_bytes("a,b") uri:data_media_type(nil) is("data:,a,b", tostring(uri)) is("a,b", uri:data_bytes(nil)) is("", uri:data_bytes()) end function test_automatic_selection_of_uri_or_base64_encoding () local uri = assert(URI:new("data:,")) uri:data_bytes("") is("data:,", tostring(uri)) uri:data_bytes(">") is("data:,%3E", tostring(uri)) is(">", uri:data_bytes()) uri:data_bytes(">>>>>") is("data:,%3E%3E%3E%3E%3E", tostring(uri)) if Filter then uri:data_bytes(">>>>>>") is("data:;base64,Pj4+Pj4+", tostring(uri)) uri:data_media_type("text/plain;foo=bar") is("data:text/plain;foo=bar;base64,Pj4+Pj4+", tostring(uri)) uri:data_media_type("foo") is("data:foo;base64,Pj4+Pj4+", tostring(uri)) uri:data_bytes((">"):rep(3000)) is("data:foo;base64," .. ("Pj4+"):rep(1000), tostring(uri)) is((">"):rep(3000), uri:data_bytes()) else uri:data_bytes(">>>>>>") is("data:,%3E%3E%3E%3E%3E%3E", tostring(uri)) uri:data_media_type("foo") is("data:foo,%3E%3E%3E%3E%3E%3E", tostring(uri)) end uri:data_media_type(nil) uri:data_bytes(nil) is("data:,", tostring(uri)) end function test_bad_uri () is_bad_uri("missing comma", "data:foo") is_bad_uri("no path at all", "data:") is_bad_uri("has host", "data://host/,") end function test_set_path () local uri = assert(URI:new("data:image/gif,foobar")) is("image/gif,foobar", uri:path("image/jpeg;foo=bar,x y,?")) is("image/jpeg;foo=bar,x%20y,%3F", uri:path(",blah")) is(",blah", uri:path(",")) is(",", uri:path()) is("data:,", tostring(uri)) end function test_set_path_bad () local uri = assert(URI:new("data:image/gif,foobar")) assert_error("no path", function () uri:path(nil) end) assert_error("empty path", function () uri:path("") end) assert_error("no comma", function () uri:path("foo;bar") end) assert_error("bad base64 encoding", function () uri:path(";base64,x_0") end) is("image/gif,foobar", uri:path()) is("data:image/gif,foobar", tostring(uri)) end function test_set_disallowed_stuff () local uri = assert(URI:new("data:,")) assert_error("can't set userinfo", function () uri:userinfo("x") end) assert_error("can't set host", function () uri:host("x") end) assert_error("can't set port", function () uri:port(23) end) is("data:,", tostring(uri)) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/ftp.lua0000644000175000017500000000314412002272735015535 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.ftp", lunit.testcase, package.seeall) function test_ftp () local uri = assert(URI:new("ftp://ftp.example.com/path")) is("ftp", uri:scheme()) is("ftp.example.com", uri:host()) is(21, uri:port()) is(nil, uri:userinfo()) is(nil, uri:username()) is(nil, uri:password()) end function test_ftp_typecode () local uri = assert(URI:new("ftp://host/path")) is(nil, uri:ftp_typecode()) is(nil, uri:ftp_typecode("d")) is("/path;type=d", uri:path()) is("ftp://host/path;type=d", tostring(uri)) is("d", uri:ftp_typecode("a")) is("/path;type=a", uri:path()) is("ftp://host/path;type=a", tostring(uri)) is("a", uri:ftp_typecode("")) is("/path", uri:path()) is("ftp://host/path", tostring(uri)) local uri = assert(URI:new("ftp://host/path;type=xyzzy")) is("/path;type=xyzzy", uri:path()) is("ftp://host/path;type=xyzzy", tostring(uri)) is("xyzzy", uri:ftp_typecode()) is("xyzzy", uri:ftp_typecode(nil)) is(nil, uri:ftp_typecode()) is("/path", uri:path()) is("ftp://host/path", tostring(uri)) end function test_normalize_path () local uri = assert(URI:new("ftp://host")) is("ftp://host/", tostring(uri)) is("/", uri:path("/foo")) is("/foo", uri:path("")) is("/", uri:path("/foo")) is("/foo", uri:path(nil)) is("/", uri:path()) end function test_bad_host () is_bad_uri("missing authority, just scheme", "ftp:") is_bad_uri("missing authority, just scheme and path", "ftp:/foo") is_bad_uri("empty host", "ftp:///foo") end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/_generic.lua0000644000175000017500000006047112002272735016525 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.generic", lunit.testcase, package.seeall) function test_normalize_percent_encoding () -- Don't use unnecessary percent encoding for unreserved characters. test_norm("x:ABCDEFGHIJKLM", "x:%41%42%43%44%45%46%47%48%49%4A%4b%4C%4d") test_norm("x:NOPQRSTUVWXYZ", "x:%4E%4f%50%51%52%53%54%55%56%57%58%59%5A") test_norm("x:abcdefghijklm", "x:%61%62%63%64%65%66%67%68%69%6A%6b%6C%6d") test_norm("x:nopqrstuvwxyz", "x:%6E%6f%70%71%72%73%74%75%76%77%78%79%7A") test_norm("x:0123456789", "x:%30%31%32%33%34%35%36%37%38%39") test_norm("x:-._~", "x:%2D%2e%5F%7e") -- Keep percent encoding for other characters in US-ASCII. test_norm_already("x:%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F") test_norm_already("x:%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F") test_norm_already("x:%20%21%22%23%24%25%26%27%28%29%2A%2B%2C") test_norm_already("x:%2F") test_norm_already("x:%3A%3B%3C%3D%3E%3F%40") test_norm_already("x:%5B%5C%5D%5E") test_norm_already("x:%60") test_norm_already("x:%7B%7C%7D") test_norm_already("x:%7F") -- Normalize hex digits in percent encoding to uppercase. test_norm("x:%0A%0B%0C%0D%0E%0F", "x:%0a%0b%0c%0d%0e%0f") test_norm("x:%AA%BB%CC%DD%EE%FF", "x:%aA%bB%cC%dD%eE%fF") -- Keep percent encoding, and normalize hex digit case, for all characters -- outside US-ASCII. for i = 0x80, 0xFF do test_norm_already(string.format("x:%%%02X", i)) test_norm(string.format("x:%%%02X", i), string.format("x:%%%02x", i)) end end function test_bad_percent_encoding () assert_error("double percent", function () URI:new("x:foo%%2525") end) assert_error("no hex digits", function () URI:new("x:foo%") end) assert_error("no hex digits 2nd time", function () URI:new("x:f%20o%") end) assert_error("1 hex digit", function () URI:new("x:foo%2") end) assert_error("1 hex digit 2nd time", function () URI:new("x:f%20o%2") end) assert_error("bad hex digit 1", function () URI:new("x:foo%G2bar") end) assert_error("bad hex digit 2", function () URI:new("x:foo%2Gbar") end) assert_error("bad hex digit both", function () URI:new("x:foo%GGbar") end) end function test_scheme () test_norm_already("foo:") test_norm_already("foo:-+.:") test_norm_already("foo:-+.0123456789:") test_norm_already("x:") test_norm("example:FooBar:Baz", "ExAMplE:FooBar:Baz") local uri = assert(URI:new("Foo-Bar:Baz%20Quux")) is("foo-bar", uri:scheme()) end function test_change_scheme () local uri = assert(URI:new("x-foo://example.com/blah")) is("x-foo://example.com/blah", tostring(uri)) is("x-foo", uri:scheme()) is("uri", uri._NAME) -- x-foo -> x-bar is("x-foo", uri:scheme("x-bar")) is("x-bar", uri:scheme()) is("x-bar://example.com/blah", tostring(uri)) is("uri", uri._NAME) -- x-bar -> http is("x-bar", uri:scheme("http")) is("http", uri:scheme()) is("http://example.com/blah", tostring(uri)) is("uri.http", uri._NAME) -- http -> x-foo is("http", uri:scheme("x-foo")) is("x-foo", uri:scheme()) is("x-foo://example.com/blah", tostring(uri)) is("uri", uri._NAME) end function test_change_scheme_bad () local uri = assert(URI:new("x-foo://foo@bar/")) -- Try changing the scheme to something invalid assert_error("bad scheme '-x-foo'", function () uri:scheme("-x-foo") end) assert_error("bad scheme 'x,foo'", function () uri:scheme("x,foo") end) assert_error("bad scheme 'x:foo'", function () uri:scheme("x:foo") end) assert_error("bad scheme 'x-foo:'", function () uri:scheme("x-foo:") end) -- Change to valid scheme, but where the rest of the URI is not valid for it assert_error("bad HTTP URI", function () uri:scheme("http") end) -- Original URI should be left unchanged is("x-foo://foo@bar/", tostring(uri)) is("x-foo", uri:scheme()) is("uri", uri._NAME) end function test_auth_userinfo () local uri = assert(URI:new("X://a-zA-Z09!$:&%40@FOO.com:80/")) is("x://a-zA-Z09!$:&%40@foo.com:80/", tostring(uri)) is("x", uri:scheme()) is("a-zA-Z09!$:&%40", uri:userinfo()) is("foo.com", uri:host()) is(80, uri:port()) end function test_auth_userinfo_bad () is_bad_uri("bad character in userinfo", "x-a://foo^bar@example.com/") end function test_auth_set_userinfo () local uri = assert(URI:new("X-foo://user:pass@FOO.com:80/")) is("user:pass", uri:userinfo("newuserinfo")) is("newuserinfo", uri:userinfo()) is("x-foo://newuserinfo@foo.com:80/", tostring(uri)) -- Userinfo should be supplied already percent-encoded, but the percent -- encoding should be normalized. is("newuserinfo", uri:userinfo("foo%3abar%3A:%78")) is("foo%3Abar%3A:x", uri:userinfo()) -- It should be OK to use more than one colon in userinfo for generic URIs, -- although not for ones which specificly divide it into username:password. is("foo%3Abar%3A:x", uri:userinfo("foo:bar:baz::")) is("foo:bar:baz::", uri:userinfo()) end function test_auth_set_bad_userinfo () local uri = assert(URI:new("X-foo://user:pass@FOO.com:80/")) assert_error("/ in userinfo", function () uri:userinfo("foo/bar") end) assert_error("@ in userinfo", function () uri:userinfo("foo@bar") end) is("user:pass", uri:userinfo()) is("x-foo://user:pass@foo.com:80/", tostring(uri)) end function test_auth_reg_name () local uri = assert(URI:new("x://azAZ0-9--foo.bqr_baz~%20!$;/")) -- TODO - %20 should probably be rejected. Apparently only UTF-8 pctenc -- should be produced, so after unescaping unreserved chars there should -- be nothing left percent encoded other than valid UTF-8 sequences. If -- that's right I could safely decode the host before returning it. is("azaz0-9--foo.bqr_baz~%20!$;", uri:host()) end function test_auth_ip4 () local uri = assert(URI:new("x://0.0.0.0/path")) is("0.0.0.0", uri:host()) uri = assert(URI:new("x://192.168.0.1/path")) is("192.168.0.1", uri:host()) uri = assert(URI:new("x://255.255.255.255/path")) is("255.255.255.255", uri:host()) end function test_auth_ip4_or_reg_name_bad () is_bad_uri("bad character in host part", "x://foo:bar/") end function test_auth_ip6 () -- The example addresses in here are all from RFC 4291 section 2.2, except -- that they get normalized to lowercase here in the results. local uri = assert(URI:new("x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]")) is("[abcd:ef01:2345:6789:abcd:ef01:2345:6789]", uri:host()) uri = assert(URI:new("x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]/")) is("[abcd:ef01:2345:6789:abcd:ef01:2345:6789]", uri:host()) uri = assert(URI:new("x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]:")) is("[abcd:ef01:2345:6789:abcd:ef01:2345:6789]", uri:host()) uri = assert(URI:new("x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]:/")) is("[abcd:ef01:2345:6789:abcd:ef01:2345:6789]", uri:host()) uri = assert(URI:new("x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]:0/")) is("[abcd:ef01:2345:6789:abcd:ef01:2345:6789]", uri:host()) uri = assert(URI:new("x://y:z@[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]:80/")) is("[abcd:ef01:2345:6789:abcd:ef01:2345:6789]", uri:host()) uri = assert(URI:new("x://[2001:DB8:0:0:8:800:200C:417A]/")) is("[2001:db8:0:0:8:800:200c:417a]", uri:host()) uri = assert(URI:new("x://[FF01:0:0:0:0:0:0:101]/")) is("[ff01:0:0:0:0:0:0:101]", uri:host()) uri = assert(URI:new("x://[ff01::101]/")) is("[ff01::101]", uri:host()) uri = assert(URI:new("x://[0:0:0:0:0:0:0:1]/")) is("[0:0:0:0:0:0:0:1]", uri:host()) uri = assert(URI:new("x://[::1]/")) is("[::1]", uri:host()) uri = assert(URI:new("x://[0:0:0:0:0:0:0:0]/")) is("[0:0:0:0:0:0:0:0]", uri:host()) uri = assert(URI:new("x://[0:0:0:0:0:0:13.1.68.3]/")) is("[0:0:0:0:0:0:13.1.68.3]", uri:host()) uri = assert(URI:new("x://[::13.1.68.3]/")) is("[::13.1.68.3]", uri:host()) uri = assert(URI:new("x://[0:0:0:0:0:FFFF:129.144.52.38]/")) is("[0:0:0:0:0:ffff:129.144.52.38]", uri:host()) uri = assert(URI:new("x://[::FFFF:129.144.52.38]/")) is("[::ffff:129.144.52.38]", uri:host()) -- These try all the cominations of abbreviating using '::'. uri = assert(URI:new("x://[08:19:2a:3B:4c:5D:6e:7F]/")) is("[08:19:2a:3b:4c:5d:6e:7f]", uri:host()) uri = assert(URI:new("x://[::19:2a:3B:4c:5D:6e:7F]/")) is("[::19:2a:3b:4c:5d:6e:7f]", uri:host()) uri = assert(URI:new("x://[::2a:3B:4c:5D:6e:7F]/")) is("[::2a:3b:4c:5d:6e:7f]", uri:host()) uri = assert(URI:new("x://[::3B:4c:5D:6e:7F]/")) is("[::3b:4c:5d:6e:7f]", uri:host()) uri = assert(URI:new("x://[::4c:5D:6e:7F]/")) is("[::4c:5d:6e:7f]", uri:host()) uri = assert(URI:new("x://[::5D:6e:7F]/")) is("[::5d:6e:7f]", uri:host()) uri = assert(URI:new("x://[::6e:7F]/")) is("[::6e:7f]", uri:host()) uri = assert(URI:new("x://[::7F]/")) is("[::7f]", uri:host()) uri = assert(URI:new("x://[::]/")) is("[::]", uri:host()) uri = assert(URI:new("x://[08::]/")) is("[08::]", uri:host()) uri = assert(URI:new("x://[08:19::]/")) is("[08:19::]", uri:host()) uri = assert(URI:new("x://[08:19:2a::]/")) is("[08:19:2a::]", uri:host()) uri = assert(URI:new("x://[08:19:2a:3B::]/")) is("[08:19:2a:3b::]", uri:host()) uri = assert(URI:new("x://[08:19:2a:3B:4c::]/")) is("[08:19:2a:3b:4c::]", uri:host()) uri = assert(URI:new("x://[08:19:2a:3B:4c:5D::]/")) is("[08:19:2a:3b:4c:5d::]", uri:host()) uri = assert(URI:new("x://[08:19:2a:3B:4c:5D:6e::]/")) is("[08:19:2a:3b:4c:5d:6e::]", uri:host()) -- Try extremes of good IPv4 addresses mapped to IPv6. uri = assert(URI:new("x://[::FFFF:0.0.0.0]/path")) is("[::ffff:0.0.0.0]", uri:host()) uri = assert(URI:new("x://[::ffff:255.255.255.255]/path")) is("[::ffff:255.255.255.255]", uri:host()) end function test_auth_ip6_bad () is_bad_uri("empty brackets", "x://[]") is_bad_uri("just colon", "x://[:]") is_bad_uri("3 colons only", "x://[:::]") is_bad_uri("3 colons at start", "x://[:::1234]") is_bad_uri("3 colons at end", "x://[1234:::]") is_bad_uri("3 colons in middle", "x://[1234:::5678]") is_bad_uri("non-hex char", "x://[ABCD:EF01:2345:6789:ABCD:EG01:2345:6789]") is_bad_uri("chunk too big", "x://[ABCD:EF01:2345:6789:ABCD:EFF01:2345:6789]") is_bad_uri("too many chunks", "x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789:1]") is_bad_uri("not enough chunks", "x://[ABCD:EF01:2345:6789:ABCD:EF01:2345]") is_bad_uri("too many chunks with ellipsis in middle", "x://[ABCD:EF01:2345:6789:ABCD::EF01:2345:6789]") is_bad_uri("too many chunks with ellipsis at end", "x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789::]") is_bad_uri("too many chunks with ellipsis at start", "x://[::ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]") is_bad_uri("two elipses, middle and end", "x://[EF01:2345::6789:ABCD:EF01:2345::]") is_bad_uri("two elipses, start and middle", "x://[::EF01:2345::6789:ABCD:EF01:2345]") is_bad_uri("two elipses, both ends", "x://[::EF01:2345:6789:ABCD:EF01:2345::]") is_bad_uri("two elipses, both middle", "x://[EF01:2345::6789:ABCD:::EF01:2345]") is_bad_uri("extra colon at start", "x://[:ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]") is_bad_uri("missing chunk at start", "x://[:EF01:2345:6789:ABCD:EF01:2345:6789]") is_bad_uri("extra colon at end", "x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789:]") is_bad_uri("missing chunk at end", "x://[ABCD:EF01:2345:6789:ABCD:EF01:2345:]") -- Bad IPv4 addresses mapped to IPv6. is_bad_uri("octet 1 too big", "x://[::FFFF:256.2.3.4]/") is_bad_uri("octet 2 too big", "x://[::FFFF:1.256.3.4]/") is_bad_uri("octet 3 too big", "x://[::FFFF:1.2.256.4]/") is_bad_uri("octet 4 too big", "x://[::FFFF:1.2.3.256]/") is_bad_uri("octet 1 leading zeroes", "x://[::FFFF:01.2.3.4]/") is_bad_uri("octet 2 leading zeroes", "x://[::FFFF:1.02.3.4]/") is_bad_uri("octet 3 leading zeroes", "x://[::FFFF:1.2.03.4]/") is_bad_uri("octet 4 leading zeroes", "x://[::FFFF:1.2.3.04]/") is_bad_uri("only 2 octets", "x://[::FFFF:1.2]/") is_bad_uri("only 3 octets", "x://[::FFFF:1.2.3]/") is_bad_uri("5 octets", "x://[::FFFF:1.2.3.4.5]/") end function test_auth_ipvfuture () local uri = assert(URI:new("x://[v123456789ABCdef.foo=bar]/")) is("[v123456789abcdef.foo=bar]", uri:host()) end function test_auth_ipvfuture_bad () is_bad_uri("missing dot", "x://[v999]") is_bad_uri("missing hex num", "x://[v.foo]") is_bad_uri("missing bit after dot", "x://[v999.]") is_bad_uri("bad character in hex num", "x://[v99g.foo]") is_bad_uri("bad character after dot", "x://[v999.foo:bar]") end function test_auth_set_host () local uri = assert(URI:new("x-a://host/path")) is("host", uri:host("FOO.BAR")) is("x-a://foo.bar/path", tostring(uri)) is("foo.bar", uri:host("[::6e:7F]")) is("x-a://[::6e:7f]/path", tostring(uri)) is("[::6e:7f]", uri:host("[v7F.foo=BAR]")) is("x-a://[v7f.foo=bar]/path", tostring(uri)) is("[v7f.foo=bar]", uri:host("")) is("x-a:///path", tostring(uri)) is("", uri:host(nil)) is(nil, uri:host()) is("x-a:/path", tostring(uri)) end function test_auth_set_host_bad () local uri = assert(URI:new("x-a://host/path")) assert_error("bad char in host", function () uri:host("foo^bar") end) assert_error("invalid IPv6 host", function () uri:host("[::3G]") end) assert_error("invalid IPvFuture host", function () uri:host("[v7.]") end) is("host", uri:host()) is("x-a://host/path", tostring(uri)) -- There must be a hsot when there is a userinfo or port. uri = assert(URI:new("x-a://foo@/")) assert_error("userinfo but no host", function () uri:host(nil) end) is("x-a://foo@/", tostring(uri)) uri = assert(URI:new("x-a://:123/")) assert_error("port but no host", function () uri:host(nil) end) is("x-a://:123/", tostring(uri)) end function test_auth_port () local uri = assert(URI:new("x://localhost:0/path")) is(0, uri:port()) uri = assert(URI:new("x://localhost:0")) is(0, uri:port()) uri = assert(URI:new("x://foo:bar@localhost:0")) is(0, uri:port()) uri = assert(URI:new("x://localhost:00/path")) is(0, uri:port()) uri = assert(URI:new("x://localhost:00")) is(0, uri:port()) uri = assert(URI:new("x://foo:bar@localhost:00")) is(0, uri:port()) uri = assert(URI:new("x://localhost:54321/path")) is(54321, uri:port()) uri = assert(URI:new("x://localhost:54321")) is(54321, uri:port()) uri = assert(URI:new("x://foo:bar@localhost:54321")) is(54321, uri:port()) uri = assert(URI:new("x://foo:bar@localhost:")) is(nil, uri:port()) uri = assert(URI:new("x://foo:bar@localhost:/")) is(nil, uri:port()) uri = assert(URI:new("x://foo:bar@localhost")) is(nil, uri:port()) uri = assert(URI:new("x://foo:bar@localhost/")) is(nil, uri:port()) end function test_auth_set_port () -- Test unusual but valid values for port. local uri = assert(URI:new("x://localhost/path")) is(nil, uri:port("12345")) -- string is(12345, uri:port()) is("x://localhost:12345/path", tostring(uri)) uri = assert(URI:new("x://localhost/path")) is(nil, uri:port(12345.0)) -- float is(12345, uri:port()) is("x://localhost:12345/path", tostring(uri)) end function test_auth_set_port_without_host () local uri = assert(URI:new("x:///path")) is(nil, uri:port(80)) is(80, uri:port()) is("", uri:host()) is("x://:80/path", tostring(uri)) uri = assert(URI:new("x:/path")) is(nil, uri:port(80)) is(80, uri:port()) is("", uri:host()) is("x://:80/path", tostring(uri)) end function test_auth_set_port_bad () local uri = assert(URI:new("x://localhost:54321/path")) assert_error("negative port number", function () uri:port(-23) end) assert_error("port not integer", function () uri:port(23.00001) end) assert_error("string not number", function () uri:port("x") end) assert_error("string not all number", function () uri:port("x23") end) assert_error("string negative number", function () uri:port("-23") end) assert_error("string empty", function () uri:port("") end) is(54321, uri:port()) is("x://localhost:54321/path", tostring(uri)) end function test_path () local uri = assert(URI:new("x:")) is("", uri:path()) uri = assert(URI:new("x:?")) is("", uri:path()) uri = assert(URI:new("x:#")) is("", uri:path()) uri = assert(URI:new("x:/")) is("/", uri:path()) uri = assert(URI:new("x://")) is("", uri:path()) uri = assert(URI:new("x://?")) is("", uri:path()) uri = assert(URI:new("x://#")) is("", uri:path()) uri = assert(URI:new("x:///")) is("/", uri:path()) uri = assert(URI:new("x:////")) is("//", uri:path()) uri = assert(URI:new("x:foo")) is("foo", uri:path()) uri = assert(URI:new("x:/foo")) is("/foo", uri:path()) uri = assert(URI:new("x://foo")) is("", uri:path()) uri = assert(URI:new("x://foo?")) is("", uri:path()) uri = assert(URI:new("x://foo#")) is("", uri:path()) uri = assert(URI:new("x:///foo")) is("/foo", uri:path()) uri = assert(URI:new("x:////foo")) is("//foo", uri:path()) uri = assert(URI:new("x://foo/")) is("/", uri:path()) uri = assert(URI:new("x://foo/bar")) is("/bar", uri:path()) end function test_path_bad () is_bad_uri("bad character in path", "x-a://host/^/") end function test_set_path_without_auth () local uri = assert(URI:new("x:blah")) is("blah", uri:path("frob%25%3a%78/%2F")) is("frob%25%3Ax/%2F", uri:path("/foo/bar")) is("/foo/bar", uri:path("//foo//bar")) is("/%2Ffoo//bar", uri:path("x ?#\"\0\127\255")) is("x%20%3F%23%22%00%7F%FF", uri:path("")) is("", uri:path(nil)) is("", uri:path()) is("x:", tostring(uri)) end function test_set_path_with_auth () local uri = assert(URI:new("x://host/wibble")) is("/wibble", uri:path("/foo/bar")) is("/foo/bar", uri:path("//foo//bar")) is("//foo//bar", uri:path(nil)) is("", uri:path("")) is("", uri:path()) is("x://host", tostring(uri)) end function test_set_path_bad () local uri = assert(URI:new("x://host/wibble")) tostring(uri) assert_error("with authority, path must start with /", function () uri:path("foo") end) assert_error("bad %-encoding, % at end", function () uri:path("foo%") end) assert_error("bad %-encoding, %2 at end", function () uri:path("foo%2") end) assert_error("bad %-encoding, %gf", function () uri:path("%gf") end) assert_error("bad %-encoding, %fg", function () uri:path("%fg") end) is("/wibble", uri:path()) is("x://host/wibble", tostring(uri)) end function test_query () local uri = assert(URI:new("x:?")) is("", uri:query()) uri = assert(URI:new("x:")) is(nil, uri:query()) uri = assert(URI:new("x:/foo")) is(nil, uri:query()) uri = assert(URI:new("x:/foo#")) is(nil, uri:query()) uri = assert(URI:new("x:/foo#bar?baz")) is(nil, uri:query()) uri = assert(URI:new("x:/foo?")) is("", uri:query()) uri = assert(URI:new("x://foo?")) is("", uri:query()) uri = assert(URI:new("x://foo/?")) is("", uri:query()) uri = assert(URI:new("x:/foo?bar")) is("bar", uri:query()) uri = assert(URI:new("x:?foo?bar?")) is("foo?bar?", uri:query()) uri = assert(URI:new("x:?foo?bar?#quux?frob")) is("foo?bar?", uri:query()) uri = assert(URI:new("x://foo/bar%3Fbaz?")) is("", uri:query()) uri = assert(URI:new("x:%3F?foo")) is("%3F", uri:path()) is("foo", uri:query()) end function test_query_bad () is_bad_uri("bad character in query", "x-a://host/path/?foo^bar") end function test_set_query () local uri = assert(URI:new("x://host/path")) is(nil, uri:query("foo/bar?baz")) is("x://host/path?foo/bar?baz", tostring(uri)) is("foo/bar?baz", uri:query("")) is("x://host/path?", tostring(uri)) is("", uri:query("foo^bar#baz")) is("x://host/path?foo%5Ebar%23baz", tostring(uri)) is("foo%5Ebar%23baz", uri:query(nil)) is(nil, uri:query()) is("x://host/path", tostring(uri)) end function test_fragment () local uri = assert(URI:new("x:")) is(nil, uri:fragment()) uri = assert(URI:new("x:#")) is("", uri:fragment()) uri = assert(URI:new("x://#")) is("", uri:fragment()) uri = assert(URI:new("x:///#")) is("", uri:fragment()) uri = assert(URI:new("x:////#")) is("", uri:fragment()) uri = assert(URI:new("x:#foo")) is("foo", uri:fragment()) uri = assert(URI:new("x:%23#foo")) is("%23", uri:path()) is("foo", uri:fragment()) uri = assert(URI:new("x:?foo?bar?#quux?frob")) is("quux?frob", uri:fragment()) end function test_fragment_bad () is_bad_uri("bad character in fragment", "x-a://host/path/#foo^bar") end function test_set_fragment () local uri = assert(URI:new("x://host/path")) is(nil, uri:fragment("foo/bar#baz")) is("x://host/path#foo/bar%23baz", tostring(uri)) is("foo/bar%23baz", uri:fragment("")) is("x://host/path#", tostring(uri)) is("", uri:fragment("foo^bar?baz")) is("x://host/path#foo%5Ebar?baz", tostring(uri)) is("foo%5Ebar?baz", uri:fragment(nil)) is(nil, uri:fragment()) is("x://host/path", tostring(uri)) end function test_bad_usage () assert_error("missing uri arg", function () URI:new() end) assert_error("nil uri arg", function () URI:new(nil) end) end function test_clone_with_new () -- Test cloning with as many components set as possible. local uri = assert(URI:new("x-foo://user:pass@bar.com:123/blah?q#frag")) tostring(uri) local clone = URI:new(uri) assert_table(clone) is("x-foo://user:pass@bar.com:123/blah?q#frag", tostring(uri)) is("x-foo://user:pass@bar.com:123/blah?q#frag", tostring(clone)) is("uri", getmetatable(uri)._NAME) is("uri", getmetatable(clone)._NAME) -- Test cloning with less stuff specified, but not in the base class. uri = assert(URI:new("http://example.com/")) clone = URI:new(uri) assert_table(clone) is("http://example.com/", tostring(uri)) is("http://example.com/", tostring(clone)) is("uri.http", getmetatable(uri)._NAME) is("uri.http", getmetatable(clone)._NAME) end function test_set_uri () local uri = assert(URI:new("x-foo://user:pass@bar.com:123/blah?q#frag")) is("x-foo://user:pass@bar.com:123/blah?q#frag", uri:uri("http://example.com:81/blah2?q2#frag2")) is("http://example.com:81/blah2?q2#frag2", uri:uri()) is("uri.http", getmetatable(uri)._NAME) is("http", uri:scheme()) is("q2", uri:query()) is("http://example.com:81/blah2?q2#frag2", uri:uri("Urn:X-FOO:bar")) is("uri.urn", getmetatable(uri)._NAME) is("x-foo", uri:nid()) is("urn:x-foo:bar", tostring(uri)) end function test_set_uri_bad () local uri = assert(URI:new("x-foo://user:pass@bar.com:123/blah?q#frag")) assert_error("can't set URI to nil", function () uri:uri(nil) end) assert_error("invalid authority", function () uri:uri("foo://@@") end) is("x-foo://user:pass@bar.com:123/blah?q#frag", uri:uri()) is("uri", getmetatable(uri)._NAME) is("x-foo", uri:scheme()) end function test_eq () local uri1str, uri2str = "x-a://host/foo", "x-a://host/bar" local uri1obj, uri2obj = assert(URI:new(uri1str)), assert(URI:new(uri2str)) assert_true(URI.eq(uri1str, uri1str), "str == str") assert_false(URI.eq(uri1str, uri2str), "str ~= str") assert_true(URI.eq(uri1str, uri1obj), "str == obj") assert_false(URI.eq(uri1str, uri2obj), "str ~= obj") assert_true(URI.eq(uri1obj, uri1str), "obj == str") assert_false(URI.eq(uri1obj, uri2str), "obj ~= str") assert_true(URI.eq(uri1obj, uri1obj), "obj == obj") assert_false(URI.eq(uri1obj, uri2obj), "obj ~= obj") end function test_eq_bad_uri () -- Check that an exception is thrown when 'eq' is given a bad URI string, -- and also that it's not just the error from trying to call the 'uri' -- method on nil, because that won't be very helpful to the caller. local ok, err = pcall(URI.eq, "^", "x-a://x/") assert_false(ok) assert_not_match("a nil value", err) ok, err = pcall(URI.eq, "x-a://x/", "^") assert_false(ok) assert_not_match("a nil value", err) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/_pristine.lua0000644000175000017500000000221012002272735016731 0ustar vsevavsevarequire "lunit" module("test.pristine", lunit.testcase, package.seeall) function test_no_global_clobbering () local globals = {} for key in pairs(_G) do globals[key] = true end -- Load all the modules for the different types of URIs, in case any one -- of those treads on a global. I keep them around in a table to make -- sure they're all loaded at the same time, just in case that does -- anything interesting. local schemes = { "_login", "_relative", "_util", "data", "file", "file.unix", "file.win32", "ftp", "http", "https", "pop", "rtsp", "rtspu", "telnet", "urn", "urn.isbn", "urn.issn", "urn.oid" } local loaded = {} local URI = require "uri" for _, name in ipairs(schemes) do loaded[name] = require("uri." .. name) end for key in pairs(_G) do lunit.assert_not_nil(globals[key], "global '" .. key .. "' created by lib") end for key in pairs(globals) do lunit.assert_not_nil(_G[key], "global '" .. key .. "' destroyed by lib") end end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/_relative.lua0000644000175000017500000000407612002272735016723 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.relative", lunit.testcase, package.seeall) local function test_rel (input, userinfo, host, port, path, query, frag, expected) local uri = assert(URI:new(input)) assert_true(uri:is_relative()) is("uri._relative", getmetatable(uri)._NAME) is(nil, uri:scheme()) is(userinfo, uri:userinfo()) is(host, uri:host()) is(port, uri:port()) is(path, uri:path()) is(query, uri:query()) is(frag, uri:fragment()) if not expected then expected = input end is(expected, uri:uri()) is(expected, tostring(uri)) end function test_relative () test_rel("", nil, nil, nil, "", nil, nil) test_rel("foo/bar", nil, nil, nil, "foo/bar", nil, nil) test_rel("/foo/bar", nil, nil, nil, "/foo/bar", nil, nil) test_rel("?query", nil, nil, nil, "", "query", nil) test_rel("?", nil, nil, nil, "", "", nil) test_rel("#foo", nil, nil, nil, "", nil, "foo") test_rel("#", nil, nil, nil, "", nil, "") test_rel("?q#f", nil, nil, nil, "", "q", "f") test_rel("?#", nil, nil, nil, "", "", "") test_rel("foo?q#f", nil, nil, nil, "foo", "q", "f") test_rel("//host.com", nil, "host.com", nil, "", nil, nil) test_rel("//host.com/blah?q#f", nil, "host.com", nil, "/blah", "q", "f") test_rel("//host.com:123/blah?q#f", nil, "host.com", 123, "/blah", "q", "f") test_rel("//u:p@host.com:123/blah?q#f", "u:p", "host.com", 123, "/blah", "q", "f") -- Paths shouldn't be normalized in a relative reference, only after it -- has been used to create an absolute one. test_rel("./foo/bar", nil, nil, nil, "./foo/bar", nil, nil) test_rel("././foo/./bar", nil, nil, nil, "././foo/./bar", nil, nil) test_rel("../foo/bar", nil, nil, nil, "../foo/bar", nil, nil) test_rel("../../foo/../bar", nil, nil, nil, "../../foo/../bar", nil, nil) end function test_bad_usage () local uri = assert(URI:new("foo")) assert_error("set scheme on relative ref", function () uri:scheme("x-foo") end) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/rtsp.lua0000644000175000017500000000271312002272735015735 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.rtsp", lunit.testcase, package.seeall) function test_rtsp () local u = assert(URI:new("RTSP://MEDIA.EXAMPLE.COM:554/twister/audiotrack")) is("rtsp://media.example.com/twister/audiotrack", tostring(u)) is("media.example.com", u:host()) is("/twister/audiotrack", u:path()) end function test_rtspu () local uri = assert(URI:new("rtspu://media.perl.com/f%C3%B4o.smi/")) is("rtspu://media.perl.com/f%C3%B4o.smi/", tostring(uri)) is("media.perl.com", uri:host()) is("/f%C3%B4o.smi/", uri:path()) end function test_switch_scheme () -- Should be no problem switching between TCP and UDP URIs, because they -- have the same syntax. local uri = assert(URI:new("rtsp://media.example.com/twister/audiotrack")) is("rtsp://media.example.com/twister/audiotrack", tostring(uri)) is("rtsp", uri:scheme("rtspu")) is("rtspu://media.example.com/twister/audiotrack", tostring(uri)) is("rtspu", uri:scheme("rtsp")) is("rtsp://media.example.com/twister/audiotrack", tostring(uri)) is("rtsp", uri:scheme()) end function test_rtsp_default_port () local uri = assert(URI:new("rtsp://host/path/")) is(554, uri:port()) uri = assert(URI:new("rtspu://host/path/")) is(554, uri:port()) is(554, uri:port(8554)) is("rtspu://host:8554/path/", tostring(uri)) is(8554, uri:port(554)) is("rtspu://host/path/", tostring(uri)) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/urn-oid.lua0000644000175000017500000000756512002272735016334 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.urn_oid", lunit.testcase, package.seeall) function test_parse_and_normalize () local uri = assert(URI:new("urn:OId:1.3.50403060.0.23")) is("uri.urn.oid", uri._NAME) is("urn:oid:1.3.50403060.0.23", uri:uri()) is("urn:oid:1.3.50403060.0.23", tostring(uri)) is("oid", uri:nid()) is("1.3.50403060.0.23", uri:nss()) is("oid:1.3.50403060.0.23", uri:path()) assert_array_shallow_equal({ 1, 3, 50403060, 0, 23 }, uri:oid_numbers()) -- Examples from RFC 3061 section 3 uri = assert(URI:new("urn:oid:1.3.6.1")) is("urn:oid:1.3.6.1", tostring(uri)) assert_array_shallow_equal({ 1, 3, 6, 1 }, uri:oid_numbers()) uri = assert(URI:new("urn:oid:1.3.6.1.4.1")) is("urn:oid:1.3.6.1.4.1", tostring(uri)) assert_array_shallow_equal({ 1, 3, 6, 1, 4, 1 }, uri:oid_numbers()) uri = assert(URI:new("urn:oid:1.3.6.1.2.1.27")) is("urn:oid:1.3.6.1.2.1.27", tostring(uri)) assert_array_shallow_equal({ 1, 3, 6, 1, 2, 1, 27 }, uri:oid_numbers()) uri = assert(URI:new("URN:OID:0.9.2342.19200300.100.4")) is("urn:oid:0.9.2342.19200300.100.4", tostring(uri)) assert_array_shallow_equal({ 0, 9, 2342, 19200300, 100, 4 }, uri:oid_numbers()) end function test_bad_syntax () is_bad_uri("empty nss", "urn:oid:") is_bad_uri("bad character", "urn:oid:1.2.x.3") is_bad_uri("missing number", "urn:oid:1.2..3") is_bad_uri("leading zero", "urn:oid:1.2.03.3") is_bad_uri("leading zero at start", "urn:oid:01.2.3.3") end function test_set_nss () local uri = assert(URI:new("urn:oid:0.1.23")) is("0.1.23", uri:nss("1")) is("urn:oid:1", tostring(uri)) is("1", uri:nss("234252345.340.4.0")) is("urn:oid:234252345.340.4.0", tostring(uri)) is("234252345.340.4.0", uri:nss()) end function test_set_bad_nss () local uri = assert(URI:new("urn:OID:0.1.23")) assert_error("set NSS to non-string value", function () uri:nss({}) end) assert_error("set NSS to empty", function () uri:nss("") end) assert_error("set NSS to bad char", function () uri:nss("x") end) -- None of that should have had any affect is("urn:oid:0.1.23", tostring(uri)) is("0.1.23", uri:nss()) assert_array_shallow_equal({ 0, 1, 23 }, uri:oid_numbers()) is("uri.urn.oid", uri._NAME) end function test_set_path () local uri = assert(URI:new("urn:OID:0.1.23")) is("oid:0.1.23", uri:path("OId:23.1.0")) is("urn:oid:23.1.0", tostring(uri)) assert_error("bad path", function () uri:path("oid:1.02") end) is("urn:oid:23.1.0", tostring(uri)) is("oid:23.1.0", uri:path()) end function test_set_oid_numbers () local uri = assert(URI:new("urn:oid:0.1.23")) assert_array_shallow_equal({ 0, 1, 23 }, uri:oid_numbers({ 1 })) is("urn:oid:1", tostring(uri)) assert_array_shallow_equal({ 1 }, uri:oid_numbers({ 234252345, 340, 4, 0 })) is("urn:oid:234252345.340.4.0", tostring(uri)) assert_array_shallow_equal({ 234252345, 340, 4, 0 }, uri:oid_numbers({ 23.42 })) is("urn:oid:23", tostring(uri)) assert_array_shallow_equal({ 23 }, uri:oid_numbers()) end function test_set_bad_oid_numbers () local uri = assert(URI:new("urn:OID:0.1.23")) assert_error("set OID numbers to non-table value", function () uri:oid_numbers("1") end) assert_error("set OID to empty list of numbers", function () uri:oid_numbers({}) end) assert_error("set OID number to negative number", function () uri:oid_numbers({ -23 }) end) assert_error("set OID number array containing bad type", function () uri:oid_numbers({ "x" }) end) -- None of that should have had any affect is("urn:oid:0.1.23", tostring(uri)) assert_array_shallow_equal({ 0, 1, 23 }, uri:oid_numbers()) is("uri.urn.oid", uri._NAME) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/file.lua0000644000175000017500000001332212002272735015662 0ustar vsevavsevarequire "uri-test" local URI = require "uri" local URIFile = require "uri.file" module("test.file", lunit.testcase, package.seeall) function test_normalize () test_norm("file:///foo", "file://LocalHost/foo") test_norm("file:///", "file://localhost/") test_norm("file:///", "file://localhost") test_norm("file:///", "file://") test_norm("file:///", "file:/") test_norm("file:///foo", "file:/foo") test_norm("file://foo/", "file://foo") end function test_invalid () is_bad_uri("just scheme", "file:") is_bad_uri("scheme with relative path", "file:foo/bar") end function test_set_host () local uri = assert(URI:new("file:///foo")) is("", uri:host()) is("", uri:host("LocalHost")) is("file:///foo", tostring(uri)) is("", uri:host("host.name")) is("file://host.name/foo", tostring(uri)) is("host.name", uri:host("")) is("file:///foo", tostring(uri)) end function test_set_path () local uri = assert(URI:new("file:///foo")) is("/foo", uri:path()) is("/foo", uri:path(nil)) is("file:///", tostring(uri)) is("/", uri:path("")) is("file:///", tostring(uri)) is("/", uri:path("/bar/frob")) is("file:///bar/frob", tostring(uri)) is("/bar/frob", uri:path("/")) is("file:///", tostring(uri)) end function test_bad_usage () local uri = assert(URI:new("file:///foo")) assert_error("nil host", function () uri:host(nil) end) assert_error("set userinfo", function () uri:userinfo("foo") end) assert_error("set port", function () uri:userinfo(23) end) assert_error("set relative path", function () uri:userinfo("foo/") end) end local function uri_to_fs (os, uristr, expected) local uri = assert(URI:new(uristr)) is(expected, uri:filesystem_path(os)) end local function fs_to_uri (os, path, expected) is(expected, tostring(URIFile.make_file_uri(path, os))) end function test_uri_to_fs_unix () uri_to_fs("unix", "file:///", "/") uri_to_fs("unix", "file:///c:", "/c:") uri_to_fs("unix", "file:///C:/", "/C:/") uri_to_fs("unix", "file:///C:/Program%20Files", "/C:/Program Files") uri_to_fs("unix", "file:///C:/Program%20Files/", "/C:/Program Files/") uri_to_fs("unix", "file:///Program%20Files/", "/Program Files/") end function test_uri_to_fs_unix_bad () -- On Unix platforms, there's no equivalent of UNC paths. local uri = assert(URI:new("file://laptop/My%20Documents/FileSchemeURIs.doc")) assert_error("Unix path with host name", function () uri:filesystem_path("unix") end) -- Unix paths can't contain null bytes or encoded slashes. uri = assert(URI:new("file:///frob/foo%00bar/quux")) assert_error("Unix path with null byte", function () uri:filesystem_path("unix") end) uri = assert(URI:new("file:///frob/foo%2Fbar/quux")) assert_error("Unix path with encoded slash", function () uri:filesystem_path("unix") end) end function test_fs_to_uri_unix () fs_to_uri("unix", "/", "file:///") fs_to_uri("unix", "//", "file:///") fs_to_uri("unix", "///", "file:///") fs_to_uri("unix", "/foo/bar", "file:///foo/bar") fs_to_uri("unix", "/foo/bar/", "file:///foo/bar/") fs_to_uri("unix", "//foo///bar//", "file:///foo/bar/") fs_to_uri("unix", "/foo bar/%2F", "file:///foo%20bar/%252F") end function test_fs_to_uri_unix_bad () -- Relative paths can't be converted to URIs, because URIs are inherently -- absolute. assert_error("relative Unix path", function () URIFile.make_file_uri("foo/bar", "unix") end) assert_error("relative empty Unix path", function () URIFile.make_file_uri("", "unix") end) end function test_uri_to_fs_win32 () uri_to_fs("win32", "file:///", "\\") uri_to_fs("win32", "file:///c:", "c:\\") uri_to_fs("win32", "file:///C:/", "C:\\") uri_to_fs("win32", "file:///C:/Program%20Files", "C:\\Program Files") uri_to_fs("win32", "file:///C:/Program%20Files/", "C:\\Program Files\\") uri_to_fs("win32", "file:///Program%20Files/", "\\Program Files\\") -- http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx uri_to_fs("win32", "file://laptop/My%20Documents/FileSchemeURIs.doc", "\\\\laptop\\My Documents\\FileSchemeURIs.doc") uri_to_fs("win32", "file:///C:/Documents%20and%20Settings/davris/FileSchemeURIs.doc", "C:\\Documents and Settings\\davris\\FileSchemeURIs.doc") -- For backwards compatibility with deprecated way of indicating drives. uri_to_fs("win32", "file:///c%7C", "c:\\") uri_to_fs("win32", "file:///c%7C/", "c:\\") uri_to_fs("win32", "file:///C%7C/foo/", "C:\\foo\\") end function test_fs_to_uri_win32 () fs_to_uri("win32", "", "file:///") fs_to_uri("win32", "\\", "file:///") fs_to_uri("win32", "c:", "file:///c:/") fs_to_uri("win32", "C:\\", "file:///C:/") fs_to_uri("win32", "C:/", "file:///C:/") fs_to_uri("win32", "C:\\Program Files", "file:///C:/Program%20Files") fs_to_uri("win32", "C:\\Program Files\\", "file:///C:/Program%20Files/") fs_to_uri("win32", "C:/Program Files/", "file:///C:/Program%20Files/") fs_to_uri("win32", "\\Program Files\\", "file:///Program%20Files/") fs_to_uri("win32", "\\\\laptop\\My Documents\\FileSchemeURIs.doc", "file://laptop/My%20Documents/FileSchemeURIs.doc") fs_to_uri("win32", "c:\\foo bar\\%2F", "file:///c:/foo%20bar/%252F") end function test_convert_on_unknown_os () local uri = assert(URI:new("file:///foo")) assert_error("filesystem_path, unknown os", function () uri:filesystem_path("NonExistent") end) assert_error("make_file_uri, unknown os", function () URIFile.make_file_uri("/foo", "NonExistent") end) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/urn.lua0000644000175000017500000001117512002272735015553 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.urn", lunit.testcase, package.seeall) function test_urn_parsing () local uri = assert(URI:new("urn:x-FOO-01239-:Nss")) is("urn:x-foo-01239-:Nss", uri:uri()) is("urn", uri:scheme()) is("x-foo-01239-:Nss", uri:path()) is("x-foo-01239-", uri:nid()) is("Nss", uri:nss()) is(nil, uri:userinfo()) is(nil, uri:host()) is(nil, uri:port()) is(nil, uri:query()) is(nil, uri:fragment()) end function test_set_nss () local uri = assert(URI:new("urn:x-FOO-01239-:Nss")) is("Nss", uri:nss("FooBar")) is("urn:x-foo-01239-:FooBar", tostring(uri)) assert_error("bad NSS, empty", function () uri:nss("") end) assert_error("bad NSS, illegal character", function () uri:nss('x"y') end) is("urn:x-foo-01239-:FooBar", tostring(uri)) end function test_bad_urn_syntax () is_bad_uri("missing nid", "urn::bar") is_bad_uri("hyphen at start of nid", "urn:-x-foo:bar") is_bad_uri("plus in middle of nid", "urn:x+foo:bar") is_bad_uri("underscore in middle of nid", "urn:x_foo:bar") is_bad_uri("dot in middle of nid", "urn:x.foo:bar") is_bad_uri("nid too long", "urn:x-012345678901234567890123456789x:bar") is_bad_uri("reserved 'urn' nid", "urn:urn:bar") is_bad_uri("missing nss", "urn:x-foo:") is_bad_uri("bad char in nss", "urn:x-foo:bar&") is_bad_uri("shoudn't have host part", "urn://foo.com/x-foo:bar") is_bad_uri("shoudn't have query part", "urn:x-foo:bar?baz") end function test_change_nid () local urn = assert(URI:new("urn:x-foo:14734966")) is("urn:x-foo:14734966", tostring(urn)) is("x-foo", urn:nid()) is("uri.urn", urn._NAME) -- x-foo -> x-bar is("x-foo", urn:nid("X-BAR")) is("x-bar", urn:nid()) is("urn:x-bar:14734966", tostring(urn)) is("uri.urn", urn._NAME) -- x-bar -> issn is("x-bar", urn:nid("issn")) is("issn", urn:nid()) is("urn:issn:1473-4966", tostring(urn)) is("uri.urn.issn", urn._NAME) -- issn -> x-foo is("issn", urn:nid("x-foo")) is("x-foo", urn:nid()) is("urn:x-foo:1473-4966", tostring(urn)) is("uri.urn", urn._NAME) end function test_change_nid_bad () local urn = assert(URI:new("urn:x-foo:frob")) -- Try changing the NID to something invalid assert_error("bad NID 'urn'", function () urn:nid("urn") end) assert_error("bad NID '-x-foo'", function () urn:nid("-x-foo") end) assert_error("bad NID 'x+foo'", function () urn:nid("x+foo") end) -- Change to valid NID, but where the NSS is not valid for it assert_error("bad NSS for ISSN URN", function () urn:nid("issn") end) -- Original URN should be left unchanged is("urn:x-foo:frob", tostring(urn)) is("x-foo", urn:nid()) is("uri.urn", urn._NAME) end function test_change_path () local urn = assert(URI:new("urn:x-foo:foopath")) is("x-foo:foopath", urn:path()) -- x-foo -> x-bar is("x-foo:foopath", urn:path("X-BAR:barpath")) is("x-bar:barpath", urn:path()) is("urn:x-bar:barpath", tostring(urn)) is("uri.urn", urn._NAME) -- x-bar -> issn is("x-bar:barpath", urn:path("issn:14734966")) is("issn:1473-4966", urn:path()) is("urn:issn:1473-4966", tostring(urn)) is("uri.urn.issn", urn._NAME) -- issn -> x-foo is("issn:1473-4966", urn:path("x-foo:foopath2")) is("x-foo:foopath2", urn:path()) is("urn:x-foo:foopath2", tostring(urn)) is("uri.urn", urn._NAME) end function test_change_path_bad () local urn = assert(URI:new("urn:x-foo:frob")) -- Try changing the NID to something invalid assert_error("bad NID 'urn'", function () urn:path("urn:frob") end) assert_error("bad NID '-x-foo'", function () urn:path("-x-foo:frob") end) assert_error("bad NID 'x+foo'", function () urn:path("x+foo:frob") end) assert_error("bad NSS, empty", function () urn:path("x-foo:") end) assert_error("bad NSS, bad char", function () urn:path('x-foo:x"y') end) -- Change to valid NID, but where the NSS is not valid for it assert_error("bad NSS for ISSN URN", function () urn:path("issn:frob") end) -- Original URN should be left unchanged is("urn:x-foo:frob", tostring(urn)) is("x-foo:frob", urn:path()) is("x-foo", urn:nid()) is("frob", urn:nss()) is("uri.urn", urn._NAME) end function test_set_disallowed_stuff () local urn = assert(URI:new("urn:x-foo:frob")) assert_error("can't set userinfo", function () urn:userinfo("x") end) assert_error("can't set host", function () urn:host("x") end) assert_error("can't set port", function () urn:port(23) end) assert_error("can't set query", function () urn:query("x") end) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/urn-issn.lua0000644000175000017500000000722412002272735016525 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.urn_issn", lunit.testcase, package.seeall) local good_issn_digits = { "02613077", -- The Guardian "14734966", -- Photography Monthly -- From the Wikipedia article on ISSN. "03178471", "15340481", -- From RFC 3044 section 5. "0259000X", "15601560", } function test_parse_and_normalize () local uri = assert(URI:new("urn:ISSN:1560-1560")) is("uri.urn.issn", uri._NAME) is("urn:issn:1560-1560", uri:uri()) is("15601560", uri:issn_digits()) uri = assert(URI:new("URN:Issn:0259-000X")) is("urn:issn:0259-000X", uri:uri()) is("0259000X", uri:issn_digits()) uri = assert(URI:new("urn:issn:0259000x")) is("urn:issn:0259-000X", uri:uri()) is("0259000X", uri:issn_digits()) end function test_bad_syntax () is_bad_uri("too many digits", "urn:issn:026130707") is_bad_uri("not enough digits", "urn:issn:0261377") is_bad_uri("too many hyphens in middle", "urn:issn:0261--3077") is_bad_uri("hyphen in wrong place", "urn:issn:026-13077") is_bad_uri("X digit in wrong place", "urn:issn:025900X0") end -- Try all the known-good sequences of digits with all possible checksums -- other than the right one, to make sure they're all detected as errors. function test_bad_checksum () for _, issn in ipairs(good_issn_digits) do local digits, good_checksum = issn:sub(1, 7), issn:sub(8, 8) good_checksum = (good_checksum == "X") and 10 or tonumber(good_checksum) for i = 0, 10 do if i ~= good_checksum then local urn = "urn:issn:" .. digits .. (i == 10 and "X" or i) is_bad_uri("bad checksum in " .. urn, urn) end end end end function test_set_nss () local uri = assert(URI:new("urn:issn:0261-3077")) is("0261-3077", uri:nss("14734966")) is("urn:issn:1473-4966", tostring(uri)) is("1473-4966", uri:nss("0259-000x")) is("urn:issn:0259-000X", tostring(uri)) is("0259-000X", uri:nss()) end function test_set_bad_nss () local uri = assert(URI:new("urn:ISSN:02613077")) assert_error("set NSS to non-string value", function () uri:nss({}) end) assert_error("set NSS to empty", function () uri:nss("") end) assert_error("set NSS to bad char", function () uri:nss("x") end) -- None of that should have had any affect is("urn:issn:0261-3077", tostring(uri)) is("0261-3077", uri:nss()) is("02613077", uri:issn_digits()) is("uri.urn.issn", uri._NAME) end function test_set_path () local uri = assert(URI:new("urn:ISSN:02613077")) is("issn:0261-3077", uri:path("ISsn:14734966")) is("urn:issn:1473-4966", tostring(uri)) assert_error("bad path", function () uri:path("issn:1234567") end) is("urn:issn:1473-4966", tostring(uri)) is("issn:1473-4966", uri:path()) end function test_set_issn_digits () local uri = assert(URI:new("urn:ISSN:0261-3077")) is("02613077", uri:issn_digits(nil)) local old = uri:issn_digits("14734966") is("02613077", old) is("14734966", uri:issn_digits()) is("urn:issn:1473-4966", uri:uri()) old = uri:issn_digits("0259-000x") is("14734966", old) is("0259000X", uri:issn_digits()) is("urn:issn:0259-000X", uri:uri()) end function test_set_bad_issn_digits () local uri = assert(URI:new("urn:ISSN:0261-3077")) assert_error("set ISSN with bad char", function () uri:issn_digits("0261-3077Y") end) assert_error("set ISSN with too many digits", function () uri:issn_digits("0261-30770") end) assert_error("set ISSN of empty string", function () uri:issn_digits("") end) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/telnet.lua0000644000175000017500000001144112002272735016236 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.telnet", lunit.testcase, package.seeall) -- This tests the generic login stuff ('username' and 'password' methods, and -- additional userinfo validation), as well as the stuff specific to telnet. function test_telnet () local uri = assert(URI:new("telnet://telnet.example.com/")) is("telnet://telnet.example.com/", uri:uri()) is("telnet://telnet.example.com/", tostring(uri)) is("uri.telnet", uri._NAME) is("telnet", uri:scheme()) is("telnet.example.com", uri:host()) is("/", uri:path()) end function test_telnet_normalize () local uri = assert(URI:new("telnet://user:password@host.com")) is("telnet://user:password@host.com/", tostring(uri)) is("/", uri:path()) is(23, uri:port()) uri = assert(URI:new("telnet://user:password@host.com:23/")) is("telnet://user:password@host.com/", tostring(uri)) is("/", uri:path()) is(23, uri:port()) end function test_telnet_invalid () is_bad_uri("no authority, empty path", "telnet:") is_bad_uri("no authority, normal path", "telnet:/") is_bad_uri("empty authority, empty path", "telnet://") is_bad_uri("empty authority, normal path", "telnet:///") is_bad_uri("bad path /x", "telnet://host/x") is_bad_uri("bad path //", "telnet://host//") end function test_telnet_set_path () local uri = assert(URI:new("telnet://foo/")) is("/", uri:path("/")) is("/", uri:path("")) is("/", uri:path(nil)) is("/", uri:path()) end function test_telnet_set_bad_path () local uri = assert(URI:new("telnet://foo/")) assert_error("bad path x", function () uri:path("x") end) assert_error("bad path /x", function () uri:path("/x") end) assert_error("bad path //", function () uri:path("//") end) end -- These test the generic stuff in uri._login. Some of the examples are -- directly from RFC 1738 section 3.1, but substituting 'telnet' for 'ftp'. function test_telnet_userinfo () local uri = assert(URI:new("telnet://host.com/")) is(nil, uri:userinfo()) is(nil, uri:username()) is(nil, uri:password()) uri = assert(URI:new("telnet://foo:bar@host.com/")) is("foo:bar", uri:userinfo()) is("foo", uri:username()) is("bar", uri:password()) uri = assert(URI:new("telnet://%3a%40:%3a%40@host.com/")) is("%3A%40:%3A%40", uri:userinfo()) is(":@", uri:username()) is(":@", uri:password()) uri = assert(URI:new("telnet://foo:@host.com/")) is("foo:", uri:userinfo()) is("foo", uri:username()) is("", uri:password()) uri = assert(URI:new("telnet://@host.com/")) is("", uri:userinfo()) is("", uri:username()) is(nil, uri:password()) uri = assert(URI:new("telnet://:@host.com/")) is(":", uri:userinfo()) is("", uri:username()) is("", uri:password()) end function test_telnet_set_userinfo () local uri = assert(URI:new("telnet://host.com/")) is(nil, uri:userinfo("")) is("telnet://@host.com/", tostring(uri)) is("", uri:userinfo(":")) is("telnet://:@host.com/", tostring(uri)) is(":", uri:userinfo("foo:")) is("telnet://foo:@host.com/", tostring(uri)) is("foo:", uri:userinfo(":bar")) is("telnet://:bar@host.com/", tostring(uri)) is(":bar", uri:userinfo("foo:bar")) is("telnet://foo:bar@host.com/", tostring(uri)) is("foo:bar", uri:userinfo()) end function test_telnet_set_bad_userinfo () local uri = assert(URI:new("telnet://host.com/")) assert_error("more than one colon", function () uri:userinfo("x::y") end) assert_error("invalid character", function () uri:userinfo("x/y") end) end function test_telnet_set_username () local uri = assert(URI:new("telnet://host.com/")) is(nil, uri:username("foo")) is(nil, uri:password()) is("telnet://foo@host.com/", tostring(uri)) is("foo", uri:username("x:y@z%")) is(nil, uri:password()) is("telnet://x%3Ay%40z%25@host.com/", tostring(uri)) is("x:y@z%", uri:username("")) is(nil, uri:password()) is("telnet://@host.com/", tostring(uri)) is("", uri:username(nil)) is(nil, uri:password()) is("telnet://host.com/", tostring(uri)) is(nil, uri:username()) end function test_telnet_set_password () local uri = assert(URI:new("telnet://host.com/")) is(nil, uri:password("foo")) is("", uri:username()) is("telnet://:foo@host.com/", tostring(uri)) is("foo", uri:password("x:y@z%")) is("", uri:username()) is("telnet://:x%3Ay%40z%25@host.com/", tostring(uri)) is("x:y@z%", uri:password("")) is("", uri:username()) is("telnet://:@host.com/", tostring(uri)) is("", uri:password(nil)) is("", uri:username()) is("telnet://@host.com/", tostring(uri)) is("", uri:username(nil)) is(nil, uri:password(nil)) is("telnet://host.com/", tostring(uri)) is(nil, uri:password()) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/_util.lua0000644000175000017500000000544112002272735016062 0ustar vsevavsevarequire "uri-test" local Util = require "uri._util" module("test.util", lunit.testcase, package.seeall) function test_metadata () is("uri._util", Util._NAME) end function test_uri_encode () is("%7Cabc%E5", Util.uri_encode("|abc\229")) is("a%62%63", Util.uri_encode("abc", "b-d")) assert_nil(Util.uri_encode(nil)) end function test_uri_decode () is("|abc\229", Util.uri_decode("%7Cabc%e5")) is("@AB", Util.uri_decode("%40A%42")) is("CDE", Util.uri_decode("CDE")) end function test_uri_decode () is("/%2F%25/..!%A1", Util.uri_decode("/%2F%25/%2e.%21%A1", "%-.!")) end function test_remove_dot_segments () is("/", Util.remove_dot_segments("/foo/../")) is("/bar", Util.remove_dot_segments("/foo/./../bar")) end function test_split () local list list = Util.split(";", "") assert_array_shallow_equal({}, list) list = Util.split(";", "foo") assert_array_shallow_equal({"foo"}, list) list = Util.split(";", "foo;bar") assert_array_shallow_equal({"foo","bar"}, list) list = Util.split(";", "foo;bar;baz") assert_array_shallow_equal({"foo","bar","baz"}, list) list = Util.split(";", ";") assert_array_shallow_equal({"",""}, list) list = Util.split(";", "foo;") assert_array_shallow_equal({"foo",""}, list) list = Util.split(";", ";foo") assert_array_shallow_equal({"","foo"}, list) -- TODO test with multi-char and more complex patterns end function test_split_with_max () local list list = Util.split(";", "foo;bar;baz", 4) assert_array_shallow_equal({"foo","bar","baz"}, list) list = Util.split(";", "foo;bar;baz", 3) assert_array_shallow_equal({"foo","bar","baz"}, list) list = Util.split(";", "foo;bar;baz", 2) assert_array_shallow_equal({"foo","bar;baz"}, list) list = Util.split(";", "foo;bar;baz", 1) assert_array_shallow_equal({"foo;bar;baz"}, list) end function test_attempt_require () local mod = Util.attempt_require("string") assert_table(mod) mod = Util.attempt_require("lua-module-which-doesn't-exist") assert_nil(mod) end function test_subclass_of () local baseclass = {} baseclass.__index = baseclass baseclass.overridden = function () return "baseclass" end baseclass.inherited = function () return "inherited" end local subclass = {} Util.subclass_of(subclass, baseclass) subclass.overridden = function () return "subclass" end assert(getmetatable(subclass) == baseclass) assert(subclass._SUPER == baseclass) local baseobject, subobject = {}, {} setmetatable(baseobject, baseclass) setmetatable(subobject, subclass) is("baseclass", baseobject:overridden()) is("subclass", subobject:overridden()) is("inherited", baseobject:inherited()) is("inherited", subobject:inherited()) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/pop.lua0000644000175000017500000001052012002272735015536 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.pop", lunit.testcase, package.seeall) function test_pop_parse_1 () local uri = assert(URI:new("Pop://rg@MAILSRV.qualcomm.COM")) is("pop://rg@mailsrv.qualcomm.com", tostring(uri)) is("pop", uri:scheme()) is("rg", uri:userinfo()) is("mailsrv.qualcomm.com", uri:host()) is(110, uri:port()) is("rg", uri:pop_user()) is("*", uri:pop_auth()) end function test_pop_parse_2 () local uri = assert(URI:new("pop://rg;AUTH=+APOP@mail.eudora.com:8110")) is("pop://rg;auth=+APOP@mail.eudora.com:8110", tostring(uri)) is("rg;auth=+APOP", uri:userinfo()) is("mail.eudora.com", uri:host()) is(8110, uri:port()) is("rg", uri:pop_user()) is("+APOP", uri:pop_auth()) end function test_pop_parse_3 () local uri = assert(URI:new("pop://baz;AUTH=SCRAM-MD5@foo.bar")) is("pop://baz;auth=SCRAM-MD5@foo.bar", tostring(uri)) is("baz;auth=SCRAM-MD5", uri:userinfo()) is("foo.bar", uri:host()) is(110, uri:port()) is("baz", uri:pop_user()) is("SCRAM-MD5", uri:pop_auth()) end function test_pop_normalize () local uri = assert(URI:new("Pop://Baz;Auth=*@Foo.Bar:110")) is("pop://Baz@foo.bar", tostring(uri)) is("Baz", uri:userinfo()) is("foo.bar", uri:host()) is(110, uri:port()) is("Baz", uri:pop_user()) is("*", uri:pop_auth()) end function test_pop_set_user () local uri = assert(URI:new("pop://host")) is(nil, uri:pop_user("foo ;bar")) is("pop://foo%20%3Bbar@host", tostring(uri)) assert_error("empty user not allowed", function () uri:pop_user("") end) is("foo ;bar", uri:pop_user(nil)) is(nil, uri:pop_user()) is("pop://host", tostring(uri)) end function test_pop_set_user_bad () local uri = assert(URI:new("pop://foo@host")) assert_error("empty user not allowed", function () uri:pop_user("") end) is("foo", uri:pop_user()) is("pop://foo@host", tostring(uri)) uri = assert(URI:new("pop://foo;auth=+APOP@host")) assert_error("user required when auth specified", function () uri:pop_user(nil) end) is("foo", uri:pop_user()) is("+APOP", uri:pop_auth()) is("pop://foo;auth=+APOP@host", tostring(uri)) end function test_pop_set_auth () local uri = assert(URI:new("pop://user@host")) is("*", uri:pop_auth("foo ;bar")) is("pop://user;auth=foo%20%3Bbar@host", tostring(uri)) is("foo ;bar", uri:pop_auth("*")) is("*", uri:pop_auth()) is("pop://user@host", tostring(uri)) end function test_pop_set_auth_bad () local uri = assert(URI:new("pop://host")) assert_error("auth not allowed without user", function () uri:pop_auth("+APOP") end) uri:pop_user("user") assert_error("empty auth not allowed", function () uri:pop_auth("") end) assert_error("nil auth not allowed", function () uri:pop_auth(nil) end) is("pop://user@host", tostring(uri)) end function test_pop_bad_syntax () is_bad_uri("path not empty", "pop://foo@host/") is_bad_uri("user empty", "pop://@host") is_bad_uri("user empty with auth", "pop://;auth=+APOP@host") is_bad_uri("auth empty", "pop://user;auth=@host") end function test_set_userinfo () local uri = assert(URI:new("pop://host")) is(nil, uri:userinfo("foo ;bar")) is("pop://foo%20%3Bbar@host", tostring(uri)) is("foo%20%3Bbar", uri:userinfo("foo;auth=+APOP")) is("pop://foo;auth=+APOP@host", tostring(uri)) is("foo;auth=+APOP", uri:userinfo("foo;AUTH=+APOP")) is("pop://foo;auth=+APOP@host", tostring(uri)) is("foo;auth=+APOP", uri:userinfo("bar;auth=*")) is("pop://bar@host", tostring(uri)) is("bar", uri:userinfo(nil)) is("pop://host", tostring(uri)) end function test_set_userinfo_bad () local uri = assert(URI:new("pop://host")) assert_error("empty userinfo", function () uri:userinfo("") end) assert_error("empty user with auth", function () uri:userinfo(";auth=*") end) assert_error("empty auth on its own", function () uri:userinfo(";auth=") end) assert_error("empty auth with user", function () uri:userinfo("foo;auth=") end) end function test_set_path () local uri = assert(URI:new("pop://host")) is("", uri:path("")) is("", uri:path(nil)) is("", uri:path()) assert_error("non-empty path", function () uri:path("/") end) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/http.lua0000644000175000017500000000363012002272735015723 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.http", lunit.testcase, package.seeall) function test_http () local uri = assert(URI:new("HTtp://FOo/Blah?Search#Id")) is("uri.http", uri._NAME) is("http://foo/Blah?Search#Id", uri:uri()) is("http://foo/Blah?Search#Id", tostring(uri)) is("http", uri:scheme()) is("foo", uri:host()) is(80, uri:port()) is("/Blah", uri:path()) is(nil, uri:userinfo()) is("Search", uri:query()) is("Id", uri:fragment()) end function test_https () local uri = assert(URI:new("HTtpS://FOo/Blah?Search#Id")) is("uri.https", uri._NAME) is("https://foo/Blah?Search#Id", uri:uri()) is("https://foo/Blah?Search#Id", tostring(uri)) is("https", uri:scheme()) is("foo", uri:host()) is(443, uri:port()) is("/Blah", uri:path()) is(nil, uri:userinfo()) is("Search", uri:query()) is("Id", uri:fragment()) end function test_http_port () local uri = assert(URI:new("http://example.com:8080/foo")) is(8080, uri:port()) local old = uri:port(1234) is(8080, old) is(1234, uri:port()) is("http://example.com:1234/foo", tostring(uri)) old = uri:port(80) is(1234, old) is(80, uri:port()) is("http://example.com/foo", tostring(uri)) end function test_normalize_port () local uri = assert(URI:new("http://foo:80/")) is("http://foo/", tostring(uri)) is(80, uri:port()) uri = assert(URI:new("http://foo:443/")) is("http://foo:443/", tostring(uri)) is(443, uri:port()) uri = assert(URI:new("https://foo:443/")) is("https://foo/", tostring(uri)) is(443, uri:port()) uri = assert(URI:new("https://foo:80/")) is("https://foo:80/", tostring(uri)) is(80, uri:port()) end function test_set_userinfo () local uri = assert(URI:new("http://host/path")) assert_error("can't set userinfo", function () uri:userinfo("x") end) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/_resolve.lua0000644000175000017500000001674412002272735016574 0ustar vsevavsevarequire "uri-test" local URI = require "uri" module("test.resolve", lunit.testcase, package.seeall) -- Test data from RFC 3986. The 'http' prefix has been changed throughout -- to 'x-foo' so as not to trigger any scheme-specific normalization. local resolve_tests = { -- 5.4.1. Normal Examples ["g:h"] = "g:h", ["g"] = "x-foo://a/b/c/g", ["./g"] = "x-foo://a/b/c/g", ["g/"] = "x-foo://a/b/c/g/", ["/g"] = "x-foo://a/g", ["//g"] = "x-foo://g", ["?y"] = "x-foo://a/b/c/d;p?y", ["g?y"] = "x-foo://a/b/c/g?y", ["#s"] = "x-foo://a/b/c/d;p?q#s", ["g#s"] = "x-foo://a/b/c/g#s", ["g?y#s"] = "x-foo://a/b/c/g?y#s", [";x"] = "x-foo://a/b/c/;x", ["g;x"] = "x-foo://a/b/c/g;x", ["g;x?y#s"] = "x-foo://a/b/c/g;x?y#s", [""] = "x-foo://a/b/c/d;p?q", ["."] = "x-foo://a/b/c/", ["./"] = "x-foo://a/b/c/", [".."] = "x-foo://a/b/", ["../"] = "x-foo://a/b/", ["../g"] = "x-foo://a/b/g", ["../.."] = "x-foo://a/", ["../../"] = "x-foo://a/", ["../../g"] = "x-foo://a/g", -- 5.4.2. Abnormal Examples ["../../../g"] = "x-foo://a/g", ["../../../../g"] = "x-foo://a/g", ["/./g"] = "x-foo://a/g", ["/../g"] = "x-foo://a/g", ["g."] = "x-foo://a/b/c/g.", [".g"] = "x-foo://a/b/c/.g", ["g.."] = "x-foo://a/b/c/g..", ["..g"] = "x-foo://a/b/c/..g", ["./../g"] = "x-foo://a/b/g", ["./g/."] = "x-foo://a/b/c/g/", ["g/./h"] = "x-foo://a/b/c/g/h", ["g/../h"] = "x-foo://a/b/c/h", ["g;x=1/./y"] = "x-foo://a/b/c/g;x=1/y", ["g;x=1/../y"] = "x-foo://a/b/c/y", ["g?y/./x"] = "x-foo://a/b/c/g?y/./x", ["g?y/../x"] = "x-foo://a/b/c/g?y/../x", ["g#s/./x"] = "x-foo://a/b/c/g#s/./x", ["g#s/../x"] = "x-foo://a/b/c/g#s/../x", ["x-foo:g"] = "x-foo:g", -- Some extra tests for good measure ["#foo?"] = "x-foo://a/b/c/d;p?q#foo?", ["?#foo"] = "x-foo://a/b/c/d;p?#foo", } local function test_abs_rel (base, uref, expect) local bad = false -- Test 'resolve' method with object as argument. local u = assert(URI:new(uref)) local b = assert(URI:new(base)) u:resolve(b) local got = tostring(u) if got ~= expect then bad = true print("URI:new(" .. uref .. "):resolve(URI:new(" .. base .. ") ===> " .. expect .. " (not " .. got .. ")") end -- Test 'resolve' method with string as argument. u = assert(URI:new(uref)) u:resolve(base) local got = tostring(u) if got ~= expect then bad = true print("URI:new(" .. uref .. "):resolve(URI:new(" .. base .. ") ===> " .. expect .. " (not " .. got .. ")") end -- Test resolving relative URI using the constructor. local u = assert(URI:new(uref, base)) local got = tostring(u) if got ~= expect then bad = true print("URI:new(" .. uref .. ", " .. base .. ") ==> " .. expect .. " (not " .. got .. ")") end return bad end function test_resolve () local base = "x-foo://a/b/c/d;p?q" local testno = 1 local bad = false for rel, abs in pairs(resolve_tests) do if test_abs_rel(base, rel, abs) then bad = true end end if bad then fail("one of the checks went wrong") end end function test_resolve_error () local base = assert(URI:new("urn:oid:1.2.3")) local uri = assert(URI:new("not-valid-path-for-urn")) -- The 'resolve' method should throw an exception if the absolute URI -- that results from the resolution would be invalid. assert_error("calling resolve() creates invalid URI", function () uri:resolve(base) end) assert_true(uri:is_relative()) is("not-valid-path-for-urn", tostring(uri)) -- But the constructor should return an error in its normal fashion. local ok, err = URI:new(uri, base) assert_nil(ok) assert_string(err) end local relativize_tests = { -- Empty path if the path is the same as the base URI's. { "http://ex/", "http://ex/", "" }, { "http://ex/a/b", "http://ex/a/b", "" }, { "http://ex/a/b/", "http://ex/a/b/", "" }, -- Absolute path if the base URI's path doesn't help. { "http://ex/", "http://ex/a/b", "/" }, { "http://ex/", "http://ex/a/b/", "/" }, { "http://ex/x/y", "http://ex/", "/x/y" }, { "http://ex/x/y/", "http://ex/", "/x/y/" }, { "http://ex/x", "http://ex/a", "/x" }, { "http://ex/x", "http://ex/a/", "/x" }, { "http://ex/x/", "http://ex/a", "/x/" }, { "http://ex/x/", "http://ex/a/", "/x/" }, { "http://ex/x/y", "http://ex/a/b", "/x/y" }, { "http://ex/x/y", "http://ex/a/b/", "/x/y" }, { "http://ex/x/y/", "http://ex/a/b", "/x/y/" }, { "http://ex/x/y/", "http://ex/a/b/", "/x/y/" }, -- Add to the end of the base path. { "x-a://ex/a/b/c", "x-a://ex/a/b/", "c" }, { "x-a://ex/a/b/c/", "x-a://ex/a/b/", "c/" }, { "x-a://ex/a/b/c/d", "x-a://ex/a/b/", "c/d" }, { "x-a://ex/a/b/c/d/", "x-a://ex/a/b/", "c/d/" }, { "x-a://ex/a/b/c/d/e", "x-a://ex/a/b/", "c/d/e" }, { "x-a://ex/a/b/c:foo/d/e", "x-a://ex/a/b/", "./c:foo/d/e" }, -- Change last segment in base path, and add to it. { "x-a://ex/a/b/", "x-a://ex/a/b/c", "./" }, { "x-a://ex/a/b/x", "x-a://ex/a/b/c", "x" }, { "x-a://ex/a/b/x/", "x-a://ex/a/b/c", "x/" }, { "x-a://ex/a/b/x/y", "x-a://ex/a/b/c", "x/y" }, { "x-a://ex/a/b/x:foo/y", "x-a://ex/a/b/c", "./x:foo/y" }, -- Use '..' segments. { "x-a://ex/a/b/c", "x-a://ex/a/b/c/d", "../c" }, { "x-a://ex/a/b/c", "x-a://ex/a/b/c/", "../c" }, { "x-a://ex/a/b/", "x-a://ex/a/b/c/", "../" }, { "x-a://ex/a/b/", "x-a://ex/a/b/c/d", "../" }, { "x-a://ex/a/b", "x-a://ex/a/b/c/", "../../b" }, { "x-a://ex/a/b", "x-a://ex/a/b/c/d", "../../b" }, { "x-a://ex/a/", "x-a://ex/a/b/c/", "../../" }, { "x-a://ex/a/", "x-a://ex/a/b/c/d", "../../" }, -- Preserve query and fragment parts. { "http://ex/a/b", "http://ex/a/b?baseq#basef", "b" }, { "http://ex/a/b:c", "http://ex/a/b:c?baseq#basef", "./b:c" }, { "http://ex/a/b?", "http://ex/a/b?baseq#basef", "?" }, { "http://ex/a/b?foo", "http://ex/a/b?baseq#basef", "?foo" }, { "http://ex/a/b?foo#", "http://ex/a/b?baseq#basef", "?foo#" }, { "http://ex/a/b?foo#bar", "http://ex/a/b?baseq#basef", "?foo#bar" }, { "http://ex/a/b#bar", "http://ex/a/b?baseq#basef", "b#bar" }, { "http://ex/a/b:foo#bar", "http://ex/a/b:foo?baseq#basef", "./b:foo#bar" }, { "http://ex/a/b:foo#bar", "http://ex/a/b:foo#basef", "#bar" }, } function test_relativize () for _, test in ipairs(relativize_tests) do local uri = assert(URI:new(test[1])) uri:relativize(test[2]) is(test[3], tostring(uri)) -- Make sure it will resolve back to the original value. uri:resolve(test[2]) is(test[1], tostring(uri)) end end function test_relativize_already_is () local uri = assert(URI:new("../foo")) uri:relativize("http://host/") is("../foo", tostring(uri)) end function test_relativize_urn () local uri = assert(URI:new("urn:oid:1.2.3")) uri:relativize("urn:oid:1") is("urn:oid:1.2.3", tostring(uri)) end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/test/urn-isbn.lua0000644000175000017500000000734412002272735016507 0ustar vsevavsevarequire "uri-test" local URI = require "uri" local Util = require "uri._util" local have_isbn_module = Util.attempt_require("isbn") module("test.urn_isbn", lunit.testcase, package.seeall) function test_isbn () -- Example from RFC 2288 local u = URI:new("URN:ISBN:0-395-36341-1") is(have_isbn_module and "urn:isbn:0-395-36341-1" or "urn:isbn:0395363411", u:uri()) is("urn", u:scheme()) is("isbn", u:nid()) is(have_isbn_module and "0-395-36341-1" or "0395363411", u:nss()) is("0395363411", u:isbn_digits()) u = URI:new("URN:ISBN:0395363411") is(have_isbn_module and "urn:isbn:0-395-36341-1" or "urn:isbn:0395363411", u:uri()) is("urn", u:scheme()) is("isbn", u:nid()) is(have_isbn_module and "0-395-36341-1" or "0395363411", u:nss()) is("0395363411", u:isbn_digits()) if have_isbn_module then local isbn = u:isbn() assert_table(isbn) is("0-395-36341-1", tostring(isbn)) is("0", isbn:group_code()) is("395", isbn:publisher_code()) is("978-0-395-36341-6", tostring(isbn:as_isbn13())) end assert_true(URI.eq("urn:isbn:088730866x", "URN:ISBN:0-88-73-08-66-X")) end function test_set_nss () local uri = assert(URI:new("urn:isbn:039-53-63411")) is(have_isbn_module and "0-395-36341-1" or "0395363411", uri:nss("088-7308-66x")) is(have_isbn_module and "urn:isbn:0-88730-866-X" or "urn:isbn:088730866X", tostring(uri)) is(have_isbn_module and "0-88730-866-X" or "088730866X", uri:nss()) end function test_set_bad_nss () local uri = assert(URI:new("urn:ISBN:039-53-63411")) assert_error("set NSS to non-string value", function () uri:nss({}) end) assert_error("set NSS to empty", function () uri:nss("") end) assert_error("set NSS to wrong length", function () uri:nss("123") end) -- None of that should have had any affect is(have_isbn_module and "urn:isbn:0-395-36341-1" or "urn:isbn:0395363411", tostring(uri)) is(have_isbn_module and "0-395-36341-1" or "0395363411", uri:nss()) is("0395363411", uri:isbn_digits()) is("uri.urn.isbn", uri._NAME) end function test_set_path () local uri = assert(URI:new("urn:ISBN:039-53-63411")) is(have_isbn_module and "isbn:0-395-36341-1" or "isbn:0395363411", uri:path("ISbn:088-73-0866x")) is(have_isbn_module and "urn:isbn:0-88730-866-X" or "urn:isbn:088730866X", tostring(uri)) assert_error("bad path", function () uri:path("isbn:1234567") end) is(have_isbn_module and "urn:isbn:0-88730-866-X" or "urn:isbn:088730866X", tostring(uri)) is(have_isbn_module and "isbn:0-88730-866-X" or "isbn:088730866X", uri:path()) end function test_isbn_setting_digits () local u = assert(URI:new("URN:ISBN:0395363411")) local old = u:isbn_digits("0-88730-866-x") is("0395363411", old) is("088730866X", u:isbn_digits()) is(have_isbn_module and "0-88730-866-X" or "088730866X", u:nss()) if have_isbn_module then is("0-88730-866-X", tostring(u:isbn())) end end function test_isbn_setting_object () if have_isbn_module then local ISBN = require "isbn" local u = assert(URI:new("URN:ISBN:0395363411")) local old = u:isbn(ISBN:new("0-88730-866-x")) assert_table(old) is("0-395-36341-1", tostring(old)) is("088730866X", u:isbn_digits()) is("0-88730-866-X", u:nss()) local new = u:isbn() assert_table(new) is("0-88730-866-X", tostring(new)) end end function test_illegal_isbn () is_bad_uri("invalid characters", "urn:ISBN:abc") if have_isbn_module then is_bad_uri("bad checksum", "urn:isbn:0395363412") is_bad_uri("wrong length", "urn:isbn:03953634101") end end -- vi:ts=4 sw=4 expandtab lua-uri-mainline/uri-test.lua0000644000175000017500000000476212002272735015550 0ustar vsevavsevarequire "lunit" local URI = require "uri" is = lunit.assert_equal function is_one_of (expecteds, actual, msg) for _, v in ipairs(expecteds) do if actual == v then return end end -- Not any of the expected answers matched. In order to report the error -- usefully, we have to list the alternatives in the error message. local err = "expected one of {" for i, v in ipairs(expecteds) do if i > 1 then err = err .. ", " end err = err .. "'" .. tostring(v) .. "'" end err = err .. "}, but was '" .. tostring(actual) .. "'" if msg then err = err .. ": " .. msg end lunit.fail(err) end function assert_isa(actual, class) lunit.assert_table(actual) lunit.assert_table(class) local mt = actual while true do mt = getmetatable(mt) if not mt then error"class not found as metatable at any level" end if mt == actual then error"circular metatables" end if mt == class then return nil end end end function assert_array_shallow_equal (expected, actual, msg) if not msg then msg = "assert_array_shallow_equal" end lunit.assert_table(actual, msg .. ", is table") is(#expected, #actual, msg .. ", same size") if #expected == #actual then for i = 1, #expected do is(expected[i], actual[i], msg .. ", element " .. i) end end for key in pairs(actual) do lunit.assert_number(key, msg .. ", non-number key in array") end end local function _count_hash_pairs (hash) local count = 0 for _, _ in pairs(hash) do count = count + 1 end return count end function assert_hash_shallow_equal (expected, actual, msg) if not msg then msg = "assert_hash_shallow_equal" end lunit.assert_table(actual, msg .. ", is table") local expsize, actualsize = _count_hash_pairs(expected), _count_hash_pairs(actual) is(expsize, actualsize, msg .. ", same size") if expsize == actualsize then for k, v in pairs(expected) do is(expected[k], actual[k], msg .. ", element " .. tostring(k)) end end end function is_bad_uri (msg, uri) local ok, err = URI:new(uri) lunit.assert_nil(ok, msg) lunit.assert_string(err, msg) end function test_norm (expected, input) local uri = assert(URI:new(input)) is(expected, uri:uri()) is(expected, tostring(uri)) lunit.assert_false(uri:is_relative()) end function test_norm_already (input) test_norm(input, input) end -- vi:ts=4 sw=4 expandtab