You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

http_io.rb 4.4 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. require 'net/http'
  2. require 'tempfile'
  3. require 'shellwords'
  4. module Cucumber
  5. module Formatter
  6. class HTTPIO
  7. class << self
  8. # Returns an IO that will write to a HTTP request's body
  9. # https_verify_mode can be set to OpenSSL::SSL::VERIFY_NONE
  10. # to ignore unsigned certificate - setting to nil will verify the certificate
  11. def open(url, https_verify_mode = nil, reporter = nil)
  12. @https_verify_mode = https_verify_mode
  13. uri, method, headers = CurlOptionParser.parse(url)
  14. IOHTTPBuffer.new(uri, method, headers, https_verify_mode, reporter)
  15. end
  16. end
  17. end
  18. class CurlOptionParser
  19. def self.parse(options)
  20. args = Shellwords.split(options)
  21. url = nil
  22. http_method = 'PUT'
  23. headers = {}
  24. until args.empty?
  25. arg = args.shift
  26. case arg
  27. when '-X', '--request'
  28. http_method = remove_arg_for(args, arg)
  29. when '-H'
  30. header_arg = remove_arg_for(args, arg)
  31. headers = headers.merge(parse_header(header_arg))
  32. else
  33. raise StandardError, "#{options} was not a valid curl command. Can't set url to #{arg} it is already set to #{url}" if url
  34. url = arg
  35. end
  36. end
  37. raise StandardError, "#{options} was not a valid curl command" unless url
  38. [
  39. url,
  40. http_method,
  41. headers
  42. ]
  43. end
  44. def self.remove_arg_for(args, arg)
  45. return args.shift unless args.empty?
  46. raise StandardError, "Missing argument for #{arg}"
  47. end
  48. def self.parse_header(header_arg)
  49. parts = header_arg.split(':', 2)
  50. raise StandardError, "#{header_arg} was not a valid header" unless parts.length == 2
  51. { parts[0].strip => parts[1].strip }
  52. end
  53. end
  54. class IOHTTPBuffer
  55. attr_reader :uri, :method, :headers
  56. def initialize(uri, method, headers = {}, https_verify_mode = nil, reporter = nil)
  57. @uri = URI(uri)
  58. @method = method
  59. @headers = headers
  60. @write_io = Tempfile.new('cucumber', encoding: 'UTF-8')
  61. @https_verify_mode = https_verify_mode
  62. @reporter = reporter || NoReporter.new
  63. end
  64. def close
  65. response = send_content(@uri, @method, @headers)
  66. @reporter.report(response.body)
  67. @write_io.close
  68. return if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPRedirection)
  69. raise StandardError, "request to #{uri} failed with status #{response.code}"
  70. end
  71. def write(data)
  72. @write_io.write(data)
  73. end
  74. def flush
  75. @write_io.flush
  76. end
  77. def closed?
  78. @write_io.closed?
  79. end
  80. private
  81. def send_content(uri, method, headers, attempt = 10)
  82. content = (method == 'GET' ? StringIO.new : @write_io)
  83. http = build_client(uri, @https_verify_mode)
  84. raise StandardError, "request to #{uri} failed (too many redirections)" if attempt <= 0
  85. req = build_request(
  86. uri,
  87. method,
  88. headers.merge(
  89. 'Content-Length' => content.size.to_s
  90. )
  91. )
  92. content.rewind
  93. req.body_stream = content
  94. begin
  95. response = http.request(req)
  96. rescue SystemCallError
  97. # We may get the redirect response before pushing the file.
  98. response = http.request(build_request(uri, method, headers))
  99. end
  100. case response
  101. when Net::HTTPAccepted
  102. send_content(URI(response['Location']), 'PUT', {}, attempt - 1) if response['Location']
  103. when Net::HTTPRedirection
  104. send_content(URI(response['Location']), method, headers, attempt - 1)
  105. end
  106. response
  107. end
  108. def build_request(uri, method, headers)
  109. method_class_name = "#{method[0].upcase}#{method[1..].downcase}"
  110. req = Net::HTTP.const_get(method_class_name).new(uri)
  111. headers.each do |header, value|
  112. req[header] = value
  113. end
  114. req
  115. end
  116. def build_client(uri, https_verify_mode)
  117. http = Net::HTTP.new(uri.hostname, uri.port)
  118. if uri.scheme == 'https'
  119. http.use_ssl = true
  120. http.verify_mode = https_verify_mode if https_verify_mode
  121. end
  122. http
  123. end
  124. end
  125. end
  126. end

No Description

Contributors (1)