Class: Html2rss::RequestService::Response

Inherits:
Object
  • Object
show all
Defined in:
lib/html2rss/request_service/response.rb

Overview

To be used by strategies to provide their response.

Constant Summary collapse

EMPTY_TRANSPORT_META =

Default when a strategy does not attach transport telemetry.

{}.freeze
EMPTY_CAPTURED_RESPONSES =

Default when a strategy does not capture sub-resource responses.

[].freeze
HTML_BODY_SNIFF =

Bodies that look like HTML even when Content-Type is missing, empty, or wrong.

/\A\s*(?:<!DOCTYPE\s+html|<html)/i

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(body:, url:, headers: {}, status: nil, transport_meta: EMPTY_TRANSPORT_META, captured_responses: EMPTY_CAPTURED_RESPONSES) ⇒ Response

rubocop:disable Metrics/MethodLength, Metrics/ParameterLists -- transport + capture fields stay co-located

Parameters:

  • body (String)

    the body of the response

  • url (Html2rss::Url)

    the final request URL

  • headers (Hash) (defaults to: {})

    the headers of the response

  • status (Integer, nil) (defaults to: nil)

    the HTTP status code when available

  • transport_meta (Hash) (defaults to: EMPTY_TRANSPORT_META)

    allowlisted upstream telemetry (frozen when present)

  • captured_responses (Array<Hash>) (defaults to: EMPTY_CAPTURED_RESPONSES)

    JSON XHR/fetch bodies captured during browser scrapes



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/html2rss/request_service/response.rb', line 35

def initialize(body:, url:, headers: {}, status: nil, transport_meta: EMPTY_TRANSPORT_META,
               captured_responses: EMPTY_CAPTURED_RESPONSES)
  @body = body

  headers = headers.dup
  headers.transform_keys!(&:to_s)
  HashUtil.assert_string_keys!(headers, context: 'response headers', deep: false)

  @headers = headers
  @status = status
  @url = url
  @transport_meta = transport_meta.nil? || transport_meta.empty? ? EMPTY_TRANSPORT_META : transport_meta.freeze
  @captured_responses = if captured_responses.nil? || captured_responses.empty?
                          EMPTY_CAPTURED_RESPONSES
                        else
                          captured_responses.freeze
                        end
end

Instance Attribute Details

#bodyString (readonly)

Returns the raw body of the response.

Returns:

  • (String)

    the raw body of the response



56
57
58
# File 'lib/html2rss/request_service/response.rb', line 56

def body
  @body
end

#captured_responsesArray<Hash> (readonly)

Returns captured JSON XHR/fetch responses (empty when unsupported).

Returns:

  • (Array<Hash>)

    captured JSON XHR/fetch responses (empty when unsupported)



71
72
73
# File 'lib/html2rss/request_service/response.rb', line 71

def captured_responses
  @captured_responses
end

#headersHash{String => Object} (readonly)

Returns the headers of the response.

Returns:

  • (Hash{String => Object})

    the headers of the response



59
60
61
# File 'lib/html2rss/request_service/response.rb', line 59

def headers
  @headers
end

#statusInteger? (readonly)

Returns the HTTP status code when known.

Returns:

  • (Integer, nil)

    the HTTP status code when known



62
63
64
# File 'lib/html2rss/request_service/response.rb', line 62

def status
  @status
end

#transport_metaHash (readonly)

Returns allowlisted upstream transport telemetry.

Returns:

  • (Hash)

    allowlisted upstream transport telemetry



68
69
70
# File 'lib/html2rss/request_service/response.rb', line 68

def transport_meta
  @transport_meta
end

#urlHtml2rss::Url (readonly)

Returns the URL of the response.

Returns:



65
66
67
# File 'lib/html2rss/request_service/response.rb', line 65

def url
  @url
end

Instance Method Details

#content_typeString

Returns normalized content type header value.

Returns:

  • (String)

    normalized content type header value



74
# File 'lib/html2rss/request_service/response.rb', line 74

def content_type = header('content-type').to_s

#feed_response?Boolean

Returns whether response content is RSS/Atom (header or sniffed body).

Returns:

  • (Boolean)

    whether response content is RSS/Atom (header or sniffed body)



85
86
87
88
89
# File 'lib/html2rss/request_service/response.rb', line 85

def feed_response?
  return @feed_response if defined?(@feed_response)

  @feed_response = feed_content_type? || (!json_response? && !html_looking_body? && feed_looking_body?)
end

#html_response?Boolean

Returns whether response content is HTML (header or sniffed body, never JSON).

Returns:

  • (Boolean)

    whether response content is HTML (header or sniffed body, never JSON)



80
81
82
# File 'lib/html2rss/request_service/response.rb', line 80

def html_response?
  content_type.include?('text/html') || (!json_response? && !feed_response? && html_looking_body?)
end

#json_response?Boolean

Returns whether response content is JSON.

Returns:

  • (Boolean)

    whether response content is JSON



77
# File 'lib/html2rss/request_service/response.rb', line 77

def json_response? = content_type.include?('application/json')

#parsed_bodyNokogiri::HTML::Document, Hash

Returns the parsed body of the response, frozen object.

Returns:

  • (Nokogiri::HTML::Document, Hash)

    the parsed body of the response, frozen object

Raises:



94
95
96
97
98
99
100
101
102
# File 'lib/html2rss/request_service/response.rb', line 94

def parsed_body
  @parsed_body ||= if html_response?
                     parse_html_document
                   elsif json_response?
                     JSON.parse(body, symbolize_names: true).freeze
                   else
                     raise UnsupportedResponseContentType, "Unsupported content type: #{content_type}"
                   end
end