module HTTPX::AltSvc

  1. lib/httpx/altsvc.rb
  2. lib/httpx/connection.rb
  3. show all

Classes and Modules

  1. HTTPX::AltSvc::ConnectionMixin

Public Instance methods

cached_altsvc(origin)
[show source]
   # File lib/httpx/altsvc.rb
68 def cached_altsvc(origin)
69   now = Utils.now
70   @altsvc_mutex.synchronize do
71     lookup(origin, now)
72   end
73 end
cached_altsvc_set(origin, entry)
[show source]
   # File lib/httpx/altsvc.rb
75 def cached_altsvc_set(origin, entry)
76   now = Utils.now
77   @altsvc_mutex.synchronize do
78     return if @altsvcs[origin].any? { |altsvc| altsvc["origin"] == entry["origin"] }
79 
80     entry["TTL"] = Integer(entry["ma"]) + now if entry.key?("ma")
81     @altsvcs[origin] << entry
82     entry
83   end
84 end
emit(request, response)
[show source]
    # File lib/httpx/altsvc.rb
 95 def emit(request, response)
 96   return unless response.respond_to?(:headers)
 97   # Alt-Svc
 98   return unless response.headers.key?("alt-svc")
 99 
100   origin = request.origin
101   host = request.uri.host
102 
103   altsvc = response.headers["alt-svc"]
104 
105   # https://datatracker.ietf.org/doc/html/rfc7838#section-3
106   # A field value containing the special value "clear" indicates that the
107   # origin requests all alternatives for that origin to be invalidated
108   # (including those specified in the same response, in case of an
109   # invalid reply containing both "clear" and alternative services).
110   if altsvc == "clear"
111     @altsvc_mutex.synchronize do
112       @altsvcs[origin].clear
113     end
114 
115     return
116   end
117 
118   parse(altsvc, host: host) do |alt_origin, alt_params|
119     alt_origin.host ||= host
120     yield(alt_origin, origin, alt_params)
121   end
122 end
lookup(origin, ttl)
[show source]
   # File lib/httpx/altsvc.rb
86 def lookup(origin, ttl)
87   return [] unless @altsvcs.key?(origin)
88 
89   @altsvcs[origin] = @altsvcs[origin].select do |entry|
90     !entry.key?("TTL") || entry["TTL"] > ttl
91   end
92   @altsvcs[origin].reject { |entry| entry["noop"] }
93 end
parse(altsvc, host: nil)
[show source]
    # File lib/httpx/altsvc.rb
124 def parse(altsvc, host: nil)
125   return enum_for(__method__, altsvc, host: host) unless block_given?
126 
127   scanner = StringScanner.new(altsvc)
128   until scanner.eos?
129     alt_services = [] #: Array[String]
130 
131     while (alt_service = scanner.scan(/[^=]+=("[^"]+")/))
132       alt_services << alt_service
133       scanner.skip(/[, ]+/)
134     end
135 
136     scanner.skip(/;/)
137 
138     alt_params = [] #: Array[String]
139     loop do
140       alt_param = scanner.scan(/[^=]+=("[^"]+"|[^;,]+)/)
141       alt_params << alt_param.strip if alt_param
142       scanner.skip(/;/)
143       break if scanner.eos? || scanner.scan(/ *, */)
144     end
145     alt_params = Hash[alt_params.map do |field|
146       field.split("=", 2)
147     end]
148 
149     alt_services.each do |alt_service|
150       alt_proto, alt_authority = alt_service.split("=", 2)
151       alt_origin = parse_altsvc_origin(alt_proto, alt_authority, host: host)
152 
153       next unless alt_origin
154 
155       yield(alt_origin, alt_params.merge("proto" => alt_proto))
156     end
157   end
158 end
parse_altsvc_origin(alt_proto, alt_origin, host: nil)
[show source]
    # File lib/httpx/altsvc.rb
169 def parse_altsvc_origin(alt_proto, alt_origin, host: nil)
170   alt_scheme = parse_altsvc_scheme(alt_proto)
171 
172   return unless alt_scheme
173 
174   alt_origin = alt_origin[1..-2] if alt_origin.start_with?("\"") && alt_origin.end_with?("\"")
175 
176   uri = URI.parse("#{alt_scheme}://#{alt_origin}")
177   uri.host = host if uri.host.nil? || uri.host.empty?
178   uri
179 end
parse_altsvc_scheme(alt_proto)
[show source]
    # File lib/httpx/altsvc.rb
160 def parse_altsvc_scheme(alt_proto)
161   case alt_proto
162   when "h2c"
163     "http"
164   when "h2", "quic", /^h3/
165     "https"
166   end
167 end