RFC 3986
Uniform Resource Identifier (URI): Generic Syntax
RFC 3986: Uniform Resource Identifier (URI): Generic Syntax ๐
Okay bestie, RFC 3986 is the big one for URIs! ๐ฆ It came out in January 2005 as a Standards Track document, and it's STD 66 in the Network Working Group series. The authors are T. Berners-Lee from W3C/MIT, R. Fielding from Day Software, and L. Masinter from Adobe Systems. It's the official Request for Comments number 3986, and it updates RFC 1738 and obsoletes RFC 2732, RFC 2396, and RFC 1808. So basically it's the main character that replaced a whole group of older docs. ๐
Status of This Memo
This document is an Internet standards track protocol for the Internet community, and it's asking everyone for discussion and suggestions to make it better. ๐ If you want the current standardization state and status of this protocol, go check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited, so share away! โจ
Copyright Notice
Copyright (C) The Internet Society (2005). ๐ธ
Abstract
Okay so a Uniform Resource Identifier (URI) is a compact string of characters that identifies an abstract or physical resource. ๐ง This spec defines the generic URI syntax, plus a process for resolving URI references that might be written in relative form. It also gives guidelines and security considerations for using URIs on the Internet, which is so important. The URI syntax is a grammar that's a superset of all valid URIs, so an implementation can parse the common parts of a URI reference without knowing the scheme-specific rules of every single identifier. Iconic. ๐ This spec does not define a generative grammar for URIs, though. That job belongs to the individual specs for each URI scheme. ๐
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1. Overview of URIs . . . . . . . . . . . . . . . . . . . . 4
1.1.1. Generic Syntax . . . . . . . . . . . . . . . . . 6
1.1.2. Examples . . . . . . . . . . . . . . . . . . . . 7
1.1.3. URI, URL, and URN . . . . . . . . . . . . . . . 7
1.2. Design Considerations . . . . . . . . . . . . . . . . . 8
1.2.1. Transcription . . . . . . . . . . . . . . . . . 8
1.2.2. Separating Identification from Interaction . . . 9
1.2.3. Hierarchical Identifiers . . . . . . . . . . . . 10
1.3. Syntax Notation . . . . . . . . . . . . . . . . . . . . 11
2. Characters . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.1. Percent-Encoding . . . . . . . . . . . . . . . . . . . . 12
2.2. Reserved Characters . . . . . . . . . . . . . . . . . . 12
2.3. Unreserved Characters . . . . . . . . . . . . . . . . . 13
2.4. When to Encode or Decode . . . . . . . . . . . . . . . . 14
2.5. Identifying Data . . . . . . . . . . . . . . . . . . . . 14
3. Syntax Components . . . . . . . . . . . . . . . . . . . . . . 16
3.1. Scheme . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.2. Authority . . . . . . . . . . . . . . . . . . . . . . . 17
3.2.1. User Information . . . . . . . . . . . . . . . . 18
3.2.2. Host . . . . . . . . . . . . . . . . . . . . . . 18
3.2.3. Port . . . . . . . . . . . . . . . . . . . . . . 22
3.3. Path . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.4. Query . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.5. Fragment . . . . . . . . . . . . . . . . . . . . . . . . 24
4. Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.1. URI Reference . . . . . . . . . . . . . . . . . . . . . 25
4.2. Relative Reference . . . . . . . . . . . . . . . . . . . 26
4.3. Absolute URI . . . . . . . . . . . . . . . . . . . . . . 27
4.4. Same-Document Reference . . . . . . . . . . . . . . . . 27
4.5. Suffix Reference . . . . . . . . . . . . . . . . . . . . 27
5. Reference Resolution . . . . . . . . . . . . . . . . . . . . . 28
5.1. Establishing a Base URI . . . . . . . . . . . . . . . . 28
5.1.1. Base URI Embedded in Content . . . . . . . . . . 29
5.1.2. Base URI from the Encapsulating Entity . . . . . 29
5.1.3. Base URI from the Retrieval URI . . . . . . . . 30
5.1.4. Default Base URI . . . . . . . . . . . . . . . . 30
5.2. Relative Resolution . . . . . . . . . . . . . . . . . . 30
5.2.1. Pre-parse the Base URI . . . . . . . . . . . . . 31
5.2.2. Transform References . . . . . . . . . . . . . . 31
5.2.3. Merge Paths . . . . . . . . . . . . . . . . . . 32
5.2.4. Remove Dot Segments . . . . . . . . . . . . . . 33
5.3. Component Recomposition . . . . . . . . . . . . . . . . 35
5.4. Reference Resolution Examples . . . . . . . . . . . . . 35
5.4.1. Normal Examples . . . . . . . . . . . . . . . . 36
5.4.2. Abnormal Examples . . . . . . . . . . . . . . . 36
6. Normalization and Comparison . . . . . . . . . . . . . . . . . 38
6.1. Equivalence . . . . . . . . . . . . . . . . . . . . . . 38
6.2. Comparison Ladder . . . . . . . . . . . . . . . . . . . 39
6.2.1. Simple String Comparison . . . . . . . . . . . . 39
6.2.2. Syntax-Based Normalization . . . . . . . . . . . 40
6.2.3. Scheme-Based Normalization . . . . . . . . . . . 41
6.2.4. Protocol-Based Normalization . . . . . . . . . . 42
7. Security Considerations . . . . . . . . . . . . . . . . . . . 43
7.1. Reliability and Consistency . . . . . . . . . . . . . . 43
7.2. Malicious Construction . . . . . . . . . . . . . . . . . 43
7.3. Back-End Transcoding . . . . . . . . . . . . . . . . . . 44
7.4. Rare IP Address Formats . . . . . . . . . . . . . . . . 45
7.5. Sensitive Information . . . . . . . . . . . . . . . . . 45
7.6. Semantic Attacks . . . . . . . . . . . . . . . . . . . . 45
8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 46
9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 46
10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 46
10.1. Normative References . . . . . . . . . . . . . . . . . . 46
10.2. Informative References . . . . . . . . . . . . . . . . . 47
A. Collected ABNF for URI . . . . . . . . . . . . . . . . . . . . 49
B. Parsing a URI Reference with a Regular Expression . . . . . . 50
C. Delimiting a URI in Context . . . . . . . . . . . . . . . . . 51
D. Changes from RFC 2396 . . . . . . . . . . . . . . . . . . . . 53
D.1. Additions . . . . . . . . . . . . . . . . . . . . . . . 53
D.2. Modifications . . . . . . . . . . . . . . . . . . . . . 53
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 60
Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 61
1. Introduction โจ
A Uniform Resource Identifier (URI) gives you a simple and extensible way to identify a resource. ๐ This spec's URI syntax and semantics come from concepts introduced by the World Wide Web global information initiative. Those identifiers have been around since 1990, and they're described in "Universal Resource Identifiers in WWW" [RFC1630]. The syntax is also designed to meet the recommendations in "Functional Recommendations for Internet Resource Locators" [RFC1736] and "Functional Requirements for Uniform Resource Names" [RFC1737]. Very intentional, very cute. ๐
This document obsoletes [RFC2396]. That one merged "Uniform Resource Locators" [RFC1738] and "Relative Uniform Resource Locators" [RFC1808] so there's one generic syntax for all URIs. ๐ฆ It also obsoletes [RFC2732], which introduced syntax for an IPv6 address. This doc leaves out the parts of RFC 1738 that defined the specific syntax of individual URI schemes. Those parts will be updated in separate documents, so keep an eye out! ๐ The process for registering new URI schemes is defined separately by [BCP35]. If you're designing a new scheme, [RFC2718] has advice for you. And all the significant changes from RFC 2396 are listed in Appendix D. ๐
This spec uses the terms "character" and "coded character set" the way [BCP19] defines them. It also uses "character encoding" in place of what [BCP19] calls a "charset". Terminology slay. ๐
1.1. Overview of URIs โจ
okay so URIs have a few vibes that make them special ๐
Uniform ๐ฆ
Uniformity is giving a lot of benefits, bestie. It lets different types of resource identifiers show up in the same context, even when the ways of accessing those resources are totally different. It gives common syntax the same meaning across different kinds of identifiers. It lets new types of identifiers join the party without messing up how the existing ones work. And it means identifiers can be reused in tons of different contexts, so new apps or protocols can borrow a big, established pile of identifiers that already exists ๐
Resource ๐
This spec doesn't limit what counts as a resource ๐ซถ "Resource" is used in a general sense for literally anything a URI can identify. Familiar examples are an electronic document, an image, a source of information with a consistent purpose (e.g., "today's weather report for Los Angeles"), a service (e.g., an HTTP-to-SMS gateway), and a collection of other resources. A resource doesn't have to be reachable over the Internet either ๐ e.g., human beings, corporations, and bound books in a library can all be resources. Abstract concepts count too, like the operators and operands of a math equation, the types of a relationship (e.g., "parent" or "employee"), or numeric values (e.g., zero, one, and infinity) ๐ง
Identifier ๐
An identifier holds the info needed to tell what's being identified apart from everything else in its scope of identification. When we say "identify" and "identifying," we mean that purpose of telling one resource apart from all the others, no matter how that gets done (e.g., by name, address, or context) ๐ฅ These words shouldn't be read as meaning an identifier defines or contains the identity of what it refers to, although that can be true for some identifiers. It also shouldn't be assumed that a system using URIs will access the resource it identifies: in lots of cases, URIs are used to point at resources with no plan to access them at all ๐ And the "one" resource being identified might not be singular (e.g., a resource might be a named set or a mapping that changes over time) ๐ธ
A URI is an identifier made of a sequence of characters that matches the syntax rule named <URI> in Section 3. It lets you identify resources uniformly through a separately defined, extensible set of naming schemes (Section 3.1). How that identification gets done, assigned, or enabled is left to each scheme's specification ๐
This spec puts no limits on what a resource is, why an app might want to refer to one, or what kinds of systems use URIs to identify things ๐ It also doesn't require that a URI keep identifying the same resource over time, even though that's a common goal for all URI schemes ๐ฅน Still, nothing here stops an app from sticking to certain types of resources, or to a subset of URIs with the characteristics it wants โจ
URIs have a global scope and are interpreted consistently no matter the context, though the result of that interpretation may be relative to the end-user's context ๐ For example, http://localhost/ means the same thing to every user of that reference, even though the network interface behind "localhost" can be different for each end-user: interpretation is independent of access. BUT an action taken based on that reference happens in relation to the end-user's context, which means an action meant for a globally unique thing has to use a URI that tells that resource apart from everything else ๐ซ URIs that identify things relative to the end-user's local context should only be used when that context is a defining part of the resource, like when an on-line help manual refers to a file on the end-user's file system (e.g., file:///etc/hosts) ๐
1.1.1. Generic Syntax ๐งฉ
Each URI starts with a scheme name, as defined in Section 3.1, that points to a specification for assigning identifiers within that scheme. So the URI syntax is a federated and extensible naming system, where each scheme's specification can further restrict the syntax and semantics of identifiers using that scheme ๐
This spec defines the parts of URI syntax that every URI scheme needs or that many schemes have in common. That gives you the syntax and semantics needed for a scheme-independent parsing mechanism for URI references, so the scheme-specific handling of a URI can wait until the scheme-specific semantics are actually needed ๐ Protocols and data formats that use URI references can point to this spec as the definition of the allowed syntax for all URIs, including schemes that haven't been defined yet. This decouples the evolution of identification schemes from the evolution of protocols, data formats, and implementations that use URIs. Iconic behavior ๐
A parser for the generic URI syntax can break any URI reference into its major components. Once the scheme is known, further scheme-specific parsing can be done on those components. In other words, the generic URI syntax is a superset of the syntax of all URI schemes ๐
1.1.2. Examples ๐
The following example URIs show off several URI schemes and the variations in their common syntax components:
ftp://ftp.is.co.za/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc2396.txt
ldap://[2001:db8::7]/c=GB?objectClass?one
mailto:John.Doe@example.com
news:comp.infosystems.www.servers.unix
tel:+1-816-555-1212
telnet://192.0.2.16:80/
urn:oasis:names:specification:docbook:dtd:xml:4.1.2
1.1.3. URI, URL, and URN ๐ท
A URI can be classified as a locator, a name, or both. "Uniform Resource Locator" (URL) refers to the subset of URIs that, besides identifying a resource, also give a way to locate it by describing its primary access mechanism (e.g., its network "location"). "Uniform Resource Name" (URN) has historically been used for both URIs under the "urn" scheme [RFC2141], which are required to stay globally unique and persistent even when the resource stops existing or becomes unavailable, and for any other URI with the properties of a name ๐ซถ
An individual scheme doesn't have to be just "name" or just "locator." Instances of URIs from any given scheme may have the characteristics of names or locators or both, and that often depends on how persistent the identifiers are and how carefully the naming authority assigns them, rather than on anything about the scheme itself ๐ง Future specs and docs should use the general term "URI" instead of the more restrictive terms "URL" and "URN" [RFC3305] โจ
1.2. Design Considerations ๐
1.2.1. Transcription โ๏ธ
The URI syntax was designed with global transcription as one of its main goals ๐ A URI is a sequence of characters from a very limited set: the letters of the basic Latin alphabet, digits, and a few special characters. A URI can be represented in lots of ways (e.g., ink on paper, pixels on a screen, or a sequence of character encoding octets) ๐๏ธ A URI's interpretation depends only on the characters used, not on how those characters are represented in a network protocol.
The whole point of transcription is best shown by a little scenario ๐ธ Imagine two colleagues, Sam and Kim, sitting in a pub at an international conference, swapping research ideas. Sam asks Kim for a location to get more info, so Kim writes the URI for the research site on a napkin. Back home, Sam pulls out the napkin, types the URI into a computer, and the computer retrieves the info Kim meant ๐ฅ
There are a few design considerations the scenario reveals:
- A URI is a sequence of characters that isn't always represented as a sequence of octets.
- A URI might be transcribed from a non-network source, so it should consist of characters that are most likely able to be entered into a computer, within the limits set by keyboards (and related input devices) across languages and locales โจ๏ธ
- A URI often has to be remembered by people, and it's easier for people to remember a URI when it's made of meaningful or familiar components ๐ง
These design considerations don't always line up ๐ For example, the most meaningful name for a URI component often needs characters that can't be typed on some systems. Being able to transcribe a resource identifier from one medium to another has been treated as more important than having a URI made of the most meaningful components possible ๐ญ
In local or regional contexts, and as technology improves, users might benefit from being able to use a wider range of characters; that kind of use is not defined by this spec ๐ Percent-encoded octets (Section 2.1) may be used within a URI to represent characters outside the range of the US-ASCII coded character set, if this representation is allowed by the scheme or by the protocol element where the URI is referenced ๐ซง Such a definition should specify the character encoding used to map those characters to octets before they're percent-encoded for the URI ๐
1.2.2. Separating Identification from Interaction โจ
okay so a super common misunderstanding about URIs is that they're only for stuff you can actually reach ๐ but nope! a URI just identifies. having one doesn't mean you can access the resource, and it doesn't promise you can. ๐ whatever you can do with a URI is decided by the protocol element, data format attribute, or natural language text it shows up in.
so a system might try all kinds of things with a URI, like "access", "update", "replace", or "find attributes" ๐ฆ but those actions are defined by the protocols that use URIs, not by this spec. we do give a few general names to common moves, though ๐ซถ URI "resolution" is figuring out which access mechanism to use and what parameters you need to "dereference" it, and it can take several rounds to get there ๐ฅ then using that access mechanism to do something with the resource is what we call dereferencing it.
when URIs are used in information retrieval systems to find sources of info, the most common kind of dereference is "retrieval", which means using a URI to get a representation of its resource โจ a "representation" is a sequence of octets plus representation metadata that describes those octets, and it records the state of the resource at the moment it was generated ๐ธ retrieval can involve using the URI as a cache key to check for a local copy, resolving the URI to find an access mechanism (if there is one), and dereferencing it to actually apply the retrieval operation ๐ depending on the protocols involved, you might also get extra info about the resource (resource metadata) and how it relates to other resources.
URI references in info retrieval systems are late-binding ๐ which means the result of an access is usually figured out when you access it, and it can change over time or depending on other stuff in the interaction. these references are made to be used later. what's being identified isn't some specific result from the past, it's a characteristic that's expected to stay true for future results ๐ง so the resource is really a sameness of characteristics observed over time, maybe explained further by comments or assertions from the resource provider. main character energy ๐
also, even though lots of URI schemes are named after protocols, that does not mean using the URI will get you to the resource through that protocol ๐ URIs are often just for identification. even when you retrieve a representation, the access might go through gateways, proxies, caches, and name resolution services that are separate from the scheme's protocol ๐ some URIs even need more than one protocol to resolve. like, DNS and HTTP are both typically used to reach the origin server of an http URI when the representation isn't in a local cache. iykyk ๐
1.2.3. Hierarchical Identifiers ๐ธ
the URI syntax is hierarchical, with components listed from most significant to least significant as you read left to right โจ for some URI schemes, the visible hierarchy stops at the scheme itself. everything after the scheme delimiter (:) is opaque to URI processing ๐ other schemes make their hierarchy explicit and visible to generic parsing algorithms ๐
the generic syntax uses the slash (/), question mark (?), and number sign (#) characters to mark off the components that matter to the generic parser's hierarchical reading of an identifier ๐ฆ that makes identifiers easier to read because the syntax looks familiar across the board, and it lets scheme-independent references be made relative to that hierarchy ๐ซถ
it's really common for a whole group or "tree" of documents to be built for one purpose, where most of the URI references point to stuff inside the tree rather than outside it ๐ง same goes for documents on a particular site, which are way more likely to link to other resources on that site than to remote ones ๐
relative referencing lets document trees stay partly independent of their location and access scheme. for example, one set of hypertext documents can be accessed and traversed through each of the "file", "http", and "ftp" schemes at the same time, as long as the documents refer to each other with relative references ๐ฅ and best of all, a whole tree like that can be moved without changing any of its relative references ๐ญ
a relative reference (Section 4.2) points at a resource by describing the difference, within a hierarchical name space, between the reference context and the target URI ๐ the reference resolution algorithm, presented in Section 5, defines how a reference gets turned into the target URI โจ since relative references can only be used inside a hierarchical URI context, designers of new URI schemes should use a syntax that's consistent with the generic syntax's hierarchical components, unless there are compelling reasons to forbid relative referencing in that scheme ๐
NOTE: Previous specifications used the terms "partial URI" and "relative URI" to denote a relative reference to a URI. As some readers misunderstood those terms to mean that relative URIs are a subset of URIs rather than a method of referencing URIs, this specification simply refers to them as relative references. ๐
all URI references get parsed by generic syntax parsers when they're used ๐ but hierarchical processing has no effect on an absolute URI used in a reference unless it contains one or more dot-segments (complete path segments of "." or "..", as described in Section 3.3) ๐ so URI scheme specs can define opaque identifiers by disallowing slash characters, question mark characters, and the URIs scheme:. and scheme:.. ๐ง
1.3. Syntax Notation ๐
this specification uses the Augmented Backus-Naur Form (ABNF) notation of [RFC2234] ๐ it also includes these core ABNF syntax rules from that spec: ALPHA (letters), CR (carriage return), DIGIT (decimal digits), DQUOTE (double quote), HEXDIG (hexadecimal digits), LF (line feed), and SP (space) โจ the complete URI syntax is collected in Appendix A ๐ซถ
2. Characters ๐ฆ
the URI syntax is a way to encode data, usually for identifying a resource, as a sequence of characters ๐ those URI characters are often encoded as octets for transport or display ๐ธ this spec doesn't require any particular character encoding for mapping between URI characters and the octets used to store or send them ๐ when a URI shows up in a protocol element, that protocol defines the character encoding. if it doesn't say, the URI is assumed to use the same character encoding as the surrounding text ๐
the ABNF notation defines its terminal values as non-negative integers (codepoints) based on the US-ASCII coded character set [ASCII] ๐ง since a URI is a sequence of characters, we have to flip that relationship around to understand the URI syntax ๐ฅ so the integer values used by ABNF must be mapped back to their matching characters via US-ASCII before the syntax rules are complete ๐
a URI is built from a limited set of characters: digits, letters, and a few graphic symbols ๐ a reserved subset of those characters can be used to delimit syntax components inside a URI ๐ the remaining characters, including the unreserved set and the reserved characters that aren't acting as delimiters, define each component's identifying data โจ
2.1. Percent-Encoding ๐
a percent-encoding mechanism is used to represent a data octet in a component when that octet's character is outside the allowed set, or when it's being used as a delimiter of, or within, the component ๐ซถ a percent-encoded octet is written as a character triplet: the percent character % followed by the two hexadecimal digits for that octet's numeric value ๐ฆ for example, %20 is the percent-encoding for the binary octet 00100000 (ABNF: %x20), which in US-ASCII is the space character (SP) ๐ Section 2.4 describes when percent-encoding and decoding gets applied ๐
pct-encoded = "%" HEXDIG HEXDIG
the uppercase hex digits 'A' through 'F' are equivalent to the lowercase digits 'a' through 'f', respectively ๐ธ if two URIs differ only in the case of the hex digits used in percent-encoded octets, they're equivalent ๐ง for consistency, URI producers and normalizers should use uppercase hex digits for all percent-encodings ๐โจ
2.2. Reserved Characters โจ
okay so URIs are made of little pieces (components and subcomponents) and they get split apart by special delimiter characters ๐ these are the "reserved" ones. they're called reserved because they may (or may not) be delimiters, depending on the generic syntax, each scheme's own syntax, or the implementation-specific syntax of a URI's dereferencing algorithm ๐ and if data for a URI component would clash with a reserved character's delimiter job, then that conflicting data must be percent-encoded before the URI is formed ๐ซถ
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
the whole point of reserved characters is to give you a set of delimiters that look different from regular data inside a URI ๐ฆ so a URI that swaps a reserved character for its percent-encoded octet is not equivalent to the original. percent-encoding a reserved character (or decoding a percent-encoded octet that matches one) changes how most applications read the URI, which is giving "not the same URI" energy ๐ so reserved characters are protected from normalization, and that's exactly why they're safe for scheme-specific and producer-specific algorithms to use when delimiting data subcomponents ๐ธ
a subset of the reserved characters (gen-delims) is used as delimiters for the generic URI components we'll get into in Section 3. the component ABNF rules never use the reserved or gen-delims rule names directly. instead, each rule lists the characters that are allowed inside that component (aka the ones that don't delimit it), and any of those that are also in the reserved set are "reserved" for use as subcomponent delimiters within that component ๐ง only the most common subcomponents are defined here. other subcomponents can be defined by a URI scheme's specification or by the implementation-specific syntax of a dereferencing algorithm, as long as they're delimited by characters from the reserved set that are allowed in that component โจ
URI producing applications should percent-encode data octets that match reserved characters, unless the URI scheme specifically allows those characters to represent data in that component ๐ and if a reserved character shows up in a URI component and nobody knows what delimiting job it's doing, then it must be interpreted as representing the data octet that matches that character's US-ASCII encoding. no vibes-based guessing allowed ๐ญ
2.3. Unreserved Characters ๐
characters that are allowed in a URI but don't have a reserved purpose are called unreserved ๐ธ that's uppercase and lowercase letters, decimal digits, hyphen, period, underscore, and tilde. literally the chill ones ๐
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
URIs that differ only in swapping an unreserved character for its percent-encoded US-ASCII octet are equivalent, meaning they identify the same resource ๐ฆ BUT (and this is a big but ๐) URI comparison implementations don't always normalize before comparing. see Section 6 for that drama. for consistency, percent-encoded octets in the ranges of ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should not be created by URI producers. and when they are found in a URI, they should be decoded back to their unreserved characters by URI normalizers ๐งนโจ
2.4. When to Encode or Decode ๐
under normal circumstances, the only time octets within a URI get percent-encoded is while the URI is being produced from its component parts ๐๏ธ this is when an implementation figures out which reserved characters are being used as subcomponent delimiters and which ones can safely be used as data. once produced, a URI is always in its percent-encoded form. no take-backs ๐
when a URI gets dereferenced, the components and subcomponents that matter to the scheme-specific dereferencing process (if there are any) must be parsed and separated before the percent-encoded octets inside them can be safely decoded ๐ฅ otherwise the data could get mistaken for delimiters, and that's a whole mess ๐ฌ the only exception is percent-encoded octets that match unreserved characters, which can be decoded at any time ๐ซถ for example, the octet for the tilde ("~") character is often encoded as "%7E" by older URI processing implementations, and that "%7E" can be replaced by "~" without changing its meaning โจ
because the percent ("%") character is the indicator for percent-encoded octets, it must be percent-encoded as "%25" for that octet to be used as data within a URI ๐ and implementations must not percent-encode or decode the same string more than once ๐ โโ๏ธ decoding something that's already decoded might make you misread a percent data octet as the start of a percent-encoding (or the other way around, when percent-encoding something that's already percent-encoded). not it. never do it ๐
2.5. Identifying Data ๐ฆ
URI characters provide the identifying data for each URI component, acting as an external interface for identification between systems ๐ธ the presence and nature of the URI production interface is hidden from the clients that use its URIs (so it's beyond the scope of the interoperability requirements in this spec). but it's a frequent source of confusion and errors when interpreting URI character issues ๐ญ implementers have to be aware that multiple character encodings are involved in producing and transmitting URIs: local name and data encoding, public interface encoding, URI character encoding, data format encoding, and protocol encoding. it's a lot, bestie ๐ซ
local names (like file system names) are stored with a local character encoding. URI producing applications (e.g., origin servers) will typically use that local encoding as the basis for producing meaningful names ๐ง the URI producer transforms the local encoding into one that's suitable for a public interface, and then transforms the public interface encoding into the restricted set of URI characters (reserved, unreserved, and percent-encodings). those characters are then encoded as octets to be used as a reference within a data format (e.g., a document charset), and those data formats are often encoded again for transmission over Internet protocols ๐ layers on layers ๐
for most systems, an unreserved character appearing within a URI component is interpreted as representing the data octet that matches that character's US-ASCII encoding. consumers of URIs assume that the letter "X" corresponds to the octet "01011000", and even when that assumption is wrong, there's no harm in making it ๐ a system that internally uses a different character encoding, like EBCDIC, will generally translate textual identifiers to UTF-8 [STD63] (or some other superset of US-ASCII) at an internal interface ๐ that gives you more meaningful identifiers than just percent-encoding the original octets would ๐
here's a lowkey iconic example ๐ say an information service stores data on an EBCDIC-based file system and serves it to clients on the Internet through an HTTP server. when an author creates a file named "Laguna Beach" on that file system, the "http" URI for that resource is expected to contain the meaningful string "Laguna%20Beach" โจ but if the server makes URIs using an overly simplistic raw octet mapping, you'd get a URI containing "%D3%81%87%A4%95%81@%C2%85%81%83%88" ๐ that's giving chaos. an internal transcoding interface fixes this by transcoding the local name to a superset of US-ASCII before the URI gets produced ๐ง and naturally, reading an incoming URI on that kind of interface requires percent-encoded octets to be decoded first (e.g., "%20" to SP) before the reverse transcoding is applied to get back the local name ๐
in some cases, the link between a URI component and the identifying data it was made to represent is way less direct than a character encoding translation ๐บ๏ธ for example, parts of a URI might reflect a query on non-ASCII data, or numeric coordinates on a map. and a URI scheme may define components with extra encoding requirements that get applied before the component is formed and the URI is produced ๐ธ
when a new URI scheme defines a component that represents textual data made of characters from the Universal Character Set [UCS], that data should first be encoded as octets using the UTF-8 character encoding [STD63]. then only the octets that don't match unreserved characters should be percent-encoded ๐ for example, the character A is represented as "A", the character LATIN CAPITAL LETTER A WITH GRAVE is represented as "%C3%80", and the character KATAKANA LETTER A is represented as "%E3%82%A2" ๐๐
3. Syntax Components ๐
the generic URI syntax is a hierarchical sequence of components called the scheme, authority, path, query, and fragment ๐ง it's giving org chart, but make it cute ๐ธ
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
the scheme and path components are required, though the path can be empty (no characters) ๐ซถ when authority is present, the path must either be empty or begin with a slash ("/") character. when authority is not present, the path cannot begin with two slash characters ("//"). these restrictions give us five different ABNF rules for a path (Section 3.3), and only one of them will match any given URI reference ๐ฅ very exact, very specific, very me ๐
here are two example URIs and their component parts ๐
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
3.1. Scheme โจ
okay so every URI starts with a scheme name, and that name points to the spec that says how identifiers in that scheme get assigned ๐ง it's giving federated and extensible naming system, bestie. Each scheme's spec can add its own restrictions on the syntax and semantics of its identifiers. main character energy ๐
Scheme names are a sequence of characters that begins with a letter, then any mix of letters, digits, plus ("+"), period ("."), or hyphen ("-") ๐ Schemes are case-insensitive, but the canonical form is lowercase, and specs that define schemes must write them in lowercase letters ๐ An implementation should accept uppercase letters as equivalent to lowercase (so "HTTP" works just like "http") for robustness, but it should only produce lowercase scheme names for consistency ๐ซถ
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
this document doesn't specify individual schemes, bestie ๐ฆ registering new URI schemes is handled separately by [BCP35], and the scheme registry keeps the mapping between scheme names and their specs. If you want advice for designing new schemes, check out [RFC2718]. URI scheme specs must define their own syntax so that every string matching their scheme-specific syntax also matches the <absolute-URI> grammar, as described in Section 4.3 ๐
and this part is so important ๐ญ when a URI breaks one or more scheme-specific restrictions, the scheme-specific resolution process should flag the reference as an error instead of ignoring the unused parts. Why? Because it cuts down on equivalent URIs and helps catch abuses of the generic syntax, which could mean the URI was built to mislead the user (Section 7.6) ๐จ not me spotting a sketchy link like it's my job ๐
3.2. Authority ๐ธ
so a lot of URI schemes have a hierarchical bit for a naming authority, which means governance of the name space in the rest of the URI gets delegated to that authority (and it can delegate further too, iykyk ๐) The generic syntax gives everyone one shared way to tell an authority apart, based on a registered name or server address, plus optional port and user information ๐ฆ
the authority component starts with a double slash ("//") and ends at the next slash ("/"), question mark ("?"), or number sign ("#") character, or at the end of the URI, whichever comes first ๐
authority = [ userinfo "@" ] host [ ":" port ]
URI producers and normalizers should leave out the ":" that separates host from port when the port is empty ๐ง Some schemes don't allow the userinfo and/or port subcomponents at all, so check the vibe of each scheme first ๐
if a URI has an authority component, then the path component must either be empty or start with a slash ("/") character. No cap, this rule is non-negotiable ๐ค Non-validating parsers (the ones that just split a URI reference into its major components) will often ignore the subcomponent structure of authority and treat it as one opaque string, from the double slash up to the first terminating delimiter, until the URI actually gets dereferenced ๐
3.2.1. User Information ๐
the userinfo subcomponent can hold a user name and, optionally, scheme-specific info about how to get authorized to access the resource. If user information is present, a commercial at-sign ("@") follows it to separate it from the host ๐
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
ok, real talk, bestie ๐ฉ using the "user:password" format in userinfo is deprecated. Applications should not render any data after the first colon (":") in a userinfo subcomponent as clear text, unless that data after the colon is the empty string (which means no password). Applications may choose to ignore or reject that data when it shows up in a reference, and they should reject storing it in unencrypted form. Passing auth info in clear text has proven to be a security risk in almost every case where it's been used ๐ญ๐ฅ
Clear text passwords in a URI are a security risk in almost every case. Don't do it, periodt ๐
when applications display a URI for user feedback (like in graphical hypertext browsing), they should render userinfo in a way that's visually distinct from the rest of the URI, when that's feasible โจ This helps users when userinfo has been sneakily crafted to look like a trusted domain name (Section 7.6). Honestly the scammers are not it ๐ โโ๏ธ๐
3.2.2. Host โจ
okay bestie so the host subcomponent of authority is identified by an IP literal wrapped in square brackets ๐, an IPv4 address in dotted-decimal form ๐ข, or a registered name ๐ธ. the host is case-insensitive ๐ . having a host in a URI does not imply that the scheme needs to actually reach that host on the Internet ๐. honestly the host syntax is often just borrowed so we can reuse the DNS registration process that already exists, which gets us a globally unique name without building a whole new registry ๐ง. but that comes with its own costs ๐, because domain name ownership can change over time for reasons the URI producer never saw coming. and sometimes the data in the host part names something that has nothing to do with an Internet host at all. we still call the ABNF rule "host" because that is its most common purpose, not its only purpose ๐.
host = IP-literal / IPv4address / reg-name
the host rule is a little ambiguous because it doesn't fully separate an IPv4address from a reg-name ๐ญ. so we use the "first-match-wins" algorithm to fix it ๐: if host matches the rule for IPv4address, it SHOULD be treated as an IPv4 address literal and NOT as a reg-name. host is case-insensitive, but producers and normalizers SHOULD use lowercase for registered names and hexadecimal addresses so everything stays uniform ๐ซถ, and only use uppercase letters for percent-encodings ๐.
a host identified by an Internet Protocol literal address, version 6 [RFC3513] or later, is marked by putting the IP literal inside square brackets ("[" and "]") ๐ฆ. this is the ONLY place square brackets are allowed in the URI syntax ๐ฅ. since future IP literal formats don't exist yet, an implementation MAY use an optional version flag to say so explicitly instead of guessing with heuristics โจ.
IP-literal = "[" ( IPv6address / IPvFuture ) "]"
IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
the version flag does NOT tell you the IP version ๐ โโ๏ธ. it tells you about future versions of the literal format. so implementations MUST NOT provide the version flag for the existing IPv4 and IPv6 literal forms described below ๐ซ. if a URI has an IP-literal starting with "v" (case-insensitive), which means the version flag is there, and an application that doesn't understand that flag dereferences it, the application SHOULD return an appropriate error for "address mechanism not supported" ๐ญ๐ .
a host identified by an IPv6 literal address is written inside the square brackets without a version flag ๐. the ABNF here is a translation of the text definition of an IPv6 literal address from [RFC3513] ๐. this syntax does NOT support IPv6 scoped addressing zone identifiers, so no zone stuff here, bestie ๐ โโ๏ธ.
a 128-bit IPv6 address is split into eight 16-bit pieces โจ. each piece is written in hexadecimal (case-insensitive) using one to four hex digits, and leading zeroes are fine ๐ง. the eight pieces go most-significant first, separated by colons ๐ซ. optionally, the two least-significant pieces MAY be written in IPv4 address textual format instead ๐ฆ. also, one or more consecutive all-zero 16-bit pieces MAY be elided, which means you drop all their digits and leave exactly two colons behind to show the gap ๐โจ.
IPv6address = 6( h16 ":" ) ls32
/ "::" 5( h16 ":" ) ls32
/ [ h16 ] "::" 4( h16 ":" ) ls32
/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
/ [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
/ [ *4( h16 ":" ) h16 ] "::" ls32
/ [ *5( h16 ":" ) h16 ] "::" h16
/ [ *6( h16 ":" ) h16 ] "::"
ls32 = ( h16 ":" h16 ) / IPv4address
; least-significant 32 bits of address
h16 = 1*4HEXDIG
; 16 bits of address represented in hexadecimal
a host identified by an IPv4 literal address is written in dotted-decimal notation ๐ข: four decimal numbers from 0 to 255, separated by "." ๐ธ. this is described in [RFC1123] by reference to [RFC0952] ๐. some platforms may interpret other dotted notations too, as described in Section 7.4 ๐, but this grammar only allows the dotted-decimal form with four octets ๐ .
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
dec-octet = DIGIT ; 0-9
/ %x31-39 DIGIT ; 10-99
/ "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255
a host identified by a registered name is a sequence of characters, usually meant to be looked up in a locally defined host or service name registry ๐๏ธ. the URI's scheme-specific semantics might require a specific registry (or fixed name table) to be used instead ๐ง. the most common name registry is the Domain Name System (DNS) ๐. a registered name meant for DNS lookup uses the syntax from Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123] ๐. it's a bunch of domain labels separated by "." ๐, where each label starts and ends with an alphanumeric character and MAY also contain "-" characters ๐. the rightmost label of a fully qualified domain name in DNS MAY be followed by a single "." and SHOULD be if it is necessary to tell the full domain name apart from some local domain ๐ซถ.
reg-name = *( unreserved / pct-encoded / sub-delims )
if the URI scheme defines a default for host, that default kicks in when the host is undefined or the registered name is empty (zero length) ๐ง. for example, the "file" scheme is set up so that no authority, an empty host, and "localhost" ALL mean the end-user's own machine ๐ป. meanwhile the "http" scheme says a missing authority or empty host is invalid ๐ โโ๏ธ.
this spec doesn't force one particular registered-name lookup technology ๐, so it doesn't restrict reg-name syntax beyond what interoperability needs ๐ซถ. instead, it hands off registered-name syntax conformance to the operating system of each app doing URI resolution ๐ , and that OS decides what it allows for host identification. a resolver could use DNS, host tables, yellow pages, NetInfo, WINS, or any other system to look up registered names ๐ฆ. however, a globally scoped naming system, like DNS fully qualified domain names, is needed for URIs meant to have global scope ๐. URI producers SHOULD use names that follow DNS syntax, even when DNS isn't obviously involved โจ, and SHOULD limit these names to no more than 255 characters in length ๐.
the reg-name syntax allows percent-encoded octets so non-ASCII registered names can be represented in a uniform way that doesn't depend on the name resolution technology ๐ธ. non-ASCII characters MUST first be encoded with UTF-8 [STD63], and then each octet of that UTF-8 sequence MUST be percent-encoded so it becomes URI characters ๐ฅ. URI producing applications MUST NOT use percent-encoding in host unless it's representing a UTF-8 character sequence ๐ โโ๏ธ. when a non-ASCII registered name is an internationalized domain name meant for DNS resolution, the name MUST be converted to the IDNA encoding [RFC3490] before the name lookup ๐. URI producers SHOULD give these names in the IDNA encoding rather than percent-encoding if they want to maximize interoperability with legacy URI resolvers ๐.
3.2.3. Port ๐ช
the port subcomponent of authority is an optional port number written in decimal ๐ข, following the host and separated from it by a single colon (":") character ๐ซ.
port = *DIGIT
a scheme MAY define a default port ๐ง. for example, the "http" scheme defines a default port of "80", which matches its reserved TCP port number ๐. the type of port the number refers to (e.g., TCP, UDP, SCTP) is defined by the URI scheme ๐ฆ. URI producers and normalizers SHOULD omit the port component and its ":" delimiter if the port is empty, or if its value would be the same as the scheme's default ๐ โจ.
3.3. Path โจ
okay so the path component is the juicy hierarchical bit ๐๏ธ it holds data, usually organized like folders, and together with the non-hierarchical query (Section 3.4) it helps pinpoint a resource within the scope of the URI's scheme and naming authority (if there is one) ๐ the path ends at the first question mark ("?") or number sign ("#") character, or at the end of the URI, whichever comes first ๐ฆ
if a URI has an authority component, then the path component must either be empty or begin with a slash ("/") character ๐ธ and if a URI does NOT have an authority component, the path cannot start with two slash characters ("//") ๐ also, a URI reference (Section 4.1) can be a relative-path reference, and in that case the first path segment cannot contain a colon (":") character, because it would look like a scheme ๐ the ABNF needs five separate rules to sort out these cases, and only one of them will match the path substring in any given URI reference ๐ง we just use the generic term "path component" for whichever substring the parser matched to one of those rules โจ
path = path-abempty ; begins with "/" or is empty
/ path-absolute ; begins with "/" but not "//"
/ path-noscheme ; begins with a non-colon segment
/ path-rootless ; begins with a segment
/ path-empty ; zero characters
path-abempty = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )
path-empty = 0<pchar>
segment = *pchar
segment-nz = 1*pchar
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
; non-zero-length segment without any colon ":"
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
a path is made of path segments separated by a slash ("/") character ๐ every URI always has a path, even though that path might be empty (zero length) ๐ using the slash to show hierarchy is only really required when a URI is going to be the context for relative references, so it's not a must everywhere ๐ซถ for example, mailto:fred@example.com has a path of "fred@example.com", but foo://info.example.com?fred has an empty path ๐
the path segments "." and "..", also known as dot-segments, are there for relative reference inside the path name hierarchy ๐ they're meant to go at the start of a relative-path reference (Section 4.2) to show where you are in the tree of names ๐งญ it's kinda like how file directories use them for "current directory" and "parent directory" ๐ BUT, unlike a real file system, these dot-segments only get interpreted inside the URI path hierarchy, and they get removed as part of the resolution process (Section 5.2) ๐
ngl this is the part people trip on: outside of hierarchical paths, the generic syntax treats a path segment as opaque ๐ฅ
URI-producing apps often use the reserved characters allowed in a segment to mark off scheme-specific or dereference-handler-specific subcomponents ๐ for example, the semicolon (";") and equals ("=") reserved characters are often used to separate parameters and their values for that segment ๐ the comma (",") is often used for similar stuff too โจ so one producer might write a segment like "name;v=1.1" to mean version 1.1 of "name", while another might write "name,1.1" to mean the exact same thing ๐ parameter types can be defined by scheme-specific semantics, but most of the time the syntax of a parameter is specific to how the URI's dereferencing algorithm is implemented ๐ค
3.4. Query ๐ท
the query component holds non-hierarchical data which, together with data in the path component (Section 3.3), helps identify a resource within the scope of the URI's scheme and naming authority (if any) ๐ซง it starts at the first question mark ("?") character and ends at a number sign ("#") character or the end of the URI, whichever comes first ๐ซ
query = *( pchar / "/" / "?" )
the slash ("/") and question mark ("?") characters are allowed to represent data inside the query component ๐ but be careful, because some older, buggy implementations might not handle that data properly when it's used as the base URI for relative references (Section 5.1) ๐ฌ they apparently fail to tell query data apart from path data when they're looking for hierarchy separators ๐ still, query components often carry identifying info as "key=value" pairs, and one super common value is a reference to another URI, so sometimes it's just better for usability to NOT percent-encode those characters ๐ญ
3.5. Fragment ๐ฆ
the fragment identifier component lets you indirectly identify a secondary resource by pointing at a primary resource plus some extra identifying info ๐ the secondary resource might be a portion or subset of the primary one, a view on its representations, or some other resource defined or described by those representations ๐ a fragment starts with a number sign ("#") character and runs until the end of the URI ๐
fragment = *( pchar / "/" / "?" )
what a fragment means is decided by the set of representations that might come back from a retrieval action on the primary resource ๐๏ธ so the fragment's format and how it gets resolved depend on the media type [RFC2046] of a potentially retrieved representation, even though that retrieval only happens if the URI is actually dereferenced ๐ง if no such representation exists, the fragment's semantics are unknown and effectively unconstrained ๐ and fragment identifier semantics are independent of the URI scheme, so scheme specs can't redefine them ๐ซ
individual media types can set their own restrictions on, or structures within, the fragment syntax for picking out different kinds of subsets, views, or external references that count as secondary resources for that media type ๐จ if the primary resource has multiple representations, which happens a lot when the representation gets picked based on attributes of the request (a.k.a., content negotiation), then whatever the fragment identifies should stay consistent across all of those representations ๐ซถ each representation should either define the fragment so it points at the same secondary resource no matter how it's represented, or leave the fragment undefined (i.e., not found) ๐
as with any URI, using a fragment doesn't mean a retrieval action is going to happen ๐ a URI with a fragment can be used to refer to the secondary resource without implying that the primary resource is accessible, or will ever be accessed ๐
fragments are kind of a big deal in information retrieval systems because they're the main way to do client-side indirect referencing ๐ฅ they let an author point at specific bits of an existing resource that the resource owner only provides indirectly ๐ that's why the fragment isn't used in the scheme-specific processing of a URI: it gets split off from the rest of the URI before dereferencing, so the user agent handles the identifying info inside it all by itself, no matter the scheme ๐ง people sometimes feel this separate handling is a loss of info, especially when redirecting references as resources move over time ๐ญ but it also stops information providers from denying reference authors the right to refer to parts of a resource selectively ๐ซถ indirect referencing gives systems that use URIs extra flexibility and extensibility too, since new media types are easier to define and deploy than new identification schemes ๐
the slash ("/") and question mark ("?") characters are allowed to represent data inside the fragment identifier ๐ be careful though, since some older, erroneous implementations might not handle this data correctly when it's used as the base URI for relative references (Section 5.1) ๐
4. Usage ๐
when applications reference a URI, they don't always use the full form defined by the "URI" syntax rule ๐ซง to save space and take advantage of hierarchical locality, lots of Internet protocol elements and media type formats let you abbreviate a URI, while others restrict the syntax to one particular form of URI ๐งฉ we define the most common forms of reference syntax in this spec, because they affect and depend on the design of the generic syntax, and they need a uniform parsing algorithm so everyone interprets them the same way ๐ค
4.1. URI Reference ๐
URI-reference is the term used for the most common usage of a resource identifier ๐ธ
URI-reference = URI / relative-ref
a URI-reference is either a URI or a relative reference ๐ฆ if the URI-reference's prefix doesn't match the syntax of a scheme followed by its colon separator, then it's a relative reference ๐งญ
a URI-reference is typically parsed into the five URI components first, so you can figure out which components are present and whether the reference is relative โจ then each component gets parsed for its subparts and their validation ๐ the ABNF of URI-reference, along with the "first-match-wins" disambiguation rule, is enough to define a validating parser for the generic syntax ๐ if you're into regular expressions, check out Appendix B for an example of a non-validating URI-reference parser that takes any string and extracts the URI components ๐ค
4.2. Relative Reference ๐ท
a relative reference uses the hierarchical syntax (Section 1.2.3) to express a URI reference relative to the name space of another hierarchical URI ๐บ๏ธ
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
relative-part = "//" authority path-abempty
/ path-absolute
/ path-noscheme
/ path-empty
the URI that a relative reference refers to, also known as the target URI, is obtained by applying the reference resolution algorithm of Section 5 ๐ฏ
a relative reference that starts with two slash characters is called a network-path reference, and those are rarely used ๐ one that starts with a single slash character is called an absolute-path reference ๐ and one that doesn't start with a slash character is called a relative-path reference ๐ญ
a path segment that contains a colon character (e.g., "this:that") can't be used as the first segment of a relative-path reference, because it'd get mistaken for a scheme name ๐ญ so that segment has to be preceded by a dot-segment (e.g., "./this:that") to make a relative-path reference ๐
4.3. Absolute URI โจ
okay so some protocol elements only accept the absolute form of a URI, and they don't want a fragment identifier tagging along ๐ like, say you're defining a base URI so relative references can use it later. then you need an absolute-URI rule that doesn't allow a fragment. that's the whole point ๐
absolute-URI = scheme ":" hier-part [ "?" query ]
URI scheme specs must define their own syntax so that every string matching their scheme-specific syntax also matches the <absolute-URI> grammar ๐ฆ Scheme specs will not define fragment identifier syntax or usage, even if it would make sense for resources reached through that scheme, because fragment identification is orthogonal to scheme definition ๐ง still, scheme specs are encouraged to include a wide range of examples, including examples that show how the scheme's URIs work with fragment identifiers when that usage is appropriate ๐
4.4. Same-Document Reference ๐ธ
okay this one is so good ๐ญ when a URI reference points to a URI that is identical to the base URI (Section 5.1) apart from its fragment component (if any), that reference is called a "same-document" reference. the most common examples are relative references that are empty, or that only have the number sign ("#") separator followed by a fragment identifier ๐ซถ
when a same-document reference gets dereferenced for a retrieval action, the target is defined to be within the same entity (representation, document, or message) as the reference, so a dereference should not result in a new retrieval action ๐
normalizing the base and target URIs before comparing them, as described in Sections 6.2.2 and 6.2.3, is allowed but rarely performed in practice ๐ normalization may increase the set of same-document references, which may be a win for some caching applications ๐ so reference authors should not assume that a slightly different, though equivalent, reference URI will (or will not) be interpreted as a same-document reference by any given application. no guessing, bestie ๐
4.5. Suffix Reference ๐
the URI syntax is designed for unambiguous reference to resources and extensibility via the URI scheme. but URI identification has become super common, and traditional media (TV, radio, newspapers, billboards, etc.) have increasingly used a suffix of the URI as a reference. it's just the authority and path parts, like this:
www.w3.org/Addressing/
or just a DNS registered name on its own ๐ these references are mainly for humans, not machines, with the assumption that context-based heuristics are enough to complete the URI (e.g., most registered names beginning with "www" are likely to have a URI prefix of "http://"). there's no standard set of heuristics for disambiguating a URI suffix, but lots of client implementations let users type them in and resolve them heuristically ๐ธ
ngl, using suffix references is common, but it should be avoided whenever possible, and it should never be used where long-term references are expected ๐ฌ the heuristics will change over time, especially when a new URI scheme becomes popular, and they're often incorrect when used out of context. they can also lead to security issues along the lines of those described in [RFC1535] ๐ฅ this is serious, so please read it twice โญ
a URI suffix has the same syntax as a relative-path reference, so a suffix reference can't be used where a relative reference is expected. that means suffix references are limited to places with no defined base URI, like dialog boxes and off-line advertisements ๐บ
5. Reference Resolution ๐
this section defines how to resolve a URI reference in a context that allows relative references, so the result is a string matching the <URI> syntax rule of Section 3 ๐ง
5.1. Establishing a Base URI ๐ฆ
the word "relative" implies that a "base URI" exists, and the relative reference gets applied against it. apart from fragment-only references (Section 4.4), relative references are only usable when a base URI is known. a parser must establish a base URI before parsing URI references that might be relative ๐ซถ a base URI must conform to the <absolute-URI> syntax rule (Section 4.3). if the base URI comes from a URI reference, then that reference must be converted to absolute form and stripped of any fragment component before it's used as a base URI ๐
there are four ways to establish the base URI of a reference, discussed below in order of precedence. you can think of the order of precedence in layers, where the innermost defined base URI has the highest precedence. here's the visual:
.----------------------------------------------------------.
| .----------------------------------------------------. |
| | .----------------------------------------------. | |
| | | .----------------------------------------. | | |
| | | | .----------------------------------. | | | |
| | | | | <relative-reference> | | | | |
| | | | `----------------------------------' | | | |
| | | | (5.1.1) Base URI embedded in content | | | |
| | | `----------------------------------------' | | |
| | | (5.1.2) Base URI of the encapsulating entity | | |
| | | (message, representation, or none) | | |
| | `----------------------------------------------' | |
| | (5.1.3) URI used to retrieve the entity | |
| `----------------------------------------------------' |
| (5.1.4) Default Base URI (application-dependent) |
`----------------------------------------------------------'
5.1.1. Base URI Embedded in Content ๐
some media types can embed a base URI for relative references right inside the content, so a parser can grab it easily. this is handy for descriptive docs, like tables of contents, that might get sent to people through other protocols than their usual retrieval context (e.g., email or USENET news) ๐ง
this spec doesn't say how a base URI gets embedded for each media type, because that's out of scope. the right syntax (when there is one) is described by the data format spec for each media type ๐
5.1.2. Base URI from the Encapsulating Entity ๐
if no base URI is embedded, the base URI comes from the representation's retrieval context. for a document enclosed inside another entity, like a message or archive, that retrieval context is the enclosing entity. so the default base URI of a representation is the base URI of the entity it's encapsulated in ๐
MHTML [RFC2557] defines a mechanism for embedding a base URI inside MIME container types (e.g., the message and multipart types) ๐ง protocols that don't use MIME message header syntax, but that do allow some form of tagged metadata in messages, may define their own syntax for a base URI as part of a message โจ
5.1.3. Base URI from the Retrieval URI ๐ซง
if no base URI is embedded and the representation isn't encapsulated in some other entity, then, if a URI was used to retrieve the representation, that URI shall be considered the base URI ๐ฏ note that if the retrieval came from a redirected request, the last URI used (i.e., the URI that actually retrieved the representation) is the base URI ๐
5.1.4. Default Base URI ๐
if none of the conditions above apply, then the base URI is defined by the application's context. since that definition is application-dependent, skipping the other methods may make the same content get interpreted differently by different types of applications ๐ตโ๐ซ
a sender of a representation with relative references is responsible for making sure a base URI for those references can be established ๐ apart from fragment-only references, relative references can only be used reliably where the base URI is well defined ๐ซถ
5.2. Relative Resolution ๐
this section describes an algorithm for converting a URI reference that might be relative to a given base URI into the parsed components of the reference's target. then you recompose the components (see Section 5.3) to form the target URI ๐ฆ this algorithm gives definitive results you can use to test other implementations' output. applications can use some other algorithm for relative reference resolution, as long as the results match what this one gives ๐
5.2.1. Pre-parse the Base URI ๐ง
the base URI (Base) is established according to Section 5.1 and parsed into the five main components described in Section 3. note that only the scheme component is required in a base URI; the other components may be empty or undefined. a component is undefined if its delimiter doesn't appear in the URI reference. the path component is never undefined, though it may be empty ๐ธ
normalizing the base URI, as described in Sections 6.2.2 and 6.2.3, is optional. a URI reference must be transformed into its target URI before it can be normalized โจ
5.2.2. Transform References ๐
for each URI reference (R), the following pseudocode describes an algorithm for transforming R into its target URI (T) ๐
-- The URI reference is parsed into the five URI components
--
(R.scheme, R.authority, R.path, R.query, R.fragment) = parse(R);
-- A non-strict parser may ignore a scheme in the reference
-- if it is identical to the base URI's scheme.
--
if ((not strict) and (R.scheme == Base.scheme)) then
undefine(R.scheme);
endif;
if defined(R.scheme) then
T.scheme = R.scheme;
T.authority = R.authority;
T.path = remove_dot_segments(R.path);
T.query = R.query;
else
if defined(R.authority) then
T.authority = R.authority;
T.path = remove_dot_segments(R.path);
T.query = R.query;
else
if (R.path == "") then
T.path = Base.path;
if defined(R.query) then
T.query = R.query;
else
T.query = Base.query;
endif;
else
if (R.path starts-with "/") then
T.path = remove_dot_segments(R.path);
else
T.path = merge(Base.path, R.path);
T.path = remove_dot_segments(T.path);
endif;
T.query = R.query;
endif;
T.authority = Base.authority;
endif;
T.scheme = Base.scheme;
endif;
T.fragment = R.fragment;
5.2.3. Merge Paths โจ
okay so the pseudocode keeps calling a "merge" routine, and it's basically how you glue the reference's path onto the base URI's path ๐ It works like this:
- If the base URI has a defined authority component and an empty path, then return a string consisting of "/" concatenated with the reference's path; otherwise,
- return a string consisting of the reference's path component appended to all but the last segment of the base URI's path (i.e., excluding any characters after the right-most "/" in the base URI path, or excluding the entire base URI path if it does not contain any "/" characters).
5.2.4. Remove Dot Segments ๐งน
the pseudocode also depends on a "remove_dot_segments" routine, which is the bouncer for the special "." and ".." complete path segments in a referenced path. It runs after the path is pulled out of a reference, whether or not the path was relative, so any invalid or extra dot-segments get cleaned up before the target URI is formed. There are lots of ways to do this, but here's a simple method that uses two string buffers ๐
- Start the input buffer with the now-appended path components, and set the output buffer to the empty string.
- Keep looping while the input buffer still has stuff in it:
- A. If the input buffer starts with "../" or "./", strip that prefix off the input buffer; otherwise,
- B. if the input buffer starts with "/./" or "/.", where "." is a complete path segment, swap that prefix for "/" in the input buffer; otherwise,
- C. if the input buffer starts with "/../" or "/..", where ".." is a complete path segment, swap that prefix for "/" in the input buffer and remove the last segment and its preceding "/" (if there is one) from the output buffer; otherwise,
- D. if the input buffer is only "." or "..", remove that from the input buffer; otherwise,
- E. move the first path segment in the input buffer to the end of the output buffer. This includes the initial "/" character (if there is one) plus any characters after it, up to but not including the next "/" or the end of the input buffer.
- Finally, the output buffer gets returned as the result of remove_dot_segments.
Dot-segments are meant for URI references that want to point to something relative to the naming hierarchy in the base URI. remove_dot_segments respects that hierarchy by removing the extra dot-segments, rather than throwing an error or leaving them around to get misread by dereference implementations ๐ฆ
Here's how those steps play out for two merged paths, with both buffers shown after each step ๐
STEP OUTPUT BUFFER INPUT BUFFER
1 : /a/b/c/./../../g
2E: /a /b/c/./../../g
2E: /a/b /c/./../../g
2E: /a/b/c /./../../g
2B: /a/b/c /../../g
2C: /a/b /../g
2C: /a /g
2E: /a/g
STEP OUTPUT BUFFER INPUT BUFFER
1 : mid/content=5/../6
2E: mid /content=5/../6
2E: mid/content=5 /../6
2C: mid /6
2E: mid/6
Some applications might find it more efficient to use two segment stacks instead of strings for remove_dot_segments โจ
Note: Beware that some older, erroneous implementations will fail to separate a reference's query component from its path component prior to merging the base and reference paths, resulting in an interoperability failure if the query component contains the strings "/../" or "/./".
5.3. Component Recomposition ๐งฉ
you can put parsed URI components back together to get the URI reference string again. In pseudocode, that looks like this:
result = ""
if defined(scheme) then
append scheme to result;
append ":" to result;
endif;
if defined(authority) then
append "//" to result;
append authority to result;
endif;
append path to result;
if defined(query) then
append "?" to result;
append query to result;
endif;
if defined(fragment) then
append "#" to result;
append fragment to result;
endif;
return result;
The distinction that matters here is between a component that is undefined and one that is empty. Undefined means its separator never showed up in the reference. Empty means the separator was there, and it was immediately followed by the next component separator or by the end of the reference. Recomposition keeps that difference intact, so please don't mix them up ๐
5.4. Reference Resolution Examples ๐ธ
Say we've got a representation with a well-defined base URI of http://a/b/c/d;p?q. Here's how relative references turn into target URIs:
5.4.1. Normal Examples
"g:h" = "g:h"
"g" = "http://a/b/c/g"
"./g" = "http://a/b/c/g"
"g/" = "http://a/b/c/g/"
"/g" = "http://a/g"
"//g" = "http://g"
"?y" = "http://a/b/c/d;p?y"
"g?y" = "http://a/b/c/g?y"
"#s" = "http://a/b/c/d;p?q#s"
"g#s" = "http://a/b/c/g#s"
"g?y#s" = "http://a/b/c/g?y#s"
";x" = "http://a/b/c/;x"
"g;x" = "http://a/b/c/g;x"
"g;x?y#s" = "http://a/b/c/g;x?y#s"
"" = "http://a/b/c/d;p?q"
"." = "http://a/b/c/"
"./" = "http://a/b/c/"
".." = "http://a/b/"
"../" = "http://a/b/"
"../g" = "http://a/b/g"
"../.." = "http://a/"
"../../" = "http://a/"
"../../g" = "http://a/g"
5.4.2. Abnormal Examples ๐
These weird ones are pretty unlikely to show up in normal life, but all URI parsers should be capable of resolving them consistently. Every example uses the same base as above.
Parsers must be careful when a relative-path reference has more ".." segments than the base URI's path has hierarchical levels. Also, the ".." syntax cannot be used to change the authority component of a URI.
"../../../g" = "http://a/g"
"../../../../g" = "http://a/g"
Similarly, parsers must remove the dot-segments "." and ".." when they are complete components of a path, but not when they are only part of a segment.
"/./g" = "http://a/g"
"/../g" = "http://a/g"
"g." = "http://a/b/c/g."
".g" = "http://a/b/c/.g"
"g.." = "http://a/b/c/g.."
"..g" = "http://a/b/c/..g"
Even less likely are the cases where a relative reference uses unnecessary or nonsensical forms of the "." and ".." complete path segments.
"./../g" = "http://a/b/g"
"./g/." = "http://a/b/c/g/"
"g/./h" = "http://a/b/c/g/h"
"g/../h" = "http://a/b/c/h"
"g;x=1/./y" = "http://a/b/c/g;x=1/y"
"g;x=1/../y" = "http://a/b/c/y"
Some applications fail to split the reference's query and/or fragment components off from the path component before merging it with the base path and removing dot-segments. This slip rarely gets noticed, since a fragment usually never includes a "/" hierarchy character, and the query component is not normally used in relative references.
"g?y/./x" = "http://a/b/c/g?y/./x"
"g?y/../x" = "http://a/b/c/g?y/../x"
"g#s/./x" = "http://a/b/c/g#s/./x"
"g#s/../x" = "http://a/b/c/g#s/../x"
Some parsers let the scheme name show up in a relative reference when it matches the base URI scheme. This is seen as a loophole in earlier specifications of partial URI [RFC1630]. Its use should be avoided, but it's allowed for backward compatibility ๐ซถ
"http:g" = "http:g" ; for strict parsers
/ "http://a/b/c/g" ; for backward compatibility
6. Normalization and Comparison ๐
One of the most common things anyone does with URIs is compare them, figuring out whether two are equivalent without using either one to access its resource. That happens every time a response cache gets accessed, when a browser checks its history to color a link, and when an XML parser handles tags in a namespace. Spiders and indexing engines often do heavy normalization before comparing, to trim down a search space or cut back on duplicate requests and stored responses ๐ฅ
URI comparison always serves some particular purpose. Protocols and implementations that compare URIs for different purposes will often face different design trade-offs about how much effort to spend on reducing aliased identifiers. This section covers the various comparison methods, the trade-offs between them, and the kinds of applications that might use each one โจ
6.1. Equivalence ๐ฆ
URIs exist to identify resources, so it seems like they should count as equivalent whenever they identify the same resource. The catch is that this definition isn't very practical, since an implementation can't compare two resources unless it has full knowledge or control of them. So equivalence and difference between URIs are decided by string comparison, maybe with extra rules from URI scheme definitions. We use the terms "different" and "equivalent" for the possible outcomes of those comparisons, though there are plenty of application-dependent versions of equivalence ๐
Even when you can tell two URIs are equivalent, URI comparison alone isn't enough to prove that two URIs identify different resources. For example, one owner of two different domain names could decide to serve the same resource from both, which gives you two different URIs for one resource. That's why comparison methods are designed to minimize false negatives while strictly avoiding false positives ๐
When testing for equivalence, applications should not directly compare relative references. Convert the references to their respective target URIs first, then compare those. When URIs get compared to decide whether to take a network action, such as retrieving a representation, fragment components (if any) should be left out of the comparison ๐
6.2. Comparison Ladder ๐ช
okay so there's a whole bunch of ways people check whether two URIs are equivalent, and they live on a range ๐ what separates them is how much processing they need and how much they reduce the chance of false negatives. like we said before, false negatives can't be eliminated ๐ญ they can be reduced, but that takes more processing and isn't cost-effective for every app.
so think of it like a ladder ๐ง we're gonna climb it together, starting with the cheap stuff that's more likely to give false negatives, and working up to the methods that cost more compute but have a lower risk of false negatives ๐ซถ
6.2.1. Simple String Comparison ๐
if two URIs are identical as character strings, then it's safe to conclude they're equivalent โจ this is super low computational cost and it's in wide use everywhere, especially in parsing land ๐
testing strings for equivalence still needs some basic precautions ๐ people call it "bit-for-bit" or "byte-for-byte" comparison, which is kinda misleading, ngl. testing equality is normally pair comparison of the characters that make up the strings. you start from the first character and keep going until both strings are fully exhausted and every character matched, or until a pair compares unequal, or until one string runs out before the other.
this character comparison needs each pair of characters to be put in comparable form ๐ for example, if one URI is stored in a byte array in EBCDIC encoding and the second is in a Java String object (UTF-16), bit-for-bit comparisons applied naively will produce errors ๐ it's better to talk about equality on a character-for-character basis rather than byte-for-byte or bit-for-bit. in practical terms, character-by-character comparisons should be done codepoint-by-codepoint after conversion to a common character encoding.
false negatives are caused by the production and use of URI aliases ๐ฆ unnecessary aliases can be reduced, regardless of the comparison method, by consistently providing URI references in an already-normalized form (i.e., a form identical to what would be produced after normalization is applied, as described below).
protocols and data formats often limit some URI comparisons to simple string comparison ๐ธ the theory is that people and implementations will, in their own best interest, be consistent in providing URI references, or at least consistent enough to cancel out any efficiency you'd get from further normalization. it's giving trust the process ๐
6.2.2. Syntax-Based Normalization ๐
implementations may use logic based on the definitions in this specification to reduce the probability of false negatives. it's moderately higher in cost than character-for-character string comparison. for example, an application using this approach could reasonably consider the following two URIs equivalent:
example://a/b/c/%7Bfoo%7D
eXAMPLE://a/./b/../b/%63/%7bfoo%7d
web user agents, like browsers, typically apply this type of URI normalization when deciding whether a cached response is available ๐ syntax-based normalization includes techniques like case normalization, percent-encoding normalization, and removal of dot-segments. main character energy โจ
6.2.2.1. Case Normalization ๐
for all URIs, the hexadecimal digits within a percent-encoding triplet (e.g., "%3a" versus "%3A") are case-insensitive and therefore should be normalized to use uppercase letters for the digits A-F.
when a URI uses components of the generic syntax, the component syntax equivalence rules always apply ๐
namely, the scheme and host are case-insensitive and therefore should be normalized to lowercase. for example, <HTTP://www.EXAMPLE.com/> is equivalent to <http://www.example.com/>. the other generic syntax components are assumed to be case-sensitive unless specifically defined otherwise by the scheme (see Section 6.2.3). ๐ซถ
6.2.2.2. Percent-Encoding Normalization ๐ง
the percent-encoding mechanism (Section 2.1) is a frequent source of variance among otherwise identical URIs ๐ญ on top of the case normalization issue we just talked about, some URI producers percent-encode octets that don't need it, which gives URIs that are equivalent to their non-encoded counterparts. these should be normalized by decoding any percent-encoded octet that corresponds to an unreserved character, as described in Section 2.3. iykyk ๐
6.2.2.3. Path Segment Normalization ๐ฃ๏ธ
the complete path segments "." and ".." are intended only for use within relative references (Section 4.1). they get removed as part of the reference resolution process (Section 5.2). but some deployed implementations incorrectly assume reference resolution isn't necessary when the reference is already a URI, so they fail to remove dot-segments when they show up in non-relative paths ๐ URI normalizers should remove dot-segments by applying the remove_dot_segments algorithm to the path, as described in Section 5.2.4. no more dot-segments being sus ๐
โโ๏ธ
6.2.3. Scheme-Based Normalization ๐ท
the syntax and semantics of URIs vary from scheme to scheme, as described by the defining specification for each scheme ๐ implementations may use scheme-specific rules, at further processing cost, to reduce the probability of false negatives. for example, because the "http" scheme uses an authority component, has a default port of "80", and defines an empty path to be equivalent to "/", these four URIs are equivalent:
http://example.com
http://example.com/
http://example.com:/
http://example.com:80/
in general, a URI that uses the generic syntax for authority with an empty path should be normalized to a path of "/". likewise, an explicit ":port", where the port is empty or the default for the scheme, is equivalent to one where the port and its ":" delimiter are elided. so it should be removed by scheme-based normalization. the second URI above is the normal form for the "http" scheme ๐
another case where normalization varies by scheme is handling an empty authority component or empty host subcomponent. for lots of scheme specs, an empty authority or host is considered an error. for others, it's considered equivalent to "localhost" or the end-user's host ๐คทโโ๏ธ when a scheme defines a default for authority and you want a URI reference to that default, the reference should be normalized to an empty authority for the sake of uniformity, brevity, and internationalization. but if either the userinfo or port subcomponents are non-empty, then the host should be given explicitly, even if it matches the default ๐
normalization should not remove delimiters when their associated component is empty, unless the scheme specification says it's licensed to do so ๐ for example, the URI http://example.com/? can't be assumed to be equivalent to any of the examples above. likewise, the presence or absence of delimiters within a userinfo subcomponent is usually significant to its interpretation. the fragment component isn't subject to any scheme-based normalization, so two URIs that differ only by the suffix # are considered different regardless of the scheme ๐ซ
some schemes define additional subcomponents that consist of case-insensitive data, which gives normalizers an implicit license to convert that data to a common case (e.g., all lowercase) ๐ก for example, URI schemes that define a subcomponent of path to contain an Internet hostname, like the "mailto" URI scheme, make that subcomponent case-insensitive and thus subject to case normalization. so mailto:Joe@Example.COM is equivalent to mailto:Joe@example.com, even though the generic syntax considers the path component to be case-sensitive ๐ฆ
other scheme-specific normalizations are possible โจ
6.2.4. Protocol-Based Normalization ๐ท๏ธ
substantial effort to reduce the incidence of false negatives is often cost-effective for web spiders ๐ธ๏ธ so they implement even more aggressive techniques in URI comparison. for example, if they observe that a URI such as
http://example.com/data
redirects to a URI that differs only in the trailing slash, like
http://example.com/data/
they will likely regard the two as equivalent in the future ๐ this kind of technique is only appropriate when equivalence is clearly indicated by both the result of accessing the resources and the common conventions of their scheme's dereference algorithm. in this case, that's HTTP origin servers using redirection to avoid problems with relative references. spiders being smart, tbh ๐
7. Security Considerations ๐จ
a URI does not in itself pose a security threat ๐ however, as URIs are often used to provide a compact set of instructions for access to network resources, care must be taken to properly interpret the data within a URI, to prevent that data from causing unintended access, and to avoid including data that should not be revealed in plain text. this part is literally serious, bestie ๐๐
7.1. Reliability and Consistency ๐ซง
there is no guarantee that once a URI has been used to retrieve information, the same information will be retrievable by that URI in the future ๐ญ nor is there any guarantee that the information retrievable via that URI in the future will be observably similar to what was retrieved in the past. the URI syntax doesn't constrain how a given scheme or authority divides up its namespace or maintains it over time. guarantees like that can only come from the person(s) controlling that namespace and the resource in question. a specific URI scheme may define additional semantics, such as name persistence, if those semantics are required of all naming authorities for that scheme ๐
7.2. Malicious Construction ๐
okay so this one is kinda sneaky bestie ๐ต๏ธโโ๏ธ sometimes you can build a URI so that something that looks totally harmless and idempotent, like just fetching a representation, actually triggers a possibly damaging remote operation ๐ the usual trick is picking a port number that isn't the one reserved for the protocol you think you're talking to. the client unknowingly connects to a server running a different protocol, and the data in the URI is full of instructions that do something unexpected once that other protocol reads them. a classic example is a protocol-based scheme with port 25, which tricks user agent software into sending an unintended or impersonating message through an SMTP server ๐ง not it!!
applications should stop dereferencing a URI that names a TCP port in the "well-known port" range (0 - 1023) unless the protocol doing the dereferencing matches the one expected on that port ๐ IANA keeps a registry of well-known ports, but applications should make these restrictions user-configurable so they don't block brand-new services from getting deployed ๐ฑ flexibility is everything, periodt โจ
and when a URI has percent-encoded octets that match the delimiters of a resolution or dereference protocol (like CR and LF for TELNET), those percent-encodings must not be decoded before they get sent over that protocol ๐ yes, sending the encoding through might technically break the protocol, but that's way less harmful than letting decoded octets get read as extra operations or parameters and setting off something unexpected and possibly harmful ๐
7.3. Back-End Transcoding ๐ง
so when a URI gets dereferenced, the data inside it is usually parsed by both the user agent and one or more servers ๐ in HTTP, for example, a typical user agent splits the URI into its five major components, connects to the authority's server, and sends it the data from the authority, path, and query components ๐ฆ then the server takes that info, breaks the path into segments and the query into key/value pairs, and calls implementation-specific handlers to respond. the big concern for servers handling a URI (whole or split up) is getting the octet data behind the characters and percent-encodings right ๐ very important, no cap
percent-encoded octets must be decoded at some point during dereferencing ๐
applications must split the URI into its components and subcomponents before decoding, otherwise the decoded octets could get mistaken for delimiters ๐จ security checks on the data in a URI should happen after decoding. one tiny note though: the %00 (NUL) percent-encoding may need special handling and should be rejected if the application isn't expecting raw data inside a component ๐
โโ๏ธ
special care is needed when the path interpretation involves a back-end file system or related system functions ๐ file systems usually give special characters a meaning of their own, like /, \, :, [, and ], plus special device names such as ., .., ..., aux, lpt, and so on ๐ป sometimes just checking whether one of those names exists makes the operating system pause or fire off unrelated system calls, which opens the door to denial of service and unintended data transfer ๐ฑ this spec can't list every single one of these characters and device names, so implementers should look up the reserved names and characters for whatever storage devices their applications might touch and restrict how data from URI components gets used accordingly ๐ซถ
7.4. Rare IP Address Formats ๐ข
so the URI syntax for IPv4address only allows the common dotted-decimal form of an IPv4 address literal ๐ but lots of implementations that process URIs lean on platform-dependent system routines, like gethostbyname() and inet_aton(), to turn the string into a real IP address ๐คฏ and those routines often accept a way bigger set of formats than what's described in Section 3.2.2, which is kinda chaotic ngl
for example, many implementations allow dotted forms of three numbers, where the last part is read as a 16-bit quantity and placed in the right-most two bytes of the network address (like a Class B network) ๐ a dotted form of two numbers means the last part is read as a 24-bit quantity placed in the right-most three bytes (Class A), and a single number with no dots is read as a 32-bit quantity and stored directly in the network address ๐งฎ it gets even more confusing because some implementations let each dotted part be read as decimal, octal, or hexadecimal, following C rules: a leading 0x or 0X means hexadecimal, a leading 0 means octal, and anything else is decimal ๐
none of these extra formats are allowed in URI syntax, because they differ between platforms ๐ซ but they can become a security issue if an application tries to filter access to resources based on an IP address in string literal form ๐ก๏ธ if you do filter like that, literals should be converted to numeric form and filtered on their numeric value, not on a prefix or suffix of the string ๐
7.5. Sensitive Information ๐คซ
URI producers should not hand out a URI containing a username or password that's meant to stay secret ๐ URIs get displayed by browsers, saved in plain-text bookmarks, and logged in user agent history and by intermediary applications (proxies), so they're basically everywhere ๐ a password showing up in the userinfo component is deprecated and should be treated as an error (or just ignored), except in those rare cases where the 'password' parameter is actually meant to be public ๐
7.6. Semantic Attacks ๐ญ
the userinfo subcomponent is rarely used and comes before the host in the authority component ๐ซฃ that means someone can build a URI that looks like it identifies a trusted naming authority while it's actually pointing to a different authority hiding behind all the noise ๐ฅธ for example:
ftp://cnn.example.com&story=breaking_news@10.0.0.1/top_story.htm
a human might assume the host is 'cnn.example.com', but it's actually '10.0.0.1' ๐ญ and a misleading userinfo subcomponent can be way longer than that example, so be warned
a misleading URI like that is an attack on the user's assumptions about what a URI means, not an attack on the software itself ๐ง user agents might reduce the impact by showing the different components of the URI in distinct ways when rendering, like using a different color or tone for userinfo when it's present ๐ธ but there's no panacea, sadly ๐ more info on URI-based semantic attacks can be found in [Siedzik] ๐
8. IANA Considerations ๐๏ธ
URI scheme names, as defined by <scheme> in Section 3.1, form a registered namespace managed by IANA under the procedures defined in [BCP35] โจ no IANA actions are required by this document, so we're all good on that front ๐
9. Acknowledgements ๐ซถ
this spec is derived from RFC 2396 [RFC2396], RFC 1808 [RFC1808], and RFC 1738 [RFC1738], and the acknowledgements in those documents still apply ๐ท it also brings in the update (with corrections) for IPv6 literals in the host syntax, as defined by Robert M. Hinden, Brian E. Carpenter, and Larry Masinter in [RFC2732] ๐ huge thanks as well to Gisle Aas, Reese Anschultz, Daniel Barclay, Tim Bray, Mike Brown, Rob Cameron, Jeremy Carroll, Dan Connolly, Adam M. Costello, John Cowan, Jason Diamond, Martin Duerst, Stefan Eissing, Clive D.W. Feather, Al Gilman, Tony Hammond, Elliotte Harold, Pat Hayes, Henry Holtzman, Ian B. Jacobs, Michael Kay, John C. Klensin, Graham Klyne, Dan Kohn, Bruce Lilly, Andrew Main, Dave McAlpin, Ira McDonald, Michael Mealling, Ray Merkert, Stephen Pollei, Julian Reschke, Tomas Rokicki, Miles Sabin, Kai Schaetzl, Mark Thomson, Ronald Tschalaer, Norm Walsh, Marc Warne, Stuart Williams, and Henry Zongaro ๐ gratefully acknowledged, every single one of them ๐
10. References ๐
10.1. Normative References
[ASCII] American National Standards Institute, "Coded Character
Set -- 7-bit American Standard Code for Information
Interchange", ANSI X3.4, 1986.
[RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
Specifications: ABNF", RFC 2234, November 1997.
[STD63] Yergeau, F., "UTF-8, a transformation format of
ISO 10646", STD 63, RFC 3629, November 2003.
[UCS] International Organization for Standardization,
"Information Technology - Universal Multiple-Octet Coded
Character Set (UCS)", ISO/IEC 10646:2003, December 2003.
10.2. Informative References โจ
okay so this is the "for further reading" pile ๐ these are informative, not normative, which means you don't need them to implement the URI syntax, but they're the whole backstory bestie ๐
- [BCP19] Freed, N. and J. Postel, "IANA Charset Registration Procedures", BCP 19, RFC 2978, October 2000.
- [BCP35] Petke, R. and I. King, "Registration Procedures for URL Scheme Names", BCP 35, RFC 2717, November 1999.
- [RFC0952] Harrenstien, K., Stahl, M., and E. Feinler, "DoD Internet host table specification", RFC 952, October 1985.
- [RFC1034] Mockapetris, P., "Domain names - concepts and facilities", STD 13, RFC 1034, November 1987.
- [RFC1123] Braden, R., "Requirements for Internet Hosts - Application and Support", STD 3, RFC 1123, October 1989.
- [RFC1535] Gavron, E., "A Security Problem and Proposed Correction With Widely Deployed DNS Software", RFC 1535, October 1993.
- [RFC1630] Berners-Lee, T., "Universal Resource Identifiers in WWW: A Unifying Syntax for the Expression of Names and Addresses of Objects on the Network as used in the World-Wide Web", RFC 1630, June 1994.
- [RFC1736] Kunze, J., "Functional Recommendations for Internet Resource Locators", RFC 1736, February 1995.
- [RFC1737] Sollins, K. and L. Masinter, "Functional Requirements for Uniform Resource Names", RFC 1737, December 1994.
- [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform Resource Locators (URL)", RFC 1738, December 1994.
- [RFC1808] Fielding, R., "Relative Uniform Resource Locators", RFC 1808, June 1995.
- [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, November 1996.
- [RFC2141] Moats, R., "URN Syntax", RFC 2141, May 1997.
- [RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.
- [RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter, S., and D. Jensen, "HTTP Extensions for Distributed Authoring -- WEBDAV", RFC 2518, February 1999.
- [RFC2557] Palme, J., Hopmann, A., and N. Shelness, "MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)", RFC 2557, March 1999.
- [RFC2718] Masinter, L., Alvestrand, H., Zigmond, D., and R. Petke, "Guidelines for new URL Schemes", RFC 2718, November 1999.
- [RFC2732] Hinden, R., Carpenter, B., and L. Masinter, "Format for Literal IPv6 Addresses in URL's", RFC 2732, December 1999.
- [RFC3305] Mealling, M. and R. Denenberg, "Report from the Joint W3C/IETF URI Planning Interest Group: Uniform Resource Identifiers (URIs), URLs, and Uniform Resource Names (URNs): Clarifications and Recommendations", RFC 3305, August 2002.
- [RFC3490] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.
- [RFC3513] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.
- [Siedzik] Siedzik, R., "Semantic Attacks: What's in a URL?", April 2001, <http://www.giac.org/practical/gsec/Richard_Siedzik_GSEC.pdf>.
Appendix A. Collected ABNF for URI ๐
okay this is the whole grammar in one place ๐งฉ every URI you'll ever meet gets built from these rules, so it's giving reference card energy
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
URI-reference = URI / relative-ref
absolute-URI = scheme ":" hier-part [ "?" query ]
relative-ref = relative-part [ "?" query ] [ "#" fragment ]
relative-part = "//" authority path-abempty
/ path-absolute
/ path-noscheme
/ path-empty
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
authority = [ userinfo "@" ] host [ ":" port ]
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
host = IP-literal / IPv4address / reg-name
port = *DIGIT
IP-literal = "[" ( IPv6address / IPvFuture ) "]"
IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
IPv6address = 6( h16 ":" ) ls32
/ "::" 5( h16 ":" ) ls32
/ [ h16 ] "::" 4( h16 ":" ) ls32
/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
/ [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
/ [ *4( h16 ":" ) h16 ] "::" ls32
/ [ *5( h16 ":" ) h16 ] "::" h16
/ [ *6( h16 ":" ) h16 ] "::"
h16 = 1*4HEXDIG
ls32 = ( h16 ":" h16 ) / IPv4address
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
dec-octet = DIGIT ; 0-9
/ %x31-39 DIGIT ; 10-99
/ "1" 2DIGIT ; 100-199
/ "2" %x30-34 DIGIT ; 200-249
/ "25" %x30-35 ; 250-255
reg-name = *( unreserved / pct-encoded / sub-delims )
path = path-abempty ; begins with "/" or is empty
/ path-absolute ; begins with "/" but not "//"
/ path-noscheme ; begins with a non-colon segment
/ path-rootless ; begins with a segment
/ path-empty ; zero characters
path-abempty = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )
path-empty = 0<pchar>
segment = *pchar
segment-nz = 1*pchar
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
; non-zero-length segment without any colon ":"
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
query = *( pchar / "/" / "?" )
fragment = *( pchar / "/" / "?" )
pct-encoded = "%" HEXDIG HEXDIG
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
Appendix B. Parsing a URI Reference with a Regular Expression ๐ง
the "first-match-wins" rule is basically the same thing as the "greedy" disambiguation that POSIX regular expressions use ๐คฏ so it's totally natural to just reach for a regex to split a URI reference into its five parts
here's the regex for breaking a well-formed URI reference into its components:
^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
12 3 4 5 6 7 8 9
those numbers on the second line are only there to help you read it ๐ they mark the reference points for each subexpression (each pair of parentheses). we call the value matched for subexpression <n> $<n>. for example, matching the expression above against
http://www.ics.uci.edu/pub/ietf/uri/#Related
gives these subexpression matches:
$1 = http:
$2 = http
$3 = //www.ics.uci.edu
$4 = www.ics.uci.edu
$5 = /pub/ietf/uri/
$6 = <undefined>
$7 = <undefined>
$8 = #Related
$9 = Related
where <undefined> just means that part isn't there, like the query in that example ๐ซถ so the five components work out to:
scheme = $2
authority = $4
path = $5
query = $7
fragment = $9
and going the other way, you can rebuild a URI reference from its components using the algorithm in Section 5.3 ๐
Appendix C. Delimiting a URI in Context ๐
URIs get passed around in formats that don't give them any clear context, and that's a whole mess ๐ญ like when they show up in plain text in email, USENET news, or printed on paper. so you need a way to pull the URI out of the surrounding text, especially from punctuation that could get mistaken for part of it.
in practice people wrap URIs in a bunch of different ways, but usually it's double-quotes like "http://example.com/", angle brackets like <http://example.com/>, or just whitespace:
http://example.com/
those wrappers are NOT part of the URI, so don't keep them ๐ โโ๏ธ
sometimes you need extra whitespace (spaces, line-breaks, tabs, etc.) to break a long URI across lines. that whitespace should be ignored when you extract the URI.
no whitespace should be introduced after a hyphen ("-") character. some typesetters and printers might (erroneously) add a hyphen at the end of a line when they break it, so if you're the interpreter and you find a URI with a line break right after a hyphen, ignore all the whitespace around that break and remember the hyphen may or may not actually be part of the URI ๐ง it's a trap, bestie ๐ชค
using <> angle brackets around each URI is especially recommended as a delimiting style when the reference has embedded whitespace ๐
the prefix "URL:" (with or without a trailing space) used to be recommended as a way to tell a URI apart from other bracketed designators ๐ฐ๏ธ it's not really used much anymore and it's no longer recommended, so we're retiring it ๐ฅ
for robustness, software that accepts a user-typed URI should attempt to recognize and strip both kinds of delimiters and any embedded whitespace โจ
here's an example. the text
Yes, Jim, I found it under "http://www.w3.org/Addressing/",
but you can probably pick it up from <ftp://foo.example.
com/rfc/>. Note the warning in <http://www.ics.uci.edu/pub/
ietf/uri/historical.html#WARNING>.
contains these URI references:
http://www.w3.org/Addressing/
ftp://foo.example.com/rfc/
http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING
Appendix D. Changes from RFC 2396 ๐ฆ
this is the glow-up log, aka everything that changed since RFC 2396 ๐
D.1. Additions
we added an ABNF rule for URI to match one common meaning of the term: an absolute URI with an optional fragment ๐
IPv6 (and later) literals are now allowed as the host part of an authority component, as described by [RFC2732] ๐ to make that work, "[" and "]" joined the reserved set, and there's a version flag to make room for future IP literal versions. square brackets are now reserved within the authority component and aren't allowed anywhere else except as the delimiters around an IP literal inside host. to do all this without changing what path, query, and fragment technically mean, those rules got rewritten to spell out exactly which characters are allowed ๐ง
[RFC2732] defers to [RFC3513] for the definition of an IPv6 literal address, but [RFC3513] unfortunately doesn't have an ABNF description of IPv6address ๐ so we made a new ABNF rule for IPv6address that matches the text representations defined by Section 2.2 of [RFC3513]. the definition of IPv4address also got a level-up, limiting each decimal octet to the range 0-255 โ
Section 6, on URI normalization and comparison, has been completely rewritten and extended, using input from Tim Bray and discussion within the W3C Technical Architecture Group ๐ main character glow-up, periodt ๐
D.2. Modifications ๐
Okay so the ad-hoc BNF from RFC 2396 got a total glow-up and is now ABNF from [RFC2234] โจ. That meant every rule name with an underscore had to switch to a dash instead ๐ฆ. A bunch of syntax rules also got deleted or simplified so the whole grammar is way easier to read ๐ซถ. If a spec still refers to the old obsolete rules, you can swap them out using this table:
+----------------+--------------------------------------------------+
| obsolete rule | translation |
+----------------+--------------------------------------------------+
| absoluteURI | absolute-URI |
| relativeURI | relative-part [ "?" query ] |
| hier_part | ( "//" authority path-abempty / |
| | path-absolute ) [ "?" query ] |
| | |
| opaque_part | path-rootless [ "?" query ] |
| net_path | "//" authority path-abempty |
| abs_path | path-absolute |
| rel_path | path-rootless |
| rel_segment | segment-nz-nc |
| reg_name | reg-name |
| server | authority |
| hostport | host [ ":" port ] |
| hostname | reg-name |
| path_segments | path-abempty |
| param | *<pchar excluding ";"> |
| | |
| uric | unreserved / pct-encoded / ";" / "?" / ":" |
| | / "@" / "&" / "=" / "+" / "$" / "," / "/" |
| | |
| uric_no_slash | unreserved / pct-encoded / ";" / "?" / ":" |
| | / "@" / "&" / "=" / "+" / "$" / "," |
| | |
| mark | "-" / "_" / "." / "!" / "~" / "*" / "'" |
| | / "(" / ")" |
| | |
| escaped | pct-encoded |
| hex | HEXDIG |
| alphanum | ALPHA / DIGIT |
+----------------+--------------------------------------------------+
<rose>Using the above obsolete rules to define scheme-specific syntax is deprecated.</rose> ๐
Section 2 got rewritten too, and it's so much clearer now ๐ธ. It explains which characters are reserved, when they're reserved, and why they're reserved, even when they aren't used as delimiters by the generic syntax ๐ง. The mark characters that are typically unsafe to decode, like the exclamation mark ("!"), asterisk ("*"), single-quote ("'"), and open and close parentheses ("(" and ")"), got moved into the reserved set ๐. This clears up the difference between reserved and unreserved and, hopefully, answers the most common question scheme designers have ๐. The percent-encoded section also got rewritten, and URI normalizers are now allowed to decode any percent-encoded octets that match unreserved characters ๐. Overall, the terms "escaped" and "unescaped" were swapped for "percent-encoded" and "decoded" so nobody mixes them up with other escape mechanisms ๐ .
The ABNF for URI and URI-reference got redesigned to be friendlier to LALR parsers and way less complicated ๐ฆ. Because of that, the layout form of syntax description was removed, along with the uric, uric_no_slash, opaque_part, net_path, abs_path, rel_path, path_segments, rel_segment, and mark rules ๐. All the references to "opaque" URIs were replaced with a better explanation of how the path component can be opaque to hierarchy โจ. The relativeURI rule was replaced with relative-ref so nobody gets confused about whether it's a subset of URI ๐ซถ. The ambiguity about parsing URI-reference as either a URI or a relative-ref with a colon in the first segment is gone, thanks to five separate path matching rules ๐ฅ.
The fragment identifier moved back into the section on generic syntax components, and it lives in the URI and relative-ref rules now ๐. It's still excluded from absolute-URI though ๐. The number sign ("#") also went back into the reserved set because the fragment syntax got reintegrated ๐.
The ABNF got corrected so the path component can be empty โญ. This means an absolute-URI can consist of nothing after the "scheme:", which is actually how it shows up in the real world with the dav: namespace [RFC2518] and the about: scheme that lots of WWW browsers use internally ๐. The ambiguity about where the authority ends and the path begins is gone too, thanks to five separate path matching rules ๐.
Registry-based naming authorities that use the generic syntax are now defined inside the host rule ๐ง. This matches what current implementations already do, where whatever name you give gets fed straight to the local name resolution mechanism, so the spec and reality finally agree โจ. It also means we don't have to re-specify DNS name formats here ๐ . The host component can now contain percent-encoded octets too, which is what lets internationalized domain names show up in URIs ๐ธ. They get processed in their native character encodings at the application layers above URI processing and then passed to an IDNA library as a registered name in the UTF-8 character encoding ๐ฆ. The server, hostport, hostname, domainlabel, toplabel, and alphanum rules were removed ๐ซถ.
The resolving relative references algorithm from [RFC2396] got rewritten with pseudocode for this revision ๐. It's clearer now and fixes these issues ๐ฅ:
- [RFC2396] section 5.2, step 6a, failed to account for a base URI with no path.
- Restored the behavior of [RFC1808] where, if the reference contains an empty path and a defined query component, the target URI inherits the base URI's path component.
- The determination of whether a URI reference is a same-document reference has been decoupled from the URI parser ๐. This makes the URI processing interface within applications simpler and matches how deployed URI processing implementations are built internally ๐ง. The determination is now based on comparing against the base URI after transforming a reference into absolute form, rather than on the format of the reference itself โจ. This might make more references count as "same-document" under this specification than under the rules in RFC 2396, especially when normalization is used to reduce aliases ๐. It does not change the status of existing same-document references, though ๐.
- The path merge routine got split into two routines ๐: merge, which describes combining the base URI path with a relative-path reference, and remove_dot_segments, which describes how to remove the special "." and ".." segments from a composed path ๐ . The remove_dot_segments algorithm now applies to all URI reference paths to match common implementations and improve URI normalization in practice ๐ธ. This only changes the parsing of abnormal references and same-scheme references where the base URI has a non-hierarchical path ๐ฆ.
Index ๐๏ธ
A
ABNF 11
absolute 27
absolute-path 26
absolute-URI 27
access 9
authority 17, 18
B
base URI 28
C
character encoding 4
character 4
characters 8, 11
coded character set 4
D
dec-octet 20
dereference 9
dot-segments 23
F
fragment 16, 24
G
gen-delims 13
generic syntax 6
H
h16 20
hier-part 16
hierarchical 10
host 18
I
identifier 5
IP-literal 19
IPv4 20
IPv4address 19, 20
IPv6 19
IPv6address 19, 20
IPvFuture 19
L
locator 7
ls32 20
M
merge 32
N
name 7
network-path 26
P
path 16, 22, 26
path-abempty 22
path-absolute 22
path-empty 22
path-noscheme 22
path-rootless 22
path-abempty 16, 22, 26
path-absolute 16, 22, 26
path-empty 16, 22, 26
path-rootless 16, 22
pchar 23
pct-encoded 12
percent-encoding 12
port 22
Q
query 16, 23
R
reg-name 21
registered name 20
relative 10, 28
relative-path 26
relative-ref 26
remove_dot_segments 33
representation 9
reserved 12
resolution 9, 28
resource 5
retrieval 9
S
same-document 27
sameness 9
scheme 16, 17
segment 22, 23
segment-nz 23
segment-nz-nc 23
sub-delims 13
suffix 27
T
transcription 8
U
uniform 4
unreserved 13
URI grammar
absolute-URI 27
ALPHA 11
authority 18
CR 11
dec-octet 20
DIGIT 11
DQUOTE 11
fragment 24
gen-delims 13
h16 20
HEXDIG 11
hier-part 16
host 19
IP-literal 19
IPv4address 20
IPv6address 20
IPvFuture 19
LF 11
ls32 20
OCTET 11
path 22
path-abempty 22
path-absolute 22
path-empty 22
path-noscheme 22
path-rootless 22
pchar 23
pct-encoded 12
port 22
query 24
reg-name 21
relative-ref 26
reserved 13
scheme 17
segment 23
segment-nz 23
segment-nz-nc 23
SP 11
sub-delims 13
unreserved 13
URI 16
URI-reference 25
userinfo 18
URI 16
URI-reference 25
URL 7
URN 7
userinfo 18
Authors' Addresses ๐
Tim Berners-Lee
World Wide Web Consortium
Massachusetts Institute of Technology
77 Massachusetts Avenue
Cambridge, MA 02139
USA
Phone: +1-617-253-5702
Fax: +1-617-258-5999
EMail: timbl@w3.org
URI: http://www.w3.org/People/Berners-Lee/
Roy T. Fielding
Day Software
5251 California Ave., Suite 110
Irvine, CA 92617
USA
Phone: +1-949-679-2960
Fax: +1-949-679-2972
EMail: fielding@gbiv.com
URI: http://roy.gbiv.com/
Larry Masinter
Adobe Systems Incorporated
345 Park Ave
San Jose, CA 95110
USA
Phone: +1-408-536-3024
EMail: LMM@acm.org
URI: http://larry.masinter.net/
Full Copyright Statement โจ
Okay bestie, legal stuff time ๐ Copyright is held by The Internet Society (2005). This document is subject to the rights, licenses and restrictions in BCP 78, and except as set forth there, the authors keep all their rights ๐
The document and the info in it are provided on an "AS IS" basis, and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. So no guarantees, no cap ๐
Intellectual Property
Okay, IP rights ๐ฆ The IETF doesn't take a position on whether any Intellectual Property Rights (or other rights) that someone claims about the tech in this doc are valid, how far they reach, or whether a license is even available. It also doesn't say it went hunting for any of them ๐ If you want the IETF's rules on rights in IETF Documents, check out BCP 78 and BCP 79 ๐ธ
Copies of IPR disclosures sent to the IETF Secretariat, plus any assurances of licenses, or the results of trying to get a general license or permission for implementers or users, can be found in the IETF's online IPR repository at http://www.ietf.org/ipr ๐ฅ
And if you know about any copyrights, patents, patent applications, or other proprietary rights that might cover tech needed to implement this standard, the IETF wants to hear about it! Send it to ietf-ipr@ietf.org ๐
Acknowledgement
Shoutout to the people keeping the lights on: funding for the RFC Editor function is currently provided by the Internet Society ๐๐ซถ
๐ฆ where this page comes from
- ietf: rfc3986 2005-01
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms