ronin-web 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/History.txt +25 -0
- data/Manifest.txt +36 -4
- data/README.txt +67 -64
- data/Rakefile +12 -3
- data/bin/ronin-web +1 -1
- data/lib/ronin/network/helpers/web.rb +221 -0
- data/lib/ronin/web.rb +1 -2
- data/lib/ronin/web/extensions.rb +0 -2
- data/lib/ronin/web/extensions/nokogiri.rb +0 -23
- data/lib/ronin/web/proxy.rb +3 -103
- data/lib/ronin/web/proxy/app.rb +31 -0
- data/lib/ronin/web/proxy/base.rb +41 -0
- data/lib/ronin/web/proxy/web.rb +42 -0
- data/lib/ronin/web/server.rb +3 -530
- data/lib/ronin/web/server/app.rb +31 -0
- data/lib/ronin/web/server/base.rb +334 -0
- data/lib/ronin/web/server/files.rb +92 -0
- data/lib/ronin/web/server/helpers.rb +25 -0
- data/lib/ronin/web/server/helpers/files.rb +126 -0
- data/lib/ronin/web/server/helpers/hosts.rb +72 -0
- data/lib/ronin/web/server/helpers/proxy.rb +153 -0
- data/lib/ronin/web/server/helpers/rendering.rb +36 -0
- data/lib/ronin/web/server/hosts.rb +86 -0
- data/lib/ronin/web/server/proxy.rb +116 -0
- data/lib/ronin/web/server/web.rb +62 -0
- data/lib/ronin/web/spider.rb +53 -26
- data/lib/ronin/web/version.rb +1 -3
- data/lib/ronin/web/web.rb +253 -95
- data/spec/spec_helper.rb +1 -1
- data/spec/web/proxy/base_spec.rb +9 -0
- data/spec/web/server/base_spec.rb +86 -0
- data/spec/web/server/classes/files/dir/file.txt +1 -0
- data/spec/web/server/classes/files/dir/index.html +1 -0
- data/spec/web/server/classes/files/dir2/file2.txt +1 -0
- data/spec/web/server/classes/files/dir3/page.xml +4 -0
- data/spec/web/server/classes/files/file.txt +1 -0
- data/spec/web/server/classes/files_app.rb +27 -0
- data/spec/web/server/classes/hosts_app.rb +40 -0
- data/spec/web/server/classes/proxy_app.rb +45 -0
- data/spec/web/server/classes/public1/static1.txt +1 -0
- data/spec/web/server/classes/public2/static2.txt +1 -0
- data/spec/web/server/classes/sub_app.rb +13 -0
- data/spec/web/server/classes/test_app.rb +20 -0
- data/spec/web/server/files_spec.rb +74 -0
- data/spec/web/server/helpers/server.rb +42 -0
- data/spec/web/server/hosts_spec.rb +55 -0
- data/spec/web/server/proxy_spec.rb +49 -0
- data/tasks/spec.rb +1 -0
- data/tasks/yard.rb +13 -0
- metadata +76 -17
- metadata.gz.sig +0 -0
- data/TODO.txt +0 -7
- data/lib/ronin/sessions/web.rb +0 -80
- data/lib/ronin/web/fingerprint.rb +0 -76
- data/spec/web/server_spec.rb +0 -142
data/lib/ronin/web.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#
|
2
|
-
#--
|
3
2
|
# Ronin Web - A Ruby library for Ronin that provides support for web
|
4
3
|
# scraping and spidering functionality.
|
5
4
|
#
|
@@ -18,13 +17,13 @@
|
|
18
17
|
# You should have received a copy of the GNU General Public License
|
19
18
|
# along with this program; if not, write to the Free Software
|
20
19
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
21
|
-
#++
|
22
20
|
#
|
23
21
|
|
24
22
|
require 'ronin/web/extensions'
|
25
23
|
require 'ronin/web/web'
|
26
24
|
require 'ronin/web/spider'
|
27
25
|
require 'ronin/web/server'
|
26
|
+
require 'ronin/web/proxy'
|
28
27
|
require 'ronin/web/version'
|
29
28
|
require 'ronin/config'
|
30
29
|
|
data/lib/ronin/web/extensions.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#
|
2
|
-
#--
|
3
2
|
# Ronin Web - A Ruby library for Ronin that provides support for web
|
4
3
|
# scraping and spidering functionality.
|
5
4
|
#
|
@@ -18,7 +17,6 @@
|
|
18
17
|
# You should have received a copy of the GNU General Public License
|
19
18
|
# along with this program; if not, write to the Free Software
|
20
19
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
21
|
-
#++
|
22
20
|
#
|
23
21
|
|
24
22
|
require 'ronin/web/extensions/nokogiri'
|
@@ -1,24 +1 @@
|
|
1
|
-
#
|
2
|
-
#--
|
3
|
-
# Ronin Web - A Ruby library for Ronin that provides support for web
|
4
|
-
# scraping and spidering functionality.
|
5
|
-
#
|
6
|
-
# Copyright (c) 2006-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
|
7
|
-
#
|
8
|
-
# This program is free software; you can redistribute it and/or modify
|
9
|
-
# it under the terms of the GNU General Public License as published by
|
10
|
-
# the Free Software Foundation; either version 2 of the License, or
|
11
|
-
# (at your option) any later version.
|
12
|
-
#
|
13
|
-
# This program is distributed in the hope that it will be useful,
|
14
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
-
# GNU General Public License for more details.
|
17
|
-
#
|
18
|
-
# You should have received a copy of the GNU General Public License
|
19
|
-
# along with this program; if not, write to the Free Software
|
20
|
-
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
21
|
-
#++
|
22
|
-
#
|
23
|
-
|
24
1
|
require 'ronin/web/extensions/nokogiri/xml'
|
data/lib/ronin/web/proxy.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#
|
2
|
-
#--
|
3
2
|
# Ronin Web - A Ruby library for Ronin that provides support for web
|
4
3
|
# scraping and spidering functionality.
|
5
4
|
#
|
@@ -18,107 +17,8 @@
|
|
18
17
|
# You should have received a copy of the GNU General Public License
|
19
18
|
# along with this program; if not, write to the Free Software
|
20
19
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
21
|
-
#++
|
22
20
|
#
|
23
21
|
|
24
|
-
require 'ronin/web/
|
25
|
-
require 'ronin/
|
26
|
-
|
27
|
-
require 'net/http'
|
28
|
-
|
29
|
-
module Ronin
|
30
|
-
module Web
|
31
|
-
class Proxy < Server
|
32
|
-
|
33
|
-
# The default HTTP Request to use
|
34
|
-
DEFAULT_HTTP_REQUEST = Net::HTTP::Get
|
35
|
-
|
36
|
-
#
|
37
|
-
# Creates a new Web Proxy using the given configuration _block_.
|
38
|
-
#
|
39
|
-
# _options_ may contain the following keys:
|
40
|
-
# <tt>:host</tt>:: The host to bind to.
|
41
|
-
# <tt>:port</tt>:: The port to listen on.
|
42
|
-
# <tt>:config</tt>:: A +Hash+ of configurable variables to be used
|
43
|
-
# in responses.
|
44
|
-
#
|
45
|
-
def initialize(options={},&block)
|
46
|
-
super(options)
|
47
|
-
|
48
|
-
@default = method(:proxy)
|
49
|
-
|
50
|
-
instance_eval(&block) if block
|
51
|
-
end
|
52
|
-
|
53
|
-
#
|
54
|
-
# Proxies the specified Rack _request_ and returns a corresponding
|
55
|
-
# Rack response.
|
56
|
-
#
|
57
|
-
def proxy(request)
|
58
|
-
server_response = http_response(request)
|
59
|
-
server_headers = server_response.to_hash
|
60
|
-
body = (server_response.body || '')
|
61
|
-
|
62
|
-
return response(body,server_headers)
|
63
|
-
end
|
64
|
-
|
65
|
-
protected
|
66
|
-
|
67
|
-
#
|
68
|
-
# Returns the Net::HTTP Request class that represents the specified
|
69
|
-
# HTTP _request_method_.
|
70
|
-
#
|
71
|
-
# http_class('POST')
|
72
|
-
# # => Net::HTTP::Post
|
73
|
-
#
|
74
|
-
def http_class(request_method)
|
75
|
-
http_method = request_method.downcase.capitalize
|
76
|
-
http_class = DEFAULT_HTTP_REQUEST
|
77
|
-
|
78
|
-
if Net::HTTP.const_defined?(http_method)
|
79
|
-
http_class = Net::HTTP.const_get(http_method)
|
80
|
-
|
81
|
-
unless http_class.kind_of?(Net::HTTPRequest)
|
82
|
-
http_class = DEFAULT_HTTP_REQUEST
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
return http_class
|
87
|
-
end
|
88
|
-
|
89
|
-
#
|
90
|
-
# Converts the Rack headers within the specified _request_ to
|
91
|
-
# Net::HTTP formatted HTTP headers.
|
92
|
-
#
|
93
|
-
def http_headers(request)
|
94
|
-
client_headers = {}
|
95
|
-
|
96
|
-
request.env.each do |name,value|
|
97
|
-
if name =~ /^HTTP_/
|
98
|
-
header_name = name.gsub(/^HTTP_/,'').split('_').map { |word|
|
99
|
-
word.capitalize
|
100
|
-
}.join('-')
|
101
|
-
|
102
|
-
client_headers[header_name] = value
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
return client_headers
|
107
|
-
end
|
108
|
-
|
109
|
-
#
|
110
|
-
# Returns the Net::HTTP response for the specified Rack _request_.
|
111
|
-
#
|
112
|
-
def http_response(request)
|
113
|
-
path = request.fullpath
|
114
|
-
http_method = http_class(request.request_method)
|
115
|
-
client_request = http_method.new(path,http_headers(request))
|
116
|
-
|
117
|
-
Net.http_session(:host => request.host, :port => request.port) do |http|
|
118
|
-
return http.request(client_request)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
22
|
+
require 'ronin/web/proxy/base'
|
23
|
+
require 'ronin/web/proxy/app'
|
24
|
+
require 'ronin/web/proxy/web'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Ronin Web - A Ruby library for Ronin that provides support for web
|
3
|
+
# scraping and spidering functionality.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20
|
+
#
|
21
|
+
|
22
|
+
require 'ronin/web/proxy/base'
|
23
|
+
|
24
|
+
module Ronin
|
25
|
+
module Web
|
26
|
+
module Proxy
|
27
|
+
class App < Base
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#
|
2
|
+
# Ronin Web - A Ruby library for Ronin that provides support for web
|
3
|
+
# scraping and spidering functionality.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20
|
+
#
|
21
|
+
|
22
|
+
require 'ronin/web/server/base'
|
23
|
+
|
24
|
+
module Ronin
|
25
|
+
module Web
|
26
|
+
module Proxy
|
27
|
+
class Base < Server::Base
|
28
|
+
|
29
|
+
# The default port to run the Web Proxy on
|
30
|
+
DEFAULT_PORT = 8080
|
31
|
+
|
32
|
+
set :port, DEFAULT_PORT
|
33
|
+
|
34
|
+
default do
|
35
|
+
proxy
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# Ronin Web - A Ruby library for Ronin that provides support for web
|
3
|
+
# scraping and spidering functionality.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation; either version 2 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program; if not, write to the Free Software
|
19
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20
|
+
#
|
21
|
+
|
22
|
+
require 'ronin/web/proxy/app'
|
23
|
+
|
24
|
+
module Ronin
|
25
|
+
module Web
|
26
|
+
#
|
27
|
+
# Returns the Ronin Web Proxy. When called for the first time
|
28
|
+
# the proxy will be started in the background with the given
|
29
|
+
# _options_.
|
30
|
+
#
|
31
|
+
def Web.proxy(options={},&block)
|
32
|
+
unless class_variable_defined?('@@ronin_web_proxy')
|
33
|
+
@@ronin_web_proxy = Proxy::App
|
34
|
+
@@ronin_web_proxy.run!(options.merge(:background => true))
|
35
|
+
end
|
36
|
+
|
37
|
+
@@ronin_web_proxy.class_eval(&block)
|
38
|
+
|
39
|
+
return @@ronin_web_proxy
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/ronin/web/server.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#
|
2
|
-
#--
|
3
2
|
# Ronin Web - A Ruby library for Ronin that provides support for web
|
4
3
|
# scraping and spidering functionality.
|
5
4
|
#
|
@@ -18,534 +17,8 @@
|
|
18
17
|
# You should have received a copy of the GNU General Public License
|
19
18
|
# along with this program; if not, write to the Free Software
|
20
19
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
21
|
-
#++
|
22
20
|
#
|
23
21
|
|
24
|
-
require '
|
25
|
-
require '
|
26
|
-
require '
|
27
|
-
|
28
|
-
begin
|
29
|
-
require 'mongrel'
|
30
|
-
rescue Gem::LoadError => e
|
31
|
-
raise(e)
|
32
|
-
rescue LoadError
|
33
|
-
require 'webrick'
|
34
|
-
end
|
35
|
-
|
36
|
-
require 'rack'
|
37
|
-
|
38
|
-
module Ronin
|
39
|
-
module Web
|
40
|
-
class Server
|
41
|
-
|
42
|
-
# Default interface to run the Web Server on
|
43
|
-
HOST = '0.0.0.0'
|
44
|
-
|
45
|
-
# Default port to run the Web Server on
|
46
|
-
PORT = 8080
|
47
|
-
|
48
|
-
# Directory index files
|
49
|
-
INDICES = ['index.htm', 'index.html']
|
50
|
-
|
51
|
-
# The host to bind to
|
52
|
-
attr_accessor :host
|
53
|
-
|
54
|
-
# The port to listen on
|
55
|
-
attr_accessor :port
|
56
|
-
|
57
|
-
# The handler to run the server under
|
58
|
-
attr_accessor :handler
|
59
|
-
|
60
|
-
#
|
61
|
-
# Creates a new Web Server using the given configuration _block_.
|
62
|
-
#
|
63
|
-
# _options_ may contain the following keys:
|
64
|
-
# <tt>:host</tt>:: The host to bind to.
|
65
|
-
# <tt>:port</tt>:: The port to listen on.
|
66
|
-
# <tt>:handler</tt>:: The handler to run the server under.
|
67
|
-
#
|
68
|
-
def initialize(options={},&block)
|
69
|
-
@host = options[:host]
|
70
|
-
@port = options[:port]
|
71
|
-
@handler = options[:handler]
|
72
|
-
|
73
|
-
@default = method(:not_found)
|
74
|
-
|
75
|
-
@vhost_patterns = {}
|
76
|
-
@vhosts = {}
|
77
|
-
|
78
|
-
@patterns = {}
|
79
|
-
@paths = {}
|
80
|
-
@directories = {}
|
81
|
-
|
82
|
-
@default_mutex = Mutex.new
|
83
|
-
@vhost_patterns_mutex = Mutex.new
|
84
|
-
@vhosts_mutex = Mutex.new
|
85
|
-
@patterns_mutex = Mutex.new
|
86
|
-
@paths_mutex = Mutex.new
|
87
|
-
@directories_mutex = Mutex.new
|
88
|
-
|
89
|
-
block.call(self) if block
|
90
|
-
end
|
91
|
-
|
92
|
-
#
|
93
|
-
# Returns the default host that the Web Server will be run on.
|
94
|
-
#
|
95
|
-
def Server.default_host
|
96
|
-
@@default_host ||= HOST
|
97
|
-
end
|
98
|
-
|
99
|
-
#
|
100
|
-
# Sets the default host that the Web Server will run on to the
|
101
|
-
# specified _host_.
|
102
|
-
#
|
103
|
-
def Server.default_host=(host)
|
104
|
-
@@default_host = host
|
105
|
-
end
|
106
|
-
|
107
|
-
#
|
108
|
-
# Returns the default port that the Web Server will run on.
|
109
|
-
#
|
110
|
-
def Server.default_port
|
111
|
-
@@default_port ||= PORT
|
112
|
-
end
|
113
|
-
|
114
|
-
#
|
115
|
-
# Sets the default port the Web Server will run on to the specified
|
116
|
-
# _port_.
|
117
|
-
#
|
118
|
-
def Server.default_port=(port)
|
119
|
-
@@default_port = port
|
120
|
-
end
|
121
|
-
|
122
|
-
#
|
123
|
-
# The Hash of the servers supported file extensions and their HTTP
|
124
|
-
# Content-Types.
|
125
|
-
#
|
126
|
-
def Server.content_types
|
127
|
-
@@content_types ||= {}
|
128
|
-
end
|
129
|
-
|
130
|
-
#
|
131
|
-
# Registers a new content _type_ for the specified file _extensions_.
|
132
|
-
#
|
133
|
-
# Server.content_type 'text/xml', ['xml', 'xsl']
|
134
|
-
#
|
135
|
-
def Server.content_type(type,extensions)
|
136
|
-
extensions.each { |ext| Server.content_types[ext] = type }
|
137
|
-
|
138
|
-
return self
|
139
|
-
end
|
140
|
-
|
141
|
-
#
|
142
|
-
# Creates a new Web Server object with the given _block_ and starts
|
143
|
-
# it using the given _options_.
|
144
|
-
#
|
145
|
-
def self.start(options={},&block)
|
146
|
-
self.new(options,&block).start
|
147
|
-
end
|
148
|
-
|
149
|
-
#
|
150
|
-
# Returns the HTTP Content-Type for the specified file _extension_.
|
151
|
-
#
|
152
|
-
# server.content_type('html')
|
153
|
-
# # => "text/html"
|
154
|
-
#
|
155
|
-
def content_type(extension)
|
156
|
-
Server.content_types[extension] ||
|
157
|
-
'application/x-unknown-content-type'
|
158
|
-
end
|
159
|
-
|
160
|
-
#
|
161
|
-
# Returns the HTTP Content-Type for the specified _file_.
|
162
|
-
#
|
163
|
-
# server.content_type_for('file.html')
|
164
|
-
# # => "text/html"
|
165
|
-
#
|
166
|
-
def content_type_for(file)
|
167
|
-
ext = File.extname(file).downcase
|
168
|
-
|
169
|
-
return content_type(ext[1..-1])
|
170
|
-
end
|
171
|
-
|
172
|
-
#
|
173
|
-
# Returns the index file contained within the _path_ of the specified
|
174
|
-
# directory. If no index file can be found, +nil+ will be returned.
|
175
|
-
#
|
176
|
-
def index_of(path)
|
177
|
-
path = File.expand_path(path)
|
178
|
-
|
179
|
-
INDICES.each do |name|
|
180
|
-
index = File.join(path,name)
|
181
|
-
|
182
|
-
return index if File.file?(index)
|
183
|
-
end
|
184
|
-
|
185
|
-
return nil
|
186
|
-
end
|
187
|
-
|
188
|
-
#
|
189
|
-
# Returns the HTTP 404 Not Found message for the requested path.
|
190
|
-
#
|
191
|
-
def not_found(request)
|
192
|
-
path = request.path_info
|
193
|
-
body = %{<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
194
|
-
<html>
|
195
|
-
<head>
|
196
|
-
<title>404 Not Found</title>
|
197
|
-
<body>
|
198
|
-
<h1>Not Found</h1>
|
199
|
-
<p>The requested URL #{CGI.escapeHTML(path)} was not found on this server.</p>
|
200
|
-
<hr>
|
201
|
-
</body>
|
202
|
-
</html>}
|
203
|
-
|
204
|
-
return response(body, :status => 404, :content_type => 'text/html')
|
205
|
-
end
|
206
|
-
|
207
|
-
#
|
208
|
-
# Returns the contents of the file at the specified _path_. If the
|
209
|
-
# _path_ points to a directory, the directory will be searched for
|
210
|
-
# an index file. If no index file can be found or _path_ points to a
|
211
|
-
# non-existant file, a "404 Not Found" response will be returned.
|
212
|
-
#
|
213
|
-
def return_file(path,request,content_type=nil)
|
214
|
-
content_type ||= content_type_for(path)
|
215
|
-
|
216
|
-
if !(File.exists?(path))
|
217
|
-
return not_found(request)
|
218
|
-
end
|
219
|
-
|
220
|
-
if File.directory?(path)
|
221
|
-
unless (path = index_of(path))
|
222
|
-
return not_found(request)
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
return response(File.new(path), :content_type => content_type)
|
227
|
-
end
|
228
|
-
|
229
|
-
#
|
230
|
-
# Returns a Rack Response object with the specified _body_, the given
|
231
|
-
# _options_ and the given _block_.
|
232
|
-
#
|
233
|
-
# _options_ may include the following keys:
|
234
|
-
# <tt>:status</tt>:: The HTTP Response status code, defaults to 200.
|
235
|
-
#
|
236
|
-
# server.response("<data>lol</data>", :content_type => 'text/xml')
|
237
|
-
#
|
238
|
-
def response(body='',options={},&block)
|
239
|
-
status = (
|
240
|
-
options.delete(:status) ||
|
241
|
-
options.delete('Status') ||
|
242
|
-
200
|
243
|
-
)
|
244
|
-
headers = {}
|
245
|
-
|
246
|
-
options.each do |name,value|
|
247
|
-
header_name = name.to_s.split('_').map { |word|
|
248
|
-
word.capitalize
|
249
|
-
}.join('-')
|
250
|
-
|
251
|
-
headers[header_name] = value.to_s
|
252
|
-
end
|
253
|
-
|
254
|
-
return Rack::Response.new(body,status,headers,&block).finish
|
255
|
-
end
|
256
|
-
|
257
|
-
#
|
258
|
-
# Returns the server that handles requests for the specified host
|
259
|
-
# _name_.
|
260
|
-
#
|
261
|
-
def vhost(name)
|
262
|
-
name = name.to_s
|
263
|
-
|
264
|
-
@vhosts_mutex.synchronize do
|
265
|
-
if @vhosts.has_key?(name)
|
266
|
-
return @vhosts[name]
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
@vhost_patterns_mutex.synchronize do
|
271
|
-
@vhost_patterns.each do |pattern,server|
|
272
|
-
return server if name.match(pattern)
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
return nil
|
277
|
-
end
|
278
|
-
|
279
|
-
#
|
280
|
-
# Use the given _server_ or _block_ as the default route for all
|
281
|
-
# other requests.
|
282
|
-
#
|
283
|
-
# server.default do |request|
|
284
|
-
# [200, {'Content-Type' => 'text/html'}, 'lol train']
|
285
|
-
# end
|
286
|
-
#
|
287
|
-
def default(server=nil,&block)
|
288
|
-
@default_mutex.synchronize do
|
289
|
-
@default = (server || block)
|
290
|
-
end
|
291
|
-
|
292
|
-
return self
|
293
|
-
end
|
294
|
-
|
295
|
-
#
|
296
|
-
# Registers the given _server_ or _block_ to be called when receiving
|
297
|
-
# requests to host names which match the specified _pattern_.
|
298
|
-
#
|
299
|
-
# server.hosts_like(/^a[0-9]\./) do |vhost|
|
300
|
-
# vhost.map('/download/') do |request|
|
301
|
-
# ...
|
302
|
-
# end
|
303
|
-
# end
|
304
|
-
#
|
305
|
-
def hosts_like(pattern,server=nil,&block)
|
306
|
-
server ||= self.class.new(&block)
|
307
|
-
|
308
|
-
@vhost_patterns_mutex.synchronize do
|
309
|
-
@vhost_patterns[pattern] = server
|
310
|
-
end
|
311
|
-
|
312
|
-
return server
|
313
|
-
end
|
314
|
-
|
315
|
-
#
|
316
|
-
# Registers the given _server_ or _block_ to be called when receiving
|
317
|
-
# requests for paths which match the specified _pattern_.
|
318
|
-
#
|
319
|
-
# server.paths_like(/\.xml$/) do |request|
|
320
|
-
# ...
|
321
|
-
# end
|
322
|
-
#
|
323
|
-
def paths_like(pattern,server=nil,&block)
|
324
|
-
@patterns_mutex.synchronize do
|
325
|
-
@patterns[pattern] = (server || block)
|
326
|
-
end
|
327
|
-
|
328
|
-
return self
|
329
|
-
end
|
330
|
-
|
331
|
-
#
|
332
|
-
# Creates a new Server object using the specified _block_ and
|
333
|
-
# connects it as a virtual host representing the specified host
|
334
|
-
# _name_.
|
335
|
-
#
|
336
|
-
# server.host('cdn.evil.com') do |server|
|
337
|
-
# ...
|
338
|
-
# end
|
339
|
-
#
|
340
|
-
def host(name,server=nil,&block)
|
341
|
-
server ||= self.class.new(&block)
|
342
|
-
|
343
|
-
@vhosts_mutex.synchronize do
|
344
|
-
@vhosts[name.to_s] = server
|
345
|
-
end
|
346
|
-
|
347
|
-
return server
|
348
|
-
end
|
349
|
-
|
350
|
-
#
|
351
|
-
# Binds the specified URL _path_ to the given _server_ or _block_.
|
352
|
-
#
|
353
|
-
# server.bind '/secrets.xml' do |request|
|
354
|
-
# [200, {'Content-Type' => 'text/xml'}, "Made you look."]
|
355
|
-
# end
|
356
|
-
#
|
357
|
-
def bind(path,server=nil,&block)
|
358
|
-
@paths_mutex.synchronize do
|
359
|
-
@paths[path] = (server || block)
|
360
|
-
end
|
361
|
-
|
362
|
-
return self
|
363
|
-
end
|
364
|
-
|
365
|
-
#
|
366
|
-
# Binds the specified URL directory _path_ to the given
|
367
|
-
# _server_ or _block_.
|
368
|
-
#
|
369
|
-
# server.map '/downloads' do |request|
|
370
|
-
# server.response(
|
371
|
-
# "Your somewhere inside the downloads directory",
|
372
|
-
# :content_type' => 'text/xml'
|
373
|
-
# )
|
374
|
-
# end
|
375
|
-
#
|
376
|
-
def map(path,server=nil,&block)
|
377
|
-
@directories_mutex.synchronize do
|
378
|
-
@directories[path] = (server || block)
|
379
|
-
end
|
380
|
-
|
381
|
-
return self
|
382
|
-
end
|
383
|
-
|
384
|
-
#
|
385
|
-
# Binds the contents of the specified _file_ to the specified URL
|
386
|
-
# _path_, using the given _options_.
|
387
|
-
#
|
388
|
-
# _options_ may contain the following keys:
|
389
|
-
# <tt>content_type</tt>:: The content-type to use when serving
|
390
|
-
# the file at the specified _path_.
|
391
|
-
#
|
392
|
-
# server.file '/robots.txt', '/path/to/my_robots.txt'
|
393
|
-
#
|
394
|
-
def file(path,file,options={})
|
395
|
-
file = File.expand_path(file)
|
396
|
-
content_type = options[:content_type]
|
397
|
-
|
398
|
-
bind(path) do |request|
|
399
|
-
if File.file?(file)
|
400
|
-
return_file(file,request,content_type)
|
401
|
-
else
|
402
|
-
not_found(request)
|
403
|
-
end
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
#
|
408
|
-
# Binds the contents of the specified _directory_ to the given
|
409
|
-
# prefix _path_.
|
410
|
-
#
|
411
|
-
# server.directory '/download/', '/tmp/files/'
|
412
|
-
#
|
413
|
-
def directory(path,directory)
|
414
|
-
sub_dirs = path.split('/')
|
415
|
-
directory = File.expand_path(directory)
|
416
|
-
|
417
|
-
map(path) do |request|
|
418
|
-
http_path = File.expand_path(request.path_info)
|
419
|
-
http_dirs = http_path.split('/')
|
420
|
-
|
421
|
-
sub_path = http_dirs[sub_dirs.length..-1].join('/')
|
422
|
-
absolute_path = File.join(directory,sub_path)
|
423
|
-
|
424
|
-
return_file(absolute_path,request)
|
425
|
-
end
|
426
|
-
end
|
427
|
-
|
428
|
-
#
|
429
|
-
# Starts the server. Mongrel will be used to run the server, if it
|
430
|
-
# is installed, otherwise WEBrick will be used.
|
431
|
-
#
|
432
|
-
def start
|
433
|
-
rack_handler = [@handler, 'Mongrel', 'WEBrick'].find do |name|
|
434
|
-
name && Rack::Handler.const_defined?(name)
|
435
|
-
end
|
436
|
-
|
437
|
-
unless rack_handler
|
438
|
-
raise(StandardError,"unable to find any Rack handlers",caller)
|
439
|
-
end
|
440
|
-
|
441
|
-
rack_options = {
|
442
|
-
'Host' => (@host || Server.default_host),
|
443
|
-
'Port' => (@port || Server.default_port)
|
444
|
-
}
|
445
|
-
|
446
|
-
Rack::Handler.const_get(rack_handler).run(self,rack_options)
|
447
|
-
return self
|
448
|
-
end
|
449
|
-
|
450
|
-
#
|
451
|
-
# The method which receives all requests.
|
452
|
-
#
|
453
|
-
def call(env)
|
454
|
-
http_host = env['HTTP_HOST']
|
455
|
-
http_path = File.expand_path(env['PATH_INFO'])
|
456
|
-
request = Rack::Request.new(env)
|
457
|
-
|
458
|
-
if http_host
|
459
|
-
if (server = vhost(http_host))
|
460
|
-
return server.call(env)
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
if http_path
|
465
|
-
@paths_mutex.synchronize do
|
466
|
-
if (block = @paths[http_path])
|
467
|
-
return block.call(request)
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
|
-
@patterns_mutex.synchronize do
|
472
|
-
@patterns.each do |pattern,block|
|
473
|
-
if http_path.match(pattern)
|
474
|
-
return block.call(request)
|
475
|
-
end
|
476
|
-
end
|
477
|
-
end
|
478
|
-
|
479
|
-
http_dirs = http_path.split('/')
|
480
|
-
|
481
|
-
@directories_mutex.synchronize do
|
482
|
-
sub_dir = @directories.keys.select { |path|
|
483
|
-
dirs = path.split('/')
|
484
|
-
|
485
|
-
http_dirs[0...dirs.length] == dirs
|
486
|
-
}.sort.last
|
487
|
-
|
488
|
-
if (sub_dir && (block = @directories[sub_dir]))
|
489
|
-
return block.call(request)
|
490
|
-
end
|
491
|
-
end
|
492
|
-
end
|
493
|
-
|
494
|
-
resp = nil
|
495
|
-
|
496
|
-
@default_mutex.synchronize do
|
497
|
-
resp = @default.call(request)
|
498
|
-
end
|
499
|
-
|
500
|
-
return resp
|
501
|
-
end
|
502
|
-
|
503
|
-
#
|
504
|
-
# Routes the specified _url_ to the call method.
|
505
|
-
#
|
506
|
-
def route(url)
|
507
|
-
url = URI(url.to_s)
|
508
|
-
|
509
|
-
return call(
|
510
|
-
'HTTP_HOST' => url.host,
|
511
|
-
'HTTP_PORT' => url.port,
|
512
|
-
'SERVER_PORT' => url.port,
|
513
|
-
'PATH_INFO' => url.path,
|
514
|
-
'QUERY_STRING' => url.query
|
515
|
-
)
|
516
|
-
end
|
517
|
-
|
518
|
-
#
|
519
|
-
# Routes the specified _path_ to the call method.
|
520
|
-
#
|
521
|
-
def route_path(path)
|
522
|
-
path, query = URI.decode(path.to_s).split('?',2)
|
523
|
-
|
524
|
-
return route(URI::HTTP.build(
|
525
|
-
:host => @host,
|
526
|
-
:port => @port,
|
527
|
-
:path => path,
|
528
|
-
:query => query
|
529
|
-
))
|
530
|
-
end
|
531
|
-
|
532
|
-
protected
|
533
|
-
|
534
|
-
content_type 'text/html', ['html', 'htm', 'xhtml']
|
535
|
-
content_type 'text/css', ['css']
|
536
|
-
content_type 'text/gif', ['gif']
|
537
|
-
content_type 'text/jpeg', ['jpeg', 'jpg']
|
538
|
-
content_type 'text/png', ['png']
|
539
|
-
content_type 'image/x-icon', ['ico']
|
540
|
-
content_type 'text/javascript', ['js']
|
541
|
-
content_type 'text/xml', ['xml', 'xsl']
|
542
|
-
content_type 'application/rss+xml', ['rss']
|
543
|
-
content_type 'application/rdf+xml', ['rdf']
|
544
|
-
content_type 'application/pdf', ['pdf']
|
545
|
-
content_type 'application/doc', ['doc']
|
546
|
-
content_type 'application/zip', ['zip']
|
547
|
-
content_type 'text/plain', ['txt', 'conf', 'rb', 'py', 'h', 'c', 'hh', 'cc', 'hpp', 'cpp']
|
548
|
-
|
549
|
-
end
|
550
|
-
end
|
551
|
-
end
|
22
|
+
require 'ronin/web/server/base'
|
23
|
+
require 'ronin/web/server/app'
|
24
|
+
require 'ronin/web/server/web'
|