Quais caracteres tornam um URL inválido?
Esses URLs são válidos?
example.com/file[/].html
http://example.com/file[/].html
Quais caracteres tornam um URL inválido?
Esses URLs são válidos?
example.com/file[/].html
http://example.com/file[/].html
Respostas:
Em geral, os URIs, conforme definidos pela RFC 3986 (consulte a Seção 2: Caracteres ), podem conter qualquer um dos 84 caracteres a seguir:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=
Observe que esta lista não indica onde esses caracteres podem ocorrer no URI.
Qualquer outro caractere precisa ser codificado com a porcentagem de codificação ( %
hh
). Cada parte do URI possui restrições adicionais sobre quais caracteres precisam ser representados por uma palavra codificada em porcentagem.
/^([!#$&-;=?-[]_a-z~]|%[0-9a-fA-F]{2})+$/
Havia mais alguma coisa que você achou que deveria estar aceitando? (Só para ficar claro, que regex apenas verifica se a cadeia contém caracteres de URL válidos, não se a cadeia contém uma URL bem formado.)
Para adicionar alguns esclarecimentos e abordar diretamente a pergunta acima, existem várias classes de caracteres que causam problemas para URLs e URIs.
Existem alguns caracteres que não são permitidos e nunca devem aparecer em um URL / URI, caracteres reservados (descritos abaixo) e outros que podem causar problemas em alguns casos, mas que estão marcados como "imprudentes" ou "não seguros". As explicações sobre por que os caracteres são restritos estão claramente descritas no RFC-1738 (URLs) e no RFC-2396 (URIs). Observe que o RFC-3986 mais recente (atualização para o RFC-1738) define a construção de quais caracteres são permitidos em um determinado contexto, mas as especificações mais antigas oferecem uma descrição mais simples e mais geral de quais caracteres não são permitidos com as regras a seguir.
Caracteres US-ASCII excluídos não permitidos na sintaxe do URI:
control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
space = <US-ASCII coded character 20 hexadecimal>
delims = "<" | ">" | "#" | "%" | <">
O caractere "#" é excluído porque é usado para delimitar um URI de um identificador de fragmento. O caractere de porcentagem "%" é excluído porque é usado para a codificação de caracteres de escape. Em outras palavras, "#" e "%" são caracteres reservados que devem ser usados em um contexto específico.
A lista de caracteres imprudentes é permitida, mas pode causar problemas:
unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
Caracteres reservados em um componente de consulta e / ou com significado especial em um URI / URL:
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
A classe de sintaxe "reservada" acima se refere aos caracteres permitidos em um URI, mas que podem não ser permitidos em um componente específico da sintaxe genérica de URI. Os caracteres no conjunto "reservado" não são reservados em todos os contextos . O nome do host, por exemplo, pode conter um nome de usuário opcional, podendo ser algo como ftp://user@hostname/
onde o caractere '@' tem um significado especial.
Aqui está um exemplo de um URL que possui caracteres inválidos e imprudentes (por exemplo, '$', '[', ']') e deve ser codificado corretamente:
http://mw1.google.com/mw-earth-vectordb/kml-samples/gp/seattle/gigapxl/$[level]/r$[y]_c$[x].jpg
Algumas das restrições de caracteres para URIs / URLs dependem da linguagem de programação. Por exemplo, o '|' O caractere (0x7C), embora marcado apenas como "imprudente" na especificação do URI, lançará uma URISyntaxException no construtor Java java.net.URI, portanto, um URL como http://api.google.com/q?exp=a|b
não é permitido e deve ser codificado como http://api.google.com/q?exp=a%7Cb
se estivesse usando Java com uma instância de objeto URI.
?
é muito bom na seção de consulta, mas impossível antes dela, e acho que não @
pertence a nenhuma dessas listas. Ah, e em vez de %25
na última corda, você não quer dizer %7C
?
A maioria das respostas existentes aqui é impraticável porque ignora totalmente o uso no mundo real de endereços como:
Primeiro, uma digressão na terminologia. Quais são esses endereços? Eles são URLs válidos?
Historicamente, a resposta foi "não". De acordo com a RFC 3986 , a partir de 2005, esses endereços não são URIs (e, portanto, não são URLs, pois os URLs são um tipo de URIs ). De acordo com a terminologia dos padrões IETF de 2005, devemos chamá-los adequadamente de IRIs (Internationalized Resource Identifiers), conforme definido na RFC 3987 , que tecnicamente não são URIs, mas podem ser convertidos em URIs simplesmente codificando por cento todos os caracteres não ASCII do IRI. .
Por especificação moderna, a resposta é "sim". O padrão de vida do WHATWG simplesmente classifica tudo o que anteriormente seria chamado de "URIs" ou "IRIs" como "URLs". Isso alinha a terminologia especificada com a forma como as pessoas normais que não leram a especificação usam a palavra "URL", que era um dos objetivos da especificação .
De acordo com esse novo significado de "URL", quais caracteres são permitidos? Em muitas partes do URL, como a string e o caminho da consulta, podemos usar "unidades de URL" arbitrárias , que são
Pontos de código de URL e bytes codificados em porcentagem .
O que são "pontos de código de URL"?
Os pontos de código da URL são ASCII alfanuméricos, U + 0021 (!), U + 0024 ($), U + 0026 (&), U + 0027 ('), U + 0028 PARENTHESIS ESQUERDO, U + 0029 PARENTHESIS DIREITO, U + 002A (*), U + 002B (+), U + 002C (,), U + 002D (-), U + 002E (.), U + 002F (/), U + 003A (:), U + 003B (;), U + 003D (=), U + 003F (?), U + 0040 (@), U + 005F (_), U + 007E (~) e pontos de código no intervalo U + 00A0 a U + 10FFFD, inclusive, excluindo substitutos e não caracteres.
(Observe que a lista de "pontos de código de URL" não inclui %
, mas isso %
é permitido em "unidades de código de URL" se fizer parte de uma sequência de codificação percentual.)
O único lugar em que posso identificar onde as especificações permitem o uso de qualquer caractere que não esteja neste conjunto é no host , onde os endereços IPv6 estão entre caracteres [
e ]
caracteres. Em qualquer outro lugar da URL, unidades de URL são permitidas ou algum conjunto de caracteres ainda mais restritivo.
Por uma questão de história, e como ela não foi explorada completamente em outras partes das respostas aqui, vamos examinar o que foi permitido no par de especificações mais antigo.
Primeiro de tudo, temos dois tipos de caracteres reservados para RFC 3986 :
:/?#[]@
, que fazem parte da sintaxe genérica para um URI definido no RFC 3986!$&'()*+,;=
, que não fazem parte da sintaxe genérica da RFC, mas são reservados para uso como componentes sintáticos de determinados esquemas de URI. Por exemplo, ponto e vírgula e vírgulas são utilizados como parte da sintaxe dos URIs de dados , e &
e =
são utilizadas como parte do ubíquo ?foo=bar&qux=baz
formato em cadeias de consulta (que não é especificado por RFC 3986).Qualquer um dos caracteres reservados acima pode ser legalmente usado em um URI sem codificação, para servir ao seu propósito sintático ou apenas como caracteres literais nos dados em alguns lugares onde esse uso não pode ser mal interpretado como o personagem que serve ao seu propósito sintático. (Por exemplo, embora /
tenha significado sintático em uma URL, você pode usá-lo não codificado em uma sequência de consultas, porque não possui significado em uma sequência de consultas.)
O RFC 3986 também especifica alguns caracteres não reservados , que sempre podem ser usados simplesmente para representar dados sem nenhuma codificação:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~
Finalmente, o %
próprio personagem é permitido para codificações percentuais.
Isso deixa apenas os seguintes caracteres ASCII que são proibidos de aparecer em um URL:
"<>\^`{|}
Todos os outros caracteres do ASCII podem legalmente aparecer em um URL.
Em seguida, o RFC 3987 estende esse conjunto de caracteres não reservados com os seguintes intervalos de caracteres unicode:
%xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
/ %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
/ %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
/ %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
/ %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
/ %xD0000-DFFFD / %xE1000-EFFFD
Essas opções de bloco das especificações antigas parecem bizarras e arbitrárias, dadas as mais recentes definições de bloco Unicode ; isso provavelmente ocorre porque os blocos foram adicionados na década desde que o RFC 3987 foi gravado.
Por fim, talvez seja interessante notar que simplesmente saber quais caracteres podem aparecer legalmente em um URL não é suficiente para reconhecer se uma determinada string é um URL legal ou não, pois alguns caracteres são válidos apenas em partes específicas do URL. Por exemplo, os caracteres reservados [
e ]
são legais como parte de um host literal IPv6 em um URL como http: // [1080 :: 8: 800: 200C: 417A] / foo, mas não são legais em nenhum outro contexto, portanto, o O exemplo do OP http://example.com/file[/].html
é ilegal.
Na sua pergunta complementar, você perguntou se www.example.com/file[/].html
é um URL válido.
Esse URL não é válido porque um URL é um tipo de URI e um URI válido deve ter um esquema como http:
(consulte a RFC 3986 ).
Se você quis perguntar se http://www.example.com/file[/].html
é um URL válido, a resposta ainda será não, porque os caracteres de colchete não são válidos lá.
Os caracteres de colchete são reservados para URLs neste formato: http://[2001:db8:85a3::8a2e:370:7334]/foo/bar
(ou seja, um literal IPv6 em vez de um nome de host)
Vale a pena ler a RFC 3986 com atenção, se você quiser entender completamente o problema.
[
e ]
não são URI válidos para quase analisadores que eu já vi. Isso realmente me ferrou no mundo real: stackoverflow.com/questions/11038967/…
Unwise
muito a sério os URIs e ainda assim ficarão bem com as bibliotecas de URL. Ou seja, não há sinalizador para ignorar Unwise
. Vou ter que verificar o que o Rust lang (já que está sendo construído para um navegador, estou curioso para saber o que faz) dos URLs. A maioria dos navegadores também passará felizmente por "[", "]". Então, em teoria, como eu disse com C / C ++, eles são sub / super, mas a realidade não é tão verdadeira. É altamente dependente da interpretação das especificações e da semântica do super / subconjunto.
Todos os caracteres válidos que podem ser usados em um URI (uma URL é um tipo de URI ) são definidos no RFC 3986 .
Todos os outros caracteres podem ser usados em um URL, desde que sejam "URL codificados" primeiro. Isso envolve a alteração do caractere inválido para "códigos" específicos (geralmente na forma do símbolo de porcentagem (%) seguido por um número hexadecimal).
Este link, referência de codificação de URL HTML , contém uma lista das codificações para caracteres inválidos.
Vários intervalos de caracteres Unicode são HTML5 válidos , embora ainda não seja uma boa ideia usá-los.
Por exemplo, os href
documentos dizem http://www.w3.org/TR/html5/links.html#attr-hyperlink-href :
O atributo href nos elementos a e area deve ter um valor que seja um URL válido potencialmente cercado por espaços.
A definição de "URL válido" aponta para http://url.spec.whatwg.org/ , que diz que visa:
Alinhe o RFC 3986 e o RFC 3987 com implementações contemporâneas e obsolete-as no processo.
Esse documento define pontos de código de URL como:
Alfanumérico ASCII, "!", "$", "&", "'", "(", ")", "*", "+", ",", "-" - ",". "," / " , ":", ";", "=", "?", "@", "_", "~" e pontos de código nos intervalos U + 00A0 a U + D7FF, U + E000 a U + FDCF , U + FDF0 a U + FFFD, U + 10000 a U + 1FFFD, U + 20000 a U + 2FFFD, U + 30000 a U + 3FFFD, U + 40000 a U + 4FFFD, U + 50000 a U + 5FFFD, U +60000 para U + 6FFFD, U + 70000 para U + 7FFFD, U + 80000 para U + 8FFFD, U + 90000 para U + 9FFFD, U + A0000 para U + AFFFD, U + B0000 para U + BFFFD, U + C0000 para U + CFFFD, U + D0000 a U + DFFFD, U + E1000 a U + EFFFD, U + F0000 a U + FFFFD, U + 100000 a U + 10FFFD.
O termo "pontos de código de URL" é então usado na declaração:
Se c não for um ponto de código de URL e não "%", analise o erro.
em várias partes do algoritmo de análise, incluindo os estados de esquema, autoridade, caminho relativo, consulta e fragmento: portanto, basicamente, a URL inteira.
Além disso, o validador http://validator.w3.org/ passa por URLs como "你好"
e não passa por URLs com caracteres como espaços"a b"
Obviamente, como mencionado por Stephen C, não se trata apenas de caracteres, mas também de contexto: você precisa entender todo o algoritmo. Porém, como a classe "pontos de código de URL" é usada nos pontos principais do algoritmo, é uma boa idéia do que você pode usar ou não.
Consulte também: Caracteres Unicode em URLs
Eu preciso selecionar o caractere para dividir os URLs em uma string, então decidi criar uma lista de caracteres que não poderiam ser encontrados no URL por mim:
>>> allowed = "-_.~!*'();:@&=+$,/?%#[]?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
>>> from string import printable
>>> ''.join(set(printable).difference(set(allowed)))
'`" <\x0b\n\r\x0c\\\t{^}|>'
Portanto, as opções possíveis são a nova linha, guia, espaço, barra invertida e "<>{}^|
. Acho que vou com o espaço ou nova linha. :)
Não é realmente uma resposta para sua pergunta, mas validar URLs é realmente uma pena. Você provavelmente está melhor validando o nome de domínio e deixando a consulta como parte da URL. Essa é a minha experiência. Você também pode recorrer ao ping do URL e ver se ele resulta em uma resposta válida, mas isso pode ser demais para uma tarefa tão simples.
Expressões regulares para detectar URLs são abundantes, pesquise no Google :)
Estou implementando o antigo leitor / gravador de solicitações e respostas http (0.9, 1.0, 1.1). Solicitar URI é o local mais problemático.
Você não pode simplesmente usar RFC 1738, 2396 ou 3986 como está. Existem muitos clientes e servidores HTTP antigos que permitem mais caracteres. Então eu fiz a pesquisa com base em logs de acesso webserver acidentalmente publicados: "GET URI HTTP/1.0" 200
.
Descobri que os seguintes caracteres não padrão são frequentemente usados no URI:
\ { } < > | ` ^ "
Esses caracteres foram descritos na RFC 1738 como inseguros .
Se você deseja ser compatível com todos os clientes e servidores HTTP antigos - é necessário permitir esses caracteres no URI da solicitação.
Por favor, leia mais informações sobre esta pesquisa em http-og .
Eu vim com algumas expressões regulares para PHP que converterão URLs em texto em tags de ancoragem. (Primeiro, converte todos os www. Urls em http: // e depois converte todos os URLs com https?: // para um href = ... html links
$string = preg_replace('/(https?:\/\/)([!#$&-;=?\-\[\]_a-z~%]+)/sim', '<a href="$1$2">$2</a>',
preg_replace('/(\s)((www\.)([!#$&-;=?\-\[\]_a-z~%]+))/sim', '$1http://$2', $string)
);