From: Eric Wong <e@80x24.org>
To: http_spew-public@bogomips.org
Subject: [PATCH] remove most uses of kgio
Date: Thu, 9 Mar 2017 20:43:24 +0000 [thread overview]
Message-ID: <20170309204324.1718-1-e@80x24.org> (raw)
And use Ruby 2.3+ *_nonblock(... exception: false) instead.
Since most of kgio-specific features are in newer releases
of Ruby, we can start phasing kgio out to avoid hassling
users with installing more software.
We can still benefit from Kgio.poll over IO.select at
the moment, but we can make it optional in the future.
---
http_spew.gemspec | 2 +-
lib/http_spew.rb | 1 +
lib/http_spew/chunky_pipe.rb | 17 +++++++++---
lib/http_spew/class_methods.rb | 4 +--
lib/http_spew/request.rb | 56 ++++++++++++++++++++++++++--------------
test/test_hit_n_run.rb | 8 +++---
test/test_request.rb | 10 +++----
test/test_unexpected_response.rb | 2 +-
8 files changed, 64 insertions(+), 36 deletions(-)
diff --git a/http_spew.gemspec b/http_spew.gemspec
index 4bede9b..d4d38da 100644
--- a/http_spew.gemspec
+++ b/http_spew.gemspec
@@ -18,6 +18,6 @@ Gem::Specification.new do |s|
s.add_dependency(%q<kcar>, [ "~> 0.3", ">= 0.3.1"])
s.add_dependency(%q<kgio>, "~> 2.6")
s.add_development_dependency(%q<olddoc>, "~> 1.0")
- s.required_ruby_version = '>= 2.1'
+ s.required_ruby_version = '>= 2.3'
s.licenses = %w(GPL-2.0+)
end
diff --git a/lib/http_spew.rb b/lib/http_spew.rb
index e6bde3b..b658627 100644
--- a/lib/http_spew.rb
+++ b/lib/http_spew.rb
@@ -1,4 +1,5 @@
# -*- encoding: binary -*-
+require "io/wait"
require "kgio"
require "kcar"
diff --git a/lib/http_spew/chunky_pipe.rb b/lib/http_spew/chunky_pipe.rb
index 4c51663..590d2f1 100644
--- a/lib/http_spew/chunky_pipe.rb
+++ b/lib/http_spew/chunky_pipe.rb
@@ -3,17 +3,28 @@
# This is a OS-level pipe that overrides IO#read to provide
# IO#readpartial-like semantics while remaining Rack::Lint-compatible
# for EOF, meaning we return nil on EOF instead of raising EOFError.
-class HTTP_Spew::ChunkyPipe < Kgio::Pipe
+class HTTP_Spew::ChunkyPipe < IO
# other threads may force an error to be raised in the +read+
# method
attr_accessor :error
+ class << self
+ alias new pipe
+ end
+
# Override IO#read to behave like IO#readpartial, but still return +nil+
# on EOF instead of raising EOFError.
- def read(*args)
+ def read(len = 16384, buf = '')
check_err!
- kgio_read(*args) || check_err! || close
+ case read_nonblock(len, buf, exception: false)
+ when nil
+ return check_err! || close
+ when :wait_readable
+ wait_readable # retry
+ else
+ return buf
+ end while true
end
def check_err!
diff --git a/lib/http_spew/class_methods.rb b/lib/http_spew/class_methods.rb
index f068f6b..79b3e47 100644
--- a/lib/http_spew/class_methods.rb
+++ b/lib/http_spew/class_methods.rb
@@ -53,7 +53,7 @@ module HTTP_Spew::ClassMethods
# If +need+ is fullfilled, it closes all incomplete requests.
def wait_mt(need, requests, timeout)
ready, failed = [], []
- r, w = Kgio::Pipe.new
+ r, w = IO.pipe
active = []
t = [ timeout ]
requests.each_with_index do |req, i|
@@ -68,7 +68,7 @@ module HTTP_Spew::ClassMethods
end
end
begin
- with_timeout(t) { r.kgio_wait_readable(t[0]) }
+ with_timeout(t) { r.wait_readable(t[0]) }
req_idx = r.read(2).unpack("v".freeze)[0]
thr = active[req_idx]
with_timeout(t) { thr.join(t[0]) }
diff --git a/lib/http_spew/request.rb b/lib/http_spew/request.rb
index 1d02a98..1647d23 100644
--- a/lib/http_spew/request.rb
+++ b/lib/http_spew/request.rb
@@ -1,4 +1,6 @@
# -*- encoding: binary -*-
+require 'socket'
+
# This is the base class actually capable of making a normal HTTP request
class HTTP_Spew::Request
@@ -21,10 +23,9 @@ class HTTP_Spew::Request
#
# +sock+ may be the String representing an address created with
# +Socket.pack_sockaddr_un+ or +Socket.pack_sockaddr_in+, or it
- # may be an actual IO object with Kgio::SocketMethods mixed in
- # (e.g. Kgio::Socket)
+ # may be an actual Socket object
def initialize(env, input, sock, allow = nil)
- @to_io = Kgio::SocketMethods === sock ? sock : Kgio::Socket.start(sock)
+ @to_io = BasicSocket === sock ? sock : start_sock(sock)
if Hash === env
@buf, @input = env_to_headers(env, input)
else
@@ -37,18 +38,21 @@ class HTTP_Spew::Request
# returns :wait_readable or :wait_writable if busy
def resume
if @buf
- case rv = @to_io.kgio_trywrite(@buf)
- when String # unlikely
- @buf = rv # loop retry, socket buffer could've expanded
- when Symbol
- return rv
- else # done writing, read more
- @buf = @input ? @input.read(0x4000, @buf) : nil
+ case w = @to_io.write_nonblock(@buf, exception: false)
+ when :wait_writable, :wait_readable
+ return w
+ else # Integer
+ len = @buf.size
+ if w == len
+ @buf = @input ? @input.read(0x4000, @buf) : nil
+ else
+ tmp = @buf.byteslice(w, len - w)
+ @buf.clear
+ @buf = tmp # loop retry, socket buffer could've expanded
+ end
end while @buf
- read_response
- else
- read_response
end
+ read_response
end
# returns a 3-element Rack response array on successful completion
@@ -64,7 +68,7 @@ class HTTP_Spew::Request
timeout -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0)
while :wait_readable == (rv = read_response) && timeout >= 0.0
t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- @to_io.kgio_wait_readable(timeout) if timeout > 0.0
+ @to_io.wait_readable(timeout) if timeout > 0.0
timeout -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0)
end
rv
@@ -78,7 +82,7 @@ class HTTP_Spew::Request
# Users do not need to call this directly, +resume+ will return the result
# of this.
def read_response
- buf = @to_io.kgio_trypeek(0x4000) or
+ buf = @to_io.recv_nonblock(0x4000, Socket::MSG_PEEK, exception: false) or
raise HttpSpew::EOF, "upstream server closed connection", []
String === buf or return buf
@@ -91,7 +95,7 @@ class HTTP_Spew::Request
end
# discard the header data from the socket buffer
- (hdr_len -= buf.size) > 0 and @to_io.kgio_read(hdr_len, buf)
+ (hdr_len -= buf.size) > 0 and @to_io.read(hdr_len, buf)
@response = r << self
end
@@ -102,10 +106,15 @@ class HTTP_Spew::Request
# Called by Rack servers to write the response to a client
def each
buf = ""
- while @to_io.kgio_read(0x4000, buf)
+ case @to_io.read_nonblock(0x4000, buf, exception: false)
+ when :wait_readable
+ @to_io.wait_readable
+ when nil
+ buf.clear
+ return
+ else
yield buf
- end
- buf.clear
+ end while true
end
# Used internally by various HTTP_Spew elements to report errors
@@ -121,4 +130,13 @@ class HTTP_Spew::Request
@to_io.close
@input = nil
end
+
+ def start_sock(ai)
+ ai = Addrinfo.new(ai) unless Addrinfo === ai
+ sock = Socket.new(ai.afamily, :SOCK_STREAM)
+ case sock.connect_nonblock(ai, exception: false)
+ when 0, :wait_writable
+ end
+ sock
+ end
end
diff --git a/test/test_hit_n_run.rb b/test/test_hit_n_run.rb
index 751a8bf..425f2d5 100644
--- a/test/test_hit_n_run.rb
+++ b/test/test_hit_n_run.rb
@@ -19,7 +19,8 @@ class TestHitNRun < Test::Unit::TestCase
end
def test_request_with_existing_socket
- sock = Kgio::Socket.new(@sockaddr)
+ sock = TCPSocket.new(@addr, @port)
+ assert(BasicSocket === sock)
req = HTTP_Spew::HitNRun.new(@env, nil, sock)
assert_equal sock, req.to_io
assert_nothing_raised { req.close }
@@ -30,8 +31,7 @@ class TestHitNRun < Test::Unit::TestCase
req = HTTP_Spew::HitNRun.new(@env, nil, @sockaddr)
sym = req.resume
if sym == :wait_writable
- set = Kgio.poll({req => sym}, 100)
- assert_equal [ req ], set.keys
+ assert req.to_io.wait_writable(0.1)
sym = req.resume
end
assert_equal HTTP_Spew::HitNRun::RESPONSE.object_id, sym.object_id
@@ -40,7 +40,7 @@ class TestHitNRun < Test::Unit::TestCase
def test_request_loop
req = HTTP_Spew::HitNRun.new(@env, nil, @sockaddr)
until Array === (rv = req.resume)
- Kgio.poll(req => rv)
+ req.__send__(rv)
end
assert_equal HTTP_Spew::HitNRun::RESPONSE.object_id, rv.object_id
end
diff --git a/test/test_request.rb b/test/test_request.rb
index 67ad70c..b8165c4 100644
--- a/test/test_request.rb
+++ b/test/test_request.rb
@@ -19,7 +19,7 @@ class TestRequest < Test::Unit::TestCase
end
def test_request_with_existing_socket
- sock = Kgio::Socket.new(@sockaddr)
+ sock = TCPSocket.new(@addr, @port)
req = HTTP_Spew::Request.new(@env, nil, sock)
assert_equal sock, req.to_io
assert_nothing_raised { req.close }
@@ -31,13 +31,11 @@ class TestRequest < Test::Unit::TestCase
sym = req.resume
assert_kind_of(Symbol, sym)
if sym == :wait_writable
- set = Kgio.poll({req => sym}, 1000)
- assert_equal [ req ], set.keys
+ assert req.to_io.wait_writable(1)
sym = req.resume
end
assert_equal :wait_readable, sym
- set = Kgio.poll({req => sym}, 1000)
- assert_equal [ req ], set.keys
+ assert req.to_io.wait_readable(1)
rv = req.resume
assert_equal req, rv[2]
end
@@ -45,7 +43,7 @@ class TestRequest < Test::Unit::TestCase
def test_request_loop
req = HTTP_Spew::Request.new(@env, nil, @sockaddr)
until Array === (rv = req.resume)
- Kgio.poll(req => rv)
+ req.to_io.__send__(rv) # wait_readable/wait_writable
end
assert_kind_of Array, rv
assert_equal 3, rv.size
diff --git a/test/test_unexpected_response.rb b/test/test_unexpected_response.rb
index bbd63be..2caff05 100644
--- a/test/test_unexpected_response.rb
+++ b/test/test_unexpected_response.rb
@@ -19,7 +19,7 @@ class TestRequest < Test::Unit::TestCase
end
def test_request_with_existing_socket
- sock = Kgio::Socket.new(@sockaddr)
+ sock = TCPSocket.new(@addr, @port)
req = HTTP_Spew::Request.new(@env, nil, sock)
assert_equal sock, req.to_io
assert_nothing_raised { req.close }
--
EW
next reply other threads:[~2017-03-09 20:43 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-09 20:43 Eric Wong [this message]
2017-03-10 0:44 ` [PATCH 2/1] make kgio entirely optional Eric Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://yhbt.net/http_spew/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170309204324.1718-1-e@80x24.org \
--to=e@80x24.org \
--cc=http_spew-public@bogomips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://yhbt.net/http_spew.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox