lib/ronin/url.rb in ronin-1.0.0.pre3 vs lib/ronin/url.rb in ronin-1.0.0.pre4

- old
+ new

@@ -1,23 +1,22 @@ # -# Ronin - A Ruby platform for exploit development and security research. +# Copyright (c) 2006-2011 Hal Brodigan (postmodern.mod3 at gmail.com) # -# Copyright (c) 2009-2010 Hal Brodigan (postmodern.mod3 at gmail.com) +# This file is part of Ronin. # -# This program is free software; you can redistribute it and/or modify +# Ronin is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # -# This program is distributed in the hope that it will be useful, +# Ronin is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# along with Ronin. If not, see <http://www.gnu.org/licenses/>. # require 'ronin/url_scheme' require 'ronin/url_query_param' require 'ronin/host_name' @@ -51,14 +50,14 @@ # The host name of the URL belongs_to :host_name # Port of the URL - belongs_to :port, :model => 'TCPPort' + belongs_to :port, :model => 'TCPPort', :required => false # Path of the URL - property :path, String, :default => '' + property :path, String # The fragment of the URL property :fragment, String # The query params of the URL @@ -83,11 +82,11 @@ # The matching URLs. # # @since 1.0.0 # def self.http - all('scheme.name' => 'http') + all(:scheme => {:name => 'http'}) end # # Searches for all URLs using HTTPS. # @@ -95,11 +94,11 @@ # The matching URLs. # # @since 1.0.0 # def self.https - all('scheme.name' => 'https') + all(:scheme => {:name => 'https'}) end # # Searches for URLs with specific host name(s). # @@ -110,11 +109,11 @@ # The matching URLs. # # @since 1.0.0 # def self.hosts(names) - all('host.address' => names) + all(:host => {:address => names}) end # # Searches for URLs with the specific port number(s). # @@ -125,11 +124,11 @@ # The matching URLs. # # @since 1.0.0 # def self.ports(numbers) - all('port.number' => numbers) + all(:port => {:number => numbers}) end # # Searches for all URLs sharing a common sub-directory. # @@ -170,11 +169,11 @@ # The URLs with the given query-param. # # @since 1.0.0 # def self.query_param(name) - all('query_params.name' => name) + all(:query_params => {:name => name}) end # # Search for all URLs with a given query-param value. # @@ -185,40 +184,101 @@ # The URLs with the given query-param value. # # @since 1.0.0 # def self.query_value(value) - all('query_params.value' => value) + all(:query_params => {:value => value}) end # + # Searches for a URL. + # + # @param [URI::HTTP, String] url + # The URL to search for. + # + # @return [URL, nil] + # The matching URL. + # + # @since 1.0.0 + # + def self.[](url) + return super(url) if url.kind_of?(Integer) + + # optionally parse the URL + url = ::URI.parse(url) unless url.kind_of?(::URI) + + port = if url.port + {:number => url.port} + end + + path = normalized_path(url) + fragment = url.fragment + + # create the initial query + query = all( + :scheme => {:name => url.scheme}, + :host_name => {:address => url.host}, + :port => port, + :path => path, + :fragment => fragment + ) + + if url.query + # add the query params to the query + URI::QueryParams.parse(url.query).each do |name,value| + query = query.all( + :query_params => {:name => name, :value => value} + ) + end + end + + return query.first + end + + # # Creates a new URL. # # @param [URI::HTTP] uri # The URI to create the URL from. # # @return [URL] # The new URL. # # @since 1.0.0 # - def URL.from(uri) - new_url = URL.new( - :scheme => URLScheme.first_or_new(:name => uri.scheme), - :host_name => HostName.first_or_new(:address => uri.host), - :port => TCPPort.first_or_new(:number => uri.port), - :path => uri.path, - :fragment => uri.fragment - ) + def self.from(uri) + # find or create the URL scheme, host_name and port + scheme = self.scheme.model.first_or_new(:name => uri.scheme) + host_name = self.host_name.model.first_or_new(:address => uri.host) + port = if uri.port + self.port.model.first_or_new(:number => uri.port) + end + path = normalized_path(uri) + fragment = uri.fragment + + query_params = [] + if uri.respond_to?(:query_params) + # find or create the URL query params uri.query_params.each do |name,value| - new_url.query_params.new(:name => name, :value => value) + query_params << self.query_params.model.first_or_new( + :name => name, + :value => value + ) end end - return new_url + # find or create the URL + return first_or_new( + :scheme => scheme, + :host_name => host_name, + :port => port, + :path => path, + :fragment => fragment, + :query_params => query_params + ) end # # Parses the URL. # @@ -230,12 +290,12 @@ # # @see URL.from # # @since 1.0.0 # - def URL.parse(url) - URL.from(::URI.parse(url)) + def self.parse(url) + from(::URI.parse(url)) end # # The host name of the url. # @@ -249,17 +309,17 @@ end # # The port number used by the URL. # - # @return [Integer] + # @return [Integer, nil] # The port number. # # @since 1.0.0 # def port_number - self.port.number + self.port.number if self.port end # # Dumps the URL query params into a URI query string. # @@ -306,25 +366,31 @@ # The URI object created from the url attributes. # # @since 1.0.0 # def to_uri + # map the URL scheme to a URI class url_class = (SCHEMES[self.scheme.name] || ::URI::Generic) host = if self.host_name self.host_name.address end port = if self.port self.port.number end + query = unless self.query_params.empty? + self.query_string + end + + # build the URI return url_class.build( :scheme => self.scheme.name, :host => host, :port => port, :path => self.path, - :query => self.query_string, + :query => query, :fragment => self.fragment ) end # @@ -335,9 +401,36 @@ # # @since 1.0.0 # def to_s self.to_uri.to_s + end + + protected + + # + # Normalizes the path of a URI. + # + # @param [URI] uri + # The URI containing the path. + # + # @return [String, nil] + # The normalized path. + # + # @since 1.0.0 + # + def self.normalized_path(uri) + case uri + when URI::HTTP + # map empty HTTP paths to '/' + unless uri.path.empty? + uri.path + else + '/' + end + else + uri.path + end end end end