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 +5 -5
- data/lib/resurfaceio/all.rb +13 -1
- data/lib/resurfaceio/base_logger.rb +33 -7
- data/lib/resurfaceio/http_logger.rb +93 -76
- data/lib/resurfaceio/http_logger_for_rack.rb +3 -3
- data/lib/resurfaceio/http_logger_for_rails.rb +9 -7
- data/lib/resurfaceio/http_message.rb +89 -0
- data/lib/resurfaceio/http_request_impl.rb +6 -1
- data/lib/resurfaceio/http_response_impl.rb +1 -1
- data/lib/resurfaceio/http_rule.rb +15 -0
- data/lib/resurfaceio/http_rules.rb +130 -0
- data/lib/resurfaceio/usage_loggers.rb +4 -4
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '081b638ef0c63585d851de54a9b30ef9b54de58cf68f880785c2e1a8d214cb54'
|
4
|
+
data.tar.gz: a71c49ec92a27637f7d77b52177df39d0b197757a056154e5247f5e40aa350d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2f2c6be12c8977756ab185cc34c64cc29b0956940139315a1d9c023f4df0756cbea1c3fdb8eaab9207070ddda63ee1dac34688d8272d1782d5664b531de94a3
|
7
|
+
data.tar.gz: 8eed5ac226184687025edf8d3f213585b73d1577c8c6a5420f71b4bc5205add88470672e350746edef7e2a48bf3441276517fcb7ec176bdb16f88b21f9059c7a
|
data/lib/resurfaceio/all.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
# © 2016-
|
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-
|
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
|
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(
|
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 <<
|
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 =
|
116
|
+
request.body = msg
|
101
117
|
else
|
102
118
|
request.add_field('Content-Encoding', 'deflated')
|
103
|
-
request.body = Zlib::Deflate.deflate(
|
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-
|
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
|
-
|
12
|
-
super(AGENT, options)
|
13
|
-
end
|
14
|
+
@@default_rules = HttpRules.strict_rules
|
14
15
|
|
15
|
-
def
|
16
|
-
|
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
|
33
|
-
|
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
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
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-
|
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.
|
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-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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-
|
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
|
|
@@ -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-
|
2
|
+
# © 2016-2019 Resurface Labs Inc.
|
3
3
|
|
4
4
|
class UsageLoggers
|
5
5
|
|
6
|
-
@@
|
6
|
+
@@BRICKED = 'true'.eql?(ENV['USAGE_LOGGERS_DISABLE'])
|
7
7
|
|
8
|
-
@@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 @@
|
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.
|
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:
|
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.
|
106
|
+
rubygems_version: 2.7.7
|
104
107
|
signing_key:
|
105
108
|
specification_version: 4
|
106
109
|
summary: Library for usage logging
|