require 'tap/controller' require 'tap/mechanize/utils' require 'tap/ubiquity/utils' module Tap module Mechanize # :startdoc::controller # :startdoc::ubiquity class Capture < Tap::Controller include Tap::Mechanize::Utils include Tap::Ubiquity::Utils PREFIX = '__redirect_http_' REDIRECT_PARAMETER = '__redirect_http_original_action' # Brings up the tutorial. def index render 'index.erb', :locals => {:captures => persistence.index } end def create(id, keep_content=true) persistence.create(id) do |io| io << YAML.dump([parse_request(keep_content)]) end download(id) end def show(id) response['Content-Type'] = "text/plain" persistence.read(id) end def download(id) path = persistence.path(id) filename = id filename += ".yml" if File.extname(id) == "" response['Content-Type'] = "text/plain" response['Content-Disposition'] = "attachment; filename=#{filename};" persistence.read(id) end def update(id="request", keep_content=true) path = persistence.path(id) requests = File.exists?(path) ? YAML.load_file(path) : [] requests << parse_request(keep_content) persistence.update(id) do |io| io << YAML.dump(requests) end download(id) end def destroy(id) persistence.destroy(id) redirect uri(:index) end # Brings up a tutorial teaching how to capture and resubmit forms. def tutorial serve js_injection(:redirect_http) do |link| content = render 'tutorial.erb' content + link end end def test render 'test.erb' end # Say is the target of the tutorial. def say "
#{request.params['words']}
" end # Returns the redirection script. def redirect_http css = render 'redirect.css' script = render 'redirect.js', :locals => { :redirect_parameter => REDIRECT_PARAMETER, :redirect_action => uri(:update), } content = render 'redirect_http.erb', :locals => { :css => css, :script => script } if request.get? response['Content-Type'] = 'text/plain' %Q{
#{content}
} else response['Content-Type'] = 'text/javascript' %Q{ if(current = document.getElementById("#{prefix}")) { RedirectHttp.revert(); } else { var div = document.createElement("div"); div.id = "#{prefix}"; div.innerHTML = #{content.to_json}; document.body.insertBefore(div, document.body.firstChild); RedirectHttp.redirect(); } } end end # Parses HTTP request def http if request.get? render 'http.erb' else keep_content = request.params['keep_content'] == "true" hash = {} parse_http_request(request.params['http'], keep_content).each_pair do |key, value| hash[key.to_s] = value end # remove extranous data hash.delete('headers') hash.delete('version') response['Content-Type'] = "text/plain" YAML.dump(hash) end end protected # helper for rendering... saves specification of # :locals => {:prefix => PREFIX} def prefix # :nodoc: PREFIX end def capture_overloaded_parameters # :nodoc: # perform the actions of Rack::Request::POST, but capture # overloaded parameter names env = request.env env["rack.request.form_input"] = env["rack.input"] unless env["rack.request.form_hash"] = parse_multipart(env) env["rack.request.form_vars"] = env["rack.input"].read env["rack.request.form_hash"] = Rack::Utils.parse_query(env["rack.request.form_vars"]) env["rack.input"].rewind if env["rack.input"].respond_to?(:rewind) end end # helper to parse the request into a request hash for # use by a Tap::Mechanize::Submit task def parse_request(keep_content=true) # :nodoc: if keep_content.kind_of?(String) keep_content = keep_content =~ /true/i end capture_overloaded_parameters hash = {} parse_rack_request(request, keep_content).each_pair do |key, value| hash[key.to_s] = value end action = hash['params'].delete(REDIRECT_PARAMETER) hash['uri'] = case action when /^http/ # action is an href already action when /^\// # make action relative to host action, query = action.split('?', 2) uri = URI.parse(hash['headers']['Referer'].to_s) uri.path = action uri.query = query.to_s.gsub(/\s/, "+") uri.to_s else # make action relative to Referer base = File.dirname(hash['headers']['Referer'].to_s) File.join(base, action) end # remove extranous data hash.delete('headers') hash.delete('version') hash end end end end