Class: Aspera::LinkHeader

Inherits:
Object
  • Object
show all
Defined in:
lib/aspera/link_header.rb

Overview

Parse and represent an HTTP Link header as per RFC 8288. Inspired by the link_header gem, with the following fixes:

- rel lookup is case-insensitive (RFC 7230: parameter names are case-insensitive)
- uses StringScanner so commas inside <URI> are never mistaken for entry separators
- no external dependency

Defined Under Namespace

Classes: Link

Constant Summary collapse

TOKEN_RE =

RFC 2616 token: any char except separators

/[^()<>@,;:\"\[\]?={}\s]+/
QUOTED_RE =

double-quoted string with backslash escapes

/"((?:[^"\\]|\\.)*)"/
HREF_RE =

possibly followed by ;

/\s*<([^>]*)>\s*;?\s*/
ATTR_RE =

key=value or key="value"

/(#{TOKEN_RE})\s*=\s*(#{TOKEN_RE}|#{QUOTED_RE})\s*/
SEMI_RE =

parameter separator

/;\s*/
COMMA_RE =

link entry separator

/,\s*/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(links = []) ⇒ LinkHeader

Returns a new instance of LinkHeader.



30
31
32
# File 'lib/aspera/link_header.rb', line 30

def initialize(links = [])
  @links = links
end

Instance Attribute Details

Returns the value of attribute links.



28
29
30
# File 'lib/aspera/link_header.rb', line 28

def links
  @links
end

Class Method Details

.parse(raw) ⇒ LinkHeader

Parse a raw Link header value into a LinkHeader instance. Uses StringScanner so that commas inside are not treated as separators.

Parameters:

Returns:



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/aspera/link_header.rb', line 48

def parse(raw)
  return new unless raw && !raw.empty?

  links = []
  scanner = StringScanner.new(raw)

  while scanner.scan(HREF_RE)
    href  = scanner[1].strip
    attrs = []
    while scanner.scan(ATTR_RE)
      key   = scanner[1]
      # scanner[2] = full match (token or "quoted"), scanner[3] = content inside double-quotes
      value = scanner[3] || scanner[2]
      attrs << [key, value]
      break unless scanner.scan(SEMI_RE)
    end
    links << Link.new(href, attrs)
    break unless scanner.scan(COMMA_RE)
  end

  new(links)
end

Instance Method Details

#find_href(rel: 'next') ⇒ String?

Return the href of the first link whose rel attribute matches rel. Comparison is case-insensitive per RFC 7230 s.3.2 and RFC 8288 s.3. Returns nil if no link with that relation exists.

Parameters:

  • rel (String) (defaults to: 'next')

Returns:



39
40
41
# File 'lib/aspera/link_header.rb', line 39

def find_href(rel: 'next')
  @links.detect { |link| link['rel']&.casecmp?(rel) }&.href
end