net-protocol 0.1.0

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,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a89e13a67cbddeb513e263e4144b6571764d29575e708fa41bde6b34f22a1861
4
+ data.tar.gz: 0ebb7c5808ba457116c5824ae27f879adc1dca00141747edeaa573e469d00391
5
+ SHA512:
6
+ metadata.gz: 561d1dae475c39c9cf2de94c3b9fcc196c134b1f5639b41cd6159d3fd4bba4faf5cd45815cbc9f4b7cf3d57a634032a9a402ff571f6f0ec9c811ca8fa8e67688
7
+ data.tar.gz: 181700c6865de4b86d2db0c52c7072e40c66dc2bbf5b3ee64747acc5e5c7c46c96d7e625ef068d8089de15a54f346a2c8566c23e1ae842e7ec5d3767f7c7d6f7
@@ -0,0 +1,24 @@
1
+ name: ubuntu
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 2.7, 2.6, 2.5, 2.4, head ]
11
+ os: [ ubuntu-latest, macos-latest ]
12
+ runs-on: ${{ matrix.os }}
13
+ steps:
14
+ - uses: actions/checkout@master
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: |
21
+ gem install bundler --no-document
22
+ bundle install
23
+ - name: Run test
24
+ run: rake test
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake"
6
+ gem "test-unit"
@@ -0,0 +1,23 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ net-protocol (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ power_assert (1.1.5)
10
+ rake (12.3.3)
11
+ test-unit (3.3.5)
12
+ power_assert
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ net-protocol!
19
+ rake
20
+ test-unit
21
+
22
+ BUNDLED WITH
23
+ 2.1.4
@@ -0,0 +1,29 @@
1
+ # Net::Protocol
2
+
3
+ The abstruct interface for net-* client.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'net-protocol'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install net-protocol
20
+
21
+ ## Development
22
+
23
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
24
+
25
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
26
+
27
+ ## Contributing
28
+
29
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/net-protocol.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.ruby_opts << "-rhelper"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "net/protocol"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,506 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # = net/protocol.rb
4
+ #
5
+ #--
6
+ # Copyright (c) 1999-2004 Yukihiro Matsumoto
7
+ # Copyright (c) 1999-2004 Minero Aoki
8
+ #
9
+ # written and maintained by Minero Aoki <aamine@loveruby.net>
10
+ #
11
+ # This program is free software. You can re-distribute and/or
12
+ # modify this program under the same terms as Ruby itself,
13
+ # Ruby Distribute License or GNU General Public License.
14
+ #
15
+ # $Id$
16
+ #++
17
+ #
18
+ # WARNING: This file is going to remove.
19
+ # Do not rely on the implementation written in this file.
20
+ #
21
+
22
+ require 'socket'
23
+ require 'timeout'
24
+ require 'io/wait'
25
+
26
+ module Net # :nodoc:
27
+
28
+ class Protocol #:nodoc: internal use only
29
+ private
30
+ def Protocol.protocol_param(name, val)
31
+ module_eval(<<-End, __FILE__, __LINE__ + 1)
32
+ def #{name}
33
+ #{val}
34
+ end
35
+ End
36
+ end
37
+
38
+ def ssl_socket_connect(s, timeout)
39
+ if timeout
40
+ while true
41
+ raise Net::OpenTimeout if timeout <= 0
42
+ start = Process.clock_gettime Process::CLOCK_MONOTONIC
43
+ # to_io is required because SSLSocket doesn't have wait_readable yet
44
+ case s.connect_nonblock(exception: false)
45
+ when :wait_readable; s.to_io.wait_readable(timeout)
46
+ when :wait_writable; s.to_io.wait_writable(timeout)
47
+ else; break
48
+ end
49
+ timeout -= Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
50
+ end
51
+ else
52
+ s.connect
53
+ end
54
+ end
55
+ end
56
+
57
+
58
+ class ProtocolError < StandardError; end
59
+ class ProtoSyntaxError < ProtocolError; end
60
+ class ProtoFatalError < ProtocolError; end
61
+ class ProtoUnknownError < ProtocolError; end
62
+ class ProtoServerError < ProtocolError; end
63
+ class ProtoAuthError < ProtocolError; end
64
+ class ProtoCommandError < ProtocolError; end
65
+ class ProtoRetriableError < ProtocolError; end
66
+ ProtocRetryError = ProtoRetriableError
67
+
68
+ ##
69
+ # OpenTimeout, a subclass of Timeout::Error, is raised if a connection cannot
70
+ # be created within the open_timeout.
71
+
72
+ class OpenTimeout < Timeout::Error; end
73
+
74
+ ##
75
+ # ReadTimeout, a subclass of Timeout::Error, is raised if a chunk of the
76
+ # response cannot be read within the read_timeout.
77
+
78
+ class ReadTimeout < Timeout::Error
79
+ def initialize(io = nil)
80
+ @io = io
81
+ end
82
+ attr_reader :io
83
+
84
+ def message
85
+ msg = super
86
+ if @io
87
+ msg = "#{msg} with #{@io.inspect}"
88
+ end
89
+ msg
90
+ end
91
+ end
92
+
93
+ ##
94
+ # WriteTimeout, a subclass of Timeout::Error, is raised if a chunk of the
95
+ # response cannot be written within the write_timeout. Not raised on Windows.
96
+
97
+ class WriteTimeout < Timeout::Error
98
+ def initialize(io = nil)
99
+ @io = io
100
+ end
101
+ attr_reader :io
102
+
103
+ def message
104
+ msg = super
105
+ if @io
106
+ msg = "#{msg} with #{@io.inspect}"
107
+ end
108
+ msg
109
+ end
110
+ end
111
+
112
+
113
+ class BufferedIO #:nodoc: internal use only
114
+ def initialize(io, read_timeout: 60, write_timeout: 60, continue_timeout: nil, debug_output: nil)
115
+ @io = io
116
+ @read_timeout = read_timeout
117
+ @write_timeout = write_timeout
118
+ @continue_timeout = continue_timeout
119
+ @debug_output = debug_output
120
+ @rbuf = ''.b
121
+ end
122
+
123
+ attr_reader :io
124
+ attr_accessor :read_timeout
125
+ attr_accessor :write_timeout
126
+ attr_accessor :continue_timeout
127
+ attr_accessor :debug_output
128
+
129
+ def inspect
130
+ "#<#{self.class} io=#{@io}>"
131
+ end
132
+
133
+ def eof?
134
+ @io.eof?
135
+ end
136
+
137
+ def closed?
138
+ @io.closed?
139
+ end
140
+
141
+ def close
142
+ @io.close
143
+ end
144
+
145
+ #
146
+ # Read
147
+ #
148
+
149
+ public
150
+
151
+ def read(len, dest = ''.b, ignore_eof = false)
152
+ LOG "reading #{len} bytes..."
153
+ read_bytes = 0
154
+ begin
155
+ while read_bytes + @rbuf.size < len
156
+ s = rbuf_consume(@rbuf.size)
157
+ read_bytes += s.size
158
+ dest << s
159
+ rbuf_fill
160
+ end
161
+ s = rbuf_consume(len - read_bytes)
162
+ read_bytes += s.size
163
+ dest << s
164
+ rescue EOFError
165
+ raise unless ignore_eof
166
+ end
167
+ LOG "read #{read_bytes} bytes"
168
+ dest
169
+ end
170
+
171
+ def read_all(dest = ''.b)
172
+ LOG 'reading all...'
173
+ read_bytes = 0
174
+ begin
175
+ while true
176
+ s = rbuf_consume(@rbuf.size)
177
+ read_bytes += s.size
178
+ dest << s
179
+ rbuf_fill
180
+ end
181
+ rescue EOFError
182
+ ;
183
+ end
184
+ LOG "read #{read_bytes} bytes"
185
+ dest
186
+ end
187
+
188
+ def readuntil(terminator, ignore_eof = false)
189
+ begin
190
+ until idx = @rbuf.index(terminator)
191
+ rbuf_fill
192
+ end
193
+ return rbuf_consume(idx + terminator.size)
194
+ rescue EOFError
195
+ raise unless ignore_eof
196
+ return rbuf_consume(@rbuf.size)
197
+ end
198
+ end
199
+
200
+ def readline
201
+ readuntil("\n").chop
202
+ end
203
+
204
+ private
205
+
206
+ BUFSIZE = 1024 * 16
207
+
208
+ def rbuf_fill
209
+ tmp = @rbuf.empty? ? @rbuf : nil
210
+ case rv = @io.read_nonblock(BUFSIZE, tmp, exception: false)
211
+ when String
212
+ return if rv.equal?(tmp)
213
+ @rbuf << rv
214
+ rv.clear
215
+ return
216
+ when :wait_readable
217
+ (io = @io.to_io).wait_readable(@read_timeout) or raise Net::ReadTimeout.new(io)
218
+ # continue looping
219
+ when :wait_writable
220
+ # OpenSSL::Buffering#read_nonblock may fail with IO::WaitWritable.
221
+ # http://www.openssl.org/support/faq.html#PROG10
222
+ (io = @io.to_io).wait_writable(@read_timeout) or raise Net::ReadTimeout.new(io)
223
+ # continue looping
224
+ when nil
225
+ raise EOFError, 'end of file reached'
226
+ end while true
227
+ end
228
+
229
+ def rbuf_consume(len)
230
+ if len == @rbuf.size
231
+ s = @rbuf
232
+ @rbuf = ''.b
233
+ else
234
+ s = @rbuf.slice!(0, len)
235
+ end
236
+ @debug_output << %Q[-> #{s.dump}\n] if @debug_output
237
+ s
238
+ end
239
+
240
+ #
241
+ # Write
242
+ #
243
+
244
+ public
245
+
246
+ def write(*strs)
247
+ writing {
248
+ write0(*strs)
249
+ }
250
+ end
251
+
252
+ alias << write
253
+
254
+ def writeline(str)
255
+ writing {
256
+ write0 str + "\r\n"
257
+ }
258
+ end
259
+
260
+ private
261
+
262
+ def writing
263
+ @written_bytes = 0
264
+ @debug_output << '<- ' if @debug_output
265
+ yield
266
+ @debug_output << "\n" if @debug_output
267
+ bytes = @written_bytes
268
+ @written_bytes = nil
269
+ bytes
270
+ end
271
+
272
+ def write0(*strs)
273
+ @debug_output << strs.map(&:dump).join if @debug_output
274
+ orig_written_bytes = @written_bytes
275
+ strs.each_with_index do |str, i|
276
+ need_retry = true
277
+ case len = @io.write_nonblock(str, exception: false)
278
+ when Integer
279
+ @written_bytes += len
280
+ len -= str.bytesize
281
+ if len == 0
282
+ if strs.size == i+1
283
+ return @written_bytes - orig_written_bytes
284
+ else
285
+ need_retry = false
286
+ # next string
287
+ end
288
+ elsif len < 0
289
+ str = str.byteslice(len, -len)
290
+ else # len > 0
291
+ need_retry = false
292
+ # next string
293
+ end
294
+ # continue looping
295
+ when :wait_writable
296
+ (io = @io.to_io).wait_writable(@write_timeout) or raise Net::WriteTimeout.new(io)
297
+ # continue looping
298
+ end while need_retry
299
+ end
300
+ end
301
+
302
+ #
303
+ # Logging
304
+ #
305
+
306
+ private
307
+
308
+ def LOG_off
309
+ @save_debug_out = @debug_output
310
+ @debug_output = nil
311
+ end
312
+
313
+ def LOG_on
314
+ @debug_output = @save_debug_out
315
+ end
316
+
317
+ def LOG(msg)
318
+ return unless @debug_output
319
+ @debug_output << msg + "\n"
320
+ end
321
+ end
322
+
323
+
324
+ class InternetMessageIO < BufferedIO #:nodoc: internal use only
325
+ def initialize(*, **)
326
+ super
327
+ @wbuf = nil
328
+ end
329
+
330
+ #
331
+ # Read
332
+ #
333
+
334
+ def each_message_chunk
335
+ LOG 'reading message...'
336
+ LOG_off()
337
+ read_bytes = 0
338
+ while (line = readuntil("\r\n")) != ".\r\n"
339
+ read_bytes += line.size
340
+ yield line.delete_prefix('.')
341
+ end
342
+ LOG_on()
343
+ LOG "read message (#{read_bytes} bytes)"
344
+ end
345
+
346
+ # *library private* (cannot handle 'break')
347
+ def each_list_item
348
+ while (str = readuntil("\r\n")) != ".\r\n"
349
+ yield str.chop
350
+ end
351
+ end
352
+
353
+ def write_message_0(src)
354
+ prev = @written_bytes
355
+ each_crlf_line(src) do |line|
356
+ write0 dot_stuff(line)
357
+ end
358
+ @written_bytes - prev
359
+ end
360
+
361
+ #
362
+ # Write
363
+ #
364
+
365
+ def write_message(src)
366
+ LOG "writing message from #{src.class}"
367
+ LOG_off()
368
+ len = writing {
369
+ using_each_crlf_line {
370
+ write_message_0 src
371
+ }
372
+ }
373
+ LOG_on()
374
+ LOG "wrote #{len} bytes"
375
+ len
376
+ end
377
+
378
+ def write_message_by_block(&block)
379
+ LOG 'writing message from block'
380
+ LOG_off()
381
+ len = writing {
382
+ using_each_crlf_line {
383
+ begin
384
+ block.call(WriteAdapter.new(self, :write_message_0))
385
+ rescue LocalJumpError
386
+ # allow `break' from writer block
387
+ end
388
+ }
389
+ }
390
+ LOG_on()
391
+ LOG "wrote #{len} bytes"
392
+ len
393
+ end
394
+
395
+ private
396
+
397
+ def dot_stuff(s)
398
+ s.sub(/\A\./, '..')
399
+ end
400
+
401
+ def using_each_crlf_line
402
+ @wbuf = ''.b
403
+ yield
404
+ if not @wbuf.empty? # unterminated last line
405
+ write0 dot_stuff(@wbuf.chomp) + "\r\n"
406
+ elsif @written_bytes == 0 # empty src
407
+ write0 "\r\n"
408
+ end
409
+ write0 ".\r\n"
410
+ @wbuf = nil
411
+ end
412
+
413
+ def each_crlf_line(src)
414
+ buffer_filling(@wbuf, src) do
415
+ while line = @wbuf.slice!(/\A[^\r\n]*(?:\n|\r(?:\n|(?!\z)))/)
416
+ yield line.chomp("\n") + "\r\n"
417
+ end
418
+ end
419
+ end
420
+
421
+ def buffer_filling(buf, src)
422
+ case src
423
+ when String # for speeding up.
424
+ 0.step(src.size - 1, 1024) do |i|
425
+ buf << src[i, 1024]
426
+ yield
427
+ end
428
+ when File # for speeding up.
429
+ while s = src.read(1024)
430
+ buf << s
431
+ yield
432
+ end
433
+ else # generic reader
434
+ src.each do |str|
435
+ buf << str
436
+ yield if buf.size > 1024
437
+ end
438
+ yield unless buf.empty?
439
+ end
440
+ end
441
+ end
442
+
443
+
444
+ #
445
+ # The writer adapter class
446
+ #
447
+ class WriteAdapter
448
+ def initialize(socket, method)
449
+ @socket = socket
450
+ @method_id = method
451
+ end
452
+
453
+ def inspect
454
+ "#<#{self.class} socket=#{@socket.inspect}>"
455
+ end
456
+
457
+ def write(str)
458
+ @socket.__send__(@method_id, str)
459
+ end
460
+
461
+ alias print write
462
+
463
+ def <<(str)
464
+ write str
465
+ self
466
+ end
467
+
468
+ def puts(str = '')
469
+ write str.chomp("\n") + "\n"
470
+ end
471
+
472
+ def printf(*args)
473
+ write sprintf(*args)
474
+ end
475
+ end
476
+
477
+
478
+ class ReadAdapter #:nodoc: internal use only
479
+ def initialize(block)
480
+ @block = block
481
+ end
482
+
483
+ def inspect
484
+ "#<#{self.class}>"
485
+ end
486
+
487
+ def <<(str)
488
+ call_block(str, &@block) if @block
489
+ end
490
+
491
+ private
492
+
493
+ # This method is needed because @block must be called by yield,
494
+ # not Proc#call. You can see difference when using `break' in
495
+ # the block.
496
+ def call_block(str)
497
+ yield str
498
+ end
499
+ end
500
+
501
+
502
+ module NetPrivate #:nodoc: obsolete
503
+ Socket = ::Net::InternetMessageIO
504
+ end
505
+
506
+ end # module Net
@@ -0,0 +1,5 @@
1
+ module Net
2
+ class Protocol
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ begin
2
+ require_relative "lib/net/protocol/version"
3
+ rescue LoadError # Fallback to load version file in ruby core repository
4
+ require_relative "version"
5
+ end
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "net-protocol"
9
+ spec.version = Net::Protocol::VERSION
10
+ spec.authors = ["Yukihiro Matsumoto"]
11
+ spec.email = ["matz@ruby-lang.org"]
12
+
13
+ spec.summary = %q{The abstruct interface for net-* client.}
14
+ spec.description = %q{The abstruct interface for net-* client.}
15
+ spec.homepage = "https://github.com/ruby/net-protocol"
16
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = spec.homepage
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: net-protocol
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yukihiro Matsumoto
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-04-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: The abstruct interface for net-* client.
14
+ email:
15
+ - matz@ruby-lang.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".github/workflows/test.yml"
21
+ - ".gitignore"
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - README.md
25
+ - Rakefile
26
+ - bin/console
27
+ - bin/setup
28
+ - lib/net/protocol.rb
29
+ - lib/net/protocol/version.rb
30
+ - net-protocol.gemspec
31
+ homepage: https://github.com/ruby/net-protocol
32
+ licenses: []
33
+ metadata:
34
+ homepage_uri: https://github.com/ruby/net-protocol
35
+ source_code_uri: https://github.com/ruby/net-protocol
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 2.3.0
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubygems_version: 3.2.0.pre1
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: The abstruct interface for net-* client.
55
+ test_files: []