shodan-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|