Разрешить URI с несколькими косыми чертами в относительной части - PullRequest
0 голосов
/ 04 октября 2018

Я должен написать скрипт на Perl, который анализирует URI из HTML.В любом случае, реальная проблема заключается в том, как разрешить относительный Uris.

У меня есть базовый URI (базовый href в html), например http://a/b/c/d;p?q (давайте рассмотрим rfc3986 ) и другиедругие URI:

/ г, // г, /// г, //// г, ч // г, г //// ч, ч /// г: f

В этом RFC, раздел 5.4.1 (ссылка выше) приведен только пример // g:

"// g" = "http://g"

Как насчет всех других случаев? Насколько я понял из rfc 3986, раздел 3.3 , допускается несколько косых черт. Итак, правильное ли следующее разрешение?

"/// g" = "http://a/b/c///g"

или что должно быть?Кто-нибудь может объяснить это лучше и доказать это с помощью устаревшего rfc или документации?

Обновление # 1 : Попробуйте посмотреть на этот рабочий URL - https: /// stackoverflow.com //////// a ///// 10161264 ///// 6618577

Что здесь происходит?

Ответы [ 3 ]

0 голосов
/ 04 октября 2018

Мне было любопытно, что Mojo :: URL сделает, поэтому я проверил.Существует большое предостережение, потому что оно не претендует на строгую совместимость:

Mojo :: URL реализует подмножество RFC 3986, RFC 3987 и URL Living Standard для унифицированных указателей ресурсов с поддержкой IDNA.и IRI.

Вот программа.

my @urls = qw(/g //g ///g ////g h//g g////h h///g:f
    https:///stackoverflow.com////////a/////10161264/////6618577
    );
my @parts = qw(scheme host port path query);
my $template = join "\n", map { "$_: %s" } @parts;

my $base_url = Mojo::URL->new( 'http://a/b/c/d;p?q' );

foreach my $u ( @urls ) {
    my $url = Mojo::URL->new( $u )->base( $base_url )->to_abs;

    no warnings qw(uninitialized);
    say '-' x 40;
    printf "%s\n$template", $u, map { $url->$_() } @parts
    }

Вот вывод:

----------------------------------------
/g
scheme: http
host: a
port:
path: /g
query: ----------------------------------------
//g
scheme: http
host: g
port:
path:
query: ----------------------------------------
///g
scheme: http
host: a
port:
path: /g
query: ----------------------------------------
////g
scheme: http
host: a
port:
path: //g
query: ----------------------------------------
h//g
scheme: http
host: a
port:
path: /b/c/h/g
query: ----------------------------------------
g////h
scheme: http
host: a
port:
path: /b/c/g/h
query: ----------------------------------------
h///g:f
scheme: http
host: a
port:
path: /b/c/h/g:f
query: ----------------------------------------
https:///stackoverflow.com////////a/////10161264/////6618577
scheme: https
host:
port:
path: /stackoverflow.com////////a/////10161264/////6618577
query:
0 голосов
/ 05 октября 2018

Я начну с подтверждения того, что все предоставленные вами URI действительны, и с предоставления результата упомянутых вами разрешений URI (и результата нескольких моих собственных):

$ perl -MURI -e'
   for my $rel (qw( /g //g ///g ////g h//g g////h h///g:f )) {
      my $uri = URI->new($rel)->abs("http://a/b/c/d;p?q");
      printf "%-20s + %-7s = %-20s   host: %-4s   path: %s\n",
         "http://a/b/c/d;p?q", $rel, $uri, $uri->host, $uri->path;
   }

   for my $base (qw( http://host/a/b/c/d http://host/a/b/c//d )) {
      my $uri = URI->new("../../e")->abs($base);
      printf "%-20s + %-7s = %-20s   host: %-4s   path: %s\n",
         $base, "../../e", $uri, $uri->host, $uri->path;
   }
'
http://a/b/c/d;p?q   + /g      = http://a/g             host: a      path: /g
http://a/b/c/d;p?q   + //g     = http://g               host: g      path:
http://a/b/c/d;p?q   + ///g    = http:///g              host:        path: /g
http://a/b/c/d;p?q   + ////g   = http:////g             host:        path: //g
http://a/b/c/d;p?q   + h//g    = http://a/b/c/h//g      host: a      path: /b/c/h//g
http://a/b/c/d;p?q   + g////h  = http://a/b/c/g////h    host: a      path: /b/c/g////h
http://a/b/c/d;p?q   + h///g:f = http://a/b/c/h///g:f   host: a      path: /b/c/h///g:f
http://host/a/b/c/d  + ../../e = http://host/a/e        host: host   path: /a/e
http://host/a/b/c//d + ../../e = http://host/a/b/e      host: host   path: /a/b/e

Далее мы рассмотрим синтаксис относительных URI, поскольку именно этот вопрос вращается вокруг вас.

relative-ref  = relative-part [ "?" query ] [ "#" fragment ]

relative-part = "//" authority path-abempty
              / path-absolute
              / path-noscheme
              / path-empty

path-abempty  = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )

segment       = *pchar         ; 0 or more <pchar>
segment-nz    = 1*pchar        ; 1 or more <pchar>   nz = non-zero

Ключевые моменты из этих правил для ответа на ваш вопрос:

  • Абсолютный путь (path-absolute) не может начинаться с //.Первый сегмент, если имеется, должен быть ненулевым по длине.Если относительный URI начинается с //, то в противном случае в пути может быть authority.
  • //, поскольку сегменты могут иметь нулевую длину.

Теперь давайте посмотрим на каждое из предоставленных вами разрешений по очереди.

/g - это абсолютный путь path-absolute и, следовательно, действительный относительный URI (relative-ref), и, следовательно,действительный URI (URI-reference).

  • Анализ URI (скажем, с использованием регулярного выражения в Приложении B) дает нам следующее:

    Base.scheme:    "http"       R.scheme:    undef
    Base.authority: "a"          R.authority: undef
    Base.path:      "/b/c/d;p"   R.path:      "/g"
    Base.query:     "q"          R.query:     undef
    Base.fragment:  undef        R.fragment:  undef
    
  • Следуя алгоритму в §5.2.2, мы получаем:

    T.path:         "/g"      ; remove_dot_segments(R.path)
    T.query:        undef     ; R.query
    T.authority:    "a"       ; Base.authority
    T.scheme:       "http"    ; Base.scheme
    T.fragment:     undef     ; R.fragment
    
  • Следуя алгоритму в §5.3, мы получаем:

    http://a/g
    

//g отличается.//g не абсолютный путь (path_absolute), поскольку абсолютный путь не может начинаться с пустого сегмента ("/" [ segment-nz *( "/" segment ) ]).

Вместо этого он следует следующимpattern:

"//" authority path-abempty
  • Анализ URI (скажем, с использованием регулярного выражения в Приложении B) дает нам следующее:

    Base.scheme:    "http"       R.scheme:    undef
    Base.authority: "a"          R.authority: "g"
    Base.path:      "/b/c/d;p"   R.path:      ""
    Base.query:     "q"          R.query:     undef
    Base.fragment:  undef        R.fragment:  undef
    
  • Следуя алгоритму в §5.2.2, мы получаем следующее:

    T.authority:    "g"           ; R.authority
    T.path:         ""            ; remove_dot_segments(R.path)
    T.query:        ""            ; R.query
    T.scheme:       "http"        ; Base.scheme
    T.fragment:     undef         ; R.fragment
    
  • Следуя алгоритму в §5.3, мы получаем следующее:

    http://g
    

Примечание : Этот сервер контактов g!


///g аналогичен //g, за исключением того, что права доступа не указаны!Это удивительно верно.

  • Анализ URI (скажем, с использованием регулярного выражения в Приложении B) дает нам следующее:

    Base.scheme:    "http"       R.scheme:    undef
    Base.authority: "a"          R.authority: ""
    Base.path:      "/b/c/d;p"   R.path:      "/g"
    Base.query:     "q"          R.query:     undef
    Base.fragment:  undef        R.fragment:  undef
    
  • Следуя алгоритму в §5.2.2, мы получаем следующее:

    T.authority:    ""        ; R.authority
    T.path:         "/g"      ; remove_dot_segments(R.path)
    T.query:        undef     ; R.query
    T.scheme:       "http"    ; Base.scheme
    T.fragment:     undef     ; R.fragment
    
  • Следуя алгоритму в §5.3, мы получаем следующее:

    http:///g
    

Примечание : Хотя этот URI действителен, он бесполезен, поскольку имя сервера (T.authority) пустое!


////g совпадает с///g за исключением R.path равным //g, поэтому мы получаем

    http:////g

Примечание : хотя этот URI действителен, он бесполезен, поскольку имя сервера (T.authority)пусто!


Последние три (h//g, g////h, h///g:f) - все относительные пути (path-noscheme).

  • ПарсингURI (скажем, с использованием регулярного выражения в Приложении B) дает нам следующее:

    Base.scheme:    "http"       R.scheme:    undef
    Base.authority: "a"          R.authority: undef
    Base.path:      "/b/c/d;p"   R.path:      "h//g"
    Base.query:     "q"          R.query:     undef
    Base.fragment:  undef        R.fragment:  undef
    
  • Следуя алгоритму в п. 5.2.2, мы получаем следующее:

    T.path:         "/b/c/h//g"    ; remove_dot_segments(merge(Base.path, R.path))
    T.query:        undef          ; R.query
    T.authority:    "a"            ; Base.authority
    T.scheme:       "http"         ; Base.scheme
    T.fragment:     undef          ; R.fragment
    
  • По алгоритмув §5.3 мы получаем следующее:

    http://a/b/c/h//g         # For h//g
    http://a/b/c/g////h       # For g////h
    http://a/b/c/h///g:f      # For h///g:f
    

Я не думаю, что примеры подходят для ответа на то, что, на мой взгляд, вы действительно хотите знать.

Посмотрите на следующие два URI.Они не эквивалентны.

http://host/a/b/c/d     # Path has 4 segments: "a", "b", "c", "d"

и

http://host/a/b/c//d    # Path has 5 segments: "a", "b", "c", "", "d"

Большинство серверов будут обращаться с ними одинаково - что хорошо, так как серверы могут свободно интерпретировать пути вкак угодно, но это имеет значение при применении относительных путей.Например, если бы это был базовый URI для ../../e, вы бы получили

http://host/a/b/c/d + ../../e = http://host/a/e

и

http://host/a/b/c//d + ../../e = http://host/a/b/e
0 голосов
/ 04 октября 2018

Нет - ///g может показаться более эквивалентным /g.«Точечные сегменты» .. и . - это то, что используется для навигации вверх и вниз по иерархии с http URL-адресами.См. Также модуль URI для обработки путей в URI.

...