Archived Forum Post

Index of archived forum posts

Question:

Exploding file upload in ActiveX Http.

May 11 '17 at 21:47

I tested this on two computers with the latest Chilkat v9.5.0.66. When I try and post a zip 132mb zip file with .SynchronousRequest, a fatal error occurs and the application crashes. I am able to post smaller zip and pdf files so know that the code works. The exact error is "Run-time error '-2147417851 (80010105)'"

Matt, I have sent an email to Chilkat support with a link to the zip.

Code to upload * Error Occurs on .SynchronousRequest call

Do
    oHttp.CloseAllConnections
    Set oResp = oHttp.SynchronousRequest(rackDomain, 443, 1, oReq)
    o("ErrorText") = oHttp.LastErrorText
    If Not (oResp Is Nothing) Then
        Process_Http = True
        o("Status_Code") = oResp.StatusCode
        o("Status_Line") = oResp.StatusLine
        o("Resp_Body") = oResp.BodyStr
        o("X-Trans-Id") = oResp.GetHeaderField("X-Trans-Id")
        o("http_last_path") = oReq.Path
        o("http_etag") = oResp.GetHeaderField("ETag")
        Set oResp = Nothing
        Exit Do

    End If
    I = I + 1
    If I = 3 Then Exit Do
    Sleep 200

Loop

Code to create the request object

With oReq
    .httpVerb = "PUT"
    .ContentType = o("http_content_type")
    .Path = rackPath & "/" & o("ContainerName") & "/" & o("RecordID") & o("FileExt")

    If Len(o("FileName")) > 0 Then
        .Path = rackPath & "/" & o("ContainerName") & "/" & o("FileName")

    End If

    .AddHeader "X-Auth-Token", rackToken
    .AddHeader "Content-Length", oBinDat.numBytes
    .AddHeader "ETag", oCrypt.HashBytesENC(oBinDat.GetBinary)

    If o("Module") = ModuleType.Issuance Then
        .AddHeader "X-Object-Meta-ArchiveID", o("RecordID")
        If Not IsNull(UsageID) Then .AddHeader "X-Object-Meta-UsageID", UsageID

    End If

    .LoadBodyFromBytes oBinDat.GetBinary

End With

Crypt Settings

With oCrypt
    .HashAlgorithm = "md5"
    .EncodingMode = "hex"

End With

Answer

Thanks Erik,

I suspect an out-of-memory condition. The following line of code would copy the data in it's entirety in memory, which would double the size held in memory:

.LoadBodyFromBytes oBinDat.GetBinary

Does the .zip file being uploaded reside as a file in the filesystem? If so, then you can just point the HttpRequest object to the file, and when Chilkat uploads, it will stream the file data directly from the file. This way, the file can be any size with no memory usage impact.

Instead of calling LoadBodyFromBytes, you would do this:

success = .StreamBodyFromFile("c:/some/path/to/the.zip")

The StreamBodyFromFile method is simply noting the path of the file that will be opened and streamed through the HTTP/HTTPS connection when the upload actually occurs.


Answer

Thanks Erik,

The solution is to avoid all places where the file's binary data is moved across the COM boundary from Chilkat to your app. In other words, when you do something like this:

.LoadBodyFromBytes oBinDat.GetBinary
The file data (132MB) is copied to a Variant and moves across the COM boundary to your app. The "explosion" ;) is likely due to the size.

What we want to do is to keep the data within Chilkat, i.e. within the native C++ code so that it never really needs to be marshaled to your app. This would be done via the BinData object.

The first step is to get the file data in a BinData object. (Maybe you've already done that?) Once accomplished, I can see two places where the code needs to be changed so we can keep the data from crossing over to the application.

1) Instead of calling oCrypt.HashBytesENC, call oCrypt.HashBdENC (where you pass it the BinData object) This is better because instead of marshaling 132MB from your app to the C++ code, you're just passing a reference to an object where the data is already contained. This makes it faster AND it prevents the temporary doubling of memory requirements.

2) I'll need to add a method to the HttpRequest object named LoadBodyfromBd (or perhaps UseBodyFromBd) so that the contents of the BinData are used for the request body. This would replace the call to LoadBodyFromBytes.

I think these changes will resolve the problem. I'll post when I have a new ActiveX build ready with this new method..