Module: ClientApiBuilder::NetHTTP::Request
- Defined in:
- lib/client_api_builder/net_http_request.rb
Constant Summary collapse
- ALLOWED_FILE_MODES =
Allowed file modes for stream_to_file to prevent arbitrary mode injection
%w[w wb a ab w+ wb+ a+ ab+].freeze
- DEFAULT_SECURE_OPTIONS =
Default connection options with secure SSL settings
{ verify_mode: OpenSSL::SSL::VERIFY_PEER, open_timeout: 30, read_timeout: 60 }.freeze
- METHOD_TO_NET_HTTP_CLASS =
{ copy: Net::HTTP::Copy, delete: Net::HTTP::Delete, get: Net::HTTP::Get, head: Net::HTTP::Head, lock: Net::HTTP::Lock, mkcol: Net::HTTP::Mkcol, move: Net::HTTP::Move, options: Net::HTTP::Options, patch: Net::HTTP::Patch, post: Net::HTTP::Post, propfind: Net::HTTP::Propfind, proppatch: Net::HTTP::Proppatch, put: Net::HTTP::Put, trace: Net::HTTP::Trace, unlock: Net::HTTP::Unlock }.freeze
Instance Method Summary collapse
- #request(method:, uri:, body:, headers:, connection_options:) ⇒ Object
- #stream(method:, uri:, body:, headers:, connection_options:) ⇒ Object
- #stream_to_file(method:, uri:, body:, headers:, connection_options:, file:) ⇒ Object
- #stream_to_io(method:, uri:, body:, headers:, connection_options:, io:) ⇒ Object
Instance Method Details
#request(method:, uri:, body:, headers:, connection_options:) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/client_api_builder/net_http_request.rb', line 38 def request(method:, uri:, body:, headers:, connection_options:) request = METHOD_TO_NET_HTTP_CLASS[method].new(uri.request_uri, headers) request.body = body if body # Merge secure defaults, then user options, ensuring SSL verification is enabled for HTTPS = uri.scheme == 'https' ? DEFAULT_SECURE_OPTIONS.merge(use_ssl: true) : {} = .merge() Net::HTTP.start(uri.hostname, uri.port, ) do |http| http.request(request) do |response| yield response if block_given? end end end |
#stream(method:, uri:, body:, headers:, connection_options:) ⇒ Object
53 54 55 56 57 58 59 |
# File 'lib/client_api_builder/net_http_request.rb', line 53 def stream(method:, uri:, body:, headers:, connection_options:) request(method: method, uri: uri, body: body, headers: headers, connection_options: ) do |response| response.read_body do |chunk| yield response, chunk end end end |
#stream_to_file(method:, uri:, body:, headers:, connection_options:, file:) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/client_api_builder/net_http_request.rb', line 67 def stream_to_file(method:, uri:, body:, headers:, connection_options:, file:) # Use dup to avoid mutating the original hash opts = .dup mode = opts.delete(:file_mode) # Validate file mode - use whitelist approach mode = if mode.nil? 'wb' elsif ALLOWED_FILE_MODES.include?(mode.to_s) mode.to_s else raise ArgumentError, "Invalid file mode: #{mode.inspect}. Allowed modes: #{ALLOWED_FILE_MODES.join(', ')}" end # Validate file path - expand to absolute path and check for path traversal = File.(file) raise ArgumentError, 'Invalid file path: potential path traversal detected' if file.to_s.include?('..') || .include?("\0") File.open(, mode) do |io| stream_to_io(method: method, uri: uri, body: body, headers: headers, connection_options: opts, io: io) end end |
#stream_to_io(method:, uri:, body:, headers:, connection_options:, io:) ⇒ Object
61 62 63 64 65 |
# File 'lib/client_api_builder/net_http_request.rb', line 61 def stream_to_io(method:, uri:, body:, headers:, connection_options:, io:) stream(method: method, uri: uri, body: body, headers: headers, connection_options: ) do |_, chunk| io.write chunk end end |