Что нового

работа с https tcp функциями

alex33

Скриптер
Сообщения
1,457
Репутация
186
Каким образом можно работать tcp функциями по протоколу https? все передаваемые данные как-то надо зашифровывать и расшифровывать, браузеры это как-то делают
вот с http всё просто
я соединяюсь TCPConnect
потом отправляю TCPSend заголовки типо
Код:
GET / HTTP/1.1
Host: test.ru
User-agent: my_user-agent
потом через TCPRecv читаю ответ сервера ну типо
Код:
HTTP/1.1 200 Ok
Server: nginx
Content-Type: text/html
Content-Length: 7

контент
я там обрабатываю этот ответ сервера
и всё хорошё работает.
но это по http
а вот https? Там шифрование...
Туда надо и посылать таким способом и возвращается зашифрованный текст
Код:
0x1603000053...
(очень большая строка такого вида)
а вот как же его расшифровать?
или в AutoIt такое сделать не возможно и следует использовать WinHttp или функции Inet?
 
Автор
alex33

alex33

Скриптер
Сообщения
1,457
Репутация
186
UP!

Думаю здесь наверно понадобится OpenSSL или что-то другое?
Что же, никто не знает что ли?
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Лучше использовать winhttp или wininet. Если вы конечно не любитель поизобретать велосипеды.
 
Автор
alex33

alex33

Скриптер
Сообщения
1,457
Репутация
186
Ну так что, ответы по теме будут или нет?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Подниму ка я эту тему...

Пример:

Код:
Global Const $iTCP_PORT 				= 80
Global Const $iTCP_MAXBYTES 			= 256 * 1024
Global Const $sTCP_USERAGENT			= 'Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0'
Global Const $sTCP_HTTP_VER				= '1.1'

TCPStartup()
Opt('TCPTimeOut', 5000)

$sURL = 'https://www.autoitscript.com/files/autoit3/autoit-v3-setup.exe'
$sFile = @DesktopDir & '\autoit-v3-setup.exe'

$aSplit = __TCP_SplitURL($sURL)
$sHeader = __TCP_GetHeader($aSplit[0], $aSplit[1], $aSplit[2])
$sLocation = __TCP_GetTagHeader($sHeader, 'Location')
$sLength = InetGetSize($sLocation) ;Number(__TCP_GetTagHeader($sHeader, 'Content-Length'))

If $sLocation <> '' Then
	ConsoleWrite('New Location: ' & $sLocation & @LF)
	$aSplit = __TCP_SplitURL($sLocation)
	$sLength = InetGetSize($sLocation)
EndIf

__TCP_GetFile($aSplit[0], $aSplit[1], $aSplit[2], $sFile)

If $sLength = FileGetSize($sFile) Then
	MsgBox(64, 'Title', 'File downloaded')
Else
	MsgBox(48, 'Title', 'File NOT downloaded')
EndIf

TCPShutdown()

Func __TCP_Connect($sHost, $iPort = '')
	If Not StringIsDigit($iPort) Or $iPort = '' Then
		$iPort = $iTCP_PORT
	EndIf
	
	Local $sName_To_IP = TCPNameToIP($sHost)
	Local $iSocket = TCPConnect($sName_To_IP, $iPort)
	
	If $iSocket = -1 Then
		TCPCloseSocket($iSocket)
		Return SetError(1, 0, '')
	EndIf
	
	Return $iSocket
EndFunc

Func __TCP_Request($sHost, $sPage, $iSocket, $sRequest = 'GET')
	Local $sCommand = ''
	
	$sCommand &= $sRequest & ' ' & $sPage & ' HTTP/' & $sTCP_HTTP_VER & @CRLF
	$sCommand &= 'Host: ' & $sHost & @CRLF
	$sCommand &= 'User-Agent: ' & $sTCP_USERAGENT & @CRLF
	$sCommand &= 'Connection: close' & @CRLF & @CRLF
	
	Local $iBytesSent = TCPSend($iSocket, $sCommand)
	Return SetError(Int($iBytesSent = 0), @error, $iBytesSent)
EndFunc

Func __TCP_GetFile($sHost, $sPage, $iPort, $sFile)
	Local $sData
	
	$iSocket = __TCP_Connect($sHost, $iPort)
	
	If @error Then
		Return SetError(1, 0, '')
	EndIf
	
	__TCP_Request($sHost, $sPage, $iSocket, 'GET')
	
	If @error Then
		TCPCloseSocket($iSocket)
		Return SetError(2, 0, '')
	EndIf
	
	$hFile = FileOpen($sFile, 18)
	
	While 1
		$sData = TCPRecv($iSocket, $iTCP_MAXBYTES, 1)
		
		If @error <> 0 Then
			ExitLoop
		EndIf
		
		FileWrite($hFile, $sData)
	WEnd
	
	FileClose($hFile)
	TCPCloseSocket($iSocket)
EndFunc

Func __TCP_GetHeader($sHost, $sPage, $iPort, $iSocket = 0)
	Local $sData
	
	If $iSocket = 0 Then
		$iSocket = __TCP_Connect($sHost, $iPort)
		
		If @error Then
			Return SetError(1, 0, '')
		EndIf
		
		__TCP_Request($sHost, $sPage, $iSocket, 'HEAD')
		
		If @error Then
			TCPCloseSocket($iSocket)
			Return SetError(2, 0, '')
		EndIf
	EndIf
	
	While 1
		$sData &= TCPRecv($iSocket, $iTCP_MAXBYTES)
		
		If @error <> 0 Then
			ExitLoop
		EndIf
	WEnd
	
	TCPCloseSocket($iSocket)
	
	Return $sData
EndFunc

Func __TCP_GetTagHeader($sHeader, $sTag)
	Local $aRet = StringRegExp($sHeader, '(?i)' & $sTag & ': ([^\r\n]+)', 3)
	
	If @error Or Not IsArray($aRet) Then
		Return SetError(1, 0, '')
	EndIf
	
	Return $aRet[0]
EndFunc

Func __TCP_SplitURL($sURL)
	Local $aHostPage[3]
	Local Const $URL_PART_HOSTNAME = 2, $URL_PART_PASSWORD = 4, $URL_PART_PORT = 5, $URL_PART_QUERY = 6, $URL_PART_SCHEME = 1, $URL_PART_USERNAME = 3
	
	Local $sScheme = __TCP_UrlGetPart($sURL, $URL_PART_SCHEME)
	Local $sHost = __TCP_UrlGetPart($sURL, $URL_PART_HOSTNAME)
	Local $sPort = __TCP_UrlGetPart($sURL, $URL_PART_PORT)
	
	$aHostPage[0] = $sHost
	$aHostPage[1] = '/' & StringRegExpReplace($sURL, '(?is)^' & $sScheme & '://.*?\Q' & $sHost & '\E(?::' & $sPort & ')?(?:/+)?(.*?)$', '\1')
	$aHostPage[2] = $sPort
	
	If Not $sPort Then
		$aHostPage[2] = $iTCP_PORT
	EndIf
	
	Return $aHostPage
EndFunc

Func __TCP_UrlGetPart($sUrl, $iPart)
	Local $Ret = DllCall('shlwapi.dll', 'long', 'UrlGetPartW', 'wstr', $sUrl, 'wstr', '', 'dword*', 4096, 'dword', $iPart, 'dword', 0)
	If @error Then Return SetError(@error, @extended, '')
	If $Ret[0] Then Return SetError(10, $Ret[0], '')
	
	Return $Ret[2]
EndFunc


С другими файлами работает, а с https не хочет.
И тут другая проблема, получение "новой" ссылки перенаправления выдаёт ту же самую ссылку :stars:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
alex33 [?]
через https данные передаются зашифрованные сертификатом, а не так, как есть...
Ну а как тогда это обходит InetGet?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
CreatoR [?]
Ну а как тогда это обходит InetGet?
Как устроена InetGet сказать не могу, но скорее всего она использует готовый механизм браузера или написана на чистом WinAPI, исключительно под загрузку файлов по определённым протоколам, в том числе и HTTPS.

Без поддержки SSL вы не сможете скачать файл по протоколу HTTPS.
Функции TCP в Autoit не поддерживают SSL. Это чистый socket, причём многие настройки в них уже сделаны за вас, разработчиками Autoit.
Но, я не исключаю возможности использования функций TCP совместно с библиотекой OpenSSL. Однако, достойной и удобной UDF я не встречал.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
CreatoR,
Вот этот сырой пример многопоточной закачки, с использованием MSXML2.ServerXMLHTTP.6.0, работает с HTTP(S) у меня на WinXP 32 и Win7 32 и в AutoIt v3.3.8.1 и v3.3.12.0:
Код:
#include <WinApi.au3>

Opt('MustDeclareVars', 1)

Local $s_Url = 'https://www.autoitscript.com/autoit3/files/beta/autoit/autoit-v3.3.13.19.zip', $i_Size, $i_Norm = 1024 * 1024, $a_Part[1][4], _
		$iTimer = TimerInit()

$a_Part[0][0] = ObjCreate('MSXML2.ServerXMLHTTP.6.0')
With $a_Part[0][0]
	.SetProxy(1)
	.Open('HEAD', $s_Url, 1)
;~ 	.SetRequestHeader('User-Agent', 'Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.16')
	.SetRequestHeader('Connection', 'close')
	.Send()
EndWith
Do
	Sleep(20)
Until $a_Part[0][0] .readyState = 4

$i_Size = Number($a_Part[0][0] .getResponseHeader('Content-Length'))
ConsoleWrite('$i_Size: ' & $i_Size & @LF)
$a_Part[0][0] = 0

$a_Part[0][0] = Ceiling($i_Size / $i_Norm)
ConsoleWrite('$a_Part[0][0]: ' & $a_Part[0][0] & @LF)
ReDim $a_Part[$a_Part[0][0] + 1][4]


For $i = 1 To $a_Part[0][0] - 1
	$a_Part[$i][0] = ObjCreate('MSXML2.ServerXMLHTTP.6.0')
	With $a_Part[$i][0]
		.SetProxy(1)
		.Open('GET', $s_Url, 1)
;~ 		.SetRequestHeader('User-Agent', 'Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.16')
		.SetRequestHeader('Range', 'bytes=' & ($i - 1) * $i_Norm & '-' & $i * $i_Norm - 1)
		.SetRequestHeader('Connection', 'close')
		.Send()
	EndWith
	ConsoleWrite($i & ' bytes=' & ($i - 1) * $i_Norm & '-' & $i * $i_Norm - 1 & @LF)
	$a_Part[$i][2] = $i_Norm
	$a_Part[0][2] += $a_Part[$i][2]
Next
$a_Part[$a_Part[0][0]][0] = ObjCreate('MSXML2.ServerXMLHTTP.6.0')
With $a_Part[$a_Part[0][0]][0]
	.SetProxy(1)
	.Open('GET', $s_Url, 1)
;~ 	.SetRequestHeader('User-Agent', 'Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.16')
	.SetRequestHeader('Range', 'bytes=' & ($a_Part[0][0] - 1) * $i_Norm & '-')
	.SetRequestHeader('Connection', 'close')
	.Send()
EndWith
ConsoleWrite($a_Part[0][0] & ' bytes=' & ($a_Part[0][0] - 1) * $i_Norm & '-' & @LF)
$a_Part[$a_Part[0][0]][2] = $i_Size - ($a_Part[0][0] - 1) * $i_Norm
$a_Part[0][2] += $a_Part[$a_Part[0][0]][2]

Local $p_D, $i_S, $h_M, $i_Byte, $hFile, $a_Res

$hFile = _WinAPI_CreateFile(@ScriptDir & '\autoit-v3.3.13.19.zip', 1, 4)
While $a_Part[0][2]
	Sleep(20)
	For $i = 1 To $a_Part[0][0]
		If Not $a_Part[$i][3] Then
			If $a_Part[$i][0] .readyState = 4 Then
				ConsoleWrite($i & @TAB & $a_Part[$i][0] .status & @TAB & $a_Part[$i][0] .statusText & @LF)
				$a_Part[$i][1] = $a_Part[$i][0] .responseStream
				ConsoleWrite($i & @TAB & '__MSXML_StreamObjGet_Ptr_Size: ' & __MSXML_StreamObjGet_Ptr_Size($a_Part[$i][1], $p_D, $i_S, $h_M) & @LF)
				_WinAPI_SetFilePointer($hFile, ($i - 1) * $i_Norm)
				_WinAPI_WriteFile($hFile, $p_D, $i_S, $i_Byte)
				$a_Res = DllCall('kernel32.dll', 'bool', 'GlobalUnlock', 'handle', $h_M)
				$a_Res = DllCall('kernel32.dll', 'ptr', 'GlobalFree', 'handle', $h_M)
				$a_Part[$i][1] = 0
				$a_Part[$i][0] = 0
				$p_D = 0
				$h_M = 0
				$i_S = 0
				$a_Res = 0
				$a_Part[$i][3] = 1
				$a_Part[0][2] -= $i_Byte
				ConsoleWrite('$a_Part[0][2]: ' & $a_Part[0][2] & @LF)
			EndIf
		EndIf
	Next
WEnd
_WinAPI_CloseHandle($hFile)
MsgBox(64, 'Info', TimerDiff($iTimer))


Func __MSXML_StreamObjGet_Ptr_Size($o_Stream, ByRef $p_Data, ByRef $i_Size, ByRef $h_Mem)
	If Not IsObj($o_Stream) Then Return False

	Local $f_Ret, $a_Res
	Do
		$a_Res = DllCall('ole32.dll', 'uint', 'GetHGlobalFromStream', 'idispatch', $o_Stream, 'ptr*', 0)
		If (@error) Or ($a_Res[0]) Then ExitLoop
		$h_Mem = $a_Res[2]
		$a_Res = DllCall('kernel32.dll', 'ptr', 'GlobalLock', 'ptr', $h_Mem)
		If (@error) Or (Not $a_Res[0]) Then ExitLoop
		$p_Data = $a_Res[0]
		$a_Res = DllCall('kernel32.dll', 'ulong_ptr', 'GlobalSize', 'ptr', $h_Mem)
		If (@error) Or (Not $a_Res[0]) Then ExitLoop
		$i_Size = $a_Res[0]
		$f_Ret = True
	Until 1
	Return $f_Ret
EndFunc   ;==>__MSXML_StreamObjGet_Ptr_Size
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Api monitor показывает что InetGet использует wininet.dll.
 

asdf8

Скриптер
Сообщения
564
Репутация
152
inververs [?]
Api monitor показывает что InetGet использует wininet.dll.
Так и IE его использует.
Наверное, можно сделать поддержку https на сокетах - копать нужно в сторону функций из cryptlib32.dll
 
Верх