Harbor::Response
Parent
Methods
- ::new
- #[]
- #[]=
- #abort!
- #buffer
- #cache
- #content_type
- #content_type=
- #delete_cookie
- #escape_filename_for_http_header
- #flush
- #headers
- #inspect
- #message
- #messages
- #not_modified!
- #puts
- #redirect
- #redirect!
- #render
- #send_file
- #send_files
- #set_cookie
- #size
- #size=
- #stream_file
- #string
- #to_a
- #unauthorized
- #unauthorized!
Constants
Attributes
Public Class Methods
Public Instance Methods
[]=(key, value)
# File lib/harbor/response.rb, line 277 277: def []=(key, value) 278: headers[key] = value 279: end
abort!(code)
# File lib/harbor/response.rb, line 199 199: def abort!(code) 200: if Harbor::View.exists?("exceptions/#{code}.html.erb") 201: render "exceptions/#{code}.html.erb" 202: end 203: 204: self.status = code 205: throw(:abort_request) 206: end
buffer()
# File lib/harbor/response.rb, line 57 57: def buffer 58: if @io.is_a?(StringIO) 59: @io.string 60: else 61: @io || "" 62: end 63: end
cache(key, last_modified, ttl = nil, max_age = nil)
# File lib/harbor/response.rb, line 117 117: def cache(key, last_modified, ttl = nil, max_age = nil) 118: raise ArgumentError.new("You must provide a block of code to cache.") unless block_given? 119: 120: store = nil 121: if key && (ttl || max_age) 122: store = Harbor::View.cache 123: 124: unless store 125: raise ArgumentError.new("Cache Store Not Defined. Please set Harbor::View.cache to your desired cache store.") 126: end 127: 128: key = "page-#{key}" 129: end 130: 131: last_modified = last_modified.httpdate 132: @headers["Last-Modified"] = last_modified 133: @headers["Cache-Control"] = "max-age=#{ttl}, must-revalidate" if ttl 134: 135: modified_since = @request.env["HTTP_IF_MODIFIED_SINCE"] 136: 137: if modified_since == last_modified && (!store || store.get(key)) 138: not_modified! 139: elsif store && item = store.get(key) 140: return puts(item.content) 141: end 142: 143: yield self 144: store.put(key, buffer, ttl, max_age) if store 145: end
content_type()
# File lib/harbor/response.rb, line 43 43: def content_type 44: @headers["Content-Type"] 45: end
content_type=(content_type)
# File lib/harbor/response.rb, line 39 39: def content_type=(content_type) 40: @headers["Content-Type"] = content_type 41: end
inspect()
# File lib/harbor/response.rb, line 235 235: def inspect 236: "<#{self.class} headers=#{headers.inspect} content_type=#{content_type.inspect} status=#{status.inspect} body=#{buffer.inspect}>" 237: end
message(key, message, use_session=true)
Calling reponse.message forces a session to load. The reasoning is as follows: 1) This will eliminate the majority of ugly query-string messages. 2) Calling response.message in an action assumes a human receiver and thus the
use of a session is valid
Nonetheless, control is left to app. Use use_session = false to use query-string based messages instead.
# File lib/harbor/response.rb, line 252 252: def message(key, message, use_session=true) 253: @request.session if use_session 254: messages[key] = message 255: end
messages()
# File lib/harbor/response.rb, line 239 239: def messages 240: @messages ||= @request.messages 241: end
not_modified!()
# File lib/harbor/response.rb, line 229 229: def not_modified! 230: NOT_MODIFIED_OMIT_HEADERS.each { |name| headers.delete(name) } 231: self.status = 304 232: throw(:abort_request) 233: end
print(value)
# File lib/harbor/response.rb, line 52 52: def print(value) 53: string.print(value) 54: self.size = string.length 55: end
puts(value)
# File lib/harbor/response.rb, line 47 47: def puts(value) 48: string.puts(value) 49: self.size = string.length 50: end
redirect(url, params = nil)
# File lib/harbor/response.rb, line 170 170: def redirect(url, params = nil) 171: url = URI.parse(url) 172: params ||= {} 173: 174: if url.query 175: params.merge!(Rack::Utils.parse_query(url.query)) 176: url.query = nil 177: end 178: 179: if @request && !@request.session? && !messages.empty? && !messages.expired? 180: messages.each { |key, value| params["messages[#{key}]"] = value } 181: end 182: 183: url.query = Rack::Utils::build_query(params) if params && params.any? 184: 185: self.status = 303 186: self.headers.merge!({ 187: "Location" => url.to_s, 188: "Content-Type" => "text/html" 189: }) 190: HEADER_BLACKLIST.each{|banned_header| self.headers.delete(banned_header)} 191: self.flush 192: self 193: end
redirect!(url, params = nil)
# File lib/harbor/response.rb, line 195 195: def redirect!(url, params = nil) 196: redirect(url, params) and throw(:abort_request) 197: end
render(view, context = {})
# File lib/harbor/response.rb, line 147 147: def render(view, context = {}) 148: if context[:layout].is_a?(Array) 149: warn "Passing multiple layouts to response.render has been deprecated. See Harbor::Layouts." 150: context[:layout] = context[:layout].first 151: end 152: 153: case view 154: when View 155: view.context.merge(context) 156: else 157: view = View.new(view, context.merge({ :request => @request, :response => self })) 158: end 159: 160: self.content_type = view.content_type 161: 162: if context.has_key?(:layout) || @request.xhr? 163: puts view.to_s(context[:layout]) 164: else 165: puts view.to_s(:search) 166: end 167: end
send_file(name, path_or_io, content_type = nil)
# File lib/harbor/response.rb, line 91 91: def send_file(name, path_or_io, content_type = nil) 92: stream_file(path_or_io, content_type) 93: 94: @headers["Content-Disposition"] = "attachment; filename=\"#{escape_filename_for_http_header(name)}\"" 95: nil 96: end
send_files(name, files)
Zip up the files (with no compression) and send it the client files should be an enumerable collection of Harbor::File instances
# File lib/harbor/response.rb, line 100 100: def send_files(name, files) 101: if @request.env["HTTP_MOD_ZIP_ENABLED"] 102: files.each do |file| 103: path = ::File.expand_path(file.path) 104: puts("#{Zlib.crc32(::File.read(path))} #{::File.size(path)} #{path} #{::File.basename(path)}") 105: end 106: headers["X-Archive-Files"] = "zip" 107: self.content_type = "application/zip" 108: @headers["Content-Disposition"] = "attachment; filename=\"#{escape_filename_for_http_header(name)}\"" 109: else 110: @io = ZippedIO.new(files) 111: self.size = @io.size 112: self.content_type = "application/zip" 113: @headers["Content-Disposition"] = "attachment; filename=\"#{escape_filename_for_http_header(name)}\"" 114: end 115: end
size()
# File lib/harbor/response.rb, line 35 35: def size 36: (@headers["Content-Length"] || buffer.size).to_i 37: end
size=(size)
# File lib/harbor/response.rb, line 31 31: def size=(size) 32: @headers["Content-Length"] = size.to_s 33: end
stream_file(path_or_io, content_type = nil)
# File lib/harbor/response.rb, line 65 65: def stream_file(path_or_io, content_type = nil) 66: io = BlockIO.new(path_or_io) 67: 68: if io.path && (header = @request.env["HTTP_X_SENDFILE_TYPE"]) 69: case header 70: when "X-Sendfile" 71: @headers["X-Sendfile"] = io.path 72: when "X-Accel-Redirect" 73: if mapping = @request.env['HTTP_X_ACCEL_MAPPING'] 74: internal, external = mapping.split('=', 2).map { |p| p.strip } 75: @headers["X-Accel-Redirect"] = io.path.sub(/^#{internal}/i, external) 76: else 77: @headers["X-Accel-Redirect"] = io.path 78: end 79: else 80: raise UnsupportedSendfileTypeError.new(header) 81: end 82: else 83: @io = io 84: end 85: 86: self.size = io.size 87: self.content_type = content_type || Harbor::Mime.mime_type(::File.extname(io.path.to_s)) 88: nil 89: end
to_a()
# File lib/harbor/response.rb, line 257 257: def to_a 258: messages.clear if messages.expired? 259: 260: if @request.session? 261: session = @request.session 262: set_cookie(session.key, session.save) 263: end 264: 265: # headers cannot be arrays 266: self.headers.each_pair do |key, value| 267: self.headers[key] = value.join("\n") if value.is_a?(Array) 268: end 269: 270: [self.status, self.headers, self.buffer] 271: end
Private Instance Methods
escape_filename_for_http_header(filename)
# File lib/harbor/response.rb, line 350 350: def escape_filename_for_http_header(filename) 351: # This would work great if IE6 could unescape the Content-Disposition filename field properly, 352: # but it can't, so we use the terribly weak version instead, until IE6 dies off... 353: #filename.gsub(/["\\\x0]/,'\\\\\0') 354: 355: filename.gsub(/[^\w\.]/, '_') 356: end