bmarzolf-picnic 0.8.0.20090420
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +1 -0
- data/History.txt +78 -0
- data/LICENSE.txt +165 -0
- data/Manifest.txt +45 -0
- data/README.txt +31 -0
- data/Rakefile +64 -0
- data/lib/picnic/authentication.rb +254 -0
- data/lib/picnic/cli.rb +165 -0
- data/lib/picnic/conf.rb +135 -0
- data/lib/picnic/controllers.rb +4 -0
- data/lib/picnic/logger.rb +41 -0
- data/lib/picnic/server.rb +99 -0
- data/lib/picnic/service_control.rb +274 -0
- data/lib/picnic/version.rb +9 -0
- data/lib/picnic.rb +11 -0
- data/setup.rb +1585 -0
- data/test/picnic_test.rb +11 -0
- data/test/test_helper.rb +2 -0
- data/vendor/camping-2.0.20090420/CHANGELOG +118 -0
- data/vendor/camping-2.0.20090420/COPYING +18 -0
- data/vendor/camping-2.0.20090420/README +82 -0
- data/vendor/camping-2.0.20090420/Rakefile +180 -0
- data/vendor/camping-2.0.20090420/bin/camping +97 -0
- data/vendor/camping-2.0.20090420/doc/camping.1.gz +0 -0
- data/vendor/camping-2.0.20090420/examples/README +5 -0
- data/vendor/camping-2.0.20090420/examples/blog.rb +375 -0
- data/vendor/camping-2.0.20090420/examples/campsh.rb +629 -0
- data/vendor/camping-2.0.20090420/examples/tepee.rb +242 -0
- data/vendor/camping-2.0.20090420/extras/Camping.gif +0 -0
- data/vendor/camping-2.0.20090420/extras/permalink.gif +0 -0
- data/vendor/camping-2.0.20090420/lib/camping/ar/session.rb +132 -0
- data/vendor/camping-2.0.20090420/lib/camping/ar.rb +78 -0
- data/vendor/camping-2.0.20090420/lib/camping/mab.rb +26 -0
- data/vendor/camping-2.0.20090420/lib/camping/reloader.rb +184 -0
- data/vendor/camping-2.0.20090420/lib/camping/server.rb +159 -0
- data/vendor/camping-2.0.20090420/lib/camping/session.rb +75 -0
- data/vendor/camping-2.0.20090420/lib/camping-unabridged.rb +630 -0
- data/vendor/camping-2.0.20090420/lib/camping.rb +52 -0
- data/vendor/camping-2.0.20090420/setup.rb +1551 -0
- data/vendor/camping-2.0.20090420/test/apps/env_debug.rb +65 -0
- data/vendor/camping-2.0.20090420/test/apps/forms.rb +95 -0
- data/vendor/camping-2.0.20090420/test/apps/misc.rb +86 -0
- data/vendor/camping-2.0.20090420/test/apps/sessions.rb +38 -0
- data/vendor/camping-2.0.20090420/test/test_camping.rb +54 -0
- metadata +140 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'irb'
|
2
|
+
require 'rack'
|
3
|
+
require 'camping/reloader'
|
4
|
+
|
5
|
+
# TODO: I guess we should documentate this too...
|
6
|
+
class Camping::Server
|
7
|
+
attr_reader :reloader
|
8
|
+
attr_accessor :conf
|
9
|
+
|
10
|
+
def initialize(conf, paths)
|
11
|
+
@conf = conf
|
12
|
+
@paths = paths
|
13
|
+
@reloader = Camping::Reloader.new
|
14
|
+
connect(@conf.database) if @conf.database
|
15
|
+
end
|
16
|
+
|
17
|
+
def connect(db)
|
18
|
+
unless Camping.autoload?(:Models)
|
19
|
+
Camping::Models::Base.establish_connection(db)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_scripts
|
24
|
+
scripts = @paths.map do |path|
|
25
|
+
case
|
26
|
+
when File.file?(path)
|
27
|
+
path
|
28
|
+
when File.directory?(path)
|
29
|
+
Dir[File.join(path, '*.rb')]
|
30
|
+
end
|
31
|
+
end.flatten.compact
|
32
|
+
@reloader.update(*scripts)
|
33
|
+
end
|
34
|
+
|
35
|
+
def index_page(apps)
|
36
|
+
welcome = "You are Camping"
|
37
|
+
header = <<-HTML
|
38
|
+
<html>
|
39
|
+
<head>
|
40
|
+
<title>#{welcome}</title>
|
41
|
+
<style type="text/css">
|
42
|
+
body {
|
43
|
+
font-family: verdana, arial, sans-serif;
|
44
|
+
padding: 10px 40px;
|
45
|
+
margin: 0;
|
46
|
+
}
|
47
|
+
h1, h2, h3, h4, h5, h6 {
|
48
|
+
font-family: utopia, georgia, serif;
|
49
|
+
}
|
50
|
+
</style>
|
51
|
+
</head>
|
52
|
+
<body>
|
53
|
+
<h1>#{welcome}</h1>
|
54
|
+
HTML
|
55
|
+
footer = '</body></html>'
|
56
|
+
main = if apps.empty?
|
57
|
+
"<p>Good day. I'm sorry, but I could not find any Camping apps."\
|
58
|
+
"You might want to take a look at the console to see if any errors"\
|
59
|
+
"have been raised</p>"
|
60
|
+
else
|
61
|
+
"<p>Good day. These are the Camping apps you've mounted.</p><ul>" +
|
62
|
+
apps.map do |mount, app|
|
63
|
+
"<li><h3 style=\"display: inline\"><a href=\"/#{mount}\">#{app}</a></h3><small> / <a href=\"/code/#{mount}\">View source</a></small></li>"
|
64
|
+
end.join("\n") + '</ul>'
|
65
|
+
end
|
66
|
+
|
67
|
+
header + main + footer
|
68
|
+
end
|
69
|
+
|
70
|
+
def app
|
71
|
+
reload!
|
72
|
+
all_apps = apps
|
73
|
+
rapp = case all_apps.length
|
74
|
+
when 0
|
75
|
+
proc{|env|[200,{'Content-Type'=>'text/html'},index_page([])]}
|
76
|
+
when 1
|
77
|
+
apps.values.first
|
78
|
+
else
|
79
|
+
hash = {
|
80
|
+
"/" => proc {|env|[200,{'Content-Type'=>'text/html'},index_page(all_apps)]}
|
81
|
+
}
|
82
|
+
all_apps.each do |mount, wrapp|
|
83
|
+
# We're doing @reloader.reload! ourself, so we don't need the wrapper.
|
84
|
+
app = wrapp.app
|
85
|
+
hash["/#{mount}"] = app
|
86
|
+
hash["/code/#{mount}"] = proc do |env|
|
87
|
+
[200,{'Content-Type'=>'text/plain','X-Sendfile'=>wrapp.script.file},'']
|
88
|
+
end
|
89
|
+
end
|
90
|
+
Rack::URLMap.new(hash)
|
91
|
+
end
|
92
|
+
rapp = Rack::ContentLength.new(rapp)
|
93
|
+
rapp = Rack::Lint.new(rapp)
|
94
|
+
rapp = XSendfile.new(rapp)
|
95
|
+
rapp = Rack::ShowExceptions.new(rapp)
|
96
|
+
end
|
97
|
+
|
98
|
+
def apps
|
99
|
+
@reloader.apps.inject({}) do |h, (mount, wrapp)|
|
100
|
+
h[mount.to_s.downcase] = wrapp
|
101
|
+
h
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def call(env)
|
106
|
+
app.call(env)
|
107
|
+
end
|
108
|
+
|
109
|
+
def start
|
110
|
+
handler, conf = case @conf.server
|
111
|
+
when "console"
|
112
|
+
puts "** Starting console"
|
113
|
+
reload!
|
114
|
+
this = self; eval("self", TOPLEVEL_BINDING).meta_def(:reload!) { this.reload!; nil }
|
115
|
+
ARGV.clear
|
116
|
+
IRB.start
|
117
|
+
exit
|
118
|
+
when "mongrel"
|
119
|
+
puts "** Starting Mongrel on #{@conf.host}:#{@conf.port}"
|
120
|
+
[Rack::Handler::Mongrel, {:Port => @conf.port, :Host => @conf.host}]
|
121
|
+
when "webrick"
|
122
|
+
puts "** Starting WEBrick on #{@conf.host}:#{@conf.port}"
|
123
|
+
[Rack::Handler::WEBrick, {:Port => @conf.port, :BindAddress => @conf.host}]
|
124
|
+
end
|
125
|
+
|
126
|
+
handler.run(self, conf)
|
127
|
+
end
|
128
|
+
|
129
|
+
def reload!
|
130
|
+
find_scripts
|
131
|
+
@reloader.reload!
|
132
|
+
end
|
133
|
+
|
134
|
+
# A Rack middleware for reading X-Sendfile. Should only be used in
|
135
|
+
# development.
|
136
|
+
class XSendfile
|
137
|
+
|
138
|
+
HEADERS = [
|
139
|
+
"X-Sendfile",
|
140
|
+
"X-Accel-Redirect",
|
141
|
+
"X-LIGHTTPD-send-file"
|
142
|
+
]
|
143
|
+
|
144
|
+
def initialize(app)
|
145
|
+
@app = app
|
146
|
+
end
|
147
|
+
|
148
|
+
def call(env)
|
149
|
+
status, headers, body = @app.call(env)
|
150
|
+
headers = Rack::Utils::HeaderHash.new(headers)
|
151
|
+
if header = HEADERS.detect { |header| headers.include?(header) }
|
152
|
+
path = headers[header]
|
153
|
+
body = File.read(path)
|
154
|
+
headers['Content-Length'] = body.length.to_s
|
155
|
+
end
|
156
|
+
[status, headers, body]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# == About camping/session.rb
|
2
|
+
# TODO: Clean everything up. Lots of just plain wrong stuff in here.
|
3
|
+
#
|
4
|
+
# This file contains two modules which supply basic sessioning to your Camping app.
|
5
|
+
# Again, we're dealing with a pretty little bit of code: approx. 60 lines.
|
6
|
+
#
|
7
|
+
# * Camping::Models::Session is a module which adds a single <tt>sessions</tt> table
|
8
|
+
# to your database.
|
9
|
+
# * Camping::Session is a module which you will mix into your application (or into
|
10
|
+
# specific controllers which require sessions) to supply a <tt>@state</tt> variable
|
11
|
+
# you can use in controllers and views.
|
12
|
+
#
|
13
|
+
# For a basic tutorial, see the *Getting Started* section of the Camping::Session module.
|
14
|
+
#require 'camping'
|
15
|
+
require 'base64'
|
16
|
+
require 'openssl'
|
17
|
+
|
18
|
+
module Camping
|
19
|
+
# The Camping::Session module is designed to be mixed into your application or into specific
|
20
|
+
# controllers which require sessions. This module defines a <tt>service</tt> method which
|
21
|
+
# intercepts all requests handed to those controllers.
|
22
|
+
#
|
23
|
+
# == Getting Started
|
24
|
+
#
|
25
|
+
# To get sessions working for your application:
|
26
|
+
#
|
27
|
+
# 1. <tt>require 'camping/session'</tt>
|
28
|
+
# 2. Mixin the module: <tt>module YourApp; include Camping::Session end</tt>
|
29
|
+
# 3. Define a secret (and keep it secret): <tt>module YourApp; @@state_secret = "SECRET!"; end</tt>
|
30
|
+
# 4. Throughout your application, use the <tt>@state</tt> var like a hash to store your application's data.
|
31
|
+
#
|
32
|
+
# == A Few Notes
|
33
|
+
#
|
34
|
+
# * The session is stored in a cookie. Look in <tt>@cookies.identity</tt>.
|
35
|
+
# * Session data is only saved if it has changed.
|
36
|
+
module Session
|
37
|
+
DIGEST = OpenSSL::Digest::SHA1.new
|
38
|
+
# This <tt>service</tt> method, when mixed into controllers, intercepts requests
|
39
|
+
# and wraps them with code to start and close the session. If a session isn't found
|
40
|
+
# in the cookie it is created. The <tt>@state</tt> variable is set and if it changes,
|
41
|
+
# it is saved back into the cookie.
|
42
|
+
def service(*a)
|
43
|
+
@session_blob = @input.camping_blob || @cookies.camping_blob
|
44
|
+
@session_hash = @input.camping_hash || @cookies.camping_hash
|
45
|
+
decoded_blob, data = '', {}
|
46
|
+
begin
|
47
|
+
if @session_blob && @session_hash && secure_blob_hasher(@session_blob) == @session_hash
|
48
|
+
decoded_blob = Base64.decode64(@session_blob)
|
49
|
+
data = Marshal.restore(decoded_blob)
|
50
|
+
end
|
51
|
+
|
52
|
+
app = C.name
|
53
|
+
@state = (data[app] ||= Camping::H[])
|
54
|
+
hash_before = decoded_blob.hash
|
55
|
+
return super(*a)
|
56
|
+
ensure
|
57
|
+
data[app] = @state
|
58
|
+
decoded_blob = Marshal.dump(data)
|
59
|
+
unless hash_before == decoded_blob.hash
|
60
|
+
@session_blob = Base64.encode64(decoded_blob).gsub("\n", '').strip
|
61
|
+
@session_hash = secure_blob_hasher(@session_blob)
|
62
|
+
raise "The session contains to much data" if @session_blob.length > 4096
|
63
|
+
@cookies.camping_blob = @session_blob
|
64
|
+
@cookies.camping_hash = @session_hash
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def secure_blob_hasher(data)
|
70
|
+
OpenSSL::HMAC.hexdigest(DIGEST, state_secret, "#{@env.REMOTE_ADDR}#{data}")
|
71
|
+
end
|
72
|
+
|
73
|
+
def state_secret; [__FILE__, File.mtime(__FILE__)].join(":") end
|
74
|
+
end
|
75
|
+
end
|