rubycas-server 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,55 +0,0 @@
1
- %w[active_support markaby tempfile uri].map{|l|require l}
2
- module Camping;Apps=[];C=self;S=IO.read(__FILE__).sub(/S=I.+$/,'')
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.
7
- respond_to?:urls;c=self/c;c="//"+@env.HTTP_HOST+c if c[/^\//];URI(c)end;def/p
8
- p[/^\//]?@root+p : p end;def errors_for o;ul.errors{o.errors.each_full{|x|li x}
9
- }if o.errors.any?end end;module Base;include Helpers;attr_accessor:input,
10
- :cookies,:env,:headers,:body,:status,:root;def method_missing*a,&b
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
16
- def initialize r,e,m;e=H[e.to_hash];@status,@method,@env,@headers,@root=200,m.
17
- downcase,e,{'Content-Type'=>"text/html"},e.SCRIPT_NAME.sub(/\/$/,'')
18
- @k=C.kp e.HTTP_COOKIE;q=C.qsp e.QUERY_STRING;@in=r
19
- if%r|\Amultipart/form-.*boundary=\"?([^\";,]+)|n.match e.CONTENT_TYPE
20
- b=/(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/;until@in.eof?;fh=H[];for l in@in
21
- case l;when Z;break;when/^Content-D.+?: form-data;/;fh.u H[*$'.
22
- scan(/(?:\s(\w+)="([^"]+)")/).flatten];when/^Content-Type: (.+?)(\r$|\Z)/m;fh[
23
- :type]=$1;end;end;fn=fh[:name];o=if fh[:filename];o=fh[:tempfile]=Tempfile.new(:C)
24
- o.binmode;else;fh=""end;while l=@in.read(16384);if l=~b;o<<$`.chomp;@in.seek(-$'.
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=
27
- @k.dup,q.dup end;def service*a;@body=send(@method,*a)if respond_to?@method
28
- @headers["Set-Cookie"]=@cookies.map{|k,v|"#{k}=#{C.escape(v)}; path=#{self/'/'
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
31
- X=module Controllers;@r=[];class<<self;def r;@r;end;def R*u;r=@r;Class.new{
32
- meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def M;def M;end;constants.map{|c|
33
- k=const_get(c);k.send:include,C,Base,Models;r[0,0]=k if !r.include?k;k.meta_def(
34
- :urls){["/#{c.downcase}"]}if !k.respond_to?:urls}end;def D p;r.map{|k|k.urls.
35
- map{|x|return k,$~[1..-1]if p=~/^#{x}\/?$/}};[NotFound,[p]]end end;class
36
- NotFound<R();def get p;r(404,Mab.new{h1 P;h2 p+" not found"})end end;class
37
- ServerError<R();def get k,m,e;r(500,Mab.new{h1 P;h2"#{k}.#{m}";h3"#{e.class
38
- } #{e.message}:";ul{e.backtrace.each{|bt|li(bt)}}}.to_s)end end;self;end;class<<
39
- self;def goes m;eval S.gsub(/Camping/,m.to_s).gsub("A\pps=[]","Cam\ping::Apps<<\
40
- self"),TOPLEVEL_BINDING;end;def escape s;s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.
41
- unpack('H2'*$&.size)*'%').upcase}.tr(' ','+')end;def un s;s.tr('+',' ').gsub(
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[
46
- 'PATH_INFO']}".gsub(/\/+/,'/'));k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.
47
- service *a;rescue Object=>x;X::ServerError.new(r,e,'get').service(k,m,x)end
48
- def method_missing m,c,*a;X.M;k=X.const_get(c).new(StringIO.new,H['HTTP_HOST',
49
- '','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s);H.new(a.pop).each{|e,f|k.send(
50
- "#{e}=",f)}if Hash===a[-1];k.service *a;end;end;module Views;include X,Helpers
51
- end;module Models;autoload:Base,'camping/db';def Y;self;end;end;class Mab<Markaby::Builder
52
- include Views;def tag!*g,&b;h=g[-1];[:href,:action,:src].map{|a|(h[a]=self/h[a])rescue
53
- 0};super end end;H=HashWithIndifferentAccess;class H;def method_missing m,*a
54
- m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m]:raise(NoMethodError,"#{m}")end
55
- alias_method:u,:regular_update;end end
@@ -1,78 +0,0 @@
1
- class MissingLibrary < Exception #:nodoc: all
2
- end
3
- begin
4
- require 'active_record'
5
- rescue LoadError => e
6
- raise MissingLibrary, "ActiveRecord could not be loaded (is it installed?): #{e.message}"
7
- end
8
-
9
- $AR_EXTRAS = %{
10
- Base = ActiveRecord::Base unless const_defined? :Base
11
-
12
- def Y; ActiveRecord::Base.verify_active_connections!; self; end
13
-
14
- class SchemaInfo < Base
15
- end
16
-
17
- def self.V(n)
18
- @final = [n, @final.to_i].max
19
- m = (@migrations ||= [])
20
- Class.new(ActiveRecord::Migration) do
21
- meta_def(:version) { n }
22
- meta_def(:inherited) { |k| m << k }
23
- end
24
- end
25
-
26
- def self.create_schema(opts = {})
27
- opts[:assume] ||= 0
28
- opts[:version] ||= @final
29
- if @migrations
30
- unless SchemaInfo.table_exists?
31
- ActiveRecord::Schema.define do
32
- create_table SchemaInfo.table_name do |t|
33
- t.column :version, :float
34
- end
35
- end
36
- end
37
-
38
- si = SchemaInfo.find(:first) || SchemaInfo.new(:version => opts[:assume])
39
- if si.version < opts[:version]
40
- @migrations.each do |k|
41
- k.migrate(:up) if si.version < k.version and k.version <= opts[:version]
42
- k.migrate(:down) if si.version > k.version and k.version > opts[:version]
43
- end
44
- si.update_attributes(:version => opts[:version])
45
- end
46
- end
47
- end
48
- }
49
-
50
- module Camping
51
- module Models
52
- A = ActiveRecord
53
- # Base is an alias for ActiveRecord::Base. The big warning I'm going to give you
54
- # about this: *Base overloads table_name_prefix.* This means that if you have a
55
- # model class Blog::Models::Post, it's table name will be <tt>blog_posts</tt>.
56
- #
57
- # ActiveRecord is not loaded if you never reference this class. The minute you
58
- # use the ActiveRecord or Camping::Models::Base class, then the ActiveRecord library
59
- # is loaded.
60
- Base = A::Base
61
-
62
- # The default prefix for Camping model classes is the topmost module name lowercase
63
- # and followed with an underscore.
64
- #
65
- # Tepee::Models::Page.table_name_prefix
66
- # #=> "tepee_pages"
67
- #
68
- def Base.table_name_prefix
69
- "#{name[/\w+/]}_".downcase.sub(/^(#{A}|camping)_/i,'')
70
- end
71
- module_eval $AR_EXTRAS
72
- end
73
- end
74
- Camping::S.sub! "autoload:Base,'camping/db'", ""
75
- Camping::S.sub! "def Y;self;end", $AR_EXTRAS
76
- Camping::Apps.each do |app|
77
- app::Models.module_eval $AR_EXTRAS
78
- end
@@ -1,244 +0,0 @@
1
- # == About camping/fastcgi.rb
2
- #
3
- # Camping works very well with FastCGI, since your application is only loaded
4
- # once -- when FastCGI starts. In addition, this class lets you mount several
5
- # Camping apps under a single FastCGI process, to help save memory costs.
6
- #
7
- # So where do you use the Camping::FastCGI class? Use it in your application's
8
- # postamble and then you can point your web server directly at your application.
9
- # See Camping::FastCGI docs for more.
10
- require 'camping'
11
- require 'fcgi'
12
-
13
- module Camping
14
- # Camping::FastCGI is a small class for hooking one or more Camping apps up to
15
- # FastCGI. Generally, you'll use this class in your application's postamble.
16
- #
17
- # == The Smallest Example
18
- #
19
- # if __FILE__ == $0
20
- # require 'camping/fastcgi'
21
- # Camping::FastCGI.start(YourApp)
22
- # end
23
- #
24
- # This example is stripped down to the basics. The postamble has no database
25
- # connection. It just loads this class and calls Camping::FastCGI.start.
26
- #
27
- # Now, in Lighttpd or Apache, you can point to your app's file, which will
28
- # be executed, only to discover that your app now speaks the FastCGI protocol.
29
- #
30
- # Here's a sample lighttpd.conf (tested with Lighttpd 1.4.11) to serve as example:
31
- #
32
- # server.port = 3044
33
- # server.bind = "127.0.0.1"
34
- # server.modules = ( "mod_fastcgi" )
35
- # server.document-root = "/var/www/camping/blog/"
36
- # server.errorlog = "/var/www/camping/blog/error.log"
37
- #
38
- # #### fastcgi module
39
- # fastcgi.server = ( "/" => (
40
- # "localhost" => (
41
- # "socket" => "/tmp/camping-blog.socket",
42
- # "bin-path" => "/var/www/camping/blog/blog.rb",
43
- # "check-local" => "disable",
44
- # "max-procs" => 1 ) ) )
45
- #
46
- # The file <tt>/var/www/camping/blog/blog.rb</tt> is the Camping app with
47
- # the postamble.
48
- #
49
- # == Mounting Many Apps
50
- #
51
- # require 'camping/fastcgi'
52
- # fast = Camping::FastCGI.new
53
- # fast.mount("/blog", Blog)
54
- # fast.mount("/tepee", Tepee)
55
- # fast.mount("/", Index)
56
- # fast.start
57
- #
58
- class FastCGI
59
- CHUNK_SIZE=(4 * 1024)
60
-
61
- attr_reader :mounts
62
-
63
- # Creates a Camping::FastCGI class with empty mounts.
64
- def initialize
65
- @mounts = {}
66
- end
67
- # Mounts a Camping application. The +dir+ being the name of the directory
68
- # to serve as the application's root. The +app+ is a Camping class.
69
- def mount(dir, app)
70
- dir.gsub!(/\/{2,}/, '/')
71
- dir.gsub!(/\/+$/, '')
72
- @mounts[dir] = app
73
- end
74
-
75
- #
76
- # Starts the FastCGI main loop.
77
- def start(&blk)
78
- FCGI.each do |req|
79
- camp_do(req, &blk)
80
- end
81
- end
82
-
83
- # A simple single-app starter mechanism
84
- #
85
- # Camping::FastCGI.start(Blog)
86
- #
87
- def self.start(app)
88
- cf = Camping::FastCGI.new
89
- cf.mount("/", app)
90
- cf.start
91
- end
92
-
93
- # Serve an entire directory of Camping apps. (See
94
- # http://code.whytheluckystiff.net/camping/wiki/TheCampingServer.)
95
- #
96
- # Use this method inside your FastCGI dispatcher:
97
- #
98
- # #!/usr/local/bin/ruby
99
- # require 'rubygems'
100
- # require 'camping/fastcgi'
101
- # Camping::Models::Base.establish_connection :adapter => 'sqlite3', :database => "/path/to/db"
102
- # Camping::FastCGI.serve("/home/why/cvs/camping/examples")
103
- #
104
- def self.serve(path, index=nil)
105
- require 'camping/reloader'
106
- if File.directory? path
107
- fast = Camping::FastCGI.new
108
- script_load = proc do |script|
109
- app = Camping::Reloader.new(script)
110
- fast.mount("/#{app.mount}", app)
111
- app
112
- end
113
- Dir[File.join(path, '*.rb')].each &script_load
114
- fast.mount("/", index) if index
115
-
116
- fast.start do |dir, app|
117
- Dir[File.join(path, dir, '*.rb')].each do |script|
118
- smount = "/" + File.basename(script, '.rb')
119
- script_load[script] unless fast.mounts.has_key? smount
120
- end
121
- end
122
- else
123
- start(Camping::Reloader.new(path))
124
- end
125
- end
126
-
127
- private
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
-
194
- def match(path, mount)
195
- m = path.match(/^#{Regexp::quote mount}(\/|$)/)
196
- if m; m.end(0)
197
- else -1
198
- end
199
- end
200
-
201
- def esc(str)
202
- str.gsub(/&/n, '&amp;').gsub(/\"/n, '&quot;').gsub(/>/n, '&gt;').gsub(/</n, '&lt;')
203
- end
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
-
243
- end
244
- end
@@ -1,163 +0,0 @@
1
- module Camping
2
- # == The Camping Reloader
3
- #
4
- # Camping apps are generally small and predictable. Many Camping apps are
5
- # contained within a single file. Larger apps are split into a handful of
6
- # other Ruby libraries within the same directory.
7
- #
8
- # Since Camping apps (and their dependencies) are loaded with Ruby's require
9
- # method, there is a record of them in $LOADED_FEATURES. Which leaves a
10
- # perfect space for this class to manage auto-reloading an app if any of its
11
- # immediate dependencies changes.
12
- #
13
- # == Wrapping Your Apps
14
- #
15
- # Since bin/camping and the Camping::FastCGI class already use the Reloader,
16
- # you probably don't need to hack it on your own. But, if you're rolling your
17
- # own situation, here's how.
18
- #
19
- # Rather than this:
20
- #
21
- # require 'yourapp'
22
- #
23
- # Use this:
24
- #
25
- # require 'camping/reloader'
26
- # Camping::Reloader.new('/path/to/yourapp.rb')
27
- #
28
- # The reloader will take care of requiring the app and monitoring all files
29
- # for alterations.
30
- class Reloader
31
- attr_accessor :klass, :mtime, :mount, :requires
32
-
33
- # Creates the reloader, assigns a +script+ to it and initially loads the
34
- # application. Pass in the full path to the script, otherwise the script
35
- # will be loaded relative to the current working directory.
36
- def initialize(script)
37
- @script = File.expand_path(script)
38
- @mount = File.basename(script, '.rb')
39
- @requires = nil
40
- load_app
41
- end
42
-
43
- # Find the application, based on the script name.
44
- def find_app(title)
45
- @klass = Object.const_get(Object.constants.grep(/^#{title}$/i)[0]) rescue nil
46
- end
47
-
48
- # If the file isn't found, if we need to remove the app from the global
49
- # namespace, this will be sure to do so and set @klass to nil.
50
- def remove_app
51
- Object.send :remove_const, @klass.name if @klass
52
- @klass = nil
53
- end
54
-
55
- # Loads (or reloads) the application. The reloader will take care of calling
56
- # this for you. You can certainly call it yourself if you feel it's warranted.
57
- def load_app
58
- title = File.basename(@script)[/^([\w_]+)/,1].gsub /_/,''
59
- begin
60
- all_requires = $LOADED_FEATURES.dup
61
- load @script
62
- @requires = ($LOADED_FEATURES - all_requires).select do |req|
63
- req.index(File.basename(@script) + "/") == 0 || req.index(title + "/") == 0
64
- end
65
- rescue Exception => e
66
- puts "!! trouble loading #{title}: [#{e.class}] #{e.message}"
67
- puts e.backtrace.join("\n")
68
- find_app title
69
- remove_app
70
- return
71
- end
72
-
73
- @mtime = mtime
74
- find_app title
75
- unless @klass and @klass.const_defined? :C
76
- puts "!! trouble loading #{title}: not a Camping app, no #{title.capitalize} module found"
77
- remove_app
78
- return
79
- end
80
-
81
- Reloader.conditional_connect
82
- @klass.create if @klass.respond_to? :create
83
- @klass
84
- end
85
-
86
- # The timestamp of the most recently modified app dependency.
87
- def mtime
88
- ((@requires || []) + [@script]).map do |fname|
89
- fname = fname.gsub(/^#{Regexp::quote File.dirname(@script)}\//, '')
90
- begin
91
- File.mtime(File.join(File.dirname(@script), fname))
92
- rescue Errno::ENOENT
93
- remove_app
94
- @mtime
95
- end
96
- end.max
97
- end
98
-
99
- # Conditional reloading of the app. This gets called on each request and
100
- # only reloads if the modification times on any of the files is updated.
101
- def reload_app
102
- return if @klass and @mtime and mtime <= @mtime
103
-
104
- if @requires
105
- @requires.each { |req| $LOADED_FEATURES.delete(req) }
106
- end
107
- k = @klass
108
- Object.send :remove_const, k.name if k
109
- load_app
110
- end
111
-
112
- # Conditionally reloads (using reload_app.) Then passes the request through
113
- # to the wrapped Camping app.
114
- def run(*a)
115
- reload_app
116
- if @klass
117
- @klass.run(*a)
118
- else
119
- Camping.run(*a)
120
- end
121
- end
122
-
123
- # Returns source code for the main script in the application.
124
- def view_source
125
- File.read(@script)
126
- end
127
-
128
- class << self
129
- def database=(db)
130
- @database = db
131
- end
132
- def log=(log)
133
- @log = log
134
- end
135
- def conditional_connect
136
- # If database models are present, `autoload?` will return nil.
137
- unless Camping::Models.autoload? :Base
138
- require 'logger'
139
- require 'camping/session'
140
- Camping::Models::Base.establish_connection @database if @database
141
-
142
- case @log
143
- when Logger
144
- Camping::Models::Base.logger = @log
145
- when String
146
- Camping::Models::Base.logger = Logger.new(@log == "-" ? STDOUT : @log)
147
- end
148
-
149
- Camping::Models::Session.create_schema
150
-
151
- if @database and @database[:adapter] == 'sqlite3'
152
- begin
153
- require 'sqlite3_api'
154
- rescue LoadError
155
- puts "!! Your SQLite3 adapter isn't a compiled extension."
156
- abort "!! Please check out http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for tips."
157
- end
158
- end
159
- end
160
- end
161
- end
162
- end
163
- end