Harbor Documentation

Constants

Attributes

  • status [RW] (Not documented)
  • headers [RW] (Not documented)
  • errors [RW] (Not documented)

Public Class Methods

new(request)

      # File lib/harbor/response.rb, line 15
15:     def initialize(request)
16:       @request = request
17:       @headers = {}
18:       @headers["Content-Type"] = "text/html"
19:       @status = 200
20:       @errors = Harbor::Errors.new
21:     end

Public Instance Methods

[](key)

       # File lib/harbor/response.rb, line 273
273:     def [](key)
274:       headers[key]
275:     end

[]=(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

flush()

      # File lib/harbor/response.rb, line 27
27:     def flush
28:       @io = nil
29:     end

headers()

      # File lib/harbor/response.rb, line 23
23:     def headers
24:       @headers
25:     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

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

unauthorized()

       # File lib/harbor/response.rb, line 208
208:     def unauthorized
209:       self.status = 401
210:     end

unauthorized!()

       # File lib/harbor/response.rb, line 212
212:     def unauthorized!
213:       abort!(401)
214:     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

string()

       # File lib/harbor/response.rb, line 345
345:     def string
346:       @io ||= StringIO.new("")
347:     end