webbed 0.1.1 → 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.
- data/.gitignore +22 -0
- data/.travis.yml +7 -0
- data/.yardopts +6 -0
- data/Gemfile +5 -13
- data/Guardfile +5 -0
- data/README.md +36 -31
- data/Rakefile +7 -14
- data/lib/webbed.rb +28 -6
- data/lib/webbed/generic_message.rb +27 -15
- data/lib/webbed/headers.rb +2 -0
- data/lib/webbed/helpers/entity_headers_helper.rb +62 -0
- data/lib/webbed/helpers/method_helper.rb +83 -0
- data/lib/webbed/helpers/rack_request_helper.rb +86 -0
- data/lib/webbed/helpers/rack_response_helper.rb +56 -0
- data/lib/webbed/helpers/request_headers_helper.rb +62 -0
- data/lib/webbed/helpers/request_uri_helper.rb +34 -0
- data/lib/webbed/helpers/response_headers_helper.rb +48 -0
- data/lib/webbed/helpers/scheme_helper.rb +26 -0
- data/lib/webbed/http_version.rb +88 -33
- data/lib/webbed/media_type.rb +160 -0
- data/lib/webbed/method.rb +63 -33
- data/lib/webbed/request.rb +65 -21
- data/lib/webbed/response.rb +65 -24
- data/lib/webbed/status_code.rb +84 -17
- data/lib/webbed/version.rb +1 -1
- data/test/support/assertions.rb +17 -0
- data/test/support/runner.rb +326 -0
- data/test/test_helper.rb +13 -0
- data/test/webbed/generic_message_test.rb +44 -0
- data/test/webbed/headers_test.rb +31 -0
- data/test/webbed/helpers/entity_headers_helper_test.rb +68 -0
- data/test/webbed/helpers/method_helper_test.rb +151 -0
- data/test/webbed/helpers/rack_request_helper_test.rb +108 -0
- data/test/webbed/helpers/rack_response_helper_test.rb +33 -0
- data/test/webbed/helpers/request_headers_helper_test.rb +57 -0
- data/test/webbed/helpers/request_uri_helper_test.rb +32 -0
- data/test/webbed/helpers/response_headers_helper_test.rb +46 -0
- data/test/webbed/helpers/scheme_helper_test.rb +28 -0
- data/test/webbed/http_version_test.rb +52 -0
- data/test/webbed/media_type_test.rb +100 -0
- data/test/webbed/method_test.rb +160 -0
- data/test/webbed/request_test.rb +74 -0
- data/test/webbed/response_test.rb +86 -0
- data/test/webbed/status_code_test.rb +105 -0
- data/webbed.gemspec +31 -0
- metadata +128 -41
data/lib/webbed/method.rb
CHANGED
@@ -1,64 +1,94 @@
|
|
1
1
|
module Webbed
|
2
|
+
# Representation of an HTTP Method.
|
2
3
|
class Method
|
3
|
-
|
4
|
-
attr_reader :name
|
5
|
-
alias :to_s :name
|
6
|
-
alias :inspect :name
|
7
|
-
|
8
4
|
DEFAULTS = {
|
9
5
|
:safe => false,
|
10
6
|
:idempotent => false,
|
11
|
-
:
|
7
|
+
:allowable_entities => [:request, :response]
|
12
8
|
}
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
# The allowable entities of a message.
|
11
|
+
#
|
12
|
+
# It can contain any combination of `:request` and `:response`.
|
13
|
+
#
|
14
|
+
# @return [Array<:request, :response>]
|
15
|
+
attr_reader :allowable_entities
|
16
|
+
|
17
|
+
# Checks for a cached Method or creates a new one.
|
18
|
+
#
|
19
|
+
# It caches the standard HTTP Methods that are in RFC 2616 as well as the
|
20
|
+
# new method `PATCH`. If the Method cannot be found, it calls `#initialize`.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# Webbed::Method.new('GET') # => Webbed::Method::GET
|
24
|
+
#
|
25
|
+
# @param (see #initialize)
|
26
|
+
# @return [Method] the new or cached Method
|
27
|
+
# @see #initialize
|
28
|
+
def self.new(value, options = {})
|
29
|
+
if const_defined?(value)
|
30
|
+
const_get(value)
|
17
31
|
else
|
18
|
-
super(
|
32
|
+
super(value, options)
|
19
33
|
end
|
20
34
|
end
|
21
35
|
|
36
|
+
# Creates a new Method.
|
37
|
+
#
|
38
|
+
# @param [String] name the name of the Method to create
|
39
|
+
# @param [Hash] options the options to create the Method with
|
40
|
+
# @option options [Boolean] :safe (false) whether or not the Method is safe
|
41
|
+
# @option options [Boolean] :idempotent (false) whether or not the Method is
|
42
|
+
# idempotent
|
43
|
+
# @option options [Array<:request, :response>] :allowable_entities
|
44
|
+
# ([:request, :response]) the allowable entites of a message
|
22
45
|
def initialize(name, options = {})
|
23
|
-
options = DEFAULTS.merge
|
46
|
+
options = DEFAULTS.merge(options)
|
24
47
|
@name = name
|
25
48
|
@safe = options[:safe]
|
26
49
|
@idempotent = options[:safe] || options[:idempotent]
|
27
|
-
@
|
28
|
-
@has_response_entity = options[:entities].include? :response
|
50
|
+
@allowable_entities = options[:allowable_entities]
|
29
51
|
end
|
30
52
|
|
53
|
+
# Whether or not the Method is safe.
|
54
|
+
#
|
55
|
+
# @return [Boolean]
|
31
56
|
def safe?
|
32
57
|
@safe
|
33
58
|
end
|
34
59
|
|
60
|
+
# Whether or not the Method is idempotent.
|
61
|
+
#
|
62
|
+
# @return [Boolean]
|
35
63
|
def idempotent?
|
36
64
|
@idempotent
|
37
65
|
end
|
38
66
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@has_response_entity
|
67
|
+
# Converts the Method to a string.
|
68
|
+
#
|
69
|
+
# @return [String]
|
70
|
+
def to_s
|
71
|
+
@name
|
45
72
|
end
|
46
73
|
|
74
|
+
# Compares the Method to another Method.
|
75
|
+
#
|
76
|
+
# Two Methods are equal if they have the same name.
|
77
|
+
#
|
78
|
+
# @param [#to_s] other_method the other Method
|
79
|
+
# @return [Boolean]
|
47
80
|
def ==(other_method)
|
48
|
-
|
81
|
+
to_s == other_method.to_s
|
49
82
|
end
|
50
83
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
TRACE = new 'TRACE', :safe => true, :idempotent => true, :entities => [:response]
|
61
|
-
CONNECT = new 'CONNECT', :safe => false, :idempotent => false, :entities => [:request, :response]
|
62
|
-
PATCH = new 'PATCH', :safe => false, :idempotent => false, :entities => [:request, :response]
|
84
|
+
OPTIONS = new('OPTIONS', :safe => true, :idempotent => true, :allowable_entities => [:response])
|
85
|
+
GET = new('GET', :safe => true, :idempotent => true, :allowable_entities => [:response])
|
86
|
+
HEAD = new('HEAD', :safe => true, :idempotent => true, :allowable_entities => [])
|
87
|
+
POST = new('POST', :safe => false, :idempotent => false, :allowable_entities => [:request, :response])
|
88
|
+
PUT = new('PUT', :safe => false, :idempotent => true, :allowable_entities => [:request, :response])
|
89
|
+
DELETE = new('DELETE', :safe => false, :idempotent => true, :allowable_entities => [:response])
|
90
|
+
TRACE = new('TRACE', :safe => true, :idempotent => true, :allowable_entities => [:response])
|
91
|
+
CONNECT = new('CONNECT', :safe => false, :idempotent => false, :allowable_entities => [:request, :response])
|
92
|
+
PATCH = new('PATCH', :safe => false, :idempotent => false, :allowable_entities => [:request, :response])
|
63
93
|
end
|
64
|
-
end
|
94
|
+
end
|
data/lib/webbed/request.rb
CHANGED
@@ -1,44 +1,88 @@
|
|
1
1
|
require 'addressable/uri'
|
2
2
|
|
3
3
|
module Webbed
|
4
|
+
# Representation of an HTTP Request.
|
5
|
+
#
|
6
|
+
# This class contains the absolute minimum for accessing the different parts
|
7
|
+
# of an HTTP Request. Helper modules provide far more functionality.
|
4
8
|
class Request
|
9
|
+
include GenericMessage
|
5
10
|
|
6
|
-
|
11
|
+
# The Request-URI of the Request.
|
12
|
+
#
|
13
|
+
# The method automatically converts the new value to an instance of
|
14
|
+
# `Addressable::URI` if it is not already one.
|
15
|
+
#
|
16
|
+
# @return [Addressable::URI]
|
17
|
+
# @note {Helpers::RequestURIHelper} aliases this method to `#request_url`.
|
7
18
|
attr_reader :request_uri
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
|
20
|
+
def request_uri=(request_uri)
|
21
|
+
@request_uri = Addressable::URI.parse(request_uri)
|
22
|
+
end
|
23
|
+
|
24
|
+
# The scheme of the Request.
|
25
|
+
#
|
26
|
+
# @return ['http', 'https']
|
27
|
+
attr_accessor :scheme
|
28
|
+
|
29
|
+
# Creates a new Request.
|
30
|
+
#
|
31
|
+
# The method converts the values passed in to their proper types.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# Webbed::Request.new('GET', 'http://example.com', {}, '')
|
35
|
+
#
|
36
|
+
# @param [Method, String] method
|
37
|
+
# @param [Addressable::URI, String] request_uri
|
38
|
+
# @param [Headers, Hash] headers
|
39
|
+
# @param [#to_s] entity_body
|
40
|
+
# @param [Array] options the options to create the Request with
|
41
|
+
# @option options [#to_s] :http_version (1.1) the HTTP-Version of the
|
42
|
+
# Request
|
43
|
+
# @option options ['http', 'https'] :scheme ('http') the scheme of the
|
44
|
+
# Request
|
45
|
+
def initialize(method, request_uri, headers, entity_body, options = {})
|
46
|
+
self.method = method
|
47
|
+
self.request_uri = request_uri
|
48
|
+
self.headers = headers
|
49
|
+
self.entity_body = entity_body
|
50
|
+
self.http_version = options[:http_version] || 1.1
|
51
|
+
self.scheme = options[:scheme] || 'http'
|
24
52
|
end
|
25
53
|
|
54
|
+
# The Method of the Request.
|
55
|
+
#
|
56
|
+
# @return [Method]
|
26
57
|
def method(*args)
|
27
58
|
return super(*args) unless args.empty?
|
28
59
|
@method
|
29
60
|
end
|
30
61
|
|
62
|
+
# Sets the Method of the Request.
|
63
|
+
#
|
64
|
+
# @param [Method] method
|
31
65
|
def method=(method)
|
32
66
|
@method = Webbed::Method.new(method)
|
33
67
|
end
|
34
68
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
69
|
+
# The Request-Line of the Request as defined in RFC 2616.
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# request = Webbed::Request.new(['GET', 'http://example.com', {}, ''])
|
73
|
+
# request.request_line # => "GET * HTTP/1.1\r\n"
|
74
|
+
#
|
75
|
+
# @return [String]
|
39
76
|
def request_line
|
40
77
|
"#{method} #{request_uri} #{http_version}\r\n"
|
41
78
|
end
|
42
79
|
alias :start_line :request_line
|
80
|
+
|
81
|
+
include Helpers::MethodHelper
|
82
|
+
include Helpers::RequestURIHelper
|
83
|
+
include Helpers::RackRequestHelper
|
84
|
+
include Helpers::SchemeHelper
|
85
|
+
include Helpers::RequestHeadersHelper
|
86
|
+
include Helpers::EntityHeadersHelper
|
43
87
|
end
|
44
88
|
end
|
data/lib/webbed/response.rb
CHANGED
@@ -1,42 +1,83 @@
|
|
1
1
|
module Webbed
|
2
|
+
# Representation of an HTTP Response.
|
3
|
+
#
|
4
|
+
# This class contains the absolute minimum for accessing the different parts
|
5
|
+
# of an HTTP Response. Helper modules provide far more functionality.
|
2
6
|
class Response
|
7
|
+
include GenericMessage
|
3
8
|
|
4
|
-
|
9
|
+
STATUS_CODE_REGEX = /^(\d{3}) (.*)$/
|
10
|
+
|
11
|
+
# The Status Code of the Response.
|
12
|
+
#
|
13
|
+
# The method automatically converts the new value to an instance of
|
14
|
+
# {StatusCode} if it is not already one.
|
15
|
+
#
|
16
|
+
# @return [#to_i]
|
5
17
|
attr_reader :status_code
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
:status_code => 200,
|
10
|
-
:reason_phrase => nil,
|
11
|
-
:headers => {},
|
12
|
-
:entity_body => ''
|
13
|
-
}
|
14
|
-
|
15
|
-
def initialize(response_hash = {})
|
16
|
-
response_hash = DEFAULTS.merge(response_hash)
|
17
|
-
|
18
|
-
self.http_version = response_hash[:http_version]
|
19
|
-
self.status_code = response_hash[:status_code]
|
20
|
-
self.reason_phrase = response_hash[:reason_phrase]
|
21
|
-
self.headers.merge!(response_hash[:headers])
|
22
|
-
self.entity_body = response_hash[:entity_body]
|
18
|
+
|
19
|
+
def status_code=(status_code)
|
20
|
+
@status_code = Webbed::StatusCode.new(status_code)
|
23
21
|
end
|
24
22
|
|
23
|
+
# The Reason Phrase of the Response.
|
24
|
+
#
|
25
|
+
# The method returns the Status Code's default reason phrase if the Reason
|
26
|
+
# Phrase has not already been set.
|
27
|
+
#
|
28
|
+
# @return [String]
|
25
29
|
def reason_phrase
|
26
|
-
@reason_phrase
|
30
|
+
defined?(@reason_phrase) ? @reason_phrase : @status_code.default_reason_phrase
|
27
31
|
end
|
28
32
|
|
29
|
-
|
30
|
-
@status_code.default_reason_phrase
|
31
|
-
end
|
33
|
+
attr_writer :reason_phrase
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
+
# Creates a new Response.
|
36
|
+
#
|
37
|
+
# The Status Code may be passed in as a string with a Reason Phrase or just
|
38
|
+
# a number. If a number is provided, the default Reason Phrase for that
|
39
|
+
# Status Code is used.
|
40
|
+
#
|
41
|
+
# The method converts the values passed in to their proper types.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# Webbed::Response.new(200, {}, '')
|
45
|
+
# Webbed::Response.new('404 Missing File', {}, '')
|
46
|
+
#
|
47
|
+
# @param [Fixnum, String] status_code
|
48
|
+
# @param [Headers, Hash] headers
|
49
|
+
# @param [#to_s] entity_body
|
50
|
+
# @param [Array] options the options to create the Response with @option
|
51
|
+
# @options options [#to_s] :http_version (1.1) the HTTP-Version of the
|
52
|
+
# Response
|
53
|
+
def initialize(status_code, headers, entity_body, options = {})
|
54
|
+
if STATUS_CODE_REGEX =~ status_code.to_s
|
55
|
+
self.status_code = $1
|
56
|
+
self.reason_phrase = $2
|
57
|
+
else
|
58
|
+
self.status_code = status_code
|
59
|
+
end
|
60
|
+
|
61
|
+
self.headers = headers
|
62
|
+
self.entity_body = entity_body
|
63
|
+
|
64
|
+
self.http_version = options.delete(:http_version) || 1.1
|
35
65
|
end
|
36
66
|
|
67
|
+
# The Status-Line of the Response.
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# response = Webbed::Response.new([200, {}, ''])
|
71
|
+
# response.status_line # => "HTTP/1.1 200 OK\r\n"
|
72
|
+
#
|
73
|
+
# @return [String]
|
37
74
|
def status_line
|
38
75
|
"#{http_version} #{status_code} #{reason_phrase}\r\n"
|
39
76
|
end
|
40
77
|
alias :start_line :status_line
|
78
|
+
|
79
|
+
include Helpers::RackResponseHelper
|
80
|
+
include Helpers::ResponseHeadersHelper
|
81
|
+
include Helpers::EntityHeadersHelper
|
41
82
|
end
|
42
83
|
end
|
data/lib/webbed/status_code.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
module Webbed
|
2
|
+
# Representation of an HTTP Status Code.
|
2
3
|
class StatusCode
|
3
|
-
|
4
4
|
include Comparable
|
5
|
-
attr_reader :status_code, :default_reason_phrase
|
6
|
-
CACHED = {}
|
7
5
|
|
8
6
|
UNKNOWN_REASON_PHRASE = 'Unknown Status Code'
|
9
7
|
REASON_PHRASES = {
|
@@ -49,54 +47,123 @@ module Webbed
|
|
49
47
|
505 => 'HTTP Version not supported'
|
50
48
|
}
|
51
49
|
|
50
|
+
@@cached = {}
|
51
|
+
|
52
|
+
# The default Reason Phrase of the Status Code.
|
53
|
+
#
|
54
|
+
# @return [String]
|
55
|
+
attr_reader :default_reason_phrase
|
56
|
+
|
57
|
+
# Retrieves a Status Code from the cache or creates a new one.
|
58
|
+
#
|
59
|
+
# All created Status Codes are cached forever.
|
60
|
+
#
|
61
|
+
# @param (see #initialize)
|
62
|
+
# @return [StatusCode] the new or cached StatusCode
|
63
|
+
# @see #initialize
|
52
64
|
def self.new(status_code)
|
53
|
-
|
65
|
+
status_code = status_code.to_i
|
66
|
+
@@cached[status_code] ||= super(status_code)
|
54
67
|
end
|
55
68
|
|
69
|
+
# Creates a new Status Code.
|
70
|
+
#
|
71
|
+
# @param [Fixnum] status_code
|
56
72
|
def initialize(status_code)
|
57
|
-
status_code = status_code.to_i
|
58
73
|
@status_code = status_code
|
59
|
-
@default_reason_phrase = REASON_PHRASES[status_code] || UNKNOWN_REASON_PHRASE
|
74
|
+
@default_reason_phrase = REASON_PHRASES[@status_code] || UNKNOWN_REASON_PHRASE
|
60
75
|
end
|
61
76
|
|
77
|
+
# Comparse the Status Code to another Status Code.
|
78
|
+
#
|
79
|
+
# @param [#to_i] other_status_code the other Status Code
|
80
|
+
# @return [Fixnum] the sign of the comparison (either `1`, `0`, or `-1`)
|
62
81
|
def <=>(other_status_code)
|
63
|
-
status_code <=> other_status_code.to_i
|
82
|
+
@status_code <=> other_status_code.to_i
|
64
83
|
end
|
65
84
|
|
85
|
+
# Converts the Status Code to an integer.
|
86
|
+
#
|
87
|
+
# @return [Fixnum]
|
66
88
|
def to_i
|
67
|
-
status_code
|
89
|
+
@status_code
|
68
90
|
end
|
69
91
|
|
92
|
+
# Converts the Status Code to a string.
|
93
|
+
#
|
94
|
+
# @return [String]
|
70
95
|
def to_s
|
71
|
-
|
96
|
+
@status_code.to_s
|
72
97
|
end
|
73
98
|
|
99
|
+
# Whether or not the Status Code is informational.
|
100
|
+
#
|
101
|
+
# According to RFC 2616, informational status codes are in the range of 100
|
102
|
+
# to 199, inclusive.
|
103
|
+
#
|
104
|
+
# @return [Boolean]
|
74
105
|
def informational?
|
75
|
-
(100...200).include?
|
106
|
+
(100...200).include?(@status_code)
|
76
107
|
end
|
77
108
|
|
78
|
-
|
79
|
-
|
109
|
+
# Whether or not the Status Code is successful.
|
110
|
+
#
|
111
|
+
# According to RFC 2616, successful status codes are in the range of 200 to
|
112
|
+
# 299, inclusive.
|
113
|
+
#
|
114
|
+
# @return [Boolean]
|
115
|
+
def successful?
|
116
|
+
(200...300).include?(@status_code)
|
80
117
|
end
|
81
118
|
|
119
|
+
# Whether or not the Status Code is a redirection.
|
120
|
+
#
|
121
|
+
# According to RFC 2616, redirection status codes are in the range of 300 to
|
122
|
+
# 399, inclusive.
|
123
|
+
#
|
124
|
+
# @return [Boolean]
|
82
125
|
def redirection?
|
83
|
-
(300...400).include?
|
126
|
+
(300...400).include?(@status_code)
|
84
127
|
end
|
85
128
|
|
129
|
+
# Whether or not the Status Code is a client error.
|
130
|
+
#
|
131
|
+
# According to RFC 2616, client error status codes are in the range of 400
|
132
|
+
# to 499, inclusive.
|
133
|
+
#
|
134
|
+
# @return [Boolean]
|
86
135
|
def client_error?
|
87
|
-
(400...500).include?
|
136
|
+
(400...500).include?(@status_code)
|
88
137
|
end
|
89
138
|
|
139
|
+
# Whether or not the Status Code is a server error.
|
140
|
+
#
|
141
|
+
# According to RFC 2616, server error status codes are in the range of 500
|
142
|
+
# to 599, inclusive.
|
143
|
+
#
|
144
|
+
# @return [Boolean]
|
90
145
|
def server_error?
|
91
|
-
(500...600).include?
|
146
|
+
(500...600).include?(@status_code)
|
92
147
|
end
|
93
148
|
|
149
|
+
# Whether or not the Status Code is unknown.
|
150
|
+
#
|
151
|
+
# According to RFC 2616, the only defined Status Code ranges are from 100 to
|
152
|
+
# 599, inclusive. Anything outside that range is an unknown Status Code.
|
153
|
+
#
|
154
|
+
# @return [Boolean]
|
94
155
|
def unknown?
|
95
|
-
!(100...600).include?
|
156
|
+
!(100...600).include?(@status_code)
|
96
157
|
end
|
97
158
|
|
159
|
+
# Whether or not the Status Code is an error.
|
160
|
+
#
|
161
|
+
# According to RFC 2616, Status Codes that signify errors are in the range
|
162
|
+
# of 400 to 599, inclusive.
|
163
|
+
#
|
164
|
+
# @return [Boolean]
|
98
165
|
def error?
|
99
|
-
(400...600).include?
|
166
|
+
(400...600).include?(@status_code)
|
100
167
|
end
|
101
168
|
end
|
102
169
|
end
|