bmarzolf-picnic 0.8.0.20090420
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/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
|