Class: Tina4::Request
- Inherits:
-
Object
- Object
- Tina4::Request
- 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
-
#content_type ⇒ Object
readonly
Returns the value of attribute content_type.
-
#env ⇒ Object
readonly
Returns the value of attribute env.
-
#ip ⇒ Object
readonly
Returns the value of attribute ip.
-
#method ⇒ Object
readonly
Returns the value of attribute method.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#path_params ⇒ Object
readonly
Returns the value of attribute path_params.
-
#query_string ⇒ Object
readonly
Returns the value of attribute query_string.
-
#user ⇒ Object
Returns the value of attribute user.
Class Method Summary collapse
-
.secure_scheme?(env) ⇒ Boolean
Is this request HTTPS from the CLIENT's point of view?.
Instance Method Summary collapse
- #[](key) ⇒ Object
- #bearer_token ⇒ Object
-
#body ⇒ Object
(also: #body_parsed)
Parsed body (JSON -> Hash, form-urlencoded -> Hash, multipart -> fields Hash, else the current fallback).
-
#body_raw ⇒ Object
Raw body string — the bytes exactly as the client sent them.
- #cookies ⇒ Object
- #files ⇒ Object
- #header(name) ⇒ Object
-
#headers ⇒ Object
Lazy accessors.
-
#initialize(env, path_params = {}) ⇒ Request
constructor
A new instance of Request.
- #json_body ⇒ Object
-
#param(key, default = nil) ⇒ Object
Look up a param by symbol or string key (indifferent access shortcut).
-
#params ⇒ Object
Merged params: query + body + path_params (path_params highest priority) Supports both string and symbol key access (indifferent access).
-
#query ⇒ Object
Parsed query string as hash.
- #session ⇒ Object
- #url ⇒ Object
Constructor Details
#initialize(env, path_params = {}) ⇒ Request
Returns a new instance of Request.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/tina4/request.rb', line 125 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_type ⇒ Object (readonly)
Returns the value of attribute content_type.
116 117 118 |
# File 'lib/tina4/request.rb', line 116 def content_type @content_type end |
#env ⇒ Object (readonly)
Returns the value of attribute env.
116 117 118 |
# File 'lib/tina4/request.rb', line 116 def env @env end |
#ip ⇒ Object (readonly)
Returns the value of attribute ip.
116 117 118 |
# File 'lib/tina4/request.rb', line 116 def ip @ip end |
#method ⇒ Object (readonly)
Returns the value of attribute method.
116 117 118 |
# File 'lib/tina4/request.rb', line 116 def method @method end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
116 117 118 |
# File 'lib/tina4/request.rb', line 116 def path @path end |
#path_params ⇒ Object (readonly)
Returns the value of attribute path_params.
116 117 118 |
# File 'lib/tina4/request.rb', line 116 def path_params @path_params end |
#query_string ⇒ Object (readonly)
Returns the value of attribute query_string.
116 117 118 |
# File 'lib/tina4/request.rb', line 116 def query_string @query_string end |
#user ⇒ Object
Returns the value of attribute user.
118 119 120 |
# File 'lib/tina4/request.rb', line 118 def user @user end |
Class Method Details
.secure_scheme?(env) ⇒ Boolean
Is this request HTTPS from the CLIENT's point of view?
TLS is normally terminated at a proxy (nginx, HAProxy, ALB, Cloudflare, most container deploys) that then forwards plain HTTP to the app, so rack.url_scheme is "http" on exactly the deployments that ARE encrypted. x-forwarded-proto carries the scheme the client actually used, and a chain of proxies appends each hop ("https, http") — the FIRST is the client-facing one. Falls back to the native rack scheme, then the CGI HTTPS var.
This is the single source of truth for BOTH the URL scheme (#url) and the session-cookie Secure flag (Session#cookie_header). They used to decide it independently and could disagree — url() said https while the cookie concluded plain HTTP and dropped Secure (ruby#31, parity with PHP Request::isSecureScheme / tina4-php#175).
173 174 175 176 177 178 179 180 181 182 |
# File 'lib/tina4/request.rb', line 173 def self.secure_scheme?(env) forwarded = (env["HTTP_X_FORWARDED_PROTO"] || "").to_s unless forwarded.strip.empty? return forwarded.split(",").first.to_s.strip.casecmp("https").zero? end scheme = (env["rack.url_scheme"] || "").to_s return true if scheme.casecmp("https").zero? https = (env["HTTPS"] || "").to_s !https.empty? && https.casecmp("off") != 0 end |
Instance Method Details
#[](key) ⇒ Object
252 253 254 |
# File 'lib/tina4/request.rb', line 252 def [](key) params[key.to_s] || params[key.to_sym] || @path_params[key.to_sym] end |
#bearer_token ⇒ Object
271 272 273 274 |
# File 'lib/tina4/request.rb', line 271 def bearer_token auth = header("authorization") || "" auth.sub(/\ABearer\s+/i, "") if auth =~ /\ABearer\s+/i end |
#body ⇒ Object Also known as: body_parsed
Parsed body (JSON -> Hash, form-urlencoded -> Hash, multipart ->
fields Hash, else the current fallback). This matches Python's
request.body, PHP's, and Node's: body is the PARSED payload, not
the raw bytes. For the raw string use body_raw.
217 218 219 |
# File 'lib/tina4/request.rb', line 217 def body @body_parsed ||= parse_body end |
#body_raw ⇒ Object
Raw body string — the bytes exactly as the client sent them.
(This is what body used to return before the cross-framework
parity flip; SOAP/GraphQL and any consumer that needs the raw text
reads this.)
225 226 227 |
# File 'lib/tina4/request.rb', line 225 def body_raw @body_raw ||= read_body end |
#cookies ⇒ Object
205 206 207 |
# File 'lib/tina4/request.rb', line 205 def @cookies ||= end |
#files ⇒ Object
237 238 239 |
# File 'lib/tina4/request.rb', line 237 def files @files ||= extract_files end |
#header(name) ⇒ Object
256 257 258 259 260 261 |
# File 'lib/tina4/request.rb', line 256 def header(name) # Headers are stored in a CaseInsensitiveHash keyed by lowercase- # dashed names ("content-type", "x-api-key"). The hash normalises # the lookup case automatically, so pass the dashed form through. headers[name.to_s.tr("_", "-")] end |
#headers ⇒ Object
Lazy accessors
201 202 203 |
# File 'lib/tina4/request.rb', line 201 def headers @headers ||= extract_headers end |
#json_body ⇒ Object
263 264 265 266 267 268 269 |
# File 'lib/tina4/request.rb', line 263 def json_body @json_body ||= begin JSON.parse(body_raw) rescue JSON::ParserError, TypeError {} end end |
#param(key, default = nil) ⇒ Object
Look up a param by symbol or string key (indifferent access shortcut).
248 249 250 |
# File 'lib/tina4/request.rb', line 248 def param(key, default = nil) params[key.to_s] || params[key.to_sym] || default end |
#params ⇒ Object
Merged params: query + body + path_params (path_params highest priority) Supports both string and symbol key access (indifferent access).
243 244 245 |
# File 'lib/tina4/request.rb', line 243 def params @params ||= build_params end |
#query ⇒ Object
Parsed query string as hash
233 234 235 |
# File 'lib/tina4/request.rb', line 233 def query @query_hash ||= parse_query_to_hash(@query_string) end |
#session ⇒ Object
209 210 211 |
# File 'lib/tina4/request.rb', line 209 def session @session ||= Tina4::Session.new(@env) end |
#url ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/tina4/request.rb', line 187 def url scheme = self.class.secure_scheme?(env) ? "https" : "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 |