http_spew 0.4.1 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +0 -1
- data/.gitignore +1 -4
- data/.manifest +3 -3
- data/.olddoc.yml +6 -0
- data/COPYING +288 -623
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +2 -3
- data/LATEST +4 -2
- data/LICENSE +8 -11
- data/NEWS +55 -0
- data/README +5 -6
- data/benchmark/bm_content_md5.rb +52 -0
- data/benchmark/bm_content_md5_input_spray.rb +59 -0
- data/http_spew.gemspec +14 -18
- data/lib/http_spew/chunky_pipe.rb +14 -3
- data/lib/http_spew/class_methods.rb +40 -12
- data/lib/http_spew/content_md5.rb +6 -6
- data/lib/http_spew/headers.rb +8 -17
- data/lib/http_spew/input_spray.rb +1 -0
- data/lib/http_spew/request.rb +46 -33
- data/lib/http_spew/version.rb +1 -1
- data/lib/http_spew.rb +14 -14
- data/pkg.mk +27 -52
- data/test/helper.rb +3 -1
- data/test/test_content_md5.rb +1 -1
- data/test/test_hit_n_run.rb +5 -5
- data/test/test_input_spray_with_md5.rb +3 -3
- data/test/test_mirror.rb +1 -1
- data/test/test_request.rb +5 -7
- data/test/test_unexpected_response.rb +2 -2
- data/test/test_upload.rb +6 -3
- metadata +31 -76
- data/.wrongdoc.yml +0 -4
- data/ChangeLog +0 -546
- data/Gemfile +0 -5
data/GIT-VERSION-FILE
CHANGED
@@ -1 +1 @@
|
|
1
|
-
GIT_VERSION = 0.
|
1
|
+
GIT_VERSION = 0.7.1
|
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
all::
|
2
|
-
RSYNC_DEST :=
|
3
|
-
rfproject := rainbows
|
2
|
+
RSYNC_DEST := yhbt.net:/srv/yhbt/http_spew
|
4
3
|
rfpackage := http_spew
|
5
4
|
|
6
5
|
RUBY_VERSION_FILE = lib/http_spew/version.rb
|
@@ -10,7 +9,7 @@ include pkg.mk
|
|
10
9
|
$(RUBY_VERSION_FILE): GIT-VERSION-FILE
|
11
10
|
@$(RM) -f $@+
|
12
11
|
@echo >> $@+ '# -*- encoding: binary -*-'
|
13
|
-
@echo >> $@+ 'HTTP_Spew.const_set :VERSION, "$(GIT_VERSION)"'
|
12
|
+
@echo >> $@+ 'HTTP_Spew.const_set :VERSION, "$(GIT_VERSION)".freeze'
|
14
13
|
@mv $@+ $@
|
15
14
|
|
16
15
|
build: $(RUBY_VERSION_FILE)
|
data/LATEST
CHANGED
data/LICENSE
CHANGED
@@ -1,17 +1,14 @@
|
|
1
|
-
|
1
|
+
http_spew is copyrighted Free Software by all contributors, see logs in
|
2
2
|
revision control for names and email addresses of all of them.
|
3
3
|
|
4
4
|
You can redistribute it and/or modify it under the terms of the GNU
|
5
|
-
General Public License
|
6
|
-
|
7
|
-
(Eric Wong) reserves the right to relicense HTTP Spew under future versions
|
8
|
-
of the GPL.
|
5
|
+
General Public License as published by the Free Software Foundation;
|
6
|
+
either version 2 of the License, or (at your option) any later version.
|
9
7
|
|
10
|
-
|
8
|
+
http_spew is distributed in the hope that it will be useful, but WITHOUT
|
11
9
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
12
|
-
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
13
|
-
|
10
|
+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
11
|
+
for more details.
|
14
12
|
|
15
|
-
You should have received a copy of the GNU General Public License
|
16
|
-
|
17
|
-
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
13
|
+
You should have received a copy of the GNU General Public License along
|
14
|
+
with this program; if not, see https://www.gnu.org/licenses/gpl-2.0.txt
|
data/NEWS
CHANGED
@@ -1,3 +1,58 @@
|
|
1
|
+
=== http_spew 0.7.1 / 2022-01-16 08:45 UTC
|
2
|
+
|
3
|
+
2 changes since v0.7.0:
|
4
|
+
doc: s/bogomips.org/yhbt.net/
|
5
|
+
fix mismatched indentation warnings
|
6
|
+
|
7
|
+
=== http_spew 0.7.0 - modernizing for newer Rubies / 2017-06-12 22:00 UTC
|
8
|
+
|
9
|
+
Ruby 2.3+ is now required as kgio dependencies are gone.
|
10
|
+
This is unlikely to be a problem in practice, as hardly
|
11
|
+
anybody uses this at the moment.
|
12
|
+
|
13
|
+
5 changes since 0.6.0:
|
14
|
+
|
15
|
+
remove most uses of kgio
|
16
|
+
make kgio entirely optional
|
17
|
+
update to only use public email address
|
18
|
+
http_spew: remove kgio require at top level
|
19
|
+
gemspec: remove olddoc as a build dependency
|
20
|
+
|
21
|
+
=== http_spew 0.6.0 - even less / 2016-11-05 02:15 UTC
|
22
|
+
|
23
|
+
Rack "to_path" support is dropped since few servers can
|
24
|
+
take advantage of this in a non-buggy way.
|
25
|
+
|
26
|
+
As a consolation, #each should be less GC-intensive by
|
27
|
+
with explicit calls to String#clear to reduce memory
|
28
|
+
pressure.
|
29
|
+
|
30
|
+
3 changes since 0.5.0
|
31
|
+
|
32
|
+
pkg.mk: avoid network for "gem install"
|
33
|
+
request: drop to_path support
|
34
|
+
explicitly clear large buf when it is obviously safe
|
35
|
+
|
36
|
+
=== http_spew 0.5.0 / 2016-10-31 20:43 UTC
|
37
|
+
|
38
|
+
This release requires Ruby 2.1 or later.
|
39
|
+
|
40
|
+
13 changes since 0.4.1:
|
41
|
+
|
42
|
+
gemspec: require kcar >= 0.3.1
|
43
|
+
test/helper: explicit redirect for Ruby 2.0.0
|
44
|
+
update packaging + docs (website)
|
45
|
+
allow all future GPL versions
|
46
|
+
add benchmark scripts
|
47
|
+
relax dependency on unicorn
|
48
|
+
declare empty classes with constant assignment
|
49
|
+
test_upload: use object_id to check matches
|
50
|
+
use frozen string literals for Ruby 2.1+
|
51
|
+
merge into kcar project and mailing list
|
52
|
+
dedicated mailing list
|
53
|
+
rely on opt_str_freeze in more places
|
54
|
+
use monotonic clock for timing
|
55
|
+
|
1
56
|
=== http_spew 0.4.1 / 2012-09-23 00:01 UTC
|
2
57
|
|
3
58
|
Fix formatting of user-supplied headers.
|
data/README
CHANGED
@@ -11,7 +11,6 @@ Use HTTP Spew if you wish you could kinda multicast with HTTP...
|
|
11
11
|
* No support for DNS resolution (WONTFIX, ever)
|
12
12
|
* No support for HTTPS
|
13
13
|
* No support for keepalive (yet?)
|
14
|
-
* No support for Ruby 1.8, this is Ruby 1.9-only
|
15
14
|
* Not remotely RFC-compliant
|
16
15
|
* Messes up analytics/reporting on servers
|
17
16
|
* Resets server connections
|
@@ -33,13 +32,13 @@ It's also completely untested and unused anywhere!
|
|
33
32
|
|
34
33
|
You can get the latest source via git from the following locations:
|
35
34
|
|
36
|
-
git://
|
35
|
+
git://yhbt.net/http_spew.git
|
37
36
|
git://repo.or.cz/http_spew.git (mirror)
|
38
37
|
|
39
38
|
You may browse the code from the web and download the latest snapshot
|
40
39
|
tarballs here:
|
41
40
|
|
42
|
-
*
|
41
|
+
* https://yhbt.net/http_spew.git
|
43
42
|
* http://repo.or.cz/w/http_spew.git (gitweb)
|
44
43
|
|
45
44
|
Inline patches (from "git format-patch") to the mailing list are
|
@@ -54,8 +53,8 @@ don't email the git mailing list or maintainer with http_spew patches.
|
|
54
53
|
== Contact
|
55
54
|
|
56
55
|
All feedback (bug reports, user/development discussion, patches, pull
|
57
|
-
requests) go to the mailing list: mailto:
|
56
|
+
requests) go to the mailing list: mailto:http_spew-public@yhbt.net
|
58
57
|
|
59
|
-
Mailing list archives
|
58
|
+
Mailing list archives may be viewed and downloaded here:
|
60
59
|
|
61
|
-
|
60
|
+
https://yhbt.net/http_spew-public/
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require "./test/helper"
|
3
|
+
require "benchmark"
|
4
|
+
|
5
|
+
class TestBMContentMD5 < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@addr, @port, @srv = start_server("./test/content-md5.ru", 1)
|
8
|
+
@sockaddr = Socket.pack_sockaddr_in(@port, @addr)
|
9
|
+
@env = {
|
10
|
+
"REQUEST_METHOD" => "PUT",
|
11
|
+
"REQUEST_URI" => "/",
|
12
|
+
"HTTP_HOST" => "example.com",
|
13
|
+
}
|
14
|
+
@tmpfiles = []
|
15
|
+
@bs = ENV['bs'] ? ENV['bs'].to_i : 1024 * 1024
|
16
|
+
@count = ENV['count'] ? ENV['count'].to_i : 1000
|
17
|
+
@cmd = %w(dd if=/dev/zero)
|
18
|
+
@cmd << "bs=#@bs"
|
19
|
+
@cmd << "count=#@count"
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
Process.kill(:QUIT, @srv)
|
24
|
+
Process.waitpid2(@srv)
|
25
|
+
@tmpfiles.each { |tmp| tmp.closed? or tmp.close! }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_upload_with_md5
|
29
|
+
rd, wr = IO.pipe
|
30
|
+
pid = fork do
|
31
|
+
$stdout.reopen(wr)
|
32
|
+
rd.close
|
33
|
+
wr.close
|
34
|
+
exec(*@cmd)
|
35
|
+
end
|
36
|
+
wr.close
|
37
|
+
@env["CONTENT_LENGTH"] = (@bs * @count).to_s
|
38
|
+
@env["rack.input"] = rd
|
39
|
+
input = HTTP_Spew::ContentMD5.new(@env)
|
40
|
+
assert_nil @env["CONTENT_LENGTH"]
|
41
|
+
assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"]
|
42
|
+
req = HTTP_Spew::Request.new(@env, input, @sockaddr)
|
43
|
+
rv = nil
|
44
|
+
res = Benchmark.measure do
|
45
|
+
rv = req.run(100000)
|
46
|
+
end
|
47
|
+
assert_equal 200, rv[0].to_i
|
48
|
+
pid, status = Process.waitpid2(pid)
|
49
|
+
assert status.success?
|
50
|
+
p res
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "./test/helper"
|
2
|
+
require "benchmark"
|
3
|
+
|
4
|
+
class TestBMContentMD5InputSpray < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@nr = 4
|
7
|
+
@addr, @port, @srv = start_server("./test/content-md5.ru", @nr)
|
8
|
+
@sockaddr = Socket.pack_sockaddr_in(@port, @addr)
|
9
|
+
@env = {
|
10
|
+
"REQUEST_METHOD" => "PUT",
|
11
|
+
"REQUEST_URI" => "/",
|
12
|
+
"HTTP_HOST" => "example.com",
|
13
|
+
}
|
14
|
+
@tmpfiles = []
|
15
|
+
@bs = ENV['bs'] ? ENV['bs'].to_i : 1024 * 1024
|
16
|
+
@count = ENV['count'] ? ENV['count'].to_i : 1000
|
17
|
+
@cmd = %w(dd if=/dev/zero)
|
18
|
+
@cmd << "bs=#@bs"
|
19
|
+
@cmd << "count=#@count"
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
Process.kill(:QUIT, @srv)
|
24
|
+
Process.waitpid2(@srv)
|
25
|
+
@tmpfiles.each { |tmp| tmp.closed? or tmp.close! }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_spray_with_md5
|
29
|
+
rd, wr = IO.pipe
|
30
|
+
pid = fork do
|
31
|
+
$stdout.reopen(wr)
|
32
|
+
rd.close
|
33
|
+
wr.close
|
34
|
+
exec(*@cmd)
|
35
|
+
end
|
36
|
+
wr.close
|
37
|
+
@env["CONTENT_LENGTH"] = (@bs * @count).to_s
|
38
|
+
@env["rack.input"] = rd
|
39
|
+
input = HTTP_Spew::ContentMD5.new(@env)
|
40
|
+
sprayer = HTTP_Spew::InputSpray.new(@env, @nr, input)
|
41
|
+
assert_nil @env["CONTENT_LENGTH"]
|
42
|
+
assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"]
|
43
|
+
reqs = sprayer.readers.map do |md5_input|
|
44
|
+
HTTP_Spew::Request.new(@env, md5_input, @sockaddr)
|
45
|
+
end
|
46
|
+
assert_equal @nr, reqs.size
|
47
|
+
rv = nil
|
48
|
+
res = Benchmark.measure do
|
49
|
+
rv = HTTP_Spew.wait_mt reqs.size, reqs, 3600
|
50
|
+
end
|
51
|
+
assert_equal @nr, rv.size
|
52
|
+
rv.each do |resp|
|
53
|
+
assert_equal 200, resp.response[0].to_i
|
54
|
+
end
|
55
|
+
pid, status = Process.waitpid2(pid)
|
56
|
+
assert status.success?
|
57
|
+
p res
|
58
|
+
end
|
59
|
+
end
|
data/http_spew.gemspec
CHANGED
@@ -1,24 +1,20 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'wrongdoc'
|
4
|
-
extend Wrongdoc::Gemspec
|
5
|
-
name, summary, title = readme_metadata
|
1
|
+
manifest = File.exist?('.manifest') ?
|
2
|
+
IO.readlines('.manifest').map!(&:chomp!) : `git ls-files`.split("\n")
|
6
3
|
|
7
4
|
Gem::Specification.new do |s|
|
8
5
|
s.name = %q{http_spew}
|
9
|
-
s.version = ENV[
|
10
|
-
s.authors = ["
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.
|
14
|
-
|
6
|
+
s.version = (ENV['VERSION'] || '0.7.1').dup
|
7
|
+
s.authors = ["http_spew hackers"]
|
8
|
+
s.description = File.read('README').split("\n\n")[1]
|
9
|
+
s.email = %q{http_spew-public@yhbt.net}
|
10
|
+
s.extra_rdoc_files = IO.readlines('.document').map!(&:chomp!).keep_if do |f|
|
11
|
+
File.exist?(f)
|
12
|
+
end
|
15
13
|
s.files = manifest
|
16
|
-
s.homepage =
|
17
|
-
s.summary =
|
18
|
-
s.rdoc_options = rdoc_options
|
19
|
-
s.rubyforge_project = %q{rainbows}
|
14
|
+
s.homepage = 'https://yhbt.net/http_spew/'
|
15
|
+
s.summary = 'HTTP Spew - LAN-only HTTP spam^H^H^H^Hclient for Ruby'
|
20
16
|
s.test_files = Dir["test/test_*.rb"]
|
21
|
-
s.add_dependency(%q<kcar>, "~> 0.3")
|
22
|
-
s.
|
23
|
-
s.
|
17
|
+
s.add_dependency(%q<kcar>, [ "~> 0.3", ">= 0.3.1"])
|
18
|
+
s.required_ruby_version = '>= 2.3'
|
19
|
+
s.licenses = %w(GPL-2.0+)
|
24
20
|
end
|
@@ -3,17 +3,28 @@
|
|
3
3
|
# This is a OS-level pipe that overrides IO#read to provide
|
4
4
|
# IO#readpartial-like semantics while remaining Rack::Lint-compatible
|
5
5
|
# for EOF, meaning we return nil on EOF instead of raising EOFError.
|
6
|
-
class HTTP_Spew::ChunkyPipe <
|
6
|
+
class HTTP_Spew::ChunkyPipe < IO
|
7
7
|
|
8
8
|
# other threads may force an error to be raised in the +read+
|
9
9
|
# method
|
10
10
|
attr_accessor :error
|
11
11
|
|
12
|
+
class << self
|
13
|
+
alias new pipe
|
14
|
+
end
|
15
|
+
|
12
16
|
# Override IO#read to behave like IO#readpartial, but still return +nil+
|
13
17
|
# on EOF instead of raising EOFError.
|
14
|
-
def read(
|
18
|
+
def read(len = 16384, buf = '')
|
15
19
|
check_err!
|
16
|
-
|
20
|
+
case read_nonblock(len, buf, exception: false)
|
21
|
+
when nil
|
22
|
+
return check_err! || close
|
23
|
+
when :wait_readable
|
24
|
+
wait_readable # retry
|
25
|
+
else
|
26
|
+
return buf
|
27
|
+
end while true
|
17
28
|
end
|
18
29
|
|
19
30
|
def check_err!
|
@@ -41,11 +41,11 @@ module HTTP_Spew::ClassMethods
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def with_timeout(t)
|
44
|
-
t0 =
|
44
|
+
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
45
45
|
yield
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
ensure
|
47
|
+
t[0] -= Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
|
48
|
+
t[0] = 0.0 if t[0] < 0
|
49
49
|
end
|
50
50
|
|
51
51
|
# Returns an array of requests that are complete, including those
|
@@ -53,14 +53,14 @@ module HTTP_Spew::ClassMethods
|
|
53
53
|
# If +need+ is fullfilled, it closes all incomplete requests.
|
54
54
|
def wait_mt(need, requests, timeout)
|
55
55
|
ready, failed = [], []
|
56
|
-
r, w =
|
56
|
+
r, w = IO.pipe
|
57
57
|
active = []
|
58
58
|
t = [ timeout ]
|
59
59
|
requests.each_with_index do |req, i|
|
60
60
|
active << Thread.new do
|
61
61
|
begin
|
62
62
|
rv = req.run(timeout)
|
63
|
-
w.write([ i ].pack("v"))
|
63
|
+
w.write([ i ].pack("v".freeze))
|
64
64
|
rv
|
65
65
|
rescue => err
|
66
66
|
err
|
@@ -68,8 +68,8 @@ module HTTP_Spew::ClassMethods
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
begin
|
71
|
-
with_timeout(t) { r.
|
72
|
-
req_idx = r.read(2).unpack("v")[0]
|
71
|
+
with_timeout(t) { r.wait_readable(t[0]) }
|
72
|
+
req_idx = r.read(2).unpack("v".freeze)[0]
|
73
73
|
thr = active[req_idx]
|
74
74
|
with_timeout(t) { thr.join(t[0]) }
|
75
75
|
rv = thr.value
|
@@ -81,9 +81,9 @@ module HTTP_Spew::ClassMethods
|
|
81
81
|
pending = requests - ready
|
82
82
|
error = HTTP_Spew::TimeoutError.new("request timed out")
|
83
83
|
ready.concat(error_all(pending, error))
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
ensure
|
85
|
+
w.close
|
86
|
+
r.close
|
87
87
|
end
|
88
88
|
|
89
89
|
def wait(need, requests, timeout)
|
@@ -110,7 +110,7 @@ module HTTP_Spew::ClassMethods
|
|
110
110
|
break if pollset.empty?
|
111
111
|
|
112
112
|
busy = pollset.keys
|
113
|
-
rv = with_timeout(t) {
|
113
|
+
rv = with_timeout(t) { do_poll(pollset, t[0]) } or break
|
114
114
|
end while t[0] > 0.0 && requests = rv.keys.concat(busy).uniq!
|
115
115
|
|
116
116
|
ready.concat(failed)
|
@@ -121,4 +121,32 @@ module HTTP_Spew::ClassMethods
|
|
121
121
|
end
|
122
122
|
ready
|
123
123
|
end
|
124
|
+
|
125
|
+
begin
|
126
|
+
require 'kgio'
|
127
|
+
def do_poll(pollset, sec) # :nodoc:
|
128
|
+
Kgio.poll(pollset, (sec * 1000).to_i)
|
129
|
+
end
|
130
|
+
rescue LoadError
|
131
|
+
# emulate Kgio.poll with IO.select
|
132
|
+
def do_poll(pollset, sec) # :nodoc:
|
133
|
+
rd = []
|
134
|
+
wr = []
|
135
|
+
pollset.each do |io, events|
|
136
|
+
case events
|
137
|
+
when :wait_readable
|
138
|
+
rd << io
|
139
|
+
when :wait_writable
|
140
|
+
wr << io
|
141
|
+
else
|
142
|
+
raise "BUG: unsupported event #{event.inspect} for #{io.inspect}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
ready = IO.select(rd, wr, nil, sec) or return
|
146
|
+
pollset.clear
|
147
|
+
ready[0].each { |io| pollset[io] = 1 } # POLLIN
|
148
|
+
ready[1].each { |io| pollset[io] = 4 } # POLLOUT
|
149
|
+
pollset
|
150
|
+
end
|
151
|
+
end
|
124
152
|
end
|
@@ -7,17 +7,16 @@ class HTTP_Spew::ContentMD5
|
|
7
7
|
attr_reader :content_md5
|
8
8
|
attr_reader :bytes_digested
|
9
9
|
|
10
|
-
CRLF = "\r\n" # :nodoc:
|
11
|
-
|
12
10
|
def initialize(env, input = env["rack.input"])
|
13
11
|
if trailer = env["HTTP_TRAILER"]
|
14
12
|
unless trailer.split(/\s*,\s*/).grep(/\AContent-MD5\z/i)[0]
|
15
|
-
trailer << (trailer.empty? ? "Content-MD5"
|
13
|
+
trailer << (trailer.empty? ? "Content-MD5".freeze
|
14
|
+
: ",Content-MD5".freeze)
|
16
15
|
end
|
17
16
|
else
|
18
|
-
env["HTTP_TRAILER"] = "Content-MD5"
|
17
|
+
env["HTTP_TRAILER"] = "Content-MD5".freeze
|
19
18
|
end
|
20
|
-
env["HTTP_TRANSFER_ENCODING"] = "chunked"
|
19
|
+
env["HTTP_TRANSFER_ENCODING"] = "chunked".freeze
|
21
20
|
@to_io, wr = HTTP_Spew::ChunkyPipe.new
|
22
21
|
expect_md5 = env.delete("HTTP_CONTENT_MD5")
|
23
22
|
expect_len = env.delete("CONTENT_LENGTH")
|
@@ -41,8 +40,9 @@ class HTTP_Spew::ContentMD5
|
|
41
40
|
@bytes_digested += n
|
42
41
|
wr.write("#{n.to_s(16)}\r\n")
|
43
42
|
digest.update(buf)
|
44
|
-
wr.write(buf <<
|
43
|
+
wr.write(buf << "\r\n".freeze)
|
45
44
|
end while input.read(0x4000, buf)
|
45
|
+
buf.clear
|
46
46
|
end
|
47
47
|
if expect_len && expect_len.to_i != @bytes_digested
|
48
48
|
raise HTTP_Spew::LengthError,
|
data/lib/http_spew/headers.rb
CHANGED
@@ -1,18 +1,10 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
module HTTP_Spew::Headers
|
3
|
-
# :stopdoc:
|
4
|
-
REQUEST_METHOD = "REQUEST_METHOD"
|
5
|
-
REQUEST_URI = "REQUEST_URI"
|
6
|
-
CRLF = "\r\n"
|
7
|
-
QUERY_STRING = "QUERY_STRING"
|
8
|
-
PATH_INFO = "PATH_INFO"
|
9
|
-
CONTENT_TYPE = "CONTENT_TYPE" # specified by Rack to be !/^HTTP_/
|
10
|
-
# :startdoc:
|
11
3
|
|
12
4
|
# regenerates the request_uri from a Rack +env+
|
13
5
|
def request_uri(env)
|
14
|
-
qs = env[QUERY_STRING]
|
15
|
-
qs.size == 0 ? env[PATH_INFO] : "#{env[PATH_INFO]}?#{qs}"
|
6
|
+
qs = env['QUERY_STRING']
|
7
|
+
qs.size == 0 ? env['PATH_INFO'] : "#{env['PATH_INFO']}?#{qs}"
|
16
8
|
end
|
17
9
|
module_function :request_uri
|
18
10
|
|
@@ -27,26 +19,25 @@ module HTTP_Spew::Headers
|
|
27
19
|
#
|
28
20
|
# buf, input = env_to_headers(env, input)
|
29
21
|
def env_to_headers(env, input)
|
30
|
-
req = "#{env[REQUEST_METHOD]} " \
|
31
|
-
"#{env[REQUEST_URI] || request_uri(env)} HTTP/1.1\r\n" \
|
22
|
+
req = "#{env['REQUEST_METHOD']} " \
|
23
|
+
"#{env['REQUEST_URI'] || request_uri(env)} HTTP/1.1\r\n" \
|
32
24
|
"Connection: close\r\n"
|
33
|
-
uscore, dash = "_", "-"
|
34
25
|
env.each do |key,value|
|
35
26
|
%r{\AHTTP_(\w+)\z} =~ key or next
|
36
27
|
key = $1
|
37
28
|
%r{\A(?:VERSION|EXPECT|TRANSFER_ENCODING|CONNECTION|KEEP_ALIVE)\z}x =~
|
38
29
|
key and next
|
39
30
|
|
40
|
-
key.tr!(
|
31
|
+
key.tr!('_'.freeze, '-'.freeze)
|
41
32
|
req << "#{key}: #{value}\r\n"
|
42
33
|
end
|
43
34
|
if input
|
44
35
|
req << (input.respond_to?(:size) ?
|
45
36
|
"Content-Length: #{input.size}\r\n" :
|
46
|
-
"Transfer-Encoding: chunked\r\n")
|
47
|
-
ct = env[CONTENT_TYPE] and req << "Content-Type: #{ct}\r\n"
|
37
|
+
"Transfer-Encoding: chunked\r\n".freeze)
|
38
|
+
ct = env['CONTENT_TYPE'] and req << "Content-Type: #{ct}\r\n"
|
48
39
|
end
|
49
|
-
req <<
|
40
|
+
req << "\r\n".freeze
|
50
41
|
String === input ? (req << input) : [ req, input ]
|
51
42
|
end
|
52
43
|
module_function :env_to_headers
|