Get HttpRequest full request string - c#

I'm working on a proxy that will relay connections to another server. I had implemented a IHttpHandler that takes requests for a specific address and sends them to my proxy.
My proxy basically starts a sockect connection to the proxied server and reads the original request:
var requestString = new StreamReader(httpRequest.InputStream).ReadToEnd();
My problem arises at this point: the input stream only contains the stream of the body of the HTTP request, not the complete request.
How can I retrieve the full HTTP Request without having to reconstruct it from the HttpRequest object?

I don't know of a definitive one-liner in ASP .NET, but you can get pretty close, as shown in this forum post. What is suggested there is to build the first line out of HttpRequest properties, then add ServerVariables["ALL_RAW"], then the request body in the InputStream as you're already doing.

The only way to get the 'full HTTP Request' object is to actually reconstruct it in some way. I'm not sure you need the whole object for this process though. Perhaps you could just grab a subset of the items in HttpRequest for processing? You could manually concatenate the various portions of the object you need into something new. Once you deviate from using HttpRequest though, it's all custom to me.

Related

what's HttpContext.Response.HasStarted for?

For example, ExceptionHandlerMiddleware Middleware code on Github
uses this as:
if (context.Response.HasStarted ||...)
I don't quite get it, how can the web server starts to send response to clients when the request still in the pipeline assuming the ExceptionHandlerMiddleware is the first middleware in the pipeline? Because the request hasn't got out of ExceptionHandlerMiddleware, so it hasn't arrived to the web server, then how could it be that the web server already starts to send responses to client in this scenario?
Any middleware or handler may choose to call WriteAsync (or other similar methods) on the HttpResponse, possibly multiple times.
It's not necessarily possible for all of those writes to just be stored in local buffers, and indeed may not be desirable to just buffer locally. So, sooner or later, those Write calls are going to result in real data being sent over the network.
And, in this concrete example, a handler may have made multiple calls such as the above before it encounters an error condition that causes control to be returned to the ExceptionHandlerMiddleware.
Your specific ExceptionHandlerMiddleware example uses Microsoft.AspNetCore.Http.HttpResponse.HasStarted:
Gets a value indicating whether response headers have been sent to the client.
https://learn.microsoft.com/en-US/dotnet/api/microsoft.aspnetcore.http.httpresponse.hasstarted?view=aspnetcore-5.0
There is also Microsoft.Net.Http.Server.Response.HasStarted:
Indicates if the response status, reason, and headers are prepared to send and can no longer be modified. This is caused by the first write or flush to the response body.
https://learn.microsoft.com/en-US/dotnet/api/microsoft.net.http.server.response.hasstarted?view=aspnetcore-1.1
Each response consis of two parts: Header and Body
These two being sent together to the client, first the headers than the body. So during development, the only opportunity to set any value on the response object that affects the headers is up to the point at which you start sending the body.
As long as you begin sending the body of the response you can no longer change the headers because they are sent as the first part of the response just before the body begins sending.

Rest Sharp - 406 Error - No match for accept header

I'm getting a 406 error when trying to use RestSharp to post a request to a third-party application. I'm new to REST, so I have to admit I didn't even know you could add headers. I tried adding these, but I'm still getting the same issue:
var client = new RestClient(myURL);
RestRequest request = new RestRequest("restAction", Method.POST);
request.AddHeader("Accept", "text/plain");
request.AddHeader("Content-Type", "text/plain");
request.AddParameter("parameter1", param1);
request.AddParameter("parameter2", param2);
var response = client.Execute(request);
From what I've read, this may be dealing with a header named "accept". Is that right?
Any idea what could be going on?
In general in HTTP, when a client makes a request to a server, it tells the server what kinds of formats it's prepared to understand (accept). This list of acceptable formats is what the Accept header is for. If the server can't respond using any of the media types in the Accept header, it will return a 406. Otherwise, it will indicate which media type it chose in the Content-Type header of the response. Putting "*/*" in the Accept header tells the server that the client can handle any response media type.
In my original comment to your question, I said that RestSharp looks like it's including "*" in the Accept header by default, but looking closer I see now that it's actually not. So, if you don't override the Accept header like you've done here, the default header value is "application/json","application/xml","text/json","text/x-json","text/javascript","text/xml", and it appears the server you're talking to doesn't speak any of these media types.
If the server you're working with doesn't speak json or xml, I don't think you can use RestSharp, unless you create your own deserializer. I'm not sure if you can do this from the public API or if you'd have to modify the source yourself and recompile it for you own needs.
Since you're still getting HTTP errors from the server, I would recommend taking RestSharp out of the equation for right now, and just speaking HTTP directly to the server until you actually get a correct response from the server. You can use a tool like Fiddler to make a HTTP requests directly. When you send the request (for now in the debugging stage), send an Accept header of "*/*" to get around the 406. Once you've figured out what media types the server can send back to you, you should change this back to being a media type you know you can read and you know the server can send.
It sounds like the main issue here is really just not knowing the protocol of the server. If there's any documentation on the service you're talking to, I would read that very carefully to figure out what media types it's prepared to respond with and how to craft the URLs that it expects.

HttpRequest vs HttpWebRequest

I have a web page that intercepts POST requests, pulls the username out of the request, and is supposed to forward the request on depending on the username. Now, I notice that the incoming HttpRequest has a Params property, and HttpWebRequest does not. Why is this? Is there a way I can capture the Params data in my outgoing HttpWebRequest?
Thanks.
They're simply two different .Net classes in two different packages:
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest%28v=vs.71%29.aspx
System.Object
System.MarshalByRefObject
System.Net.WebRequest
System.Net.HttpWebRequest
http://msdn.microsoft.com/en-us/library/system.web.httprequest.aspx
System.Object
System.Web.HttpRequest
HttpWebRequest is an old .Net 1.1 thing - I would definitely use Web.HttpRequest if you're planning on refactoring any code (or writing any new code!)
IMHO...
For starters, they're completely different classes, in different namespaces. That being said,
Params is a wrapper that exposes both querystring parameters as well as POST data. When you are construcing a request you can't write to params, you have to specify what kind of data you are actually adding. So you should add it to the target url as a querystring or you can add it to the body of the request and make it a POST.

Easy alternative to HttpWebRequest for POST requests?

I need to trigger an action on a remote server using an http POST request. The server sends a response, either Y or N, to inform me if the action suceeded or not.
I am looking at using HttpWebRequest to do this, but this seems too complex. To use this class you have to set all the headers, such as content type and content length.
Is there a quicker way to send a POST request that doesn't require setting lower level properties such as this?
Try this WebClient
// Create a new WebClient instance.
WebClient myWebClient = new WebClient();
byte[] responseArray = myWebClient.UploadData("YOUR URI","POST","DATA to be Posted");
You can try with WebClient class. It's much more simpler and it's basically a wrapper for HttpWebRequest. It encapsulate all this complex logic you're trying to avoid.
I think the easiest built in class in the framework is WebClient. Scott Hanselman has an example on how to perform gets and posts using it. This SO answer also has a good overview on how to post data.
If you have control over the server you're posting to, you might want to consider making it respond with HTTP status codes instead of some custom method.
the wcf web api project has an http client. It's super easy to use. http://wcf.codeplex.com/

Change the Uri of a instance of HttpWebRequest?

I have an instance of an HttpWebRequest that I'm intercepting in an event.
I would like to edit the url before the request is sent but I can't find a way of doing this.
The property RequestUri is read only.
I've thought of a few ways but can't seem to find a working solution:
-Using reflection to set the value ?
-Creating a new request and then cloning all properties. not sure how to do that.
If you think in terms of the HTTP protocol, each request is stateless / unique. The only way to link one request to another is programmatically through something like Cookies, but to the HTTP protocol itself the request is unique.
I think the HttpWebRequest object was designed with this in mind. Each HttpWebRequest represents one unique call to a URL and you build up the parameters for that call. If you want to do another request to a different URL you would create a new HttpWebRequest and pass it the state information you are using, ie: Cookie container, header information etc.
The long winded answer to this is the object is designed to have a read only url and the only way to handle it is to:
Use a little reflection hack, such as you have already done, if you absolutely need to use the given HttpWebRequest object you have.
Create a new HttpWebRequest (WebRequest.Create()) and copy your state information over to the new request.
You can use RewritePath to do this.
F.e.
HttpContext.Current.RewritePath("newurl.aspx");

Categories

Resources