cloudkit 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,2 +1,9 @@
1
+ 0.9.1
2
+ - Fixed Rack::Lint/rackup errors related to Content-Type headers
3
+ - Patched Rack to support StringIO#string in Rack::Lint::InputWrapper
4
+ - Fixed server_url encoding in OpenIDStore
5
+ - Added sqlite3-ruby dependency in gemspec
6
+ - Updated documentation
7
+
1
8
  0.9.0
2
9
  - First public gem release
data/README CHANGED
@@ -6,6 +6,10 @@ More specifically, CloudKit provides RESTful JSON storage with optional OpenID a
6
6
 
7
7
  CloudKit is Rack middleware and as such can be used on its own or alongside other Rack-based applications or middleware components like Rails, Merb or Sinatra.
8
8
 
9
+ ===Install
10
+
11
+ gem install cloudkit
12
+
9
13
  ===Examples
10
14
 
11
15
  In a rackup file called config.ru:
@@ -29,10 +33,34 @@ An explicit version of example 2, minus the default developer landing page:
29
33
  use CloudKit::OAuthFilter
30
34
  use CloudKit::OpenIDFilter
31
35
  use CloudKit::Service, :collections => [:notes, :todos]
32
- run lambda {|env| [200, {}, ['HELLO']]}
36
+ run lambda {|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
37
+
38
+ The same as above, using MySQL:
39
+
40
+ require 'cloudkit'
41
+ use Rack::Config { |env|
42
+ env['cloudkit.storage.uri'] = 'mysql://user:pass@localhost/cloudkit_example'
43
+ }
44
+ use Rack::Pool::Session
45
+ use CloudKit::OAuthFilter
46
+ use CloudKit::OpenIDFilter
47
+ use CloudKit::Service, :collections => [:notes, :todos]
48
+ run lambda {|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
33
49
 
34
50
  See the examples directory for more.
35
51
 
52
+ ===Online
53
+
54
+ Main Site: http://getcloudkit.com
55
+
56
+ Blog: http://blog.joncrosby.me
57
+
58
+ Google Group: http://groups.google.com/group/cloudkit
59
+
60
+ Source: http://github.com/jcrosby/cloudkit
61
+
62
+ ===License
63
+
36
64
  Copyright (c) 2008 Jon Crosby http://joncrosby.me
37
65
 
38
66
  Permission is hereby granted, free of charge, to any person obtaining
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
2
2
  s.specification_version = 2 if s.respond_to? :specification_version=
3
3
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
4
  s.name = "cloudkit"
5
- s.version = "0.9.0"
6
- s.date = "2008-12-22"
5
+ s.version = "0.9.1"
6
+ s.date = "2008-12-31"
7
7
  s.summary = "An Open Web JSON Appliance."
8
8
  s.description = "An Open Web JSON Appliance."
9
9
  s.authors = ["Jon Crosby"]
@@ -11,11 +11,11 @@ Gem::Specification.new do |s|
11
11
  s.homepage = "http://getcloudkit.com"
12
12
  s.files = %w[
13
13
  CHANGES
14
- cloudkit.gemspec
15
14
  COPYING
16
15
  README
17
16
  Rakefile
18
17
  TODO
18
+ cloudkit.gemspec
19
19
  doc/curl.html
20
20
  doc/images/example-code.gif
21
21
  doc/images/json-title.gif
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
38
38
  lib/cloudkit/openid_filter.rb
39
39
  lib/cloudkit/openid_store.rb
40
40
  lib/cloudkit/rack/builder.rb
41
+ lib/cloudkit/rack/lint.rb
41
42
  lib/cloudkit/rack/router.rb
42
43
  lib/cloudkit/request.rb
43
44
  lib/cloudkit/service.rb
@@ -79,4 +80,5 @@ Gem::Specification.new do |s|
79
80
  s.add_dependency 'oauth', '>= 0.2.7'
80
81
  s.add_dependency 'ruby-openid', '= 2.1.2'
81
82
  s.add_dependency 'json', '= 1.1.3'
83
+ s.add_dependency 'sqlite3-ruby', '= 1.2.4'
82
84
  end
@@ -74,6 +74,7 @@ See what we can do with these note resources:
74
74
  $ curl -i -XOPTIONS http://localhost:3000/notes<br/>
75
75
  HTTP/1.1 200 OK<br/>
76
76
  Content-Length: 0<br/>
77
+ Content-Type: application/json<br/>
77
78
  Allow: GET, HEAD, POST, OPTIONS<br/>
78
79
  Connection: keep-alive<br/>
79
80
  </div>
@@ -94,10 +95,6 @@ List the currently available notes:
94
95
  </div>
95
96
  </p>
96
97
 
97
- <p>
98
- The Link header will be explained momentarily.
99
- </p>
100
-
101
98
  <p>
102
99
  Create a note using <a href="http://tools.ietf.org/html/rfc2616#section-9.5">POST</a>:
103
100
  <div class="code">
@@ -179,9 +176,7 @@ Along with the usual metadata, individual resources also provide discovery
179
176
  information via
180
177
  <a href="http://www.mnot.net/drafts/draft-nottingham-http-link-header-03.txt">Link Headers</a>
181
178
  as shown above. These links allow user agents to find related resources such as
182
- the complete history of a document and its
183
- <a href="http://tools.ietf.org/html/rfc2616#section-14.19">ETags</a>.
184
- The utility of these items will be demonstrated momentarily.
179
+ the complete history of a document.
185
180
  </p>
186
181
 
187
182
  <p>
@@ -218,8 +213,9 @@ Succeed in updating by being specific:
218
213
  </p>
219
214
 
220
215
  <p>
221
- (Note: Your ETag will likely be different so substitute the one that curl
222
- provided when you created your own "abc" resource.)
216
+ (Note: Your <a href="http://tools.ietf.org/html/rfc2616#section-14.19">ETag</a>
217
+ will likely be different so substitute the one that curl provided when you
218
+ created your own "abc" resource.)
223
219
  </p>
224
220
 
225
221
  <p>
@@ -22,6 +22,11 @@
22
22
  <div class="subtitle">An Open Web JSON Appliance</div>
23
23
  </div>
24
24
  </div>
25
+ <div class="meta">
26
+ <p class="wrapper">
27
+ Version 0.9.1 released. Install with <em>gem install cloudkit</em>.
28
+ </p>
29
+ </div>
25
30
  <div class="wrapper intro-row">
26
31
  <div class="column-one">
27
32
  <div class="block-header">
@@ -118,7 +118,7 @@ a {
118
118
  font-family: 'Courier New', monospace;
119
119
  color: #00ff00;
120
120
  background-color: black;
121
- font-size: 13px;
121
+ font-size: 12px;
122
122
  width: 100%;
123
123
  margin-left: 20px;
124
124
  margin-bottom: 30px;
@@ -3,4 +3,4 @@ require 'cloudkit'
3
3
  use Rack::Session::Pool
4
4
  use CloudKit::OpenIDFilter
5
5
  use CloudKit::Service, :collections => [:notes]
6
- run lambda{|env| [200, {}, ['HELLO']]}
6
+ run lambda{|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
@@ -2,4 +2,4 @@ $:.unshift File.expand_path(File.dirname(__FILE__)) + '/../lib'
2
2
  require 'cloudkit'
3
3
  use CloudKit::OAuthFilter
4
4
  use CloudKit::Service, :collections => [:notes]
5
- run lambda{|env| [200, {}, ['HELLO']]}
5
+ run lambda{|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
@@ -7,4 +7,4 @@ use Rack::Session::Pool
7
7
  use CloudKit::OAuthFilter
8
8
  use CloudKit::OpenIDFilter
9
9
  use CloudKit::Service, :collections => [:notes]
10
- run lambda{|env| [200, {}, ['HELLO']]}
10
+ run lambda{|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
@@ -1,10 +1,10 @@
1
1
  $:.unshift File.expand_path(File.dirname(__FILE__)) + '/../lib'
2
2
  require 'cloudkit'
3
3
  use Rack::Config do |env|
4
- env['cloudkit.storage.uri'] = 'mysql://root:@localhost/cloudkit_example'
4
+ env['cloudkit.storage.uri'] = 'mysql://user:pass@localhost/cloudkit_example'
5
5
  end
6
6
  use Rack::Session::Pool
7
7
  use CloudKit::OAuthFilter
8
8
  use CloudKit::OpenIDFilter
9
9
  use CloudKit::Service, :collections => [:notes]
10
- run lambda{|env| [200, {}, ['HELLO']]}
10
+ run lambda{|env| [200, {'Content-Type' => 'text/html'}, ['HELLO']]}
@@ -27,6 +27,7 @@ require 'cloudkit/oauth_store'
27
27
  require 'cloudkit/openid_filter'
28
28
  require 'cloudkit/openid_store'
29
29
  require 'cloudkit/rack/builder'
30
+ require 'cloudkit/rack/lint'
30
31
  require 'cloudkit/rack/router'
31
32
  require 'cloudkit/request'
32
33
  require 'cloudkit/service'
@@ -99,7 +99,7 @@ module CloudKit
99
99
  @@store.put(
100
100
  "/cloudkit_oauth_request_tokens/#{token_id}",
101
101
  :json => request_token)
102
- [201, {}, ["oauth_token=#{token_id}&oauth_token_secret=#{secret}"]]
102
+ [201, {'Content-Type' => 'text/html'}, ["oauth_token=#{token_id}&oauth_token_secret=#{secret}"]]
103
103
  end
104
104
 
105
105
  def request_authorization(request)
@@ -186,7 +186,7 @@ module CloudKit
186
186
  @@store.delete(
187
187
  "/cloudkit_oauth_request_tokens/#{request[:oauth_token]}",
188
188
  :etag => request_token_response.etag)
189
- [201, {}, ["oauth_token=#{token_id}&oauth_token_secret=#{secret}"]]
189
+ [201, {'Content-Type' => 'text/html'}, ["oauth_token=#{token_id}&oauth_token_secret=#{secret}"]]
190
190
  end
191
191
 
192
192
  def inject_user_or_challenge(request)
@@ -232,7 +232,8 @@ module CloudKit
232
232
  def challenge_headers(request)
233
233
  {
234
234
  'WWW-Authenticate' => "OAuth realm=\"http://#{request.env['HTTP_HOST']}\"",
235
- 'Link' => discovery_link(request)
235
+ 'Link' => discovery_link(request),
236
+ 'Content-Type' => 'application/json'
236
237
  }
237
238
  end
238
239
 
@@ -242,7 +243,7 @@ module CloudKit
242
243
 
243
244
  def login_redirect(request)
244
245
  request.session['return_to'] = request.url if request.session
245
- [302, {'Location' => request.login_url}, []]
246
+ [302, {'Location' => request.login_url, 'Content-Type' => 'text/html'}, []]
246
247
  end
247
248
 
248
249
  def load_user_from_session(request)
@@ -11,7 +11,7 @@ module CloudKit
11
11
  class OpenIDFilter
12
12
  include Util
13
13
 
14
- @@lock = Mutex.new
14
+ @@lock = Mutex.new
15
15
  @@store = nil
16
16
 
17
17
  def initialize(app, options={})
@@ -21,7 +21,7 @@ module CloudKit
21
21
  def call(env)
22
22
  @@lock.synchronize do
23
23
  @@store = OpenIDStore.new(env[storage_uri_key])
24
- @users = UserStore.new(env[storage_uri_key])
24
+ @users = UserStore.new(env[storage_uri_key])
25
25
  @@store.get_association('x') rescue nil # refresh sqlite3
26
26
  end unless @@store
27
27
 
@@ -39,7 +39,11 @@ module CloudKit
39
39
  else
40
40
  if request.env[challenge_key]
41
41
  store_location(request)
42
- erb(request, :openid_login, request.env[challenge_key], 401)
42
+ erb(
43
+ request,
44
+ :openid_login,
45
+ request.env[challenge_key].merge('Content-Type' => 'text/html'),
46
+ 401)
43
47
  elsif !request.via.include?(oauth_filter_key)
44
48
  store_location(request)
45
49
  login_redirect(request)
@@ -61,7 +65,10 @@ module CloudKit
61
65
 
62
66
  request.env[auth_key] = nil
63
67
  request.flash['info'] = 'You have been logged out.'
64
- response = Rack::Response.new([], 302, {'Location' => request.login_url})
68
+ response = Rack::Response.new(
69
+ [],
70
+ 302,
71
+ {'Location' => request.login_url, 'Content-Type' => 'text/html'})
65
72
  response.delete_cookie('remember_me')
66
73
  response.finish
67
74
  end
@@ -72,14 +79,14 @@ module CloudKit
72
79
 
73
80
  def begin_openid_login(request)
74
81
  begin
75
- response = openid_consumer(request).begin request[:openid_url]
82
+ response = openid_consumer(request).begin(request[:openid_url])
76
83
  rescue => e
77
84
  request.flash[:error] = e
78
85
  return login_redirect(request)
79
86
  end
80
87
 
81
88
  redirect_url = response.redirect_url(base_url(request), full_url(request))
82
- [302, {'Location' => redirect_url}, []]
89
+ [302, {'Location' => redirect_url, 'Content-Type' => 'text/html'}, []]
83
90
  end
84
91
 
85
92
  def complete_openid_login(request)
@@ -116,10 +123,13 @@ module CloudKit
116
123
  user['remember_me_token'] = Base64.encode64(
117
124
  OpenSSL::Random.random_bytes(32)).gsub(/\W/,'')
118
125
  url = request.session.delete('return_to')
119
- response = Rack::Response.new([], 302, {'Location' => (url || '/')})
126
+ response = Rack::Response.new(
127
+ [],
128
+ 302,
129
+ {'Location' => (url || '/'), 'Content-Type' => 'text/html'})
120
130
  response.set_cookie(
121
131
  'remember_me', {
122
- :value => user['remember_me_token'],
132
+ :value => user['remember_me_token'],
123
133
  :expires => Time.at(user['remember_me_expiration']).utc})
124
134
  json = JSON.generate(user)
125
135
  @users.put(user_uri, :etag => user_result.etag, :json => json)
@@ -132,7 +142,7 @@ module CloudKit
132
142
  end
133
143
 
134
144
  def login_redirect(request)
135
- [302, {'Location' => request.login_url}, []]
145
+ [302, {'Location' => request.login_url, 'Content-Type' => 'text/html'}, []]
136
146
  end
137
147
 
138
148
  def base_url(request)
@@ -72,9 +72,11 @@ module CloudKit
72
72
  def use_nonce(server_url, timestamp, salt) #:nodoc:
73
73
  return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew
74
74
 
75
- fragment = URI.escape([server_url, timestamp, salt].join('-'))
76
- uri = "/cloudkit_openid_nonces/#{fragment}"
77
- result = @@store.put(uri, :json => '{}')
75
+ fragment = URI.escape(
76
+ [server_url, timestamp, salt].join('-'),
77
+ Regexp.union(URI::REGEXP::UNSAFE, '/', ':'))
78
+ uri = "/cloudkit_openid_nonces/#{fragment}"
79
+ result = @@store.put(uri, :json => '{}')
78
80
  return (result.status == 201)
79
81
  end
80
82
 
@@ -10,7 +10,7 @@ module Rack #:nodoc:
10
10
  if (env['PATH_INFO'] == '/')
11
11
  [200, {'Content-Type' => 'text/html'}, [welcome]]
12
12
  else
13
- [404, {}, []]
13
+ [404, {'Content-Type' => 'text/html'}, []]
14
14
  end
15
15
  end
16
16
  @ins << default_app if @last_cloudkit_id == @ins.last.object_id
@@ -0,0 +1,12 @@
1
+ module Rack #:nodoc:
2
+ class Lint #:nodoc:
3
+ class InputWrapper
4
+
5
+ # Rack::Lint wraps StringIO but does not pass #string to the underlying
6
+ # object. This patch fixes the issue.
7
+ def string
8
+ @input.string
9
+ end
10
+ end
11
+ end
12
+ end
@@ -39,7 +39,9 @@ module CloudKit::ResponseHelpers
39
39
  end
40
40
 
41
41
  def allow(methods)
42
- CloudKit::Response.new(200, {'Allow' => methods.join(', ')})
42
+ CloudKit::Response.new(
43
+ 200,
44
+ {'Allow' => methods.join(', '), 'Content-Type' => 'application/json'})
43
45
  end
44
46
 
45
47
  def response(status, content='', etag=nil, last_modified=nil, options={})
@@ -21,6 +21,7 @@ end
21
21
 
22
22
  def plain_service
23
23
  Rack::Builder.new do
24
+ use Rack::Lint
24
25
  use Rack::Config do |env|
25
26
  env['cloudkit.storage.uri'] = 'sqlite://service.db'
26
27
  end
@@ -31,6 +32,7 @@ end
31
32
 
32
33
  def authed_service
33
34
  Rack::Builder.new do
35
+ use Rack::Lint
34
36
  use Rack::Config do |env|
35
37
  env['cloudkit.storage.uri'] = 'sqlite://service.db'
36
38
  r = CloudKit::Request.new(env)
@@ -43,6 +45,7 @@ end
43
45
 
44
46
  def openid_app
45
47
  Rack::Builder.new do
48
+ use Rack::Lint
46
49
  use Rack::Session::Pool
47
50
  use CloudKit::OpenIDFilter
48
51
  run echo_env(auth_key)
@@ -14,7 +14,17 @@ class ServiceTest < Test::Unit::TestCase
14
14
  should "return a 501 for unimplemented methods" do
15
15
  response = @request.request('TRACE', '/items')
16
16
  assert_equal 501, response.status
17
- response = @request.request('REJUXTAPOSE', '/items')
17
+
18
+ # disable Rack::Lint so that an invalid HTTP method
19
+ # can be tested
20
+ app = Rack::Builder.new {
21
+ use Rack::Config do |env|
22
+ env['cloudkit.storage.uri'] = 'sqlite://service.db'
23
+ end
24
+ use CloudKit::Service, :collections => [:items, :things]
25
+ run echo_text('nothing')
26
+ }
27
+ response = Rack::MockRequest.new(app).request('REJUXTAPOSE', '/items')
18
28
  assert_equal 501, response.status
19
29
  end
20
30
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Crosby
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-22 00:00:00 -08:00
12
+ date: 2008-12-31 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -82,6 +82,16 @@ dependencies:
82
82
  - !ruby/object:Gem::Version
83
83
  version: 1.1.3
84
84
  version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: sqlite3-ruby
87
+ type: :runtime
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "="
92
+ - !ruby/object:Gem::Version
93
+ version: 1.2.4
94
+ version:
85
95
  description: An Open Web JSON Appliance.
86
96
  email: jon@joncrosby.me
87
97
  executables: []
@@ -92,11 +102,11 @@ extra_rdoc_files: []
92
102
 
93
103
  files:
94
104
  - CHANGES
95
- - cloudkit.gemspec
96
105
  - COPYING
97
106
  - README
98
107
  - Rakefile
99
108
  - TODO
109
+ - cloudkit.gemspec
100
110
  - doc/curl.html
101
111
  - doc/images/example-code.gif
102
112
  - doc/images/json-title.gif
@@ -119,6 +129,7 @@ files:
119
129
  - lib/cloudkit/openid_filter.rb
120
130
  - lib/cloudkit/openid_store.rb
121
131
  - lib/cloudkit/rack/builder.rb
132
+ - lib/cloudkit/rack/lint.rb
122
133
  - lib/cloudkit/rack/router.rb
123
134
  - lib/cloudkit/request.rb
124
135
  - lib/cloudkit/service.rb