camping 1.5 → 1.5.180
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +29 -1
- data/lib/camping-unabridged.rb +33 -17
- data/lib/camping.rb +19 -16
- data/lib/camping/fastcgi.rb +109 -63
- data/lib/camping/reloader.rb +1 -7
- data/lib/camping/webrick.rb +1 -1
- data/test/test_xhtml_trans.rb +55 -0
- metadata +5 -4
data/Rakefile
CHANGED
|
@@ -2,13 +2,14 @@ require 'rake'
|
|
|
2
2
|
require 'rake/clean'
|
|
3
3
|
require 'rake/gempackagetask'
|
|
4
4
|
require 'rake/rdoctask'
|
|
5
|
+
require 'rake/testtask'
|
|
5
6
|
require 'fileutils'
|
|
6
7
|
include FileUtils
|
|
7
8
|
|
|
8
9
|
NAME = "camping"
|
|
9
10
|
REV = File.read(".svn/entries")[/committed-rev="(\d+)"/, 1] rescue nil
|
|
10
11
|
VERS = ENV['VERSION'] || ("1.5" + (REV ? ".#{REV}" : ""))
|
|
11
|
-
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
|
12
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config', 'test/test.log']
|
|
12
13
|
RDOC_OPTS = ['--quiet', '--title', "Camping, the Documentation",
|
|
13
14
|
"--opname", "index.html",
|
|
14
15
|
"--line-numbers",
|
|
@@ -74,11 +75,32 @@ spec =
|
|
|
74
75
|
s.bindir = "bin"
|
|
75
76
|
end
|
|
76
77
|
|
|
78
|
+
omni =
|
|
79
|
+
Gem::Specification.new do |s|
|
|
80
|
+
s.name = "camping-omnibus"
|
|
81
|
+
s.version = VERS
|
|
82
|
+
s.platform = Gem::Platform::RUBY
|
|
83
|
+
s.summary = "the camping meta-package for updating ActiveRecord, Mongrel and SQLite3 bindings"
|
|
84
|
+
s.description = s.summary
|
|
85
|
+
%w[author email homepage].each { |x| s.__send__("#{x}=", spec.__send__(x)) }
|
|
86
|
+
|
|
87
|
+
s.add_dependency('camping', "=#{VERS}")
|
|
88
|
+
s.add_dependency('activerecord')
|
|
89
|
+
s.add_dependency('sqlite3-ruby', '>=1.1.0.1')
|
|
90
|
+
s.add_dependency('mongrel')
|
|
91
|
+
s.add_dependency('acts_as_versioned')
|
|
92
|
+
s.add_dependency('RedCloth')
|
|
93
|
+
end
|
|
94
|
+
|
|
77
95
|
Rake::GemPackageTask.new(spec) do |p|
|
|
78
96
|
p.need_tar = true
|
|
79
97
|
p.gem_spec = spec
|
|
80
98
|
end
|
|
81
99
|
|
|
100
|
+
Rake::GemPackageTask.new(omni) do |p|
|
|
101
|
+
p.gem_spec = omni
|
|
102
|
+
end
|
|
103
|
+
|
|
82
104
|
task :install do
|
|
83
105
|
sh %{rake package}
|
|
84
106
|
sh %{sudo gem install pkg/#{NAME}-#{VERS}}
|
|
@@ -87,3 +109,9 @@ end
|
|
|
87
109
|
task :uninstall => [:clean] do
|
|
88
110
|
sh %{sudo gem uninstall #{NAME}}
|
|
89
111
|
end
|
|
112
|
+
|
|
113
|
+
Rake::TestTask.new(:test) do |t|
|
|
114
|
+
t.test_files = FileList['test/test_*.rb']
|
|
115
|
+
# t.warning = true
|
|
116
|
+
# t.verbose = true
|
|
117
|
+
end
|
data/lib/camping-unabridged.rb
CHANGED
|
@@ -203,10 +203,10 @@ module Camping
|
|
|
203
203
|
# </div>
|
|
204
204
|
#
|
|
205
205
|
def R(c,*g)
|
|
206
|
-
p=/\(.+?\)
|
|
207
|
-
g.inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|
|
|
206
|
+
p,h=/\(.+?\)/,g.grep(Hash)
|
|
207
|
+
(g-=h).inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|
|
|
208
208
|
s.sub p,C.escape((a[a.class.primary_key]rescue a))
|
|
209
|
-
}
|
|
209
|
+
}+(h.any?? "?"+h[0].map{|x|x.map{|z|C.escape z}*"="}*"&": "")
|
|
210
210
|
end
|
|
211
211
|
|
|
212
212
|
# Shows AR validation errors for the object passed.
|
|
@@ -337,7 +337,7 @@ module Camping
|
|
|
337
337
|
a.shift if a[0]==:render
|
|
338
338
|
m=Mab.new({},self)
|
|
339
339
|
s=m.capture{send(*a,&b)}
|
|
340
|
-
s=m.layout{s} if /^_/!~a[0].to_s and m.respond_to?:layout
|
|
340
|
+
s=m.capture{send(:layout){s}} if /^_/!~a[0].to_s and m.respond_to?:layout
|
|
341
341
|
s
|
|
342
342
|
end
|
|
343
343
|
|
|
@@ -368,12 +368,26 @@ module Camping
|
|
|
368
368
|
#
|
|
369
369
|
def r(s, b, h = {}); @status = s; @headers.merge!(h); @body = b; end
|
|
370
370
|
|
|
371
|
+
# Turn a controller into an array. This is designed to be used to pipe
|
|
372
|
+
# controllers into the <tt>r</tt> method. A great way to forward your
|
|
373
|
+
# requests!
|
|
374
|
+
#
|
|
375
|
+
# class Read < '/(\d+)'
|
|
376
|
+
# def get(id)
|
|
377
|
+
# Post.find(id)
|
|
378
|
+
# rescue
|
|
379
|
+
# r *Blog.get(:NotFound, @env.REQUEST_URI)
|
|
380
|
+
# end
|
|
381
|
+
# end
|
|
382
|
+
#
|
|
383
|
+
def to_a;[@status, @body, @headers] end
|
|
384
|
+
|
|
371
385
|
def initialize(r, e, m) #:nodoc:
|
|
372
386
|
e = H[e.to_hash]
|
|
373
387
|
@status, @method, @env, @headers, @root = 200, m.downcase, e,
|
|
374
388
|
{'Content-Type'=>'text/html'}, e.SCRIPT_NAME.sub(/\/$/,'')
|
|
375
389
|
@k = C.kp(e.HTTP_COOKIE)
|
|
376
|
-
qs = C.
|
|
390
|
+
qs = C.qsp(e.QUERY_STRING)
|
|
377
391
|
@in = r
|
|
378
392
|
if %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)|n.match(e.CONTENT_TYPE)
|
|
379
393
|
b = /(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/
|
|
@@ -404,11 +418,11 @@ module Camping
|
|
|
404
418
|
end
|
|
405
419
|
o<<l
|
|
406
420
|
end
|
|
407
|
-
|
|
421
|
+
C.qsp(fn,'&;',fh,qs) if fn
|
|
408
422
|
fh[:tempfile].rewind if fh.is_a?H
|
|
409
423
|
end
|
|
410
424
|
elsif @method == "post"
|
|
411
|
-
qs.merge!(C.
|
|
425
|
+
qs.merge!(C.qsp(@in.read))
|
|
412
426
|
end
|
|
413
427
|
@cookies, @input = @k.dup, qs.dup
|
|
414
428
|
end
|
|
@@ -427,7 +441,9 @@ module Camping
|
|
|
427
441
|
# Used by the web server to convert the current request to a string. If you need to
|
|
428
442
|
# alter the way Camping builds HTTP headers, consider overriding this method.
|
|
429
443
|
def to_s
|
|
430
|
-
|
|
444
|
+
a=[]
|
|
445
|
+
@headers.map{|k,v|[*v].map{|x|a<<"#{k}: #{x}"}}
|
|
446
|
+
"Status: #{@status}#{Z+a*Z+Z*2+@body}"
|
|
431
447
|
end
|
|
432
448
|
|
|
433
449
|
end
|
|
@@ -518,7 +534,7 @@ module Camping
|
|
|
518
534
|
end
|
|
519
535
|
constants.map { |c|
|
|
520
536
|
k=const_get(c)
|
|
521
|
-
k.send:include,C,Base,Models
|
|
537
|
+
k.send :include,C,Base,Models
|
|
522
538
|
r[0,0]=k if !r.include?k
|
|
523
539
|
k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls
|
|
524
540
|
}
|
|
@@ -614,28 +630,28 @@ module Camping
|
|
|
614
630
|
|
|
615
631
|
# Parses a query string into an Camping::H object.
|
|
616
632
|
#
|
|
617
|
-
# input = Camping.
|
|
633
|
+
# input = Camping.qsp("name=Philarp+Tremain&hair=sandy+blonde")
|
|
618
634
|
# input.name
|
|
619
635
|
# #=> "Philarp Tremaine"
|
|
620
636
|
#
|
|
621
637
|
# Also parses out the Hash-like syntax used in PHP and Rails and builds
|
|
622
638
|
# nested hashes from it.
|
|
623
639
|
#
|
|
624
|
-
# input = Camping.
|
|
640
|
+
# input = Camping.qsp("post[id]=1&post[user]=_why")
|
|
625
641
|
# #=> {'post' => {'id' => '1', 'user' => '_why'}}
|
|
626
642
|
#
|
|
627
|
-
def
|
|
643
|
+
def qsp(qs, d='&;', y=nil, z=H[])
|
|
628
644
|
m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)}
|
|
629
645
|
(qs||'').
|
|
630
646
|
split(/[#{d}] */n).
|
|
631
|
-
inject(H[]) { |h,p| k, v=un(p).split('=',2)
|
|
647
|
+
inject((b,z=z,H[])[0]) { |h,p| k, v=un(p).split('=',2)
|
|
632
648
|
h.u(k.split(/[\]\[]+/).reverse.
|
|
633
|
-
inject(v) { |x,i| H[i,x] },&m)
|
|
649
|
+
inject(y||v) { |x,i| H[i,x] },&m)
|
|
634
650
|
}
|
|
635
651
|
end
|
|
636
652
|
|
|
637
653
|
# Parses a string of cookies from the <tt>Cookie</tt> header.
|
|
638
|
-
def kp(s); c =
|
|
654
|
+
def kp(s); c = qsp(s, ';,'); end
|
|
639
655
|
|
|
640
656
|
# Fields a request through Camping. For traditional CGI applications, the method can be
|
|
641
657
|
# executed without arguments.
|
|
@@ -661,7 +677,7 @@ module Camping
|
|
|
661
677
|
X.M
|
|
662
678
|
k,a=X.D un("/#{e['PATH_INFO']}".gsub(/\/+/,'/'))
|
|
663
679
|
k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.service *a
|
|
664
|
-
rescue
|
|
680
|
+
rescue Object=>x
|
|
665
681
|
X::ServerError.new(r,e,'get').service(k,m,x)
|
|
666
682
|
end
|
|
667
683
|
|
|
@@ -718,7 +734,7 @@ module Camping
|
|
|
718
734
|
#
|
|
719
735
|
# Models cannot be referred to in Views at this time.
|
|
720
736
|
module Models
|
|
721
|
-
autoload:Base,'camping/db'
|
|
737
|
+
autoload :Base,'camping/db'
|
|
722
738
|
def Y;self;end
|
|
723
739
|
end
|
|
724
740
|
|
data/lib/camping.rb
CHANGED
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
%w[active_support markaby tempfile uri].map{|l|require l}
|
|
2
2
|
module Camping;Apps=[];C=self;S=IO.read(__FILE__).sub(/S=I.+$/,'')
|
|
3
|
-
P="Cam\ping Problem!";module Helpers;def R
|
|
4
|
-
urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|s.sub p,C.
|
|
5
|
-
a.class.primary_key]rescue a))}
|
|
3
|
+
P="Cam\ping Problem!";module Helpers;def R(c,*g);p,h=/\(.+?\)/,g.grep(Hash)
|
|
4
|
+
(g-=h).inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|s.sub p,C.
|
|
5
|
+
escape((a[a.class.primary_key]rescue a))}+(h.any?? "?"+h[0].map{|x|x.map{|z|C.
|
|
6
|
+
escape z}*"="}*"&": "")end;def URL c='/',*a;c=R(c,*a)if c.
|
|
6
7
|
respond_to?:urls;c=self/c;c="//"+@env.HTTP_HOST+c if c[/^\//];URI(c)end;def/p
|
|
7
8
|
p[/^\//]?@root+p : p end;def errors_for o;ul.errors{o.errors.each_full{|x|li x}
|
|
8
9
|
}if o.errors.any?end end;module Base;include Helpers;attr_accessor:input,
|
|
9
10
|
:cookies,:env,:headers,:body,:status,:root;def method_missing*a,&b
|
|
10
|
-
a.shift if a[0]==:render;m=Mab.new({},self);s=m.capture{send(*a,&b)}
|
|
11
|
-
/^_/!~a[0].to_s and m.respond_to?:layout
|
|
12
|
-
|
|
11
|
+
a.shift if a[0]==:render;m=Mab.new({},self);s=m.capture{send(*a,&b)}
|
|
12
|
+
s=m.capture{send(:layout){s}} if /^_/!~a[0].to_s and m.respond_to?:layout
|
|
13
|
+
s end;def r s,b,h={};@status=s;@headers.merge!h;@body=b end
|
|
14
|
+
def redirect*a;r 302,'','Location'=>URL(*a)end;Z="\r\n"
|
|
15
|
+
def to_a;[@status,@body,@headers]end
|
|
13
16
|
def initialize r,e,m;e=H[e.to_hash];@status,@method,@env,@headers,@root=200,m.
|
|
14
17
|
downcase,e,{'Content-Type'=>"text/html"},e.SCRIPT_NAME.sub(/\/$/,'')
|
|
15
|
-
@k=C.kp e.HTTP_COOKIE;q=C.
|
|
18
|
+
@k=C.kp e.HTTP_COOKIE;q=C.qsp e.QUERY_STRING;@in=r
|
|
16
19
|
if%r|\Amultipart/form-.*boundary=\"?([^\";,]+)|n.match e.CONTENT_TYPE
|
|
17
20
|
b=/(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/;until@in.eof?;fh=H[];for l in@in
|
|
18
21
|
case l;when Z;break;when/^Content-D.+?: form-data;/;fh.u H[*$'.
|
|
19
22
|
scan(/(?:\s(\w+)="([^"]+)")/).flatten];when/^Content-Type: (.+?)(\r$|\Z)/m;fh[
|
|
20
23
|
:type]=$1;end;end;fn=fh[:name];o=if fh[:filename];o=fh[:tempfile]=Tempfile.new(:C)
|
|
21
24
|
o.binmode;else;fh=""end;while l=@in.read(16384);if l=~b;o<<$`.chomp;@in.seek(-$'.
|
|
22
|
-
size,IO::SEEK_CUR);break;end;o<<l;end;
|
|
23
|
-
fh.is_a?H;end;elsif@method=="post";q.u C.
|
|
25
|
+
size,IO::SEEK_CUR);break;end;o<<l;end;C.qsp(fn,'&;',fh,q) if fn;fh[:tempfile].rewind if
|
|
26
|
+
fh.is_a?H;end;elsif@method=="post";q.u C.qsp(@in.read)end;@cookies,@input=
|
|
24
27
|
@k.dup,q.dup end;def service*a;@body=send(@method,*a)if respond_to?@method
|
|
25
28
|
@headers["Set-Cookie"]=@cookies.map{|k,v|"#{k}=#{C.escape(v)}; path=#{self/'/'
|
|
26
|
-
}"if v!=@k[k]}-[nil];self end;def to_s;
|
|
27
|
-
|
|
29
|
+
}"if v!=@k[k]}-[nil];self end;def to_s;a=[];@headers.map{|k,v|[*v].map{|x|a<<
|
|
30
|
+
"#{k}: #{x}"}};"Status: #{@status}#{Z+a*Z+Z*2+@body}"end;end
|
|
28
31
|
X=module Controllers;@r=[];class<<self;def r;@r;end;def R*u;r=@r;Class.new{
|
|
29
32
|
meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def M;def M;end;constants.map{|c|
|
|
30
33
|
k=const_get(c);k.send:include,C,Base,Models;r[0,0]=k if !r.include?k;k.meta_def(
|
|
@@ -36,12 +39,12 @@ ServerError<R();def get k,m,e;r(500,Mab.new{h1 P;h2"#{k}.#{m}";h3"#{e.class
|
|
|
36
39
|
self;def goes m;eval S.gsub(/Camping/,m.to_s).gsub("A\pps=[]","Cam\ping::Apps<<\
|
|
37
40
|
self"),TOPLEVEL_BINDING;end;def escape s;s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.
|
|
38
41
|
unpack('H2'*$&.size)*'%').upcase}.tr(' ','+')end;def un s;s.tr('+',' ').gsub(
|
|
39
|
-
/%([\da-f]{2})/in){[$1].pack('H*')}end;def
|
|
40
|
-
n,&m)rescue([*o]<<n)};q.to_s.split(/[#{d}] */n).inject(H[]){|h,p|k,v=un(p).
|
|
41
|
-
split('=',2);h.u k.split(/[\]\[]+/).reverse.inject(v){|x,i|H[i,x]},&m}end;def
|
|
42
|
-
kp s;c=
|
|
42
|
+
/%([\da-f]{2})/in){[$1].pack('H*')}end;def qsp q,d='&;',y=nil,z=H[];m=proc{|_,o,n|o.u(
|
|
43
|
+
n,&m)rescue([*o]<<n)};q.to_s.split(/[#{d}] */n).inject((b,z=z,H[])[0]){|h,p|k,v=un(p).
|
|
44
|
+
split('=',2);h.u k.split(/[\]\[]+/).reverse.inject(y||v){|x,i|H[i,x]},&m}end;def
|
|
45
|
+
kp s;c=qsp(s,';,')end;def run r=$stdin,e=ENV;X.M;k,a=X.D un("/#{e[
|
|
43
46
|
'PATH_INFO']}".gsub(/\/+/,'/'));k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.
|
|
44
|
-
service *a;rescue
|
|
47
|
+
service *a;rescue Object=>x;X::ServerError.new(r,e,'get').service(k,m,x)end
|
|
45
48
|
def method_missing m,c,*a;X.M;k=X.const_get(c).new(StringIO.new,H['HTTP_HOST',
|
|
46
49
|
'','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s);H.new(a.pop).each{|e,f|k.send(
|
|
47
50
|
"#{e}=",f)}if Hash===a[-1];k.service *a;end;end;module Views;include X,Helpers
|
data/lib/camping/fastcgi.rb
CHANGED
|
@@ -58,6 +58,8 @@ module Camping
|
|
|
58
58
|
class FastCGI
|
|
59
59
|
CHUNK_SIZE=(4 * 1024)
|
|
60
60
|
|
|
61
|
+
attr_reader :mounts
|
|
62
|
+
|
|
61
63
|
# Creates a Camping::FastCGI class with empty mounts.
|
|
62
64
|
def initialize
|
|
63
65
|
@mounts = {}
|
|
@@ -69,71 +71,12 @@ class FastCGI
|
|
|
69
71
|
dir.gsub!(/\/+$/, '')
|
|
70
72
|
@mounts[dir] = app
|
|
71
73
|
end
|
|
74
|
+
|
|
72
75
|
#
|
|
73
76
|
# Starts the FastCGI main loop.
|
|
74
|
-
def start
|
|
77
|
+
def start(&blk)
|
|
75
78
|
FCGI.each do |req|
|
|
76
|
-
|
|
77
|
-
begin
|
|
78
|
-
root, path = "/"
|
|
79
|
-
if ENV['FORCE_ROOT'] and ENV['FORCE_ROOT'].to_i == 1
|
|
80
|
-
path = req.env['REQUEST_URI']
|
|
81
|
-
else
|
|
82
|
-
root = req.env['SCRIPT_NAME']
|
|
83
|
-
path = req.env['PATH_INFO']
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
dir, app = @mounts.max { |a,b| match(path, a[0]) <=> match(path, b[0]) }
|
|
87
|
-
unless dir and app
|
|
88
|
-
dir, app = '/', Camping
|
|
89
|
-
end
|
|
90
|
-
yield dir, app if block_given?
|
|
91
|
-
|
|
92
|
-
req.env['SERVER_SCRIPT_NAME'] = req.env['SCRIPT_NAME']
|
|
93
|
-
req.env['SERVER_PATH_INFO'] = req.env['PATH_INFO']
|
|
94
|
-
req.env['SCRIPT_NAME'] = File.join(root, dir)
|
|
95
|
-
req.env['PATH_INFO'] = path.gsub(/^#{dir}/, '')
|
|
96
|
-
|
|
97
|
-
controller = app.run(req.in, req.env)
|
|
98
|
-
sendfile = nil
|
|
99
|
-
headers = {}
|
|
100
|
-
controller.headers.each do |k, v|
|
|
101
|
-
if k =~ /^X-SENDFILE$/i and !ENV['SERVER_X_SENDFILE']
|
|
102
|
-
sendfile = v
|
|
103
|
-
else
|
|
104
|
-
headers[k] = v
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
body = controller.body
|
|
109
|
-
controller.body = ""
|
|
110
|
-
controller.headers = headers
|
|
111
|
-
|
|
112
|
-
req.out << controller.to_s
|
|
113
|
-
if sendfile
|
|
114
|
-
File.open(sendfile, "rb") do |f|
|
|
115
|
-
while chunk = f.read(CHUNK_SIZE) and chunk.length > 0
|
|
116
|
-
req.out << chunk
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
elsif body.respond_to? :read
|
|
120
|
-
while chunk = body.read(CHUNK_SIZE) and chunk.length > 0
|
|
121
|
-
req.out << chunk
|
|
122
|
-
end
|
|
123
|
-
body.close if body.respond_to? :close
|
|
124
|
-
else
|
|
125
|
-
req.out << body.to_s
|
|
126
|
-
end
|
|
127
|
-
rescue Exception => e
|
|
128
|
-
req.out << "Content-Type: text/html\r\n\r\n" +
|
|
129
|
-
"<h1>Camping Problem!</h1>" +
|
|
130
|
-
"<h2><strong>#{root}</strong>#{path}</h2>" +
|
|
131
|
-
"<h3>#{e.class} #{esc e.message}</h3>" +
|
|
132
|
-
"<ul>" + e.backtrace.map { |bt| "<li>#{esc bt}</li>" }.join + "</ul>" +
|
|
133
|
-
"<hr /><p>#{req.env.inspect}</p>"
|
|
134
|
-
ensure
|
|
135
|
-
req.finish
|
|
136
|
-
end
|
|
79
|
+
camp_do(req, &blk)
|
|
137
80
|
end
|
|
138
81
|
end
|
|
139
82
|
|
|
@@ -173,7 +116,7 @@ class FastCGI
|
|
|
173
116
|
fast.start do |dir, app|
|
|
174
117
|
Dir[File.join(path, dir, '*.rb')].each do |script|
|
|
175
118
|
smount = "/" + File.basename(script, '.rb')
|
|
176
|
-
script_load[script] unless
|
|
119
|
+
script_load[script] unless fast.mounts.has_key? smount
|
|
177
120
|
end
|
|
178
121
|
end
|
|
179
122
|
else
|
|
@@ -183,6 +126,71 @@ class FastCGI
|
|
|
183
126
|
|
|
184
127
|
private
|
|
185
128
|
|
|
129
|
+
def camp_do(req)
|
|
130
|
+
root, path, dir, app = "/"
|
|
131
|
+
if ENV['FORCE_ROOT'] and ENV['FORCE_ROOT'].to_i == 1
|
|
132
|
+
path = req.env['SCRIPT_NAME']
|
|
133
|
+
else
|
|
134
|
+
root = req.env['SCRIPT_NAME']
|
|
135
|
+
path = req.env['PATH_INFO']
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
dir, app = @mounts.max { |a,b| match(path, a[0]) <=> match(path, b[0]) }
|
|
139
|
+
unless dir and app
|
|
140
|
+
dir, app = '/', Camping
|
|
141
|
+
end
|
|
142
|
+
yield dir, app if block_given?
|
|
143
|
+
|
|
144
|
+
req.env['SERVER_SCRIPT_NAME'] = req.env['SCRIPT_NAME']
|
|
145
|
+
req.env['SERVER_PATH_INFO'] = req.env['PATH_INFO']
|
|
146
|
+
req.env['SCRIPT_NAME'] = File.join(root, dir)
|
|
147
|
+
req.env['PATH_INFO'] = path.gsub(/^#{dir}/, '')
|
|
148
|
+
|
|
149
|
+
controller = app.run(SeekStream.new(req.in), req.env)
|
|
150
|
+
sendfile = nil
|
|
151
|
+
headers = {}
|
|
152
|
+
controller.headers.each do |k, v|
|
|
153
|
+
if k =~ /^X-SENDFILE$/i and !ENV['SERVER_X_SENDFILE']
|
|
154
|
+
sendfile = v
|
|
155
|
+
else
|
|
156
|
+
headers[k] = v
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
body = controller.body
|
|
161
|
+
controller.body = ""
|
|
162
|
+
controller.headers = headers
|
|
163
|
+
|
|
164
|
+
req.out << controller.to_s
|
|
165
|
+
if sendfile
|
|
166
|
+
File.open(sendfile, "rb") do |f|
|
|
167
|
+
while chunk = f.read(CHUNK_SIZE) and chunk.length > 0
|
|
168
|
+
req.out << chunk
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
elsif body.respond_to? :read
|
|
172
|
+
while chunk = body.read(CHUNK_SIZE) and chunk.length > 0
|
|
173
|
+
req.out << chunk
|
|
174
|
+
end
|
|
175
|
+
body.close if body.respond_to? :close
|
|
176
|
+
else
|
|
177
|
+
req.out << body.to_s
|
|
178
|
+
end
|
|
179
|
+
rescue Exception => e
|
|
180
|
+
req.out << server_error(root, path, exc, req)
|
|
181
|
+
ensure
|
|
182
|
+
req.finish
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def server_error(root, path, exc, req)
|
|
186
|
+
"Content-Type: text/html\r\n\r\n" +
|
|
187
|
+
"<h1>Camping Problem!</h1>" +
|
|
188
|
+
"<h2><strong>#{root}</strong>#{path}</h2>" +
|
|
189
|
+
"<h3>#{exc.class} #{esc exc.message}</h3>" +
|
|
190
|
+
"<ul>" + exc.backtrace.map { |bt| "<li>#{esc bt}</li>" }.join + "</ul>" +
|
|
191
|
+
"<hr /><p>#{req.env.inspect}</p>"
|
|
192
|
+
end
|
|
193
|
+
|
|
186
194
|
def match(path, mount)
|
|
187
195
|
m = path.match(/^#{Regexp::quote mount}(\/|$)/)
|
|
188
196
|
if m; m.end(0)
|
|
@@ -194,5 +202,43 @@ class FastCGI
|
|
|
194
202
|
str.gsub(/&/n, '&').gsub(/\"/n, '"').gsub(/>/n, '>').gsub(/</n, '<')
|
|
195
203
|
end
|
|
196
204
|
|
|
205
|
+
class SeekStream
|
|
206
|
+
def initialize(stream)
|
|
207
|
+
@last_read = ""
|
|
208
|
+
@stream = stream
|
|
209
|
+
@buffer = ""
|
|
210
|
+
end
|
|
211
|
+
def eof?
|
|
212
|
+
@buffer.empty? && @stream.eof?
|
|
213
|
+
end
|
|
214
|
+
def each
|
|
215
|
+
while true
|
|
216
|
+
pull(1024) until eof? or @buffer.index("\n")
|
|
217
|
+
return nil if eof?
|
|
218
|
+
yield @buffer.slice!(0..(@buffer.index("\n") || -1))
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
def pull(len)
|
|
222
|
+
@buffer += @stream.read(len).to_s
|
|
223
|
+
end
|
|
224
|
+
def read(len = 16384)
|
|
225
|
+
pull(len)
|
|
226
|
+
@last_read =
|
|
227
|
+
if eof?
|
|
228
|
+
nil
|
|
229
|
+
else
|
|
230
|
+
@buffer.slice!(0...len)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
def seek(len, typ)
|
|
234
|
+
raise NotImplementedError, "only IO::SEEK_CUR is supported with SeekStream" if typ != IO::SEEK_CUR
|
|
235
|
+
raise NotImplementedError, "only rewinding is supported with SeekStream" if len > 0
|
|
236
|
+
raise NotImplementedError, "rewinding #{-len} past the buffer #{@last_read.size} start not supported with SeekStream" if -len > @last_read.size
|
|
237
|
+
@buffer = @last_read[len..-1] + @buffer
|
|
238
|
+
@last_read = ""
|
|
239
|
+
self
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
197
243
|
end
|
|
198
244
|
end
|
data/lib/camping/reloader.rb
CHANGED
|
@@ -146,13 +146,7 @@ class Reloader
|
|
|
146
146
|
Camping::Models::Base.logger = Logger.new(@log == "-" ? STDOUT : @log)
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
Camping::Models::Session.create_schema
|
|
151
|
-
rescue MissingSourceFile
|
|
152
|
-
puts "** #$0 stopped: SQLite3 not found, please install."
|
|
153
|
-
puts "** See http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for instructions."
|
|
154
|
-
exit
|
|
155
|
-
end
|
|
149
|
+
Camping::Models::Session.create_schema
|
|
156
150
|
|
|
157
151
|
if @database and @database[:adapter] == 'sqlite3'
|
|
158
152
|
begin
|
data/lib/camping/webrick.rb
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require 'mosquito'
|
|
2
|
+
|
|
3
|
+
Camping.goes :XhtmlTrans
|
|
4
|
+
|
|
5
|
+
module XhtmlTrans
|
|
6
|
+
module Controllers
|
|
7
|
+
class WithLayout < R '/with_layout'
|
|
8
|
+
def get
|
|
9
|
+
render :with_layout
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class WithoutLayout < R '/without_layout'
|
|
14
|
+
def get
|
|
15
|
+
render :_without_layout
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module Views
|
|
21
|
+
def layout
|
|
22
|
+
xhtml_transitional do
|
|
23
|
+
head do title "title" end
|
|
24
|
+
body do capture { yield } end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def with_layout
|
|
29
|
+
h1 "With layout"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def _without_layout
|
|
33
|
+
xhtml_transitional do
|
|
34
|
+
head do title "title" end
|
|
35
|
+
body do h1 "Without layout" end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class XhtmlTransTest < Camping::FunctionalTest
|
|
42
|
+
def test_with_layout
|
|
43
|
+
get '/with_layout'
|
|
44
|
+
|
|
45
|
+
assert(@response.body =~ /DOCTYPE/, "No doctype defined")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_without_layout
|
|
49
|
+
get '/without_layout'
|
|
50
|
+
|
|
51
|
+
assert(@response.body =~ /DOCTYPE/, "No doctype defined")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
metadata
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
|
-
rubygems_version: 0.9.0.
|
|
2
|
+
rubygems_version: 0.9.0.8
|
|
3
3
|
specification_version: 1
|
|
4
4
|
name: camping
|
|
5
5
|
version: !ruby/object:Gem::Version
|
|
6
|
-
version:
|
|
7
|
-
date:
|
|
6
|
+
version: 1.5.180
|
|
7
|
+
date: 2007-01-06 00:00:00 -07:00
|
|
8
8
|
summary: minature rails for stay-at-home moms
|
|
9
9
|
require_paths:
|
|
10
10
|
- lib
|
|
@@ -34,6 +34,7 @@ files:
|
|
|
34
34
|
- Rakefile
|
|
35
35
|
- bin/camping
|
|
36
36
|
- doc/camping.1.gz
|
|
37
|
+
- test/test_xhtml_trans.rb
|
|
37
38
|
- lib/camping
|
|
38
39
|
- lib/camping.rb
|
|
39
40
|
- lib/camping-unabridged.rb
|
|
@@ -45,9 +46,9 @@ files:
|
|
|
45
46
|
- extras/permalink.gif
|
|
46
47
|
- extras/Camping.gif
|
|
47
48
|
- extras/flipbook_rdoc.rb
|
|
49
|
+
- examples/campsh.rb
|
|
48
50
|
- examples/tepee.rb
|
|
49
51
|
- examples/blog.rb
|
|
50
|
-
- examples/campsh.rb
|
|
51
52
|
- CHANGELOG
|
|
52
53
|
test_files: []
|
|
53
54
|
|