Prevent URL encoding at QueryString.Add() - c#

I am making a Restful api using OData, and for some reasons I want to force the expand filtering inside the middleware.
So if the clients sends in
http://localhost:52973/odata/customers
The Middleware should automatically change it into
http://localhost:52973/odata/customers?$expand=Contact,Address
In order to do this I've made a simple if statement inside my middleware
if (ctx.Request.Path.Value.Contains("customers") && !ctx.Request.QueryString.Value.Contains("?$expand"))
{
string uri = #"?$expand=";
ctx.Request.QueryString = ctx.Request.QueryString.Add(uri, "Contact,Address");
}
Unfortunately, it keeps generating the following: {?%3F%5C$expand%5C%3D=Contact,Address}
I've tried adding backslashes inside the uri string, but that didn't solve it.

I would assume that it is url-encoding ("escaping") the '$' character to make it safer, so I would not approach this problem from that angle. I would modify your consumers of this request to url-decode the request, which may be automatically done. See QueryString.ToUriComponent, and also the QueryString.ToString() method too.

Related

Can you use custom HTTP request methods with http.client?

Is there a way to use HTTP request methods that are not implemented by System.Net.Http.HttpMethod?
I try to update files with a REST interface. The way it is implemented, I GET a list of files and their hashes. Then I check if any of these files have changed on my side and if so, I POST each file to the API, otherwise I skip it.
When I'm done, the endpoint expects an UPDATE request to know that I'm done sending files. But there is no UPDATE method in HttpMethod.
Is there a way to alter REQUEST_METHOD manually in a HttpRequestMessage or do they need to recode the endpoint?
Looking up System.Net.Http.HttpMethod only gives the following options: GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE, PATCH and CONNECT. There is no obvious way to add a custom method.
In the case where you need an HttpMethod that does not exist in the static properties of the class, you can just use the constructor which allows you to pass any string method:
var customHttpMethod = new HttpMethod("UPDATE");

Correct way of manipulating the url coming from App.config

I have a URL ("http://localhost:2477/") on which I do get and post request. I have stored this URL in the app.config file of my project.
In the code, depending on the function, I add the string "getValue?id={0}" or "postValue" to this URL. But I later ran into an issue when I changed the URL to "http://localhost:2477" (no forward slash in the end) in the app.config.
Took me some embarrassing amount of time to figure out this issue, which made me wonder if there is a good way to handle this case.
Irrespective of the case when there is a forward slash or not in the URL, I want my code to change it to a proper URL.
Always use Path.Combine(string, string). This method will conform a valid path and should add the / if needed.
edit
I realized my answer does not work for URL, just for file paths.
What you’re looking for is Uri constructor instead.
Uri baseUri = new Uri("http://www.contoso.com");
Uri myUri = new Uri(baseUri, "catalog/shownew.htm");
Using the Uri class you can modify your URL more elegantly. You can access the Host, Port, Query, etc. with ease. A similar question was asked here.
Try to use the UriBuilder, it's far more flexible as the Uri Constructor.
See https://stackoverflow.com/a/20164328/10574963

How to clean up existing response in webapi?

There is a authentication library that I have to use that helpfully does things like
Response.Redirect(url, false);
inside of it's method calls. I can't change this libraries code and it's fine for MVC style apps but in angular SPA -> WebApi apps this is just awful.
I really need a 401 otherwise I get into trouble with CORS when my angular scripts, using $http, try to call out to the auth server on another domain in response to the 302, that's if it even could as the Response.Redirect also sends down the object moved html and the angle brackets cause an error to be thrown.
Since I have to make the call to the auth library first the Response.Redirect is already in the response pipeline and so I need to clean it up to remove the body content and convert the 302 into a 401. I thought I could just:
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent("data");
}
but this just gets appended to the response and doesn't replace it plus I also need the Location: header which I can't seem to access via WebApi methods.
So instead I've had to do this in my ApiController:
var ctxw = this.Request.Properties["MS_HtpContext"] as HttpContextWrapper;
var ctx = ctxw.ApplicationInstance.Context;
var url = ctx.Response.RedirectLocation;
ctx.Response.ClearContent();
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent(url);
}
But this seems terrible and counter to webapi "feel". Plus I'm tied to the controller in doing this. I can't get the wrapper in a MessageHandler for example.
What I'd like to do is monitor the response for a given route in a message handler or in an AuthorizationFilterAttribute, if its a 302, I want to read it's headers, take what I want, wipe it and replace it with my own "fresh" response as a 401. How can I do this?
You might want to write your own ActionFilter and override its OnActionExecuted method where you can access HttpActionExecutedContext. From there, you can check response code, for example, and overwrite response with whatever you want.
Ref: https://msdn.microsoft.com/en-us/library/system.web.http.filters.actionfilterattribute.onactionexecuted%28v=vs.118%29.aspx#M:System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuted%28System.Web.Http.Filters.HttpActionExecutedContext%29

.NET 4.6 HttpResponse.PushPromise methods to manage http/2 PUSH_PROMISE header

I am a bit confused about PUSH PROMISE http/2 header handling in .NET4.6.
When I look HttpResponse.PushPromise there are two overloads:
One that accepts path to resource public void PushPromise(string path) - am assuming resource is then read and binary sent across to client.
Second public void PushPromise(string path, string method, NameValueCollection headers) that accepts sting method and NameValueCollection headers which I am failing to understand.
Why would I want to pass method (assuming HttpMethod like GET, POST, etc) and collection of headers inside PUSH PROMISE header?
From reading the HTTP/2 spec (Section 8.2), here is what I gather:
Passing the method
PUSH_PROMISE frames are required to be cacheable and safe. You have the option of using GET and HEAD, as those are the only two http methods that are defined as both safe and cacheable.
Passing headers
Since PUSH_PROMISE frames are required to be cacheable, this could be used to add specific Cache-Control directives to the promise. Section 8.2.2 of the spec states that a client has the option to download the promised stream and can refuse it, which I imagine a client would do if it found that it had an up-to-date version of the resource in its cache.
Controlling caching is the most obvious reason I can see for why you might pass headers, but there may be other reasons as well. If you're writing a custom client, you may use certain X-Headers to provide other hints (that aren't related to caching) to the client so it can decide whether or not it wants to accept the promised stream.
You'll want to pass headers for anything that will cause your response to vary (i.e. anything in your Vary response header). The biggest one I've found is compression.
Read those headers from the original client request and include them with your push promise, e.g.:
var headers = new NameValueCollection { { "accept-encoding", this.Request.Headers["accept-encoding"] } };
this.Response.PushPromise("~/Scripts/jquery.js", "GET", headers);`

Getting the HTTP Referrer in ASP.NET

I'm looking for a quick, easy and reliable way of getting the browser's HTTP Referrer in ASP.Net (C#). I know the HTTP Referrer itself is unreliable, but I do want a reliable way of getting the referrer if it is present.
You could use the UrlReferrer property of the current request:
Request.UrlReferrer
This will read the Referer HTTP header from the request which may or may not be supplied by the client (user agent).
Request.Headers["Referer"]
Explanation
The Request.UrlReferrer property will throw a System.UriFormatException if the referer HTTP header is malformed (which can happen since it is not usually under your control).
Therefore, the Request.UrlReferrer property is not 100% reliable - it may contain data that cannot be parsed into a Uri class. To ensure the value is always readable, use Request.Headers["Referer"] instead.
As for using Request.ServerVariables as others here have suggested, per MSDN:
Request.ServerVariables Collection
The ServerVariables collection retrieves the values of predetermined environment variables and request header information.
Request.Headers Property
Gets a collection of HTTP headers.
Request.Headers is a better choice than Request.ServerVariables, since Request.ServerVariables contains all of the environment variables as well as the headers, where Request.Headers is a much shorter list that only contains the headers.
So the most reliable solution is to use the Request.Headers collection to read the value directly. Do heed Microsoft's warnings about HTML encoding the value if you are going to display it on a form, though.
Use the Request.UrlReferrer property.
Underneath the scenes it is just checking the ServerVariables("HTTP_REFERER") property.
Like this: HttpRequest.UrlReferrer Property
Uri myReferrer = Request.UrlReferrer;
string actual = myReferrer.ToString();
I'm using .Net Core 2 mvc,
this one work for me ( to get the previews page) :
HttpContext.Request.Headers["Referer"];
Since Google takes you to this post when searching for C# Web API Referrer here's the deal: Web API uses a different type of Request from normal MVC Request called HttpRequestMessage which does not include UrlReferrer. Since a normal Web API request does not include this information, if you really need it, you must have your clients go out of their way to include it. Although you could make this be part of your API Object, a better way is to use Headers.
First, you can extend HttpRequestMessage to provide a UrlReferrer() method:
public static string UrlReferrer(this HttpRequestMessage request)
{
return request.Headers.Referrer == null ? "unknown" : request.Headers.Referrer.AbsoluteUri;
}
Then your clients need to set the Referrer Header to their API Request:
// Microsoft.AspNet.WebApi.Client
client.DefaultRequestHeaders.Referrer = new Uri(url);
And now the Web API Request includes the referrer data which you can access like this from your Web API:
Request.UrlReferrer();
string referrer = HttpContext.Current.Request.UrlReferrer.ToString();
Sometime you must to give all the link like this
System.Web.HttpContext.Current.Request.UrlReferrer.ToString();
(in option when "Current" not founded)
Using .NET Core or .NET 5 I would recommend this:
httpContext.Request.Headers.TryGetValue("Referer", out var refererHeader)
Belonging to other reply, I have added condition clause for getting null.
string ComingUrl = "";
if (Request.UrlReferrer != null)
{
ComingUrl = System.Web.HttpContext.Current.Request.UrlReferrer.ToString();
}
else
{
ComingUrl = "Direct"; // Your code
}

Categories