benchmark-http 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b3803e60e468cb173cbaf5df1556f95fc7dfe89531fb785530050875a5a32e1
4
- data.tar.gz: a5c54afd2afb70743f6d589eaa784c593a5f78d96e59c87c996ef90a7aa968fb
3
+ metadata.gz: '069082c04439ca3f6d2a49daa213721646b46051c0ea6b9c55d0247adfdcbeaf'
4
+ data.tar.gz: 041fc41a0379bac2264ff90dde3dbc03ef6a20216deeb75fa3fdb818294bdf7f
5
5
  SHA512:
6
- metadata.gz: aff57e060c1239d34ef229f33c6141beefdea04970adf8608d119824cc512bcb5e994df5df3290023f03e1f3a3563184a8437b377ad01a26d1576718cfa45715
7
- data.tar.gz: 78d67c5fd5dfdbe15306723711ea4b274278e9c694d287105f3b808d725b10ae500c64007f67497eddd655d4b8a8603c02395b99b1db23422fd725711e649209
6
+ metadata.gz: 8ff5661cfa6ee80bbd0737b87a872da7e180bdb27536dbcc321625e331c8557333e314a1eedc9f1af1e9924cb556146540463aed89242b186c336032bd892289
7
+ data.tar.gz: b842c305fc9ab7a18bb1c0f7dbcc2e6b7933dbae5cdfed237b040fa2c1a79edc16cfdc74083213067feca4493cda4a16d4f670e654d668e3870335f2090776ce
@@ -7,6 +7,7 @@ matrix:
7
7
  - rvm: 2.4
8
8
  - rvm: 2.5
9
9
  - rvm: 2.6
10
+ - rvm: 2.7
10
11
  - rvm: jruby-head
11
12
  env: JRUBY_OPTS="--debug -X+O"
12
13
  - rvm: ruby-head
@@ -18,13 +18,8 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative '../seconds'
22
- require_relative '../statistics'
23
- require_relative '../links_filter'
21
+ require_relative '../spider'
24
22
 
25
- require 'async'
26
- require 'async/http/client'
27
- require 'async/http/endpoint'
28
23
  require 'async/await'
29
24
 
30
25
  require 'samovar'
@@ -46,97 +41,19 @@ module Benchmark
46
41
  many :urls, "One or more hosts to benchmark"
47
42
 
48
43
  def log(method, url, response)
49
- puts "#{method} #{url} -> #{response.version} #{response.status} (#{response.body&.length || 'unspecified'} bytes)"
50
-
51
- response.headers.each do |key, value|
52
- puts "\t#{key}: #{value}"
53
- end if @options[:headers]
54
- end
55
-
56
- def extract_links(url, response)
57
- base = url
58
-
59
- body = response.read
60
-
61
- begin
62
- filter = LinksFilter.parse(body)
63
- rescue
64
- Async.logger.error($!)
65
- return []
66
- end
67
-
68
- if filter.base
69
- base = base + filter.base
70
- end
71
-
72
- filter.links.collect do |href|
73
- next if href.nil? or href.empty?
44
+ Async.logger.call(self, severity: (response.failure? ? :warn : :info)) do |buffer|
45
+ buffer.puts "#{method} #{url} -> #{response.version} #{response.status} (#{response.body&.length || 'unspecified'} bytes)"
74
46
 
75
- begin
76
- full_url = base + href
77
-
78
- if full_url.host == url.host && full_url.kind_of?(URI::HTTP)
79
- yield full_url
80
- end
81
- rescue ArgumentError, URI::InvalidURIError
82
- puts "Could not fetch #{href}, relative to #{base}."
83
- end
84
- end.compact
85
- end
86
-
87
- async def fetch(statistics, client, url, depth = @options[:depth], fetched = Set.new)
88
- return if fetched.include?(url) or depth == 0
89
-
90
- fetched << url
91
-
92
- request_uri = url.request_uri
93
-
94
- response = client.head(request_uri).tap(&:read)
95
-
96
- log("HEAD", url, response)
97
-
98
- if response.redirection?
99
- location = url + response.headers['location']
100
- if location.host == url.host
101
- puts "Following redirect to #{location}..."
102
- return fetch(statistics, client, location, depth-1, fetched).wait
103
- else
104
- puts "Ignoring redirect to #{location}."
105
- return
106
- end
107
- end
108
-
109
- content_type = response.headers['content-type']
110
- unless content_type&.start_with? 'text/html'
111
- puts "Unsupported content type: #{content_type}"
112
- return
47
+ response.headers.each do |key, value|
48
+ buffer.puts "\t#{key}: #{value}"
49
+ end if @options[:headers]
113
50
  end
114
-
115
- response = statistics.measure do
116
- client.get(request_uri)
117
- end
118
-
119
- log("GET", url, response)
120
-
121
- extract_links(url, response) do |href|
122
- fetch(statistics, client, href, depth - 1, fetched)
123
- end.each(&:wait)
124
- rescue Async::TimeoutError
125
- Async.logger.error("Timeout while fetching #{url}")
126
- rescue StandardError
127
- Async.logger.error($!)
128
51
  end
129
52
 
130
- async def call
131
- statistics = Statistics.new
53
+ sync def call
54
+ spider = HTTP::Spider.new(depth: @options[:depth])
132
55
 
133
- @urls.each do |url|
134
- endpoint = Async::HTTP::Endpoint.parse(url, timeout: 10)
135
-
136
- Async::HTTP::Client.open(endpoint, endpoint.protocol, connection_limit: 4) do |client|
137
- fetch(statistics, client, endpoint.url).wait
138
- end
139
- end
56
+ statistics = spider.call(@urls, &self.method(:log))
140
57
 
141
58
  statistics.print
142
59
 
@@ -0,0 +1,132 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'seconds'
22
+ require_relative 'statistics'
23
+ require_relative 'links_filter'
24
+
25
+ require 'async'
26
+ require 'async/http/client'
27
+ require 'async/http/endpoint'
28
+ require 'async/await'
29
+
30
+ require 'uri'
31
+
32
+ module Benchmark
33
+ module HTTP
34
+ class Spider
35
+ include Async::Await
36
+
37
+ def initialize(depth: nil)
38
+ @depth = depth
39
+ end
40
+
41
+ def extract_links(url, response)
42
+ base = url
43
+
44
+ body = response.read
45
+
46
+ begin
47
+ filter = LinksFilter.parse(body)
48
+ rescue
49
+ Async.logger.error(self) {$!}
50
+ return []
51
+ end
52
+
53
+ if filter.base
54
+ base = base + filter.base
55
+ end
56
+
57
+ filter.links.collect do |href|
58
+ next if href.nil? or href.empty?
59
+
60
+ begin
61
+ full_url = base + href
62
+
63
+ if full_url.host == url.host && full_url.kind_of?(URI::HTTP)
64
+ yield full_url
65
+ end
66
+ rescue ArgumentError, URI::InvalidURIError
67
+ Async.logger.warn(self) {"Could not fetch #{href}, relative to #{base}!"}
68
+ next # Don't accumulate an item into the resulting array.
69
+ end
70
+ end.compact
71
+ end
72
+
73
+ async def fetch(statistics, client, url, depth = @depth, fetched = Set.new, &block)
74
+ return if fetched.include?(url) or depth == 0
75
+
76
+ fetched << url
77
+
78
+ request_uri = url.request_uri
79
+
80
+ response = client.head(request_uri).tap(&:read)
81
+
82
+ yield("HEAD", url, response) if block_given?
83
+
84
+ if response.redirection?
85
+ location = url + response.headers['location']
86
+ if location.host == url.host
87
+ Async.logger.info(self) {"Following redirect to #{location}..."}
88
+ fetch(statistics, client, location, depth-1, fetched, &block).wait
89
+ return
90
+ else
91
+ Async.logger.info(self) {"Ignoring redirect to #{location}."}
92
+ return
93
+ end
94
+ end
95
+
96
+ content_type = response.headers['content-type']
97
+ unless content_type&.start_with? 'text/html'
98
+ # puts "Unsupported content type: #{content_type}"
99
+ return
100
+ end
101
+
102
+ response = statistics.measure do
103
+ client.get(request_uri)
104
+ end
105
+
106
+ yield("GET", url, response) if block_given?
107
+
108
+ extract_links(url, response) do |href|
109
+ fetch(statistics, client, href, depth - 1, fetched, &block)
110
+ end.each(&:wait)
111
+ rescue Async::TimeoutError
112
+ Async.logger.error(self) {"Timeout while fetching #{url}"}
113
+ rescue StandardError
114
+ Async.logger.error(self) {$!}
115
+ end
116
+
117
+ sync def call(urls, &block)
118
+ statistics = Statistics.new
119
+
120
+ urls.each do |url|
121
+ endpoint = Async::HTTP::Endpoint.parse(url, timeout: 10)
122
+
123
+ Async::HTTP::Client.open(endpoint, endpoint.protocol, connection_limit: 4) do |client|
124
+ fetch(statistics, client, endpoint.url, &block).wait
125
+ end
126
+ end
127
+
128
+ return statistics
129
+ end
130
+ end
131
+ end
132
+ end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Benchmark
22
22
  module HTTP
23
- VERSION = "0.9.0"
23
+ VERSION = "0.10.0"
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: benchmark-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-16 00:00:00.000000000 Z
11
+ date: 2020-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-io
@@ -146,6 +146,7 @@ files:
146
146
  - lib/benchmark/http/command/spider.rb
147
147
  - lib/benchmark/http/links_filter.rb
148
148
  - lib/benchmark/http/seconds.rb
149
+ - lib/benchmark/http/spider.rb
149
150
  - lib/benchmark/http/statistics.rb
150
151
  - lib/benchmark/http/version.rb
151
152
  homepage: https://github.com/socketry/benchmark-http
@@ -166,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
167
  - !ruby/object:Gem::Version
167
168
  version: '0'
168
169
  requirements: []
169
- rubygems_version: 3.0.4
170
+ rubygems_version: 3.1.2
170
171
  signing_key:
171
172
  specification_version: 4
172
173
  summary: An asynchronous benchmark toolbox for modern HTTP servers.