Skip to content

Instantly share code, notes, and snippets.

@julik
Created August 23, 2019 00:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save julik/2bfc895e796531dcb6baf1bd6e7e0dc5 to your computer and use it in GitHub Desktop.
Save julik/2bfc895e796531dcb6baf1bd6e7e0dc5 to your computer and use it in GitHub Desktop.
class MultipartRangesWriter
ALPHABET = ('0'..'9').to_a + ('a'..'z').to_a + ('A'..'Z').to_a
def initialize
# RFC1521 says that a boundary "must be no longer than 70 characters, not counting the two leading hyphens".
# Modulo-based random is biased but it doesn't matter much for us
@boundary = SecureRandom.bytes(64).unpack("C*").map {|b| ALPHABET[b % ALPHABET.length] }.join
end
class NullWriter < Struct.new(:offset)
def write(str)
advance(str.bytesize)
end
def advance(by)
self.offset += by
end
end
def content_type_header_value
"multipart/byte-ranges; boundary=#{@boundary}"
end
# Compute the full length of the MIME message with all the parts,
# headers and whatnot
def full_message_length(*http_ranges)
writer = NullWriter.new(0)
http_ranges.each.with_index do |range, i|
write_boundary_and_headers(writer, i, range.begin, range.end)
writer.advance(range.end - range.begin + 1)
end
writer.offset
end
def write_boundary_and_headers(socket, part_index, http_range)
range_size = http_range.end - http_range.begin + 1
if part_index > 0
socket.write("\r\n")
end
socket.write("--#{@boundary}\r\n")
socket.write("Content-Type: binary/octet-stream\r\n")
socket.write("Content-Range: bytes #{http_range.begin}-#{http_range.end}/#{range_size}\r\n")
socket.write("\r\n")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment