ethon 0.18.0 → 0.19.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 +4 -4
- data/CHANGELOG.md +681 -2
- data/README.md +183 -40
- data/lib/ethon/curl.rb +22 -0
- data/lib/ethon/curls/classes.rb +284 -12
- data/lib/ethon/curls/codes.rb +28 -9
- data/lib/ethon/curls/constants.rb +61 -4
- data/lib/ethon/curls/form_options.rb +2 -1
- data/lib/ethon/curls/functions.rb +60 -11
- data/lib/ethon/curls/infos.rb +104 -5
- data/lib/ethon/curls/introspection.rb +139 -0
- data/lib/ethon/curls/introspection_constants.rb +42 -0
- data/lib/ethon/curls/mime.rb +187 -0
- data/lib/ethon/curls/optional.rb +14 -0
- data/lib/ethon/curls/options.rb +298 -71
- data/lib/ethon/curls/settings.rb +12 -3
- data/lib/ethon/curls/share.rb +165 -0
- data/lib/ethon/curls/share_constants.rb +47 -0
- data/lib/ethon/curls/url.rb +171 -0
- data/lib/ethon/curls/url_constants.rb +78 -0
- data/lib/ethon/easy/callbacks.rb +177 -51
- data/lib/ethon/easy/features.rb +4 -1
- data/lib/ethon/easy/files.rb +113 -0
- data/lib/ethon/easy/form.rb +65 -6
- data/lib/ethon/easy/header.rb +57 -15
- data/lib/ethon/easy/headers_api.rb +79 -0
- data/lib/ethon/easy/http/actionable.rb +25 -3
- data/lib/ethon/easy/http/get.rb +5 -1
- data/lib/ethon/easy/http/post.rb +1 -0
- data/lib/ethon/easy/http/postable.rb +9 -2
- data/lib/ethon/easy/http/putable.rb +19 -4
- data/lib/ethon/easy/http.rb +16 -4
- data/lib/ethon/easy/informations.rb +51 -2
- data/lib/ethon/easy/mime.rb +29 -0
- data/lib/ethon/easy/mirror.rb +17 -4
- data/lib/ethon/easy/operations.rb +259 -11
- data/lib/ethon/easy/options.rb +327 -8
- data/lib/ethon/easy/queryable.rb +59 -14
- data/lib/ethon/easy/response_callbacks.rb +33 -12
- data/lib/ethon/easy/share.rb +28 -0
- data/lib/ethon/easy/url.rb +32 -0
- data/lib/ethon/easy/util.rb +19 -0
- data/lib/ethon/easy.rb +185 -10
- data/lib/ethon/errors/fork_safety.rb +10 -0
- data/lib/ethon/errors/form_add.rb +12 -0
- data/lib/ethon/errors/global_init.rb +1 -1
- data/lib/ethon/errors/header.rb +12 -0
- data/lib/ethon/errors/invalid_option.rb +3 -1
- data/lib/ethon/errors/invalid_value.rb +3 -1
- data/lib/ethon/errors/mime.rb +17 -0
- data/lib/ethon/errors/multi_add.rb +1 -1
- data/lib/ethon/errors/multi_assign.rb +12 -0
- data/lib/ethon/errors/multi_fdset.rb +1 -1
- data/lib/ethon/errors/multi_perform.rb +12 -0
- data/lib/ethon/errors/multi_poll.rb +12 -0
- data/lib/ethon/errors/multi_remove.rb +1 -1
- data/lib/ethon/errors/multi_timeout.rb +2 -2
- data/lib/ethon/errors/multi_wait.rb +12 -0
- data/lib/ethon/errors/multi_wakeup.rb +12 -0
- data/lib/ethon/errors/select.rb +1 -1
- data/lib/ethon/errors/set_option.rb +27 -0
- data/lib/ethon/errors/share.rb +17 -0
- data/lib/ethon/errors/unsupported_option.rb +23 -0
- data/lib/ethon/errors/url.rb +17 -0
- data/lib/ethon/errors.rb +13 -0
- data/lib/ethon/libc.rb +30 -1
- data/lib/ethon/loggable.rb +1 -1
- data/lib/ethon/multi/operations.rb +269 -25
- data/lib/ethon/multi/options.rb +86 -12
- data/lib/ethon/multi/stack.rb +175 -10
- data/lib/ethon/multi.rb +44 -12
- data/lib/ethon/version.rb +1 -1
- data/lib/ethon.rb +8 -9
- metadata +35 -6
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Ethon
|
|
3
|
+
module Curl
|
|
4
|
+
|
|
5
|
+
# Thin wrapper around libcurl's share API.
|
|
6
|
+
class Share < OwnedPointer
|
|
7
|
+
CALLBACKS_MUTEX = Mutex.new
|
|
8
|
+
|
|
9
|
+
attr_reader :lockfunction, :unlockfunction
|
|
10
|
+
|
|
11
|
+
def self.native_release(pointer)
|
|
12
|
+
Curl.share_cleanup(pointer) if Curl.respond_to?(:share_cleanup)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Callback functions must outlive the Share because libcurl invokes them
|
|
16
|
+
# again from curl_share_cleanup.
|
|
17
|
+
def self.callbacks
|
|
18
|
+
@callbacks ||= {}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.release(pointer)
|
|
22
|
+
super
|
|
23
|
+
ensure
|
|
24
|
+
key = [Process.pid, pointer.address]
|
|
25
|
+
begin
|
|
26
|
+
CALLBACKS_MUTEX.synchronize { callbacks.delete(key) }
|
|
27
|
+
rescue ThreadError, SignalException
|
|
28
|
+
# Finalizers can run in a trap context where locking is forbidden.
|
|
29
|
+
callbacks.delete(key)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Build the dispatcher on the class so the closure does not retain the
|
|
34
|
+
# Share instance; otherwise the callback registry itself would keep every
|
|
35
|
+
# share handle alive.
|
|
36
|
+
#
|
|
37
|
+
# curl_lock_function and curl_unlock_function do not take the same
|
|
38
|
+
# arguments. An unlock callback receives the user pointer where a lock
|
|
39
|
+
# callback receives the access mode.
|
|
40
|
+
def self.lock_function(callback)
|
|
41
|
+
FFI::Function.new(:void, [:pointer, :int, :int, :pointer], proc do |handle, data, access, userp|
|
|
42
|
+
callback.call(handle, Curl::LockData[data], Curl::LockAccess[access], userp)
|
|
43
|
+
end)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.unlock_function(callback)
|
|
47
|
+
FFI::Function.new(:void, [:pointer, :int, :pointer], proc do |handle, data, userp|
|
|
48
|
+
callback.call(handle, Curl::LockData[data], userp)
|
|
49
|
+
end)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def initialize
|
|
53
|
+
Curl.init
|
|
54
|
+
unless Curl.respond_to?(:share_init)
|
|
55
|
+
raise NotImplementedError, "curl_share_init is not supported by this libcurl"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
pointer = Curl.share_init
|
|
59
|
+
raise NoMemoryError, "curl_share_init failed" if pointer.null?
|
|
60
|
+
|
|
61
|
+
super(pointer)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Share a data type between easy handles.
|
|
65
|
+
#
|
|
66
|
+
# @param [ Symbol, String ] data One of :cookie, :dns, :ssl_session,
|
|
67
|
+
# :connect, :psl, or :hsts.
|
|
68
|
+
#
|
|
69
|
+
# @return [ Share ] self
|
|
70
|
+
def share(data)
|
|
71
|
+
setopt(:share, data)
|
|
72
|
+
self
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Stop sharing a data type.
|
|
76
|
+
#
|
|
77
|
+
# @param [ Symbol, String ] data The data type.
|
|
78
|
+
#
|
|
79
|
+
# @return [ Share ] self
|
|
80
|
+
def unshare(data)
|
|
81
|
+
setopt(:unshare, data)
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Set the callback libcurl calls before accessing shared data.
|
|
86
|
+
#
|
|
87
|
+
# The block receives the easy handle, the shared data type, the access
|
|
88
|
+
# mode, and the user pointer. libcurl requires lock and unlock callbacks
|
|
89
|
+
# when a share handle is used from more than one thread.
|
|
90
|
+
#
|
|
91
|
+
# @example Lock shared cookies.
|
|
92
|
+
# share.lockfunction = proc { |handle, data, access, userp| mutex.synchronize { ... } }
|
|
93
|
+
#
|
|
94
|
+
# @param [ Proc, nil ] callback The lock callback.
|
|
95
|
+
#
|
|
96
|
+
# @return [ Proc, nil ] The callback.
|
|
97
|
+
def lockfunction=(callback)
|
|
98
|
+
set_callback(:lockfunc, callback)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Set the callback libcurl calls before releasing a share lock.
|
|
102
|
+
#
|
|
103
|
+
# The block receives the easy handle, the shared data type, and the user
|
|
104
|
+
# pointer. libcurl's unlock callback has no access mode argument.
|
|
105
|
+
#
|
|
106
|
+
# @param [ Proc, nil ] callback The unlock callback.
|
|
107
|
+
#
|
|
108
|
+
# @return [ Proc, nil ] The callback.
|
|
109
|
+
def unlockfunction=(callback)
|
|
110
|
+
set_callback(:unlockfunc, callback)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
private
|
|
114
|
+
|
|
115
|
+
def setopt(option, data)
|
|
116
|
+
check_pid!
|
|
117
|
+
unless data.is_a?(Symbol) || data.is_a?(String)
|
|
118
|
+
raise Errors::InvalidValue.new(option, data)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
value = Curl::LockData[data.to_sym]
|
|
122
|
+
raise Errors::InvalidValue.new(option, data) unless value
|
|
123
|
+
|
|
124
|
+
code = Curl.share_setopt(self, option, :long, value)
|
|
125
|
+
raise Errors::Share.new(code) unless code == :ok
|
|
126
|
+
|
|
127
|
+
code
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def set_callback(option, callback)
|
|
131
|
+
check_pid!
|
|
132
|
+
unless callback.nil? || callback.is_a?(Proc)
|
|
133
|
+
raise Errors::InvalidValue.new(option, callback)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# libcurl calls the lock and unlock callbacks again during
|
|
137
|
+
# curl_share_cleanup, so the FFI::Function itself must stay alive.
|
|
138
|
+
function = if callback
|
|
139
|
+
option == :lockfunc ? self.class.lock_function(callback) : self.class.unlock_function(callback)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
code = Curl.share_setopt(self, option, :pointer, function)
|
|
143
|
+
raise Errors::Share.new(code) unless code == :ok
|
|
144
|
+
|
|
145
|
+
key = [Process.pid, address]
|
|
146
|
+
CALLBACKS_MUTEX.synchronize do
|
|
147
|
+
registry = self.class.callbacks[key] ||= {}
|
|
148
|
+
if function
|
|
149
|
+
registry[option] = function
|
|
150
|
+
else
|
|
151
|
+
registry.delete(option)
|
|
152
|
+
self.class.callbacks.delete(key) if registry.empty?
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
if option == :lockfunc
|
|
157
|
+
@lockfunction = callback
|
|
158
|
+
else
|
|
159
|
+
@unlockfunction = callback
|
|
160
|
+
end
|
|
161
|
+
callback
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Ethon
|
|
3
|
+
module Curl
|
|
4
|
+
# CURLSHcode values.
|
|
5
|
+
ShareCode = enum(:share_code, [
|
|
6
|
+
:ok,
|
|
7
|
+
:bad_option,
|
|
8
|
+
:in_use,
|
|
9
|
+
:invalid,
|
|
10
|
+
:nomem,
|
|
11
|
+
:not_built_in,
|
|
12
|
+
:last
|
|
13
|
+
])
|
|
14
|
+
|
|
15
|
+
# CURLSHoption values.
|
|
16
|
+
ShareOption = enum(:share_option, [
|
|
17
|
+
:none,
|
|
18
|
+
:share,
|
|
19
|
+
:unshare,
|
|
20
|
+
:lockfunc,
|
|
21
|
+
:unlockfunc,
|
|
22
|
+
:userdata,
|
|
23
|
+
:last
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
# curl_lock_data values.
|
|
27
|
+
LockData = enum(:lock_data, [
|
|
28
|
+
:none,
|
|
29
|
+
:share,
|
|
30
|
+
:cookie,
|
|
31
|
+
:dns,
|
|
32
|
+
:ssl_session,
|
|
33
|
+
:connect,
|
|
34
|
+
:psl,
|
|
35
|
+
:hsts,
|
|
36
|
+
:last
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
# curl_lock_access values.
|
|
40
|
+
LockAccess = enum(:lock_access, [
|
|
41
|
+
:none,
|
|
42
|
+
:shared,
|
|
43
|
+
:single,
|
|
44
|
+
:last
|
|
45
|
+
])
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Ethon
|
|
3
|
+
module Curl
|
|
4
|
+
|
|
5
|
+
# CURLOPT_CURLU takes a CURLU handle.
|
|
6
|
+
Ethon::Curls::Options.option(:easy, :curlu, :ffipointer, 282)
|
|
7
|
+
|
|
8
|
+
# Thin wrapper around libcurl's URL API (curl_url).
|
|
9
|
+
class Url < OwnedPointer
|
|
10
|
+
def self.native_release(pointer)
|
|
11
|
+
Curl.url_cleanup(pointer) if Curl.respond_to?(:url_cleanup)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Create a URL handle, optionally parsing a URL string.
|
|
15
|
+
#
|
|
16
|
+
# @param [ String, Url, FFI::Pointer, nil ] url The URL, a URL handle
|
|
17
|
+
# to copy, or a native handle.
|
|
18
|
+
# @param [ Integer, Symbol, Array ] flags CURLU_* flags. These are only
|
|
19
|
+
# applied when parsing a String; a copied handle already has its parts.
|
|
20
|
+
def initialize(url = nil, flags = 0)
|
|
21
|
+
Curl.init
|
|
22
|
+
unless Curl.respond_to?(:url)
|
|
23
|
+
raise NotImplementedError, "curl_url is not supported by this libcurl"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
copying = url.is_a?(Ethon::Curl::Url)
|
|
27
|
+
if copying
|
|
28
|
+
url.check_pid!
|
|
29
|
+
if normalize_flags(flags) != 0
|
|
30
|
+
raise ArgumentError, "flags cannot be applied when copying an Ethon::Curl::Url"
|
|
31
|
+
end
|
|
32
|
+
# Parsing the copied handle's string form would fail for partial
|
|
33
|
+
# handles and could normalize a complete one. Duplicate the parts
|
|
34
|
+
# instead.
|
|
35
|
+
pointer = Curl.url_dup(url)
|
|
36
|
+
raise NoMemoryError, "curl_url_dup failed" if pointer.null?
|
|
37
|
+
elsif url.is_a?(::FFI::Pointer)
|
|
38
|
+
pointer = url
|
|
39
|
+
else
|
|
40
|
+
pointer = Curl.url
|
|
41
|
+
raise NoMemoryError, "curl_url failed" if pointer.null?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
super(pointer)
|
|
45
|
+
begin
|
|
46
|
+
set(:url, url, flags) if url && !url.is_a?(::FFI::Pointer) && !copying
|
|
47
|
+
rescue Exception
|
|
48
|
+
# A rejected URL must not leave the native handle to the finalizer.
|
|
49
|
+
free
|
|
50
|
+
raise
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Set a URL part.
|
|
55
|
+
#
|
|
56
|
+
# @param [ Symbol, String, Integer ] part The CURLUPart name or value.
|
|
57
|
+
# @param [ String, nil ] value The new value, or nil to clear the part.
|
|
58
|
+
# @param [ Integer, Symbol, Array ] flags CURLU_* flags.
|
|
59
|
+
#
|
|
60
|
+
# @raise [ Errors::InvalidValue ] If the part or a flag is unknown, or
|
|
61
|
+
# the value contains a NUL byte, CR, or LF.
|
|
62
|
+
#
|
|
63
|
+
# @return [ Url ] self
|
|
64
|
+
def set(part, value, flags = 0)
|
|
65
|
+
check_pid!
|
|
66
|
+
code = Curl.url_set(self, normalize_part(part), normalize_value(value),
|
|
67
|
+
normalize_flags(flags))
|
|
68
|
+
raise Errors::Url.new(code) unless code == :ok
|
|
69
|
+
|
|
70
|
+
self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Get a URL part.
|
|
74
|
+
#
|
|
75
|
+
# @param [ Symbol, String, Integer ] part The CURLUPart name or value.
|
|
76
|
+
# @param [ Integer, Symbol, Array ] flags CURLU_* flags.
|
|
77
|
+
#
|
|
78
|
+
# @raise [ Errors::InvalidValue ] If the part or a flag is unknown.
|
|
79
|
+
#
|
|
80
|
+
# @return [ String ] The part value.
|
|
81
|
+
def get(part, flags = 0)
|
|
82
|
+
check_pid!
|
|
83
|
+
output = ::FFI::MemoryPointer.new(:pointer)
|
|
84
|
+
code = Curl.url_get(self, normalize_part(part), output, normalize_flags(flags))
|
|
85
|
+
raise Errors::Url.new(code) unless code == :ok
|
|
86
|
+
|
|
87
|
+
pointer = output.read_pointer
|
|
88
|
+
begin
|
|
89
|
+
pointer.read_string
|
|
90
|
+
ensure
|
|
91
|
+
Curl.free(pointer)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Duplicate the URL handle.
|
|
96
|
+
#
|
|
97
|
+
# @return [ Url ] The copied URL.
|
|
98
|
+
def dup
|
|
99
|
+
check_pid!
|
|
100
|
+
pointer = Curl.url_dup(self)
|
|
101
|
+
raise NoMemoryError, "curl_url_dup failed" if pointer.null?
|
|
102
|
+
|
|
103
|
+
self.class.new(pointer)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Cloning shares the native handle in Ruby, so route it through #dup.
|
|
107
|
+
def clone(freeze: true)
|
|
108
|
+
copy = dup
|
|
109
|
+
copy.freeze if freeze && frozen?
|
|
110
|
+
copy
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def to_s
|
|
114
|
+
get(:url)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
# Only names that exist in CURLUPart reach libcurl. FFI would raise its
|
|
120
|
+
# own ArgumentError for anything else. Direct enum values stay supported,
|
|
121
|
+
# like the named option setters.
|
|
122
|
+
def normalize_part(part)
|
|
123
|
+
name = part.is_a?(String) ? part.to_sym : part
|
|
124
|
+
values = Curl::UrlPart.to_h
|
|
125
|
+
unless values.key?(name) || (name.is_a?(Integer) && values.value?(name))
|
|
126
|
+
raise Errors::InvalidValue.new(:url_part, part)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
name
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# libcurl takes a C string, so an embedded NUL would silently truncate
|
|
133
|
+
# the value. nil clears the part.
|
|
134
|
+
#
|
|
135
|
+
# The URL API also accepts CR and LF, which libcurl writes verbatim into
|
|
136
|
+
# the request line or query. A path or query containing CRLF can add
|
|
137
|
+
# attackers' headers to the request, so reject them here just like the
|
|
138
|
+
# string URL parser does. Callers that need such bytes in a URL must
|
|
139
|
+
# percent-encode them.
|
|
140
|
+
def normalize_value(value)
|
|
141
|
+
return if value.nil?
|
|
142
|
+
|
|
143
|
+
string = value.to_s
|
|
144
|
+
if string.include?("\0") || string.include?("\r") || string.include?("\n")
|
|
145
|
+
raise Errors::InvalidValue.new(:url_value, value)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
string
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Only CURLU_* flag names reach libcurl. FFI would raise its own
|
|
152
|
+
# ArgumentError for anything else. Direct bit values stay supported, like
|
|
153
|
+
# the named option setters.
|
|
154
|
+
def normalize_flags(flags)
|
|
155
|
+
return flags if flags.is_a?(Integer)
|
|
156
|
+
|
|
157
|
+
Array(flags).inject(0) { |mask, flag| mask | normalize_flag(flag) }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def normalize_flag(flag)
|
|
161
|
+
return flag if flag.is_a?(Integer)
|
|
162
|
+
|
|
163
|
+
name = flag.is_a?(String) ? flag.to_sym : flag
|
|
164
|
+
value = name.is_a?(Symbol) && Curl::UrlFlags.to_h[name]
|
|
165
|
+
raise Errors::InvalidValue.new(:url_flags, flag) unless value
|
|
166
|
+
|
|
167
|
+
value
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Ethon
|
|
3
|
+
module Curl
|
|
4
|
+
# CURLUPart values from curl/urlapi.h.
|
|
5
|
+
UrlPart = enum(:url_part, [
|
|
6
|
+
:url,
|
|
7
|
+
:scheme,
|
|
8
|
+
:user,
|
|
9
|
+
:password,
|
|
10
|
+
:options,
|
|
11
|
+
:host,
|
|
12
|
+
:port,
|
|
13
|
+
:path,
|
|
14
|
+
:query,
|
|
15
|
+
:fragment,
|
|
16
|
+
:zoneid
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
# CURLUcode values from curl/urlapi.h.
|
|
20
|
+
UrlCode = enum(:url_code, [
|
|
21
|
+
:ok,
|
|
22
|
+
:bad_handle,
|
|
23
|
+
:bad_partpointer,
|
|
24
|
+
:malformed_input,
|
|
25
|
+
:bad_port_number,
|
|
26
|
+
:unsupported_scheme,
|
|
27
|
+
:urldecode,
|
|
28
|
+
:out_of_memory,
|
|
29
|
+
:user_not_allowed,
|
|
30
|
+
:unknown_part,
|
|
31
|
+
:no_scheme,
|
|
32
|
+
:no_user,
|
|
33
|
+
:no_password,
|
|
34
|
+
:no_options,
|
|
35
|
+
:no_host,
|
|
36
|
+
:no_port,
|
|
37
|
+
:no_query,
|
|
38
|
+
:no_fragment,
|
|
39
|
+
:no_zoneid,
|
|
40
|
+
:bad_file_url,
|
|
41
|
+
:bad_fragment,
|
|
42
|
+
:bad_hostname,
|
|
43
|
+
:bad_ipv6,
|
|
44
|
+
:bad_login,
|
|
45
|
+
:bad_password,
|
|
46
|
+
:bad_path,
|
|
47
|
+
:bad_query,
|
|
48
|
+
:bad_scheme,
|
|
49
|
+
:bad_slashes,
|
|
50
|
+
:bad_user,
|
|
51
|
+
:lacks_idn,
|
|
52
|
+
:too_large,
|
|
53
|
+
:backslash,
|
|
54
|
+
:last
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
# CURLU_* flag bits from curl/urlapi.h.
|
|
58
|
+
UrlFlags = bitmask(:url_flags, [
|
|
59
|
+
nil,
|
|
60
|
+
:default_port,
|
|
61
|
+
:no_default_port,
|
|
62
|
+
:default_scheme,
|
|
63
|
+
:non_support_scheme,
|
|
64
|
+
:path_as_is,
|
|
65
|
+
:disallow_user,
|
|
66
|
+
:urldecode,
|
|
67
|
+
:urlencode,
|
|
68
|
+
:appendquery,
|
|
69
|
+
:guess_scheme,
|
|
70
|
+
:no_authority,
|
|
71
|
+
:allow_space,
|
|
72
|
+
:punycode,
|
|
73
|
+
:puny2idn,
|
|
74
|
+
:get_empty,
|
|
75
|
+
:no_guess_scheme
|
|
76
|
+
])
|
|
77
|
+
end
|
|
78
|
+
end
|