Solved

Problem posting multipart/form-data to server

Posted on 2008-10-27
7
810 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
Comment Utility
How are you opening the pdf file? As a string??
0
 

Author Comment

by:tlconsulting
Comment Utility
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
Comment Utility
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
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:tlconsulting
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

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…
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

762 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

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now