rackful 0.1.4 → 0.2.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.
- checksums.yaml +7 -0
- data/CHANGES.md +18 -8
- data/RACKFUL.md +46 -34
- data/README.md +11 -5
- data/example/config.ru +19 -25
- data/lib/rackful.rb +11 -2
- data/lib/rackful/httpstatus.rb +250 -0
- data/lib/rackful/middleware.rb +2 -3
- data/lib/rackful/middleware/headerspoofing.rb +49 -0
- data/lib/rackful/middleware/methodoverride.rb +136 -0
- data/lib/rackful/parser.rb +315 -0
- data/lib/rackful/request.rb +103 -53
- data/lib/rackful/resource.rb +158 -221
- data/lib/rackful/serializer.rb +133 -215
- data/lib/rackful/server.rb +76 -86
- data/lib/rackful/uri.rb +150 -0
- data/mkdoc.sh +4 -2
- data/rackful.gemspec +6 -5
- metadata +66 -58
- data/lib/rackful/http_status.rb +0 -285
- data/lib/rackful/middleware/header_spoofing.rb +0 -72
- data/lib/rackful/middleware/method_spoofing.rb +0 -101
- data/lib/rackful/middleware/relative_location.rb +0 -71
- data/lib/rackful/path.rb +0 -179
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9219f743c670f4a149826fcf581a97e7c08251d6
|
4
|
+
data.tar.gz: 10ec5c1eb9c59f3d7adda6ed9be9518773311ba9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f3d112684686175bc973cd240cce7bf899684fe115184ea94b0cd4797d49aa45a1b939983f5af12f9cc3702a03eb541030023319205996bae5b951711e2fd783
|
7
|
+
data.tar.gz: a44bd266844173251e1c0a4ac35c9b7a3be32a77bfd4e369773cb6b49cecc47867e766e04cc8d0bf3eb0f2cbe28779dda4a7b52823b9104ce9e585ad0fec342b
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
0.2.x
|
2
|
+
=====
|
3
|
+
The 0.2.x series is a major revision, not backward compatible with 0.1.x.
|
4
|
+
|
5
|
+
0.2.0
|
6
|
+
-----
|
7
|
+
* Removed Request::current, because it won’t work well with single-threaded
|
8
|
+
concurrency models (fibers, eventmachine and the like) and it’s not essential.
|
9
|
+
* Rackful::Server#call was made reentrant. This is necessary for response code
|
10
|
+
100 Continue.
|
11
|
+
|
1
12
|
0.1.x
|
2
13
|
=====
|
3
14
|
The 0.1.x series is a major revision, not backward compatible with 0.0.x.
|
@@ -9,18 +20,17 @@ The 0.1.x series is a major revision, not backward compatible with 0.0.x.
|
|
9
20
|
|
10
21
|
0.1.0
|
11
22
|
-----
|
12
|
-
* Complete revision of the
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
serializers, especially for hypermedia, to distinguish paths from "ordinary"
|
23
|
+
* Complete revision of the `Rackful::HTTPStatus` exception class. From now on, there’s
|
24
|
+
a separate class for each HTTP status code, e.g. `Rackful::HTTP404NotFound`.
|
25
|
+
* `Rackful::Path`, a subclass of `String`, is used for HTTP paths. This allows
|
26
|
+
serializers, especially for hypermedia, to distinguish paths from “ordinary”
|
17
27
|
strings, and render them accordingly.
|
18
|
-
* The concept of
|
28
|
+
* The concept of `Rackful::Serializer Serializers` was introduced. A serializer
|
19
29
|
is an object that knows how to serialize an object to a certain media type.
|
20
30
|
* The mechanism for content negotiation has changed completely. See
|
21
|
-
|
31
|
+
`Rackful::Resource#serializer` and `Rackful::Resource::ClassMethods#best_content_type`.
|
22
32
|
* The mechanism for implementing HTTP method handlers has changed. See
|
23
|
-
|
33
|
+
`Rackful::Resource#do_METHOD` and `Rackful::Resource::ClassMethods#add_parser`.
|
24
34
|
|
25
35
|
0.0.x
|
26
36
|
=====
|
data/RACKFUL.md
CHANGED
@@ -1,25 +1,27 @@
|
|
1
|
-
Rackful
|
2
|
-
=======
|
1
|
+
# @title Rackful
|
3
2
|
|
4
|
-
Library for creating
|
3
|
+
Library for creating ReSTful web services
|
5
4
|
|
6
|
-
The latest documentation
|
7
|
-
[here, as GitHub pages](http://pieterb.github.com/Rackful/).
|
5
|
+
The latest “stable” documentation can be found here:
|
8
6
|
|
9
|
-
|
10
|
-
|
7
|
+
* [User documentation](http://pieterb.github.com/Rackful/)
|
8
|
+
* [Developer documentation](http://pieterb.github.com/Rackful/devel/) (includes
|
9
|
+
documentation for private methods and other internals)
|
11
10
|
|
12
|
-
|
11
|
+
Overview
|
12
|
+
========
|
13
|
+
|
14
|
+
Confronted with the task of implementing a ReSTful web service in Ruby, I
|
13
15
|
checked out a number of existing libraries and frameworks, including
|
14
|
-
Ruby-on-Rails, and then decided to brew my own, the reason being that I couldn
|
16
|
+
Ruby-on-Rails, and then decided to brew my own, the reason being that I couldn’t
|
15
17
|
find a library or framework with all of the following properties:
|
16
18
|
|
17
19
|
* **Small** Some of these frameworks are really big. I need to get a job done in
|
18
20
|
time. If understanding the framework takes more time than writing my own, I
|
19
|
-
must at least feel confident that the framework I
|
21
|
+
must at least feel confident that the framework I’m learning is more powerful
|
20
22
|
that what I can come up with by myself. Ruby-on-Rails is probably the biggest
|
21
23
|
framework out there, and it still lacks many features that are essential to
|
22
|
-
|
24
|
+
ReSTful web service programming.
|
23
25
|
|
24
26
|
This library is small. You could read _all_ the source code in less than an
|
25
27
|
hour, and understand every detail.
|
@@ -28,20 +30,20 @@ find a library or framework with all of the following properties:
|
|
28
30
|
subject of more than one flame-war over the years. Not much I can add to the
|
29
31
|
debate...
|
30
32
|
|
31
|
-
_...but,_ with Ruby, you shouldn
|
32
|
-
Unless, of course, you
|
33
|
+
_...but,_ with Ruby, you shouldn’t _need_ code generation!
|
34
|
+
Unless, of course, you’re an ex-Java programmer and/or don’t understand
|
33
35
|
meta-programming.
|
34
36
|
|
35
37
|
* **Full support for conditional requests** using `If-*:` request headers. Most
|
36
|
-
libraries
|
37
|
-
headers, and only for `GET` and `HEAD` requests. For
|
38
|
+
libraries’ support is limited to `If-None-Match:` and `If-Modified-Since:`
|
39
|
+
headers, and only for `GET` and `HEAD` requests. For ReSTful web services,
|
38
40
|
the `If-Match:` and `If-Unmodified-Since:` headers are at least as important,
|
39
41
|
particularly for unsafe methods like `PUT`, `POST`, `PATCH`, and `DELETE`.
|
40
42
|
|
41
43
|
This library fully supports the `ETag:` and `Last-Modified:` headers, and all
|
42
44
|
`If-*:` headers.
|
43
45
|
|
44
|
-
* **Resource centered** Some libraries claim
|
46
|
+
* **Resource centered** Some libraries claim ReSTfulness, but at the same
|
45
47
|
time have a servet-like interface, which requires you to implement method
|
46
48
|
handles such as `doPOST(url)`. In these method handlers you have to find out
|
47
49
|
what resource is posted to, depending on the URL.
|
@@ -52,7 +54,7 @@ find a library or framework with all of the following properties:
|
|
52
54
|
Hello World!
|
53
55
|
------------
|
54
56
|
|
55
|
-
Here
|
57
|
+
Here’s a working example of a simple ReSTful server:
|
56
58
|
|
57
59
|
{include:file:example/config.ru}
|
58
60
|
|
@@ -67,7 +69,7 @@ something like this:
|
|
67
69
|
|
68
70
|
Go with your browser to {http://localhost:9292/} and be greeted.
|
69
71
|
|
70
|
-
In this example, we implement `GET` and `PUT` requests for the resource at
|
72
|
+
In this example, we implement `GET` and `PUT` requests for the resource at “/”. but
|
71
73
|
we get a few things for free:
|
72
74
|
|
73
75
|
### Free `OPTIONS` response:
|
@@ -79,36 +81,36 @@ Request:
|
|
79
81
|
|
80
82
|
Response:
|
81
83
|
|
82
|
-
HTTP/1.1 204 No Content
|
84
|
+
HTTP/1.1 204 No Content
|
83
85
|
Allow: PUT, GET, HEAD, OPTIONS
|
84
86
|
Date: Tue, 10 Jul 2012 10:22:52 GMT
|
85
87
|
|
86
88
|
As you can see, the server accurately reports all available methods for the
|
87
89
|
resource. Notice the availability of the `HEAD` method; if you implement the
|
88
|
-
`GET` method, you
|
90
|
+
`GET` method, you’ll get `HEAD` for free. It’s still a good idea to explicitly
|
89
91
|
implement your own `HEAD` request handler, especially for expensive resources,
|
90
92
|
when responding to a `HEAD` request should be much more efficient than generating
|
91
93
|
a full `GET` response, and strip off the response body.
|
92
94
|
|
93
95
|
### Free conditional request handling:
|
94
96
|
|
95
|
-
Let
|
97
|
+
Let’s first get the current state of the resource, with this request:
|
96
98
|
|
97
99
|
GET / HTTP/1.1
|
98
100
|
Host: localhost:9292
|
99
101
|
|
100
102
|
Response:
|
101
103
|
|
102
|
-
HTTP/1.1 200 OK
|
104
|
+
HTTP/1.1 200 OK
|
103
105
|
Content-Type: text/plain
|
104
106
|
Content-Length: 12
|
105
107
|
ETag: "86fb269d190d2c85f6e0468ceca42a20"
|
106
108
|
Date: Tue, 10 Jul 2012 10:34:36 GMT
|
107
|
-
|
109
|
+
|
108
110
|
Hello world!
|
109
111
|
|
110
|
-
Now, we
|
111
|
-
the state we last saw, to avoid the
|
112
|
+
Now, we’d like to change the state of the resource, but only if it’s still in
|
113
|
+
the state we last saw, to avoid the “lost update problem”. To do that, we
|
112
114
|
produce an `If-Match:` header, with the entity tag of our last version:
|
113
115
|
|
114
116
|
PUT / HTTP/1.1
|
@@ -116,7 +118,7 @@ produce an `If-Match:` header, with the entity tag of our last version:
|
|
116
118
|
Content-Type: text/plain
|
117
119
|
Content-Length: 31
|
118
120
|
If-Match: "86fb269d190d2c85f6e0468ceca42a20"
|
119
|
-
|
121
|
+
|
120
122
|
All your base are belong to us.
|
121
123
|
|
122
124
|
Response:
|
@@ -131,7 +133,7 @@ resource. When we replay this request, we get the following response:
|
|
131
133
|
HTTP/1.1 412 Precondition Failed
|
132
134
|
Content-Type: text/html; charset="UTF-8"
|
133
135
|
Date: Tue, 10 Jul 2012 11:06:54 GMT
|
134
|
-
|
136
|
+
|
135
137
|
[...]
|
136
138
|
<h1>HTTP/1.1 412 Precondition Failed</h1>
|
137
139
|
<p>If-Match: "86fb269d190d2c85f6e0468ceca42a20"</p>
|
@@ -143,17 +145,27 @@ response body, the server kindly points out exactly which precondition.
|
|
143
145
|
Further reading
|
144
146
|
---------------
|
145
147
|
* {Rackful::Server#initialize} for more information about your Resource Factory.
|
146
|
-
* {Rackful::Resource#get\_etag} and {Rackful::Resource#get\_last\_modified} for more
|
147
|
-
conditional requests.
|
148
|
+
* {Rackful::Resource#get\_etag} and {Rackful::Resource#get\_last\_modified} for more
|
149
|
+
information on conditional requests.
|
148
150
|
* {Rackful::Resource#do\_METHOD} for more information about writing your own request
|
149
151
|
handlers.
|
150
|
-
|
151
|
-
|
152
|
-
|
152
|
+
|
153
|
+
Development
|
154
|
+
===========
|
155
|
+
Some conventions used throughout the code and documentation:
|
156
|
+
|
157
|
+
* In {Rack}, URLs are represented by Ruby Strings. In Rackful, URLs are
|
158
|
+
represented by objects of class {::URI::HTTP} wherever possible. This can
|
159
|
+
lead to confusion. As a convention, methods and variables that return/contain
|
160
|
+
a URL String have `url` in their names. while methods and variables that
|
161
|
+
return/contain a {::URI::HTTP} object have `uri` in their names. Yes, it’s
|
162
|
+
ugly, but it helps.
|
163
|
+
* URI’s are stored and passed around in their {::URI::Generic#normalize normalized}
|
164
|
+
form wherever possible.
|
153
165
|
|
154
166
|
Licensing
|
155
|
-
|
156
|
-
Copyright ©2011-
|
167
|
+
=========
|
168
|
+
Copyright ©2011-2014 Pieter van Beek <pieter@djinnit.com>
|
157
169
|
|
158
170
|
Licensed under the {file:LICENSE.md Apache License 2.0}. You should have received a copy of the
|
159
171
|
license as part of this distribution.
|
data/README.md
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
Rackful
|
2
2
|
=======
|
3
3
|
|
4
|
-
Library for creating
|
4
|
+
Library for creating ReSTful web services
|
5
5
|
|
6
|
-
The latest documentation
|
7
|
-
|
6
|
+
The latest “stable” documentation can be found here:
|
7
|
+
|
8
|
+
* [User documentation](http://pieterb.github.com/Rackful/)
|
9
|
+
* [Developer documentation](http://pieterb.github.com/Rackful/devel/) (includes
|
10
|
+
documentation for private methods and other internals)
|
11
|
+
|
12
|
+
Documentation for older versions:
|
13
|
+
* [User documentation v0.1.5](http://pieterb.github.com/Rackful/0.1.5)
|
8
14
|
|
9
15
|
Licensing
|
10
16
|
---------
|
11
|
-
Copyright ©2011-
|
17
|
+
Copyright ©2011-2014 Pieter van Beek <pieter@djinnit.com>
|
12
18
|
|
13
|
-
Licensed under the Apache License 2.0. You should have received a copy of the
|
19
|
+
Licensed under the {file:LICENSE.md Apache License 2.0}. You should have received a copy of the
|
14
20
|
license as part of this distribution.
|
data/example/config.ru
CHANGED
@@ -1,44 +1,38 @@
|
|
1
1
|
# Load core functionality:
|
2
2
|
require 'rackful'
|
3
3
|
|
4
|
-
# Load extra middlewares: ({Rackful::
|
5
|
-
# Rackful::RelativeLocation})
|
4
|
+
# Load extra middlewares: ({Rackful::MethodOverride}, {Rackful::HeaderSpoofing})
|
6
5
|
require 'rackful/middleware'
|
7
6
|
|
8
7
|
require 'digest/md5'
|
9
8
|
|
10
9
|
# The class of the object we're going to serve:
|
11
|
-
class Root
|
12
|
-
include Rackful::Resource
|
10
|
+
class Root < Rackful::Resource
|
13
11
|
attr_reader :to_rackful
|
14
12
|
def initialize
|
15
|
-
|
16
|
-
@to_rackful =
|
13
|
+
super( 'http://localhost:9292/hallo_wereld' )
|
14
|
+
@to_rackful = {
|
15
|
+
:a => 'Hello',
|
16
|
+
:b => Time.now,
|
17
|
+
:c => URI('http://www.example.com/some/path') }
|
17
18
|
end
|
18
19
|
def do_PUT request, response
|
19
|
-
@to_rackful =
|
20
|
+
@to_rackful = self.parser(request).parse
|
20
21
|
end
|
21
22
|
def get_etag
|
22
|
-
'"' + Digest::MD5.new.update(to_rackful).to_s + '"'
|
23
|
+
'"' + Digest::MD5.new.update(to_rackful.inspect).to_s + '"'
|
23
24
|
end
|
24
|
-
add_serializer Rackful::XHTML, 1.0
|
25
|
-
add_serializer Rackful::JSON,
|
26
|
-
|
25
|
+
add_serializer Rackful::Serializer::XHTML, 1.0
|
26
|
+
add_serializer Rackful::Serializer::JSON, 0.5
|
27
|
+
add_parser Rackful::Parser::XHTML
|
28
|
+
add_parser Rackful::Parser::JSON
|
27
29
|
end
|
28
|
-
$root_resource =
|
30
|
+
$root_resource = nil
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
def [] uri
|
33
|
-
case uri
|
34
|
-
when '/'; $root_resource
|
35
|
-
else; nil
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
use Rackful::MethodSpoofing
|
32
|
+
use Rack::Reloader
|
33
|
+
use Rackful::MethodOverride
|
41
34
|
use Rackful::HeaderSpoofing
|
42
|
-
use Rackful::RelativeLocation
|
43
35
|
|
44
|
-
run Rackful::Server.new
|
36
|
+
run Rackful::Server.new { |uri|
|
37
|
+
$root_resource ||= Root.new
|
38
|
+
}
|
data/lib/rackful.rb
CHANGED
@@ -1,6 +1,15 @@
|
|
1
|
-
require '
|
1
|
+
require 'uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'rack'
|
4
|
+
require 'rack/utils'
|
5
|
+
require 'base64'
|
6
|
+
require 'time'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
require 'rackful/uri.rb'
|
2
10
|
require 'rackful/request.rb'
|
3
11
|
require 'rackful/serializer.rb'
|
12
|
+
require 'rackful/parser.rb'
|
4
13
|
require 'rackful/resource.rb'
|
5
|
-
require 'rackful/
|
14
|
+
require 'rackful/httpstatus.rb'
|
6
15
|
require 'rackful/server.rb'
|
@@ -0,0 +1,250 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Required for parsing:
|
3
|
+
require 'rackful/resource.rb'
|
4
|
+
require 'rackful/serializer.rb'
|
5
|
+
|
6
|
+
|
7
|
+
module Rackful
|
8
|
+
|
9
|
+
=begin markdown
|
10
|
+
Exception which represents an HTTP Status response.
|
11
|
+
@abstract
|
12
|
+
=end
|
13
|
+
class HTTPStatus < RuntimeError
|
14
|
+
|
15
|
+
|
16
|
+
class Resource < ::Rackful::Resource
|
17
|
+
class XHTML < Serializer::XHTML
|
18
|
+
|
19
|
+
|
20
|
+
def header
|
21
|
+
retval = super
|
22
|
+
retval += "<h1>HTTP/1.1 #{Rack::Utils.escape_html(resource.title)}</h1>\n"
|
23
|
+
unless resource.message.empty?
|
24
|
+
retval += "<div id=\"rackful-description\">#{resource.message}</div>\n"
|
25
|
+
end
|
26
|
+
retval
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def headers; self.resource.headers; end
|
31
|
+
|
32
|
+
|
33
|
+
end # class Rackful::HTTPStatus::XHTML
|
34
|
+
|
35
|
+
|
36
|
+
add_serializer XHTML, 1.0
|
37
|
+
|
38
|
+
extend Forwardable
|
39
|
+
def_delegators :@http_status_object, :headers, :to_rackful, :title, :message
|
40
|
+
|
41
|
+
|
42
|
+
def initialize(uri, http_status_object)
|
43
|
+
super(uri)
|
44
|
+
@http_status_object = http_status_object
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
end # class Rackful::HTTPStatus::Resource
|
49
|
+
|
50
|
+
|
51
|
+
attr_reader :status, :headers, :to_rackful
|
52
|
+
|
53
|
+
|
54
|
+
=begin markdown
|
55
|
+
@param status [Symbol, Integer] e.g. `404` or `:not_found`
|
56
|
+
@param message [String] XHTML
|
57
|
+
@param info [ { Symbol => Object, String => String } ]
|
58
|
+
* **Objects** indexed by **Symbols** are returned in the response body.
|
59
|
+
* **Strings** indexed by **Strings** are returned as response headers.
|
60
|
+
=end
|
61
|
+
def initialize status, message = nil, info = {}
|
62
|
+
@status = Rack::Utils.status_code status
|
63
|
+
raise "Wrong status: #{status}" if 0 === @status
|
64
|
+
message ||= ''
|
65
|
+
@headers = {}
|
66
|
+
@to_rackful = {}
|
67
|
+
info.each do
|
68
|
+
|k, v|
|
69
|
+
if k.kind_of? Symbol
|
70
|
+
@to_rackful[k] = v
|
71
|
+
else
|
72
|
+
@headers[k] = v.to_s
|
73
|
+
end
|
74
|
+
end
|
75
|
+
@to_rackful = nil if @to_rackful.empty?
|
76
|
+
if message
|
77
|
+
message = message.to_s
|
78
|
+
begin
|
79
|
+
Nokogiri.XML(
|
80
|
+
'<?xml version="1.0" encoding="UTF-8" ?>' +
|
81
|
+
"<div>#{message}</div>"
|
82
|
+
) do |config| config.strict.nonet end
|
83
|
+
rescue
|
84
|
+
message = Rack::Utils.escape_html(message)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
super message
|
88
|
+
end
|
89
|
+
|
90
|
+
def serializer request
|
91
|
+
Resource.new( request.url, self ).serializer( request )
|
92
|
+
end
|
93
|
+
|
94
|
+
def title
|
95
|
+
"#{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}"
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
end # class Rackful::HTTPStatus
|
101
|
+
|
102
|
+
|
103
|
+
=begin markdown
|
104
|
+
@abstract Base class for HTTP status codes with only a simple text message, or
|
105
|
+
no message at all.
|
106
|
+
=end
|
107
|
+
class HTTPSimpleStatus < HTTPStatus
|
108
|
+
|
109
|
+
def initialize message = nil
|
110
|
+
/HTTP(\d\d\d)\w+\z/ === self.class.to_s
|
111
|
+
status = $1.to_i
|
112
|
+
super( status, message )
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
class HTTP201Created < HTTPStatus
|
119
|
+
|
120
|
+
def initialize locations
|
121
|
+
locations = [ locations ] unless locations.kind_of? Array
|
122
|
+
locations = locations.collect { |l| URI(l) }
|
123
|
+
if locations.size > 1
|
124
|
+
super( 201, 'New resources were created:', :locations => locations )
|
125
|
+
else
|
126
|
+
location = locations[0]
|
127
|
+
super(
|
128
|
+
201, 'A new resource was created:',
|
129
|
+
:"Location" => location, 'Location' => location
|
130
|
+
)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
class HTTP202Accepted < HTTPStatus
|
138
|
+
|
139
|
+
def initialize location = nil
|
140
|
+
if location
|
141
|
+
location = URI(location)
|
142
|
+
super(
|
143
|
+
202, "The request body you sent has been accepted for processing.",
|
144
|
+
:"Job status location:" => location, 'Location' => location
|
145
|
+
)
|
146
|
+
else
|
147
|
+
super 202
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
class HTTP301MovedPermanently < HTTPStatus
|
155
|
+
|
156
|
+
def initialize location
|
157
|
+
location = URI(location)
|
158
|
+
super( 301, '', :'New location:' => location, 'Location' => location )
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
class HTTP303SeeOther < HTTPStatus
|
165
|
+
|
166
|
+
def initialize location
|
167
|
+
location = URI(location)
|
168
|
+
super( 303, '', :'See:' => location, 'Location' => location )
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
class HTTP304NotModified < HTTPStatus
|
175
|
+
|
176
|
+
def initialize
|
177
|
+
super( 304 )
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
class HTTP307TemporaryRedirect < HTTPStatus
|
184
|
+
|
185
|
+
def initialize location
|
186
|
+
location = URI(location)
|
187
|
+
super( 301, '', :'Current location:' => location, 'Location' => location )
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
class HTTP400BadRequest < HTTPSimpleStatus; end
|
194
|
+
|
195
|
+
class HTTP403Forbidden < HTTPSimpleStatus; end
|
196
|
+
|
197
|
+
class HTTP404NotFound < HTTPSimpleStatus; end
|
198
|
+
|
199
|
+
|
200
|
+
class HTTP405MethodNotAllowed < HTTPStatus
|
201
|
+
|
202
|
+
def initialize methods
|
203
|
+
super( 405, '', 'Allow' => methods.join(', '), :'Allowed methods:' => methods )
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
class HTTP406NotAcceptable < HTTPStatus
|
210
|
+
|
211
|
+
def initialize content_types
|
212
|
+
super( 406, '', :'Available content-type(s):' => content_types )
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
class HTTP409Conflict < HTTPSimpleStatus; end
|
219
|
+
|
220
|
+
class HTTP410Gone < HTTPSimpleStatus; end
|
221
|
+
|
222
|
+
class HTTP411LengthRequired < HTTPSimpleStatus; end
|
223
|
+
|
224
|
+
|
225
|
+
class HTTP412PreconditionFailed < HTTPStatus
|
226
|
+
|
227
|
+
def initialize header = nil
|
228
|
+
info = header ? { :'Failed precondition:' => header } : {}
|
229
|
+
super( 412, '', info )
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
class HTTP415UnsupportedMediaType < HTTPStatus
|
236
|
+
|
237
|
+
def initialize media_types
|
238
|
+
super( 415, '', :'Supported media-type(s):' => media_types )
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
class HTTP422UnprocessableEntity < HTTPSimpleStatus; end
|
245
|
+
|
246
|
+
class HTTP501NotImplemented < HTTPSimpleStatus; end
|
247
|
+
|
248
|
+
class HTTP503ServiceUnavailable < HTTPSimpleStatus; end
|
249
|
+
|
250
|
+
end # module Rackful
|