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