kernul 1.0.0
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/History.txt +3 -0
- data/Manifest.txt +16 -0
- data/README.txt +41 -0
- data/Rakefile +23 -0
- data/lib/kernul.rb +38 -0
- data/lib/kernul/app.rb +16 -0
- data/lib/kernul/base.rb +91 -0
- data/lib/kernul/request.rb +15 -0
- data/lib/kernul/response.rb +30 -0
- data/lib/kernul/unracker.rb +50 -0
- data/spec/app_spec.rb +26 -0
- data/spec/base_spec.rb +150 -0
- data/spec/request_spec.rb +20 -0
- data/spec/response_spec.rb +20 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/unracker_spec.rb +86 -0
- metadata +110 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
Rakefile
|
4
|
+
README.txt
|
5
|
+
lib/kernul.rb
|
6
|
+
lib/kernul/app.rb
|
7
|
+
lib/kernul/base.rb
|
8
|
+
lib/kernul/request.rb
|
9
|
+
lib/kernul/response.rb
|
10
|
+
lib/kernul/unracker.rb
|
11
|
+
spec/app_spec.rb
|
12
|
+
spec/base_spec.rb
|
13
|
+
spec/request_spec.rb
|
14
|
+
spec/response_spec.rb
|
15
|
+
spec/spec_helper.rb
|
16
|
+
spec/unracker_spec.rb
|
data/README.txt
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
= Kernul, A generic web platform for Ruby.
|
2
|
+
|
3
|
+
Kernul is a semi-centralized, highly extensible, and easy to manage generic web platform written in Ruby. Better documentation will come in version 1.1.0.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
=== Archive Installation
|
8
|
+
|
9
|
+
rake install
|
10
|
+
|
11
|
+
=== Gem Installation
|
12
|
+
|
13
|
+
Make sure that you have installed jchris-couchrest from github before installing Kernul.
|
14
|
+
|
15
|
+
gem install kernul
|
16
|
+
|
17
|
+
== Usage
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'kernul'
|
21
|
+
require 'mongrel' # This can be any Rack handler
|
22
|
+
|
23
|
+
url = 'kernul.com'
|
24
|
+
db = 'localhost:5984/kernul'
|
25
|
+
host = '0.0.0.0'
|
26
|
+
port = 80
|
27
|
+
|
28
|
+
Kernul::Base.new(:url => url, :db => db, :host => host, :port => port, :handler => Rack::Handler::Mongrel).start
|
29
|
+
|
30
|
+
This will start up a Rack server. If you would only like to create the Rack class because your host requires a Rackup file, simply
|
31
|
+
remove the <tt>start</tt> call at the end of the last line. You can also remove the <tt>:host</tt>, <tt>:port</tt>, and <tt>:handler</tt>
|
32
|
+
options. See Kernul::Base for more details.
|
33
|
+
|
34
|
+
|
35
|
+
== Meta
|
36
|
+
|
37
|
+
Written by Alex Kern
|
38
|
+
|
39
|
+
Copyright (c) 2008-2009 Alex Kern
|
40
|
+
|
41
|
+
Released under the MIT License
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/kernul.rb'
|
6
|
+
|
7
|
+
Hoe.new('kernul', Kernul::VERSION) do |p|
|
8
|
+
p.name = 'kernul'
|
9
|
+
p.author = 'Alex Kern'
|
10
|
+
p.summary = 'A generic web platform for Ruby.'
|
11
|
+
p.description = 'A semi-centralized, highly extensible, and easy to manage generic web platform written in Ruby.'
|
12
|
+
p.email = 'capnkernul@gmail.com'
|
13
|
+
p.url = 'http://kernul.com/'
|
14
|
+
p.remote_rdoc_dir = ''
|
15
|
+
p.rubyforge_name = 'kernul'
|
16
|
+
p.extra_deps = [['activesupport', '>= 2.0.0'],
|
17
|
+
['rack', '>= 0.4.0'],
|
18
|
+
['jchris-couchrest', '>= 0.9.0']]
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Release and publish documentation"
|
23
|
+
task :repubdoc => [:release, :publish_docs]
|
data/lib/kernul.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008 Alexander Kern
|
3
|
+
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
|
11
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
12
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
14
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
15
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
16
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
17
|
+
# SOFTWARE.
|
18
|
+
#--
|
19
|
+
|
20
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
21
|
+
|
22
|
+
# The gems
|
23
|
+
require 'rubygems'
|
24
|
+
require 'active_support'
|
25
|
+
require 'rack'
|
26
|
+
require 'couchrest'
|
27
|
+
require 'rest_client'
|
28
|
+
|
29
|
+
module Kernul
|
30
|
+
VERSION = '1.0.0'
|
31
|
+
end
|
32
|
+
|
33
|
+
# The other files
|
34
|
+
require 'kernul/app'
|
35
|
+
require 'kernul/request'
|
36
|
+
require 'kernul/response'
|
37
|
+
require 'kernul/unracker'
|
38
|
+
require 'kernul/base'
|
data/lib/kernul/app.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
class App < CouchRest::Model
|
2
|
+
key_accessor :name, :symbol, :key, :url
|
3
|
+
view_by :symbol
|
4
|
+
|
5
|
+
# Shortcut to finding an application by its symbol
|
6
|
+
def self.find_by_symbol(symbol)
|
7
|
+
by_symbol(:key => symbol)[0]
|
8
|
+
end
|
9
|
+
|
10
|
+
# Authenticates an application using its symbol and key
|
11
|
+
def self.authenticate(symbol, key)
|
12
|
+
app = self.find_by_symbol(symbol)
|
13
|
+
return app if app and app.key == key
|
14
|
+
return false
|
15
|
+
end
|
16
|
+
end
|
data/lib/kernul/base.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module Kernul
|
2
|
+
# Handles all requests in and out of kernul.
|
3
|
+
class Base
|
4
|
+
class << self; attr_accessor :url, :handler, :options, :db; end
|
5
|
+
|
6
|
+
# Creates a new kernul. It requires some configuration options:
|
7
|
+
# - <tt>:db</tt> - URL of the CouchDB database.
|
8
|
+
# - <tt>:url</tt> - URL that this kernul will be accessed on.
|
9
|
+
#
|
10
|
+
# And one optional one:
|
11
|
+
# - <tt>:handler</tt> - Constant to Rack handler. Needed if using <tt>#start</tt>.
|
12
|
+
# - <tt>:host</tt> - Host to listen on. Needed if using <tt>#start</tt>.
|
13
|
+
# - <tt>:port</tt> - Port to listen on. Needed if using <tt>#start</tt>.
|
14
|
+
# - <tt>:options</tt> - Extra options passed to the handler.
|
15
|
+
def initialize(args)
|
16
|
+
self.class.url = args[:url]
|
17
|
+
self.class.handler = args[:handler]
|
18
|
+
|
19
|
+
options = { :Host => args[:host], :Port => args[:port] }
|
20
|
+
options.merge!(args[:options]) if args[:options]
|
21
|
+
self.class.options = options
|
22
|
+
|
23
|
+
self.class.start_db(args[:db])
|
24
|
+
end
|
25
|
+
|
26
|
+
# Starts up the kernul's Rack server. Not needed on some hosts which require rackup files.
|
27
|
+
def start
|
28
|
+
self.class.handler.run Rack::CommonLogger.new(self), self.class.options
|
29
|
+
end
|
30
|
+
|
31
|
+
# Starts the CouchDB database with CouchRest. Creates the database
|
32
|
+
# if it isn't already created.
|
33
|
+
def self.start_db(url)
|
34
|
+
CouchRest::Model.default_database = CouchRest.database!(url)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Called by Rack whenever there's a request to the kernul.
|
38
|
+
def call(env)
|
39
|
+
begin
|
40
|
+
request = Unracker.unrack_request(env)
|
41
|
+
|
42
|
+
request.request_app = App.authenticate(request.user, request.password)
|
43
|
+
return Response.invalid_key unless request.request_app
|
44
|
+
|
45
|
+
request.target_app = App.find_by_symbol(self.class.subdomains(request.url)[-1])
|
46
|
+
return Response.invalid_target unless request.target_app
|
47
|
+
|
48
|
+
return self.class.dispatch(request)
|
49
|
+
rescue Exception => e
|
50
|
+
return Response.default(e)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns all subdomains of the url provided.
|
55
|
+
def self.subdomains(url, tld_length = 1)
|
56
|
+
parts = URI.parse(url).host.split('.')
|
57
|
+
parts[0..-(tld_length+2)]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Prepares and sends the HTTP request to the target application.
|
61
|
+
def self.dispatch(request)
|
62
|
+
method = request.method
|
63
|
+
url = request.target_app.url << URI.parse(request.url).request_uri
|
64
|
+
headers = dispatch_headers(request)
|
65
|
+
payload = request.payload
|
66
|
+
|
67
|
+
dispatch = RestClient::Request::NoExceptions.new(:method => method, :url => url, :headers => headers, :payload => payload)
|
68
|
+
retrieve = dispatch.execute
|
69
|
+
retrieve[1] = filter_headers(retrieve[1])
|
70
|
+
retrieve
|
71
|
+
end
|
72
|
+
|
73
|
+
# Prepares the dispatch's headers.
|
74
|
+
def self.dispatch_headers(request)
|
75
|
+
headers = {}
|
76
|
+
request.headers.each { |key, value| headers[key.to_s.gsub(/_/, " ").titleize.gsub(/ /, "-")] = value }
|
77
|
+
|
78
|
+
headers['Referer'] = "#{request.request_app.symbol}.#{self.url}"
|
79
|
+
headers['Pragma'] = [request.target_app.key, headers['Pragma']].join(' ')
|
80
|
+
headers.delete_if { |key, value| ['Host', 'Version', 'Authorization'].include? key }
|
81
|
+
headers
|
82
|
+
end
|
83
|
+
|
84
|
+
# Filters the returned headers from the dispatch and chooses
|
85
|
+
# which ones will be sent back to the request app.
|
86
|
+
def self.filter_headers(response_headers)
|
87
|
+
response_headers.delete_if { |key, value| ['content-encoding', 'content-length', 'transfer-encoding'].include? key }
|
88
|
+
response_headers
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Extension of RestClient::Request to allow the HTTP code, headers, and body to be
|
2
|
+
# directly accessed without the use of exceptions.
|
3
|
+
class RestClient::Request
|
4
|
+
attr_accessor :request_app, :target_app # Add the ability to store these apps in a request
|
5
|
+
|
6
|
+
class NoExceptions < RestClient::Request
|
7
|
+
# Returns the results of the request in the form of a Rack array.
|
8
|
+
def process_result(res)
|
9
|
+
result_headers = res.header.to_hash
|
10
|
+
result_headers.each { |key, value| result_headers[key] = value[0]}
|
11
|
+
|
12
|
+
[res.code, result_headers, decode(res['content-encoding'], res.body)]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Convenience class to store the possible responses used
|
2
|
+
# in a kernul. They return Rack arrays.
|
3
|
+
module Kernul
|
4
|
+
module Response
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# The Rack array for an invalid symbol and/or key
|
8
|
+
def invalid_key
|
9
|
+
[ 401, {
|
10
|
+
'Content-Type' => 'text/plain',
|
11
|
+
'WWW-Authenticate' => "Basic realm=\"#{Kernul::Base.url}\""
|
12
|
+
}, 'Invalid key' ]
|
13
|
+
end
|
14
|
+
|
15
|
+
# The Rack array if the target doesn't exist or no target is provided
|
16
|
+
def invalid_target
|
17
|
+
[ 400, {
|
18
|
+
'Content-Type' => 'text/plain'
|
19
|
+
}, 'Invalid target' ]
|
20
|
+
end
|
21
|
+
|
22
|
+
# The Rack array if there was an uncaught error or something horrible occured
|
23
|
+
def default(error='')
|
24
|
+
[ 500, {
|
25
|
+
'Content-Type' => 'text/plain'
|
26
|
+
}, error.to_s ]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Takes rack environments and makes them into a RestClient requests.
|
2
|
+
module Kernul
|
3
|
+
module Unracker
|
4
|
+
# Removes all the important data from the Rack request and returns
|
5
|
+
# a RestClient::Request with that data for easy access.
|
6
|
+
def self.unrack_request(env)
|
7
|
+
url = generate_url(env)
|
8
|
+
|
9
|
+
if ['GET', 'POST', 'PUT', 'DELETE'].include?(env['REQUEST_METHOD'])
|
10
|
+
method = env['REQUEST_METHOD']
|
11
|
+
else
|
12
|
+
method = 'GET'
|
13
|
+
end
|
14
|
+
|
15
|
+
headers = unrack_headers(env)
|
16
|
+
payload = env['rack.input']
|
17
|
+
|
18
|
+
if env['HTTP_AUTHORIZATION']
|
19
|
+
auth = env['HTTP_AUTHORIZATION'].split(" ")[1].unpack("m*").first.split(/:/, 2)
|
20
|
+
else
|
21
|
+
auth = ["",""]
|
22
|
+
end
|
23
|
+
|
24
|
+
user = auth.first
|
25
|
+
password = auth.last
|
26
|
+
|
27
|
+
RestClient::Request.new(:method => method, :url => url, :headers => headers, :user => user, :password => password, :payload => payload)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Recreates the request URL from the Rack environment data.
|
31
|
+
def self.generate_url(env)
|
32
|
+
url = env['rack.url_scheme'] + "://"
|
33
|
+
url << env['SERVER_NAME']
|
34
|
+
url << ":" + env["SERVER_PORT"]
|
35
|
+
url << env['SCRIPT_NAME']
|
36
|
+
url << env['PATH_INFO'] unless env['PATH_INFO'].nil?
|
37
|
+
url << "?" << env['QUERY_STRING'] unless env['QUERY_STRING'].empty?
|
38
|
+
url
|
39
|
+
end
|
40
|
+
|
41
|
+
# Removes all HTTP headers from the Rack environment data and returns
|
42
|
+
# them as a hash.
|
43
|
+
def self.unrack_headers(env)
|
44
|
+
hash = {}
|
45
|
+
http_headers = env.select { |key, value| key[0..4] == "HTTP_" }
|
46
|
+
http_headers.each { |t| hash[t[0].dup[5..-1]] = t[1] }
|
47
|
+
hash
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/app_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe App do
|
4
|
+
it "should be able to find things by symbol" do
|
5
|
+
app = App.new(:symbol => 'test')
|
6
|
+
App.should_receive(:by_symbol).and_return([app])
|
7
|
+
App.find_by_symbol('test').should == app
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return nil if no application with that symbol exists" do
|
11
|
+
App.should_receive(:by_symbol).and_return([])
|
12
|
+
App.find_by_symbol('no_such_app').should == nil
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be able to authenticate an app" do
|
16
|
+
app = App.new(:symbol => 'symbol', :key => 'key')
|
17
|
+
App.should_receive(:by_symbol).and_return([app])
|
18
|
+
App.authenticate('symbol', 'key').should == app
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return false when trying to authenticate an app if the credentials are bad" do
|
22
|
+
app = App.new(:symbol => 'symbol', :key => 'key')
|
23
|
+
App.should_receive(:by_symbol).and_return([app])
|
24
|
+
App.authenticate('wrong', 'wrong').should == false
|
25
|
+
end
|
26
|
+
end
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Kernul::Base do
|
4
|
+
it "should be able to create a database" do
|
5
|
+
Kernul::Base.start_db('localhost:5984').should be_an_instance_of(CouchRest::Database)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be able to parse subdomains" do
|
9
|
+
Kernul::Base.subdomains('http://sub1.lol.com').should == ['sub1']
|
10
|
+
Kernul::Base.subdomains('http://sub2.sub1.lol.com').should == ['sub2', 'sub1']
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should change the request headers" do
|
14
|
+
dummy = mock('dummy');
|
15
|
+
dummy.stub!(:headers).and_return('TEST' => 'TEST', 'TEST_TEST' => 'TEST', 'PRAGMA' => 'no-cache', 'HOST' => 'test.com', 'VERSION' => '1.3.3.7', 'AUTHORIZATION' => 'topsecret')
|
16
|
+
dummy.stub!(:request_app).and_return(dummy)
|
17
|
+
dummy.stub!(:symbol).and_return('testing')
|
18
|
+
dummy.stub!(:target_app).and_return(dummy)
|
19
|
+
dummy.stub!(:key).and_return('password')
|
20
|
+
Kernul::Base.should_receive(:url).and_return('example.com')
|
21
|
+
|
22
|
+
result = Kernul::Base.dispatch_headers(dummy)
|
23
|
+
result['Test'].should == 'TEST'
|
24
|
+
result['Test-Test'].should == 'TEST'
|
25
|
+
result['Referer'].should == 'testing.example.com'
|
26
|
+
result['Pragma'].should == 'password no-cache'
|
27
|
+
result['Host'].should be_nil
|
28
|
+
result['Version'].should be_nil
|
29
|
+
result['Authorization'].should be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should filter out the encoding headers from a response" do
|
33
|
+
Kernul::Base.filter_headers('test' => 'test').should == {'test' => 'test'}
|
34
|
+
Kernul::Base.filter_headers('test' => 'test', 'content-encoding' => 'gzip').should == {'test' => 'test'}
|
35
|
+
Kernul::Base.filter_headers('test' => 'test', 'content-length' => '1').should == {'test' => 'test'}
|
36
|
+
Kernul::Base.filter_headers('test' => 'test', 'transfer-encoding' => '1').should == {'test' => 'test'}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be able to dispatch a request" do
|
40
|
+
request = mock('request')
|
41
|
+
target_app = mock('target_app')
|
42
|
+
request.stub!(:method).and_return('GET')
|
43
|
+
request.stub!(:target_app).and_return(target_app)
|
44
|
+
request.stub!(:url).and_return('http://google.com/')
|
45
|
+
request.stub!(:payload).and_return('')
|
46
|
+
target_app.stub!(:url).and_return('http://google.com/')
|
47
|
+
Kernul::Base.should_receive(:dispatch_headers).and_return({})
|
48
|
+
|
49
|
+
# This will contact google which will always show a 301 Found redirect to their www subdomain.
|
50
|
+
result = Kernul::Base.dispatch(request)
|
51
|
+
result.should be_an_instance_of(Array)
|
52
|
+
result[0].should == '301'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should be able to be created without being started" do
|
56
|
+
Kernul::Base.should_receive(:start_db).and_return(true)
|
57
|
+
kernul = Kernul::Base.new(:url => 'kernul.com', :db => 'test')
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should merge the handler options when created" do
|
61
|
+
kernul = Kernul::Base.new(:url => 'kernul.com', :db => 'test', :host => '0.0.0.0', :port => 80, :options => {:test => 'test'})
|
62
|
+
Kernul::Base.options.should == { :Host => '0.0.0.0', :Port => 80, :test => 'test' }
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be able to be started as a Rack server" do
|
66
|
+
handler = mock('handler')
|
67
|
+
handler.should_receive(:run).and_return(true)
|
68
|
+
kernul = Kernul::Base.new(:url => 'kernul.com', :db => 'test', :host => '0.0.0.0', :port => 80, :handler => handler)
|
69
|
+
kernul.start
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe Kernul::Base, "#call" do
|
74
|
+
it "should unrack the environment" do
|
75
|
+
env = mock('env')
|
76
|
+
Kernul::Unracker.should_receive(:unrack_request).and_return(nil)
|
77
|
+
kernul = Kernul::Base.new(:url => 'kernul.com', :db => 'test')
|
78
|
+
kernul.call(env)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should show an invalid key error if the username and password are wrong" do
|
82
|
+
env = mock('env')
|
83
|
+
request = mock('request')
|
84
|
+
request.should_receive(:user).and_return('user')
|
85
|
+
request.should_receive(:password).and_return('password')
|
86
|
+
request.should_receive(:request_app).and_return(false)
|
87
|
+
request.should_receive(:request_app=).and_return(false)
|
88
|
+
App.should_receive(:authenticate).and_return(false)
|
89
|
+
Kernul::Unracker.stub!(:unrack_request).and_return(request)
|
90
|
+
Kernul::Response.should_receive(:invalid_key).and_return([])
|
91
|
+
kernul = Kernul::Base.new(:url => 'kernul.com', :db => 'test')
|
92
|
+
kernul.call(env).should == []
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should show an invalid target error if an invalid target app is supplied" do
|
96
|
+
env = mock('env')
|
97
|
+
request = mock('request')
|
98
|
+
request_app = mock('request_app')
|
99
|
+
request.stub!(:user).and_return('user')
|
100
|
+
request.stub!(:password).and_return('password')
|
101
|
+
request.stub!(:request_app).and_return(request_app)
|
102
|
+
request.stub!(:request_app=).and_return(request_app)
|
103
|
+
request.should_receive(:url).and_return('test.example.com')
|
104
|
+
request.should_receive(:target_app).and_return(false)
|
105
|
+
request.should_receive(:target_app=).and_return(false)
|
106
|
+
Kernul::Base.should_receive(:subdomains).and_return([])
|
107
|
+
App.stub!(:authenticate).and_return(request_app)
|
108
|
+
App.should_receive(:find_by_symbol).and_return(false)
|
109
|
+
Kernul::Unracker.stub!(:unrack_request).and_return(request)
|
110
|
+
Kernul::Response.should_receive(:invalid_target).and_return([])
|
111
|
+
kernul = Kernul::Base.new(:url => 'kernul.com', :db => 'test')
|
112
|
+
kernul.call(env).should == []
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should dispatch the request if it is valid" do
|
116
|
+
env = mock('env')
|
117
|
+
request = mock('request')
|
118
|
+
request_app = mock('request_app')
|
119
|
+
target_app = mock('target_app')
|
120
|
+
request.stub!(:user).and_return('user')
|
121
|
+
request.stub!(:password).and_return('password')
|
122
|
+
request.stub!(:request_app).and_return(request_app)
|
123
|
+
request.stub!(:request_app=).and_return(request_app)
|
124
|
+
request.stub!(:url).and_return('test.example.com')
|
125
|
+
request.stub!(:target_app).and_return(target_app)
|
126
|
+
request.stub!(:target_app=).and_return(target_app)
|
127
|
+
Kernul::Base.stub!(:subdomains).and_return([])
|
128
|
+
App.stub!(:authenticate).and_return(request_app)
|
129
|
+
App.stub!(:find_by_symbol).and_return(target_app)
|
130
|
+
Kernul::Unracker.stub!(:unrack_request).and_return(request)
|
131
|
+
Kernul::Base.should_receive(:dispatch).and_return([])
|
132
|
+
kernul = Kernul::Base.new(:url => 'kernul.com', :db => 'test')
|
133
|
+
kernul.call(env).should == []
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should report database communication errors" do
|
137
|
+
env = mock('env')
|
138
|
+
request = mock('request')
|
139
|
+
request.stub!(:user).and_return('user')
|
140
|
+
request.stub!(:password).and_return('password')
|
141
|
+
request.stub!(:request_app).and_return(false)
|
142
|
+
request.stub!(:request_app=).and_return(false)
|
143
|
+
Kernul::Unracker.stub!(:unrack_request).and_return(request)
|
144
|
+
Kernul::Response.should_receive(:default).and_return([])
|
145
|
+
|
146
|
+
# This makes the database fail to connect, causing an Exception to be raised.
|
147
|
+
kernul = Kernul::Base.new(:url => 'kernul.com', :db => '1crazyinsaneurl.com')
|
148
|
+
kernul.call(env).should == []
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe RestClient::Request::NoExceptions do
|
4
|
+
it "should return a rack array of the response" do
|
5
|
+
dummy = mock('dummy');
|
6
|
+
request = RestClient::Request::NoExceptions.new(:method => 'GET', :url => 'nowhere');
|
7
|
+
dummy.stub!(:code).and_return(200)
|
8
|
+
dummy.stub!(:header).and_return(:test => ['test'])
|
9
|
+
dummy.stub!(:body).and_return('testestest')
|
10
|
+
dummy.stub!(:[]).with('content-encoding').and_return('text/plain')
|
11
|
+
request.should_receive(:decode).and_return('testestest')
|
12
|
+
|
13
|
+
result = request.process_result(dummy)
|
14
|
+
result.should be_an_instance_of(Array)
|
15
|
+
result.length.should == 3
|
16
|
+
result[0].should be_an_instance_of(Fixnum)
|
17
|
+
result[1].should be_an_instance_of(Hash)
|
18
|
+
result[2].should be_an_instance_of(String)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Kernul::Response do
|
4
|
+
it "should return a Rack array" do
|
5
|
+
[Kernul::Response.invalid_key, Kernul::Response.invalid_target, Kernul::Response.default].each do |array|
|
6
|
+
array.should be_an_instance_of(Array)
|
7
|
+
array.length.should == 3
|
8
|
+
array[0].should be_an_instance_of(Fixnum)
|
9
|
+
array[1].should be_an_instance_of(Hash)
|
10
|
+
array[2].should be_an_instance_of(String)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should convert exceptions to text in a default response" do
|
15
|
+
Kernul::Response.default[2].should == ''
|
16
|
+
Kernul::Response.default('')[2].should == ''
|
17
|
+
Kernul::Response.default('test')[2].should == 'test'
|
18
|
+
Kernul::Response.default(ArgumentError)[2].should == 'ArgumentError'
|
19
|
+
end
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Kernul::Unracker do
|
4
|
+
it "should be able to recreate a url" do
|
5
|
+
env = Rack::MockRequest.env_for('http://example.com:80/')
|
6
|
+
Kernul::Unracker.generate_url(env).should == 'http://example.com:80/'
|
7
|
+
|
8
|
+
env = Rack::MockRequest.env_for('http://lol.example.com:80/')
|
9
|
+
Kernul::Unracker.generate_url(env).should == 'http://lol.example.com:80/'
|
10
|
+
|
11
|
+
env = Rack::MockRequest.env_for('http://example.com:23/')
|
12
|
+
Kernul::Unracker.generate_url(env).should == 'http://example.com:23/'
|
13
|
+
|
14
|
+
env = Rack::MockRequest.env_for('https://example.com:80/')
|
15
|
+
Kernul::Unracker.generate_url(env).should == 'https://example.com:80/'
|
16
|
+
|
17
|
+
env = Rack::MockRequest.env_for('http://example.com:80/lol')
|
18
|
+
Kernul::Unracker.generate_url(env).should == 'http://example.com:80/lol'
|
19
|
+
|
20
|
+
env = Rack::MockRequest.env_for('http://example.com:80/?lol')
|
21
|
+
Kernul::Unracker.generate_url(env).should == 'http://example.com:80/?lol'
|
22
|
+
|
23
|
+
env = Rack::MockRequest.env_for('http://example.com:80/#lol')
|
24
|
+
Kernul::Unracker.generate_url(env).should == 'http://example.com:80/'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to unrack the headers" do
|
28
|
+
env = Rack::MockRequest.env_for('http://example.com:80/')
|
29
|
+
Kernul::Unracker.unrack_headers(env).should == {}
|
30
|
+
|
31
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', {'lol' => 'lol'})
|
32
|
+
Kernul::Unracker.unrack_headers(env).should == {}
|
33
|
+
|
34
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', {'HTTP_REFERER' => 'lol'})
|
35
|
+
Kernul::Unracker.unrack_headers(env).should == {'REFERER' => 'lol'}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe Kernul::Unracker, "#unrack_request" do
|
40
|
+
it "should return a RestClient::Request" do
|
41
|
+
env = Rack::MockRequest.env_for('http://example.com:80/')
|
42
|
+
Kernul::Unracker.unrack_request(env).should be_an_instance_of(RestClient::Request)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should have a method" do
|
46
|
+
env = Rack::MockRequest.env_for('http://example.com:80/')
|
47
|
+
Kernul::Unracker.unrack_request(env).method.should == 'GET'
|
48
|
+
|
49
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', {:method => 'GET'})
|
50
|
+
Kernul::Unracker.unrack_request(env).method.should == 'GET'
|
51
|
+
|
52
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', {:method => 'POST'})
|
53
|
+
Kernul::Unracker.unrack_request(env).method.should == 'POST'
|
54
|
+
|
55
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', {:method => 'PUT'})
|
56
|
+
Kernul::Unracker.unrack_request(env).method.should == 'PUT'
|
57
|
+
|
58
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', {:method => 'DELETE'})
|
59
|
+
Kernul::Unracker.unrack_request(env).method.should == 'DELETE'
|
60
|
+
|
61
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', {:method => 'NOTAMETHOD'})
|
62
|
+
Kernul::Unracker.unrack_request(env).method.should == "GET"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be able to have a payload" do
|
66
|
+
env = Rack::MockRequest.env_for('http://example.com:80/')
|
67
|
+
Kernul::Unracker.unrack_request(env).payload.read.should == ''
|
68
|
+
|
69
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', :input => "lol")
|
70
|
+
Kernul::Unracker.unrack_request(env).payload.read.should == 'lol'
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should have a username and password" do
|
74
|
+
env = Rack::MockRequest.env_for('http://example.com:80/')
|
75
|
+
Kernul::Unracker.unrack_request(env).user.should == ""
|
76
|
+
Kernul::Unracker.unrack_request(env).password.should == ""
|
77
|
+
|
78
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', 'HTTP_AUTHORIZATION' => "Basic #{['lol:rofl'].pack("m*")}")
|
79
|
+
Kernul::Unracker.unrack_request(env).user.should == "lol"
|
80
|
+
Kernul::Unracker.unrack_request(env).password.should == "rofl"
|
81
|
+
|
82
|
+
env = Rack::MockRequest.env_for('http://example.com:80/', 'HTTP_AUTHORIZATION' => 'Basic lol:rofl')
|
83
|
+
Kernul::Unracker.unrack_request(env).user.should_not == "lol"
|
84
|
+
Kernul::Unracker.unrack_request(env).password.should_not == "rofl"
|
85
|
+
end
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kernul
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alex Kern
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-01 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.0.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rack
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.4.0
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: jchris-couchrest
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.0
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: hoe
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.8.2
|
54
|
+
version:
|
55
|
+
description: A semi-centralized, highly extensible, and easy to manage generic web platform written in Ruby.
|
56
|
+
email: capnkernul@gmail.com
|
57
|
+
executables: []
|
58
|
+
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files:
|
62
|
+
- History.txt
|
63
|
+
- Manifest.txt
|
64
|
+
- README.txt
|
65
|
+
files:
|
66
|
+
- History.txt
|
67
|
+
- Manifest.txt
|
68
|
+
- Rakefile
|
69
|
+
- README.txt
|
70
|
+
- lib/kernul.rb
|
71
|
+
- lib/kernul/app.rb
|
72
|
+
- lib/kernul/base.rb
|
73
|
+
- lib/kernul/request.rb
|
74
|
+
- lib/kernul/response.rb
|
75
|
+
- lib/kernul/unracker.rb
|
76
|
+
- spec/app_spec.rb
|
77
|
+
- spec/base_spec.rb
|
78
|
+
- spec/request_spec.rb
|
79
|
+
- spec/response_spec.rb
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
- spec/unracker_spec.rb
|
82
|
+
has_rdoc: true
|
83
|
+
homepage: http://kernul.com/
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options:
|
86
|
+
- --main
|
87
|
+
- README.txt
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
version:
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: "0"
|
101
|
+
version:
|
102
|
+
requirements: []
|
103
|
+
|
104
|
+
rubyforge_project: kernul
|
105
|
+
rubygems_version: 1.3.1
|
106
|
+
signing_key:
|
107
|
+
specification_version: 2
|
108
|
+
summary: A generic web platform for Ruby.
|
109
|
+
test_files: []
|
110
|
+
|