aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-11-30 12:48:35 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2020-11-30 15:20:05 +0100
commita1bef749032350a0247a809e6f428ffe199f9646 (patch)
tree4cd22e3de1d7d67d63e5a9c474f3a001907079ef
parentfetcher: enable HTTP/2.0 on systems that support it (diff)
downloadwireguard-windows-a1bef749032350a0247a809e6f428ffe199f9646.tar.xz
wireguard-windows-a1bef749032350a0247a809e6f428ffe199f9646.zip
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 <Jason@zx2c4.com>
-rw-r--r--updater/constants.go7
-rw-r--r--updater/downloader.go73
-rwxr-xr-xupdater/winhttp/httptest.exebin0 -> 3318784 bytes
-rw-r--r--updater/winhttp/mksyscall.go8
-rw-r--r--updater/winhttp/syscall_windows.go345
-rw-r--r--updater/winhttp/winhttp.go214
-rw-r--r--updater/winhttp/winhttp_test.go72
-rw-r--r--updater/winhttp/zsyscall_windows.go155
8 files changed, 846 insertions, 28 deletions
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
--- /dev/null
+++ b/updater/winhttp/httptest.exe
Binary files 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
+}