tilia-http 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.rubocop.yml +35 -0
- data/.simplecov +4 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.sabre.md +235 -0
- data/CONTRIBUTING.md +25 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +69 -0
- data/LICENSE +27 -0
- data/LICENSE.sabre +27 -0
- data/README.md +68 -0
- data/Rakefile +17 -0
- data/examples/asyncclient.rb +45 -0
- data/examples/basicauth.rb +39 -0
- data/examples/client.rb +20 -0
- data/examples/reverseproxy.rb +39 -0
- data/examples/stringify.rb +37 -0
- data/lib/tilia/http/auth/abstract_auth.rb +51 -0
- data/lib/tilia/http/auth/aws.rb +191 -0
- data/lib/tilia/http/auth/basic.rb +43 -0
- data/lib/tilia/http/auth/bearer.rb +37 -0
- data/lib/tilia/http/auth/digest.rb +187 -0
- data/lib/tilia/http/auth.rb +12 -0
- data/lib/tilia/http/client.rb +452 -0
- data/lib/tilia/http/client_exception.rb +15 -0
- data/lib/tilia/http/client_http_exception.rb +37 -0
- data/lib/tilia/http/http_exception.rb +21 -0
- data/lib/tilia/http/message.rb +241 -0
- data/lib/tilia/http/message_decorator_trait.rb +183 -0
- data/lib/tilia/http/message_interface.rb +154 -0
- data/lib/tilia/http/request.rb +235 -0
- data/lib/tilia/http/request_decorator.rb +160 -0
- data/lib/tilia/http/request_interface.rb +126 -0
- data/lib/tilia/http/response.rb +164 -0
- data/lib/tilia/http/response_decorator.rb +58 -0
- data/lib/tilia/http/response_interface.rb +36 -0
- data/lib/tilia/http/sapi.rb +165 -0
- data/lib/tilia/http/url_util.rb +70 -0
- data/lib/tilia/http/util.rb +51 -0
- data/lib/tilia/http/version.rb +9 -0
- data/lib/tilia/http.rb +416 -0
- data/test/http/auth/aws_test.rb +189 -0
- data/test/http/auth/basic_test.rb +60 -0
- data/test/http/auth/bearer_test.rb +47 -0
- data/test/http/auth/digest_test.rb +141 -0
- data/test/http/client_mock.rb +101 -0
- data/test/http/client_test.rb +331 -0
- data/test/http/message_decorator_test.rb +67 -0
- data/test/http/message_test.rb +163 -0
- data/test/http/request_decorator_test.rb +87 -0
- data/test/http/request_test.rb +132 -0
- data/test/http/response_decorator_test.rb +28 -0
- data/test/http/response_test.rb +38 -0
- data/test/http/sapi_mock.rb +12 -0
- data/test/http/sapi_test.rb +133 -0
- data/test/http/url_util_test.rb +155 -0
- data/test/http/util_test.rb +186 -0
- data/test/http_test.rb +102 -0
- data/test/test_helper.rb +6 -0
- data/tilia-http.gemspec +18 -0
- metadata +192 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
module Tilia
|
2
|
+
module Http
|
3
|
+
# Response Decorator
|
4
|
+
#
|
5
|
+
# This helper class allows you to easily create decorators for the Response
|
6
|
+
# object.
|
7
|
+
class ResponseDecorator
|
8
|
+
include Tilia::Http::ResponseInterface
|
9
|
+
include Tilia::Http::MessageDecoratorTrait
|
10
|
+
|
11
|
+
# Constructor.
|
12
|
+
#
|
13
|
+
# @param ResponseInterface inner
|
14
|
+
def initialize(inner)
|
15
|
+
@inner = inner
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the current HTTP status code.
|
19
|
+
#
|
20
|
+
# @return int
|
21
|
+
def status
|
22
|
+
@inner.status
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the human-readable status string.
|
26
|
+
#
|
27
|
+
# In the case of a 200, this may for example be 'OK'.
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
def status_text
|
31
|
+
@inner.status_text
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sets the HTTP status code.
|
35
|
+
#
|
36
|
+
# This can be either the full HTTP status code with human readable string,
|
37
|
+
# for example: "403 I can't let you do that, Dave".
|
38
|
+
#
|
39
|
+
# Or just the code, in which case the appropriate default message will be
|
40
|
+
# added.
|
41
|
+
#
|
42
|
+
# @param [String, Fixnum] status
|
43
|
+
# @return [void]
|
44
|
+
def status=(status)
|
45
|
+
@inner.status = status
|
46
|
+
end
|
47
|
+
|
48
|
+
# Serializes the request object as a string.
|
49
|
+
#
|
50
|
+
# This is useful for debugging purposes.
|
51
|
+
#
|
52
|
+
# @return [String]
|
53
|
+
def to_s
|
54
|
+
@inner.to_s
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Tilia
|
2
|
+
module Http
|
3
|
+
# This interface represents a HTTP response.
|
4
|
+
module ResponseInterface
|
5
|
+
include Tilia::Http::MessageInterface
|
6
|
+
|
7
|
+
# Returns the current HTTP status code.
|
8
|
+
#
|
9
|
+
# @return int
|
10
|
+
def status
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the human-readable status string.
|
14
|
+
#
|
15
|
+
# In the case of a 200, this may for example be 'OK'.
|
16
|
+
#
|
17
|
+
# @return [String]
|
18
|
+
def status_text
|
19
|
+
end
|
20
|
+
|
21
|
+
# Sets the HTTP status code.
|
22
|
+
#
|
23
|
+
# This can be either the full HTTP status code with human readable string,
|
24
|
+
# for example: "403 I can't let you do that, Dave".
|
25
|
+
#
|
26
|
+
# Or just the code, in which case the appropriate default message will be
|
27
|
+
# added.
|
28
|
+
#
|
29
|
+
# @param [String, Fixnum] status
|
30
|
+
# @throws \InvalidArgumentExeption
|
31
|
+
# @return [void]
|
32
|
+
def status=(_status)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'base64'
|
3
|
+
module Tilia
|
4
|
+
module Http
|
5
|
+
# PHP SAPI
|
6
|
+
#
|
7
|
+
# This object is responsible for:
|
8
|
+
# 1. Constructing a Request object based on the current HTTP request sent to
|
9
|
+
# the PHP process.
|
10
|
+
# 2. Sending the Response object back to the client.
|
11
|
+
#
|
12
|
+
# It could be said that this class provides a mapping between the Request and
|
13
|
+
# Response objects, and php's:
|
14
|
+
#
|
15
|
+
# * $_SERVER
|
16
|
+
# * $_POST
|
17
|
+
# * $_FILES
|
18
|
+
# * php://input
|
19
|
+
# * echo
|
20
|
+
# * header
|
21
|
+
# * php://output
|
22
|
+
#
|
23
|
+
# You can choose to either call all these methods statically, but you can also
|
24
|
+
# instantiate this as an object to allow for polymorhpism.
|
25
|
+
class Sapi
|
26
|
+
# This static method will create a new Request object, based on the
|
27
|
+
# current PHP request.
|
28
|
+
#
|
29
|
+
# @return Request
|
30
|
+
def self.request
|
31
|
+
fail NotImplementedError, 'This object method now is an instance method'
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sends the HTTP response back to a HTTP client.
|
35
|
+
#
|
36
|
+
# This calls php's header function and streams the body to php://output.
|
37
|
+
#
|
38
|
+
# @param ResponseInterface response
|
39
|
+
# @return [void]
|
40
|
+
def self.send_response(response)
|
41
|
+
# RUBY: Rack does not support HTTP Version (?)
|
42
|
+
# header("HTTP/#{response.http_version} #{response.status} #{response.status_text}")
|
43
|
+
|
44
|
+
status = response.status
|
45
|
+
headers = {}
|
46
|
+
response.headers.each do |key, value|
|
47
|
+
headers[key] = value.join("\n")
|
48
|
+
end
|
49
|
+
|
50
|
+
body = response.body_as_stream
|
51
|
+
content_length = response.header('Content-Length')
|
52
|
+
if content_length
|
53
|
+
output = StringIO.new
|
54
|
+
output.write body.read(content_length.to_i)
|
55
|
+
output.rewind
|
56
|
+
body = output
|
57
|
+
end
|
58
|
+
|
59
|
+
[status, headers, body]
|
60
|
+
end
|
61
|
+
|
62
|
+
# This static method will create a new Request object, based on a PHP
|
63
|
+
# $_SERVER array.
|
64
|
+
#
|
65
|
+
# @param array server_array
|
66
|
+
# @return Request
|
67
|
+
def self.create_from_server_array(server_array)
|
68
|
+
headers = {}
|
69
|
+
method = nil
|
70
|
+
url = nil
|
71
|
+
http_version = '1.1'
|
72
|
+
|
73
|
+
protocol = 'http'
|
74
|
+
host_name = 'localhost'
|
75
|
+
|
76
|
+
server_array.each do |key, value|
|
77
|
+
case key
|
78
|
+
when 'SERVER_PROTOCOL'
|
79
|
+
http_version = '1.0' if value == 'HTTP/1.0'
|
80
|
+
when 'REQUEST_METHOD'
|
81
|
+
method = value
|
82
|
+
when 'REQUEST_URI'
|
83
|
+
url = value
|
84
|
+
|
85
|
+
# These sometimes should up without a HTTP_ prefix
|
86
|
+
when 'CONTENT_TYPE'
|
87
|
+
headers['Content-Type'] = value
|
88
|
+
when 'CONTENT_LENGTH'
|
89
|
+
headers['Content-Length'] = value
|
90
|
+
|
91
|
+
# mod_php on apache will put credentials in these variables.
|
92
|
+
# (fast)cgi does not usually do this, however.
|
93
|
+
when 'PHP_AUTH_USER'
|
94
|
+
if server_array.key? 'PHP_AUTH_PW'
|
95
|
+
headers['Authorization'] = "Basic #{Base64.strict_encode64 "#{value}:#{server_array['PHP_AUTH_PW']}"}"
|
96
|
+
end
|
97
|
+
when 'PHP_AUTH_DIGEST'
|
98
|
+
headers['Authorization'] = "Digest #{value}"
|
99
|
+
|
100
|
+
# Apache may prefix the HTTP_AUTHORIZATION header with
|
101
|
+
# REDIRECT_, if mod_rewrite was used.
|
102
|
+
when 'REDIRECT_HTTP_AUTHORIZATION'
|
103
|
+
headers['Authorization'] = value
|
104
|
+
|
105
|
+
when 'HTTP_HOST'
|
106
|
+
host_name = value
|
107
|
+
headers['Host'] = value
|
108
|
+
|
109
|
+
when 'HTTPS'
|
110
|
+
protocol = 'https' if value && value != 'off'
|
111
|
+
|
112
|
+
# RUBY
|
113
|
+
when 'rack.url_scheme'
|
114
|
+
protocol = value
|
115
|
+
|
116
|
+
else
|
117
|
+
if key.index('HTTP_') == 0
|
118
|
+
# It's a HTTP header
|
119
|
+
|
120
|
+
# Normalizing it to be prettier
|
121
|
+
header = key[5..-1].downcase
|
122
|
+
|
123
|
+
# Transforming dashes into spaces, and uppercasing
|
124
|
+
# every first letter.
|
125
|
+
# Turning spaces into dashes.
|
126
|
+
header = header.split(/_/).map(&:capitalize).join('-')
|
127
|
+
|
128
|
+
headers[header] = value
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
r = Tilia::Http::Request.new(method, url, headers)
|
134
|
+
r.http_version = http_version
|
135
|
+
r.raw_server_data = server_array
|
136
|
+
r.absolute_url = "#{protocol}://#{host_name}#{url}"
|
137
|
+
r
|
138
|
+
end
|
139
|
+
|
140
|
+
# TODO: document
|
141
|
+
def initialize(env)
|
142
|
+
@env = env
|
143
|
+
@rack_request = Rack::Request.new(env)
|
144
|
+
end
|
145
|
+
|
146
|
+
# TODO: document
|
147
|
+
def request
|
148
|
+
r = create_from_server_array(@env)
|
149
|
+
r.body = StringIO.new
|
150
|
+
r.post_data = @rack_request.POST
|
151
|
+
r
|
152
|
+
end
|
153
|
+
|
154
|
+
# TODO: document
|
155
|
+
def send_response(response)
|
156
|
+
self.class.send_response(response)
|
157
|
+
end
|
158
|
+
|
159
|
+
# TODO: document
|
160
|
+
def create_from_server_array(server_array)
|
161
|
+
self.class.create_from_server_array(server_array)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Tilia
|
2
|
+
module Http
|
3
|
+
# URL utility class
|
4
|
+
#
|
5
|
+
# Note: this class is deprecated. All its functionality moved to functions.php
|
6
|
+
# or sabre\uri.
|
7
|
+
#
|
8
|
+
# @deprectated
|
9
|
+
module UrlUtil
|
10
|
+
# Encodes the path of a url.
|
11
|
+
#
|
12
|
+
# slashes (/) are treated as path-separators.
|
13
|
+
#
|
14
|
+
# @deprecated use \Sabre\HTTP\encode_path
|
15
|
+
# @param [String] path
|
16
|
+
# @return [String]
|
17
|
+
def self.encode_path(path)
|
18
|
+
Tilia::Http.encode_path(path)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Encodes a 1 segment of a path
|
22
|
+
#
|
23
|
+
# Slashes are considered part of the name, and are encoded as %2f
|
24
|
+
#
|
25
|
+
# @deprecated use \Sabre\HTTP\encode_path_segment
|
26
|
+
# @param [String] path_segment
|
27
|
+
# @return [String]
|
28
|
+
def self.encode_path_segment(path_segment)
|
29
|
+
Tilia::Http.encode_path_segment(path_segment)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Decodes a url-encoded path
|
33
|
+
#
|
34
|
+
# @deprecated use \Sabre\HTTP\decodePath
|
35
|
+
# @param [String] path
|
36
|
+
# @return [String]
|
37
|
+
def self.decode_path(path)
|
38
|
+
Tilia::Http.decode_path(path)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Decodes a url-encoded path segment
|
42
|
+
#
|
43
|
+
# @deprecated use \Sabre\HTTP\decode_path_segment
|
44
|
+
# @param [String] path
|
45
|
+
# @return [String]
|
46
|
+
def self.decode_path_segment(path)
|
47
|
+
Tilia::Http.decode_path_segment(path)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the 'dirname' and 'basename' for a path.
|
51
|
+
#
|
52
|
+
# @deprecated Use Sabre\Uri\split.
|
53
|
+
# @param [String] path
|
54
|
+
# @return array
|
55
|
+
def self.split_path(path)
|
56
|
+
Tilia::Uri.split(path)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Resolves relative urls, like a browser would.
|
60
|
+
#
|
61
|
+
# @deprecated Use Sabre\Uri\resolve.
|
62
|
+
# @param [String] base_path
|
63
|
+
# @param [String] new_path
|
64
|
+
# @return [String]
|
65
|
+
def self.resolve(base_path, new_path)
|
66
|
+
Tilia::Uri.resolve(base_path, new_path)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Tilia
|
2
|
+
module Http
|
3
|
+
# HTTP utility methods
|
4
|
+
#
|
5
|
+
# @deprecated All these functions moved to the Tilia::Http namespace
|
6
|
+
module Util
|
7
|
+
# Content negotiation
|
8
|
+
#
|
9
|
+
# @deprecated Use Tilia::Http::negotiate_content_type
|
10
|
+
# @param [String, nil] accept_header_value
|
11
|
+
# @param array available_options
|
12
|
+
# @return [String, nil]
|
13
|
+
def self.negotiate_content_type(accept_header_value, available_options)
|
14
|
+
Http.negotiate_content_type(accept_header_value, available_options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Deprecated! Use negotiateContentType.
|
18
|
+
#
|
19
|
+
# @deprecated Use Tilia::Http::negotiate_content_type
|
20
|
+
# @param [String, nil] accept_header
|
21
|
+
# @param array available_options
|
22
|
+
# @return [String, nil]
|
23
|
+
def self.negotiate(accept_header_value, available_options)
|
24
|
+
Http.negotiate_content_type(accept_header_value, available_options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Parses a RFC2616-compatible date string
|
28
|
+
#
|
29
|
+
# This method returns false if the date is invalid
|
30
|
+
#
|
31
|
+
# @deprecated Use Tilia::Http::parse_date
|
32
|
+
# @param [String] date_header
|
33
|
+
# @return bool|DateTime
|
34
|
+
def self.parse_http_date(date_header)
|
35
|
+
Http.parse_date(date_header)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Transforms a DateTime object to HTTP's most common date format.
|
39
|
+
#
|
40
|
+
# We're serializing it as the RFC 1123 date, which, for HTTP must be
|
41
|
+
# specified as GMT.
|
42
|
+
#
|
43
|
+
# @deprecated Use Tilia::Http::to_date
|
44
|
+
# @param \DateTime date_time
|
45
|
+
# @return [String]
|
46
|
+
def self.to_http_date(date_time)
|
47
|
+
Http.to_date(date_time)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|