Server side redirect truncating request payloads - c#

I'm on IIS 6 and I have an ASP.Net 4.0 site that's a single page to serve as a SOAP reverse proxy. I have to modify the return content in order to delete a trouble node from the response and add a tracking node.
In order to facilitate its function as a reverse proxy for all addresses, I have the 404 on the server set to a custom "URL" of "/default.aspx" (the page for my app)
For requests without a payload, it works perfectly - such as for ?WSDL Urls. It requests the proper URL from the target system, gets the response and sends it back - it's pretty utterly transparent in this regard.
However, when a SOAP request is being made with an input payload, the Request.InputStream in the code is always empty. Empty - with one exception - using SOAPUI, I can override the end point and send the request directly to /default.aspx and it will receive the input payload. Thus, I have determined that the custom 404 handler is - when server-side transferring the request - stripping the payload. I know the payload is being sent - I have even wiresharked it on the server to be sure. But then when I add code to log the contents of Request.InputStream it's blank - even though Request.ContentLength shows the right content length for the original request.
I've also been looking for a good way to use ASP.Net to intercept the requests directly rather than allowing the normal IIS 404 handler to take care of it but even with a wildcard mapping, I can't seem to get the settings right nor am I fully confident that it would help. (But I'm hoping it would?)
Finally, I don't have corporate permission to install MVC framework.
Thus, I need either some configuration for IIS I am missing to make this work properly or some other method of ensuring that I get the request payload to my web page.
Thanks!

What about using an HTTP Handler mapped to all requests?
You'll need to add a wildcard application mapping as detailed here and correctly configure your HTTP Handler.

Related

Change/prevent WCF redirection

Running an old (we hope to phase it out soon(tm)) WCF Rest API. We got an endpoint like GET .../MyService.svc/. When WCF receives a request to GET .../MyService.svc (without slash) it will automatically redirect to the resource with a slash (through an HTTP 307).
Is there any way to change this behavior to either throw an error, or, ideally, having the resource listen to either of those endpoints (generically)? Because obviously WCF finds the right resource (otherwise it couldn't redirect), so it would make much more sense to directly execute that call instead of redirecting - especially with a temporary 307.
Cheers!

Servce Fabric Reverse Proxy Integration in ASP.NET Core 404 Response

I'm working on an implementation of ICommunicationClient and accompanying stuff for HTTP protocol communication which should be compatible with SF reverse proxy. The most subtle part for me is retry policy. According to Azure docs for 404 errors reverse proxy relies on X-Service-Fabric header to be returned from web service when deciding if it should retry.
ASP.NET Core provides middleware for integration with a reverse proxy which adds X-Service-Fabric header to every 404 response.
Assume we have the scenario when ServicePartitionClient cached the endpoint for a stateless service listening on port 3001. At some point, this service may be moved to another node. On the first node, the Service Fabric runtime allocates a different service with its own endpoints but using the same middleware and listening on the same 3001 port.
When a client tries to call the original service at its old (cached) address it will receive 404 response containing the X-Service-Fabric header. According to reverse proxy policies it shouldn't retry, but for me, it seems like the client will stay connected to the wrong service forever and won't attempt to re-resolve the endpoint.
I can't find any information about this case in the documentation, did I miss something here? Is it safe to rely on this standard middleware and don't do retry attempts on 404 errors with X-Service-Fabric: ResourceNotFound header?
In the described case the communication client will be invalidated by staying connected to the wrong service. It is recommended by Microsoft to use unique URL prefixes for services with dynamically-assigned port to handle those scenarios.
In ASP.NET Core programmers can leverage ServiceFabricMiddleware which checks URL prefixes and returns 410 Gone if they don't match. Then HTTP implementation of ICommunicationClient can retry with re-resolving endpoint only for 410 responses and don't perform any retries on 404 response with X-Service-Fabric: ResourceNotFound header if reverse proxy integration is enabled.
In your given scenario, when your Client encounters a 404, the X-Service-Fabric:ResourceNotFound header isn't the only attribute your code could examine when deciding whether or not to retry some operation.
To simplistically address your concern that your client won't be able to tell the difference between a "friendly" node and a "newly arrived" node, and since you're already working with http headers, you could add a custom HTTP header to outgoing responses to identify that a request comes from your application.
When the client receives a 404, you can simply check for the presence of your custom header to answer the question of whether or not it's a "legit" retry. Of course, adding a custom HTTP header just for the sake of this validation check may be more of a global solution to a local problem. Ed: goes without saying that this should not be used to make security decisions by the application
A more elegant and complex means of accomplishing the same would be to deduce the same result using a different combination of HTTP headers and response attributes (e.g., see if some other headers are expected/unexpected), but this could also be a hyper-local solution to the problem.

Remove custom http header from future requests in .net web api

I've added a custom header X-XSRF-TOKEN and when a user logs out I want to be able to remove that header from future requests sent by the browser.
In the logout web api action I can modify the header like so:
Request.GetOwinContext().Response.Headers.Append("X-XSRF-TOKEN", "ModifiedToken");
On future requests it now sends requests with the X-XSRF-TOKEN with the value ModifiedToken. Is there a way I can remove it instead. With cookies you can expire them.
If I call the remove function on the Request or Response headers, on the next request to the server the header is still present:
Request.GetOwinContext().Response.Headers.Remove("X-XSRF-TOKEN");
or
Request.GetOwinContext().Request.Headers.Remove("X-XSRF-TOKEN");
Is it even possible to do this or even guarantee the browser will actually stop sending the header?
Try This.
Request.GetOwinContext().Response.Headers.Append("NULL", "ModifiedToken");
Note - I am not sure it will work or not. But you can try this one as well.

Handling 100-continue when redirecting a POST request from a Web API controller

I have an ApiController which responds to a POST request by redirecting it via HTTP's status code 307. It does so using only information from the header, so the body of the request is not needed by this action. This action is equivalent to:
public HttpResponseMessage Post() {
var url;
// Some logic to construct the URL
var response = new HttpResponseMessage(HttpStatusCode.TemporaryRedirect);
response.Headers.Location = new System.Uri(url);
return response;
}
This is straightforward enough, but there is one improvement I would like to make. The request body could potentially contain a large amount of data, so I would like to leverage the HTTP status code 100 to make this request more efficient. With the controller as it is now, a conversation might look like this:
> POST /api/test HTTP/1.1
> Expect: 100-continue
> ...
< HTTP/1.1 100 Continue
> (request body is sent)
< HTTP/1.1 307 Temporary Redirect
< Location: (the URL)
< ...
Since the request body is not needed by the redirection action, I would like to be able to shorten the conversation to:
> POST /api/controller HTTP/1.1
> Expect: 100-continue
> ...
< HTTP/1.1 307 Temporary Redirect
< Location: (the URL)
< ...
I have spent the better part of a day researching how to accomplish this, and I have not been able to come up with a solution. In my research, I have learned:
When the ApiController's action executes, the 100 Continue has already been sent.
When the ApiController is constructed, the 100 Continue has already been sent.
When the HttpApplication's PreRequestHandlerExecute event is triggered, the 100 Continue response has not been sent.
When a DelegatingHandler executes, the 100 Continue has already been sent.
Based on this, the best solution I have come up with so far is to create an HttpModule which uses the RouteData on the RequestContext to override the response when the ApiController in question is the recipient of the request. This is far from an ideal solution, however, for several reasons (code separation, not taking advantage of Web API's parameter binding, and bypassing additional logic in an AuthorizeAttribute on the ApiController).
It seems as if there must be a better solution to this, but I have found very little information on how to properly handle the Expect: 100-continue header in a Web API application. What would be the simplest way to implement this ApiController to properly handle the Expect: 100-continue header?
...Are you sure that you need this optimization?
If you're using IIS 6, you're looking at kicking down into IIS 5 Compatibility Mode and writing a ReadRawData/SendRawData ISAPI Filter. An ISAPI Extension is out of the question for reasons given further down in my response. (If you're using IIS 5 or below, may God have mercy on your soul)
If you're using IIS 7+, you might be able to get away with writing an IIS Native Module.
You are correct in your thinking that by the time the controller becomes involved, the response has already been sent because Web API lives inside ASP.NET; this response is being handled by the IIS Core.
Some light reading material
HTTP.SYS IIS and the 100 Continue
David Wang
A "100 continue", like a "400 Bad Request" or a Kernel Response Cache Hit, is special in that HTTP.SYS transparently handles it in kernel mode without notifying user mode of anything.In addition, ISAPI Extensions cannot interact with any response output - they can only generate response output, not see results of response output. Thus, an ISAPI Extension will never be able to interact with requests that generate "100 continue" nor "100 continue" responses themselves to suppress them.
On IIS6, the only way to inject user mode processing into these
transparent request handlings of HTTP.SYS is to run in IIS5
Compatibility Mode and use an ReadRawData/SendRawData ISAPI Filter.
ReadRawData forces HTTP.SYS to hand the raw data off the network into
user mode for filtering PRIOR to parsing that user mode output into
HTTP requests to place into queues.
Of course, this method completely defeats the purpose of running IIS6
with Application Pools and process isolation (a single failure in this
filtering user mode process halts the entire server)... but such is
the server-side compromise when the client is buggy...
FYI: This approach will not work on Vista Server/IIS7. HTTP.SYS will
no longer hand raw data off the network into user mode for filtering
prior to parsing, so it will be impossible for user mode code to know
that a request which triggers the automatic "100 continue" happened.
Edit
Haacked Http Web Request Expect 100 Continue
I assume that you are redirecting the browser to another controller in the same solution. Instead of the redirect, you could process the request directly in the original url-address. This way the client would need to send the request only once without being redirected at all.
One way to implement this would be to write your own IHttpControllerSelector which would assign the request to the correct controller based on the request headers.
You might want to check the following SO-question if you want to assign the custom selector to some specific route only:
ASP.NET Web API custom IHttpControllerSelector for a single route

Proxy server cache is dangerous for private data?

Suppose I have a asp.net mvc 3 application with an interface named /getdata, different users connect to the server by my PC client software and get private data using this interface. Different users are identified by their own well-encrypted tokens.
Now the problem is ClientA told us he got another user's data. From the log of ClientA we found he got ClientB's (but they don't know each other, they can't share accounts). I looked through the code of my web application but couldn't find any chance to mix their data.
So I wonder can this happen:
(1) ClientB starts a http request to http://mysite.com/getdata, with his token in the http header, via a web proxy.
(2) The web proxy accesses my web server, get ClientB's data.
(3) My web server approves the request and returns ClientB's data, since everything is correct.
(4) ClientB gets his data and correctly displayed
(5) Almost the same time after ClientB get his data, ClientA starts a same request, with ClientA's token in the header.
(6) The web proxy find the url that ClientA requesting is the same as ClientB's, and the result is still in cache, then returns ClientB's data. Then ClientA gets another's data.
In my web app interface, at the very beginning I already set all the response no-cache, max-age=0 and so on to prevent client-side cache. My question is:
Can the scanario in the image happen?
If yes, how can I prevent the web proxy returning cached data? I can't modify the program of the PC client, and web proxy servers are out of my control.
If no, what's the possible reason that A is getting B's data?
Can the scanario in the image happen?
Yes, this is possible if the clients are using the GET verb to access the /getdata endpoint.
If yes, how can I prevent the web proxy returning cached data? I can't modify the program of the PC client, and web proxy servers are out of my control.
Decorate the controller action that is serving the GetData endpoint with a [NoCache] attribute to ensure that no data gets cached downstream.

Categories

Resources