about summary refs log tree commit diff stats
path: root/adapter
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-12-15 15:35:38 +0100
committerbptato <nincsnevem662@gmail.com>2023-12-15 15:51:49 +0100
commitfc09f0bee88cbbb90a89798a55a1d405f62ce8a7 (patch)
tree3c23ee4ef94491e62772a41cd7392d4bd204eabc /adapter
parenta55c1ab95ecb0d79c73bbb82edd99b737c601260 (diff)
downloadchawan-fc09f0bee88cbbb90a89798a55a1d405f62ce8a7.tar.gz
ftp: fix unnecessary slashes being added to path; move bindings/curl
also in ftp: clean up resources before exit
Diffstat (limited to 'adapter')
-rw-r--r--adapter/protocol/curl.nim426
-rw-r--r--adapter/protocol/curlerrors.nim2
-rw-r--r--adapter/protocol/curlwrap.nim2
-rw-r--r--adapter/protocol/ftp.nim51
-rw-r--r--adapter/protocol/gopher.nim4
-rw-r--r--adapter/protocol/http.nim2
6 files changed, 461 insertions, 26 deletions
diff --git a/adapter/protocol/curl.nim b/adapter/protocol/curl.nim
new file mode 100644
index 00000000..a12e81c4
--- /dev/null
+++ b/adapter/protocol/curl.nim
@@ -0,0 +1,426 @@
+const curllib = (func(): string =
+  const curlLibName {.strdefine.} = ""
+  when curlLibName != "":
+    return curlLibName
+  elif defined(windows):
+    return "libcurl.dll"
+  elif defined(macos):
+    return "libcurl(|.4|.4.8.0).dylib"
+  else: # assume posix
+    return "libcurl.so(|.4|.4.8.0)"
+)()
+
+const
+  CURL_GLOBAL_SSL* = 1 shl 0 # no purpose since 7.57.0
+  CURL_GLOBAL_WIN32* = 1 shl 1
+  CURL_GLOBAL_ALL* = CURL_GLOBAL_SSL or CURL_GLOBAL_WIN32
+  CURL_GLOBAL_NOTHING* = 0
+  CURL_GLOBAL_DEFAULT* = CURL_GLOBAL_ALL
+  CURL_GLOBAL_ACK_EINTR* = 1 shl 2
+
+const
+  CURLOPTTYPE_LONG = 0
+  CURLOPTTYPE_OBJECTPOINT = 10000
+  CURLOPTTYPE_FUNCTIONPOINT = 20000
+  CURLOPTTYPE_OFF_T = 30000
+  CURLOPTTYPE_BLOB = 40000
+
+const
+  CURLOPTTYPE_STRINGPOINT = CURLOPTTYPE_OBJECTPOINT
+  CURLOPTTYPE_SLISTPOINT = CURLOPTTYPE_OBJECTPOINT
+  CURLOPTTYPE_CBPOINT = CURLOPTTYPE_OBJECTPOINT
+  CURLOPTTYPE_VALUES = CURLOPTTYPE_LONG
+
+const
+  CURLINFO_STRING = 0x100000
+  CURLINFO_LONG = 0x200000
+  CURLINFO_DOUBLE = 0x300000
+  CURLINFO_SLIST = 0x400000
+  CURLINFO_PTR = 0x400000 # same as SLIST
+  CURLINFO_SOCKET = 0x500000
+  CURLINFO_OFF_T = 0x600000
+  CURLINFO_MASK {.used.} = 0x0fffff
+  CURLINFO_TYPEMASK {.used.} = 0xf00000
+
+const
+  CURL_WAIT_POLLIN* = 0x0001
+  CURL_WAIT_POLLPRI* = 0x0002
+  CURL_WAIT_POLLOUT* = 0x0004
+
+# CURLU
+const
+  CURLU_DEFAULT_PORT* = (1 shl 0)       # return default port number
+  CURLU_NO_DEFAULT_PORT* = (1 shl 1)    # act as if no port number was set,
+                                        # if the port number matches the
+                                        # default for the scheme
+  CURLU_DEFAULT_SCHEME* = (1 shl 2)     # return default scheme if missing
+  CURLU_NON_SUPPORT_SCHEME* = (1 shl 3) # allow non-supported scheme
+  CURLU_PATH_AS_IS* = (1 shl 4)         # leave dot sequences
+  CURLU_DISALLOW_USER* = (1 shl 5)      # no user+password allowed
+  CURLU_URLDECODE* = (1 shl 6)          # URL decode on get
+  CURLU_URLENCODE* = (1 shl 7)          # URL encode on set
+  CURLU_APPENDQUERY* = (1 shl 8)        # append a form style part
+  CURLU_GUESS_SCHEME* = (1 shl 9)       # legacy curl-style guessing
+  CURLU_NO_AUTHORITY* = (1 shl 10)      # Allow empty authority when the scheme
+                                        # is unknown.
+  CURLU_ALLOW_SPACE* = (1 shl 11)       # Allow spaces in the URL
+  CURLU_PUNYCODE* = (1 shl 12)          # get the host name in punycode
+  CURLU_PUNY2IDN* = (1 shl 13)          # punycode => IDN conversion
+
+{.push cdecl, dynlib: curllib.}
+
+type
+  CURL* = distinct pointer
+  CURLM* = distinct pointer
+  CURLU* = distinct pointer
+
+  curl_mime_struct = object
+  curl_mime* = ptr curl_mime_struct
+  curl_mimepart_struct = object
+  curl_mimepart* = ptr curl_mimepart_struct
+  curl_slist_struct = object
+  curl_slist* = ptr curl_slist_struct
+  curl_socket_t = cint
+  curl_waitfd* = object
+    fd*: curl_socket_t
+    events*: cshort
+    revents*: cshort # this is, in fact, supported.
+  CURLMsg_data {.union.} = object
+    whatever: pointer
+    result*: CURLcode
+  CURLMsg_struct = object
+    msg*: CURLMSG_E
+    easy_handle*: CURL
+    data*: CURLMsg_data
+  CURLMsg* = ptr CURLMsg_struct
+
+  CURLoption* {.size: sizeof(cint).} = enum
+    # Long
+    CURLOPT_PORT = CURLOPTTYPE_LONG + 3
+    CURLOPT_SSLVERSION = CURLOPTTYPE_VALUES + 32
+    CURLOPT_TIMECONDITION = CURLOPTTYPE_VALUES + 33
+    CURLOPT_POST = CURLOPTTYPE_LONG + 47
+    CURLOPT_DIRLISTONLY = CURLOPTTYPE_LONG + 48
+    CURLOPT_FOLLOWLOCATION = CURLOPTTYPE_LONG + 52
+    CURLOPT_POSTFIELDSIZE = CURLOPTTYPE_LONG + 60
+    CURLOPT_HTTPGET = CURLOPTTYPE_LONG + 80
+    CURLOPT_FTP_FILEMETHOD = CURLOPTTYPE_VALUES + 138
+    CURLOPT_CONNECT_ONLY = CURLOPTTYPE_LONG + 141
+
+    # Objectpoint
+    CURLOPT_WRITEDATA = CURLOPTTYPE_CBPOINT + 1
+    CURLOPT_URL = CURLOPTTYPE_STRINGPOINT + 2
+    CURLOPT_PROXY = CURLOPTTYPE_STRINGPOINT + 4
+    CURLOPT_POSTFIELDS = CURLOPTTYPE_OBJECTPOINT + 15
+    CURLOPT_HTTPHEADER = CURLOPTTYPE_SLISTPOINT + 23
+    CURLOPT_HEADERDATA = CURLOPTTYPE_CBPOINT + 29
+    CURLOPT_ACCEPT_ENCODING = CURLOPTTYPE_STRINGPOINT + 102
+    CURLOPT_MIMEPOST = CURLOPTTYPE_OBJECTPOINT + 269
+    CURLOPT_CURLU = CURLOPTTYPE_OBJECTPOINT + 282
+    CURLOPT_PREREQDATA = CURLOPTTYPE_CBPOINT + 313
+
+    # Functionpoint
+    CURLOPT_WRITEFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 11
+    CURLOPT_READFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 12
+    CURLOPT_HEADERFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 79
+    CURLOPT_PREREQFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 312
+
+    # Off-t
+    CURLOPT_INFILESIZE_LARGE = CURLOPTTYPE_OFF_T + 115
+    CURLOPT_RESUME_FROM_LARGE = CURLOPTTYPE_OFF_T + 116
+    CURLOPT_POSTFIELDSIZE_LARGE = CURLOPTTYPE_OFF_T + 120
+
+    # Blob
+    CURLOPT_SSLCERT_BLOB = CURLOPTTYPE_BLOB + 291
+    CURLOPT_SSLKEY_BLOB = CURLOPTTYPE_BLOB + 292
+    CURLOPT_PROXY_SSLCERT_BLOB = CURLOPTTYPE_BLOB + 293
+    CURLOPT_PROXY_SSLKEY_BLOB = CURLOPTTYPE_BLOB + 294
+    CURLOPT_ISSUECERT_BLOB = CURLOPTTYPE_BLOB + 295
+
+  CURLINFO* {.size: sizeof(cint).} = enum
+    CURLINFO_NONE # first, never use this
+
+    # String
+    CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31
+
+    # Long
+    CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2
+
+    # Double
+    CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3
+
+    # S-list
+    CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27
+    CURLINFO_COOKIELIST = CURLINFO_SLIST + 28
+
+    # Pointer
+    CURLINFO_CERTINFO = CURLINFO_PTR + 34
+    CURLINFO_TLS_SESSION = CURLINFO_PTR + 43
+    CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45
+
+    # Socket
+    CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44
+
+    # Off_t
+    CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7
+    CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 9
+
+  CURLcode* {.size: sizeof(cint).} = enum
+    CURLE_OK = 0,
+    CURLE_UNSUPPORTED_PROTOCOL,    # 1
+    CURLE_FAILED_INIT,             # 2
+    CURLE_URL_MALFORMAT,           # 3
+    CURLE_NOT_BUILT_IN,            # 4 - [was obsoleted in August 2007 for
+                                   # 7.17.0, reused in April 2011 for 7.21.5]
+    CURLE_COULDNT_RESOLVE_PROXY,   # 5
+    CURLE_COULDNT_RESOLVE_HOST,    # 6
+    CURLE_COULDNT_CONNECT,         # 7
+    CURLE_WEIRD_SERVER_REPLY,      # 8
+    CURLE_REMOTE_ACCESS_DENIED,    # 9 a service was denied by the server
+                                   # due to lack of access - when login fails
+                                   # this is not returned.
+    CURLE_FTP_ACCEPT_FAILED,       # 10 - [was obsoleted in April 2006 for
+                                   # 7.15.4, reused in Dec 2011 for 7.24.0]
+    CURLE_FTP_WEIRD_PASS_REPLY,    # 11
+    CURLE_FTP_ACCEPT_TIMEOUT,      # 12 - timeout occurred accepting server
+                                   # [was obsoleted in August 2007 for 7.17.0,
+                                   # reused in Dec 2011 for 7.24.0]
+    CURLE_FTP_WEIRD_PASV_REPLY,    # 13
+    CURLE_FTP_WEIRD_227_FORMAT,    # 14
+    CURLE_FTP_CANT_GET_HOST,       # 15
+    CURLE_HTTP2,                   # 16 - A problem in the http2 framing layer.
+                                   # [was obsoleted in August 2007 for 7.17.0,
+                                   # reused in July 2014 for 7.38.0]
+    CURLE_FTP_COULDNT_SET_TYPE,    # 17
+    CURLE_PARTIAL_FILE,            # 18
+    CURLE_FTP_COULDNT_RETR_FILE,   # 19
+    CURLE_OBSOLETE20,              # 20 - NOT USED
+    CURLE_QUOTE_ERROR,             # 21 - quote command failure
+    CURLE_HTTP_RETURNED_ERROR,     # 22
+    CURLE_WRITE_ERROR,             # 23
+    CURLE_OBSOLETE24,              # 24 - NOT USED
+    CURLE_UPLOAD_FAILED,           # 25 - failed upload "command"
+    CURLE_READ_ERROR,              # 26 - couldn't open/read from file
+    CURLE_OUT_OF_MEMORY,           # 27
+    CURLE_OPERATION_TIMEDOUT,      # 28 - the timeout time was reached
+    CURLE_OBSOLETE29,              # 29 - NOT USED
+    CURLE_FTP_PORT_FAILED,         # 30 - FTP PORT operation failed
+    CURLE_FTP_COULDNT_USE_REST,    # 31 - the REST command failed
+    CURLE_OBSOLETE32,              # 32 - NOT USED
+    CURLE_RANGE_ERROR,             # 33 - RANGE "command" didn't work
+    CURLE_HTTP_POST_ERROR,         # 34
+    CURLE_SSL_CONNECT_ERROR,       # 35 - wrong when connecting with SSL
+    CURLE_BAD_DOWNLOAD_RESUME,     # 36 - couldn't resume download
+    CURLE_FILE_COULDNT_READ_FILE,  # 37
+    CURLE_LDAP_CANNOT_BIND,        # 38
+    CURLE_LDAP_SEARCH_FAILED,      # 39
+    CURLE_OBSOLETE40,              # 40 - NOT USED
+    CURLE_FUNCTION_NOT_FOUND,      # 41 - NOT USED starting with 7.53.0
+    CURLE_ABORTED_BY_CALLBACK,     # 42
+    CURLE_BAD_FUNCTION_ARGUMENT,   # 43
+    CURLE_OBSOLETE44,              # 44 - NOT USED
+    CURLE_INTERFACE_FAILED,        # 45 - CURLOPT_INTERFACE failed
+    CURLE_OBSOLETE46,              # 46 - NOT USED
+    CURLE_TOO_MANY_REDIRECTS,      # 47 - catch endless re-direct loops
+    CURLE_UNKNOWN_OPTION,          # 48 - User specified an unknown option
+    CURLE_SETOPT_OPTION_SYNTAX,    # 49 - Malformed setopt option
+    CURLE_OBSOLETE50,              # 50 - NOT USED
+    CURLE_OBSOLETE51,              # 51 - NOT USED
+    CURLE_GOT_NOTHING,             # 52 - when this is a specific error
+    CURLE_SSL_ENGINE_NOTFOUND,     # 53 - SSL crypto engine not found
+    CURLE_SSL_ENGINE_SETFAILED,    # 54 - can not set SSL crypto engine as
+                                   # default
+    CURLE_SEND_ERROR,              # 55 - failed sending network data
+    CURLE_RECV_ERROR,              # 56 - failure in receiving network data
+    CURLE_OBSOLETE57,              # 57 - NOT IN USE
+    CURLE_SSL_CERTPROBLEM,         # 58 - problem with the local certificate
+    CURLE_SSL_CIPHER,              # 59 - couldn't use specified cipher
+    CURLE_PEER_FAILED_VERIFICATION, # 60 - peer's certificate or fingerprint
+                                   # wasn't verified fine
+    CURLE_BAD_CONTENT_ENCODING,    # 61 - Unrecognized/bad encoding
+    CURLE_OBSOLETE62,              # 62 - NOT IN USE since 7.82.0
+    CURLE_FILESIZE_EXCEEDED,       # 63 - Maximum file size exceeded
+    CURLE_USE_SSL_FAILED,          # 64 - Requested FTP SSL level failed
+    CURLE_SEND_FAIL_REWIND,        # 65 - Sending the data requires a rewind
+                                   # that failed
+    CURLE_SSL_ENGINE_INITFAILED,   # 66 - failed to initialise ENGINE
+    CURLE_LOGIN_DENIED,            # 67 - user, password or similar was not
+                                   # accepted and we failed to login
+    CURLE_TFTP_NOTFOUND,           # 68 - file not found on server
+    CURLE_TFTP_PERM,               # 69 - permission problem on server
+    CURLE_REMOTE_DISK_FULL,        # 70 - out of disk space on server
+    CURLE_TFTP_ILLEGAL,            # 71 - Illegal TFTP operation
+    CURLE_TFTP_UNKNOWNID,          # 72 - Unknown transfer ID
+    CURLE_REMOTE_FILE_EXISTS,      # 73 - File already exists
+    CURLE_TFTP_NOSUCHUSER,         # 74 - No such user
+    CURLE_CONV_FAILED,             # 75 - conversion failed
+    CURLE_OBSOLETE76,              # 76 - NOT IN USE since 7.82.0
+    CURLE_SSL_CACERT_BADFILE,      # 77 - could not load CACERT file, missing
+                                   # or wrong format
+    CURLE_REMOTE_FILE_NOT_FOUND,   # 78 - remote file not found
+    CURLE_SSH,                     # 79 - error from the SSH layer, somewhat
+                                   # generic so the error message will be of
+                                   # interest when this has happened
+
+    CURLE_SSL_SHUTDOWN_FAILED,     # 80 - Failed to shut down the SSL
+                                   # connection
+    CURLE_AGAIN,                   # 81 - socket is not ready for send/recv,
+                                   # wait till it's ready and try again (Added
+                                   # in 7.18.2)
+    CURLE_SSL_CRL_BADFILE,         # 82 - could not load CRL file, missing or
+                                   # wrong format (Added in 7.19.0)
+    CURLE_SSL_ISSUER_ERROR,        # 83 - Issuer check failed.  (Added in
+                                   # 7.19.0)
+    CURLE_FTP_PRET_FAILED,         # 84 - a PRET command failed
+    CURLE_RTSP_CSEQ_ERROR,         # 85 - mismatch of RTSP CSeq numbers
+    CURLE_RTSP_SESSION_ERROR,      # 86 - mismatch of RTSP Session Ids
+    CURLE_FTP_BAD_FILE_LIST,       # 87 - unable to parse FTP file list
+    CURLE_CHUNK_FAILED,            # 88 - chunk callback reported error
+    CURLE_NO_CONNECTION_AVAILABLE, # 89 - No connection available, the
+                                   # session will be queued
+    CURLE_SSL_PINNEDPUBKEYNOTMATCH, # 90 - specified pinned public key did not
+                                   #  match
+    CURLE_SSL_INVALIDCERTSTATUS,   # 91 - invalid certificate status
+    CURLE_HTTP2_STREAM,            # 92 - stream error in HTTP/2 framing layer
+    CURLE_RECURSIVE_API_CALL,      # 93 - an api function was called from
+                                   # inside a callback
+    CURLE_AUTH_ERROR,              # 94 - an authentication function returned an
+                                   # error
+    CURLE_HTTP3,                   # 95 - An HTTP/3 layer problem
+    CURLE_QUIC_CONNECT_ERROR,      # 96 - QUIC connection error
+    CURLE_PROXY,                   # 97 - proxy handshake error
+    CURLE_SSL_CLIENTCERT,          # 98 - client-side certificate required
+    CURLE_UNRECOVERABLE_POLL,      # 99 - poll/select returned fatal error
+    CURL_LAST # never use!
+
+  curl_ftpmethod* {.size: sizeof(clong).} = enum
+    CURLFTPMETHOD_DEFAULT, # let libcurl pick
+    CURLFTPMETHOD_MULTICWD, # single CWD operation for each path part
+    CURLFTPMETHOD_NOCWD, # no CWD at all
+    CURLFTPMETHOD_SINGLECWD, # one CWD to full dir, then work on file
+
+  CURLMcode* {.size: sizeof(cint).} = enum
+    CURLM_CALL_MULTI_PERFORM = -1, # please call curl_multi_perform() or
+                                   #   curl_multi_socket*() soon
+    CURLM_OK,
+    CURLM_BAD_HANDLE,      # the passed-in handle is not a valid CURLM handle
+    CURLM_BAD_EASY_HANDLE, # an easy handle was not good/valid
+    CURLM_OUT_OF_MEMORY,   # if you ever get this, you're in deep sh*t
+    CURLM_INTERNAL_ERROR,  # this is a libcurl bug
+    CURLM_BAD_SOCKET,      # the passed in socket argument did not match
+    CURLM_UNKNOWN_OPTION,  # curl_multi_setopt() with unsupported option
+    CURLM_ADDED_ALREADY,   # an easy handle already added to a multi handle was
+                           #   attempted to get added - again
+    CURLM_RECURSIVE_API_CALL, # an api function was called from inside a
+                              #   callback
+    CURLM_WAKEUP_FAILURE,  # wakeup is unavailable or failed
+    CURLM_BAD_FUNCTION_ARGUMENT, # function called with a bad parameter
+    CURLM_ABORTED_BY_CALLBACK,
+    CURLM_UNRECOVERABLE_POLL,
+    CURLM_LAST
+
+  CURLMSG_E* {.size: sizeof(cint).} = enum
+    CURLMSG_NONE # first, not used
+    CURLMSG_DONE # This easy handle has completed. 'result' contains
+                 # the CURLcode of the transfer
+    CURLMSG_LAST # last, not used
+
+  CURLUcode* {.size: sizeof(cint).} = enum
+    CURLUE_OK,
+    CURLUE_BAD_HANDLE # 1
+    CURLUE_BAD_PARTPOINTER # 2
+    CURLUE_MALFORMED_INPUT # 3
+    CURLUE_BAD_PORT_NUMBER # 4
+    CURLUE_UNSUPPORTED_SCHEME # 5
+    CURLUE_URLDECODE # 6
+    CURLUE_OUT_OF_MEMORY # 7
+    CURLUE_USER_NOT_ALLOWED # 8
+    CURLUE_UNKNOWN_PART # 9
+    CURLUE_NO_SCHEME # 10
+    CURLUE_NO_USER # 11
+    CURLUE_NO_PASSWORD # 12
+    CURLUE_NO_OPTIONS # 13
+    CURLUE_NO_HOST # 14
+    CURLUE_NO_PORT # 15
+    CURLUE_NO_QUERY # 16
+    CURLUE_NO_FRAGMENT # 17
+    CURLUE_NO_ZONEID # 18
+    CURLUE_BAD_FILE_URL # 19
+    CURLUE_BAD_FRAGMENT # 20
+    CURLUE_BAD_HOSTNAME # 21
+    CURLUE_BAD_IPV6 # 22
+    CURLUE_BAD_LOGIN # 23
+    CURLUE_BAD_PASSWORD # 24
+    CURLUE_BAD_PATH # 25
+    CURLUE_BAD_QUERY # 26
+    CURLUE_BAD_SCHEME # 27
+    CURLUE_BAD_SLASHES # 28
+    CURLUE_BAD_USER # 29
+    CURLUE_LACKS_IDN # 30
+    CURLUE_LAST
+
+  CURLUPart* {.size: sizeof(cint).} = enum
+    CURLUPART_URL
+    CURLUPART_SCHEME
+    CURLUPART_USER
+    CURLUPART_PASSWORD
+    CURLUPART_OPTIONS
+    CURLUPART_HOST
+    CURLUPART_PORT
+    CURLUPART_PATH
+    CURLUPART_QUERY
+    CURLUPART_FRAGMENT
+    CURLUPART_ZONEID # added in 7.65.0
+
+proc `==`*(a: CURL, b: CURL): bool {.borrow.}
+proc `==`*(a: CURL, b: typeof(nil)): bool {.borrow.}
+proc `==`*(a: CURLM, b: CURLM): bool {.borrow.}
+proc `==`*(a: CURLM, b: typeof(nil)): bool {.borrow.}
+
+{.push importc.}
+
+proc curl_global_init*(flags: clong): CURLcode
+proc curl_global_cleanup*()
+proc curl_free*(p: pointer)
+
+proc curl_easy_init*(): CURL
+proc curl_easy_cleanup*(handle: CURL)
+proc curl_easy_setopt*(handle: CURL, option: CURLoption): CURLcode {.varargs.}
+proc curl_easy_perform*(handle: CURL): CURLcode
+proc curl_easy_getinfo*(handle: CURL, info: CURLINFO): CURLcode {.varargs.}
+proc curl_easy_strerror*(errornum: CURLcode): cstring
+
+proc curl_url*(): CURLU
+proc curl_url_cleanup*(handle: CURLU)
+proc curl_url_dup*(inh: CURLU): CURLU
+proc curl_url_get*(handle: CURLU, what: CURLUPart, part: ptr cstring,
+  flags: cuint): CURLUcode
+proc curl_url_set*(handle: CURLU, what: CURLUPart, part: cstring,
+  flags: cuint): CURLUcode
+proc curl_url_strerror*(code: CURLUcode): cstring
+
+proc curl_mime_init*(handle: CURL): curl_mime
+proc curl_mime_free*(mime: curl_mime)
+proc curl_mime_addpart*(mime: curl_mime): curl_mimepart
+proc curl_mime_name*(part: curl_mimepart, name: cstring)
+proc curl_mime_data*(part: curl_mimepart, data: pointer, datasize: csize_t)
+proc curl_mime_filename*(part: curl_mimepart, name: cstring)
+proc curl_mime_filedata*(part: curl_mimepart, filename: cstring)
+
+proc curl_slist_append*(slist: curl_slist, str: cstring): curl_slist
+proc curl_slist_free_all*(slist: curl_slist)
+
+proc curl_multi_init*(): CURLM
+proc curl_multi_add_handle*(multi_handle: CURLM, curl_handle: CURL): CURLMcode
+proc curl_multi_remove_handle*(multi_handle: CURLM, curl_handle: CURL): CURLMcode
+proc curl_multi_fdset*(multi_handle: CURLM, read_fd_set, write_fd_set, exc_fd_set: pointer, max_fd: ptr cint): CURLMcode
+proc curl_multi_wait*(multi_handle: CURLM, extra_fds: ptr curl_waitfd, extra_nfds: cuint, timeout_ns: cint, ret: ptr cint): CURLMcode
+proc curl_multi_poll*(multi_handle: CURLM, extra_fds: ptr curl_waitfd, extra_nfds: cuint, timeout_ns: cint, ret: ptr cint): CURLMcode
+proc curl_multi_wakeup*(multi_handle: CURLM): CURLMcode
+proc curl_multi_perform*(multi_handle: CURLM, running_handles: ptr cint): CURLMcode
+proc curl_multi_cleanup*(multi_handle: CURLM): CURLMcode
+proc curl_multi_info_read*(multi_handle: CURLM, msgs_in_queue: ptr cint): CURLMsg
+proc curl_multi_strerror*(code: CURLMcode): cstring
+{.pop.}
+
+{.pop.}
diff --git a/adapter/protocol/curlerrors.nim b/adapter/protocol/curlerrors.nim
index 3bb6cf6d..ce50cd82 100644
--- a/adapter/protocol/curlerrors.nim
+++ b/adapter/protocol/curlerrors.nim
@@ -1,4 +1,4 @@
-import bindings/curl
+import curl
 import loader/connecterror
 
 func curlErrorToChaError*(res: CURLcode): ConnectErrorCode =
diff --git a/adapter/protocol/curlwrap.nim b/adapter/protocol/curlwrap.nim
index 41ef5355..523c260f 100644
--- a/adapter/protocol/curlwrap.nim
+++ b/adapter/protocol/curlwrap.nim
@@ -1,4 +1,4 @@
-import bindings/curl
+import curl
 
 template setopt*(curl: CURL, opt: CURLoption, arg: typed) =
   discard curl_easy_setopt(curl, opt, arg)
diff --git a/adapter/protocol/ftp.nim b/adapter/protocol/ftp.nim
index 1a406743..064c0396 100644
--- a/adapter/protocol/ftp.nim
+++ b/adapter/protocol/ftp.nim
@@ -2,11 +2,11 @@ import std/envvars
 import std/options
 import std/strutils
 
+import curl
 import curlerrors
 import curlwrap
 import dirlist
 
-import bindings/curl
 import loader/connecterror
 import types/opt
 import utils/twtstr
@@ -154,6 +154,10 @@ proc main() =
   doAssert curl != nil
   let opath = getEnv("MAPPED_URI_PATH")
   let path = percentDecode(opath)
+  let op = FtpHandle(
+    curl: curl,
+    dirmode: path.len > 0 and path[^1] == '/'
+  )
   let url = curl_url()
   const flags = cuint(CURLU_PATH_AS_IS)
   url.set(CURLUPART_SCHEME, getEnv("MAPPED_URI_SCHEME"), flags)
@@ -171,39 +175,44 @@ proc main() =
   # necessary to specify absolute paths.
   # This is incredibly confusing, and probably not what the user wanted.
   # So we work around it by adding the extra slash ourselves.
+  #
+  # But before that, we take the serialized URL without the path for
+  # setting the base URL:
+  url.set(CURLUPART_PATH, opath, flags)
+  if op.dirmode:
+    let surl = url.get(CURLUPART_URL, cuint(CURLU_PUNY2IDN))
+    if surl == nil:
+      stdout.write("Cha-Control: ConnectionError " & $int(ERROR_INVALID_URL))
+      curl_url_cleanup(url)
+      curl_easy_cleanup(curl)
+      return
+    op.base = $surl
+    op.path = path
+    curl_free(surl)
+  # Now for the workaround:
   url.set(CURLUPART_PATH, '/' & opath, flags)
+  # Set opts for the request
   curl.setopt(CURLOPT_CURLU, url)
-  let dirmode = path.len > 0 and path[^1] == '/'
-  let op = FtpHandle(
-    curl: curl,
-    dirmode: dirmode
-  )
   curl.setopt(CURLOPT_HEADERDATA, op)
   curl.setopt(CURLOPT_HEADERFUNCTION, curlWriteHeader)
   curl.setopt(CURLOPT_WRITEDATA, op)
   curl.setopt(CURLOPT_WRITEFUNCTION, curlWriteBody)
   curl.setopt(CURLOPT_FTP_FILEMETHOD, CURLFTPMETHOD_SINGLECWD)
-  if dirmode:
-    const flags = cuint(CURLU_PUNY2IDN)
-    let surl = url.get(CURLUPART_URL, flags)
-    if surl == nil:
-      stdout.write("Cha-Control: ConnectionError " & $int(ERROR_INVALID_URL))
-      return
-    op.base = $surl
-    op.path = path
   let purl = getEnv("ALL_PROXY")
   if purl != "":
     curl.setopt(CURLOPT_PROXY, purl)
   if getEnv("REQUEST_METHOD") != "GET":
+    # fail
     let code = $int(ERROR_INVALID_METHOD)
     stdout.write("Cha-Control: ConnectionError " & $code & "\n")
-    return
-  let res = curl_easy_perform(curl)
-  if res != CURLE_OK:
-    if not op.statusline:
-      stdout.write(getCurlConnectionError(res))
-  elif op.dirmode:
-    op.finish()
+  else:
+    let res = curl_easy_perform(curl)
+    if res != CURLE_OK:
+      if not op.statusline:
+        stdout.write(getCurlConnectionError(res))
+    elif op.dirmode:
+      op.finish()
+  curl_url_cleanup(url)
   curl_easy_cleanup(curl)
 
 main()
diff --git a/adapter/protocol/gopher.nim b/adapter/protocol/gopher.nim
index 7ee7b625..7742613c 100644
--- a/adapter/protocol/gopher.nim
+++ b/adapter/protocol/gopher.nim
@@ -1,11 +1,11 @@
 import std/envvars
 
-import curlwrap
+import curl
 import curlerrors
+import curlwrap
 
 import ../gophertypes
 
-import bindings/curl
 import loader/connecterror
 import utils/twtstr
 
diff --git a/adapter/protocol/http.nim b/adapter/protocol/http.nim
index 45a78c46..d973bd1d 100644
--- a/adapter/protocol/http.nim
+++ b/adapter/protocol/http.nim
@@ -1,10 +1,10 @@
 import std/envvars
 import std/strutils
 
+import curl
 import curlerrors
 import curlwrap
 
-import bindings/curl
 import utils/twtstr
 
 type
bptato <nincsnevem662@gmail.com> 2023-07-02 14:13:02 +0200 Add platform object conversion to union type' href='/ahoang/chawan/commit/src/io/request.nim?id=341299a491183c7c99f98b0ed3ce13307ab20b17'>341299a4 ^
e2203257 ^
bfaf210d ^






51d83224 ^
36390a56 ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331