Jump to content

_WinHttpWriteData


Recommended Posts

Dear All, 

I am not new to AutoIT but amazingly have not posted on the Forum before and I'm hoping that this might be something that someone can help with? I'm trying to use a REST API to upload some file attachments and for the life of me cannot get binary files to upload correctly. I've done a trace of a working solution using Curl on Windows and to my surprise this just uploaded the multipart/form-data as non base64 encoded jpeg image data. Although I can get files to upload (both base64 encoded and without) the uploaded files are not binary but full of the string representation of the binary file as hex bytes!

I've been using the _WinHttpWriteData so that the jpeg image file can be read and then uploaded to the REST API in a binary format but this does not seem to work. As I could not get this function to work I am now using a direct copy of the code from the excellent TinyPicSharer app (https://www.autoitscript.com/forum/topic/122168-tinypicsharer-v-1034-new-version-08-june-2013/?page=1) which uploads the binary data 2048 bytes at a time. I'm using Fiddler2 to capture the traffic and you can immediately see the image data is uploaded as a string of hex bytes 0x1111111111 rather than binary data. 

The file was being read using the force binary mode, but after analysing the TinyPicSharer the image file is now just read and then the StringToBinary is used to supposedly convert this back to binary for use with the _WinHttpWriteData function, as per the TinyPicSharer code.

I don't have any descent quality code to share but can highlight the important parts as follows:

Func _PicReadData ( $sPicPath )
    If Not FileExists ( $sPicPath ) Then Return SetError ( -1 )
    Local $hFile = FileOpen ( $sPicPath )

    If $hFile = -1 Then Return SetError ( 1 )
    Local $sData = FileRead ( $hFile )

    If @error Then Return SetError ( 2 )
    FileClose ( $hFile )
    Return $sData
EndFunc ;==> _PicReadData ()

Func _GenerateBoundary ( $iLen )
    Local $sString = ''
    Do
        Switch Random ( 1, 3, 1 )
            Case 1
                $sString &= Chr ( Random ( 48, 57, 1 ) )  ; 0 to 9
            Case 2
                $sString &= Chr ( Random ( 65, 90, 1 ) )  ; A to Z
            Case 3
                $sString &= Chr ( Random ( 97, 122, 1 ) ) ; a to z
        EndSwitch
    Until StringLen ( $sString ) = $iLen
    Return $sString
EndFunc ;==> _GenerateBoundary ()

Func _GetExtByFullPath ( $sFullPath )
    Local $aFileName = StringSplit ( $sFullPath, '.' )
    If Not @error Then Return $aFileName[$aFileName[0]]
    Return SetError ( 1 )
EndFunc ;==> _GetExtByFullPath ()

Func _GetFullNameByFullPath ( $sFullPath )
    Local $aFileName = StringSplit ( $sFullPath, '\' )
    If Not @error Then Return $aFileName[$aFileName[0]]
    Return SetError ( 1 )
EndFunc ;==> _GetFullNameByFullPath ()

Func _PicGetContentType ( $sPicPath )
    If Not FileExists ( $sPicPath ) Then Return SetError ( -1 )
    Local $sExt = _GetExtByFullPath ( $sPicPath )
    If @error Or $sExt = '' Then Return SetError ( 1 )
    Local $sContentType
    Switch $sExt
        Case 'jpg', 'jpe', 'jpeg'
            $sContentType = 'Content-Type: image/jpeg'  ; ie 'Content-Type: image/pjpeg'
        Case 'gif'
            $sContentType = 'Content-Type: image/gif'
        Case 'bmp'
            $sContentType = 'Content-Type: image/bmp'
        Case 'png'
            $sContentType = 'Content-Type: image/png'   ; ie Content-Type: image/x-png
        Case 'tif', 'tiff'
            $sContentType = 'Content-Type: image/tiff'
        Case Else
            Return SetError ( 2 )
    EndSwitch
    Return $sContentType
EndFunc ;==> _PicGetContentType ()
Func _HostAbloadSetDataToSend ( $sPicPath )
    If Not FileExists ( $sPicPath ) Then Return SetError ( -1 )
    Local $sData = _PicReadData ( $sPicPath )

    If @error Then Return SetError ( 1 )
    Local $sImageName = _GetFullNameByFullPath ( $sPicPath )
    If @error Or $sImageName = '' Then Return SetError ( 2 )
    Local $sContentType = _PicGetContentType ( $sPicPath )
    If @error Then Return SetError ( 3 )
    Return SetError ( 0, '', $gsBoundary & @CRLF & _
        'Content-Disposition: form-data; name="img0"; filename="' & $sImageName & '"' & @CRLF & $sContentType & @CRLF & @CRLF & $sData & @CRLF & $gsBoundary & @CRLF & _
        'Content-Disposition: form-data; name="resize"' & @CRLF & @CRLF & 'none' & @CRLF & $gsBoundary & @CRLF & _
        'Content-Disposition: form-data; name="delete"' & @CRLF & @CRLF & 'never' & @CRLF & $gsBoundary & '--' )
    
EndFunc ;==> _HostAbloadSetDataToSend ()
$sContentType = 'Content-Type: multipart/form-data; boundary=' & StringTrimLeft ( $sBoundary, 2 )
_WinHttpSendRequest ( $hRequest, $sContentType, $WINHTTP_NO_REQUEST_DATA, StringLen ( $sDataToSend ) )
Func _PicUploadProgress ( $hRequest, $sPicPath, $sDataToSend )
    If Not FileExists ( $sPicPath ) Then Return SetError ( -1 )
    Local $sDatas = StringToBinary ( $sDataToSend )
    Local $iNumberOfBytesToSend = 2048 ; 1024; 2048; 8192
    ;GUICtrlSetState ( $idUploadProgress, $GUI_SHOW )
    ;GUICtrlSetState ( $idLabelMessage, $GUI_SHOW )
    Local $Bin, $iPercent, $iStart = 1, $iExtended = 0
    While 1
        $Bin = BinaryMid ( $sDatas, $iStart, $iNumberOfBytesToSend )

        If BinaryLen ( $Bin ) = 0 Then Return
        _WinHTTPWriteData ( $hRequest, $Bin, 1 )

        If Not @error Then
            $iExtended += @extended
            $iPercent =  Round ( ( $iExtended  ) / ( StringLen ( $sDataToSend ) ) * 100, 2 )
            If $iPercent > 97 Then $iPercent = 97
            ;GUICtrlSetData ( $idUploadProgress, $iPercent )
            ;ControlSetText ( $hGui, '', $idLabelMessage, $iPercent & '%', 0 )
            $iStart += $iNumberOfBytesToSend
        Else
            $Bin = 0
            Return SetError ( 1 )
        EndIf
    WEnd
EndFunc ;==> _PicUploadProgress ()

The most important and relevant parts of the above functions have been bolded for clarity. No matter what I've tried the following data always uploads as a hex string, not binary data which is what is required. See below:

--Y73rYY9z9k82irNh3TcxX9lJ4u64N1
Content-Disposition: form-data; name="image1"; filename="screenshot1.jpg"
Content-Type: application/octent-stream
Content-Type: image/jpeg

0xFFD8FFE000104A46494600010101006000600000FFDB004300080606070605080707070909080A0C140D0C0B0B0C1912130F141D1A1F1E1D1A1C1C20242E2720222C231C1C2837292C30313434341F27393D38323C2E3334...etc, etc.

Please can someone confirm how it is possible to read a binary file and POST this to a REST API as binary data rather than a hex string representation using _WinHttpSendRequest and/or _WinHttpWriteData with the binary flag?

Many thanks in advance.

Link to comment
Share on other sites

Just for point of reference, here are some other posts on a similar subject but none that seem to resolve my issue. Perhaps it can't be done in AutoIT?

I am using WinHttp v1.6.2.5 and AutoIT v3.3.14.2 here. 

It just doesn't seem possible to supply the binary data from an image file (or similar) to the WinHttpSendRequest or WinHttpWriteData functions?

Would really appreciate anyone's help or thoughts on this?

Thank you in advance.

Link to comment
Share on other sites

Hi TranceXX, 

I feel honoured to have a response from such an elite forum member and really appreciate you taking the time to give your feedback. I must admit I've not investigated this function much, so will go away and experiment a bit further. I've just downloaded v1.6.3.8 of the WinHttp UDF so will also give this a try as you suggest and will report back here, hopefully with some good news!

 

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...