HttpWebResponse contentLength always -1 - c#

My web response content length always seem to be -1 after my web request. I'm sure you massage and signature are right.
What am I doing wrong here?
string msg = string.Format("{0}{1}{2}", nonce, clientId, apiKey);
string signature = ByteArrayToString(SignHMACSHA256(apiSecret, StrinToByteArray(msg))).ToUpper();
const string endpoint = "https://www.bitstamp.net/api/balance/";
HttpWebRequest request = WebRequest.Create(endpoint) as HttpWebRequest;
request.Proxy = null;
request.Method = "POST";
request.ContentType = "application/xml";
request.Accept = "application/xml";
request.Headers.Add("key", apiKey);
request.Headers.Add("signature", signature);
request.Headers.Add("nonce", nonce.ToString());
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

From the documentation,
The ContentLength property contains the value of the Content-Length header returned with the response. If the Content-Length header is not set in the response, ContentLength is set to the value -1.

Got it working with webClient instead of the httpWebRequest.
If someone can get it working with httpWebRequest, you wil get the answer.
string msg = string.Format("{0}{1}{2}", nonce, clientId, apiKey);
var signature = ByteArrayToString(SignHMACSHA256(apiSecret, StrinToByteArray(msg))).ToUpper();
var path = "https://www.bitstamp.net/api/user_transactions/";
using (WebClient client = new WebClient())
{
byte[] response = client.UploadValues(path, new NameValueCollection()
{
{ "key", apiKey },
{ "signature", signature },
{ "nonce", nonce.ToString()},
});
var str = System.Text.Encoding.Default.GetString(response);
}

Because this worked with 'WebClient', there was nothing wrong with the request, which means almost definitely that the request was being sent back 'Chunked'. This is indicated by the header 'Transfer-Encoding'.
There are several reasons why the webserver might send back something chunked including the fact that the return is binary.
I came to this page because Fiddler was "interfering" with my request by turning a perfectly good response by the server and then returning it chunked to my client. That was because I had the 'Stream' button pushed or active. When it isn't, it sends the data back buffered which preserves the response from the server. That was a horrible thing to track down..
But the research did tell me about why the Content-Length header might be -1.
The solution? Either fix the way the server (or proxy in my case) is sending the response back, or just read the response stream to the end. The latter will return all the chunks to you connected and you can take a length of the bytes returned.
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
String responseString = reader.ReadToEnd();
int responseLength = responseString.Length;
If you want bytes it is more involved -- not sure if there is a reader that allows you to read to the end -- the Binary reader requires a buffer up front.
An elegant way to consume (all bytes of a) BinaryReader?
Njoy.

Related

c# .net Http response 411 length required when length is included

I'm trying to get a simple response from a local .net site of my own. (Really I'm just trying to see what the content-body looks like from the server side.) Here is the controller method that's sending the response:
public HttpResponseMessage Post([FromBody]string value)
{
data.Add(value);
var msg = Request.CreateResponse(HttpStatusCode.Created);
msg.Headers.Location = new Uri(Request.RequestUri + "/" + (data.Count-1).ToString());
msg.Content = new StringContent(value);
return msg;
}
And here is the code that's making the request:
HttpWebRequest request;
request = (HttpWebRequest)WebRequest.Create ("http://localhost:50203/api/Values");
request.Method = "POST";
try
{
WebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
byte[] requestBody = ASCIIEncoding.ASCII.GetBytes(HttpUtility.UrlEncode("grant_type=client_credentials"));
request.ContentLength = requestBody.Length;
dataStream.Write(requestBody, 0, requestBody.Length);
StreamReader reader = new StreamReader(dataStream);
myString = reader.ReadToEnd();
}
I'm getting the response message: HTTP Error 411. The request must be chunked or have a content length. But as you can see I DO assign the content length in the line: request.ContentLength = requestBody.Length;.
Why am I getting this error?
Thanks to help from itsme86 I was able to see what was happening. It had to do with misunderstanding the HttpWebRequest method. I was trying to set the content length and write to the request after I'd already posted it using the GetResponse method. I should have posted the length first. This wasn't a particularly good question, and no one else should answer.

REST API PATCH request

I'm trying to send requests and get responses from MailChimp API . . so far, GET, POST and DELETE are working good however, PATCH always results to Bad Request can you identify the error in this code?
string data = "{\"name\": \"TestListTWOTWOTWO\"}";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Headers[HttpRequestHeader.Authorization] = accessToken;
request.Method = "PATCH";
request.ContentType = "text/plain;charset=utf-8";
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] bytes = encoding.GetBytes(data);
request.ContentLength = bytes.Length;
using (Stream requestStream = request.GetRequestStream())
{
// Send the data.
requestStream.Write(bytes, 0, bytes.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
the error occus on the line with request.GetResponse();
it is an unhandled WebException saying The remote server returned an error: (400) Bad Request
after checking the error response, here's the what it says
"Your request doesn't appear to be valid JSON:
\nParse error on line 1:\nPATCH /3.0/lists/9bb\n^\n
Expected one of: 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '['"
Many C# libraries seem to try to use the Expect: 100-Continue header, which MailChimp/Akamai has a problem with when combined with PATCH. You have two options.
Turn off Expect: 100-Continue in your HTTP library. In one C# library, you do that with a line of code like Client.DefaultRequestHeaders.ExpectContinue = False
Tunnel the PATCH request through HTTP POST using the X-Http-Method-Override header. Here's more details on that header.
Cause PATCH is a quite new RFC, so you would not expect that more then a few services support it at all. You'd better check that if the service supports it.
You send request using json format, but set content type to "text/plain" is that OK?

Unable to read HttpResponse from HTTPS

public void HttpsRequest(string address)
{
string data;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
byte[] resp = new byte[(int)response.ContentLength];
Stream receiveStream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(receiveStream, Encoding.ASCII))
{
data = reader.ReadToEnd();
}
}
I get an Arithmetic operation resulted in an overflow when I am trying to read a page over https. Errors occur because the response gives me ContentLenght = -1.
Using fiddler I can see that the page was received. Some other websites using HTTPS works fine but most of them not.
If I query https://www.google.com, I get the same error message, because not every response has a content length. Use this code to avoid the problem:
public static void HttpsRequest(string address)
{
string data;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
request.Method = "GET";
using (WebResponse response = request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
data = reader.ReadToEnd();
}
}
}
This behavior is expected: not every response contains content length.
There is nothing in your sample that requires length to be known, so simply not reading it maybe enough.
From HttpWebResponse.ContentLength Property
The ContentLength property contains the value of the Content-Length header returned with the response. If the Content-Length header is not set in the response, ContentLength is set to the value -1.
If Content-Length header is not set it does not mean that you got a bad response.

Send http request to server without expecting a response

I have a need to send a POST http request to a server ,but it should not expect a response. What method should i use for it ?
I have been using
WebRequest request2 = WebRequest.Create("http://local.ape-project.org:6969");
request2.Method = "POST";
String sendcmd = "[{\"cmd\":\"SEND\",\"chl\":3,\"params\":{\"msg\":\"Helloworld!\",\"pipe\":\"" + sub1 + "\"},\"sessid\":\"" + sub + "\"}]";
byte[] byteArray2 = Encoding.UTF8.GetBytes(sendcmd);
Stream dataStream2 = request2.GetRequestStream();
dataStream2.Write(byteArray2, 0, byteArray2.Length);
dataStream2.Close();
WebResponse response2 = request2.GetResponse();
to send a request and get back a response. This works fine if the request will get a response back from the server. But, for my need, i just need to send a POST request. And there will be no response associated with the request i am sending. How do i do it ?
If i use the request2.GetRespnse() command , i get an error that "The connection was closed unexpectedly"
Any help will be appreciated. thanks
If you're using the HTTP protocol, there has to be a response.
However, it doesn't need to be a very big response:
HTTP/1.1 200 OK
Date: insert date here
Content-Length: 0
\r\n
refer to this answer.
What you are looking for, I think, is the Fire and Forget pattern.
HTTP requires response as already mentioned by Mike Caron. But as a quick (dirty) fix you could catch the "connnection closed unexpectedly" error and continue.
If your server is OK with this, you can always use RAW socket to send request then close it.
If you don't want to wait for response you can send data in another thread or simple use
WebClient.UploadStringAsync, but note that response always take place after request. Using another thread for request allows you to ignore response processing.
Take a look at this it may help.
public static void SetRequest(string mXml)
{
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.CreateHttp("http://dork.com/service");
webRequest.Method = "POST";
webRequest.Headers["SOURCE"] = "WinApp";
// Decide your encoding here
//webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentType = "text/xml; charset=utf-8";
// You should setContentLength
byte[] content = System.Text.Encoding.UTF8.GetBytes(mXml);
webRequest.ContentLength = content.Length;
var reqStream = await webRequest.GetRequestStreamAsync();
reqStream.Write(content, 0, content.Length);
var res = await httpRequest(webRequest);
}

getting this error: "The remote server returned an error: (422) Unprocessable Entity." when doing post from C# to RoR

This code is for an outlook plugin. We're trying to POST to a page and are getting this error:
The remote server returned an error: (422) Unprocessable Entity.
The C# code is here:
webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();
Byte[] postData = asciiEncoding.GetBytes("email=e2#email.com&password=hunter2");
char[] resultHTML = asciiEncoding.GetChars(webClient.UploadData("http://url", "POST", postData));
string convertedResultHTML = new string(resultHTML);
Any idea what could be causing this?
POST data must be encoded prior to be sent out on the wire as ASCII, if you are sending character not in the ASCII range. You should try something like:
Byte[] postData = asciiEncoding.GetBytes(HttpUtility.UrlEncode("email=e2#email.com&password=hunter2"));
Because of its limited functionality, I avoid using WebClient and use WebRequest instead. The code below:
does not expect an HTTP 100 status code to be returned,
creates a CookieContainer to store any cookies we pick up,
sets the Content Length header, and
UrlEncodes each value in the post data.
Give the following a try and see if it works for you.
System.Net.ServicePointManager.Expect100Continue = false;
System.Net.CookieContainer cookies = new System.Net.CookieContainer();
// this first request just ensures we have a session cookie, if one exists
System.Net.WebRequest req = System.Net.WebRequest.Create("http://localhost/test.aspx");
((System.Net.HttpWebRequest)req).CookieContainer = cookies;
req.GetResponse().Close();
// this request submits the data to the server
req = System.Net.WebRequest.Create("http://localhost/test.aspx");
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
((System.Net.HttpWebRequest)req).CookieContainer = cookies;
string parms = string.Format("email={0}&password={1}",
System.Web.HttpUtility.UrlEncode("e2#email.com"),
System.Web.HttpUtility.UrlEncode("hunter2"));
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(parms);
req.ContentLength = bytes.Length;
// perform the POST
using (System.IO.Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
// read the response
string response;
using (System.Net.WebResponse resp = req.GetResponse())
{
if (resp == null) return;
using (System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()))
{
response = sr.ReadToEnd().Trim();
}
}
// the variable response holds the results of the request...
Credits: Hanselman, Simon (SO Question)
This is the RoR application telling you that you have not formed a request that it can handle; the destination script exists (otherwise you'd see a 404), the request is being handled (otherwise you'd get a 400 error) and it's been encoded correctly (or you'd get a 415 error) but the actual instruction can't be carried out.
Looking at it, you seem to be loading some email information. The RoR application could be telling you that the username and password is wrong, or that the user doesn't exist, or something else. It's up to the RoR application itself.
I think the code itself is good; it's just that the app at the other end isn't happy about doing what you ask it. Are you missing something else in the request information, like a command? (eg command=getnetemails&email=e2#email.com&password=hunter2) Are you sure the email/password combination you are passing is good?
see here for more on the 422 error.
Add the below line above your code.
System.Net.ServicePointManager.Expect100Continue = false;
Are you trying to access an authentication required page?
it was solved by returning xml instead of just unstructured text on the RoR side

Categories