aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2015-11-08 13:26:52 +0900
committerKazuki Yamaguchi <k@rhe.jp>2015-11-08 13:26:52 +0900
commit4fd79fb69c1f49620d9ec19497fd8a2096fcc44f (patch)
treeda8af6ba3437debef64f67e2e51df14e5179cb5d /lib
parent2535477c65a0093aa14324a5c47d8ea12b6da255 (diff)
downloadplum-4fd79fb69c1f49620d9ec19497fd8a2096fcc44f.tar.gz
client: add HTTP/1.x client
Diffstat (limited to 'lib')
-rw-r--r--lib/plum.rb1
-rw-r--r--lib/plum/client/legacy_client_session.rb88
2 files changed, 89 insertions, 0 deletions
diff --git a/lib/plum.rb b/lib/plum.rb
index 7b8e2ed..5c754ea 100644
--- a/lib/plum.rb
+++ b/lib/plum.rb
@@ -26,3 +26,4 @@ require "plum/client"
require "plum/client/response"
require "plum/client/connection"
require "plum/client/client_session"
+require "plum/client/legacy_client_session"
diff --git a/lib/plum/client/legacy_client_session.rb b/lib/plum/client/legacy_client_session.rb
new file mode 100644
index 0000000..731dfc3
--- /dev/null
+++ b/lib/plum/client/legacy_client_session.rb
@@ -0,0 +1,88 @@
+# -*- frozen-string-literal: true -*-
+module Plum
+ # HTTP/1.x client session.
+ class LegacyClientSession
+ # Creates a new HTTP/1.1 client session
+ def initialize(socket, config)
+ require "http/parser"
+ @socket = socket
+ @config = config
+
+ @parser = setup_parser
+ @requests = []
+ @response = nil
+ @headers_callback = nil
+ end
+
+ def succ
+ @parser << @socket.readpartial(1024)
+ rescue => e # including HTTP::Parser::Error
+ fail(e)
+ end
+
+ def empty?
+ !@response
+ end
+
+ def close
+ @closed = true
+ @response._fail if @response
+ end
+
+ def request(headers, body = nil, &headers_cb)
+ response = Response.new
+ @requests << [response, headers, body, headers_cb]
+ consume_queue
+ response
+ end
+
+ private
+ def fail(exception)
+ close
+ raise exception
+ end
+
+ def consume_queue
+ return if @response
+
+ response, headers, body, cb = @requests.shift
+ headers["host"] = headers[":authority"] || headers["host"] || @config[:hostname]
+ @response = response
+ @headers_callback = cb
+
+ @socket << "%s %s HTTP/1.1\r\n" % [headers[":method"], headers[":path"]]
+ headers.each { |key, value|
+ next if key.start_with?(":") # HTTP/2 psuedo headers
+ @socket << "%s: %s\r\n" % [key, value]
+ }
+ @socket << "\r\n"
+
+ if body
+ @socket << body
+ end
+ end
+
+ def setup_parser
+ parser = HTTP::Parser.new
+ parser.on_headers_complete = proc {
+ resp_headers = parser.headers.map { |key, value| [key.downcase, value] }.to_h
+ @response._headers({ ":status" => parser.status_code }.merge(resp_headers))
+ @headers_callback.call(@response) if @headers_callback
+ }
+
+ parser.on_body = proc { |chunk|
+ @response._chunk(chunk)
+ }
+
+ parser.on_message_complete = proc { |env|
+ @response._finish
+ @response = nil
+ @headers_callback = nil
+ close unless parser.keep_alive?
+ consume_queue
+ }
+
+ parser
+ end
+ end
+end