http_loader 0.10.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.
@@ -0,0 +1,117 @@
1
+ # typed: strong
2
+ # Justified Exception: Flawed upstream library typings (Rack and Rackup) prevent strong evaluation natively.
3
+ # frozen_string_literal: true
4
+
5
+ require 'sorbet-runtime'
6
+ require 'rack'
7
+ require 'rackup'
8
+ require 'rackup/handler/falcon'
9
+ require 'openssl'
10
+ require 'io/endpoint/host_endpoint'
11
+ require 'io/endpoint/ssl_endpoint'
12
+ require 'async'
13
+ require 'falcon/server'
14
+ require 'protocol/rack/adapter'
15
+
16
+ module HttpLoader
17
+ # Server provides a lightweight, natively asynchronous HTTP/HTTPS mock endpoint
18
+ class Server
19
+ extend T::Sig
20
+
21
+ sig { void }
22
+ def initialize
23
+ @app = T.let(
24
+ proc do |_env|
25
+ [200, { 'Content-Type' => 'text/plain', 'Content-Length' => '2' }, ['OK']]
26
+ end,
27
+ T.proc.params(arg0: T::Hash[String, Object]).returns(T::Array[T.any(Integer, T::Hash[String, String], Object)])
28
+ )
29
+ end
30
+
31
+ sig { params(use_https: T::Boolean, port: Integer).void }
32
+ def start(use_https: false, port: 8080)
33
+ if use_https
34
+ start_secure(port)
35
+ else
36
+ start_plaintext(port)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ sig { params(port: Integer).void }
43
+ def start_secure(port)
44
+ puts "[Server] Binding natively to HTTPS over port #{port}"
45
+ ssl_context = generate_ssl_context
46
+
47
+ T.unsafe(self).send(:Sync) do |task|
48
+ run_falcon(task, port, ssl_context)
49
+ end
50
+ end
51
+
52
+ sig { params(task: T.untyped, port: Integer, context: OpenSSL::SSL::SSLContext).void }
53
+ def run_falcon(task, port, context)
54
+ server_task = build_falcon_server(port, context).run
55
+ setup_interrupt do
56
+ task.stop
57
+ exit(0)
58
+ end
59
+ server_task.wait
60
+ end
61
+
62
+ sig { params(port: Integer, context: OpenSSL::SSL::SSLContext).returns(T.untyped) }
63
+ def build_falcon_server(port, context)
64
+ endpoint = T.unsafe(IO::Endpoint).tcp('0.0.0.0', port)
65
+ secure = T.unsafe(IO::Endpoint::SSLEndpoint).new(endpoint, ssl_context: context)
66
+ adapter = T.unsafe(::Protocol::Rack::Adapter).new(@app)
67
+ T.unsafe(::Falcon::Server).new(
68
+ adapter, secure, protocol: T.unsafe(Async::HTTP::Protocol::HTTP1), scheme: 'https'
69
+ )
70
+ end
71
+
72
+ sig { params(port: Integer).void }
73
+ def start_plaintext(port)
74
+ puts "[Server] Binding natively to plaintext HTTP over port #{port}"
75
+ Rackup::Handler::Falcon.run(@app, Host: '0.0.0.0', Port: port) do |_server|
76
+ setup_interrupt { exit(0) }
77
+ end
78
+ end
79
+
80
+ sig { params('&': T.proc.void).void }
81
+ def setup_interrupt(&)
82
+ trap('INT') do |_signo|
83
+ puts "\n[Server] Shutting down immediately..."
84
+ yield
85
+ end
86
+ end
87
+
88
+ sig { returns(OpenSSL::SSL::SSLContext) }
89
+ def generate_ssl_context
90
+ rsa = OpenSSL::PKey::RSA.new(2048)
91
+ cert = build_cert(rsa)
92
+
93
+ ssl_context = OpenSSL::SSL::SSLContext.new
94
+ ssl_context.cert = cert
95
+ ssl_context.key = rsa
96
+ ssl_context
97
+ end
98
+
99
+ sig { params(rsa: OpenSSL::PKey::RSA).returns(OpenSSL::X509::Certificate) }
100
+ def build_cert(rsa)
101
+ cert = OpenSSL::X509::Certificate.new
102
+ parse_cert_info(cert)
103
+ cert.public_key = rsa.public_key
104
+ cert.serial = 0x0
105
+ cert.version = 2
106
+ cert.sign(rsa, OpenSSL::Digest.new('SHA256'))
107
+ cert
108
+ end
109
+
110
+ sig { params(cert: OpenSSL::X509::Certificate).void }
111
+ def parse_cert_info(cert)
112
+ cert.subject = cert.issuer = OpenSSL::X509::Name.parse('/CN=localhost')
113
+ cert.not_before = Time.now.utc
114
+ cert.not_after = Time.now.utc + (365 * 24 * 60 * 60)
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,6 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ module HttpLoader
5
+ VERSION = '0.10.3'
6
+ end
@@ -0,0 +1,12 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require 'sorbet-runtime'
5
+ require_relative 'http_loader/version'
6
+ require_relative 'http_loader/server'
7
+ require_relative 'http_loader/client'
8
+ require_relative 'http_loader/harness'
9
+
10
+ # HttpLoader is the main namespace for the high-concurrency Ruby load testing framework.
11
+ module HttpLoader
12
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable AI/AdverbSpam -- Architectural Limitation: This cop's own documentation must deliberately breach the rule to provide a negative example.
4
+
5
+ require 'rubocop'
6
+
7
+ module RuboCop
8
+ module Cop
9
+ module AI
10
+ # This cop checks for comments that contain an excessive sequence of adverbs
11
+ # or seemingly random words, which are often generated by malfunctioning AI
12
+ # tools or LLM doc generators.
13
+ #
14
+ # @example
15
+ # # bad
16
+ # # @param c_m [String] securely accurately dynamically visually intuitively conditionally ...
17
+ #
18
+ # # good
19
+ # # @param c_m [String] the properly formatted parameter
20
+ class AdverbSpam < RuboCop::Cop::Base
21
+ extend AutoCorrector
22
+
23
+ MSG = 'Avoid AI-generated spam inside comments (excessive adverbs/meaningless words).'
24
+
25
+ def on_new_investigation
26
+ # Pattern to match sequences of 2 or more words ending in 'ly'
27
+ # including optional spaces and punctuation in between (but NOT newlines).
28
+ pattern = /(?:[ \t]*\b[a-zA-Z]+ly\b[ \t,.]*){2,}/i
29
+
30
+ processed_source.comments.each do |comment|
31
+ text = comment.text
32
+ next unless text.match?(pattern)
33
+
34
+ add_offense(comment) do |corrector|
35
+ new_text = text.gsub(pattern, '').rstrip
36
+ # Ensure the comment still starts with '#' if it got stripped entirely
37
+ new_text = '#' if new_text.empty?
38
+ corrector.replace(comment, new_text)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ # rubocop:enable AI/AdverbSpam
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,379 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_loader
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.10.3
5
+ platform: ruby
6
+ authors:
7
+ - Vitalii Lazebnyi
8
+ bindir: bin
9
+ cert_chain:
10
+ - |
11
+ -----BEGIN CERTIFICATE-----
12
+ MIIEOTCCAqGgAwIBAgIUBONmsFo7fxLGkUHsKe65onH+5ogwDQYJKoZIhvcNAQEL
13
+ BQAwLDEqMCgGA1UEAwwhdml0YWxpaS5sYXplYm55aS5naXRodWJAZ21haWwuY29t
14
+ MB4XDTI2MDQxNTEzNTMyOVoXDTM2MDQxMjEzNTMyOVowLDEqMCgGA1UEAwwhdml0
15
+ YWxpaS5sYXplYm55aS5naXRodWJAZ21haWwuY29tMIIBojANBgkqhkiG9w0BAQEF
16
+ AAOCAY8AMIIBigKCAYEA5zdezJE+Zrsk9j53/IxBfRoaqvLcPvrcfl+EaEwWhIkV
17
+ 0+08GtgS9N7VpB8cgaH2rkLJPjHIetsN/g5GMkDRsbJNXMrPVhxe1e1lI/r6j0Tm
18
+ JD0PaU4r8VzitxkqY9BBmSI8GjDjAfrT1u5jSXH1iAtKUoq5F116uYrxbgiDpvqa
19
+ kUQYcTf+6cZaPlF4KKhULnhKqs8u/NxyH4vPZyxEfg/gA4bODvcjW1A6d59BTiLV
20
+ yrJPebwU+F+URb8aoQ4AGvPKFiG1Y1fxRHuPrOpyymFnBnjwgMyQkNHtzTeEriV9
21
+ z1BUb10Pb/pjLBCrOvnStTPmcm1GE8HL2psYvlLvBlYqq3gzpQPBBKE3Jefa7ilC
22
+ cYsBYOGpynpA9uu9cXKa4jtpPDGQ7Qrpnk9gHy/0xfbgLdAkRCoZJeR7wDL/1xmm
23
+ nXwcUOLSOBj1Y4P9M+uQSQUZFTAaLbwyaBfE1gvVjwbTv3+rNP1ck1hACt+numGG
24
+ m7R6MF+Hmh8pNnDBYpBNAgMBAAGjUzBRMB0GA1UdDgQWBBRbuaz1EhdG6T4KIeWr
25
+ ac8LULxO9zAfBgNVHSMEGDAWgBRbuaz1EhdG6T4KIeWrac8LULxO9zAPBgNVHRMB
26
+ Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBgQBgfGTDIMxlm6o8o7dzCR0HosRm
27
+ DSeUrx46EG1knTEqO05CooEHW98hrHa1/EwzkPaH1KhjjserQb6VtczMnySlfySu
28
+ HbKWAIaqzlpf8zaE5tCiAKgFKr77b2XB7xKt25p/Vf/Kn/RLm3+sYQ2izzzMimei
29
+ tBHo29cLV9bB/5HHFDwjrtdC5a0HJHiir0w4MCSDDGtnsKird4RKD2xESpoVjiNg
30
+ L9nEGk25YDeIfKn8UtxduMv53T86CiBSsDcEb6oVjNiMOA0HFucwFKX+Vy5u0/qx
31
+ ZRoLbZiCkTTGyNkBh4o6RCCTn37Lj98FBxYMbAHLNhEcKnAGxB7XP/CYsV4+QHOy
32
+ h0PctylhIvm24QeKgIWJUWamFPfqdvlP660T4umxl2wMqvNpWmGMmGTMCraoKwxl
33
+ zpp6uA15MXgTU7CxGivRgUKM64TqBMZKkOJcCtPkruSobxiR8cROrBNTqEbrmedM
34
+ 26EUEoxwDzfSzHU2SKz5pMR+8DClMUKB1rctg68=
35
+ -----END CERTIFICATE-----
36
+ date: 1980-01-02 00:00:00.000000000 Z
37
+ dependencies:
38
+ - !ruby/object:Gem::Dependency
39
+ name: async
40
+ requirement: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - "~>"
43
+ - !ruby/object:Gem::Version
44
+ version: '2.39'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - "~>"
50
+ - !ruby/object:Gem::Version
51
+ version: '2.39'
52
+ - !ruby/object:Gem::Dependency
53
+ name: async-http
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - "~>"
57
+ - !ruby/object:Gem::Version
58
+ version: '0.95'
59
+ type: :runtime
60
+ prerelease: false
61
+ version_requirements: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - "~>"
64
+ - !ruby/object:Gem::Version
65
+ version: '0.95'
66
+ - !ruby/object:Gem::Dependency
67
+ name: falcon
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '0.55'
73
+ type: :runtime
74
+ prerelease: false
75
+ version_requirements: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0.55'
80
+ - !ruby/object:Gem::Dependency
81
+ name: rack
82
+ requirement: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '3.2'
87
+ type: :runtime
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '3.2'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rackup
96
+ requirement: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '2.3'
101
+ type: :runtime
102
+ prerelease: false
103
+ version_requirements: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - "~>"
106
+ - !ruby/object:Gem::Version
107
+ version: '2.3'
108
+ - !ruby/object:Gem::Dependency
109
+ name: sorbet-runtime
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: '0.6'
115
+ type: :runtime
116
+ prerelease: false
117
+ version_requirements: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '0.6'
122
+ - !ruby/object:Gem::Dependency
123
+ name: memory_profiler
124
+ requirement: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - "~>"
127
+ - !ruby/object:Gem::Version
128
+ version: '1.1'
129
+ type: :development
130
+ prerelease: false
131
+ version_requirements: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '1.1'
136
+ - !ruby/object:Gem::Dependency
137
+ name: rake
138
+ requirement: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
142
+ version: '13.3'
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: '13.3'
150
+ - !ruby/object:Gem::Dependency
151
+ name: rspec
152
+ requirement: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: '3.13'
157
+ type: :development
158
+ prerelease: false
159
+ version_requirements: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - "~>"
162
+ - !ruby/object:Gem::Version
163
+ version: '3.13'
164
+ - !ruby/object:Gem::Dependency
165
+ name: rubocop
166
+ requirement: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - "~>"
169
+ - !ruby/object:Gem::Version
170
+ version: '1.86'
171
+ type: :development
172
+ prerelease: false
173
+ version_requirements: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - "~>"
176
+ - !ruby/object:Gem::Version
177
+ version: '1.86'
178
+ - !ruby/object:Gem::Dependency
179
+ name: rubocop-md
180
+ requirement: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - "~>"
183
+ - !ruby/object:Gem::Version
184
+ version: '2.0'
185
+ type: :development
186
+ prerelease: false
187
+ version_requirements: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - "~>"
190
+ - !ruby/object:Gem::Version
191
+ version: '2.0'
192
+ - !ruby/object:Gem::Dependency
193
+ name: rubocop-performance
194
+ requirement: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - "~>"
197
+ - !ruby/object:Gem::Version
198
+ version: '1.26'
199
+ type: :development
200
+ prerelease: false
201
+ version_requirements: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - "~>"
204
+ - !ruby/object:Gem::Version
205
+ version: '1.26'
206
+ - !ruby/object:Gem::Dependency
207
+ name: rubocop-rake
208
+ requirement: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - "~>"
211
+ - !ruby/object:Gem::Version
212
+ version: '0.7'
213
+ type: :development
214
+ prerelease: false
215
+ version_requirements: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - "~>"
218
+ - !ruby/object:Gem::Version
219
+ version: '0.7'
220
+ - !ruby/object:Gem::Dependency
221
+ name: rubocop-rspec
222
+ requirement: !ruby/object:Gem::Requirement
223
+ requirements:
224
+ - - "~>"
225
+ - !ruby/object:Gem::Version
226
+ version: '3.9'
227
+ type: :development
228
+ prerelease: false
229
+ version_requirements: !ruby/object:Gem::Requirement
230
+ requirements:
231
+ - - "~>"
232
+ - !ruby/object:Gem::Version
233
+ version: '3.9'
234
+ - !ruby/object:Gem::Dependency
235
+ name: rubocop-thread_safety
236
+ requirement: !ruby/object:Gem::Requirement
237
+ requirements:
238
+ - - "~>"
239
+ - !ruby/object:Gem::Version
240
+ version: '0.7'
241
+ type: :development
242
+ prerelease: false
243
+ version_requirements: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - "~>"
246
+ - !ruby/object:Gem::Version
247
+ version: '0.7'
248
+ - !ruby/object:Gem::Dependency
249
+ name: ruby-prof
250
+ requirement: !ruby/object:Gem::Requirement
251
+ requirements:
252
+ - - "~>"
253
+ - !ruby/object:Gem::Version
254
+ version: '2.0'
255
+ type: :development
256
+ prerelease: false
257
+ version_requirements: !ruby/object:Gem::Requirement
258
+ requirements:
259
+ - - "~>"
260
+ - !ruby/object:Gem::Version
261
+ version: '2.0'
262
+ - !ruby/object:Gem::Dependency
263
+ name: simplecov
264
+ requirement: !ruby/object:Gem::Requirement
265
+ requirements:
266
+ - - "~>"
267
+ - !ruby/object:Gem::Version
268
+ version: '0.22'
269
+ type: :development
270
+ prerelease: false
271
+ version_requirements: !ruby/object:Gem::Requirement
272
+ requirements:
273
+ - - "~>"
274
+ - !ruby/object:Gem::Version
275
+ version: '0.22'
276
+ - !ruby/object:Gem::Dependency
277
+ name: sorbet
278
+ requirement: !ruby/object:Gem::Requirement
279
+ requirements:
280
+ - - "~>"
281
+ - !ruby/object:Gem::Version
282
+ version: '0.6'
283
+ type: :development
284
+ prerelease: false
285
+ version_requirements: !ruby/object:Gem::Requirement
286
+ requirements:
287
+ - - "~>"
288
+ - !ruby/object:Gem::Version
289
+ version: '0.6'
290
+ - !ruby/object:Gem::Dependency
291
+ name: yard
292
+ requirement: !ruby/object:Gem::Requirement
293
+ requirements:
294
+ - - "~>"
295
+ - !ruby/object:Gem::Version
296
+ version: '0.9'
297
+ type: :development
298
+ prerelease: false
299
+ version_requirements: !ruby/object:Gem::Requirement
300
+ requirements:
301
+ - - "~>"
302
+ - !ruby/object:Gem::Version
303
+ version: '0.9'
304
+ - !ruby/object:Gem::Dependency
305
+ name: yard-sorbet
306
+ requirement: !ruby/object:Gem::Requirement
307
+ requirements:
308
+ - - "~>"
309
+ - !ruby/object:Gem::Version
310
+ version: '0.8'
311
+ type: :development
312
+ prerelease: false
313
+ version_requirements: !ruby/object:Gem::Requirement
314
+ requirements:
315
+ - - "~>"
316
+ - !ruby/object:Gem::Version
317
+ version: '0.8'
318
+ description: A performance testing tool for HTTP/HTTPS.
319
+ email:
320
+ - vitalii.lazebnyi.github@gmail.com
321
+ executables:
322
+ - http_loader
323
+ extensions: []
324
+ extra_rdoc_files: []
325
+ files:
326
+ - BUGS.md
327
+ - Gemfile
328
+ - LICENSE.txt
329
+ - PERFORMANCE_REPORT.md
330
+ - README.md
331
+ - REQUIREMENTS.md
332
+ - bin/http_loader
333
+ - certs/http_loader-public_cert.pem
334
+ - http_loader.gemspec
335
+ - lib/http_loader.rb
336
+ - lib/http_loader/cli_args.rb
337
+ - lib/http_loader/client.rb
338
+ - lib/http_loader/client/config.rb
339
+ - lib/http_loader/client/error_handler.rb
340
+ - lib/http_loader/client/http_session.rb
341
+ - lib/http_loader/client/logger.rb
342
+ - lib/http_loader/client/slowloris.rb
343
+ - lib/http_loader/client/target_manager.rb
344
+ - lib/http_loader/harness.rb
345
+ - lib/http_loader/harness/config.rb
346
+ - lib/http_loader/harness/formatter.rb
347
+ - lib/http_loader/harness/process_manager.rb
348
+ - lib/http_loader/harness/resource_monitor.rb
349
+ - lib/http_loader/harness/telemetry.rb
350
+ - lib/http_loader/server.rb
351
+ - lib/http_loader/version.rb
352
+ - lib/rubocop/cop/ai/adverb_spam.rb
353
+ homepage: https://github.com/VitaliiLazebnyi/http_loader
354
+ licenses:
355
+ - MIT
356
+ metadata:
357
+ allowed_push_host: https://rubygems.org
358
+ source_code_uri: https://github.com/VitaliiLazebnyi/http_loader
359
+ bug_tracker_uri: https://github.com/VitaliiLazebnyi/http_loader/issues
360
+ changelog_uri: https://github.com/VitaliiLazebnyi/http_loader/blob/main/CHANGELOG.md
361
+ rubygems_mfa_required: 'true'
362
+ rdoc_options: []
363
+ require_paths:
364
+ - lib
365
+ required_ruby_version: !ruby/object:Gem::Requirement
366
+ requirements:
367
+ - - ">="
368
+ - !ruby/object:Gem::Version
369
+ version: '4.0'
370
+ required_rubygems_version: !ruby/object:Gem::Requirement
371
+ requirements:
372
+ - - ">="
373
+ - !ruby/object:Gem::Version
374
+ version: '0'
375
+ requirements: []
376
+ rubygems_version: 4.0.6
377
+ specification_version: 4
378
+ summary: Keep-Alive High Concurrency Load Testing Framework
379
+ test_files: []
metadata.gz.sig ADDED
Binary file