require 'tap/controller' require 'tap/mechanize/utils' require 'tap/ubiquity/utils' require 'uri' module Tap module Mechanize # :startdoc::controller # :startdoc::ubiquity class Capture < Tap::Controller include Tap::Mechanize::Utils include Tap::Ubiquity::Utils PREFIX = '__redirect_http_' # Brings up the tutorial. def index render 'index.erb', :locals => {:captures => data.index(:data) } end def create(id) data.create(:data, id) do |io| io << YAML.dump([parse_request]) end download(id) end def show(id) response['Content-Type'] = "text/plain" data.read(:data, id) end def download(id) path = data.path(:data, id) filename = id filename += ".yml" if File.extname(id) == "" response['Content-Type'] = "text/plain" response['Content-Disposition'] = "attachment; filename=#{filename};" data.read(:data, id) end def update(id="request") path = data.path(:data, id) requests = File.exists?(path) ? YAML.load_file(path) : [] requests << parse_request data.create_or_update(:data, id) do |io| io << YAML.dump(requests) end download(id) end def destroy(id) data.destroy(:data, id) redirect uri(:index) end # Brings up a tutorial teaching how to capture and resubmit forms. def tutorial render 'tutorial.erb' end def command serve js_injection(:redirect_http) 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 # note configs are formatted into the javascript; keys MUST be valid # names, but values can be anything that converts to json configs = [ [:submit_request, false], [:keep_content, false], [:keep_headers, false], [:name, 'request'] ] css = render 'redirect.css' script = render 'redirect.js', :locals => { :redirect_action => uri(:update), :configs => configs } content = render 'redirect_http.erb', :locals => { :css => css, :script => script, :configs => configs } 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 data server.data end def uri(*args) "http://#{server.host}:#{server.port}#{super}" end # Returns the data recieved in the query string. def get_params env = request.env if env["rack.request.query_string"] == request.query_string env["rack.request.query_hash"] else env["rack.request.query_string"] = request.query_string env["rack.request.query_hash"] = parse_query(request.query_string) end end # Returns the data recieved in the request body. # # This method support both application/x-www-form-urlencoded and # multipart/form-data. def post_params env = request.env if env["rack.request.form_input"].eql? env["rack.input"] env["rack.request.form_hash"] elsif request.form_data? env["rack.request.form_input"] = env["rack.input"] unless env["rack.request.form_hash"] = Rack::Utils::Multipart.parse_multipart(env) form_vars = env["rack.input"].read # Fix for Safari Ajax postings that always append \0 form_vars.sub!(/\0\z/, '') env["rack.request.form_vars"] = form_vars env["rack.request.form_hash"] = parse_query(form_vars) begin env["rack.input"].rewind if env["rack.input"].respond_to?(:rewind) rescue Errno::ESPIPE # Handles exceptions raised by input streams that cannot be rewound # such as when using plain CGI under Apache end end env["rack.request.form_hash"] else {} end end def capture_parameters # :nodoc: get_params.update(post_params) end # helper to parse the request into a request hash for # use by a Tap::Mechanize::Submit task def parse_request params = capture_parameters capture_params = {} params.each_key do |key| if key =~ /#{prefix}/ normalize_params(capture_params, key, params.delete(key)) end end capture_params = capture_params[prefix] hash = {} parse_rack_request(request, params, capture_params['keep_content'] == "true").each_pair do |key, value| hash[key.to_s] = value end action = capture_params['original_action'] 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 extra data unless capture_params['keep_headers'] == 'true' hash.delete('headers') end hash.delete('version') hash end end end end