Class: Response

Inherits:
Object
  • Object
show all
Defined in:
lib/fresco/runtime/runtime.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(status: 0, body: "", content_type: "text/plain; charset=utf-8", file_path: "", location: "") ⇒ Response

All slots are kwargs with defaults. The defaults are sentinels —external callers go through the .text / .html / .json / .markdown / .file / .redirect helpers below. Spinel’s type inference for ‘initialize` kwargs reads each default to fix the C parameter type; without a default the slot collapses to mrb_int. `file_path == “”` means “body response”; non-empty means “sendfile this path on the wire”. `location == “”` means “no redirect”; non-empty emits a `Location:` header alongside the chosen 3xx status.



663
664
665
666
667
668
669
670
671
672
673
674
675
676
# File 'lib/fresco/runtime/runtime.rb', line 663

def initialize(status: 0, body: "", content_type: "text/plain; charset=utf-8", file_path: "", location: "")
  @status       = status
  @body         = body
  @content_type = content_type
  @file_path    = file_path
  @location     = location
  # Set-Cookie can repeat; one fully-formatted line per entry. Seed
  # and delete to pin Array<String> for Spinel. Writes go through
  # #set_cookie / #set_cookie_with_opts (named mutators) — the same
  # poly-receiver-write trap that motivated Response's attr_reader
  # surface also kills `res.set_cookies << x` from outside.
  @set_cookies  = [""]
  @set_cookies.delete_at(0)
end

Instance Attribute Details

#bodyObject (readonly)

Returns the value of attribute body.



653
654
655
# File 'lib/fresco/runtime/runtime.rb', line 653

def body
  @body
end

#content_typeObject (readonly)

Returns the value of attribute content_type.



653
654
655
# File 'lib/fresco/runtime/runtime.rb', line 653

def content_type
  @content_type
end

#file_pathObject (readonly)

Returns the value of attribute file_path.



653
654
655
# File 'lib/fresco/runtime/runtime.rb', line 653

def file_path
  @file_path
end

#locationObject (readonly)

Returns the value of attribute location.



653
654
655
# File 'lib/fresco/runtime/runtime.rb', line 653

def location
  @location
end

#set_cookiesObject (readonly)

Returns the value of attribute set_cookies.



653
654
655
# File 'lib/fresco/runtime/runtime.rb', line 653

def set_cookies
  @set_cookies
end

#statusObject (readonly)

Returns the value of attribute status.



653
654
655
# File 'lib/fresco/runtime/runtime.rb', line 653

def status
  @status
end

Class Method Details

.file(status, path, content_type) ⇒ Object



732
733
734
# File 'lib/fresco/runtime/runtime.rb', line 732

def self.file(status, path, content_type)
  new(status: status, body: "", content_type: content_type, file_path: path, location: "")
end

.html(status, body) ⇒ Object



714
715
716
# File 'lib/fresco/runtime/runtime.rb', line 714

def self.html(status, body)
  new(status: status, body: body, content_type: "text/html; charset=utf-8", file_path: "", location: "")
end

.json(status, body) ⇒ Object

‘body` is a `Hash<Symbol, *>` — the typical JSON-response shape. We call `Spinel::Json.encode_hash` directly (not `encode`) so the hash type stays pinned at the call boundary. Going through `encode(body)` boxes the hash as `sp_RbVal`, and the analyzer’s polymorphic ‘.each` lowering only walks array-tag classes — a Hash payload silently iterates zero entries (yielding `“{}”`).



724
725
726
# File 'lib/fresco/runtime/runtime.rb', line 724

def self.json(status, body)
  new(status: status, body: Spinel::Json.encode_hash(body), content_type: "application/json", file_path: "", location: "")
end

.markdown(status, body) ⇒ Object



728
729
730
# File 'lib/fresco/runtime/runtime.rb', line 728

def self.markdown(status, body)
  new(status: status, body: body, content_type: "text/markdown; charset=utf-8", file_path: "", location: "")
end

.redirect(location = "", status: 302) ⇒ Object

302 Found by default (matches Rails’ ‘redirect_to`). Pass `status:` for 301 (permanent), 303 (POST → GET, See Other), or 307/308. The body is empty — clients follow the Location header without reading it — but content_type stays at the text/plain default so anything that does look at the response sees a sane Content-Type.



741
742
743
# File 'lib/fresco/runtime/runtime.rb', line 741

def self.redirect(location = "", status: 302)
  new(status: status, body: "", content_type: "text/plain; charset=utf-8", file_path: "", location: location)
end

.text(status, body) ⇒ Object

Every helper passes ‘location: “”` explicitly even though it’s the initialize default. Spinel lowers an omitted kwarg as a literal 0 (NULL pointer) into the C callee, NOT the Ruby-side default — so ‘Response.text` without `location:` would store NULL on @location and `build_headers` later strlen()s it → segfault. Same trap for any other helper that builds a Response from `new(…)` without supplying every kwarg.



710
711
712
# File 'lib/fresco/runtime/runtime.rb', line 710

def self.text(status, body)
  new(status: status, body: body, content_type: "text/plain; charset=utf-8", file_path: "", location: "")
end

Instance Method Details

Append a Set-Cookie line with no attributes: ‘name=value` (value URL-encoded). The handful of apps that want Path/HttpOnly/SameSite use #set_cookie_with_opts instead.



681
682
683
# File 'lib/fresco/runtime/runtime.rb', line 681

def set_cookie(name, value)
  @set_cookies.push(name + "=" + url_encode(value))
end

Append a Set-Cookie line with attributes. ‘opts` is a Str→Str hash (`“Path” => “/”`, `“HttpOnly” => “”` for bare flags, etc.). Kept on a separate method (vs an optional kwarg) so this parameter stays monomorphic on StrStrHash — see [[spinel_poly_hash_each]]; an opts-default of `{}` would collapse to RbVal and the iteration would silently no-op.



691
692
693
694
695
696
697
698
699
700
701
# File 'lib/fresco/runtime/runtime.rb', line 691

def set_cookie_with_opts(name, value, opts)
  line = name + "=" + url_encode(value)
  opts.each do |k, v|
    if v.length == 0
      line += "; " + k # bare flag (HttpOnly, Secure)
    else
      line += "; " + k + "=" + v
    end
  end
  @set_cookies.push(line)
end