Solved

Problem posting multipart/form-data to server

Posted on 2008-10-27
7
845 Views
Last Modified: 2011-10-19
I am working on a project written in VB6 where I need to upload a PDF to a server over HTTP.  The file must be posted as multipart/form-data.  For some reason, when the file gets transmitted, it is getting corrupted.  I have verified that the binary data is correct immediately before I post to the server.  After I post, some of the binary data is different and the PDF will not display properly.  I am using ServerXMLHTTP to post the file.  I have included my code, the original PDF (PDF-Before.pdf), the form data that I am posting (PostData-Before.txt), the form data that gets received by the server (PostData-After.txt), and the resulting PDF file (PDF-After.pdf).  If I compare the before and after files using WinDiff, there are a few sections that are different in the binary data.  It is always the same parts that are different.  I would greatly appreciate your assistance with this.  
Dim objHTTP As ServerXMLHTTP40
Set objHTTP = New MSXML2.ServerXMLHTTP40
Call objHTTP.Open("POST", strURL, False)
Call objHTTP.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------7d83cf5800be")
Call objHTTP.Send(strBody)

Open in new window

PDF-Before.pdf
PDF-After.pdf
PostData-Before.txt
PostData-After.txt
0
Comment
Question by:tlconsulting
  • 4
  • 3
7 Comments
 
LVL 10

Expert Comment

by:c0ldfyr3
ID: 22820443
How are you opening the pdf file? As a string??
0
 

Author Comment

by:tlconsulting
ID: 22823541
The code I am using to retrieve the binary data from the PDF is below.  I verified that I can write the PDF back to a file from the string, as shown in the commented out code, and the PDF is not corrupt at that point.  It only gets corrupt after is is posted over HTTP.
Function GetBinaryFile(strFileName As String) As String
    Dim strFile As String
    Dim nFile
    
    ' Grap the file
    nFile = FreeFile
    Open strFileName For Binary Access Read As #nFile
    strFile = String(LOF(nFile), " ")
    Get #nFile, , strFile
    Close #nFile
    
    GetBinaryFile = strFile
    
    'nFile = FreeFile
    'Open "c:\temp\stream.pdf" For Binary Access Write As #nFile
    'Put #nFile, , strFile
    'Close #nFile
    
End Function

Open in new window

0
 
LVL 10

Assisted Solution

by:c0ldfyr3
c0ldfyr3 earned 400 total points
ID: 22823604
Can you try this please. Change your variable strBody to be as below...
Dim strBody()                       As Byte
 
strBody = GetBinaryFile("C:\Path\To\PDF.pdf")
Dim objHTTP As ServerXMLHTTP40
Set objHTTP = New MSXML2.ServerXMLHTTP40
Call objHTTP.Open("POST", strURL, False)
Call objHTTP.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------7d83cf5800be")
Call objHTTP.Send(strBody)
 
'******************************************************************'
 
Function GetBinaryFile(strFileName As String) As Byte()
    Dim strFile()                   As Byte
    Dim nFile                       As Long
    nFile = FreeFile
    Open strFileName For Binary Access Read As #nFile
        ReDim strFile(1 To LOF(nFile))
        Get #nFile, , strFile
    Close #nFile
    
    GetBinaryFile = strFile
End Function

Open in new window

0
Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

 

Author Comment

by:tlconsulting
ID: 22823829
The post data must be formatted as shown in PostData-Before.txt.  I can't just post the raw binary data.  I have a separate function that does the formatting as shown below.  Since the rest of the data is string data, how would I incorporate the byte array?

bound = "---------------------------7d83cf5800be"
boundSeparator = "--" & bound & vbCrLf
boundFooter = "--" & bound & "--" & vbCrLf
 
strBody = boundSeparator
 
strBody = strBody & "Content-Disposition: form-data; name=""" & "ID" & """" & vbCrLf & vbCrLf & gstrFNCUserNameXML
strBody = strBody & vbCrLf & boundSeparator
 
strBody = strBody & "Content-Disposition: form-data; name=""" & "PASSWORD" & """" & vbCrLf & vbCrLf & gstrFNCPasswordXML
strBody = strBody & vbCrLf & boundSeparator
 
strBody = strBody & "Content-Disposition: form-data; name=""" & "PORT_ID" & """" & vbCrLf & vbCrLf & strECNClientId
strBody = strBody & vbCrLf & boundSeparator
 
strBody = strBody & "Content-Disposition: form-data; name=""" & "FOLDER" & """" & vbCrLf & vbCrLf & strTransactionId
strBody = strBody & vbCrLf & boundSeparator
 
strBody = strBody & "Content-Disposition: form-data; name=""" & "INVOICE_NUM" & """" & vbCrLf & vbCrLf & lngOrderId
strBody = strBody & vbCrLf & boundSeparator
 
strBody = strBody & "Content-Disposition: form-data; name=""" & "TOTAL_FEE" & """" & vbCrLf & vbCrLf & curFee
strBody = strBody & vbCrLf & boundSeparator
 
strFileContent = GetBinaryFile(strSavePath & "\" & strFileName)
strBody = strBody & "Content-Disposition: form-data; name=""" & "FILE_REPORT" & """; filename=""" & strSavePath & "\" & strFileName & """" & vbCrLf & _
	"Content-Type: application/pdf" & vbCrLf & vbCrLf & strFileContent & vbCrLf
		
strBody = strBody & boundFooter

Open in new window

0
 
LVL 10

Assisted Solution

by:c0ldfyr3
c0ldfyr3 earned 400 total points
ID: 22823868
Can you post all of that down as far as the two vbCrLf before strFileContent and then the bytearray, I'm not familiar with that XML HTTP but it probably accepts a variant?

Call objHTTP.Send(strBody) 'Post Data
Call objHTTP.Send(bBytes) 'Byte Array
Call objHTTP.Send(boundFooter) 'Footer
0
 

Author Comment

by:tlconsulting
ID: 22824022
The send method can only be called once on the object.  It throws an error if it is called more than once.  
0
 

Accepted Solution

by:
tlconsulting earned 0 total points
ID: 22825879
I got it working!  I had to convert the entire string to a byte array first.  Thanks c0ldfyr3, your posts are what gave me the idea to try this.  The working code is posted below.  
Dim objHTTP As ServerXMLHTTP40
Dim b() As Byte
Set objHTTP = New MSXML2.ServerXMLHTTP40
Call objHTTP.Open("POST", strURL, False)
Call objHTTP.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------7d83cf5800be")
b = StrConv(strBody, vbFromUnicode)
Call objHTTP.Send(b)

Open in new window

0

Featured Post

Windows Server 2016: All you need to know

Learn about Hyper-V features that increase functionality and usability of Microsoft Windows Server 2016. Also, throughout this eBook, you’ll find some basic PowerShell examples that will help you leverage the scripts in your environments!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction HyperText Transfer Protocol (http://www.ietf.org/rfc/rfc2616.txt) or "HTTP" is the underpinning of internet communication.  As a teacher of web development I have heard many questions, mostly from my younger students who have come to t…
A few customers have recently asked my thoughts on Password Managers.  As Security is a big part of our industry I was initially very hesitant and sceptical about giving a program all of my secret passwords.  But as I was getting asked about them mo…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

773 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question