berkeley_library-util 0.1.4 → 0.1.5
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 +4 -4
- data/.idea/util.iml +7 -7
- data/.rubocop.yml +4 -0
- data/CHANGES.md +7 -0
- data/lib/berkeley_library/util/module_info.rb +1 -1
- data/lib/berkeley_library/util/uris/requester.rb +36 -9
- data/lib/berkeley_library/util/uris.rb +68 -3
- data/spec/berkeley_library/util/uris/requester_spec.rb +64 -0
- data/spec/berkeley_library/util/uris_spec.rb +95 -4
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9eac060e7b0956b965455bddb8cc6c9721d5af784ac421766c2d791d99632927
|
|
4
|
+
data.tar.gz: a68fecb0b685ddffa3cb0fff6a46180e377efeb71b1cc5d23a389117c27be72d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 052c93d1c09d569479d4bec70ffa9413e3ab0404f19482955b89552891c7058ab76ec11191456aa79016e1e2c98403eb355c89982ffe31f31d37f650517970b2
|
|
7
|
+
data.tar.gz: 530542deae99ffbd089cfc294b614d9560e2298ed4f7a20161970185935155a620b578bd99066a219e7d0410305d525e354c9b811162adbefdf3dda35c904427
|
data/.idea/util.iml
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
<content url="file://$MODULE_DIR$" />
|
|
9
9
|
<orderEntry type="jdk" jdkName="RVM: ruby-2.7.4" jdkType="RUBY_SDK" />
|
|
10
10
|
<orderEntry type="sourceFolder" forTests="false" />
|
|
11
|
-
<orderEntry type="library" scope="PROVIDED" name="actionpack (v7.0.
|
|
12
|
-
<orderEntry type="library" scope="PROVIDED" name="actionview (v7.0.
|
|
13
|
-
<orderEntry type="library" scope="PROVIDED" name="activesupport (v7.0.
|
|
11
|
+
<orderEntry type="library" scope="PROVIDED" name="actionpack (v7.0.3, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
12
|
+
<orderEntry type="library" scope="PROVIDED" name="actionview (v7.0.3, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
13
|
+
<orderEntry type="library" scope="PROVIDED" name="activesupport (v7.0.3, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
14
14
|
<orderEntry type="library" scope="PROVIDED" name="addressable (v2.8.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
15
15
|
<orderEntry type="library" scope="PROVIDED" name="amazing_print (v1.4.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
16
16
|
<orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
<orderEntry type="library" scope="PROVIDED" name="http-cookie (v1.0.4, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
36
36
|
<orderEntry type="library" scope="PROVIDED" name="i18n (v1.10.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
37
37
|
<orderEntry type="library" scope="PROVIDED" name="lograge (v0.12.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
38
|
-
<orderEntry type="library" scope="PROVIDED" name="loofah (v2.
|
|
38
|
+
<orderEntry type="library" scope="PROVIDED" name="loofah (v2.18.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
39
39
|
<orderEntry type="library" scope="PROVIDED" name="method_source (v1.0.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
40
40
|
<orderEntry type="library" scope="PROVIDED" name="mime-types (v3.4.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
41
41
|
<orderEntry type="library" scope="PROVIDED" name="mime-types-data (v3.2022.0105, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
42
42
|
<orderEntry type="library" scope="PROVIDED" name="minitest (v5.15.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
43
43
|
<orderEntry type="library" scope="PROVIDED" name="netrc (v0.11.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
44
|
-
<orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.13.
|
|
44
|
+
<orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.13.6, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
45
45
|
<orderEntry type="library" scope="PROVIDED" name="oj (v3.13.11, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
46
46
|
<orderEntry type="library" scope="PROVIDED" name="ougai (v1.9.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
47
47
|
<orderEntry type="library" scope="PROVIDED" name="parallel (v1.22.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
<orderEntry type="library" scope="PROVIDED" name="rack-test (v1.1.0, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
53
53
|
<orderEntry type="library" scope="PROVIDED" name="rails-dom-testing (v2.0.3, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
54
54
|
<orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.4.2, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
55
|
-
<orderEntry type="library" scope="PROVIDED" name="railties (v7.0.
|
|
55
|
+
<orderEntry type="library" scope="PROVIDED" name="railties (v7.0.3, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
56
56
|
<orderEntry type="library" scope="PROVIDED" name="rainbow (v3.1.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
57
57
|
<orderEntry type="library" scope="PROVIDED" name="rake (v13.0.6, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
58
58
|
<orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.3.1, RVM: ruby-2.7.4) [gem]" level="application" />
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
</RakeTaskImpl>
|
|
99
99
|
<RakeTaskImpl description="Run all specs in spec directory, with coverage" fullCommand="coverage" id="coverage" />
|
|
100
100
|
<RakeTaskImpl description="Run tests, check test coverage, check code style, check for vulnerabilities, build gem" fullCommand="default" id="default" />
|
|
101
|
-
<RakeTaskImpl description="Build berkeley_library-util.gemspec as berkeley_library-util-0.1.
|
|
101
|
+
<RakeTaskImpl description="Build berkeley_library-util.gemspec as berkeley_library-util-0.1.4.gem" fullCommand="gem" id="gem" />
|
|
102
102
|
<RakeTaskImpl description="Run RuboCop with auto-correct, and output results to console" fullCommand="ra" id="ra" />
|
|
103
103
|
<RakeTaskImpl description="Run rubocop with HTML output" fullCommand="rubocop" id="rubocop" />
|
|
104
104
|
<RakeTaskImpl id="rubocop">
|
data/.rubocop.yml
CHANGED
|
@@ -55,6 +55,10 @@ Style/CommentedKeyword:
|
|
|
55
55
|
Style/Documentation:
|
|
56
56
|
Enabled: false
|
|
57
57
|
|
|
58
|
+
# You say "cryptic", I say "compact"
|
|
59
|
+
Style/FormatString:
|
|
60
|
+
EnforcedStyle: percent
|
|
61
|
+
|
|
58
62
|
# Adding more line noise to format strings will not improve them
|
|
59
63
|
Style/FormatStringToken:
|
|
60
64
|
Enabled: false
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# 0.1.5 (2022-09-16)
|
|
2
|
+
|
|
3
|
+
- Adds `URIs#path_escape` to escape URL path segments
|
|
4
|
+
- Adds `URIs#head` and `URIs#head_response`, to make a HEAD request and return the HTTP status code
|
|
5
|
+
and raw response object, respectively
|
|
6
|
+
- Clarifies documentation for `URIs#get` and `URIs#get_response` regarding unsuccessful requests
|
|
7
|
+
|
|
1
8
|
# 0.1.4 (2022-07-20)
|
|
2
9
|
|
|
3
10
|
- Adds `URIs#safe_parse_uri`, which returns `nil` for invalid URLs (unlike `URIs#uri_or_nil`, which
|
|
@@ -7,7 +7,7 @@ module BerkeleyLibrary
|
|
|
7
7
|
SUMMARY = 'Miscellaneous Ruby utilities for the UC Berkeley Library'.freeze
|
|
8
8
|
DESCRIPTION = 'A collection of miscellaneous Ruby routines for the UC Berkeley Library.'.freeze
|
|
9
9
|
LICENSE = 'MIT'.freeze
|
|
10
|
-
VERSION = '0.1.
|
|
10
|
+
VERSION = '0.1.5'.freeze
|
|
11
11
|
HOMEPAGE = 'https://github.com/BerkeleyLibrary/util'.freeze
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -16,29 +16,56 @@ module BerkeleyLibrary
|
|
|
16
16
|
# @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
|
|
17
17
|
# @param headers [Hash] the request headers.
|
|
18
18
|
# @return [String] the body as a string.
|
|
19
|
-
# @raise [RestClient::Exception] in the event of an
|
|
19
|
+
# @raise [RestClient::Exception] in the event of an unsuccessful request.
|
|
20
20
|
def get(uri, params: {}, headers: {})
|
|
21
|
-
resp =
|
|
21
|
+
resp = make_request(:get, uri, params, headers)
|
|
22
22
|
resp.body
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
# Performs a
|
|
25
|
+
# Performs a HEAD request and returns the response status as an integer.
|
|
26
|
+
# Note that unlike {Requester#get}, this does not raise an error in the
|
|
27
|
+
# event of an unsuccessful request.
|
|
28
|
+
#
|
|
29
|
+
# @param uri [URI, String] the URI to HEAD
|
|
30
|
+
# @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
|
|
31
|
+
# @param headers [Hash] the request headers.
|
|
32
|
+
# @return [Integer] the response code as an integer.
|
|
33
|
+
def head(uri, params: {}, headers: {})
|
|
34
|
+
head_response(uri, params: params, headers: headers).code
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Performs a GET request and returns the response, even in the event of
|
|
38
|
+
# a failed request.
|
|
26
39
|
#
|
|
27
40
|
# @param uri [URI, String] the URI to GET
|
|
28
41
|
# @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
|
|
29
42
|
# @param headers [Hash] the request headers.
|
|
30
43
|
# @return [RestClient::Response] the body as a string.
|
|
31
44
|
def get_response(uri, params: {}, headers: {})
|
|
32
|
-
|
|
45
|
+
make_request(:get, uri, params, headers)
|
|
46
|
+
rescue RestClient::Exception => e
|
|
47
|
+
e.response
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Performs a HEAD request and returns the response, even in the event of
|
|
51
|
+
# a failed request.
|
|
52
|
+
#
|
|
53
|
+
# @param uri [URI, String] the URI to HEAD
|
|
54
|
+
# @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
|
|
55
|
+
# @param headers [Hash] the request headers.
|
|
56
|
+
# @return [RestClient::Response] the body as a string.
|
|
57
|
+
def head_response(uri, params: {}, headers: {})
|
|
58
|
+
make_request(:head, uri, params, headers)
|
|
33
59
|
rescue RestClient::Exception => e
|
|
34
60
|
e.response
|
|
35
61
|
end
|
|
36
62
|
|
|
37
63
|
private
|
|
38
64
|
|
|
39
|
-
|
|
65
|
+
# @return [RestClient::Response]
|
|
66
|
+
def make_request(method, uri, params, headers)
|
|
40
67
|
url_str = url_str_with_params(uri, params)
|
|
41
|
-
|
|
68
|
+
req_resp_or_raise(method, url_str, headers)
|
|
42
69
|
end
|
|
43
70
|
|
|
44
71
|
def url_str_with_params(uri, params)
|
|
@@ -57,15 +84,15 @@ module BerkeleyLibrary
|
|
|
57
84
|
end
|
|
58
85
|
|
|
59
86
|
# @return [RestClient::Response]
|
|
60
|
-
def
|
|
61
|
-
resp = RestClient.
|
|
87
|
+
def req_resp_or_raise(method, url_str, headers)
|
|
88
|
+
resp = RestClient::Request.execute(method: method, url: url_str, headers: headers)
|
|
62
89
|
begin
|
|
63
90
|
return resp if (status = resp.code) == 200
|
|
64
91
|
|
|
65
92
|
raise(exception_for(resp, status))
|
|
66
93
|
ensure
|
|
67
94
|
# noinspection RubyMismatchedReturnType
|
|
68
|
-
logger.info("
|
|
95
|
+
logger.info("#{method.to_s.upcase} #{url_str} returned #{status}")
|
|
69
96
|
end
|
|
70
97
|
end
|
|
71
98
|
|
|
@@ -8,6 +8,8 @@ module BerkeleyLibrary
|
|
|
8
8
|
module URIs
|
|
9
9
|
include BerkeleyLibrary::Logging
|
|
10
10
|
|
|
11
|
+
UTF_8 = Encoding::UTF_8
|
|
12
|
+
|
|
11
13
|
class << self
|
|
12
14
|
include URIs
|
|
13
15
|
end
|
|
@@ -24,18 +26,31 @@ module BerkeleyLibrary
|
|
|
24
26
|
Appender.new(uri, *elements).to_uri
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
# Performs a GET request.
|
|
29
|
+
# Performs a GET request and returns the response body as a string.
|
|
28
30
|
#
|
|
29
31
|
# @param uri [URI, String] the URI to GET
|
|
30
32
|
# @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
|
|
31
33
|
# @param headers [Hash] the request headers.
|
|
32
34
|
# @return [String] the body as a string.
|
|
33
|
-
# @raise [RestClient::Exception] in the event of an
|
|
35
|
+
# @raise [RestClient::Exception] in the event of an unsuccessful request.
|
|
34
36
|
def get(uri, params: {}, headers: {})
|
|
35
37
|
Requester.get(uri, params: params, headers: headers)
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
# Performs a
|
|
40
|
+
# Performs a HEAD request and returns the response status as an integer.
|
|
41
|
+
# Note that unlike {Requester#get}, this does not raise an error in the
|
|
42
|
+
# event of an unsuccessful request.
|
|
43
|
+
#
|
|
44
|
+
# @param uri [URI, String] the URI to HEAD
|
|
45
|
+
# @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
|
|
46
|
+
# @param headers [Hash] the request headers.
|
|
47
|
+
# @return [Integer] the response code as an integer.
|
|
48
|
+
def head(uri, params: {}, headers: {})
|
|
49
|
+
Requester.head(uri, params: params, headers: headers)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Performs a GET request and returns the response, even in the event of
|
|
53
|
+
# a failed request.
|
|
39
54
|
#
|
|
40
55
|
# @param uri [URI, String] the URI to GET
|
|
41
56
|
# @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
|
|
@@ -45,6 +60,17 @@ module BerkeleyLibrary
|
|
|
45
60
|
Requester.get_response(uri, params: params, headers: headers)
|
|
46
61
|
end
|
|
47
62
|
|
|
63
|
+
# Performs a HEAD request and returns the response, even in the event of
|
|
64
|
+
# a failed request.
|
|
65
|
+
#
|
|
66
|
+
# @param uri [URI, String] the URI to HEAD
|
|
67
|
+
# @param params [Hash] the query parameters to add to the URI. (Note that the URI may already include query parameters.)
|
|
68
|
+
# @param headers [Hash] the request headers.
|
|
69
|
+
# @return [RestClient::Response] the body as a string.
|
|
70
|
+
def head_response(uri, params: {}, headers: {})
|
|
71
|
+
Requester.head_response(uri, params: params, headers: headers)
|
|
72
|
+
end
|
|
73
|
+
|
|
48
74
|
# Returns the specified URL as a URI, or `nil` if the URL is `nil`.
|
|
49
75
|
# @param url [String, URI, nil] the URL.
|
|
50
76
|
# @return [URI] the URI, or `nil`.
|
|
@@ -54,6 +80,19 @@ module BerkeleyLibrary
|
|
|
54
80
|
Validator.uri_or_nil(url)
|
|
55
81
|
end
|
|
56
82
|
|
|
83
|
+
# Escapes the specified string so that it can be used as a URL path segment,
|
|
84
|
+
# replacing disallowed characters (including /) with percent-encodings as needed.
|
|
85
|
+
def path_escape(s)
|
|
86
|
+
raise ArgumentError, "Can't escape #{s.inspect}: not a string" unless s.respond_to?(:encoding)
|
|
87
|
+
raise ArgumentError, "Can't escape #{s.inspect}: expected #{UTF_8}, was #{s.encoding}" unless s.encoding == UTF_8
|
|
88
|
+
|
|
89
|
+
''.tap do |escaped|
|
|
90
|
+
s.bytes.each do |b|
|
|
91
|
+
escaped << (should_escape?(b, :path_segment) ? '%%%02X' % b : b.chr)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
57
96
|
# Returns the specified URL as a URI, or `nil` if the URL cannot
|
|
58
97
|
# be parsed.
|
|
59
98
|
# @param url [Object, nil] the URL.
|
|
@@ -65,6 +104,32 @@ module BerkeleyLibrary
|
|
|
65
104
|
logger.warn("Error parsing URL #{url.inspect}", e)
|
|
66
105
|
nil
|
|
67
106
|
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
# TODO: extend to cover other modes - host, zone, path, password, query, fragment
|
|
111
|
+
# cf. https://github.com/golang/go/blob/master/src/net/url/url.go
|
|
112
|
+
ALLOWED_BYTES_BY_MODE = {
|
|
113
|
+
path_segment: [0x24, 0x26, 0x2b, 0x3a, 0x3d, 0x40] # @ & = + $
|
|
114
|
+
}.freeze
|
|
115
|
+
|
|
116
|
+
def should_escape?(b, mode)
|
|
117
|
+
return false if unreserved?(b)
|
|
118
|
+
return false if ALLOWED_BYTES_BY_MODE[mode]&.include?(b)
|
|
119
|
+
|
|
120
|
+
true
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
124
|
+
def unreserved?(byte)
|
|
125
|
+
return true if byte >= 0x41 && byte <= 0x5a # A-Z
|
|
126
|
+
return true if byte >= 0x61 && byte <= 0x7a # a-z
|
|
127
|
+
return true if byte >= 0x30 && byte <= 0x39 # 0-9
|
|
128
|
+
return true if [0x2d, 0x2e, 0x5f, 0x7e].include?(byte) # - . _ ~
|
|
129
|
+
|
|
130
|
+
false
|
|
131
|
+
end
|
|
132
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
68
133
|
end
|
|
69
134
|
end
|
|
70
135
|
end
|
|
@@ -66,6 +66,70 @@ module BerkeleyLibrary
|
|
|
66
66
|
expect(result).to eq(expected_body)
|
|
67
67
|
end
|
|
68
68
|
end
|
|
69
|
+
|
|
70
|
+
describe :head do
|
|
71
|
+
it 'returns an HTTP status code for a URL string' do
|
|
72
|
+
url = 'https://example.org/'
|
|
73
|
+
expected_status = 203
|
|
74
|
+
stub_request(:head, url).to_return(status: expected_status)
|
|
75
|
+
|
|
76
|
+
result = Requester.head(url)
|
|
77
|
+
expect(result).to eq(expected_status)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'returns an HTTP response body for a URI' do
|
|
81
|
+
uri = URI.parse('https://example.org/')
|
|
82
|
+
expected_status = 203
|
|
83
|
+
stub_request(:head, uri).to_return(status: expected_status)
|
|
84
|
+
|
|
85
|
+
result = Requester.head(uri)
|
|
86
|
+
expect(result).to eq(expected_status)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'appends query parameters' do
|
|
90
|
+
url = 'https://example.org/'
|
|
91
|
+
params = { p1: 1, p2: 2 }
|
|
92
|
+
url_with_query = "#{url}?#{URI.encode_www_form(params)}"
|
|
93
|
+
expected_status = 203
|
|
94
|
+
stub_request(:head, url_with_query).to_return(status: expected_status)
|
|
95
|
+
|
|
96
|
+
result = Requester.head(url, params: params)
|
|
97
|
+
expect(result).to eq(expected_status)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'sends request headers' do
|
|
101
|
+
url = 'https://example.org/'
|
|
102
|
+
headers = { 'X-help' => 'I am trapped in a unit test' }
|
|
103
|
+
expected_status = 203
|
|
104
|
+
stub_request(:head, url).with(headers: headers).to_return(status: expected_status)
|
|
105
|
+
|
|
106
|
+
result = Requester.head(url, headers: headers)
|
|
107
|
+
expect(result).to eq(expected_status)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it 'returns the status even for unsuccessful requests' do
|
|
111
|
+
aggregate_failures 'responses' do
|
|
112
|
+
[207, 400, 401, 403, 404, 405, 418, 451, 500, 503].each do |expected_status|
|
|
113
|
+
url = "http://example.edu/#{expected_status}"
|
|
114
|
+
stub_request(:head, url).to_return(status: expected_status)
|
|
115
|
+
|
|
116
|
+
result = Requester.head(url)
|
|
117
|
+
expect(result).to eq(expected_status)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'handles redirects' do
|
|
123
|
+
url1 = 'https://example.org/'
|
|
124
|
+
url2 = 'https://example.edu/'
|
|
125
|
+
stub_request(:head, url1).to_return(status: 302, headers: { 'Location' => url2 })
|
|
126
|
+
expected_status = 203
|
|
127
|
+
stub_request(:head, url2).to_return(status: expected_status)
|
|
128
|
+
|
|
129
|
+
result = Requester.head(url1)
|
|
130
|
+
expect(result).to eq(expected_status)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
69
133
|
end
|
|
70
134
|
end
|
|
71
135
|
end
|
|
@@ -16,16 +16,14 @@ module BerkeleyLibrary::Util
|
|
|
16
16
|
expect(new_uri).to eq(expected_uri)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
xit "doesn't append to a bare URI when there's nothing to append" do
|
|
19
|
+
it 'returns a bare URI when there\'s nothing to append' do
|
|
21
20
|
original_url = 'https://example.org'
|
|
22
21
|
new_uri = URIs.append(original_url)
|
|
23
22
|
expected_uri = URI(original_url)
|
|
24
23
|
expect(new_uri).to eq(expected_uri)
|
|
25
24
|
end
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
xit "doesn't append to a bare URI when there's only a query string" do
|
|
26
|
+
it 'appends to a bare URI even when there\'s only a query string' do
|
|
29
27
|
original_url = 'https://example.org'
|
|
30
28
|
new_uri = URIs.append(original_url, '?foo=bar')
|
|
31
29
|
expected_uri = URI("#{original_url}?foo=bar")
|
|
@@ -136,6 +134,19 @@ module BerkeleyLibrary::Util
|
|
|
136
134
|
new_uri = URIs.append(original_uri, '?qux=corge', '&grault=plugh#xyzzy')
|
|
137
135
|
expect(new_uri).to eq(URI('https://example.org/foo/bar?qux=corge&grault=plugh#xyzzy'))
|
|
138
136
|
end
|
|
137
|
+
|
|
138
|
+
it 'rejects invalid characters' do
|
|
139
|
+
original_uri = URI('https://example.org/')
|
|
140
|
+
expect { URIs.append(original_uri, '精力善用') }.to raise_error(URI::InvalidComponentError)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'accepts percent-encoded path segments' do
|
|
144
|
+
original_uri = URI('https://example.org/')
|
|
145
|
+
encoded_segment = URIs.path_escape('精力善用')
|
|
146
|
+
new_uri = URIs.append(original_uri, encoded_segment, 'foo.html')
|
|
147
|
+
expected_url = "https://example.org/#{encoded_segment}/foo.html"
|
|
148
|
+
expect(new_uri).to eq(URI(expected_url))
|
|
149
|
+
end
|
|
139
150
|
end
|
|
140
151
|
|
|
141
152
|
describe 'requests' do
|
|
@@ -177,6 +188,42 @@ module BerkeleyLibrary::Util
|
|
|
177
188
|
expect(response.code).to eq(404)
|
|
178
189
|
end
|
|
179
190
|
end
|
|
191
|
+
|
|
192
|
+
describe :head do
|
|
193
|
+
it 'makes a HEAD request' do
|
|
194
|
+
expected_status = 200
|
|
195
|
+
stub_request(:head, url_with_query).with(headers: headers).to_return(status: expected_status)
|
|
196
|
+
|
|
197
|
+
result = URIs.head(url, params: params, headers: headers)
|
|
198
|
+
expect(result).to eq(expected_status)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it 'returns the status even for unsuccessful requests' do
|
|
202
|
+
expected_status = 404
|
|
203
|
+
stub_request(:head, url_with_query).with(headers: headers).to_return(status: expected_status)
|
|
204
|
+
|
|
205
|
+
result = URIs.head(url, params: params, headers: headers)
|
|
206
|
+
expect(result).to eq(expected_status)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
describe :head_response do
|
|
211
|
+
it 'makes a HEAD request' do
|
|
212
|
+
stub_request(:head, url_with_query).with(headers: headers).to_return(body: expected_body)
|
|
213
|
+
|
|
214
|
+
response = URIs.head_response(url, params: params, headers: headers)
|
|
215
|
+
expect(response.body).to eq(expected_body)
|
|
216
|
+
expect(response.code).to eq(200)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
it 'returns the response even for errors' do
|
|
220
|
+
stub_request(:head, url_with_query).with(headers: headers).to_return(status: 404, body: expected_body)
|
|
221
|
+
|
|
222
|
+
response = URIs.head_response(url, params: params, headers: headers)
|
|
223
|
+
expect(response.body).to eq(expected_body)
|
|
224
|
+
expect(response.code).to eq(404)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
180
227
|
end
|
|
181
228
|
|
|
182
229
|
describe :safe_parse_uri do
|
|
@@ -210,5 +257,49 @@ module BerkeleyLibrary::Util
|
|
|
210
257
|
end
|
|
211
258
|
end
|
|
212
259
|
end
|
|
260
|
+
|
|
261
|
+
describe :path_escape do
|
|
262
|
+
let(:in_out) do
|
|
263
|
+
{
|
|
264
|
+
'' => '',
|
|
265
|
+
'corge' => 'corge',
|
|
266
|
+
'foo+bar' => 'foo+bar',
|
|
267
|
+
'qux/quux' => 'qux%2Fquux',
|
|
268
|
+
'foo bar baz' => 'foo%20bar%20baz',
|
|
269
|
+
'25%' => '25%25',
|
|
270
|
+
"\t !\"#$%&'()*+,/:;<=>?@[\\]^`{|}☺" => '%09%20%21%22%23$%25&%27%28%29%2A+%2C%2F:%3B%3C=%3E%3F@%5B%5C%5D%5E%60%7B%7C%7D%E2%98%BA',
|
|
271
|
+
'精力善用' => '%E7%B2%BE%E5%8A%9B%E5%96%84%E7%94%A8'
|
|
272
|
+
}
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it 'escapes a path segment' do
|
|
276
|
+
aggregate_failures do
|
|
277
|
+
in_out.each do |in_str, out_str|
|
|
278
|
+
expect(URIs.path_escape(in_str)).to eq(out_str)
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it 'rejects non-strings' do
|
|
284
|
+
str = in_out.keys.last
|
|
285
|
+
expect { URIs.path_escape(str.bytes) }.to raise_error(ArgumentError)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
it 'rejects non-UTF-8 strings' do
|
|
289
|
+
str = in_out.keys.last
|
|
290
|
+
expect { URIs.path_escape(str.encode(Encoding::Shift_JIS)) }.to raise_error(ArgumentError)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it 'accepts non-UTF-8 strings converted to UTF-8' do
|
|
294
|
+
in_str = in_out.keys.last
|
|
295
|
+
out_str = in_out[in_str]
|
|
296
|
+
|
|
297
|
+
# OK, we're really just testing String#encode here, but
|
|
298
|
+
# it's useful for documentation
|
|
299
|
+
in_str_sjis = in_str.encode(Encoding::Shift_JIS)
|
|
300
|
+
in_str_utf8 = in_str_sjis.encode(Encoding::UTF_8)
|
|
301
|
+
expect(URIs.path_escape(in_str_utf8)).to eq(out_str)
|
|
302
|
+
end
|
|
303
|
+
end
|
|
213
304
|
end
|
|
214
305
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: berkeley_library-util
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Moles
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-09-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: berkeley_library-logging
|