Last active
August 29, 2015 14:17
-
-
Save mwisnicki/f91f9e50813ee53b3bfa to your computer and use it in GitHub Desktop.
Ruby XML-RPC over Unix Domain Socket (SCGI)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# vim: ai ts=2 | |
require 'xmlrpc/client' | |
module XMLRPC | |
class LocalClient < Client | |
def initialize(path, timeout) | |
super("unix:", path, 0, nil, nil, nil, nil, false, timeout) | |
end | |
private | |
def net_http(host, port, proxy_host, proxy_port) | |
LocalHTTP.new @path, port, proxy_host, proxy_port | |
end | |
class LocalHTTP < Net::HTTP | |
def connect | |
D "opening unix socket #{@address}" | |
s = timeout(@open_timeout) { UNIXSocket.open(@address) } | |
D "opened" | |
@socket = ::Net::BufferedIO.new(s) | |
@socket.read_timeout = @read_timeout | |
@socket.continue_timeout = @continue_timeout | |
@socket.debug_output = @debug_output | |
@socket.instance_variable_set('@scgi_http_hack', true) | |
on_connect | |
end | |
def request_post(path, data, initheader = nil, &block) | |
request SCGIPost.new(path, initheader), data, &block | |
end | |
private | |
module SCGISupport | |
def encode_netstring(s) | |
sprintf('%d:%s', s.length, s) | |
end | |
def make_headers(headers) | |
headers.flatten.join("\0") + "\0" | |
end | |
def scgi_headers(data, headers=[]) | |
headers=make_headers([ | |
['CONTENT_LENGTH', data.length.to_s], | |
['SCGI', '1'] | |
] + headers) | |
encode_netstring(headers) | |
end | |
end | |
class SCGIPost < Net::HTTP::Post | |
private | |
include SCGISupport | |
def write_header(sock, ver, path) | |
end | |
def send_request_with_body(sock, ver, path, body) | |
self.content_length = body.bytesize | |
delete 'Transfer-Encoding' | |
supply_default_content_type | |
write_header sock, ver, path | |
wait_for_continue sock, ver if sock.continue_timeout | |
sock.write scgi_headers(body)+","+body | |
end | |
end | |
end | |
end | |
class ::Net::HTTPResponse | |
class << self | |
alias_method :read_new_noscgi, :read_new | |
def read_new(sock) | |
if is_scgi(sock) then | |
read_new_scgi(sock) | |
else | |
read_new_noscgi(sock) | |
end | |
end | |
private | |
def read_new_scgi(sock) | |
httpv = "1.0" | |
code = nil | |
msg = nil | |
headers = [] | |
each_response_header(sock) do |k,v| | |
if k == 'Status' then | |
code, msg = read_status_header(v) | |
else | |
headers << [k,v] | |
end | |
end | |
res = response_class(code).new(httpv, code, msg) | |
headers.each do |k,v| | |
res.add_field k, v | |
end | |
res | |
end | |
def read_status_header(str) | |
m = /\A(\d\d\d)\s*(.*)\z/in.match(str) or | |
raise Net::HTTPBadResponse, "wrong status header: #{str.dump}" | |
m.captures | |
end | |
def is_scgi(sock) | |
sock.instance_variable_get('@scgi_http_hack') | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment