mirror of
https://github.com/github/rails.git
synced 2026-01-12 08:08:31 -05:00
Compare commits
301 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
685cb901fc | ||
|
|
e9f9d05a94 | ||
|
|
7b6670cc08 | ||
|
|
ed2d852bdc | ||
|
|
726ab5316d | ||
|
|
ecd6fb250a | ||
|
|
9f8ee9dd97 | ||
|
|
b2969e6b48 | ||
|
|
b8f240961a | ||
|
|
9b3770f14f | ||
|
|
eefc42630f | ||
|
|
ca84456c93 | ||
|
|
9b6ee49490 | ||
|
|
f0fa43cffc | ||
|
|
208685d29d | ||
|
|
33e9676968 | ||
|
|
28a87a2d54 | ||
|
|
3aaacc67e8 | ||
|
|
6ba9bd8d09 | ||
|
|
0b57366c77 | ||
|
|
2ff2fecb37 | ||
|
|
9adaec4b4f | ||
|
|
c799732c64 | ||
|
|
ade414a33a | ||
|
|
bd5b782424 | ||
|
|
74f7149ef6 | ||
|
|
0b94ea60f1 | ||
|
|
c0dbd4d501 | ||
|
|
64f1090b56 | ||
|
|
6668f3d858 | ||
|
|
198d1720a0 | ||
|
|
e423b0095f | ||
|
|
7ab460b10d | ||
|
|
7f93fa6ddc | ||
|
|
c2e20b0786 | ||
|
|
c78f87cec4 | ||
|
|
3f416f3a54 | ||
|
|
087bdaf5f8 | ||
|
|
2b02d0daf7 | ||
|
|
5e079feafa | ||
|
|
b5b36fcf2f | ||
|
|
a169838ab7 | ||
|
|
90f3061c41 | ||
|
|
34745176af | ||
|
|
581ed6ab6e | ||
|
|
117eeefb76 | ||
|
|
4299e71018 | ||
|
|
06d4ca0254 | ||
|
|
bb5437286a | ||
|
|
18a926b11b | ||
|
|
a71a160bc2 | ||
|
|
c474fc130c | ||
|
|
dbfac55a3c | ||
|
|
80964e83eb | ||
|
|
88384457ee | ||
|
|
37ea897a44 | ||
|
|
55d463eeea | ||
|
|
5f847d2fa7 | ||
|
|
e4652359c3 | ||
|
|
a03cb40ce5 | ||
|
|
9ab900156d | ||
|
|
c6bbe648e8 | ||
|
|
dc6f44fae6 | ||
|
|
76e373c559 | ||
|
|
1d8013e2ce | ||
|
|
cb312a2e76 | ||
|
|
e7be98f40c | ||
|
|
d8f1980343 | ||
|
|
76d83c0d5c | ||
|
|
7335865bd9 | ||
|
|
e43316238d | ||
|
|
c3c6f25ec7 | ||
|
|
331461a65e | ||
|
|
fd05501b4d | ||
|
|
0fa76e01de | ||
|
|
1c215bab58 | ||
|
|
c7238a0746 | ||
|
|
71123b2913 | ||
|
|
2eede7e5ac | ||
|
|
507b8182cf | ||
|
|
3df96518be | ||
|
|
84420c7f12 | ||
|
|
c57e85fd13 | ||
|
|
2eca011798 | ||
|
|
f6cf01337f | ||
|
|
0ad86343c6 | ||
|
|
42524c2bf1 | ||
|
|
46f1ddbff9 | ||
|
|
b18f5c9af1 | ||
|
|
18e9b2ffc9 | ||
|
|
9ec3637bc5 | ||
|
|
ba9248e6e3 | ||
|
|
a27559cddf | ||
|
|
e786726603 | ||
|
|
a1d2a22047 | ||
|
|
d43ecd5b32 | ||
|
|
61359bf6ad | ||
|
|
a2beda1177 | ||
|
|
52c895d565 | ||
|
|
74f90612ec | ||
|
|
a6eb61b7e4 | ||
|
|
fe11782158 | ||
|
|
899e99a025 | ||
|
|
e0774e4730 | ||
|
|
60f783d9ce | ||
|
|
6b46d65597 | ||
|
|
fb1588c5ff | ||
|
|
dea5a10f71 | ||
|
|
11dafeaa75 | ||
|
|
bb99aa1149 | ||
|
|
b132992978 | ||
|
|
78a1fda7c8 | ||
|
|
8d02083f23 | ||
|
|
b1c36b7088 | ||
|
|
b2d4142fb7 | ||
|
|
1aae5e70ef | ||
|
|
a2a34133d8 | ||
|
|
79aa54d0c7 | ||
|
|
3ad5fd1879 | ||
|
|
4c3725723f | ||
|
|
c20a4d18e3 | ||
|
|
01a9fbbcca | ||
|
|
8d4ca9edc6 | ||
|
|
d793a56121 | ||
|
|
f424efe97f | ||
|
|
9f7ff621bd | ||
|
|
b0be721dd9 | ||
|
|
8ca8ac379d | ||
|
|
589ce09564 | ||
|
|
6c42c142e2 | ||
|
|
abc06a2f76 | ||
|
|
b0c3d451a2 | ||
|
|
7e86f9b4d2 | ||
|
|
abe97736b8 | ||
|
|
7e0f60d2ed | ||
|
|
3afa5385c9 | ||
|
|
c545331f9e | ||
|
|
cd0ecff00b | ||
|
|
a0c761dc6b | ||
|
|
b5cf2b4b82 | ||
|
|
8378a44ff9 | ||
|
|
4f0c8ef9f1 | ||
|
|
bc302f2aec | ||
|
|
08d94d3f7e | ||
|
|
10ec012f58 | ||
|
|
92fd824480 | ||
|
|
6d916329b8 | ||
|
|
84465a2cc1 | ||
|
|
0fee359278 | ||
|
|
e0eb8e9c65 | ||
|
|
2826324e56 | ||
|
|
1681ede605 | ||
|
|
44db47c63e | ||
|
|
25139ac92c | ||
|
|
0e52a609fd | ||
|
|
df78de2bc8 | ||
|
|
36b91e34f4 | ||
|
|
bdfddb09d7 | ||
|
|
fdfc8e3b9c | ||
|
|
f5ed5c317e | ||
|
|
96183e0f28 | ||
|
|
f2e32e4fd7 | ||
|
|
8beb84fa33 | ||
|
|
a448e74661 | ||
|
|
fb526a0470 | ||
|
|
96c19ff7cc | ||
|
|
9b78af95be | ||
|
|
5a63df211d | ||
|
|
1851596db5 | ||
|
|
0665182950 | ||
|
|
515917f5d8 | ||
|
|
bc52d81306 | ||
|
|
dbbf2fd19c | ||
|
|
9476d628a3 | ||
|
|
7240e8af6a | ||
|
|
f2990620d7 | ||
|
|
17f2fb44c0 | ||
|
|
8c049c6b20 | ||
|
|
761c9cd5db | ||
|
|
a159fd0b8c | ||
|
|
e8b84ab1b4 | ||
|
|
383ea02e38 | ||
|
|
597fb1da94 | ||
|
|
c6e33d30c1 | ||
|
|
a61a39ecd4 | ||
|
|
b64d1fe637 | ||
|
|
6f17422ca7 | ||
|
|
bac12fa5fc | ||
|
|
56fdfeb265 | ||
|
|
881712cf50 | ||
|
|
b2c91983dc | ||
|
|
bdace5d6aa | ||
|
|
0fcb4302e1 | ||
|
|
11361a9e79 | ||
|
|
add3ccbca6 | ||
|
|
d35a67bba3 | ||
|
|
7e79889d1c | ||
|
|
43e2bbe28e | ||
|
|
b154b97ea4 | ||
|
|
15cafbe267 | ||
|
|
12bbc34aca | ||
|
|
8141f0894e | ||
|
|
27651c1fad | ||
|
|
a9ef2fd56c | ||
|
|
ae63d5c90d | ||
|
|
6f3896751a | ||
|
|
5b0f839054 | ||
|
|
a5d8c95a7c | ||
|
|
dec2c4f4e3 | ||
|
|
99cdea7cbe | ||
|
|
c2d13a9a53 | ||
|
|
fb615cd7fd | ||
|
|
4ae4828953 | ||
|
|
f57ca87729 | ||
|
|
7b6383f263 | ||
|
|
257a29d3cc | ||
|
|
8298bef72e | ||
|
|
046c900df2 | ||
|
|
504f7cfbb3 | ||
|
|
0963774c0a | ||
|
|
2d3bc99b0d | ||
|
|
ba9c469113 | ||
|
|
bfbdeeae30 | ||
|
|
67e18c523c | ||
|
|
526f1e5f15 | ||
|
|
f8f4872fcc | ||
|
|
fad166c152 | ||
|
|
78e4d88c70 | ||
|
|
ac42e6951f | ||
|
|
d0d10f51d7 | ||
|
|
69c4e4ce65 | ||
|
|
80473e035a | ||
|
|
70af7efa16 | ||
|
|
56b35afbdd | ||
|
|
0e9190c902 | ||
|
|
449cf50d85 | ||
|
|
05defcd63a | ||
|
|
f8f365346e | ||
|
|
4a745ca670 | ||
|
|
68bfd8a392 | ||
|
|
549b2ad77c | ||
|
|
09a23d2290 | ||
|
|
7d2173ec5c | ||
|
|
cc53229378 | ||
|
|
844da12ba6 | ||
|
|
a9c69f3bb0 | ||
|
|
687d7f52c4 | ||
|
|
cbf36cf57c | ||
|
|
52c922fad1 | ||
|
|
da93d69bcb | ||
|
|
e703fc101b | ||
|
|
85b6d79d8a | ||
|
|
5ed6a8447b | ||
|
|
54a5088cd5 | ||
|
|
08302d2feb | ||
|
|
c7e875abdb | ||
|
|
1ac00a6844 | ||
|
|
e4accdec0c | ||
|
|
b41c3ba154 | ||
|
|
0f44d37d04 | ||
|
|
ed8cabcec2 | ||
|
|
3d6ed50187 | ||
|
|
b760d699a8 | ||
|
|
5796a92433 | ||
|
|
b1a97a4998 | ||
|
|
a815f0c5a3 | ||
|
|
9da7ff8842 | ||
|
|
2ed893bdce | ||
|
|
240f4e944c | ||
|
|
f7e27bd078 | ||
|
|
6a9e188c0c | ||
|
|
aa449141b4 | ||
|
|
a9032c885f | ||
|
|
e8ba5265e0 | ||
|
|
50f3754525 | ||
|
|
4986d5ed04 | ||
|
|
4fef5af9c3 | ||
|
|
e5af56abfe | ||
|
|
9d3bd87045 | ||
|
|
6b0616d1b8 | ||
|
|
d3da1a2c66 | ||
|
|
8e6a044b2b | ||
|
|
50b7c0c104 | ||
|
|
c66013e2c5 | ||
|
|
9e08e196fa | ||
|
|
17b4fd25e4 | ||
|
|
bd9ca9aed0 | ||
|
|
f97da34b4f | ||
|
|
326188c25e | ||
|
|
60e82a3ca2 | ||
|
|
3ff921a65a | ||
|
|
b10bf834b7 | ||
|
|
86f0287993 | ||
|
|
ab2d7c8b5d | ||
|
|
ca5f5d97b9 | ||
|
|
e3f14d12cd | ||
|
|
e53791f8c0 | ||
|
|
48fbe7b0d8 | ||
|
|
55e88eeee4 | ||
|
|
8be3e09fcf | ||
|
|
ef0591efc2 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
*.gem
|
||||
pkg
|
||||
.bundle
|
||||
debug.log
|
||||
|
||||
1
.ruby-version
Normal file
1
.ruby-version
Normal file
@@ -0,0 +1 @@
|
||||
2.0.0-github
|
||||
7
Gemfile.sh
Normal file
7
Gemfile.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
gem install mocha -v=0.13.1
|
||||
gem install rake -v=10.1.0
|
||||
gem install rdoc -v=4.0.1
|
||||
gem install sqlite3 -v=1.3.7
|
||||
gem install rack -v=1.4.5
|
||||
gem install erubis -v=2.7.0
|
||||
gem install json -v=1.8.0
|
||||
11
Rakefile
11
Rakefile
@@ -1,5 +1,5 @@
|
||||
require 'rake'
|
||||
require 'rake/rdoctask'
|
||||
require 'rdoc/task'
|
||||
|
||||
env = %(PKG_BUILD="#{ENV['PKG_BUILD']}") if ENV['PKG_BUILD']
|
||||
|
||||
@@ -12,24 +12,29 @@ end
|
||||
desc 'Run all tests by default'
|
||||
task :default => :test
|
||||
|
||||
%w(test rdoc pgem package release).each do |task_name|
|
||||
%w(test rdoc pgem package release gem).each do |task_name|
|
||||
desc "Run #{task_name} task for all projects"
|
||||
task task_name do
|
||||
passed = true
|
||||
PROJECTS.each do |project|
|
||||
system %(cd #{project} && #{env} #{$0} #{task_name})
|
||||
passed &&= $?.success?
|
||||
end
|
||||
exit! passed
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
desc "Generate documentation for the Rails framework"
|
||||
Rake::RDocTask.new do |rdoc|
|
||||
RDoc::Task.new do |rdoc|
|
||||
rdoc.rdoc_dir = 'doc/rdoc'
|
||||
rdoc.title = "Ruby on Rails Documentation"
|
||||
rdoc.main = "railties/README"
|
||||
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
rdoc.options << '-A cattr_accessor=object'
|
||||
rdoc.options << '--charset' << 'utf-8'
|
||||
rdoc.options << '--main' << 'railties/README'
|
||||
|
||||
rdoc.template = ENV['template'] ? "#{ENV['template']}.rb" : './doc/template/horo'
|
||||
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
*2.3.11 (February 9, 2011)*
|
||||
*2.3.10 (October 15, 2010)*
|
||||
*2.3.9 (September 4, 2010)*
|
||||
*2.3.8 (May 24, 2010)*
|
||||
*2.3.7 (May 24, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
||||
|
||||
*2.3.6 (May 23, 2010)*
|
||||
|
||||
* Upgrade TMail from 1.2.3 to 1.2.7. [Mikel Lindsaar]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
require 'rubygems'
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
require 'rdoc/task'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
require 'rubygems/package_task'
|
||||
require File.join(File.dirname(__FILE__), 'lib', 'action_mailer', 'version')
|
||||
|
||||
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
||||
@@ -29,7 +29,7 @@ Rake::TestTask.new { |t|
|
||||
|
||||
|
||||
# Generate the RDoc documentation
|
||||
Rake::RDocTask.new { |rdoc|
|
||||
RDoc::Task.new { |rdoc|
|
||||
rdoc.rdoc_dir = 'doc'
|
||||
rdoc.title = "Action Mailer -- Easy email delivery and testing"
|
||||
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
||||
@@ -54,19 +54,17 @@ spec = Gem::Specification.new do |s|
|
||||
s.rubyforge_project = "actionmailer"
|
||||
s.homepage = "http://www.rubyonrails.org"
|
||||
|
||||
s.add_dependency('actionpack', '= 2.3.6' + PKG_BUILD)
|
||||
s.add_dependency('actionpack', '= 2.3.14' + PKG_BUILD)
|
||||
|
||||
s.has_rdoc = true
|
||||
s.requirements << 'none'
|
||||
s.require_path = 'lib'
|
||||
s.autorequire = 'action_mailer'
|
||||
|
||||
s.files = [ "Rakefile", "install.rb", "README", "CHANGELOG", "MIT-LICENSE" ]
|
||||
s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
||||
s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
||||
end
|
||||
|
||||
Rake::GemPackageTask.new(spec) do |p|
|
||||
Gem::PackageTask.new(spec) do |p|
|
||||
p.gem_spec = spec
|
||||
p.need_tar = true
|
||||
p.need_zip = true
|
||||
|
||||
@@ -58,5 +58,3 @@ module Net
|
||||
end
|
||||
|
||||
autoload :MailHelper, 'action_mailer/mail_helper'
|
||||
|
||||
require 'action_mailer/vendor/tmail'
|
||||
|
||||
@@ -195,6 +195,39 @@ module ActionMailer #:nodoc:
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# = Multipart Emails with Attachments
|
||||
#
|
||||
# Multipart emails that also have attachments can be created by nesting a "multipart/alternative" part
|
||||
# within an email that has its content type set to "multipart/mixed". This would also need two templates
|
||||
# in place within +app/views/mailer+ called "welcome_email.text.html.erb" and "welcome_email.text.plain.erb"
|
||||
#
|
||||
# class ApplicationMailer < ActionMailer::Base
|
||||
# def signup_notification(recipient)
|
||||
# recipients recipient.email_address_with_name
|
||||
# subject "New account information"
|
||||
# from "system@example.com"
|
||||
# content_type "multipart/mixed"
|
||||
#
|
||||
# part "multipart/alternative" do |alternative|
|
||||
#
|
||||
# alternative.part "text/html" do |html|
|
||||
# html.body = render_message("welcome_email.text.html", :message => "<h1>HTML content</h1>")
|
||||
# end
|
||||
#
|
||||
# alternative.part "text/plain" do |plain|
|
||||
# plain.body = render_message("welcome_email.text.plain", :message => "text content")
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# attachment :content_type => "image/png",
|
||||
# :body => File.read(File.join(RAILS_ROOT, 'public/images/rails.png'))
|
||||
#
|
||||
# attachment "application/pdf" do |a|
|
||||
# a.body = File.read('/Users/mikel/Code/mail/spec/fixtures/attachments/test.pdf')
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# = Configuration options
|
||||
#
|
||||
@@ -278,7 +311,7 @@ module ActionMailer #:nodoc:
|
||||
@@raise_delivery_errors = true
|
||||
cattr_accessor :raise_delivery_errors
|
||||
|
||||
superclass_delegating_accessor :delivery_method
|
||||
class_attribute :delivery_method
|
||||
self.delivery_method = :smtp
|
||||
|
||||
@@perform_deliveries = true
|
||||
|
||||
@@ -105,7 +105,7 @@ module ActionMailer
|
||||
private
|
||||
# Extend the template class instance with our controller's helper module.
|
||||
def initialize_template_class_with_helper(assigns)
|
||||
returning(template = initialize_template_class_without_helper(assigns)) do
|
||||
initialize_template_class_without_helper(assigns).tap do |template|
|
||||
template.extend self.class.master_helper_module
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,6 +43,8 @@ module ActionMailer
|
||||
end
|
||||
|
||||
def set_expected_mail
|
||||
failed_pre_200
|
||||
|
||||
@expected = TMail::Mail.new
|
||||
@expected.set_content_type "text", "plain", { "charset" => charset }
|
||||
@expected.mime_version = '1.0'
|
||||
|
||||
@@ -2,7 +2,7 @@ module ActionMailer
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 3
|
||||
TINY = 6
|
||||
TINY = 14
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
require 'rubygems'
|
||||
require 'test/unit'
|
||||
|
||||
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
||||
$:.unshift "#{File.dirname(__FILE__)}/../../activesupport/lib"
|
||||
$:.unshift "#{File.dirname(__FILE__)}/../../actionpack/lib"
|
||||
require 'action_mailer'
|
||||
require 'action_mailer/test_case'
|
||||
|
||||
# Show backtraces for deprecated behavior for quicker cleanup.
|
||||
ActiveSupport::Deprecation.debug = true
|
||||
|
||||
# Bogus template processors
|
||||
ActionView::Template.register_template_handler :haml, lambda { |template| "Look its HAML!".inspect }
|
||||
ActionView::Template.register_template_handler :bak, lambda { |template| "Lame backup".inspect }
|
||||
|
||||
$:.unshift "#{File.dirname(__FILE__)}/fixtures/helpers"
|
||||
|
||||
ActionView::Base.cache_template_loading = true
|
||||
FIXTURE_LOAD_PATH = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures'))
|
||||
ActionMailer::Base.template_root = FIXTURE_LOAD_PATH
|
||||
|
||||
class MockSMTP
|
||||
def self.deliveries
|
||||
@@deliveries
|
||||
end
|
||||
|
||||
def initialize
|
||||
@@deliveries = []
|
||||
end
|
||||
|
||||
def sendmail(mail, from, to)
|
||||
@@deliveries << [mail, from, to]
|
||||
end
|
||||
|
||||
def start(*args)
|
||||
yield self
|
||||
end
|
||||
end
|
||||
|
||||
class Net::SMTP
|
||||
def self.new(*args)
|
||||
MockSMTP.new
|
||||
end
|
||||
end
|
||||
|
||||
def uses_gem(gem_name, test_name, version = '> 0')
|
||||
gem gem_name.to_s, version
|
||||
require gem_name.to_s
|
||||
yield
|
||||
rescue LoadError
|
||||
$stderr.puts "Skipping #{test_name} tests. `gem install #{gem_name}` and try again."
|
||||
end
|
||||
|
||||
def set_delivery_method(delivery_method)
|
||||
@old_delivery_method = ActionMailer::Base.delivery_method
|
||||
ActionMailer::Base.delivery_method = delivery_method
|
||||
end
|
||||
|
||||
def restore_delivery_method
|
||||
ActionMailer::Base.delivery_method = @old_delivery_method
|
||||
end
|
||||
@@ -1,54 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class AssetHostMailer < ActionMailer::Base
|
||||
def email_with_asset(recipient)
|
||||
recipients recipient
|
||||
subject "testing email containing asset path while asset_host is set"
|
||||
from "tester@example.com"
|
||||
end
|
||||
end
|
||||
|
||||
class AssetHostTest < Test::Unit::TestCase
|
||||
def setup
|
||||
set_delivery_method :test
|
||||
ActionMailer::Base.perform_deliveries = true
|
||||
ActionMailer::Base.deliveries = []
|
||||
|
||||
@recipient = 'test@localhost'
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_asset_host_as_string
|
||||
ActionController::Base.asset_host = "http://www.example.com"
|
||||
mail = AssetHostMailer.deliver_email_with_asset(@recipient)
|
||||
assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.strip
|
||||
end
|
||||
|
||||
def test_asset_host_as_one_arguement_proc
|
||||
ActionController::Base.asset_host = Proc.new { |source|
|
||||
if source.starts_with?('/images')
|
||||
"http://images.example.com"
|
||||
else
|
||||
"http://assets.example.com"
|
||||
end
|
||||
}
|
||||
mail = AssetHostMailer.deliver_email_with_asset(@recipient)
|
||||
assert_equal "<img alt=\"Somelogo\" src=\"http://images.example.com/images/somelogo.png\" />", mail.body.strip
|
||||
end
|
||||
|
||||
def test_asset_host_as_two_arguement_proc
|
||||
ActionController::Base.asset_host = Proc.new {|source,request|
|
||||
if request && request.ssl?
|
||||
"https://www.example.com"
|
||||
else
|
||||
"http://www.example.com"
|
||||
end
|
||||
}
|
||||
mail = nil
|
||||
assert_nothing_raised { mail = AssetHostMailer.deliver_email_with_asset(@recipient) }
|
||||
assert_equal "<img alt=\"Somelogo\" src=\"http://www.example.com/images/somelogo.png\" />", mail.body.strip
|
||||
end
|
||||
end
|
||||
@@ -1,51 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class DefaultDeliveryMethodMailer < ActionMailer::Base
|
||||
end
|
||||
|
||||
class NonDefaultDeliveryMethodMailer < ActionMailer::Base
|
||||
self.delivery_method = :sendmail
|
||||
end
|
||||
|
||||
class ActionMailerBase_delivery_method_Test < Test::Unit::TestCase
|
||||
def setup
|
||||
set_delivery_method :smtp
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_should_be_the_default_smtp
|
||||
assert_equal :smtp, ActionMailer::Base.delivery_method
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
|
||||
def setup
|
||||
set_delivery_method :smtp
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_should_be_the_default_smtp
|
||||
assert_equal :smtp, DefaultDeliveryMethodMailer.delivery_method
|
||||
end
|
||||
end
|
||||
|
||||
class NonDefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
|
||||
def setup
|
||||
set_delivery_method :smtp
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_should_be_the_set_delivery_method
|
||||
assert_equal :sendmail, NonDefaultDeliveryMethodMailer.delivery_method
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<%= image_tag "somelogo.png" %>
|
||||
@@ -1 +0,0 @@
|
||||
Inside
|
||||
@@ -1 +0,0 @@
|
||||
text/html multipart
|
||||
@@ -1 +0,0 @@
|
||||
text/plain multipart
|
||||
@@ -1 +0,0 @@
|
||||
You logged out
|
||||
@@ -1 +0,0 @@
|
||||
We do not spam
|
||||
@@ -1 +0,0 @@
|
||||
first mail
|
||||
@@ -1 +0,0 @@
|
||||
So, <%= example_format(@text) %>
|
||||
@@ -1 +0,0 @@
|
||||
Hello, <%= person_name %>. Thanks for registering!
|
||||
@@ -1 +0,0 @@
|
||||
This message brought to you by <%= name_of_the_mailer_class %>.
|
||||
@@ -1,5 +0,0 @@
|
||||
From "Romeo and Juliet":
|
||||
|
||||
<%= block_format @text %>
|
||||
|
||||
Good ol' Shakespeare.
|
||||
@@ -1,5 +0,0 @@
|
||||
module ExampleHelper
|
||||
def example_format(text)
|
||||
"<em><strong><small>#{h(text)}</small></strong></em>".html_safe
|
||||
end
|
||||
end
|
||||
@@ -1 +0,0 @@
|
||||
Hello from layout <%= yield %>
|
||||
@@ -1 +0,0 @@
|
||||
text/plain layout - <%= yield %>
|
||||
@@ -1 +0,0 @@
|
||||
Spammer layout <%= yield %>
|
||||
@@ -1 +0,0 @@
|
||||
Have a lovely picture, from me. Enjoy!
|
||||
14
actionmailer/test/fixtures/raw_email
vendored
14
actionmailer/test/fixtures/raw_email
vendored
@@ -1,14 +0,0 @@
|
||||
From jamis_buck@byu.edu Mon May 2 16:07:05 2005
|
||||
Mime-Version: 1.0 (Apple Message framework v622)
|
||||
Content-Transfer-Encoding: base64
|
||||
Message-Id: <d3b8cf8e49f04480850c28713a1f473e@37signals.com>
|
||||
Content-Type: text/plain;
|
||||
charset=EUC-KR;
|
||||
format=flowed
|
||||
To: willard15georgina@jamis.backpackit.com
|
||||
From: Jamis Buck <jamis@37signals.com>
|
||||
Subject: =?EUC-KR?Q?NOTE:_=C7=D1=B1=B9=B8=BB=B7=CE_=C7=CF=B4=C2_=B0=CD?=
|
||||
Date: Mon, 2 May 2005 16:07:05 -0600
|
||||
|
||||
tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin
|
||||
wLogSmFtaXPA1LTPtNku
|
||||
20
actionmailer/test/fixtures/raw_email10
vendored
20
actionmailer/test/fixtures/raw_email10
vendored
@@ -1,20 +0,0 @@
|
||||
Return-Path: <xxx@xxxx.xxx>
|
||||
Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:05 -0500
|
||||
Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:04 -0500
|
||||
Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:03 -0500
|
||||
Date: Tue, 10 May 2005 15:27:03 -0500
|
||||
From: xxx@xxxx.xxx
|
||||
Sender: xxx@xxxx.xxx
|
||||
To: xxxxxxxxxxx@xxxx.xxxx.xxx
|
||||
Message-Id: <xxx@xxxx.xxx>
|
||||
X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx
|
||||
Delivered-To: xxx@xxxx.xxx
|
||||
Importance: normal
|
||||
Content-Type: text/plain; charset=X-UNKNOWN
|
||||
|
||||
Test test. Hi. Waving. m
|
||||
|
||||
----------------------------------------------------------------
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Envoyé par le service de messagerie texte de Bell Mobilité.
|
||||
----------------------------------------------------------------
|
||||
32
actionmailer/test/fixtures/raw_email12
vendored
32
actionmailer/test/fixtures/raw_email12
vendored
@@ -1,32 +0,0 @@
|
||||
Mime-Version: 1.0 (Apple Message framework v730)
|
||||
Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151
|
||||
Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com>
|
||||
From: foo@example.com
|
||||
Subject: testing
|
||||
Date: Mon, 6 Jun 2005 22:21:22 +0200
|
||||
To: blah@example.com
|
||||
|
||||
|
||||
--Apple-Mail-13-196941151
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain;
|
||||
charset=ISO-8859-1;
|
||||
delsp=yes;
|
||||
format=flowed
|
||||
|
||||
This is the first part.
|
||||
|
||||
--Apple-Mail-13-196941151
|
||||
Content-Type: image/jpeg
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Location: Photo25.jpg
|
||||
Content-ID: <qbFGyPQAS8>
|
||||
Content-Disposition: inline
|
||||
|
||||
jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw
|
||||
ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE
|
||||
QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB
|
||||
gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5=
|
||||
|
||||
--Apple-Mail-13-196941151--
|
||||
|
||||
29
actionmailer/test/fixtures/raw_email13
vendored
29
actionmailer/test/fixtures/raw_email13
vendored
@@ -1,29 +0,0 @@
|
||||
Mime-Version: 1.0 (Apple Message framework v730)
|
||||
Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151
|
||||
Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com>
|
||||
From: foo@example.com
|
||||
Subject: testing
|
||||
Date: Mon, 6 Jun 2005 22:21:22 +0200
|
||||
To: blah@example.com
|
||||
|
||||
|
||||
--Apple-Mail-13-196941151
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain;
|
||||
charset=ISO-8859-1;
|
||||
delsp=yes;
|
||||
format=flowed
|
||||
|
||||
This is the first part.
|
||||
|
||||
--Apple-Mail-13-196941151
|
||||
Content-Type: text/x-ruby-script; name="hello.rb"
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Disposition: attachment;
|
||||
filename="api.rb"
|
||||
|
||||
puts "Hello, world!"
|
||||
gets
|
||||
|
||||
--Apple-Mail-13-196941151--
|
||||
|
||||
114
actionmailer/test/fixtures/raw_email2
vendored
114
actionmailer/test/fixtures/raw_email2
vendored
@@ -1,114 +0,0 @@
|
||||
From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005
|
||||
Return-Path: <xxxxxxxxx.xxxxxxx@gmail.com>
|
||||
X-Original-To: xxxxx@xxxxx.xxxxxxxxx.com
|
||||
Delivered-To: xxxxx@xxxxx.xxxxxxxxx.com
|
||||
Received: from localhost (localhost [127.0.0.1])
|
||||
by xxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 06C9DA98D
|
||||
for <xxxxx@xxxxx.xxxxxxxxx.com>; Sun, 8 May 2005 19:09:13 +0000 (GMT)
|
||||
Received: from xxxxx.xxxxxxxxx.com ([127.0.0.1])
|
||||
by localhost (xxxxx.xxxxxxxxx.com [127.0.0.1]) (amavisd-new, port 10024)
|
||||
with LMTP id 88783-08 for <xxxxx@xxxxx.xxxxxxxxx.com>;
|
||||
Sun, 8 May 2005 19:09:12 +0000 (GMT)
|
||||
Received: from xxxxxxx.xxxxxxxxx.com (xxxxxxx.xxxxxxxxx.com [69.36.39.150])
|
||||
by xxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 10D8BA960
|
||||
for <xxxxx@xxxxxxxxx.org>; Sun, 8 May 2005 19:09:12 +0000 (GMT)
|
||||
Received: from zproxy.gmail.com (zproxy.gmail.com [64.233.162.199])
|
||||
by xxxxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 9EBC4148EAB
|
||||
for <xxxxx@xxxxxxxxx.com>; Sun, 8 May 2005 14:09:11 -0500 (CDT)
|
||||
Received: by zproxy.gmail.com with SMTP id 13so1233405nzp
|
||||
for <xxxxx@xxxxxxxxx.com>; Sun, 08 May 2005 12:09:11 -0700 (PDT)
|
||||
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws;
|
||||
s=beta; d=gmail.com;
|
||||
h=received:message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:references;
|
||||
b=cid1mzGEFa3gtRa06oSrrEYfKca2CTKu9sLMkWxjbvCsWMtp9RGEILjUz0L5RySdH5iO661LyNUoHRFQIa57bylAbXM3g2DTEIIKmuASDG3x3rIQ4sHAKpNxP7Pul+mgTaOKBv+spcH7af++QEJ36gHFXD2O/kx9RePs3JNf/K8=
|
||||
Received: by 10.36.10.16 with SMTP id 16mr1012493nzj;
|
||||
Sun, 08 May 2005 12:09:11 -0700 (PDT)
|
||||
Received: by 10.36.5.10 with HTTP; Sun, 8 May 2005 12:09:11 -0700 (PDT)
|
||||
Message-ID: <e85734b90505081209eaaa17b@mail.gmail.com>
|
||||
Date: Sun, 8 May 2005 14:09:11 -0500
|
||||
From: xxxxxxxxx xxxxxxx <xxxxxxxxx.xxxxxxx@gmail.com>
|
||||
Reply-To: xxxxxxxxx xxxxxxx <xxxxxxxxx.xxxxxxx@gmail.com>
|
||||
To: xxxxx xxxx <xxxxx@xxxxxxxxx.com>
|
||||
Subject: Fwd: Signed email causes file attachments
|
||||
In-Reply-To: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com>
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="----=_Part_5028_7368284.1115579351471"
|
||||
References: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com>
|
||||
|
||||
------=_Part_5028_7368284.1115579351471
|
||||
Content-Type: text/plain; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Disposition: inline
|
||||
|
||||
We should not include these files or vcards as attachments.
|
||||
|
||||
---------- Forwarded message ----------
|
||||
From: xxxxx xxxxxx <xxxxxxxx@xxx.com>
|
||||
Date: May 8, 2005 1:17 PM
|
||||
Subject: Signed email causes file attachments
|
||||
To: xxxxxxx@xxxxxxxxxx.com
|
||||
|
||||
|
||||
Hi,
|
||||
|
||||
Just started to use my xxxxxxxx account (to set-up a GTD system,
|
||||
natch) and noticed that when I send content via email the signature/
|
||||
certificate from my email account gets added as a file (e.g.
|
||||
"smime.p7s").
|
||||
|
||||
Obviously I can uncheck the signature option in the Mail compose
|
||||
window but how often will I remember to do that?
|
||||
|
||||
Is there any way these kind of files could be ignored, e.g. via some
|
||||
sort of exclusions list?
|
||||
|
||||
------=_Part_5028_7368284.1115579351471
|
||||
Content-Type: application/pkcs7-signature; name=smime.p7s
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="smime.p7s"
|
||||
|
||||
MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w
|
||||
ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh
|
||||
d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt
|
||||
YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD
|
||||
ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL
|
||||
7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw
|
||||
o8xS3A0a1LXealcmlEbJibmKkEaoXci3MhryLgpaa+Kk/sH02SNatDO1vS28bPsibZpcc6deFrla
|
||||
hSYnL+PW54mDTGHIcCN2fbx/Y6qspzqmtKaXrv75NBtuy9cB6KzU4j2xXbTkAwz3pRSghJJaAwdp
|
||||
+yIivAD3vr0kJE3p+Ez34HMh33EXEpFoWcN+MCEQZD9WnmFViMrvfvMXLGVFQfAAcC060eGFSRJ1
|
||||
ZQ9UVQIDAQABoy0wKzAbBgNVHREEFDASgRBzbWhhdW5jaEBtYWMuY29tMAwGA1UdEwEB/wQCMAAw
|
||||
DQYJKoZIhvcNAQEEBQADgYEAQMrg1n2pXVWteP7BBj+Pk3UfYtbuHb42uHcLJjfjnRlH7AxnSwrd
|
||||
L3HED205w3Cq8T7tzVxIjRRLO/ljq0GedSCFBky7eYo1PrXhztGHCTSBhsiWdiyLWxKlOxGAwJc/
|
||||
lMMnwqLOdrQcoF/YgbjeaUFOQbUh94w9VDNpWZYCZwcwggM/MIICqKADAgECAgENMA0GCSqGSIb3
|
||||
DQEBBQUAMIHRMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlD
|
||||
YXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0
|
||||
aW9uIFNlcnZpY2VzIERpdmlzaW9uMSQwIgYDVQQDExtUaGF3dGUgUGVyc29uYWwgRnJlZW1haWwg
|
||||
Q0ExKzApBgkqhkiG9w0BCQEWHHBlcnNvbmFsLWZyZWVtYWlsQHRoYXd0ZS5jb20wHhcNMDMwNzE3
|
||||
MDAwMDAwWhcNMTMwNzE2MjM1OTU5WjBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENv
|
||||
bnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVtYWlsIElz
|
||||
c3VpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMSmPFVzVftOucqZWh5owHUEcJ3f
|
||||
6f+jHuy9zfVb8hp2vX8MOmHyv1HOAdTlUAow1wJjWiyJFXCO3cnwK4Vaqj9xVsuvPAsH5/EfkTYk
|
||||
KhPPK9Xzgnc9A74r/rsYPge/QIACZNenprufZdHFKlSFD0gEf6e20TxhBEAeZBlyYLf7AgMBAAGj
|
||||
gZQwgZEwEgYDVR0TAQH/BAgwBgEB/wIBADBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLnRo
|
||||
YXd0ZS5jb20vVGhhd3RlUGVyc29uYWxGcmVlbWFpbENBLmNybDALBgNVHQ8EBAMCAQYwKQYDVR0R
|
||||
BCIwIKQeMBwxGjAYBgNVBAMTEVByaXZhdGVMYWJlbDItMTM4MA0GCSqGSIb3DQEBBQUAA4GBAEiM
|
||||
0VCD6gsuzA2jZqxnD3+vrL7CF6FDlpSdf0whuPg2H6otnzYvwPQcUCCTcDz9reFhYsPZOhl+hLGZ
|
||||
GwDFGguCdJ4lUJRix9sncVcljd2pnDmOjCBPZV+V2vf3h9bGCE6u9uo05RAaWzVNd+NWIXiC3CEZ
|
||||
Nd4ksdMdRv9dX2VPMYIC5zCCAuMCAQEwaTBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3Rl
|
||||
IENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVtYWls
|
||||
IElzc3VpbmcgQ0ECAw5c+TAJBgUrDgMCGgUAoIIBUzAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcB
|
||||
MBwGCSqGSIb3DQEJBTEPFw0wNTA1MDgxODE3NDZaMCMGCSqGSIb3DQEJBDEWBBQSkG9j6+hB0pKp
|
||||
fV9tCi/iP59sNTB4BgkrBgEEAYI3EAQxazBpMGIxCzAJBgNVBAYTAlpBMSUwIwYDVQQKExxUaGF3
|
||||
dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMSwwKgYDVQQDEyNUaGF3dGUgUGVyc29uYWwgRnJlZW1h
|
||||
aWwgSXNzdWluZyBDQQIDDlz5MHoGCyqGSIb3DQEJEAILMWugaTBiMQswCQYDVQQGEwJaQTElMCMG
|
||||
A1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNv
|
||||
bmFsIEZyZWVtYWlsIElzc3VpbmcgQ0ECAw5c+TANBgkqhkiG9w0BAQEFAASCAQAm1GeF7dWfMvrW
|
||||
8yMPjkhE+R8D1DsiCoWSCp+5gAQm7lcK7V3KrZh5howfpI3TmCZUbbaMxOH+7aKRKpFemxoBY5Q8
|
||||
rnCkbpg/++/+MI01T69hF/rgMmrGcrv2fIYy8EaARLG0xUVFSZHSP+NQSYz0TTmh4cAESHMzY3JA
|
||||
nHOoUkuPyl8RXrimY1zn0lceMXlweZRouiPGuPNl1hQKw8P+GhOC5oLlM71UtStnrlk3P9gqX5v7
|
||||
Tj7Hx057oVfY8FMevjxGwU3EK5TczHezHbWWgTyum9l2ZQbUQsDJxSniD3BM46C1VcbDLPaotAZ0
|
||||
fTYLZizQfm5hcWEbfYVzkSzLAAAAAAAA
|
||||
------=_Part_5028_7368284.1115579351471--
|
||||
|
||||
70
actionmailer/test/fixtures/raw_email3
vendored
70
actionmailer/test/fixtures/raw_email3
vendored
@@ -1,70 +0,0 @@
|
||||
From xxxx@xxxx.com Tue May 10 11:28:07 2005
|
||||
Return-Path: <xxxx@xxxx.com>
|
||||
X-Original-To: xxxx@xxxx.com
|
||||
Delivered-To: xxxx@xxxx.com
|
||||
Received: from localhost (localhost [127.0.0.1])
|
||||
by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F
|
||||
for <xxxx@xxxx.com>; Tue, 10 May 2005 17:26:50 +0000 (GMT)
|
||||
Received: from xxx.xxxxx.com ([127.0.0.1])
|
||||
by localhost (xxx.xxxxx.com [127.0.0.1]) (amavisd-new, port 10024)
|
||||
with LMTP id 70060-03 for <xxxx@xxxx.com>;
|
||||
Tue, 10 May 2005 17:26:49 +0000 (GMT)
|
||||
Received: from xxx.xxxxx.com (xxx.xxxxx.com [69.36.39.150])
|
||||
by xxx.xxxxx.com (Postfix) with ESMTP id 8B957A94B
|
||||
for <xxxx@xxxx.com>; Tue, 10 May 2005 17:26:48 +0000 (GMT)
|
||||
Received: from xxx.xxxxx.com (xxx.xxxxx.com [64.233.184.203])
|
||||
by xxx.xxxxx.com (Postfix) with ESMTP id 9972514824C
|
||||
for <xxxx@xxxx.com>; Tue, 10 May 2005 12:26:40 -0500 (CDT)
|
||||
Received: by xxx.xxxxx.com with SMTP id 68so1694448wri
|
||||
for <xxxx@xxxx.com>; Tue, 10 May 2005 10:26:40 -0700 (PDT)
|
||||
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws;
|
||||
s=beta; d=xxxxx.com;
|
||||
h=received:message-id:date:from:reply-to:to:subject:mime-version:content-type;
|
||||
b=g8ZO5ttS6GPEMAz9WxrRk9+9IXBUfQIYsZLL6T88+ECbsXqGIgfGtzJJFn6o9CE3/HMrrIGkN5AisxVFTGXWxWci5YA/7PTVWwPOhJff5BRYQDVNgRKqMl/SMttNrrRElsGJjnD1UyQ/5kQmcBxq2PuZI5Zc47u6CILcuoBcM+A=
|
||||
Received: by 10.54.96.19 with SMTP id t19mr621017wrb;
|
||||
Tue, 10 May 2005 10:26:39 -0700 (PDT)
|
||||
Received: by 10.54.110.5 with HTTP; Tue, 10 May 2005 10:26:39 -0700 (PDT)
|
||||
Message-ID: <xxxx@xxxx.com>
|
||||
Date: Tue, 10 May 2005 11:26:39 -0600
|
||||
From: Test Tester <xxxx@xxxx.com>
|
||||
Reply-To: Test Tester <xxxx@xxxx.com>
|
||||
To: xxxx@xxxx.com, xxxx@xxxx.com
|
||||
Subject: Another PDF
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="----=_Part_2192_32400445.1115745999735"
|
||||
X-Virus-Scanned: amavisd-new at textdrive.com
|
||||
|
||||
------=_Part_2192_32400445.1115745999735
|
||||
Content-Type: text/plain; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Disposition: inline
|
||||
|
||||
Just attaching another PDF, here, to see what the message looks like,
|
||||
and to see if I can figure out what is going wrong here.
|
||||
|
||||
------=_Part_2192_32400445.1115745999735
|
||||
Content-Type: application/pdf; name="broken.pdf"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="broken.pdf"
|
||||
|
||||
JVBERi0xLjQNCiXk9tzfDQoxIDAgb2JqDQo8PCAvTGVuZ3RoIDIgMCBSDQogICAvRmlsdGVyIC9G
|
||||
bGF0ZURlY29kZQ0KPj4NCnN0cmVhbQ0KeJy9Wt2KJbkNvm/od6jrhZxYln9hWEh2p+8HBvICySaE
|
||||
ycLuTV4/1ifJ9qnq09NpSBimu76yLUuy/qzqcPz7+em3Ixx/CDc6CsXxs3b5+fvfjr/8cPz6/BRu
|
||||
rbfAx/n3739/fuJylJ5u5fjX81OuDr4deK4Bz3z/aDP+8fz0yw8g0Ofq7ktr1Mn+u28rvhy/jVeD
|
||||
QSa+9YNKHP/pxjvDNfVAx/m3MFz54FhvTbaseaxiDoN2LeMVMw+yA7RbHSCDzxZuaYB2E1Yay7QU
|
||||
x89vz0+tyFDKMlAHK5yqLmnjF+c4RjEiQIUeKwblXMe+AsZjN1J5yGQL5DHpDHksurM81rF6PKab
|
||||
gK6zAarIDzIiUY23rJsN9iorAE816aIu6lsgAdQFsuhhkHOUFgVjp2GjMqSewITXNQ27jrMeamkg
|
||||
1rPI3iLWG2CIaSBB+V1245YVRICGbbpYKHc2USFDl6M09acQVQYhlwIrkBNLISvXhGlF1wi5FHCw
|
||||
wxZkoGNJlVeJCEsqKA+3YAV5AMb6KkeaqEJQmFKKQU8T1pRi2ihE1Y4CDrqoYFFXYjJJOatsyzuI
|
||||
8SIlykuxKTMibWK8H1PgEvqYgs4GmQSrEjJAalgGirIhik+p4ZQN9E3ETFPAHE1b8pp1l/0Rc1gl
|
||||
fQs0ABWvyoZZzU8VnPXwVVcO9BEsyjEJaO6eBoZRyKGlrKoYoOygA8BGIzgwN3RQ15ouigG5idZQ
|
||||
fx2U4Db2CqiLO0WHAZoylGiCAqhniNQjFjQPSkmjwfNTgQ6M1Ih+eWo36wFmjIxDJZiGUBiWsAyR
|
||||
xX3EekGOizkGI96Ol9zVZTAivikURhRsHh2E3JhWMpSTZCnnonrLhMCodgrNcgo4uyJUJc6qnVss
|
||||
nrGd1Ptr0YwisCOYyIbUwVjV4xBUNLbguSO2YHujonAMJkMdSI7bIw91Akq2AUlMUWGFTMAOamjU
|
||||
OvZQCxIkY2pCpMFo/IwLdVLHs6nddwTRrgoVbvLU9eB0G4EMndV0TNoxHbt3JBWwK6hhv3iHfDtF
|
||||
yokB302IpEBTnWICde4uYc/1khDbSIkQopO6lcqamGBu1OSE3N5IPSsZX00CkSHRiiyx6HQIShsS
|
||||
HSVNswdVsaOUSAWq9aYhDtGDaoG5a3lBGkYt/lFlBFt1UqrYnzVtUpUQnLiZeouKgf1KhRBViRRk
|
||||
ExepJCzTwEmFDalIRbLEGtw0gfpESOpIAF/NnpPzcVCG86s0g2DuSyd41uhNGbEgaSrWEXORErbw
|
||||
------=_Part_2192_32400445.1115745999735--
|
||||
|
||||
59
actionmailer/test/fixtures/raw_email4
vendored
59
actionmailer/test/fixtures/raw_email4
vendored
@@ -1,59 +0,0 @@
|
||||
Return-Path: <xxx@xxxx.xxx>
|
||||
Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for <xxx@xxxx.xxx>; Sun, 8 May 2005 12:30:23 -0500
|
||||
Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id j48HUC213279 for <xxx@xxxx.xxx>; Sun, 8 May 2005 12:30:13 -0500
|
||||
Received: from conversion-xxx.xxxx.xxx.net by xxx.xxxx.xxx id <0IG600901LQ64I@xxx.xxxx.xxx> for <xxx@xxxx.xxx>; Sun, 8 May 2005 12:30:12 -0500
|
||||
Received: from agw1 by xxx.xxxx.xxx with ESMTP id <0IG600JFYLYCAxxx@xxxx.xxx> for <xxx@xxxx.xxx>; Sun, 8 May 2005 12:30:12 -0500
|
||||
Date: Sun, 8 May 2005 12:30:08 -0500
|
||||
From: xxx@xxxx.xxx
|
||||
To: xxx@xxxx.xxx
|
||||
Message-Id: <7864245.1115573412626.JavaMxxx@xxxx.xxx>
|
||||
Subject: Filth
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary=mimepart_427e4cb4ca329_133ae40413c81ef
|
||||
X-Mms-Priority: 1
|
||||
X-Mms-Transaction-Id: 3198421808-0
|
||||
X-Mms-Message-Type: 0
|
||||
X-Mms-Sender-Visibility: 1
|
||||
X-Mms-Read-Reply: 1
|
||||
X-Original-To: xxx@xxxx.xxx
|
||||
X-Mms-Message-Class: 0
|
||||
X-Mms-Delivery-Report: 0
|
||||
X-Mms-Mms-Version: 16
|
||||
Delivered-To: xxx@xxxx.xxx
|
||||
X-Nokia-Ag-Version: 2.0
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
|
||||
--mimepart_427e4cb4ca329_133ae40413c81ef
|
||||
Content-Type: multipart/mixed; boundary=mimepart_427e4cb4cbd97_133ae40413c8217
|
||||
|
||||
|
||||
|
||||
--mimepart_427e4cb4cbd97_133ae40413c8217
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Disposition: inline
|
||||
Content-Location: text.txt
|
||||
|
||||
Some text
|
||||
|
||||
--mimepart_427e4cb4cbd97_133ae40413c8217--
|
||||
|
||||
--mimepart_427e4cb4ca329_133ae40413c81ef
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
|
||||
--
|
||||
This Orange Multi Media Message was sent wirefree from an Orange
|
||||
MMS phone. If you would like to reply, please text or phone the
|
||||
sender directly by using the phone number listed in the sender's
|
||||
address. To learn more about Orange's Multi Media Messaging
|
||||
Service, find us on the Web at xxx.xxxx.xxx.uk/mms
|
||||
|
||||
|
||||
--mimepart_427e4cb4ca329_133ae40413c81ef
|
||||
|
||||
|
||||
--mimepart_427e4cb4ca329_133ae40413c81ef-
|
||||
|
||||
19
actionmailer/test/fixtures/raw_email5
vendored
19
actionmailer/test/fixtures/raw_email5
vendored
@@ -1,19 +0,0 @@
|
||||
Return-Path: <xxx@xxxx.xxx>
|
||||
Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:05 -0500
|
||||
Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:04 -0500
|
||||
Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:03 -0500
|
||||
Date: Tue, 10 May 2005 15:27:03 -0500
|
||||
From: xxx@xxxx.xxx
|
||||
Sender: xxx@xxxx.xxx
|
||||
To: xxxxxxxxxxx@xxxx.xxxx.xxx
|
||||
Message-Id: <xxx@xxxx.xxx>
|
||||
X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx
|
||||
Delivered-To: xxx@xxxx.xxx
|
||||
Importance: normal
|
||||
|
||||
Test test. Hi. Waving. m
|
||||
|
||||
----------------------------------------------------------------
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Envoyé par le service de messagerie texte de Bell Mobilité.
|
||||
----------------------------------------------------------------
|
||||
20
actionmailer/test/fixtures/raw_email6
vendored
20
actionmailer/test/fixtures/raw_email6
vendored
@@ -1,20 +0,0 @@
|
||||
Return-Path: <xxx@xxxx.xxx>
|
||||
Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:05 -0500
|
||||
Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:04 -0500
|
||||
Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:03 -0500
|
||||
Date: Tue, 10 May 2005 15:27:03 -0500
|
||||
From: xxx@xxxx.xxx
|
||||
Sender: xxx@xxxx.xxx
|
||||
To: xxxxxxxxxxx@xxxx.xxxx.xxx
|
||||
Message-Id: <xxx@xxxx.xxx>
|
||||
X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx
|
||||
Delivered-To: xxx@xxxx.xxx
|
||||
Importance: normal
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
|
||||
Test test. Hi. Waving. m
|
||||
|
||||
----------------------------------------------------------------
|
||||
Sent via Bell Mobility's Text Messaging service.
|
||||
Envoyé par le service de messagerie texte de Bell Mobilité.
|
||||
----------------------------------------------------------------
|
||||
66
actionmailer/test/fixtures/raw_email7
vendored
66
actionmailer/test/fixtures/raw_email7
vendored
@@ -1,66 +0,0 @@
|
||||
Mime-Version: 1.0 (Apple Message framework v730)
|
||||
Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151
|
||||
Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com>
|
||||
From: foo@example.com
|
||||
Subject: testing
|
||||
Date: Mon, 6 Jun 2005 22:21:22 +0200
|
||||
To: blah@example.com
|
||||
|
||||
|
||||
--Apple-Mail-13-196941151
|
||||
Content-Type: multipart/mixed;
|
||||
boundary=Apple-Mail-12-196940926
|
||||
|
||||
|
||||
--Apple-Mail-12-196940926
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain;
|
||||
charset=ISO-8859-1;
|
||||
delsp=yes;
|
||||
format=flowed
|
||||
|
||||
This is the first part.
|
||||
|
||||
--Apple-Mail-12-196940926
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Type: text/x-ruby-script;
|
||||
x-unix-mode=0666;
|
||||
name="test.rb"
|
||||
Content-Disposition: attachment;
|
||||
filename=test.rb
|
||||
|
||||
puts "testing, testing"
|
||||
|
||||
--Apple-Mail-12-196940926
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Type: application/pdf;
|
||||
x-unix-mode=0666;
|
||||
name="test.pdf"
|
||||
Content-Disposition: inline;
|
||||
filename=test.pdf
|
||||
|
||||
YmxhaCBibGFoIGJsYWg=
|
||||
|
||||
--Apple-Mail-12-196940926
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Type: text/plain;
|
||||
charset=US-ASCII;
|
||||
format=flowed
|
||||
|
||||
|
||||
|
||||
--Apple-Mail-12-196940926--
|
||||
|
||||
--Apple-Mail-13-196941151
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Type: application/pkcs7-signature;
|
||||
name=smime.p7s
|
||||
Content-Disposition: attachment;
|
||||
filename=smime.p7s
|
||||
|
||||
jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw
|
||||
ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE
|
||||
QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB
|
||||
gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5=
|
||||
|
||||
--Apple-Mail-13-196941151--
|
||||
47
actionmailer/test/fixtures/raw_email8
vendored
47
actionmailer/test/fixtures/raw_email8
vendored
@@ -1,47 +0,0 @@
|
||||
From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005
|
||||
Return-Path: <xxxxxxxxx.xxxxxxx@gmail.com>
|
||||
Message-ID: <e85734b90505081209eaaa17b@mail.gmail.com>
|
||||
Date: Sun, 8 May 2005 14:09:11 -0500
|
||||
From: xxxxxxxxx xxxxxxx <xxxxxxxxx.xxxxxxx@gmail.com>
|
||||
Reply-To: xxxxxxxxx xxxxxxx <xxxxxxxxx.xxxxxxx@gmail.com>
|
||||
To: xxxxx xxxx <xxxxx@xxxxxxxxx.com>
|
||||
Subject: Fwd: Signed email causes file attachments
|
||||
In-Reply-To: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com>
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="----=_Part_5028_7368284.1115579351471"
|
||||
References: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com>
|
||||
|
||||
------=_Part_5028_7368284.1115579351471
|
||||
Content-Type: text/plain; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Disposition: inline
|
||||
|
||||
We should not include these files or vcards as attachments.
|
||||
|
||||
---------- Forwarded message ----------
|
||||
From: xxxxx xxxxxx <xxxxxxxx@xxx.com>
|
||||
Date: May 8, 2005 1:17 PM
|
||||
Subject: Signed email causes file attachments
|
||||
To: xxxxxxx@xxxxxxxxxx.com
|
||||
|
||||
|
||||
Hi,
|
||||
|
||||
Test attachments oddly encoded with japanese charset.
|
||||
|
||||
|
||||
------=_Part_5028_7368284.1115579351471
|
||||
Content-Type: application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment
|
||||
|
||||
MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w
|
||||
ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh
|
||||
d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt
|
||||
YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD
|
||||
ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL
|
||||
7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw
|
||||
------=_Part_5028_7368284.1115579351471--
|
||||
|
||||
28
actionmailer/test/fixtures/raw_email9
vendored
28
actionmailer/test/fixtures/raw_email9
vendored
@@ -1,28 +0,0 @@
|
||||
Received: from xxx.xxx.xxx ([xxx.xxx.xxx.xxx] verified)
|
||||
by xxx.com (CommuniGate Pro SMTP 4.2.8)
|
||||
with SMTP id 2532598 for xxx@xxx.com; Wed, 23 Feb 2005 17:51:49 -0500
|
||||
Received-SPF: softfail
|
||||
receiver=xxx.com; client-ip=xxx.xxx.xxx.xxx; envelope-from=xxx@xxx.xxx
|
||||
quite Delivered-To: xxx@xxx.xxx
|
||||
Received: by xxx.xxx.xxx (Wostfix, from userid xxx)
|
||||
id 0F87F333; Wed, 23 Feb 2005 16:16:17 -0600
|
||||
Date: Wed, 23 Feb 2005 18:20:17 -0400
|
||||
From: "xxx xxx" <xxx@xxx.xxx>
|
||||
Message-ID: <4D6AA7EB.6490534@xxx.xxx>
|
||||
To: xxx@xxx.com
|
||||
Subject: Stop adware/spyware once and for all.
|
||||
X-Scanned-By: MIMEDefang 2.11 (www dot roaringpenguin dot com slash mimedefang)
|
||||
|
||||
You are infected with:
|
||||
Ad Ware and Spy Ware
|
||||
|
||||
Get your free scan and removal download now,
|
||||
before it gets any worse.
|
||||
|
||||
http://xxx.xxx.info?aid=3D13&?stat=3D4327kdzt
|
||||
|
||||
|
||||
|
||||
|
||||
no more? (you will still be infected)
|
||||
http://xxx.xxx.info/discon/?xxx@xxx.com
|
||||
@@ -1,14 +0,0 @@
|
||||
Mime-Version: 1.0 (Apple Message framework v730)
|
||||
Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com>
|
||||
From: foo@example.com
|
||||
Subject: testing
|
||||
Date: Mon, 6 Jun 2005 22:21:22 +0200
|
||||
To: blah@example.com
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain
|
||||
|
||||
A fax has arrived from remote ID ''.=0D=0A-----------------------=
|
||||
-------------------------------------=0D=0ATime: 3/9/2006 3:50:52=
|
||||
PM=0D=0AReceived from remote ID: =0D=0AInbound user ID XXXXXXXXXX, r=
|
||||
outing code XXXXXXXXX=0D=0AResult: (0/352;0/0) Successful Send=0D=0AP=
|
||||
age record: 1 - 1=0D=0AElapsed time: 00:58 on channel 11=0D=0A
|
||||
@@ -1,104 +0,0 @@
|
||||
Return-Path: <mikel.other@baci>
|
||||
Received: from some.isp.com by baci with ESMTP id 632BD5758 for <mikel.lindsaar@baci>; Sun, 21 Oct 2007 19:38:21 +1000
|
||||
Date: Sun, 21 Oct 2007 19:38:13 +1000
|
||||
From: Mikel Lindsaar <mikel.other@baci>
|
||||
Reply-To: Mikel Lindsaar <mikel.other@baci>
|
||||
To: mikel.lindsaar@baci
|
||||
Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a>
|
||||
Subject: Testing outlook
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/alternative; boundary=----=_NextPart_000_0093_01C81419.EB75E850
|
||||
Delivered-To: mikel.lindsaar@baci
|
||||
X-Mimeole: Produced By Microsoft MimeOLE V6.00.2900.3138
|
||||
X-Msmail-Priority: Normal
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
|
||||
|
||||
------=_NextPart_000_0093_01C81419.EB75E850
|
||||
Content-Type: text/plain; charset=iso-8859-1
|
||||
Content-Transfer-Encoding: Quoted-printable
|
||||
|
||||
Hello
|
||||
This is an outlook test
|
||||
|
||||
So there.
|
||||
|
||||
Me.
|
||||
|
||||
------=_NextPart_000_0093_01C81419.EB75E850
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
Content-Transfer-Encoding: Quoted-printable
|
||||
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<HTML><HEAD>
|
||||
<META http-equiv=3DContent-Type content=3D"text/html; =
|
||||
charset=3Diso-8859-1">
|
||||
<META content=3D"MSHTML 6.00.6000.16525" name=3DGENERATOR>
|
||||
<STYLE></STYLE>
|
||||
</HEAD>
|
||||
<BODY bgColor=3D#ffffff>
|
||||
<DIV><FONT face=3DArial size=3D2>Hello</FONT></DIV>
|
||||
<DIV><FONT face=3DArial size=3D2><STRONG>This is an outlook=20
|
||||
test</STRONG></FONT></DIV>
|
||||
<DIV><FONT face=3DArial size=3D2><STRONG></STRONG></FONT> </DIV>
|
||||
<DIV><FONT face=3DArial size=3D2><STRONG>So there.</STRONG></FONT></DIV>
|
||||
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
|
||||
<DIV><FONT face=3DArial size=3D2>Me.</FONT></DIV></BODY></HTML>
|
||||
|
||||
|
||||
------=_NextPart_000_0093_01C81419.EB75E850--
|
||||
|
||||
|
||||
Return-Path: <mikel.other@baci>
|
||||
Received: from some.isp.com by baci with ESMTP id 632BD5758 for <mikel.lindsaar@baci>; Sun, 21 Oct 2007 19:38:21 +1000
|
||||
Date: Sun, 21 Oct 2007 19:38:13 +1000
|
||||
From: Mikel Lindsaar <mikel.other@baci>
|
||||
Reply-To: Mikel Lindsaar <mikel.other@baci>
|
||||
To: mikel.lindsaar@baci
|
||||
Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a>
|
||||
Subject: Testing outlook
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/alternative; boundary=----=_NextPart_000_0093_01C81419.EB75E850
|
||||
Delivered-To: mikel.lindsaar@baci
|
||||
X-Mimeole: Produced By Microsoft MimeOLE V6.00.2900.3138
|
||||
X-Msmail-Priority: Normal
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
|
||||
|
||||
------=_NextPart_000_0093_01C81419.EB75E850
|
||||
Content-Type: text/plain; charset=iso-8859-1
|
||||
Content-Transfer-Encoding: Quoted-printable
|
||||
|
||||
Hello
|
||||
This is an outlook test
|
||||
|
||||
So there.
|
||||
|
||||
Me.
|
||||
|
||||
------=_NextPart_000_0093_01C81419.EB75E850
|
||||
Content-Type: text/html; charset=iso-8859-1
|
||||
Content-Transfer-Encoding: Quoted-printable
|
||||
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<HTML><HEAD>
|
||||
<META http-equiv=3DContent-Type content=3D"text/html; =
|
||||
charset=3Diso-8859-1">
|
||||
<META content=3D"MSHTML 6.00.6000.16525" name=3DGENERATOR>
|
||||
<STYLE></STYLE>
|
||||
</HEAD>
|
||||
<BODY bgColor=3D#ffffff>
|
||||
<DIV><FONT face=3DArial size=3D2>Hello</FONT></DIV>
|
||||
<DIV><FONT face=3DArial size=3D2><STRONG>This is an outlook=20
|
||||
test</STRONG></FONT></DIV>
|
||||
<DIV><FONT face=3DArial size=3D2><STRONG></STRONG></FONT> </DIV>
|
||||
<DIV><FONT face=3DArial size=3D2><STRONG>So there.</STRONG></FONT></DIV>
|
||||
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
|
||||
<DIV><FONT face=3DArial size=3D2>Me.</FONT></DIV></BODY></HTML>
|
||||
|
||||
|
||||
------=_NextPart_000_0093_01C81419.EB75E850--
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
From jamis@37signals.com Thu Feb 22 11:20:31 2007
|
||||
Mime-Version: 1.0 (Apple Message framework v752.3)
|
||||
Message-Id: <2CCE0408-10C7-4045-9B16-A1C11C31469B@37signals.com>
|
||||
Content-Type: multipart/signed;
|
||||
micalg=sha1;
|
||||
boundary=Apple-Mail-42-587703407;
|
||||
protocol="application/pkcs7-signature"
|
||||
To: Jamis Buck <jamis@jamisbuck.org>
|
||||
Subject: Testing attachments
|
||||
From: Jamis Buck <jamis@37signals.com>
|
||||
Date: Thu, 22 Feb 2007 11:20:31 -0700
|
||||
|
||||
|
||||
--Apple-Mail-42-587703407
|
||||
Content-Type: multipart/mixed;
|
||||
boundary=Apple-Mail-41-587703287
|
||||
|
||||
|
||||
--Apple-Mail-41-587703287
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-Type: text/plain;
|
||||
charset=US-ASCII;
|
||||
format=flowed
|
||||
|
||||
Here is a test of an attachment via email.
|
||||
|
||||
- Jamis
|
||||
|
||||
|
||||
--Apple-Mail-41-587703287
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Type: image/png;
|
||||
x-unix-mode=0644;
|
||||
name=byo-ror-cover.png
|
||||
Content-Disposition: inline;
|
||||
filename=truncated.png
|
||||
|
||||
iVBORw0KGgoAAAANSUhEUgAAAKUAAADXCAYAAAB7wZEQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz
|
||||
AAALEgAACxIB0t1+/AAAABd0RVh0Q3JlYXRpb24gVGltZQAxLzI1LzIwMDeD9CJVAAAAGHRFWHRT
|
||||
b2Z0d2FyZQBBZG9iZSBGaXJld29ya3NPsx9OAAAyBWlUWHRYTUw6Y29tLmFkb2JlLnhtcDw/eHBh
|
||||
Y2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1l
|
||||
dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDQuMS1j
|
||||
MDIwIDEuMjU1NzE2LCBUdWUgT2N0IDEwIDIwMDYgMjM6MTY6MzQiPgogICA8cmRmOlJERiB4bWxu
|
||||
czpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAg
|
||||
ICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4YXA9Imh0
|
||||
dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iPgogICAgICAgICA8eGFwOkNyZWF0b3JUb29sPkFk
|
||||
b2JlIEZpcmV3b3JrcyBDUzM8L3hhcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhhcDpDcmVhdGVE
|
||||
YXRlPjIwMDctMDEtMjVUMDU6Mjg6MjFaPC94YXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhhcDpN
|
||||
b2RpZnlEYXRlPjIwMDctMDEtMjVUMDU6Mjg6MjFaPC94YXA6TW9kaWZ5RGF0ZT4KICAgICAgPC9y
|
||||
ZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAg
|
||||
ICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+CiAgICAg
|
||||
ICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgIDwvcmRmOkRlc2NyaXB0
|
||||
hhojpmnJMfaYFmSkXWg5PGCmHXVj/c9At0hSK2xGdd8F3muk0VFjb4f5Ue0ksQ8qAcq0delaXhdb
|
||||
DjKNnF+3B3t9kObZYmk7AZgWYqO9anpR3wpM9sQ5XslB9a+kWyTtNb0fOmudzGHfPFBQDKesyycm
|
||||
DBL7Cw5bXjIEuci+SSOm/LYnXDZu6iuPEj8lYBb+OU8xx1f9m+e5rhJiYKqjo5vHfiZp+VUkW9xc
|
||||
Ufd6JHNWc47PkQqb9ie3SLEZB/ZqyAssiqURY+G35iOMZUrHbasHnb80QAPv9FHtAbJIyro7bi5b
|
||||
ai2TEAKen5+LJNWrglZjm3UbZvt7KryA2J5b5J1jZF8kL6GzvG1Zqx54Y1y7J7n20wMOt9frG2sW
|
||||
uwGP07kNz3732vf6bfvAvLldfS+9fts2euXY37D+R29FGZdlnhzV4TTFmPJduBP2RbNNua4rTqcT
|
||||
Qt7Xy1KUB0AHSdP5AZQYvHZg7WD1XvYeMO1A9HhZPqMX5KXbMBrn2efxns/ee21674efxz4Tp/fq
|
||||
2HZ648dgYaC1i3Vq1IbNPq3PvDTPezY9FaRISjvnzWqdgcWN8EJgjnNq+Z7ktOm9l2Nfth28EZi4
|
||||
bG/we5JwxM+Tql47/D/X6b38I8/RyxvxPJrX6zvQbo3h9jyJx+C0ALX327QETHl5eYlaYCT5rPTb
|
||||
+5/rAq26t3lKIxV/p88hq6ptngdgCzoPjJqndiLfc/6y5A14WeDFGNPct4iUsJBV2bYzLEV7m83s
|
||||
6Rp63VPhHKC/g/LzaU9qexJRr56043JWinqAtfZqsSm1sjoznthl54dtCqv+uL4nIY+oYWuc3+nH
|
||||
kGfn8b0HQpvOYLQAZUDanbJs3jQhITZEgdarZK+cO6ySlL13rut5nFaN23s7u3Snz6eRPTkCoc2/
|
||||
Vp1zHfZVFpZ87FiMVLV1iqyK5rlzfji2GzjfDsodlD+Weo5UD4h6PwKqzQMqID0tq2VjjFVSMpis
|
||||
ZLRAs7sePZBZAHI+gIanB8I7MD+femAceeUe2Kxa5jS950kZ1p5eNEdeX1+jFmSpZ+1EdWCsDcne
|
||||
NPNgUHNw3aYpnzv9PGTX0uo94EtN9qq1rOdxe3kc79T8ukeHJJ8Fnxej6qlylbLLsjQLOy6Xy2a1
|
||||
kefs/N+nM7+S7IG5/E5Yc7F003pWErLjbH0O5cGadiMptSB/DZ5U5DI9yeg5MFYyMj8lC/Y7/Xjq
|
||||
OZlWcnpg9aQfXz2HRq+Wn5xOp6gN8tWq8R44e2pfyzLYemEgprst+XXk2Zj2nXlbsG05BprndTMv
|
||||
C3QRaXczshhVsHnMgfYn80Y2g5JureA6wBasPeP7LkE/jvZMJAaf/g/U2RelHsisvan5FqweIAHg
|
||||
Pwc7L68GxvVDAAAAAElFTkSuQmCC
|
||||
|
||||
--Apple-Mail-41-587703287--
|
||||
|
||||
--Apple-Mail-42-587703407
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Type: application/pkcs7-signature;
|
||||
name=smime.p7s
|
||||
Content-Disposition: attachment;
|
||||
filename=smime.p7s
|
||||
|
||||
MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGJzCCAuAw
|
||||
ggJJoAMCAQICEFjnFNYXwDEZRWY5EkfzopUwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCWkEx
|
||||
JTAjBgNVBAoTHFRoYXd0ZSBDb25zdWx0aW5nIChQdHkpIEx0ZC4xLDAqBgNVBAMTI1RoYXd0ZSBQ
|
||||
ZXJzb25hbCBGcmVlbWFpbCBJc3N1aW5nIENBMB4XDTA2MDkxMjE3MDExMloXDTA3MDkxMjE3MDEx
|
||||
MlowRTEfMB0GA1UEAxMWVGhhd3RlIEZyZWVtYWlsIE1lbWJlcjEiMCAGCSqGSIb3DQEJARYTamFt
|
||||
aXNAMzdzaWduYWxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO2A9JeOFIFJ
|
||||
G6z8pTcAldrZ2nMe+Xb1tNrbHgoVzN/QhHXM4qst2Ml93cmFLjMmwG7P9RJeU4oNx+jTqVoBB7NV
|
||||
Ne1/o56Do0KhfMZ9iUDQdPLbkZMq4EEpFMdm6PyM3muRKwPhj66iAWe/osCb8DowUK2f66vaRx0Z
|
||||
Y0MQHIIrXE02Ta4IfAhIfPqBLkZ4WgTYBHN9vMdYea1jF0GO4gqGk1wqwb3yxv2QMYMbwJ6SI+k/
|
||||
ZjkSR/OilTCBhwYLKoZIhvcNAQkQAgsxeKB2MGIxCzAJBgNVBAYTAlpBMSUwIwYDVQQKExxUaGF3
|
||||
dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMSwwKgYDVQQDEyNUaGF3dGUgUGVyc29uYWwgRnJlZW1h
|
||||
aWwgSXNzdWluZyBDQQIQWOcU1hfAMRlFZjkSR/OilTANBgkqhkiG9w0BAQEFAASCAQCfwQiC3v6/
|
||||
yleRDGv3bJ4nQYQ+c3mz3+mn3Xi6uU35n3piwxZZaWRdmLyiXPvU+QReHpSf3l2qsEZM3sdE0XF9
|
||||
eRul/+QTFJcDNXOEAxG1zC2Gpz+6c6RrX4Ou12Pwkp+pNrZWTSY/mZgdqcArupOBcZi7qBjoWcy5
|
||||
wb54dfvSSjrjmqLbkH/E8ww/6gGQuU/xXpAUZgUrTmQHrNKeIdSh5oDkOxFaFWvnmb8Z/2ixKqW/
|
||||
Ux6WqamyvBtTs/5YBEtnpZOk+uVoscYEUBhU+DVJ2OSvTdXSivMtBdXmGTsG22k+P1NGUHi/A7ev
|
||||
xPaO0uk4V8xyjNlN4HPuGpkrlXwPAAAAAAAA
|
||||
|
||||
--Apple-Mail-42-587703407--
|
||||
@@ -1,14 +0,0 @@
|
||||
From jamis@37signals.com Mon May 2 16:07:05 2005
|
||||
Mime-Version: 1.0 (Apple Message framework v622)
|
||||
Content-Transfer-Encoding: base64
|
||||
Message-Id: <d3b8cf8e49f04480850c28713a1f473e@37signals.com>
|
||||
Content-Type: text/plain;
|
||||
charset=EUC-KR;
|
||||
format=flowed
|
||||
To: jamis@37signals.com
|
||||
From: Jamis Buck <jamis@37signals.com>
|
||||
Subject: Re: Test: =?UTF-8?B?Iua8ouWtlyI=?= mid =?UTF-8?B?Iua8ouWtlyI=?= tail
|
||||
Date: Mon, 2 May 2005 16:07:05 -0600
|
||||
|
||||
tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin
|
||||
wLogSmFtaXPA1LTPtNku
|
||||
@@ -1 +0,0 @@
|
||||
second mail
|
||||
@@ -1,3 +0,0 @@
|
||||
Hello there,
|
||||
|
||||
Mr. <%= @recipient %>
|
||||
@@ -1 +0,0 @@
|
||||
let's go!
|
||||
@@ -1,2 +0,0 @@
|
||||
body: <%= @body %>
|
||||
bar: <%= @bar %>
|
||||
@@ -1,6 +0,0 @@
|
||||
%p Hello there,
|
||||
|
||||
%p
|
||||
Mr.
|
||||
= @recipient
|
||||
from haml
|
||||
@@ -1,6 +0,0 @@
|
||||
%p Hello there,
|
||||
|
||||
%p
|
||||
Mr.
|
||||
= @recipient
|
||||
from haml
|
||||
@@ -1 +0,0 @@
|
||||
Ignored when searching for implicitly multipart parts.
|
||||
@@ -1 +0,0 @@
|
||||
Ignored when searching for implicitly multipart parts.
|
||||
@@ -1,10 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
HTML formatted message to <strong><%= @recipient %></strong>.
|
||||
</body>
|
||||
</html>
|
||||
<html>
|
||||
<body>
|
||||
HTML formatted message to <strong><%= @recipient %></strong>.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,10 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
HTML formatted message to <strong><%= @recipient %></strong>.
|
||||
</body>
|
||||
</html>
|
||||
<html>
|
||||
<body>
|
||||
HTML formatted message to <strong><%= @recipient %></strong>.
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,2 +0,0 @@
|
||||
Plain text to <%= @recipient %>.
|
||||
Plain text to <%= @recipient %>.
|
||||
@@ -1 +0,0 @@
|
||||
yaml to: <%= @recipient %>
|
||||
@@ -1 +0,0 @@
|
||||
Hey Ho, <%= render :partial => "subtemplate" %>
|
||||
@@ -1,2 +0,0 @@
|
||||
xml.instruct!
|
||||
xml.test
|
||||
@@ -1,2 +0,0 @@
|
||||
xml.instruct!
|
||||
xml.test
|
||||
@@ -1,3 +0,0 @@
|
||||
Hello there,
|
||||
|
||||
Mr. <%= @recipient %>
|
||||
@@ -1,5 +0,0 @@
|
||||
Hello there,
|
||||
|
||||
Mr. <%= @recipient %>. Please see our greeting at <%= @welcome_url %> <%= welcome_url %>
|
||||
|
||||
<%= image_tag "somelogo.png" %>
|
||||
@@ -1,95 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
module MailerHelper
|
||||
def person_name
|
||||
"Mr. Joe Person"
|
||||
end
|
||||
end
|
||||
|
||||
class HelperMailer < ActionMailer::Base
|
||||
helper MailerHelper
|
||||
helper :example
|
||||
|
||||
def use_helper(recipient)
|
||||
recipients recipient
|
||||
subject "using helpers"
|
||||
from "tester@example.com"
|
||||
end
|
||||
|
||||
def use_example_helper(recipient)
|
||||
recipients recipient
|
||||
subject "using helpers"
|
||||
from "tester@example.com"
|
||||
self.body = { :text => "emphasize me!" }
|
||||
end
|
||||
|
||||
def use_mail_helper(recipient)
|
||||
recipients recipient
|
||||
subject "using mailing helpers"
|
||||
from "tester@example.com"
|
||||
self.body = { :text =>
|
||||
"But soft! What light through yonder window breaks? It is the east, " +
|
||||
"and Juliet is the sun. Arise, fair sun, and kill the envious moon, " +
|
||||
"which is sick and pale with grief that thou, her maid, art far more " +
|
||||
"fair than she. Be not her maid, for she is envious! Her vestal " +
|
||||
"livery is but sick and green, and none but fools do wear it. Cast " +
|
||||
"it off!"
|
||||
}
|
||||
end
|
||||
|
||||
def use_helper_method(recipient)
|
||||
recipients recipient
|
||||
subject "using helpers"
|
||||
from "tester@example.com"
|
||||
self.body = { :text => "emphasize me!" }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def name_of_the_mailer_class
|
||||
self.class.name
|
||||
end
|
||||
helper_method :name_of_the_mailer_class
|
||||
end
|
||||
|
||||
class MailerHelperTest < Test::Unit::TestCase
|
||||
def new_mail( charset="utf-8" )
|
||||
mail = TMail::Mail.new
|
||||
mail.set_content_type "text", "plain", { "charset" => charset } if charset
|
||||
mail
|
||||
end
|
||||
|
||||
def setup
|
||||
set_delivery_method :test
|
||||
ActionMailer::Base.perform_deliveries = true
|
||||
ActionMailer::Base.deliveries = []
|
||||
|
||||
@recipient = 'test@localhost'
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_use_helper
|
||||
mail = HelperMailer.create_use_helper(@recipient)
|
||||
assert_match %r{Mr. Joe Person}, mail.encoded
|
||||
end
|
||||
|
||||
def test_use_example_helper
|
||||
mail = HelperMailer.create_use_example_helper(@recipient)
|
||||
assert_match %r{<em><strong><small>emphasize me!}, mail.encoded
|
||||
end
|
||||
|
||||
def test_use_helper_method
|
||||
mail = HelperMailer.create_use_helper_method(@recipient)
|
||||
assert_match %r{HelperMailer}, mail.encoded
|
||||
end
|
||||
|
||||
def test_use_mail_helper
|
||||
mail = HelperMailer.create_use_mail_helper(@recipient)
|
||||
assert_match %r{ But soft!}, mail.encoded
|
||||
assert_match %r{east, and\n Juliet}, mail.encoded
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class AutoLayoutMailer < ActionMailer::Base
|
||||
def hello(recipient)
|
||||
recipients recipient
|
||||
subject "You have a mail"
|
||||
from "tester@example.com"
|
||||
end
|
||||
|
||||
def spam(recipient)
|
||||
recipients recipient
|
||||
subject "You have a mail"
|
||||
from "tester@example.com"
|
||||
body render(:inline => "Hello, <%= @world %>", :layout => 'spam', :body => { :world => "Earth" })
|
||||
end
|
||||
|
||||
def nolayout(recipient)
|
||||
recipients recipient
|
||||
subject "You have a mail"
|
||||
from "tester@example.com"
|
||||
body render(:inline => "Hello, <%= @world %>", :layout => false, :body => { :world => "Earth" })
|
||||
end
|
||||
|
||||
def multipart(recipient, type = nil)
|
||||
recipients recipient
|
||||
subject "You have a mail"
|
||||
from "tester@example.com"
|
||||
|
||||
content_type(type) if type
|
||||
end
|
||||
end
|
||||
|
||||
class ExplicitLayoutMailer < ActionMailer::Base
|
||||
layout 'spam', :except => [:logout]
|
||||
|
||||
def signup(recipient)
|
||||
recipients recipient
|
||||
subject "You have a mail"
|
||||
from "tester@example.com"
|
||||
end
|
||||
|
||||
def logout(recipient)
|
||||
recipients recipient
|
||||
subject "You have a mail"
|
||||
from "tester@example.com"
|
||||
end
|
||||
end
|
||||
|
||||
class LayoutMailerTest < Test::Unit::TestCase
|
||||
def setup
|
||||
set_delivery_method :test
|
||||
ActionMailer::Base.perform_deliveries = true
|
||||
ActionMailer::Base.deliveries = []
|
||||
|
||||
@recipient = 'test@localhost'
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_should_pickup_default_layout
|
||||
mail = AutoLayoutMailer.create_hello(@recipient)
|
||||
assert_equal "Hello from layout Inside", mail.body.strip
|
||||
end
|
||||
|
||||
def test_should_pickup_multipart_layout
|
||||
mail = AutoLayoutMailer.create_multipart(@recipient)
|
||||
assert_equal "multipart/alternative", mail.content_type
|
||||
assert_equal 2, mail.parts.size
|
||||
|
||||
assert_equal 'text/plain', mail.parts.first.content_type
|
||||
assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
|
||||
|
||||
assert_equal 'text/html', mail.parts.last.content_type
|
||||
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
|
||||
end
|
||||
|
||||
def test_should_pickup_multipartmixed_layout
|
||||
mail = AutoLayoutMailer.create_multipart(@recipient, "multipart/mixed")
|
||||
assert_equal "multipart/mixed", mail.content_type
|
||||
assert_equal 2, mail.parts.size
|
||||
|
||||
assert_equal 'text/plain', mail.parts.first.content_type
|
||||
assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
|
||||
|
||||
assert_equal 'text/html', mail.parts.last.content_type
|
||||
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
|
||||
end
|
||||
|
||||
def test_should_fix_multipart_layout
|
||||
mail = AutoLayoutMailer.create_multipart(@recipient, "text/plain")
|
||||
assert_equal "multipart/alternative", mail.content_type
|
||||
assert_equal 2, mail.parts.size
|
||||
|
||||
assert_equal 'text/plain', mail.parts.first.content_type
|
||||
assert_equal "text/plain layout - text/plain multipart", mail.parts.first.body
|
||||
|
||||
assert_equal 'text/html', mail.parts.last.content_type
|
||||
assert_equal "Hello from layout text/html multipart", mail.parts.last.body
|
||||
end
|
||||
|
||||
|
||||
def test_should_pickup_layout_given_to_render
|
||||
mail = AutoLayoutMailer.create_spam(@recipient)
|
||||
assert_equal "Spammer layout Hello, Earth", mail.body.strip
|
||||
end
|
||||
|
||||
def test_should_respect_layout_false
|
||||
mail = AutoLayoutMailer.create_nolayout(@recipient)
|
||||
assert_equal "Hello, Earth", mail.body.strip
|
||||
end
|
||||
|
||||
def test_explicit_class_layout
|
||||
mail = ExplicitLayoutMailer.create_signup(@recipient)
|
||||
assert_equal "Spammer layout We do not spam", mail.body.strip
|
||||
end
|
||||
|
||||
def test_explicit_layout_exceptions
|
||||
mail = ExplicitLayoutMailer.create_logout(@recipient)
|
||||
assert_equal "You logged out", mail.body.strip
|
||||
end
|
||||
end
|
||||
@@ -1,116 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class RenderMailer < ActionMailer::Base
|
||||
def inline_template(recipient)
|
||||
recipients recipient
|
||||
subject "using helpers"
|
||||
from "tester@example.com"
|
||||
body render(:inline => "Hello, <%= @world %>", :body => { :world => "Earth" })
|
||||
end
|
||||
|
||||
def file_template(recipient)
|
||||
recipients recipient
|
||||
subject "using helpers"
|
||||
from "tester@example.com"
|
||||
body render(:file => "signed_up", :body => { :recipient => recipient })
|
||||
end
|
||||
|
||||
def rxml_template(recipient)
|
||||
recipients recipient
|
||||
subject "rendering rxml template"
|
||||
from "tester@example.com"
|
||||
end
|
||||
|
||||
def included_subtemplate(recipient)
|
||||
recipients recipient
|
||||
subject "Including another template in the one being rendered"
|
||||
from "tester@example.com"
|
||||
end
|
||||
|
||||
def included_old_subtemplate(recipient)
|
||||
recipients recipient
|
||||
subject "Including another template in the one being rendered"
|
||||
from "tester@example.com"
|
||||
body render(:inline => "Hello, <%= render \"subtemplate\" %>", :body => { :world => "Earth" })
|
||||
end
|
||||
|
||||
def initialize_defaults(method_name)
|
||||
super
|
||||
mailer_name "test_mailer"
|
||||
end
|
||||
end
|
||||
|
||||
class FirstMailer < ActionMailer::Base
|
||||
def share(recipient)
|
||||
recipients recipient
|
||||
subject "using helpers"
|
||||
from "tester@example.com"
|
||||
end
|
||||
end
|
||||
|
||||
class SecondMailer < ActionMailer::Base
|
||||
def share(recipient)
|
||||
recipients recipient
|
||||
subject "using helpers"
|
||||
from "tester@example.com"
|
||||
end
|
||||
end
|
||||
|
||||
class RenderHelperTest < Test::Unit::TestCase
|
||||
def setup
|
||||
set_delivery_method :test
|
||||
ActionMailer::Base.perform_deliveries = true
|
||||
ActionMailer::Base.deliveries = []
|
||||
|
||||
@recipient = 'test@localhost'
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_inline_template
|
||||
mail = RenderMailer.create_inline_template(@recipient)
|
||||
assert_equal "Hello, Earth", mail.body.strip
|
||||
end
|
||||
|
||||
def test_file_template
|
||||
mail = RenderMailer.create_file_template(@recipient)
|
||||
assert_equal "Hello there, \n\nMr. test@localhost", mail.body.strip
|
||||
end
|
||||
|
||||
def test_rxml_template
|
||||
mail = RenderMailer.deliver_rxml_template(@recipient)
|
||||
assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test/>", mail.body.strip
|
||||
end
|
||||
|
||||
def test_included_subtemplate
|
||||
mail = RenderMailer.deliver_included_subtemplate(@recipient)
|
||||
assert_equal "Hey Ho, let's go!", mail.body.strip
|
||||
end
|
||||
end
|
||||
|
||||
class FirstSecondHelperTest < Test::Unit::TestCase
|
||||
def setup
|
||||
set_delivery_method :test
|
||||
ActionMailer::Base.perform_deliveries = true
|
||||
ActionMailer::Base.deliveries = []
|
||||
|
||||
@recipient = 'test@localhost'
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_ordering
|
||||
mail = FirstMailer.create_share(@recipient)
|
||||
assert_equal "first mail", mail.body.strip
|
||||
mail = SecondMailer.create_share(@recipient)
|
||||
assert_equal "second mail", mail.body.strip
|
||||
mail = FirstMailer.create_share(@recipient)
|
||||
assert_equal "first mail", mail.body.strip
|
||||
mail = SecondMailer.create_share(@recipient)
|
||||
assert_equal "second mail", mail.body.strip
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,105 +0,0 @@
|
||||
# encoding: utf-8
|
||||
require 'abstract_unit'
|
||||
require 'tempfile'
|
||||
|
||||
class QuotingTest < Test::Unit::TestCase
|
||||
# Move some tests from TMAIL here
|
||||
def test_unquote_quoted_printable
|
||||
a ="=?ISO-8859-1?Q?[166417]_Bekr=E6ftelse_fra_Rejsefeber?="
|
||||
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
||||
assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
|
||||
end
|
||||
|
||||
def test_unquote_base64
|
||||
a ="=?ISO-8859-1?B?WzE2NjQxN10gQmVrcuZmdGVsc2UgZnJhIFJlanNlZmViZXI=?="
|
||||
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
||||
assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
|
||||
end
|
||||
|
||||
def test_unquote_without_charset
|
||||
a ="[166417]_Bekr=E6ftelse_fra_Rejsefeber"
|
||||
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
||||
assert_equal "[166417]_Bekr=E6ftelse_fra_Rejsefeber", b
|
||||
end
|
||||
|
||||
def test_unqoute_multiple
|
||||
quoted ="=?utf-8?q?Re=3A_=5B12=5D_=23137=3A_Inkonsistente_verwendung_von_=22Hin?==?utf-8?b?enVmw7xnZW4i?="
|
||||
actual = TMail::Unquoter.unquote_and_convert_to(quoted, 'utf-8')
|
||||
|
||||
expected = "Re: [12] #137: Inkonsistente verwendung von \"Hinzuf\303\274gen\""
|
||||
expected.force_encoding 'ASCII-8BIT' if expected.respond_to?(:force_encoding)
|
||||
|
||||
assert_equal expected, actual
|
||||
end
|
||||
|
||||
def test_unqoute_in_the_middle
|
||||
a ="Re: Photos =?ISO-8859-1?Q?Brosch=FCre_Rand?="
|
||||
b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
|
||||
assert_equal "Re: Photos Brosch\303\274re Rand", b
|
||||
end
|
||||
|
||||
def test_unqoute_iso
|
||||
a ="=?ISO-8859-1?Q?Brosch=FCre_Rand?="
|
||||
b = TMail::Unquoter.unquote_and_convert_to(a, 'iso-8859-1')
|
||||
expected = "Brosch\374re Rand"
|
||||
expected.force_encoding 'iso-8859-1' if expected.respond_to?(:force_encoding)
|
||||
assert_equal expected, b
|
||||
end
|
||||
|
||||
def test_quote_multibyte_chars
|
||||
original = "\303\246 \303\270 and \303\245"
|
||||
original.force_encoding('ASCII-8BIT') if original.respond_to?(:force_encoding)
|
||||
|
||||
result = execute_in_sandbox(<<-CODE)
|
||||
$:.unshift(File.dirname(__FILE__) + "/../lib/")
|
||||
if RUBY_VERSION < '1.9'
|
||||
$KCODE = 'u'
|
||||
require 'jcode'
|
||||
end
|
||||
require 'action_mailer/quoting'
|
||||
include ActionMailer::Quoting
|
||||
quoted_printable(#{original.inspect}, "UTF-8")
|
||||
CODE
|
||||
|
||||
unquoted = TMail::Unquoter.unquote_and_convert_to(result, nil)
|
||||
assert_equal unquoted, original
|
||||
end
|
||||
|
||||
|
||||
# test an email that has been created using \r\n newlines, instead of
|
||||
# \n newlines.
|
||||
def test_email_quoted_with_0d0a
|
||||
mail = TMail::Mail.parse(IO.read("#{File.dirname(__FILE__)}/fixtures/raw_email_quoted_with_0d0a"))
|
||||
assert_match %r{Elapsed time}, mail.body
|
||||
end
|
||||
|
||||
def test_email_with_partially_quoted_subject
|
||||
mail = TMail::Mail.parse(IO.read("#{File.dirname(__FILE__)}/fixtures/raw_email_with_partially_quoted_subject"))
|
||||
expected = "Re: Test: \"\346\274\242\345\255\227\" mid \"\346\274\242\345\255\227\" tail"
|
||||
expected.force_encoding('ASCII-8BIT') if expected.respond_to?(:force_encoding)
|
||||
assert_equal expected, mail.subject
|
||||
end
|
||||
|
||||
private
|
||||
# This whole thing *could* be much simpler, but I don't think Tempfile,
|
||||
# popen and others exist on all platforms (like Windows).
|
||||
def execute_in_sandbox(code)
|
||||
test_name = "#{File.dirname(__FILE__)}/am-quoting-test.#{$$}.rb"
|
||||
res_name = "#{File.dirname(__FILE__)}/am-quoting-test.#{$$}.out"
|
||||
|
||||
File.open(test_name, "w+") do |file|
|
||||
file.write(<<-CODE)
|
||||
block = Proc.new do
|
||||
#{code}
|
||||
end
|
||||
puts block.call
|
||||
CODE
|
||||
end
|
||||
|
||||
system("ruby #{test_name} > #{res_name}") or raise "could not run test in sandbox"
|
||||
File.read(res_name).chomp
|
||||
ensure
|
||||
File.delete(test_name) rescue nil
|
||||
File.delete(res_name) rescue nil
|
||||
end
|
||||
end
|
||||
@@ -1,129 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class TestHelperMailer < ActionMailer::Base
|
||||
def test
|
||||
recipients "test@example.com"
|
||||
from "tester@example.com"
|
||||
body render(:inline => "Hello, <%= @world %>", :body => { :world => "Earth" })
|
||||
end
|
||||
end
|
||||
|
||||
class TestHelperMailerTest < ActionMailer::TestCase
|
||||
def test_setup_sets_right_action_mailer_options
|
||||
assert_equal :test, ActionMailer::Base.delivery_method
|
||||
assert ActionMailer::Base.perform_deliveries
|
||||
assert_equal [], ActionMailer::Base.deliveries
|
||||
end
|
||||
|
||||
def test_setup_creates_the_expected_mailer
|
||||
assert @expected.is_a?(TMail::Mail)
|
||||
assert_equal "1.0", @expected.mime_version
|
||||
assert_equal "text/plain", @expected.content_type
|
||||
end
|
||||
|
||||
def test_mailer_class_is_correctly_inferred
|
||||
assert_equal TestHelperMailer, self.class.mailer_class
|
||||
end
|
||||
|
||||
def test_determine_default_mailer_raises_correct_error
|
||||
assert_raise(ActionMailer::NonInferrableMailerError) do
|
||||
self.class.determine_default_mailer("NotAMailerTest")
|
||||
end
|
||||
end
|
||||
|
||||
def test_charset_is_utf_8
|
||||
assert_equal "utf-8", charset
|
||||
end
|
||||
|
||||
def test_encode
|
||||
assert_equal "=?utf-8?Q?=0Aasdf=0A?=", encode("\nasdf\n")
|
||||
end
|
||||
|
||||
def test_assert_emails
|
||||
assert_nothing_raised do
|
||||
assert_emails 1 do
|
||||
TestHelperMailer.deliver_test
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_repeated_assert_emails_calls
|
||||
assert_nothing_raised do
|
||||
assert_emails 1 do
|
||||
TestHelperMailer.deliver_test
|
||||
end
|
||||
end
|
||||
|
||||
assert_nothing_raised do
|
||||
assert_emails 2 do
|
||||
TestHelperMailer.deliver_test
|
||||
TestHelperMailer.deliver_test
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_assert_emails_with_no_block
|
||||
assert_nothing_raised do
|
||||
TestHelperMailer.deliver_test
|
||||
assert_emails 1
|
||||
end
|
||||
|
||||
assert_nothing_raised do
|
||||
TestHelperMailer.deliver_test
|
||||
TestHelperMailer.deliver_test
|
||||
assert_emails 3
|
||||
end
|
||||
end
|
||||
|
||||
def test_assert_no_emails
|
||||
assert_nothing_raised do
|
||||
assert_no_emails do
|
||||
TestHelperMailer.create_test
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_assert_emails_too_few_sent
|
||||
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||
assert_emails 2 do
|
||||
TestHelperMailer.deliver_test
|
||||
end
|
||||
end
|
||||
|
||||
assert_match /2 .* but 1/, error.message
|
||||
end
|
||||
|
||||
def test_assert_emails_too_many_sent
|
||||
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||
assert_emails 1 do
|
||||
TestHelperMailer.deliver_test
|
||||
TestHelperMailer.deliver_test
|
||||
end
|
||||
end
|
||||
|
||||
assert_match /1 .* but 2/, error.message
|
||||
end
|
||||
|
||||
def test_assert_no_emails_failure
|
||||
error = assert_raise ActiveSupport::TestCase::Assertion do
|
||||
assert_no_emails do
|
||||
TestHelperMailer.deliver_test
|
||||
end
|
||||
end
|
||||
|
||||
assert_match /0 .* but 1/, error.message
|
||||
end
|
||||
end
|
||||
|
||||
class AnotherTestHelperMailerTest < ActionMailer::TestCase
|
||||
tests TestHelperMailer
|
||||
|
||||
def setup
|
||||
@test_var = "a value"
|
||||
end
|
||||
|
||||
def test_setup_shouldnt_conflict_with_mailer_setup
|
||||
assert @expected.is_a?(TMail::Mail)
|
||||
assert_equal 'a value', @test_var
|
||||
end
|
||||
end
|
||||
@@ -1,22 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class TMailMailTest < Test::Unit::TestCase
|
||||
def test_body
|
||||
m = TMail::Mail.new
|
||||
expected = 'something_with_underscores'
|
||||
m.encoding = 'quoted-printable'
|
||||
quoted_body = [expected].pack('*M')
|
||||
m.body = quoted_body
|
||||
assert_equal "something_with_underscores=\n", m.quoted_body
|
||||
assert_equal expected, m.body
|
||||
end
|
||||
|
||||
def test_nested_attachments_are_recognized_correctly
|
||||
fixture = File.read("#{File.dirname(__FILE__)}/fixtures/raw_email_with_nested_attachment")
|
||||
mail = TMail::Mail.parse(fixture)
|
||||
assert_equal 2, mail.attachments.length
|
||||
assert_equal "image/png", mail.attachments.first.content_type
|
||||
assert_equal 1902, mail.attachments.first.length
|
||||
assert_equal "application/pkcs7-signature", mail.attachments.last.content_type
|
||||
end
|
||||
end
|
||||
@@ -1,76 +0,0 @@
|
||||
require 'abstract_unit'
|
||||
|
||||
class TestMailer < ActionMailer::Base
|
||||
|
||||
default_url_options[:host] = 'www.basecamphq.com'
|
||||
|
||||
def signed_up_with_url(recipient)
|
||||
@recipients = recipient
|
||||
@subject = "[Signed up] Welcome #{recipient}"
|
||||
@from = "system@loudthinking.com"
|
||||
@sent_on = Time.local(2004, 12, 12)
|
||||
|
||||
@body["recipient"] = recipient
|
||||
@body["welcome_url"] = url_for :host => "example.com", :controller => "welcome", :action => "greeting"
|
||||
end
|
||||
|
||||
class <<self
|
||||
attr_accessor :received_body
|
||||
end
|
||||
|
||||
def receive(mail)
|
||||
self.class.received_body = mail.body
|
||||
end
|
||||
end
|
||||
|
||||
class ActionMailerUrlTest < Test::Unit::TestCase
|
||||
include ActionMailer::Quoting
|
||||
|
||||
def encode( text, charset="utf-8" )
|
||||
quoted_printable( text, charset )
|
||||
end
|
||||
|
||||
def new_mail( charset="utf-8" )
|
||||
mail = TMail::Mail.new
|
||||
mail.mime_version = "1.0"
|
||||
if charset
|
||||
mail.set_content_type "text", "plain", { "charset" => charset }
|
||||
end
|
||||
mail
|
||||
end
|
||||
|
||||
def setup
|
||||
set_delivery_method :test
|
||||
ActionMailer::Base.perform_deliveries = true
|
||||
ActionMailer::Base.deliveries = []
|
||||
|
||||
@recipient = 'test@localhost'
|
||||
end
|
||||
|
||||
def teardown
|
||||
restore_delivery_method
|
||||
end
|
||||
|
||||
def test_signed_up_with_url
|
||||
ActionController::Routing::Routes.draw do |map|
|
||||
map.connect ':controller/:action/:id'
|
||||
map.welcome 'welcome', :controller=>"foo", :action=>"bar"
|
||||
end
|
||||
|
||||
expected = new_mail
|
||||
expected.to = @recipient
|
||||
expected.subject = "[Signed up] Welcome #{@recipient}"
|
||||
expected.body = "Hello there, \n\nMr. #{@recipient}. Please see our greeting at http://example.com/welcome/greeting http://www.basecamphq.com/welcome\n\n<img alt=\"Somelogo\" src=\"/images/somelogo.png\" />"
|
||||
expected.from = "system@loudthinking.com"
|
||||
expected.date = Time.local(2004, 12, 12)
|
||||
|
||||
created = nil
|
||||
assert_nothing_raised { created = TestMailer.create_signed_up_with_url(@recipient) }
|
||||
assert_not_nil created
|
||||
assert_equal expected.encoded, created.encoded
|
||||
|
||||
assert_nothing_raised { TestMailer.deliver_signed_up_with_url(@recipient) }
|
||||
assert_not_nil ActionMailer::Base.deliveries.first
|
||||
assert_equal expected.encoded, ActionMailer::Base.deliveries.first.encoded
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,24 @@
|
||||
*2.3.11 (February 9, 2011)*
|
||||
|
||||
* Two security fixes. CVE-2011-0446, CVE-2011-0447
|
||||
|
||||
*2.3.10 (October 15, 2010)*
|
||||
|
||||
*2.3.9 (September 4, 2010)*
|
||||
|
||||
* Version bump.
|
||||
|
||||
|
||||
*2.3.8 (May 24, 2010)*
|
||||
|
||||
* HTML safety: fix compatibility *without* the optional rails_xss plugin.
|
||||
|
||||
|
||||
*2.3.7 (May 24, 2010)*
|
||||
|
||||
* HTML safety: fix compatibility with the optional rails_xss plugin. [Nathan Weizenbaum, Santiago Pastorino]
|
||||
|
||||
|
||||
*2.3.6 (May 23, 2010)*
|
||||
|
||||
* JSON: set Base.include_root_in_json = true to include a root value in the JSON: {"post": {"title": ...}}. Mirrors the Active Record option. #2584 [Matthew Moore, Joe Martinez, Elad Meidar, Santiago Pastorino]
|
||||
@@ -1914,7 +1935,7 @@ superclass' view_paths. [Rick Olson]
|
||||
|
||||
* Update documentation for erb trim syntax. #5651 [matt@mattmargolis.net]
|
||||
|
||||
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info]
|
||||
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com]
|
||||
|
||||
* Reset @html_document between requests so assert_tag works. #4810 [Jarkko Laine, easleydp@gmail.com]
|
||||
|
||||
@@ -2511,7 +2532,7 @@ superclass' view_paths. [Rick Olson]
|
||||
|
||||
* Provide support for decimal columns to form helpers. Closes #5672. [Dave Thomas]
|
||||
|
||||
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com, sebastien@goetzilla.info]
|
||||
* Pass :id => nil or :class => nil to error_messages_for to supress that html attribute. #3586 [olivier_ansaldi@yahoo.com]
|
||||
|
||||
* Reset @html_document between requests so assert_tag works. #4810 [Jarkko Laine, easleydp@gmail.com]
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
require 'rubygems'
|
||||
require 'rake'
|
||||
require 'rake/testtask'
|
||||
require 'rake/rdoctask'
|
||||
require 'rdoc/task'
|
||||
require 'rake/packagetask'
|
||||
require 'rake/gempackagetask'
|
||||
require 'rubygems/package_task'
|
||||
require File.join(File.dirname(__FILE__), 'lib', 'action_pack', 'version')
|
||||
|
||||
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
||||
@@ -45,7 +45,7 @@ end
|
||||
|
||||
# Genereate the RDoc documentation
|
||||
|
||||
Rake::RDocTask.new { |rdoc|
|
||||
RDoc::Task.new { |rdoc|
|
||||
rdoc.rdoc_dir = 'doc'
|
||||
rdoc.title = "Action Pack -- On rails from request to response"
|
||||
rdoc.options << '--line-numbers' << '--inline-source'
|
||||
@@ -76,14 +76,13 @@ spec = Gem::Specification.new do |s|
|
||||
s.rubyforge_project = "actionpack"
|
||||
s.homepage = "http://www.rubyonrails.org"
|
||||
|
||||
s.has_rdoc = true
|
||||
s.requirements << 'none'
|
||||
|
||||
s.add_dependency('activesupport', '= 2.3.6' + PKG_BUILD)
|
||||
s.add_dependency('rack', '~> 1.1.0')
|
||||
s.add_dependency('activesupport', '= 2.3.14' + PKG_BUILD)
|
||||
s.add_dependency('erubis', '~> 2.7.0')
|
||||
s.add_dependency('rack', '~> 1.1')
|
||||
|
||||
s.require_path = 'lib'
|
||||
s.autorequire = 'action_controller'
|
||||
|
||||
s.files = [ "Rakefile", "install.rb", "README", "RUNNING_UNIT_TESTS", "CHANGELOG", "MIT-LICENSE" ]
|
||||
dist_dirs.each do |dir|
|
||||
@@ -91,7 +90,7 @@ spec = Gem::Specification.new do |s|
|
||||
end
|
||||
end
|
||||
|
||||
Rake::GemPackageTask.new(spec) do |p|
|
||||
Gem::PackageTask.new(spec) do |p|
|
||||
p.gem_spec = spec
|
||||
p.need_tar = true
|
||||
p.need_zip = true
|
||||
|
||||
@@ -31,7 +31,6 @@ rescue LoadError
|
||||
end
|
||||
end
|
||||
|
||||
gem 'rack', '~> 1.1.0'
|
||||
require 'rack'
|
||||
require 'action_controller/cgi_ext'
|
||||
|
||||
|
||||
@@ -1088,6 +1088,9 @@ module ActionController #:nodoc:
|
||||
# redirect_to post_url(@post), :status => 301
|
||||
# redirect_to :action=>'atom', :status => 302
|
||||
#
|
||||
# The status code can either be a standard {HTTP Status code}[http://www.iana.org/assignments/http-status-codes] as an
|
||||
# integer, or a symbol representing the downcased, underscored and symbolized description.
|
||||
#
|
||||
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
|
||||
# +alert+ and +notice+ as well as a general purpose +flash+ bucket.
|
||||
#
|
||||
@@ -1097,8 +1100,7 @@ module ActionController #:nodoc:
|
||||
# redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
|
||||
# redirect_to { :action=>'atom' }, :alert => "Something serious happened"
|
||||
#
|
||||
# When using <tt>redirect_to :back</tt>, if there is no referrer,
|
||||
# RedirectBackError will be raised. You may specify some fallback
|
||||
# When using <tt>redirect_to :back</tt>, if there is no referrer, RedirectBackError will be raised. You may specify some fallback
|
||||
# behavior for this case by rescuing RedirectBackError.
|
||||
def redirect_to(options = {}, response_status = {}) #:doc:
|
||||
raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
|
||||
@@ -1330,8 +1332,11 @@ module ActionController #:nodoc:
|
||||
if action_methods.include?(action_name)
|
||||
send(action_name)
|
||||
default_render unless performed?
|
||||
elsif respond_to? :method_missing
|
||||
method_missing action_name
|
||||
elsif RUBY_VERSION == "1.9.3" && respond_to?(:method_missing)
|
||||
method_missing action_name.intern
|
||||
default_render unless performed?
|
||||
elsif RUBY_VERSION >= "2.0.0" && respond_to?(:method_missing, true) && !method(:method_missing).private?
|
||||
method_missing action_name.intern
|
||||
default_render unless performed?
|
||||
else
|
||||
begin
|
||||
|
||||
@@ -154,7 +154,7 @@ module ActionController #:nodoc:
|
||||
path = controller.url_for(options).split('://').last
|
||||
normalize!(path)
|
||||
add_extension!(path, @extension)
|
||||
@path = URI.unescape(path)
|
||||
@path = URI::DEFAULT_PARSER.unescape(path)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -65,8 +65,8 @@ module ActionController #:nodoc:
|
||||
def read_fragment(key, options = nil)
|
||||
return unless cache_configured?
|
||||
|
||||
key = fragment_cache_key(key)
|
||||
self.class.benchmark "Cached fragment hit: #{key}" do
|
||||
key = fragment_cache_key(key)
|
||||
result = cache_store.read(key, options)
|
||||
result.respond_to?(:html_safe) ? result.html_safe : result
|
||||
end
|
||||
|
||||
@@ -97,7 +97,7 @@ module ActionController #:nodoc:
|
||||
|
||||
private
|
||||
def page_cache_file(path)
|
||||
name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/'))
|
||||
name = (path.empty? || path == "/") ? "/index" : URI::DEFAULT_PARSER.unescape(path.chomp('/'))
|
||||
name << page_cache_extension unless (name.split('/').last || name).include? '.'
|
||||
return name
|
||||
end
|
||||
@@ -149,4 +149,4 @@ module ActionController #:nodoc:
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -60,7 +60,7 @@ module ActionController #:nodoc:
|
||||
attr_reader :controller
|
||||
|
||||
def initialize(controller)
|
||||
@controller, @cookies = controller, controller.request.cookies
|
||||
@controller, @cookies, @secure = controller, controller.request.cookies, controller.request.ssl?
|
||||
super()
|
||||
update(@cookies)
|
||||
end
|
||||
@@ -81,7 +81,7 @@ module ActionController #:nodoc:
|
||||
|
||||
options[:path] = "/" unless options.has_key?(:path)
|
||||
super(key.to_s, options[:value])
|
||||
@controller.response.set_cookie(key, options)
|
||||
@controller.response.set_cookie(key, options) if write_cookie?(options)
|
||||
end
|
||||
|
||||
# Removes the cookie on the client machine by setting the value to an empty string
|
||||
@@ -126,6 +126,12 @@ module ActionController #:nodoc:
|
||||
def signed
|
||||
@signed ||= SignedCookieJar.new(self)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def write_cookie?(cookie)
|
||||
@secure || !cookie[:secure] || defined?(Rails.env) && Rails.env.development?
|
||||
end
|
||||
end
|
||||
|
||||
class PermanentCookieJar < CookieJar #:nodoc:
|
||||
|
||||
@@ -287,7 +287,6 @@ module ActionController
|
||||
"REMOTE_ADDR" => remote_addr,
|
||||
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
|
||||
"CONTENT_LENGTH" => data ? data.length.to_s : nil,
|
||||
"HTTP_COOKIE" => encode_cookies,
|
||||
"HTTP_ACCEPT" => accept,
|
||||
|
||||
"rack.version" => [0,1],
|
||||
@@ -298,6 +297,8 @@ module ActionController
|
||||
"rack.run_once" => false
|
||||
)
|
||||
|
||||
env['HTTP_COOKIE'] = encode_cookies if cookies.any?
|
||||
|
||||
(headers || {}).each do |key, value|
|
||||
key = key.to_s.upcase.gsub(/-/, "_")
|
||||
key = "HTTP_#{key}" unless env.has_key?(key) || key =~ /^HTTP_/
|
||||
@@ -414,15 +415,25 @@ module ActionController
|
||||
end
|
||||
|
||||
def multipart_requestify(params, first=true)
|
||||
returning Hash.new do |p|
|
||||
Array.new.tap do |p|
|
||||
params.each do |key, value|
|
||||
k = first ? key.to_s : "[#{key.to_s}]"
|
||||
if Hash === value
|
||||
multipart_requestify(value, false).each do |subkey, subvalue|
|
||||
p[k + subkey] = subvalue
|
||||
p << [k + subkey, subvalue]
|
||||
end
|
||||
elsif Array === value
|
||||
value.each do |element|
|
||||
if Hash === element || Array === element
|
||||
multipart_requestify(element, false).each do |subkey, subvalue|
|
||||
p << ["#{k}[]#{subkey}", subvalue]
|
||||
end
|
||||
else
|
||||
p << ["#{k}[]", element]
|
||||
end
|
||||
end
|
||||
else
|
||||
p[k] = value
|
||||
p << [k, value]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -453,6 +464,7 @@ EOF
|
||||
end
|
||||
end.join("")+"--#{boundary}--\r"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A module used to extend ActionController::Base, so that integration tests
|
||||
@@ -500,7 +512,7 @@ EOF
|
||||
reset! unless @integration_session
|
||||
# reset the html_document variable, but only for new get/post calls
|
||||
@html_document = nil unless %w(cookies assigns).include?(method)
|
||||
returning @integration_session.__send__(method, *args) do
|
||||
@integration_session.__send__(method, *args).tap do
|
||||
copy_session_variables!
|
||||
end
|
||||
end
|
||||
@@ -524,7 +536,7 @@ EOF
|
||||
if self.class.respond_to?(:fixture_table_names)
|
||||
self.class.fixture_table_names.each do |table_name|
|
||||
name = table_name.tr(".", "_")
|
||||
next unless respond_to?(name)
|
||||
next unless respond_to?(name, true)
|
||||
extras.__send__(:define_method, name) { |*args|
|
||||
delegate.send(name, *args)
|
||||
}
|
||||
@@ -556,7 +568,7 @@ EOF
|
||||
def method_missing(sym, *args, &block)
|
||||
reset! unless @integration_session
|
||||
if @integration_session.respond_to?(sym)
|
||||
returning @integration_session.__send__(sym, *args, &block) do
|
||||
@integration_session.__send__(sym, *args, &block).tap do
|
||||
copy_session_variables!
|
||||
end
|
||||
else
|
||||
|
||||
@@ -446,8 +446,10 @@ EOM
|
||||
end
|
||||
|
||||
def reset_session
|
||||
@env['rack.session.options'].delete(:id)
|
||||
@env['rack.session'] = {}
|
||||
# session may be a hash, if so, we do not want to call destroy
|
||||
# fixes issue 6440
|
||||
session.destroy if session and session.respond_to?(:destroy)
|
||||
self.session = {}
|
||||
end
|
||||
|
||||
def session_options
|
||||
|
||||
@@ -76,7 +76,11 @@ module ActionController #:nodoc:
|
||||
protected
|
||||
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
|
||||
def verify_authenticity_token
|
||||
verified_request? || raise(ActionController::InvalidAuthenticityToken)
|
||||
verified_request? || handle_unverified_request
|
||||
end
|
||||
|
||||
def handle_unverified_request
|
||||
reset_session
|
||||
end
|
||||
|
||||
# Returns true or false if a request is verified. Checks:
|
||||
@@ -85,11 +89,10 @@ module ActionController #:nodoc:
|
||||
# * is it a GET request? Gets should be safe and idempotent
|
||||
# * Does the form_authenticity_token match the given token value from the params?
|
||||
def verified_request?
|
||||
!protect_against_forgery? ||
|
||||
request.method == :get ||
|
||||
request.xhr? ||
|
||||
!verifiable_request_format? ||
|
||||
form_authenticity_token == form_authenticity_param
|
||||
!protect_against_forgery? ||
|
||||
request.get? ||
|
||||
form_authenticity_token == form_authenticity_param ||
|
||||
form_authenticity_token == request.headers['X-CSRF-Token']
|
||||
end
|
||||
|
||||
def form_authenticity_param
|
||||
|
||||
@@ -15,7 +15,7 @@ module ActionController #:nodoc:
|
||||
# behavior is achieved by overriding the <tt>rescue_action_in_public</tt>
|
||||
# and <tt>rescue_action_locally</tt> methods.
|
||||
module Rescue
|
||||
LOCALHOST = ['127.0.0.1', '::1'].freeze
|
||||
LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/].freeze
|
||||
|
||||
DEFAULT_RESCUE_RESPONSE = :internal_server_error
|
||||
DEFAULT_RESCUE_RESPONSES = {
|
||||
@@ -122,7 +122,7 @@ module ActionController #:nodoc:
|
||||
# method if you wish to redefine the meaning of a local request to
|
||||
# include remote IP addresses or other criteria.
|
||||
def local_request? #:doc:
|
||||
LOCALHOST.any?{ |local_ip| request.remote_addr == local_ip && request.remote_ip == local_ip }
|
||||
LOCALHOST.any?{ |local_ip| request.remote_addr =~ local_ip && request.remote_ip =~ local_ip }
|
||||
end
|
||||
|
||||
# Render detailed diagnostics for unhandled exceptions rescued from
|
||||
|
||||
@@ -659,7 +659,7 @@ module ActionController
|
||||
end
|
||||
|
||||
def add_conditions_for(conditions, method)
|
||||
returning({:conditions => conditions.dup}) do |options|
|
||||
({:conditions => conditions.dup}).tap do |options|
|
||||
options[:conditions][:method] = method unless method == :any
|
||||
end
|
||||
end
|
||||
|
||||
@@ -64,12 +64,13 @@ module ActionController # :nodoc:
|
||||
# the character set information will also be included in the content type
|
||||
# information.
|
||||
def content_type=(mime_type)
|
||||
self.headers["Content-Type"] =
|
||||
new_content_type =
|
||||
if mime_type =~ /charset/ || (c = charset).nil?
|
||||
mime_type.to_s
|
||||
else
|
||||
"#{mime_type}; charset=#{c}"
|
||||
end
|
||||
self.headers["Content-Type"] = URI::DEFAULT_PARSER.escape(new_content_type, "\r\n")
|
||||
end
|
||||
|
||||
# Returns the response's content MIME type, or nil if content type has been set.
|
||||
|
||||
@@ -377,7 +377,7 @@ module ActionController
|
||||
ActiveSupport::Inflector.module_eval do
|
||||
# Ensures that routes are reloaded when Rails inflections are updated.
|
||||
def inflections_with_route_reloading(&block)
|
||||
returning(inflections_without_route_reloading(&block)) {
|
||||
(inflections_without_route_reloading(&block)).tap {
|
||||
ActionController::Routing::Routes.reload! if block_given?
|
||||
}
|
||||
end
|
||||
|
||||
@@ -65,7 +65,7 @@ module ActionController
|
||||
# map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
|
||||
#
|
||||
def parameter_shell
|
||||
@parameter_shell ||= returning({}) do |shell|
|
||||
@parameter_shell ||= {}.tap do |shell|
|
||||
requirements.each do |key, requirement|
|
||||
shell[key] = requirement unless requirement.is_a? Regexp
|
||||
end
|
||||
@@ -76,7 +76,7 @@ module ActionController
|
||||
# includes keys that appear inside the path, and keys that have requirements
|
||||
# placed upon them.
|
||||
def significant_keys
|
||||
@significant_keys ||= returning([]) do |sk|
|
||||
@significant_keys ||= [].tap do |sk|
|
||||
segments.each { |segment| sk << segment.key if segment.respond_to? :key }
|
||||
sk.concat requirements.keys
|
||||
sk.uniq!
|
||||
@@ -86,7 +86,7 @@ module ActionController
|
||||
# Return a hash of key/value pairs representing the keys in the route that
|
||||
# have defaults, or which are specified by non-regexp requirements.
|
||||
def defaults
|
||||
@defaults ||= returning({}) do |hash|
|
||||
@defaults ||= {}.tap do |hash|
|
||||
segments.each do |segment|
|
||||
next unless segment.respond_to? :default
|
||||
hash[segment.key] = segment.default unless segment.default.nil?
|
||||
@@ -212,6 +212,10 @@ module ActionController
|
||||
def recognition_conditions
|
||||
result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"]
|
||||
result << "[conditions[:method]].flatten.include?(env[:method])" if conditions[:method]
|
||||
result << "conditions[:host] === env[:host]" if conditions[:host]
|
||||
result << "conditions[:domain] === env[:domain]" if conditions[:domain]
|
||||
result << "conditions[:subdomain] === env[:subdomain]" if conditions[:subdomain]
|
||||
result << "conditions[:fullsubdomain] === env[:fullsubdomain]" if conditions[:fullsubdomain]
|
||||
result
|
||||
end
|
||||
|
||||
|
||||
@@ -496,7 +496,13 @@ module ActionController
|
||||
# Subclasses and plugins may override this method to extract further attributes
|
||||
# from the request, for use by route conditions and such.
|
||||
def extract_request_environment(request)
|
||||
{ :method => request.method }
|
||||
{
|
||||
:method => request.method,
|
||||
:host => request.host,
|
||||
:domain => request.domain,
|
||||
:subdomain => request.subdomains.first,
|
||||
:fullsubdomain => request.subdomains.join('.')
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,7 +36,7 @@ module ActionController
|
||||
end
|
||||
|
||||
def interpolation_chunk
|
||||
URI.escape(value, UNSAFE_PCHAR)
|
||||
URI::DEFAULT_PARSER.escape(value, UNSAFE_PCHAR)
|
||||
end
|
||||
|
||||
# Return a string interpolation statement for this segment and those before it.
|
||||
@@ -173,7 +173,7 @@ module ActionController
|
||||
end
|
||||
|
||||
def interpolation_chunk(value_code = local_name)
|
||||
"\#{URI.escape(#{value_code}.to_s, ActionController::Routing::Segment::UNSAFE_PCHAR)}"
|
||||
"\#{URI::DEFAULT_PARSER.escape(#{value_code}.to_s, ActionController::Routing::Segment::UNSAFE_PCHAR)}"
|
||||
end
|
||||
|
||||
def string_structure(prior_segments)
|
||||
@@ -221,7 +221,7 @@ module ActionController
|
||||
default_value = default ? default.inspect : nil
|
||||
%[
|
||||
value = if (m = match[#{next_capture}])
|
||||
URI.unescape(m)
|
||||
URI::DEFAULT_PARSER.unescape(m)
|
||||
else
|
||||
#{default_value}
|
||||
end
|
||||
@@ -244,7 +244,7 @@ module ActionController
|
||||
"(?i-:(#{(regexp || Regexp.union(*possible_names)).source}))"
|
||||
end
|
||||
|
||||
# Don't URI.escape the controller name since it may contain slashes.
|
||||
# Don't URI::DEFAULT_PARSER.escape the controller name since it may contain slashes.
|
||||
def interpolation_chunk(value_code = local_name)
|
||||
"\#{#{value_code}.to_s}"
|
||||
end
|
||||
@@ -270,7 +270,7 @@ module ActionController
|
||||
end
|
||||
|
||||
def extract_value
|
||||
"#{local_name} = hash[:#{key}] && Array(hash[:#{key}]).collect { |path_component| URI.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}"
|
||||
"#{local_name} = hash[:#{key}] && Array(hash[:#{key}]).collect { |path_component| URI::DEFAULT_PARSER.escape(path_component.to_param, ActionController::Routing::Segment::UNSAFE_PCHAR) }.to_param #{"|| #{default.inspect}" if default}"
|
||||
end
|
||||
|
||||
def default
|
||||
@@ -300,7 +300,7 @@ module ActionController
|
||||
class Result < ::Array #:nodoc:
|
||||
def to_s() join '/' end
|
||||
def self.new_escaped(strings)
|
||||
new strings.collect {|str| URI.unescape str}
|
||||
new strings.collect {|str| URI::DEFAULT_PARSER.unescape str}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -333,7 +333,7 @@ module ActionController
|
||||
def match_extraction(next_capture)
|
||||
%[
|
||||
if (m = match[#{next_capture}])
|
||||
params[:#{key}] = URI.unescape(m.from(1))
|
||||
params[:#{key}] = URI::DEFAULT_PARSER.unescape(m.from(1))
|
||||
end
|
||||
]
|
||||
end
|
||||
|
||||
@@ -2,13 +2,42 @@ require 'rack/utils'
|
||||
|
||||
module ActionController
|
||||
module Session
|
||||
class AbstractStore
|
||||
class AbstractStore
|
||||
ENV_SESSION_KEY = 'rack.session'.freeze
|
||||
ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
|
||||
|
||||
HTTP_COOKIE = 'HTTP_COOKIE'.freeze
|
||||
SET_COOKIE = 'Set-Cookie'.freeze
|
||||
|
||||
# thin wrapper around Hash that allows us to lazily
|
||||
# load session id into session_options
|
||||
class OptionsHash < Hash
|
||||
def initialize(by, env, default_options)
|
||||
@by = by
|
||||
@env = env
|
||||
@session_id_loaded = false
|
||||
merge!(default_options)
|
||||
end
|
||||
|
||||
def [](key)
|
||||
if key == :id
|
||||
load_session_id! unless super(:id) || has_session_id?
|
||||
end
|
||||
super(key)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def has_session_id?
|
||||
@session_id_loaded
|
||||
end
|
||||
|
||||
def load_session_id!
|
||||
self[:id] = @by.send(:extract_session_id, @env)
|
||||
@session_id_loaded = true
|
||||
end
|
||||
end
|
||||
|
||||
class SessionHash < Hash
|
||||
def initialize(by, env)
|
||||
super()
|
||||
@@ -25,21 +54,42 @@ module ActionController
|
||||
end
|
||||
|
||||
def [](key)
|
||||
load! unless @loaded
|
||||
load_for_read!
|
||||
super
|
||||
end
|
||||
|
||||
def has_key?(key)
|
||||
load_for_read!
|
||||
super
|
||||
end
|
||||
|
||||
def []=(key, value)
|
||||
load! unless @loaded
|
||||
load_for_write!
|
||||
super
|
||||
end
|
||||
|
||||
def clear
|
||||
load_for_write!
|
||||
super
|
||||
end
|
||||
|
||||
def to_hash
|
||||
load_for_read!
|
||||
h = {}.replace(self)
|
||||
h.delete_if { |k,v| v.nil? }
|
||||
h
|
||||
end
|
||||
|
||||
def update(hash)
|
||||
load_for_write!
|
||||
super
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
load_for_write!
|
||||
super
|
||||
end
|
||||
|
||||
def data
|
||||
ActiveSupport::Deprecation.warn(
|
||||
"ActionController::Session::AbstractStore::SessionHash#data " +
|
||||
@@ -48,40 +98,43 @@ module ActionController
|
||||
end
|
||||
|
||||
def inspect
|
||||
load! unless @loaded
|
||||
load_for_read!
|
||||
super
|
||||
end
|
||||
|
||||
def exists?
|
||||
return @exists if instance_variable_defined?(:@exists)
|
||||
@exists = @by.send(:exists?, @env)
|
||||
end
|
||||
|
||||
def loaded?
|
||||
@loaded
|
||||
end
|
||||
|
||||
def destroy
|
||||
clear
|
||||
@by.send(:destroy, @env) if @by
|
||||
@env[ENV_SESSION_OPTIONS_KEY][:id] = nil if @env && @env[ENV_SESSION_OPTIONS_KEY]
|
||||
@loaded = false
|
||||
end
|
||||
|
||||
private
|
||||
def loaded?
|
||||
@loaded
|
||||
|
||||
def load_for_read!
|
||||
load! if !loaded? && exists?
|
||||
end
|
||||
|
||||
def load_for_write!
|
||||
load! unless loaded?
|
||||
end
|
||||
|
||||
def load!
|
||||
stale_session_check! do
|
||||
id, session = @by.send(:load_session, @env)
|
||||
(@env[ENV_SESSION_OPTIONS_KEY] ||= {})[:id] = id
|
||||
replace(session)
|
||||
@loaded = true
|
||||
end
|
||||
id, session = @by.send(:load_session, @env)
|
||||
@env[ENV_SESSION_OPTIONS_KEY][:id] = id
|
||||
replace(session)
|
||||
@loaded = true
|
||||
end
|
||||
|
||||
def stale_session_check!
|
||||
yield
|
||||
rescue ArgumentError => argument_error
|
||||
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
|
||||
begin
|
||||
# Note that the regexp does not allow $1 to end with a ':'
|
||||
$1.constantize
|
||||
rescue LoadError, NameError => const_error
|
||||
raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
|
||||
end
|
||||
|
||||
retry
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DEFAULT_OPTIONS = {
|
||||
@@ -120,18 +173,18 @@ module ActionController
|
||||
end
|
||||
|
||||
def call(env)
|
||||
session = SessionHash.new(self, env)
|
||||
|
||||
env[ENV_SESSION_KEY] = session
|
||||
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
|
||||
|
||||
prepare!(env)
|
||||
response = @app.call(env)
|
||||
|
||||
session_data = env[ENV_SESSION_KEY]
|
||||
options = env[ENV_SESSION_OPTIONS_KEY]
|
||||
|
||||
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
|
||||
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
|
||||
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.loaded? || options[:expire_after]
|
||||
request = ActionController::Request.new(env)
|
||||
|
||||
return response if (options[:secure] && !request.ssl?)
|
||||
|
||||
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
|
||||
|
||||
sid = options[:id] || generate_sid
|
||||
|
||||
@@ -139,21 +192,12 @@ module ActionController
|
||||
return response
|
||||
end
|
||||
|
||||
cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid)
|
||||
cookie << "; domain=#{options[:domain]}" if options[:domain]
|
||||
cookie << "; path=#{options[:path]}" if options[:path]
|
||||
if options[:expire_after]
|
||||
expiry = Time.now + options[:expire_after]
|
||||
cookie << "; expires=#{expiry.httpdate}"
|
||||
end
|
||||
cookie << "; Secure" if options[:secure]
|
||||
cookie << "; HttpOnly" if options[:httponly]
|
||||
request_cookies = env["rack.request.cookie_hash"]
|
||||
|
||||
headers = response[1]
|
||||
unless headers[SET_COOKIE].blank?
|
||||
headers[SET_COOKIE] << "\n#{cookie}"
|
||||
else
|
||||
headers[SET_COOKIE] = cookie
|
||||
if (request_cookies.nil? || request_cookies[@key] != sid) || options[:expire_after]
|
||||
cookie = {:value => sid}
|
||||
cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
|
||||
Rack::Utils.set_cookie_header!(response[1], @key, cookie.merge(options))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -161,18 +205,39 @@ module ActionController
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def prepare!(env)
|
||||
env[ENV_SESSION_KEY] = SessionHash.new(self, env)
|
||||
env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
|
||||
end
|
||||
|
||||
def generate_sid
|
||||
ActiveSupport::SecureRandom.hex(16)
|
||||
end
|
||||
|
||||
def load_session(env)
|
||||
request = Rack::Request.new(env)
|
||||
sid = request.cookies[@key]
|
||||
unless @cookie_only
|
||||
sid ||= request.params[@key]
|
||||
stale_session_check! do
|
||||
sid = current_session_id(env)
|
||||
sid, session = get_session(env, sid)
|
||||
[sid, session]
|
||||
end
|
||||
sid, session = get_session(env, sid)
|
||||
[sid, session]
|
||||
end
|
||||
|
||||
def extract_session_id(env)
|
||||
stale_session_check! do
|
||||
request = Rack::Request.new(env)
|
||||
sid = request.cookies[@key]
|
||||
sid ||= request.params[@key] unless @cookie_only
|
||||
sid
|
||||
end
|
||||
end
|
||||
|
||||
def current_session_id(env)
|
||||
env[ENV_SESSION_OPTIONS_KEY][:id]
|
||||
end
|
||||
|
||||
def exists?(env)
|
||||
current_session_id(env).present?
|
||||
end
|
||||
|
||||
def get_session(env, sid)
|
||||
@@ -182,6 +247,30 @@ module ActionController
|
||||
def set_session(env, sid, session_data)
|
||||
raise '#set_session needs to be implemented.'
|
||||
end
|
||||
|
||||
def destroy(env)
|
||||
raise '#destroy needs to be implemented.'
|
||||
end
|
||||
|
||||
module SessionUtils
|
||||
private
|
||||
def stale_session_check!
|
||||
yield
|
||||
rescue ArgumentError => argument_error
|
||||
if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
|
||||
begin
|
||||
# Note that the regexp does not allow $1 to end with a ':'
|
||||
$1.constantize
|
||||
rescue LoadError, NameError => const_error
|
||||
raise ActionController::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
|
||||
end
|
||||
retry
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
include SessionUtils
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,6 +36,8 @@ module ActionController
|
||||
#
|
||||
# Note that changing digest or secret invalidates all existing sessions!
|
||||
class CookieStore
|
||||
include AbstractStore::SessionUtils
|
||||
|
||||
# Cookies can typically store 4096 bytes.
|
||||
MAX = 4096
|
||||
SECRET_MIN_LENGTH = 30 # characters
|
||||
@@ -50,7 +52,6 @@ module ActionController
|
||||
|
||||
ENV_SESSION_KEY = "rack.session".freeze
|
||||
ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
|
||||
HTTP_SET_COOKIE = "Set-Cookie".freeze
|
||||
|
||||
# Raised when storing more than 4K of session data.
|
||||
class CookieOverflow < StandardError; end
|
||||
@@ -93,73 +94,81 @@ module ActionController
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
|
||||
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
|
||||
|
||||
prepare!(env)
|
||||
|
||||
status, headers, body = @app.call(env)
|
||||
|
||||
session_data = env[ENV_SESSION_KEY]
|
||||
options = env[ENV_SESSION_OPTIONS_KEY]
|
||||
request = ActionController::Request.new(env)
|
||||
|
||||
if !(options[:secure] && !request.ssl?) && (!session_data.is_a?(AbstractStore::SessionHash) || session_data.loaded? || options[:expire_after])
|
||||
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
|
||||
|
||||
if !session_data.is_a?(AbstractStore::SessionHash) || session_data.send(:loaded?) || options[:expire_after]
|
||||
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.send(:loaded?)
|
||||
persistent_session_id!(session_data)
|
||||
session_data = marshal(session_data.to_hash)
|
||||
|
||||
raise CookieOverflow if session_data.size > MAX
|
||||
|
||||
cookie = Hash.new
|
||||
cookie[:value] = session_data
|
||||
unless options[:expire_after].nil?
|
||||
cookie[:expires] = Time.now + options[:expire_after]
|
||||
end
|
||||
|
||||
cookie = build_cookie(@key, cookie.merge(options))
|
||||
unless headers[HTTP_SET_COOKIE].blank?
|
||||
headers[HTTP_SET_COOKIE] << "\n#{cookie}"
|
||||
else
|
||||
headers[HTTP_SET_COOKIE] = cookie
|
||||
end
|
||||
Rack::Utils.set_cookie_header!(headers, @key, cookie.merge(options))
|
||||
end
|
||||
|
||||
[status, headers, body]
|
||||
end
|
||||
|
||||
private
|
||||
# Should be in Rack::Utils soon
|
||||
def build_cookie(key, value)
|
||||
case value
|
||||
when Hash
|
||||
domain = "; domain=" + value[:domain] if value[:domain]
|
||||
path = "; path=" + value[:path] if value[:path]
|
||||
# According to RFC 2109, we need dashes here.
|
||||
# N.B.: cgi.rb uses spaces...
|
||||
expires = "; expires=" + value[:expires].clone.gmtime.
|
||||
strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
|
||||
secure = "; secure" if value[:secure]
|
||||
httponly = "; HttpOnly" if value[:httponly]
|
||||
value = value[:value]
|
||||
end
|
||||
value = [value] unless Array === value
|
||||
cookie = Rack::Utils.escape(key) + "=" +
|
||||
value.map { |v| Rack::Utils.escape(v) }.join("&") +
|
||||
"#{domain}#{path}#{expires}#{secure}#{httponly}"
|
||||
|
||||
def prepare!(env)
|
||||
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
|
||||
env[ENV_SESSION_OPTIONS_KEY] = AbstractStore::OptionsHash.new(self, env, @default_options)
|
||||
end
|
||||
|
||||
def load_session(env)
|
||||
request = Rack::Request.new(env)
|
||||
session_data = request.cookies[@key]
|
||||
data = unmarshal(session_data) || persistent_session_id!({})
|
||||
data = unpacked_cookie_data(env)
|
||||
data = persistent_session_id!(data)
|
||||
[data[:session_id], data]
|
||||
end
|
||||
|
||||
def extract_session_id(env)
|
||||
if data = unpacked_cookie_data(env)
|
||||
persistent_session_id!(data) unless data.empty?
|
||||
data[:session_id]
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def current_session_id(env)
|
||||
env[ENV_SESSION_OPTIONS_KEY][:id]
|
||||
end
|
||||
|
||||
def exists?(env)
|
||||
current_session_id(env).present?
|
||||
end
|
||||
|
||||
def unpacked_cookie_data(env)
|
||||
env["action_dispatch.request.unsigned_session_cookie"] ||= begin
|
||||
stale_session_check! do
|
||||
request = Rack::Request.new(env)
|
||||
session_data = request.cookies[@key]
|
||||
unmarshal(session_data) || {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Marshal a session hash into safe cookie data. Include an integrity hash.
|
||||
def marshal(session)
|
||||
@verifier.generate(persistent_session_id!(session))
|
||||
@verifier.generate(session)
|
||||
end
|
||||
|
||||
# Unmarshal cookie data to a hash and verify its integrity.
|
||||
def unmarshal(cookie)
|
||||
persistent_session_id!(@verifier.verify(cookie)) if cookie
|
||||
@verifier.verify(cookie) if cookie
|
||||
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||
nil
|
||||
end
|
||||
@@ -200,13 +209,17 @@ module ActionController
|
||||
|
||||
def verifier_for(secret, digest)
|
||||
key = secret.respond_to?(:call) ? secret.call : secret
|
||||
ActiveSupport::MessageVerifier.new(key, digest)
|
||||
ActiveSupport::MessageVerifier.new(key, digest: digest)
|
||||
end
|
||||
|
||||
def generate_sid
|
||||
ActiveSupport::SecureRandom.hex(16)
|
||||
end
|
||||
|
||||
def destroy(env)
|
||||
# session data is stored on client; nothing to do here
|
||||
end
|
||||
|
||||
def persistent_session_id!(data)
|
||||
(data ||= {}).merge!(inject_persistent_session_id(data))
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
begin
|
||||
require_library_or_gem 'memcache'
|
||||
|
||||
require 'thread'
|
||||
module ActionController
|
||||
module Session
|
||||
class MemCacheStore < AbstractStore
|
||||
@@ -43,6 +43,15 @@ begin
|
||||
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
||||
return false
|
||||
end
|
||||
|
||||
def destroy(env)
|
||||
if sid = current_session_id(env)
|
||||
@pool.delete(sid)
|
||||
end
|
||||
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -450,7 +450,7 @@ module ActionController #:nodoc:
|
||||
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
|
||||
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
|
||||
@request.env['HTTP_ACCEPT'] = [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
|
||||
returning __send__(request_method, action, parameters, session, flash) do
|
||||
__send__(request_method, action, parameters, session, flash).tap do
|
||||
@request.env.delete 'HTTP_X_REQUESTED_WITH'
|
||||
@request.env.delete 'HTTP_ACCEPT'
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'uri'
|
||||
|
||||
module ActionController
|
||||
# In <b>routes.rb</b> one defines URL-to-controller mappings, but the reverse
|
||||
# is also possible: an URL can be generated from one of your routing definitions.
|
||||
@@ -92,6 +94,14 @@ module ActionController
|
||||
# end
|
||||
# end
|
||||
module UrlWriter
|
||||
RESERVED_PCHAR = ':@&=+$,;%'
|
||||
SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}"
|
||||
if RUBY_VERSION >= '1.9'
|
||||
UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze
|
||||
else
|
||||
UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze
|
||||
end
|
||||
|
||||
def self.included(base) #:nodoc:
|
||||
ActionController::Routing::Routes.install_helpers(base)
|
||||
base.mattr_accessor :default_url_options
|
||||
@@ -142,7 +152,7 @@ module ActionController
|
||||
end
|
||||
trailing_slash = options.delete(:trailing_slash) if options.key?(:trailing_slash)
|
||||
url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root]
|
||||
anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options[:anchor]
|
||||
anchor = "##{URI::DEFAULT_PARSER.escape(options.delete(:anchor).to_param.to_s, UNSAFE_PCHAR)}" if options[:anchor]
|
||||
generated = Routing::Routes.generate(options, {})
|
||||
url << (trailing_slash ? generated.sub(/\?|\z/) { "/" + $& } : generated)
|
||||
url << anchor if anchor
|
||||
|
||||
@@ -4,7 +4,7 @@ require 'html/selector'
|
||||
require 'html/sanitizer'
|
||||
|
||||
module HTML #:nodoc:
|
||||
# A top-level HTMl document. You give it a body of text, and it will parse that
|
||||
# A top-level HTML document. You give it a body of text, and it will parse that
|
||||
# text into a tree of nodes.
|
||||
class Document #:nodoc:
|
||||
|
||||
@@ -48,7 +48,7 @@ EOF
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Search the tree for (and return) the first node that matches the given
|
||||
# conditions. The conditions are interpreted differently for different node
|
||||
# types, see HTML::Text#find and HTML::Tag#find.
|
||||
@@ -62,7 +62,7 @@ EOF
|
||||
def find_all(conditions)
|
||||
@root.find_all(conditions)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'strscan'
|
||||
|
||||
module HTML #:nodoc:
|
||||
|
||||
|
||||
class Conditions < Hash #:nodoc:
|
||||
def initialize(hash)
|
||||
super()
|
||||
@@ -18,14 +18,14 @@ module HTML #:nodoc:
|
||||
hash[k] = Conditions.new(v)
|
||||
when :children
|
||||
hash[k] = v = keys_to_symbols(v)
|
||||
v.each do |k,v2|
|
||||
case k
|
||||
v.each do |key,value|
|
||||
case key
|
||||
when :count, :greater_than, :less_than
|
||||
# keys are valid, and require no further processing
|
||||
when :only
|
||||
v[k] = Conditions.new(v2)
|
||||
v[key] = Conditions.new(value)
|
||||
else
|
||||
raise "illegal key #{k.inspect} => #{v2.inspect}"
|
||||
raise "illegal key #{key.inspect} => #{value.inspect}"
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -38,18 +38,14 @@ module HTML #:nodoc:
|
||||
private
|
||||
|
||||
def keys_to_strings(hash)
|
||||
hash.keys.inject({}) do |h,k|
|
||||
h[k.to_s] = hash[k]
|
||||
h
|
||||
end
|
||||
Hash[hash.keys.map {|k| [k.to_s, hash[k]]}]
|
||||
end
|
||||
|
||||
def keys_to_symbols(hash)
|
||||
hash.keys.inject({}) do |h,k|
|
||||
Hash[hash.keys.map do |k|
|
||||
raise "illegal key #{k.inspect}" unless k.respond_to?(:to_sym)
|
||||
h[k.to_sym] = hash[k]
|
||||
h
|
||||
end
|
||||
[k.to_sym, hash[k]]
|
||||
end]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -57,17 +53,17 @@ module HTML #:nodoc:
|
||||
class Node #:nodoc:
|
||||
# The array of children of this node. Not all nodes have children.
|
||||
attr_reader :children
|
||||
|
||||
|
||||
# The parent node of this node. All nodes have a parent, except for the
|
||||
# root node.
|
||||
attr_reader :parent
|
||||
|
||||
|
||||
# The line number of the input where this node was begun
|
||||
attr_reader :line
|
||||
|
||||
|
||||
# The byte position in the input where this node was begun
|
||||
attr_reader :position
|
||||
|
||||
|
||||
# Create a new node as a child of the given parent.
|
||||
def initialize(parent, line=0, pos=0)
|
||||
@parent = parent
|
||||
@@ -77,9 +73,7 @@ module HTML #:nodoc:
|
||||
|
||||
# Return a textual representation of the node.
|
||||
def to_s
|
||||
s = ""
|
||||
@children.each { |child| s << child.to_s }
|
||||
s
|
||||
@children.join()
|
||||
end
|
||||
|
||||
# Return false (subclasses must override this to provide specific matching
|
||||
@@ -92,7 +86,7 @@ module HTML #:nodoc:
|
||||
# returns non +nil+. Returns the result of the #find call that succeeded.
|
||||
def find(conditions)
|
||||
conditions = validate_conditions(conditions)
|
||||
@children.each do |child|
|
||||
@children.each do |child|
|
||||
node = child.find(conditions)
|
||||
return node if node
|
||||
end
|
||||
@@ -133,7 +127,7 @@ module HTML #:nodoc:
|
||||
|
||||
equivalent
|
||||
end
|
||||
|
||||
|
||||
class <<self
|
||||
def parse(parent, line, pos, content, strict=true)
|
||||
if content !~ /^<\S/
|
||||
@@ -160,11 +154,11 @@ module HTML #:nodoc:
|
||||
|
||||
return CDATA.new(parent, line, pos, scanner.pre_match.gsub(/<!\[CDATA\[/, ''))
|
||||
end
|
||||
|
||||
|
||||
closing = ( scanner.scan(/\//) ? :close : nil )
|
||||
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[-:\w\x00-\x09\x0b-\x0c\x0e-\x1f]+/)
|
||||
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[^\s!>\/]+/)
|
||||
name.downcase!
|
||||
|
||||
|
||||
unless closing
|
||||
scanner.skip(/\s*/)
|
||||
attributes = {}
|
||||
@@ -177,6 +171,7 @@ module HTML #:nodoc:
|
||||
case text
|
||||
when "\\" then
|
||||
value << text
|
||||
break if scanner.eos?
|
||||
value << scanner.getch
|
||||
when delim
|
||||
break
|
||||
@@ -190,13 +185,13 @@ module HTML #:nodoc:
|
||||
attributes[attr.downcase] = value
|
||||
scanner.skip(/\s*/)
|
||||
end
|
||||
|
||||
|
||||
closing = ( scanner.scan(/\//) ? :self : nil )
|
||||
end
|
||||
|
||||
|
||||
unless scanner.scan(/\s*>/)
|
||||
if strict
|
||||
raise "expected > (got #{scanner.rest.inspect} for #{content}, #{attributes.inspect})"
|
||||
raise "expected > (got #{scanner.rest.inspect} for #{content}, #{attributes.inspect})"
|
||||
else
|
||||
# throw away all text until we find what we're looking for
|
||||
scanner.skip_until(/>/) or scanner.terminate
|
||||
@@ -211,9 +206,9 @@ module HTML #:nodoc:
|
||||
|
||||
# A node that represents text, rather than markup.
|
||||
class Text < Node #:nodoc:
|
||||
|
||||
|
||||
attr_reader :content
|
||||
|
||||
|
||||
# Creates a new text node as a child of the given parent, with the given
|
||||
# content.
|
||||
def initialize(parent, line, pos, content)
|
||||
@@ -239,7 +234,7 @@ module HTML #:nodoc:
|
||||
def find(conditions)
|
||||
match(conditions) && self
|
||||
end
|
||||
|
||||
|
||||
# Returns non-+nil+ if this node meets the given conditions, or +nil+
|
||||
# otherwise. See the discussion of #find for the valid conditions.
|
||||
def match(conditions)
|
||||
@@ -267,7 +262,7 @@ module HTML #:nodoc:
|
||||
content == node.content
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# A CDATA node is simply a text node with a specialized way of displaying
|
||||
# itself.
|
||||
class CDATA < Text #:nodoc:
|
||||
@@ -280,16 +275,16 @@ module HTML #:nodoc:
|
||||
# closing tag, or a self-closing tag. It has a name, and may have a hash of
|
||||
# attributes.
|
||||
class Tag < Node #:nodoc:
|
||||
|
||||
|
||||
# Either +nil+, <tt>:close</tt>, or <tt>:self</tt>
|
||||
attr_reader :closing
|
||||
|
||||
|
||||
# Either +nil+, or a hash of attributes for this node.
|
||||
attr_reader :attributes
|
||||
|
||||
# The name of this tag.
|
||||
attr_reader :name
|
||||
|
||||
|
||||
# Create a new node as a child of the given parent, using the given content
|
||||
# to describe the node. It will be parsed and the node name, attributes and
|
||||
# closing status extracted.
|
||||
@@ -343,7 +338,7 @@ module HTML #:nodoc:
|
||||
def tag?
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
# Returns +true+ if the node meets any of the given conditions. The
|
||||
# +conditions+ parameter must be a hash of any of the following keys
|
||||
# (all are optional):
|
||||
@@ -403,7 +398,7 @@ module HTML #:nodoc:
|
||||
# node.match :descendant => { :tag => "strong" }
|
||||
#
|
||||
# # test if the node has between 2 and 4 span tags as immediate children
|
||||
# node.match :children => { :count => 2..4, :only => { :tag => "span" } }
|
||||
# node.match :children => { :count => 2..4, :only => { :tag => "span" } }
|
||||
#
|
||||
# # get funky: test to see if the node is a "div", has a "ul" ancestor
|
||||
# # and an "li" parent (with "class" = "enum"), and whether or not it has
|
||||
@@ -438,7 +433,7 @@ module HTML #:nodoc:
|
||||
|
||||
# test children
|
||||
return false unless children.find { |child| child.match(conditions[:child]) } if conditions[:child]
|
||||
|
||||
|
||||
# test ancestors
|
||||
if conditions[:ancestor]
|
||||
return false unless catch :found do
|
||||
@@ -456,13 +451,13 @@ module HTML #:nodoc:
|
||||
child.match(:descendant => conditions[:descendant])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# count children
|
||||
if opts = conditions[:children]
|
||||
matches = children.select do |c|
|
||||
(c.kind_of?(HTML::Tag) and (c.closing == :self or ! c.childless?))
|
||||
end
|
||||
|
||||
|
||||
matches = matches.select { |c| c.match(opts[:only]) } if opts[:only]
|
||||
opts.each do |key, value|
|
||||
next if key == :only
|
||||
@@ -488,24 +483,24 @@ module HTML #:nodoc:
|
||||
self_index = siblings.index(self)
|
||||
|
||||
if conditions[:sibling]
|
||||
return false unless siblings.detect do |s|
|
||||
return false unless siblings.detect do |s|
|
||||
s != self && s.match(conditions[:sibling])
|
||||
end
|
||||
end
|
||||
|
||||
if conditions[:before]
|
||||
return false unless siblings[self_index+1..-1].detect do |s|
|
||||
return false unless siblings[self_index+1..-1].detect do |s|
|
||||
s != self && s.match(conditions[:before])
|
||||
end
|
||||
end
|
||||
|
||||
if conditions[:after]
|
||||
return false unless siblings[0,self_index].detect do |s|
|
||||
return false unless siblings[0,self_index].detect do |s|
|
||||
s != self && s.match(conditions[:after])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
@@ -514,7 +509,7 @@ module HTML #:nodoc:
|
||||
return false unless closing == node.closing && self.name == node.name
|
||||
attributes == node.attributes
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
# Match the given value to the given condition.
|
||||
def match_condition(value, condition)
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
require 'set'
|
||||
require 'cgi'
|
||||
require 'active_support/core_ext/class/attribute'
|
||||
|
||||
module HTML
|
||||
class Sanitizer
|
||||
def sanitize(text, options = {})
|
||||
return text unless sanitizeable?(text)
|
||||
tokenize(text, options).join
|
||||
end
|
||||
|
||||
|
||||
def sanitizeable?(text)
|
||||
!(text.nil? || text.empty? || !text.index("<"))
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def tokenize(text, options)
|
||||
tokenizer = HTML::Tokenizer.new(text)
|
||||
@@ -19,27 +23,27 @@ module HTML
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
|
||||
def process_node(node, result, options)
|
||||
result << node.to_s
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class FullSanitizer < Sanitizer
|
||||
def sanitize(text, options = {})
|
||||
result = super
|
||||
# strip any comments, and if they have a newline at the end (ie. line with
|
||||
# only a comment) strip that too
|
||||
result.gsub!(/<!--(.*?)-->[\n]?/m, "") if result
|
||||
result = result.gsub(/<!--(.*?)-->[\n]?/m, "") if (result && result =~ /<!--(.*?)-->[\n]?/m)
|
||||
# Recurse - handle all dirty nested tags
|
||||
result == text ? result : sanitize(result, options)
|
||||
end
|
||||
|
||||
|
||||
def process_node(node, result, options)
|
||||
result << node.to_s if node.class == HTML::Text
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class LinkSanitizer < FullSanitizer
|
||||
cattr_accessor :included_tags, :instance_writer => false
|
||||
self.included_tags = Set.new(%w(a href))
|
||||
@@ -47,51 +51,51 @@ module HTML
|
||||
def sanitizeable?(text)
|
||||
!(text.nil? || text.empty? || !((text.index("<a") || text.index("<href")) && text.index(">")))
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
def process_node(node, result, options)
|
||||
result << node.to_s unless node.is_a?(HTML::Tag) && included_tags.include?(node.name)
|
||||
result << node.to_s unless node.is_a?(HTML::Tag) && included_tags.include?(node.name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class WhiteListSanitizer < Sanitizer
|
||||
[:protocol_separator, :uri_attributes, :allowed_attributes, :allowed_tags, :allowed_protocols, :bad_tags,
|
||||
:allowed_css_properties, :allowed_css_keywords, :shorthand_css_properties].each do |attr|
|
||||
class_inheritable_accessor attr, :instance_writer => false
|
||||
class_attribute attr, :instance_writer => false
|
||||
end
|
||||
|
||||
# A regular expression of the valid characters used to separate protocols like
|
||||
# the ':' in 'http://foo.com'
|
||||
self.protocol_separator = /:|(�*58)|(p)|(%|%)3A/
|
||||
|
||||
self.protocol_separator = /:|(�*58)|(p)|(�*3a)|(%|%)3A/i
|
||||
|
||||
# Specifies a Set of HTML attributes that can have URIs.
|
||||
self.uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc))
|
||||
|
||||
# Specifies a Set of 'bad' tags that the #sanitize helper will remove completely, as opposed
|
||||
# to just escaping harmless tags like <font>
|
||||
self.bad_tags = Set.new(%w(script))
|
||||
|
||||
|
||||
# Specifies the default Set of tags that the #sanitize helper will allow unscathed.
|
||||
self.allowed_tags = Set.new(%w(strong em b i p code pre tt samp kbd var sub
|
||||
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dt dd abbr
|
||||
self.allowed_tags = Set.new(%w(strong em b i p code pre tt samp kbd var sub
|
||||
sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dl dt dd abbr
|
||||
acronym a img blockquote del ins))
|
||||
|
||||
# Specifies the default Set of html attributes that the #sanitize helper will leave
|
||||
# Specifies the default Set of html attributes that the #sanitize helper will leave
|
||||
# in the allowed tag.
|
||||
self.allowed_attributes = Set.new(%w(href src width height alt cite datetime title class name xml:lang abbr))
|
||||
|
||||
|
||||
# Specifies the default Set of acceptable css properties that #sanitize and #sanitize_css will accept.
|
||||
self.allowed_protocols = Set.new(%w(ed2k ftp http https irc mailto news gopher nntp telnet webcal xmpp callto
|
||||
self.allowed_protocols = Set.new(%w(ed2k ftp http https irc mailto news gopher nntp telnet webcal xmpp callto
|
||||
feed svn urn aim rsync tag ssh sftp rtsp afs))
|
||||
|
||||
|
||||
# Specifies the default Set of acceptable css keywords that #sanitize and #sanitize_css will accept.
|
||||
self.allowed_css_properties = Set.new(%w(azimuth background-color border-bottom-color border-collapse
|
||||
border-color border-left-color border-right-color border-top-color clear color cursor direction display
|
||||
self.allowed_css_properties = Set.new(%w(azimuth background-color border-bottom-color border-collapse
|
||||
border-color border-left-color border-right-color border-top-color clear color cursor direction display
|
||||
elevation float font font-family font-size font-style font-variant font-weight height letter-spacing line-height
|
||||
overflow pause pause-after pause-before pitch pitch-range richness speak speak-header speak-numeral speak-punctuation
|
||||
speech-rate stress text-align text-decoration text-indent unicode-bidi vertical-align voice-family volume white-space
|
||||
width))
|
||||
|
||||
|
||||
# Specifies the default Set of acceptable css keywords that #sanitize and #sanitize_css will accept.
|
||||
self.allowed_css_keywords = Set.new(%w(auto aqua black block blue bold both bottom brown center
|
||||
collapse dashed dotted fuchsia gray green !important italic left lime maroon medium none navy normal
|
||||
@@ -100,14 +104,14 @@ module HTML
|
||||
# Specifies the default Set of allowed shorthand css properties for the #sanitize and #sanitize_css helpers.
|
||||
self.shorthand_css_properties = Set.new(%w(background border margin padding))
|
||||
|
||||
# Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute
|
||||
# Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute
|
||||
def sanitize_css(style)
|
||||
# disallow urls
|
||||
style = style.to_s.gsub(/url\s*\(\s*[^\s)]+?\s*\)\s*/, ' ')
|
||||
|
||||
# gauntlet
|
||||
if style !~ /^([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*$/ ||
|
||||
style !~ /^(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*$/
|
||||
if style !~ /\A([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*\z/ ||
|
||||
style !~ /\A(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*\z/
|
||||
return ''
|
||||
end
|
||||
|
||||
@@ -115,10 +119,10 @@ module HTML
|
||||
style.scan(/([-\w]+)\s*:\s*([^:;]*)/) do |prop,val|
|
||||
if allowed_css_properties.include?(prop.downcase)
|
||||
clean << prop + ': ' + val + ';'
|
||||
elsif shorthand_css_properties.include?(prop.split('-')[0].downcase)
|
||||
elsif shorthand_css_properties.include?(prop.split('-')[0].downcase)
|
||||
unless val.split().any? do |keyword|
|
||||
!allowed_css_keywords.include?(keyword) &&
|
||||
keyword !~ /^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$/
|
||||
!allowed_css_keywords.include?(keyword) &&
|
||||
keyword !~ /\A(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/
|
||||
end
|
||||
clean << prop + ': ' + val + ';'
|
||||
end
|
||||
@@ -143,7 +147,7 @@ module HTML
|
||||
else
|
||||
options[:parent].unshift node.name
|
||||
end
|
||||
|
||||
|
||||
process_attributes_for node, options
|
||||
|
||||
options[:tags].include?(node.name) ? node : nil
|
||||
@@ -151,7 +155,7 @@ module HTML
|
||||
bad_tags.include?(options[:parent].first) ? nil : node.to_s.gsub(/</, "<")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def process_attributes_for(node, options)
|
||||
return unless node.attributes
|
||||
node.attributes.keys.each do |attr_name|
|
||||
@@ -166,8 +170,8 @@ module HTML
|
||||
end
|
||||
|
||||
def contains_bad_protocols?(attr_name, value)
|
||||
uri_attributes.include?(attr_name) &&
|
||||
(value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first))
|
||||
uri_attributes.include?(attr_name) &&
|
||||
(value =~ /(^[^\/:]*):|(�*58)|(p)|(�*3a)|(%|%)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -128,6 +128,8 @@ module HTML
|
||||
# (no parent element).
|
||||
# * <tt>:empty</tt> -- Match the element only if it has no child elements,
|
||||
# and no text content.
|
||||
# * <tt>:content(string)</tt> -- Match the element only if it has <tt>string</tt>
|
||||
# as its text content (ignoring leading and trailing whitespace).
|
||||
# * <tt>:only-child</tt> -- Match the element if it is the only child (element)
|
||||
# of its parent element.
|
||||
# * <tt>:only-of-type</tt> -- Match the element if it is the only child (element)
|
||||
@@ -182,7 +184,7 @@ module HTML
|
||||
# not another using <tt>:not</tt>. For example:
|
||||
# p:not(.post)
|
||||
# Matches all paragraphs that do not have the class <tt>.post</tt>.
|
||||
#
|
||||
#
|
||||
# === Substitution Values
|
||||
#
|
||||
# You can use substitution with identifiers, class names and element values.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'strscan'
|
||||
|
||||
module HTML #:nodoc:
|
||||
|
||||
|
||||
# A simple HTML tokenizer. It simply breaks a stream of text into tokens, where each
|
||||
# token is a string. Each string represents either "text", or an HTML element.
|
||||
#
|
||||
@@ -14,15 +14,16 @@ module HTML #:nodoc:
|
||||
# p token
|
||||
# end
|
||||
class Tokenizer #:nodoc:
|
||||
|
||||
|
||||
# The current (byte) position in the text
|
||||
attr_reader :position
|
||||
|
||||
|
||||
# The current line number
|
||||
attr_reader :line
|
||||
|
||||
|
||||
# Create a new Tokenizer for the given text.
|
||||
def initialize(text)
|
||||
text.encode! if text.encoding_aware?
|
||||
@scanner = StringScanner.new(text)
|
||||
@position = 0
|
||||
@line = 0
|
||||
@@ -41,7 +42,7 @@ module HTML #:nodoc:
|
||||
update_current_line(scan_text)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
# Treat the text at the current position as a tag, and scan it. Supports
|
||||
@@ -68,13 +69,13 @@ module HTML #:nodoc:
|
||||
def scan_text
|
||||
"#{@scanner.getch}#{@scanner.scan(/[^<]*/)}"
|
||||
end
|
||||
|
||||
|
||||
# Counts the number of newlines in the text and updates the current line
|
||||
# accordingly.
|
||||
def update_current_line(text)
|
||||
text.scan(/\r?\n/) { @current_line += 1 }
|
||||
end
|
||||
|
||||
|
||||
# Skips over quoted strings, so that less-than and greater-than characters
|
||||
# within the strings are ignored.
|
||||
def consume_quoted_regions
|
||||
@@ -95,11 +96,12 @@ module HTML #:nodoc:
|
||||
while match = @scanner.scan_until(/[\\#{delim}]/)
|
||||
text << match
|
||||
break if @scanner.matched == delim
|
||||
break if @scanner.eos?
|
||||
text << @scanner.getch # skip the escaped character
|
||||
end
|
||||
end
|
||||
text
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 3
|
||||
TINY = 6
|
||||
TINY = 14
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user