Can't post file data when request is sent over SSL - c#

I have problems trying to use custom basic authentication module similar to this. The client uses HttpWebRequest class.
The client runs the following code:
void uploadFile( string serverUrl, string filePath )
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.
Create( serverUrl );
CredentialCache cache = new CredentialCache();
cache.Add( new Uri( serverUrl ), "Basic", new NetworkCredential( "User", "pass" ) );
request.Credentials = cache;
request.Method = "POST";
request.ContentType = "application/octet-stream";
request.Timeout = 60000;
request.KeepAlive = true;
using( BinaryReader reader = new BinaryReader(
File.OpenRead( filePath ) ) ) {
request.ContentLength = reader.BaseStream.Length;
using( Stream stream = request.GetRequestStream() ) {
byte[] buffer = new byte[1024];
while( true ) {
int bytesRead = reader.Read( buffer, 0, buffer.Length );
if( bytesRead == 0 ) {
break;
}
stream.Write( buffer, 0, bytesRead );
}
}
}
HttpWebResponse result = (HttpWebResponse)request.GetResponse();
//handle result - not relevant
}
If the request is created for a URI starting with http:// it works okay - a request reaches the server, the authentication module is passed the request, it replies with WWW-Authenticate, the request is repeated now with authentication parameters, the module validates it and it passes further.
If the request is created for a URI starting with https:// it doesn't work. The initial request gets to the module and the module replies with WWW-Authenticate
void ReplyWithAuthHeader()
{
HttpContext currentContext = HttpContext.Current;
context.Response.StatusCode = 401;
context.Response.AddHeader( "WWW-Authenticate",
String.Format("Basic realm=\"{0}\"", "myname.mycompany.com"));
}
an an exception is thrown at the client with "Unable to write data to the transport connection: An established connection was aborted by the software in your host machine." text.
I tried System.Net tracing and discovered that after sending the initial request the client gets back the following header:
Date: Fri, 04 Feb 2011 12:15:04 GMT
Server: Microsoft-IIS/5.1
X-Powered-By: ASP.NET
while when the URI started with http:// the client received the following:
Content-Length: 1894
Cache-Control: private
Content-Type: text/html; charset=utf-8
Date: Fri, 04 Feb 2011 12:12:11 GMT
Server: Microsoft-IIS/5.1
WWW-Authenticate: Basic realm="myname.mycompany.com"
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
so clearly the WWW-Authenticate response is swallowed somewhere and doesn't reach the client.
Also if I exclude the code that writes the file data into the request it also authenticates okay.
How do I fix this? How do I make the WWW-Authenticate response get to the client?

What are the http status codes returned from the server?
Is the certificate of the server valid?
Can you post the stack trace?
Try to disable your firewall and other networking tools like fiddler etc on your client.
Also try with the KeepAlive property to false.

Related

Capture response information from (3rd party) web service on error

I have the following code, which submits XML to a 3rd party web service, which errors (intentionally, at the moment) on "req.GetResponse()" with the error, detailed below.
byte[] bytes = Encoding.ASCII.GetBytes(myXMLData);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(myWebsite);
using (Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
WebResponse response = req.GetResponse();
string responseStream = StringFromResponseStream(response);
Error from GetResponse()
Exception thrown: 'System.New.WebExtension' in System.dll
Additional information: The remote server returned an error: (400) Bad Request
When I trace this call in Fiddler, I can see that the response from the service, also includes a far more useful error (below; RAW view), which I am trying to get to:
HTTP/1.1 400 Bad Request
Date: Thu, 16 Jun 2016 10:42:26 GMT
Cache-Control: private
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Type: text/plain; charset=UTF-8
Content-Length: 54
Caseprovider-Credentials: <snip>
Caseprovider-Credentialshash: <snip>
Caseprovider-Apiversion: 15
Connection: close
No supported action 'SomeName' available for 'SomeValue'
Having a 'watch' on the variables doesn't seem to show where I might obtain this from (and quite possibly something simple that I have overlooked)
Have eventually found a resolution for the; where 'result' contains the content from the process; there's more to do, but this is the basics of what I needed.
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(myWebSite);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));
StringContent stringContent = new StringContent(myXMLData);
stringContent.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
HttpResponseMessage httpResponseMessage = httpClient.PostAsync(httpClient.BaseAddress, stringContent).Result;
string result = httpResponseMessage.Content.ReadAsStringAsync().Result;
}

Request canceled when downloading feed

I have a worker role on Azure. Every two hours, i download products from 3 different affiliate company.
First time, when the job runs, it's works perfect. The next time the job should run, I get from one affiliate, "The request was aborted: The request was canceled." The 2 others works perfect.
It's not just once, every time. I have ask this affiliate company, but there is no problem. So it must be my code. I have this to download json doc:
using (var Client = new WebClient())
{
Client.Headers.Add("X-API-KEY", Key);
Data = Client.DownloadString(URL);
}
What have I missed?
UPDATE 1:
i have try this:
HttpWebRequest Req = (HttpWebRequest)WebRequest.Create(URL);
Req.KeepAlive = false;
Req.Headers.Add("X-API-KEY", Key);
Req.Method = "GET";
using (var Resp = Req.GetResponse())
{
using (var Reader = new StreamReader(Resp.GetResponseStream()))
{
Data = Reader.ReadToEnd();
}
}
Same problem.
UPDATE 2
Request 1
GET https://se.#####.com/1/stores.json HTTP/1.1
X-API-KEY: x.............N
Host: se.#####.com
Connection: Close
Response 1
HTTP/1.1 200
Server: nginx
Date: Mon, 08 Jun 2015 14:56:39 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: close
Set-Cookie: ci_session=..............; expires=Mon, 08-Jun-2015 16:56:39 GMT; Max-Age=7200; path=/
e30
{"status":true,"data":[................]}
0
Request 2
GET https://se.#####.com/1/stores.json HTTP/1.1
X-API-KEY: x.............N
Host: se.#####.com
Connection: Close
Response 2
HTTP/1.1 200
Server: nginx
Date: Mon, 08 Jun 2015 15:06:29 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: close
Set-Cookie: ci_session=..................; expires=Mon, 08-Jun-2015 17:06:29 GMT; Max-Age=7200; path=/
e30
{"status":true,"data":[.....................]}
0
UPDATE 3
[TestMethod]
public void DownloadTest()
{
Test();
Test();
Test();
}
private static void Test()
{
const string merchantsUrl = "https://se.#####.com/1/stores.json";
string Data;
var Req = (HttpWebRequest)WebRequest.Create(merchantsUrl);
Req.KeepAlive = false;
Req.Headers.Add("X-API-KEY", ".....");
Req.Method = "GET";
using (var Resp = Req.GetResponse())
{
using (var Reader = new StreamReader(Resp.GetResponseStream()))
{
Data = Reader.ReadToEnd();
}
}
}
Change the order of requests and see if the request to same company is failing?
By default WebClient opens a connection as KeepAlive which might be causing this issue. So try explicitly mentioning that KeepAlive mode is false.
Capture the request details for the first time and second time in fiddler or similar tools which could give you more details in tracking down the issue.

What prestashop web service http HEAD returns

I'm developing a class that operates with the prestashop web service.
And I have a problem now because I don't know what a HEAD request actually gets back from prestashop webservice...
This is my code:
#region HEAD
public string Head() {
string requestURL = WebServiceURL + "/" + Table + "/" + TableID;
WebRequest wr = WebRequest.Create(requestURL);
wr.Method = "HEAD";
wr.ContentType = "application/xml";
wr.Credentials = new NetworkCredential(UserName, PassWord);
try {
HttpWebResponse response = (HttpWebResponse) wr.GetResponse();
return response.Headers.ToString();
}catch(Exception) { return ""; }
}
#endregion
which return this:
Vary: Host
Access-Time: 1391506047
PSWS-Version: 1.5.6.1
Execution-Time: 0.011
Content-Sha1: ...
Content-Type: text/xml;charset=utf-8
Date: Tue, 04 Feb 2014 09:27:26 GMT
Set-Cookie: ....; httponly
Server: Apache/2.4.3 (Win32) OpenSSL/1.0.1c PHP/5.4.7
X-Powered-By: PrestaShop Webservice
Now my question is, if this is the correct way of getting the HEAD data from the prestashop webservice and if this data is right?
Thx :)
Data looks OK.
I wouldn't use Content-Type header in your code, because HEAD is similar to GET and sends no message body in a request even in a response, only the header data is submitted back to the client.
Check HTTP Method Definitions.

How do I carry a cookie from a System.Net.HttpWebResponse to the next System.Net.HttpWebRequest?

I'm trying to do some automated web requests and need to maintain a cookie from one to the next. I can see that I'm getting back the cookie I want from the initial response, but I can't attach it to the next request.
c# code
// response part
using (var wresp = (System.Net.HttpWebResponse)wrequest.GetResponse())
{
// respblob gets returned and is accessible to the next request
respblob.CookieList = new List<System.Net.Cookie>();
foreach (System.Net.Cookie cook in wresp.Cookies)
{
respblob.CookieList.Add(cook);
}
// ... more stuff not related to cookies
}
// next request part
var wrequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
wrequest.Method = "POST";
wrequest.ContentType = "application/x-www-form-urlencoded";
wrequest.CookieContainer = new System.Net.CookieContainer();
// request.CookieList contains one cookie as expected
// from the previous response
for (int j = 0; j < request.CookieList.Count; j++)
{
wrequest.CookieContainer.Add(request.CookieList[j]);
}
// .... write data to request body
// ... complete the request, etc
here is a recorded exchange for the two request/response actions.
request:
GET http://domain.com/Login.aspx?ReturnUrl=%2fDefault.aspx HTTP/1.1
Host: domain.com
Connection: Keep-Alive
response:
HTTP/1.1 200 OK
Date: Tue, 15 May 2012 17:17:52 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Set-Cookie: ASP.NET_SessionId=zzz4fpb4alwi1du2yavx5tah; path=/; HttpOnly
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 24408
...html content...
next request:
POST http://domain.com/Login.aspx?ReturnUrl=%2fDefault.aspx HTTP/1.1
Host: domain.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 979
Expect: 100-continue
__LASTFOCUS=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=viewstateclipped&__EVENTVALIDATION=validationclipped&ctl00%2524ContentPlaceHolder1%2524Login1%2524LoginButton=&ctl00%2524ContentPlaceHolder1%2524Login1%2524UserName=my.email%40example.com&ctl00%2524ContentPlaceHolder1%2524Login1%2524Password=myPassword
So even though the cookie exists in the HttpWebRequest CookieContainer, it doesn't get sent with the request. What am I doing wrong?
You should use the same CookieContainer instance for the both HttpWebRequest objects that you are using. simply create a CookieContainer instance once:
var cookieContainer = new CookieContainer();
and then have your both request objects use this instance:
var request1 = (HttpWebRequest)WebRequest.Create("http://example.com/url1");
// assign the cookie container for the first request
request1.CookieContainer = cookieContainer;
... go ahead and send the request and process the response
var request2 = (HttpWebRequest)WebRequest.Create("http://example.com/url2");
// reuse the same cookie container instance as the first request
request2.CookieContainer = cookieContainer;
... go ahead and send the request and process the response
Since you are using the same CookieContainer for the both requests, when the first request stores the cookie in this container, the cookie will be emitted alongside the second request automatically. This of course assumes that the second request is to the same domain as the first one.
Also since the cookie is a session cookie (HttpOnly flag) you cannot read its value from the client.

HttpWebRequest POST gives 500 server error

I need to make from my app an authentificated httpwebrequest. the response to my request should be in json format. for this i'm using the code below:
// Create the web request
Uri address = new Uri("http://www.mysite.com/remote/user/login/format/json");
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
request.UseDefaultCredentials = false;
request.Credentials = new NetworkCredential(UserName, Password);
request.PreAuthenticate = true;
request.ContentType = "application/x-www-form-urlencoded";
request.Accept = "application/json";
string data = string.Format("username={0}&password={1}", otherusername, otherpassword);
// Create a byte array of the data we want to send
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data);
// Set the content length in the request headers
request.ContentLength = byteData.Length;
//Write data
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
// Get response
try
{
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
// Console application output
jsonResponse = reader.ReadToEnd();
reader.Close();
}
user = new User();
JObject o = JObject.Parse(jsonResponse);
user.Unguessable_id = (string)o["unguessable_id"];
user.Print_id = (string)o["print_id"];
user.Rrid = (string)o["rrid"];
user.Raid = (string)o["raid"];
}
catch (WebException ex) {
errorMessage = ex.Message;
}
the problem is that the very first call it always gives a 500 error on the server. and the request fails. if i redo the call(by making an refresh in my browser) the request is successful.
the request should look like this in normal conditions:
POST /remote/user/login/format/json HTTP/1.1
Host: <yourhost>
username=user&password=pass
but when the server sends out the 500 error he received something like this:
username=user&password=passwordPOST /remote/user/login/format/json HTTP/1.1
any idea why this is happening? in my test app if i refresh the page that makes the httpwebrequest the call is successful.
EDIT:
after installing Fiddler the requests made look like this:
=> the one that generates 500
POST http://www.mysite.com/remote/user/login/format/json HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Host: www.mysite.com
Content-Length: 30
Expect: 100-continue
Connection: Keep-Alive
username=user&password=pass
=> the one made on refresh
POST http://www.mysite.com/remote/user/login/format/json HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic ZGNpOkFpR2g3YWVj
Host: www.mysite.com
Content-Length: 30
Expect: 100-continue
Connection: Keep-Alive
username=user&password=pass
it seems that Authorization: Basic ZGNpOkFpR2g3YWVj is not included in the first request...why is that happening?(i'm using the same code for both requests)
I would advice you to install Fiddler to see what's really happening
I needed to add:
request.Headers.Add("Authorization: Basic ZGNpOkFpR2g3YWVj");
weird though that for the second request it was added automatically..

Categories

Resources