shodan-ruby 0.1.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/COPYING.txt +339 -0
- data/History.txt +9 -0
- data/Manifest.txt +25 -0
- data/README.txt +129 -0
- data/Rakefile +26 -0
- data/lib/shodan/extensions/uri/http.rb +31 -0
- data/lib/shodan/extensions/uri/query_params.rb +105 -0
- data/lib/shodan/extensions/uri.rb +22 -0
- data/lib/shodan/extensions.rb +21 -0
- data/lib/shodan/has_pages.rb +231 -0
- data/lib/shodan/host.rb +146 -0
- data/lib/shodan/page.rb +308 -0
- data/lib/shodan/query.rb +250 -0
- data/lib/shodan/shodan.rb +216 -0
- data/lib/shodan/version.rb +24 -0
- data/lib/shodan.rb +23 -0
- data/spec/has_pages_examples.rb +17 -0
- data/spec/host_spec.rb +115 -0
- data/spec/page_has_hosts_examples.rb +31 -0
- data/spec/page_spec.rb +91 -0
- data/spec/query_spec.rb +95 -0
- data/spec/shodan_spec.rb +34 -0
- data/spec/spec_helper.rb +7 -0
- data/tasks/spec.rb +10 -0
- data/tasks/yard.rb +13 -0
- data.tar.gz.sig +0 -0
- metadata +144 -0
- metadata.gz.sig +1 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# shodan-ruby - A Ruby interface to SHODAN, a computer search engine.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com)
|
5
|
+
#
|
6
|
+
# This program is free software; you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation; either version 2 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'shodan/extensions/uri'
|
@@ -0,0 +1,231 @@
|
|
1
|
+
#
|
2
|
+
# shodan-ruby - A Ruby interface to SHODAN, a computer search engine.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com)
|
5
|
+
#
|
6
|
+
# This program is free software; you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation; either version 2 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
#
|
20
|
+
|
21
|
+
module Shodan
|
22
|
+
module HasPages
|
23
|
+
include Enumerable
|
24
|
+
|
25
|
+
#
|
26
|
+
# The first page.
|
27
|
+
#
|
28
|
+
# @return [Page]
|
29
|
+
# The first page.
|
30
|
+
#
|
31
|
+
def first_page
|
32
|
+
page_cache[1]
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# The page at a given index.
|
37
|
+
#
|
38
|
+
# @param [Integer] index
|
39
|
+
# The index to request a page for.
|
40
|
+
#
|
41
|
+
# @return [Page]
|
42
|
+
# The page at the specified index.
|
43
|
+
#
|
44
|
+
def [](index)
|
45
|
+
page_cache[index]
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# The pages at the given indices.
|
50
|
+
#
|
51
|
+
# @param [Range, Array<Integer>]
|
52
|
+
# The indices to request pages for.
|
53
|
+
#
|
54
|
+
# @return [Array<Page>]
|
55
|
+
# The pages at the specified indices.
|
56
|
+
#
|
57
|
+
def pages(indices)
|
58
|
+
indices.map { |index| page_cache[index] }
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Iterates over the pages at given indices.
|
63
|
+
#
|
64
|
+
# @param [Range, Array<Integer>]
|
65
|
+
# The indices to request pages for.
|
66
|
+
#
|
67
|
+
# @yield [page]
|
68
|
+
# The given block will be passed each page at one of the specified
|
69
|
+
# indices.
|
70
|
+
#
|
71
|
+
# @yieldparam [Page] page
|
72
|
+
# The page at one of the specified indices.
|
73
|
+
#
|
74
|
+
# @return [self]
|
75
|
+
#
|
76
|
+
def each_page(indices,&block)
|
77
|
+
indices.map { |index| block.call(page_cache[index]) }
|
78
|
+
return self
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Iterates over every page, until an empty page is encountered.
|
83
|
+
#
|
84
|
+
# @yield [page]
|
85
|
+
# The given block will receive every non-empty page.
|
86
|
+
#
|
87
|
+
# @yieldparam [Page] page
|
88
|
+
# A non-empty page.
|
89
|
+
#
|
90
|
+
# @return [self]
|
91
|
+
#
|
92
|
+
def each(&block)
|
93
|
+
index = 1
|
94
|
+
|
95
|
+
until ((next_page = page_cache[index]).empty?) do
|
96
|
+
block.call(next_page)
|
97
|
+
index = index + 1
|
98
|
+
end
|
99
|
+
|
100
|
+
return self
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Iterates over every host.
|
105
|
+
#
|
106
|
+
# @yield [host]
|
107
|
+
# If a block is given, it will be passed every host from every page.
|
108
|
+
#
|
109
|
+
# @yieldparam [Host] host
|
110
|
+
# A host.
|
111
|
+
#
|
112
|
+
# @return [self]
|
113
|
+
#
|
114
|
+
def each_host(&block)
|
115
|
+
each { |page| page.each(&block) }
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Iterates over the hosts in a page at a given index.
|
120
|
+
#
|
121
|
+
# @param [Integer] index
|
122
|
+
# The index of the page to iterate over.
|
123
|
+
#
|
124
|
+
# @yield [host]
|
125
|
+
# If a block is given, it will be passed every host on the page at
|
126
|
+
# the specified index.
|
127
|
+
#
|
128
|
+
# @yieldparam [Host] host
|
129
|
+
# A host on the page at the specified index.
|
130
|
+
#
|
131
|
+
def each_on_page(index,&block)
|
132
|
+
page_cache[index].each(&block)
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Iterates over each host on the pages at the given indices.
|
137
|
+
#
|
138
|
+
# @param [Range, Array<Integer>] indices
|
139
|
+
# The indices of the pages.
|
140
|
+
#
|
141
|
+
# @yield [host]
|
142
|
+
# If a block is given, it will be passed ever host on the pages
|
143
|
+
# at the specified indices.
|
144
|
+
#
|
145
|
+
# @yieldparam [Host] host
|
146
|
+
# A host on one of the pages at the specified indices.
|
147
|
+
#
|
148
|
+
# @return [self]
|
149
|
+
#
|
150
|
+
def each_on_pages(indices,&block)
|
151
|
+
each_page(indices) { |page| page.each(&block) }
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# The first host on the first page.
|
156
|
+
#
|
157
|
+
# @return [Host]
|
158
|
+
# The first host.
|
159
|
+
#
|
160
|
+
def first_host
|
161
|
+
first_page.first
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# Returns the host at a given index.
|
166
|
+
#
|
167
|
+
# @param [Integer] index
|
168
|
+
# The index to request the host at.
|
169
|
+
#
|
170
|
+
# @return [Host]
|
171
|
+
# The host at the given index.
|
172
|
+
#
|
173
|
+
def host_at(index)
|
174
|
+
page(page_index_of(index))[result_index_of(index)]
|
175
|
+
end
|
176
|
+
|
177
|
+
protected
|
178
|
+
|
179
|
+
#
|
180
|
+
# Calculates the page index for a given result rank.
|
181
|
+
#
|
182
|
+
# @param [Integer]
|
183
|
+
# The rank of a result within the total results.
|
184
|
+
#
|
185
|
+
# @return [Integer]
|
186
|
+
# The index of the page that will contain the result, with the
|
187
|
+
# specified rank.
|
188
|
+
#
|
189
|
+
def page_index_of(rank)
|
190
|
+
(((rank.to_i - 1) / results_per_page.to_i) + 1)
|
191
|
+
end
|
192
|
+
|
193
|
+
#
|
194
|
+
# Calculates the result rank of the first result on the page at the
|
195
|
+
# given index.
|
196
|
+
#
|
197
|
+
# @param [Integer] page_index
|
198
|
+
# The index of a page.
|
199
|
+
#
|
200
|
+
# @return [Integer]
|
201
|
+
# The rank of the first result on the page, with the specified index.
|
202
|
+
#
|
203
|
+
def result_offset_of(page_index)
|
204
|
+
((page_index.to_i - 1) * results_per_page.to_i)
|
205
|
+
end
|
206
|
+
|
207
|
+
#
|
208
|
+
# Calculates the in-page index of a given result rank.
|
209
|
+
#
|
210
|
+
# @param [Integer] rank
|
211
|
+
# The result rank.
|
212
|
+
#
|
213
|
+
# @return [Integer]
|
214
|
+
# The index of the result, within the page that will contain the
|
215
|
+
# result.
|
216
|
+
#
|
217
|
+
def result_index_of(rank)
|
218
|
+
((rank.to_i - 1) % results_per_page.to_i)
|
219
|
+
end
|
220
|
+
|
221
|
+
#
|
222
|
+
# The page cache.
|
223
|
+
#
|
224
|
+
# @return [Hash{Integer => Page}]
|
225
|
+
# A persistant Hash of pages.
|
226
|
+
#
|
227
|
+
def page_cache
|
228
|
+
@page_cache ||= Hash.new { |hash,key| hash[key] = page(key.to_i) }
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
data/lib/shodan/host.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
#
|
2
|
+
# shodan-ruby - A Ruby interface to SHODAN, a computer search engine.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com)
|
5
|
+
#
|
6
|
+
# This program is free software; you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation; either version 2 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
#
|
20
|
+
|
21
|
+
module Shodan
|
22
|
+
class Host
|
23
|
+
|
24
|
+
# The IP of the host
|
25
|
+
attr_reader :ip
|
26
|
+
|
27
|
+
# The date the host was added
|
28
|
+
attr_reader :date
|
29
|
+
|
30
|
+
# The host-name of the host
|
31
|
+
attr_reader :hostname
|
32
|
+
|
33
|
+
# The response returned by the host
|
34
|
+
attr_reader :response
|
35
|
+
|
36
|
+
# The HTTP version supported by the host
|
37
|
+
attr_reader :http_version
|
38
|
+
|
39
|
+
# The HTTP status code in the response
|
40
|
+
attr_reader :http_code
|
41
|
+
|
42
|
+
# The HTTP status string in the response
|
43
|
+
attr_reader :http_status
|
44
|
+
|
45
|
+
# The HTTP headers included in the response
|
46
|
+
attr_reader :http_headers
|
47
|
+
|
48
|
+
# The body of the HTTP response
|
49
|
+
attr_reader :http_body
|
50
|
+
|
51
|
+
#
|
52
|
+
# Creates a new Host object.
|
53
|
+
#
|
54
|
+
# @param [String] ip
|
55
|
+
# The IP address of the host.
|
56
|
+
#
|
57
|
+
# @param [String] date
|
58
|
+
# The date the host was added.
|
59
|
+
#
|
60
|
+
# @param [String] response
|
61
|
+
# The response received from the host.
|
62
|
+
#
|
63
|
+
# @param [String] hostname
|
64
|
+
# The optional name of the host.
|
65
|
+
#
|
66
|
+
def initialize(ip,date,response,hostname=nil)
|
67
|
+
@ip = ip
|
68
|
+
@date = Date.parse(date)
|
69
|
+
@response = response
|
70
|
+
@hostname = hostname
|
71
|
+
|
72
|
+
@http_version = nil
|
73
|
+
@http_code = nil
|
74
|
+
@http_status = nil
|
75
|
+
@http_headers = {}
|
76
|
+
@http_body = nil
|
77
|
+
|
78
|
+
if response =~ /^HTTP\/?/
|
79
|
+
lines = response.split(/[\r\n]/)
|
80
|
+
match = lines.first.split(/\s+/,3)
|
81
|
+
|
82
|
+
if match[0].include?('/')
|
83
|
+
@http_version = match[0].split('/').last
|
84
|
+
end
|
85
|
+
|
86
|
+
if match[1]
|
87
|
+
@http_code = match[1].to_i
|
88
|
+
end
|
89
|
+
|
90
|
+
@http_status = match[2]
|
91
|
+
@http_body = ''
|
92
|
+
|
93
|
+
lines[1..-1].each_with_index do |line,index|
|
94
|
+
if line.empty?
|
95
|
+
@http_body = lines[(index+2)..-1].join("\n")
|
96
|
+
break
|
97
|
+
end
|
98
|
+
|
99
|
+
name, value = line.chomp.split(/:\s+/,2)
|
100
|
+
|
101
|
+
@http_headers[name] = value
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# The server software the host runs.
|
108
|
+
#
|
109
|
+
# @return [String]
|
110
|
+
# The name of the software.
|
111
|
+
#
|
112
|
+
def server_name
|
113
|
+
if (server = @http_headers['Server'])
|
114
|
+
return server.split('/',2).first
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# The server software version.
|
120
|
+
#
|
121
|
+
# @return [String]
|
122
|
+
# The version of the software.
|
123
|
+
#
|
124
|
+
def server_version
|
125
|
+
if (server = @http_headers['Server'])
|
126
|
+
return server.split('/',2).last
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
protected
|
131
|
+
|
132
|
+
#
|
133
|
+
# Provides transparent access to the values in +headers+.
|
134
|
+
#
|
135
|
+
def method_missing(sym,*args,&block)
|
136
|
+
if (args.empty? && block.nil?)
|
137
|
+
name = sym.id2name.gsub(/_/,'-').capitalize
|
138
|
+
|
139
|
+
return @http_headers[name] if @http_headers.key?(name)
|
140
|
+
end
|
141
|
+
|
142
|
+
return super(sym,*args,&block)
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
data/lib/shodan/page.rb
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
#
|
2
|
+
# shodan-ruby - A Ruby interface to SHODAN, a computer search engine.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009 Hal Brodigan (postmodern.mod3 at gmail.com)
|
5
|
+
#
|
6
|
+
# This program is free software; you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation; either version 2 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'shodan/host'
|
22
|
+
|
23
|
+
module Shodan
|
24
|
+
class Page < Array
|
25
|
+
|
26
|
+
#
|
27
|
+
# Creates a new Page object.
|
28
|
+
#
|
29
|
+
# @param [Array] hosts
|
30
|
+
# The initial hosts.
|
31
|
+
#
|
32
|
+
# @yield [page]
|
33
|
+
# If a block is given, it will be passed the page.
|
34
|
+
#
|
35
|
+
# @yieldparam [Page] page
|
36
|
+
# The newly created Page object.
|
37
|
+
#
|
38
|
+
def initialize(hosts=[],&block)
|
39
|
+
super(hosts)
|
40
|
+
|
41
|
+
block.call(self) if block
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Maps the hosts within the page.
|
46
|
+
#
|
47
|
+
# @yield [host]
|
48
|
+
# The given block will be used to map each host in the page.
|
49
|
+
#
|
50
|
+
# @yieldparam [Host] host
|
51
|
+
# A host within the page.
|
52
|
+
#
|
53
|
+
# @return [Array]
|
54
|
+
# The resulting mapped Array.
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# page.map
|
58
|
+
# # => #<Page: ...>
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# page.map { |host| host.ip }
|
62
|
+
# # => [...]
|
63
|
+
#
|
64
|
+
def map(&block)
|
65
|
+
return self unless block
|
66
|
+
|
67
|
+
mapped = []
|
68
|
+
|
69
|
+
each { |element| mapped << block.call(element) }
|
70
|
+
return mapped
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Selects the hosts within the page.
|
75
|
+
#
|
76
|
+
# @yield [host]
|
77
|
+
# The given block will be used to select hosts from the page.
|
78
|
+
#
|
79
|
+
# @yieldparam [Host] host
|
80
|
+
# A host in the page.
|
81
|
+
#
|
82
|
+
# @return [Page]
|
83
|
+
# A sub-set of the hosts within the page.
|
84
|
+
#
|
85
|
+
# @example
|
86
|
+
# page.select { |host| host.headers['Server'] =~ /IIS/ }
|
87
|
+
#
|
88
|
+
def select(&block)
|
89
|
+
self.class.new(super(&block))
|
90
|
+
end
|
91
|
+
|
92
|
+
alias hosts_with select
|
93
|
+
|
94
|
+
#
|
95
|
+
# Iterates over the IP addresses of every host in the page.
|
96
|
+
#
|
97
|
+
# @yield [ip]
|
98
|
+
# If a block is given, it will be passed the IP addresses of every
|
99
|
+
# host.
|
100
|
+
#
|
101
|
+
# @yieldparam [String] ip
|
102
|
+
# An IP address of a host.
|
103
|
+
#
|
104
|
+
# @return [self]
|
105
|
+
#
|
106
|
+
def each_ip(&block)
|
107
|
+
each do |host|
|
108
|
+
block.call(host.ip) if block
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Selects the hosts with the matching IP address.
|
114
|
+
#
|
115
|
+
# @param [Regexp, String] ip
|
116
|
+
# The IP address to search for.
|
117
|
+
#
|
118
|
+
# @yield [host]
|
119
|
+
# If a block is also given, it will be passed every matching host.
|
120
|
+
#
|
121
|
+
# @yieldparam [Host] host
|
122
|
+
# A host with the matching IP address.
|
123
|
+
#
|
124
|
+
# @return [Array<Host>]
|
125
|
+
# The hosts with the matching IP address.
|
126
|
+
#
|
127
|
+
def hosts_with_ip(ip,&block)
|
128
|
+
hosts_with do |host|
|
129
|
+
if host.ip.match(ip)
|
130
|
+
block.call(host) if block
|
131
|
+
|
132
|
+
true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# The IP addresses of the hosts in the page.
|
139
|
+
#
|
140
|
+
# @return [Array<String>]
|
141
|
+
# The IP addresses.
|
142
|
+
#
|
143
|
+
def ips
|
144
|
+
Enumerator.new(self,:each_ip).to_a
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Iterates over the host names of every host in the page.
|
149
|
+
#
|
150
|
+
# @yield [hostname]
|
151
|
+
# If a block is given, it will be passed the host names of every host.
|
152
|
+
#
|
153
|
+
# @yieldparam [String] hostname
|
154
|
+
# A host name.
|
155
|
+
#
|
156
|
+
# @return [self]
|
157
|
+
#
|
158
|
+
def each_hostname(&block)
|
159
|
+
each do |host|
|
160
|
+
block.call(host.hostname) if (block && host.hostname)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# Selects the hosts with the matching host name.
|
166
|
+
#
|
167
|
+
# @param [Regexp, String] hostname
|
168
|
+
# The host name to search for.
|
169
|
+
#
|
170
|
+
# @yield [host]
|
171
|
+
# If a block is also given, it will be passed every matching host.
|
172
|
+
#
|
173
|
+
# @yieldparam [Host] host
|
174
|
+
# A host with the matching host name.
|
175
|
+
#
|
176
|
+
# @return [Array<Host>]
|
177
|
+
# The hosts with the matching host name.
|
178
|
+
#
|
179
|
+
def hosts_with_name(name,&block)
|
180
|
+
hosts_with do |host|
|
181
|
+
if (host.hostname && host.hostname.match(name))
|
182
|
+
block.call(host) if block
|
183
|
+
|
184
|
+
true
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
# The names of the hosts in the page.
|
191
|
+
#
|
192
|
+
# @return [Array<String>]
|
193
|
+
# The host names.
|
194
|
+
#
|
195
|
+
def hostnames
|
196
|
+
Enumerator.new(self,:each_hostname).to_a
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
# Iterates over the dates that each host was added.
|
201
|
+
#
|
202
|
+
# @yield [date]
|
203
|
+
# If a block is given, it will be passed the dates that each host was
|
204
|
+
# added.
|
205
|
+
#
|
206
|
+
# @yieldparam [Date] date
|
207
|
+
# A date that a host was added.
|
208
|
+
#
|
209
|
+
# @return [self]
|
210
|
+
#
|
211
|
+
def each_date(&block)
|
212
|
+
each do |host|
|
213
|
+
block.call(host.date) if block
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
#
|
218
|
+
# The dates that the hosts were added.
|
219
|
+
#
|
220
|
+
# @return [Array<Date>]
|
221
|
+
# The dates.
|
222
|
+
#
|
223
|
+
def dates
|
224
|
+
Enumerator.new(self,:each_date).to_a
|
225
|
+
end
|
226
|
+
|
227
|
+
#
|
228
|
+
# Iterates over the responses of each host in the page.
|
229
|
+
#
|
230
|
+
# @yield [response]
|
231
|
+
# If a block is given, it will be passed the responses of each host.
|
232
|
+
#
|
233
|
+
# @yieldparam [String] response
|
234
|
+
# The initial response of a host.
|
235
|
+
#
|
236
|
+
# @return [self]
|
237
|
+
#
|
238
|
+
def each_response(&block)
|
239
|
+
each do |host|
|
240
|
+
block.call(host.response) if block
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Selects the hosts with the matching response.
|
246
|
+
#
|
247
|
+
# @param [Regexp, String] pattern
|
248
|
+
# The response pattern to search for.
|
249
|
+
#
|
250
|
+
# @yield [host]
|
251
|
+
# If a block is also given, it will be passed every matching host.
|
252
|
+
#
|
253
|
+
# @yieldparam [Host] host
|
254
|
+
# A host with the matching response.
|
255
|
+
#
|
256
|
+
# @return [Array<Host>]
|
257
|
+
# The hosts with the matching response.
|
258
|
+
#
|
259
|
+
def responses_with(pattern,&block)
|
260
|
+
hosts_with do |host|
|
261
|
+
if host.response.match(pattern)
|
262
|
+
block.call(host) if block
|
263
|
+
|
264
|
+
true
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
#
|
270
|
+
# The responses of the hosts in the page.
|
271
|
+
#
|
272
|
+
# @return [Array<String>]
|
273
|
+
# The responses.
|
274
|
+
#
|
275
|
+
def responses(&block)
|
276
|
+
Enumerator.new(self,:each_response).to_a
|
277
|
+
end
|
278
|
+
|
279
|
+
#
|
280
|
+
# Itereates over the HTTP headers of each host in the page.
|
281
|
+
#
|
282
|
+
# @yield [headers]
|
283
|
+
# If a block is given, it will be passed the headers from each host
|
284
|
+
# in the page.
|
285
|
+
#
|
286
|
+
# @yieldparam [Hash] headers
|
287
|
+
# The headers from a host in the page.
|
288
|
+
#
|
289
|
+
# @return [self]
|
290
|
+
#
|
291
|
+
def each_http_headers(&block)
|
292
|
+
each do |host|
|
293
|
+
block.call(host.http_headers) if block
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
#
|
298
|
+
# The HTTP headers from the hosts in the page.
|
299
|
+
#
|
300
|
+
# @return [Array<Hash>]
|
301
|
+
# The HTTP headers.
|
302
|
+
#
|
303
|
+
def http_headers
|
304
|
+
Enumerator.new(self,:each_http_headers).to_a
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
308
|
+
end
|