Search code examples
xmlhttprequestautoitwinhttprequest

AutoIT - winhttp.winhttprequest.5.1 MSXML2.XMLHTTP.6.0 large download fail


I have a problem with winhttp.winhttprequest.5.1 & MSXML2.XMLHTTP.6.0 for download large bin file. My code :

;Droit Admin
#RequireAdmin

;Handler Error
Global $__g_oHTTP_ErrorHandler = ObjEvent("AutoIt.Error", __HTTP_OnError)

$local = @DesktopDir & "\test.bin"
$lien = "https://mylink1-26Mb"
;$lien = "https://mylink2-11Mb"

$oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1")

;First Connection with SSO authenticate
$url = "https://sso.authenticate"
$target = "https://domain"
$body = "USER=ABCD1234&PASSWORD=AZERTY&target=" & $target
$oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1")
$oHTTP.Open("POST", $url, False)
$oHTTP.Send($body)

;Print
ConsoleWrite($oHTTP.Status & @CR)
ConsoleWrite($oHTTP.GetAllResponseHeaders & @CR)

Console :

200
Cache-Control: no-cache, private
Connection: Keep-Alive Date: Thu,25 Aug 2022 07:12:25 GMT
Keep-Alive: timeout=5, max=98
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: text/html;charset=UTF-8
Expires: -1
Server: Apache
Vary: Accept-Encoding
X-Vcap-Request-Id: ############################

;Request HEAD to obtain size file
$oHTTP.Open("HEAD", $lien, False)
$oHTTP.Send()

;Print
$size_cloud_file = $oHTTP.GetResponseHeader("Content-Length")
ConsoleWrite($oHTTP.Status & @CR)
ConsoleWrite($oHTTP.GetAllResponseHeaders & @CR)

Console :

200
Cache-Control: no-cache, private
Connection: Keep-Alive
Date: Thu, 25 Aug 2022 07:12:25 GMT
Keep-Alive: timeout=5, max=97
Pragma: no-cache
qr> Content-Length: 26683497
Content-Type: text/plain;charset=UTF-8 Expires: 0
Server: Apache
Content-Description: File Transfer
Content-Disposition: attachment;filename=file.bin
X-Vcap-Request-Id: ########################

;Download File
$oHTTP.Open("GET", $lien, False)
$oHTTP.Send()

;Print all values
Consolewrite("#Status                           : " & $oHTTP.Status & @CR)
Consolewrite("#Status Text                      : " & $oHTTP.StatusText & @CR)
Consolewrite("#GetAllResponseHeaders            : " & @CR & $oHTTP.GetAllResponseHeaders & @CR)
;Consolewrite("Response Text                   : " & $oHTTP.ResponseText & @CR)
if ($oHTTP.option(0)) Then Consolewrite("#UserAgentString                   : " & $oHTTP.option(0) & @CR)
if ($oHTTP.option(1)) Then Consolewrite("#URL                               : " & $oHTTP.option(1) & @CR)
if ($oHTTP.option(2)) Then Consolewrite("#URLCodePage                       : " & $oHTTP.option(2) & @CR)
if ($oHTTP.option(3)) Then Consolewrite("#EscapePercentInURL                : " & $oHTTP.option(3) & @CR)
if ($oHTTP.option(4)) Then Consolewrite("#SslErrorIgnoreFlags               : " & $oHTTP.option(4) & @CR)
if ($oHTTP.option(5)) Then Consolewrite("#SelectCertificate                 : " & $oHTTP.option(5) & @CR)
if ($oHTTP.option(6)) Then Consolewrite("#EnableRedirects                   : " & $oHTTP.option(6) & @CR)
if ($oHTTP.option(7)) Then Consolewrite("#UrlEscapeDisable                  : " & $oHTTP.option(7) & @CR)
if ($oHTTP.option(8)) Then Consolewrite("#UrlEscapeDisableQuery             : " & $oHTTP.option(8) & @CR)
if ($oHTTP.option(9)) Then Consolewrite("#SecureProtocols                   : " & $oHTTP.option(9) & @CR)
if ($oHTTP.option(10)) Then Consolewrite("#EnableTracing                     : " & $oHTTP.option(10) & @CR)
if ($oHTTP.option(11)) Then Consolewrite("#RevertImpersonationOverSsl        : " & $oHTTP.option(11) & @CR)
if ($oHTTP.option(12)) Then Consolewrite("#EnableHttpsToHttpRedirects        : " & $oHTTP.option(12) & @CR)
if ($oHTTP.option(13)) Then Consolewrite("#EnablePassportAuthentication      : " & $oHTTP.option(13) & @CR)
if ($oHTTP.option(14)) Then Consolewrite("#MaxAutomaticRedirects             : " & $oHTTP.option(14) & @CR)
if ($oHTTP.option(15)) Then Consolewrite("#MaxResponseHeaderSize             : " & $oHTTP.option(15) & @CR)
if ($oHTTP.option(16)) Then Consolewrite("#MaxResponseDrainSize              : " & $oHTTP.option(16) & @CR)
if ($oHTTP.option(17)) Then Consolewrite("#EnableHttp1_1                     : " & $oHTTP.option(17) & @CR)
if ($oHTTP.option(18)) Then Consolewrite("#EnableCertificateRevocationCheck  : " & $oHTTP.option(18) & @CR)

Console :

#Status : 200
#Status Text : OK
#GetAllResponseHeaders :
Cache-Control: no-cache, private
Connection: Keep-Alive
Date: Thu, 25 Aug 2022 07:12:26 GMT
Keep-Alive: timeout=5, max=96
Pragma: no-cache
Content-Length: 26683497
Content-Type: text/plain;charset=UTF-8
Expires: 0
Server: Apache Vary: Accept-Encoding
Content-Description: File Transfer
Content-Disposition: attachment;filename=file.bin
X-Vcap-Request-Id: ######################################

#UserAgentString : Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)
#URL : https://mylink1-26Mb
#URLCodePage : 65001
#EnableRedirects : True
#UrlEscapeDisableQuery : True
#RevertImpersonationOverSsl : True
#MaxAutomaticRedirects : 10
#MaxResponseHeaderSize : 65536
#MaxResponseDrainSize : 1024000
#EnableHttp1_1 : True

;Copy ResponseBody to bin local file
FileDelete($local)
$handle = FileOpen($local, 18)
FileWrite($handle, $oHTTP.ResponseBody)         ;=> ResponseBody empty or not exist
FileClose($handle)

Func __HTTP_OnError($oError)
    ConsoleWrite(@ScriptName & " (" & $oError.scriptline & ") : ==> COM Error intercepted !" & @CRLF & _
            @TAB & "err.number is: " & @TAB & @TAB & "0x" & Hex($oError.number) & @CRLF & _
            @TAB & "err.windescription:" & @TAB & $oError.windescription & @CRLF & _
            @TAB & "err.description is: " & @TAB & $oError.description & @CRLF & _
            @TAB & "err.source is: " & @TAB & @TAB & $oError.source & @CRLF & _
            @TAB & "err.helpfile is: " & @TAB & $oError.helpfile & @CRLF & _
            @TAB & "err.helpcontext is: " & @TAB & $oError.helpcontext & @CRLF & _
            @TAB & "err.lastdllerror is: " & @TAB & $oError.lastdllerror & @CRLF & _
            @TAB & "err.scriptline is: " & @TAB & $oError.scriptline & @CRLF & _
            @TAB & "err.retcode is: " & @TAB & "0x" & Hex($oError.retcode) & @CRLF & @CRLF)
EndFunc   ;==>_MyCOMErrFunc

If i use the same script with a 11Mb file, there are no problem !
It's same error with COM : "MSXML2.XMLHTTP.6.0"

Thanks for your help !


Solution

  • Solution :

    I use https://github.com/dragana-r/autoit-winhttp Thanks to @dragana

    #include <WinHttpConstants.au3>
    #include <WinHttp.au3>
    
    Func Download($lien,$local,$progressbar)
    
        ;Check compatibility with windows
        If Not _WinHttpCheckPlatform() Then
           ConsoleWrite("WinHTTP not compatible" & @CR)
           Return "WinHTTP not compatible"
        EndIf
    
        $sProxy = "my_proxy:my_port"
        $sProxyBypass = "my_proxy_local_bypass"
        $url = "https://sso.authenticate"
        $target = "https://domain"
        $body = "USER=ABCD1234&PASSWORD=AZERTY&target=" & $target
    
        ;First connexion POST
        ;OPEN
        $hOpen = _WinHttpOpen("Mozilla/5.0 (Windows NT 10.0; Win64; x64)   AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240", _
                              $WINHTTP_ACCESS_TYPE_NAMED_PROXY, _
                              $sProxy, _
                              $sProxyBypass)
        if @error Then
           ConsoleWrite("ERREUR : WinHttpOpen :" & @error & @CR)
           Return "ERREUR : WinHttpOpen"
        EndIf
    
        ;CONNECT
        $hConnect = _WinHttpConnect($hOpen, $url, $INTERNET_DEFAULT_HTTPS_PORT)
        if @error Then
           ConsoleWrite("ERREUR : WinHttpConnect1 : " & @error)
           Return "ERREUR : WinHttpConnect1"
        EndIf
    
        ;REQUEST SEND
        $hRequest =  _WinHttpSimpleSendSSLRequest($hConnect, "POST", $surl, $WINHTTP_NO_REFERER, $body)
        if @error Then
           ConsoleWrite("ERREUR : WinHttpSimpleSendSSLRequest1 : " & @error)
           Return "ERREUR : WinHttpSimpleSendSSLRequest1"
        EndIf
    
        ;WAIT
        _WinHttpReceiveResponse($hRequest)
    
        ;OUT if problems
        If ( _WinHttpQueryHeaders($hRequest, $WINHTTP_QUERY_STATUS_CODE) <> 200 ) Then
           ConsoleWrite("ERREUR : Connexion fail" & @CR)
           Return "ERREUR : Connexion fail"
        EndIf
    
        ;Second : HEAD (obtain size) 
        $url_crack = _WinHttpCrackUrl($lien)
        $url = $url_crack[0] & "://" & $url_crack[2] & "/"
        $surl = $url_crack[6] & $url_crack[7]
    
        $hConnect = _WinHttpConnect($hOpen, $url, $INTERNET_DEFAULT_HTTPS_PORT)
        if @error Then
           ConsoleWrite("ERREUR : WinHttpConnect2 : " & @error)
           Return "ERREUR : WinHttpConnect2"
        EndIf
    
        $hRequest =  _WinHttpSimpleSendSSLRequest($hConnect, "HEAD", $surl, $WINHTTP_NO_REFERER)
        if @error Then
           ConsoleWrite("ERREUR : WinHttpSimpleSendSSLRequest2 : " & @error & @CR)
           Return "ERREUR : WinHttpSimpleSendSSLRequest2"
        EndIf
    
        ;WAIT
        _WinHttpReceiveResponse($hRequest)
    
        ;OUT if problems
        If ( _WinHttpQueryOption($hRequest, $WINHTTP_OPTION_URL) <> $lien ) Then
           ConsoleWrite("ERREUR : Requête HEAD" &@CR)
           Return "ERREUR : Requête HEAD"
        EndIf
    
        $size_cloud_file = _WinHttpQueryHeaders($hRequest, $WINHTTP_QUERY_CONTENT_LENGTH)
        $size_local_file = FileGetSize($local)
        GUICtrlSetData($progressbar, 0)
        GUICtrlSetState($progressbar, $GUI_SHOW)
    
        ;If size is different
        If $size_cloud_file <> $size_local_file Then
    
           ;CONNECT
           $hConnect = _WinHttpConnect($hOpen, $url, $INTERNET_DEFAULT_HTTPS_PORT)
           if @error Then
              ConsoleWrite("ERREUR : WinHttpConnect3 : " & @error & @CR)
              Return "ERREUR : WinHttpConnect3"
           EndIf
    
           $hRequest =  _WinHttpSimpleSendSSLRequest($hConnect, _
                                                    "GET", _
                                                    $surl, _
                                                    Default, _
                                                    Default, _
                                                    Default)
           if @error Then
              ConsoleWrite("ERREUR : WinHttpSimpleSendSSLRequest : " & @error)
              Return "ERREUR : WinHttpSimpleSendSSLRequest"
           EndIf
    
    
           $sData = Binary("")
           If _WinHttpQueryDataAvailable($hRequest) Then
              While 1
    
                  $sChunk = _WinHttpReadData($hRequest, 2)
                  If @error Then ExitLoop
                  $sData &= $sChunk
    
                  $pourcent = Int((BinaryLen($sData) / $size_cloud_file) * 100)
                  GUICtrlSetData($progressbar, $pourcent)
    
              WEnd
          Else
              ConsoleWrite("ERREUR : WinHttpQueryDataAvailable : " & @error)
              Return "ERREUR : WinHttpQueryDataAvailable"
          EndIf
    
          ;Copy Byte Array to file
          FileDelete($local)
          $handle = FileOpen($local, 18)
          FileWrite($handle, $sData)
          FileClose($handle)
    
          ;If fail copy or download
          If ( FileGetSize($local) <> $size_cloud_file ) Then
    
             ConsoleWrite("ERREUR : File error" & @CR)
             Return "ERREUR : File error"
    
          EndIf
    
    
    endfunc