./lib/lux/response/response.rb in lux-fw-0.2.3 vs ./lib/lux/response/response.rb in lux-fw-0.5.32

- old
+ new

@@ -5,13 +5,12 @@ class Lux::Response # define in seconds, how long should page be accessible in client cache # if defined, cache becomes public and can be cache by proxies # use with care.only for static resources and attr_reader :max_age + attr_accessor :headers, :cookies, :content_type, :status - attr_accessor :body, :headers, :cookies, :content_type, :status, :cookie_multidomain, :cookie_domain - def initialize @render_start = Time.monotonic @headers = Lux::Response::Header.new @max_age = 0 end @@ -27,26 +26,30 @@ def max_age= age @max_age = age.to_i end + # http 103 + def early_hints link=nil, type=nil + @early_hints ||= [] + @early_hints.push [link, type] if type && !@early_hints.include?(link) + @early_hints + end + def etag *args unless @headers['etag'] args.push current.request.url key = '"%s"' % Lux.cache.generate_key(args) key = 'W/%s' % key unless max_age > 0 @headers['etag'] = key end - if current.request.env['HTTP_IF_NONE_MATCH'] == @headers['etag'] - @status = 304 - @body = 'not-modified' - true - else - false + if !@body && current.request.env['HTTP_IF_NONE_MATCH'] == @headers['etag'] + status 304 + body 'not-modified' end end def status num=nil return @status unless num @@ -62,38 +65,35 @@ @body = msg if msg throw :done end - def body what=nil - @body ||= what - - if @body && block_given? - @body = yield @body - Lux.error 'Lux.current.response.body is not a string (bad current.response.body filter)' unless @body.is_a?(String) - end - + def body body_data=nil, status=nil + @status = status if status + @body = body_data if body_data + @body = yield @body if block_given? @body end - alias :body= :body - def body! what - @body = what + def body? + !!@body end def content_type type=nil return @content_type unless type - # can be set only once - return @content_type if @content_type + if type.is_a?(Symbol) + case type + when :javascript then 'application/javascript' + when :json then 'application/json' + when :text then 'text/plain' + when :html then 'text/html' + else + raise ArgumentError.new('Bad content type') + end + end - type = 'application/json' if type == :json - type = 'text/plain' if type == :text - type = 'text/html' if type == :html - - raise 'Invalid page content-type %s' % type if type === Symbol - @content_type = type end def content_type= type content_type type @@ -103,21 +103,45 @@ @flash ||= Flash.new current.session[:lux_flash] message ? @flash.error(message) : @flash end - def redirect where=nil, opts={} - return @headers['location'] unless where + def send_file file, opts={} + ::Lux::Response::File.new(file, opts).send + end + # redirect '/foo' + # redirect :back, info: 'bar ...' + def redirect where, opts={} + where = current.request.env['HTTP_REFERER'].or('/') if where == :back + where = "#{current.request.path}#{where}" if where[0,1] == '?' + where = current.host + where unless where.include?('://') + + # local redirect + if where.include?(current.host) + redirect_var = Lux.config.redirect_var || :_r + + url = Url.new where + url[redirect_var] = current.request.params[redirect_var].to_i + 1 + + where = + if opts.delete(:silent) + url.delete redirect_var + url.to_s + else + url[redirect_var] > 3 ? '/' : url.to_s + end + end + @status = opts.delete(:status) || 302 opts.map { |k,v| flash.send(k, v) } - @headers['location'] = where.index('//') ? where : "#{current.host}#{where}" + @body = %[redirecting to #{where}\n\n#{opts.values.join("\n")}] + + @headers['location'] = where @headers['access-control-expose-headers'] ||= 'Location' - @body = %[redirecting to #{@headers['location']}\n\n#{opts.values.join("\n")}] - throw :done end def permanent_redirect where redirect where, status:301 @@ -130,19 +154,18 @@ return true if yield *credentials end status 401 header('WWW-Authenticate', 'Basic realm="%s"' % relam.or('default')) - body = ErrorCell.unauthorized('HTTP 401 Authorization needed') - - false + body 'HTTP 401 Authorization needed' + throw :done end def write_response_body unless @body - @status = 404 - @body = Lux.error 'Document not found' + @status = 204 + @body = 'Lux HTTP ERROR 204: NO CONTENT' end # respond as JSON if we recive hash if @body.kind_of?(Hash) @body = Lux.dev? ? JSON.pretty_generate(@body) : JSON.generate(@body) @@ -162,17 +185,10 @@ @content_type ||= 'text/html' end end def write_response_header - domain = - if cookie_multidomain && current.domain.index('.') - ".#{current.domain}" - else - cookie_domain || current.request.host - end - # cache-control @headers['cache-control'] ||= Proc.new do cc = ['max-age=%d' % max_age] cc.push max_age > 0 ? 'public, no-cache' : 'private, must-revalidate' cc.join(', ') @@ -180,36 +196,28 @@ current.session[:lux_flash] = flash.to_h # dont annd cookies to public pages (images, etc..) unless @headers['cache-control'].index('public') - encrypted = Crypt.encrypt(current.session.to_json) - - if current.cookies[Lux.config.session_cookie_name] != encrypted - @headers['set-cookie'] = "#{Lux.config.session_cookie_name}=#{encrypted}; Expires=#{(Time.now+1.month).utc}; Path=/; Domain=#{domain};" - end + cookie = current.session.generate_cookie + @headers['set-cookie'] = cookie if cookie end etag(@body) if current.request.request_method == 'GET' @headers['x-lux-speed'] = "#{((Time.monotonic - @render_start)*1000).round(1)} ms" @headers['content-type'] ||= "#{@content_type}; charset=utf-8" - @headers['content-length'] = @body.bytesize + @headers['content-length'] = @body.bytesize.to_s + # if "no-store" is present then HTTP_IF_NONE_MATCH is not sent from browser end def render write_response_body write_response_header @status ||= 200 Lux.log " #{@status}, #{@headers['x-lux-speed']}" - - if ENV['LUX_PRINT_ROUTES'] - print '* Finished route print ' - puts @status == 404 ? 'without a match'.red : 'with a match'.green - exit - end [@status, @headers.to_h, [@body]] end end