yahns Ruby server user/dev discussion
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: yahns-public@yhbt.net
Subject: [PATCH 2/3] extras/proxy_pass: support Unix domain sockets as backends
Date: Sat, 14 Mar 2015 03:17:57 +0000	[thread overview]
Message-ID: <1426303078-4525-3-git-send-email-e@80x24.org> (raw)
In-Reply-To: <1426303078-4525-1-git-send-email-e@80x24.org>

Of course, some users will prefer to bind HTTP application
servers to Unix domain sockets for better isolation and (maybe)
better performance.
---
 extras/proxy_pass.rb           |  7 +++--
 test/test_extras_proxy_pass.rb | 69 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/extras/proxy_pass.rb b/extras/proxy_pass.rb
index d435ebe..00adf18 100644
--- a/extras/proxy_pass.rb
+++ b/extras/proxy_pass.rb
@@ -112,12 +112,15 @@ class ProxyPass # :nodoc:
 
   def initialize(dest, timeout = 5)
     case dest
+    when %r{\Aunix:([^:]+)(?::(/.*))?\z}
+      path = $2
+      @sockaddr = Socket.sockaddr_un($1)
     when %r{\Ahttp://([^/]+)(/.*)?\z}
       path = $2
       host, port = $1.split(':')
       @sockaddr = Socket.sockaddr_in(port || 80, host)
     else
-      raise ArgumentError, "destination must be an HTTP URL"
+      raise ArgumentError, "destination must be an HTTP URL or unix: path"
     end
     init_path_vars(path)
     @pool = ConnPool.new
@@ -125,7 +128,7 @@ class ProxyPass # :nodoc:
   end
 
   def init_path_vars(path)
-    path ||= '$(fullpath)'
+    path ||= '$fullpath'
     # methods from Rack::Request we want:
     allow = %w(fullpath host_with_port host port url path)
     want = path.scan(/\$(\w+)/).flatten! || []
diff --git a/test/test_extras_proxy_pass.rb b/test/test_extras_proxy_pass.rb
index 8842683..5bbce73 100644
--- a/test/test_extras_proxy_pass.rb
+++ b/test/test_extras_proxy_pass.rb
@@ -1,6 +1,7 @@
 # Copyright (C) 2015 all contributors <yahns-public@yhbt.net>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative 'server_helper'
+require 'json'
 
 class TestExtrasProxyPass < Testcase
   ENV["N"].to_i > 1 and parallelize_me!
@@ -34,6 +35,74 @@ class TestExtrasProxyPass < Testcase
     server_helper_teardown
   end
 
+  def test_unix_socket_no_path
+    tmpdir = Dir.mktmpdir
+    unix_path = "#{tmpdir}/proxy_pass.sock"
+    unix_srv = UNIXServer.new(unix_path)
+    err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
+    host2, port2 = @srv2.addr[3], @srv2.addr[1]
+    pid = mkserver(cfg) do
+      @srv.autoclose = @srv2.autoclose = false
+      ENV["YAHNS_FD"] = "#{@srv.fileno},#{@srv2.fileno}"
+      $LOAD_PATH.unshift "#{Dir.pwd}/extras"
+      require 'proxy_pass'
+      cfg.instance_eval do
+        app(:rack, ProxyPass.new("unix:#{unix_path}:/$fullpath")) do
+          listen "#{host}:#{port}"
+        end
+        app(:rack, ProxyPass.new("unix:#{unix_path}:/foo$fullpath")) do
+          listen "#{host2}:#{port2}"
+        end
+        stderr_path err.path
+      end
+    end
+
+    pid2 = mkserver(cfg, unix_srv) do
+      @srv.close
+      @srv2.close
+      cfg.instance_eval do
+        rapp = lambda do |env|
+          body = env.to_json
+          hdr = {
+            'Content-Length' => body.bytesize.to_s,
+            'Content-Type' => 'application/json',
+          }
+          [ 200, hdr, [ body ] ]
+        end
+        app(:rack, rapp) { listen unix_path }
+        stderr_path err.path
+      end
+    end
+    Net::HTTP.start(host, port) do |http|
+      res = http.request(Net::HTTP::Get.new('/f00'))
+      assert_equal 200, res.code.to_i
+      body = JSON.parse(res.body)
+      assert_equal '/f00', body['PATH_INFO']
+
+      res = http.request(Net::HTTP::Get.new('/f00foo'))
+      assert_equal 200, res.code.to_i
+      body = JSON.parse(res.body)
+      assert_equal '/f00foo', body['PATH_INFO']
+    end
+
+    Net::HTTP.start(host2, port2) do |http|
+      res = http.request(Net::HTTP::Get.new('/Foo'))
+      assert_equal 200, res.code.to_i
+      body = JSON.parse(res.body)
+      assert_equal '/foo/Foo', body['PATH_INFO']
+
+      res = http.request(Net::HTTP::Get.new('/Foofoo'))
+      assert_equal 200, res.code.to_i
+      body = JSON.parse(res.body)
+      assert_equal '/foo/Foofoo', body['PATH_INFO']
+    end
+  ensure
+    quit_wait(pid)
+    quit_wait(pid2)
+    unix_srv.close if unix_srv
+    FileUtils.rm_rf(tmpdir) if tmpdir
+  end
+
   def test_proxy_pass
     err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
     host2, port2 = @srv2.addr[3], @srv2.addr[1]
-- 
EW


  parent reply	other threads:[~2015-03-14  3:18 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-14  3:17 [PATCH 0/3] towards becoming a fully-buffering reverse proxy Eric Wong
2015-03-14  3:17 ` [PATCH 1/3] extras/proxy_pass: implicit $fullpath expansion for upstreams Eric Wong
2015-03-14  3:17 ` Eric Wong [this message]
2015-03-14  3:17 ` [PATCH 3/3] proxy_pass: officially become a part of yahns 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/yahns/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1426303078-4525-3-git-send-email-e@80x24.org \
    --to=e@80x24.org \
    --cc=yahns-public@yhbt.net \
    /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/yahns.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).