resurfaceio-logger 1.8.3 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6325802c6b0b9f45a243d514552865acafe0cf8a
4
- data.tar.gz: 549e12382335f21c169d8657313cf2f60c241bda
2
+ SHA256:
3
+ metadata.gz: '081b638ef0c63585d851de54a9b30ef9b54de58cf68f880785c2e1a8d214cb54'
4
+ data.tar.gz: a71c49ec92a27637f7d77b52177df39d0b197757a056154e5247f5e40aa350d1
5
5
  SHA512:
6
- metadata.gz: 99ec978f7215220b3d35ac7148aa436ddf1e4981983f884836338760a5e6cf6b55b16fd27f6b930bf16b1a85b8b801e3d05a425ec07c0dfb9804a81765726502
7
- data.tar.gz: 1b126b84b901f850adf3e701a5d97242305f33b844fb72de1c5c2ffcaf04a5006bba7a9a0ff48825884767e55d5b71fd674f2dc9aed8cf2cc9221ef9dc41e9af
6
+ metadata.gz: f2f2c6be12c8977756ab185cc34c64cc29b0956940139315a1d9c023f4df0756cbea1c3fdb8eaab9207070ddda63ee1dac34688d8272d1782d5664b531de94a3
7
+ data.tar.gz: 8eed5ac226184687025edf8d3f213585b73d1577c8c6a5420f71b4bc5205add88470672e350746edef7e2a48bf3441276517fcb7ec176bdb16f88b21f9059c7a
@@ -1,12 +1,15 @@
1
1
  # coding: utf-8
2
- # © 2016-2017 Resurface Labs LLC
2
+ # © 2016-2019 Resurface Labs Inc.
3
3
 
4
4
  require 'resurfaceio/base_logger'
5
5
  require 'resurfaceio/http_logger'
6
6
  require 'resurfaceio/http_logger_for_rack'
7
7
  require 'resurfaceio/http_logger_for_rails'
8
+ require 'resurfaceio/http_message'
8
9
  require 'resurfaceio/http_request_impl'
9
10
  require 'resurfaceio/http_response_impl'
11
+ require 'resurfaceio/http_rule'
12
+ require 'resurfaceio/http_rules'
10
13
  require 'resurfaceio/usage_loggers'
11
14
 
12
15
  module Resurfaceio
@@ -23,12 +26,21 @@ module Resurfaceio
23
26
  class HttpLoggerForRails < HttpLoggerForRails
24
27
  end
25
28
 
29
+ class HttpMessage < HttpMessage
30
+ end
31
+
26
32
  class HttpRequestImpl < HttpRequestImpl
27
33
  end
28
34
 
29
35
  class HttpResponseImpl < HttpResponseImpl
30
36
  end
31
37
 
38
+ class HttpRule < HttpRule
39
+ end
40
+
41
+ class HttpRules < HttpRules
42
+ end
43
+
32
44
  class UsageLoggers < UsageLoggers
33
45
  end
34
46
 
@@ -1,9 +1,10 @@
1
1
  # coding: utf-8
2
- # © 2016-2017 Resurface Labs LLC
2
+ # © 2016-2019 Resurface Labs Inc.
3
3
 
4
4
  require 'uri'
5
5
  require 'net/http'
6
6
  require 'net/https'
7
+ require 'socket'
7
8
  require 'zlib'
8
9
  require 'resurfaceio/usage_loggers'
9
10
 
@@ -11,6 +12,7 @@ class BaseLogger
11
12
 
12
13
  def initialize(agent, options = {})
13
14
  @agent = agent
15
+ @host = BaseLogger.host_lookup
14
16
  @skip_compression = false
15
17
  @skip_submission = false
16
18
  @version = BaseLogger.version_lookup
@@ -48,6 +50,8 @@ class BaseLogger
48
50
  @enabled = false
49
51
  end
50
52
  end
53
+
54
+ @enableable = !@queue.nil? || !@url.nil?
51
55
  end
52
56
 
53
57
  def agent
@@ -60,14 +64,26 @@ class BaseLogger
60
64
  end
61
65
 
62
66
  def enable
63
- @enabled = true unless @queue.nil? && @url.nil?
67
+ @enabled = true if @enableable
64
68
  self
65
69
  end
66
70
 
71
+ def enableable?
72
+ @enableable
73
+ end
74
+
67
75
  def enabled?
68
76
  @enabled && UsageLoggers.enabled?
69
77
  end
70
78
 
79
+ def host
80
+ @host
81
+ end
82
+
83
+ def queue
84
+ @queue
85
+ end
86
+
71
87
  def skip_compression?
72
88
  @skip_compression
73
89
  end
@@ -84,11 +100,11 @@ class BaseLogger
84
100
  @skip_submission = value
85
101
  end
86
102
 
87
- def submit(json)
88
- if @skip_submission || !enabled?
103
+ def submit(msg)
104
+ if msg.nil? || @skip_submission || !enabled?
89
105
  true
90
106
  elsif @queue
91
- @queue << json
107
+ @queue << msg
92
108
  true
93
109
  else
94
110
  begin
@@ -97,10 +113,10 @@ class BaseLogger
97
113
  @url_connection.use_ssl = @url.include?('https')
98
114
  request = Net::HTTP::Post.new(@url_parsed.path)
99
115
  if @skip_compression
100
- request.body = json
116
+ request.body = msg
101
117
  else
102
118
  request.add_field('Content-Encoding', 'deflated')
103
- request.body = Zlib::Deflate.deflate(json)
119
+ request.body = Zlib::Deflate.deflate(msg)
104
120
  end
105
121
  response = @url_connection.request(request)
106
122
  response.code.to_i == 204
@@ -119,6 +135,16 @@ class BaseLogger
119
135
  @version
120
136
  end
121
137
 
138
+ def self.host_lookup
139
+ dyno = ENV['DYNO']
140
+ return dyno unless dyno.nil?
141
+ begin
142
+ Socket.gethostname
143
+ rescue
144
+ 'unknown'
145
+ end
146
+ end
147
+
122
148
  def self.version_lookup
123
149
  Gem.loaded_specs['resurfaceio-logger'].version.to_s
124
150
  end
@@ -1,107 +1,124 @@
1
1
  # coding: utf-8
2
- # © 2016-2017 Resurface Labs LLC
2
+ # © 2016-2019 Resurface Labs Inc.
3
3
 
4
4
  require 'json'
5
5
  require 'resurfaceio/base_logger'
6
+ require 'resurfaceio/http_message'
7
+ require 'resurfaceio/http_rule'
8
+ require 'resurfaceio/http_rules'
6
9
 
7
10
  class HttpLogger < BaseLogger
8
11
 
9
12
  AGENT = 'http_logger.rb'.freeze
10
13
 
11
- def initialize(options={})
12
- super(AGENT, options)
13
- end
14
+ @@default_rules = HttpRules.strict_rules
14
15
 
15
- def format(request, response, response_body=nil, request_body=nil, now=nil)
16
- message = []
17
- append_value message, 'request_method', request.request_method
18
- append_value message, 'request_url', request.url
19
- append_value message, 'response_code', response.status
20
- append_request_headers message, request
21
- append_request_params message, request
22
- append_response_headers message, response
23
- append_value message, 'request_body', request_body unless request_body == ''
24
- final_response_body = response_body.nil? ? response.body : response_body
25
- append_value message, 'response_body', final_response_body unless final_response_body == ''
26
- message << ['agent', @agent]
27
- message << ['version', @version]
28
- message << ['now', now.nil? ? (Time.now.to_f * 1000).floor.to_s : now]
29
- JSON.generate message
16
+ def self.default_rules
17
+ @@default_rules
30
18
  end
31
19
 
32
- def log(request, response, response_body=nil, request_body=nil)
33
- !enabled? || submit(format(request, response, response_body, request_body))
20
+ def self.default_rules=(val)
21
+ @@default_rules = val.gsub(/^\s*include default\s*$/, '')
34
22
  end
35
23
 
36
24
  def self.string_content_type?(s)
37
25
  !s.nil? && !(s =~ /^(text\/(html|plain|xml))|(application\/(json|soap|xml|x-www-form-urlencoded))/i).nil?
38
26
  end
39
27
 
40
- protected
41
-
42
- def append_request_headers(message, request)
43
- respond_to_env = request.respond_to?(:env)
44
- if respond_to_env || request.respond_to?(:headers)
45
- headers = respond_to_env ? request.env : request.headers
46
- headers.each do |name, value|
47
- unless value.nil?
48
- if name =~ /^CONTENT_TYPE/
49
- message << ['request_header:content-type', value]
50
- end
51
- if name =~ /^HTTP_/
52
- message << ["request_header:#{name[5..-1].downcase.tr('_', '-')}", value]
53
- end
54
- end
55
- end unless headers.nil?
56
- end
57
- end
28
+ def initialize(options = {})
29
+ super(AGENT, options)
58
30
 
59
- def append_request_params(message, request)
60
- respond_to_env = request.respond_to?(:env)
61
- if respond_to_env || request.respond_to?(:form_hash)
62
- hash = respond_to_env ? request.env['rack.request.form_hash'] : request.form_hash
63
- hash.each do |name, value|
64
- append_value message, "request_param:#{name.downcase}", value
65
- end unless hash.nil?
31
+ # read rules from param or defaults
32
+ if options.respond_to?(:has_key?) && options.has_key?(:rules)
33
+ @rules = options[:rules].gsub(/^\s*include default\s*$/, @@default_rules)
34
+ @rules = @@default_rules unless @rules.strip.length > 0
35
+ else
36
+ @rules = @@default_rules
66
37
  end
67
- if respond_to_env || request.respond_to?(:query_hash)
68
- hash = respond_to_env ? request.env['rack.request.query_hash'] : request.query_hash
69
- hash.each do |name, value|
70
- append_value message, "request_param:#{name.downcase}", value
71
- end unless hash.nil?
38
+
39
+ # parse and break rules out by verb
40
+ prs = HttpRules.parse(@rules)
41
+ @rules_allow_http_url = prs.select {|r| 'allow_http_url' == r.verb}.length > 0
42
+ @rules_copy_session_field = prs.select {|r| 'copy_session_field' == r.verb}
43
+ @rules_remove = prs.select {|r| 'remove' == r.verb}
44
+ @rules_remove_if = prs.select {|r| 'remove_if' == r.verb}
45
+ @rules_remove_if_found = prs.select {|r| 'remove_if_found' == r.verb}
46
+ @rules_remove_unless = prs.select {|r| 'remove_unless' == r.verb}
47
+ @rules_remove_unless_found = prs.select {|r| 'remove_unless_found' == r.verb}
48
+ @rules_replace = prs.select {|r| 'replace' == r.verb}
49
+ @rules_sample = prs.select {|r| 'sample' == r.verb}
50
+ @rules_stop = prs.select {|r| 'stop' == r.verb}
51
+ @rules_stop_if = prs.select {|r| 'stop_if' == r.verb}
52
+ @rules_stop_if_found = prs.select {|r| 'stop_if_found' == r.verb}
53
+ @rules_stop_unless = prs.select {|r| 'stop_unless' == r.verb}
54
+ @rules_stop_unless_found = prs.select {|r| 'stop_unless_found' == r.verb}
55
+ @skip_compression = prs.select {|r| 'skip_compression' == r.verb}.length > 0
56
+ @skip_submission = prs.select {|r| 'skip_submission' == r.verb}.length > 0
57
+
58
+ # finish validating rules
59
+ raise RuntimeError.new('Multiple sample rules') if @rules_sample.length > 1
60
+ unless @url.nil? || @url.start_with?('https') || @rules_allow_http_url
61
+ @enableable = false
62
+ @enabled = false
72
63
  end
73
64
  end
74
65
 
75
- def append_response_headers(message, response)
76
- found_content_type = false
77
- if response.respond_to?(:headers)
78
- response.headers.each do |name, value|
79
- unless value.nil?
80
- name = name.downcase
81
- found_content_type = true if name =~ /^content-type/
82
- message << ["response_header:#{name}", value]
83
- end
84
- end unless response.headers.nil?
85
- end
86
- unless found_content_type || response.content_type.nil?
87
- message << ['response_header:content-type', response.content_type]
88
- end
66
+ def rules
67
+ @rules
68
+ end
69
+
70
+ def log(request, response, response_body = nil, request_body = nil)
71
+ !enabled? || submit(format(request, response, response_body, request_body))
89
72
  end
90
73
 
91
- def append_value(message, key, value=nil)
92
- unless key.nil?
93
- unless value.nil?
94
- case value
95
- when Array
96
- message << [key, value.join]
97
- when String
98
- message << [key, value]
99
- else
100
- message << [key, value.to_s]
74
+ def format(request, response, response_body = nil, request_body = nil, now = nil)
75
+ details = HttpMessage.build(request, response, response_body, request_body)
76
+
77
+ # copy data from session if configured
78
+ unless @rules_copy_session_field.empty?
79
+ ssn = request.session
80
+ if !ssn.nil? && ssn.respond_to?(:keys)
81
+ @rules_copy_session_field.each do |r|
82
+ ssn.keys.each {|d| (details << ["session_field:#{d}", ssn[d].to_s]) if r.param1.match(d)}
101
83
  end
102
84
  end
103
85
  end
104
- message
86
+
87
+ # quit early based on stop rules if configured
88
+ @rules_stop.each {|r| details.each {|d| return nil if r.scope.match(d[0])}}
89
+ @rules_stop_if_found.each {|r| details.each {|d| return nil if r.scope.match(d[0]) && r.param1.match(d[1])}}
90
+ @rules_stop_if.each {|r| details.each {|d| return nil if r.scope.match(d[0]) && r.param1.match(d[1])}}
91
+ passed = 0
92
+ @rules_stop_unless_found.each {|r| details.each {|d| passed += 1 if r.scope.match(d[0]) && r.param1.match(d[1])}}
93
+ return nil if passed != @rules_stop_unless_found.length
94
+ passed = 0
95
+ @rules_stop_unless.each {|r| details.each {|d| passed += 1 if r.scope.match(d[0]) && r.param1.match(d[1])}}
96
+ return nil if passed != @rules_stop_unless.length
97
+
98
+ # do sampling if configured
99
+ return nil if !@rules_sample[0].nil? && (rand * 100 >= @rules_sample[0].param1)
100
+
101
+ # winnow sensitive details based on remove rules if configured
102
+ @rules_remove.each {|r| details.delete_if {|d| r.scope.match(d[0])}}
103
+ @rules_remove_unless_found.each {|r| details.delete_if {|d| r.scope.match(d[0]) && !r.param1.match(d[1])}}
104
+ @rules_remove_if_found.each {|r| details.delete_if {|d| r.scope.match(d[0]) && r.param1.match(d[1])}}
105
+ @rules_remove_unless.each {|r| details.delete_if {|d| r.scope.match(d[0]) && !r.param1.match(d[1])}}
106
+ @rules_remove_if.each {|r| details.delete_if {|d| r.scope.match(d[0]) && r.param1.match(d[1])}}
107
+ return nil if details.empty?
108
+
109
+ # mask sensitive details based on replace rules if configured
110
+ @rules_replace.each {|r| details.each {|d| d[1] = d[1].gsub(r.param1, r.param2) if r.scope.match(d[0])}}
111
+
112
+ # remove any details with empty values
113
+ details.delete_if {|d| '' == d[1]}
114
+ return nil if details.empty?
115
+
116
+ # finish message
117
+ details << ['now', now.nil? ? (Time.now.to_f * 1000).floor.to_s : now]
118
+ details << ['agent', @agent]
119
+ details << ['host', @host]
120
+ details << ['version', @version]
121
+ JSON.generate details
105
122
  end
106
123
 
107
124
  end
@@ -1,12 +1,12 @@
1
1
  # coding: utf-8
2
- # © 2016-2017 Resurface Labs LLC
2
+ # © 2016-2019 Resurface Labs Inc.
3
3
 
4
4
  require 'rack'
5
5
  require 'resurfaceio/http_logger'
6
6
 
7
7
  class HttpLoggerForRack # http://rack.rubyforge.org/doc/SPEC.html
8
8
 
9
- def initialize(app, options={})
9
+ def initialize(app, options = {})
10
10
  @app = app
11
11
  @logger = HttpLogger.new(options)
12
12
  end
@@ -21,7 +21,7 @@ class HttpLoggerForRack # http://rack.rubyforge.org/doc/SPEC.html
21
21
  response = Rack::Response.new(body, status, headers)
22
22
  if HttpLogger::string_content_type?(response.content_type)
23
23
  request = Rack::Request.new(env)
24
- @logger.log(request, response)
24
+ @logger.submit(@logger.format(request, response))
25
25
  end
26
26
  end
27
27
  [status, headers, body]
@@ -1,11 +1,11 @@
1
1
  # coding: utf-8
2
- # © 2016-2017 Resurface Labs LLC
2
+ # © 2016-2019 Resurface Labs Inc.
3
3
 
4
4
  require 'resurfaceio/http_logger'
5
5
 
6
6
  class HttpLoggerForRails
7
7
 
8
- def initialize(options={})
8
+ def initialize(options = {})
9
9
  @logger = HttpLogger.new(options)
10
10
  end
11
11
 
@@ -15,11 +15,13 @@ class HttpLoggerForRails
15
15
 
16
16
  def around(controller)
17
17
  yield
18
- request = controller.request
19
- response = controller.response
20
- status = response.status
21
- if (status < 300 || status == 302) && HttpLogger::string_content_type?(response.content_type)
22
- @logger.log(request, response)
18
+ if @logger.enabled?
19
+ request = controller.request
20
+ response = controller.response
21
+ status = response.status
22
+ if (status < 300 || status == 302) && HttpLogger::string_content_type?(response.content_type)
23
+ @logger.submit(@logger.format(request, response))
24
+ end
23
25
  end
24
26
  end
25
27
 
@@ -0,0 +1,89 @@
1
+ # coding: utf-8
2
+ # © 2016-2019 Resurface Labs Inc.
3
+
4
+ require 'json'
5
+
6
+ class HttpMessage
7
+
8
+ def self.build(request, response, response_body = nil, request_body = nil)
9
+ message = []
10
+ append_value message, 'request_method', request.request_method unless request.request_method.nil?
11
+ append_value message, 'request_url', request.url unless request.url.nil?
12
+ append_value message, 'response_code', response.status unless response.status.nil?
13
+ append_request_headers message, request
14
+ append_request_params message, request
15
+ append_response_headers message, response
16
+ append_value message, 'request_body', request_body unless request_body == ''
17
+ final_response_body = response_body.nil? ? response.body : response_body
18
+ append_value message, 'response_body', final_response_body unless final_response_body == ''
19
+ return message
20
+ end
21
+
22
+ protected
23
+
24
+ def self.append_request_headers(message, request)
25
+ respond_to_env = request.respond_to?(:env)
26
+ if respond_to_env || request.respond_to?(:headers)
27
+ headers = respond_to_env ? request.env : request.headers
28
+ headers.each do |name, value|
29
+ unless value.nil?
30
+ if name =~ /^CONTENT_TYPE/
31
+ message << ['request_header:content-type', value]
32
+ end
33
+ if name =~ /^HTTP_/
34
+ message << ["request_header:#{name[5..-1].downcase.tr('_', '-')}", value]
35
+ end
36
+ end
37
+ end unless headers.nil?
38
+ end
39
+ end
40
+
41
+ def self.append_request_params(message, request)
42
+ respond_to_env = request.respond_to?(:env)
43
+ if respond_to_env || request.respond_to?(:form_hash)
44
+ hash = respond_to_env ? request.env['rack.request.form_hash'] : request.form_hash
45
+ hash.each do |name, value|
46
+ append_value message, "request_param:#{name.downcase}", value
47
+ end unless hash.nil?
48
+ end
49
+ if respond_to_env || request.respond_to?(:query_hash)
50
+ hash = respond_to_env ? request.env['rack.request.query_hash'] : request.query_hash
51
+ hash.each do |name, value|
52
+ append_value message, "request_param:#{name.downcase}", value
53
+ end unless hash.nil?
54
+ end
55
+ end
56
+
57
+ def self.append_response_headers(message, response)
58
+ found_content_type = false
59
+ if response.respond_to?(:headers)
60
+ response.headers.each do |name, value|
61
+ unless value.nil?
62
+ name = name.downcase
63
+ found_content_type = true if name =~ /^content-type/
64
+ message << ["response_header:#{name}", value]
65
+ end
66
+ end unless response.headers.nil?
67
+ end
68
+ unless found_content_type || response.content_type.nil?
69
+ message << ['response_header:content-type', response.content_type]
70
+ end
71
+ end
72
+
73
+ def self.append_value(message, key, value = nil)
74
+ unless key.nil?
75
+ unless value.nil?
76
+ case value
77
+ when Array
78
+ message << [key, value.join]
79
+ when String
80
+ message << [key, value]
81
+ else
82
+ message << [key, value.to_s]
83
+ end
84
+ end
85
+ end
86
+ message
87
+ end
88
+
89
+ end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2017 Resurface Labs LLC
2
+ # © 2016-2019 Resurface Labs Inc.
3
3
 
4
4
  class HttpRequestImpl
5
5
 
@@ -7,6 +7,7 @@ class HttpRequestImpl
7
7
  @form_hash = Hash.new
8
8
  @headers = Hash.new
9
9
  @query_hash = Hash.new
10
+ @session = Hash.new
10
11
  end
11
12
 
12
13
  def add_header(key, value)
@@ -40,6 +41,10 @@ class HttpRequestImpl
40
41
  @query_hash
41
42
  end
42
43
 
44
+ def session
45
+ @session
46
+ end
47
+
43
48
  attr_accessor :request_method
44
49
  attr_accessor :url
45
50
 
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
- # © 2016-2017 Resurface Labs LLC
2
+ # © 2016-2019 Resurface Labs Inc.
3
3
 
4
4
  class HttpResponseImpl
5
5
 
@@ -0,0 +1,15 @@
1
+ # coding: utf-8
2
+ # © 2016-2019 Resurface Labs Inc.
3
+
4
+ class HttpRule
5
+
6
+ def initialize(verb, scope = nil, param1 = nil, param2 = nil)
7
+ @verb = verb
8
+ @scope = scope
9
+ @param1 = param1
10
+ @param2 = param2
11
+ end
12
+
13
+ attr_reader :verb, :scope, :param1, :param2
14
+
15
+ end
@@ -0,0 +1,130 @@
1
+ # coding: utf-8
2
+ # © 2016-2019 Resurface Labs Inc.
3
+
4
+ class HttpRules
5
+
6
+ def self.debug_rules
7
+ "allow_http_url\ncopy_session_field /.*/\n"
8
+ end
9
+
10
+ def self.standard_rules
11
+ %q(/request_header:cookie|response_header:set-cookie/ remove
12
+ /(request|response)_body|request_param/ replace /[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)/, /x@y.com/
13
+ /request_body|request_param|response_body/ replace /[0-9\.\-\/]{9,}/, /xyxy/
14
+ )
15
+ end
16
+
17
+ def self.strict_rules
18
+ %q(/request_url/ replace /([^\?;]+).*/, !\\\\1!
19
+ /request_body|response_body|request_param:.*|request_header:(?!user-agent).*|response_header:(?!(content-length)|(content-type)).*/ remove
20
+ )
21
+ end
22
+
23
+ def self.parse(rules)
24
+ result = []
25
+ unless rules.nil?
26
+ rules = rules.gsub(/^\s*include debug\s*$/, debug_rules)
27
+ rules = rules.gsub(/^\s*include standard\s*$/, standard_rules)
28
+ rules = rules.gsub(/^\s*include strict\s*$/, strict_rules)
29
+ rules.each_line do |rule|
30
+ parsed = parse_rule(rule)
31
+ result << parsed unless parsed.nil?
32
+ end
33
+ end
34
+ result
35
+ end
36
+
37
+ def self.parse_rule(r)
38
+ if r.nil? || r.match(REGEX_BLANK_OR_COMMENT)
39
+ nil
40
+ elsif r.match(REGEX_ALLOW_HTTP_URL)
41
+ HttpRule.new('allow_http_url')
42
+ elsif (m = r.match(REGEX_COPY_SESSION_FIELD))
43
+ HttpRule.new('copy_session_field', nil, parse_regex(r, m[1]))
44
+ elsif (m = r.match(REGEX_REMOVE))
45
+ HttpRule.new('remove', parse_regex(r, m[1]))
46
+ elsif (m = r.match(REGEX_REMOVE_IF))
47
+ HttpRule.new('remove_if', parse_regex(r, m[1]), parse_regex(r, m[2]))
48
+ elsif (m = r.match(REGEX_REMOVE_IF_FOUND))
49
+ HttpRule.new('remove_if_found', parse_regex(r, m[1]), parse_regex_find(r, m[2]))
50
+ elsif (m = r.match(REGEX_REMOVE_UNLESS))
51
+ HttpRule.new('remove_unless', parse_regex(r, m[1]), parse_regex(r, m[2]))
52
+ elsif (m = r.match(REGEX_REMOVE_UNLESS_FOUND))
53
+ HttpRule.new('remove_unless_found', parse_regex(r, m[1]), parse_regex_find(r, m[2]))
54
+ elsif (m = r.match(REGEX_REPLACE))
55
+ HttpRule.new('replace', parse_regex(r, m[1]), parse_regex_find(r, m[2]), parse_string(r, m[3]))
56
+ elsif (m = r.match(REGEX_SAMPLE))
57
+ m1 = m[1].to_i
58
+ raise RuntimeError.new("Invalid sample percent: #{m1}") if m1 < 1 || m1 > 99
59
+ HttpRule.new('sample', nil, m1)
60
+ elsif r.match(REGEX_SKIP_COMPRESSION)
61
+ HttpRule.new('skip_compression')
62
+ elsif r.match(REGEX_SKIP_SUBMISSION)
63
+ HttpRule.new('skip_submission')
64
+ elsif (m = r.match(REGEX_STOP))
65
+ HttpRule.new('stop', parse_regex(r, m[1]))
66
+ elsif (m = r.match(REGEX_STOP_IF))
67
+ HttpRule.new('stop_if', parse_regex(r, m[1]), parse_regex(r, m[2]))
68
+ elsif (m = r.match(REGEX_STOP_IF_FOUND))
69
+ HttpRule.new('stop_if_found', parse_regex(r, m[1]), parse_regex_find(r, m[2]))
70
+ elsif (m = r.match(REGEX_STOP_UNLESS))
71
+ HttpRule.new('stop_unless', parse_regex(r, m[1]), parse_regex(r, m[2]))
72
+ elsif (m = r.match(REGEX_STOP_UNLESS_FOUND))
73
+ HttpRule.new('stop_unless_found', parse_regex(r, m[1]), parse_regex_find(r, m[2]))
74
+ else
75
+ raise RuntimeError.new("Invalid rule: #{r}")
76
+ end
77
+ end
78
+
79
+ protected
80
+
81
+ def self.parse_regex(r, regex)
82
+ s = parse_string(r, regex)
83
+ raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}") if '*' == s || '+' == s || '?' == s
84
+ s = "^#{s}" unless s.start_with?('^')
85
+ s = "#{s}$" unless s.end_with?('$')
86
+ begin
87
+ return Regexp.compile(s)
88
+ rescue RegexpError
89
+ raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}")
90
+ end
91
+ end
92
+
93
+ def self.parse_regex_find(r, regex)
94
+ begin
95
+ return Regexp.compile(parse_string(r, regex))
96
+ rescue RegexpError
97
+ raise RuntimeError.new("Invalid regex (#{regex}) in rule: #{r}")
98
+ end
99
+ end
100
+
101
+ def self.parse_string(r, expr)
102
+ %w(~ ! % | /).each do |sep|
103
+ if (m = expr.match(/^[#{sep}](.*)[#{sep}]$/))
104
+ m1 = m[1]
105
+ raise RuntimeError.new("Unescaped separator (#{sep}) in rule: #{r}") if m1.match(/^[#{sep}].*|.*[^\\][#{sep}].*/)
106
+ return m1.gsub("\\#{sep}", sep)
107
+ end
108
+ end
109
+ raise RuntimeError.new("Invalid expression (#{expr}) in rule: #{r}")
110
+ end
111
+
112
+ REGEX_ALLOW_HTTP_URL = /^\s*allow_http_url\s*(#.*)?$/.freeze
113
+ REGEX_BLANK_OR_COMMENT = /^\s*([#].*)*$/.freeze
114
+ REGEX_COPY_SESSION_FIELD = /^\s*copy_session_field\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
115
+ REGEX_REMOVE = /^\s*([~!%|\/].+[~!%|\/])\s*remove\s*(#.*)?$/.freeze
116
+ REGEX_REMOVE_IF = /^\s*([~!%|\/].+[~!%|\/])\s*remove_if\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
117
+ REGEX_REMOVE_IF_FOUND = /^\s*([~!%|\/].+[~!%|\/])\s*remove_if_found\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
118
+ REGEX_REMOVE_UNLESS = /^\s*([~!%|\/].+[~!%|\/])\s*remove_unless\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
119
+ REGEX_REMOVE_UNLESS_FOUND = /^\s*([~!%|\/].+[~!%|\/])\s*remove_unless_found\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
120
+ REGEX_REPLACE = /^\s*([~!%|\/].+[~!%|\/])\s*replace[\s]+([~!%|\/].+[~!%|\/]),[\s]+([~!%|\/].*[~!%|\/])\s*(#.*)?$/.freeze
121
+ REGEX_SAMPLE = /^\s*sample\s+(\d+)\s*(#.*)?$/.freeze
122
+ REGEX_SKIP_COMPRESSION = /^\s*skip_compression\s*(#.*)?$/.freeze
123
+ REGEX_SKIP_SUBMISSION = /^\s*skip_submission\s*(#.*)?$/.freeze
124
+ REGEX_STOP = /^\s*([~!%|\/].+[~!%|\/])\s*stop\s*(#.*)?$/.freeze
125
+ REGEX_STOP_IF = /^\s*([~!%|\/].+[~!%|\/])\s*stop_if\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
126
+ REGEX_STOP_IF_FOUND = /^\s*([~!%|\/].+[~!%|\/])\s*stop_if_found\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
127
+ REGEX_STOP_UNLESS = /^\s*([~!%|\/].+[~!%|\/])\s*stop_unless\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
128
+ REGEX_STOP_UNLESS_FOUND = /^\s*([~!%|\/].+[~!%|\/])\s*stop_unless_found\s+([~!%|\/].+[~!%|\/])\s*(#.*)?$/.freeze
129
+
130
+ end
@@ -1,18 +1,18 @@
1
1
  # coding: utf-8
2
- # © 2016-2017 Resurface Labs LLC
2
+ # © 2016-2019 Resurface Labs Inc.
3
3
 
4
4
  class UsageLoggers
5
5
 
6
- @@DISABLED = 'true'.eql?(ENV['USAGE_LOGGERS_DISABLE'])
6
+ @@BRICKED = 'true'.eql?(ENV['USAGE_LOGGERS_DISABLE'])
7
7
 
8
- @@disabled = @@DISABLED
8
+ @@disabled = @@BRICKED
9
9
 
10
10
  def self.disable
11
11
  @@disabled = true
12
12
  end
13
13
 
14
14
  def self.enable
15
- @@disabled = false unless @@DISABLED
15
+ @@disabled = false unless @@BRICKED
16
16
  end
17
17
 
18
18
  def self.enabled?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resurfaceio-logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.3
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - RobDickinson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-11 00:00:00.000000000 Z
11
+ date: 2019-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -77,8 +77,11 @@ files:
77
77
  - lib/resurfaceio/http_logger.rb
78
78
  - lib/resurfaceio/http_logger_for_rack.rb
79
79
  - lib/resurfaceio/http_logger_for_rails.rb
80
+ - lib/resurfaceio/http_message.rb
80
81
  - lib/resurfaceio/http_request_impl.rb
81
82
  - lib/resurfaceio/http_response_impl.rb
83
+ - lib/resurfaceio/http_rule.rb
84
+ - lib/resurfaceio/http_rules.rb
82
85
  - lib/resurfaceio/usage_loggers.rb
83
86
  homepage: https://github.com/resurfaceio/logger-ruby
84
87
  licenses:
@@ -100,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
103
  version: '0'
101
104
  requirements: []
102
105
  rubyforge_project:
103
- rubygems_version: 2.5.2
106
+ rubygems_version: 2.7.7
104
107
  signing_key:
105
108
  specification_version: 4
106
109
  summary: Library for usage logging