Class: Tep::Request
- Inherits:
-
Object
- Object
- Tep::Request
- Defined in:
- lib/tep/request.rb
Instance Attribute Summary collapse
-
#cookies ⇒ Object
Returns the value of attribute cookies.
-
#http_version ⇒ Object
Returns the value of attribute http_version.
-
#identity ⇒ Object
Set by the auth-filter (Tep::AuthFilter, run before the user’s before-filter – see Tep::App#auth_filter).
-
#ivars ⇒ Object
Returns the value of attribute ivars.
-
#params ⇒ Object
Returns the value of attribute params.
-
#passed ⇒ Object
Returns the value of attribute passed.
-
#path ⇒ Object
Returns the value of attribute path.
-
#query ⇒ Object
Returns the value of attribute query.
-
#raw_body ⇒ Object
Returns the value of attribute raw_body.
-
#raw_path ⇒ Object
Returns the value of attribute raw_path.
-
#remote_host ⇒ Object
Returns the value of attribute remote_host.
-
#req_headers ⇒ Object
Returns the value of attribute req_headers.
-
#session ⇒ Object
Returns the value of attribute session.
-
#verb ⇒ Object
Returns the value of attribute verb.
Instance Method Summary collapse
- #accept ⇒ Object
- #body ⇒ Object
-
#consume_body(client_fd) ⇒ Object
Pull any remaining body bytes from ‘client_fd` up to the advertised Content-Length, then merge form / multipart fields into @params.
-
#consume_body_via_scheduler(client_fd) ⇒ Object
Scheduler-friendly body drain.
- #content_length ⇒ Object
- #content_type ⇒ Object
- #form? ⇒ Boolean
-
#headers ⇒ Object
Sinatra-compat read aliases.
-
#host ⇒ Object
—- Rack::Request-style accessors (reads only, no .ip yet) —- These are convenience getters over headers we already parse; ‘.ip` would need a sphttp_accept_with_peer C helper before it can land cleanly, so it’s deferred.
-
#initialize ⇒ Request
constructor
A new instance of Request.
-
#keep_alive? ⇒ Boolean
Spinel’s Hash returns “” for missing string keys, not nil – so an empty Connection header looks the same as no header at all.
-
#multipart? ⇒ Boolean
True when the request body is a multipart/form-data submission (browsers use this for any form built via ‘new FormData(…)` or carrying file inputs).
-
#parse_form_body ⇒ Object
Shared form / multipart -> @params merge.
- #referer ⇒ Object
-
#referrer ⇒ Object
spelling alias.
-
#scheme ⇒ Object
tep doesn’t terminate TLS itself; both flags reflect “is this connection encrypted from the client’s view?” via the ‘X-Forwarded-Proto: https` header that any reasonable reverse proxy sets.
- #set_passed ⇒ Object
- #ssl? ⇒ Boolean
- #user_agent ⇒ Object
Constructor Details
#initialize ⇒ Request
Returns a new instance of Request.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/tep/request.rb', line 15 def initialize @verb = "" @path = "" @raw_path = "" @http_version = "HTTP/1.0" @params = Tep.str_hash # path captures + query + form merged @query = Tep.str_hash # raw query string only @req_headers = Tep.str_hash # downcased header names; renamed # from `headers` to avoid sharing # an ivar slot with Response (spinel # mis-codegens polymorphic ivar # writes when two classes share an # ivar name). @cookies = Tep.str_hash # parsed from Cookie: header @session = Session.new # signed cookie store @raw_body = "" # same reasoning as req_headers @remote_host = "" @passed = false # `pass` flag: skip to the next matching route @ivars = Tep.str_hash # per-request bag for `@name = ...` # set by handlers and `before` filters, # read by templates as `ivars[k]`. The # Sinatra-compat translator rewrites # `@x = v` -> `req.ivars["x"] = (v).to_s` # in handler bodies and `@x` -> `ivars["x"]` # inside ERB chunks. @identity = Tep::Identity.anonymous end |
Instance Attribute Details
#cookies ⇒ Object
Returns the value of attribute cookies.
5 6 7 |
# File 'lib/tep/request.rb', line 5 def @cookies end |
#http_version ⇒ Object
Returns the value of attribute http_version.
4 5 6 |
# File 'lib/tep/request.rb', line 4 def http_version @http_version end |
#identity ⇒ Object
Set by the auth-filter (Tep::AuthFilter, run before the user’s before-filter – see Tep::App#auth_filter). Always populated: Tep::Identity.anonymous when no provider matched, otherwise the matched provider’s Identity. Handlers and filters can rely on req.identity being non-nil.
13 14 15 |
# File 'lib/tep/request.rb', line 13 def identity @identity end |
#ivars ⇒ Object
Returns the value of attribute ivars.
7 8 9 |
# File 'lib/tep/request.rb', line 7 def ivars @ivars end |
#params ⇒ Object
Returns the value of attribute params.
5 6 7 |
# File 'lib/tep/request.rb', line 5 def params @params end |
#passed ⇒ Object
Returns the value of attribute passed.
43 44 45 |
# File 'lib/tep/request.rb', line 43 def passed @passed end |
#path ⇒ Object
Returns the value of attribute path.
4 5 6 |
# File 'lib/tep/request.rb', line 4 def path @path end |
#query ⇒ Object
Returns the value of attribute query.
5 6 7 |
# File 'lib/tep/request.rb', line 5 def query @query end |
#raw_body ⇒ Object
Returns the value of attribute raw_body.
5 6 7 |
# File 'lib/tep/request.rb', line 5 def raw_body @raw_body end |
#raw_path ⇒ Object
Returns the value of attribute raw_path.
4 5 6 |
# File 'lib/tep/request.rb', line 4 def raw_path @raw_path end |
#remote_host ⇒ Object
Returns the value of attribute remote_host.
6 7 8 |
# File 'lib/tep/request.rb', line 6 def remote_host @remote_host end |
#req_headers ⇒ Object
Returns the value of attribute req_headers.
5 6 7 |
# File 'lib/tep/request.rb', line 5 def req_headers @req_headers end |
#session ⇒ Object
Returns the value of attribute session.
5 6 7 |
# File 'lib/tep/request.rb', line 5 def session @session end |
#verb ⇒ Object
Returns the value of attribute verb.
4 5 6 |
# File 'lib/tep/request.rb', line 4 def verb @verb end |
Instance Method Details
#accept ⇒ Object
93 |
# File 'lib/tep/request.rb', line 93 def accept; @req_headers["accept"]; end |
#body ⇒ Object
52 |
# File 'lib/tep/request.rb', line 52 def body; @raw_body; end |
#consume_body(client_fd) ⇒ Object
Pull any remaining body bytes from ‘client_fd` up to the advertised Content-Length, then merge form / multipart fields into @params. Used by Tep::Server (prefork, blocking fds) – under the prefork model recv() blocks naturally until bytes arrive, so `sphttp_drain_body` (a tight blocking-recv loop) is the right primitive.
Tep::Server::Scheduled uses ‘consume_body_via_scheduler` below instead, because its client fd is non-blocking + a blocking recv would starve the whole worker.
No-op on bodyless requests. Form parsing handles ‘application/x-www-form-urlencoded`; multipart handles `multipart/form-data` (text fields only; file uploads skipped). Other content types leave @raw_body intact for handlers that want to consume it directly.
128 129 130 131 132 133 134 135 136 137 |
# File 'lib/tep/request.rb', line 128 def consume_body(client_fd) cl = content_length already = @raw_body.length if cl > already rest = Sock.sphttp_drain_body(client_fd, cl - already) @raw_body = @raw_body + rest end parse_form_body 0 end |
#consume_body_via_scheduler(client_fd) ⇒ Object
Scheduler-friendly body drain. Loops on ‘Sock.sphttp_recv_some` + `Tep::Scheduler.io_wait` so other fibers keep running while we wait for body bytes. Per-recv timeout caps the wait at 5s – a client that opened the request but never sent the body gets dropped instead of hanging the fiber forever.
Returns @raw_body.length after the drain. Body parsing (form / multipart -> @params) happens at the end via parse_form_body, same shape as consume_body.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/tep/request.rb', line 149 def consume_body_via_scheduler(client_fd) cl = content_length while @raw_body.length < cl ready = Tep::Scheduler.io_wait(client_fd, Tep::Scheduler::READ, 5) if ready == 0 break # timeout -- client never finished sending end chunk = Sock.sphttp_recv_some(client_fd, cl - @raw_body.length) if chunk.length == 0 # Over TLS an empty read can be a partial record (SSL_read # WANT_READ/WANT_WRITE) rather than a peer close -- re-park on # the indicated direction and retry instead of truncating the # body. Plaintext EOF/error (status 3/-1) still breaks. st = Sock.sphttp_io_status if st == 1 next end if st == 2 Tep::Scheduler.io_wait(client_fd, Tep::Scheduler::WRITE, 5) next end break # peer closed mid-body end @raw_body = @raw_body + chunk end parse_form_body 0 end |
#content_length ⇒ Object
68 69 70 |
# File 'lib/tep/request.rb', line 68 def content_length @req_headers["content-length"].to_i end |
#content_type ⇒ Object
94 |
# File 'lib/tep/request.rb', line 94 def content_type; @req_headers["content-type"]; end |
#form? ⇒ Boolean
72 73 74 |
# File 'lib/tep/request.rb', line 72 def form? @req_headers["content-type"].downcase.start_with?("application/x-www-form-urlencoded") end |
#headers ⇒ Object
Sinatra-compat read aliases. Writers stay on the renamed slots (req_headers, raw_body) – a ‘req.headers = v` from user code goes through these getters, but assignment back into the request via this method name is intentionally not provided (the framework doesn’t expect handlers to mutate the request).
51 |
# File 'lib/tep/request.rb', line 51 def headers; @req_headers; end |
#host ⇒ Object
—- Rack::Request-style accessors (reads only, no .ip yet) —- These are convenience getters over headers we already parse; ‘.ip` would need a sphttp_accept_with_peer C helper before it can land cleanly, so it’s deferred.
89 |
# File 'lib/tep/request.rb', line 89 def host; @req_headers["host"]; end |
#keep_alive? ⇒ Boolean
Spinel’s Hash returns “” for missing string keys, not nil – so an empty Connection header looks the same as no header at all. We treat both as “use HTTP/1.1 default behaviour”.
57 58 59 60 61 62 63 64 65 66 |
# File 'lib/tep/request.rb', line 57 def keep_alive? lc = @req_headers["connection"].downcase if lc == "close" return false end if lc == "keep-alive" return true end @http_version == "HTTP/1.1" end |
#multipart? ⇒ Boolean
True when the request body is a multipart/form-data submission (browsers use this for any form built via ‘new FormData(…)` or carrying file inputs). Tep::Multipart.parse handles the text fields; file-upload parts are skipped in v1.
80 81 82 |
# File 'lib/tep/request.rb', line 80 def multipart? @req_headers["content-type"].downcase.start_with?("multipart/form-data") end |
#parse_form_body ⇒ Object
Shared form / multipart -> @params merge. Both server-side body-drain paths call this once their drain step has filled
181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/tep/request.rb', line 181 def parse_form_body if form? Url.parse_query(@raw_body).each do |k, v| @params[k] = v end elsif multipart? Tep::Multipart.parse(@raw_body, @req_headers["content-type"]).each do |k, v| @params[k] = v end end 0 end |
#referer ⇒ Object
91 |
# File 'lib/tep/request.rb', line 91 def referer; @req_headers["referer"]; end |
#referrer ⇒ Object
spelling alias
92 |
# File 'lib/tep/request.rb', line 92 def referrer; @req_headers["referer"]; end |
#scheme ⇒ Object
tep doesn’t terminate TLS itself; both flags reflect “is this connection encrypted from the client’s view?” via the ‘X-Forwarded-Proto: https` header that any reasonable reverse proxy sets.
100 101 102 103 104 105 106 |
# File 'lib/tep/request.rb', line 100 def scheme proto = @req_headers["x-forwarded-proto"] if proto.length > 0 return proto.downcase end "http" end |
#set_passed ⇒ Object
44 |
# File 'lib/tep/request.rb', line 44 def set_passed; @passed = true; end |
#ssl? ⇒ Boolean
108 109 110 |
# File 'lib/tep/request.rb', line 108 def ssl? scheme == "https" end |
#user_agent ⇒ Object
90 |
# File 'lib/tep/request.rb', line 90 def user_agent; @req_headers["user-agent"]; end |