kernul 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|