mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-10-08 00:02:42 -04:00
This returns the filename advertised in the content-disposition header. It reuses the same logic which existed for parsing multipart responses, which itself was based on `rack`'s.
86 lines
2.2 KiB
Ruby
86 lines
2.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module HTTPX
|
|
module Utils
|
|
using URIExtensions
|
|
using HTTPX::RegexpExtensions unless Regexp.method_defined?(:match?)
|
|
|
|
TOKEN = %r{[^\s()<>,;:\\"/\[\]?=]+}.freeze
|
|
VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/.freeze
|
|
FILENAME_REGEX = /\s*filename=(#{VALUE})/.freeze
|
|
FILENAME_EXTENSION_REGEX = /\s*filename\*=(#{VALUE})/.freeze
|
|
|
|
module_function
|
|
|
|
def now
|
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
end
|
|
|
|
def elapsed_time(monotonic_timestamp)
|
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) - monotonic_timestamp
|
|
end
|
|
|
|
# The value of this field can be either an HTTP-date or a number of
|
|
# seconds to delay after the response is received.
|
|
def parse_retry_after(retry_after)
|
|
# first: bet on it being an integer
|
|
Integer(retry_after)
|
|
rescue ArgumentError
|
|
# Then it's a datetime
|
|
time = Time.httpdate(retry_after)
|
|
time - Time.now
|
|
end
|
|
|
|
def get_filename(header, _prefix_regex = nil)
|
|
filename = nil
|
|
case header
|
|
when FILENAME_REGEX
|
|
filename = Regexp.last_match(1)
|
|
filename = Regexp.last_match(1) if filename =~ /^"(.*)"$/
|
|
when FILENAME_EXTENSION_REGEX
|
|
filename = Regexp.last_match(1)
|
|
encoding, _, filename = filename.split("'", 3)
|
|
end
|
|
|
|
return unless filename
|
|
|
|
filename = URI::DEFAULT_PARSER.unescape(filename) if filename.scan(/%.?.?/).all? { |s| /%[0-9a-fA-F]{2}/.match?(s) }
|
|
|
|
filename.scrub!
|
|
|
|
filename = filename.gsub(/\\(.)/, '\1') unless /\\[^\\"]/.match?(filename)
|
|
|
|
filename.force_encoding ::Encoding.find(encoding) if encoding
|
|
|
|
filename
|
|
end
|
|
|
|
if RUBY_VERSION < "2.3"
|
|
|
|
def to_uri(uri)
|
|
URI(uri)
|
|
end
|
|
|
|
else
|
|
|
|
URIParser = URI::RFC2396_Parser.new
|
|
|
|
def to_uri(uri)
|
|
return URI(uri) unless uri.is_a?(String) && !uri.ascii_only?
|
|
|
|
uri = URI(URIParser.escape(uri))
|
|
|
|
non_ascii_hostname = URIParser.unescape(uri.host)
|
|
|
|
non_ascii_hostname.force_encoding(Encoding::UTF_8)
|
|
|
|
idna_hostname = Punycode.encode_hostname(non_ascii_hostname)
|
|
|
|
uri.host = idna_hostname
|
|
uri.non_ascii_hostname = non_ascii_hostname
|
|
uri
|
|
end
|
|
end
|
|
end
|
|
end
|