IIS & Chrome: failed to load resource: net::ERR_INCOMPLETE_CHUNKED_ENCODING - c#

I recently came across a Chrome issue which I think is worth sharing it with you.
I worked on a self written API using an HttpHandler which primary should return json data. But when an error occures I wanted to display an html file. That worked pretty well in IE and FF, but not in Chrome.
Looking to the developer tools revealed this error: net::ERR_INCOMPLETE_CHUNKED_ENCODING
Google said not very much about this issue while it was seen very much. All I got to know was, that it was magically disappearing after some time.
I found out it lays on this lines of code:
result.StoreResult(context);
context.Response.Flush();
context.Response.Close(); //<-- this causes the error
After removing the last line it worked well. I donĀ“t know why only Chrome had/has an issue with that, but it seemed as if I closed the response stream before chrome finished reading it.
I hope it helps those of you coming across the same or a similar issue.
Now my question:
How is the best pratice in closing/flushing the response stream? Are there any rules?

According to ASP.NET sets the transfer encoding as chunked on premature flushing the Response:
ASP.NET transfers the data to the client in chunked encoding (Transfer-Encoding: chunked), if you prematurely flush the Response stream for the Http request and the Content-Length header for the Response is not explicitly set by you.
Solution: You need to explicitly set the Content-Length header for the Response to prevent ASP.NET from chunking the response on flushing.
Here's the C# code that I used for preventing ASP.NET from chunking the response by setting the required header:
protected void writeJsonData (string s) {
HttpContext context=this.Context;
HttpResponse response=context.Response;
context.Response.ContentType = "text/json";
byte[] b = response.ContentEncoding.GetBytes(s);
response.AddHeader("Content-Length", b.Length.ToString());
response.BinaryWrite(b);
try
{
this.Context.Response.Flush();
this.Context.Response.Close();
}
catch (Exception) { }
}

I was running into this error when generating a file and pushing it to the user for download, but only occasionally. When it didn't fail, the file was consistently 2 bytes short. Close() forcibly closes the connection, whether it's finished or not, and in my case it was not. Leaving it out, as suggested in the question, meant the resulting file contained both the generated content as well as the HTML for the entire page.
The solution here was replacing
context.Response.Flush();
context.Response.Close();
with
context.Response.End();
which does the same, but without cutting the transaction short.

In my case, the problem was cache-related and was happening when doing a CORS request.
Forcing the response header Cache-Control to no-cache resolved my issue:
[ using Symfony HttpFoundation component ]
<?php
$response->headers->add(array(
'Cache-Control' => 'no-cache'
));

I was also getting same error. This issue was with web server user permission on cache folder.

On the offchance that someone is landing here as a result of issues with their ASP.net Core project, I was able to resolve by adding the IIS middleware.
This is done by adding UseIISIntegration when instantiating your webhost instance.

Once I had the same problem and the main reason was lying in my controller return type.
If you try to return a C# object just as-is, you will only get net::ERR_INCOMPLETE_CHUNKED_ENCODING so don't forget to serialize your complex objects before sending them out for java script client (or View).
i.e. my controller return type was :
public async Task<List<ComplexModel>> GetComplexModelList(){
return new List<ComplexModel>()
}
Which caused INCOMPLETE_CHUNKED_ENCODING error, so I tried to fix my mistake with something like:
using Newtonsoft.Json;
...
public async Task<string> GetComplexModelList(){
return JsonConvert.SerializeObject(new List<ComplexModel>())
}

Related

Autodesk Forge Error trying to access the API online

I have a problem loading a 3D model on an online server, the error shown is related to accessing the Forge API, locally works smoothly however when mounted on the server or a website is made marks the following error "Failed to load resource: the server responded with a status of 404 (Not Found)", then "onDocumentLoadFailure() - errorCode:7".
As I comment, what I find stranger is that, locally, it works. Attached the segment of the code where it displays the error.
function getAccessToken() {
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", '/api/forge/toke', false); //Address not found
xmlHttp.send(null);
return xmlHttp.responseText;
}
Thank you very much in advance.
Are you sure the code you're running locally and the code you've deployed are really the same?
The getAccessToken function doesn't seem to be correct, for several reasons:
First of all, there seems to be a typo in the URL - shouldn't it be /api/forge/token instead of /api/forge/toke?
More importantly, the HTTP request is asynchronous, meaning that it cannot return the response immediately after calling xmlHttp.send(). You can find more details about the usage of XMLHttpRequest in https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest.
And finally, assuming that the function is passed to Autodesk.Viewing.Initializer options, it should return the token using a callback parameter passed to it (as shown in https://forge.autodesk.com/en/docs/viewer/v7/developers_guide/viewer_basics/initialization/#example).
With that, your getAccessToken should probably look more like this (using the more modern fetch and async/await):
async function getAccessToken(callback) {
const resp = await fetch('/api/forge/token');
const json = await resp.json();
callback(json.access_token, json.expires_in);
}
I've already found the issue. When I make the deploy I have to change the url where the request is made for the public or the name of the domain. For example: mywebsite.com/aplication-name/api/forge/token.

Problems with ApiController in Blazor App

So I'm wracking my brain here. I have a Blazor Server App that I've created, and to it I've added a few ApiControllers. I am getting what seems to me to be strange errors, only with the production environment. For some reason the Request.Body is being disposed before I ever get to read it. I've tried reading with a StreamReader, copying into a new MemoryStream, what's weird is, it will work for maybe a dozen requests, then stops working and starts throwing either "Reading not allowed after stream is completed" or "IFeatureCollection has been disposed" errors. I can get it to work flawlessly in debug mode with IIS Express in VS. But it will not work consistently on IIS server. Oddly enough, it WILL work consistently when calls are sent with Postman. Just really odd. So basically what I have as an example is, an ApiController, ProfileController, and it just has 1 POST method
[HttpPost]
public async void Post()
{
String bodyContent = String.Empty;
using(StreamReader rdr = new StreamReader(Request.Body))
{
bodyContent = await rdr.ReadToEndAsync();
}
// use body content xml, generate response xml
String responseXML = "ResponseText";
Response.ContentType = "application/xml";
Response.WriteAsync(responseXML);
}
So I get errors some times when reading the request stream above, sometimes that works then I get an error that the Response has been disposed when I try to set ContentType
Is there something about Blazor that is consuming the Request/Response streams ahead of the API routing? This just really baffles me.
// public async void Post()
public async Task Post()
async void methods are not awaitable, the aspnet framework has no way of knowing that your action is still running and returns the response immediately.
what seems to me to be strange errors
Yes, it can accidentally succeed. Threading and asynchrony errors can be very undeterministic.

How can i edit a HTTP a request C# using fiddlercore

What I want to be able to do: Edit HTTP Requests before they are sent off to the server
User navigates to a webpage of their choice in their browser > They encounter a request they wish to edit > they edit the request and then that gets sent to the server instead of the original one.
What I have done so far: I have captured the request, now I need help finding the code to edit it. Here is my code for capturing the request so far:
Fiddler.FiddlerApplication.BeforeRequest += sess =>
{
//Code to detect user specified URL here
}
Is it possible for me to edit the request before it is actually sent? If it can be done using the FiddlerCore API only then I'd be grateful, although I am willing to download more binaries if required.
Additional notes: I have tried streamwriters, binary writers, copy the respose into a memory stream edit it then copy it back, none of those methods work for me. Also when I try some methods my app just hangs and doesn't respond to things like pressing the X.
Maybe I'm just bad at explaining what I'm trying to achieve seems the only good answer I have has been about reponses :/
If the request reads the string "hello world" then I'd like the user to be able to change the REQUEST to say "hello there"
Such a noobish mistake I made, I thought that RequestBody was read only! Turns out I could have simply edited the response like this:
session.RequestBody = myBytes;
Really annoyed at myself for this!
In the demo app, adding the delegate is shown as:
Fiddler.FiddlerApplication.BeforeResponse += delegate(Fiddler.Session oS) {
// Console.WriteLine("{0}:HTTP {1} for {2}", oS.id, oS.responseCode, oS.fullUrl);
// Uncomment the following two statements to decompress/unchunk the
// HTTP response and subsequently modify any HTTP responses to replace
// instances of the word "Microsoft" with "Bayden". You MUST also
// set bBufferResponse = true inside the beforeREQUEST method above.
//
//oS.utilDecodeResponse(); oS.utilReplaceInResponse("Microsoft", "Bayden");
};

HttpWebRequest vs Webclient (Special scenario)

I know this question has been answered before in this thread, but I couldn't seem to find the details.
In my scenario, I am building a console application which will keep an eye on html page source for any changes. If any update/change occurs, I will perform further operations. Moreover, I'll also perform a request after every 1 second, or as soon as the previous request finishes.
I can't seem to figure out should I use HttpWebRequest or WebClient for downloading the html page source and perform comparison? What do you think would be an ideal solution in my case? Speed and reliability both :)
I'd go with HttpWebRequst because it's not as abstracted and lets you fiddle with HTTP params quite a bit. It gives you the option to not download the entire page if the server returns "file not changed", for example.
If you add some parameters to your request like IfModifiedSince (it might be HEAD or GET request) the server may return the response code 304 - NOT MODIFIED. Refer to description of caching in HTTP for further explanation.
The point is to make sure that you only download the full page when it's actually modified since the last time you fetched it. Most of the time it won't be changed (I suppose, can't know for sure without knowing your domain), so you only need to get a lightweight response from server which simply states "nothing changed here".
Update: code sample demonstrating the use of IfModifiedSince property:
bool IsResourceModified(string url, DateTime dateTime) {
try {
var request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
request.IfModifiedSince = dateTime;
request.Method = "HEAD";
var response = (HttpWebResponse)request.GetResponse();
return true;
}
catch(WebException ex) {
if(ex.Status != WebExceptionStatus.ProtocolError)
throw;
var response = (HttpWebResponse)ex.Response;
if(response.StatusCode != HttpStatusCode.NotModified)
throw;
return false;
}
}
This method should return true if the page was modifed since the dateTime date and false if it wasn't. GetResponse method will throw a WebException if you make a HEAD-request and the server returns 304 - NOT MODIFIED (which is kinda unfortunate). We have to make sure that it's not some other web connection problem, that's why I check the status of web exception and the HTTP status in response. If anything else caused an exception we just throw it further.
Console.WriteLine(IsResourceModified("http://example.com", new DateTime(2009)));
Console.WriteLine(IsResourceModified("http://example.com", DateTime.Now));
This sample code produces the output:
True
False
Note: make sure to read Jim Mischel's addition to this answer as he gives few good advices on this technique.
I was going to leave this as a comment to #Dyppl's response, but it became too long.
Dyppl's response is generally good advice, and the way that I would approach this problem. However, there are a few things you should keep in mind.
First, there's no reason to do a HEAD request, followed by a GET if the page has been modified. You can do a GET with the IfModifiedSince header set, and the server will either return the entire page or a 304. Doing the HEAD first, followed by the 'GET`, ends up making two requests to the server, which defeats much of the purpose of the conditional request.
Second, you should set the IfModifiedSince property to the LastModified value returned by the previous response (i.e. HttpWebResponse.LastModified) because the server's time might not be synchronized with your computer. Also, I've found that a large percentage of sites, particularly those with generated content (like WordPress blogs) lie. They always return the current date/time in the LastModified header. As a result, there is no benefit to doing the If-Modified-Since check on those sites.
If you know that the site lies and always returns the current date/time, you can keep track of the ContentLength header that's returned from the page when you download it. Then, when you want to check to see if the page has changed, do a HEAD request and check the returned ContentLength header with the saved value. If they match, then it's unlikely that the page has changed. If they don't match, then do a GET request to update your copy of the page and keep the new ContentLength.
This technique does have the disadvantage of requiring two requests if the page has changed. It's also not 100% reliable on all servers. Some will return a different ContentLength for the HEAD request, and some don't return a valid ContentLength at all. That said, I've found it to be effective for a large number of sites.

Capturing raw HTTP POST Data during Exception

I have a WCF Service hosted in IIS/ASP.NET that accepts HTTP Post (not form post) of serialized objects.
If the client sends malformed requests (eg they're not serializing the object correctly) I'd like to log the message sent up.
We're already using ELMAH to capture unhandled exceptions, so simply attaching the post data would be the easiest option.
I can get the current HttpContext during an exception, however this does only contains the HTTP Header information.
My question is this: Is there some way of capturing the original HTTP POST request body? Or, failing that - a better way (without a reverse proxy) of capturing the input that caused the error?
Edit: Just to clarify, running packet-level capturing at all times isn't really suitable. I'm after a solution that I can deploy to Production servers, and which will have clients outside our control or ability to monitor.
Edit #2: A suggestion was made to access the Request.InputStream - this doesn't work if you're trying to read after WCF has read the request off the stream.
A sample piece of code to see how I've tried using this is here.
StringBuilder log = new StringBuilder();
var request = HttpContext.Current.Request;
if (request.InputStream != null)
{
log.AppendLine(string.Format("request.InputStream.Position = \"{0}\"", request.InputStream.Position));
if (request.InputStream.Position != 0)
{
request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
using (StreamReader sr = new StreamReader(request.InputStream))
{
log.AppendLine(string.Format("Original Input: \"{0}\"", sr.ReadToEnd()));
}
}
else
{
log.AppendLine("request.Inputstream = null");
}
log.ToString();
The ouput of log.ToString() is:
request.InputStream.Position = "0"
Original Input: ""
By the time it gets to your service the request is processed and not available to you.
However ... you could attach a message inspector. Message Inspectors allow you to fiddle with the message before it reaches your operation implementations. You could create a buffered copy of the message, and copy it into the OperationContext.Current.
Ugly hack of course, and it will mean memory overhead as now two copies of the message are floating about for every request.
Did you look at the System.Web.Request.InputStream Property? It should have exactly what you want.
How to "rewind" the InputStream Property.
if (Request.InputStream.Position != 0)
{
Request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
Another option you should look into is capturing this information with an HTTPModule on the BeginRequest event. The data should be there at BeginRequest event because I do not believe WCF picks up the request until after PostAuthenticateEvent.
from under ASP.NET (ASP web service under IIS) the following code helps:
if (request.InputStream.Position != 0)
{
request.InputStream.Seek(0, System.IO.SeekOrigin.Begin);
}
WCF maybe different (that is it Disposes InputStream after reading it)
Use fiddler. Free from MS. Works great.

Categories