Post form data using HttpWebRequest - c#

I want to post some form data to a specified URL that isn't inside my own web application. It has the same domain, such like "domain.client.nl". The web application has a url "web.domain.client.nl" en the url where I want to post to is "idp.domain.client.nl".
But my code does nothing..... does someone knows what I'm doing wrong?
Wouter
StringBuilder postData = new StringBuilder();
postData.Append(HttpUtility.UrlEncode(String.Format("username={0}&", uname)));
postData.Append(HttpUtility.UrlEncode(String.Format("password={0}&", pword)));
postData.Append(HttpUtility.UrlEncode(String.Format("url_success={0}&", urlSuccess)));
postData.Append(HttpUtility.UrlEncode(String.Format("url_failed={0}", urlFailed)));
ASCIIEncoding ascii = new ASCIIEncoding();
byte[] postBytes = ascii.GetBytes(postData.ToString());
// set up request object
HttpWebRequest request;
try
{
request = (HttpWebRequest)HttpWebRequest.Create(WebSiteConstants.UrlIdp);
}
catch (UriFormatException)
{
request = null;
}
if (request == null)
throw new ApplicationException("Invalid URL: " + WebSiteConstants.UrlIdp);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
// add post data to request
Stream postStream = request.GetRequestStream();
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Flush();
postStream.Close();

Both the field name and the value should be url encoded.
format of the post data and query string are the same
The .net way of doing is something like this
NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("field1","value1");
outgoingQueryString.Add("field2", "value2");
string postdata = outgoingQueryString.ToString();
This will take care of encoding the fields and the value names

Try this:
var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx");
var postData = "thing1=hello";
postData += "&thing2=world";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

You are encoding the form incorrectly. You should only encode the values:
StringBuilder postData = new StringBuilder();
postData.Append("username=" + HttpUtility.UrlEncode(uname) + "&");
postData.Append("password=" + HttpUtility.UrlEncode(pword) + "&");
postData.Append("url_success=" + HttpUtility.UrlEncode(urlSuccess) + "&");
postData.Append("url_failed=" + HttpUtility.UrlEncode(urlFailed));
edit
I was incorrect. According to RFC1866 section 8.2.1 both names and values should be encoded.
But for the given example, the names do not have any characters that needs to be encoded, so in this case my code example is correct ;)
The code in the question is still incorrect as it would encode the equal sign which is the reason to why the web server cannot decode it.
A more proper way would have been:
StringBuilder postData = new StringBuilder();
postData.AppendUrlEncoded("username", uname);
postData.AppendUrlEncoded("password", pword);
postData.AppendUrlEncoded("url_success", urlSuccess);
postData.AppendUrlEncoded("url_failed", urlFailed);
//in an extension class
public static void AppendUrlEncoded(this StringBuilder sb, string name, string value)
{
if (sb.Length != 0)
sb.Append("&");
sb.Append(HttpUtility.UrlEncode(name));
sb.Append("=");
sb.Append(HttpUtility.UrlEncode(value));
}

Use this code:
internal void SomeFunction() {
Dictionary<string, string> formField = new Dictionary<string, string>();
formField.Add("Name", "Henry");
formField.Add("Age", "21");
string body = GetBodyStringFromDictionary(formField);
// output : Name=Henry&Age=21
}
internal string GetBodyStringFromDictionary(Dictionary<string, string> formField)
{
string body = string.Empty;
foreach (var pair in formField)
{
body += $"{pair.Key}={pair.Value}&";
}
// delete last "&"
body = body.Substring(0, body.Length - 1);
return body;
}

List<KeyValuePair<string, string>> formField= new List<KeyValuePair<string,string>>();
formField.Add(new KeyValuePair<string, string>("Name", "Henry"));
formField.Add(new KeyValuePair<string, string>("Age", "21"));
var body = string.Join("&", formField.Select(kvp => $"{kvp.Key}={kvp.Value}"));

Related

C# Upload file error - Corrupt form data: no leading boundary

I am using this code below to authenticate and upload file to a website, but I am getting an error "Corrupt form data: no leading boundary".
In the Fiddler I see this, ( I see the exact same thing when I upload the file using browser), not sure why I am getting an error when I am doing using C# HttpWebRequest/WebClient
Fiddler Info:
------WebKitFormBoundary9ewWOMyBmk0YAhTL
Content-Disposition: form-data; name="FileSubmitted"; filename="SAMPLE_0001.xls"
Content-Type: application/vnd.ms-excel
------WebKitFormBoundary9ewWOMyBmk0YAhTL
Content-Disposition: form-data; name="FileSubmittedValue"
C:\path\SAMPLE_0001.xls
------WebKitFormBoundary9ewWOMyBmk0YAhTL--
Assumptions:
I hard coded the 'boundary' value, because I am not sure how to get the 'boundary' value after login.
Code: Copied from Stackoverflow
static void Main()
{
NameValueCollection nvCollection = new NameValueCollection();
CookieAwareWebClient webClient = new CookieAwareWebClient();
nvCollection.Clear();
nvCollection["Name"] = "ABC";
nvCollection["Password"] = "XYZ";
//Login to the Site
byte[] responseBytes = webClient.UploadValues("https://www.somesite.com/login.cfm", "POST", nvCollection);
string resultAuthTicket = Encoding.UTF8.GetString(responseBytes);
//Get Cookies
CookieCollection cookies = webClient.CookieContainer.GetCookies(new Uri("https://www.somesite.com/login.cfm"));
//
string URL = "https://www.somesite.com/app/request.cfm";
string boundary = "----WebKitFormBoundary9ewWOMyBmk0YAhTL";
string FilePath = "C:\\Users\\user.name\\Desktop\\SAMPLE_0001.xls";
byte[] fileData = GetMultipartFormData(new Dictionary<string, object>() { { "FileSubmitted", FilePath } }, boundary);
PostForm(URL, "", "", fileData, boundary, cookies);
}
private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
{
Encoding encoding = Encoding.UTF8;
Stream formDataStream = new System.IO.MemoryStream();
bool needsCLRF = false;
foreach (var param in postParameters)
{
// Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
// Skip it on the first parameter, add it to subsequent parameters.
if (needsCLRF)
formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));
needsCLRF = true;
{
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
boundary,
param.Key,
param.Value,
"application/vnd.ms-excel");
formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
string postData2 = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\" \r\n\r\n{2}",
boundary,
"FileSubmittedValue",
"C:\\path\\SAMPLE_0001.xls");
formDataStream.Write(encoding.GetBytes(postData2), 0, encoding.GetByteCount(postData2));
}
}
// Add the end of the request. Start with a newline
string footer = "\r\n--" + boundary + "--\r\n";
formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));
// Dump the Stream into a byte[]
formDataStream.Position = 0;
byte[] formData = new byte[formDataStream.Length];
formDataStream.Read(formData, 0, formData.Length);
formDataStream.Close();
return formData;
}
private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData, string boundary, CookieCollection cookies)
{
HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
if (request == null)
{
throw new NullReferenceException("request is not a http request");
}
// Set up the request properties.
request.UserAgent = userAgent;
request.ContentLength = formData.Length;
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.Method = "POST";
request.KeepAlive = true;
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(cookies);
request.Host = "secure.somesite.com";
request.Referer = String.Format("https://secure.somesite.com/app/request.cfm?CFID={0}&CFTOKEN={1}", cookies[0].Value, cookies[1].Value);
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36";
// Send the form data to the request.
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(formData, 0, formData.Length);
requestStream.Close();
}
try
{
return request.GetResponse() as HttpWebResponse;
}
catch (WebException wex)
{
var pageContent = new StreamReader(wex.Response.GetResponseStream())
.ReadToEnd();
return null;
}
return null;
}
Error:
<head><title>JRun Servlet Error</title></head><h1>500 </h1><body>
<pre>
Corrupt form data: no leading boundary: != ------WebKitFormBoundary9ewWOMyBmk0YAhTL</pre><br><pre>
java.io.IOException: Corrupt form data: no leading boundary: != ------WebKitFormBoundary9ewWOMyBmk0YAhTL
at com.oreilly.servlet.multipart.MultipartParser.<init>(MultipartParser.java:176)
at com.oreilly.servlet.multipart.MultipartParser.<init>(MultipartParser.java:95)
at coldfusion.filter.FormScope.fillMultipart(FormScope.java:170)
at coldfusion.filter.FusionContext.SymTab_initForRequest(FusionContext.java:435)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:33)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.filter.RequestThrottleFilter.invoke(RequestThrottleFilter.java:126)
at coldfusion.CfmServlet.service(CfmServlet.java:175)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at jrun.servlet.FilterChain.service(FilterChain.java:101)
at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106)
at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)
at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)
</pre></body>
Don't Knows: Since I copied this source code from Stackoverflow, I don't know if the file really getting uploaded to C:\Path folder on server (look at the Fiddler data).
Update: When I try to upload file using browser I see Content-Length: 49504, but when I try using C# program Content-Length: 385 (Even when I use the same file in both browser and C# program)
Also, when I try now I am getting "No data was received in the uploaded file SAMPLE_0001.xls"
The code is missing this line of code, which is the actual file content.
formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
Thanks all for your help!

C# HttpWebRequest Post Method many parameters in form

I am writing a simple C# program to do some web request and posting data.
I understand how the basics work like how to login with password and stuff of a html form.
However I am wondering if there is a lot of input parameters (such as this question page ) like check boxes and text fields, is there any efficient method than hard-coding 20 parameters in a string and passing it in? I can read the html file parse it and scan out the input and use String builder to make such a string but I am wondering is there a more efficient method than doing that?
private HtmlAgilityPack.HtmlDocument getpage(string url ,String input)
{
try
{
Stream datastream;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(cookies);
request.AllowAutoRedirect = true;
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2";
request.ContentType = "application/x-www-form-urlencoded";
if (input!=null)
{
String postData = "";
request.Method = "POST";
if (input == "login")
{
postData = String.Format("username={0}&password={1}", "myusername", "mypassword");
}
else if (input == "sendMessage")
{
//THIS IS THE LONG STRING THAT I DON'T WANT TO HARD CODE
postData = String.Format("reciever={0}&sendmessage={1}", "thepersontomessage" ,this.DefaultMessage);
//I am just puting two parameters for now, there should be alot
}
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentLength = byteArray.Length;
datastream = request.GetRequestStream();
datastream.Write(byteArray, 0, byteArray.Length);
datastream.Close();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
datastream = response.GetResponseStream();
String sourceCode = "";
using (StreamReader reader = new StreamReader(datastream))
{
sourceCode = reader.ReadToEnd();
}
HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
htmlDoc.LoadHtml(sourceCode);
this.cookies.Add(response.Cookies);
return htmlDoc;
}
catch (Exception)
{
return null;
}
Also is there a simple way to see what are the parameter values set to when I click a button on a html form within a browser (basically the post url string and parameter values that is sent) so I can hardcode those values into the Postdatastring (check boxs, texts etc)
Personally what I would do is build the parameters as a Dictionary<string,string> so that you can just do:
var parms = new Dictionary<string,string>();
parms.Add("username","fred");
You can then have a method such as:
string DictToString(Dictionary<string,string> dict)
{
StringBuilder builder = new StringBuilder();
foreach(KeyValuePair<string,string> kvp in dict) {
builder.Append(kvp.Key + "=" + kvp.Value + "&");
}
return builder.ToString();
}
You can then get the final parameter string with:
var parms_str = builder.ToString();

missing post data by using HttpWebRequest

I got a problem on posting data by using HttpWebRequest.
There is a string(ie. key1=value1&key2=value2&key3=value3) and I have post it to a site (ie. www.*.com/edit), but ,I don't know why that sometimes it's nothing wrong , but sometimes ,the first key=value1 will be missing, only key2=value&key3=value3 that can find in HttpAnalyzer.
public static string SubmitData(string Url, string FormData, CookieContainer _Cc, string ContentType)
{
Stream RequestStream = null, ResponseStream = null; StreamReader Sr = null;
HttpWebRequest HRequest = (HttpWebRequest)WebRequest.Create(Url);
try
{
HRequest.CookieContainer = _Cc;
HRequest.Method = "POST";
HRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)";
HRequest.ContentType = ContentType;
HRequest.ContentLength = FormData.Length;
//byte[] BFromData = new ASCIIEncoding().GetBytes(FormData);
byte[] BFromData = Encoding.ASCII.GetBytes(FormData);
BFromData = Encoding.Convert(Encoding.ASCII, Encoding.UTF8, BFromData);//ascii → utf8
RequestStream = HRequest.GetRequestStream();
RequestStream.Write(BFromData, 0, BFromData.Length);
//RequestStream.Write(utf8Bytes,0,utf8Bytes.Length );
HttpWebResponse HResponse = (HttpWebResponse)HRequest.GetResponse();
ResponseStream = HResponse.GetResponseStream();
Sr = new StreamReader(ResponseStream, Encoding.UTF8);
return Sr.ReadToEnd();
}
catch
{
return "";
}
finally
{
if (null != RequestStream) RequestStream.Close();
if (null != ResponseStream) ResponseStream.Close();
if (null != Sr) Sr.Close();
}
}
Use Fiddler to see how the request looks like when you click on the form then try using this approach and modify what you need for your request.
public static void PostDataAndDoSomething()
{
string URI = "http://www.something.com";
//make your request payload
string requestBody = String.Format("{{'param1': {0}, 'param2': {1}}}",value1, value2); //json format
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URI); //make request
// set request headers as you need
request.ContentType = "application/json; charset=UTF-8";
request.Accept = "application/json, text/javascript;
request.Method = "POST";
request.UserAgent = "";
request.Headers.Add("X-Requested-With", "XMLHttpRequest");
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(requestBody); //write your request payload
}
WebResponse response = request.GetResponse();
string jsonData = String.Empty;
using (var reader = new StreamReader(response.GetResponseStream()))
{
jsonData = reader.ReadToEnd();
}
response.Close();
//do something with your data, deserialize, Regex etc....
}

Google Api get token request returns invalid_request

I'm trying to get Google APi's access_token using c# and always getting error message invalid_request. There is my code:
var Params = new Dictionary<string, string>();
Params["client_id"] = GoogleApplicationAPI.CLIENT_ID;
Params["client_secret"] = GoogleApplicationAPI.CLIENT_SECRET;
Params["code"] = "4/08Z_Us0a_blkMlXihlixR1579TYu.smV5ucbI8U4VOl05ti8ZT3ZD4CgMcgI";
Params["redirect_uri"] = GoogleApplicationAPI.RETURN_URL;
Params["grant_type"] = "authorization_code";
var RequestData = "";
foreach (var Item in Params)
{
RequestData += Item.Key + "=" + HttpUtility.UrlEncode(Item.Value) + "&";
}
string Url = "https://accounts.google.com/o/oauth2/token";
var request = (HttpWebRequest) WebRequest.Create(Url);
request.Method = HttpMethod.Post.ToString();
request.ContentType = "application/x-www-form-urlencoded";
var SendData = Encoding.UTF8.GetBytes(RequestData);
try
{
request.ContentLength = SendData.Length;
Stream OutputStream = request.GetRequestStream();
OutputStream.Write(SendData, 0, SendData.Length);
} catch {}
try
{
using (var response = (HttpWebResponse) request.GetResponse())
{
var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
string JSON = sr.ReadToEnd();
}
} catch {}
I use https://developers.google.com/accounts/docs/OAuth2WebServer#offline
Try removing the call to HttpUtility.UrlEncode on each item in the request data. You shouldn't need to do this as the data is not going into the url it's being POSTed. This is no doubt diluting the information being sent which is resulting in your Invalid Request response.

programatically send a form with POST

I need to programatically send a form over POST. I have 4 fields, one checkbox and a submit button. how can i go about it?
I use these functions assuming your question is about a forms application.
You can call
HttpPost(
post_url,
"field_name_1", value_1,
"field_name_2", value_2,
...);
Here they are:
public static string HttpPost(string url, params object[] postData)
{
StringBuilder post = new StringBuilder();
for (int i = 0; i < postData.Length; i += 2)
post.Append(string.Format("{0}{1}={2}", i == 0 ? "" : "&", postData[i], postData[i + 1]));
return HttpPost(url, post.ToString());
}
public static string HttpPost(string url, string postData)
{
postData = postData.Replace("\r\n", "");
try
{
WebRequest req = WebRequest.Create(url);
byte[] send = Encoding.Default.GetBytes(postData);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = send.Length;
Stream sout = req.GetRequestStream();
sout.Write(send, 0, send.Length);
sout.Flush();
sout.Close();
WebResponse res = req.GetResponse();
StreamReader sr = new StreamReader(res.GetResponseStream());
string returnvalue = sr.ReadToEnd();
return returnvalue;
}
catch (Exception ex)
{
Debug.WriteLine("POST Error on {0}\n {1}", url, ex.Message);
return "";
}
}
This should do the trick:
NameValueCollection formData = new NameValueCollection();
formData.Add("field1", "value1");
formData.Add("field2", "value2");
// ... and so on ...
WebClient client = new WebClient();
byte[] result = client.UploadValues("http://www.example.com", formData);
The information, that you have checkboxes or submit buttons is not transferred. It's always name and value.
JQuery $.Post() does exactly that.

Categories

Resources