eventmachine-proxy 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d605cb41d1c6ee818040dc71dbb074903085bce6c5785345df7f2cd8163dd7c5
4
+ data.tar.gz: 4089a8b4fd56162c73c6492de7df6012259b7ba820daab52e6e3018d1560fd01
5
+ SHA512:
6
+ metadata.gz: a26b3131f83886f407f637f98e04e7f3cdd73e0107ba571fab704aa933ef5ac781dd9d85e5069fecb1f1710838abd7b340bac132887da38b87c2030556b9173e
7
+ data.tar.gz: d5d58fec5932cb8d43c660d17c0c6fba6cf5ab59097eb1a4dba3e0f4698de0f4bbdc7bd3c92d6303e56601659e5dcbfdcff5958d469019854f9682332007ec2d
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "proxy"
4
+
5
+ module EventMachine::Protocols
6
+ class CONNECT < Proxy
7
+ REQLINE = /\ACONNECT ([^:]+):([1-9][0-9]*) (HTTP\/[0-1]\.\d+).*\r?\n\r?\n/m
8
+ private_constant :REQLINE
9
+
10
+ def receive_message(msg)
11
+ return unless msg.include?("\r\n\r\n") || msg.include?("\n\n")
12
+ match = msg.match(REQLINE) or return failure(:invalid_request)
13
+ host, port, httpv = match.captures
14
+ completion = proxy_to(host, port)
15
+ completion.callback do |server|
16
+ server.send_data(match.post_match)
17
+ send_data("#{httpv} 200 Connection established\r\n\r\n")
18
+ end
19
+ completion.errback { |e| failure(e) }
20
+ true # done
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "eventmachine"
4
+ require "ipaddr"
5
+
6
+ module EventMachine::Protocols
7
+ class Proxy < EventMachine::Connection
8
+ def initialize(opts = {})
9
+ @buf = nil
10
+ @failed = false
11
+ @server = nil
12
+ @connect_timeout = opts.fetch(:connect_timeout, 20.0)
13
+ @connection_buffer_size = opts.fetch(:connection_buffer_size, 2**23)
14
+ @request_buffer_size = opts.fetch(:request_buffer_size, 2**10)
15
+ @connection_inactivity_timeout = opts.fetch(:connection_inactivity_timeout, 0)
16
+ @allow_all = opts.fetch(:allow_all, false)
17
+ end
18
+
19
+ def receive_data(data)
20
+ return if @failed
21
+ @buf ? @buf << data : @buf = data
22
+ if @buf.bytesize >= @request_buffer_size
23
+ failure(:request_too_large)
24
+ else
25
+ done = receive_message(@buf)
26
+ @buf = nil if done || @failed
27
+ end
28
+ end
29
+
30
+ def proxy_target_unbound
31
+ close_connection
32
+ end
33
+
34
+ def unbind
35
+ @server&.close_connection_after_writing
36
+ @server = nil
37
+ end
38
+
39
+ private
40
+
41
+ def proxy_to(host, port)
42
+ completion = EventMachine::Completion.new
43
+ begin
44
+ @server = EventMachine.connect(host, port, Server)
45
+ rescue => e
46
+ completion.fail(e)
47
+ else
48
+ @server.errback { |e| completion.fail(e) }
49
+ @server.callback do
50
+ if @allow_all || !@server.special_purpose?
51
+ completion.succeed(@server)
52
+ else
53
+ completion.fail(:disallowed)
54
+ end
55
+ end
56
+ @server.pending_connect_timeout = @connect_timeout
57
+ @server.comm_inactivity_timeout = @connection_inactivity_timeout
58
+ proxy_incoming_to(@server, @connection_buffer_size)
59
+ @server.proxy_incoming_to(self, @connection_buffer_size)
60
+ end
61
+ completion
62
+ end
63
+
64
+ def failure(comment, data = nil)
65
+ @failed = true
66
+ close_connection_after_writing
67
+ end
68
+
69
+ class Server < EventMachine::Connection
70
+ include EventMachine::Deferrable
71
+
72
+ def post_init
73
+ @connected = false
74
+ end
75
+
76
+ def connection_completed
77
+ @connected = true
78
+ succeed
79
+ end
80
+
81
+ def unbind(errno)
82
+ fail(errno) unless @connected
83
+ end
84
+
85
+ def special_purpose?
86
+ addr = Addrinfo.new(get_peername)
87
+ addr.ipv4_loopback? ||
88
+ addr.ipv4_multicast? ||
89
+ addr.ipv4_private? ||
90
+ addr.ipv6_linklocal? ||
91
+ addr.ipv6_loopback? ||
92
+ addr.ipv6_mc_global? ||
93
+ addr.ipv6_mc_linklocal? ||
94
+ addr.ipv6_mc_nodelocal? ||
95
+ addr.ipv6_mc_orglocal? ||
96
+ addr.ipv6_mc_sitelocal? ||
97
+ addr.ipv6_multicast? ||
98
+ addr.ipv6_sitelocal? ||
99
+ addr.ipv6_unique_local? ||
100
+ addr.ipv6_unspecified? ||
101
+ addr.ipv6_v4mapped?
102
+ end
103
+ end
104
+ private_constant :Server
105
+ end
106
+ private_constant :Proxy
107
+ end
@@ -0,0 +1 @@
1
+ require "eventmachine/protocols/connect"
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eventmachine-proxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - soylent
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-06-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: eventmachine
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ description:
28
+ email:
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/eventmachine-proxy.rb
34
+ - lib/eventmachine/protocols/connect.rb
35
+ - lib/eventmachine/protocols/proxy.rb
36
+ homepage: https://github.com/soylent/eventmachine-proxy
37
+ licenses:
38
+ - MIT
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 2.5.0
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubygems_version: 3.5.3
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: minimal CONNECT proxy
59
+ test_files: []