1#![warn(missing_docs)]
68
69use std::ffi::{c_char, c_long, c_short, c_void, CStr};
70use std::ptr;
71
72#[repr(C)]
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77#[allow(non_camel_case_types, missing_docs)]
78pub enum CURLcode {
79 CURLE_OK = 0,
80 CURLE_UNSUPPORTED_PROTOCOL = 1,
81 CURLE_FAILED_INIT = 2,
82 CURLE_URL_MALFORMAT = 3,
83 CURLE_COULDNT_RESOLVE_PROXY = 5,
84 CURLE_COULDNT_RESOLVE_HOST = 6,
85 CURLE_COULDNT_CONNECT = 7,
86 CURLE_FTP_WEIRD_SERVER_REPLY = 8,
87 CURLE_REMOTE_ACCESS_DENIED = 9,
88 CURLE_HTTP2 = 16,
89 CURLE_HTTP_RETURNED_ERROR = 22,
90 CURLE_WRITE_ERROR = 23,
91 CURLE_READ_ERROR = 26,
92 CURLE_OUT_OF_MEMORY = 27,
93 CURLE_OPERATION_TIMEDOUT = 28,
94 CURLE_SSL_CONNECT_ERROR = 35,
95 CURLE_ABORTED_BY_CALLBACK = 42,
96 CURLE_BAD_FUNCTION_ARGUMENT = 43,
97 CURLE_UNKNOWN_OPTION = 48,
98 CURLE_GOT_NOTHING = 52,
99 CURLE_SEND_ERROR = 55,
100 CURLE_RECV_ERROR = 56,
101 CURLE_SSL_CERTPROBLEM = 58,
102 CURLE_PEER_FAILED_VERIFICATION = 60,
103 CURLE_FILESIZE_EXCEEDED = 63,
104 CURLE_LOGIN_DENIED = 67,
105 CURLE_TOO_MANY_REDIRECTS = 47,
106 CURLE_HTTP3 = 95,
107 CURLE_PARTIAL_FILE = 18,
108 CURLE_RANGE_ERROR = 33,
109 CURLE_AGAIN = 81,
110 CURLE_AUTH_ERROR = 94,
111 CURLE_UNRECOVERABLE_POLL = 99,
112 CURLE_FTP_COULDNT_RETR_FILE = 19,
113 CURLE_UPLOAD_FAILED = 25,
114 CURLE_LDAP_SEARCH_FAILED = 39,
115 CURLE_FUNCTION_NOT_FOUND = 41,
116 CURLE_INTERFACE_FAILED = 45,
117 CURLE_SSL_ENGINE_NOTFOUND = 53,
118 CURLE_SSL_ENGINE_SETFAILED = 54,
119 CURLE_RTSP_CSEQ_ERROR = 85,
120 CURLE_RTSP_SESSION_ERROR = 86,
121 CURLE_SSL_PINNEDPUBKEYNOTMATCH = 90,
122 CURLE_SSL_INVALIDCERTSTATUS = 91,
123}
124
125#[repr(C)]
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130#[allow(non_camel_case_types, missing_docs)]
131pub enum CURLoption {
132 CURLOPT_WRITEDATA = 10001,
134 CURLOPT_URL = 10002,
135 CURLOPT_PROXY = 10004,
136 CURLOPT_USERPWD = 10005,
137 CURLOPT_RANGE = 10007,
138 CURLOPT_ERRORBUFFER = 10010,
139 CURLOPT_POSTFIELDS = 10015,
140 CURLOPT_USERAGENT = 10018,
141 CURLOPT_COOKIE = 10022,
142 CURLOPT_HTTPHEADER = 10023,
143 CURLOPT_SSLCERT = 10025,
144 CURLOPT_HEADERDATA = 10029,
145 CURLOPT_CUSTOMREQUEST = 10036,
146 CURLOPT_STDERR = 10037,
147 CURLOPT_CAINFO = 10065,
148 CURLOPT_SSLKEY = 10087,
149 CURLOPT_INTERFACE = 10062,
150 CURLOPT_SSL_CIPHER_LIST = 10083,
151 CURLOPT_ACCEPT_ENCODING = 10102,
152 CURLOPT_COOKIEFILE = 10031,
153 CURLOPT_COOKIEJAR = 10082,
154 CURLOPT_COOKIELIST = 10135,
155 CURLOPT_PROXYUSERPWD = 10006,
156 CURLOPT_NOPROXY = 10177,
157 CURLOPT_RESOLVE = 10203,
158 CURLOPT_PINNEDPUBLICKEY = 10230,
159 CURLOPT_UNIX_SOCKET_PATH = 10231,
160 CURLOPT_PROXY_CAINFO = 10246,
161 CURLOPT_PROXY_SSLCERT = 10254,
162 CURLOPT_PROXY_SSLKEY = 10255,
163 CURLOPT_READDATA = 10009,
164 CURLOPT_DEBUGDATA = 10095,
165 CURLOPT_DNS_SERVERS = 10211,
166 CURLOPT_TLSAUTH_TYPE = 10216,
167 CURLOPT_TLSAUTH_USERNAME = 10217,
168 CURLOPT_TLSAUTH_PASSWORD = 10218,
169 CURLOPT_DOH_URL = 10279,
170 CURLOPT_HSTS = 10300,
171 CURLOPT_PROTOCOLS_STR = 10318,
172 CURLOPT_REDIR_PROTOCOLS_STR = 10319,
173
174 CURLOPT_TIMEOUT = 13,
176 CURLOPT_LOW_SPEED_LIMIT = 19,
177 CURLOPT_LOW_SPEED_TIME = 20,
178 CURLOPT_SSLVERSION = 32,
179 CURLOPT_VERBOSE = 41,
180 CURLOPT_NOBODY = 44,
181 CURLOPT_FAILONERROR = 45,
182 CURLOPT_UPLOAD = 46,
183 CURLOPT_POST = 47,
184 CURLOPT_FOLLOWLOCATION = 52,
185 CURLOPT_PUT = 54,
186 CURLOPT_POSTFIELDSIZE = 60,
187 CURLOPT_HTTPPROXYTUNNEL = 61,
188 CURLOPT_SSL_VERIFYPEER = 64,
189 CURLOPT_MAXREDIRS = 68,
190 CURLOPT_FRESH_CONNECT = 74,
191 CURLOPT_FORBID_REUSE = 75,
192 CURLOPT_CONNECTTIMEOUT = 78,
193 CURLOPT_HTTPGET = 80,
194 CURLOPT_SSL_VERIFYHOST = 81,
195 CURLOPT_PROXYAUTH = 111,
196 CURLOPT_HTTPAUTH = 107,
197 CURLOPT_MAXFILESIZE = 114,
198 CURLOPT_PROXY_SSL_VERIFYPEER = 248,
199 CURLOPT_PROXY_SSL_VERIFYHOST = 249,
200 CURLOPT_TCP_NODELAY = 121,
201 CURLOPT_LOCALPORT = 139,
202 CURLOPT_TIMEOUT_MS = 155,
203 CURLOPT_CONNECTTIMEOUT_MS = 156,
204 CURLOPT_POSTREDIR = 161,
205 CURLOPT_DNS_CACHE_TIMEOUT = 92,
206 CURLOPT_TRANSFER_ENCODING = 207,
207 CURLOPT_EXPECT_100_TIMEOUT_MS = 227,
208 CURLOPT_PATH_AS_IS = 234,
209 CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS = 271,
210 CURLOPT_DNS_SHUFFLE_ADDRESSES = 275,
211 CURLOPT_UNRESTRICTED_AUTH = 105,
212 CURLOPT_IGNORE_CONTENT_LENGTH = 136,
213 CURLOPT_TCP_KEEPALIVE = 213,
214 CURLOPT_SSL_SESSIONID_CACHE = 150,
215 CURLOPT_PORT = 3,
216 CURLOPT_INFILESIZE = 14,
217 CURLOPT_RESUME_FROM = 21,
218 CURLOPT_PROXYPORT = 59,
219 CURLOPT_FILETIME = 69,
220 CURLOPT_MAXCONNECTS = 71,
221 CURLOPT_BUFFERSIZE = 98,
222 CURLOPT_PROXYTYPE = 101,
223 CURLOPT_IPRESOLVE = 113,
224 CURLOPT_FTP_FILEMETHOD = 138,
225 CURLOPT_PIPEWAIT = 237,
226 CURLOPT_STREAM_WEIGHT = 239,
227 CURLOPT_TCP_FASTOPEN = 244,
228 CURLOPT_SOCKS5_AUTH = 267,
229 CURLOPT_HTTP09_ALLOWED = 285,
230
231 CURLOPT_POSTFIELDSIZE_LARGE = 30120,
233 CURLOPT_INFILESIZE_LARGE = 30115,
234 CURLOPT_MAXFILESIZE_LARGE = 30117,
235 CURLOPT_MAX_SEND_SPEED_LARGE = 30145,
236 CURLOPT_MAX_RECV_SPEED_LARGE = 30146,
237
238 CURLOPT_CAPATH = 10097,
240 CURLOPT_REFERER = 10016,
241 CURLOPT_XOAUTH2_BEARER = 10220,
242 CURLOPT_AWS_SIGV4 = 10306,
243
244 CURLOPT_SHARE = 10100,
246 CURLOPT_PRIVATE = 10103,
247 CURLOPT_MIMEPOST = 10269,
248
249 CURLOPT_WRITEFUNCTION = 20011,
251 CURLOPT_READFUNCTION = 20012,
252 CURLOPT_PROGRESSFUNCTION = 20056,
253 CURLOPT_HEADERFUNCTION = 20079,
254 CURLOPT_DEBUGFUNCTION = 20094,
255 CURLOPT_SEEKFUNCTION = 20167,
256 CURLOPT_XFERINFOFUNCTION = 20219,
257
258 CURLOPT_NOPROGRESS = 43,
260 CURLOPT_AUTOREFERER = 58,
261 CURLOPT_HTTP_VERSION = 84,
262 CURLOPT_NOSIGNAL = 99,
263 CURLOPT_LOCALPORTRANGE = 164,
264
265 CURLOPT_RESUME_FROM_LARGE = 30116,
267
268 CURLOPT_PROGRESSDATA = 10057,
270 CURLOPT_SEEKDATA = 10168,
271}
272
273#[repr(C)]
277#[derive(Debug, Clone, Copy, PartialEq, Eq)]
278#[allow(non_camel_case_types, missing_docs)]
279pub enum CURLUcode {
280 CURLUE_OK = 0,
281 CURLUE_BAD_HANDLE = 1,
282 CURLUE_BAD_PARTPOINTER = 2,
283 CURLUE_MALFORMED_INPUT = 3,
284 CURLUE_BAD_PORT_NUMBER = 4,
285 CURLUE_UNSUPPORTED_SCHEME = 5,
286 CURLUE_OUT_OF_MEMORY = 7,
287 CURLUE_NO_SCHEME = 8,
288 CURLUE_NO_HOST = 9,
289 CURLUE_UNKNOWN_PART = 11,
290}
291
292#[repr(C)]
294#[derive(Debug, Clone, Copy, PartialEq, Eq)]
295#[allow(non_camel_case_types, missing_docs)]
296pub enum CURLUPart {
297 CURLUPART_URL = 0,
298 CURLUPART_SCHEME = 1,
299 CURLUPART_USER = 2,
300 CURLUPART_PASSWORD = 3,
301 CURLUPART_OPTIONS = 4,
302 CURLUPART_HOST = 5,
303 CURLUPART_PORT = 6,
304 CURLUPART_PATH = 7,
305 CURLUPART_QUERY = 8,
306 CURLUPART_FRAGMENT = 9,
307 CURLUPART_ZONEID = 10,
308}
309
310#[repr(C)]
314#[derive(Debug, Clone, Copy, PartialEq, Eq)]
315#[allow(non_camel_case_types, missing_docs)]
316pub enum CURLINFO {
317 CURLINFO_EFFECTIVE_URL = 0x0010_0001,
318 CURLINFO_RESPONSE_CODE = 0x0020_0002,
319 CURLINFO_TOTAL_TIME = 0x0030_0003,
320 CURLINFO_NAMELOOKUP_TIME = 0x0030_0004,
321 CURLINFO_CONNECT_TIME = 0x0030_0005,
322 CURLINFO_SIZE_UPLOAD = 0x0030_0007,
323 CURLINFO_SIZE_DOWNLOAD = 0x0030_0008,
324 CURLINFO_SPEED_DOWNLOAD = 0x0030_0009,
325 CURLINFO_SPEED_UPLOAD = 0x0030_000A,
326 CURLINFO_HEADER_SIZE = 0x0020_000B,
327 CURLINFO_FILETIME = 0x0020_000E,
328 CURLINFO_CONTENT_LENGTH_DOWNLOAD = 0x0030_000F,
329 CURLINFO_CONTENT_LENGTH_UPLOAD = 0x0030_0010,
330 CURLINFO_PRETRANSFER_TIME = 0x0030_000E,
331 CURLINFO_STARTTRANSFER_TIME = 0x0030_0011,
332 CURLINFO_CONTENT_TYPE = 0x0010_0012,
333 CURLINFO_REDIRECT_COUNT = 0x0020_0014,
334 CURLINFO_SSL_VERIFYRESULT = 0x0020_000D,
335 CURLINFO_PRIVATE = 0x0010_0015,
336 CURLINFO_OS_ERRNO = 0x0020_0019,
337 CURLINFO_PRIMARY_IP = 0x0010_0020,
338 CURLINFO_NUM_CONNECTS = 0x0020_0026,
339 CURLINFO_LOCAL_IP = 0x0010_0029,
340 CURLINFO_REDIRECT_URL = 0x0010_0031,
341 CURLINFO_HTTP_VERSION = 0x0020_0032,
342 CURLINFO_APPCONNECT_TIME = 0x0030_0033,
343 CURLINFO_CONDITION_UNMET = 0x0020_0035,
344 CURLINFO_PRIMARY_PORT = 0x0020_0040,
345 CURLINFO_LOCAL_PORT = 0x0020_0042,
346 CURLINFO_SCHEME = 0x0010_0044,
347 CURLINFO_REDIRECT_TIME = 0x0030_0013,
348 CURLINFO_TOTAL_TIME_T = 0x0060_003E,
349 CURLINFO_NAMELOOKUP_TIME_T = 0x0060_003F,
350 CURLINFO_CONNECT_TIME_T = 0x0060_0040,
351 CURLINFO_PRETRANSFER_TIME_T = 0x0060_0041,
352 CURLINFO_STARTTRANSFER_TIME_T = 0x0060_0042,
353 CURLINFO_REDIRECT_TIME_T = 0x0060_0043,
354 CURLINFO_APPCONNECT_TIME_T = 0x0060_0044,
355 CURLINFO_RETRY_AFTER = 0x0020_003A,
356 CURLINFO_SIZE_UPLOAD_T = 0x0060_0045,
357 CURLINFO_SIZE_DOWNLOAD_T = 0x0060_0046,
358 CURLINFO_SPEED_DOWNLOAD_T = 0x0060_0047,
359 CURLINFO_SPEED_UPLOAD_T = 0x0060_0048,
360 CURLINFO_REQUEST_SIZE = 0x0020_000C,
361 CURLINFO_HTTP_CONNECTCODE = 0x0020_0016,
362 CURLINFO_HTTPAUTH_AVAIL = 0x0020_0017,
363 CURLINFO_PROXYAUTH_AVAIL = 0x0020_0018,
364}
365
366#[repr(C)]
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371#[allow(non_camel_case_types, missing_docs)]
372pub enum CURLMcode {
373 CURLM_OK = 0,
374 CURLM_BAD_HANDLE = -1,
375 CURLM_BAD_EASY_HANDLE = -2,
376 CURLM_OUT_OF_MEMORY = -3,
377 CURLM_INTERNAL_ERROR = -4,
378 CURLM_UNKNOWN_OPTION = -6,
379}
380
381#[repr(C)]
383#[derive(Debug, Clone, Copy, PartialEq, Eq)]
384#[allow(non_camel_case_types, missing_docs)]
385pub enum CURLMSG {
386 CURLMSG_DONE = 1,
387}
388
389#[repr(C)]
391#[allow(non_camel_case_types, missing_docs)]
392pub struct CURLMsg {
393 pub msg: CURLMSG,
394 pub easy_handle: *mut c_void,
395 pub result: CURLcode,
396}
397
398#[repr(C)]
400#[derive(Debug, Clone, Copy, PartialEq, Eq)]
401#[allow(non_camel_case_types, missing_docs)]
402pub enum CURLMoption {
403 CURLMOPT_SOCKETFUNCTION = 20001,
404 CURLMOPT_SOCKETDATA = 10002,
405 CURLMOPT_PIPELINING = 3,
406 CURLMOPT_TIMERFUNCTION = 20004,
407 CURLMOPT_TIMERDATA = 10005,
408 CURLMOPT_MAXCONNECTS = 6,
409 CURLMOPT_MAX_HOST_CONNECTIONS = 7,
410 CURLMOPT_MAX_TOTAL_CONNECTIONS = 13,
411}
412
413#[repr(C)]
415#[allow(non_camel_case_types, missing_docs)]
416pub struct curl_waitfd {
417 pub fd: c_long,
418 pub events: c_short,
419 pub revents: c_short,
420}
421
422#[repr(C)]
427#[allow(non_camel_case_types, missing_docs)]
428pub struct curl_blob {
429 pub data: *const c_void,
430 pub len: usize,
431 pub flags: u32,
432}
433
434#[allow(non_camel_case_types)]
436type CurlSocketCallback =
437 unsafe extern "C" fn(*mut c_void, c_long, c_long, *mut c_void, *mut c_void) -> c_long;
438
439#[allow(non_camel_case_types)]
441type CurlTimerCallback = unsafe extern "C" fn(*mut c_void, c_long, *mut c_void) -> c_long;
442
443type WriteCallback = unsafe extern "C" fn(*const c_char, usize, usize, *mut c_void) -> usize;
448
449type HeaderCallback = unsafe extern "C" fn(*const c_char, usize, usize, *mut c_void) -> usize;
452
453type ReadCallback = unsafe extern "C" fn(*mut c_char, usize, usize, *mut c_void) -> usize;
458
459type DebugCallback =
465 unsafe extern "C" fn(*mut c_void, c_long, *const c_char, usize, *mut c_void) -> c_long;
466
467type ProgressCallback = unsafe extern "C" fn(*mut c_void, f64, f64, f64, f64) -> c_long;
472
473type XferInfoCallback = unsafe extern "C" fn(*mut c_void, i64, i64, i64, i64) -> c_long;
478
479type SeekCallback = unsafe extern "C" fn(*mut c_void, i64, c_long) -> c_long;
483
484type InterleaveCallback = unsafe extern "C" fn(*mut c_void, usize, usize, *mut c_void) -> usize;
489
490#[repr(C)]
494#[derive(Debug, Clone, Copy, PartialEq, Eq)]
495#[allow(non_camel_case_types, missing_docs)]
496pub enum CURLSHcode {
497 CURLSHE_OK = 0,
498 CURLSHE_BAD_OPTION = 1,
499 CURLSHE_IN_USE = 2,
500 CURLSHE_INVALID = 3,
501 CURLSHE_NOMEM = 4,
502 CURLSHE_NOT_BUILT_IN = 5,
503}
504
505#[repr(C)]
507#[derive(Debug, Clone, Copy, PartialEq, Eq)]
508#[allow(non_camel_case_types, missing_docs)]
509pub enum CURLSHoption {
510 CURLSHOPT_SHARE = 1,
511 CURLSHOPT_UNSHARE = 2,
512 CURLSHOPT_LOCKFUNC = 3,
513 CURLSHOPT_UNLOCKFUNC = 4,
514}
515
516struct MimeHandle {
520 form: liburlx::MultipartForm,
521}
522
523struct MimePartHandle {
525 name: Option<String>,
526 data: Option<Vec<u8>>,
527 filename: Option<String>,
528 mime_type: Option<String>,
529}
530
531#[no_mangle]
538pub unsafe extern "C" fn curl_mime_init(_easy: *mut c_void) -> *mut c_void {
539 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
540 let handle = Box::new(MimeHandle { form: liburlx::MultipartForm::new() });
541 Box::into_raw(handle).cast::<c_void>()
542 }));
543 result.unwrap_or(ptr::null_mut())
544}
545
546#[no_mangle]
553pub unsafe extern "C" fn curl_mime_addpart(mime: *mut c_void) -> *mut c_void {
554 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
555 if mime.is_null() {
556 return ptr::null_mut();
557 }
558 let part =
559 Box::new(MimePartHandle { name: None, data: None, filename: None, mime_type: None });
560 Box::into_raw(part).cast::<c_void>()
561 }));
562 result.unwrap_or(ptr::null_mut())
563}
564
565#[no_mangle]
572pub unsafe extern "C" fn curl_mime_name(part: *mut c_void, name: *const c_char) -> CURLcode {
573 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
574 if part.is_null() || name.is_null() {
575 return CURLcode::CURLE_BAD_FUNCTION_ARGUMENT;
576 }
577 let p = unsafe { &mut *part.cast::<MimePartHandle>() };
579 let s = unsafe { CStr::from_ptr(name) };
581 match s.to_str() {
582 Ok(name_str) => {
583 p.name = Some(name_str.to_string());
584 CURLcode::CURLE_OK
585 }
586 Err(_) => CURLcode::CURLE_BAD_FUNCTION_ARGUMENT,
587 }
588 }));
589 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
590}
591
592#[no_mangle]
600pub unsafe extern "C" fn curl_mime_data(
601 part: *mut c_void,
602 data: *const c_char,
603 datasize: usize,
604) -> CURLcode {
605 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
606 if part.is_null() || data.is_null() {
607 return CURLcode::CURLE_BAD_FUNCTION_ARGUMENT;
608 }
609 let p = unsafe { &mut *part.cast::<MimePartHandle>() };
611
612 let bytes = if datasize == usize::MAX {
613 let s = unsafe { CStr::from_ptr(data) };
616 s.to_bytes().to_vec()
617 } else {
618 unsafe { std::slice::from_raw_parts(data.cast::<u8>(), datasize) }.to_vec()
620 };
621
622 p.data = Some(bytes);
623 CURLcode::CURLE_OK
624 }));
625 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
626}
627
628#[no_mangle]
635pub unsafe extern "C" fn curl_mime_filename(
636 part: *mut c_void,
637 filename: *const c_char,
638) -> CURLcode {
639 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
640 if part.is_null() || filename.is_null() {
641 return CURLcode::CURLE_BAD_FUNCTION_ARGUMENT;
642 }
643 let p = unsafe { &mut *part.cast::<MimePartHandle>() };
645 let s = unsafe { CStr::from_ptr(filename) };
647 match s.to_str() {
648 Ok(f) => {
649 p.filename = Some(f.to_string());
650 CURLcode::CURLE_OK
651 }
652 Err(_) => CURLcode::CURLE_BAD_FUNCTION_ARGUMENT,
653 }
654 }));
655 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
656}
657
658#[no_mangle]
665pub unsafe extern "C" fn curl_mime_type(part: *mut c_void, mimetype: *const c_char) -> CURLcode {
666 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
667 if part.is_null() || mimetype.is_null() {
668 return CURLcode::CURLE_BAD_FUNCTION_ARGUMENT;
669 }
670 let p = unsafe { &mut *part.cast::<MimePartHandle>() };
672 let s = unsafe { CStr::from_ptr(mimetype) };
674 match s.to_str() {
675 Ok(t) => {
676 p.mime_type = Some(t.to_string());
677 CURLcode::CURLE_OK
678 }
679 Err(_) => CURLcode::CURLE_BAD_FUNCTION_ARGUMENT,
680 }
681 }));
682 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
683}
684
685#[no_mangle]
692pub unsafe extern "C" fn curl_mime_free(mime: *mut c_void) {
693 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
694 if !mime.is_null() {
695 let _ = unsafe { Box::from_raw(mime.cast::<MimeHandle>()) };
697 }
698 }));
699}
700
701unsafe fn finalize_mime_part(mime: *mut c_void, part: *mut c_void) {
707 if mime.is_null() || part.is_null() {
708 return;
709 }
710 let m = unsafe { &mut *mime.cast::<MimeHandle>() };
712 let p = unsafe { Box::from_raw(part.cast::<MimePartHandle>()) };
713
714 if let (Some(name), Some(data)) = (&p.name, &p.data) {
715 if let Some(ref filename) = p.filename {
716 m.form.file_data(name, filename, data);
717 } else {
718 if let Ok(text) = std::str::from_utf8(data) {
720 m.form.field(name, text);
721 } else {
722 m.form.file_data(name, "data", data);
724 }
725 }
726 }
727}
728
729#[no_mangle]
737pub extern "C" fn curl_share_init() -> *mut c_void {
738 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
739 let share = Box::new(liburlx::Share::new());
740 Box::into_raw(share).cast::<c_void>()
741 }));
742 result.unwrap_or(ptr::null_mut())
743}
744
745#[no_mangle]
751pub unsafe extern "C" fn curl_share_cleanup(share: *mut c_void) -> CURLSHcode {
752 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
753 if share.is_null() {
754 return CURLSHcode::CURLSHE_INVALID;
755 }
756 let _ = unsafe { Box::from_raw(share.cast::<liburlx::Share>()) };
758 CURLSHcode::CURLSHE_OK
759 }));
760 result.unwrap_or(CURLSHcode::CURLSHE_INVALID)
761}
762
763#[no_mangle]
770pub unsafe extern "C" fn curl_share_setopt(
771 share: *mut c_void,
772 option: c_long,
773 value: *const c_void,
774) -> CURLSHcode {
775 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
776 if share.is_null() {
777 return CURLSHcode::CURLSHE_INVALID;
778 }
779
780 let s = unsafe { &mut *share.cast::<liburlx::Share>() };
782
783 match option {
784 1 => {
786 let lock_data = value as c_long;
787 match lock_data {
788 2 => {
790 s.add(liburlx::ShareType::Cookies);
791 CURLSHcode::CURLSHE_OK
792 }
793 3 => {
795 s.add(liburlx::ShareType::Dns);
796 CURLSHcode::CURLSHE_OK
797 }
798 _ => CURLSHcode::CURLSHE_BAD_OPTION,
799 }
800 }
801 2 => {
803 let lock_data = value as c_long;
804 match lock_data {
805 2 => {
806 s.remove(liburlx::ShareType::Cookies);
807 CURLSHcode::CURLSHE_OK
808 }
809 3 => {
810 s.remove(liburlx::ShareType::Dns);
811 CURLSHcode::CURLSHE_OK
812 }
813 _ => CURLSHcode::CURLSHE_BAD_OPTION,
814 }
815 }
816 3 | 4 => CURLSHcode::CURLSHE_OK,
819 _ => CURLSHcode::CURLSHE_BAD_OPTION,
820 }
821 }));
822 result.unwrap_or(CURLSHcode::CURLSHE_INVALID)
823}
824
825#[no_mangle]
831#[allow(clippy::missing_const_for_fn)]
832pub extern "C" fn curl_share_strerror(code: CURLSHcode) -> *const c_char {
833 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
834 let msg = match code {
835 CURLSHcode::CURLSHE_OK => c"No error",
836 CURLSHcode::CURLSHE_BAD_OPTION => c"Bad option in share call",
837 CURLSHcode::CURLSHE_IN_USE => c"Share already in use",
838 CURLSHcode::CURLSHE_INVALID => c"Invalid share handle",
839 CURLSHcode::CURLSHE_NOMEM => c"Out of memory",
840 CURLSHcode::CURLSHE_NOT_BUILT_IN => c"Feature not available",
841 };
842 msg.as_ptr()
843 }));
844 result.unwrap_or(c"Unknown error".as_ptr())
845}
846
847struct UrlHandle {
854 scheme: Option<String>,
855 user: Option<String>,
856 password: Option<String>,
857 host: Option<String>,
858 port: Option<u16>,
859 path: Option<String>,
860 query: Option<String>,
861 fragment: Option<String>,
862 cached_url: Option<String>,
864}
865
866impl UrlHandle {
867 const fn new() -> Self {
868 Self {
869 scheme: None,
870 user: None,
871 password: None,
872 host: None,
873 port: None,
874 path: None,
875 query: None,
876 fragment: None,
877 cached_url: None,
878 }
879 }
880
881 fn reassemble(&mut self) -> String {
883 let scheme = self.scheme.as_deref().unwrap_or("https");
884 let mut url = format!("{scheme}://");
885 if let Some(ref user) = self.user {
886 url.push_str(user);
887 if let Some(ref pass) = self.password {
888 url.push(':');
889 url.push_str(pass);
890 }
891 url.push('@');
892 }
893 if let Some(ref host) = self.host {
894 url.push_str(host);
895 }
896 if let Some(port) = self.port {
897 url.push(':');
898 url.push_str(&port.to_string());
899 }
900 url.push_str(self.path.as_deref().unwrap_or("/"));
901 if let Some(ref query) = self.query {
902 url.push('?');
903 url.push_str(query);
904 }
905 if let Some(ref fragment) = self.fragment {
906 url.push('#');
907 url.push_str(fragment);
908 }
909 self.cached_url = Some(url.clone());
910 url
911 }
912
913 fn set_url(&mut self, url_str: &str) -> CURLUcode {
915 match liburlx::Url::parse(url_str) {
916 Ok(parsed) => {
917 self.scheme = Some(parsed.scheme().to_string());
918 let user = parsed.username();
919 self.user = if user.is_empty() { None } else { Some(user.to_string()) };
920 self.password = parsed.password().map(String::from);
921 self.host = parsed.host_str().map(String::from);
922 self.port = parsed.port();
923 let path = parsed.path();
924 self.path = Some(path.to_string());
925 self.query = parsed.query().map(String::from);
926 self.fragment = parsed.fragment().map(String::from);
927 self.cached_url = Some(parsed.as_str().to_string());
928 CURLUcode::CURLUE_OK
929 }
930 Err(_) => CURLUcode::CURLUE_MALFORMED_INPUT,
931 }
932 }
933}
934
935impl Clone for UrlHandle {
936 fn clone(&self) -> Self {
937 Self {
938 scheme: self.scheme.clone(),
939 user: self.user.clone(),
940 password: self.password.clone(),
941 host: self.host.clone(),
942 port: self.port,
943 path: self.path.clone(),
944 query: self.query.clone(),
945 fragment: self.fragment.clone(),
946 cached_url: self.cached_url.clone(),
947 }
948 }
949}
950
951#[no_mangle]
957pub extern "C" fn curl_url() -> *mut c_void {
958 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
959 let handle = Box::new(UrlHandle::new());
960 Box::into_raw(handle).cast::<c_void>()
961 }));
962 result.unwrap_or(ptr::null_mut())
963}
964
965#[no_mangle]
971pub unsafe extern "C" fn curl_url_cleanup(handle: *mut c_void) {
972 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
973 if !handle.is_null() {
974 let _ = unsafe { Box::from_raw(handle.cast::<UrlHandle>()) };
976 }
977 }));
978}
979
980#[no_mangle]
986pub unsafe extern "C" fn curl_url_dup(handle: *mut c_void) -> *mut c_void {
987 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
988 if handle.is_null() {
989 return ptr::null_mut();
990 }
991 let h = unsafe { &*handle.cast::<UrlHandle>() };
993 let dup = Box::new(h.clone());
994 Box::into_raw(dup).cast::<c_void>()
995 }));
996 result.unwrap_or(ptr::null_mut())
997}
998
999#[no_mangle]
1006pub unsafe extern "C" fn curl_url_set(
1007 handle: *mut c_void,
1008 what: c_long,
1009 content: *const c_char,
1010 _flags: c_long,
1011) -> CURLUcode {
1012 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1013 if handle.is_null() {
1014 return CURLUcode::CURLUE_BAD_HANDLE;
1015 }
1016
1017 let h = unsafe { &mut *handle.cast::<UrlHandle>() };
1019
1020 let value = if content.is_null() {
1022 None
1023 } else {
1024 match unsafe { CStr::from_ptr(content) }.to_str() {
1026 Ok(s) => Some(s.to_string()),
1027 Err(_) => return CURLUcode::CURLUE_MALFORMED_INPUT,
1028 }
1029 };
1030
1031 h.cached_url = None; match what {
1034 0 => {
1036 if let Some(ref url_str) = value {
1037 return h.set_url(url_str);
1038 }
1039 *h = UrlHandle::new();
1041 CURLUcode::CURLUE_OK
1042 }
1043 1 => {
1045 h.scheme = value;
1046 CURLUcode::CURLUE_OK
1047 }
1048 2 => {
1050 h.user = value;
1051 CURLUcode::CURLUE_OK
1052 }
1053 3 => {
1055 h.password = value;
1056 CURLUcode::CURLUE_OK
1057 }
1058 4 | 10 => CURLUcode::CURLUE_OK,
1060 5 => {
1062 h.host = value;
1063 CURLUcode::CURLUE_OK
1064 }
1065 6 => {
1067 if let Some(ref port_str) = value {
1068 match port_str.parse::<u16>() {
1069 Ok(port) => {
1070 h.port = Some(port);
1071 CURLUcode::CURLUE_OK
1072 }
1073 Err(_) => CURLUcode::CURLUE_BAD_PORT_NUMBER,
1074 }
1075 } else {
1076 h.port = None;
1077 CURLUcode::CURLUE_OK
1078 }
1079 }
1080 7 => {
1082 h.path = value;
1083 CURLUcode::CURLUE_OK
1084 }
1085 8 => {
1087 h.query = value;
1088 CURLUcode::CURLUE_OK
1089 }
1090 9 => {
1092 h.fragment = value;
1093 CURLUcode::CURLUE_OK
1094 }
1095 _ => CURLUcode::CURLUE_UNKNOWN_PART,
1096 }
1097 }));
1098 result.unwrap_or(CURLUcode::CURLUE_BAD_HANDLE)
1099}
1100
1101#[no_mangle]
1111pub unsafe extern "C" fn curl_url_get(
1112 handle: *mut c_void,
1113 what: c_long,
1114 part: *mut *mut c_char,
1115 _flags: c_long,
1116) -> CURLUcode {
1117 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1118 if handle.is_null() {
1119 return CURLUcode::CURLUE_BAD_HANDLE;
1120 }
1121 if part.is_null() {
1122 return CURLUcode::CURLUE_BAD_PARTPOINTER;
1123 }
1124
1125 let h = unsafe { &mut *handle.cast::<UrlHandle>() };
1127
1128 let component: Option<String> = match what {
1129 0 => Some(h.reassemble()),
1131 1 => h.scheme.clone(),
1133 2 => h.user.clone(),
1135 3 => h.password.clone(),
1137 4 | 10 => None,
1139 5 => h.host.clone(),
1141 6 => h.port.map(|p| p.to_string()),
1143 7 => h.path.clone(),
1145 8 => h.query.clone(),
1147 9 => h.fragment.clone(),
1149 _ => return CURLUcode::CURLUE_UNKNOWN_PART,
1150 };
1151
1152 if let Some(s) = component {
1153 std::ffi::CString::new(s).map_or(CURLUcode::CURLUE_OUT_OF_MEMORY, |cstr| {
1155 unsafe {
1157 *part = cstr.into_raw();
1158 }
1159 CURLUcode::CURLUE_OK
1160 })
1161 } else {
1162 unsafe {
1165 *part = ptr::null_mut();
1166 }
1167 CURLUcode::CURLUE_OK
1168 }
1169 }));
1170 result.unwrap_or(CURLUcode::CURLUE_BAD_HANDLE)
1171}
1172
1173#[no_mangle]
1179pub unsafe extern "C" fn curl_free(ptr: *mut c_void) {
1180 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1181 if !ptr.is_null() {
1182 let _ = unsafe { std::ffi::CString::from_raw(ptr.cast::<c_char>()) };
1184 }
1185 }));
1186}
1187
1188#[repr(C)]
1194pub struct curl_slist {
1195 pub data: *mut c_char,
1197 pub next: *mut Self,
1199}
1200
1201#[no_mangle]
1208pub unsafe extern "C" fn curl_slist_append(
1209 list: *mut curl_slist,
1210 data: *const c_char,
1211) -> *mut curl_slist {
1212 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1213 if data.is_null() {
1214 return list;
1215 }
1216
1217 let s = unsafe { CStr::from_ptr(data) };
1219 let owned = s.to_bytes().to_vec();
1220 let mut buf = owned;
1221 buf.push(0); let boxed = buf.into_boxed_slice();
1224 let data_ptr = Box::into_raw(boxed).cast::<c_char>();
1225
1226 let node = Box::new(curl_slist { data: data_ptr, next: ptr::null_mut() });
1227
1228 let node_ptr = Box::into_raw(node);
1229
1230 if list.is_null() {
1231 node_ptr
1232 } else {
1233 let mut current = list;
1235 while unsafe { !(*current).next.is_null() } {
1237 current = unsafe { (*current).next };
1238 }
1239 unsafe {
1241 (*current).next = node_ptr;
1242 }
1243 list
1244 }
1245 }));
1246 result.unwrap_or(ptr::null_mut())
1247}
1248
1249#[no_mangle]
1255pub unsafe extern "C" fn curl_slist_free_all(list: *mut curl_slist) {
1256 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1257 let mut current = list;
1258 while !current.is_null() {
1259 let node = unsafe { Box::from_raw(current) };
1261 let next = node.next;
1262
1263 if !node.data.is_null() {
1265 let s = unsafe { CStr::from_ptr(node.data) };
1267 let len = s.to_bytes_with_nul().len();
1268 let raw_slice =
1269 unsafe { std::slice::from_raw_parts_mut(node.data.cast::<u8>(), len) };
1270 let _ = unsafe { Box::from_raw(raw_slice) };
1271 }
1272
1273 current = next;
1274 }
1275 }));
1276}
1277
1278struct EasyHandle {
1282 easy: liburlx::Easy,
1283 last_response: Option<liburlx::Response>,
1284 write_callback: Option<WriteCallback>,
1285 write_data: *mut c_void,
1286 header_callback: Option<HeaderCallback>,
1287 header_data: *mut c_void,
1288 read_callback: Option<ReadCallback>,
1289 read_data: *mut c_void,
1290 debug_callback: Option<DebugCallback>,
1291 debug_data: *mut c_void,
1292 progress_callback: Option<ProgressCallback>,
1293 xferinfo_callback: Option<XferInfoCallback>,
1294 progress_data: *mut c_void,
1295 seek_callback: Option<SeekCallback>,
1296 seek_data: *mut c_void,
1297 noprogress: bool,
1298 postfields: Option<Vec<u8>>,
1299 infilesize: Option<u64>,
1300 private_data: *mut c_void,
1301 mime_parts: Vec<(*mut c_void, *mut c_void)>,
1303 mimepost: *mut c_void,
1305 error_buf: [u8; 256],
1306 interleave_callback: Option<InterleaveCallback>,
1307 interleave_data: *mut c_void,
1308 rtsp_session_id_cstr: Option<std::ffi::CString>,
1310 include_headers: bool,
1312}
1313
1314unsafe impl Send for EasyHandle {}
1319
1320#[no_mangle]
1326pub extern "C" fn curl_easy_init() -> *mut c_void {
1327 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1328 let handle = Box::new(EasyHandle {
1329 easy: liburlx::Easy::new(),
1330 last_response: None,
1331 write_callback: None,
1332 write_data: ptr::null_mut(),
1333 header_callback: None,
1334 header_data: ptr::null_mut(),
1335 read_callback: None,
1336 read_data: ptr::null_mut(),
1337 debug_callback: None,
1338 debug_data: ptr::null_mut(),
1339 progress_callback: None,
1340 xferinfo_callback: None,
1341 progress_data: ptr::null_mut(),
1342 seek_callback: None,
1343 seek_data: ptr::null_mut(),
1344 noprogress: true,
1345 postfields: None,
1346 infilesize: None,
1347 private_data: ptr::null_mut(),
1348 mime_parts: Vec::new(),
1349 mimepost: ptr::null_mut(),
1350 error_buf: [0u8; 256],
1351 interleave_callback: None,
1352 interleave_data: ptr::null_mut(),
1353 rtsp_session_id_cstr: None,
1354 include_headers: false,
1355 });
1356 Box::into_raw(handle).cast::<c_void>()
1357 }));
1358 result.unwrap_or(ptr::null_mut())
1359}
1360
1361#[no_mangle]
1368pub unsafe extern "C" fn curl_easy_cleanup(handle: *mut c_void) {
1369 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1370 if !handle.is_null() {
1371 let _ = unsafe { Box::from_raw(handle.cast::<EasyHandle>()) };
1373 }
1374 }));
1375}
1376
1377#[no_mangle]
1384pub unsafe extern "C" fn curl_easy_duphandle(handle: *mut c_void) -> *mut c_void {
1385 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1386 if handle.is_null() {
1387 return ptr::null_mut();
1388 }
1389
1390 let h = unsafe { &*handle.cast::<EasyHandle>() };
1392 let dup = Box::new(EasyHandle {
1393 easy: h.easy.clone(),
1394 last_response: None,
1395 write_callback: h.write_callback,
1396 write_data: h.write_data,
1397 header_callback: h.header_callback,
1398 header_data: h.header_data,
1399 read_callback: h.read_callback,
1400 read_data: h.read_data,
1401 debug_callback: h.debug_callback,
1402 debug_data: h.debug_data,
1403 progress_callback: h.progress_callback,
1404 xferinfo_callback: h.xferinfo_callback,
1405 progress_data: h.progress_data,
1406 seek_callback: h.seek_callback,
1407 seek_data: h.seek_data,
1408 noprogress: h.noprogress,
1409 postfields: h.postfields.clone(),
1410 infilesize: h.infilesize,
1411 private_data: h.private_data,
1412 mime_parts: Vec::new(),
1413 mimepost: ptr::null_mut(),
1414 error_buf: [0u8; 256],
1415 interleave_callback: h.interleave_callback,
1416 interleave_data: h.interleave_data,
1417 rtsp_session_id_cstr: None,
1418 include_headers: h.include_headers,
1419 });
1420 Box::into_raw(dup).cast::<c_void>()
1421 }));
1422 result.unwrap_or(ptr::null_mut())
1423}
1424
1425#[no_mangle]
1431pub unsafe extern "C" fn curl_easy_reset(handle: *mut c_void) {
1432 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1433 if handle.is_null() {
1434 return;
1435 }
1436
1437 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
1439 h.easy = liburlx::Easy::new();
1440 h.last_response = None;
1441 h.write_callback = None;
1442 h.write_data = ptr::null_mut();
1443 h.header_callback = None;
1444 h.header_data = ptr::null_mut();
1445 h.read_callback = None;
1446 h.read_data = ptr::null_mut();
1447 h.debug_callback = None;
1448 h.debug_data = ptr::null_mut();
1449 h.progress_callback = None;
1450 h.xferinfo_callback = None;
1451 h.progress_data = ptr::null_mut();
1452 h.seek_callback = None;
1453 h.seek_data = ptr::null_mut();
1454 h.noprogress = true;
1455 h.postfields = None;
1456 h.infilesize = None;
1457 h.private_data = ptr::null_mut();
1458 h.mime_parts.clear();
1459 h.mimepost = ptr::null_mut();
1460 h.error_buf = [0u8; 256];
1461 h.interleave_callback = None;
1462 h.interleave_data = ptr::null_mut();
1463 h.rtsp_session_id_cstr = None;
1464 h.include_headers = false;
1465 }));
1466}
1467
1468unsafe fn read_cstr(value: *const c_void) -> Option<&'static str> {
1474 if value.is_null() {
1475 return None;
1476 }
1477 let cstr = unsafe { CStr::from_ptr(value.cast::<c_char>()) };
1479 cstr.to_str().ok()
1480}
1481
1482#[no_mangle]
1489#[allow(clippy::too_many_lines)]
1490pub unsafe extern "C" fn curl_easy_setopt(
1491 handle: *mut c_void,
1492 option: c_long,
1493 value: *const c_void,
1494) -> CURLcode {
1495 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1496 if handle.is_null() {
1497 return CURLcode::CURLE_FAILED_INIT;
1498 }
1499
1500 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
1502
1503 match option {
1504 10002 => {
1508 match unsafe { read_cstr(value) } {
1510 Some(s) => match h.easy.url(s) {
1511 Ok(()) => CURLcode::CURLE_OK,
1512 Err(_) => CURLcode::CURLE_URL_MALFORMAT,
1513 },
1514 None => CURLcode::CURLE_URL_MALFORMAT,
1515 }
1516 }
1517
1518 20011 => {
1520 h.write_callback =
1522 Some(unsafe { std::mem::transmute::<*const c_void, WriteCallback>(value) });
1523 CURLcode::CURLE_OK
1524 }
1525
1526 10001 => {
1528 h.write_data = value.cast_mut();
1529 CURLcode::CURLE_OK
1530 }
1531
1532 20079 => {
1534 h.header_callback =
1536 Some(unsafe { std::mem::transmute::<*const c_void, HeaderCallback>(value) });
1537 CURLcode::CURLE_OK
1538 }
1539
1540 10029 => {
1542 h.header_data = value.cast_mut();
1543 CURLcode::CURLE_OK
1544 }
1545
1546 20012 => {
1548 h.read_callback =
1550 Some(unsafe { std::mem::transmute::<*const c_void, ReadCallback>(value) });
1551 CURLcode::CURLE_OK
1552 }
1553
1554 10009 => {
1556 h.read_data = value.cast_mut();
1557 CURLcode::CURLE_OK
1558 }
1559
1560 20094 => {
1562 h.debug_callback =
1564 Some(unsafe { std::mem::transmute::<*const c_void, DebugCallback>(value) });
1565 CURLcode::CURLE_OK
1566 }
1567
1568 10095 => {
1570 h.debug_data = value.cast_mut();
1571 CURLcode::CURLE_OK
1572 }
1573
1574 10018 => {
1576 if let Some(s) = unsafe { read_cstr(value) } {
1578 h.easy.header("User-Agent", s);
1579 }
1580 CURLcode::CURLE_OK
1581 }
1582
1583 10015 => {
1585 if value.is_null() {
1586 h.postfields = None;
1587 } else {
1588 let data = unsafe { CStr::from_ptr(value.cast::<c_char>()) };
1590 h.postfields = Some(data.to_bytes().to_vec());
1591 }
1592 CURLcode::CURLE_OK
1593 }
1594
1595 10004 => {
1597 match unsafe { read_cstr(value) } {
1599 Some(s) => match h.easy.proxy(s) {
1600 Ok(()) => CURLcode::CURLE_OK,
1601 Err(_) => CURLcode::CURLE_URL_MALFORMAT,
1602 },
1603 None => CURLcode::CURLE_OK,
1604 }
1605 }
1606
1607 10177 => {
1609 if let Some(s) = unsafe { read_cstr(value) } {
1611 h.easy.noproxy(s);
1612 }
1613 CURLcode::CURLE_OK
1614 }
1615
1616 10036 => {
1618 if let Some(s) = unsafe { read_cstr(value) } {
1620 h.easy.method(s);
1621 }
1622 CURLcode::CURLE_OK
1623 }
1624
1625 10005 => {
1627 if let Some(s) = unsafe { read_cstr(value) } {
1629 if let Some((user, pass)) = s.split_once(':') {
1630 h.easy.basic_auth(user, pass);
1631 } else {
1632 h.easy.basic_auth(s, "");
1633 }
1634 }
1635 CURLcode::CURLE_OK
1636 }
1637
1638 10007 => {
1640 if let Some(s) = unsafe { read_cstr(value) } {
1642 h.easy.range(s);
1643 }
1644 CURLcode::CURLE_OK
1645 }
1646
1647 10022 => {
1649 if let Some(s) = unsafe { read_cstr(value) } {
1651 h.easy.header("Cookie", s);
1652 }
1653 CURLcode::CURLE_OK
1654 }
1655
1656 10025 => {
1658 if let Some(s) = unsafe { read_cstr(value) } {
1660 h.easy.ssl_client_cert(std::path::Path::new(s));
1661 }
1662 CURLcode::CURLE_OK
1663 }
1664
1665 10087 => {
1667 if let Some(s) = unsafe { read_cstr(value) } {
1669 h.easy.ssl_client_key(std::path::Path::new(s));
1670 }
1671 CURLcode::CURLE_OK
1672 }
1673
1674 10065 => {
1676 if let Some(s) = unsafe { read_cstr(value) } {
1678 h.easy.ssl_ca_cert(std::path::Path::new(s));
1679 }
1680 CURLcode::CURLE_OK
1681 }
1682
1683 10097 => {
1685 CURLcode::CURLE_OK
1688 }
1689
1690 10102 => {
1692 h.easy.accept_encoding(!value.is_null());
1693 CURLcode::CURLE_OK
1694 }
1695
1696 10231 => {
1698 if let Some(s) = unsafe { read_cstr(value) } {
1700 h.easy.unix_socket(s);
1701 }
1702 CURLcode::CURLE_OK
1703 }
1704
1705 10230 => {
1707 if let Some(s) = unsafe { read_cstr(value) } {
1709 h.easy.ssl_pinned_public_key(s);
1710 }
1711 CURLcode::CURLE_OK
1712 }
1713
1714 10062 => {
1716 if let Some(s) = unsafe { read_cstr(value) } {
1718 h.easy.interface(s);
1719 }
1720 CURLcode::CURLE_OK
1721 }
1722
1723 10083 => {
1725 if let Some(s) = unsafe { read_cstr(value) } {
1727 h.easy.ssl_cipher_list(s);
1728 }
1729 CURLcode::CURLE_OK
1730 }
1731
1732 10031 => {
1734 if let Some(s) = unsafe { read_cstr(value) } {
1736 if h.easy.cookie_file(s).is_err() {
1737 h.easy.cookie_jar(true);
1739 }
1740 } else {
1741 h.easy.cookie_jar(true);
1743 }
1744 CURLcode::CURLE_OK
1745 }
1746
1747 10082 => {
1749 if let Some(s) = unsafe { read_cstr(value) } {
1751 h.easy.cookie_jar_file(s);
1752 }
1753 CURLcode::CURLE_OK
1754 }
1755
1756 10006 => {
1758 if let Some(s) = unsafe { read_cstr(value) } {
1760 if let Some((user, pass)) = s.split_once(':') {
1761 h.easy.proxy_auth(user, pass);
1762 } else {
1763 h.easy.proxy_auth(s, "");
1764 }
1765 }
1766 CURLcode::CURLE_OK
1767 }
1768
1769 10254 => {
1771 if let Some(s) = unsafe { read_cstr(value) } {
1773 h.easy.proxy_ssl_client_cert(std::path::Path::new(s));
1774 }
1775 CURLcode::CURLE_OK
1776 }
1777
1778 10255 => {
1780 if let Some(s) = unsafe { read_cstr(value) } {
1782 h.easy.proxy_ssl_client_key(std::path::Path::new(s));
1783 }
1784 CURLcode::CURLE_OK
1785 }
1786
1787 10203 => {
1789 if !value.is_null() {
1791 let mut current = value.cast::<curl_slist>().cast_mut();
1792 while !current.is_null() {
1793 let node = unsafe { &*current };
1795 if !node.data.is_null() {
1796 if let Ok(s) = unsafe { CStr::from_ptr(node.data) }.to_str() {
1798 let parts: Vec<&str> = s.splitn(3, ':').collect();
1800 if parts.len() == 3 {
1801 let host_port = format!("{}:{}", parts[0], parts[1]);
1802 h.easy.resolve(&host_port, parts[2]);
1803 }
1804 }
1805 }
1806 current = node.next;
1807 }
1808 }
1809 CURLcode::CURLE_OK
1810 }
1811
1812 10023 => {
1814 if !value.is_null() {
1816 let mut current = value.cast::<curl_slist>().cast_mut();
1817 while !current.is_null() {
1818 let node = unsafe { &*current };
1820 if !node.data.is_null() {
1821 if let Ok(s) = unsafe { CStr::from_ptr(node.data) }.to_str() {
1823 if let Some((name, val)) = s.split_once(':') {
1824 h.easy.header(name.trim(), val.trim());
1825 }
1826 }
1827 }
1828 current = node.next;
1829 }
1830 }
1831 CURLcode::CURLE_OK
1832 }
1833
1834 42 => {
1838 h.include_headers = value as c_long != 0;
1839 CURLcode::CURLE_OK
1840 }
1841
1842 47 => {
1844 if value as c_long != 0 {
1845 h.easy.method("POST");
1846 }
1847 CURLcode::CURLE_OK
1848 }
1849
1850 44 => {
1852 if value as c_long != 0 {
1853 h.easy.method("HEAD");
1854 }
1855 CURLcode::CURLE_OK
1856 }
1857
1858 45 => {
1860 h.easy.fail_on_error(value as c_long != 0);
1861 CURLcode::CURLE_OK
1862 }
1863
1864 46 | 54 => {
1866 if value as c_long != 0 {
1867 h.easy.method("PUT");
1868 }
1869 CURLcode::CURLE_OK
1870 }
1871
1872 52 => {
1874 h.easy.follow_redirects(value as c_long != 0);
1875 CURLcode::CURLE_OK
1876 }
1877
1878 60 => {
1880 CURLcode::CURLE_OK
1882 }
1883
1884 64 => {
1886 h.easy.ssl_verify_peer(value as c_long != 0);
1887 CURLcode::CURLE_OK
1888 }
1889
1890 68 => {
1892 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
1893 h.easy.max_redirects(value as u32);
1894 CURLcode::CURLE_OK
1895 }
1896
1897 78 => {
1899 #[allow(clippy::cast_sign_loss)]
1900 let secs = value as u64;
1901 if secs > 0 {
1902 h.easy.connect_timeout(std::time::Duration::from_secs(secs));
1903 }
1904 CURLcode::CURLE_OK
1905 }
1906
1907 80 => {
1909 if value as c_long != 0 {
1910 h.easy.method("GET");
1911 }
1912 CURLcode::CURLE_OK
1913 }
1914
1915 81 => {
1917 h.easy.ssl_verify_host(value as c_long >= 2);
1919 CURLcode::CURLE_OK
1920 }
1921
1922 107 => {
1924 CURLcode::CURLE_OK
1927 }
1928
1929 111 => {
1931 CURLcode::CURLE_OK
1934 }
1935
1936 121 => {
1938 h.easy.tcp_nodelay(value as c_long != 0);
1939 CURLcode::CURLE_OK
1940 }
1941
1942 139 => {
1944 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
1945 h.easy.local_port(value as u16);
1946 CURLcode::CURLE_OK
1947 }
1948
1949 213 => {
1951 if value as c_long != 0 {
1952 h.easy.tcp_keepalive(std::time::Duration::from_secs(60));
1953 }
1954 CURLcode::CURLE_OK
1955 }
1956
1957 13 => {
1959 #[allow(clippy::cast_sign_loss)]
1960 let secs = value as u64;
1961 if secs > 0 {
1962 h.easy.timeout(std::time::Duration::from_secs(secs));
1963 }
1964 CURLcode::CURLE_OK
1965 }
1966
1967 41 => {
1969 h.easy.verbose(value as c_long != 0);
1970 CURLcode::CURLE_OK
1971 }
1972
1973 32 => {
1975 let version = value as c_long;
1977 if version == 6 {
1978 h.easy.ssl_min_version(liburlx::TlsVersion::Tls12);
1979 } else if version == 7 {
1980 h.easy.ssl_min_version(liburlx::TlsVersion::Tls13);
1981 }
1982 CURLcode::CURLE_OK
1983 }
1984
1985 19 => {
1987 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
1988 h.easy.low_speed_limit(value as u32);
1989 CURLcode::CURLE_OK
1990 }
1991
1992 20 => {
1994 #[allow(clippy::cast_sign_loss)]
1995 let secs = value as u64;
1996 h.easy.low_speed_time(std::time::Duration::from_secs(secs));
1997 CURLcode::CURLE_OK
1998 }
1999
2000 74 => {
2002 h.easy.fresh_connect(value as c_long != 0);
2003 CURLcode::CURLE_OK
2004 }
2005
2006 75 => {
2008 h.easy.forbid_reuse(value as c_long != 0);
2009 CURLcode::CURLE_OK
2010 }
2011
2012 155 => {
2014 #[allow(clippy::cast_sign_loss)]
2015 let ms = value as u64;
2016 if ms > 0 {
2017 h.easy.timeout(std::time::Duration::from_millis(ms));
2018 }
2019 CURLcode::CURLE_OK
2020 }
2021
2022 156 => {
2024 #[allow(clippy::cast_sign_loss)]
2025 let ms = value as u64;
2026 if ms > 0 {
2027 h.easy.connect_timeout(std::time::Duration::from_millis(ms));
2028 }
2029 CURLcode::CURLE_OK
2030 }
2031
2032 150 => {
2034 h.easy.ssl_session_cache(value as c_long != 0);
2035 CURLcode::CURLE_OK
2036 }
2037
2038 248 => {
2040 h.easy.proxy_ssl_verify_peer(value as c_long != 0);
2041 CURLcode::CURLE_OK
2042 }
2043
2044 30115 => {
2046 #[allow(clippy::cast_sign_loss)]
2047 let size = value as u64;
2048 h.infilesize = Some(size);
2049 h.easy.infilesize(size);
2050 CURLcode::CURLE_OK
2051 }
2052
2053 92 => {
2055 #[allow(clippy::cast_sign_loss)]
2056 let secs = value as u64;
2057 h.easy.dns_cache_timeout(std::time::Duration::from_secs(secs));
2058 CURLcode::CURLE_OK
2059 }
2060
2061 271 => {
2063 #[allow(clippy::cast_sign_loss)]
2064 let ms = value as u64;
2065 h.easy.happy_eyeballs_timeout(std::time::Duration::from_millis(ms));
2066 CURLcode::CURLE_OK
2067 }
2068
2069 10211 => {
2071 if let Some(s) = unsafe { read_cstr(value) } {
2073 match h.easy.dns_servers(s) {
2074 Ok(()) => CURLcode::CURLE_OK,
2075 Err(_) => CURLcode::CURLE_BAD_FUNCTION_ARGUMENT,
2076 }
2077 } else {
2078 CURLcode::CURLE_OK
2079 }
2080 }
2081
2082 10279 => {
2084 if let Some(s) = unsafe { read_cstr(value) } {
2086 h.easy.doh_url(s);
2087 }
2088 CURLcode::CURLE_OK
2089 }
2090
2091 105 => {
2093 h.easy.unrestricted_auth(value as c_long != 0);
2094 CURLcode::CURLE_OK
2095 }
2096
2097 136 => {
2099 h.easy.ignore_content_length(value as c_long != 0);
2100 CURLcode::CURLE_OK
2101 }
2102
2103 30145 => {
2105 #[allow(clippy::cast_sign_loss)]
2106 let speed = value as u64;
2107 if speed > 0 {
2108 h.easy.max_send_speed(speed);
2109 }
2110 CURLcode::CURLE_OK
2111 }
2112
2113 30146 => {
2115 #[allow(clippy::cast_sign_loss)]
2116 let speed = value as u64;
2117 if speed > 0 {
2118 h.easy.max_recv_speed(speed);
2119 }
2120 CURLcode::CURLE_OK
2121 }
2122
2123 43 => {
2125 h.noprogress = value as c_long != 0;
2126 CURLcode::CURLE_OK
2127 }
2128
2129 20056 => {
2131 h.progress_callback =
2133 Some(unsafe { std::mem::transmute::<*const c_void, ProgressCallback>(value) });
2134 CURLcode::CURLE_OK
2135 }
2136
2137 20219 => {
2139 h.xferinfo_callback =
2141 Some(unsafe { std::mem::transmute::<*const c_void, XferInfoCallback>(value) });
2142 CURLcode::CURLE_OK
2143 }
2144
2145 10057 => {
2147 h.progress_data = value.cast_mut();
2148 CURLcode::CURLE_OK
2149 }
2150
2151 20167 => {
2153 h.seek_callback =
2155 Some(unsafe { std::mem::transmute::<*const c_void, SeekCallback>(value) });
2156 CURLcode::CURLE_OK
2157 }
2158
2159 10168 => {
2161 h.seek_data = value.cast_mut();
2162 CURLcode::CURLE_OK
2163 }
2164
2165 10103 => {
2167 h.private_data = value.cast_mut();
2168 CURLcode::CURLE_OK
2169 }
2170
2171 10100 => {
2173 if value.is_null() {
2174 } else {
2176 let share = unsafe { &*value.cast::<liburlx::Share>() };
2178 h.easy.set_share(share.clone());
2179 }
2180 CURLcode::CURLE_OK
2181 }
2182
2183 10269 => {
2185 h.mimepost = value.cast_mut();
2186 for &(mime, part) in &h.mime_parts {
2188 unsafe { finalize_mime_part(mime, part) };
2190 }
2191 h.mime_parts.clear();
2192 CURLcode::CURLE_OK
2193 }
2194
2195 10016 => {
2197 if let Some(s) = unsafe { read_cstr(value) } {
2199 h.easy.header("Referer", s);
2200 }
2201 CURLcode::CURLE_OK
2202 }
2203
2204 10220 => {
2206 if let Some(s) = unsafe { read_cstr(value) } {
2208 h.easy.bearer_token(s);
2209 }
2210 CURLcode::CURLE_OK
2211 }
2212
2213 10216 => {
2215 CURLcode::CURLE_OK
2218 }
2219
2220 10217 => {
2222 if let Some(s) = unsafe { read_cstr(value) } {
2224 h.easy.ssl_srp_user(s);
2225 }
2226 CURLcode::CURLE_OK
2227 }
2228
2229 10218 => {
2231 if let Some(s) = unsafe { read_cstr(value) } {
2233 h.easy.ssl_srp_password(s);
2234 }
2235 CURLcode::CURLE_OK
2236 }
2237
2238 10306 => {
2240 CURLcode::CURLE_OK
2244 }
2245
2246 58 => {
2248 CURLcode::CURLE_OK
2250 }
2251
2252 84 => {
2254 let version = value as c_long;
2255 match version {
2256 0 => h.easy.http_version(liburlx::HttpVersion::None),
2258 1 => h.easy.http_version(liburlx::HttpVersion::Http10),
2260 2 => h.easy.http_version(liburlx::HttpVersion::Http11),
2262 3 | 4 => h.easy.http_version(liburlx::HttpVersion::Http2),
2264 5 => h.easy.http_version(liburlx::HttpVersion::Http2PriorKnowledge),
2266 _ => {}
2267 }
2268 CURLcode::CURLE_OK
2269 }
2270
2271 99 => {
2273 CURLcode::CURLE_OK
2275 }
2276
2277 71 => {
2279 let max = value as usize;
2280 h.easy.max_pool_connections(max);
2281 CURLcode::CURLE_OK
2282 }
2283
2284 237 => {
2286 CURLcode::CURLE_OK
2288 }
2289
2290 239 => {
2292 CURLcode::CURLE_OK
2294 }
2295
2296 244 => {
2298 CURLcode::CURLE_OK
2300 }
2301
2302 285 => {
2304 h.easy.http09_allowed(!value.is_null());
2305 CURLcode::CURLE_OK
2306 }
2307
2308 3 => {
2310 CURLcode::CURLE_OK
2313 }
2314
2315 14 => {
2317 CURLcode::CURLE_OK
2320 }
2321
2322 21 => {
2324 #[allow(clippy::cast_sign_loss)]
2326 let offset = value as u64;
2327 h.easy.resume_from(offset);
2328 CURLcode::CURLE_OK
2329 }
2330
2331 113 => {
2333 CURLcode::CURLE_OK
2336 }
2337
2338 30120 => {
2340 CURLcode::CURLE_OK
2343 }
2344
2345 164 => {
2347 CURLcode::CURLE_OK
2349 }
2350
2351 30116 => {
2353 #[allow(clippy::cast_sign_loss)]
2354 let offset = value as u64;
2355 h.easy.resume_from(offset);
2356 CURLcode::CURLE_OK
2357 }
2358
2359 30117 => {
2361 CURLcode::CURLE_OK
2363 }
2364
2365 10010 => {
2367 CURLcode::CURLE_OK
2370 }
2371
2372 10037 => {
2374 CURLcode::CURLE_OK
2376 }
2377
2378 61 => {
2380 CURLcode::CURLE_OK
2382 }
2383
2384 114 => {
2386 CURLcode::CURLE_OK
2388 }
2389
2390 10135 => {
2392 let _ = unsafe { read_cstr(value) };
2396 CURLcode::CURLE_OK
2397 }
2398
2399 161 => {
2401 let mask = value as c_long;
2403 h.easy.post301(mask & 1 != 0);
2404 h.easy.post302(mask & 2 != 0);
2405 h.easy.post303(mask & 4 != 0);
2406 CURLcode::CURLE_OK
2407 }
2408
2409 207 => {
2411 h.easy.accept_encoding(value as c_long != 0);
2413 CURLcode::CURLE_OK
2414 }
2415
2416 227 => {
2418 #[allow(clippy::cast_sign_loss)]
2419 let ms = value as u64;
2420 if ms > 0 {
2421 h.easy.expect_100_timeout(std::time::Duration::from_millis(ms));
2422 }
2423 CURLcode::CURLE_OK
2424 }
2425
2426 234 => {
2428 h.easy.path_as_is(value as c_long != 0);
2429 CURLcode::CURLE_OK
2430 }
2431
2432 10246 => {
2434 if let Some(s) = unsafe { read_cstr(value) } {
2436 let _ = s;
2438 }
2439 CURLcode::CURLE_OK
2440 }
2441
2442 249 => {
2444 CURLcode::CURLE_OK
2446 }
2447
2448 275 => {
2450 h.easy.dns_shuffle(value as c_long != 0);
2451 CURLcode::CURLE_OK
2452 }
2453
2454 10300 => {
2456 if let Some(_path) = unsafe { read_cstr(value) } {
2458 h.easy.hsts(true);
2460 }
2461 CURLcode::CURLE_OK
2462 }
2463
2464 10318 => {
2466 if let Some(s) = unsafe { read_cstr(value) } {
2468 h.easy.set_protocols_str(s);
2469 }
2470 CURLcode::CURLE_OK
2471 }
2472
2473 10319 => {
2475 if let Some(s) = unsafe { read_cstr(value) } {
2477 h.easy.set_redir_protocols_str(s);
2478 }
2479 CURLcode::CURLE_OK
2480 }
2481
2482 10243 => {
2484 if !value.is_null() {
2486 let mut entries = Vec::new();
2488 let mut node = value.cast::<curl_slist>();
2489 while !node.is_null() {
2491 let n = unsafe { &*node };
2492 if !n.data.is_null() {
2493 if let Ok(s) = unsafe { CStr::from_ptr(n.data) }.to_str() {
2495 entries.push(s.to_string());
2496 }
2497 }
2498 node = n.next;
2499 }
2500 for entry in &entries {
2501 h.easy.connect_to(entry);
2502 }
2503 }
2504 CURLcode::CURLE_OK
2505 }
2506
2507 274 => {
2509 h.easy.haproxy_protocol(value as c_long != 0);
2510 CURLcode::CURLE_OK
2511 }
2512
2513 10024 => {
2515 CURLcode::CURLE_OK
2517 }
2518
2519 10264 => {
2521 if let Some(s) = unsafe { read_cstr(value) } {
2523 h.easy.abstract_unix_socket(s);
2524 }
2525 CURLcode::CURLE_OK
2526 }
2527
2528 306 => {
2530 let verify = value as c_long != 0;
2531 h.easy.doh_insecure(!verify);
2532 CURLcode::CURLE_OK
2533 }
2534
2535 307 => {
2537 CURLcode::CURLE_OK
2539 }
2540
2541 40291 => {
2543 if value.is_null() {
2544 return CURLcode::CURLE_BAD_FUNCTION_ARGUMENT;
2545 }
2546 let blob = unsafe { &*value.cast::<curl_blob>() };
2548 if blob.data.is_null() || blob.len == 0 {
2549 return CURLcode::CURLE_BAD_FUNCTION_ARGUMENT;
2550 }
2551 let data = unsafe { std::slice::from_raw_parts(blob.data.cast::<u8>(), blob.len) };
2553 h.easy.ssl_client_cert_blob(data.to_vec());
2554 CURLcode::CURLE_OK
2555 }
2556
2557 40292 => {
2559 if value.is_null() {
2560 return CURLcode::CURLE_BAD_FUNCTION_ARGUMENT;
2561 }
2562 let blob = unsafe { &*value.cast::<curl_blob>() };
2564 if blob.data.is_null() || blob.len == 0 {
2565 return CURLcode::CURLE_BAD_FUNCTION_ARGUMENT;
2566 }
2567 let data = unsafe { std::slice::from_raw_parts(blob.data.cast::<u8>(), blob.len) };
2569 h.easy.ssl_client_key_blob(data.to_vec());
2570 CURLcode::CURLE_OK
2571 }
2572
2573 40309 => {
2575 if value.is_null() {
2576 h.easy.clear_ssl_ca_cert_blob();
2578 return CURLcode::CURLE_OK;
2579 }
2580 let blob = unsafe { &*value.cast::<curl_blob>() };
2582 if blob.data.is_null() || blob.len == 0 {
2583 h.easy.clear_ssl_ca_cert_blob();
2585 return CURLcode::CURLE_OK;
2586 }
2587 let data = unsafe { std::slice::from_raw_parts(blob.data.cast::<u8>(), blob.len) };
2589 h.easy.ssl_ca_cert_blob(data.to_vec());
2590 CURLcode::CURLE_OK
2591 }
2592
2593 314 => {
2595 CURLcode::CURLE_OK
2597 }
2598
2599 98 => {
2601 CURLcode::CURLE_OK
2603 }
2604
2605 280 => {
2607 CURLcode::CURLE_OK
2609 }
2610
2611 69 => {
2613 CURLcode::CURLE_OK
2615 }
2616
2617 10017 => {
2621 if let Some(s) = unsafe { read_cstr(value) } {
2623 h.easy.ftp_active_port(s);
2624 }
2625 CURLcode::CURLE_OK
2626 }
2627
2628 85 => {
2630 h.easy.ftp_use_epsv(value as c_long != 0);
2631 CURLcode::CURLE_OK
2632 }
2633
2634 106 => {
2636 h.easy.ftp_use_eprt(value as c_long != 0);
2637 CURLcode::CURLE_OK
2638 }
2639
2640 110 => {
2642 h.easy.ftp_create_dirs(value as c_long != 0);
2643 CURLcode::CURLE_OK
2644 }
2645
2646 137 => {
2648 h.easy.ftp_skip_pasv_ip(value as c_long != 0);
2649 CURLcode::CURLE_OK
2650 }
2651
2652 138 => {
2654 #[allow(clippy::cast_sign_loss)]
2655 let method = match value as c_long {
2656 1 => liburlx::FtpMethod::MultiCwd,
2657 2 => liburlx::FtpMethod::NoCwd,
2658 3 => liburlx::FtpMethod::SingleCwd,
2659 _ => liburlx::FtpMethod::default(),
2660 };
2661 h.easy.ftp_method(method);
2662 CURLcode::CURLE_OK
2663 }
2664
2665 10134 => {
2667 if let Some(s) = unsafe { read_cstr(value) } {
2669 h.easy.ftp_account(s);
2670 }
2671 CURLcode::CURLE_OK
2672 }
2673
2674 10147 => {
2676 CURLcode::CURLE_OK
2678 }
2679
2680 154 => {
2682 CURLcode::CURLE_OK
2684 }
2685
2686 188 => {
2688 CURLcode::CURLE_OK
2690 }
2691
2692 119 => {
2694 let mode = match value as c_long {
2695 2 | 3 => liburlx::FtpSslMode::Explicit,
2696 _ => liburlx::FtpSslMode::None,
2697 };
2698 h.easy.ftp_ssl_mode(mode);
2699 CURLcode::CURLE_OK
2700 }
2701
2702 151 => {
2706 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
2707 h.easy.ssh_auth_types(value as u32);
2708 CURLcode::CURLE_OK
2709 }
2710
2711 10152 => {
2713 if let Some(s) = unsafe { read_cstr(value) } {
2715 h.easy.ssh_public_keyfile(s);
2716 }
2717 CURLcode::CURLE_OK
2718 }
2719
2720 10153 => {
2722 if let Some(s) = unsafe { read_cstr(value) } {
2724 h.easy.ssh_key_path(s);
2725 }
2726 CURLcode::CURLE_OK
2727 }
2728
2729 10183 => {
2731 if let Some(s) = unsafe { read_cstr(value) } {
2733 h.easy.ssh_known_hosts_path(s);
2734 }
2735 CURLcode::CURLE_OK
2736 }
2737
2738 10270 => {
2740 if let Some(s) = unsafe { read_cstr(value) } {
2742 h.easy.ssh_host_key_sha256(s);
2743 }
2744 CURLcode::CURLE_OK
2745 }
2746
2747 10162 => {
2749 CURLcode::CURLE_OK
2751 }
2752
2753 268 => {
2755 CURLcode::CURLE_OK
2757 }
2758
2759 59 => {
2763 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
2764 h.easy.proxy_port(value as u16);
2765 CURLcode::CURLE_OK
2766 }
2767
2768 101 => {
2770 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
2771 h.easy.proxy_type(value as u32);
2772 CURLcode::CURLE_OK
2773 }
2774
2775 10175 => {
2777 if let Some(s) = unsafe { read_cstr(value) } {
2779 h.easy.proxy_auth(s, "");
2781 }
2782 CURLcode::CURLE_OK
2783 }
2784
2785 10176 => {
2787 if let Some(s) = unsafe { read_cstr(value) } {
2789 h.easy.proxy_auth("", s);
2791 }
2792 CURLcode::CURLE_OK
2793 }
2794
2795 10262 => {
2797 if let Some(s) = unsafe { read_cstr(value) } {
2799 h.easy.pre_proxy(s);
2800 }
2801 CURLcode::CURLE_OK
2802 }
2803
2804 10247 => {
2806 CURLcode::CURLE_OK
2808 }
2809
2810 10260 => {
2812 CURLcode::CURLE_OK
2814 }
2815
2816 10263 => {
2818 CURLcode::CURLE_OK
2820 }
2821
2822 250 => {
2824 CURLcode::CURLE_OK
2826 }
2827
2828 10259 => {
2830 CURLcode::CURLE_OK
2832 }
2833
2834 10277 => {
2836 CURLcode::CURLE_OK
2838 }
2839
2840 267 => {
2842 CURLcode::CURLE_OK
2844 }
2845
2846 189 => {
2848 let req_val = value as c_long;
2849 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
2850 if let Some(req) = liburlx::protocol::rtsp::RtspRequest::from_long(req_val as u32) {
2851 h.easy.set_rtsp_request(req);
2852 CURLcode::CURLE_OK
2853 } else {
2854 CURLcode::CURLE_BAD_FUNCTION_ARGUMENT
2855 }
2856 }
2857
2858 10190 => {
2860 let sid = unsafe { read_cstr(value) };
2861 h.easy.set_rtsp_session_id(sid);
2862 CURLcode::CURLE_OK
2863 }
2864
2865 10191 => {
2867 if let Some(uri) = unsafe { read_cstr(value) } {
2868 h.easy.set_rtsp_stream_uri(uri);
2869 }
2870 CURLcode::CURLE_OK
2871 }
2872
2873 10192 => {
2875 if let Some(transport) = unsafe { read_cstr(value) } {
2876 h.easy.set_rtsp_transport(transport);
2877 }
2878 CURLcode::CURLE_OK
2879 }
2880
2881 193 => {
2883 let cseq = value as c_long;
2884 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
2885 h.easy.set_rtsp_client_cseq(cseq as u32);
2886 CURLcode::CURLE_OK
2887 }
2888
2889 194 | 20196 | 10195 => CURLcode::CURLE_OK,
2892
2893 _ => CURLcode::CURLE_UNKNOWN_OPTION,
2894 }
2895 }));
2896 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
2897}
2898
2899#[no_mangle]
2905#[allow(clippy::too_many_lines)]
2906pub unsafe extern "C" fn curl_easy_perform(handle: *mut c_void) -> CURLcode {
2907 if handle.is_null() {
2908 return CURLcode::CURLE_FAILED_INIT;
2909 }
2910
2911 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
2913
2914 if !h.mimepost.is_null() {
2916 let mime = unsafe { &*h.mimepost.cast::<MimeHandle>() };
2918 let content_type = mime.form.content_type();
2919 let body = mime.form.encode();
2920 h.easy.header("Content-Type", &content_type);
2921 h.easy.body(&body);
2922 }
2923
2924 if let Some(ref body) = h.postfields {
2926 h.easy.body(body);
2927 } else if let Some(read_cb) = h.read_callback {
2928 let mut upload_data = Vec::new();
2930 let mut buf = [0u8; 16384]; loop {
2932 let n =
2935 unsafe { read_cb(buf.as_mut_ptr().cast::<c_char>(), 1, buf.len(), h.read_data) };
2936 if n == 0x1000_0000 {
2938 return CURLcode::CURLE_ABORTED_BY_CALLBACK;
2939 }
2940 if n == 0 {
2941 break;
2942 }
2943 if n > buf.len() {
2944 return CURLcode::CURLE_READ_ERROR;
2945 }
2946 upload_data.extend_from_slice(&buf[..n]);
2947 }
2948 if !upload_data.is_empty() {
2949 h.easy.body(&upload_data);
2950 }
2951 }
2952
2953 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| h.easy.perform()));
2955
2956 match result {
2957 Ok(Ok(response)) => {
2958 if let Some(debug_cb) = h.debug_callback {
2960 for (name, value) in response.headers() {
2962 let line = format!("{name}: {value}\r\n");
2963 let bytes = line.into_bytes();
2964 let _ = unsafe {
2966 debug_cb(
2967 handle,
2968 1, bytes.as_ptr().cast::<c_char>(),
2970 bytes.len(),
2971 h.debug_data,
2972 )
2973 };
2974 }
2975
2976 let body = response.body();
2978 if !body.is_empty() {
2979 let _ = unsafe {
2981 debug_cb(
2982 handle,
2983 2, body.as_ptr().cast::<c_char>(),
2985 body.len(),
2986 h.debug_data,
2987 )
2988 };
2989 }
2990 }
2991
2992 let mut output = Vec::new();
2994 if h.include_headers {
2995 if let Some(raw) = response.raw_headers() {
2996 output.extend_from_slice(raw);
2999 } else {
3000 let eol = if response.uses_crlf() { "\r\n" } else { "\n" };
3002 let reason = response.status_reason().unwrap_or("OK");
3003 let http_ver = response.http_version();
3004 let status_line =
3005 format!("HTTP/{http_ver} {} {}{eol}", response.status(), reason);
3006 output.extend_from_slice(status_line.as_bytes());
3007 for (name, value) in response.headers_ordered() {
3008 let line = format!("{name}: {value}{eol}");
3009 output.extend_from_slice(line.as_bytes());
3010 }
3011 output.extend_from_slice(eol.as_bytes());
3012 }
3013 }
3014 output.extend_from_slice(response.body());
3015
3016 if !output.is_empty() {
3018 if let Some(cb) = h.write_callback {
3019 let written = unsafe {
3021 cb(output.as_ptr().cast::<c_char>(), 1, output.len(), h.write_data)
3022 };
3023 if written != output.len() {
3024 return CURLcode::CURLE_WRITE_ERROR;
3025 }
3026 } else {
3027 use std::io::Write;
3029 let _ = std::io::stdout().write_all(&output);
3030 }
3031 }
3032
3033 if let Some(cb) = h.header_callback {
3035 for (name, value) in response.headers() {
3036 let header_line = format!("{name}: {value}\r\n");
3037 let bytes = header_line.as_bytes();
3038 let _written = unsafe {
3040 cb(bytes.as_ptr().cast::<c_char>(), 1, bytes.len(), h.header_data)
3041 };
3042 }
3043 }
3044
3045 if !h.noprogress {
3047 let info = response.transfer_info();
3048 let dl_total = response.body().len() as u64;
3049 let dl_now = dl_total;
3050 let ul_total = info.size_upload;
3051 let ul_now = ul_total;
3052 #[allow(clippy::cast_precision_loss, clippy::cast_possible_wrap)]
3053 if let Some(xfer_cb) = h.xferinfo_callback {
3054 let ret = unsafe {
3056 xfer_cb(
3057 h.progress_data,
3058 dl_total as i64,
3059 dl_now as i64,
3060 ul_total as i64,
3061 ul_now as i64,
3062 )
3063 };
3064 if ret != 0 {
3065 return CURLcode::CURLE_ABORTED_BY_CALLBACK;
3066 }
3067 } else if let Some(prog_cb) = h.progress_callback {
3068 let ret = unsafe {
3070 prog_cb(
3071 h.progress_data,
3072 dl_total as f64,
3073 dl_now as f64,
3074 ul_total as f64,
3075 ul_now as f64,
3076 )
3077 };
3078 if ret != 0 {
3079 return CURLcode::CURLE_ABORTED_BY_CALLBACK;
3080 }
3081 }
3082 }
3083
3084 h.last_response = Some(response);
3085 CURLcode::CURLE_OK
3086 }
3087 Ok(Err(e)) => {
3088 let msg = e.to_string();
3090 let bytes = msg.as_bytes();
3091 let len = bytes.len().min(h.error_buf.len() - 1);
3092 h.error_buf[..len].copy_from_slice(&bytes[..len]);
3093 h.error_buf[len] = 0;
3094
3095 error_to_curlcode(&e)
3096 }
3097 Err(_) => {
3098 CURLcode::CURLE_FAILED_INIT
3100 }
3101 }
3102}
3103
3104#[no_mangle]
3111#[allow(clippy::too_many_lines)]
3112pub unsafe extern "C" fn curl_easy_getinfo(
3113 handle: *mut c_void,
3114 info: c_long,
3115 out: *mut c_void,
3116) -> CURLcode {
3117 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3118 if handle.is_null() || out.is_null() {
3119 return CURLcode::CURLE_FAILED_INIT;
3120 }
3121
3122 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
3124
3125 if info == 0x10_0015 {
3127 let out = unsafe { &mut *out.cast::<*mut c_void>() };
3129 *out = h.private_data;
3130 return CURLcode::CURLE_OK;
3131 }
3132
3133 let Some(ref response) = h.last_response else {
3134 return CURLcode::CURLE_GOT_NOTHING;
3135 };
3136
3137 match info {
3138 0x10_0001 => {
3140 let out = unsafe { &mut *out.cast::<*const c_char>() };
3142 *out = response.effective_url().as_ptr().cast::<c_char>();
3143 CURLcode::CURLE_OK
3144 }
3145
3146 0x20_0002 => {
3148 let out = unsafe { &mut *out.cast::<c_long>() };
3150 *out = c_long::from(response.status());
3151 CURLcode::CURLE_OK
3152 }
3153
3154 0x30_0003 => {
3156 let out = unsafe { &mut *out.cast::<f64>() };
3158 *out = response.transfer_info().time_total.as_secs_f64();
3159 CURLcode::CURLE_OK
3160 }
3161
3162 0x30_0004 => {
3164 let out = unsafe { &mut *out.cast::<f64>() };
3166 *out = response.transfer_info().time_namelookup.as_secs_f64();
3167 CURLcode::CURLE_OK
3168 }
3169
3170 0x30_0005 => {
3172 let out = unsafe { &mut *out.cast::<f64>() };
3174 *out = response.transfer_info().time_connect.as_secs_f64();
3175 CURLcode::CURLE_OK
3176 }
3177
3178 0x30_0008 => {
3180 let out = unsafe { &mut *out.cast::<f64>() };
3182 #[allow(clippy::cast_precision_loss)]
3183 {
3184 *out = response.size_download() as f64;
3185 }
3186 CURLcode::CURLE_OK
3187 }
3188
3189 0x30_0009 => {
3191 let out = unsafe { &mut *out.cast::<f64>() };
3193 let total = response.transfer_info().time_total.as_secs_f64();
3194 #[allow(clippy::cast_precision_loss)]
3195 if total > 0.0 {
3196 *out = response.size_download() as f64 / total;
3197 } else {
3198 *out = 0.0;
3199 }
3200 CURLcode::CURLE_OK
3201 }
3202
3203 0x20_000B => {
3205 let out = unsafe { &mut *out.cast::<c_long>() };
3207 let header_size: usize = response
3209 .headers()
3210 .iter()
3211 .map(|(k, v)| k.len() + v.len() + 4) .sum();
3213 #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
3214 {
3215 *out = header_size as c_long;
3216 }
3217 CURLcode::CURLE_OK
3218 }
3219
3220 0x30_0011 => {
3222 let out = unsafe { &mut *out.cast::<f64>() };
3224 *out = response.transfer_info().time_starttransfer.as_secs_f64();
3225 CURLcode::CURLE_OK
3226 }
3227
3228 0x10_0012 => {
3230 let out = unsafe { &mut *out.cast::<*const c_char>() };
3232 *out =
3233 response.content_type().map_or(ptr::null(), |ct| ct.as_ptr().cast::<c_char>());
3234 CURLcode::CURLE_OK
3235 }
3236
3237 0x20_0014 => {
3239 let out = unsafe { &mut *out.cast::<c_long>() };
3241 #[allow(clippy::cast_possible_wrap, clippy::cast_lossless)]
3242 {
3243 *out = response.transfer_info().num_redirects as c_long;
3244 }
3245 CURLcode::CURLE_OK
3246 }
3247
3248 0x30_0033 => {
3250 let out = unsafe { &mut *out.cast::<f64>() };
3252 *out = response.transfer_info().time_appconnect.as_secs_f64();
3253 CURLcode::CURLE_OK
3254 }
3255
3256 0x30_0007 | 0x30_0010 => {
3258 let out = unsafe { &mut *out.cast::<f64>() };
3260 #[allow(clippy::cast_precision_loss)]
3261 {
3262 *out = response.transfer_info().size_upload as f64;
3263 }
3264 CURLcode::CURLE_OK
3265 }
3266
3267 0x30_000A => {
3269 let out = unsafe { &mut *out.cast::<f64>() };
3271 *out = response.transfer_info().speed_upload;
3272 CURLcode::CURLE_OK
3273 }
3274
3275 0x30_000E => {
3277 let out = unsafe { &mut *out.cast::<f64>() };
3279 *out = response.transfer_info().time_pretransfer.as_secs_f64();
3280 CURLcode::CURLE_OK
3281 }
3282
3283 0x20_000D => {
3285 let out = unsafe { &mut *out.cast::<c_long>() };
3287 *out = 0;
3290 CURLcode::CURLE_OK
3291 }
3292
3293 0x20_000E => {
3295 let out = unsafe { &mut *out.cast::<c_long>() };
3297 *out = -1;
3299 CURLcode::CURLE_OK
3300 }
3301
3302 0x30_000F => {
3304 let out = unsafe { &mut *out.cast::<f64>() };
3306 #[allow(clippy::cast_precision_loss)]
3308 {
3309 *out = response.size_download() as f64;
3310 }
3311 CURLcode::CURLE_OK
3312 }
3313
3314 0x20_0032 => {
3316 let out = unsafe { &mut *out.cast::<c_long>() };
3318 *out = 2;
3320 CURLcode::CURLE_OK
3321 }
3322
3323 0x20_0040 => {
3325 let out = unsafe { &mut *out.cast::<c_long>() };
3327 if let Ok(url) = liburlx::Url::parse(response.effective_url()) {
3329 *out = c_long::from(url.port_or_default().unwrap_or(0));
3330 } else {
3331 *out = 0;
3332 }
3333 CURLcode::CURLE_OK
3334 }
3335
3336 0x20_0019 => {
3338 let out = unsafe { &mut *out.cast::<c_long>() };
3340 *out = 0;
3342 CURLcode::CURLE_OK
3343 }
3344
3345 0x10_0020 => {
3347 let out = unsafe { &mut *out.cast::<*const c_char>() };
3349 *out = c"".as_ptr();
3351 CURLcode::CURLE_OK
3352 }
3353
3354 0x20_001A => {
3356 let out = unsafe { &mut *out.cast::<c_long>() };
3358 *out = 1;
3360 CURLcode::CURLE_OK
3361 }
3362
3363 0x10_0029 => {
3365 let out = unsafe { &mut *out.cast::<*const c_char>() };
3367 *out = c"".as_ptr();
3369 CURLcode::CURLE_OK
3370 }
3371
3372 0x10_0031 => {
3374 let out = unsafe { &mut *out.cast::<*const c_char>() };
3376 if response.is_redirect() {
3378 *out = response
3379 .header("location")
3380 .map_or(ptr::null(), |loc| loc.as_ptr().cast::<c_char>());
3381 } else {
3382 *out = ptr::null();
3383 }
3384 CURLcode::CURLE_OK
3385 }
3386
3387 0x20_0035 => {
3389 let out = unsafe { &mut *out.cast::<c_long>() };
3391 *out = c_long::from(response.status() == 304);
3393 CURLcode::CURLE_OK
3394 }
3395
3396 0x20_0042 => {
3398 let out = unsafe { &mut *out.cast::<c_long>() };
3400 *out = 0;
3402 CURLcode::CURLE_OK
3403 }
3404
3405 0x10_0044 => {
3407 let out = unsafe { &mut *out.cast::<*const c_char>() };
3411 *out = response.effective_url().as_ptr().cast::<c_char>();
3412 CURLcode::CURLE_OK
3413 }
3414
3415 0x30_0013 => {
3417 let out = unsafe { &mut *out.cast::<f64>() };
3419 *out = 0.0;
3422 CURLcode::CURLE_OK
3423 }
3424
3425 0x60_003E => {
3427 let out = unsafe { &mut *out.cast::<i64>() };
3429 #[allow(clippy::cast_possible_truncation)]
3430 {
3431 *out = response.transfer_info().time_total.as_micros() as i64;
3432 }
3433 CURLcode::CURLE_OK
3434 }
3435
3436 0x60_003F => {
3438 let out = unsafe { &mut *out.cast::<i64>() };
3440 #[allow(clippy::cast_possible_truncation)]
3441 {
3442 *out = response.transfer_info().time_namelookup.as_micros() as i64;
3443 }
3444 CURLcode::CURLE_OK
3445 }
3446
3447 0x60_0040 => {
3449 let out = unsafe { &mut *out.cast::<i64>() };
3451 #[allow(clippy::cast_possible_truncation)]
3452 {
3453 *out = response.transfer_info().time_connect.as_micros() as i64;
3454 }
3455 CURLcode::CURLE_OK
3456 }
3457
3458 0x60_0041 => {
3460 let out = unsafe { &mut *out.cast::<i64>() };
3462 #[allow(clippy::cast_possible_truncation)]
3463 {
3464 *out = response.transfer_info().time_pretransfer.as_micros() as i64;
3465 }
3466 CURLcode::CURLE_OK
3467 }
3468
3469 0x60_0042 => {
3471 let out = unsafe { &mut *out.cast::<i64>() };
3473 #[allow(clippy::cast_possible_truncation)]
3474 {
3475 *out = response.transfer_info().time_starttransfer.as_micros() as i64;
3476 }
3477 CURLcode::CURLE_OK
3478 }
3479
3480 0x60_0043 => {
3482 let out = unsafe { &mut *out.cast::<i64>() };
3484 *out = 0;
3486 CURLcode::CURLE_OK
3487 }
3488
3489 0x60_0044 => {
3491 let out = unsafe { &mut *out.cast::<i64>() };
3493 #[allow(clippy::cast_possible_truncation)]
3494 {
3495 *out = response.transfer_info().time_appconnect.as_micros() as i64;
3496 }
3497 CURLcode::CURLE_OK
3498 }
3499
3500 0x20_003A => {
3502 let out = unsafe { &mut *out.cast::<c_long>() };
3504 *out = 0;
3506 CURLcode::CURLE_OK
3507 }
3508
3509 0x60_0045 => {
3511 let out = unsafe { &mut *out.cast::<i64>() };
3513 #[allow(clippy::cast_possible_wrap)]
3514 {
3515 *out = response.transfer_info().size_upload as i64;
3516 }
3517 CURLcode::CURLE_OK
3518 }
3519
3520 0x60_0046 => {
3522 let out = unsafe { &mut *out.cast::<i64>() };
3524 #[allow(clippy::cast_possible_wrap)]
3525 {
3526 *out = response.size_download() as i64;
3527 }
3528 CURLcode::CURLE_OK
3529 }
3530
3531 0x60_0047 => {
3533 let out = unsafe { &mut *out.cast::<i64>() };
3535 #[allow(clippy::cast_possible_truncation)]
3536 {
3537 *out = response.transfer_info().speed_download as i64;
3538 }
3539 CURLcode::CURLE_OK
3540 }
3541
3542 0x60_0048 => {
3544 let out = unsafe { &mut *out.cast::<i64>() };
3546 #[allow(clippy::cast_possible_truncation)]
3547 {
3548 *out = response.transfer_info().speed_upload as i64;
3549 }
3550 CURLcode::CURLE_OK
3551 }
3552
3553 0x20_000C => {
3555 let out = unsafe { &mut *out.cast::<c_long>() };
3557 *out = 0;
3559 CURLcode::CURLE_OK
3560 }
3561
3562 0x20_0016 => {
3564 let out = unsafe { &mut *out.cast::<c_long>() };
3566 *out = 0;
3568 CURLcode::CURLE_OK
3569 }
3570
3571 0x20_0017 => {
3573 let out = unsafe { &mut *out.cast::<c_long>() };
3575 *out = 1;
3579 CURLcode::CURLE_OK
3580 }
3581
3582 0x20_0018 => {
3584 let out = unsafe { &mut *out.cast::<c_long>() };
3586 *out = 0;
3588 CURLcode::CURLE_OK
3589 }
3590
3591 0x10_0045 => {
3593 let out = unsafe { &mut *out.cast::<*const c_char>() };
3594 if let Some(sid) = h.easy.rtsp_session_id() {
3595 *out = sid.as_ptr().cast::<c_char>();
3596 } else {
3597 *out = ptr::null();
3598 }
3599 CURLcode::CURLE_OK
3600 }
3601
3602 0x20_0045 => {
3604 let out = unsafe { &mut *out.cast::<c_long>() };
3605 #[allow(clippy::cast_lossless)]
3608 {
3609 *out = h.easy.rtsp_client_cseq() as c_long;
3610 }
3611 CURLcode::CURLE_OK
3612 }
3613
3614 0x20_0046 => {
3616 let out = unsafe { &mut *out.cast::<c_long>() };
3617 #[allow(clippy::cast_lossless)]
3620 {
3621 *out = h.easy.rtsp_server_cseq() as c_long;
3622 }
3623 CURLcode::CURLE_OK
3624 }
3625
3626 0x20_0047 => {
3628 let out = unsafe { &mut *out.cast::<c_long>() };
3629 #[allow(clippy::cast_lossless)]
3632 {
3633 *out = h.easy.rtsp_cseq_recv() as c_long;
3634 }
3635 CURLcode::CURLE_OK
3636 }
3637
3638 _ => CURLcode::CURLE_UNKNOWN_OPTION,
3639 }
3640 }));
3641 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
3642}
3643
3644#[no_mangle]
3650#[allow(clippy::missing_const_for_fn)] pub extern "C" fn curl_easy_strerror(code: CURLcode) -> *const c_char {
3652 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3653 let msg = match code {
3654 CURLcode::CURLE_OK => c"No error",
3655 CURLcode::CURLE_UNSUPPORTED_PROTOCOL => c"Unsupported protocol",
3656 CURLcode::CURLE_FAILED_INIT => c"Failed initialization",
3657 CURLcode::CURLE_URL_MALFORMAT => c"URL using bad/illegal format or missing URL",
3658 CURLcode::CURLE_COULDNT_RESOLVE_PROXY => c"Couldn't resolve proxy name",
3659 CURLcode::CURLE_COULDNT_RESOLVE_HOST => c"Couldn't resolve host name",
3660 CURLcode::CURLE_COULDNT_CONNECT => c"Failed to connect to host or proxy",
3661 CURLcode::CURLE_FTP_WEIRD_SERVER_REPLY => c"Weird server reply",
3662 CURLcode::CURLE_REMOTE_ACCESS_DENIED => c"Access denied",
3663 CURLcode::CURLE_HTTP2 => c"Error in the HTTP2 framing layer",
3664 CURLcode::CURLE_HTTP_RETURNED_ERROR => c"HTTP response code said error",
3665 CURLcode::CURLE_WRITE_ERROR => c"Failed writing received data to disk/application",
3666 CURLcode::CURLE_READ_ERROR => c"Failed to read data",
3667 CURLcode::CURLE_OUT_OF_MEMORY => c"Out of memory",
3668 CURLcode::CURLE_OPERATION_TIMEDOUT => c"Operation timed out",
3669 CURLcode::CURLE_SSL_CONNECT_ERROR => c"SSL connect error",
3670 CURLcode::CURLE_ABORTED_BY_CALLBACK => c"Aborted by callback",
3671 CURLcode::CURLE_BAD_FUNCTION_ARGUMENT => c"A libcurl function was given a bad argument",
3672 CURLcode::CURLE_UNKNOWN_OPTION => c"An unknown option was passed to libcurl",
3673 CURLcode::CURLE_GOT_NOTHING => c"Server returned nothing (no headers, no data)",
3674 CURLcode::CURLE_SEND_ERROR => c"Failed sending data to the peer",
3675 CURLcode::CURLE_RECV_ERROR => c"Failure when receiving data from the peer",
3676 CURLcode::CURLE_SSL_CERTPROBLEM => c"Problem with the local SSL certificate",
3677 CURLcode::CURLE_PEER_FAILED_VERIFICATION => {
3678 c"SSL peer certificate or SSH remote key was not OK"
3679 }
3680 CURLcode::CURLE_LOGIN_DENIED => c"Login denied",
3681 CURLcode::CURLE_FILESIZE_EXCEEDED => c"Maximum file size exceeded",
3682 CURLcode::CURLE_TOO_MANY_REDIRECTS => c"Number of redirects hit maximum amount",
3683 CURLcode::CURLE_HTTP3 => c"Error in the HTTP3 layer",
3684 CURLcode::CURLE_PARTIAL_FILE => c"Transferred a partial file",
3685 CURLcode::CURLE_RANGE_ERROR => c"Requested range was not delivered",
3686 CURLcode::CURLE_AGAIN => c"Socket is not ready for send/recv",
3687 CURLcode::CURLE_AUTH_ERROR => c"An authentication function returned an error",
3688 CURLcode::CURLE_UNRECOVERABLE_POLL => c"Unrecoverable error in select/poll",
3689 CURLcode::CURLE_FTP_COULDNT_RETR_FILE => c"FTP: couldn't retrieve (RETR failed)",
3690 CURLcode::CURLE_UPLOAD_FAILED => c"Upload failed",
3691 CURLcode::CURLE_LDAP_SEARCH_FAILED => c"LDAP search failed",
3692 CURLcode::CURLE_FUNCTION_NOT_FOUND => c"A required function was not found",
3693 CURLcode::CURLE_INTERFACE_FAILED => c"Failed binding local connection end",
3694 CURLcode::CURLE_SSL_ENGINE_NOTFOUND => c"SSL crypto engine not found",
3695 CURLcode::CURLE_SSL_ENGINE_SETFAILED => c"Can not set SSL crypto engine as default",
3696 CURLcode::CURLE_RTSP_CSEQ_ERROR => c"RTSP CSeq mismatch or invalid CSeq",
3697 CURLcode::CURLE_RTSP_SESSION_ERROR => c"RTSP session error",
3698 CURLcode::CURLE_SSL_PINNEDPUBKEYNOTMATCH => c"SSL public key does not match pinned key",
3699 CURLcode::CURLE_SSL_INVALIDCERTSTATUS => {
3700 c"SSL server certificate status verification failed"
3701 }
3702 };
3703 msg.as_ptr()
3704 }));
3705 result.unwrap_or(c"Unknown error".as_ptr())
3706}
3707
3708struct MultiHandle {
3712 multi: liburlx::Multi,
3713 easy_handles: Vec<*mut c_void>,
3714 msg_queue: Vec<CURLMsg>,
3716 socket_callback: Option<CurlSocketCallback>,
3718 socket_data: *mut c_void,
3720 timer_callback: Option<CurlTimerCallback>,
3722 timer_data: *mut c_void,
3724}
3725
3726#[allow(clippy::non_send_fields_in_send_ty)]
3730unsafe impl Send for MultiHandle {}
3731
3732#[no_mangle]
3738pub extern "C" fn curl_multi_init() -> *mut c_void {
3739 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3740 let handle = Box::new(MultiHandle {
3741 multi: liburlx::Multi::new(),
3742 easy_handles: Vec::new(),
3743 msg_queue: Vec::new(),
3744 socket_callback: None,
3745 socket_data: ptr::null_mut(),
3746 timer_callback: None,
3747 timer_data: ptr::null_mut(),
3748 });
3749 Box::into_raw(handle).cast::<c_void>()
3750 }));
3751 result.unwrap_or(ptr::null_mut())
3752}
3753
3754#[no_mangle]
3760pub unsafe extern "C" fn curl_multi_cleanup(handle: *mut c_void) -> CURLMcode {
3761 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3762 if handle.is_null() {
3763 return CURLMcode::CURLM_BAD_HANDLE;
3764 }
3765 let _ = unsafe { Box::from_raw(handle.cast::<MultiHandle>()) };
3767 CURLMcode::CURLM_OK
3768 }));
3769 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
3770}
3771
3772#[no_mangle]
3778pub unsafe extern "C" fn curl_multi_add_handle(multi: *mut c_void, easy: *mut c_void) -> CURLMcode {
3779 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3780 if multi.is_null() {
3781 return CURLMcode::CURLM_BAD_HANDLE;
3782 }
3783 if easy.is_null() {
3784 return CURLMcode::CURLM_BAD_EASY_HANDLE;
3785 }
3786
3787 let m = unsafe { &mut *multi.cast::<MultiHandle>() };
3789 let e = unsafe { &*easy.cast::<EasyHandle>() };
3790
3791 m.multi.add(e.easy.clone());
3792 m.easy_handles.push(easy);
3793
3794 CURLMcode::CURLM_OK
3795 }));
3796 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
3797}
3798
3799#[no_mangle]
3805pub unsafe extern "C" fn curl_multi_remove_handle(
3806 multi: *mut c_void,
3807 easy: *mut c_void,
3808) -> CURLMcode {
3809 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3810 if multi.is_null() {
3811 return CURLMcode::CURLM_BAD_HANDLE;
3812 }
3813 if easy.is_null() {
3814 return CURLMcode::CURLM_BAD_EASY_HANDLE;
3815 }
3816
3817 let m = unsafe { &mut *multi.cast::<MultiHandle>() };
3819
3820 if let Some(pos) = m.easy_handles.iter().position(|&h| h == easy) {
3821 let _ = m.easy_handles.remove(pos);
3822 let _ = m.multi.remove(pos);
3823 CURLMcode::CURLM_OK
3824 } else {
3825 CURLMcode::CURLM_BAD_EASY_HANDLE
3826 }
3827 }));
3828 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
3829}
3830
3831#[no_mangle]
3838pub unsafe extern "C" fn curl_multi_perform(
3839 multi: *mut c_void,
3840 running_handles: *mut c_long,
3841) -> CURLMcode {
3842 let outer = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3843 if multi.is_null() {
3844 return CURLMcode::CURLM_BAD_HANDLE;
3845 }
3846
3847 let m = unsafe { &mut *multi.cast::<MultiHandle>() };
3849
3850 let easy_ptrs: Vec<*mut c_void> = m.easy_handles.clone();
3852
3853 let result = m.multi.perform_blocking();
3854
3855 match result {
3856 Ok(results) => {
3857 m.msg_queue.clear();
3859
3860 for (i, result) in results.into_iter().enumerate() {
3862 if i < easy_ptrs.len() {
3863 let eh = unsafe { &mut *easy_ptrs[i].cast::<EasyHandle>() };
3865 let curl_result = match result {
3866 Ok(response) => {
3867 eh.last_response = Some(response);
3868 CURLcode::CURLE_OK
3869 }
3870 Err(e) => {
3871 let code = error_to_curlcode(&e);
3872 let msg = e.to_string();
3873 let bytes = msg.as_bytes();
3874 let len = bytes.len().min(eh.error_buf.len() - 1);
3875 eh.error_buf[..len].copy_from_slice(&bytes[..len]);
3876 eh.error_buf[len] = 0;
3877 code
3878 }
3879 };
3880
3881 m.msg_queue.push(CURLMsg {
3882 msg: CURLMSG::CURLMSG_DONE,
3883 easy_handle: easy_ptrs[i],
3884 result: curl_result,
3885 });
3886 }
3887 }
3888
3889 if !running_handles.is_null() {
3890 unsafe {
3892 *running_handles = 0;
3893 } }
3895
3896 CURLMcode::CURLM_OK
3897 }
3898 Err(_) => CURLMcode::CURLM_INTERNAL_ERROR,
3899 }
3900 }));
3901 outer.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
3902}
3903
3904#[no_mangle]
3916pub unsafe extern "C" fn curl_multi_info_read(
3917 multi: *mut c_void,
3918 msgs_in_queue: *mut c_long,
3919) -> *const CURLMsg {
3920 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3921 if multi.is_null() {
3922 if !msgs_in_queue.is_null() {
3923 unsafe {
3925 *msgs_in_queue = 0;
3926 }
3927 }
3928 return ptr::null();
3929 }
3930
3931 let m = unsafe { &mut *multi.cast::<MultiHandle>() };
3933
3934 if m.msg_queue.is_empty() {
3935 if !msgs_in_queue.is_null() {
3936 unsafe {
3938 *msgs_in_queue = 0;
3939 }
3940 }
3941 return ptr::null();
3942 }
3943
3944 let msg = m.msg_queue.remove(0);
3948
3949 if !msgs_in_queue.is_null() {
3951 unsafe {
3953 #[allow(clippy::cast_possible_wrap)]
3954 {
3955 *msgs_in_queue = m.msg_queue.len() as c_long;
3956 }
3957 }
3958 }
3959
3960 m.msg_queue.push(msg);
3963 let last_idx = m.msg_queue.len() - 1;
3964 &raw const m.msg_queue[last_idx]
3965 }));
3966 result.unwrap_or(ptr::null::<CURLMsg>())
3967}
3968
3969#[no_mangle]
3976pub unsafe extern "C" fn curl_multi_setopt(
3977 multi: *mut c_void,
3978 option: c_long,
3979 value: *const c_void,
3980) -> CURLMcode {
3981 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
3982 if multi.is_null() {
3983 return CURLMcode::CURLM_BAD_HANDLE;
3984 }
3985
3986 let m = unsafe { &mut *multi.cast::<MultiHandle>() };
3988
3989 match option {
3990 3 => {
3992 let val = value as c_long;
3993 if val == 0 {
3994 m.multi.pipelining(liburlx::PipeliningMode::Nothing);
3995 } else {
3996 m.multi.pipelining(liburlx::PipeliningMode::Multiplex);
3997 }
3998 CURLMcode::CURLM_OK
3999 }
4000 6 | 13 => {
4002 let val = value as usize;
4003 if val > 0 {
4004 m.multi.max_total_connections(val);
4005 }
4006 CURLMcode::CURLM_OK
4007 }
4008 7 => {
4010 let val = value as usize;
4011 if val > 0 {
4012 m.multi.max_host_connections(val);
4013 }
4014 CURLMcode::CURLM_OK
4015 }
4016 10002 => {
4018 m.socket_data = value.cast_mut();
4019 CURLMcode::CURLM_OK
4020 }
4021 10005 => {
4023 m.timer_data = value.cast_mut();
4024 CURLMcode::CURLM_OK
4025 }
4026 20001 => {
4028 if value.is_null() {
4029 m.socket_callback = None;
4030 } else {
4031 m.socket_callback = Some(unsafe {
4033 std::mem::transmute::<*const c_void, CurlSocketCallback>(value)
4034 });
4035 }
4036 CURLMcode::CURLM_OK
4037 }
4038 20004 => {
4040 if value.is_null() {
4041 m.timer_callback = None;
4042 } else {
4043 m.timer_callback = Some(unsafe {
4045 std::mem::transmute::<*const c_void, CurlTimerCallback>(value)
4046 });
4047 }
4048 CURLMcode::CURLM_OK
4049 }
4050 _ => CURLMcode::CURLM_UNKNOWN_OPTION,
4051 }
4052 }));
4053 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
4054}
4055
4056#[no_mangle]
4066pub unsafe extern "C" fn curl_multi_timeout(
4067 multi: *mut c_void,
4068 timeout_ms: *mut c_long,
4069) -> CURLMcode {
4070 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4071 if multi.is_null() {
4072 return CURLMcode::CURLM_BAD_HANDLE;
4073 }
4074 if timeout_ms.is_null() {
4075 return CURLMcode::CURLM_BAD_HANDLE;
4076 }
4077
4078 let m = unsafe { &*multi.cast::<MultiHandle>() };
4083
4084 unsafe {
4086 if m.msg_queue.is_empty() && m.easy_handles.is_empty() {
4087 *timeout_ms = -1; } else if !m.msg_queue.is_empty() {
4089 *timeout_ms = 0; } else {
4091 *timeout_ms = 100; }
4093 }
4094
4095 CURLMcode::CURLM_OK
4096 }));
4097 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
4098}
4099
4100#[no_mangle]
4111pub unsafe extern "C" fn curl_multi_wait(
4112 multi: *mut c_void,
4113 _extra_fds: *mut curl_waitfd,
4114 _extra_nfds: c_long,
4115 timeout_ms: c_long,
4116 numfds: *mut c_long,
4117) -> CURLMcode {
4118 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4119 if multi.is_null() {
4120 return CURLMcode::CURLM_BAD_HANDLE;
4121 }
4122
4123 #[allow(clippy::cast_sign_loss)]
4126 let ms = if timeout_ms <= 0 { 100 } else { timeout_ms as u64 };
4127 std::thread::sleep(std::time::Duration::from_millis(ms));
4128
4129 if !numfds.is_null() {
4130 unsafe {
4132 *numfds = 0;
4133 }
4134 }
4135
4136 CURLMcode::CURLM_OK
4137 }));
4138 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
4139}
4140
4141#[no_mangle]
4150pub unsafe extern "C" fn curl_multi_poll(
4151 multi: *mut c_void,
4152 fds: *mut curl_waitfd,
4153 nfds: c_long,
4154 timeout_ms: c_long,
4155 numfds: *mut c_long,
4156) -> CURLMcode {
4157 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4158 unsafe { curl_multi_wait(multi, fds, nfds, timeout_ms, numfds) }
4160 }));
4161 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
4162}
4163
4164#[no_mangle]
4172pub unsafe extern "C" fn curl_multi_wakeup(multi: *mut c_void) -> CURLMcode {
4173 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4174 if multi.is_null() {
4175 return CURLMcode::CURLM_BAD_HANDLE;
4176 }
4177 CURLMcode::CURLM_OK
4179 }));
4180 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
4181}
4182
4183#[no_mangle]
4194pub unsafe extern "C" fn curl_multi_fdset(
4195 multi: *mut c_void,
4196 _read_fd_set: *mut c_void,
4197 _write_fd_set: *mut c_void,
4198 _exc_fd_set: *mut c_void,
4199 max_fd: *mut c_long,
4200) -> CURLMcode {
4201 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4202 if multi.is_null() {
4203 return CURLMcode::CURLM_BAD_HANDLE;
4204 }
4205
4206 if !max_fd.is_null() {
4207 unsafe {
4209 *max_fd = -1; }
4211 }
4212
4213 CURLMcode::CURLM_OK
4214 }));
4215 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
4216}
4217
4218#[no_mangle]
4229pub unsafe extern "C" fn curl_multi_socket_action(
4230 multi: *mut c_void,
4231 sockfd: c_long,
4232 _ev_bitmask: c_long,
4233 running_handles: *mut c_long,
4234) -> CURLMcode {
4235 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4236 if multi.is_null() {
4237 return CURLMcode::CURLM_BAD_HANDLE;
4238 }
4239
4240 if sockfd == -1 {
4242 return unsafe { curl_multi_perform(multi, running_handles) };
4245 }
4246
4247 if !running_handles.is_null() {
4249 let m = unsafe { &*multi.cast::<MultiHandle>() };
4251 unsafe {
4253 #[allow(clippy::cast_possible_wrap)]
4254 {
4255 *running_handles = m.easy_handles.len() as c_long;
4256 }
4257 }
4258 }
4259
4260 CURLMcode::CURLM_OK
4261 }));
4262 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
4263}
4264
4265#[no_mangle]
4271#[allow(clippy::missing_const_for_fn)]
4272pub extern "C" fn curl_multi_strerror(code: CURLMcode) -> *const c_char {
4273 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4274 let msg = match code {
4275 CURLMcode::CURLM_OK => c"No error",
4276 CURLMcode::CURLM_BAD_HANDLE => c"Invalid multi handle",
4277 CURLMcode::CURLM_BAD_EASY_HANDLE => c"Invalid easy handle",
4278 CURLMcode::CURLM_OUT_OF_MEMORY => c"Out of memory",
4279 CURLMcode::CURLM_INTERNAL_ERROR => c"Internal error",
4280 CURLMcode::CURLM_UNKNOWN_OPTION => c"Unknown option",
4281 };
4282 msg.as_ptr()
4283 }));
4284 result.unwrap_or(c"Unknown error".as_ptr())
4285}
4286
4287#[no_mangle]
4299pub unsafe extern "C" fn curl_escape(string: *const c_char, length: c_long) -> *mut c_char {
4300 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4301 if string.is_null() {
4302 return ptr::null_mut();
4303 }
4304
4305 let input = if length == 0 {
4306 unsafe { CStr::from_ptr(string) }.to_bytes()
4308 } else {
4309 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
4310 unsafe {
4312 std::slice::from_raw_parts(string.cast::<u8>(), length as usize)
4313 }
4314 };
4315
4316 let encoded = percent_encode(input);
4317
4318 std::ffi::CString::new(encoded).map_or(ptr::null_mut(), std::ffi::CString::into_raw)
4319 }));
4320 result.unwrap_or(ptr::null_mut())
4321}
4322
4323#[no_mangle]
4334pub unsafe extern "C" fn curl_unescape(
4335 string: *const c_char,
4336 length: c_long,
4337 outlength: *mut c_long,
4338) -> *mut c_char {
4339 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4340 if string.is_null() {
4341 return ptr::null_mut();
4342 }
4343
4344 let input = if length == 0 {
4345 unsafe { CStr::from_ptr(string) }.to_bytes()
4347 } else {
4348 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
4349 unsafe {
4351 std::slice::from_raw_parts(string.cast::<u8>(), length as usize)
4352 }
4353 };
4354
4355 let decoded = percent_decode(input);
4356
4357 if !outlength.is_null() {
4358 unsafe {
4360 #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
4361 {
4362 *outlength = decoded.len() as c_long;
4363 }
4364 }
4365 }
4366
4367 std::ffi::CString::new(decoded).map_or(ptr::null_mut(), std::ffi::CString::into_raw)
4368 }));
4369 result.unwrap_or(ptr::null_mut())
4370}
4371
4372#[no_mangle]
4382pub unsafe extern "C" fn curl_easy_escape(
4383 _handle: *mut c_void,
4384 string: *const c_char,
4385 length: c_long,
4386) -> *mut c_char {
4387 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4388 unsafe { curl_escape(string, length) }
4390 }));
4391 result.unwrap_or(ptr::null_mut())
4392}
4393
4394#[no_mangle]
4405pub unsafe extern "C" fn curl_easy_unescape(
4406 _handle: *mut c_void,
4407 string: *const c_char,
4408 inlength: c_long,
4409 outlength: *mut c_long,
4410) -> *mut c_char {
4411 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4412 unsafe { curl_unescape(string, inlength, outlength) }
4414 }));
4415 result.unwrap_or(ptr::null_mut())
4416}
4417
4418#[no_mangle]
4428pub unsafe extern "C" fn curl_getdate(datestring: *const c_char, _now: *const c_void) -> i64 {
4429 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4430 if datestring.is_null() {
4431 return -1;
4432 }
4433
4434 let Ok(s) = unsafe { CStr::from_ptr(datestring) }.to_str() else {
4436 return -1;
4437 };
4438
4439 parse_http_date(s).unwrap_or(-1)
4440 }));
4441 result.unwrap_or(-1)
4442}
4443
4444#[no_mangle]
4453#[allow(clippy::missing_const_for_fn)]
4454pub unsafe extern "C" fn curl_formadd(_first: *mut *mut c_void, _last: *mut *mut c_void) -> c_long {
4455 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4456 7 }));
4458 result.unwrap_or(7) }
4460
4461#[no_mangle]
4469#[allow(clippy::missing_const_for_fn)]
4470pub unsafe extern "C" fn curl_formfree(_form: *mut c_void) {
4471 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4472 }));
4474}
4475
4476fn percent_encode(input: &[u8]) -> String {
4478 let mut result = String::with_capacity(input.len());
4479 for &byte in input {
4480 if byte.is_ascii_alphanumeric()
4481 || byte == b'-'
4482 || byte == b'_'
4483 || byte == b'.'
4484 || byte == b'~'
4485 {
4486 result.push(char::from(byte));
4487 } else {
4488 result.push('%');
4489 result.push(char::from(HEX_UPPER[usize::from(byte >> 4)]));
4490 result.push(char::from(HEX_UPPER[usize::from(byte & 0x0F)]));
4491 }
4492 }
4493 result
4494}
4495
4496const HEX_UPPER: [u8; 16] = *b"0123456789ABCDEF";
4498
4499fn percent_decode(input: &[u8]) -> Vec<u8> {
4501 let mut result = Vec::with_capacity(input.len());
4502 let mut i = 0;
4503 while i < input.len() {
4504 if input[i] == b'%' && i + 2 < input.len() {
4505 if let (Some(hi), Some(lo)) = (hex_val(input[i + 1]), hex_val(input[i + 2])) {
4506 result.push(hi << 4 | lo);
4507 i += 3;
4508 continue;
4509 }
4510 } else if input[i] == b'+' {
4511 result.push(b' ');
4512 i += 1;
4513 continue;
4514 }
4515 result.push(input[i]);
4516 i += 1;
4517 }
4518 result
4519}
4520
4521const fn hex_val(byte: u8) -> Option<u8> {
4523 match byte {
4524 b'0'..=b'9' => Some(byte - b'0'),
4525 b'a'..=b'f' => Some(byte - b'a' + 10),
4526 b'A'..=b'F' => Some(byte - b'A' + 10),
4527 _ => None,
4528 }
4529}
4530
4531fn parse_http_date(s: &str) -> Option<i64> {
4538 let s = s.trim();
4539
4540 if let Some(ts) = parse_rfc2822(s) {
4542 return Some(ts);
4543 }
4544
4545 if let Some(ts) = parse_rfc850(s) {
4547 return Some(ts);
4548 }
4549
4550 parse_asctime(s)
4552}
4553
4554fn month_from_name(name: &str) -> Option<u32> {
4556 match name {
4557 "Jan" => Some(0),
4558 "Feb" => Some(1),
4559 "Mar" => Some(2),
4560 "Apr" => Some(3),
4561 "May" => Some(4),
4562 "Jun" => Some(5),
4563 "Jul" => Some(6),
4564 "Aug" => Some(7),
4565 "Sep" => Some(8),
4566 "Oct" => Some(9),
4567 "Nov" => Some(10),
4568 "Dec" => Some(11),
4569 _ => None,
4570 }
4571}
4572
4573const DAYS_IN_MONTH: [u32; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
4575
4576const fn is_leap_year(year: i64) -> bool {
4578 (year % 4 == 0 && year % 100 != 0) || year % 400 == 0
4579}
4580
4581fn date_to_timestamp(year: i64, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> i64 {
4583 let mut days: i64 = 0;
4585 if year >= 1970 {
4586 for y in 1970..year {
4587 days += if is_leap_year(y) { 366 } else { 365 };
4588 }
4589 } else {
4590 for y in year..1970 {
4591 days -= if is_leap_year(y) { 366 } else { 365 };
4592 }
4593 }
4594
4595 for m in 0..month {
4597 days += i64::from(DAYS_IN_MONTH[m as usize]);
4598 if m == 1 && is_leap_year(year) {
4599 days += 1;
4600 }
4601 }
4602
4603 days += i64::from(day) - 1;
4605
4606 days * 86400 + i64::from(hour) * 3600 + i64::from(min) * 60 + i64::from(sec)
4607}
4608
4609fn parse_rfc2822(s: &str) -> Option<i64> {
4611 let s = s.find(", ").map_or(s, |pos| &s[pos + 2..]);
4613 let parts: Vec<&str> = s.split_whitespace().collect();
4614 if parts.len() < 4 {
4615 return None;
4616 }
4617
4618 let day: u32 = parts[0].parse().ok()?;
4619 let month = month_from_name(parts[1])?;
4620 let year: i64 = parts[2].parse().ok()?;
4621 let time_parts: Vec<&str> = parts[3].split(':').collect();
4622 if time_parts.len() != 3 {
4623 return None;
4624 }
4625 let hour: u32 = time_parts[0].parse().ok()?;
4626 let min: u32 = time_parts[1].parse().ok()?;
4627 let sec: u32 = time_parts[2].parse().ok()?;
4628
4629 Some(date_to_timestamp(year, month, day, hour, min, sec))
4630}
4631
4632fn parse_rfc850(s: &str) -> Option<i64> {
4634 let pos = s.find(", ")?;
4635 let s = &s[pos + 2..];
4636 let parts: Vec<&str> = s.split_whitespace().collect();
4637 if parts.len() < 2 {
4638 return None;
4639 }
4640
4641 let date_parts: Vec<&str> = parts[0].split('-').collect();
4643 if date_parts.len() != 3 {
4644 return None;
4645 }
4646 let day: u32 = date_parts[0].parse().ok()?;
4647 let month = month_from_name(date_parts[1])?;
4648 let mut year: i64 = date_parts[2].parse().ok()?;
4649 if year < 100 {
4650 year += if year < 70 { 2000 } else { 1900 };
4651 }
4652
4653 let time_parts: Vec<&str> = parts[1].split(':').collect();
4654 if time_parts.len() != 3 {
4655 return None;
4656 }
4657 let hour: u32 = time_parts[0].parse().ok()?;
4658 let min: u32 = time_parts[1].parse().ok()?;
4659 let sec: u32 = time_parts[2].parse().ok()?;
4660
4661 Some(date_to_timestamp(year, month, day, hour, min, sec))
4662}
4663
4664fn parse_asctime(s: &str) -> Option<i64> {
4666 let parts: Vec<&str> = s.split_whitespace().collect();
4667 if parts.len() < 5 {
4668 return None;
4669 }
4670
4671 let month = month_from_name(parts[1])?;
4673 let day: u32 = parts[2].parse().ok()?;
4674 let time_parts: Vec<&str> = parts[3].split(':').collect();
4675 if time_parts.len() != 3 {
4676 return None;
4677 }
4678 let hour: u32 = time_parts[0].parse().ok()?;
4679 let min: u32 = time_parts[1].parse().ok()?;
4680 let sec: u32 = time_parts[2].parse().ok()?;
4681 let year: i64 = parts[4].parse().ok()?;
4682
4683 Some(date_to_timestamp(year, month, day, hour, min, sec))
4684}
4685
4686#[no_mangle]
4694#[allow(clippy::missing_const_for_fn)]
4695pub extern "C" fn curl_version() -> *const c_char {
4696 let result =
4697 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| c"liburlx/0.1.0".as_ptr()));
4698 result.unwrap_or(c"liburlx/unknown".as_ptr())
4699}
4700
4701#[no_mangle]
4707#[allow(clippy::missing_const_for_fn)]
4708pub extern "C" fn urlx_version() -> *const c_char {
4709 let result =
4710 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| c"liburlx/0.1.0".as_ptr()));
4711 result.unwrap_or(c"liburlx/unknown".as_ptr())
4712}
4713
4714#[no_mangle]
4725#[allow(clippy::missing_const_for_fn)] pub extern "C" fn curl_global_init(_flags: c_long) -> CURLcode {
4727 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| CURLcode::CURLE_OK));
4728 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
4729}
4730
4731#[no_mangle]
4737#[allow(clippy::missing_const_for_fn)] pub extern "C" fn curl_global_cleanup() {
4739 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {}));
4740}
4741
4742pub const CURL_GLOBAL_SSL: c_long = 1;
4745pub const CURL_GLOBAL_WIN32: c_long = 2;
4747pub const CURL_GLOBAL_ALL: c_long = 3;
4749pub const CURL_GLOBAL_DEFAULT: c_long = 3;
4751
4752#[repr(C)]
4759pub struct CurlVersionInfo {
4760 pub age: c_long,
4762 pub version: *const c_char,
4764 pub version_num: c_long,
4766 pub host: *const c_char,
4768 pub features: c_long,
4770 pub ssl_version: *const c_char,
4772 pub ssl_version_num: c_long,
4774 pub libz_version: *const c_char,
4776 pub protocols: *const *const c_char,
4778}
4779
4780unsafe impl Sync for CurlVersionInfo {}
4783
4784pub const CURL_VERSION_SSL: c_long = 1 << 2;
4786pub const CURL_VERSION_HTTP2: c_long = 1 << 16;
4788pub const CURL_VERSION_ASYNCHDNS: c_long = 1 << 7;
4790pub const CURL_VERSION_PSL: c_long = 1 << 20;
4792
4793#[no_mangle]
4802pub extern "C" fn curl_version_info(_age: c_long) -> *const CurlVersionInfo {
4803 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4804 static INFO: std::sync::OnceLock<&'static CurlVersionInfo> = std::sync::OnceLock::new();
4806 let info = INFO.get_or_init(|| {
4807 let protocols: &'static [*const c_char] = Box::leak(Box::new([
4809 c"http".as_ptr(),
4810 c"https".as_ptr(),
4811 c"ftp".as_ptr(),
4812 c"ftps".as_ptr(),
4813 c"sftp".as_ptr(),
4814 c"scp".as_ptr(),
4815 c"ws".as_ptr(),
4816 c"wss".as_ptr(),
4817 ptr::null(), ]));
4819 Box::leak(Box::new(CurlVersionInfo {
4820 age: 0,
4821 version: c"0.1.0".as_ptr(),
4822 version_num: 0x000_100, host: c"urlx".as_ptr(),
4824 features: CURL_VERSION_SSL | CURL_VERSION_HTTP2 | CURL_VERSION_PSL,
4825 ssl_version: c"rustls/0.23".as_ptr(),
4826 ssl_version_num: 0,
4827 libz_version: ptr::null(),
4828 protocols: protocols.as_ptr(),
4829 }))
4830 });
4831 std::ptr::from_ref::<CurlVersionInfo>(info)
4832 }));
4833 result.unwrap_or(ptr::null::<CurlVersionInfo>())
4834}
4835
4836#[no_mangle]
4842#[allow(clippy::missing_const_for_fn)] pub extern "C" fn curl_easy_pause(_handle: *mut c_void, _bitmask: c_long) -> CURLcode {
4844 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
4845 CURLcode::CURLE_OK
4847 }));
4848 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
4849}
4850
4851pub const CURLPAUSE_RECV: c_long = 1;
4854pub const CURLPAUSE_SEND: c_long = 4;
4856pub const CURLPAUSE_ALL: c_long = 5;
4858pub const CURLPAUSE_CONT: c_long = 0;
4860
4861#[no_mangle]
4867#[allow(clippy::missing_const_for_fn)] pub extern "C" fn curl_easy_upkeep(_handle: *mut c_void) -> CURLcode {
4869 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| CURLcode::CURLE_OK));
4870 result.unwrap_or(CURLcode::CURLE_UNKNOWN_OPTION)
4871}
4872
4873#[no_mangle]
4879#[allow(clippy::missing_const_for_fn)] pub extern "C" fn curl_multi_assign(
4881 _multi_handle: *mut c_void,
4882 _sockfd: c_long,
4883 _sockp: *mut c_void,
4884) -> CURLMcode {
4885 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| CURLMcode::CURLM_OK));
4886 result.unwrap_or(CURLMcode::CURLM_INTERNAL_ERROR)
4887}
4888
4889fn error_to_curlcode(err: &liburlx::Error) -> CURLcode {
4893 match err {
4894 liburlx::Error::UrlParse(_) => CURLcode::CURLE_URL_MALFORMAT,
4895 liburlx::Error::Connect(_) => CURLcode::CURLE_COULDNT_CONNECT,
4896 liburlx::Error::Tls(_) => CURLcode::CURLE_SSL_CONNECT_ERROR,
4897 liburlx::Error::Http(msg) => {
4898 if msg.contains("unsupported scheme") {
4899 CURLcode::CURLE_UNSUPPORTED_PROTOCOL
4900 } else if msg.contains("resolve") || msg.contains("DNS") {
4901 CURLcode::CURLE_COULDNT_RESOLVE_HOST
4902 } else if msg.contains("HTTP error") && msg.contains("fail_on_error") {
4903 CURLcode::CURLE_HTTP_RETURNED_ERROR
4904 } else if msg.contains("aborted by") || msg.contains("callback") {
4905 CURLcode::CURLE_ABORTED_BY_CALLBACK
4906 } else if msg.contains("FTP") {
4907 CURLcode::CURLE_FTP_WEIRD_SERVER_REPLY
4908 } else {
4909 CURLcode::CURLE_RECV_ERROR
4910 }
4911 }
4912 liburlx::Error::Timeout(_) | liburlx::Error::SpeedLimit { .. } => {
4913 CURLcode::CURLE_OPERATION_TIMEDOUT
4914 }
4915 liburlx::Error::RtspCseqError(_) => CURLcode::CURLE_RTSP_CSEQ_ERROR,
4916 liburlx::Error::RtspSessionError(_) => CURLcode::CURLE_RTSP_SESSION_ERROR,
4917 liburlx::Error::Transfer { code, .. } => match *code {
4918 8 => CURLcode::CURLE_FTP_WEIRD_SERVER_REPLY,
4919 43 => CURLcode::CURLE_BAD_FUNCTION_ARGUMENT,
4920 85 => CURLcode::CURLE_RTSP_CSEQ_ERROR,
4921 86 => CURLcode::CURLE_RTSP_SESSION_ERROR,
4922 _ => CURLcode::CURLE_RECV_ERROR,
4923 },
4924 _ => CURLcode::CURLE_RECV_ERROR,
4925 }
4926}
4927
4928#[cfg(test)]
4931#[allow(clippy::unwrap_used)]
4932mod tests {
4933 use super::*;
4934
4935 #[test]
4936 fn version_returns_non_null() {
4937 let ptr = urlx_version();
4938 assert!(!ptr.is_null());
4939 }
4940
4941 #[test]
4942 fn curl_version_returns_non_null() {
4943 let ptr = curl_version();
4944 assert!(!ptr.is_null());
4945 }
4946
4947 #[test]
4948 fn easy_init_cleanup() {
4949 let handle = curl_easy_init();
4950 assert!(!handle.is_null());
4951 unsafe { curl_easy_cleanup(handle) };
4952 }
4953
4954 #[test]
4955 fn easy_cleanup_null_is_safe() {
4956 unsafe { curl_easy_cleanup(ptr::null_mut()) };
4957 }
4958
4959 #[test]
4960 fn easy_setopt_url() {
4961 let handle = curl_easy_init();
4962 let url = c"http://example.com";
4963 let code = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
4964 assert_eq!(code, CURLcode::CURLE_OK);
4965 unsafe { curl_easy_cleanup(handle) };
4966 }
4967
4968 #[test]
4969 fn easy_setopt_invalid_url() {
4970 let handle = curl_easy_init();
4971 let url = c"";
4972 let code = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
4973 assert_eq!(code, CURLcode::CURLE_URL_MALFORMAT);
4974 unsafe { curl_easy_cleanup(handle) };
4975 }
4976
4977 #[test]
4978 fn easy_setopt_null_url() {
4979 let handle = curl_easy_init();
4980 let code = unsafe { curl_easy_setopt(handle, 10002, ptr::null()) };
4981 assert_eq!(code, CURLcode::CURLE_URL_MALFORMAT);
4982 unsafe { curl_easy_cleanup(handle) };
4983 }
4984
4985 #[test]
4986 fn easy_setopt_verbose() {
4987 let handle = curl_easy_init();
4988 let code = unsafe { curl_easy_setopt(handle, 41, std::ptr::dangling::<c_void>()) };
4989 assert_eq!(code, CURLcode::CURLE_OK);
4990 unsafe { curl_easy_cleanup(handle) };
4991 }
4992
4993 #[test]
4994 fn easy_setopt_follow_redirects() {
4995 let handle = curl_easy_init();
4996 let code = unsafe { curl_easy_setopt(handle, 52, std::ptr::dangling::<c_void>()) };
4997 assert_eq!(code, CURLcode::CURLE_OK);
4998 unsafe { curl_easy_cleanup(handle) };
4999 }
5000
5001 #[test]
5002 fn easy_setopt_timeout() {
5003 let handle = curl_easy_init();
5004 let code = unsafe { curl_easy_setopt(handle, 13, 30 as *const c_void) };
5005 assert_eq!(code, CURLcode::CURLE_OK);
5006 unsafe { curl_easy_cleanup(handle) };
5007 }
5008
5009 #[test]
5010 fn easy_setopt_unknown_option() {
5011 let handle = curl_easy_init();
5012 let code = unsafe { curl_easy_setopt(handle, 99999, ptr::null()) };
5013 assert_eq!(code, CURLcode::CURLE_UNKNOWN_OPTION);
5014 unsafe { curl_easy_cleanup(handle) };
5015 }
5016
5017 #[test]
5018 fn easy_setopt_null_handle() {
5019 let code = unsafe { curl_easy_setopt(ptr::null_mut(), 10002, ptr::null()) };
5020 assert_eq!(code, CURLcode::CURLE_FAILED_INIT);
5021 }
5022
5023 #[test]
5024 fn easy_perform_without_url() {
5025 let handle = curl_easy_init();
5026 let code = unsafe { curl_easy_perform(handle) };
5027 assert_ne!(code, CURLcode::CURLE_OK);
5028 unsafe { curl_easy_cleanup(handle) };
5029 }
5030
5031 #[test]
5032 fn easy_perform_null_handle() {
5033 let code = unsafe { curl_easy_perform(ptr::null_mut()) };
5034 assert_eq!(code, CURLcode::CURLE_FAILED_INIT);
5035 }
5036
5037 #[test]
5038 fn easy_getinfo_null_handle() {
5039 let mut code: c_long = 0;
5040 let out_ptr = ptr::from_mut(&mut code).cast::<c_void>();
5041 let result = unsafe { curl_easy_getinfo(ptr::null_mut(), 0x20_0002, out_ptr) };
5042 assert_eq!(result, CURLcode::CURLE_FAILED_INIT);
5043 }
5044
5045 #[test]
5046 fn easy_getinfo_no_response() {
5047 let handle = curl_easy_init();
5048 let url = c"http://example.com";
5049 let _code = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
5050
5051 let mut code: c_long = 0;
5052 let out_ptr = ptr::from_mut(&mut code).cast::<c_void>();
5053 let result = unsafe { curl_easy_getinfo(handle, 0x20_0002, out_ptr) };
5054 assert_eq!(result, CURLcode::CURLE_GOT_NOTHING);
5055 unsafe { curl_easy_cleanup(handle) };
5056 }
5057
5058 #[test]
5059 fn easy_strerror_ok() {
5060 let msg = curl_easy_strerror(CURLcode::CURLE_OK);
5061 assert!(!msg.is_null());
5062 let s = unsafe { CStr::from_ptr(msg) };
5063 assert_eq!(s.to_str().unwrap(), "No error");
5064 }
5065
5066 #[test]
5067 fn easy_strerror_timeout() {
5068 let msg = curl_easy_strerror(CURLcode::CURLE_OPERATION_TIMEDOUT);
5069 let s = unsafe { CStr::from_ptr(msg) };
5070 assert_eq!(s.to_str().unwrap(), "Operation timed out");
5071 }
5072
5073 #[test]
5074 fn easy_strerror_all_codes() {
5075 let codes = [
5077 CURLcode::CURLE_OK,
5078 CURLcode::CURLE_UNSUPPORTED_PROTOCOL,
5079 CURLcode::CURLE_FAILED_INIT,
5080 CURLcode::CURLE_URL_MALFORMAT,
5081 CURLcode::CURLE_COULDNT_RESOLVE_PROXY,
5082 CURLcode::CURLE_COULDNT_RESOLVE_HOST,
5083 CURLcode::CURLE_COULDNT_CONNECT,
5084 CURLcode::CURLE_FTP_WEIRD_SERVER_REPLY,
5085 CURLcode::CURLE_REMOTE_ACCESS_DENIED,
5086 CURLcode::CURLE_HTTP2,
5087 CURLcode::CURLE_HTTP_RETURNED_ERROR,
5088 CURLcode::CURLE_WRITE_ERROR,
5089 CURLcode::CURLE_READ_ERROR,
5090 CURLcode::CURLE_OUT_OF_MEMORY,
5091 CURLcode::CURLE_OPERATION_TIMEDOUT,
5092 CURLcode::CURLE_SSL_CONNECT_ERROR,
5093 CURLcode::CURLE_ABORTED_BY_CALLBACK,
5094 CURLcode::CURLE_BAD_FUNCTION_ARGUMENT,
5095 CURLcode::CURLE_UNKNOWN_OPTION,
5096 CURLcode::CURLE_GOT_NOTHING,
5097 CURLcode::CURLE_SEND_ERROR,
5098 CURLcode::CURLE_RECV_ERROR,
5099 CURLcode::CURLE_SSL_CERTPROBLEM,
5100 CURLcode::CURLE_PEER_FAILED_VERIFICATION,
5101 CURLcode::CURLE_LOGIN_DENIED,
5102 ];
5103 for code in codes {
5104 let msg = curl_easy_strerror(code);
5105 assert!(!msg.is_null(), "strerror returned null for {code:?}");
5106 }
5107 }
5108
5109 #[test]
5110 fn easy_setopt_custom_request() {
5111 let handle = curl_easy_init();
5112 let method = c"DELETE";
5113 let code = unsafe { curl_easy_setopt(handle, 10036, method.as_ptr().cast::<c_void>()) };
5114 assert_eq!(code, CURLcode::CURLE_OK);
5115 unsafe { curl_easy_cleanup(handle) };
5116 }
5117
5118 #[test]
5119 fn easy_setopt_nobody() {
5120 let handle = curl_easy_init();
5121 let code = unsafe { curl_easy_setopt(handle, 44, std::ptr::dangling::<c_void>()) };
5122 assert_eq!(code, CURLcode::CURLE_OK);
5123 unsafe { curl_easy_cleanup(handle) };
5124 }
5125
5126 #[test]
5127 fn easy_setopt_postfields() {
5128 let handle = curl_easy_init();
5129 let data = c"key=value";
5130 let code = unsafe { curl_easy_setopt(handle, 10015, data.as_ptr().cast::<c_void>()) };
5131 assert_eq!(code, CURLcode::CURLE_OK);
5132 unsafe { curl_easy_cleanup(handle) };
5133 }
5134
5135 #[test]
5136 fn easy_setopt_proxy() {
5137 let handle = curl_easy_init();
5138 let proxy = c"http://proxy:8080";
5139 let code = unsafe { curl_easy_setopt(handle, 10004, proxy.as_ptr().cast::<c_void>()) };
5140 assert_eq!(code, CURLcode::CURLE_OK);
5141 unsafe { curl_easy_cleanup(handle) };
5142 }
5143
5144 #[test]
5145 fn easy_setopt_userpwd() {
5146 let handle = curl_easy_init();
5147 let up = c"user:pass";
5148 let code = unsafe { curl_easy_setopt(handle, 10005, up.as_ptr().cast::<c_void>()) };
5149 assert_eq!(code, CURLcode::CURLE_OK);
5150 unsafe { curl_easy_cleanup(handle) };
5151 }
5152
5153 #[test]
5154 fn easy_setopt_ssl_verify() {
5155 let handle = curl_easy_init();
5156 let code = unsafe { curl_easy_setopt(handle, 64, ptr::null()) };
5158 assert_eq!(code, CURLcode::CURLE_OK);
5159 let code = unsafe { curl_easy_setopt(handle, 81, 2 as *const c_void) };
5161 assert_eq!(code, CURLcode::CURLE_OK);
5162 unsafe { curl_easy_cleanup(handle) };
5163 }
5164
5165 #[test]
5166 fn easy_setopt_tcp_options() {
5167 let handle = curl_easy_init();
5168 let code = unsafe { curl_easy_setopt(handle, 121, std::ptr::dangling::<c_void>()) };
5170 assert_eq!(code, CURLcode::CURLE_OK);
5171 let code = unsafe { curl_easy_setopt(handle, 213, std::ptr::dangling::<c_void>()) };
5173 assert_eq!(code, CURLcode::CURLE_OK);
5174 unsafe { curl_easy_cleanup(handle) };
5175 }
5176
5177 #[test]
5178 fn easy_setopt_fail_on_error() {
5179 let handle = curl_easy_init();
5180 let code = unsafe { curl_easy_setopt(handle, 45, std::ptr::dangling::<c_void>()) };
5181 assert_eq!(code, CURLcode::CURLE_OK);
5182 unsafe { curl_easy_cleanup(handle) };
5183 }
5184
5185 #[test]
5186 fn easy_setopt_accept_encoding() {
5187 let handle = curl_easy_init();
5188 let enc = c"gzip, deflate";
5189 let code = unsafe { curl_easy_setopt(handle, 10102, enc.as_ptr().cast::<c_void>()) };
5190 assert_eq!(code, CURLcode::CURLE_OK);
5191 unsafe { curl_easy_cleanup(handle) };
5192 }
5193
5194 #[test]
5195 fn easy_setopt_range() {
5196 let handle = curl_easy_init();
5197 let range = c"0-99";
5198 let code = unsafe { curl_easy_setopt(handle, 10007, range.as_ptr().cast::<c_void>()) };
5199 assert_eq!(code, CURLcode::CURLE_OK);
5200 unsafe { curl_easy_cleanup(handle) };
5201 }
5202
5203 #[test]
5204 fn easy_setopt_httpget() {
5205 let handle = curl_easy_init();
5206 let code = unsafe { curl_easy_setopt(handle, 80, std::ptr::dangling::<c_void>()) };
5207 assert_eq!(code, CURLcode::CURLE_OK);
5208 unsafe { curl_easy_cleanup(handle) };
5209 }
5210
5211 #[test]
5212 fn easy_setopt_upload() {
5213 let handle = curl_easy_init();
5214 let code = unsafe { curl_easy_setopt(handle, 46, std::ptr::dangling::<c_void>()) };
5215 assert_eq!(code, CURLcode::CURLE_OK);
5216 unsafe { curl_easy_cleanup(handle) };
5217 }
5218
5219 #[test]
5220 fn easy_setopt_sslversion() {
5221 let handle = curl_easy_init();
5222 let code = unsafe { curl_easy_setopt(handle, 32, 6 as *const c_void) };
5224 assert_eq!(code, CURLcode::CURLE_OK);
5225 unsafe { curl_easy_cleanup(handle) };
5226 }
5227
5228 #[test]
5229 fn easy_duphandle() {
5230 let handle = curl_easy_init();
5231 let url = c"http://example.com";
5232 let _ = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
5233
5234 let dup = unsafe { curl_easy_duphandle(handle) };
5235 assert!(!dup.is_null());
5236 assert_ne!(dup, handle);
5237
5238 unsafe {
5239 curl_easy_cleanup(dup);
5240 curl_easy_cleanup(handle);
5241 }
5242 }
5243
5244 #[test]
5245 fn easy_duphandle_null() {
5246 let dup = unsafe { curl_easy_duphandle(ptr::null_mut()) };
5247 assert!(dup.is_null());
5248 }
5249
5250 #[test]
5251 fn easy_reset() {
5252 let handle = curl_easy_init();
5253 let url = c"http://example.com";
5254 let _ = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
5255 unsafe { curl_easy_reset(handle) };
5256 let code = unsafe { curl_easy_perform(handle) };
5258 assert_ne!(code, CURLcode::CURLE_OK);
5259 unsafe { curl_easy_cleanup(handle) };
5260 }
5261
5262 #[test]
5263 fn slist_append_and_free() {
5264 let list = unsafe { curl_slist_append(ptr::null_mut(), c"Header1: value1".as_ptr()) };
5265 assert!(!list.is_null());
5266
5267 let list = unsafe { curl_slist_append(list, c"Header2: value2".as_ptr()) };
5268 assert!(!list.is_null());
5269
5270 let first = unsafe { CStr::from_ptr((*list).data) };
5272 assert_eq!(first.to_str().unwrap(), "Header1: value1");
5273
5274 let second = unsafe { CStr::from_ptr((*(*list).next).data) };
5276 assert_eq!(second.to_str().unwrap(), "Header2: value2");
5277
5278 unsafe { curl_slist_free_all(list) };
5279 }
5280
5281 #[test]
5282 fn slist_free_null_is_safe() {
5283 unsafe { curl_slist_free_all(ptr::null_mut()) };
5284 }
5285
5286 #[test]
5287 fn slist_append_null_data() {
5288 let list = unsafe { curl_slist_append(ptr::null_mut(), ptr::null()) };
5289 assert!(list.is_null());
5290 }
5291
5292 #[test]
5293 fn multi_init_cleanup() {
5294 let handle = curl_multi_init();
5295 assert!(!handle.is_null());
5296 let code = unsafe { curl_multi_cleanup(handle) };
5297 assert_eq!(code, CURLMcode::CURLM_OK);
5298 }
5299
5300 #[test]
5301 fn multi_cleanup_null() {
5302 let code = unsafe { curl_multi_cleanup(ptr::null_mut()) };
5303 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
5304 }
5305
5306 #[test]
5307 fn multi_add_remove_handle() {
5308 let multi = curl_multi_init();
5309 let easy = curl_easy_init();
5310
5311 let code = unsafe { curl_multi_add_handle(multi, easy) };
5312 assert_eq!(code, CURLMcode::CURLM_OK);
5313
5314 let code = unsafe { curl_multi_remove_handle(multi, easy) };
5315 assert_eq!(code, CURLMcode::CURLM_OK);
5316
5317 unsafe {
5318 curl_easy_cleanup(easy);
5319 let _ = curl_multi_cleanup(multi);
5320 }
5321 }
5322
5323 #[test]
5324 fn multi_add_null_handles() {
5325 let multi = curl_multi_init();
5326 assert_eq!(
5327 unsafe { curl_multi_add_handle(ptr::null_mut(), ptr::null_mut()) },
5328 CURLMcode::CURLM_BAD_HANDLE
5329 );
5330 assert_eq!(
5331 unsafe { curl_multi_add_handle(multi, ptr::null_mut()) },
5332 CURLMcode::CURLM_BAD_EASY_HANDLE
5333 );
5334 let _ = unsafe { curl_multi_cleanup(multi) };
5335 }
5336
5337 #[test]
5338 fn multi_remove_nonexistent() {
5339 let multi = curl_multi_init();
5340 let easy = curl_easy_init();
5341
5342 let code = unsafe { curl_multi_remove_handle(multi, easy) };
5343 assert_eq!(code, CURLMcode::CURLM_BAD_EASY_HANDLE);
5344
5345 unsafe {
5346 curl_easy_cleanup(easy);
5347 let _ = curl_multi_cleanup(multi);
5348 }
5349 }
5350
5351 #[test]
5352 fn error_code_mapping() {
5353 assert_eq!(
5354 error_to_curlcode(&liburlx::Error::UrlParse("bad".to_string())),
5355 CURLcode::CURLE_URL_MALFORMAT
5356 );
5357 assert_eq!(
5358 error_to_curlcode(&liburlx::Error::Timeout(std::time::Duration::from_secs(1))),
5359 CURLcode::CURLE_OPERATION_TIMEDOUT
5360 );
5361 }
5362
5363 #[test]
5364 fn error_code_http_returned_error() {
5365 assert_eq!(
5366 error_to_curlcode(&liburlx::Error::Http(
5367 "HTTP error 404 (fail_on_error enabled)".to_string()
5368 )),
5369 CURLcode::CURLE_HTTP_RETURNED_ERROR
5370 );
5371 }
5372
5373 #[test]
5374 fn error_code_aborted_by_callback() {
5375 assert_eq!(
5376 error_to_curlcode(&liburlx::Error::Http(
5377 "transfer aborted by progress callback".to_string()
5378 )),
5379 CURLcode::CURLE_ABORTED_BY_CALLBACK
5380 );
5381 }
5382
5383 #[test]
5384 fn error_code_ftp() {
5385 assert_eq!(
5386 error_to_curlcode(&liburlx::Error::Http("FTP protocol error".to_string())),
5387 CURLcode::CURLE_FTP_WEIRD_SERVER_REPLY
5388 );
5389 }
5390
5391 #[test]
5392 fn easy_setopt_httpheader_with_slist() {
5393 let handle = curl_easy_init();
5394 let list = unsafe { curl_slist_append(ptr::null_mut(), c"X-Custom: test".as_ptr()) };
5395 let code = unsafe { curl_easy_setopt(handle, 10023, list.cast::<c_void>()) };
5396 assert_eq!(code, CURLcode::CURLE_OK);
5397 unsafe {
5398 curl_slist_free_all(list);
5399 curl_easy_cleanup(handle);
5400 }
5401 }
5402
5403 #[test]
5404 fn easy_setopt_timeout_ms() {
5405 let handle = curl_easy_init();
5406 let code = unsafe { curl_easy_setopt(handle, 155, 5000_usize as *const c_void) };
5408 assert_eq!(code, CURLcode::CURLE_OK);
5409 unsafe { curl_easy_cleanup(handle) };
5410 }
5411
5412 #[test]
5413 fn easy_setopt_connecttimeout_ms() {
5414 let handle = curl_easy_init();
5415 let code = unsafe { curl_easy_setopt(handle, 156, 3000_usize as *const c_void) };
5417 assert_eq!(code, CURLcode::CURLE_OK);
5418 unsafe { curl_easy_cleanup(handle) };
5419 }
5420
5421 #[test]
5422 fn easy_setopt_fresh_connect() {
5423 let handle = curl_easy_init();
5424 let code = unsafe { curl_easy_setopt(handle, 74, std::ptr::dangling::<c_void>()) };
5426 assert_eq!(code, CURLcode::CURLE_OK);
5427 unsafe { curl_easy_cleanup(handle) };
5428 }
5429
5430 #[test]
5431 fn easy_setopt_forbid_reuse() {
5432 let handle = curl_easy_init();
5433 let code = unsafe { curl_easy_setopt(handle, 75, std::ptr::dangling::<c_void>()) };
5435 assert_eq!(code, CURLcode::CURLE_OK);
5436 unsafe { curl_easy_cleanup(handle) };
5437 }
5438
5439 #[test]
5440 fn easy_setopt_low_speed_limit() {
5441 let handle = curl_easy_init();
5442 let code = unsafe { curl_easy_setopt(handle, 19, 1000_usize as *const c_void) };
5444 assert_eq!(code, CURLcode::CURLE_OK);
5445 unsafe { curl_easy_cleanup(handle) };
5446 }
5447
5448 #[test]
5449 fn easy_setopt_low_speed_time() {
5450 let handle = curl_easy_init();
5451 let code = unsafe { curl_easy_setopt(handle, 20, 30_usize as *const c_void) };
5453 assert_eq!(code, CURLcode::CURLE_OK);
5454 unsafe { curl_easy_cleanup(handle) };
5455 }
5456
5457 #[test]
5458 fn easy_setopt_max_send_speed() {
5459 let handle = curl_easy_init();
5460 let code = unsafe { curl_easy_setopt(handle, 30145, 1024_usize as *const c_void) };
5462 assert_eq!(code, CURLcode::CURLE_OK);
5463 unsafe { curl_easy_cleanup(handle) };
5464 }
5465
5466 #[test]
5467 fn easy_setopt_max_recv_speed() {
5468 let handle = curl_easy_init();
5469 let code = unsafe { curl_easy_setopt(handle, 30146, 2048_usize as *const c_void) };
5471 assert_eq!(code, CURLcode::CURLE_OK);
5472 unsafe { curl_easy_cleanup(handle) };
5473 }
5474
5475 #[test]
5476 fn easy_setopt_ssl_cipher_list() {
5477 let handle = curl_easy_init();
5478 let ciphers = c"HIGH:!aNULL:!MD5";
5479 let code = unsafe { curl_easy_setopt(handle, 10083, ciphers.as_ptr().cast::<c_void>()) };
5480 assert_eq!(code, CURLcode::CURLE_OK);
5481 unsafe { curl_easy_cleanup(handle) };
5482 }
5483
5484 #[test]
5485 fn easy_setopt_cookiefile() {
5486 let handle = curl_easy_init();
5487 let path = c"/tmp/cookies.txt";
5488 let code = unsafe { curl_easy_setopt(handle, 10031, path.as_ptr().cast::<c_void>()) };
5489 assert_eq!(code, CURLcode::CURLE_OK);
5490 unsafe { curl_easy_cleanup(handle) };
5491 }
5492
5493 #[test]
5494 fn easy_setopt_cookiefile_null_enables_engine() {
5495 let handle = curl_easy_init();
5496 let code = unsafe { curl_easy_setopt(handle, 10031, ptr::null()) };
5498 assert_eq!(code, CURLcode::CURLE_OK);
5499 unsafe { curl_easy_cleanup(handle) };
5500 }
5501
5502 #[test]
5503 fn easy_setopt_cookiejar() {
5504 let handle = curl_easy_init();
5505 let path = c"/tmp/cookies_out.txt";
5506 let code = unsafe { curl_easy_setopt(handle, 10082, path.as_ptr().cast::<c_void>()) };
5507 assert_eq!(code, CURLcode::CURLE_OK);
5508 unsafe { curl_easy_cleanup(handle) };
5509 }
5510
5511 #[test]
5512 fn easy_setopt_ssl_sessionid_cache() {
5513 let handle = curl_easy_init();
5514 let code = unsafe { curl_easy_setopt(handle, 150, std::ptr::dangling::<c_void>()) };
5516 assert_eq!(code, CURLcode::CURLE_OK);
5517 let code = unsafe { curl_easy_setopt(handle, 150, ptr::null()) };
5519 assert_eq!(code, CURLcode::CURLE_OK);
5520 unsafe { curl_easy_cleanup(handle) };
5521 }
5522
5523 #[test]
5524 fn easy_setopt_interface() {
5525 let handle = curl_easy_init();
5526 let iface = c"lo0";
5527 let code = unsafe { curl_easy_setopt(handle, 10062, iface.as_ptr().cast::<c_void>()) };
5528 assert_eq!(code, CURLcode::CURLE_OK);
5529 unsafe { curl_easy_cleanup(handle) };
5530 }
5531
5532 #[test]
5533 fn easy_setopt_proxyuserpwd() {
5534 let handle = curl_easy_init();
5535 let up = c"proxyuser:proxypass";
5536 let code = unsafe { curl_easy_setopt(handle, 10006, up.as_ptr().cast::<c_void>()) };
5538 assert_eq!(code, CURLcode::CURLE_OK);
5539 unsafe { curl_easy_cleanup(handle) };
5540 }
5541
5542 #[test]
5543 fn easy_setopt_proxyauth() {
5544 let handle = curl_easy_init();
5545 let code = unsafe { curl_easy_setopt(handle, 111, std::ptr::dangling::<c_void>()) };
5547 assert_eq!(code, CURLcode::CURLE_OK);
5548 unsafe { curl_easy_cleanup(handle) };
5549 }
5550
5551 #[test]
5552 fn easy_setopt_proxy_sslcert() {
5553 let handle = curl_easy_init();
5554 let path = c"/tmp/proxy-cert.pem";
5555 let code = unsafe { curl_easy_setopt(handle, 10254, path.as_ptr().cast::<c_void>()) };
5557 assert_eq!(code, CURLcode::CURLE_OK);
5558 unsafe { curl_easy_cleanup(handle) };
5559 }
5560
5561 #[test]
5562 fn easy_setopt_proxy_sslkey() {
5563 let handle = curl_easy_init();
5564 let path = c"/tmp/proxy-key.pem";
5565 let code = unsafe { curl_easy_setopt(handle, 10255, path.as_ptr().cast::<c_void>()) };
5567 assert_eq!(code, CURLcode::CURLE_OK);
5568 unsafe { curl_easy_cleanup(handle) };
5569 }
5570
5571 #[test]
5572 fn easy_setopt_proxy_ssl_verifypeer() {
5573 let handle = curl_easy_init();
5574 let code = unsafe { curl_easy_setopt(handle, 248, std::ptr::dangling::<c_void>()) };
5576 assert_eq!(code, CURLcode::CURLE_OK);
5577 unsafe { curl_easy_cleanup(handle) };
5578 }
5579
5580 unsafe extern "C" fn test_read_cb(
5581 _buf: *mut c_char,
5582 _size: usize,
5583 _nmemb: usize,
5584 _data: *mut c_void,
5585 ) -> usize {
5586 0 }
5588
5589 unsafe extern "C" fn test_debug_cb(
5590 _handle: *mut c_void,
5591 _info_type: c_long,
5592 _data: *mut c_char,
5593 _size: usize,
5594 _userdata: *mut c_void,
5595 ) -> c_long {
5596 0
5597 }
5598
5599 #[test]
5600 fn easy_setopt_readfunction() {
5601 let handle = curl_easy_init();
5602 let code = unsafe { curl_easy_setopt(handle, 20012, test_read_cb as *const c_void) };
5604 assert_eq!(code, CURLcode::CURLE_OK);
5605 unsafe { curl_easy_cleanup(handle) };
5606 }
5607
5608 #[test]
5609 fn easy_setopt_readdata() {
5610 let handle = curl_easy_init();
5611 let mut data: usize = 42;
5613 let code =
5614 unsafe { curl_easy_setopt(handle, 10009, ptr::from_mut(&mut data).cast::<c_void>()) };
5615 assert_eq!(code, CURLcode::CURLE_OK);
5616 unsafe { curl_easy_cleanup(handle) };
5617 }
5618
5619 #[test]
5620 fn easy_setopt_debugfunction() {
5621 let handle = curl_easy_init();
5622 let code = unsafe { curl_easy_setopt(handle, 20094, test_debug_cb as *const c_void) };
5624 assert_eq!(code, CURLcode::CURLE_OK);
5625 unsafe { curl_easy_cleanup(handle) };
5626 }
5627
5628 #[test]
5629 fn easy_setopt_debugdata() {
5630 let handle = curl_easy_init();
5631 let mut data: usize = 99;
5633 let code =
5634 unsafe { curl_easy_setopt(handle, 10095, ptr::from_mut(&mut data).cast::<c_void>()) };
5635 assert_eq!(code, CURLcode::CURLE_OK);
5636 unsafe { curl_easy_cleanup(handle) };
5637 }
5638
5639 #[test]
5640 fn easy_setopt_infilesize_large() {
5641 let handle = curl_easy_init();
5642 let code = unsafe { curl_easy_setopt(handle, 30115, 4096_usize as *const c_void) };
5644 assert_eq!(code, CURLcode::CURLE_OK);
5645 unsafe { curl_easy_cleanup(handle) };
5646 }
5647
5648 #[test]
5649 fn easy_duphandle_preserves_callbacks() {
5650 let handle = curl_easy_init();
5651 let _ = unsafe { curl_easy_setopt(handle, 20012, test_read_cb as *const c_void) };
5652 let _ = unsafe { curl_easy_setopt(handle, 20094, test_debug_cb as *const c_void) };
5653 let _ = unsafe { curl_easy_setopt(handle, 30115, 1024_usize as *const c_void) };
5654
5655 let dup = unsafe { curl_easy_duphandle(handle) };
5656 assert!(!dup.is_null());
5657
5658 let dup_h = unsafe { &*dup.cast::<EasyHandle>() };
5660 assert!(dup_h.read_callback.is_some());
5661 assert!(dup_h.debug_callback.is_some());
5662 assert_eq!(dup_h.infilesize, Some(1024));
5663
5664 unsafe {
5665 curl_easy_cleanup(dup);
5666 curl_easy_cleanup(handle);
5667 }
5668 }
5669
5670 #[test]
5671 fn easy_reset_clears_callbacks() {
5672 let handle = curl_easy_init();
5673 let _ = unsafe { curl_easy_setopt(handle, 20012, test_read_cb as *const c_void) };
5674 let _ = unsafe { curl_easy_setopt(handle, 30115, 2048_usize as *const c_void) };
5675
5676 unsafe { curl_easy_reset(handle) };
5677
5678 let h = unsafe { &*handle.cast::<EasyHandle>() };
5679 assert!(h.read_callback.is_none());
5680 assert!(h.debug_callback.is_none());
5681 assert!(h.infilesize.is_none());
5682
5683 unsafe { curl_easy_cleanup(handle) };
5684 }
5685
5686 #[test]
5687 fn easy_setopt_dns_cache_timeout() {
5688 let handle = curl_easy_init();
5689 let code = unsafe { curl_easy_setopt(handle, 92, 120_usize as *const c_void) };
5691 assert_eq!(code, CURLcode::CURLE_OK);
5692 unsafe { curl_easy_cleanup(handle) };
5693 }
5694
5695 #[test]
5696 fn easy_setopt_happy_eyeballs_timeout() {
5697 let handle = curl_easy_init();
5698 let code = unsafe { curl_easy_setopt(handle, 271, 100_usize as *const c_void) };
5700 assert_eq!(code, CURLcode::CURLE_OK);
5701 unsafe { curl_easy_cleanup(handle) };
5702 }
5703
5704 #[test]
5705 fn easy_setopt_dns_servers() {
5706 let handle = curl_easy_init();
5707 let servers = c"8.8.8.8,8.8.4.4";
5709 let code = unsafe { curl_easy_setopt(handle, 10211, servers.as_ptr().cast::<c_void>()) };
5710 assert_eq!(code, CURLcode::CURLE_OK);
5711 unsafe { curl_easy_cleanup(handle) };
5712 }
5713
5714 #[test]
5715 fn easy_setopt_dns_servers_invalid() {
5716 let handle = curl_easy_init();
5717 let servers = c"not-valid";
5718 let code = unsafe { curl_easy_setopt(handle, 10211, servers.as_ptr().cast::<c_void>()) };
5719 assert_eq!(code, CURLcode::CURLE_BAD_FUNCTION_ARGUMENT);
5720 unsafe { curl_easy_cleanup(handle) };
5721 }
5722
5723 #[test]
5724 fn easy_setopt_doh_url() {
5725 let handle = curl_easy_init();
5726 let url = c"https://dns.google/dns-query";
5728 let code = unsafe { curl_easy_setopt(handle, 10279, url.as_ptr().cast::<c_void>()) };
5729 assert_eq!(code, CURLcode::CURLE_OK);
5730 unsafe { curl_easy_cleanup(handle) };
5731 }
5732
5733 #[test]
5734 fn easy_setopt_unrestricted_auth() {
5735 let handle = curl_easy_init();
5736 let code = unsafe { curl_easy_setopt(handle, 105, std::ptr::dangling::<c_void>()) };
5738 assert_eq!(code, CURLcode::CURLE_OK);
5739 unsafe { curl_easy_cleanup(handle) };
5740 }
5741
5742 #[test]
5743 fn easy_setopt_ignore_content_length() {
5744 let handle = curl_easy_init();
5745 let code = unsafe { curl_easy_setopt(handle, 136, std::ptr::dangling::<c_void>()) };
5747 assert_eq!(code, CURLcode::CURLE_OK);
5748 unsafe { curl_easy_cleanup(handle) };
5749 }
5750
5751 unsafe extern "C" fn test_progress_cb(
5754 _clientp: *mut c_void,
5755 _dltotal: f64,
5756 _dlnow: f64,
5757 _ultotal: f64,
5758 _ulnow: f64,
5759 ) -> c_long {
5760 0 }
5762
5763 unsafe extern "C" fn test_xferinfo_cb(
5764 _clientp: *mut c_void,
5765 _dltotal: i64,
5766 _dlnow: i64,
5767 _ultotal: i64,
5768 _ulnow: i64,
5769 ) -> c_long {
5770 0 }
5772
5773 unsafe extern "C" fn test_seek_cb(
5774 _clientp: *mut c_void,
5775 _offset: i64,
5776 _origin: c_long,
5777 ) -> c_long {
5778 0 }
5780
5781 #[test]
5782 fn easy_setopt_progressfunction() {
5783 let handle = curl_easy_init();
5784 let code = unsafe { curl_easy_setopt(handle, 20056, test_progress_cb as *const c_void) };
5786 assert_eq!(code, CURLcode::CURLE_OK);
5787 unsafe { curl_easy_cleanup(handle) };
5788 }
5789
5790 #[test]
5791 fn easy_setopt_xferinfofunction() {
5792 let handle = curl_easy_init();
5793 let code = unsafe { curl_easy_setopt(handle, 20219, test_xferinfo_cb as *const c_void) };
5795 assert_eq!(code, CURLcode::CURLE_OK);
5796 unsafe { curl_easy_cleanup(handle) };
5797 }
5798
5799 #[test]
5800 fn easy_setopt_progressdata() {
5801 let handle = curl_easy_init();
5802 let mut data: usize = 42;
5804 let code =
5805 unsafe { curl_easy_setopt(handle, 10057, ptr::from_mut(&mut data).cast::<c_void>()) };
5806 assert_eq!(code, CURLcode::CURLE_OK);
5807 unsafe { curl_easy_cleanup(handle) };
5808 }
5809
5810 #[test]
5811 fn easy_setopt_noprogress() {
5812 let handle = curl_easy_init();
5813 let h = unsafe { &*handle.cast::<EasyHandle>() };
5815 assert!(h.noprogress);
5816
5817 let code = unsafe { curl_easy_setopt(handle, 43, ptr::null()) };
5819 assert_eq!(code, CURLcode::CURLE_OK);
5820 let h = unsafe { &*handle.cast::<EasyHandle>() };
5821 assert!(!h.noprogress);
5822
5823 let code = unsafe { curl_easy_setopt(handle, 43, std::ptr::dangling::<c_void>()) };
5825 assert_eq!(code, CURLcode::CURLE_OK);
5826 let h = unsafe { &*handle.cast::<EasyHandle>() };
5827 assert!(h.noprogress);
5828
5829 unsafe { curl_easy_cleanup(handle) };
5830 }
5831
5832 #[test]
5833 fn easy_setopt_seekfunction() {
5834 let handle = curl_easy_init();
5835 let code = unsafe { curl_easy_setopt(handle, 20167, test_seek_cb as *const c_void) };
5837 assert_eq!(code, CURLcode::CURLE_OK);
5838 unsafe { curl_easy_cleanup(handle) };
5839 }
5840
5841 #[test]
5842 fn easy_setopt_seekdata() {
5843 let handle = curl_easy_init();
5844 let mut data: usize = 99;
5846 let code =
5847 unsafe { curl_easy_setopt(handle, 10168, ptr::from_mut(&mut data).cast::<c_void>()) };
5848 assert_eq!(code, CURLcode::CURLE_OK);
5849 unsafe { curl_easy_cleanup(handle) };
5850 }
5851
5852 #[test]
5855 fn easy_setopt_private() {
5856 let handle = curl_easy_init();
5857 let mut data: usize = 12345;
5858 let code =
5860 unsafe { curl_easy_setopt(handle, 10103, ptr::from_mut(&mut data).cast::<c_void>()) };
5861 assert_eq!(code, CURLcode::CURLE_OK);
5862
5863 let mut out: *mut c_void = ptr::null_mut();
5865 let result = unsafe {
5866 curl_easy_getinfo(handle, 0x10_0015, ptr::from_mut(&mut out).cast::<c_void>())
5867 };
5868 assert_eq!(result, CURLcode::CURLE_OK);
5869 assert_eq!(out, ptr::from_mut(&mut data).cast::<c_void>());
5870
5871 unsafe { curl_easy_cleanup(handle) };
5872 }
5873
5874 #[test]
5875 fn easy_getinfo_private_default_null() {
5876 let handle = curl_easy_init();
5877 let mut out: *mut c_void = std::ptr::dangling_mut::<c_void>();
5878 let result = unsafe {
5880 curl_easy_getinfo(handle, 0x10_0015, ptr::from_mut(&mut out).cast::<c_void>())
5881 };
5882 assert_eq!(result, CURLcode::CURLE_OK);
5883 assert!(out.is_null());
5884 unsafe { curl_easy_cleanup(handle) };
5885 }
5886
5887 #[test]
5890 fn easy_setopt_share() {
5891 let handle = curl_easy_init();
5892 let share = curl_share_init();
5893
5894 let code = unsafe { curl_easy_setopt(handle, 10100, share.cast::<c_void>()) };
5896 assert_eq!(code, CURLcode::CURLE_OK);
5897
5898 let code = unsafe { curl_easy_setopt(handle, 10100, ptr::null()) };
5900 assert_eq!(code, CURLcode::CURLE_OK);
5901
5902 unsafe {
5903 let _ = curl_share_cleanup(share);
5904 curl_easy_cleanup(handle);
5905 }
5906 }
5907
5908 #[test]
5911 fn mime_init_free() {
5912 let handle = curl_easy_init();
5913 let mime = unsafe { curl_mime_init(handle) };
5914 assert!(!mime.is_null());
5915 unsafe {
5916 curl_mime_free(mime);
5917 curl_easy_cleanup(handle);
5918 }
5919 }
5920
5921 #[test]
5922 fn mime_free_null_is_safe() {
5923 unsafe { curl_mime_free(ptr::null_mut()) };
5924 }
5925
5926 #[test]
5927 fn mime_addpart() {
5928 let handle = curl_easy_init();
5929 let mime = unsafe { curl_mime_init(handle) };
5930 let part = unsafe { curl_mime_addpart(mime) };
5931 assert!(!part.is_null());
5932 unsafe {
5934 let code = curl_mime_name(part, c"field1".as_ptr());
5936 assert_eq!(code, CURLcode::CURLE_OK);
5937 let code = curl_mime_data(part, c"value1".as_ptr(), usize::MAX);
5938 assert_eq!(code, CURLcode::CURLE_OK);
5939 finalize_mime_part(mime, part);
5941 curl_mime_free(mime);
5942 curl_easy_cleanup(handle);
5943 }
5944 }
5945
5946 #[test]
5947 fn mime_name_null_part() {
5948 let code = unsafe { curl_mime_name(ptr::null_mut(), c"test".as_ptr()) };
5949 assert_eq!(code, CURLcode::CURLE_BAD_FUNCTION_ARGUMENT);
5950 }
5951
5952 #[test]
5953 fn mime_data_null_part() {
5954 let code = unsafe { curl_mime_data(ptr::null_mut(), c"test".as_ptr(), 4) };
5955 assert_eq!(code, CURLcode::CURLE_BAD_FUNCTION_ARGUMENT);
5956 }
5957
5958 #[test]
5959 fn mime_data_with_explicit_size() {
5960 let handle = curl_easy_init();
5961 let mime = unsafe { curl_mime_init(handle) };
5962 let part = unsafe { curl_mime_addpart(mime) };
5963 let code = unsafe { curl_mime_name(part, c"binary".as_ptr()) };
5964 assert_eq!(code, CURLcode::CURLE_OK);
5965 let data = b"hello";
5966 let code = unsafe { curl_mime_data(part, data.as_ptr().cast::<c_char>(), 5) };
5967 assert_eq!(code, CURLcode::CURLE_OK);
5968 unsafe {
5969 finalize_mime_part(mime, part);
5970 curl_mime_free(mime);
5971 curl_easy_cleanup(handle);
5972 }
5973 }
5974
5975 #[test]
5976 fn mime_filename() {
5977 let handle = curl_easy_init();
5978 let mime = unsafe { curl_mime_init(handle) };
5979 let part = unsafe { curl_mime_addpart(mime) };
5980 let code = unsafe { curl_mime_filename(part, c"upload.txt".as_ptr()) };
5981 assert_eq!(code, CURLcode::CURLE_OK);
5982 let code = unsafe { curl_mime_filename(ptr::null_mut(), c"test".as_ptr()) };
5983 assert_eq!(code, CURLcode::CURLE_BAD_FUNCTION_ARGUMENT);
5984 unsafe {
5985 let _ = Box::from_raw(part.cast::<MimePartHandle>());
5987 curl_mime_free(mime);
5988 curl_easy_cleanup(handle);
5989 }
5990 }
5991
5992 #[test]
5993 fn mime_type() {
5994 let handle = curl_easy_init();
5995 let mime = unsafe { curl_mime_init(handle) };
5996 let part = unsafe { curl_mime_addpart(mime) };
5997 let code = unsafe { curl_mime_type(part, c"text/plain".as_ptr()) };
5998 assert_eq!(code, CURLcode::CURLE_OK);
5999 let p = unsafe { &*part.cast::<MimePartHandle>() };
6000 assert_eq!(p.mime_type.as_deref(), Some("text/plain"));
6001 unsafe {
6002 let _ = Box::from_raw(part.cast::<MimePartHandle>());
6003 curl_mime_free(mime);
6004 curl_easy_cleanup(handle);
6005 }
6006 }
6007
6008 #[test]
6009 fn mime_type_null_part() {
6010 let code = unsafe { curl_mime_type(ptr::null_mut(), c"text/plain".as_ptr()) };
6011 assert_eq!(code, CURLcode::CURLE_BAD_FUNCTION_ARGUMENT);
6012 }
6013
6014 #[test]
6015 fn easy_setopt_mimepost() {
6016 let handle = curl_easy_init();
6017 let mime = unsafe { curl_mime_init(handle) };
6018 let part = unsafe { curl_mime_addpart(mime) };
6019 let _ = unsafe { curl_mime_name(part, c"field".as_ptr()) };
6020 let _ = unsafe { curl_mime_data(part, c"value".as_ptr(), usize::MAX) };
6021 unsafe { finalize_mime_part(mime, part) };
6022
6023 let code = unsafe { curl_easy_setopt(handle, 10269, mime.cast::<c_void>()) };
6025 assert_eq!(code, CURLcode::CURLE_OK);
6026
6027 unsafe {
6028 curl_mime_free(mime);
6029 curl_easy_cleanup(handle);
6030 }
6031 }
6032
6033 #[test]
6036 fn share_init_cleanup() {
6037 let share = curl_share_init();
6038 assert!(!share.is_null());
6039 let code = unsafe { curl_share_cleanup(share) };
6040 assert_eq!(code, CURLSHcode::CURLSHE_OK);
6041 }
6042
6043 #[test]
6044 fn share_cleanup_null() {
6045 let code = unsafe { curl_share_cleanup(ptr::null_mut()) };
6046 assert_eq!(code, CURLSHcode::CURLSHE_INVALID);
6047 }
6048
6049 #[test]
6050 fn share_setopt_dns() {
6051 let share = curl_share_init();
6052 let code = unsafe { curl_share_setopt(share, 1, 3 as *const c_void) };
6054 assert_eq!(code, CURLSHcode::CURLSHE_OK);
6055 let _ = unsafe { curl_share_cleanup(share) };
6056 }
6057
6058 #[test]
6059 fn share_setopt_cookies() {
6060 let share = curl_share_init();
6061 let code = unsafe { curl_share_setopt(share, 1, 2 as *const c_void) };
6063 assert_eq!(code, CURLSHcode::CURLSHE_OK);
6064 let _ = unsafe { curl_share_cleanup(share) };
6065 }
6066
6067 #[test]
6068 fn share_setopt_unshare() {
6069 let share = curl_share_init();
6070 let _ = unsafe { curl_share_setopt(share, 1, 3 as *const c_void) };
6072 let code = unsafe { curl_share_setopt(share, 2, 3 as *const c_void) };
6074 assert_eq!(code, CURLSHcode::CURLSHE_OK);
6075 let _ = unsafe { curl_share_cleanup(share) };
6076 }
6077
6078 #[test]
6079 fn share_setopt_bad_option() {
6080 let share = curl_share_init();
6081 let code = unsafe { curl_share_setopt(share, 99, ptr::null()) };
6082 assert_eq!(code, CURLSHcode::CURLSHE_BAD_OPTION);
6083 let _ = unsafe { curl_share_cleanup(share) };
6084 }
6085
6086 #[test]
6087 fn share_setopt_null_handle() {
6088 let code = unsafe { curl_share_setopt(ptr::null_mut(), 1, 3 as *const c_void) };
6089 assert_eq!(code, CURLSHcode::CURLSHE_INVALID);
6090 }
6091
6092 #[test]
6093 fn share_setopt_lockfunc_accepted() {
6094 let share = curl_share_init();
6095 let code = unsafe { curl_share_setopt(share, 3, ptr::null()) };
6097 assert_eq!(code, CURLSHcode::CURLSHE_OK);
6098 let code = unsafe { curl_share_setopt(share, 4, ptr::null()) };
6100 assert_eq!(code, CURLSHcode::CURLSHE_OK);
6101 let _ = unsafe { curl_share_cleanup(share) };
6102 }
6103
6104 #[test]
6105 fn share_strerror_ok() {
6106 let msg = curl_share_strerror(CURLSHcode::CURLSHE_OK);
6107 assert!(!msg.is_null());
6108 let s = unsafe { CStr::from_ptr(msg) };
6109 assert_eq!(s.to_str().unwrap(), "No error");
6110 }
6111
6112 #[test]
6113 fn share_strerror_all_codes() {
6114 let codes = [
6115 CURLSHcode::CURLSHE_OK,
6116 CURLSHcode::CURLSHE_BAD_OPTION,
6117 CURLSHcode::CURLSHE_IN_USE,
6118 CURLSHcode::CURLSHE_INVALID,
6119 CURLSHcode::CURLSHE_NOMEM,
6120 CURLSHcode::CURLSHE_NOT_BUILT_IN,
6121 ];
6122 for code in codes {
6123 let msg = curl_share_strerror(code);
6124 assert!(!msg.is_null(), "share_strerror returned null for {code:?}");
6125 }
6126 }
6127
6128 #[test]
6131 fn easy_duphandle_preserves_progress_callbacks() {
6132 let handle = curl_easy_init();
6133 let _ = unsafe { curl_easy_setopt(handle, 20056, test_progress_cb as *const c_void) };
6134 let _ = unsafe { curl_easy_setopt(handle, 20219, test_xferinfo_cb as *const c_void) };
6135 let _ = unsafe { curl_easy_setopt(handle, 20167, test_seek_cb as *const c_void) };
6136 let mut priv_data: usize = 42;
6137 let _ = unsafe {
6138 curl_easy_setopt(handle, 10103, ptr::from_mut(&mut priv_data).cast::<c_void>())
6139 };
6140
6141 let dup = unsafe { curl_easy_duphandle(handle) };
6142 assert!(!dup.is_null());
6143 let dup_h = unsafe { &*dup.cast::<EasyHandle>() };
6144 assert!(dup_h.progress_callback.is_some());
6145 assert!(dup_h.xferinfo_callback.is_some());
6146 assert!(dup_h.seek_callback.is_some());
6147 assert_eq!(dup_h.private_data, ptr::from_mut(&mut priv_data).cast::<c_void>());
6148
6149 unsafe {
6150 curl_easy_cleanup(dup);
6151 curl_easy_cleanup(handle);
6152 }
6153 }
6154
6155 #[test]
6156 fn easy_reset_clears_new_fields() {
6157 let handle = curl_easy_init();
6158 let _ = unsafe { curl_easy_setopt(handle, 20056, test_progress_cb as *const c_void) };
6159 let _ = unsafe { curl_easy_setopt(handle, 20219, test_xferinfo_cb as *const c_void) };
6160 let _ = unsafe { curl_easy_setopt(handle, 20167, test_seek_cb as *const c_void) };
6161 let _ = unsafe { curl_easy_setopt(handle, 10103, 42usize as *const c_void) };
6162 let _ = unsafe { curl_easy_setopt(handle, 43, ptr::null()) }; unsafe { curl_easy_reset(handle) };
6165
6166 let h = unsafe { &*handle.cast::<EasyHandle>() };
6167 assert!(h.progress_callback.is_none());
6168 assert!(h.xferinfo_callback.is_none());
6169 assert!(h.seek_callback.is_none());
6170 assert!(h.private_data.is_null());
6171 assert!(h.noprogress); assert!(h.mimepost.is_null());
6173
6174 unsafe { curl_easy_cleanup(handle) };
6175 }
6176
6177 #[test]
6180 fn url_init_cleanup() {
6181 let handle = curl_url();
6182 assert!(!handle.is_null());
6183 unsafe { curl_url_cleanup(handle) };
6184 }
6185
6186 #[test]
6187 fn url_cleanup_null_is_safe() {
6188 unsafe { curl_url_cleanup(ptr::null_mut()) };
6189 }
6190
6191 #[test]
6192 fn url_set_full_url() {
6193 let handle = curl_url();
6194 let url = c"https://example.com/path?q=1#frag";
6195 let code = unsafe { curl_url_set(handle, 0, url.as_ptr(), 0) };
6196 assert_eq!(code, CURLUcode::CURLUE_OK);
6197
6198 let mut part: *mut c_char = ptr::null_mut();
6200 let code = unsafe { curl_url_get(handle, 1, &raw mut part, 0) };
6201 assert_eq!(code, CURLUcode::CURLUE_OK);
6202 assert!(!part.is_null());
6203 let scheme = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6204 assert_eq!(scheme, "https");
6205 unsafe { curl_free(part.cast::<c_void>()) };
6206
6207 let mut part: *mut c_char = ptr::null_mut();
6209 let code = unsafe { curl_url_get(handle, 5, &raw mut part, 0) };
6210 assert_eq!(code, CURLUcode::CURLUE_OK);
6211 let host = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6212 assert_eq!(host, "example.com");
6213 unsafe { curl_free(part.cast::<c_void>()) };
6214
6215 let mut part: *mut c_char = ptr::null_mut();
6217 let code = unsafe { curl_url_get(handle, 7, &raw mut part, 0) };
6218 assert_eq!(code, CURLUcode::CURLUE_OK);
6219 let path = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6220 assert_eq!(path, "/path");
6221 unsafe { curl_free(part.cast::<c_void>()) };
6222
6223 let mut part: *mut c_char = ptr::null_mut();
6225 let code = unsafe { curl_url_get(handle, 8, &raw mut part, 0) };
6226 assert_eq!(code, CURLUcode::CURLUE_OK);
6227 let query = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6228 assert_eq!(query, "q=1");
6229 unsafe { curl_free(part.cast::<c_void>()) };
6230
6231 let mut part: *mut c_char = ptr::null_mut();
6233 let code = unsafe { curl_url_get(handle, 9, &raw mut part, 0) };
6234 assert_eq!(code, CURLUcode::CURLUE_OK);
6235 let frag = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6236 assert_eq!(frag, "frag");
6237 unsafe { curl_free(part.cast::<c_void>()) };
6238
6239 unsafe { curl_url_cleanup(handle) };
6240 }
6241
6242 #[test]
6243 fn url_set_individual_parts() {
6244 let handle = curl_url();
6245 let _ = unsafe { curl_url_set(handle, 1, c"https".as_ptr(), 0) };
6246 let _ = unsafe { curl_url_set(handle, 5, c"example.com".as_ptr(), 0) };
6247 let _ = unsafe { curl_url_set(handle, 6, c"8080".as_ptr(), 0) };
6248 let _ = unsafe { curl_url_set(handle, 7, c"/api/v1".as_ptr(), 0) };
6249
6250 let mut part: *mut c_char = ptr::null_mut();
6252 let code = unsafe { curl_url_get(handle, 0, &raw mut part, 0) };
6253 assert_eq!(code, CURLUcode::CURLUE_OK);
6254 let url = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6255 assert_eq!(url, "https://example.com:8080/api/v1");
6256 unsafe { curl_free(part.cast::<c_void>()) };
6257
6258 unsafe { curl_url_cleanup(handle) };
6259 }
6260
6261 #[test]
6262 fn url_set_with_userinfo() {
6263 let handle = curl_url();
6264 let url = c"http://user:pass@example.com/";
6265 let _ = unsafe { curl_url_set(handle, 0, url.as_ptr(), 0) };
6266
6267 let mut part: *mut c_char = ptr::null_mut();
6268 let code = unsafe { curl_url_get(handle, 2, &raw mut part, 0) };
6269 assert_eq!(code, CURLUcode::CURLUE_OK);
6270 let user = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6271 assert_eq!(user, "user");
6272 unsafe { curl_free(part.cast::<c_void>()) };
6273
6274 let mut part: *mut c_char = ptr::null_mut();
6275 let code = unsafe { curl_url_get(handle, 3, &raw mut part, 0) };
6276 assert_eq!(code, CURLUcode::CURLUE_OK);
6277 let pass = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6278 assert_eq!(pass, "pass");
6279 unsafe { curl_free(part.cast::<c_void>()) };
6280
6281 unsafe { curl_url_cleanup(handle) };
6282 }
6283
6284 #[test]
6285 fn url_set_bad_port() {
6286 let handle = curl_url();
6287 let code = unsafe { curl_url_set(handle, 6, c"not_a_port".as_ptr(), 0) };
6288 assert_eq!(code, CURLUcode::CURLUE_BAD_PORT_NUMBER);
6289 unsafe { curl_url_cleanup(handle) };
6290 }
6291
6292 #[test]
6293 fn url_set_malformed_url() {
6294 let handle = curl_url();
6295 let code = unsafe { curl_url_set(handle, 0, c"".as_ptr(), 0) };
6296 assert_eq!(code, CURLUcode::CURLUE_MALFORMED_INPUT);
6297 unsafe { curl_url_cleanup(handle) };
6298 }
6299
6300 #[test]
6301 fn url_set_null_clears() {
6302 let handle = curl_url();
6303 let _ = unsafe { curl_url_set(handle, 0, c"https://example.com/path".as_ptr(), 0) };
6304 let code = unsafe { curl_url_set(handle, 8, ptr::null(), 0) };
6306 assert_eq!(code, CURLUcode::CURLUE_OK);
6307
6308 let mut part: *mut c_char = ptr::null_mut();
6309 let code = unsafe { curl_url_get(handle, 8, &raw mut part, 0) };
6310 assert_eq!(code, CURLUcode::CURLUE_OK);
6311 assert!(part.is_null()); unsafe { curl_url_cleanup(handle) };
6314 }
6315
6316 #[test]
6317 fn url_get_null_handle() {
6318 let mut part: *mut c_char = ptr::null_mut();
6319 let code = unsafe { curl_url_get(ptr::null_mut(), 0, &raw mut part, 0) };
6320 assert_eq!(code, CURLUcode::CURLUE_BAD_HANDLE);
6321 }
6322
6323 #[test]
6324 fn url_set_null_handle() {
6325 let code = unsafe { curl_url_set(ptr::null_mut(), 0, c"test".as_ptr(), 0) };
6326 assert_eq!(code, CURLUcode::CURLUE_BAD_HANDLE);
6327 }
6328
6329 #[test]
6330 fn url_get_unknown_part() {
6331 let handle = curl_url();
6332 let mut part: *mut c_char = ptr::null_mut();
6333 let code = unsafe { curl_url_get(handle, 99, &raw mut part, 0) };
6334 assert_eq!(code, CURLUcode::CURLUE_UNKNOWN_PART);
6335 unsafe { curl_url_cleanup(handle) };
6336 }
6337
6338 #[test]
6339 fn url_dup() {
6340 let handle = curl_url();
6341 let _ = unsafe { curl_url_set(handle, 0, c"https://example.com/path".as_ptr(), 0) };
6342
6343 let dup = unsafe { curl_url_dup(handle) };
6344 assert!(!dup.is_null());
6345
6346 let mut part: *mut c_char = ptr::null_mut();
6348 let code = unsafe { curl_url_get(dup, 1, &raw mut part, 0) };
6349 assert_eq!(code, CURLUcode::CURLUE_OK);
6350 let scheme = unsafe { CStr::from_ptr(part) }.to_str().unwrap();
6351 assert_eq!(scheme, "https");
6352 unsafe { curl_free(part.cast::<c_void>()) };
6353
6354 unsafe {
6355 curl_url_cleanup(dup);
6356 curl_url_cleanup(handle);
6357 }
6358 }
6359
6360 #[test]
6361 fn url_dup_null() {
6362 let dup = unsafe { curl_url_dup(ptr::null_mut()) };
6363 assert!(dup.is_null());
6364 }
6365
6366 #[test]
6367 fn curl_free_null_is_safe() {
6368 unsafe { curl_free(ptr::null_mut()) };
6369 }
6370
6371 #[test]
6374 fn easy_setopt_referer() {
6375 let handle = curl_easy_init();
6376 let referer = c"https://example.com/";
6377 let code = unsafe { curl_easy_setopt(handle, 10016, referer.as_ptr().cast::<c_void>()) };
6379 assert_eq!(code, CURLcode::CURLE_OK);
6380 unsafe { curl_easy_cleanup(handle) };
6381 }
6382
6383 #[test]
6384 fn easy_setopt_http_version() {
6385 let handle = curl_easy_init();
6386 let code = unsafe { curl_easy_setopt(handle, 84, 2 as *const c_void) };
6389 assert_eq!(code, CURLcode::CURLE_OK);
6390 let code = unsafe { curl_easy_setopt(handle, 84, 3 as *const c_void) };
6392 assert_eq!(code, CURLcode::CURLE_OK);
6393 unsafe { curl_easy_cleanup(handle) };
6394 }
6395
6396 #[test]
6397 fn easy_setopt_nosignal() {
6398 let handle = curl_easy_init();
6399 let code = unsafe { curl_easy_setopt(handle, 99, std::ptr::dangling::<c_void>()) };
6401 assert_eq!(code, CURLcode::CURLE_OK);
6402 unsafe { curl_easy_cleanup(handle) };
6403 }
6404
6405 #[test]
6406 fn easy_setopt_autoreferer() {
6407 let handle = curl_easy_init();
6408 let code = unsafe { curl_easy_setopt(handle, 58, std::ptr::dangling::<c_void>()) };
6410 assert_eq!(code, CURLcode::CURLE_OK);
6411 unsafe { curl_easy_cleanup(handle) };
6412 }
6413
6414 #[test]
6415 fn easy_setopt_resume_from_large() {
6416 let handle = curl_easy_init();
6417 let code = unsafe { curl_easy_setopt(handle, 30116, 1024_usize as *const c_void) };
6419 assert_eq!(code, CURLcode::CURLE_OK);
6420 unsafe { curl_easy_cleanup(handle) };
6421 }
6422
6423 #[test]
6424 fn easy_setopt_xoauth2_bearer() {
6425 let handle = curl_easy_init();
6426 let token = c"ya29.token123";
6427 let code = unsafe { curl_easy_setopt(handle, 10220, token.as_ptr().cast::<c_void>()) };
6429 assert_eq!(code, CURLcode::CURLE_OK);
6430 unsafe { curl_easy_cleanup(handle) };
6431 }
6432
6433 #[test]
6434 fn easy_setopt_localportrange() {
6435 let handle = curl_easy_init();
6436 let code = unsafe { curl_easy_setopt(handle, 164, 10_usize as *const c_void) };
6438 assert_eq!(code, CURLcode::CURLE_OK);
6439 unsafe { curl_easy_cleanup(handle) };
6440 }
6441
6442 #[test]
6445 fn multi_info_read_empty() {
6446 let multi = curl_multi_init();
6447 let mut msgs_in_queue: c_long = 99;
6448 let msg = unsafe { curl_multi_info_read(multi, &raw mut msgs_in_queue) };
6449 assert!(msg.is_null());
6450 assert_eq!(msgs_in_queue, 0);
6451 let _ = unsafe { curl_multi_cleanup(multi) };
6452 }
6453
6454 #[test]
6455 fn multi_info_read_null_handle() {
6456 let mut msgs_in_queue: c_long = 99;
6457 let msg = unsafe { curl_multi_info_read(ptr::null_mut(), &raw mut msgs_in_queue) };
6458 assert!(msg.is_null());
6459 assert_eq!(msgs_in_queue, 0);
6460 }
6461
6462 #[test]
6463 fn multi_setopt_pipelining() {
6464 let multi = curl_multi_init();
6465 let code = unsafe { curl_multi_setopt(multi, 3, 2 as *const c_void) };
6467 assert_eq!(code, CURLMcode::CURLM_OK);
6468 let m = unsafe { &*multi.cast::<MultiHandle>() };
6470 assert_eq!(m.multi.pipelining_mode(), liburlx::PipeliningMode::Multiplex);
6471
6472 let code = unsafe { curl_multi_setopt(multi, 3, ptr::null()) };
6474 assert_eq!(code, CURLMcode::CURLM_OK);
6475 let m = unsafe { &*multi.cast::<MultiHandle>() };
6476 assert_eq!(m.multi.pipelining_mode(), liburlx::PipeliningMode::Nothing);
6477
6478 let _ = unsafe { curl_multi_cleanup(multi) };
6479 }
6480
6481 #[test]
6482 fn multi_setopt_max_total_connections() {
6483 let multi = curl_multi_init();
6484 let code = unsafe { curl_multi_setopt(multi, 13, 4 as *const c_void) };
6486 assert_eq!(code, CURLMcode::CURLM_OK);
6487 let _ = unsafe { curl_multi_cleanup(multi) };
6488 }
6489
6490 #[test]
6491 fn multi_setopt_max_host_connections() {
6492 let multi = curl_multi_init();
6493 let code = unsafe { curl_multi_setopt(multi, 7, 2 as *const c_void) };
6495 assert_eq!(code, CURLMcode::CURLM_OK);
6496 let _ = unsafe { curl_multi_cleanup(multi) };
6497 }
6498
6499 #[test]
6500 fn multi_setopt_maxconnects() {
6501 let multi = curl_multi_init();
6502 let code = unsafe { curl_multi_setopt(multi, 6, 10 as *const c_void) };
6504 assert_eq!(code, CURLMcode::CURLM_OK);
6505 let _ = unsafe { curl_multi_cleanup(multi) };
6506 }
6507
6508 #[test]
6509 fn multi_setopt_unknown_option() {
6510 let multi = curl_multi_init();
6511 let code = unsafe { curl_multi_setopt(multi, 99999, ptr::null()) };
6512 assert_eq!(code, CURLMcode::CURLM_UNKNOWN_OPTION);
6513 let _ = unsafe { curl_multi_cleanup(multi) };
6514 }
6515
6516 #[test]
6517 fn multi_setopt_null_handle() {
6518 let code = unsafe { curl_multi_setopt(ptr::null_mut(), 3, ptr::null()) };
6519 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
6520 }
6521
6522 #[test]
6523 fn multi_setopt_socket_data() {
6524 let multi = curl_multi_init();
6525 let mut data: usize = 42;
6526 let code =
6528 unsafe { curl_multi_setopt(multi, 10002, ptr::from_mut(&mut data).cast::<c_void>()) };
6529 assert_eq!(code, CURLMcode::CURLM_OK);
6530 let m = unsafe { &*multi.cast::<MultiHandle>() };
6531 assert_eq!(m.socket_data, ptr::from_mut(&mut data).cast::<c_void>());
6532 let _ = unsafe { curl_multi_cleanup(multi) };
6533 }
6534
6535 #[test]
6536 fn multi_setopt_timer_data() {
6537 let multi = curl_multi_init();
6538 let mut data: usize = 99;
6539 let code =
6541 unsafe { curl_multi_setopt(multi, 10005, ptr::from_mut(&mut data).cast::<c_void>()) };
6542 assert_eq!(code, CURLMcode::CURLM_OK);
6543 let m = unsafe { &*multi.cast::<MultiHandle>() };
6544 assert_eq!(m.timer_data, ptr::from_mut(&mut data).cast::<c_void>());
6545 let _ = unsafe { curl_multi_cleanup(multi) };
6546 }
6547
6548 unsafe extern "C" fn test_socket_cb(
6549 _easy: *mut c_void,
6550 _s: c_long,
6551 _what: c_long,
6552 _userp: *mut c_void,
6553 _socketp: *mut c_void,
6554 ) -> c_long {
6555 0
6556 }
6557
6558 unsafe extern "C" fn test_timer_cb(
6559 _multi: *mut c_void,
6560 _timeout_ms: c_long,
6561 _userp: *mut c_void,
6562 ) -> c_long {
6563 0
6564 }
6565
6566 #[test]
6567 fn multi_setopt_socket_function() {
6568 let multi = curl_multi_init();
6569 let code = unsafe { curl_multi_setopt(multi, 20001, test_socket_cb as *const c_void) };
6571 assert_eq!(code, CURLMcode::CURLM_OK);
6572 let m = unsafe { &*multi.cast::<MultiHandle>() };
6573 assert!(m.socket_callback.is_some());
6574
6575 let code = unsafe { curl_multi_setopt(multi, 20001, ptr::null()) };
6577 assert_eq!(code, CURLMcode::CURLM_OK);
6578 let m = unsafe { &*multi.cast::<MultiHandle>() };
6579 assert!(m.socket_callback.is_none());
6580
6581 let _ = unsafe { curl_multi_cleanup(multi) };
6582 }
6583
6584 #[test]
6585 fn multi_setopt_timer_function() {
6586 let multi = curl_multi_init();
6587 let code = unsafe { curl_multi_setopt(multi, 20004, test_timer_cb as *const c_void) };
6589 assert_eq!(code, CURLMcode::CURLM_OK);
6590 let m = unsafe { &*multi.cast::<MultiHandle>() };
6591 assert!(m.timer_callback.is_some());
6592
6593 let code = unsafe { curl_multi_setopt(multi, 20004, ptr::null()) };
6595 assert_eq!(code, CURLMcode::CURLM_OK);
6596 let m = unsafe { &*multi.cast::<MultiHandle>() };
6597 assert!(m.timer_callback.is_none());
6598
6599 let _ = unsafe { curl_multi_cleanup(multi) };
6600 }
6601
6602 #[test]
6603 fn multi_timeout_no_work() {
6604 let multi = curl_multi_init();
6605 let mut timeout_ms: c_long = 99;
6606 let code = unsafe { curl_multi_timeout(multi, &raw mut timeout_ms) };
6607 assert_eq!(code, CURLMcode::CURLM_OK);
6608 assert_eq!(timeout_ms, -1); let _ = unsafe { curl_multi_cleanup(multi) };
6610 }
6611
6612 #[test]
6613 fn multi_timeout_null_handle() {
6614 let mut timeout_ms: c_long = 0;
6615 let code = unsafe { curl_multi_timeout(ptr::null_mut(), &raw mut timeout_ms) };
6616 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
6617 }
6618
6619 #[test]
6620 fn multi_timeout_null_output() {
6621 let multi = curl_multi_init();
6622 let code = unsafe { curl_multi_timeout(multi, ptr::null_mut()) };
6623 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
6624 let _ = unsafe { curl_multi_cleanup(multi) };
6625 }
6626
6627 #[test]
6628 fn multi_timeout_with_handles() {
6629 let multi = curl_multi_init();
6630 let easy = curl_easy_init();
6631 let url = c"http://127.0.0.1:1";
6632 let _ = unsafe { curl_easy_setopt(easy, 10002, url.as_ptr().cast::<c_void>()) };
6633 let _ = unsafe { curl_multi_add_handle(multi, easy) };
6634
6635 let mut timeout_ms: c_long = 0;
6636 let code = unsafe { curl_multi_timeout(multi, &raw mut timeout_ms) };
6637 assert_eq!(code, CURLMcode::CURLM_OK);
6638 assert_eq!(timeout_ms, 100); let _ = unsafe { curl_multi_remove_handle(multi, easy) };
6641 unsafe { curl_easy_cleanup(easy) };
6642 let _ = unsafe { curl_multi_cleanup(multi) };
6643 }
6644
6645 #[test]
6646 fn multi_wakeup() {
6647 let multi = curl_multi_init();
6648 let code = unsafe { curl_multi_wakeup(multi) };
6649 assert_eq!(code, CURLMcode::CURLM_OK);
6650 let _ = unsafe { curl_multi_cleanup(multi) };
6651 }
6652
6653 #[test]
6654 fn multi_wakeup_null() {
6655 let code = unsafe { curl_multi_wakeup(ptr::null_mut()) };
6656 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
6657 }
6658
6659 #[test]
6660 fn multi_fdset_empty() {
6661 let multi = curl_multi_init();
6662 let mut max_fd: c_long = 99;
6663 let code = unsafe {
6664 curl_multi_fdset(
6665 multi,
6666 ptr::null_mut(),
6667 ptr::null_mut(),
6668 ptr::null_mut(),
6669 &raw mut max_fd,
6670 )
6671 };
6672 assert_eq!(code, CURLMcode::CURLM_OK);
6673 assert_eq!(max_fd, -1); let _ = unsafe { curl_multi_cleanup(multi) };
6675 }
6676
6677 #[test]
6678 fn multi_fdset_null_handle() {
6679 let mut max_fd: c_long = 0;
6680 let code = unsafe {
6681 curl_multi_fdset(
6682 ptr::null_mut(),
6683 ptr::null_mut(),
6684 ptr::null_mut(),
6685 ptr::null_mut(),
6686 &raw mut max_fd,
6687 )
6688 };
6689 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
6690 }
6691
6692 #[test]
6693 fn multi_fdset_null_maxfd() {
6694 let multi = curl_multi_init();
6695 let code = unsafe {
6696 curl_multi_fdset(
6697 multi,
6698 ptr::null_mut(),
6699 ptr::null_mut(),
6700 ptr::null_mut(),
6701 ptr::null_mut(),
6702 )
6703 };
6704 assert_eq!(code, CURLMcode::CURLM_OK);
6705 let _ = unsafe { curl_multi_cleanup(multi) };
6706 }
6707
6708 #[test]
6709 fn multi_socket_action_null_handle() {
6710 let mut running: c_long = 0;
6711 let code = unsafe { curl_multi_socket_action(ptr::null_mut(), 0, 0, &raw mut running) };
6712 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
6713 }
6714
6715 #[test]
6716 fn multi_socket_action_specific_socket() {
6717 let multi = curl_multi_init();
6718 let mut running: c_long = 99;
6719 let code = unsafe { curl_multi_socket_action(multi, 5, 0, &raw mut running) };
6721 assert_eq!(code, CURLMcode::CURLM_OK);
6722 assert_eq!(running, 0);
6723 let _ = unsafe { curl_multi_cleanup(multi) };
6724 }
6725
6726 #[test]
6727 fn multi_strerror_ok() {
6728 let msg = curl_multi_strerror(CURLMcode::CURLM_OK);
6729 assert!(!msg.is_null());
6730 let s = unsafe { CStr::from_ptr(msg) };
6731 assert_eq!(s.to_str().unwrap(), "No error");
6732 }
6733
6734 #[test]
6735 fn multi_strerror_all_codes() {
6736 let codes = [
6737 CURLMcode::CURLM_OK,
6738 CURLMcode::CURLM_BAD_HANDLE,
6739 CURLMcode::CURLM_BAD_EASY_HANDLE,
6740 CURLMcode::CURLM_OUT_OF_MEMORY,
6741 CURLMcode::CURLM_INTERNAL_ERROR,
6742 CURLMcode::CURLM_UNKNOWN_OPTION,
6743 ];
6744 for code in codes {
6745 let msg = curl_multi_strerror(code);
6746 assert!(!msg.is_null(), "multi_strerror returned null for {code:?}");
6747 }
6748 }
6749
6750 #[test]
6751 fn multi_wait_null_handle() {
6752 let mut numfds: c_long = 0;
6753 let code =
6754 unsafe { curl_multi_wait(ptr::null_mut(), ptr::null_mut(), 0, 0, &raw mut numfds) };
6755 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
6756 }
6757
6758 #[test]
6759 fn multi_poll_null_handle() {
6760 let mut numfds: c_long = 0;
6761 let code =
6762 unsafe { curl_multi_poll(ptr::null_mut(), ptr::null_mut(), 0, 0, &raw mut numfds) };
6763 assert_eq!(code, CURLMcode::CURLM_BAD_HANDLE);
6764 }
6765
6766 #[test]
6769 fn curl_escape_simple() {
6770 let input = c"hello world";
6771 let result = unsafe { curl_escape(input.as_ptr(), 0) };
6772 assert!(!result.is_null());
6773 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6774 assert_eq!(s, "hello%20world");
6775 unsafe { curl_free(result.cast::<c_void>()) };
6776 }
6777
6778 #[test]
6779 fn curl_escape_with_length() {
6780 let input = c"abc123";
6781 let result = unsafe { curl_escape(input.as_ptr(), 3) };
6782 assert!(!result.is_null());
6783 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6784 assert_eq!(s, "abc"); unsafe { curl_free(result.cast::<c_void>()) };
6786 }
6787
6788 #[test]
6789 fn curl_escape_special_chars() {
6790 let input = c"key=value&foo=bar";
6791 let result = unsafe { curl_escape(input.as_ptr(), 0) };
6792 assert!(!result.is_null());
6793 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6794 assert_eq!(s, "key%3Dvalue%26foo%3Dbar");
6795 unsafe { curl_free(result.cast::<c_void>()) };
6796 }
6797
6798 #[test]
6799 fn curl_escape_null_returns_null() {
6800 let result = unsafe { curl_escape(ptr::null(), 0) };
6801 assert!(result.is_null());
6802 }
6803
6804 #[test]
6805 fn curl_escape_unreserved_chars_preserved() {
6806 let input = c"abc-_.~XYZ";
6807 let result = unsafe { curl_escape(input.as_ptr(), 0) };
6808 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6809 assert_eq!(s, "abc-_.~XYZ");
6810 unsafe { curl_free(result.cast::<c_void>()) };
6811 }
6812
6813 #[test]
6814 fn curl_unescape_simple() {
6815 let input = c"hello%20world";
6816 let mut outlen: c_long = 0;
6817 let result = unsafe { curl_unescape(input.as_ptr(), 0, &raw mut outlen) };
6818 assert!(!result.is_null());
6819 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6820 assert_eq!(s, "hello world");
6821 assert_eq!(outlen, 11);
6822 unsafe { curl_free(result.cast::<c_void>()) };
6823 }
6824
6825 #[test]
6826 fn curl_unescape_plus_to_space() {
6827 let input = c"hello+world";
6828 let result = unsafe { curl_unescape(input.as_ptr(), 0, ptr::null_mut()) };
6829 assert!(!result.is_null());
6830 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6831 assert_eq!(s, "hello world");
6832 unsafe { curl_free(result.cast::<c_void>()) };
6833 }
6834
6835 #[test]
6836 fn curl_unescape_null_returns_null() {
6837 let result = unsafe { curl_unescape(ptr::null(), 0, ptr::null_mut()) };
6838 assert!(result.is_null());
6839 }
6840
6841 #[test]
6842 fn curl_unescape_with_length() {
6843 let input = c"%41%42%43DEF";
6844 let mut outlen: c_long = 0;
6845 let result = unsafe { curl_unescape(input.as_ptr(), 9, &raw mut outlen) };
6846 assert!(!result.is_null());
6847 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6848 assert_eq!(s, "ABC");
6849 assert_eq!(outlen, 3);
6850 unsafe { curl_free(result.cast::<c_void>()) };
6851 }
6852
6853 #[test]
6854 fn curl_easy_escape_delegates() {
6855 let handle = curl_easy_init();
6856 let input = c"test value";
6857 let result = unsafe { curl_easy_escape(handle, input.as_ptr(), 0) };
6858 assert!(!result.is_null());
6859 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6860 assert_eq!(s, "test%20value");
6861 unsafe {
6862 curl_free(result.cast::<c_void>());
6863 curl_easy_cleanup(handle);
6864 }
6865 }
6866
6867 #[test]
6868 fn curl_easy_unescape_delegates() {
6869 let handle = curl_easy_init();
6870 let input = c"test%20value";
6871 let mut outlen: c_long = 0;
6872 let result = unsafe { curl_easy_unescape(handle, input.as_ptr(), 0, &raw mut outlen) };
6873 assert!(!result.is_null());
6874 let s = unsafe { CStr::from_ptr(result) }.to_str().unwrap();
6875 assert_eq!(s, "test value");
6876 assert_eq!(outlen, 10);
6877 unsafe {
6878 curl_free(result.cast::<c_void>());
6879 curl_easy_cleanup(handle);
6880 }
6881 }
6882
6883 #[test]
6884 fn curl_escape_roundtrip() {
6885 let input = c"hello world/foo?bar=baz&qux=123";
6886 let encoded = unsafe { curl_escape(input.as_ptr(), 0) };
6887 assert!(!encoded.is_null());
6888 let decoded = unsafe { curl_unescape(encoded, 0, ptr::null_mut()) };
6889 assert!(!decoded.is_null());
6890 let s = unsafe { CStr::from_ptr(decoded) }.to_str().unwrap();
6891 assert_eq!(s, "hello world/foo?bar=baz&qux=123");
6892 unsafe {
6893 curl_free(decoded.cast::<c_void>());
6894 curl_free(encoded.cast::<c_void>());
6895 }
6896 }
6897
6898 #[test]
6901 fn getdate_rfc2822() {
6902 let date = c"Sun, 06 Nov 1994 08:49:37 GMT";
6903 let ts = unsafe { curl_getdate(date.as_ptr(), ptr::null()) };
6904 assert_eq!(ts, 784_111_777);
6905 }
6906
6907 #[test]
6908 fn getdate_rfc850() {
6909 let date = c"Sunday, 06-Nov-94 08:49:37 GMT";
6910 let ts = unsafe { curl_getdate(date.as_ptr(), ptr::null()) };
6911 assert_eq!(ts, 784_111_777);
6912 }
6913
6914 #[test]
6915 fn getdate_asctime() {
6916 let date = c"Sun Nov 6 08:49:37 1994";
6917 let ts = unsafe { curl_getdate(date.as_ptr(), ptr::null()) };
6918 assert_eq!(ts, 784_111_777);
6919 }
6920
6921 #[test]
6922 fn getdate_null_returns_negative() {
6923 let ts = unsafe { curl_getdate(ptr::null(), ptr::null()) };
6924 assert_eq!(ts, -1);
6925 }
6926
6927 #[test]
6928 fn getdate_invalid_returns_negative() {
6929 let date = c"not a date";
6930 let ts = unsafe { curl_getdate(date.as_ptr(), ptr::null()) };
6931 assert_eq!(ts, -1);
6932 }
6933
6934 #[test]
6935 fn getdate_epoch() {
6936 let date = c"Thu, 01 Jan 1970 00:00:00 GMT";
6937 let ts = unsafe { curl_getdate(date.as_ptr(), ptr::null()) };
6938 assert_eq!(ts, 0);
6939 }
6940
6941 #[test]
6942 fn getdate_y2k() {
6943 let date = c"Sat, 01 Jan 2000 00:00:00 GMT";
6944 let ts = unsafe { curl_getdate(date.as_ptr(), ptr::null()) };
6945 assert_eq!(ts, 946_684_800);
6946 }
6947
6948 #[test]
6951 fn formadd_returns_disabled() {
6952 let result =
6953 unsafe { curl_formadd(ptr::null_mut::<*mut c_void>(), ptr::null_mut::<*mut c_void>()) };
6954 assert_eq!(result, 7); }
6956
6957 #[test]
6958 fn formfree_null_is_safe() {
6959 unsafe { curl_formfree(ptr::null_mut()) };
6960 }
6961
6962 #[test]
6965 fn easy_setopt_path_as_is() {
6966 let handle = curl_easy_init();
6967 let code = unsafe { curl_easy_setopt(handle, 234, std::ptr::dangling::<c_void>()) };
6969 assert_eq!(code, CURLcode::CURLE_OK);
6970 unsafe { curl_easy_cleanup(handle) };
6971 }
6972
6973 #[test]
6974 fn easy_setopt_expect_100_timeout_ms() {
6975 let handle = curl_easy_init();
6976 let code = unsafe { curl_easy_setopt(handle, 227, 1000 as *const c_void) };
6978 assert_eq!(code, CURLcode::CURLE_OK);
6979 unsafe { curl_easy_cleanup(handle) };
6980 }
6981
6982 #[test]
6983 fn easy_setopt_postredir() {
6984 let handle = curl_easy_init();
6985 let code = unsafe { curl_easy_setopt(handle, 161, 7 as *const c_void) };
6987 assert_eq!(code, CURLcode::CURLE_OK);
6988 unsafe { curl_easy_cleanup(handle) };
6989 }
6990
6991 #[test]
6992 fn easy_setopt_transfer_encoding() {
6993 let handle = curl_easy_init();
6994 let code = unsafe { curl_easy_setopt(handle, 207, std::ptr::dangling::<c_void>()) };
6996 assert_eq!(code, CURLcode::CURLE_OK);
6997 unsafe { curl_easy_cleanup(handle) };
6998 }
6999
7000 #[test]
7001 fn easy_setopt_dns_shuffle_addresses() {
7002 let handle = curl_easy_init();
7003 let code = unsafe { curl_easy_setopt(handle, 275, std::ptr::dangling::<c_void>()) };
7005 assert_eq!(code, CURLcode::CURLE_OK);
7006 unsafe { curl_easy_cleanup(handle) };
7007 }
7008
7009 #[test]
7010 fn easy_setopt_httpproxytunnel() {
7011 let handle = curl_easy_init();
7012 let code = unsafe { curl_easy_setopt(handle, 61, std::ptr::dangling::<c_void>()) };
7014 assert_eq!(code, CURLcode::CURLE_OK);
7015 unsafe { curl_easy_cleanup(handle) };
7016 }
7017
7018 #[test]
7019 fn easy_setopt_maxfilesize() {
7020 let handle = curl_easy_init();
7021 let code = unsafe { curl_easy_setopt(handle, 114, 1_048_576 as *const c_void) };
7023 assert_eq!(code, CURLcode::CURLE_OK);
7024 unsafe { curl_easy_cleanup(handle) };
7025 }
7026
7027 #[test]
7028 fn easy_setopt_maxfilesize_large() {
7029 let handle = curl_easy_init();
7030 let code = unsafe { curl_easy_setopt(handle, 30117, 1_048_576 as *const c_void) };
7032 assert_eq!(code, CURLcode::CURLE_OK);
7033 unsafe { curl_easy_cleanup(handle) };
7034 }
7035
7036 #[test]
7037 fn easy_setopt_hsts() {
7038 let handle = curl_easy_init();
7039 let path = c"/tmp/hsts.txt";
7040 let code = unsafe { curl_easy_setopt(handle, 10300, path.as_ptr().cast::<c_void>()) };
7042 assert_eq!(code, CURLcode::CURLE_OK);
7043 unsafe { curl_easy_cleanup(handle) };
7044 }
7045
7046 #[test]
7047 fn easy_setopt_cookielist() {
7048 let handle = curl_easy_init();
7049 let cmd = c"ALL";
7050 let code = unsafe { curl_easy_setopt(handle, 10135, cmd.as_ptr().cast::<c_void>()) };
7052 assert_eq!(code, CURLcode::CURLE_OK);
7053 unsafe { curl_easy_cleanup(handle) };
7054 }
7055
7056 #[test]
7057 fn easy_setopt_errorbuffer() {
7058 let handle = curl_easy_init();
7059 let mut buf = [0u8; 256];
7060 let code = unsafe {
7062 curl_easy_setopt(handle, 10010, buf.as_mut_ptr().cast::<c_void>().cast_const())
7063 };
7064 assert_eq!(code, CURLcode::CURLE_OK);
7065 unsafe { curl_easy_cleanup(handle) };
7066 }
7067
7068 #[test]
7069 fn easy_setopt_stderr() {
7070 let handle = curl_easy_init();
7071 let code = unsafe { curl_easy_setopt(handle, 10037, ptr::null()) };
7073 assert_eq!(code, CURLcode::CURLE_OK);
7074 unsafe { curl_easy_cleanup(handle) };
7075 }
7076
7077 #[test]
7078 fn easy_setopt_protocols_str() {
7079 let handle = curl_easy_init();
7080 let proto = c"http,https,ftp";
7081 let code = unsafe { curl_easy_setopt(handle, 10318, proto.as_ptr().cast::<c_void>()) };
7083 assert_eq!(code, CURLcode::CURLE_OK);
7084 unsafe { curl_easy_cleanup(handle) };
7085 }
7086
7087 #[test]
7088 fn easy_setopt_redir_protocols_str() {
7089 let handle = curl_easy_init();
7090 let proto = c"http,https";
7091 let code = unsafe { curl_easy_setopt(handle, 10319, proto.as_ptr().cast::<c_void>()) };
7093 assert_eq!(code, CURLcode::CURLE_OK);
7094 unsafe { curl_easy_cleanup(handle) };
7095 }
7096
7097 #[test]
7098 fn easy_setopt_proxy_cainfo() {
7099 let handle = curl_easy_init();
7100 let path = c"/tmp/proxy-ca.pem";
7101 let code = unsafe { curl_easy_setopt(handle, 10246, path.as_ptr().cast::<c_void>()) };
7103 assert_eq!(code, CURLcode::CURLE_OK);
7104 unsafe { curl_easy_cleanup(handle) };
7105 }
7106
7107 #[test]
7108 fn easy_setopt_proxy_ssl_verifyhost() {
7109 let handle = curl_easy_init();
7110 let code = unsafe { curl_easy_setopt(handle, 249, 2 as *const c_void) };
7112 assert_eq!(code, CURLcode::CURLE_OK);
7113 unsafe { curl_easy_cleanup(handle) };
7114 }
7115
7116 #[test]
7119 fn easy_getinfo_filetime_returns_unknown() {
7120 let handle = curl_easy_init();
7121 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7123 h.last_response = Some(liburlx::Response::new(
7124 200,
7125 std::collections::HashMap::new(),
7126 Vec::new(),
7127 "http://example.com".to_string(),
7128 ));
7129
7130 let mut val: c_long = 0;
7131 let result = unsafe {
7132 curl_easy_getinfo(handle, 0x20_000E, ptr::from_mut(&mut val).cast::<c_void>())
7133 };
7134 assert_eq!(result, CURLcode::CURLE_OK);
7135 assert_eq!(val, -1); unsafe { curl_easy_cleanup(handle) };
7138 }
7139
7140 #[test]
7141 fn easy_getinfo_content_length_download() {
7142 let handle = curl_easy_init();
7143 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7144 h.last_response = Some(liburlx::Response::new(
7145 200,
7146 std::collections::HashMap::new(),
7147 b"hello".to_vec(),
7148 "http://example.com".to_string(),
7149 ));
7150
7151 let mut val: f64 = 0.0;
7152 let result = unsafe {
7153 curl_easy_getinfo(handle, 0x30_000F, ptr::from_mut(&mut val).cast::<c_void>())
7154 };
7155 assert_eq!(result, CURLcode::CURLE_OK);
7156 assert!((val - 5.0).abs() < f64::EPSILON);
7157
7158 unsafe { curl_easy_cleanup(handle) };
7159 }
7160
7161 #[test]
7162 fn easy_getinfo_os_errno() {
7163 let handle = curl_easy_init();
7164 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7165 h.last_response = Some(liburlx::Response::new(
7166 200,
7167 std::collections::HashMap::new(),
7168 Vec::new(),
7169 "http://example.com".to_string(),
7170 ));
7171
7172 let mut val: c_long = 99;
7173 let result = unsafe {
7174 curl_easy_getinfo(handle, 0x20_0019, ptr::from_mut(&mut val).cast::<c_void>())
7175 };
7176 assert_eq!(result, CURLcode::CURLE_OK);
7177 assert_eq!(val, 0);
7178
7179 unsafe { curl_easy_cleanup(handle) };
7180 }
7181
7182 #[test]
7183 fn easy_getinfo_primary_ip() {
7184 let handle = curl_easy_init();
7185 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7186 h.last_response = Some(liburlx::Response::new(
7187 200,
7188 std::collections::HashMap::new(),
7189 Vec::new(),
7190 "http://example.com".to_string(),
7191 ));
7192
7193 let mut val: *const c_char = ptr::null();
7194 let result = unsafe {
7195 curl_easy_getinfo(handle, 0x10_0020, ptr::from_mut(&mut val).cast::<c_void>())
7196 };
7197 assert_eq!(result, CURLcode::CURLE_OK);
7198 assert!(!val.is_null());
7199
7200 unsafe { curl_easy_cleanup(handle) };
7201 }
7202
7203 #[test]
7204 fn easy_getinfo_num_connects() {
7205 let handle = curl_easy_init();
7206 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7207 h.last_response = Some(liburlx::Response::new(
7208 200,
7209 std::collections::HashMap::new(),
7210 Vec::new(),
7211 "http://example.com".to_string(),
7212 ));
7213
7214 let mut val: c_long = 0;
7215 let result = unsafe {
7216 curl_easy_getinfo(handle, 0x20_001A, ptr::from_mut(&mut val).cast::<c_void>())
7217 };
7218 assert_eq!(result, CURLcode::CURLE_OK);
7219 assert_eq!(val, 1);
7220
7221 unsafe { curl_easy_cleanup(handle) };
7222 }
7223
7224 #[test]
7225 fn easy_getinfo_local_ip() {
7226 let handle = curl_easy_init();
7227 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7228 h.last_response = Some(liburlx::Response::new(
7229 200,
7230 std::collections::HashMap::new(),
7231 Vec::new(),
7232 "http://example.com".to_string(),
7233 ));
7234
7235 let mut val: *const c_char = ptr::null();
7236 let result = unsafe {
7237 curl_easy_getinfo(handle, 0x10_0029, ptr::from_mut(&mut val).cast::<c_void>())
7238 };
7239 assert_eq!(result, CURLcode::CURLE_OK);
7240 assert!(!val.is_null());
7241
7242 unsafe { curl_easy_cleanup(handle) };
7243 }
7244
7245 #[test]
7246 fn easy_getinfo_redirect_url_none() {
7247 let handle = curl_easy_init();
7248 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7249 h.last_response = Some(liburlx::Response::new(
7250 200,
7251 std::collections::HashMap::new(),
7252 Vec::new(),
7253 "http://example.com".to_string(),
7254 ));
7255
7256 let mut val: *const c_char = std::ptr::dangling::<c_char>();
7257 let result = unsafe {
7258 curl_easy_getinfo(handle, 0x10_0031, ptr::from_mut(&mut val).cast::<c_void>())
7259 };
7260 assert_eq!(result, CURLcode::CURLE_OK);
7261 assert!(val.is_null()); unsafe { curl_easy_cleanup(handle) };
7264 }
7265
7266 #[test]
7267 fn easy_getinfo_redirect_url_present() {
7268 let handle = curl_easy_init();
7269 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7270 let mut headers = std::collections::HashMap::new();
7271 let _ = headers.insert("location".to_string(), "http://other.com/".to_string());
7272 h.last_response = Some(liburlx::Response::new(
7273 302,
7274 headers,
7275 Vec::new(),
7276 "http://example.com".to_string(),
7277 ));
7278
7279 let mut val: *const c_char = ptr::null();
7280 let result = unsafe {
7281 curl_easy_getinfo(handle, 0x10_0031, ptr::from_mut(&mut val).cast::<c_void>())
7282 };
7283 assert_eq!(result, CURLcode::CURLE_OK);
7284 assert!(!val.is_null());
7285
7286 unsafe { curl_easy_cleanup(handle) };
7287 }
7288
7289 #[test]
7290 fn easy_getinfo_condition_unmet_false() {
7291 let handle = curl_easy_init();
7292 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7293 h.last_response = Some(liburlx::Response::new(
7294 200,
7295 std::collections::HashMap::new(),
7296 Vec::new(),
7297 "http://example.com".to_string(),
7298 ));
7299
7300 let mut val: c_long = 99;
7301 let result = unsafe {
7302 curl_easy_getinfo(handle, 0x20_0035, ptr::from_mut(&mut val).cast::<c_void>())
7303 };
7304 assert_eq!(result, CURLcode::CURLE_OK);
7305 assert_eq!(val, 0);
7306
7307 unsafe { curl_easy_cleanup(handle) };
7308 }
7309
7310 #[test]
7311 fn easy_getinfo_condition_unmet_304() {
7312 let handle = curl_easy_init();
7313 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7314 h.last_response = Some(liburlx::Response::new(
7315 304,
7316 std::collections::HashMap::new(),
7317 Vec::new(),
7318 "http://example.com".to_string(),
7319 ));
7320
7321 let mut val: c_long = 0;
7322 let result = unsafe {
7323 curl_easy_getinfo(handle, 0x20_0035, ptr::from_mut(&mut val).cast::<c_void>())
7324 };
7325 assert_eq!(result, CURLcode::CURLE_OK);
7326 assert_eq!(val, 1);
7327
7328 unsafe { curl_easy_cleanup(handle) };
7329 }
7330
7331 #[test]
7332 fn easy_getinfo_local_port() {
7333 let handle = curl_easy_init();
7334 let h = unsafe { &mut *handle.cast::<EasyHandle>() };
7335 h.last_response = Some(liburlx::Response::new(
7336 200,
7337 std::collections::HashMap::new(),
7338 Vec::new(),
7339 "http://example.com".to_string(),
7340 ));
7341
7342 let mut val: c_long = 99;
7343 let result = unsafe {
7344 curl_easy_getinfo(handle, 0x20_0042, ptr::from_mut(&mut val).cast::<c_void>())
7345 };
7346 assert_eq!(result, CURLcode::CURLE_OK);
7347 assert_eq!(val, 0);
7348
7349 unsafe { curl_easy_cleanup(handle) };
7350 }
7351
7352 #[test]
7355 fn percent_encode_all_bytes() {
7356 assert_eq!(percent_encode(b"abc"), "abc");
7357 assert_eq!(percent_encode(b" "), "%20");
7358 assert_eq!(percent_encode(b"\x00"), "%00");
7359 assert_eq!(percent_encode(b"\xFF"), "%FF");
7360 assert_eq!(percent_encode(b"a b"), "a%20b");
7361 }
7362
7363 #[test]
7364 fn percent_decode_all() {
7365 assert_eq!(percent_decode(b"abc"), b"abc");
7366 assert_eq!(percent_decode(b"%20"), b" ");
7367 assert_eq!(percent_decode(b"a+b"), b"a b");
7368 assert_eq!(percent_decode(b"%00"), b"\x00");
7369 assert_eq!(percent_decode(b"%FF"), b"\xFF");
7370 assert_eq!(percent_decode(b"%2f"), b"/"); }
7372
7373 #[test]
7374 fn percent_decode_invalid_hex() {
7375 assert_eq!(percent_decode(b"%ZZ"), b"%ZZ");
7377 assert_eq!(percent_decode(b"%2"), b"%2"); }
7379
7380 #[test]
7381 fn date_parsing_internal() {
7382 assert_eq!(month_from_name("Jan"), Some(0));
7384 assert_eq!(month_from_name("Dec"), Some(11));
7385 assert_eq!(month_from_name("Bad"), None);
7386
7387 assert!(is_leap_year(2000));
7388 assert!(!is_leap_year(1900));
7389 assert!(is_leap_year(2004));
7390 assert!(!is_leap_year(2001));
7391
7392 assert_eq!(date_to_timestamp(1970, 0, 1, 0, 0, 0), 0);
7394 assert_eq!(date_to_timestamp(1970, 0, 2, 0, 0, 0), 86400);
7396 }
7397
7398 #[test]
7401 fn global_init_cleanup() {
7402 let code = curl_global_init(CURL_GLOBAL_ALL);
7403 assert_eq!(code, CURLcode::CURLE_OK);
7404 curl_global_cleanup();
7405 }
7406
7407 #[test]
7408 fn global_init_default() {
7409 let code = curl_global_init(CURL_GLOBAL_DEFAULT);
7410 assert_eq!(code, CURLcode::CURLE_OK);
7411 }
7412
7413 #[test]
7414 fn version_info_returns_valid() {
7415 let info = curl_version_info(0);
7416 assert!(!info.is_null());
7417 let info = unsafe { &*info };
7419 assert_eq!(info.age, 0);
7420 assert!(!info.version.is_null());
7421 assert_ne!(info.features & CURL_VERSION_SSL, 0);
7423 assert_ne!(info.features & CURL_VERSION_HTTP2, 0);
7424 assert_ne!(info.features & CURL_VERSION_PSL, 0);
7425 assert!(!info.protocols.is_null());
7427 let first = unsafe { CStr::from_ptr(*info.protocols) };
7430 assert_eq!(first.to_str().unwrap(), "http");
7431 }
7432
7433 #[test]
7434 fn easy_pause_noop() {
7435 let handle = curl_easy_init();
7436 assert!(!handle.is_null());
7437 let code = curl_easy_pause(handle, CURLPAUSE_ALL);
7438 assert_eq!(code, CURLcode::CURLE_OK);
7439 let code = curl_easy_pause(handle, CURLPAUSE_CONT);
7440 assert_eq!(code, CURLcode::CURLE_OK);
7441 unsafe { curl_easy_cleanup(handle) };
7442 }
7443
7444 #[test]
7445 fn easy_upkeep_noop() {
7446 let handle = curl_easy_init();
7447 let code = curl_easy_upkeep(handle);
7448 assert_eq!(code, CURLcode::CURLE_OK);
7449 unsafe { curl_easy_cleanup(handle) };
7450 }
7451
7452 #[test]
7453 fn multi_assign_noop() {
7454 let multi = curl_multi_init();
7455 assert_eq!(curl_multi_assign(multi, 0, ptr::null_mut()), CURLMcode::CURLM_OK);
7456 let _ = unsafe { curl_multi_cleanup(multi) };
7457 }
7458
7459 #[test]
7460 fn easy_setopt_haproxyprotocol() {
7461 let handle = curl_easy_init();
7462 let code =
7464 unsafe { curl_easy_setopt(handle, 274, std::ptr::without_provenance::<c_void>(1)) };
7465 assert_eq!(code, CURLcode::CURLE_OK);
7466 unsafe { curl_easy_cleanup(handle) };
7467 }
7468
7469 #[test]
7470 fn easy_setopt_httppost_deprecated() {
7471 let handle = curl_easy_init();
7472 let code = unsafe { curl_easy_setopt(handle, 10024, ptr::null()) };
7474 assert_eq!(code, CURLcode::CURLE_OK);
7475 unsafe { curl_easy_cleanup(handle) };
7476 }
7477
7478 #[test]
7479 fn easy_setopt_abstract_unix_socket() {
7480 let handle = curl_easy_init();
7481 let path = std::ffi::CString::new("/tmp/test.sock").unwrap();
7482 let code = unsafe { curl_easy_setopt(handle, 10264, path.as_ptr().cast::<c_void>()) };
7484 assert_eq!(code, CURLcode::CURLE_OK);
7485 unsafe { curl_easy_cleanup(handle) };
7486 }
7487
7488 #[test]
7489 fn easy_setopt_doh_ssl_verifypeer() {
7490 let handle = curl_easy_init();
7491 let code =
7493 unsafe { curl_easy_setopt(handle, 306, std::ptr::without_provenance::<c_void>(1)) };
7494 assert_eq!(code, CURLcode::CURLE_OK);
7495 unsafe { curl_easy_cleanup(handle) };
7496 }
7497
7498 #[test]
7499 fn easy_setopt_buffersize() {
7500 let handle = curl_easy_init();
7501 let code = unsafe { curl_easy_setopt(handle, 98, 65536 as *const c_void) };
7503 assert_eq!(code, CURLcode::CURLE_OK);
7504 unsafe { curl_easy_cleanup(handle) };
7505 }
7506
7507 #[test]
7508 fn easy_setopt_maxlifetime_conn() {
7509 let handle = curl_easy_init();
7510 let code = unsafe { curl_easy_setopt(handle, 314, 300 as *const c_void) };
7512 assert_eq!(code, CURLcode::CURLE_OK);
7513 unsafe { curl_easy_cleanup(handle) };
7514 }
7515
7516 #[test]
7517 fn new_curlcodes_strerror() {
7518 assert_ne!(curl_easy_strerror(CURLcode::CURLE_FILESIZE_EXCEEDED), ptr::null());
7519 assert_ne!(curl_easy_strerror(CURLcode::CURLE_TOO_MANY_REDIRECTS), ptr::null());
7520 assert_ne!(curl_easy_strerror(CURLcode::CURLE_HTTP3), ptr::null());
7521 assert_ne!(curl_easy_strerror(CURLcode::CURLE_PARTIAL_FILE), ptr::null());
7522 assert_ne!(curl_easy_strerror(CURLcode::CURLE_RANGE_ERROR), ptr::null());
7523 assert_ne!(curl_easy_strerror(CURLcode::CURLE_AGAIN), ptr::null());
7524 }
7525
7526 #[test]
7527 fn curlinfo_enum_has_timing_t_variants() {
7528 let _ = CURLINFO::CURLINFO_TOTAL_TIME_T;
7530 let _ = CURLINFO::CURLINFO_NAMELOOKUP_TIME_T;
7531 let _ = CURLINFO::CURLINFO_CONNECT_TIME_T;
7532 let _ = CURLINFO::CURLINFO_PRETRANSFER_TIME_T;
7533 let _ = CURLINFO::CURLINFO_STARTTRANSFER_TIME_T;
7534 let _ = CURLINFO::CURLINFO_REDIRECT_TIME_T;
7535 let _ = CURLINFO::CURLINFO_APPCONNECT_TIME_T;
7536 let _ = CURLINFO::CURLINFO_SIZE_UPLOAD_T;
7537 let _ = CURLINFO::CURLINFO_SIZE_DOWNLOAD_T;
7538 let _ = CURLINFO::CURLINFO_SPEED_DOWNLOAD_T;
7539 let _ = CURLINFO::CURLINFO_SPEED_UPLOAD_T;
7540 let _ = CURLINFO::CURLINFO_REDIRECT_TIME;
7541 let _ = CURLINFO::CURLINFO_RETRY_AFTER;
7542 }
7543
7544 #[test]
7545 fn global_constants_defined() {
7546 assert_eq!(CURL_GLOBAL_SSL, 1);
7547 assert_eq!(CURL_GLOBAL_WIN32, 2);
7548 assert_eq!(CURL_GLOBAL_ALL, 3);
7549 assert_eq!(CURL_GLOBAL_DEFAULT, 3);
7550 assert_eq!(CURLPAUSE_RECV, 1);
7551 assert_eq!(CURLPAUSE_SEND, 4);
7552 assert_eq!(CURLPAUSE_ALL, 5);
7553 assert_eq!(CURLPAUSE_CONT, 0);
7554 }
7555
7556 #[test]
7559 fn easy_setopt_cainfo_blob() {
7560 let handle = curl_easy_init();
7561 let pem_data = b"-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----\n";
7562 let blob =
7563 curl_blob { data: pem_data.as_ptr().cast::<c_void>(), len: pem_data.len(), flags: 0 };
7564 let code =
7566 unsafe { curl_easy_setopt(handle, 40309, ptr::from_ref(&blob).cast::<c_void>()) };
7567 assert_eq!(code, CURLcode::CURLE_OK);
7568 unsafe { curl_easy_cleanup(handle) };
7569 }
7570
7571 #[test]
7572 fn easy_setopt_sslcert_blob() {
7573 let handle = curl_easy_init();
7574 let pem_data = b"-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----\n";
7575 let blob =
7576 curl_blob { data: pem_data.as_ptr().cast::<c_void>(), len: pem_data.len(), flags: 0 };
7577 let code =
7579 unsafe { curl_easy_setopt(handle, 40291, ptr::from_ref(&blob).cast::<c_void>()) };
7580 assert_eq!(code, CURLcode::CURLE_OK);
7581 unsafe { curl_easy_cleanup(handle) };
7582 }
7583
7584 #[test]
7585 fn easy_setopt_sslkey_blob() {
7586 let handle = curl_easy_init();
7587 let pem_data = b"-----BEGIN PRIVATE KEY-----\ntest\n-----END PRIVATE KEY-----\n";
7588 let blob =
7589 curl_blob { data: pem_data.as_ptr().cast::<c_void>(), len: pem_data.len(), flags: 0 };
7590 let code =
7592 unsafe { curl_easy_setopt(handle, 40292, ptr::from_ref(&blob).cast::<c_void>()) };
7593 assert_eq!(code, CURLcode::CURLE_OK);
7594 unsafe { curl_easy_cleanup(handle) };
7595 }
7596
7597 #[test]
7598 fn easy_setopt_blob_null_clears_setting() {
7599 let handle = curl_easy_init();
7600 let code = unsafe { curl_easy_setopt(handle, 40309, ptr::null()) };
7602 assert_eq!(code, CURLcode::CURLE_OK);
7603 unsafe { curl_easy_cleanup(handle) };
7604 }
7605
7606 #[test]
7607 fn easy_setopt_cainfo_blob_empty_clears_setting() {
7608 let handle = curl_easy_init();
7609 let blob = curl_blob { data: ptr::null(), len: 0, flags: 0 };
7611 let code =
7612 unsafe { curl_easy_setopt(handle, 40309, ptr::from_ref(&blob).cast::<c_void>()) };
7613 assert_eq!(code, CURLcode::CURLE_OK);
7614 unsafe { curl_easy_cleanup(handle) };
7615 }
7616
7617 #[test]
7618 fn easy_setopt_blob_null_data_returns_error() {
7619 let handle = curl_easy_init();
7620 let blob = curl_blob { data: ptr::null(), len: 10, flags: 0 };
7621 let code =
7622 unsafe { curl_easy_setopt(handle, 40291, ptr::from_ref(&blob).cast::<c_void>()) };
7623 assert_eq!(code, CURLcode::CURLE_BAD_FUNCTION_ARGUMENT);
7624 unsafe { curl_easy_cleanup(handle) };
7625 }
7626
7627 #[test]
7628 fn easy_setopt_blob_zero_len_returns_error() {
7629 let handle = curl_easy_init();
7630 let data = b"some data";
7631 let blob = curl_blob { data: data.as_ptr().cast::<c_void>(), len: 0, flags: 0 };
7632 let code =
7633 unsafe { curl_easy_setopt(handle, 40292, ptr::from_ref(&blob).cast::<c_void>()) };
7634 assert_eq!(code, CURLcode::CURLE_BAD_FUNCTION_ARGUMENT);
7635 unsafe { curl_easy_cleanup(handle) };
7636 }
7637
7638 #[test]
7641 fn easy_setopt_ftpport() {
7642 let handle = curl_easy_init();
7643 let addr = c"-";
7644 let code = unsafe { curl_easy_setopt(handle, 10017, addr.as_ptr().cast::<c_void>()) };
7645 assert_eq!(code, CURLcode::CURLE_OK);
7646 unsafe { curl_easy_cleanup(handle) };
7647 }
7648
7649 #[test]
7650 fn easy_setopt_ftp_use_epsv() {
7651 let handle = curl_easy_init();
7652 let code = unsafe { curl_easy_setopt(handle, 85, ptr::null()) };
7653 assert_eq!(code, CURLcode::CURLE_OK);
7654 unsafe { curl_easy_cleanup(handle) };
7655 }
7656
7657 #[test]
7658 fn easy_setopt_ftp_use_eprt() {
7659 let handle = curl_easy_init();
7660 let code = unsafe { curl_easy_setopt(handle, 106, std::ptr::dangling::<c_void>()) };
7661 assert_eq!(code, CURLcode::CURLE_OK);
7662 unsafe { curl_easy_cleanup(handle) };
7663 }
7664
7665 #[test]
7666 fn easy_setopt_ftp_create_missing_dirs() {
7667 let handle = curl_easy_init();
7668 let code = unsafe { curl_easy_setopt(handle, 110, std::ptr::dangling::<c_void>()) };
7669 assert_eq!(code, CURLcode::CURLE_OK);
7670 unsafe { curl_easy_cleanup(handle) };
7671 }
7672
7673 #[test]
7674 fn easy_setopt_ftp_skip_pasv_ip() {
7675 let handle = curl_easy_init();
7676 let code = unsafe { curl_easy_setopt(handle, 137, std::ptr::dangling::<c_void>()) };
7677 assert_eq!(code, CURLcode::CURLE_OK);
7678 unsafe { curl_easy_cleanup(handle) };
7679 }
7680
7681 #[test]
7682 fn easy_setopt_ftp_filemethod() {
7683 let handle = curl_easy_init();
7684 let code = unsafe { curl_easy_setopt(handle, 138, 3_usize as *const c_void) };
7686 assert_eq!(code, CURLcode::CURLE_OK);
7687 unsafe { curl_easy_cleanup(handle) };
7688 }
7689
7690 #[test]
7691 fn easy_setopt_ftp_account() {
7692 let handle = curl_easy_init();
7693 let acct = c"myaccount";
7694 let code = unsafe { curl_easy_setopt(handle, 10134, acct.as_ptr().cast::<c_void>()) };
7695 assert_eq!(code, CURLcode::CURLE_OK);
7696 unsafe { curl_easy_cleanup(handle) };
7697 }
7698
7699 #[test]
7700 fn easy_setopt_use_ssl() {
7701 let handle = curl_easy_init();
7702 let code = unsafe { curl_easy_setopt(handle, 119, 2_usize as *const c_void) };
7704 assert_eq!(code, CURLcode::CURLE_OK);
7705 unsafe { curl_easy_cleanup(handle) };
7706 }
7707
7708 #[test]
7711 fn easy_setopt_ssh_auth_types() {
7712 let handle = curl_easy_init();
7713 let code = unsafe { curl_easy_setopt(handle, 151, 3_usize as *const c_void) };
7715 assert_eq!(code, CURLcode::CURLE_OK);
7716 unsafe { curl_easy_cleanup(handle) };
7717 }
7718
7719 #[test]
7720 fn easy_setopt_ssh_public_keyfile() {
7721 let handle = curl_easy_init();
7722 let path = c"/home/user/.ssh/id_rsa.pub";
7723 let code = unsafe { curl_easy_setopt(handle, 10152, path.as_ptr().cast::<c_void>()) };
7724 assert_eq!(code, CURLcode::CURLE_OK);
7725 unsafe { curl_easy_cleanup(handle) };
7726 }
7727
7728 #[test]
7729 fn easy_setopt_ssh_private_keyfile() {
7730 let handle = curl_easy_init();
7731 let path = c"/home/user/.ssh/id_rsa";
7732 let code = unsafe { curl_easy_setopt(handle, 10153, path.as_ptr().cast::<c_void>()) };
7733 assert_eq!(code, CURLcode::CURLE_OK);
7734 unsafe { curl_easy_cleanup(handle) };
7735 }
7736
7737 #[test]
7738 fn easy_setopt_ssh_knownhosts() {
7739 let handle = curl_easy_init();
7740 let path = c"/home/user/.ssh/known_hosts";
7741 let code = unsafe { curl_easy_setopt(handle, 10183, path.as_ptr().cast::<c_void>()) };
7742 assert_eq!(code, CURLcode::CURLE_OK);
7743 unsafe { curl_easy_cleanup(handle) };
7744 }
7745
7746 #[test]
7747 fn easy_setopt_ssh_host_public_key_sha256() {
7748 let handle = curl_easy_init();
7749 let fp = c"AAAA+bbb/ccc=";
7750 let code = unsafe { curl_easy_setopt(handle, 10270, fp.as_ptr().cast::<c_void>()) };
7751 assert_eq!(code, CURLcode::CURLE_OK);
7752 unsafe { curl_easy_cleanup(handle) };
7753 }
7754
7755 #[test]
7758 fn easy_setopt_proxyport() {
7759 let handle = curl_easy_init();
7760 let code = unsafe { curl_easy_setopt(handle, 59, 8080_usize as *const c_void) };
7761 assert_eq!(code, CURLcode::CURLE_OK);
7762 unsafe { curl_easy_cleanup(handle) };
7763 }
7764
7765 #[test]
7766 fn easy_setopt_proxytype() {
7767 let handle = curl_easy_init();
7768 let code = unsafe { curl_easy_setopt(handle, 101, 5_usize as *const c_void) };
7770 assert_eq!(code, CURLcode::CURLE_OK);
7771 unsafe { curl_easy_cleanup(handle) };
7772 }
7773
7774 #[test]
7775 fn easy_setopt_proxyusername() {
7776 let handle = curl_easy_init();
7777 let user = c"proxyuser";
7778 let code = unsafe { curl_easy_setopt(handle, 10175, user.as_ptr().cast::<c_void>()) };
7779 assert_eq!(code, CURLcode::CURLE_OK);
7780 unsafe { curl_easy_cleanup(handle) };
7781 }
7782
7783 #[test]
7784 fn easy_setopt_proxypassword() {
7785 let handle = curl_easy_init();
7786 let pass = c"proxypass";
7787 let code = unsafe { curl_easy_setopt(handle, 10176, pass.as_ptr().cast::<c_void>()) };
7788 assert_eq!(code, CURLcode::CURLE_OK);
7789 unsafe { curl_easy_cleanup(handle) };
7790 }
7791
7792 #[test]
7793 fn easy_setopt_pre_proxy() {
7794 let handle = curl_easy_init();
7795 let url = c"socks5://proxy.example.com:1080";
7796 let code = unsafe { curl_easy_setopt(handle, 10262, url.as_ptr().cast::<c_void>()) };
7797 assert_eq!(code, CURLcode::CURLE_OK);
7798 unsafe { curl_easy_cleanup(handle) };
7799 }
7800
7801 #[test]
7802 fn easy_setopt_socks5_auth() {
7803 let handle = curl_easy_init();
7804 let code = unsafe { curl_easy_setopt(handle, 267, 3_usize as *const c_void) };
7805 assert_eq!(code, CURLcode::CURLE_OK);
7806 unsafe { curl_easy_cleanup(handle) };
7807 }
7808
7809 #[test]
7810 fn easy_setopt_maxconnects() {
7811 let handle = curl_easy_init();
7812 let code = unsafe { curl_easy_setopt(handle, 71, 5_usize as *const c_void) };
7813 assert_eq!(code, CURLcode::CURLE_OK);
7814 unsafe { curl_easy_cleanup(handle) };
7815 }
7816
7817 #[test]
7818 fn easy_setopt_pipewait() {
7819 let handle = curl_easy_init();
7820 let code = unsafe { curl_easy_setopt(handle, 237, std::ptr::dangling::<c_void>()) };
7821 assert_eq!(code, CURLcode::CURLE_OK);
7822 unsafe { curl_easy_cleanup(handle) };
7823 }
7824
7825 #[test]
7826 fn easy_setopt_stream_weight() {
7827 let handle = curl_easy_init();
7828 let code = unsafe { curl_easy_setopt(handle, 239, 16_usize as *const c_void) };
7829 assert_eq!(code, CURLcode::CURLE_OK);
7830 unsafe { curl_easy_cleanup(handle) };
7831 }
7832
7833 #[test]
7834 fn easy_setopt_tcp_fastopen() {
7835 let handle = curl_easy_init();
7836 let code = unsafe { curl_easy_setopt(handle, 244, std::ptr::dangling::<c_void>()) };
7837 assert_eq!(code, CURLcode::CURLE_OK);
7838 unsafe { curl_easy_cleanup(handle) };
7839 }
7840
7841 #[test]
7842 fn easy_setopt_http09_allowed() {
7843 let handle = curl_easy_init();
7844 let code = unsafe { curl_easy_setopt(handle, 285, std::ptr::dangling::<c_void>()) };
7845 assert_eq!(code, CURLcode::CURLE_OK);
7846 unsafe { curl_easy_cleanup(handle) };
7847 }
7848
7849 #[test]
7850 fn curlcode_auth_error_exists() {
7851 assert_eq!(CURLcode::CURLE_AUTH_ERROR as i32, 94);
7852 }
7853
7854 #[test]
7855 fn curlcode_ssl_pinnedpubkey_exists() {
7856 assert_eq!(CURLcode::CURLE_SSL_PINNEDPUBKEYNOTMATCH as i32, 90);
7857 }
7858
7859 #[test]
7860 fn easy_setopt_port() {
7861 let handle = curl_easy_init();
7862 let code = unsafe { curl_easy_setopt(handle, 3, 8080_usize as *const c_void) };
7863 assert_eq!(code, CURLcode::CURLE_OK);
7864 unsafe { curl_easy_cleanup(handle) };
7865 }
7866
7867 #[test]
7868 fn easy_setopt_infilesize() {
7869 let handle = curl_easy_init();
7870 let code = unsafe { curl_easy_setopt(handle, 14, 1024_usize as *const c_void) };
7871 assert_eq!(code, CURLcode::CURLE_OK);
7872 unsafe { curl_easy_cleanup(handle) };
7873 }
7874
7875 #[test]
7876 fn easy_setopt_resume_from() {
7877 let handle = curl_easy_init();
7878 let code = unsafe { curl_easy_setopt(handle, 21, 512_usize as *const c_void) };
7879 assert_eq!(code, CURLcode::CURLE_OK);
7880 unsafe { curl_easy_cleanup(handle) };
7881 }
7882
7883 #[test]
7884 fn easy_setopt_ipresolve() {
7885 let handle = curl_easy_init();
7886 let code = unsafe { curl_easy_setopt(handle, 113, std::ptr::dangling::<c_void>()) };
7887 assert_eq!(code, CURLcode::CURLE_OK);
7888 unsafe { curl_easy_cleanup(handle) };
7889 }
7890
7891 #[test]
7892 fn easy_setopt_postfieldsize_large() {
7893 let handle = curl_easy_init();
7894 let code = unsafe { curl_easy_setopt(handle, 30120, 4096_usize as *const c_void) };
7895 assert_eq!(code, CURLcode::CURLE_OK);
7896 unsafe { curl_easy_cleanup(handle) };
7897 }
7898
7899 #[test]
7900 fn easy_setopt_capath() {
7901 let handle = curl_easy_init();
7902 let path = c"/etc/ssl/certs";
7903 let code = unsafe { curl_easy_setopt(handle, 10097, path.as_ptr().cast::<c_void>()) };
7904 assert_eq!(code, CURLcode::CURLE_OK);
7905 unsafe { curl_easy_cleanup(handle) };
7906 }
7907
7908 #[test]
7909 fn easy_getinfo_request_size() {
7910 let handle = curl_easy_init();
7911 let url = c"http://example.com";
7912 let _ = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
7913 let _ = unsafe { curl_easy_perform(handle) };
7914 let mut size: c_long = -1;
7915 let code = unsafe {
7917 curl_easy_getinfo(handle, 0x20_000C, std::ptr::addr_of_mut!(size).cast::<c_void>())
7918 };
7919 assert_eq!(code, CURLcode::CURLE_OK);
7920 assert_eq!(size, 0);
7921 unsafe { curl_easy_cleanup(handle) };
7922 }
7923
7924 #[test]
7925 fn easy_getinfo_http_connectcode() {
7926 let handle = curl_easy_init();
7927 let url = c"http://example.com";
7928 let _ = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
7929 let _ = unsafe { curl_easy_perform(handle) };
7930 let mut code_val: c_long = -1;
7931 let code = unsafe {
7933 curl_easy_getinfo(handle, 0x20_0016, std::ptr::addr_of_mut!(code_val).cast::<c_void>())
7934 };
7935 assert_eq!(code, CURLcode::CURLE_OK);
7936 assert_eq!(code_val, 0);
7937 unsafe { curl_easy_cleanup(handle) };
7938 }
7939
7940 #[test]
7941 fn easy_getinfo_httpauth_avail() {
7942 let handle = curl_easy_init();
7943 let url = c"http://example.com";
7944 let _ = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
7945 let _ = unsafe { curl_easy_perform(handle) };
7946 let mut auth: c_long = -1;
7947 let code = unsafe {
7949 curl_easy_getinfo(handle, 0x20_0017, std::ptr::addr_of_mut!(auth).cast::<c_void>())
7950 };
7951 assert_eq!(code, CURLcode::CURLE_OK);
7952 assert_eq!(auth, 1); unsafe { curl_easy_cleanup(handle) };
7954 }
7955
7956 #[test]
7957 fn easy_getinfo_proxyauth_avail() {
7958 let handle = curl_easy_init();
7959 let url = c"http://example.com";
7960 let _ = unsafe { curl_easy_setopt(handle, 10002, url.as_ptr().cast::<c_void>()) };
7961 let _ = unsafe { curl_easy_perform(handle) };
7962 let mut auth: c_long = -1;
7963 let code = unsafe {
7965 curl_easy_getinfo(handle, 0x20_0018, std::ptr::addr_of_mut!(auth).cast::<c_void>())
7966 };
7967 assert_eq!(code, CURLcode::CURLE_OK);
7968 assert_eq!(auth, 0);
7969 unsafe { curl_easy_cleanup(handle) };
7970 }
7971}