diff --git a/lib/hyde/request.rb b/lib/hyde/request.rb index cc7191c..fd8ea51 100644 --- a/lib/hyde/request.rb +++ b/lib/hyde/request.rb @@ -1,21 +1,87 @@ +# frozen_string_literal: true + require 'uri' module Hyde + # Request wrapper for Rack protocol class Request + # @param env [Array] def initialize(env) - @env = env - @method = env["REQUEST_METHOD"] - @path = env["PATH_INFO"] + # Should not be used under regular circumstances or depended upon. + @_original_env = env + # Rack environment variable bindings. Should be public. + @request_method = env["REQUEST_METHOD"] @script_name = env["SCRIPT_NAME"] - @query_string = env["QUERY_STRING"] - @host = env["SERVER_NAME"] - @port = env["SERVER_PORT"] - @virtual_host = env["HTTP_HOST"] - @headers = env.filter { |k, _| k.start_with? "HTTP_" } + @path_info = env["PATH_INFO"] + @server_name = env["SERVER_NAME"] + @server_port = env["SERVER_PORT"] + @server_protocol = env["SERVER_PROTOCOL"] + @headers = init_headers(env) + # Encapsulates all rack variables. Should not be public. + @rack = init_rack_vars(env) end - attr_reader @host - attr_reader @port + # Returns request body (if POST data exists) + def body + @rack.input&.gets + end + attr_reader :request_method, :script_name, :path_info, :server_name, :server_port, :server_protocol, :headers + + private + + # Initialize rack parameters struct + # @param env [Hash] + # @return Object + def init_rack_vars(env) + rack_vars = env.filter_map do |k| + k.delete_prefix "rack." if k.start_with? "rack." + end + rack_vars["multipart"] = init_multipart_vars + rack_keys = rack_vars.keys.map(&:to_sym) + Struct.new(*rack_keys) + .new(*rack_vars.values_at(rack_keys)) + .freeze + end + + # Initialize multipart parameters struct + # @param env [Hash] + # @return Object + def init_multipart_vars + multipart_vars = env.filter_map do |k| + k.delete_prefix "rack.multipart." if k.start_with? "rack.multipart" + end + multipart_keys = multipart_vars.keys.map(&:to_sym) + Struct.new(*multipart_keys) + .new(*multipart_vars.values_at(multipart_keys)) + .freeze + end + + # Iniitalize headers hash + # @param env [Hash] + # @return Hash + def init_headers(env) + headers = env.filter_map do |name, value| + [name.delete_prefix("HTTP_"), value] if name.start_with?("HTTP_") + end.to_h + headers.merge!({ "CONTENT_TYPE" => env["CONTENT_TYPE"], + "CONTENT_LENGTH" => env["CONTENT_LENGTH"] }) + headers.freeze + end + end + + # Rack protocol response wrapper. + class Response + def initialize + @status = 404 + @headers = {} + @body = [] + end + + # Finish constructing Rack protocol response. + # @return [Array(Integer,Hash,Array)] + def finalize + [@status, @headers, @body] + end end end