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
data/lib/ethon/curls/codes.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Ethon
|
|
|
7
7
|
module Codes
|
|
8
8
|
|
|
9
9
|
# Libcurl error codes, refer
|
|
10
|
-
# https://github.com/
|
|
10
|
+
# https://github.com/curl/curl/blob/master/include/curl/curl.h for details
|
|
11
11
|
def easy_codes
|
|
12
12
|
[
|
|
13
13
|
:ok,
|
|
@@ -18,7 +18,7 @@ module Ethon
|
|
|
18
18
|
:couldnt_resolve_proxy,
|
|
19
19
|
:couldnt_resolve_host,
|
|
20
20
|
:couldnt_connect,
|
|
21
|
-
:ftp_weird_server_reply,
|
|
21
|
+
:ftp_weird_server_reply, # CURLE_WEIRD_SERVER_REPLY since 7.51.0
|
|
22
22
|
:remote_access_denied,
|
|
23
23
|
:ftp_accept_failed,
|
|
24
24
|
:ftp_weird_pass_reply,
|
|
@@ -44,14 +44,14 @@ module Ethon
|
|
|
44
44
|
:ftp_couldnt_use_rest,
|
|
45
45
|
:obsolete32,
|
|
46
46
|
:range_error,
|
|
47
|
-
:http_post_error,
|
|
47
|
+
:http_post_error, # CURLE_OBSOLETE34 since 7.56.0
|
|
48
48
|
:ssl_connect_error,
|
|
49
49
|
:bad_download_resume,
|
|
50
50
|
:file_couldnt_read_file,
|
|
51
51
|
:ldap_cannot_bind,
|
|
52
52
|
:ldap_search_failed,
|
|
53
53
|
:obsolete40,
|
|
54
|
-
:function_not_found,
|
|
54
|
+
:function_not_found, # CURLE_OBSOLETE41 since 7.53.0
|
|
55
55
|
:aborted_by_callback,
|
|
56
56
|
:bad_function_argument,
|
|
57
57
|
:obsolete44,
|
|
@@ -59,7 +59,7 @@ module Ethon
|
|
|
59
59
|
:obsolete46,
|
|
60
60
|
:too_many_redirects ,
|
|
61
61
|
:unknown_option,
|
|
62
|
-
:telnet_option_syntax
|
|
62
|
+
:telnet_option_syntax, # CURLE_SETOPT_OPTION_SYNTAX since 7.78.0
|
|
63
63
|
:obsolete50,
|
|
64
64
|
:obsolete51,
|
|
65
65
|
:got_nothing,
|
|
@@ -72,7 +72,7 @@ module Ethon
|
|
|
72
72
|
:ssl_cipher,
|
|
73
73
|
:peer_failed_verification,
|
|
74
74
|
:bad_content_encoding,
|
|
75
|
-
:ldap_invalid_url,
|
|
75
|
+
:ldap_invalid_url, # CURLE_OBSOLETE62 since 7.82.0
|
|
76
76
|
:filesize_exceeded,
|
|
77
77
|
:use_ssl_failed,
|
|
78
78
|
:send_fail_rewind,
|
|
@@ -85,8 +85,8 @@ module Ethon
|
|
|
85
85
|
:tftp_unknownid,
|
|
86
86
|
:remote_file_exists,
|
|
87
87
|
:tftp_nosuchuser,
|
|
88
|
-
:conv_failed,
|
|
89
|
-
:conv_reqd,
|
|
88
|
+
:conv_failed, # CURLE_OBSOLETE75 since 7.82.0
|
|
89
|
+
:conv_reqd, # CURLE_OBSOLETE76 since 7.82.0
|
|
90
90
|
:ssl_cacert_badfile,
|
|
91
91
|
:remote_file_not_found,
|
|
92
92
|
:ssh,
|
|
@@ -99,12 +99,25 @@ module Ethon
|
|
|
99
99
|
:rtsp_session_error,
|
|
100
100
|
:ftp_bad_file_list,
|
|
101
101
|
:chunk_failed,
|
|
102
|
+
:no_connection_available,
|
|
103
|
+
:ssl_pinnedpubkeynotmatch,
|
|
104
|
+
:ssl_invalidcertstatus,
|
|
105
|
+
:http2_stream,
|
|
106
|
+
:recursive_api_call,
|
|
107
|
+
:auth_error,
|
|
108
|
+
:http3,
|
|
109
|
+
:quic_connect_error,
|
|
110
|
+
:proxy,
|
|
111
|
+
:ssl_clientcert,
|
|
112
|
+
:unrecoverable_poll,
|
|
113
|
+
:too_large,
|
|
114
|
+
:ech_required,
|
|
102
115
|
:last
|
|
103
116
|
]
|
|
104
117
|
end
|
|
105
118
|
|
|
106
119
|
# Curl-Multi socket error codes, refer
|
|
107
|
-
# https://github.com/
|
|
120
|
+
# https://github.com/curl/curl/blob/master/include/curl/multi.h for details
|
|
108
121
|
def multi_codes
|
|
109
122
|
[
|
|
110
123
|
:call_multi_perform, -1,
|
|
@@ -115,6 +128,12 @@ module Ethon
|
|
|
115
128
|
:internal_error,
|
|
116
129
|
:bad_socket,
|
|
117
130
|
:unknown_option,
|
|
131
|
+
:added_already,
|
|
132
|
+
:recursive_api_call,
|
|
133
|
+
:wakeup_failure,
|
|
134
|
+
:bad_function_argument,
|
|
135
|
+
:aborted_by_callback,
|
|
136
|
+
:unrecoverable_poll,
|
|
118
137
|
:last
|
|
119
138
|
]
|
|
120
139
|
end
|
|
@@ -4,6 +4,34 @@ module Ethon
|
|
|
4
4
|
# :nodoc:
|
|
5
5
|
VERSION_NOW = 3
|
|
6
6
|
|
|
7
|
+
# curl_sslbackend values used by curl_global_sslset.
|
|
8
|
+
SslBackend = enum(:ssl_backend, [
|
|
9
|
+
:none,
|
|
10
|
+
:openssl,
|
|
11
|
+
:gnutls,
|
|
12
|
+
:nss,
|
|
13
|
+
:obsolete4,
|
|
14
|
+
:gskit,
|
|
15
|
+
:polarssl,
|
|
16
|
+
:wolfssl,
|
|
17
|
+
:schannel,
|
|
18
|
+
:securetransport,
|
|
19
|
+
:axtls,
|
|
20
|
+
:mbedtls,
|
|
21
|
+
:mesalink,
|
|
22
|
+
:bearssl,
|
|
23
|
+
:rustls
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
# CURLsslset values returned by curl_global_sslset. These are not CURLcode
|
|
27
|
+
# values, even though both start at zero.
|
|
28
|
+
SslSetCode = enum(:ssl_set_code, [
|
|
29
|
+
:ok,
|
|
30
|
+
:unknown_backend,
|
|
31
|
+
:too_late,
|
|
32
|
+
:no_backends
|
|
33
|
+
])
|
|
34
|
+
|
|
7
35
|
# Flag. Initialize SSL.
|
|
8
36
|
GLOBAL_SSL = 0x01
|
|
9
37
|
# Flag. Initialize win32 socket libraries.
|
|
@@ -24,18 +52,18 @@ module Ethon
|
|
|
24
52
|
MultiOption = enum(:multi_option, multi_options(:enum).to_a.flatten)
|
|
25
53
|
|
|
26
54
|
# Used by curl_debug_callback when setting CURLOPT_DEBUGFUNCTION
|
|
27
|
-
# https://github.com/
|
|
55
|
+
# https://github.com/curl/curl/blob/master/include/curl/curl.h#L378 for details
|
|
28
56
|
DebugInfoType = enum(:debug_info_type, debug_info_types)
|
|
29
57
|
|
|
30
58
|
# :nodoc:
|
|
31
59
|
InfoType = enum(info_types.to_a.flatten)
|
|
32
60
|
|
|
33
61
|
# Info details, refer
|
|
34
|
-
# https://github.com/
|
|
62
|
+
# https://github.com/curl/curl/blob/master/src/tool_writeout.c#L66 for details
|
|
35
63
|
Info = enum(:info, infos.to_a.flatten)
|
|
36
64
|
|
|
37
65
|
# Form options, used by FormAdd for temporary storage, refer
|
|
38
|
-
# https://github.com/
|
|
66
|
+
# https://github.com/curl/curl/blob/master/lib/formdata.h#L51 for details
|
|
39
67
|
FormOption = enum(:form_option, form_options)
|
|
40
68
|
|
|
41
69
|
# :nodoc:
|
|
@@ -59,8 +87,26 @@ module Ethon
|
|
|
59
87
|
VERSION_NTLM_WB = (1<<15) # NTLM delegating to winbind helper
|
|
60
88
|
VERSION_HTTP2 = (1<<16) # HTTP2 support built
|
|
61
89
|
VERSION_GSSAPI = (1<<17) # GSS-API is supported
|
|
90
|
+
VERSION_KERBEROS5 = (1<<18) # Kerberos V5 auth is supported
|
|
91
|
+
VERSION_UNIX_SOCKETS = (1<<19) # Unix domain sockets support
|
|
92
|
+
VERSION_PSL = (1<<20) # Public Suffix List support
|
|
93
|
+
VERSION_HTTPS_PROXY = (1<<21) # HTTPS-proxy support built-in
|
|
94
|
+
VERSION_MULTI_SSL = (1<<22) # Multiple SSL backends available
|
|
95
|
+
VERSION_BROTLI = (1<<23) # Brotli features are present
|
|
96
|
+
VERSION_ALTSVC = (1<<24) # Alt-Svc handling built-in
|
|
97
|
+
VERSION_HTTP3 = (1<<25) # HTTP3 support built-in
|
|
98
|
+
VERSION_ZSTD = (1<<26) # zstd features are present
|
|
99
|
+
VERSION_UNICODE = (1<<27) # Unicode support on Windows
|
|
100
|
+
VERSION_HSTS = (1<<28) # HSTS is supported
|
|
101
|
+
VERSION_GSASL = (1<<29) # libgsasl is supported
|
|
102
|
+
VERSION_THREADSAFE = (1<<30) # libcurl API is thread-safe
|
|
62
103
|
|
|
63
|
-
|
|
104
|
+
# curl_socket_t is int on Unix and SOCKET (UINT_PTR) on Windows.
|
|
105
|
+
SOCKET_BAD = if Curl.windows?
|
|
106
|
+
(1 << (::FFI.type_size(:size_t) * 8)) - 1
|
|
107
|
+
else
|
|
108
|
+
-1
|
|
109
|
+
end
|
|
64
110
|
SOCKET_TIMEOUT = SOCKET_BAD
|
|
65
111
|
|
|
66
112
|
PollAction = enum(:poll_action, [
|
|
@@ -76,5 +122,16 @@ module Ethon
|
|
|
76
122
|
:out, # CURL_CSELECT_OUT - 0x02 (bit 1)
|
|
77
123
|
:err, # CURL_CSELECT_ERR - 0x04 (bit 2)
|
|
78
124
|
])
|
|
125
|
+
|
|
126
|
+
# Bitmasks for curl_easy_pause.
|
|
127
|
+
PAUSE_RECV = (1<<0)
|
|
128
|
+
PAUSE_SEND = (1<<2)
|
|
129
|
+
PAUSE_ALL = (PAUSE_RECV | PAUSE_SEND)
|
|
130
|
+
PAUSE_CONT = 0
|
|
131
|
+
|
|
132
|
+
# Event bits for curl_multi_wait/curl_multi_poll.
|
|
133
|
+
WAIT_POLLIN = 0x0001
|
|
134
|
+
WAIT_POLLPRI = 0x0002
|
|
135
|
+
WAIT_POLLOUT = 0x0004
|
|
79
136
|
end
|
|
80
137
|
end
|
|
@@ -6,7 +6,7 @@ module Ethon
|
|
|
6
6
|
module FormOptions
|
|
7
7
|
|
|
8
8
|
# Form options, used by FormAdd for temporary storage, refer
|
|
9
|
-
# https://github.com/
|
|
9
|
+
# https://github.com/curl/curl/blob/master/lib/formdata.h#L51 for details
|
|
10
10
|
def form_options
|
|
11
11
|
[
|
|
12
12
|
:none,
|
|
@@ -29,6 +29,7 @@ module Ethon
|
|
|
29
29
|
:end,
|
|
30
30
|
:obsolete2,
|
|
31
31
|
:stream,
|
|
32
|
+
:contentlen,
|
|
32
33
|
:last
|
|
33
34
|
]
|
|
34
35
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
require 'ethon/curls/optional'
|
|
2
3
|
module Ethon
|
|
3
4
|
module Curls
|
|
4
5
|
|
|
@@ -12,8 +13,14 @@ module Ethon
|
|
|
12
13
|
base.attach_function :global_cleanup, :curl_global_cleanup, [], :void
|
|
13
14
|
base.attach_function :free, :curl_free, [:pointer], :void
|
|
14
15
|
|
|
16
|
+
Ethon::Curls::Optional.attach(base, :easy_header, :curl_easy_header, [:pointer, :string, :size_t, :uint, :int, :pointer], :header_code, blocking: false)
|
|
17
|
+
Ethon::Curls::Optional.attach(base, :easy_nextheader, :curl_easy_nextheader, [:pointer, :uint, :int, :pointer], Curl::HeaderData.ptr, blocking: false)
|
|
18
|
+
Ethon::Curls::Optional.attach(base, :easy_option_by_name, :curl_easy_option_by_name, [:string], Curl::EasyOptionInfo.ptr, blocking: false)
|
|
19
|
+
Ethon::Curls::Optional.attach(base, :easy_option_by_id, :curl_easy_option_by_id, [:easy_option], Curl::EasyOptionInfo.ptr, blocking: false)
|
|
20
|
+
Ethon::Curls::Optional.attach(base, :easy_option_next, :curl_easy_option_next, [:pointer], Curl::EasyOptionInfo.ptr, blocking: false)
|
|
21
|
+
|
|
15
22
|
base.attach_function :easy_init, :curl_easy_init, [], :pointer
|
|
16
|
-
base.attach_function :easy_cleanup, :curl_easy_cleanup, [:pointer], :void
|
|
23
|
+
base.attach_function :easy_cleanup, :curl_easy_cleanup, [:pointer], :void, blocking: true
|
|
17
24
|
base.attach_function :easy_getinfo, :curl_easy_getinfo, [:pointer, :info, :varargs], :easy_code
|
|
18
25
|
base.attach_function :easy_setopt, :curl_easy_setopt, [:pointer, :easy_option, :varargs], :easy_code
|
|
19
26
|
base.instance_variable_set(:@blocking, true)
|
|
@@ -21,38 +28,80 @@ module Ethon
|
|
|
21
28
|
base.attach_function :easy_strerror, :curl_easy_strerror, [:easy_code], :string
|
|
22
29
|
base.attach_function :easy_escape, :curl_easy_escape, [:pointer, :pointer, :int], :pointer
|
|
23
30
|
base.attach_function :easy_reset, :curl_easy_reset, [:pointer], :void
|
|
24
|
-
base
|
|
31
|
+
Ethon::Curls::Optional.attach(base, :easy_duphandle, :curl_easy_duphandle, [:pointer], :pointer, blocking: false)
|
|
32
|
+
|
|
33
|
+
Ethon::Curls::Optional.attach(base, :url, :curl_url, [], :pointer, blocking: false)
|
|
34
|
+
Ethon::Curls::Optional.attach(base, :url_cleanup, :curl_url_cleanup, [:pointer], :void, blocking: false)
|
|
35
|
+
Ethon::Curls::Optional.attach(base, :url_dup, :curl_url_dup, [:pointer], :pointer, blocking: false)
|
|
36
|
+
Ethon::Curls::Optional.attach(base, :url_get, :curl_url_get, [:pointer, :url_part, :pointer, :url_flags], :url_code, blocking: false)
|
|
37
|
+
Ethon::Curls::Optional.attach(base, :url_set, :curl_url_set, [:pointer, :url_part, :string, :url_flags], :url_code, blocking: false)
|
|
38
|
+
Ethon::Curls::Optional.attach(base, :url_strerror, :curl_url_strerror, [:url_code], :string, blocking: false)
|
|
25
39
|
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
# The form API is deprecated and absent from builds configured with
|
|
41
|
+
# --disable-form-api. Attach it when present so Ethon still loads.
|
|
42
|
+
Ethon::Curls::Optional.attach(base, :formadd, :curl_formadd, [:pointer, :pointer, :varargs], :int)
|
|
43
|
+
Ethon::Curls::Optional.attach(base, :formfree, :curl_formfree, [:pointer], :void)
|
|
44
|
+
|
|
45
|
+
Ethon::Curls::Optional.attach(base, :share_init, :curl_share_init, [], :pointer, blocking: false)
|
|
46
|
+
Ethon::Curls::Optional.attach(base, :share_cleanup, :curl_share_cleanup, [:pointer], :share_code, blocking: false)
|
|
47
|
+
Ethon::Curls::Optional.attach(base, :share_setopt, :curl_share_setopt, [:pointer, :share_option, :varargs], :share_code, blocking: false)
|
|
48
|
+
Ethon::Curls::Optional.attach(base, :share_strerror, :curl_share_strerror, [:share_code], :string, blocking: false)
|
|
28
49
|
|
|
29
50
|
base.attach_function :multi_init, :curl_multi_init, [], :pointer
|
|
30
|
-
base.attach_function :multi_cleanup, :curl_multi_cleanup, [:pointer], :void
|
|
51
|
+
base.attach_function :multi_cleanup, :curl_multi_cleanup, [:pointer], :void, blocking: true
|
|
31
52
|
base.attach_function :multi_add_handle, :curl_multi_add_handle, [:pointer, :pointer], :multi_code
|
|
32
|
-
base.attach_function :multi_remove_handle, :curl_multi_remove_handle, [:pointer, :pointer], :multi_code
|
|
53
|
+
base.attach_function :multi_remove_handle, :curl_multi_remove_handle, [:pointer, :pointer], :multi_code, blocking: true
|
|
33
54
|
base.attach_function :multi_info_read, :curl_multi_info_read, [:pointer, :pointer], Curl::Msg.ptr
|
|
34
|
-
base.attach_function :multi_perform, :curl_multi_perform, [:pointer, :pointer], :multi_code
|
|
55
|
+
base.attach_function :multi_perform, :curl_multi_perform, [:pointer, :pointer], :multi_code, blocking: true
|
|
35
56
|
base.attach_function :multi_timeout, :curl_multi_timeout, [:pointer, :pointer], :multi_code
|
|
36
57
|
base.attach_function :multi_fdset, :curl_multi_fdset, [:pointer, Curl::FDSet.ptr, Curl::FDSet.ptr, Curl::FDSet.ptr, :pointer], :multi_code
|
|
37
|
-
base.attach_function :multi_strerror, :curl_multi_strerror, [:
|
|
58
|
+
base.attach_function :multi_strerror, :curl_multi_strerror, [:multi_code], :string
|
|
38
59
|
base.attach_function :multi_setopt, :curl_multi_setopt, [:pointer, :multi_option, :varargs], :multi_code
|
|
39
|
-
base.attach_function :multi_socket_action, :curl_multi_socket_action, [:pointer, :
|
|
60
|
+
base.attach_function :multi_socket_action, :curl_multi_socket_action, [:pointer, :curl_socket_t, :socket_readiness, :pointer], :multi_code, blocking: true
|
|
61
|
+
base.attach_function :multi_assign, :curl_multi_assign, [:pointer, :curl_socket_t, :pointer], :multi_code
|
|
62
|
+
|
|
63
|
+
Ethon::Curls::Optional.attach(base, :multi_get_handles, :curl_multi_get_handles, [:pointer], :pointer, blocking: false)
|
|
64
|
+
Ethon::Curls::Optional.attach(base, :global_sslset, :curl_global_sslset, [:ssl_backend, :string, :pointer], :ssl_set_code, blocking: false)
|
|
65
|
+
Ethon::Curls::Optional.attach(base, :global_trace, :curl_global_trace, [:string], :easy_code, blocking: false)
|
|
40
66
|
|
|
41
67
|
base.attach_function :version, :curl_version, [], :string
|
|
42
|
-
base.attach_function :
|
|
68
|
+
base.attach_function :curl_version_info, :curl_version_info, [:int], Curl::VersionInfoData.ptr
|
|
69
|
+
|
|
70
|
+
Ethon::Curls::Optional.attach(base, :mime_init, :curl_mime_init, [:pointer], :pointer, blocking: false)
|
|
71
|
+
Ethon::Curls::Optional.attach(base, :mime_free, :curl_mime_free, [:pointer], :void, blocking: false)
|
|
72
|
+
Ethon::Curls::Optional.attach(base, :mime_addpart, :curl_mime_addpart, [:pointer], :pointer, blocking: false)
|
|
73
|
+
Ethon::Curls::Optional.attach(base, :mime_name, :curl_mime_name, [:pointer, :string], :easy_code, blocking: false)
|
|
74
|
+
Ethon::Curls::Optional.attach(base, :mime_filename, :curl_mime_filename, [:pointer, :string], :easy_code, blocking: false)
|
|
75
|
+
Ethon::Curls::Optional.attach(base, :mime_type, :curl_mime_type, [:pointer, :string], :easy_code, blocking: false)
|
|
76
|
+
Ethon::Curls::Optional.attach(base, :mime_encoder, :curl_mime_encoder, [:pointer, :string], :easy_code, blocking: false)
|
|
77
|
+
Ethon::Curls::Optional.attach(base, :mime_data, :curl_mime_data, [:pointer, :pointer, :size_t], :easy_code, blocking: false)
|
|
78
|
+
Ethon::Curls::Optional.attach(base, :mime_filedata, :curl_mime_filedata, [:pointer, :string], :easy_code, blocking: false)
|
|
79
|
+
Ethon::Curls::Optional.attach(base, :mime_headers, :curl_mime_headers, [:pointer, :pointer, :int], :easy_code, blocking: false)
|
|
43
80
|
|
|
44
81
|
base.attach_function :slist_append, :curl_slist_append, [:pointer, :string], :pointer
|
|
45
82
|
base.attach_function :slist_free_all, :curl_slist_free_all, [:pointer], :void
|
|
46
83
|
base.instance_variable_set(:@blocking, true)
|
|
47
84
|
|
|
85
|
+
Ethon::Curls::Optional.attach(base, :easy_unescape, :curl_easy_unescape, [:pointer, :pointer, :int, :pointer], :pointer, blocking: false)
|
|
86
|
+
Ethon::Curls::Optional.attach(base, :easy_pause, :curl_easy_pause, [:pointer, :int], :easy_code, blocking: false)
|
|
87
|
+
Ethon::Curls::Optional.attach(base, :easy_send, :curl_easy_send, [:pointer, :pointer, :size_t, :pointer], :easy_code, blocking: false)
|
|
88
|
+
Ethon::Curls::Optional.attach(base, :easy_recv, :curl_easy_recv, [:pointer, :pointer, :size_t, :pointer], :easy_code, blocking: false)
|
|
89
|
+
Ethon::Curls::Optional.attach(base, :multi_wait, :curl_multi_wait, [:pointer, :pointer, :uint, :int, :pointer], :multi_code, blocking: true)
|
|
90
|
+
Ethon::Curls::Optional.attach(base, :easy_upkeep, :curl_easy_upkeep, [:pointer], :easy_code, blocking: false)
|
|
91
|
+
Ethon::Curls::Optional.attach(base, :multi_poll, :curl_multi_poll, [:pointer, :pointer, :uint, :int, :pointer], :multi_code, blocking: true)
|
|
92
|
+
Ethon::Curls::Optional.attach(base, :multi_wakeup, :curl_multi_wakeup, [:pointer], :multi_code, blocking: false)
|
|
93
|
+
|
|
48
94
|
if Curl.windows?
|
|
49
95
|
base.ffi_lib 'ws2_32'
|
|
50
96
|
else
|
|
51
97
|
base.ffi_lib ::FFI::Library::LIBC
|
|
52
98
|
end
|
|
53
99
|
|
|
54
|
-
|
|
100
|
+
# select() blocks for the multi timeout. Release the GVL so other Ruby
|
|
101
|
+
# threads can run while the select fallback is waiting.
|
|
102
|
+
base.attach_function :select, [:int, Curl::FDSet.ptr, Curl::FDSet.ptr, Curl::FDSet.ptr, Curl::Timeval.ptr], :int, blocking: true
|
|
55
103
|
end
|
|
104
|
+
|
|
56
105
|
end
|
|
57
106
|
end
|
|
58
107
|
end
|
data/lib/ethon/curls/infos.rb
CHANGED
|
@@ -17,12 +17,15 @@ module Ethon
|
|
|
17
17
|
:string =>0x100000,
|
|
18
18
|
:long => 0x200000,
|
|
19
19
|
:double =>0x300000,
|
|
20
|
-
:slist => 0x400000
|
|
20
|
+
:slist => 0x400000,
|
|
21
|
+
:ptr => 0x400000,
|
|
22
|
+
:socket =>0x500000,
|
|
23
|
+
:off_t => 0x600000
|
|
21
24
|
}
|
|
22
25
|
end
|
|
23
26
|
|
|
24
|
-
#
|
|
25
|
-
# https://github.com/
|
|
27
|
+
# https://curl.se/libcurl/c/CURLOPT_DEBUGFUNCTION.html
|
|
28
|
+
# https://github.com/curl/curl/blob/master/include/curl/curl.h#L378
|
|
26
29
|
#
|
|
27
30
|
# @example Return debug info types.
|
|
28
31
|
# Ethon::Curl.debug_info_types
|
|
@@ -41,7 +44,7 @@ module Ethon
|
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
# Return Info details, refer
|
|
44
|
-
# https://github.com/
|
|
47
|
+
# https://github.com/curl/curl/blob/master/src/tool_writeout.c#L66 for details
|
|
45
48
|
#
|
|
46
49
|
# @example Return infos.
|
|
47
50
|
# Ethon::Curl.infos
|
|
@@ -49,6 +52,40 @@ module Ethon
|
|
|
49
52
|
# @return [ Hash ] The infos.
|
|
50
53
|
def infos
|
|
51
54
|
{
|
|
55
|
+
:size_upload_t => info_types[:off_t] + 7,
|
|
56
|
+
:size_download_t => info_types[:off_t] + 8,
|
|
57
|
+
:speed_download_t => info_types[:off_t] + 9,
|
|
58
|
+
:speed_upload_t => info_types[:off_t] + 10,
|
|
59
|
+
:filetime_t => info_types[:off_t] + 14,
|
|
60
|
+
:content_length_download_t =>info_types[:off_t] + 15,
|
|
61
|
+
:content_length_upload_t =>info_types[:off_t] + 16,
|
|
62
|
+
:http_version => info_types[:long] + 46,
|
|
63
|
+
:proxy_ssl_verifyresult => info_types[:long] + 47,
|
|
64
|
+
:scheme => info_types[:string] + 49,
|
|
65
|
+
:total_time_t => info_types[:off_t] + 50,
|
|
66
|
+
:namelookup_time_t => info_types[:off_t] + 51,
|
|
67
|
+
:connect_time_t => info_types[:off_t] + 52,
|
|
68
|
+
:pretransfer_time_t => info_types[:off_t] + 53,
|
|
69
|
+
:starttransfer_time_t => info_types[:off_t] + 54,
|
|
70
|
+
:redirect_time_t => info_types[:off_t] + 55,
|
|
71
|
+
:appconnect_time_t => info_types[:off_t] + 56,
|
|
72
|
+
:retry_after => info_types[:off_t] + 57,
|
|
73
|
+
:effective_method => info_types[:string] + 58,
|
|
74
|
+
:proxy_error => info_types[:long] + 59,
|
|
75
|
+
:referer => info_types[:string] + 60,
|
|
76
|
+
:cainfo => info_types[:string] + 61,
|
|
77
|
+
:capath => info_types[:string] + 62,
|
|
78
|
+
:xfer_id => info_types[:off_t] + 63,
|
|
79
|
+
:conn_id => info_types[:off_t] + 64,
|
|
80
|
+
:queue_time_t => info_types[:off_t] + 65,
|
|
81
|
+
:used_proxy => info_types[:long] + 66,
|
|
82
|
+
:posttransfer_time_t => info_types[:off_t] + 67,
|
|
83
|
+
:earlydata_sent_t => info_types[:off_t] + 68,
|
|
84
|
+
:httpauth_used => info_types[:long] + 69,
|
|
85
|
+
:proxyauth_used => info_types[:long] + 70,
|
|
86
|
+
:size_delivered => info_types[:off_t] + 71,
|
|
87
|
+
:activesocket => info_types[:socket] + 44,
|
|
88
|
+
:tls_ssl_ptr => info_types[:ptr] + 45,
|
|
52
89
|
:effective_url => info_types[:string] + 1,
|
|
53
90
|
:response_code => info_types[:long] + 2,
|
|
54
91
|
:total_time => info_types[:double] + 3,
|
|
@@ -91,7 +128,7 @@ module Ethon
|
|
|
91
128
|
:primary_port => info_types[:long] + 40,
|
|
92
129
|
:local_ip => info_types[:string] + 41,
|
|
93
130
|
:local_port => info_types[:long] + 42,
|
|
94
|
-
:last =>
|
|
131
|
+
:last =>71
|
|
95
132
|
}
|
|
96
133
|
end
|
|
97
134
|
|
|
@@ -146,6 +183,68 @@ module Ethon
|
|
|
146
183
|
double_ptr.read_double
|
|
147
184
|
end
|
|
148
185
|
end
|
|
186
|
+
|
|
187
|
+
# Return info as a 64-bit integer (curl_off_t).
|
|
188
|
+
def get_info_off_t(option, handle)
|
|
189
|
+
int64_ptr = ::FFI::MemoryPointer.new(:int64)
|
|
190
|
+
|
|
191
|
+
if easy_getinfo(handle, option, :pointer, int64_ptr) == :ok
|
|
192
|
+
int64_ptr.read_int64
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Return info as a curl_socket_t.
|
|
197
|
+
def get_info_socket(option, handle)
|
|
198
|
+
if Curl.windows?
|
|
199
|
+
ptr = ::FFI::MemoryPointer.new(:size_t)
|
|
200
|
+
return unless easy_getinfo(handle, option, :pointer, ptr) == :ok
|
|
201
|
+
::FFI.type_size(:size_t) == 8 ? ptr.read_uint64 : ptr.read_uint32
|
|
202
|
+
else
|
|
203
|
+
ptr = ::FFI::MemoryPointer.new(:int)
|
|
204
|
+
ptr.read_int if easy_getinfo(handle, option, :pointer, ptr) == :ok
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Return info as a raw pointer.
|
|
209
|
+
def get_info_ptr(option, handle)
|
|
210
|
+
ptr = ::FFI::MemoryPointer.new(:pointer)
|
|
211
|
+
|
|
212
|
+
if easy_getinfo(handle, option, :pointer, ptr) == :ok
|
|
213
|
+
value = ptr.read_pointer
|
|
214
|
+
value unless value.null?
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Return info as array of strings.
|
|
219
|
+
#
|
|
220
|
+
# @example Return info.
|
|
221
|
+
# Curl.get_info_slist(:ssl_engines, easy)
|
|
222
|
+
#
|
|
223
|
+
# @param [ Symbol ] option The option name.
|
|
224
|
+
# @param [ ::FFI::Pointer ] handle The easy handle.
|
|
225
|
+
#
|
|
226
|
+
# @return [ Array ] The info.
|
|
227
|
+
def get_info_slist(option, handle)
|
|
228
|
+
result = ::FFI::MemoryPointer.new(:pointer)
|
|
229
|
+
return unless easy_getinfo(handle, option, :pointer, result) == :ok
|
|
230
|
+
|
|
231
|
+
pointer = result.read_pointer
|
|
232
|
+
return [] if pointer.null?
|
|
233
|
+
|
|
234
|
+
list = Curl::Slist.new(pointer)
|
|
235
|
+
list.to_a
|
|
236
|
+
ensure
|
|
237
|
+
list.free if list
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Return certificate information copied from libcurl-owned memory.
|
|
241
|
+
def get_info_certinfo(option, handle)
|
|
242
|
+
result = ::FFI::MemoryPointer.new(:pointer)
|
|
243
|
+
return unless easy_getinfo(handle, option, :pointer, result) == :ok
|
|
244
|
+
|
|
245
|
+
pointer = result.read_pointer
|
|
246
|
+
pointer.null? ? [] : Curl::Certinfo.new(pointer).to_a
|
|
247
|
+
end
|
|
149
248
|
end
|
|
150
249
|
end
|
|
151
250
|
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Ethon
|
|
3
|
+
module Curl
|
|
4
|
+
class << self
|
|
5
|
+
# Look up a libcurl option by name.
|
|
6
|
+
#
|
|
7
|
+
# @param [ String, Symbol ] name The CURLOPT name.
|
|
8
|
+
#
|
|
9
|
+
# @return [ EasyOptionInfo, nil ] The option metadata.
|
|
10
|
+
def easy_option(name)
|
|
11
|
+
return unless respond_to?(:easy_option_by_name)
|
|
12
|
+
|
|
13
|
+
info = easy_option_by_name(name.to_s)
|
|
14
|
+
info.null? ? nil : info
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Look up a libcurl option by numeric id.
|
|
18
|
+
#
|
|
19
|
+
# @param [ Integer, Symbol ] id The CURLoption id or name.
|
|
20
|
+
#
|
|
21
|
+
# @return [ EasyOptionInfo, nil ] The option metadata.
|
|
22
|
+
def option_by_id(id)
|
|
23
|
+
return unless respond_to?(:easy_option_by_id)
|
|
24
|
+
|
|
25
|
+
info = easy_option_by_id(id)
|
|
26
|
+
info.null? ? nil : info
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Enumerate all libcurl option metadata.
|
|
30
|
+
#
|
|
31
|
+
# @return [ Enumerator, Array ] The metadata.
|
|
32
|
+
def each_easy_option
|
|
33
|
+
unless respond_to?(:easy_option_next)
|
|
34
|
+
raise NotImplementedError, "curl_easy_option_next is not supported by this libcurl"
|
|
35
|
+
end
|
|
36
|
+
return enum_for(:each_easy_option) unless block_given?
|
|
37
|
+
|
|
38
|
+
info = easy_option_next(::FFI::Pointer::NULL)
|
|
39
|
+
until info.null?
|
|
40
|
+
yield info
|
|
41
|
+
info = easy_option_next(info)
|
|
42
|
+
end
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def easy_option_list
|
|
47
|
+
each_easy_option.to_a
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# The full version info struct when the runtime supports it.
|
|
51
|
+
#
|
|
52
|
+
# @return [ VersionInfoDataFull, nil ] The full version metadata.
|
|
53
|
+
def version_info_full
|
|
54
|
+
info = version_info
|
|
55
|
+
return unless info && info[:curl_version] >= CURLVERSION_ELEVENTH
|
|
56
|
+
|
|
57
|
+
VersionInfoDataFull.new(info.to_ptr)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Protocols supported by the loaded libcurl.
|
|
61
|
+
#
|
|
62
|
+
# @return [ Array<String> ] Protocol names.
|
|
63
|
+
def protocols
|
|
64
|
+
string_array(version_info[:protocols])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Return whether libcurl knows an option.
|
|
68
|
+
#
|
|
69
|
+
# Easy options are checked against libcurl's own option table on 7.73.0
|
|
70
|
+
# and newer. Older versions cannot answer that question, so it returns
|
|
71
|
+
# `true` for every option Ethon knows. Multi options are only checked
|
|
72
|
+
# against Ethon's table, because libcurl does not expose multi option
|
|
73
|
+
# metadata.
|
|
74
|
+
#
|
|
75
|
+
# @param [ String, Symbol ] name The CURLOPT_* name without the prefix.
|
|
76
|
+
# @param [ Symbol ] type :easy or :multi.
|
|
77
|
+
#
|
|
78
|
+
# @return [ Boolean ] True when the option is available.
|
|
79
|
+
def supports_option?(name, type = :easy)
|
|
80
|
+
name = name.to_sym if name.is_a?(String)
|
|
81
|
+
options = type == :multi ? multi_options(nil) : easy_options(nil)
|
|
82
|
+
option = options[name]
|
|
83
|
+
return false unless option
|
|
84
|
+
|
|
85
|
+
if type == :easy && respond_to?(:easy_option_by_id)
|
|
86
|
+
# Resolve by id so Ethon aliases such as :unix_socket are reported
|
|
87
|
+
# correctly; libcurl's by-name lookup only knows canonical names.
|
|
88
|
+
!easy_option_by_id(option[:opt]).null?
|
|
89
|
+
else
|
|
90
|
+
true
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Check the loaded libcurl version against a dotted version number.
|
|
95
|
+
#
|
|
96
|
+
# @example
|
|
97
|
+
# Ethon::Curl.version_at_least?("7.66.0")
|
|
98
|
+
#
|
|
99
|
+
# @param [ String ] version The version to compare, for example "7.66.0".
|
|
100
|
+
#
|
|
101
|
+
# @return [ Boolean ] True when libcurl is at least that version.
|
|
102
|
+
def version_at_least?(version)
|
|
103
|
+
parts = version.to_s.split(".").map(&:to_i)
|
|
104
|
+
required = (parts[0].to_i << 16) | (parts[1].to_i << 8) | parts[2].to_i
|
|
105
|
+
version_info[:version_num] >= required
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Feature names supported by the loaded libcurl.
|
|
109
|
+
#
|
|
110
|
+
# @return [ Array<String> ] Feature names.
|
|
111
|
+
def feature_names
|
|
112
|
+
info = version_info_full
|
|
113
|
+
return [] unless info
|
|
114
|
+
|
|
115
|
+
string_array(info[:feature_names])
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Read a NULL-terminated array of C strings.
|
|
119
|
+
#
|
|
120
|
+
# @param [ FFI::Pointer, nil ] pointer The array pointer.
|
|
121
|
+
#
|
|
122
|
+
# @return [ Array<String> ] The strings.
|
|
123
|
+
def string_array(pointer)
|
|
124
|
+
return [] if pointer.nil? || pointer.null?
|
|
125
|
+
|
|
126
|
+
strings = []
|
|
127
|
+
offset = 0
|
|
128
|
+
loop do
|
|
129
|
+
string = pointer.get_pointer(offset)
|
|
130
|
+
break if string.null?
|
|
131
|
+
|
|
132
|
+
strings << string.read_string
|
|
133
|
+
offset += ::FFI.type_size(:pointer)
|
|
134
|
+
end
|
|
135
|
+
strings
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Ethon
|
|
3
|
+
module Curl
|
|
4
|
+
# The struct age at which curl_version_info_data exposes feature_names.
|
|
5
|
+
CURLVERSION_ELEVENTH = 10
|
|
6
|
+
|
|
7
|
+
# CURLHcode values.
|
|
8
|
+
HeaderCode = enum(:header_code, [
|
|
9
|
+
:ok,
|
|
10
|
+
:badindex,
|
|
11
|
+
:missing,
|
|
12
|
+
:noheaders,
|
|
13
|
+
:norequest,
|
|
14
|
+
:out_of_memory,
|
|
15
|
+
:bad_argument,
|
|
16
|
+
:not_built_in
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
# CURLH_* origin bits.
|
|
20
|
+
HeaderOrigin = bitmask(:header_origin, [
|
|
21
|
+
nil,
|
|
22
|
+
:header,
|
|
23
|
+
:trailer,
|
|
24
|
+
:connect,
|
|
25
|
+
:"1xx",
|
|
26
|
+
:pseudo
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
# curl_easytype values used by curl_easy_option_*.
|
|
30
|
+
EasyType = enum(:easy_type, [
|
|
31
|
+
:long,
|
|
32
|
+
:values,
|
|
33
|
+
:off_t,
|
|
34
|
+
:object,
|
|
35
|
+
:string,
|
|
36
|
+
:slist,
|
|
37
|
+
:cbptr,
|
|
38
|
+
:blob,
|
|
39
|
+
:function
|
|
40
|
+
])
|
|
41
|
+
end
|
|
42
|
+
end
|