kataba 1.1.1 → 1.1.3
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/lib/kataba/fetcher.rb +33 -2
- data/lib/kataba.rb +29 -3
- metadata +12 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0c1a21b706cc4e327925cd9d936247e6f5ce17ea3964853f1b442e5ee8ecae3b
|
|
4
|
+
data.tar.gz: 11ad87d5a2baede9403e4b83e2e5db01f5f2b8fe9702371228018cb96534ec22
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e2bdb712cd9c063469ee35b6dd5c3f1321018fc490ed25cb095c63715aaf63829915db1b99bfac94d87e574c88e301145fde7359cc57139dd1a997d61954bddc
|
|
7
|
+
data.tar.gz: d21c6a7c83b2a93c89115305856cf2824a62cfa75e7aaa32bda7ea0f4d648bb4d8e6e4db3d4e45ea734a2bc495ea33d3737eb62bc85b3fd076958375d3d0e6fa
|
data/lib/kataba/fetcher.rb
CHANGED
|
@@ -32,10 +32,25 @@ module Kataba
|
|
|
32
32
|
'/mods/xml.xsd' => '/standards/mods/xml.xsd',
|
|
33
33
|
}.freeze
|
|
34
34
|
|
|
35
|
+
# Seconds to wait for a schema host to accept the connection, and then to
|
|
36
|
+
# deliver the body. Net::HTTP's own defaults are 60s each, which is a
|
|
37
|
+
# fallback rather than a considered number: a schema is a small file from a
|
|
38
|
+
# public host, and both are paid per redirect hop and again on the
|
|
39
|
+
# alternate-scheme attempt, so an unbounded fetch can hold a caller's
|
|
40
|
+
# thread for many minutes.
|
|
41
|
+
DEFAULT_OPEN_TIMEOUT = 3
|
|
42
|
+
DEFAULT_READ_TIMEOUT = 10
|
|
43
|
+
|
|
35
44
|
class FetchError < StandardError; end
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
# A subclass, so a consumer's `rescue FetchError` covers a timeout while
|
|
47
|
+
# one that wants to retry a timeout without retrying a 404 still can.
|
|
48
|
+
class FetchTimeout < FetchError; end
|
|
49
|
+
|
|
50
|
+
def initialize(uri, open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT)
|
|
38
51
|
@original_uri = uri
|
|
52
|
+
@open_timeout = open_timeout
|
|
53
|
+
@read_timeout = read_timeout
|
|
39
54
|
end
|
|
40
55
|
|
|
41
56
|
def fetch
|
|
@@ -75,7 +90,23 @@ module Kataba
|
|
|
75
90
|
parsed = URI.parse(uri)
|
|
76
91
|
http = Net::HTTP.new(parsed.host, parsed.port)
|
|
77
92
|
http.use_ssl = (parsed.scheme == 'https')
|
|
78
|
-
|
|
93
|
+
http.open_timeout = @open_timeout
|
|
94
|
+
http.read_timeout = @read_timeout
|
|
95
|
+
# Net::HTTP retries an idempotent request once on a read timeout, so the
|
|
96
|
+
# ceiling per hop would otherwise be twice read_timeout. Nothing here
|
|
97
|
+
# reuses a socket, so that retry can only re-wait a timeout that has
|
|
98
|
+
# already expired.
|
|
99
|
+
http.max_retries = 0
|
|
100
|
+
|
|
101
|
+
response =
|
|
102
|
+
begin
|
|
103
|
+
http.get(parsed.request_uri)
|
|
104
|
+
rescue Timeout::Error => e
|
|
105
|
+
# Both Net::OpenTimeout and Net::ReadTimeout are Timeout::Errors, and
|
|
106
|
+
# Timeout::Error is a RuntimeError — so an unwrapped timeout lands in
|
|
107
|
+
# a consumer's generic rescue rather than its fetch-failure branch.
|
|
108
|
+
raise FetchTimeout, "timed out fetching #{uri} (#{e.class}: #{e.message})"
|
|
109
|
+
end
|
|
79
110
|
|
|
80
111
|
if response.is_a?(Net::HTTPRedirection)
|
|
81
112
|
target = resolve_redirect(parsed, response['location'])
|
data/lib/kataba.rb
CHANGED
|
@@ -46,9 +46,23 @@ module Kataba
|
|
|
46
46
|
# Kataba.configuration.mirror_list = File.join(Rails.root, 'config', 'mirror.yml')
|
|
47
47
|
attr_accessor :mirror_list
|
|
48
48
|
|
|
49
|
+
# Seconds Kataba waits for a schema host to accept a connection, and then
|
|
50
|
+
# to deliver the body. Raise them for a slow mirror; lower them when the
|
|
51
|
+
# caller is a request thread that must not be held. Both are paid per
|
|
52
|
+
# redirect hop and again on the alternate-scheme attempt, so the ceiling
|
|
53
|
+
# for one schema is a multiple of these, not either on its own.
|
|
54
|
+
#
|
|
55
|
+
# Example:
|
|
56
|
+
# Kataba.configuration.open_timeout = 5
|
|
57
|
+
# Kataba.configuration.read_timeout = 20
|
|
58
|
+
attr_accessor :open_timeout
|
|
59
|
+
attr_accessor :read_timeout
|
|
60
|
+
|
|
49
61
|
# Default configuration values
|
|
50
62
|
def initialize
|
|
51
63
|
@offline_storage = "#{Dir.tmpdir}/kataba"
|
|
64
|
+
@open_timeout = Kataba::Fetcher::DEFAULT_OPEN_TIMEOUT
|
|
65
|
+
@read_timeout = Kataba::Fetcher::DEFAULT_READ_TIMEOUT
|
|
52
66
|
end
|
|
53
67
|
end
|
|
54
68
|
|
|
@@ -61,6 +75,14 @@ module Kataba
|
|
|
61
75
|
# Arguments:
|
|
62
76
|
# xsd_uri: (String)
|
|
63
77
|
|
|
78
|
+
# Dir.chdir is process-wide state, not thread-local: if two threads each
|
|
79
|
+
# have a chdir block open at once, Ruby raises "conflicting chdir during
|
|
80
|
+
# another chdir block" rather than let one thread's cwd stomp on the
|
|
81
|
+
# other's. A shared Mutex serializes just that step across threads in one
|
|
82
|
+
# process — cheap, since by this point it's a local file read + a Nokogiri
|
|
83
|
+
# parse, not the network fetch (which stays outside the lock).
|
|
84
|
+
CHDIR_MUTEX = Mutex.new
|
|
85
|
+
|
|
64
86
|
def self.fetch_schema(xsd_uri)
|
|
65
87
|
uri_md5 = Digest::MD5.hexdigest(xsd_uri)
|
|
66
88
|
dir_path = "#{self.configuration.offline_storage}"
|
|
@@ -77,8 +99,10 @@ module Kataba
|
|
|
77
99
|
end
|
|
78
100
|
|
|
79
101
|
# Validate and return Nokogiri schema
|
|
80
|
-
|
|
81
|
-
|
|
102
|
+
CHDIR_MUTEX.synchronize do
|
|
103
|
+
Dir.chdir(dir_path) do
|
|
104
|
+
return Nokogiri::XML::Schema(IO.read(xsd_path))
|
|
105
|
+
end
|
|
82
106
|
end
|
|
83
107
|
rescue Nokogiri::XML::SyntaxError
|
|
84
108
|
# Poisoned cache (e.g. a pre-fix install that stored a bad fetch).
|
|
@@ -122,7 +146,9 @@ module Kataba
|
|
|
122
146
|
fetch_uri = mirror unless mirror.to_s.empty?
|
|
123
147
|
end
|
|
124
148
|
|
|
125
|
-
body = Kataba::Fetcher.new(fetch_uri
|
|
149
|
+
body = Kataba::Fetcher.new(fetch_uri,
|
|
150
|
+
open_timeout: self.configuration.open_timeout,
|
|
151
|
+
read_timeout: self.configuration.read_timeout).fetch
|
|
126
152
|
|
|
127
153
|
# Write to a .part file first; only rename to the final cache path
|
|
128
154
|
# after we've confirmed the bytes parse as XML. Without this, a
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kataba
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Cliff
|
|
@@ -14,56 +14,56 @@ dependencies:
|
|
|
14
14
|
name: nokogiri
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- -
|
|
17
|
+
- - '>='
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '1.19'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- -
|
|
24
|
+
- - '>='
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.19'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- -
|
|
31
|
+
- - '>='
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '0'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- -
|
|
38
|
+
- - '>='
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: minitest
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- -
|
|
45
|
+
- - '>='
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- -
|
|
52
|
+
- - '>='
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: webmock
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- -
|
|
59
|
+
- - '>='
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
61
|
version: '0'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- -
|
|
66
|
+
- - '>='
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
69
|
description: Kataba allows for mirroring and offline storage of XSD files, to enhance
|
|
@@ -85,16 +85,16 @@ require_paths:
|
|
|
85
85
|
- lib
|
|
86
86
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
87
|
requirements:
|
|
88
|
-
- -
|
|
88
|
+
- - '>='
|
|
89
89
|
- !ruby/object:Gem::Version
|
|
90
90
|
version: '3.2'
|
|
91
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
|
-
- -
|
|
93
|
+
- - '>='
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '0'
|
|
96
96
|
requirements: []
|
|
97
|
-
rubygems_version: 3.
|
|
97
|
+
rubygems_version: 3.0.9
|
|
98
98
|
signing_key:
|
|
99
99
|
specification_version: 4
|
|
100
100
|
summary: XML Schema Definition (XSD) mirroring and offline validation for Nokogiri
|