From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS51815 62.102.148.0/23 X-Spam-Status: No, score=-1.8 required=3.0 tests=BAYES_00,RCVD_IN_MSPIKE_BL, RCVD_IN_MSPIKE_ZBI,RCVD_IN_XBL,RDNS_NONE,SPF_FAIL,SPF_HELO_FAIL, TO_EQ_FM_DOM_SPF_FAIL shortcircuit=no autolearn=no autolearn_force=no version=3.4.0 Received: from 80x24.org (unknown [62.102.148.67]) by dcvr.yhbt.net (Postfix) with ESMTP id 1FB861FCA0 for ; Tue, 28 Mar 2017 01:16:48 +0000 (UTC) From: Eric Wong To: spew@80x24.org Subject: [PATCH] WIP rack_proxy1 Date: Tue, 28 Mar 2017 01:16:46 +0000 Message-Id: <20170328011646.29455-1-e@80x24.org> List-Id: untested! --- lib/yahns/proxy_pass.rb | 3 ++ lib/yahns/rack_proxy1.rb | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 lib/yahns/rack_proxy1.rb diff --git a/lib/yahns/proxy_pass.rb b/lib/yahns/proxy_pass.rb index 0ada4a6..15be710 100644 --- a/lib/yahns/proxy_pass.rb +++ b/lib/yahns/proxy_pass.rb @@ -18,6 +18,9 @@ class Yahns::ProxyPass # :nodoc: attr_reader :proxy_buffering, :response_headers + # only used by yahns/rack_proxy1: + attr_accessor :worker_processes + def initialize(dest, opts = {}) case dest when %r{\Aunix:([^:]+)(?::(/.*))?\z} diff --git a/lib/yahns/rack_proxy1.rb b/lib/yahns/rack_proxy1.rb new file mode 100644 index 0000000..fdd474e --- /dev/null +++ b/lib/yahns/rack_proxy1.rb @@ -0,0 +1,86 @@ +# -*- encoding: binary -*- +# Copyright (C) 2017 all contributors +# License: GPL-3.0+ +# frozen_string_literal: true +require_relative 'rack' # require 'yahns/rack' +require_relative 'proxy_pass' +require 'socket' + +# Basically, a lazy way to setup ProxyPass to hand off some (or all) +# requests to a simple, buggy-code tolerant HTTP server backend. +class Yahns::RackProxy1 < Yahns::Rack # :nodoc: + + # the key is the destination returned by the top-level config.ru + # and the value is a Yahns::ProxyPass Rack app. + # (default: PROXY_ALL). + # { + # :pass => Yahns::ProxyPass, + # :alt => Yahns::ProxyPass, + # ... + # } + attr_reader :proxy_pass_map + + # By default, proxy all requests by using the :pass return value + # Users can selectively process requests for non-buggy code in + # the core yahns processes. + PROXY_ALL = lambda { |env| :pass } # :nodoc: + + def initialize(ru = proxy_all, opts = {}) + # common options to be shared by all ProxyPass instances + gppopts = {} + [ :response_headers, :proxy_buffering ].each { |f| gppopts[f] = opts[f] } + + pass = opts[:pass] + pass = { pass: pass } if String === pass + @proxy_pass_map = pass = pass.dup + + # setup each backend: + pass.each do |key, ppopts| + ppopts = gppopts.merge(ppopts || {}) + host = ppopts.delete(:host) || '127.0.0.1' + + # nope, no UNIXServer support, maybe not worth it do deal + # with FS perms in containers. + srv = TCPServer.new(host, 0) # 0: bind random port + srv.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 1) + srv.setsockopt(:IPPROTO_TCP, :TCP_NODELAY, 1) + + # Deferring accepts slows down core yahns, but it's useful for + # less-sophisticated upstream (backend) servers: + Socket.const_defined?(:TCP_DEFER_ACCEPT) and + srv.setsockopt(:IPPROTO_TCP, :TCP_DEFER_ACCEPT, 1) + + # Should we bother with SO_SNDBUF, SO_RCVBUF? Seems largely + # unused in other servers and unused code is bloat... + + srv.listen(ppopts.delete(:backlog) || 1024) + dest = "http://#{host}:#{srv.addr[1]}/" + ppass = Yahns::ProxyPass.new(dest, ppopts) + ppass.worker_processes = nr + pass[key] = ppass + end + super(ru, opts) # Yahns::Rack#initialize + end + + def build_app! + super # Yahns::Rack#build_app! + proxy_app = @app + + # wrap the (possibly-)user-supplied app + @app = lambda do |env| + res = proxy_app.call(env) + + Array === res and return res # standard Rack response + + proxy_pass = @proxy_pass_map[res] and return proxy_pass.call(env) + + logger = env['rack.logger'] and + logger.error("proxy app returned unhandled response: #{res.inspect}") + + [ 500, [ %w(Content-Type text/plain) ], [] ] + end + end +end + +# register ourselves +Yahns::Config::APP_CLASS[:rack_proxy1] = Yahns::RackProxy1 -- EW