ronin-web 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|