sitehub 0.4.3 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +31 -0
  3. data/.gitignore +2 -1
  4. data/.reek +41 -0
  5. data/.simplecov +7 -0
  6. data/Gemfile.lock +61 -33
  7. data/README.md +4 -0
  8. data/Rakefile +1 -1
  9. data/circle.yml +1 -1
  10. data/lib/sitehub/builder.rb +19 -36
  11. data/lib/sitehub/collection/split_route_collection.rb +18 -13
  12. data/lib/sitehub/collection/split_route_collection/split.rb +6 -4
  13. data/lib/sitehub/constants.rb +2 -1
  14. data/lib/sitehub/constants/http_header_keys.rb +2 -0
  15. data/lib/sitehub/constants/rack_http_header_keys.rb +2 -0
  16. data/lib/sitehub/cookie.rb +4 -13
  17. data/lib/sitehub/cookie/attribute.rb +10 -9
  18. data/lib/sitehub/cookie/flag.rb +5 -8
  19. data/lib/sitehub/cookie_rewriting.rb +12 -5
  20. data/lib/sitehub/downstream_client.rb +37 -0
  21. data/lib/sitehub/equality.rb +28 -0
  22. data/lib/sitehub/forward_proxy.rb +19 -62
  23. data/lib/sitehub/forward_proxy_builder.rb +70 -49
  24. data/lib/sitehub/getter_setter_methods.rb +21 -0
  25. data/lib/sitehub/http_headers.rb +45 -48
  26. data/lib/sitehub/location_rewriter.rb +29 -0
  27. data/lib/sitehub/location_rewriters.rb +23 -0
  28. data/lib/sitehub/memoize.rb +25 -0
  29. data/lib/sitehub/middleware.rb +16 -6
  30. data/lib/sitehub/middleware/error_handling.rb +20 -0
  31. data/lib/sitehub/middleware/forward_proxies.rb +54 -0
  32. data/lib/sitehub/{logging.rb → middleware/logging.rb} +0 -0
  33. data/lib/sitehub/middleware/logging/access_logger.rb +36 -0
  34. data/lib/sitehub/middleware/logging/error_logger.rb +38 -0
  35. data/lib/sitehub/middleware/logging/log_entry.rb +16 -0
  36. data/lib/sitehub/middleware/logging/log_stash.rb +12 -0
  37. data/lib/sitehub/middleware/logging/log_wrapper.rb +24 -0
  38. data/lib/sitehub/middleware/logging/request_log.rb +74 -0
  39. data/lib/sitehub/middleware/reverse_proxy.rb +37 -0
  40. data/lib/sitehub/middleware/transaction_id.rb +18 -0
  41. data/lib/sitehub/nil_location_rewriter.rb +7 -0
  42. data/lib/sitehub/nil_proxy.rb +11 -0
  43. data/lib/sitehub/request.rb +101 -0
  44. data/lib/sitehub/request_mapping.rb +16 -18
  45. data/lib/sitehub/resolver.rb +1 -1
  46. data/lib/sitehub/response.rb +10 -0
  47. data/lib/sitehub/string_utils.rb +13 -0
  48. data/lib/sitehub/version.rb +1 -1
  49. data/sitehub.gemspec +4 -1
  50. data/spec/equality_spec.rb +32 -0
  51. data/spec/sitehub/builder_spec.rb +29 -22
  52. data/spec/sitehub/collection/route_collection_spec.rb +15 -14
  53. data/spec/sitehub/collection/split_route_collection/split_spec.rb +26 -0
  54. data/spec/sitehub/collection/split_route_collection_spec.rb +15 -3
  55. data/spec/sitehub/cookie/flag_spec.rb +1 -1
  56. data/spec/sitehub/cookie_rewriting_spec.rb +6 -10
  57. data/spec/sitehub/downstream_client_spec.rb +72 -0
  58. data/spec/sitehub/equality_spec.rb +32 -0
  59. data/spec/sitehub/forward_proxy_builder_spec.rb +92 -55
  60. data/spec/sitehub/forward_proxy_spec.rb +29 -97
  61. data/spec/sitehub/http_headers_spec.rb +32 -52
  62. data/spec/sitehub/integration_spec.rb +1 -1
  63. data/spec/sitehub/location_rewriter_spec.rb +46 -0
  64. data/spec/sitehub/{path_directives_spec.rb → location_rewriters_spec.rb} +8 -8
  65. data/spec/sitehub/memoize_spec.rb +56 -0
  66. data/spec/sitehub/middleware/error_handling_spec.rb +34 -0
  67. data/spec/sitehub/middleware/forward_proxies_spec.rb +105 -0
  68. data/spec/sitehub/middleware/logging/access_logger_spec.rb +51 -0
  69. data/spec/sitehub/middleware/logging/error_logger_spec.rb +84 -0
  70. data/spec/sitehub/middleware/logging/log_entry_spec.rb +33 -0
  71. data/spec/sitehub/middleware/logging/log_stash_spec.rb +21 -0
  72. data/spec/sitehub/middleware/logging/log_wrapper_spec.rb +31 -0
  73. data/spec/sitehub/middleware/logging/request_log_spec.rb +108 -0
  74. data/spec/sitehub/middleware/reverse_proxy_spec.rb +113 -0
  75. data/spec/sitehub/middleware/transaction_id_spec.rb +30 -0
  76. data/spec/sitehub/middleware_spec.rb +23 -13
  77. data/spec/sitehub/nil_location_rewriter_spec.rb +10 -0
  78. data/spec/sitehub/nil_proxy_spec.rb +14 -0
  79. data/spec/sitehub/request_mapping_spec.rb +21 -23
  80. data/spec/sitehub/request_spec.rb +228 -0
  81. data/spec/sitehub/resolver_spec.rb +2 -5
  82. data/spec/sitehub/response_spec.rb +30 -0
  83. data/spec/spec_helper.rb +12 -6
  84. data/spec/support/async/middleware.rb +1 -0
  85. data/spec/support/patch/rack/response.rb +7 -5
  86. data/spec/support/shared_contexts.rb +3 -0
  87. data/spec/support/shared_contexts/http_proxy_rules_context.rb +36 -0
  88. data/spec/support/shared_contexts/middleware_context.rb +6 -6
  89. data/spec/support/shared_contexts/module_spec_context.rb +7 -0
  90. data/spec/support/shared_contexts/rack_request_context.rb +18 -0
  91. data/spec/support/shared_contexts/rack_test_context.rb +0 -1
  92. data/spec/support/shared_examples.rb +3 -0
  93. data/spec/support/shared_examples/memoized_helpers.rb +7 -0
  94. data/spec/support/shared_examples/prohibited_http_header_filter.rb +16 -0
  95. data/spec/support/silent_warnings.rb +1 -1
  96. data/tasks/code_quality.rake +6 -0
  97. metadata +99 -29
  98. data/lib/sitehub/forward_proxies.rb +0 -49
  99. data/lib/sitehub/logging/access_logger.rb +0 -78
  100. data/lib/sitehub/logging/error_logger.rb +0 -36
  101. data/lib/sitehub/logging/log_entry.rb +0 -15
  102. data/lib/sitehub/logging/log_stash.rb +0 -10
  103. data/lib/sitehub/logging/log_wrapper.rb +0 -23
  104. data/lib/sitehub/path_directive.rb +0 -32
  105. data/lib/sitehub/path_directives.rb +0 -22
  106. data/lib/sitehub/reverse_proxy.rb +0 -57
  107. data/lib/sitehub/string_sanitiser.rb +0 -7
  108. data/lib/sitehub/transaction_id.rb +0 -16
  109. data/spec/sitehub/error_handling_spec.rb +0 -20
  110. data/spec/sitehub/forward_proxies_spec.rb +0 -103
  111. data/spec/sitehub/logging/access_logger_spec.rb +0 -128
  112. data/spec/sitehub/logging/error_logger_spec.rb +0 -78
  113. data/spec/sitehub/logging/log_entry_spec.rb +0 -31
  114. data/spec/sitehub/logging/log_stash_spec.rb +0 -19
  115. data/spec/sitehub/logging/log_wrapper_spec.rb +0 -29
  116. data/spec/sitehub/path_directive_spec.rb +0 -47
  117. data/spec/sitehub/reverse_proxy_spec.rb +0 -111
  118. data/spec/sitehub/transaction_id_spec.rb +0 -28
  119. data/spec/support/async/response_handler.rb +0 -16
  120. data/spec/support/shared_contexts/async_context.rb +0 -14
@@ -1,78 +0,0 @@
1
- require 'sitehub/logging/error_logger'
2
-
3
- class SiteHub
4
- module Logging
5
- describe ErrorLogger do
6
- let(:app) { proc { [200, {}, []] } }
7
- subject { described_class.new(app) }
8
-
9
- describe '#initialize' do
10
- context 'logger supplied' do
11
- it 'sets logger to that logger' do
12
- expect(described_class.new(:app, :custom_logger).logger).to eq(LogWrapper.new(:custom_logger))
13
- end
14
- end
15
-
16
- context 'logger not supplied' do
17
- it 'sets the logger to go to STDERR' do
18
- expect(::Logger).to receive(:new).with(STDERR).and_return(:logging)
19
- expect(described_class.new(:app).logger).to eq(LogWrapper.new(:logging))
20
- end
21
- end
22
- end
23
-
24
- describe '#before_call' do
25
- it 'adds a collection hold errors' do
26
- env = {}
27
- subject.call(env)
28
- expect(env[ERRORS]).to eq([])
29
- end
30
- end
31
-
32
- describe '#call' do
33
- let(:output) { StringIO.new }
34
- let(:logger) { Logger.new(output) }
35
- let(:error_message) { 'error' }
36
- let(:errors) do
37
- Logging::LogStash.new.tap do |stash|
38
- stash << error_message
39
- end
40
- end
41
- subject { described_class.new(app, logger) }
42
-
43
- context 'errors have occurred' do
44
- it 'logs errors' do
45
- log_message = subject.log_message(error: error_message, transaction_id: :transaction_id)
46
- subject.call(ERRORS => errors, Constants::RackHttpHeaderKeys::TRANSACTION_ID => :transaction_id)
47
- expect(output.string).to eq(log_message)
48
- end
49
- end
50
-
51
- context 'no errors have occured' do
52
- it 'does not log anything' do
53
- expect(logger).to_not receive(:write)
54
- subject.call(ERRORS => [])
55
- end
56
- end
57
- end
58
-
59
- describe '#log_message' do
60
- let(:error) { 'error' }
61
- it 'contains the time and date' do
62
- now = Time.now
63
- expect(Time).to receive(:now).and_return(now)
64
- expected_time = now.strftime('%d/%b/%Y:%H:%M:%S %z')
65
- expect(subject.log_message(error: error, transaction_id: :transaction_id)).to start_with("[#{expected_time}]")
66
- end
67
-
68
- it 'logs statements made against blah' do
69
- expect(subject.log_message(error: error, transaction_id: :transaction_id)).to match(/ERROR: .* - ?#{error}$/)
70
- end
71
-
72
- it 'contains the transation id of the request' do
73
- expect(subject.log_message(error: error, transaction_id: :transaction_id)).to include('ERROR: transaction_id')
74
- end
75
- end
76
- end
77
- end
78
- end
@@ -1,31 +0,0 @@
1
- require 'sitehub/logging/log_entry'
2
- class SiteHub
3
- module Logging
4
- describe LogEntry do
5
- describe '#initialize' do
6
- let(:time) { Time.now }
7
- subject do
8
- described_class.new(:message, time)
9
- end
10
-
11
- it 'sets the message' do
12
- expect(subject.message).to be(:message)
13
- end
14
-
15
- it 'sets the time' do
16
- expect(subject.time).to be(time)
17
- end
18
-
19
- context 'time not supplied' do
20
- subject do
21
- described_class.new(:message)
22
- end
23
- it 'defaults the time' do
24
- expect(Time).to receive(:now).and_return(:current_time)
25
- expect(subject.time).to be(:current_time)
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,19 +0,0 @@
1
- require 'sitehub/logging/log_stash'
2
-
3
- class SiteHub
4
- module Logging
5
- describe LogStash do
6
- it 'inherits Array' do
7
- expect(subject).to be_a_kind_of(Array)
8
- end
9
-
10
- describe '#<<' do
11
- it 'adds a LogEntry' do
12
- allow(Time).to receive(:now).and_return(:current_time)
13
- subject << :message
14
- expect(subject).to eq([LogEntry.new(:message)])
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,29 +0,0 @@
1
- require 'sitehub/logging/log_wrapper'
2
- class SiteHub
3
- module Logging
4
- describe LogWrapper do
5
- describe '#write' do
6
- let(:logger) { double('logger') }
7
- subject do
8
- described_class.new(logger)
9
- end
10
-
11
- context 'logger responds to <<' do
12
- it 'calls << when writing out the log' do
13
- message = 'message'
14
- expect(logger).to receive(:<<).with(message)
15
- subject.write(message)
16
- end
17
- end
18
-
19
- context 'logger responds to write' do
20
- it 'calls << when writing out the log' do
21
- message = 'message'
22
- expect(logger).to receive(:write).with(message)
23
- subject.write(message)
24
- end
25
- end
26
- end
27
- end
28
- end
29
- end
@@ -1,47 +0,0 @@
1
- require 'sitehub/path_directive'
2
- class SiteHub
3
- describe PathDirective do
4
- subject do
5
- described_class.new(%r{/match}, '/path_template')
6
- end
7
-
8
- describe '#match?' do
9
- context 'matcher applies' do
10
- it 'returns true' do
11
- expect(subject.match?('/match')).to eq(true)
12
- end
13
- end
14
-
15
- context 'matcher does not apply' do
16
- it 'returns false' do
17
- expect(subject.match?('/mismatch')).to eq(false)
18
- end
19
- end
20
- end
21
-
22
- describe '#apply' do
23
- subject do
24
- described_class.new(Regexp.new('http://www.upstream.com/orders/(.*)'), '/$1')
25
- end
26
-
27
- let(:url) { 'http://www.upstream.com/orders/123' }
28
-
29
- it 'uses the url to populate the path template' do
30
- expect(subject.apply(url)).to eq('/123')
31
- end
32
-
33
- it 'retains the query string' do
34
- expect(subject.apply("#{url}?param=value")).to eq('/123?param=value')
35
- end
36
- end
37
-
38
- describe '#path_template' do
39
- it 'returns a duplicate of the path_template every time' do
40
- version1 = subject.path_template
41
- version2 = subject.path_template
42
- expect(version1).to eq(version2)
43
- expect(version1).to_not be(version2)
44
- end
45
- end
46
- end
47
- end
@@ -1,111 +0,0 @@
1
- class SiteHub
2
- describe ReverseProxy do
3
- include_context :middleware_test
4
-
5
- let(:mapped_path) { '/orders' }
6
- let(:user_facing_app_url) { "http://example.org#{mapped_path}" }
7
-
8
- let(:downstream_mapping) { 'https://downstream.com/app1/orders' }
9
- let(:downstream_location) { "#{downstream_mapping}/123/confirmation" }
10
-
11
- let(:request_mapping) do
12
- RequestMapping.new source_url: "#{user_facing_app_url}/123/payment",
13
- mapped_url: downstream_mapping,
14
- mapped_path: mapped_path
15
- end
16
-
17
- let(:app) do
18
- proc { downstream_response }
19
- end
20
- let(:downstream_response) { Rack::Response.new('downstream', 200, 'header1' => 'header1') }
21
-
22
- subject(:reverse_proxy) { described_class.new(app, []) }
23
- let(:env) { { REQUEST_MAPPING => request_mapping } }
24
-
25
- describe '#call' do
26
- subject(:response) do
27
- status, headers, body = reverse_proxy.call(env).to_a
28
- Rack::Response.new(body, status, headers)
29
- end
30
-
31
- it 'copies the downstream body in to the response' do
32
- expect(response.body).to eq(downstream_response.body)
33
- end
34
-
35
- it 'copies the downstream headers in to the response' do
36
- expect(response.headers).to eq(downstream_response.headers)
37
- end
38
-
39
- it 'copies the downstream status in to the response' do
40
- expect(response.status).to eq(downstream_response.status)
41
- end
42
-
43
- context 'cookies' do
44
- context 'downstream response contains a cookie' do
45
- it 'rewrites it to use the upstream domain' do
46
- downstream_response.set_cookie('downstream.cookie', domain: '.downstream.com', value: 'value')
47
-
48
- expect(reverse_proxy)
49
- .to receive(:rewrite_cookies)
50
- .with(downstream_response.headers, substitute_domain: URI(request_mapping.source_url).host)
51
-
52
- reverse_proxy.call(env)
53
- end
54
- end
55
-
56
- context 'downstream response does not contain a cookie' do
57
- it 'does not attempt to rewrite the cookies' do
58
- downstream_headers = downstream_response.headers
59
- downstream_headers[HttpHeaders::LOCATION_HEADER] = downstream_location
60
- expect(reverse_proxy).not_to receive(:rewrite_cookies)
61
- reverse_proxy.call(env)
62
- end
63
- end
64
- end
65
-
66
- # Location, Content-Location and URI
67
- it 'rewrites the Location header' do
68
- downstream_response.headers[HttpHeaders::LOCATION_HEADER] = downstream_location
69
-
70
- expect(reverse_proxy)
71
- .to receive(:interpolate_location)
72
- .with(downstream_location, request_mapping.source_url)
73
- .and_return(:interpolated_location)
74
-
75
- reverse_proxy.call(env)
76
- expect(downstream_response.headers[HttpHeaders::LOCATION_HEADER]).to eq(:interpolated_location)
77
- end
78
- end
79
-
80
- describe '#interpolate_location' do
81
- it 'changes the domain' do
82
- expect(reverse_proxy.interpolate_location(downstream_location, request_mapping.source_url)).to eq('http://example.org/app1/orders/123/confirmation')
83
- end
84
-
85
- context 'there is a directive that applies' do
86
- context 'matcher is a regexp' do
87
- subject do
88
- directive = { %r{#{downstream_mapping}/(.*)/confirmation} => '/confirmation/$1' }
89
- described_class.new(inner_app, directive)
90
- end
91
- it 'changes the path' do
92
- expect(subject.interpolate_location(downstream_location, request_mapping.source_url)).to eq('http://example.org/confirmation/123')
93
- end
94
- end
95
-
96
- context 'matcher is a string' do
97
- let(:downstream_url) { 'http://downstream.com/confirmation' }
98
- subject do
99
- directive = { downstream_url => '/congratulations' }
100
- described_class.new(inner_app, directive)
101
- end
102
- it 'changes the path' do
103
- actual = subject.interpolate_location(downstream_url, request_mapping.source_url)
104
- expected = 'http://example.org/congratulations'
105
- expect(actual).to eq(expected)
106
- end
107
- end
108
- end
109
- end
110
- end
111
- end
@@ -1,28 +0,0 @@
1
- require 'sitehub/transaction_id'
2
-
3
- class SiteHub
4
- describe TransactionId do
5
- let(:transaction_id) { Constants::RackHttpHeaderKeys::TRANSACTION_ID }
6
- subject do
7
- described_class.new(proc {})
8
- end
9
- it 'adds a unique identifier to the request' do
10
- uuid = UUID.generate(:compact)
11
- expect(UUID).to receive(:generate).with(:compact).and_return(uuid)
12
- env = {}
13
- subject.call(env)
14
-
15
- expect(env[transaction_id]).to eq(uuid)
16
- end
17
-
18
- context 'transaction id header already exists' do
19
- it 'leaves it intact' do
20
- expect(UUID).to_not receive(:generate)
21
- env = { transaction_id => :exiting_id }
22
- subject.call(env)
23
-
24
- expect(env[transaction_id]).to eq(:exiting_id)
25
- end
26
- end
27
- end
28
- end
@@ -1,16 +0,0 @@
1
- module Async
2
- class ResponseHandler < EM::DefaultDeferrable
3
- attr_reader :last_response, :callback_args
4
-
5
- alias arg callback_args
6
-
7
- def succeed(arg)
8
- sitehub_response = arg[:downstream_response]
9
- instance_variable_set(:@arg, arg)
10
- status, headers, body = *sitehub_response.to_a
11
- rack_response = Rack::Response.new(body, status, headers)
12
- instance_variable_set(:@last_response, rack_response)
13
- EM.stop
14
- end
15
- end
16
- end
@@ -1,14 +0,0 @@
1
- require_relative '../async'
2
- shared_context :async do
3
- def callback
4
- @callback ||= Async::Callback.new
5
- end
6
-
7
- def async_response_handler
8
- @async_response_handler = Async::ResponseHandler.new
9
- end
10
-
11
- def last_response
12
- app.last_response
13
- end
14
- end