Please read my blog's comment policy here.
Today’s question is a simple one: “What is the maximum URL length supported by Internet Explorer?”
And the answer, as befitting an IEInternals post, is surprisingly complicated.
The simplistic answer is that WinINET.h defines INTERNET_MAX_URL_LENGTH as 2083 characters, and this limit remains in force in a number of places. However, the true limit can be both longer and shorter than this.
In Internet Explorer 7, the IE team began the process of replacing legacy string-based URL handling code with CURI, a new object that manages URLs and exposes functionality via the IUri interface. This object internally has no formal limit on URL length, allowing URIs up to the effective size limit of COM strings (at least several hundred megabytes in a 32bit process).
However, CURI was not plumbed everywhere throughout Internet Explorer, the network stack, and Windows at large, and the legacy 2083 character limit remained in practical effect until IE8. If a larger URL reached CURI but later needed to flow through a legacy codepath, the URL would either be truncated or the codepath would exit with an error.
In IE8, CURI was used more broadly, and HTTP and HTTPS URLs could exceed the old limit, but only if the traffic was not sent through a proxy server. The code that prepared requests for a proxy was only fixed later in IE9. However, even today there are code paths that will not handle URLs that exceed the legacy limit; for instance, the WinINET cache will not store and retrieve resources that were retrieved from a URL longer than the legacy limit.
Beyond the local limit, the network path itself may effectively enforce a limit; some servers will reject requests whose headers are longer than 4k or 16k, for instance, and because the URL is contained in the header, requests of huge URLs may fail.
Internet Explorer 8 introduced support for DataURIs, a method of encoding a resource directly within a URI using base64 encoding. For performance reasons, IE8 supported DataURIs up to 32kb in length and this longer limit required changes elsewhere. For example, some DOM attributes at the time were limited to 4096 characters, a factor that would have hampered use of DataURIs in the HREF attributes of IMG elements.
In IE9, the 32kb limit for DataURIs was removed, although for security reasons their use remains limited to certain contexts (specifically, scenarios that create a security context, like IFRAMES, are forbidden). You still should avoid using huge DataURIs in most cases, however, as performance of large DataURIs often lags other approaches.
Mailto is one of the most interesting protocols in the browser, as it’s implemented as both an Asynchronous Pluggable Protocol and an Application Protocol. This means that URLMon itself both implements the protocol (to make security decisions about it) and delegates its handling out to the system (to invoke a mail client).
Why does URLMon have an Asynchronous Pluggable Protocol implementation of mailto, instead of just treating it like any other Application Protocol? Because in the 1990s, it wasn’t uncommon to have <FORM ACTION="mailto:firstname.lastname@example.org">. When the web form was submitted, the browser would serialize the data into the body of an email message and submit the form data to the specified email address using the visitor’s email client. This process goes down Internet Explorer’s navigation codepath and uses the URLMon APP workflow.
This use of the mailto syntax is now very uncommon, although it is still supported in Internet Explorer, Firefox, and Chrome. Because it necessarily reveals the sender’s email address, IE will show the following warning:
This arcana is relevant in this post only for one reason: Asynchronous Pluggable Protocols implement the IInternetProtocolInfo interface to allow the browser to query the protocol for information about URLs that utilize this protocol. The browser calls the ParseUrl to ask for a “security URL” that is equivalent to the target URL, and the simplistic mailto protocol implementation simply copies the entire mailto URL to the target buffer. This causes a failure because the GetSecurityId method does not accept Security IDs longer than MAX_SIZE_SECURITY_ID, 512 bytes, and as a consequence the attempt to launch longer mailto URLs will fail. Unfortunately, this failure doesn’t result in a meaningful error message; the browser isn’t robust against failures at this point and thus navigating to such URLs may result in an endlessly-spinning donut, a blank tab, or a “Page cannot be displayed” error.
There are some codepaths that manage to avoid the GetSecurityId problem, but not reliably (e.g. depending on the user’s IE version and Zone configuration) and thus it is recommended that you avoid mailto URLs longer than 512 bytes.
Application Protocols are subject to even weirder limits. On Windows 8.1, for instance, if you directly pass a 4k Application Protocol URL to ShellExecute in native code, the URL is silently truncated at the 2083 character mark.
In Internet Explorer 11, attempting to launch an Application Protocol URL longer than 507 characters fails with an exception:
In Chrome, if you attempt to an Application Protocol URL over 2046 characters, you’ll see the regular Security Prompt, but clicking its “Launch Application” button does nothing.
Beyond the underlying limitations, the User Interface also enforces various limits around URL length. For instance, the browser address bar is capped at 2047 characters. Start > Run is limited to 259 characters (the MAX_PATH limit of 260, which leaves one character for the null-terminator). Internet Explorer versions up to version 11 do not allow you to bookmark URLs longer than 260 characters. The Windows RichEdit v2 control's Automatic Hyperlink behavior (EM_AUTOURLDETECT) truncates the link after around 512 characters; this limit is higher in RichEdit5W controls.
MS06-042 contained a security bug where a MAX_URL_LENGTH string was copied into a MAX_PATH buffer - See www.securityfocus.com/.../threaded.
[EricLaw] Indeed, the risk of string buffer overflows was one of the biggest threats to the CURI plumbing work. While simple buffer overflows are no longer extremely likely (due to the use of safer string handling functions throughout the codebase) more subtle security errors are certainly a risk if a truncation occurs or if an error result is thrown in an unexpected place.