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
}
Related
I have an MVC WebAPI 2 project with a Controllers controller. The Method I'm trying to call is POST (Create). I need to access the referring URL that called that method yet, no matter what object I access, the referring URL either doesn't exist in the object or is null.
For example, I've added the HTTPContext reference and the following returns null:
var thingythingthing = HttpContext.Current.Request.UrlReferrer;
The Request object does not have a UrlReferrer property.
This returns null as well:
HttpContext.Current.Request.ServerVariables["HTTP_REFERER"]
I cannot modify the headers because I need to be able to generate a link to the method and filter access by origin of the call.
Any particular place I should be look or, alternatively, any particular reason why those are returning null?
Edit: I have a solution for GET methods (HttpContext.Current.Request.RequestContext.HttpContext.Request.UrlReferrer) but not for POST methods.
See this answer. Basically, WebAPI requests use a different kind of request object. You can create an extension method that provides a UrlReferrer for you, though. From the linked answer:
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();
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
I have the following code with which I download a web-page into a byte array and then print it with Response.Write:
WebClient client = new WebClient();
byte[] data = client.DownloadData(requestUri);
/*********** Init response headers ********/
WebHeaderCollection responseHeaders = client.ResponseHeaders;
for (int i = 0; i < responseHeaders.Count; i++)
{
Response.Headers.Add(responseHeaders.GetKey(i), responseHeaders[i]);
}
/***************************************************/
Besides of the response headers, I need to add request headers as well. I try to do it with the following code:
/*********** Init request headers ********/
NameValueCollection requestHeaders = Request.Headers;
foreach (string key in requestHeaders)
{
client.Headers.Add(key, requestHeaders[key]);
}
/***************************************************/
However it does not work and I get the following exception:
This header must be modified using the appropriate property.Parameter name: name
Could anybody help me with this? What's the correct way of adding request headers with WebClient?
Thank you.
The headers collection "protects" some of the possible headers as described on the msdn page here: http://msdn.microsoft.com/en-us/library/system.net.webclient.headers.aspx
That page seems to give all the answer you need but to quote the important part:
Some common headers are considered restricted and are protected by the
system and cannot be set or changed in a WebHeaderCollection object.
Any attempt to set one of these restricted headers in the
WebHeaderCollection object associated with a WebClient object will
throw an exception later when attempting to send the WebClient
request.
Restricted headers protected by the system include, but are not
limited to the following:
Date
Host
In addition, some other headers are also restricted when using a
WebClient object. These restricted headers include, but are not
limited to the following:
Accept
Connection
Content-Length
Expect (when the value is set to "100-continue"
If-Modified-Since
Range
Transfer-Encoding
The HttpWebRequest class has properties for setting some of the above
headers. If it is important for an application to set these headers,
then the HttpWebRequest class should be used instead of the WebRequest
class.
I suspect the reason for this is that many of the headers such as Date and host must be set differently on a different request. You should not be copying them. Indeed I would personally probably suggest that you should not be copying any of them. Put in your own user agent - If the page you are getting relies on a certain value then I'd think you want to make sure you always send a valid value rather than relying on the original user to give you that information.
Essentially work out what you need to do rather than finding something that works and doing that without fully understanding what you are doing.
Looks like you're trying to set some header which is must be set using one of the WebClient properties (CachePolicy, ContentLength or ContentType)
Moreover, it's not very good to blindly copy all the headers, you need to get just those you really need.
I am trying to read the HTML of a page that contains a non-delayed redirect. The following snippet (C#) will give me the destination/redirected page, not the initial one I need to see:
using System.Net;
using System.Text;
public class SomeClass {
public static void Main() {
byte[] data = new WebClient().DownloadData("http://SomeUrl.com");
System.Console.WriteLine(Encoding.ASCII.GetString(data));
}
}
Is there a way to get the HTML of a redirecting page? (I prefer .NET but a snippet in Java or Python would be fine too. Thx!)
Unless the redirect is done on the client side you can't. If the redirect is done server side, then no html is actually generated to the client, but the header is redirected at the new server.
It would take more work, but rather than using WebClient, use HttpWebRequest and set the AllowAutoRedirect property to False. A redirect will then throw an exception, but you can get any response text (and some pages do have response text along with the redirect) from the exception's response object. After you get the response from the exception, you can issue another HttpWebRequest for the redirect URL (specified in the Location response header).
You might be able to do something similar with WebRequest if you create a derived object, MyWebRequest, where you overload the GetWebRequest method and set the AllowAutoRedirect property. I don't know what kind of exception, if any, the DownloadData method will return if you do something like that.
As somebody said previously, this will only work for those pages that do client-side redirects (typically 301 or 302). If there is server-side redirection going on, you'd never know it.
Simplest answer would be to add the current page onto the QueryString component of the redirect when redirecting, for instance:
Response.Redirect(newPage + "?FromPage=" + Request.Url);
Then the new page could see where you cane from by simply looking at Request.QueryString("FromPage").
If you want to get the source of an html page you can use this tool:
http://www.selfseo.com/html_source_view.php
Whats the difference between these two properties?
To put into context, I am determining if a redirect occurs if our ResponseUri != RequestUri.
While a redirect occurs regardless the url http://adage.com/adages/article?article_id=140560 will provide a different ResponseUri (http://adage.com/adages/post.php) than the Address (http://adage.com/adages/post?article_id=140560).
It appears the ResponseUri takes the Content-Location header and uses it while the Address maintains the correct location.
Would it be correct to compare the RequestUri to the HttpWebRequest.Address to check for redirects?
Yes, comparing request.RequestUri and request.Address is the way to go. At least in Mono response.ResponseUri is the same as request.Address.
I know this is an old question, but I found it while researching this topic and noticed it wasn't actually answered correctly.
While HttpWebRequest.Address and HttpWebResponse.ResponseUri should always be the same, here is the difference:
HttpWebResponse.Address will return the Uri of the page actually responding
HttpWebResponse.ResponseUri will return the value of the Content-Location header (if present). While the documentation doesn't explicitly state what happens if the Content-Location header is not present, it is assumed it will use the same value as Address.
Remember HTTP headers can be forged, so Microsoft recommends using Address instead of ResponseUri for security reasons.
http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.responseuri.aspx
Have you thought about setting request.AllowAutoRedirect=false and then reissuing the request on a redirect?
The Uri comparison should also work fine, although I am not sure of all the edge cases