HttpWebRequest receives "WebException: The request timed out" - c#

After endless research and testing of different combinations, I'm clueless right now.
I receive an WebException: The request timed out only if I my byteArray gets filled by something else than System.Text.Encoding.UTF8.GetBytes(""). (Like "hello")
The server setup is a https-request to a Google Load Balancer, which communicates with the backend via HTTP. The backend is an Apache with PHP.
For testing purposes (self-signed SSL-Cert) I have this:
System.Net.ServicePointManager.ServerCertificateValidationCallback =
delegate (object s,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors){
return true;
};
If I enter the URL in my web-browser (Chrome), I get a response.
If I use the HTTP-requester from Mozilla with or without content to send, I get the correct response data (after adding an SSL-Security exception)
If I run my code below with System.Text.Encoding.UTF8.GetBytes("") everything works (except I cannot send data and therefore receive what I want)
Here's the code I'm using.
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://someurl.com/some.php");
webRequest.Proxy = null;
webRequest.Credentials = CredentialCache.DefaultCredentials;
webRequest.Method = "POST";
webRequest.Timeout = 3000;
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes("someData"); //works if empty
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = byteArray.Length;
Stream postData = webRequest.GetRequestStream();
postData.Write(byteArray, 0, byteArray.Length);
postData.Close();
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); //ERROR MESSAGE
Stream dataStream = webResponse.GetResponseStream();
reader = new StreamReader(dataStream);
string data = reader.ReadToEnd(); //output data
reader.Close ();
dataStream.Close ();
webResponse.Close ();
The exact error (btw, all this happens in the Unity3D editor):
WebException: The request timed out
System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult)
System.Net.HttpWebRequest.GetResponse ()
So why on earth is it not working, once there is something the GetRequestStream has to write?
Thanks and all the best,
Kruegbert
..::Addendum
if I increase the timeout, it just takes longer until the same msg appears.
If I write webRequest.ContentLength = byteArray.Length+1 I receive a response, but it's a WebException error: ProtocolError
If I write webRequest.ContentLength = byteArray.Length-1 I get the ProtocolViolationException
I already tried the same with try/catch/using resulting in the same behaviour

I figured out, why it was not working - still I don't know why it behaves like this. (Maybe a UnityEditor thing)
I added
webRequest.ProtocolVersion = HttpVersion.Version10;
and everything worked. No more timeout errors. And yes webRequest.ProtocolVersion = HttpVersion.Version11; results in the timeout error.
However, making a HttpRequest from the web succeeds with either of these: HTTP/1.1, HTTP/1.0 (with Host header), HTTP/1.0 (without Host header)

Related

WebRequest timeout from Windows Service and Server

Currently we have a Windows Service which processes messages from RabbitMQ. It does this by using a web request to a URi. We then read the response and then proceed from there if it is successful.
Process Messages Method
//Deserialze the response
PMResponse res = (PMResponse)ser.ReadObject(GetResponse(addr + paramArgs));
GetResponse Method
private static MemoryStream GetResponse(string URi)
{
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create(URi);
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
string postData = "";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
//Console.WriteLine(responseFromServer);
MemoryStream mStrm = new MemoryStream(Encoding.UTF8.GetBytes(responseFromServer));
reader.Close();
dataStream.Close();
return mStrm;
}
The service is installed on one of our servers where, last week out of nowhere, the application stopped processing messages.
The web service we use to process the SMS messages works fine when we open the parameterised URL in the web browser.
The service also works on my local machine. However when deployed on the server either as a service or as a test console application the operation times out.
What problems do you think there are? The code works, just not on this server.
Answering to save people time:
"The problem is resolved, the company we use for sending the SMS restarted their servers and it worked fine. Many man hours wasted on this before it even got to me hah. Thanks for your time guys."

How can I avoid a "Bad Request - Invalid Hostname" error when making a REST call from a Compact Framework client?

I used this code from here to try to call a REST Controller method on a Web API server app from a Compact Framework client:
public static void SendXMLFile3(string uri, string data)
{
WebRequest request = WebRequest.Create (uri);
request.Method = "POST";
string postData = data;
byte[] byteArray = Encoding.UTF8.GetBytes (postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream ();
dataStream.Write (byteArray, 0, byteArray.Length);
dataStream.Close ();
WebResponse response = request.GetResponse ();
MessageBox.Show(((HttpWebResponse) response).StatusDescription);
dataStream = response.GetResponseStream ();
StreamReader reader = new StreamReader (dataStream);
string responseFromServer = reader.ReadToEnd();
MessageBox.Show(responseFromServer);
reader.Close ();
dataStream.Close ();
response.Close ();
}
...I had earlier tried this code, which I got from the book "Microsoft .NET Compact Framework":
public static void SendXMLFile2(string uri, string data)
{
WebRequest req = WebRequest.Create(uri);
req.Method = "Post";
req.ContentType = "text/plain; charset=utf-8";
byte[] encodedBytes = Encoding.UTF8.GetBytes(data);
req.ContentLength = encodedBytes.Length;
Stream requestStream = req.GetRequestStream();
requestStream.Write(encodedBytes, 0, encodedBytes.Length);
requestStream.Close();
WebResponse result = req.GetResponse();
MessageBox.Show(result.ToString());
}
...but I get "400 - Bad Request" with the new (as well as the old) code.
My initial attempt also does not work, with the same result (400):
public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create(uri);
myHttpWebRequest.AllowWriteStreamBuffering=false;
string postData = "<Command><DSD><line_id>1</line_id><invoice_no>david_dsd</invoice_no>. . .</DSD></Command>"; // TODO: if this works, replace it with the real data
myHttpWebRequest.Method="POST";
UTF8Encoding encodedData = new UTF8Encoding();
byte[] byteArray=encodedData.GetBytes(postData);
myHttpWebRequest.ContentType = "application/xml";
myHttpWebRequest.ContentLength=byteArray.Length;
Stream newStream=myHttpWebRequest.GetRequestStream();
newStream.Write(byteArray,0,byteArray.Length);
newStream.Close();
HttpWebResponse myHttpWebResponse=(HttpWebResponse)myHttpWebRequest.GetResponse();
return myHttpWebResponse.StatusDescription;
}
There is much more about the plethora of variations I have tried here, where I have reached my length-of-post limit.
UPDATE
Note that the Server code doesn't know/care that the file is XML:
[HttpPost]
[Route("api/inventory/sendXML/{userId}/{pwd}/{filename}")]
public async Task SendInventoryXML(String userId, String pwd, String fileName)
{
Task task = Request.Content.ReadAsStreamAsync().ContinueWith(t =>
{
var stream = t.Result;
using (FileStream fileStream = File.Create(String.Format(#"C:\HDP\{0}.xml", fileName), (int)stream.Length))
{
byte[] bytesInStream = new byte[stream.Length];
stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
fileStream.Write(bytesInStream, 0, bytesInStream.Length);
}
});
}
UPDATE 2
I tried Charles to see if it would pick up the local HTTP traffic, but it is also deaf to such (like Fiddler, without special ministrations, anyway). This is what Charles looks like after getting the "400 - Bad Request" error:
UPDATE 3
I found this suggestion somewhere to get Fiddler to show local HTTP traffic:
Tools--> Fiddler Options. Choose Connections tab. Check the 'USe PAC Script' option.
...but it didn't work - I still see no HTTP traffic when getting the "400 (Bad Request)" message.
UPDATE 4
I am now seeing "400 (Bad Request)" in Fiddler 2, too; to get it, I enter any of the following in Postman (don't see this in Fiddler when calling from CE/CF/handheld app):
http://SHANNON2:21608/api/inventory/sendXML/su/su/blablee // Hostname
http://SHANNON2.:21608/api/inventory/sendXML/su/su/blablee // Hostname with Fiddler-fooler appended "."
http://192.168.125.50:21608/api/inventory/sendXML/su/su/blablee // IP Address
(Fiddler does not capture anything if I replace the hostname or IP Address with "localhost")
Note: For these URLs in Postman, I have "Post" (as opposed to GET, etc.) selected, and an XML file attached.
Inspectors.Headers in Fiddler shows:
POST /api/inventory/sendXML/su/su/blablee HTTP/1.1
Although I consider this a minor debugging victory, I still don't see why I'm getting the "400" error.
Fiddler tells me, in the Inspectors.WebView pane:
Bad Request - Invalid Hostname
--------------------------------------------------------------------------------
HTTP Error 400. The request hostname is invalid.
How can that be? When I run it from Postman, I hit the breakpoint in the server - if the hostname is invalid, why is it being reached?
UPDATE 5
Testing the call from Fiddler Composer and Postman, the only way I can reach the breakpoint in the server code is by using "localhost" - replacing that with the PC's IPAddress (192.168.125.50) or HostName (SHANNON2) does not reach the breakpoint. While "interesting," calling "localhost" from the handheld device is obviously not an option.
UPDATE 6
Related new question here.
UPDATE 7
The crux of the biscuit was adding at the command prompt either this:
netsh http add urlacl url=http://shannon2:80/ user=everyone
...or this:
netsh http add urlacl url=http://shannon2:8080/ user=everyone
See Update 5 here for more details
Adding my observations, if you are facing the issue Bad Request - Invalid Hostname while calling the API from Postman. Something like this.
Consider adding the Host in Headers, it will work.
Updated after someone is not able to view the image: If the images are not loading, then basically this you have to do:
Basically, you have to add Content-Length and Host. Postman auto calculates when the request is sent. These can be enabled in postman by unhiding auto-generated headers in Postman. or you can set by your own.
The crux of the biscuit was adding at the command prompt either this:
netsh http add urlacl url=http://shannon2:80/ user=everyone
...or this:
netsh http add urlacl url=http://shannon2:8080/ user=everyone
See Update 5 here for more details

Received "Request was cancelled" error when writing JSON data to HttpWebRequest

I've a iOS application written in C# using Monodevelop, and as part of the application I make a call to a web service. The web service call requires that JSON data to be written to the request. However, I receive an error the first time I attempt to write the data; all subsequent calls to the same method with the same parameters work. The following is a snippet of the relavent code:
// Start snippet
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create (_connectionSettings.Uri);
request.Timeout = 15000; // milliseconds
if (_connectionSettings.Username != "") {
request.Credentials = new NetworkCredential (_connectionSettings.Username, _connectionSettings.Password);
}
if (post) {
request.Method = "POST";
request.ContentType = "application/json";
if (jsonData != null) {
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(jsonData);
request.ContentLength = byteArray.Length;
using (Stream ds = request.GetRequestStream()) { //<--- ERROR HERE
ds.Write (byteArray, 0, byteArray.Length);
}
} else {
request.Method = "GET";
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
// end snippet
The error I get is as follows:
System.Net.WebException: Request was cancelled. --->
System.Exception:
Cannot close the stream until all bytes are written
--- End of inner exception stack trace --- at
System.Net.WebConnectionStream.Close ()
[0x00121] in
/Developer/MonoTouch/Source/mono/mcs/class/System/System.Net/WebConnectionStream.cs:785
at System.IO.Stream.Dispose () [0x00000] in
/Developer/MonoTouch/Source/mono/mcs/class/corlib/System.IO/Stream.cs:93
at
MyCustomMethod (System.String& responseString, System.String jsonData, Boolean post,
Boolean suppressAlert) [0x00101] in /Path/To/My/Class.cs:192
Any ideas what I could be doing wrong?
EDIT
Ok, apparently when stepping through the application, the method works every time. What I've noticed is that when the error is throw, the request.ContentLength is zero despite the fact that the byteArray.Length is non-zero. However when stepping through the application, the request.ContentLength keeps the expected value of the byteArray.Length.
Ok, it looks like we don't need to set the request.ContentLength at all. Removing the line:
request.ContentLength = byteArray.Length;
fixes the issue entirely. I'm still curious if this is a bug in the library as most of the code samples show setting the HttpWebRequest's ContentLength, and it works properly on subsequent tries.

SSL HttpWebRequest causes internal server error?

I am trying to write a login script, but for some reason I am getting an internal server error (500).
I tried this with PHP and cURL, there I got a response when I set the option VERIFY_PEER = false.
Here's the C# code:
private void Login()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://whatever.com");
ASCIIEncoding encoding = new ASCIIEncoding();
string postData = string.Format("user={0}&password={1}&submit=login", User, Password);
byte[] data = Encoding.ASCII.GetBytes(postData);
webRequest.Method = "POST";
ServicePointManager.ServerCertificateValidationCallback = (x,y,z,a) => true;
webRequest.ContentLength = data.Length;
webRequest.KeepAlive = false;
using (Stream stream = webRequest.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
{
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
{
Console.WriteLine(responseStream.ReadToEnd());
}
}
}
Does anybody know why I am not getting a response?
Thanks for your help.
I would suggest using Fiddler to inspect the HTTP request/responses. You can set it up to intercept HTTPS traffic too. That way you can see exactly what your system is requesting.
From your comments your getting a 500 error, that normally means the url/request is malformed if it works from one script/app and not the other. This will let you see whats being request (and highlight any protocol error for you).
I found the mistake... It seems as if the server requieres a "valid" useragent. When setting firefox as a useragent, everything works fine.

ASP HttpWebRequest and Redirect

OK, I have a client doing a POST to a server with some data. The server receives the post, and answers with a redirect. The problem is that the client does not redirects. Also, I've tried to check the StatusCode of the response the client gets, and it is always the same "OK". Instead of the redirect code. What am I missing?
In the client side I have something like this:
StringBuilder sb;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost/serv/Default.aspx");
request.Method = "POST";
byte[] data = Encoding.ASCII.GetBytes(GetDATA());
request.ContentType = "text/xml";
request.ContentLength = data.Length;
Stream stream = request.GetRequestStream();
stream.Write(data, 0, data.Length);
request.AllowAutoRedirect = true;
request.MaximumAutomaticRedirections = 10;
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
response.Close(); } catch(Exception ex) {}
In the server side I have just this line:
HttpContext.Current.Response.Redirect("http://www.google.com", true);
In this case, the client receives an answer and does not do nothing.
Thanks.
When you have "AllowAutoRedirect" set to true, it means that your HttpWebRequest object will make a 2nd webrequest once it sees a redirect. When you see the "200 OK" from the response object, it is because you are seeing the response for "www.google.com". You can check the Response.ResponseURI to verify this.
You'll need to turn off the "AllowAutoRedirect", then check the response code like Oded said.

Categories

Resources