class WinRM::WSMV::ReceiveResponseReader

Class for reading wsmv Receive_Response messages

Attributes

logger[R]

Public Class Methods

new(transport, logger) click to toggle source

Creates a new ReceiveResponseReader @param transport [HttpTransport] The WinRM SOAP transport @param logger [Logger] The logger to log diagnostic messages to

# File lib/winrm/wsmv/receive_response_reader.rb, line 30
def initialize(transport, logger)
  @transport = transport
  @logger = logger
  @output_decoder = CommandOutputDecoder.new
end

Public Instance Methods

read_output(wsmv_message) { |handled_out| ... } click to toggle source

Reads streams and returns decoded output @param wsmv_message [WinRM::WSMV::Base] A wsmv message to send to endpoint @yieldparam [string] standard out response text @yieldparam [string] standard error response text @yieldreturn [WinRM::Output] The command output

# File lib/winrm/wsmv/receive_response_reader.rb, line 43
def read_output(wsmv_message)
  with_output do |output|
    read_response(wsmv_message, true) do |stream, doc|
      handled_out = handle_stream(stream, output, doc)
      yield handled_out if handled_out && block_given?
    end
  end
end
read_response(wsmv_message, wait_for_done_state = false) { |stream, resp_doc| ... } click to toggle source

Reads streams sent in one or more receive response messages @param wsmv_message [WinRM::WSMV::Base] A wsmv message to send to endpoint @param wait_for_done_state whether to poll for a CommandState of Done @yieldparam [Hash] Hash representation of stream with type and text @yieldparam [REXML::Document] Complete SOAP envelope returned to wsmv_message

# File lib/winrm/wsmv/receive_response_reader.rb, line 57
def read_response(wsmv_message, wait_for_done_state = false)
  resp_doc = nil
  until command_done?(resp_doc, wait_for_done_state)
    logger.debug('[WinRM] Waiting for output...')
    resp_doc = send_get_output_message(wsmv_message.build)
    logger.debug('[WinRM] Processing output')
    read_streams(resp_doc) do |stream|
      yield stream, resp_doc
    end
  end
end

Protected Instance Methods

with_output() { |output| ... } click to toggle source
# File lib/winrm/wsmv/receive_response_reader.rb, line 71
def with_output
  output = WinRM::Output.new
  yield output
  output.exitcode ||= 0
  output
end

Private Instance Methods

command_done?(resp_doc, wait_for_done_state) click to toggle source
# File lib/winrm/wsmv/receive_response_reader.rb, line 106
def command_done?(resp_doc, wait_for_done_state)
  return false unless resp_doc
  return true unless wait_for_done_state

  REXML::XPath.match(
    resp_doc,
    "//*[@State='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/" \
    "CommandState/Done']"
  ).any?
end
handle_stream(stream, output, resp_doc) click to toggle source
# File lib/winrm/wsmv/receive_response_reader.rb, line 80
def handle_stream(stream, output, resp_doc)
  decoded_text = @output_decoder.decode(stream[:text])
  return unless decoded_text

  out = { stream[:type] => decoded_text }
  output << out
  if (code = REXML::XPath.first(resp_doc, "//*[local-name() = 'ExitCode']"))
    output.exitcode = code.text.to_i
  end
  [out[:stdout], out[:stderr]]
end
read_streams(response_document) { |type: attributes.to_sym, text: text| ... } click to toggle source
# File lib/winrm/wsmv/receive_response_reader.rb, line 117
def read_streams(response_document)
  body_path = "/*[local-name() = 'Envelope']/*[local-name() = 'Body']"
  path = "#{body_path}/*[local-name() = 'ReceiveResponse']/*[local-name() = 'Stream']"
  REXML::XPath.match(response_document, path).each do |stream|
    next if stream.text.nil? || stream.text.empty?

    yield type: stream.attributes['Name'].to_sym, text: stream.text
  end
end
send_get_output_message(message) click to toggle source
# File lib/winrm/wsmv/receive_response_reader.rb, line 92
def send_get_output_message(message)
  @transport.send_request(message)
rescue WinRMWSManFault => e
  # If no output is available before the wsman:OperationTimeout expires,
  # the server MUST return a WSManFault with the Code attribute equal to
  # 2150858793. When the client receives this fault, it SHOULD issue
  # another Receive request.
  # http://msdn.microsoft.com/en-us/library/cc251676.aspx
  raise unless e.fault_code == '2150858793'

  logger.debug('[WinRM] retrying receive request after timeout')
  retry
end