experella-proxy 0.0.10 → 0.0.11

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.
@@ -1,5 +1,4 @@
1
1
  module ExperellaProxy
2
-
3
2
  # static getter for the connection_manager variable
4
3
  #
5
4
  # @return [ConnectionManager] connection_manager
@@ -9,13 +8,12 @@ module ExperellaProxy
9
8
 
10
9
  # The ConnectionManager is responsible for queueing and matching frontend {Connection} and {BackendServer} objects
11
10
  class ConnectionManager
12
-
13
11
  # The constructor
14
12
  #
15
13
  def initialize
16
- @connection_queue = [] #array queue of client connection objects
17
- @backend_queue = [] #array queue of available backend servers
18
- @backend_list = {} #list of all backend servers
14
+ @connection_queue = [] # array queue of client connection objects
15
+ @backend_queue = [] # array queue of available backend servers
16
+ @backend_list = {} # list of all backend servers
19
17
  end
20
18
 
21
19
  # Matches {Request} to queued {BackendServer}
@@ -34,16 +32,16 @@ module ExperellaProxy
34
32
  def backend_available?(request)
35
33
  @backend_queue.each do |backend|
36
34
  if backend.accept?(request)
37
- #connect backend to requests connection if request matches
35
+ # connect backend to requests connection if request matches
38
36
  backend.workload += 1
39
37
  ret = @backend_queue.delete(backend)
40
- #requeue backend if concurrency isnt maxed
38
+ # requeue backend if concurrency isnt maxed
41
39
  @backend_queue.push(backend) if backend.workload < backend.concurrency
42
40
  return ret
43
41
  end
44
42
  end
45
43
  if match_any_backend?(request)
46
- #push requests connection on queue if no backend was connected
44
+ # push requests connection on queue if no backend was connected
47
45
  @connection_queue.push(request.conn)
48
46
  :queued
49
47
  else
@@ -58,14 +56,14 @@ module ExperellaProxy
58
56
  # @param backend [BackendServer] BackendServer which got free
59
57
  # @return [NilClass]
60
58
  def free_backend(backend)
61
- #check if any queued connections match new available backend
59
+ # check if any queued connections match new available backend
62
60
  conn = match_connections(backend)
63
61
  if conn
64
- #return matching connection
65
- #you should try to connect the new backend to this connection
62
+ # return matching connection
63
+ # you should try to connect the new backend to this connection
66
64
  return conn
67
65
  else
68
- #push free backend on queue if it wasn't used for a queued conn or is already queued (concurrency)
66
+ # push free backend on queue if it wasn't used for a queued conn or is already queued (concurrency)
69
67
  @backend_queue.push(backend) if @backend_list.include?(backend.name) && !@backend_queue.include?(backend)
70
68
  backend.workload -= 1
71
69
  end
@@ -78,17 +76,16 @@ module ExperellaProxy
78
76
  # @return [Connection] a queued connection that would match the BackendServer
79
77
  # @return [Boolean] true if backend was added to list
80
78
  def add_backend(backend)
81
-
82
79
  @backend_list[backend.name] = backend
83
80
 
84
- #check if any queued connections match new available backend
81
+ # check if any queued connections match new available backend
85
82
  conn = match_connections(backend)
86
83
  if conn
87
- #return matching connection
88
- #you should try to connect the new backend to this connection
84
+ # return matching connection
85
+ # you should try to connect the new backend to this connection
89
86
  return conn
90
87
  else
91
- #queue new backend
88
+ # queue new backend
92
89
  @backend_queue.push(backend)
93
90
  end
94
91
  true
@@ -99,7 +96,6 @@ module ExperellaProxy
99
96
  # @param backend [BackendServer] the BackendServer to be removed
100
97
  # @return [Boolean] true if a backend was removed, else returns false
101
98
  def remove_backend(backend)
102
-
103
99
  ret = @backend_list.delete(backend.name)
104
100
  @backend_queue.delete(backend)
105
101
 
@@ -138,7 +134,7 @@ module ExperellaProxy
138
134
  @connection_queue.size
139
135
  end
140
136
 
141
- private
137
+ private
142
138
 
143
139
  # Matches request to all known backends
144
140
  #
@@ -162,6 +158,5 @@ module ExperellaProxy
162
158
  end
163
159
  nil
164
160
  end
165
-
166
161
  end
167
- end
162
+ end
@@ -1,14 +1,12 @@
1
1
  module ExperellaProxy
2
-
3
2
  # defined hop by hop header fields
4
- HOP_HEADERS = ["Connection", "Keep-Alive", "Proxy-Authorization", "TE", "Trailer", "Transfer-Encoding", "Upgrade"]
3
+ HOP_HEADERS = %w(Connection Keep-Alive Proxy-Authorization TE Trailer Transfer-Encoding Upgrade)
5
4
 
6
5
  # Provides getters for global variables
7
6
  #
8
7
  # All methods are private. The module needs to be included in every Class which needs it.
9
8
  module Globals
10
-
11
- private
9
+ private
12
10
 
13
11
  # @!visibility public
14
12
 
@@ -25,8 +23,8 @@ module ExperellaProxy
25
23
  # @param [Hash] details contains details of the event
26
24
  # see ExperellaProxy::Configuration#on_event
27
25
 
28
- def event(name,details={})
29
- config.on_event.call(name,details)
26
+ def event(name, details={})
27
+ config.on_event.call(name, details)
30
28
  end
31
29
 
32
30
  # Get the global connection manager
@@ -40,4 +38,4 @@ module ExperellaProxy
40
38
  config.logger
41
39
  end
42
40
  end
43
- end
41
+ end
@@ -1,45 +1,44 @@
1
1
  module ExperellaProxy
2
-
3
2
  # Every standard HTTP code mapped to the appropriate message.
4
3
  #
5
4
  # @author Mongrel.
6
5
  HTTP_STATUS_CODES = {
7
- 100 => 'Continue',
8
- 101 => 'Switching Protocols',
9
- 200 => 'OK',
10
- 201 => 'Created',
11
- 202 => 'Accepted',
12
- 203 => 'Non-Authoritative Information',
13
- 204 => 'No Content',
14
- 205 => 'Reset Content',
15
- 206 => 'Partial Content',
16
- 300 => 'Multiple Choices',
17
- 301 => 'Moved Permanently',
18
- 302 => 'Moved Temporarily',
19
- 303 => 'See Other',
20
- 304 => 'Not Modified',
21
- 305 => 'Use Proxy',
22
- 400 => 'Bad Request',
23
- 401 => 'Unauthorized',
24
- 402 => 'Payment Required',
25
- 403 => 'Forbidden',
26
- 404 => 'Not Found',
27
- 405 => 'Method Not Allowed',
28
- 406 => 'Not Acceptable',
29
- 407 => 'Proxy Authentication Required',
30
- 408 => 'Request Time-out',
31
- 409 => 'Conflict',
32
- 410 => 'Gone',
33
- 411 => 'Length Required',
34
- 412 => 'Precondition Failed',
35
- 413 => 'Request Entity Too Large',
36
- 414 => 'Request-URI Too Large',
37
- 415 => 'Unsupported Media Type',
38
- 500 => 'Internal Server Error',
39
- 501 => 'Not Implemented',
40
- 502 => 'Bad Gateway',
41
- 503 => 'Service Unavailable',
42
- 504 => 'Gateway Time-out',
43
- 505 => 'HTTP Version not supported'
6
+ 100 => 'Continue',
7
+ 101 => 'Switching Protocols',
8
+ 200 => 'OK',
9
+ 201 => 'Created',
10
+ 202 => 'Accepted',
11
+ 203 => 'Non-Authoritative Information',
12
+ 204 => 'No Content',
13
+ 205 => 'Reset Content',
14
+ 206 => 'Partial Content',
15
+ 300 => 'Multiple Choices',
16
+ 301 => 'Moved Permanently',
17
+ 302 => 'Moved Temporarily',
18
+ 303 => 'See Other',
19
+ 304 => 'Not Modified',
20
+ 305 => 'Use Proxy',
21
+ 400 => 'Bad Request',
22
+ 401 => 'Unauthorized',
23
+ 402 => 'Payment Required',
24
+ 403 => 'Forbidden',
25
+ 404 => 'Not Found',
26
+ 405 => 'Method Not Allowed',
27
+ 406 => 'Not Acceptable',
28
+ 407 => 'Proxy Authentication Required',
29
+ 408 => 'Request Time-out',
30
+ 409 => 'Conflict',
31
+ 410 => 'Gone',
32
+ 411 => 'Length Required',
33
+ 412 => 'Precondition Failed',
34
+ 413 => 'Request Entity Too Large',
35
+ 414 => 'Request-URI Too Large',
36
+ 415 => 'Unsupported Media Type',
37
+ 500 => 'Internal Server Error',
38
+ 501 => 'Not Implemented',
39
+ 502 => 'Bad Gateway',
40
+ 503 => 'Service Unavailable',
41
+ 504 => 'Gateway Time-out',
42
+ 505 => 'HTTP Version not supported'
44
43
  }
45
44
  end
@@ -11,8 +11,7 @@ module ExperellaProxy
11
11
  # @param options [Hash] option Hash passed to the {Connection}
12
12
  # @param blk [Block] Block evaluated in each new {Connection}
13
13
  def self.start(options, &blk)
14
-
15
- #initalize backend servers from config
14
+ # initalize backend servers from config
16
15
  config.backends.each do |backend|
17
16
  connection_manager.add_backend(BackendServer.new(backend[:host], backend[:port], backend))
18
17
  logger.info "Initializing backend #{backend[:name]} at #{backend[:host]}:#{backend[:port]} with concurrency\
@@ -21,11 +20,11 @@ module ExperellaProxy
21
20
  logger.info "Backend mangles: #{backend[:mangle].inspect}"
22
21
  end
23
22
 
24
- #start eventmachine
23
+ # start eventmachine
25
24
  EM.epoll
26
25
  EM.run do
27
- trap("TERM") { stop }
28
- trap("INT") { stop }
26
+ trap("TERM"){ stop }
27
+ trap("INT"){ stop }
29
28
 
30
29
  if config.proxy.empty?
31
30
  logger.fatal "No proxy host:port address configured. Stopping experella-proxy."
@@ -37,10 +36,10 @@ module ExperellaProxy
37
36
  unless proxy[:options].nil?
38
37
  opts = options.merge(proxy[:options])
39
38
  end
40
- logger.info "Launching experella-proxy at #{proxy[:host]}:#{proxy[:port]} with #{config.timeout}s timeout..."
39
+ logger.info "Launching experella-proxy (#{ExperellaProxy::VERSION}) at #{proxy[:host]}:#{proxy[:port]} with #{config.timeout}s timeout..."
41
40
  logger.info "with options: #{opts.inspect}"
42
- EventMachine::start_server(proxy[:host], proxy[:port],
43
- Connection, opts) do |conn|
41
+ EventMachine.start_server(proxy[:host], proxy[:port],
42
+ Connection, opts) do |conn|
44
43
  conn.instance_eval(&blk)
45
44
  end
46
45
  end
@@ -53,7 +52,7 @@ module ExperellaProxy
53
52
  #
54
53
  def self.stop
55
54
  if EM.reactor_running?
56
- EventMachine::stop_event_loop
55
+ EventMachine.stop_event_loop
57
56
  end
58
57
  end
59
58
  end
@@ -5,7 +5,6 @@ module ExperellaProxy
5
5
  # Every Request belongs to a client {Connection}
6
6
  #
7
7
  class Request
8
-
9
8
  include ExperellaProxy::Globals
10
9
 
11
10
  attr_accessor :keep_alive, :chunked
@@ -18,9 +17,9 @@ module ExperellaProxy
18
17
  @conn = conn
19
18
  @header = {}
20
19
  @chunked = false # if true the parsed body will be chunked
21
- @uri = {} #contains port, path and query information for faster backend selection
20
+ @uri = {} # contains port, path and query information for faster backend selection
22
21
  @keep_alive = true
23
- @send_buffer = String.new
22
+ @send_buffer = ''
24
23
  @response = Response.new(self)
25
24
  end
26
25
 
@@ -64,21 +63,21 @@ module ExperellaProxy
64
63
  # First Header after Startline will always be "Host: ", after that order is determined by {#header}.each
65
64
  #
66
65
  def reconstruct_header
67
- #split send_buffer into header and body part
66
+ # split send_buffer into header and body part
68
67
  buf = @send_buffer.split(/\r\n\r\n/, 2) unless flushed?
69
68
  @send_buffer = ""
70
- #start line
69
+ # start line
71
70
  @send_buffer << @header[:http_method] + ' '
72
71
  @send_buffer << @header[:request_url] + ' '
73
72
  @send_buffer << "HTTP/1.1\r\n"
74
- @send_buffer << "Host: " + @header[:Host] + "\r\n" #add Host first for better header readability
75
- #header fields
73
+ @send_buffer << "Host: " + @header[:Host] + "\r\n" # add Host first for better header readability
74
+ # header fields
76
75
  @header.each do |key, value|
77
- unless key == :http_method || key == :request_url || key == :http_version || key == :Host #exclude startline parameters
76
+ unless key == :http_method || key == :request_url || key == :http_version || key == :Host # exclude startline parameters
78
77
  @send_buffer << key.to_s + ": "
79
78
  if value.is_a?(Array)
80
79
  @send_buffer << value.shift
81
- until value.empty? do
80
+ until value.empty?
82
81
  @send_buffer << "," + value.shift
83
82
  end
84
83
  else
@@ -88,8 +87,8 @@ module ExperellaProxy
88
87
  end
89
88
  end
90
89
  @send_buffer << "\r\n"
91
- #reconstruction complete
92
- @send_buffer << buf[1] unless buf.nil? #append buffered body
90
+ # reconstruction complete
91
+ @send_buffer << buf[1] unless buf.nil? # append buffered body
93
92
  event(:request_reconstruct_header, :data => @send_buffer)
94
93
  end
95
94
 
@@ -99,8 +98,8 @@ module ExperellaProxy
99
98
  #
100
99
  # @param hsh [Hash] hash with HTTP header Key:Value pairs
101
100
  def update_header(hsh)
102
- hsh = hsh.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
101
+ hsh = hsh.reduce({}){ |memo, (k, v)| memo[k.to_sym] = v; memo }
103
102
  @header.update(hsh)
104
103
  end
105
104
  end
106
- end
105
+ end
@@ -5,7 +5,6 @@ module ExperellaProxy
5
5
  # Every Response belongs to a request {Request}
6
6
  #
7
7
  class Response
8
-
9
8
  include ExperellaProxy::Globals
10
9
 
11
10
  attr_reader :header
@@ -18,12 +17,12 @@ module ExperellaProxy
18
17
  @conn = request.conn
19
18
  @header = {}
20
19
  @status_code = 500
21
- @no_length = false #set true if no content-length or transfer-encoding given
22
- @keep_parsing = true #used for special no length case
20
+ @no_length = false # set true if no content-length or transfer-encoding given
21
+ @keep_parsing = true # used for special no length case
23
22
  @chunked = false # if true the parsed body will be chunked
24
23
  @buffer = false # default is false, so incoming data will be streamed,
25
24
  # used for http1.0 clients and transfer-encoding chunked backend responses
26
- @send_buffer = String.new
25
+ @send_buffer = ''
27
26
  @response_parser = Http::Parser.new
28
27
  init_http_parser
29
28
  end
@@ -36,33 +35,29 @@ module ExperellaProxy
36
35
  #
37
36
  # @param str [String] data as string
38
37
  def <<(str)
39
- begin
40
- if @keep_parsing
41
- offset = @response_parser << str
42
-
43
- #edge case for message without content-length and transfer encoding
44
- @conn.send_data str[offset..-1] unless @keep_parsing
45
- else
46
- @conn.send_data str
47
- end
48
-
49
- rescue Http::Parser::Error
50
- event(:response_add, :signature => @conn.signature, :error => true,
51
- :description => "parser error caused by invalid response data")
52
- # on error unbind response_parser object, so additional data doesn't get parsed anymore
53
- #
54
- # assigning a string to the parser variable, will cause incoming data to get buffered
55
- # imho this is a better solution than adding a condition for this rare error case
56
- @response_parser = ""
57
- @conn.close
38
+ if @keep_parsing
39
+ offset = (@response_parser << str)
40
+ # edge case for message without content-length and transfer encoding
41
+ @conn.send_data str[offset..-1] unless @keep_parsing
42
+ else
43
+ @conn.send_data str
58
44
  end
45
+ rescue Http::Parser::Error
46
+ event(:response_add, :signature => @conn.signature, :error => true,
47
+ :description => "parser error caused by invalid response data")
48
+ # on error unbind response_parser object, so additional data doesn't get parsed anymore
49
+ #
50
+ # assigning a string to the parser variable, will cause incoming data to get buffered
51
+ # imho this is a better solution than adding a condition for this rare error case
52
+ @response_parser = ""
53
+ @conn.close
59
54
  end
60
55
 
61
56
  # Returns the data in send_buffer and empties the send_buffer
62
57
  #
63
58
  # @return [String] data to send
64
59
  def flush
65
- event(:response_flush,:data => @send_buffer)
60
+ event(:response_flush, :data => @send_buffer)
66
61
  @send_buffer.slice!(0, @send_buffer.length)
67
62
  end
68
63
 
@@ -81,16 +76,16 @@ module ExperellaProxy
81
76
  #
82
77
  def reconstruct_header
83
78
  @send_buffer = ""
84
- #start line
79
+ # start line
85
80
  @send_buffer << "HTTP/1.1 "
86
81
  @send_buffer << @status_code.to_s + ' '
87
82
  @send_buffer << HTTP_STATUS_CODES[@status_code] + "\r\n"
88
- #header fields
83
+ # header fields
89
84
  @header.each do |key, value|
90
85
  @send_buffer << key.to_s + ": "
91
86
  if value.is_a?(Array)
92
87
  @send_buffer << value.shift
93
- until value.empty? do
88
+ until value.empty?
94
89
  @send_buffer << "," + value.shift
95
90
  end
96
91
  else
@@ -99,7 +94,7 @@ module ExperellaProxy
99
94
  @send_buffer << "\r\n"
100
95
  end
101
96
  @send_buffer << "\r\n"
102
- #reconstruction complete
97
+ # reconstruction complete
103
98
  event(:response_reconstruct_header, :data => @send_buffer)
104
99
  end
105
100
 
@@ -109,15 +104,15 @@ module ExperellaProxy
109
104
  #
110
105
  # @param hsh [Hash] hash with HTTP header Key:Value pairs
111
106
  def update_header(hsh)
112
- hsh = hsh.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
107
+ hsh = hsh.reduce({}){ |memo, (k, v)| memo[k.to_sym] = v; memo }
113
108
  @header.update(hsh)
114
109
  end
115
110
 
116
- private
111
+ private
117
112
 
118
113
  # initializes the response http parser
119
114
  def init_http_parser
120
- #called when response headers are completely parsed (first \r\n\r\n triggers this)
115
+ # called when response headers are completely parsed (first \r\n\r\n triggers this)
121
116
  @response_parser.on_headers_complete = proc do |h|
122
117
 
123
118
  @status_code = @response_parser.status_code
@@ -142,7 +137,7 @@ module ExperellaProxy
142
137
  @no_length = true
143
138
  @header[:Connection] = "close"
144
139
  end
145
- #chunked encoded
140
+ # chunked encoded
146
141
  else
147
142
  # buffer response data if client uses http 1.0 until message complete
148
143
  if @request.header[:http_version][0] == 1 && @request.header[:http_version][1] == 0
@@ -168,7 +163,6 @@ module ExperellaProxy
168
163
  h.delete(s)
169
164
  end
170
165
 
171
-
172
166
  via = h.delete("Via")
173
167
  if via.nil?
174
168
  via = "1.1 experella"
@@ -219,4 +213,4 @@ module ExperellaProxy
219
213
  end
220
214
  end
221
215
  end
222
- end
216
+ end
@@ -7,7 +7,7 @@ module ExperellaProxy
7
7
  #
8
8
  # @param options [Hash] options Hash passed to the proxy
9
9
  def initialize(options)
10
- @options=options
10
+ @options = options
11
11
  end
12
12
 
13
13
  attr_reader :options
@@ -25,7 +25,6 @@ module ExperellaProxy
25
25
  # {Connection#unbind} in on_unbind
26
26
  #
27
27
  def run
28
-
29
28
  Proxy.start(options = {}) do |conn|
30
29
  event(:server_new_connection, :msec => msec, :signature => signature)
31
30
 
@@ -58,10 +57,6 @@ module ExperellaProxy
58
57
 
59
58
  end
60
59
  end
61
-
62
60
  end
63
-
64
61
  end
65
-
66
62
  end
67
-
@@ -1,5 +1,9 @@
1
1
  module ExperellaProxy
2
2
  # ExperellaProxy Gemversion
3
+ # 0.0.11
4
+ # * output version on start
5
+ # * rubocup config file
6
+ # * applied rubyocop config file
3
7
  # 0.0.10
4
8
  # * no logging any more just firing events
5
9
  # 0.0.9
@@ -23,5 +27,5 @@ module ExperellaProxy
23
27
  # * added self-signed SSL certificate for TLS/HTTPS
24
28
  # * added config template init functionality
25
29
  #
26
- VERSION = "0.0.10"
30
+ VERSION = "0.0.11"
27
31
  end
@@ -1,6 +1,7 @@
1
1
  require 'optparse'
2
2
  require 'eventmachine'
3
3
  require 'http_parser.rb'
4
+ require 'experella-proxy/version'
4
5
  require 'experella-proxy/globals'
5
6
  require 'experella-proxy/http_status_codes'
6
7
  require 'experella-proxy/configuration'
@@ -35,7 +36,6 @@ require 'experella-proxy/response'
35
36
  # @see file:README.md README
36
37
  # @author Dennis-Florian Herr 2014 @Experteer GmbH
37
38
  module ExperellaProxy
38
-
39
39
  # Initializes ExperellaProxy's {Configuration} and {ConnectionManager}
40
40
  #
41
41
  # @param [Hash] options Hash passed to the configuration
@@ -43,11 +43,11 @@ module ExperellaProxy
43
43
  # @return [Boolean] true if successful false if NoConfigError was raised
44
44
  def self.init(options={})
45
45
  begin
46
- Configuration.new(options)
47
- rescue Configuration::NoConfigError => e
48
- puts e.message
49
- puts e.backtrace.join("\n\t")
50
- return false
46
+ Configuration.new(options)
47
+ rescue Configuration::NoConfigError => e
48
+ puts e.message
49
+ puts e.backtrace.join("\n\t")
50
+ return false
51
51
  end
52
52
  @connection_manager = ConnectionManager.new
53
53
  true
@@ -66,19 +66,18 @@ module ExperellaProxy
66
66
  # Loses all buffered data
67
67
  def self.restart
68
68
  opts = @server.options
69
- self.stop
69
+ stop
70
70
  Server.new(opts).run if ExperellaProxy.init(opts)
71
71
  end
72
72
 
73
73
  # Stops ExperellaProxy
74
74
  #
75
75
  def self.stop
76
- Proxy.stop
76
+ Proxy.stop
77
77
  end
78
-
79
78
  end
80
79
 
81
- #startup
80
+ # startup
82
81
  ARGV << '--help' if ARGV.empty?
83
82
 
84
83
  options = {}
@@ -1,10 +1,9 @@
1
1
  require 'eventmachine'
2
2
  require 'http_parser.rb'
3
3
  module EchoServer
4
-
5
4
  def post_init
6
5
  @parser = Http::Parser.new
7
- @buffer = String.new
6
+ @buffer = ''
8
7
 
9
8
  @parser.on_headers_complete = proc do |h|
10
9
  if @parser.request_path == "/chunked"
@@ -30,15 +29,14 @@ module EchoServer
30
29
  end
31
30
  end
32
31
 
33
- def receive_data data
32
+ def receive_data(data)
34
33
  @buffer << data
35
34
  @parser << data
36
35
  end
37
-
38
36
  end
39
37
 
40
38
  EventMachine.run do
41
- trap("QUIT") { EM.stop }
39
+ trap("QUIT"){ EM.stop }
42
40
 
43
41
  if ARGV.count == 2
44
42
  EventMachine.start_server ARGV.first, ARGV.last.to_i, EchoServer
@@ -46,4 +44,4 @@ EventMachine.run do
46
44
  raise "invalid number of params, expected [server] [port]"
47
45
  end
48
46
 
49
- end
47
+ end