lib/wunderbar/cgi-methods.rb in wunderbar-0.9.0 vs lib/wunderbar/cgi-methods.rb in wunderbar-0.10.0

- old
+ new

@@ -1,113 +1,175 @@ module Wunderbar module CGI + HIDE_FRAME = [ %r{/(wunderbar|webrick)/}, + %r{/gems/.*/(builder|rack|sinatra)/} ] + # produce json def self.json(&block) + headers = { 'type' => 'application/json', 'Cache-Control' => 'no-cache' } builder = JsonBuilder.new - output = builder.encode($param, &block) - Kernel.print "Status: 404 Not Found\r\n" if output == {} + output = builder.encode($params, &block) + headers['status'] = "404 Not Found" if output == {} rescue Exception => exception - Kernel.print "Status: 500 Internal Error\r\n" Wunderbar.error exception.inspect + headers['status'] = "500 Internal Server Error" backtrace = [] exception.backtrace.each do |frame| - next if frame =~ %r{/wunderbar/} - next if frame =~ %r{/gems/.*/builder/} + next if HIDE_FRAME.any? {|re| frame =~ re} Wunderbar.warn " #{frame}" backtrace << frame end builder = JsonBuilder.new builder._exception exception.inspect builder._backtrace backtrace ensure - out? 'type' => 'application/json', 'Cache-Control' => 'no-cache' do - builder.target! - end + out?(headers) { builder.target! } end # produce text def self.text &block + headers = {'type' => 'text/plain', 'charset' => 'UTF-8'} builder = TextBuilder.new - output = builder.encode($param, &block) - Kernel.print "Status: 404 Not Found\r\n" if output == '' + output = builder.encode($params, &block) + headers['status'] = "404 Not Found" if output == '' rescue Exception => exception Wunderbar.error exception.inspect - Kernel.print "Status: 500 Internal Error\r\n" + headers['status'] = "500 Internal Server Error" builder.puts unless builder.size == 0 builder.puts exception.inspect exception.backtrace.each do |frame| - next if frame =~ %r{/wunderbar/} - next if frame =~ %r{/gems/.*/builder/} + next if HIDE_FRAME.any? {|re| frame =~ re} Wunderbar.warn " #{frame}" builder.puts " #{frame}" end ensure - out? 'type' => 'text/plain', 'Cache-Control' => 'no-cache' do - builder.target! - end + out?(headers) { builder.target! } end # Conditionally provide output, based on ETAG def self.out?(headers, &block) content = block.call require 'digest/md5' etag = Digest::MD5.hexdigest(content) - if ENV['HTTP_IF_NONE_MATCH'] == etag.inspect - Kernel.print "Status: 304 Not Modified\r\n\r\n" + if $env.HTTP_IF_NONE_MATCH == etag.inspect + headers['Date'] = ::CGI.rfc1123_date(Time.now) + $cgi.out headers.merge('status' => '304 Not Modified') do + '' + end else $cgi.out headers.merge('Etag' => etag.inspect) do content end end rescue end # produce html/xhtml def self.html(*args, &block) - args << {} if args.empty? - if Hash === args.first - args.first[:xmlns] ||= 'http://www.w3.org/1999/xhtml' - end - mimetype = ($XHTML ? 'application/xhtml+xml' : 'text/html') + headers = { 'type' => 'text/html', 'charset' => 'UTF-8' } + headers['type'] = 'application/xhtml+xml' if @xhtml + x = HtmlMarkup.new - x._! "\xEF\xBB\xBF" - x._.declare :DOCTYPE, :html begin - output = x.html *args, &block + if @xhtml + output = x.xhtml *args, &block + else + output = x.html *args, &block + end rescue ::Exception => exception - Kernel.print "Status: 500 Internal Error\r\n" + headers['status'] = "500 Internal Server Error" x.clear! - x._! "\xEF\xBB\xBF" - x._.declare :DOCTYPE, :html output = x.html(*args) do _head do - _title 'Internal Error' + _title 'Internal Server Error' end _body do - _h1 'Internal Error' + _h1 'Internal Server Error' text = exception.inspect Wunderbar.error text exception.backtrace.each do |frame| - next if frame =~ %r{/wunderbar/} - next if frame =~ %r{/gems/.*/builder/} + next if HIDE_FRAME.any? {|re| frame =~ re} Wunderbar.warn " #{frame}" text += "\n #{frame}" end _pre text end end end - out? 'type' => mimetype, 'charset' => 'UTF-8' do - output + out?(headers) { output } + end + + def self.call(env) + require 'etc' + $USER = ENV['REMOTE_USER'] ||= ENV['USER'] || Etc.getlogin + + accept = $env.HTTP_ACCEPT.to_s + request_uri = $env.REQUEST_URI.to_s + + # implied request types + xhr_json = Wunderbar::Options::XHR_JSON || (accept =~ /json/) + text = Wunderbar::Options::TEXT || + (accept =~ /plain/ and accept !~ /html/) + @xhtml = (accept =~ /xhtml/ or accept == '') + + # overrides via the uri query parameter + xhr_json ||= (request_uri =~ /\?json$/) + text ||= (request_uri =~ /\?text$/) + + # overrides via the command line + xhtml_override = ARGV.include?('--xhtml') + html_override = ARGV.include?('--html') + + # disable conneg if only one handler is provided + if Wunderbar.queue.length == 1 + type = Wunderbar.queue.first.first + xhr_json = (type == :json) + text = (type == :text) end + + Wunderbar.queue.each do |type, args, block| + case type + when :html, :xhtml + unless xhr_json or text + if type == :html + @xhtml = false unless xhtml_override + else + @xhtml = false if html_override + end + + self.html(*args, &block) + return + end + when :json + if xhr_json + self.json(*args, &block) + return + end + when :text + if text + self.text(*args, &block) + return + end + end + end end + + # map Ruby CGI headers to Rack headers + def self.headers(headers) + result = headers.dup + type = result.delete('type') || 'text/html' + charset = result.delete('charset') + type = "#{type}; charset=#{charset}" if charset + result['Content-Type'] ||= type + result + end end @queue = [] # canonical interface @@ -125,42 +187,9 @@ def self.text(*args, &block) @queue << [:text, args, block] end - def self.evaluate - queue, @queue = @queue, [] - xhtml = ARGV.delete('--xhtml') - html = ARGV.delete('--html') - - queue.each do |type, args, block| - case type - when :html - unless $XHR_JSON or $TEXT - $XHTML = false unless xhtml - CGI.html(*args, &block) - break - end - when :xhtml - unless $XHR_JSON or $TEXT - $XHTML = false if html - CGI.html(*args, &block) - break - end - when :json - if $XHR_JSON - CGI.json(*args, &block) - break - end - when :text - if $TEXT - CGI.text(*args, &block) - break - end - end - end + def self.queue + @queue end -end - -at_exit do - Wunderbar.evaluate end