编写一些植入体或是小的下载者等,并且有要实现HTTP请求的需求的情况下,使用Windows的
WinHTTP
或是Wininet
两种方式去做是比较好的,因为他们不依赖于语言的HTTP实现,而是依赖于系统的API,对减小程序体积也有很大的作用。
在工作中使用Nim编写HTTP请求时候也是考虑使用WinHTTP API
来实现HTTP请求,并且为了OPSEC
考虑,请求全部使用TLS以及实现域前置,刚好存在一个Nim第三方库:https://github.com/treeform/puppy,可以实现需求,在同事尼哥实现了一些功能后发现,功能在Windows 7 X64
下无法使用,报错:
明显是Puppy的自定义报错,显示了WinHttpOpen
这个API执行后的错误,首先上网查找资料看到的都是Windows7默认情况下不会启用TLS1.1
以及TLS1.2
,当时在这里浪费了不少时间,查找资料发现的解决办法可以是更改注册表启用,但是这个很显然不是我们喜欢的办法。
于是查找资料发现可以在程序中使用WinHttpSetOption
来设置一些option,只需要指定WINHTTP_OPTION_SECURE_PROTOCOLS
,可以设置如下值:
于是乎找到Puppy库的路径发现最终在Windows平台实现HTTP请求功能的代码在目录:puppy\src\puppy\platforms\win32
,
主要关注第一个文件和第三个文件即可,然后在platform.nim
文件中,执行完WinHttpOpen
后添加如下代码设置可接受协议:
var dwFlags :DWORD = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 or WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2
let issucceed = WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, cast[ptr LPVOID](dwFlags.unsafeAddr), 4)
当然还需要在windefs.nim
中定义API结构:
WINHTTP_OPTION_SECURE_PROTOCOLS* = 84
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1* = 0x00000200
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2* = 0x00000800proc WinHttpSetOption*(
hInternet: HINTERNET,
dwOption: DWORD,
lpBuffer: LPVOID,
dwBufferLength: DWORD
): BOOL {.dynlib: "winhttp".}
添加完需要在puppy目录重新nimble install
,再重新编译程序后发现报错还是一样,才反应过来就是这个API本身报错,我先解决这个API本身的错误就好了,查看文档发现puppy这个库调用WinHttpOpen
,代理参数是使用的WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
,那么这个是“**Supported in Windows 8.1 and newer.**”
所以说Windows 7没办法使用,可以直接更改为WINHTTP_ACCESS_TYPE_NO_PROXY
,或是WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
,但是文档又说在 Windows 8.1 及更高版本上不推荐使用此选项。
咱也不知道为什么不推荐,所以说可以加一个判断系统版本来判断版本选择对应的代理方式
对应issues:https://github.com/treeform/puppy/issues/70,当时应该先看看lib的issues的,切记,甩自己两个大逼兜。
最后接着把刚开始的WinHttpSetOption
加到后面,确保奇奇怪怪的环境不会出问题,最终的代码就如下:
定义一些宏:
以及结构:
代码实现:
这样的话就可以在Windows 7 实现了。
加,这个字我已经说累了。