lib/playwright/channel_owners/request.rb
require 'base64' module Playwright # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_network.py define_channel_owner :Request do private def after_initialize @redirected_from = ChannelOwners::Request.from_nullable(@initializer['redirectedFrom']) @redirected_from&.send(:update_redirected_to, self) @provisional_headers = RawHeaders.new(@initializer['headers']) @timing = { startTime: 0, domainLookupStart: -1, domainLookupEnd: -1, connectStart: -1, secureConnectionStart: -1, connectEnd: -1, requestStart: -1, responseStart: -1, responseEnd: -1, } @fallback_overrides = {} @url = @initializer['url'] end private def fallback_overrides @fallback_overrides end def apply_fallback_overrides(overrides) allowed_key = %i[url method headers postData] overrides.each do |key, value| raise ArgumentError.new("invalid key: #{key}") unless allowed_key.include?(key) @fallback_overrides[key] = value end @fallback_overrides end def url @fallback_overrides[:url] || @url end private def internal_url @url end def resource_type @initializer['resourceType'] end def method @fallback_overrides[:method] || @initializer['method'] end def post_data post_data_buffer end def post_data_json data = post_data return unless data content_type = headers['content-type'] return unless content_type if content_type.include?("application/x-www-form-urlencoded") URI.decode_www_form(data).to_h else JSON.parse(data) end end def post_data_buffer if (override = @fallback_overrides[:postData]) return override end if (base64_content = @initializer['postData']) Base64.strict_decode64(base64_content) else nil end end def existing_response @response end def response resp = @channel.send_message_to_server('response') ChannelOwners::Response.from_nullable(resp) end class FramePageNotReadyError < StandardError MESSAGE = [ 'Frame for this navigation request is not available, because the request', 'was issued before the frame is created. You can check whether the request', 'is a navigation request by calling isNavigationRequest() method.', ].join('\n').freeze def initialize super(MESSAGE) end end def frame ChannelOwners::Frame.from(@initializer['frame']).tap do |result| unless result.page raise FramePageNotReadyError.new end end end def navigation_request? @initializer['isNavigationRequest'] end def failure @failure_text end attr_reader :redirected_from, :redirected_to, :timing def headers if (override = @fallback_overrides[:headers]) RawHeaders.new(HttpHeaders.new(override).as_serialized).headers else @provisional_headers.headers end end # @return [RawHeaders|nil] private def actual_headers if (override = @fallback_overrides[:headers]) RawHeaders.new(HttpHeaders.new(override).as_serialized) else @actual_headers ||= raw_request_headers end end private def raw_request_headers RawHeaders.new(@channel.send_message_to_server('rawRequestHeaders')) end def all_headers actual_headers.headers end def headers_array actual_headers.headers_array end def header_value(name) actual_headers.get(name) end def header_values(name) actual_headers.get_all(name) end def sizes res = response unless res raise 'Unable to fetch sizes for failed request' end res.send(:sizes) end private def update_response(response) @response = response end private def update_redirected_to(request) @redirected_to = request end private def update_failure_text(failure_text) @failure_text = failure_text end private def update_timings( start_time:, domain_lookup_start:, domain_lookup_end:, connect_start:, secure_connection_start:, connect_end:, request_start:, response_start:) @timing[:startTime] = start_time @timing[:domainLookupStart] = domain_lookup_start @timing[:domainLookupEnd] = domain_lookup_end @timing[:connectStart] = connect_start @timing[:secureConnectionStart] = secure_connection_start @timing[:connectEnd] = connect_end @timing[:requestStart] = request_start @timing[:responseStart] = response_start end private def update_response_end_timing(response_end_timing) @timing[:responseEnd] = response_end_timing end end end