ASP.NET MVC, Url Routing: Maximum Path (URL) Length
Asked Answered
D

7

72

The Scenario

I have an application where we took the good old query string URL structure:

?x=1&y=2&z=3&a=4&b=5&c=6

and changed it into a path structure:

/x/1/y/2/z/3/a/4/b/5/c/6

We're using ASP.NET MVC and (naturally) ASP.NET routing.

The Problem

The problem is that our parameters are dynamic, and there is (theoretically) no limit to the amount of parameters that we need to accommodate for.

This is all fine until we got hit by the following train:

HTTP Error 400.0 - Bad Request ASP.NET detected invalid characters in the URL.

IIS would throw this error when our URL got past a certain length.

The Nitty Gritty

Here's what we found out:

This is not an IIS problem

IIS does have a max path length limit, but the above error is not this.

Learn dot iis dot net How to Use Request Filtering Section "Filter Based on Request Limits"

If the path was too long for IIS, it would throw a 404.14, not a 400.0.

Besides, the IIS max path (and query) length are configurable:

<requestLimits


   maxAllowedContentLength="30000000"


   maxUrl="260"


   maxQueryString="25" 


              />

This is an ASP.NET Problem

After some poking around:

IIS Forums Thread: ASP.NET 2.0 maximum URL length? http://forums.iis.net/t/1105360.aspx

it turns out that this is an ASP.NET (well, .NET really) problem.

The heart of the matter is that, as far as I can tell, ASP.NET cannot handle paths longer than 260 characters.

The nail in the coffin in that this is confirmed by Phil the Haack himself:

Stack Overflow ASP.NET url MAX_PATH limit Question ID 265251

The Question

So what's the question?

The question is, how big of a limitation is this?

For my app, it's a deal killer. For most apps, it's probably a non-issue.

What about disclosure? No where where ASP.NET Routing is mentioned have I ever heard a peep about this limitation. The fact that ASP.NET MVC uses ASP.NET routing makes the impact of this even bigger.

What do you think?

Daiquiri answered 26/7, 2009 at 22:29 Comment(0)
A
47

I ended up using the following in the web.config to solve this problem using Mvc2 and .Net Framework 4.0

<httpRuntime maxUrlLength="1000" relaxedUrlToFileSystemMapping="true" />
Airing answered 7/4, 2011 at 18:23 Comment(6)
Max Url Length can be 2097151.Tegantegmen
nogo for 260 segment limit, also changed support.microsoft.com/en-us/kb/820129 UrlSegmentMaxCount also nogoLeninism
Yeah relaxedUrlToFileSystemMapping is the only way to goRich
I did not need the relaxedUrlToFileSystemMapping to correct the HTTP 400 errors on long URLs; just setting the maxUrlLength did the trick.Kluge
The .NET MAXPATH limitation has now been solved in 4.6.2 (blogs.msdn.microsoft.com/dotnet/2016/08/02/…)Trisaccharide
Thanks a lot , this is the only solution that worked with me.I got 404 error page but it was fixed when i set relaxedUrlToFileSystemMapping="true"Trillby
S
35

Http.sys service is coded with default maximum of 260 characters per Url segment.

An "Url segment" in this context is the content between "/" characters in the Url. For example:

http://www.example.com/segment-one/segment-two/segment-three

The max allowed Url segment length can be changed with registry settings:

  • Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters
  • Value: UrlSegmentMaxLength
  • Type: REG_DWORD
  • Data: (Your desired new Url segment maximum allowed length, e.g. 4096)

More about http.sys settings: http://support.microsoft.com/kb/820129

The maximum allowed value is 32766. If a larger value is specified, it will be ignored. (Credit: Juan Mendes)

Restarting the PC is required to make a change to this setting take effect. (Credit: David Rettenbacher, Juan Mendes)

Strasbourg answered 19/10, 2011 at 7:12 Comment(7)
This fixed it for me as well. We had one really long url segment (note: not total url length) which was causing the problem. I suppose in this case it's worth wondering if you're doing it right when a single url segment is more than 260 chars!Deposition
Worth to note that a restart is required for this setting to take effect.Ragamuffin
machine restart or just IIS?Kolva
I had to restart the whole machine. Warning: I initially set this value too high (2097151) and it didn't stick. It finally worked when I looked at the document linked to in the answer and saw that the max value is 32766Correll
I dont see this settings in my registry on Win Server 08. I assume this needs to be added. Please clarify whether it needs to be added as a key or as a dword / etc. Thanks.Theca
@Theca This fixed the 260 char URL segment max issue for me. A machine restart was required (just restarting IIS didn't do it). The registry value should be created if it doesn't exist and should be of type REG_DWORD.Kluge
is there anything similar in the webc.onfig to define the same? I do not want to restart my other applications on the same server while doing this activity.Midas
L
34

To solve this, do this:

In the root web.config for your project, under the system.web node:

<system.web>
    <httpRuntime maxUrlLength="10999" maxQueryStringLength="2097151" />
...

In addition, I had to add this under the system.webServer node or I got a security error for my long query strings:

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxUrl="10999" maxQueryString="2097151" />
      </requestFiltering>
    </security>
...
Linnell answered 19/9, 2013 at 21:45 Comment(3)
it's worked for me, system.webServer node is importent!Rusk
@Leninism it seems related to a check agains file system rules, but setting relaxedUrlToFileSystemMapping to true doesn't help either.Macroscopic
Solved my issue in rest api application to handle very long GET queriesKessinger
D
17

OK so part of the reason I posted this was also because we have found a work around.

I hope this will be useful to someone in the future :D

The workaround

The workaround is quite simple, and it's quite nice too.

Since we know which parts of the site will need to use dynamic parameters (and hence will have a dynamic path and length), we can avoid sending this long url to ASP.NET routing by intercepting it before it even hits ASP.NET

Enter IIS7 Url Rewriting (or any equivalent rewrite module).

We set up a rule like this:

    <rewrite>
        <rules>
            <rule>
                <rule name="Remove Category Request Parameters From Url">
                <match url="^category/(\d+)/{0,1}(.*)$" />
                <action type="Rewrite" url="category/{R:1}" />
            </rule>
        </rules>
    </rewrite>

Basically, what we're doing is just keeping enough of the path to be able to call the correct route downstream. The rest of the URL path we are hacking off.

Where does the rest of the URL go?

Well, when a rewrite rule is fired, the IIS7 URL Rewrite module automagically sets this header in the request:

HTTP_X_ORIGINAL_URL

Downstream, in the part of the app that parses the dynamic path, instead of looking at the path:

HttpContext.Request.Url.PathAndQuery

we look at that header instead:

HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

Problem solved... almost!

The Snags

Accessing the Header

In case you need to know, to access the IIS7 Rewrite Module header, you can do so in two ways:

HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

or

HttpContext.Request.Headers["X-ORIGINAL-URL"]

Fixing Relative Paths

What you will also notice is that, with the above setup, all relative paths break (URLs that were defined with a "~").

This includes URLs defined with the ASP.NET MVC HtmlHelper and UrlHelper methods (like Url.Route("Bla")).

This is where access to the ASP.NET MVC code is awesome.

In the System.Web.Mvc.PathHelper.GenerateClientUrlInternal() method, there is a check being made to see if the same URL Rewrite module header exists (see above):

// we only want to manipulate the path if URL rewriting is active, else we risk breaking the generated URL
NameValueCollection serverVars = httpContext.Request.ServerVariables;
bool urlRewriterIsEnabled = (serverVars != null && serverVars[_urlRewriterServerVar] != null);
if (!urlRewriterIsEnabled) {
    return contentPath;
}

If it does, some work is done to preserve the originating URL.

In our case, since we are not using URL rewriting in the "normal" way, we want to short circuit this process.

We want to pretend like no URL rewriting happened, since we don't want relative paths to be considered in the context of the original URL.

The simplest hack that I could think of was to remove that server variable completely, so ASP.NET MVC would not find it:

protected void Application_BeginRequest()
{
    string iis7UrlRewriteServerVariable = "HTTP_X_ORIGINAL_URL";

    string headerValue = Request.ServerVariables[iis7UrlRewriteServerVariable];

    if (String.IsNullOrEmpty(headerValue) == false)
    {
        Request.ServerVariables.Remove(iis7UrlRewriteServerVariable);

        Context.Items.Add(iis7UrlRewriteServerVariable, headerValue);
    }
}

(Note that, in the above method, I'm removing the header from Request.ServerVariables but still retaining it, stashing it in Context.Items. The reason for this is that I need access to the header value later on in the request pipe.)

Hope this helps!

Daiquiri answered 26/7, 2009 at 22:54 Comment(3)
Please can you set this as the answer?Norling
I set this as the answer as per your request.Daiquiri
If I do this, do I also still need to change the web.config file? I would like to avoid changing the web.config file so that I can allow long requests to one particular URL only, whilst blocking them as normal for all of the rest.Acidulate
R
4

I was having a similar max URL length issue using ASP.NET Web API 4, which generated a slightly different error:

404 Error

The fix for me was described above by updating the Web.config with BOTH of the following tags:

<system.web>
    <httpRuntime maxUrlLength="10999" maxQueryStringLength="2097151" />

and

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxUrl="10999" maxQueryString="2097151" />
      </requestFiltering>
    </security>
Replevin answered 9/8, 2018 at 18:28 Comment(0)
T
1

I think you're trying to hard to use GET. Try changing the request method to POST and put those query string parameters into the request body.

Long URL does not help SEO as well, does it?

Turney answered 26/7, 2009 at 22:36 Comment(1)
I'm using GET for two reasons: 1) These URLs need to be shared, and need to be persistent 2) I'm not POSTing anything. This is a read operation. > Long URL does not help SEO as well, does it? I'm not sure, but if the request is complex, so is the query... no getting around that unless I use non-semantic URLs instead.Daiquiri
C
1

It appears that the hard-coded max URL length has been fixed in .NET 4.0. In particular, there is now a web.config section with:

<httpRuntime maxRequestPathLength="260" maxQueryStringLength="2048" /> 

that let you expand the range of allowed URLs.

Calipash answered 5/4, 2011 at 9:23 Comment(3)
Joannes, thanks for updating this topic. This was scheduled to be fixed in .NET 4, and thankfully it has made it in.Daiquiri
Unfortunately this is not correct. Microsoft changed their mind and changed it to the answer given by lmingle. Namely something like <httpRuntime maxUrlLength="1024" relaxedUrlToFileSystemMapping="true"/>Pikestaff
Dommer, Joannes, thanks for following up on this. I have changed the accepted answer accordingly. I have not been able to verify myself, though.Daiquiri

© 2022 - 2024 — McMap. All rights reserved.