sitehub 0.4.2 → 0.4.3

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.
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