Module: Ruby::Rego::Builtins::Codecs::JsonSchema::Formats::Rfc2047
- Defined in:
- lib/ruby/rego/builtins/codecs/json_schema_email.rb
Overview
The slice of Go’s net/mail decodeRFC2047Word + mime.WordDecoder.Decode that MailAddress’
consume_phrase needs (mirroring Go’s net/mail -> mime package boundary). All pure byte functions:
an encoded-word is structurally =?charset?encoding?text?= (>=8 bytes, exactly four ?, non-empty
charset, one-byte encoding) with a decodable B/Q payload; only utf-8/iso-8859-1/us-ascii convert
natively, anything else errors. Byte-oriented to mirror Go (len / index / base64 / qDecode on
bytes). See the differential coverage in the email spec.
:reek:UncommunicativeModuleName – “Rfc2047” is the RFC number, the canonical name for this spec.
Constant Summary collapse
- CHARSETS =
Charsets mime.WordDecoder.convert handles without a CharsetReader (EqualFold, i.e. ASCII-case).
%w[utf-8 iso-8859-1 us-ascii].freeze
Class Method Summary collapse
-
.base64_char?(byte) ⇒ Boolean
:reek:NilCheck.
-
.base64_decodes?(text) ⇒ Boolean
base64.StdEncoding.DecodeString success boundary: length a multiple of 4, only alphabet bytes with 0-2 trailing
=padding. -
.hex_byte?(byte) ⇒ Boolean
:reek:NilCheck.
-
.payload_decodes?(encoding, text) ⇒ Boolean
mime
decode: ‘B’/’b’ = base64.StdEncoding, ‘Q’/’q’ = qDecode. -
.qdecodes?(text) ⇒ Boolean
Port of mime.qDecode’s per-byte acceptance:
_, an=XXhex escape (needs two hex digits), printable ASCII, or TAB/LF/CR. -
.qtext_byte?(byte) ⇒ Boolean
qDecode-acceptable raw byte: ‘_’ or printable ASCII (0x20..0x7E) or TAB/LF/CR.
-
.status(word) ⇒ Object
How consume_phrase must treat an atom
word, mirroring Go’s decodeRFC2047Word isEncoded/err: :charset_error - a real encoded-word whose payload decodes but whose charset mime can’t convert (Go’s Decode errors); :empty - a real encoded-word with an empty payload, decoding to “” (isEncoded, dropped); :encoded - a real encoded-word with non-empty content (isEncoded); :raw - anything else: a plain atom, a malformed encoded-word, or one whose B/Q payload fails to decode — Go keeps the raw text (isEncoded=false).
Class Method Details
.base64_char?(byte) ⇒ Boolean
:reek:NilCheck
474 475 476 477 478 479 |
# File 'lib/ruby/rego/builtins/codecs/json_schema_email.rb', line 474 def self.base64_char?(byte) return false if byte.nil? (0x41..0x5A).cover?(byte) || (0x61..0x7A).cover?(byte) || (0x30..0x39).cover?(byte) || byte == 0x2B || byte == 0x2F # '+' '/' end |
.base64_decodes?(text) ⇒ Boolean
base64.StdEncoding.DecodeString success boundary: length a multiple of 4, only alphabet bytes
with 0-2 trailing = padding. Empty text decodes to empty (success).
rubocop:disable Metrics/MethodLength
:reek:TooManyStatements
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
# File 'lib/ruby/rego/builtins/codecs/json_schema_email.rb', line 428 def self.base64_decodes?(text) bytes = text.b size = bytes.bytesize return true if size.zero? return false unless (size % 4).zero? pad = 0 pad += 1 while pad < 2 && bytes.getbyte(size - 1 - pad) == 0x3D # Scan the body bytes in place (no substring / no Array#bytes allocation) — like qdecodes?. index = 0 body = size - pad while index < body return false unless base64_char?(bytes.getbyte(index)) index += 1 end true end |
.hex_byte?(byte) ⇒ Boolean
:reek:NilCheck
491 492 493 494 495 |
# File 'lib/ruby/rego/builtins/codecs/json_schema_email.rb', line 491 def self.hex_byte?(byte) return false if byte.nil? (0x30..0x39).cover?(byte) || (0x41..0x46).cover?(byte) || (0x61..0x66).cover?(byte) end |
.payload_decodes?(encoding, text) ⇒ Boolean
mime decode: ‘B’/’b’ = base64.StdEncoding, ‘Q’/’q’ = qDecode. Any other encoding byte errors.
:reek:ControlParameter – dispatches on the encoding byte, like Go’s decode(encoding, text).
416 417 418 419 420 421 422 |
# File 'lib/ruby/rego/builtins/codecs/json_schema_email.rb', line 416 def self.payload_decodes?(encoding, text) case encoding when "B", "b" then base64_decodes?(text) when "Q", "q" then qdecodes?(text) else false end end |
.qdecodes?(text) ⇒ Boolean
Port of mime.qDecode’s per-byte acceptance: _, an =XX hex escape (needs two hex digits),
printable ASCII, or TAB/LF/CR. Any other byte errors. Returns whether the whole run decodes.
rubocop:disable Metrics/MethodLength
:reek:TooManyStatements :reek:DuplicateMethodCall
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
# File 'lib/ruby/rego/builtins/codecs/json_schema_email.rb', line 453 def self.qdecodes?(text) bytes = text.b index = 0 size = bytes.bytesize while index < size byte = bytes.getbyte(index) if byte == 0x3D # '=' return false if index + 2 >= size return false unless hex_byte?(bytes.getbyte(index + 1)) && hex_byte?(bytes.getbyte(index + 2)) index += 2 elsif !qtext_byte?(byte) return false end index += 1 end true end |
.qtext_byte?(byte) ⇒ Boolean
qDecode-acceptable raw byte: ‘_’ or printable ASCII (0x20..0x7E) or TAB/LF/CR. nil (an out-of-bounds read) is never acceptable. :reek:NilCheck
484 485 486 487 488 |
# File 'lib/ruby/rego/builtins/codecs/json_schema_email.rb', line 484 def self.qtext_byte?(byte) return false if byte.nil? byte == 0x5F || (0x20..0x7E).cover?(byte) || byte == 0x09 || byte == 0x0A || byte == 0x0D end |
.status(word) ⇒ Object
How consume_phrase must treat an atom word, mirroring Go’s decodeRFC2047Word isEncoded/err:
:charset_error - a real encoded-word whose payload decodes but whose charset mime can’t
convert (Go’s Decode errors);
:empty - a real encoded-word with an empty payload, decoding to “” (isEncoded, dropped);
:encoded - a real encoded-word with non-empty content (isEncoded);
:raw - anything else: a plain atom, a malformed encoded-word, or one whose B/Q
payload fails to decode — Go keeps the raw text (isEncoded=false).
rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
:reek:TooManyStatements :reek:DuplicateMethodCall
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
# File 'lib/ruby/rego/builtins/codecs/json_schema_email.rb', line 396 def self.status(word) bytes = word.b return :raw if bytes.bytesize < 8 || !bytes.start_with?("=?") || !bytes.end_with?("?=") return :raw unless bytes.count("?") == 4 charset, rest = bytes[2...-2].to_s.split("?", 2) encoding, text = rest.to_s.split("?", 2) return :raw if charset.to_s.empty? || encoding.to_s.bytesize != 1 return :raw unless payload_decodes?(encoding.to_s, text.to_s) return :charset_error unless CHARSETS.include?(charset.to_s.downcase) # Emptiness of the raw text is exact: no NON-empty payload that passes payload_decodes? can # decode to "" (min base64 quantum is 4 chars -> >=1 byte; qDecode never deletes bytes), so we # need not actually decode to know the content is empty. text.to_s.empty? ? :empty : :encoded end |