Posting multipart/form-data using VB.NET

M

Mark Waser

Hi all,

I'm trying to post multipart/form-data to a web page but seem to have
run into a wall. I'm familiar with RFC 1867 and have done this before (with
AOLServer and Tcl) but just can't seem to get it to work in Visual Basic. I
tried coding it once myself from scratch and then modified a class that I
found on a newsgroup (referenced below). Both seem to be doing the same
thing and neither works (or rather, they seem to work but the server doesn't
see the variables that I am attempting to pass to it). Can anyone either a)
direct me to some code that they KNOW is functional or b) give me any
pointers to where I might be going wrong?

The second set of code that I'm using is copied below and is translated
from c# from the following newsgroup:
http://groups.google.com/groups?q=norvanco.com&hl=en&lr=&ie=UTF-8&oe=UTF-8&s
elm=OaDlKeDTDHA.2144%40TK2MSFTNGP11.phx.gbl&rnum=6

If anyone could help, I would greatly appreciate it.

Mark
Imports System

Imports System.Net

Imports System.Text

Imports System.IO

Imports System.Collections

Module Module1

'/// <summary>

'/// Allow the transfer of data files using the W3C's specification

'/// for HTTP multipart form data. Microsoft's version has a bug

'/// where it does not format the ending boundary correctly.

'/// Written by: (e-mail address removed)

'/// </summary>

Public Class MultipartForm

Public Cookies As CookieContainer

'/// <summary>

'/// Holds any form fields and values that you

'/// wish to transfer with your data.

'/// </summary>

Private coFormFields As Hashtable

'/// <summary>

'/// Used mainly to avoid passing parameters to other routines.

'/// Could have been local to sendFile().

'/// </summary>

Protected coRequest As HttpWebRequest

'/// <summary>

'/// Used if we are testing and want to output the raw

'/// request, minus http headers, out to a file.

'/// </summary>

Protected coFileStream As System.IO.Stream

'/// <summary>

'/// Defined to build the form field data that is being

'/// passed along with the request.

'/// </summary>

Dim CONTENT_DISP As String = "Content-Disposition: form-data; name="

'/// <summary>

'/// Allows you to specify the specific version of HTTP to use for uploads.

'/// The dot NET stuff currently does not allow you to remove the
continue-100 header

'/// from 1.1 and 1.0 currently has a bug in it where it adds the
continue-100. MS

'/// has sent a patch to remove the continue-100 in HTTP 1.0.

'/// </summary>

' public Version TransferHttpVersion

' {get{return coHttpVersion;}set{coHttpVersion=value;}}

' Version coHttpVersion;

Public TransferHttpVersion As Version

'/// <summary>

'/// Used to change the content type of the file being sent.

'/// Currently defaults to: text/xml. Other options are

'/// text/plain or binary

'/// </summary>

'public string FileContentType

'{get{return coFileContentType;}set{coFileContentType=value;}}

'string coFileContentType;

Public FileContentType As String

'/// <summary>

'/// Initialize our class for use to send data files.

'/// </summary>

'/// <param name="url">The web address of the recipient of the data
transfer.</param>

Public Sub New(ByVal _url As String)

URL = _url

coFormFields = New Hashtable()

ResponseText = New StringBuilder()

BufferSize = 1024 * 10

BeginBoundary = "BoundarySepR8R"

TransferHttpVersion = HttpVersion.Version11

FileContentType = "text/xml"

End Sub

'//---------- BEGIN PROPERTIES SECTION ----------

Dim _BeginBoundary As String

'/// <summary>

'/// The string that defines the begining boundary of

'/// our multipart transfer as defined in the w3c specs.

'/// This method also sets the Content and Ending

'/// boundaries as defined by the w3c specs.

'/// </summary>

Public Property BeginBoundary() As String

Get

Return _BeginBoundary

End Get

Set(ByVal Value As String)

_BeginBoundary = Value

ContentBoundary = "--" + BeginBoundary

EndingBoundary = ContentBoundary + "--"

End Set

End Property

'/// <summary>

'/// The string that defines the content boundary of

'/// our multipart transfer as defined in the w3c specs.

'/// </summary>

Protected ContentBoundary As String

'/// <summary>

'/// The string that defines the ending boundary of

'/// our multipart transfer as defined in the w3c specs.

'/// </summary>

Protected EndingBoundary As String

'/// <summary>

'/// The data returned to us after the transfer is completed.

'/// </summary>

Public ResponseText As StringBuilder

'/// <summary>

'/// The web address of the recipient of the transfer.

'/// </summary>

Public URL As String

'/// <summary>

'/// Allows us to determine the size of the buffer used

'/// to send a piece of the file at a time out the IO

'/// stream. Defaults to 1024 * 10.

'/// </summary>

Public BufferSize As Integer

'//---------- END PROPERTIES SECTION ----------

'/// <summary>

'/// Used to signal we want the output to go to a

'/// text file verses being transfered to a URL.

'/// </summary>

'/// <param name="path"></param>

Public Sub setFilename(ByVal path As String)

coFileStream = New System.IO.FileStream(path, FileMode.Create,
FileAccess.Write)

End Sub

'/// <summary>

'/// Allows you to add some additional field data to be

'/// sent along with the transfer. This is usually used

'/// for things like userid and password to validate the

'/// transfer.

'/// </summary>

'/// <param name="key">The form field name</param>

'/// <param name="str">The form field value</param>

Public Sub setField(ByVal key As String, ByVal str As String)

coFormFields.Add(key, str)

End Sub

'/// <summary>

'/// Determines if we have a file stream set, and returns either

'/// the HttpWebRequest stream of the file.

'/// </summary>

'/// <returns></returns>

Public Function getStream() As System.IO.Stream

Dim io As System.IO.Stream

If (coFileStream Is Nothing) Then

io = coRequest.GetRequestStream()

Else

io = coFileStream

End If

Return io

End Function

'/// <summary>

'/// Here we actually make the request to the web server and

'/// retrieve it's response into a text buffer.

'/// </summary>

Public Sub getResponse()

If (coFileStream Is Nothing) Then

Dim io As System.IO.Stream

Dim oResponse As WebResponse

Try

oResponse = coRequest.GetResponse()

Catch web As WebException

oResponse = web.Response

End Try

If (Not (oResponse Is Nothing)) Then

io = oResponse.GetResponseStream()

Dim sr As StreamReader = New StreamReader(io)

Dim str As String

ResponseText.Length = 0

str = sr.ReadLine()

While (Not (str Is Nothing))

ResponseText.Append(str)

str = sr.ReadLine()

End While

oResponse.Close()

Else

Throw New Exception("MultipartForm: Error retrieving server response")

End If

End If

End Sub

'/// <summary>

'/// Transmits a file to the web server stated in the

'/// URL property. You may call this several times and it

'/// will use the values previously set for fields and URL.

'/// </summary>

'/// <param name="aFilename">The full path of file being transfered.</param>

Public Sub sendFile(ByVal aFilename As String)

'// The live of this object is only good during

'// this function. Used mainly to avoid passing

'// around parameters to other functions.

coRequest = WebRequest.Create(URL)

coRequest.CookieContainer = Cookies

'// Set use HTTP 1.0 or 1.1.

coRequest.ProtocolVersion = TransferHttpVersion

coRequest.Method = "POST"

coRequest.ContentType = "multipart/form-data, boundary=" + BeginBoundary

coRequest.Headers.Add("Cache-Control", "no-cache")

coRequest.KeepAlive = True

Dim strFields As String = getFormfields()

Dim strFileHdr As String = getFileheader(aFilename)

Dim strFileTlr As String = getFiletrailer()

Dim info As FileInfo = New FileInfo(aFilename)

coRequest.ContentLength = strFields.Length + strFileHdr.Length +
strFileTlr.Length + info.Length

Dim io As System.IO.Stream

io = getStream()

writeString(io, strFields)

writeString(io, strFileHdr)

writeFile(io, aFilename)

'writeString(io, "fast as fast can be, you'll never catch me")

writeString(io, strFileTlr)

io.Close()

MsgBox(coRequest.Headers.ToString)

getResponse()

'// End the life time of this request object.

coRequest = Nothing

End Sub

'/// <summary>

'/// Mainly used to turn the string into a byte buffer and then

'/// write it to our IO stream.

'/// </summary>

'/// <param name="io">The io stream for output.</param>

'/// <param name="str">The data to write.</param>

Public Sub writeString(ByVal io As System.IO.Stream, ByVal str As String)

Dim PostData As Byte() = System.Text.Encoding.ASCII.GetBytes(str)

io.Write(PostData, 0, PostData.Length)

End Sub

'/// <summary>

'/// Builds the proper format of the multipart data that

'/// contains the form fields and their respective values.

'/// </summary>

'/// <returns>The data to send in the multipart upload.</returns>

Public Function getFormfields() As String

Dim str As String = ""

Dim myEnumerator As IDictionaryEnumerator = coFormFields.GetEnumerator()

While (myEnumerator.MoveNext())

str += ContentBoundary + vbCrLf + CONTENT_DISP + """" + myEnumerator.Key +
"""" + vbCrLf + vbCrLf + myEnumerator.Value + vbCrLf

End While

Return str

End Function

'/// <summary>

'/// Returns the proper content information for the

'/// file we are sending.

'/// </summary>

'/// <remarks>

'/// Hits Patel reported a bug when used with ActiveFile.

'/// Added semicolon after sendfile to resolve that issue.

'/// Tested for compatibility with IIS 5.0 and Java.

'/// </remarks>

'/// <param name="aFilename"></param>

'/// <returns></returns>

Public Function getFileheader(ByVal aFilename As String) As String

Return ContentBoundary + vbCrLf + CONTENT_DISP + """userfile""; filename="""
+ Path.GetFileName(aFilename) + """" + vbCrLf + "Content-type: " +
FileContentType + vbCrLf + vbCrLf

End Function

'/// <summary>

'/// Creates the proper ending boundary for the multipart upload.

'/// </summary>

'/// <returns>The ending boundary.</returns>

Public Function getFiletrailer() As String

Return vbCrLf + EndingBoundary

End Function

'/// <summary>

'/// Reads in the file a chunck at a time then sends it to the

'/// output stream.

'/// </summary>

'/// <param name="io">The io stream to write the file to.</param>

'/// <param name="aFilename">The name of the file to transfer.</param>

Public Sub writeFile(ByVal io As System.IO.Stream, ByVal aFilename As
String)

Dim readIn As FileStream = New FileStream(aFilename, FileMode.Open,
FileAccess.Read)

readIn.Seek(0, SeekOrigin.Begin) ' move to the start of the file

Dim fileData(BufferSize) As Byte

Dim bytes As Integer

bytes = readIn.Read(fileData, 0, BufferSize)

While (bytes > 0)

'// read the file data and send a chunk at a time

io.Write(fileData, 0, bytes)

bytes = readIn.Read(fileData, 0, BufferSize)

End While

readIn.Close()

End Sub

End Class

End Module


--
Charity: Give a man a fish, feed him for a day
Education: Teach a man to fish, feed him his entire life
Humanism: Teach a man to believe in himself, and he will learn more than
just how to fish.
Teach a man to believe in mankind ....
 
M

MSFT

Hi Mark,

I only have a C# sample on hand, you may first take a look at it to see if
it will help:

First you need to create the server side code by following the steps in
this article:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q323246

Then sent the request in your application with following code:

using System;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Text;
namespace PostMultipartForm
{
class Class1
{
/// The main entry point for the application.
static CookieContainer CookieJar = new CookieContainer();
[STAThread]
static void Main(string[] args)
{
string HiddenValue = test();
//RFC 1867 states that you add to -- to the Boundry that you use in the
body of the post
string dataBoundary = "--xyz";
// you will need to change the URL to point to your box
HttpWebRequest Req =
(HttpWebRequest)WebRequest.Create("http://yourservername/csharpupload/webfor
m1.aspx"
);
Req.UserAgent = "Upload Test";
Req.ContentType = "multipart/form-data; boundary=xyz";
Req.Method = "POST";
Req.KeepAlive = true;
Req.CookieContainer = CookieJar;
string FileData = "this is test file data\r\n"; // test data to send.
StringBuilder DataString = new StringBuilder();
DataString.Append(dataBoundary + "\r\n");
//This sends the viewstate info
DataString.Append("Content-Disposition: form-data; name=" + HiddenValue
+ "\r\n"
+ dataBoundary + "\r\n");
DataString.Append("Content-Disposition: form-data; name=" + "\"" +
"File1" +
"\"" +
"; filename=" + "\"" + "TestFile3.txt" + "\"" + "\r\n");
DataString.Append("Content-Type: text/plain\r\n\r\n");
DataString.Append(FileData);
DataString.Append(dataBoundary + "\r\n");
DataString.Append("Content-Disposition: form-data; name=" + "\"" +
"Submit1" +
"\"" + "\r\n\r\n" + "Upload\r\n" + dataBoundary + "--\r\n");

Console.Write(DataString);
byte []Postdata =
System.Text.Encoding.Default.GetBytes(DataString.ToString());
Req.ContentLength = Postdata.Length;
Stream tempStream = Req.GetRequestStream();
// write the data to be posted to the Request Stream
tempStream.Write(Postdata,0,Postdata.Length);
tempStream.Close();
HttpWebResponse Resp = (HttpWebResponse)Req.GetResponse();
//Read the raw HTML from the request
StreamReader sr = new StreamReader(Resp.GetResponseStream(),
Encoding.Default);
//Convert the stream to a string
string s = sr.ReadToEnd();
sr.Close();
Resp.Close();
Console.WriteLine(s);
}
static string test()
{
HttpWebRequest Req =
(HttpWebRequest)WebRequest.Create("http://YourWebServer/csharpupload/webform
1.aspx")
;
Req.UserAgent = "Upload Test";
Req.Method = "GET";
Req.CookieContainer = CookieJar;
HttpWebResponse Resp = (HttpWebResponse)Req.GetResponse();
//Read the raw HTML from the request
StreamReader sr = new StreamReader(Resp.GetResponseStream(),
Encoding.Default);
//Convert the stream to a string
string s = sr.ReadToEnd();
sr.Close();
Resp.Close();
int start = 0, end = 0;
start = s.IndexOf("__VIEWSTATE");
if (start > 0)
{
end = s.IndexOf("value=", start);
}
else
{
//did not find the viewstate handle here
}
start = end;
end = s.IndexOf("/", start);
//remove the value= and the quotes from the viewstate value.
string vstate = "\"" + "__VIEWSTATE" + "\"\r\n\r\n" + s.Substring(start
+ 7,
((end-2) - (start + 7)));
vstate.Replace("+", "%2B");
vstate.Replace("=", "%3D");
return vstate;
}
}
}


Hope this help,


Luke
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
M

Mark Waser

Hi Luke,

First off, sorry for the delay but I had to switch languages everywhere.

I built the server side code. It works fine. I can see the files I
upload manually in the Data directory.

I built your class 1. As written, it returns an exception that the
remote server returned an error: (500) Internal Server Error.

<possible sidetrack> Looking at RFC1867, I note that
Req.ContentType = "multipart/form-data; boundary=xyz";
maybe should be
Req.ContentType = "multipart/form-data, boundary=xyz";
(replacing semi-colon with comma)

When I do this, the exception goes away but the file is not uploaded. I
went through the exact same routine with my original VB program and it
behaved exactly the same) </possible sidetrack>

So, once again, I'm at an impasse. Should I do something to try to
track down the internal server error? Can my code call a server of yours
that might be set up to determine what it's passing that might be a problem?
Any suggestions?

By the way, I am using the following:
Microsoft .Net Framework 1.0 version 1.0.3705
Microsoft Development Environment 2002 version 7.0.9466

We do have the newest Framework and Visual Studio 2003 but they
currently aren't approved (i.e. I could switch if it were 100% the case that
the older version is the problem but not otherwise).

Any advice? Does this code actually work on your set-up (and if so,
what versions are you using)?

Thanks.

Mark


MSFT said:
Hi Mark,

I only have a C# sample on hand, you may first take a look at it to see if
it will help:

First you need to create the server side code by following the steps in
this article:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q323246

Then sent the request in your application with following code:

using System;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Text;
namespace PostMultipartForm
{
class Class1
{
/// The main entry point for the application.
static CookieContainer CookieJar = new CookieContainer();
[STAThread]
static void Main(string[] args)
{
string HiddenValue = test();
//RFC 1867 states that you add to -- to the Boundry that you use in the
body of the post
string dataBoundary = "--xyz";
// you will need to change the URL to point to your box
HttpWebRequest Req =
(HttpWebRequest)WebRequest.Create("http://yourservername/csharpupload/webfor
m1.aspx"
);
Req.UserAgent = "Upload Test";
Req.ContentType = "multipart/form-data; boundary=xyz";
Req.Method = "POST";
Req.KeepAlive = true;
Req.CookieContainer = CookieJar;
string FileData = "this is test file data\r\n"; // test data to send.
StringBuilder DataString = new StringBuilder();
DataString.Append(dataBoundary + "\r\n");
//This sends the viewstate info
DataString.Append("Content-Disposition: form-data; name=" + HiddenValue
+ "\r\n"
+ dataBoundary + "\r\n");
DataString.Append("Content-Disposition: form-data; name=" + "\"" +
"File1" +
"\"" +
"; filename=" + "\"" + "TestFile3.txt" + "\"" + "\r\n");
DataString.Append("Content-Type: text/plain\r\n\r\n");
DataString.Append(FileData);
DataString.Append(dataBoundary + "\r\n");
DataString.Append("Content-Disposition: form-data; name=" + "\"" +
"Submit1" +
"\"" + "\r\n\r\n" + "Upload\r\n" + dataBoundary + "--\r\n");

Console.Write(DataString);
byte []Postdata =
System.Text.Encoding.Default.GetBytes(DataString.ToString());
Req.ContentLength = Postdata.Length;
Stream tempStream = Req.GetRequestStream();
// write the data to be posted to the Request Stream
tempStream.Write(Postdata,0,Postdata.Length);
tempStream.Close();
HttpWebResponse Resp = (HttpWebResponse)Req.GetResponse();
//Read the raw HTML from the request
StreamReader sr = new StreamReader(Resp.GetResponseStream(),
Encoding.Default);
//Convert the stream to a string
string s = sr.ReadToEnd();
sr.Close();
Resp.Close();
Console.WriteLine(s);
}
static string test()
{
HttpWebRequest Req =
(HttpWebRequest)WebRequest.Create("http://YourWebServer/csharpupload/webform
1.aspx")
;
Req.UserAgent = "Upload Test";
Req.Method = "GET";
Req.CookieContainer = CookieJar;
HttpWebResponse Resp = (HttpWebResponse)Req.GetResponse();
//Read the raw HTML from the request
StreamReader sr = new StreamReader(Resp.GetResponseStream(),
Encoding.Default);
//Convert the stream to a string
string s = sr.ReadToEnd();
sr.Close();
Resp.Close();
int start = 0, end = 0;
start = s.IndexOf("__VIEWSTATE");
if (start > 0)
{
end = s.IndexOf("value=", start);
}
else
{
//did not find the viewstate handle here
}
start = end;
end = s.IndexOf("/", start);
//remove the value= and the quotes from the viewstate value.
string vstate = "\"" + "__VIEWSTATE" + "\"\r\n\r\n" + s.Substring(start
+ 7,
((end-2) - (start + 7)));
vstate.Replace("+", "%2B");
vstate.Replace("=", "%3D");
return vstate;
}
}
}


Hope this help,


Luke
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
M

Mark Waser

Hi Luke,

First off, sorry for the delay but I had to switch languages everywhere.

I built the server side code. It works fine. I can see the files I
upload manually in the Data directory.

I built your class 1. As written, it returns an exception that the
remote server returned an error: (500) Internal Server Error.

<possible sidetrack> Looking at RFC1867, I note that
Req.ContentType = "multipart/form-data; boundary=xyz";
maybe should be
Req.ContentType = "multipart/form-data, boundary=xyz";
(replacing semi-colon with comma)

When I do this, the exception goes away but the file is not uploaded. I
went through the exact same routine with my original VB program and it
behaved exactly the same) </possible sidetrack>

So, once again, I'm at an impasse. Should I do something to try to
track down the internal server error? Can my code call a server of yours
that might be set up to determine what it's passing that might be a problem?
Any suggestions?

By the way, I am using the following:
Microsoft .Net Framework 1.0 version 1.0.3705
Microsoft Development Environment 2002 version 7.0.9466

We do have the newest Framework and Visual Studio 2003 but they
currently aren't approved (i.e. I could switch if it were 100% the case that
the older version is the problem but not otherwise).

Any advice? Does this code actually work on your set-up (and if so,
what versions are you using)?

Thanks.

Mark


MSFT said:
Hi Mark,

I only have a C# sample on hand, you may first take a look at it to see if
it will help:

First you need to create the server side code by following the steps in
this article:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q323246

Then sent the request in your application with following code:

using System;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Text;
namespace PostMultipartForm
{
class Class1
{
/// The main entry point for the application.
static CookieContainer CookieJar = new CookieContainer();
[STAThread]
static void Main(string[] args)
{
string HiddenValue = test();
//RFC 1867 states that you add to -- to the Boundry that you use in the
body of the post
string dataBoundary = "--xyz";
// you will need to change the URL to point to your box
HttpWebRequest Req =
(HttpWebRequest)WebRequest.Create("http://yourservername/csharpupload/webfor
m1.aspx"
);
Req.UserAgent = "Upload Test";
Req.ContentType = "multipart/form-data; boundary=xyz";
Req.Method = "POST";
Req.KeepAlive = true;
Req.CookieContainer = CookieJar;
string FileData = "this is test file data\r\n"; // test data to send.
StringBuilder DataString = new StringBuilder();
DataString.Append(dataBoundary + "\r\n");
//This sends the viewstate info
DataString.Append("Content-Disposition: form-data; name=" + HiddenValue
+ "\r\n"
+ dataBoundary + "\r\n");
DataString.Append("Content-Disposition: form-data; name=" + "\"" +
"File1" +
"\"" +
"; filename=" + "\"" + "TestFile3.txt" + "\"" + "\r\n");
DataString.Append("Content-Type: text/plain\r\n\r\n");
DataString.Append(FileData);
DataString.Append(dataBoundary + "\r\n");
DataString.Append("Content-Disposition: form-data; name=" + "\"" +
"Submit1" +
"\"" + "\r\n\r\n" + "Upload\r\n" + dataBoundary + "--\r\n");

Console.Write(DataString);
byte []Postdata =
System.Text.Encoding.Default.GetBytes(DataString.ToString());
Req.ContentLength = Postdata.Length;
Stream tempStream = Req.GetRequestStream();
// write the data to be posted to the Request Stream
tempStream.Write(Postdata,0,Postdata.Length);
tempStream.Close();
HttpWebResponse Resp = (HttpWebResponse)Req.GetResponse();
//Read the raw HTML from the request
StreamReader sr = new StreamReader(Resp.GetResponseStream(),
Encoding.Default);
//Convert the stream to a string
string s = sr.ReadToEnd();
sr.Close();
Resp.Close();
Console.WriteLine(s);
}
static string test()
{
HttpWebRequest Req =
(HttpWebRequest)WebRequest.Create("http://YourWebServer/csharpupload/webform
1.aspx")
;
Req.UserAgent = "Upload Test";
Req.Method = "GET";
Req.CookieContainer = CookieJar;
HttpWebResponse Resp = (HttpWebResponse)Req.GetResponse();
//Read the raw HTML from the request
StreamReader sr = new StreamReader(Resp.GetResponseStream(),
Encoding.Default);
//Convert the stream to a string
string s = sr.ReadToEnd();
sr.Close();
Resp.Close();
int start = 0, end = 0;
start = s.IndexOf("__VIEWSTATE");
if (start > 0)
{
end = s.IndexOf("value=", start);
}
else
{
//did not find the viewstate handle here
}
start = end;
end = s.IndexOf("/", start);
//remove the value= and the quotes from the viewstate value.
string vstate = "\"" + "__VIEWSTATE" + "\"\r\n\r\n" + s.Substring(start
+ 7,
((end-2) - (start + 7)));
vstate.Replace("+", "%2B");
vstate.Replace("=", "%3D");
return vstate;
}
}
}


Hope this help,


Luke
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
¥

¥xÆW·L³n§Þ³N³B¤ä´©³¡

Hi Mark,

I found there is no matter whenever we use:

Req.ContentType = "multipart/form-data; boundary=xyz";

or

Req.ContentType = "multipart/form-data, boundary=xyz";

I have convert the sample to VB code as following:


Public Function test() As String

Dim CookieJar As New CookieContainer


Dim Req As HttpWebRequest =
CType(WebRequest.Create("http://localhost/webapplication10/webform2.aspx"),
HttpWebRequest)

Req.UserAgent = "Upload Test"
Req.Method = "GET"
Req.CookieContainer = CookieJar

Dim Resp As HttpWebResponse = CType(Req.GetResponse(),
HttpWebResponse)

'Read the raw HTML from the request

Dim sr As StreamReader = New StreamReader(Resp.GetResponseStream(),
Encoding.Default)

'Convert the stream to a string

Dim s As String = sr.ReadToEnd()
sr.Close()
Resp.Close()

Dim start As Integer = 0
Dim TheEnd As Integer = 0

start = s.IndexOf("__VIEWSTATE")

If (start > 0) Then

TheEnd = s.IndexOf("value=", start)

Else

'did not find the viewstate handle here
End If

start = TheEnd
TheEnd = s.IndexOf("/", start)
'remove the value= and the quotes from the viewstate value.

Dim vstate As String = """" + "__VIEWSTATE" + """" + vbCrLf +
vbCrLf + s.Substring(start + 7, ((TheEnd - 2) - (start + 7)))
vstate.Replace("+", "%2B")
vstate.Replace("=", "%3D")

MsgBox(vstate)
Return vstate

End Function

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim CookieJar As New CookieContainer
Dim HiddenValue As String = test()

'RFC 1867 states that you add to -- to the Boundry that you use in
the body of the post

Dim dataBoundary As String = "--xyz"

' you will need to change the URL to point to your box

Dim Req As HttpWebRequest =
CType(WebRequest.Create("http://localhost/webapplication10/webform2.aspx"),
HttpWebRequest)
Req.UserAgent = "Upload Test"
Req.ContentType = "multipart/form-data; boundary=xyz"
Req.Method = "POST"
Req.KeepAlive = True
Req.CookieContainer = CookieJar

Dim FileData As String = "this is test file data" + vbCrLf ' test
data to send.

Dim DataString As StringBuilder = New StringBuilder

DataString.Append(dataBoundary + vbCrLf)

'This sends the viewstate info

DataString.Append("Content-Disposition: form-data; name=" +
HiddenValue + vbCrLf + dataBoundary + vbCrLf)
DataString.Append("Content-Disposition: form-data; name=" + """" +
"File1" + """" + "; filename=" + """" + "TestFile3.txt" + """" + vbCrLf)

DataString.Append("Content-Type: text/plain" + vbCrLf + vbCrLf)
DataString.Append(FileData)
DataString.Append(dataBoundary + vbCrLf)
DataString.Append("Content-Disposition: form-data; name=" + """" +
"Submit1" + """" + vbCrLf + vbCrLf + "Upload" + vbCrLf + dataBoundary +
"--" + vbCrLf)


MsgBox(DataString.ToString())

Dim Postdata() As Byte =
System.Text.Encoding.Default.GetBytes(DataString.ToString())
Req.ContentLength = Postdata.Length

Dim tempStream As Stream = Req.GetRequestStream()

' write the data to be posted to the Request Stream

tempStream.Write(Postdata, 0, Postdata.Length)
tempStream.Close()

Dim Resp As HttpWebResponse = CType(Req.GetResponse(),
HttpWebResponse)

'Read the raw HTML from the request

Dim sr As StreamReader = New StreamReader(Resp.GetResponseStream(),
Encoding.Default)

'Convert the stream to a string
Dim s As String = sr.ReadToEnd()
sr.Close()
Resp.Close()

End Sub

It is workable on my Windows server 2003 and VS.NET 2003.

Luke
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 
M

Mark Waser

Hi Luke,

Wow. This is getting frustrating. I took your code and put it in
VS.NET 2003. I received exactly the same results (Internal Server Error 500
from the remote server when I used a semi-colon; no error and no upload when
I received a comma).

I can not easily change my test server to Windows Server 2003 (though
we're slated to upgrade in December). Further, doing so would be kind of
irrelevant anyways because the whole purpose of this routine was to upload
something to a partner's server which we have no control over (and which
was/is behaving exactly the same way - - internal server error 500 for
semi-colon; no upload for comma).

Apparently either Windows Server 2003 is more tolerant of whatever is
being sent up OR what I'm sending up with your code is not what you're
sending up (due to .NET versions maybe? I'm showing 1.1.4322). Is there a
Windows Server 2003 that I can upload to in order to distinguish between
these two cases?

Thanks.

Mark
 
M

Mark Waser

Hi Luke,

The more I think about it, the more that I feel that the Server 2003 is
a red herring. The form clearly works when it is submitted by a browser so
it should work the same way when submitted by a program IF the program is
submitting the same stream that the browser is. Do you have any code that
allows you to log the exact stream received by a server so that I can
attempt to figure out what is different between what a browser submits and
what the program submits?

Thanks.

Mark

--
Charity: Give a man a fish, feed him for a day
Education: Teach a man to fish, feed him his entire life
Humanism: Teach a man to believe in himself, and he will learn more than
just how to fish.
Teach a man to believe in mankind ....
 
M

MSFT

Hi Mark,

With the sample code, the request sent to server will be same whenever we
use IE or a windows application to upload the file. One thing I notice is
that the error message you get:

(500) Internal Server Error.

It is a general message and there is no detail information. I think you may
try following code in the upload aspx file to see we can get more detaill
information:

string fn = System.IO.Path.GetFileName(File1.PostedFile.FileName);
string SaveLocation = Server.MapPath("Data") + "\\" + fn;

Response.Write("ContentLength:"+ File1.PostFile.ContentLength)
Response.Write("ContentType:"+ File1.PostFile.ContentType)
Response.Write("FileName:"+ File1.PostFile.FileName)

Response.Write("SaveLocation:"+ SaveLocation)

try
{
File1.PostedFile.SaveAs(SaveLocation);
Response.Write("The file has been uploaded.");
}
catch ( Exception ex )
{
Response.Write("Error: " + ex.InnerException.Message);
}


Luke
Microsoft Online Support

Get Secure! www.microsoft.com/security
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top