rails-profiler 0.34.4 → 0.34.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/profiler/middleware/profiler_middleware.rb +11 -1
- data/lib/profiler/models/profile.rb +46 -4
- data/lib/profiler/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b498ec1274af5787fe96b70e64613b009298b578a7b084d65d450ec86a431bc
|
|
4
|
+
data.tar.gz: b575d9afef090eee5539cfca2ffd536887d90b4c08a3b5099504a8e31ca69eab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7da413fad8fd79420dddc04242b1ce30c05aac1106073219b7c0dcda26dada8c59a1b8e0d6a6c3c403d92ee6cd519271285d5f99fe6670b0e970179f79be119
|
|
7
|
+
data.tar.gz: d36516568229d7fa228dad51b70a30e8ca2753cc07fa114279f322200d32bd9a4f5e02891ff0ea96b0c904dc1594d528f677129b840fe0acadd2f106f29ea9cc
|
data/CHANGELOG.md
CHANGED
|
@@ -19,6 +19,22 @@ every commit of every tag interval is accounted for one way or the other.
|
|
|
19
19
|
|
|
20
20
|
## [Unreleased]
|
|
21
21
|
|
|
22
|
+
## [0.34.5] - 2026-10-16
|
|
23
|
+
|
|
24
|
+
<!-- stamped -->
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **Request capture:** the parameters of a request are now read once the application has returned, so
|
|
29
|
+
route parameters are present and `param_encoding` is applied, and they are converted to UTF-8. They
|
|
30
|
+
used to be read in the outermost middleware, before the router ran.
|
|
31
|
+
- **Request capture:** a text body keeps its accents. It is now read in the `charset` of its
|
|
32
|
+
`Content-Type`, UTF-8 when it declares none, and invalid bytes are replaced, instead of every
|
|
33
|
+
accent being turned into a replacement character.
|
|
34
|
+
- **Request capture:** a request whose `Content-Type` declares a charset Ruby cannot convert from
|
|
35
|
+
(`charset=utf-7`, `charset=internal`) no longer loses its profile; the body is read as UTF-8 with
|
|
36
|
+
invalid bytes replaced.
|
|
37
|
+
|
|
22
38
|
## [0.34.4] - 2026-10-16
|
|
23
39
|
|
|
24
40
|
<!-- stamped -->
|
|
@@ -28,7 +28,7 @@ module Profiler
|
|
|
28
28
|
kept = nil
|
|
29
29
|
begin
|
|
30
30
|
begin
|
|
31
|
-
profile = Models::Profile.new(build_request(env))
|
|
31
|
+
profile = Models::Profile.new(build_request(env), params: false)
|
|
32
32
|
profile.gem_version = Profiler::VERSION
|
|
33
33
|
Profiler::CurrentContext.token = profile.token
|
|
34
34
|
|
|
@@ -57,10 +57,12 @@ module Profiler
|
|
|
57
57
|
begin
|
|
58
58
|
response = @app.call(env)
|
|
59
59
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
60
|
+
capture_params(env, profile) if failed_request?(e)
|
|
60
61
|
record_failed_request(env, profile, collectors, request_body, allocations_before, e) if failed_request?(e)
|
|
61
62
|
raise
|
|
62
63
|
end
|
|
63
64
|
|
|
65
|
+
capture_params(env, profile)
|
|
64
66
|
response, kept = complete_profile(env, profile, collectors, request_body, allocations_before, response)
|
|
65
67
|
response
|
|
66
68
|
ensure
|
|
@@ -74,6 +76,14 @@ module Profiler
|
|
|
74
76
|
|
|
75
77
|
private
|
|
76
78
|
|
|
79
|
+
# Read after the application has run, so after the routing: the route parameters are there,
|
|
80
|
+
# and the params carry the encoding the route declared, as the controller saw them.
|
|
81
|
+
def capture_params(env, profile)
|
|
82
|
+
profile.capture_params(build_request(env))
|
|
83
|
+
rescue => e
|
|
84
|
+
Profiler.log_error("ProfilerMiddleware: could not read the request params", e)
|
|
85
|
+
end
|
|
86
|
+
|
|
77
87
|
def complete_profile(env, profile, collectors, request_body, allocations_before, response)
|
|
78
88
|
status, headers, body = response
|
|
79
89
|
|
|
@@ -22,7 +22,9 @@ module Profiler
|
|
|
22
22
|
:collectors_released_after_seconds, :params_truncated,
|
|
23
23
|
:gem_version
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
# +params+: false leaves the params to capture_params, for a caller that builds the profile
|
|
26
|
+
# before the router has run.
|
|
27
|
+
def initialize(request = nil, params: true)
|
|
26
28
|
@token = SecureRandom.hex(16)
|
|
27
29
|
@started_at = Time.now
|
|
28
30
|
@collectors_data = {}
|
|
@@ -34,12 +36,19 @@ module Profiler
|
|
|
34
36
|
if request
|
|
35
37
|
@path = request.path
|
|
36
38
|
@method = request.request_method
|
|
37
|
-
|
|
38
|
-
Profiler.configuration.max_captured_body_bytes)
|
|
39
|
+
capture_params(request) if params
|
|
39
40
|
@headers = extract_headers(request.env)
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
43
|
|
|
44
|
+
# The request's params as the controller sees them. Read once the router has run: Rails
|
|
45
|
+
# adds the route parameters (:id...) and applies the routes' param_encoding only then, so
|
|
46
|
+
# a read before it keeps neither.
|
|
47
|
+
def capture_params(request)
|
|
48
|
+
@params, @params_truncated = cap_params(sanitize_params(utf8_params(request.params)),
|
|
49
|
+
Profiler.configuration.max_captured_body_bytes)
|
|
50
|
+
end
|
|
51
|
+
|
|
43
52
|
# The sizes are those of the whole bodies, when a body was cut at max_captured_body_bytes;
|
|
44
53
|
# *_size_is_minimum when the whole size is not known (no Content-Length, a stream that
|
|
45
54
|
# stopped), only that it is at least that.
|
|
@@ -252,7 +261,7 @@ module Profiler
|
|
|
252
261
|
# compressed format (zip, png, gzip...) does not hold the secret as it is.
|
|
253
262
|
{ body: Base64.strict_encode64(Redaction.hide_credentials(raw.b)), encoding: "base64" }
|
|
254
263
|
else
|
|
255
|
-
text = Redaction.filter_body(raw, content_type)
|
|
264
|
+
text = utf8_text(Redaction.filter_body(raw, content_type), content_type)
|
|
256
265
|
if compress_body?(text)
|
|
257
266
|
# The fastest level: paid on the request, a quarter larger than the default level.
|
|
258
267
|
{ body: Base64.strict_encode64(Zlib::Deflate.deflate(text, Zlib::BEST_SPEED)), encoding: "gzip+base64" }
|
|
@@ -262,6 +271,39 @@ module Profiler
|
|
|
262
271
|
end
|
|
263
272
|
end
|
|
264
273
|
|
|
274
|
+
# The text as UTF-8: a body read from the wire is binary, and is taken for the charset its
|
|
275
|
+
# Content-Type declares (UTF-8 when it declares none, or one Ruby does not know). Bytes
|
|
276
|
+
# that do not belong to it are replaced, never raised on.
|
|
277
|
+
def utf8_text(text, content_type)
|
|
278
|
+
return text.encode("UTF-8", invalid: :replace, undef: :replace) unless text.encoding == Encoding::BINARY
|
|
279
|
+
|
|
280
|
+
charset = content_type.to_s[/charset\s*=\s*"?([^\s";]+)/i, 1]
|
|
281
|
+
source = begin
|
|
282
|
+
charset ? Encoding.find(charset) : Encoding::UTF_8
|
|
283
|
+
rescue ArgumentError
|
|
284
|
+
Encoding::UTF_8
|
|
285
|
+
end
|
|
286
|
+
# "internal" is a name Ruby knows but resolves to nil, "utf-7" is a dummy encoding with no converter.
|
|
287
|
+
source ||= Encoding::UTF_8
|
|
288
|
+
begin
|
|
289
|
+
text.dup.force_encoding(source).encode("UTF-8", invalid: :replace, undef: :replace)
|
|
290
|
+
rescue EncodingError
|
|
291
|
+
text.dup.force_encoding(Encoding::UTF_8).encode("UTF-8", invalid: :replace, undef: :replace)
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# The params with their strings in UTF-8: a route's param_encoding gives some another
|
|
296
|
+
# encoding, which the profile must not carry into its JSON.
|
|
297
|
+
def utf8_params(value)
|
|
298
|
+
case value
|
|
299
|
+
when Hash then value.to_h { |k, v| [utf8_params(k), utf8_params(v)] }
|
|
300
|
+
when Array then value.map { |v| utf8_params(v) }
|
|
301
|
+
when String
|
|
302
|
+
value.encoding == Encoding::UTF_8 ? value : value.encode("UTF-8", invalid: :replace, undef: :replace)
|
|
303
|
+
else value
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
265
307
|
def body_size(captured, total)
|
|
266
308
|
captured_size = captured.to_s.bytesize
|
|
267
309
|
total ||= captured_size
|
data/lib/profiler/version.rb
CHANGED