Class: Wsv::Response

Inherits:
Object
  • Object
show all
Defined in:
lib/wsv/response.rb,
lib/wsv/response/file_body.rb,
lib/wsv/response/string_body.rb,
lib/wsv/response/file_builder.rb,
lib/wsv/response/text_builder.rb

Defined Under Namespace

Classes: FileBody, FileBuilder, StringBody, TextBuilder

Constant Summary collapse

SERVER_NAME =
"wsv/#{Wsv::VERSION}".freeze
INVALID_HEADER_NAME =
/[\s:]/
INVALID_HEADER_VALUE =
/[\r\n]/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(status:, headers: {}, body: "") ⇒ Response

Returns a new instance of Response.



19
20
21
22
23
24
# File 'lib/wsv/response.rb', line 19

def initialize(status:, headers: {}, body: "")
  validate_headers(headers)
  @status = status
  @headers = headers
  @body = body.is_a?(String) ? StringBody.new(body) : body
end

Instance Attribute Details

#headersObject (readonly)

Returns the value of attribute headers.



17
18
19
# File 'lib/wsv/response.rb', line 17

def headers
  @headers
end

#statusObject (readonly)

Returns the value of attribute status.



17
18
19
# File 'lib/wsv/response.rb', line 17

def status
  @status
end

Class Method Details

.file(path) ⇒ Object



56
57
58
# File 'lib/wsv/response.rb', line 56

def self.file(path, **)
  FileBuilder.new(path, **).build
end

.not_modifiedObject



64
65
66
# File 'lib/wsv/response.rb', line 64

def self.not_modified
  new(status: 304, headers: { "Cache-Control" => "no-cache" }, body: "")
end

.range_not_satisfiable(file_size, head: false) ⇒ Object



68
69
70
# File 'lib/wsv/response.rb', line 68

def self.range_not_satisfiable(file_size, head: false)
  TextBuilder.new(416, head: head, headers: { "Content-Range" => "bytes */#{file_size}" }).build
end

.redirect(location, head: false) ⇒ Object



60
61
62
# File 'lib/wsv/response.rb', line 60

def self.redirect(location, head: false)
  TextBuilder.new(301, head: head, headers: { "Location" => location }).build
end

.text(status) ⇒ Object



52
53
54
# File 'lib/wsv/response.rb', line 52

def self.text(status, **)
  TextBuilder.new(status, **).build
end

Instance Method Details

#bodyObject



26
27
28
# File 'lib/wsv/response.rb', line 26

def body
  @body.to_s
end

#reasonObject



30
31
32
# File 'lib/wsv/response.rb', line 30

def reason
  Status.reason(status)
end

#with_headers(extra) ⇒ Object

Returns a new Response with ‘extra` merged into the headers, sharing the same body object so streaming (FileBody) is preserved.



36
37
38
# File 'lib/wsv/response.rb', line 36

def with_headers(extra)
  self.class.new(status: @status, headers: @headers.merge(extra), body: @body)
end

#write_to(io) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/wsv/response.rb', line 40

def write_to(io)
  io.write "HTTP/1.1 #{status} #{reason}\r\n"
  io.write "Server: #{SERVER_NAME}\r\n"
  io.write "Connection: close\r\n"
  unless headers.any? { |name, _value| name.to_s.casecmp?("X-Content-Type-Options") }
    io.write "X-Content-Type-Options: nosniff\r\n"
  end
  headers.each { |name, value| io.write "#{name}: #{value}\r\n" }
  io.write "\r\n"
  @body.write_to(io)
end