Class: Tina4::Request

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/request.rb

Defined Under Namespace

Classes: PayloadTooLarge

Constant Summary collapse

TINA4_MAX_UPLOAD_SIZE =

Maximum upload size in bytes (default 10 MB). Override via TINA4_MAX_UPLOAD_SIZE env var.

Integer(ENV.fetch("TINA4_MAX_UPLOAD_SIZE", 10_485_760))

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, path_params = {}) ⇒ Request

Returns a new instance of Request.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/tina4/request.rb', line 48

def initialize(env, path_params = {})
  @env = env
  @method = env["REQUEST_METHOD"]
  @path = env["PATH_INFO"] || "/"
  @query_string = env["QUERY_STRING"] || ""
  @content_type = env["CONTENT_TYPE"] || ""
  @path_params = path_params

  # Check upload size limit
  content_length = (env["CONTENT_LENGTH"] || 0).to_i
  if content_length > TINA4_MAX_UPLOAD_SIZE
    raise PayloadTooLarge,
      "Request body (#{content_length} bytes) exceeds TINA4_MAX_UPLOAD_SIZE (#{TINA4_MAX_UPLOAD_SIZE} bytes)"
  end

  # Client IP with X-Forwarded-For support
  @ip = extract_client_ip

  # Lazy-initialized fields (nil = not yet computed)
  @headers = nil
  @cookies = nil
  @session = nil
  @body_raw = nil
  @params = nil
  @files = nil
  @json_body = nil
  @query_hash = nil
  @body_parsed = nil
end

Instance Attribute Details

#content_typeObject (readonly)

Returns the value of attribute content_type.



39
40
41
# File 'lib/tina4/request.rb', line 39

def content_type
  @content_type
end

#envObject (readonly)

Returns the value of attribute env.



39
40
41
# File 'lib/tina4/request.rb', line 39

def env
  @env
end

#ipObject (readonly)

Returns the value of attribute ip.



39
40
41
# File 'lib/tina4/request.rb', line 39

def ip
  @ip
end

#methodObject (readonly)

Returns the value of attribute method.



39
40
41
# File 'lib/tina4/request.rb', line 39

def method
  @method
end

#pathObject (readonly)

Returns the value of attribute path.



39
40
41
# File 'lib/tina4/request.rb', line 39

def path
  @path
end

#path_paramsObject (readonly)

Returns the value of attribute path_params.



39
40
41
# File 'lib/tina4/request.rb', line 39

def path_params
  @path_params
end

#query_stringObject (readonly)

Returns the value of attribute query_string.



39
40
41
# File 'lib/tina4/request.rb', line 39

def query_string
  @query_string
end

#userObject

Returns the value of attribute user.



41
42
43
# File 'lib/tina4/request.rb', line 41

def user
  @user
end

Instance Method Details

#[](key) ⇒ Object



137
138
139
# File 'lib/tina4/request.rb', line 137

def [](key)
  params[key.to_s] || params[key.to_sym] || @path_params[key.to_sym]
end

#bearer_tokenObject



153
154
155
156
# File 'lib/tina4/request.rb', line 153

def bearer_token
  auth = header("authorization") || ""
  auth.sub(/\ABearer\s+/i, "") if auth =~ /\ABearer\s+/i
end

#bodyObject

Raw body string



108
109
110
# File 'lib/tina4/request.rb', line 108

def body
  @body_raw ||= read_body
end

#body_parsedObject

Parsed body (JSON or form data)



113
114
115
# File 'lib/tina4/request.rb', line 113

def body_parsed
  @body_parsed ||= parse_body
end

#cookiesObject



99
100
101
# File 'lib/tina4/request.rb', line 99

def cookies
  @cookies ||= parse_cookies
end

#filesObject



122
123
124
# File 'lib/tina4/request.rb', line 122

def files
  @files ||= extract_files
end

#header(name) ⇒ Object



141
142
143
# File 'lib/tina4/request.rb', line 141

def header(name)
  headers[name.to_s.downcase.gsub("-", "_")]
end

#headersObject

Lazy accessors



95
96
97
# File 'lib/tina4/request.rb', line 95

def headers
  @headers ||= extract_headers
end

#json_bodyObject



145
146
147
148
149
150
151
# File 'lib/tina4/request.rb', line 145

def json_body
  @json_body ||= begin
    JSON.parse(body)
  rescue JSON::ParserError, TypeError
    {}
  end
end

#param(key, default = nil) ⇒ Object

Look up a param by symbol or string key (indifferent access shortcut).



133
134
135
# File 'lib/tina4/request.rb', line 133

def param(key, default = nil)
  params[key.to_s] || params[key.to_sym] || default
end

#paramsObject

Merged params: query + body + path_params (path_params highest priority) Supports both string and symbol key access (indifferent access).



128
129
130
# File 'lib/tina4/request.rb', line 128

def params
  @params ||= build_params
end

#queryObject

Parsed query string as hash



118
119
120
# File 'lib/tina4/request.rb', line 118

def query
  @query_hash ||= parse_query_to_hash(@query_string)
end

#sessionObject



103
104
105
# File 'lib/tina4/request.rb', line 103

def session
  @session ||= Tina4::Session.new(@env)
end

#urlObject

Full absolute URL — scheme://host/path. Honours X-Forwarded-Proto / X-Forwarded-Host so apps behind a proxy still see the URL the client used. Matches Python/PHP/Node parity.



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/tina4/request.rb', line 81

def url
  scheme = env["HTTP_X_FORWARDED_PROTO"] || env["rack.url_scheme"] || "http"
  host = env["HTTP_X_FORWARDED_HOST"] || env["HTTP_HOST"] || env["SERVER_NAME"] || "localhost"
  port = env["SERVER_PORT"]
  url_str = "#{scheme}://#{host}"
  # Only append :port when the host doesn't already include one
  # (HTTP_HOST often does) and it's not the default for the scheme.
  url_str += ":#{port}" if port && !host.include?(":") && port.to_s != "80" && port.to_s != "443"
  url_str += @path
  url_str += "?#{@query_string}" unless @query_string.empty?
  url_str
end