sitehub 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +17 -0
  3. data/Gemfile +0 -2
  4. data/Gemfile.lock +15 -1
  5. data/README.md +23 -0
  6. data/Rakefile +3 -9
  7. data/circle.yml +6 -0
  8. data/lib/sitehub/builder.rb +19 -19
  9. data/lib/sitehub/collection/route_collection.rb +7 -9
  10. data/lib/sitehub/collection/split_route_collection/split.rb +7 -5
  11. data/lib/sitehub/collection/split_route_collection.rb +13 -10
  12. data/lib/sitehub/collection.rb +26 -21
  13. data/lib/sitehub/constants/http_header_keys.rb +2 -6
  14. data/lib/sitehub/constants/rack_http_header_keys.rb +2 -2
  15. data/lib/sitehub/constants.rb +3 -3
  16. data/lib/sitehub/cookie/attribute.rb +4 -4
  17. data/lib/sitehub/cookie/flag.rb +4 -5
  18. data/lib/sitehub/cookie.rb +10 -14
  19. data/lib/sitehub/cookie_rewriting.rb +11 -13
  20. data/lib/sitehub/forward_proxies.rb +12 -13
  21. data/lib/sitehub/forward_proxy.rb +38 -24
  22. data/lib/sitehub/forward_proxy_builder.rb +38 -21
  23. data/lib/sitehub/http_headers.rb +39 -26
  24. data/lib/sitehub/logging/access_logger.rb +39 -35
  25. data/lib/sitehub/logging/error_logger.rb +7 -7
  26. data/lib/sitehub/logging/log_entry.rb +6 -5
  27. data/lib/sitehub/logging/log_stash.rb +2 -2
  28. data/lib/sitehub/logging/log_wrapper.rb +5 -5
  29. data/lib/sitehub/logging.rb +1 -1
  30. data/lib/sitehub/middleware.rb +2 -2
  31. data/lib/sitehub/path_directive.rb +10 -10
  32. data/lib/sitehub/path_directives.rb +5 -4
  33. data/lib/sitehub/request_mapping.rb +13 -11
  34. data/lib/sitehub/resolver.rb +5 -6
  35. data/lib/sitehub/reverse_proxy.rb +16 -12
  36. data/lib/sitehub/rules.rb +2 -2
  37. data/lib/sitehub/string_sanitiser.rb +1 -1
  38. data/lib/sitehub/transaction_id.rb +3 -3
  39. data/lib/sitehub/version.rb +1 -1
  40. data/lib/sitehub.rb +1 -1
  41. data/sitehub.gemspec +27 -29
  42. data/spec/sitehub/builder_spec.rb +18 -20
  43. data/spec/sitehub/collection/route_collection_spec.rb +16 -14
  44. data/spec/sitehub/collection/split_route_collection_spec.rb +8 -10
  45. data/spec/sitehub/collection_spec.rb +7 -7
  46. data/spec/sitehub/cookie/attribute_spec.rb +3 -3
  47. data/spec/sitehub/cookie/flag_spec.rb +2 -2
  48. data/spec/sitehub/cookie_rewriting_spec.rb +15 -12
  49. data/spec/sitehub/cookie_spec.rb +7 -18
  50. data/spec/sitehub/error_handling_spec.rb +2 -3
  51. data/spec/sitehub/forward_proxies_spec.rb +16 -12
  52. data/spec/sitehub/forward_proxy_builder_spec.rb +53 -30
  53. data/spec/sitehub/forward_proxy_spec.rb +26 -22
  54. data/spec/sitehub/http_headers_spec.rb +17 -18
  55. data/spec/sitehub/integration_spec.rb +4 -5
  56. data/spec/sitehub/logging/access_logger_spec.rb +25 -24
  57. data/spec/sitehub/logging/error_logger_spec.rb +5 -7
  58. data/spec/sitehub/logging/log_entry_spec.rb +2 -5
  59. data/spec/sitehub/logging/log_stash_spec.rb +1 -3
  60. data/spec/sitehub/logging/log_wrapper_spec.rb +0 -4
  61. data/spec/sitehub/middleware_spec.rb +1 -5
  62. data/spec/sitehub/path_directive_spec.rb +4 -7
  63. data/spec/sitehub/path_directives_spec.rb +6 -7
  64. data/spec/sitehub/request_mapping_spec.rb +2 -5
  65. data/spec/sitehub/resolver_spec.rb +1 -1
  66. data/spec/sitehub/reverse_proxy_spec.rb +37 -31
  67. data/spec/sitehub/transaction_id_spec.rb +3 -3
  68. data/spec/sitehub_spec.rb +2 -4
  69. data/spec/support/async/callback.rb +11 -0
  70. data/spec/support/async/middleware.rb +25 -0
  71. data/spec/support/async/response_handler.rb +16 -0
  72. data/spec/support/async.rb +4 -0
  73. data/spec/support/patch/rack/response.rb +13 -21
  74. data/spec/support/shared_contexts/async_context.rb +3 -58
  75. data/spec/support/shared_contexts/middleware_context.rb +15 -17
  76. data/spec/support/shared_contexts/rack_test_context.rb +3 -3
  77. data/spec/support/shared_contexts/sitehub_context.rb +9 -4
  78. data/spec/support/silent_warnings.rb +2 -3
  79. data/tasks/code_quality.rake +15 -0
  80. data/tasks/gem_tasks.rake +1 -0
  81. data/tasks/support/console.rb +7 -0
  82. data/tasks/testing.rake +4 -0
  83. data/tasks/util_tasks.rake +7 -0
  84. metadata +27 -3
  85. data/spec/basket_spec.rb +0 -30
@@ -7,9 +7,8 @@ require 'em-http'
7
7
 
8
8
  class SiteHub
9
9
  class ForwardProxies
10
-
11
10
  NOT_FOUND = Rack::Response.new(['page not found'], 404, {})
12
- def call env
11
+ def call(env)
13
12
  source_request = Rack::Request.new(env)
14
13
 
15
14
  forward_proxy = mapped_route(path: source_request.path, request: source_request)
@@ -19,32 +18,32 @@ class SiteHub
19
18
  end
20
19
 
21
20
  def init
22
- forward_proxies.values.each { |proxy| proxy.build }
21
+ forward_proxies.values.each(&:build)
23
22
  self
24
23
  end
25
24
 
26
- def << route
25
+ def <<(route)
27
26
  forward_proxies[route.mapped_path] = route
28
27
  end
29
28
 
30
29
  def mapped_route(path:, request:)
30
+ fwd_proxy_builder = forward_proxies[mapping(path)]
31
+ fwd_proxy_builder ? fwd_proxy_builder.resolve(id: request.cookies[RECORDED_ROUTES_COOKIE], env: request.env) : nil
32
+ end
31
33
 
32
- key = forward_proxies.keys.find do |key|
34
+ def mapping(path)
35
+ forward_proxies.keys.find do |key|
33
36
  case key
34
- when Regexp
35
- key.match(path)
36
- else
37
- path == key
37
+ when Regexp
38
+ key.match(path)
39
+ else
40
+ path == key
38
41
  end
39
42
  end
40
-
41
- forward_proxy_builder = forward_proxies[key]
42
- forward_proxy_builder ? forward_proxy_builder.resolve(id: request.cookies[RECORDED_ROUTES_COOKIE], env: request.env) : nil
43
43
  end
44
44
 
45
45
  def forward_proxies
46
46
  @forward_proxies ||= {}
47
47
  end
48
-
49
48
  end
50
49
  end
@@ -1,3 +1,4 @@
1
+ # rubocop:disable Metrics/ParameterLists
1
2
  require 'sitehub/http_headers'
2
3
  require 'sitehub/request_mapping'
3
4
  require 'sitehub/rules'
@@ -6,7 +7,6 @@ require 'faraday'
6
7
  require 'sitehub/constants'
7
8
  class SiteHub
8
9
  class ForwardProxy
9
-
10
10
  ERROR_RESPONSE = Rack::Response.new(['error'], 500, {})
11
11
 
12
12
  include HttpHeaders, Rules, Resolver, Constants
@@ -14,39 +14,48 @@ class SiteHub
14
14
  attr_reader :url, :id, :mapped_path, :http_client, :sitehub_cookie_path, :sitehub_cookie_name
15
15
 
16
16
  def initialize(url:, id:, mapped_path: nil, rule: nil, sitehub_cookie_path: nil, sitehub_cookie_name:)
17
- @id, @url, @rule, @mapped_path = id, url, rule, mapped_path
17
+ @id = id
18
+ @url = url
19
+ @rule = rule
20
+ @mapped_path = mapped_path
18
21
  @sitehub_cookie_path = sitehub_cookie_path
19
22
  @sitehub_cookie_name = sitehub_cookie_name
20
- @http_client = Faraday.new(ssl: {verify:false}) do |con|
23
+ @http_client = Faraday.new(ssl: { verify: false }) do |con|
21
24
  con.adapter :em_synchrony
22
25
  end
23
26
  end
24
27
 
25
- def call env
28
+ def call(env)
26
29
  source_request = Rack::Request.new(env)
30
+ request_mapping = env[REQUEST_MAPPING] = request_mapping(source_request)
31
+ mapped_uri = URI(request_mapping.computed_uri)
27
32
 
28
- request_mapping = request_mapping(source_request)
33
+ downstream_response = proxy_call(request_headers(mapped_uri, source_request), mapped_uri, source_request)
29
34
 
30
- mapped_uri = URI(request_mapping.computed_uri)
35
+ response(downstream_response, source_request)
36
+ rescue StandardError => e
37
+ env[ERRORS] << e.message
38
+ ERROR_RESPONSE.dup
39
+ end
31
40
 
32
- request_headers = sanitise_headers(extract_http_headers(source_request.env))
33
- request_headers[HOST_HEADER] = "#{mapped_uri.host}:#{mapped_uri.port}"
34
- request_headers[X_FORWARDED_HOST_HEADER] = append_host(request_headers[X_FORWARDED_HOST_HEADER].to_s, source_request.url)
35
- env[REQUEST_MAPPING] = request_mapping
41
+ def response(response, source_request)
42
+ Rack::Response.new(response.body, response.status, sanitise_headers(response.headers)).tap do |r|
43
+ r.set_cookie(sitehub_cookie_name, path: (sitehub_cookie_path || source_request.path), value: id)
44
+ end
45
+ end
36
46
 
37
- begin
38
- response = http_client.send(source_request.request_method.downcase, mapped_uri) do |request|
39
- request.headers = request_headers
40
- request.body = source_request.body.read
41
- request.params = source_request.params
42
- end
47
+ def request_headers(mapped_uri, source_request)
48
+ headers = sanitise_headers(extract_http_headers(source_request.env))
49
+ headers[HOST_HEADER] = "#{mapped_uri.host}:#{mapped_uri.port}"
50
+ headers[X_FORWARDED_HOST_HEADER] = append_host(headers[X_FORWARDED_HOST_HEADER].to_s, source_request.url)
51
+ headers
52
+ end
43
53
 
44
- Rack::Response.new(response.body, response.status, sanitise_headers(response.headers)).tap do |r|
45
- r.set_cookie(sitehub_cookie_name, path: (sitehub_cookie_path || source_request.path), value: id)
46
- end
47
- rescue Exception => e
48
- env[ERRORS] << e.message
49
- ERROR_RESPONSE.dup
54
+ def proxy_call(headers, mapped_uri, source_request)
55
+ http_client.send(source_request.request_method.downcase, mapped_uri) do |request|
56
+ request.headers = headers
57
+ request.body = source_request.body.read
58
+ request.params = source_request.params
50
59
  end
51
60
  end
52
61
 
@@ -54,14 +63,19 @@ class SiteHub
54
63
  RequestMapping.new(source_url: source_request.url, mapped_url: url, mapped_path: mapped_path)
55
64
  end
56
65
 
57
- def == other
66
+ def ==(other)
58
67
  other.is_a?(ForwardProxy) && url == other.url
59
68
  end
60
69
 
61
70
  private
71
+
62
72
  def append_host(forwarded_host, destination_uri)
63
73
  destination_uri = URI(destination_uri)
64
- forwarded_host == EMPTY_STRING ? "#{destination_uri.host}:#{destination_uri.port}" : "#{forwarded_host},#{destination_uri.host}"
74
+ if forwarded_host == EMPTY_STRING
75
+ "#{destination_uri.host}:#{destination_uri.port}"
76
+ else
77
+ "#{forwarded_host},#{destination_uri.host}"
78
+ end
65
79
  end
66
80
  end
67
81
  end
@@ -6,17 +6,20 @@ require_relative 'collection/route_collection'
6
6
  require_relative 'middleware'
7
7
 
8
8
  class SiteHub
9
-
10
9
  class ForwardProxyBuilder
11
10
  include Middleware
12
11
  include Rules, Resolver
13
12
 
14
- class InvalidDefinitionException < Exception;
13
+ class InvalidDefinitionException < Exception
15
14
  end
16
15
 
16
+ INVALID_SPLIT_MSG = 'label and url must be defined if not supplying a block'.freeze
17
+ ROUTES_WITH_SPLITS_MSG = 'you cant register routes and splits at the same level'.freeze
18
+ INVALID_ROUTE_DEF_MSG = 'rule must be specified when supplying a block'.freeze
19
+
17
20
  attr_reader :mapped_path, :default_proxy, :routes, :middlewares, :splits, :sitehub_cookie_name
18
21
 
19
- def initialize(url: nil, mapped_path:, rule:nil, sitehub_cookie_name: nil, &block)
22
+ def initialize(url: nil, mapped_path:, rule: nil, sitehub_cookie_name: nil, &block)
20
23
  @mapped_path = mapped_path
21
24
  @middlewares = []
22
25
  @splits = Collection::SplitRouteCollection.new
@@ -24,10 +27,11 @@ class SiteHub
24
27
  @sitehub_cookie_name = sitehub_cookie_name
25
28
  rule(rule) if rule
26
29
  default(url: url) if url
27
- if block
28
- instance_eval(&block)
29
- raise InvalidDefinitionException unless valid?
30
- end
30
+
31
+ return unless block
32
+
33
+ instance_eval(&block)
34
+ raise InvalidDefinitionException unless valid?
31
35
  end
32
36
 
33
37
  def valid?
@@ -35,23 +39,34 @@ class SiteHub
35
39
  endpoints.valid?
36
40
  end
37
41
 
38
- def endpoints collection=nil
42
+ def endpoints(collection = nil)
39
43
  return @endpoints || Collection::RouteCollection.new unless collection
40
44
 
41
- raise InvalidDefinitionException, 'you cant register routes and splits at the same level' if @endpoints && @endpoints != collection
45
+ raise InvalidDefinitionException, ROUTES_WITH_SPLITS_MSG if @endpoints && @endpoints != collection
42
46
  @endpoints = collection
43
47
  end
44
48
 
45
- def split(percentage:, url:, label:, &block)
49
+ def split(percentage:, url: nil, label: nil, &block)
46
50
  endpoints(splits)
47
- endpoints.add label.to_sym, forward_proxy(label: label, url: url), percentage
51
+
52
+ raise InvalidDefinitionException, INVALID_SPLIT_MSG unless block || [url, label].all?
53
+
54
+ label = label ? label.to_sym : UUID.generate(:compact)
55
+
56
+ proxy = block ? new(&block).build : forward_proxy(label: label, url: url)
57
+
58
+ endpoints.add label, proxy, percentage
59
+ end
60
+
61
+ def new(&block)
62
+ self.class.new(mapped_path: mapped_path, &block)
48
63
  end
49
64
 
50
- def route url:nil, label:nil, rule: nil, &block
65
+ def route(url: nil, label: nil, rule: nil, &block)
51
66
  endpoints(routes)
52
67
 
53
68
  if block
54
- raise InvalidDefinitionException, 'rule must be specified when supplying a block'unless rule
69
+ raise InvalidDefinitionException, INVALID_ROUTE_DEF_MSG unless rule
55
70
  builder = self.class.new(mapped_path: mapped_path, rule: rule, &block).build
56
71
  endpoints.add UUID.generate(:compact), builder
57
72
  else
@@ -63,12 +78,11 @@ class SiteHub
63
78
  @default_proxy = forward_proxy(label: :default, url: url)
64
79
  end
65
80
 
66
- def sitehub_cookie_path path=nil
81
+ def sitehub_cookie_path(path = nil)
67
82
  return @sitehub_cookie_path unless path
68
83
  @sitehub_cookie_path = path
69
84
  end
70
85
 
71
-
72
86
  def build
73
87
  endpoints.transform do |proxy|
74
88
  apply_middleware(proxy).tap do |wrapped_proxy|
@@ -86,14 +100,17 @@ class SiteHub
86
100
  endpoints[id] || endpoints.resolve(env: env) || default_proxy
87
101
  end
88
102
 
89
- def == other
90
- other.is_a?(ForwardProxyBuilder) && self.default_proxy == other.default_proxy && self.endpoints == other.endpoints
103
+ def ==(other)
104
+ other.is_a?(ForwardProxyBuilder) && default_proxy == other.default_proxy && endpoints == other.endpoints
91
105
  end
92
106
 
93
-
94
107
  def forward_proxy(label:, url:, rule: nil)
95
- ForwardProxy.new(url: url, id: label.to_sym, mapped_path: mapped_path, sitehub_cookie_path: sitehub_cookie_path, sitehub_cookie_name: sitehub_cookie_name, rule: rule)
108
+ ForwardProxy.new(url: url,
109
+ id: label.to_sym,
110
+ mapped_path: mapped_path,
111
+ sitehub_cookie_path: sitehub_cookie_path,
112
+ sitehub_cookie_name: sitehub_cookie_name,
113
+ rule: rule)
96
114
  end
97
115
  end
98
-
99
- end
116
+ end
@@ -9,52 +9,65 @@ class SiteHub
9
9
  RACK_HTTP_HEADER_ID = /#{HTTP_PREFIX.source}[A-Z_]+$/
10
10
  COMMAND_FOLLOWED_BY_SPACES = /,\s+/
11
11
 
12
+ SHOULD_NOT_TRANSFER = [PROXY_CONNECTION].freeze
13
+
14
+ HOP_BY_HOP = [CONNECTION_HEADER,
15
+ KEEP_ALIVE,
16
+ PROXY_AUTHENTICATE,
17
+ PROXY_AUTHORIZATION,
18
+ TE,
19
+ TRAILERS,
20
+ TRANSFER_ENCODING,
21
+ CONTENT_ENCODING].freeze
22
+
12
23
  def split_field(f)
13
- f ? f.split(COMMAND_FOLLOWED_BY_SPACES).collect { |i| i.downcase } : []
24
+ f ? f.split(COMMAND_FOLLOWED_BY_SPACES).collect(&:downcase) : []
14
25
  end
15
26
 
16
27
  def sanitise_headers(src)
17
-
18
- sanitised_headers = {}
19
-
20
28
  connections = split_field(src[CONNECTION_HEADER])
21
- src.each do |key, value|
22
- key = key.downcase.gsub(UNDERSCORE, HYPHEN)
23
- if HopByHop.member?(key) ||
24
- connections.member?(key) ||
25
- ShouldNotTransfer.member?(key)
26
- next
27
- end
28
- sanitised_headers[key] = value
29
- end
30
29
 
31
- sanitised_headers[LOCATION_HEADER].gsub!(HTTP_OR_SSL_PORT, EMPTY_STRING) if sanitised_headers[LOCATION_HEADER]
30
+ {}.tap do |sanitised_headers|
31
+ src.each do |key, value|
32
+ key = key.downcase.gsub(UNDERSCORE, HYPHEN)
33
+ next if HOP_BY_HOP.member?(key) || connections.member?(key) || SHOULD_NOT_TRANSFER.member?(key)
34
+ sanitised_headers[key] = value
35
+ end
32
36
 
33
- sanitised_headers
37
+ sanitised_headers[LOCATION_HEADER].gsub!(HTTP_OR_SSL_PORT, EMPTY_STRING) if sanitised_headers[LOCATION_HEADER]
38
+ end
34
39
  end
35
40
 
36
-
37
-
38
41
  def extract_http_headers(env)
39
- headers = env.reject do |k, v|
40
- !RackHttpHeaderKeys::HTTP_HEADER_FILTER_EXCEPTIONS.include?(k.to_s.upcase) && (!(RACK_HTTP_HEADER_ID === k) || v.nil?)
41
- end.map do |k, v|
42
- [reconstruct_header_name(k), v]
43
- end.inject(Rack::Utils::HeaderHash.new) do |hash, k_v|
42
+ headers = remove_excluded_headers(env)
43
+
44
+ headers = headers.to_a.each_with_object(Rack::Utils::HeaderHash.new) do |k_v, hash|
44
45
  k, v = k_v
45
- hash[k] = v
46
+ hash[reconstruct_header_name(k)] = v
46
47
  hash
47
48
  end
48
49
 
49
- x_forwarded_for = (headers[X_FORWARDED_FOR_HEADER].to_s.split(COMMAND_FOLLOWED_BY_SPACES) << env[RackHttpHeaderKeys::REMOTE_ADDRESS_ENV_KEY]).join(COMMA_WITH_SPACE)
50
+ remote_address = env[RackHttpHeaderKeys::REMOTE_ADDRESS_ENV_KEY]
51
+ headers.merge!(X_FORWARDED_FOR_HEADER => x_forwarded_for_value(headers, remote_address))
52
+ end
50
53
 
51
- headers.merge!(X_FORWARDED_FOR_HEADER => x_forwarded_for)
54
+ def x_forwarded_for_value(headers, remote_address)
55
+ (forwarded_address_list(headers) << remote_address).join(COMMA_WITH_SPACE)
52
56
  end
53
57
 
58
+ def forwarded_address_list(headers)
59
+ headers[X_FORWARDED_FOR_HEADER].to_s.split(COMMAND_FOLLOWED_BY_SPACES)
60
+ end
54
61
 
62
+ def remove_excluded_headers(env)
63
+ env.reject do |k, v|
64
+ !RackHttpHeaderKeys::HTTP_HEADER_FILTER_EXCEPTIONS.include?(k.to_s.upcase) &&
65
+ (!RACK_HTTP_HEADER_ID.match(k) || v.nil?)
66
+ end
67
+ end
55
68
 
56
69
  def reconstruct_header_name(name)
57
70
  name.sub(HTTP_PREFIX, EMPTY_STRING).gsub(UNDERSCORE, HYPHEN)
58
71
  end
59
72
  end
60
- end
73
+ end
@@ -1,9 +1,10 @@
1
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
1
2
  require 'logger'
2
3
  require 'rack/commonlogger'
3
4
  require_relative 'log_wrapper'
4
5
  require 'sitehub/constants'
5
6
 
6
- #Very heavily based on Rack::CommonLogger
7
+ # Very heavily based on Rack::CommonLogger
7
8
  class SiteHub
8
9
  module Logging
9
10
  class AccessLogger
@@ -11,54 +12,57 @@ class SiteHub
11
12
 
12
13
  include Constants
13
14
 
14
- FORMAT = %{%s - %s [%s] transaction_id:%s: "%s %s%s => %s %s" %d %s %0.4f\n}.freeze
15
- PATH_INFO = RackHttpHeaderKeys::PATH_INFO
16
- REQUEST_METHOD = RackHttpHeaderKeys::REQUEST_METHOD
17
- SCRIPT_NAME = RackHttpHeaderKeys::SCRIPT_NAME
18
- QUERY_STRING = RackHttpHeaderKeys::QUERY_STRING
19
- X_FORWARDED_FOR = RackHttpHeaderKeys::X_FORWARDED_FOR
20
- REMOTE_ADDR = RackHttpHeaderKeys::REMOTE_ADDR
21
- HTTP_VERSION = RackHttpHeaderKeys::HTTP_VERSION
22
- REMOTE_USER = RackHttpHeaderKeys::REMOTE_USER
23
- TRANSACTION_ID = RackHttpHeaderKeys::TRANSACTION_ID
24
- CONTENT_LENGTH = HttpHeaderKeys::CONTENT_LENGTH
25
- ZERO_STRING = '0'
15
+ FORMAT = %(%s - %s [%s] transaction_id:%s: "%s %s%s => %s %s" %d %s %0.4f\n).freeze
16
+ ZERO_STRING = '0'.freeze
26
17
  STATUS_RANGE = 0..3
27
18
 
28
- def initialize app, logger = ::Logger.new(STDOUT)
19
+ def initialize(app, logger = ::Logger.new(STDOUT))
29
20
  @app = app
30
21
  @logger = LogWrapper.new(logger)
31
22
  end
32
23
 
33
- def call env
24
+ def call(env)
34
25
  start_time = Time.now
35
26
 
36
27
  @app.call(env).tap do |response|
37
- status, headers, body = response.to_a
38
- log env, status, headers, env[REQUEST_MAPPING], start_time
28
+ status, headers, _body = response.to_a
29
+ log_message = format(log_template, *log_content(start_time, env, headers, env[REQUEST_MAPPING], status))
30
+ logger.write(log_message)
39
31
  end
40
32
  end
41
33
 
42
- def log(env, status, header, mapped_request, began_at)
34
+ def log_content(began_at, env, header, mapped_request, status)
43
35
  now = Time.now
44
- length = extract_content_length(header)
36
+ [
37
+ source_address(env),
38
+ remote_user(env[RackHttpHeaderKeys::REMOTE_USER]),
39
+ now.strftime(TIME_STAMP_FORMAT),
40
+ env[RackHttpHeaderKeys::TRANSACTION_ID],
41
+ env[RackHttpHeaderKeys::REQUEST_METHOD],
42
+ env[RackHttpHeaderKeys::PATH_INFO],
43
+ query_string(env[RackHttpHeaderKeys::QUERY_STRING]),
44
+ mapped_url(mapped_request),
45
+ env[RackHttpHeaderKeys::HTTP_VERSION],
46
+ status.to_s[STATUS_RANGE],
47
+ extract_content_length(header),
48
+ now - began_at
49
+ ]
50
+ end
45
51
 
52
+ def mapped_url(mapped_request)
53
+ mapped_request ? mapped_request.mapped_url.to_s : EMPTY_STRING
54
+ end
46
55
 
47
- msg = log_template % [
48
- env[X_FORWARDED_FOR] || env[REMOTE_ADDR] || HYPHEN,
49
- env[REMOTE_USER] || "-",
50
- now.strftime(TIME_STAMP_FORMAT),
51
- env[TRANSACTION_ID],
52
- env[REQUEST_METHOD],
53
- env[PATH_INFO],
54
- env[QUERY_STRING].empty? ? EMPTY_STRING : QUESTION_MARK+env[QUERY_STRING],
55
- mapped_request ? mapped_request.mapped_url.to_s : EMPTY_STRING,
56
- env[HTTP_VERSION],
57
- status.to_s[STATUS_RANGE],
58
- length,
59
- now - began_at]
56
+ def query_string(query_string)
57
+ query_string.empty? ? EMPTY_STRING : QUESTION_MARK + query_string
58
+ end
59
+
60
+ def remote_user(remote_user)
61
+ remote_user || '-'
62
+ end
60
63
 
61
- logger.write(msg)
64
+ def source_address(env)
65
+ env[RackHttpHeaderKeys::X_FORWARDED_FOR] || env[RackHttpHeaderKeys::REMOTE_ADDR] || HYPHEN
62
66
  end
63
67
 
64
68
  def log_template
@@ -66,9 +70,9 @@ class SiteHub
66
70
  end
67
71
 
68
72
  def extract_content_length(headers)
69
- value = headers[CONTENT_LENGTH] or return HYPHEN
73
+ (value = headers[HttpHeaderKeys::CONTENT_LENGTH]) || (return HYPHEN)
70
74
  value.to_s == ZERO_STRING ? HYPHEN : value
71
75
  end
72
76
  end
73
77
  end
74
- end
78
+ end
@@ -6,8 +6,7 @@ class SiteHub
6
6
  module Logging
7
7
  class ErrorLogger
8
8
  include Constants
9
- LOG_TEMPLATE = '[%s] ERROR: %s - %s'
10
-
9
+ LOG_TEMPLATE = '[%s] ERROR: %s - %s'.freeze
11
10
 
12
11
  attr_reader :logger
13
12
 
@@ -16,11 +15,13 @@ class SiteHub
16
15
  @logger = LogWrapper.new(logger)
17
16
  end
18
17
 
19
- def call env
18
+ def call(env)
20
19
  env[ERRORS] ||= LogStash.new
21
20
  @app.call(env).tap do
22
21
  unless env[ERRORS].empty?
23
- messages = env[ERRORS].collect { |log_entry| log_message(error: log_entry.message, transaction_id: env[RackHttpHeaderKeys::TRANSACTION_ID]) }
22
+ messages = env[ERRORS].collect do |log_entry|
23
+ log_message(error: log_entry.message, transaction_id: env[RackHttpHeaderKeys::TRANSACTION_ID])
24
+ end
24
25
 
25
26
  logger.write(messages.join(NEW_LINE))
26
27
  end
@@ -28,9 +29,8 @@ class SiteHub
28
29
  end
29
30
 
30
31
  def log_message(error:, transaction_id:)
31
- LOG_TEMPLATE % [Time.now.strftime(TIME_STAMP_FORMAT), transaction_id, error]
32
+ format(LOG_TEMPLATE, Time.now.strftime(TIME_STAMP_FORMAT), transaction_id, error)
32
33
  end
33
-
34
34
  end
35
35
  end
36
- end
36
+ end
@@ -2,13 +2,14 @@ class SiteHub
2
2
  module Logging
3
3
  class LogEntry
4
4
  attr_reader :message, :time
5
- def initialize message, time=Time.now
6
- @message, @time = message, time
5
+ def initialize(message, time = Time.now)
6
+ @message = message
7
+ @time = time
7
8
  end
8
9
 
9
- def == other
10
- other.is_a?(LogEntry) && self.message == other.message && self.time == other.time
10
+ def ==(other)
11
+ other.is_a?(LogEntry) && message == other.message && time == other.time
11
12
  end
12
13
  end
13
14
  end
14
- end
15
+ end
@@ -2,9 +2,9 @@ require_relative 'log_entry'
2
2
  class SiteHub
3
3
  module Logging
4
4
  class LogStash < Array
5
- def << message
5
+ def <<(message)
6
6
  super(LogEntry.new(message))
7
7
  end
8
8
  end
9
9
  end
10
- end
10
+ end
@@ -3,11 +3,11 @@ class SiteHub
3
3
  class LogWrapper
4
4
  attr_reader :logger
5
5
 
6
- def initialize logger
6
+ def initialize(logger)
7
7
  @logger = logger
8
8
  end
9
9
 
10
- def write msg
10
+ def write(msg)
11
11
  if logger.respond_to?(:<<)
12
12
  logger << msg
13
13
  elsif logger.respond_to?(:write)
@@ -15,9 +15,9 @@ class SiteHub
15
15
  end
16
16
  end
17
17
 
18
- def == other
19
- other.is_a?(LogWrapper) && self.logger == other.logger
18
+ def ==(other)
19
+ other.is_a?(LogWrapper) && logger == other.logger
20
20
  end
21
21
  end
22
22
  end
23
- end
23
+ end
@@ -2,4 +2,4 @@ require_relative 'logging/access_logger'
2
2
  require_relative 'logging/error_logger'
3
3
  require_relative 'logging/log_entry'
4
4
  require_relative 'logging/log_stash'
5
- require_relative 'logging/log_wrapper'
5
+ require_relative 'logging/log_wrapper'
@@ -5,7 +5,7 @@ class SiteHub
5
5
  end
6
6
 
7
7
  def use(middleware_clazz, *args, &block)
8
- middlewares << [middleware_clazz, args, block|| proc{}]
8
+ middlewares << [middleware_clazz, args, block || proc {}]
9
9
  end
10
10
 
11
11
  def apply_middleware(forward_proxy)
@@ -18,4 +18,4 @@ class SiteHub
18
18
  end
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -2,31 +2,31 @@ class SiteHub
2
2
  class PathDirective
3
3
  attr_reader :matcher, :path_template
4
4
 
5
- def initialize matcher, path_template
6
- @matcher, @path_template = matcher, path_template
5
+ def initialize(matcher, path_template)
6
+ @matcher = matcher
7
+ @path_template = path_template
7
8
  end
8
9
 
9
- def match? url
10
- !!matcher.match(url)
10
+ def match?(url)
11
+ !matcher.match(url).nil?
11
12
  end
12
13
 
13
14
  def path_template
14
15
  @path_template.dup
15
16
  end
16
17
 
17
- def apply url
18
+ def apply(url)
18
19
  url_components = matcher.match(url).captures
19
20
 
20
21
  path_template.tap do |p|
21
22
  url_components.each_with_index do |m, index|
22
- p.gsub!(RequestMapping::CAPTURE_GROUP_REFERENCE % (index+1), m)
23
+ p.gsub!(RequestMapping::CAPTURE_GROUP_REFERENCE % (index + 1), m)
23
24
  end
24
25
  end
25
-
26
26
  end
27
27
 
28
- def == other
29
- other.is_a?(PathDirective) && self.matcher == other.matcher && self.path_template == other.path_template
28
+ def ==(other)
29
+ other.is_a?(PathDirective) && matcher == other.matcher && path_template == other.path_template
30
30
  end
31
31
  end
32
- end
32
+ end
@@ -1,11 +1,12 @@
1
1
  require 'sitehub/path_directive'
2
2
  class SiteHub
3
3
  class PathDirectives < Array
4
- def initialize map={}
4
+ def initialize(map = {})
5
5
  enriched = map.map do |array|
6
- matcher,path_template = array.first, array.last
6
+ matcher = array.first
7
+ path_template = array.last
7
8
 
8
- matcher = matcher.is_a?(Regexp) ? matcher : %r{#{matcher}}
9
+ matcher = matcher.is_a?(Regexp) ? matcher : /#{matcher}/
9
10
  PathDirective.new(matcher, path_template)
10
11
  end
11
12
 
@@ -18,4 +19,4 @@ class SiteHub
18
19
  end
19
20
  end
20
21
  end
21
- end
22
+ end