Class: Audioproxy::UrlBuilder
- Inherits:
-
Object
- Object
- Audioproxy::UrlBuilder
- Defined in:
- lib/audioproxy/url_builder.rb
Overview
Assembles {endpoint}/{signature}/{options}/{source} URLs, byte-compatible
with the proxy's reference signer.
The signature covers everything after itself (leading / included), so an
endpoint path prefix cannot disturb it.
This is the Rails-facing half and may use ActiveSupport freely. The HMAC itself lives in Audioproxy::Signer, which may not — see D1.
Constant Summary collapse
- INSECURE_SEGMENT =
Literal signature segment the proxy accepts under AP_ALLOW_INSECURE.
"insecure".freeze
- FALLBACK_OPTIONS =
The proxy's path grammar has no optionless form, so the minimal always-valid options string is its default format spelled out.
"f:mp3".freeze
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
Instance Method Summary collapse
-
#initialize(config = Audioproxy.config) ⇒ UrlBuilder
constructor
A new instance of UrlBuilder.
-
#sign(rest_of_path) ⇒ Object
Signs via Audioproxy::Signer.
-
#url_for(source, raw: nil, endpoint: nil, unsigned: nil, expires_in: Expiry::UNSET, expires_at: Expiry::UNSET, **typed) ⇒ Object
Typed option keys (+f:+,
br:,t:…) arrive as keyword arguments and render in the order they were written.
Constructor Details
#initialize(config = Audioproxy.config) ⇒ UrlBuilder
Returns a new instance of UrlBuilder.
24 25 26 |
# File 'lib/audioproxy/url_builder.rb', line 24 def initialize(config = Audioproxy.config) @config = config end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
22 23 24 |
# File 'lib/audioproxy/url_builder.rb', line 22 def config @config end |
Instance Method Details
#sign(rest_of_path) ⇒ Object
Signs via Audioproxy::Signer. Whether the config can sign is this class's problem; how the bytes are produced is the signer's.
57 58 59 60 61 62 63 64 |
# File 'lib/audioproxy/url_builder.rb', line 57 def sign(rest_of_path) missing = [ (:key unless config.key), (:salt unless config.salt) ].compact unless missing.empty? raise ConfigurationError, "Audioproxy cannot sign a URL: #{missing.join(" and ")} not configured (set them, or use unsigned: true)" end Signer.new(key: config.key, salt: config.salt).sign(rest_of_path) end |
#url_for(source, raw: nil, endpoint: nil, unsigned: nil, expires_in: Expiry::UNSET, expires_at: Expiry::UNSET, **typed) ⇒ Object
Typed option keys (+f:+, br:, t: …) arrive as keyword arguments and
render in the order they were written. Each is also accepted as its
spelled-out alias (+format:+, bitrate:, trim: …), resolved to the
canonical key before anything is rendered. A keyword that is neither a
builder option nor a proxy option key raises rather than being ignored.
expires_in: (a duration or Integer seconds from now) and expires_at:
(the instant itself) are mutually exclusive and time-box this one URL,
overriding config.expires_in; either given as nil opts out of it (D6).
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/audioproxy/url_builder.rb', line 37 def url_for(source, raw: nil, endpoint: nil, unsigned: nil, expires_in: Expiry::UNSET, expires_at: Expiry::UNSET, **typed) base = endpoint.nil? ? config.endpoint : Config.new.tap { |c| c.endpoint = endpoint }.endpoint raise ConfigurationError, "Audioproxy has no endpoint configured" if base.nil? # Once per URL, so the window arithmetic and the past-check cannot # straddle a second boundary (D4). expiry = Expiry.( expires_in: expires_in, expires_at: expires_at, default_expires_in: config.expires_in, now: Time.now.to_i ) rest_of_path = "/#{(raw, typed, expiry)}/#{source_segment(source)}" insecure = unsigned.nil? ? config.unsigned : unsigned "#{base}/#{insecure ? INSECURE_SEGMENT : sign(rest_of_path)}#{rest_of_path}" end |