From a1bef749032350a0247a809e6f428ffe199f9646 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 30 Nov 2020 12:48:35 +0100 Subject: updater: another attempt at winhttp This reverts commit fbc3ceba56df06a61346f0b873f1e1d85c5b05a9, while reworking it too. This saves 2M in the binary. Signed-off-by: Jason A. Donenfeld --- updater/constants.go | 7 +- updater/downloader.go | 73 +++++--- updater/winhttp/httptest.exe | Bin 0 -> 3318784 bytes updater/winhttp/mksyscall.go | 8 + updater/winhttp/syscall_windows.go | 345 ++++++++++++++++++++++++++++++++++++ updater/winhttp/winhttp.go | 214 ++++++++++++++++++++++ updater/winhttp/winhttp_test.go | 72 ++++++++ updater/winhttp/zsyscall_windows.go | 155 ++++++++++++++++ 8 files changed, 846 insertions(+), 28 deletions(-) create mode 100755 updater/winhttp/httptest.exe create mode 100644 updater/winhttp/mksyscall.go create mode 100644 updater/winhttp/syscall_windows.go create mode 100644 updater/winhttp/winhttp.go create mode 100644 updater/winhttp/winhttp_test.go create mode 100644 updater/winhttp/zsyscall_windows.go (limited to 'updater') diff --git a/updater/constants.go b/updater/constants.go index b8e31473..104acea2 100644 --- a/updater/constants.go +++ b/updater/constants.go @@ -7,8 +7,11 @@ package updater const ( releasePublicKeyBase64 = "RWRNqGKtBXftKTKPpBPGDMe8jHLnFQ0EdRy8Wg0apV6vTDFLAODD83G4" - latestVersionURL = "https://download.wireguard.com/windows-client/latest.sig" - msiURL = "https://download.wireguard.com/windows-client/%s" + updateServerHost = "download.wireguard.com" + updateServerPort = 443 + updateServerUseHttps = true + latestVersionPath = "/windows-client/latest.sig" + msiPath = "/windows-client/%s" msiArchPrefix = "wireguard-%s-" msiSuffix = ".msi" ) diff --git a/updater/downloader.go b/updater/downloader.go index c0eca7c4..98159553 100644 --- a/updater/downloader.go +++ b/updater/downloader.go @@ -11,12 +11,12 @@ import ( "fmt" "hash" "io" - "net/http" "sync/atomic" "golang.org/x/crypto/blake2b" "golang.zx2c4.com/wireguard/windows/elevate" + "golang.zx2c4.com/wireguard/windows/updater/winhttp" "golang.zx2c4.com/wireguard/windows/version" ) @@ -47,30 +47,55 @@ type UpdateFound struct { hash [blake2b.Size256]byte } -func CheckForUpdate() (*UpdateFound, error) { +func CheckForUpdate() (updateFound *UpdateFound, err error) { + updateFound, _, _, err = checkForUpdate(false) + return +} + +func checkForUpdate(keepSession bool) (*UpdateFound, *winhttp.Session, *winhttp.Connection, error) { if !version.IsRunningOfficialVersion() { - return nil, errors.New("Build is not official, so updates are disabled") + return nil, nil, nil, errors.New("Build is not official, so updates are disabled") } - request, err := http.NewRequest(http.MethodGet, latestVersionURL, nil) + session, err := winhttp.NewSession(version.UserAgent()) if err != nil { - return nil, err + return nil, nil, nil, err } - request.Header.Add("User-Agent", version.UserAgent()) - response, err := http.DefaultClient.Do(request) + defer func() { + if err != nil || !keepSession { + session.Close() + } + }() + connection, err := session.Connect(updateServerHost, updateServerPort, updateServerUseHttps) if err != nil { - return nil, err + return nil, nil, nil, err } - defer response.Body.Close() + defer func() { + if err != nil || !keepSession { + connection.Close() + } + }() + response, err := connection.Get(latestVersionPath, true) + if err != nil { + return nil, nil, nil, err + } + defer response.Close() var fileList [1024 * 512] /* 512 KiB */ byte - bytesRead, err := response.Body.Read(fileList[:]) + bytesRead, err := response.Read(fileList[:]) if err != nil && (err != io.EOF || bytesRead == 0) { - return nil, err + return nil, nil, nil, err } files, err := readFileList(fileList[:bytesRead]) if err != nil { - return nil, err + return nil, nil, nil, err } - return findCandidate(files) + updateFound, err := findCandidate(files) + if err != nil { + return nil, nil, nil, err + } + if keepSession { + return updateFound, session, connection, nil + } + return updateFound, nil, nil, nil } var updateInProgress = uint32(0) @@ -88,11 +113,13 @@ func DownloadVerifyAndExecute(userToken uintptr) (progress chan DownloadProgress defer atomic.StoreUint32(&updateInProgress, 0) progress <- DownloadProgress{Activity: "Checking for update"} - update, err := CheckForUpdate() + update, session, connection, err := checkForUpdate(true) if err != nil { progress <- DownloadProgress{Error: err} return } + defer connection.Close() + defer session.Close() if update == nil { progress <- DownloadProgress{Error: errors.New("No update was found")} return @@ -113,21 +140,15 @@ func DownloadVerifyAndExecute(userToken uintptr) (progress chan DownloadProgress dp := DownloadProgress{Activity: "Downloading update"} progress <- dp - request, err := http.NewRequest(http.MethodGet, fmt.Sprintf(msiURL, update.name), nil) - if err != nil { - progress <- DownloadProgress{Error: err} - return - } - request.Header.Add("User-Agent", version.UserAgent()) - request.Header.Set("Accept-Encoding", "identity") - response, err := http.DefaultClient.Do(request) + response, err := connection.Get(fmt.Sprintf(msiPath, update.name), false) if err != nil { progress <- DownloadProgress{Error: err} return } - defer response.Body.Close() - if response.ContentLength >= 0 { - dp.BytesTotal = uint64(response.ContentLength) + defer response.Close() + length, err := response.Length() + if err == nil && length >= 0 { + dp.BytesTotal = length progress <- dp } hasher, err := blake2b.New256(nil) @@ -136,7 +157,7 @@ func DownloadVerifyAndExecute(userToken uintptr) (progress chan DownloadProgress return } pm := &progressHashWatcher{&dp, progress, hasher} - _, err = io.Copy(file, io.TeeReader(io.LimitReader(response.Body, 1024*1024*100 /* 100 MiB */), pm)) + _, err = io.Copy(file, io.TeeReader(io.LimitReader(response, 1024*1024*100 /* 100 MiB */), pm)) if err != nil { progress <- DownloadProgress{Error: err} return diff --git a/updater/winhttp/httptest.exe b/updater/winhttp/httptest.exe new file mode 100755 index 00000000..9f7ecda4 Binary files /dev/null and b/updater/winhttp/httptest.exe differ diff --git a/updater/winhttp/mksyscall.go b/updater/winhttp/mksyscall.go new file mode 100644 index 00000000..b714c7ee --- /dev/null +++ b/updater/winhttp/mksyscall.go @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package winhttp + +//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go diff --git a/updater/winhttp/syscall_windows.go b/updater/winhttp/syscall_windows.go new file mode 100644 index 00000000..8c3f857c --- /dev/null +++ b/updater/winhttp/syscall_windows.go @@ -0,0 +1,345 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package winhttp + +import ( + "golang.org/x/sys/windows" +) + +type _HINTERNET windows.Handle + +type Error uint32 + +const ( + _WINHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0 + _WINHTTP_ACCESS_TYPE_NO_PROXY = 1 + _WINHTTP_ACCESS_TYPE_NAMED_PROXY = 3 + _WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY = 4 + + _WINHTTP_FLAG_ASYNC = 0x10000000 + + _WINHTTP_INVALID_STATUS_CALLBACK = ^uintptr(0) + + _WINHTTP_CALLBACK_STATUS_RESOLVING_NAME = 0x00000001 + _WINHTTP_CALLBACK_STATUS_NAME_RESOLVED = 0x00000002 + _WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER = 0x00000004 + _WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER = 0x00000008 + _WINHTTP_CALLBACK_STATUS_SENDING_REQUEST = 0x00000010 + _WINHTTP_CALLBACK_STATUS_REQUEST_SENT = 0x00000020 + _WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE = 0x00000040 + _WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED = 0x00000080 + _WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION = 0x00000100 + _WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED = 0x00000200 + _WINHTTP_CALLBACK_STATUS_HANDLE_CREATED = 0x00000400 + _WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING = 0x00000800 + _WINHTTP_CALLBACK_STATUS_DETECTING_PROXY = 0x00001000 + _WINHTTP_CALLBACK_STATUS_REDIRECT = 0x00004000 + _WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE = 0x00008000 + _WINHTTP_CALLBACK_STATUS_SECURE_FAILURE = 0x00010000 + _WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE = 0x00020000 + _WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE = 0x00040000 + _WINHTTP_CALLBACK_STATUS_READ_COMPLETE = 0x00080000 + _WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE = 0x00100000 + _WINHTTP_CALLBACK_STATUS_REQUEST_ERROR = 0x00200000 + _WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE = 0x00400000 + _WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE = 0x01000000 + _WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE = 0x02000000 + _WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE = 0x04000000 + _WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE = 0x10000000 + _WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE = 0x20000000 + + _WINHTTP_CALLBACK_FLAG_RESOLVE_NAME = _WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | _WINHTTP_CALLBACK_STATUS_NAME_RESOLVED + _WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER = _WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | _WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER + _WINHTTP_CALLBACK_FLAG_SEND_REQUEST = _WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | _WINHTTP_CALLBACK_STATUS_REQUEST_SENT + _WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE = _WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | _WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED + _WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION = _WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | _WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED + _WINHTTP_CALLBACK_FLAG_HANDLES = _WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | _WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING + _WINHTTP_CALLBACK_FLAG_DETECTING_PROXY = _WINHTTP_CALLBACK_STATUS_DETECTING_PROXY + _WINHTTP_CALLBACK_FLAG_REDIRECT = _WINHTTP_CALLBACK_STATUS_REDIRECT + _WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE = _WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE + _WINHTTP_CALLBACK_FLAG_SECURE_FAILURE = _WINHTTP_CALLBACK_STATUS_SECURE_FAILURE + _WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE = _WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE + _WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE = _WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE + _WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE = _WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE + _WINHTTP_CALLBACK_FLAG_READ_COMPLETE = _WINHTTP_CALLBACK_STATUS_READ_COMPLETE + _WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE = _WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE + _WINHTTP_CALLBACK_FLAG_REQUEST_ERROR = _WINHTTP_CALLBACK_STATUS_REQUEST_ERROR + _WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE = _WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE + _WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS = _WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE | _WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE | _WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE | _WINHTTP_CALLBACK_STATUS_READ_COMPLETE | _WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE | _WINHTTP_CALLBACK_STATUS_REQUEST_ERROR | _WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE + _WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS = 0xffffffff + + _INTERNET_DEFAULT_PORT = 0 + _INTERNET_DEFAULT_HTTP_PORT = 80 + _INTERNET_DEFAULT_HTTPS_PORT = 443 + + _WINHTTP_FLAG_SECURE = 0x00800000 + _WINHTTP_FLAG_ESCAPE_PERCENT = 0x00000004 + _WINHTTP_FLAG_NULL_CODEPAGE = 0x00000008 + _WINHTTP_FLAG_BYPASS_PROXY_CACHE = 0x00000100 + _WINHTTP_FLAG_REFRESH = _WINHTTP_FLAG_BYPASS_PROXY_CACHE + _WINHTTP_FLAG_ESCAPE_DISABLE = 0x00000040 + _WINHTTP_FLAG_ESCAPE_DISABLE_QUERY = 0x00000080 + + _WINHTTP_QUERY_MIME_VERSION = 0 + _WINHTTP_QUERY_CONTENT_TYPE = 1 + _WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 + _WINHTTP_QUERY_CONTENT_ID = 3 + _WINHTTP_QUERY_CONTENT_DESCRIPTION = 4 + _WINHTTP_QUERY_CONTENT_LENGTH = 5 + _WINHTTP_QUERY_CONTENT_LANGUAGE = 6 + _WINHTTP_QUERY_ALLOW = 7 + _WINHTTP_QUERY_PUBLIC = 8 + _WINHTTP_QUERY_DATE = 9 + _WINHTTP_QUERY_EXPIRES = 10 + _WINHTTP_QUERY_LAST_MODIFIED = 11 + _WINHTTP_QUERY_MESSAGE_ID = 12 + _WINHTTP_QUERY_URI = 13 + _WINHTTP_QUERY_DERIVED_FROM = 14 + _WINHTTP_QUERY_COST = 15 + _WINHTTP_QUERY_LINK = 16 + _WINHTTP_QUERY_PRAGMA = 17 + _WINHTTP_QUERY_VERSION = 18 + _WINHTTP_QUERY_STATUS_CODE = 19 + _WINHTTP_QUERY_STATUS_TEXT = 20 + _WINHTTP_QUERY_RAW_HEADERS = 21 + _WINHTTP_QUERY_RAW_HEADERS_CRLF = 22 + _WINHTTP_QUERY_CONNECTION = 23 + _WINHTTP_QUERY_ACCEPT = 24 + _WINHTTP_QUERY_ACCEPT_CHARSET = 25 + _WINHTTP_QUERY_ACCEPT_ENCODING = 26 + _WINHTTP_QUERY_ACCEPT_LANGUAGE = 27 + _WINHTTP_QUERY_AUTHORIZATION = 28 + _WINHTTP_QUERY_CONTENT_ENCODING = 29 + _WINHTTP_QUERY_FORWARDED = 30 + _WINHTTP_QUERY_FROM = 31 + _WINHTTP_QUERY_IF_MODIFIED_SINCE = 32 + _WINHTTP_QUERY_LOCATION = 33 + _WINHTTP_QUERY_ORIG_URI = 34 + _WINHTTP_QUERY_REFERER = 35 + _WINHTTP_QUERY_RETRY_AFTER = 36 + _WINHTTP_QUERY_SERVER = 37 + _WINHTTP_QUERY_TITLE = 38 + _WINHTTP_QUERY_USER_AGENT = 39 + _WINHTTP_QUERY_WWW_AUTHENTICATE = 40 + _WINHTTP_QUERY_PROXY_AUTHENTICATE = 41 + _WINHTTP_QUERY_ACCEPT_RANGES = 42 + _WINHTTP_QUERY_SET_COOKIE = 43 + _WINHTTP_QUERY_COOKIE = 44 + _WINHTTP_QUERY_REQUEST_METHOD = 45 + _WINHTTP_QUERY_REFRESH = 46 + _WINHTTP_QUERY_CONTENT_DISPOSITION = 47 + _WINHTTP_QUERY_AGE = 48 + _WINHTTP_QUERY_CACHE_CONTROL = 49 + _WINHTTP_QUERY_CONTENT_BASE = 50 + _WINHTTP_QUERY_CONTENT_LOCATION = 51 + _WINHTTP_QUERY_CONTENT_MD5 = 52 + _WINHTTP_QUERY_CONTENT_RANGE = 53 + _WINHTTP_QUERY_ETAG = 54 + _WINHTTP_QUERY_HOST = 55 + _WINHTTP_QUERY_IF_MATCH = 56 + _WINHTTP_QUERY_IF_NONE_MATCH = 57 + _WINHTTP_QUERY_IF_RANGE = 58 + _WINHTTP_QUERY_IF_UNMODIFIED_SINCE = 59 + _WINHTTP_QUERY_MAX_FORWARDS = 60 + _WINHTTP_QUERY_PROXY_AUTHORIZATION = 61 + _WINHTTP_QUERY_RANGE = 62 + _WINHTTP_QUERY_TRANSFER_ENCODING = 63 + _WINHTTP_QUERY_UPGRADE = 64 + _WINHTTP_QUERY_VARY = 65 + _WINHTTP_QUERY_VIA = 66 + _WINHTTP_QUERY_WARNING = 67 + _WINHTTP_QUERY_EXPECT = 68 + _WINHTTP_QUERY_PROXY_CONNECTION = 69 + _WINHTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 + _WINHTTP_QUERY_PROXY_SUPPORT = 75 + _WINHTTP_QUERY_AUTHENTICATION_INFO = 76 + _WINHTTP_QUERY_PASSPORT_URLS = 77 + _WINHTTP_QUERY_PASSPORT_CONFIG = 78 + _WINHTTP_QUERY_MAX = 78 + _WINHTTP_QUERY_CUSTOM = 65535 + _WINHTTP_QUERY_FLAG_REQUEST_HEADERS = 0x80000000 + _WINHTTP_QUERY_FLAG_SYSTEMTIME = 0x40000000 + _WINHTTP_QUERY_FLAG_NUMBER = 0x20000000 + _WINHTTP_QUERY_FLAG_NUMBER64 = 0x08000000 + + _WINHTTP_FIRST_OPTION = _WINHTTP_OPTION_CALLBACK + _WINHTTP_OPTION_CALLBACK = 1 + _WINHTTP_OPTION_RESOLVE_TIMEOUT = 2 + _WINHTTP_OPTION_CONNECT_TIMEOUT = 3 + _WINHTTP_OPTION_CONNECT_RETRIES = 4 + _WINHTTP_OPTION_SEND_TIMEOUT = 5 + _WINHTTP_OPTION_RECEIVE_TIMEOUT = 6 + _WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT = 7 + _WINHTTP_OPTION_HANDLE_TYPE = 9 + _WINHTTP_OPTION_READ_BUFFER_SIZE = 12 + _WINHTTP_OPTION_WRITE_BUFFER_SIZE = 13 + _WINHTTP_OPTION_PARENT_HANDLE = 21 + _WINHTTP_OPTION_EXTENDED_ERROR = 24 + _WINHTTP_OPTION_SECURITY_FLAGS = 31 + _WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT = 32 + _WINHTTP_OPTION_URL = 34 + _WINHTTP_OPTION_SECURITY_KEY_BITNESS = 36 + _WINHTTP_OPTION_PROXY = 38 + _WINHTTP_OPTION_PROXY_RESULT_ENTRY = 39 + _WINHTTP_OPTION_USER_AGENT = 41 + _WINHTTP_OPTION_CONTEXT_VALUE = 45 + _WINHTTP_OPTION_CLIENT_CERT_CONTEXT = 47 + _WINHTTP_OPTION_REQUEST_PRIORITY = 58 + _WINHTTP_OPTION_HTTP_VERSION = 59 + _WINHTTP_OPTION_DISABLE_FEATURE = 63 + _WINHTTP_OPTION_CODEPAGE = 68 + _WINHTTP_OPTION_MAX_CONNS_PER_SERVER = 73 + _WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER = 74 + _WINHTTP_OPTION_AUTOLOGON_POLICY = 77 + _WINHTTP_OPTION_SERVER_CERT_CONTEXT = 78 + _WINHTTP_OPTION_ENABLE_FEATURE = 79 + _WINHTTP_OPTION_WORKER_THREAD_COUNT = 80 + _WINHTTP_OPTION_PASSPORT_COBRANDING_TEXT = 81 + _WINHTTP_OPTION_PASSPORT_COBRANDING_URL = 82 + _WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH = 83 + _WINHTTP_OPTION_SECURE_PROTOCOLS = 84 + _WINHTTP_OPTION_ENABLETRACING = 85 + _WINHTTP_OPTION_PASSPORT_SIGN_OUT = 86 + _WINHTTP_OPTION_PASSPORT_RETURN_URL = 87 + _WINHTTP_OPTION_REDIRECT_POLICY = 88 + _WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS = 89 + _WINHTTP_OPTION_MAX_HTTP_STATUS_CONTINUE = 90 + _WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE = 91 + _WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE = 92 + _WINHTTP_OPTION_CONNECTION_INFO = 93 + _WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST = 94 + _WINHTTP_OPTION_SPN = 96 + _WINHTTP_OPTION_GLOBAL_PROXY_CREDS = 97 + _WINHTTP_OPTION_GLOBAL_SERVER_CREDS = 98 + _WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT = 99 + _WINHTTP_OPTION_REJECT_USERPWD_IN_URL = 100 + _WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS = 101 + _WINHTTP_OPTION_RECEIVE_PROXY_CONNECT_RESPONSE = 103 + _WINHTTP_OPTION_IS_PROXY_CONNECT_RESPONSE = 104 + _WINHTTP_OPTION_SERVER_SPN_USED = 106 + _WINHTTP_OPTION_PROXY_SPN_USED = 107 + _WINHTTP_OPTION_SERVER_CBT = 108 + _WINHTTP_OPTION_UNSAFE_HEADER_PARSING = 110 + _WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS = 111 + _WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET = 114 + _WINHTTP_OPTION_WEB_SOCKET_CLOSE_TIMEOUT = 115 + _WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL = 116 + _WINHTTP_OPTION_DECOMPRESSION = 118 + _WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE = 122 + _WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE = 123 + _WINHTTP_OPTION_TCP_PRIORITY_HINT = 128 + _WINHTTP_OPTION_CONNECTION_FILTER = 131 + _WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL = 133 + _WINHTTP_OPTION_HTTP_PROTOCOL_USED = 134 + _WINHTTP_OPTION_KDC_PROXY_SETTINGS = 136 + _WINHTTP_OPTION_ENCODE_EXTRA = 138 + _WINHTTP_OPTION_DISABLE_STREAM_QUEUE = 139 + _WINHTTP_OPTION_IPV6_FAST_FALLBACK = 140 + _WINHTTP_OPTION_CONNECTION_STATS_V0 = 141 + _WINHTTP_OPTION_REQUEST_TIMES = 142 + _WINHTTP_OPTION_EXPIRE_CONNECTION = 143 + _WINHTTP_OPTION_DISABLE_SECURE_PROTOCOL_FALLBACK = 144 + _WINHTTP_OPTION_HTTP_PROTOCOL_REQUIRED = 145 + _WINHTTP_OPTION_REQUEST_STATS = 146 + _WINHTTP_OPTION_SERVER_CERT_CHAIN_CONTEXT = 147 + _WINHTTP_LAST_OPTION = _WINHTTP_OPTION_SERVER_CERT_CHAIN_CONTEXT + + _ICU_ESCAPE = 0x80000000 + _ICU_ESCAPE_AUTHORITY = 0x00002000 + _ICU_REJECT_USERPWD = 0x00004000 + + _INTERNET_SCHEME_HTTP = 1 + _INTERNET_SCHEME_HTTPS = 2 + _INTERNET_SCHEME_FTP = 3 + _INTERNET_SCHEME_SOCKS = 4 + + _WINHTTP_ERROR_BASE = 12000 + _ERROR_WINHTTP_OUT_OF_HANDLES = Error(12000 + 1) + _ERROR_WINHTTP_TIMEOUT = Error(12000 + 2) + _ERROR_WINHTTP_INTERNAL_ERROR = Error(12000 + 4) + _ERROR_WINHTTP_INVALID_URL = Error(12000 + 5) + _ERROR_WINHTTP_UNRECOGNIZED_SCHEME = Error(12000 + 6) + _ERROR_WINHTTP_NAME_NOT_RESOLVED = Error(12000 + 7) + _ERROR_WINHTTP_INVALID_OPTION = Error(12000 + 9) + _ERROR_WINHTTP_OPTION_NOT_SETTABLE = Error(12000 + 11) + _ERROR_WINHTTP_SHUTDOWN = Error(12000 + 12) + _ERROR_WINHTTP_LOGIN_FAILURE = Error(12000 + 15) + _ERROR_WINHTTP_OPERATION_CANCELLED = Error(12000 + 17) + _ERROR_WINHTTP_INCORRECT_HANDLE_TYPE = Error(12000 + 18) + _ERROR_WINHTTP_INCORRECT_HANDLE_STATE = Error(12000 + 19) + _ERROR_WINHTTP_CANNOT_CONNECT = Error(12000 + 29) + _ERROR_WINHTTP_CONNECTION_ERROR = Error(12000 + 30) + _ERROR_WINHTTP_RESEND_REQUEST = Error(12000 + 32) + _ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED = Error(12000 + 44) + _ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN = Error(12000 + 100) + _ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND = Error(12000 + 101) + _ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND = Error(12000 + 102) + _ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN = Error(12000 + 103) + _ERROR_WINHTTP_HEADER_NOT_FOUND = Error(12000 + 150) + _ERROR_WINHTTP_INVALID_SERVER_RESPONSE = Error(12000 + 152) + _ERROR_WINHTTP_INVALID_HEADER = Error(12000 + 153) + _ERROR_WINHTTP_INVALID_QUERY_REQUEST = Error(12000 + 154) + _ERROR_WINHTTP_HEADER_ALREADY_EXISTS = Error(12000 + 155) + _ERROR_WINHTTP_REDIRECT_FAILED = Error(12000 + 156) + _ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR = Error(12000 + 178) + _ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT = Error(12000 + 166) + _ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT = Error(12000 + 167) + _ERROR_WINHTTP_UNHANDLED_SCRIPT_TYPE = Error(12000 + 176) + _ERROR_WINHTTP_SCRIPT_EXECUTION_ERROR = Error(12000 + 177) + _ERROR_WINHTTP_NOT_INITIALIZED = Error(12000 + 172) + _ERROR_WINHTTP_SECURE_FAILURE = Error(12000 + 175) + _ERROR_WINHTTP_SECURE_CERT_DATE_INVALID = Error(12000 + 37) + _ERROR_WINHTTP_SECURE_CERT_CN_INVALID = Error(12000 + 38) + _ERROR_WINHTTP_SECURE_INVALID_CA = Error(12000 + 45) + _ERROR_WINHTTP_SECURE_CERT_REV_FAILED = Error(12000 + 57) + _ERROR_WINHTTP_SECURE_CHANNEL_ERROR = Error(12000 + 157) + _ERROR_WINHTTP_SECURE_INVALID_CERT = Error(12000 + 169) + _ERROR_WINHTTP_SECURE_CERT_REVOKED = Error(12000 + 170) + _ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE = Error(12000 + 179) + _ERROR_WINHTTP_AUTODETECTION_FAILED = Error(12000 + 180) + _ERROR_WINHTTP_HEADER_COUNT_EXCEEDED = Error(12000 + 181) + _ERROR_WINHTTP_HEADER_SIZE_OVERFLOW = Error(12000 + 182) + _ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW = Error(12000 + 183) + _ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW = Error(12000 + 184) + _ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY = Error(12000 + 185) + _ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY = Error(12000 + 186) + _ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED_PROXY = Error(12000 + 187) + _ERROR_WINHTTP_SECURE_FAILURE_PROXY = Error(12000 + 188) + _ERROR_WINHTTP_RESERVED_189 = Error(12000 + 189) + _ERROR_WINHTTP_HTTP_PROTOCOL_MISMATCH = Error(12000 + 190) + _WINHTTP_ERROR_LAST = _WINHTTP_ERROR_BASE + 190 +) + +type _URL_COMPONENTS struct { + structSize uint32 + scheme *uint16 + schemeLength uint32 + schemeType uint32 + hostName *uint16 + hostNameLength uint32 + port uint16 + username *uint16 + usernameLength uint32 + password *uint16 + passwordLength uint32 + urlPath *uint16 + urlPathLength uint32 + extraInfo *uint16 + extraInfoLength uint32 +} + +//sys winHttpOpen(userAgent *uint16, accessType uint32, proxy *uint16, proxyBypass *uint16, flags uint32) (sessionHandle _HINTERNET, err error) = winhttp.WinHttpOpen +//sys winHttpSetStatusCallback(handle _HINTERNET, callback uintptr, notificationFlags uint32, reserved uintptr) (previousCallback uintptr, err error) [failretval==_WINHTTP_INVALID_STATUS_CALLBACK] = winhttp.WinHttpSetStatusCallback +//sys winHttpCloseHandle(handle _HINTERNET) (err error) = winhttp.WinHttpCloseHandle +//sys winHttpConnect(sessionHandle _HINTERNET, serverName *uint16, serverPort uint16, reserved uint32) (handle _HINTERNET, err error) = winhttp.WinHttpConnect +//sys winHttpOpenRequest(connectHandle _HINTERNET, verb *uint16, objectName *uint16, version *uint16, referrer *uint16, acceptTypes **uint16, flags uint32) (requestHandle _HINTERNET, err error) = winhttp.WinHttpOpenRequest +//sys winHttpSendRequest(requestHandle _HINTERNET, headers *uint16, headersLength uint32, optional *byte, optionalLength uint32, totalLength uint32, context uintptr) (err error) = winhttp.WinHttpSendRequest +//sys winHttpReceiveResponse(requestHandle _HINTERNET, reserved uintptr) (err error) = winhttp.WinHttpReceiveResponse +//sys winHttpQueryHeaders(requestHandle _HINTERNET, infoLevel uint32, name *uint16, buffer unsafe.Pointer, bufferLen *uint32, index *uint32) (err error) = winhttp.WinHttpQueryHeaders +//sys winHttpQueryDataAvailable(requestHandle _HINTERNET, bytesAvailable *uint32) (err error) = winhttp.WinHttpQueryDataAvailable +//sys winHttpReadData(requestHandle _HINTERNET, buffer *byte, bufferSize uint32, bytesRead *uint32) (err error) = winhttp.WinHttpReadData +//sys winHttpCrackUrl(url *uint16, urlSize uint32, flags uint32, components *_URL_COMPONENTS) (err error) = winhttp.WinHttpCrackUrl +//sys winHttpSetOption(sessionOrRequestHandle _HINTERNET, option uint32, buffer unsafe.Pointer, bufferLen uint32) (err error) = winhttp.WinHttpSetOption diff --git a/updater/winhttp/winhttp.go b/updater/winhttp/winhttp.go new file mode 100644 index 00000000..02be18a3 --- /dev/null +++ b/updater/winhttp/winhttp.go @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package winhttp + +import ( + "fmt" + "io" + "runtime" + "strconv" + "strings" + "sync/atomic" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +type Session struct { + handle _HINTERNET +} +type Connection struct { + handle _HINTERNET + session *Session + https bool +} +type Response struct { + handle _HINTERNET + connection *Connection +} + +func convertError(err *error) { + if *err == nil { + return + } + if se, ok := (*err).(syscall.Errno); ok { + if se > _WINHTTP_ERROR_BASE && se <= _WINHTTP_ERROR_LAST { + *err = Error(se) + } + } +} + +func isWin7() bool { + maj, min, _ := windows.RtlGetNtVersionNumbers() + return maj < 6 || (maj == 6 && min <= 1) +} + +func NewSession(userAgent string) (session *Session, err error) { + session = new(Session) + defer convertError(&err) + defer func() { + if err != nil { + session.Close() + session = nil + } + }() + userAgent16, err := windows.UTF16PtrFromString(userAgent) + if err != nil { + return + } + var proxyFlag uint32 = _WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY + if isWin7() { + proxyFlag = _WINHTTP_ACCESS_TYPE_DEFAULT_PROXY + } + session.handle, err = winHttpOpen(userAgent16, proxyFlag, nil, nil, 0) + if err != nil { + return + } + var enableHttp2 uint32 = 1 + _ = winHttpSetOption(session.handle, _WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, unsafe.Pointer(&enableHttp2), uint32(unsafe.Sizeof(enableHttp2))) // Don't check return value, in case of old Windows + + runtime.SetFinalizer(session, func(session *Session) { + session.Close() + }) + return +} + +func (session *Session) Close() (err error) { + defer convertError(&err) + handle := (_HINTERNET)(atomic.SwapUintptr((*uintptr)(&session.handle), 0)) + if handle == 0 { + return + } + return winHttpCloseHandle(handle) +} + +func (session *Session) Connect(server string, port uint16, https bool) (connection *Connection, err error) { + connection = &Connection{session: session} + defer convertError(&err) + defer func() { + if err != nil { + connection.Close() + connection = nil + } + }() + server16, err := windows.UTF16PtrFromString(server) + if err != nil { + return + } + connection.handle, err = winHttpConnect(session.handle, server16, port, 0) + if err != nil { + return + } + connection.https = https + + runtime.SetFinalizer(connection, func(connection *Connection) { + connection.Close() + }) + return +} + +func (connection *Connection) Close() (err error) { + defer convertError(&err) + handle := (_HINTERNET)(atomic.SwapUintptr((*uintptr)(&connection.handle), 0)) + if handle == 0 { + return + } + return winHttpCloseHandle(handle) +} + +func (connection *Connection) Get(path string, refresh bool) (response *Response, err error) { + response = &Response{connection: connection} + defer convertError(&err) + defer func() { + if err != nil { + response.Close() + response = nil + } + }() + var flags uint32 + if refresh { + flags |= _WINHTTP_FLAG_REFRESH + } + if connection.https { + flags |= _WINHTTP_FLAG_SECURE + } + path16, err := windows.UTF16PtrFromString(path) + if err != nil { + return + } + get16, err := windows.UTF16PtrFromString("GET") + if err != nil { + return + } + response.handle, err = winHttpOpenRequest(connection.handle, get16, path16, nil, nil, nil, flags) + if err != nil { + return + } + err = winHttpSendRequest(response.handle, nil, 0, nil, 0, 0, 0) + if err != nil { + return + } + err = winHttpReceiveResponse(response.handle, 0) + if err != nil { + return + } + + runtime.SetFinalizer(response, func(response *Response) { + response.Close() + }) + return +} + +func (response *Response) Length() (length uint64, err error) { + defer convertError(&err) + numBuf := make([]uint16, 22) + numLen := uint32(len(numBuf) * 2) + err = winHttpQueryHeaders(response.handle, _WINHTTP_QUERY_CONTENT_LENGTH, nil, unsafe.Pointer(&numBuf[0]), &numLen, nil) + if err != nil { + return + } + length, err = strconv.ParseUint(windows.UTF16ToString(numBuf[:numLen]), 10, 64) + if err != nil { + return + } + return +} + +func (response *Response) Read(p []byte) (n int, err error) { + defer convertError(&err) + if len(p) == 0 { + return 0, nil + } + var bytesRead uint32 + err = winHttpReadData(response.handle, &p[0], uint32(len(p)), &bytesRead) + if err != nil { + return 0, nil + } + if bytesRead == 0 || int(bytesRead) < 0 { + return 0, io.EOF + } + return int(bytesRead), nil +} + +func (response *Response) Close() (err error) { + defer convertError(&err) + handle := (_HINTERNET)(atomic.SwapUintptr((*uintptr)(&response.handle), 0)) + if handle == 0 { + return + } + return winHttpCloseHandle(handle) +} + +func (error Error) Error() string { + var message [2048]uint16 + n, err := windows.FormatMessage(windows.FORMAT_MESSAGE_FROM_HMODULE|windows.FORMAT_MESSAGE_IGNORE_INSERTS|windows.FORMAT_MESSAGE_MAX_WIDTH_MASK, + modwinhttp.Handle(), uint32(error), 0, message[:], nil) + if err != nil { + return fmt.Sprintf("WinHTTP error #%d", error) + } + return strings.TrimSpace(windows.UTF16ToString(message[:n])) +} diff --git a/updater/winhttp/winhttp_test.go b/updater/winhttp/winhttp_test.go new file mode 100644 index 00000000..da590cf2 --- /dev/null +++ b/updater/winhttp/winhttp_test.go @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package winhttp + +import ( + "fmt" + "io" + "io/ioutil" + "runtime" + "testing" +) + +type progressPrinter struct { + downloaded uint64 + total uint64 +} + +func (pp *progressPrinter) Write(p []byte) (int, error) { + bytes := len(p) + pp.downloaded += uint64(bytes) + fmt.Printf("%d/%d bytes, %f%%\n", pp.downloaded, pp.total, float64(pp.downloaded)/float64(pp.total)*100.0) + return bytes, nil +} + +func TestResponse(t *testing.T) { + session, err := NewSession("WinHTTP Test Suite/1.0") + if err != nil { + t.Fatal(err) + } + connection, err := session.Connect("zx2c4.com", 443, true) + if err != nil { + t.Fatal(err) + } + r, err := connection.Get("/ip", true) + length, err := r.Length() + if err != nil { + t.Fatal(err) + } + fmt.Printf("The length is %d\n", length) + bytes, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err) + } + fmt.Println(string(bytes)) + r.Close() + + connection, err = session.Connect("speed.hetzner.de", 443, true) + if err != nil { + t.Fatal(err) + } + r, err = connection.Get("/10GB.bin", false) + if err != nil { + t.Fatal(err) + } + length, err = r.Length() + if err != nil { + t.Fatal(err) + } + amountRead, err := io.Copy(&progressPrinter{total: length}, r) + if err != nil { + t.Fatal(err) + } + r.Close() + if length != uint64(amountRead) { + t.Fatalf("Expected to read %d, but only read %d", length, amountRead) + } + + runtime.GC() // Try to force the finalizers to be called +} diff --git a/updater/winhttp/zsyscall_windows.go b/updater/winhttp/zsyscall_windows.go new file mode 100644 index 00000000..1c45994f --- /dev/null +++ b/updater/winhttp/zsyscall_windows.go @@ -0,0 +1,155 @@ +// Code generated by 'go generate'; DO NOT EDIT. + +package winhttp + +import ( + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var _ unsafe.Pointer + +// Do the interface allocations only once for common +// Errno values. +const ( + errnoERROR_IO_PENDING = 997 +) + +var ( + errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) + errERROR_EINVAL error = syscall.EINVAL +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return errERROR_EINVAL + case errnoERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} + +var ( + modwinhttp = windows.NewLazySystemDLL("winhttp.dll") + + procWinHttpCloseHandle = modwinhttp.NewProc("WinHttpCloseHandle") + procWinHttpConnect = modwinhttp.NewProc("WinHttpConnect") + procWinHttpCrackUrl = modwinhttp.NewProc("WinHttpCrackUrl") + procWinHttpOpen = modwinhttp.NewProc("WinHttpOpen") + procWinHttpOpenRequest = modwinhttp.NewProc("WinHttpOpenRequest") + procWinHttpQueryDataAvailable = modwinhttp.NewProc("WinHttpQueryDataAvailable") + procWinHttpQueryHeaders = modwinhttp.NewProc("WinHttpQueryHeaders") + procWinHttpReadData = modwinhttp.NewProc("WinHttpReadData") + procWinHttpReceiveResponse = modwinhttp.NewProc("WinHttpReceiveResponse") + procWinHttpSendRequest = modwinhttp.NewProc("WinHttpSendRequest") + procWinHttpSetOption = modwinhttp.NewProc("WinHttpSetOption") + procWinHttpSetStatusCallback = modwinhttp.NewProc("WinHttpSetStatusCallback") +) + +func winHttpCloseHandle(handle _HINTERNET) (err error) { + r1, _, e1 := syscall.Syscall(procWinHttpCloseHandle.Addr(), 1, uintptr(handle), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpConnect(sessionHandle _HINTERNET, serverName *uint16, serverPort uint16, reserved uint32) (handle _HINTERNET, err error) { + r0, _, e1 := syscall.Syscall6(procWinHttpConnect.Addr(), 4, uintptr(sessionHandle), uintptr(unsafe.Pointer(serverName)), uintptr(serverPort), uintptr(reserved), 0, 0) + handle = _HINTERNET(r0) + if handle == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpCrackUrl(url *uint16, urlSize uint32, flags uint32, components *_URL_COMPONENTS) (err error) { + r1, _, e1 := syscall.Syscall6(procWinHttpCrackUrl.Addr(), 4, uintptr(unsafe.Pointer(url)), uintptr(urlSize), uintptr(flags), uintptr(unsafe.Pointer(components)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpOpen(userAgent *uint16, accessType uint32, proxy *uint16, proxyBypass *uint16, flags uint32) (sessionHandle _HINTERNET, err error) { + r0, _, e1 := syscall.Syscall6(procWinHttpOpen.Addr(), 5, uintptr(unsafe.Pointer(userAgent)), uintptr(accessType), uintptr(unsafe.Pointer(proxy)), uintptr(unsafe.Pointer(proxyBypass)), uintptr(flags), 0) + sessionHandle = _HINTERNET(r0) + if sessionHandle == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpOpenRequest(connectHandle _HINTERNET, verb *uint16, objectName *uint16, version *uint16, referrer *uint16, acceptTypes **uint16, flags uint32) (requestHandle _HINTERNET, err error) { + r0, _, e1 := syscall.Syscall9(procWinHttpOpenRequest.Addr(), 7, uintptr(connectHandle), uintptr(unsafe.Pointer(verb)), uintptr(unsafe.Pointer(objectName)), uintptr(unsafe.Pointer(version)), uintptr(unsafe.Pointer(referrer)), uintptr(unsafe.Pointer(acceptTypes)), uintptr(flags), 0, 0) + requestHandle = _HINTERNET(r0) + if requestHandle == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpQueryDataAvailable(requestHandle _HINTERNET, bytesAvailable *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procWinHttpQueryDataAvailable.Addr(), 2, uintptr(requestHandle), uintptr(unsafe.Pointer(bytesAvailable)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpQueryHeaders(requestHandle _HINTERNET, infoLevel uint32, name *uint16, buffer unsafe.Pointer, bufferLen *uint32, index *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procWinHttpQueryHeaders.Addr(), 6, uintptr(requestHandle), uintptr(infoLevel), uintptr(unsafe.Pointer(name)), uintptr(buffer), uintptr(unsafe.Pointer(bufferLen)), uintptr(unsafe.Pointer(index))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpReadData(requestHandle _HINTERNET, buffer *byte, bufferSize uint32, bytesRead *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procWinHttpReadData.Addr(), 4, uintptr(requestHandle), uintptr(unsafe.Pointer(buffer)), uintptr(bufferSize), uintptr(unsafe.Pointer(bytesRead)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpReceiveResponse(requestHandle _HINTERNET, reserved uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procWinHttpReceiveResponse.Addr(), 2, uintptr(requestHandle), uintptr(reserved), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpSendRequest(requestHandle _HINTERNET, headers *uint16, headersLength uint32, optional *byte, optionalLength uint32, totalLength uint32, context uintptr) (err error) { + r1, _, e1 := syscall.Syscall9(procWinHttpSendRequest.Addr(), 7, uintptr(requestHandle), uintptr(unsafe.Pointer(headers)), uintptr(headersLength), uintptr(unsafe.Pointer(optional)), uintptr(optionalLength), uintptr(totalLength), uintptr(context), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpSetOption(sessionOrRequestHandle _HINTERNET, option uint32, buffer unsafe.Pointer, bufferLen uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procWinHttpSetOption.Addr(), 4, uintptr(sessionOrRequestHandle), uintptr(option), uintptr(buffer), uintptr(bufferLen), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func winHttpSetStatusCallback(handle _HINTERNET, callback uintptr, notificationFlags uint32, reserved uintptr) (previousCallback uintptr, err error) { + r0, _, e1 := syscall.Syscall6(procWinHttpSetStatusCallback.Addr(), 4, uintptr(handle), uintptr(callback), uintptr(notificationFlags), uintptr(reserved), 0, 0) + previousCallback = uintptr(r0) + if previousCallback == _WINHTTP_INVALID_STATUS_CALLBACK { + err = errnoErr(e1) + } + return +} -- cgit v1.2.3-59-g8ed1b