Разрешение относительных URI в Java 8 при устранении ошибки JDKJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Разрешение относительных URI в Java 8 при устранении ошибки JDK

Сообщение Anonymous »

Я застрял на Java 8. У меня есть программа, которая создает и разрешает URI с помощью java.net.URI. Обычно это всегда схема http, но потенциально мы можем получить и другие, которые нам нужно будет обработать.

Код: Выделить всё

import java.net.URI;

class Scratch {
public static void main(String[] args) throws Exception {
URI base = new URI("https://example.com/");
URI other = new URI("path/to/resource?query=hello");
URI result = base.resolve(other);
System.out.println(result);
}
}
Это приводит к правильному URI, как и ожидалось:

https://example.com/path/to /resource?query=hello

Однако из-за JDK-8272702 это ведет себя довольно неожиданно при разрешении относительных URI в различных другой способами.
Примеры
Вот несколько примеров различных относительных разрешений и их ожиданий:

Код: Выделить всё

import java.net.URI;

class Scratch {
private static final String F = "%-20s %-15s %-35s %-35s%n";
public static void main(String[] args) throws Exception {
System.out.printf(F, "Base", "Resolve part", "Expected", "Actual (if different)");
test("https://a.com", ".", "https://a.com/");
test("https://a.com", "./", "https://a.com/");
test("https://a.com", "./path", "https://a.com/path");
test("https://a.com", "path", "https://a.com/path");
test("https://a.com", "path/", "https://a.com/path/");
test("https://a.com", "./path/", "https://a.com/path/");
test("https://a.com", "../", "https://a.com/../");
test("https://a.com", "../path", "https://a.com/../path");
test("https://a.com", "../path/", "https://a.com/../path/");

System.out.println("\nTrailing slash");
test("https://a.com/", ".", "https://a.com/");
test("https://a.com/", "./", "https://a.com/");
test("https://a.com/", "./path", "https://a.com/path");
test("https://a.com/", "path", "https://a.com/path");
test("https://a.com/", "path/", "https://a.com/path/");
test("https://a.com/", "./path/", "https://a.com/path/");
test("https://a.com/", "../", "https://a.com/../");
test("https://a.com/", "../path", "https://a.com/../path");
test("https://a.com/", "../path/", "https://a.com/../path/");
}

private static void test(String base, String resolve, String expected) throws Exception {
URI baseUri = new URI(base);
URI resolveUri = new URI(resolve);
URI actual = baseUri.resolve(resolveUri);
URI expectedUri = new URI(expected);
String difference = actual.equals(expectedUri) ? "" : actual.toString();
System.out.printf(F, baseUri, resolveUri, expectedUri, difference);
}
}
В Java 21, где связанная ошибка «исправлена» и при условии, что вывод каждого разрешения верен, мы получаем следующий вывод:

Код: Выделить всё

Base                 Resolve part    Expected                            Actual (if different)
https://a.com        .                https://a.com/
https://a.com        ./              https://a.com/
https://a.com        ./path          https://a.com/path
https://a.com        path            https://a.com/path
https://a.com        path/           https://a.com/path/
https://a.com        ./path/         https://a.com/path/
https://a.com        ../             https://a.com/../
https://a.com        ../path         https://a.com/../path
https://a.com        ../path/        https://a.com/../path/

Trailing slash
https://a.com/       .               https://a.com/
https://a.com/       ./              https://a.com/
https://a.com/       ./path          https://a.com/path
https://a.com/       path            https://a.com/path
https://a.com/       path/           https://a.com/path/
https://a.com/       ./path/         https://a.com/path/
https://a.com/       ../             https://a.com/../
https://a.com/       ../path         https://a.com/../path
https://a.com/       ../path/        https://a.com/../path/
Вызов Java 8
Однако при запуске на Java 8 (1.8.0_322):

Код: Выделить всё

Base                 Resolve part    Expected                            Actual (if different)
https://a.com        .               https://a.com/                      https://a.com
https://a.com        ./              https://a.com/                      https://a.com
https://a.com        ./path          https://a.com/path                  https://a.compath
https://a.com        path            https://a.com/path                  https://a.compath
https://a.com        path/           https://a.com/path/                 https://a.compath/
https://a.com        ./path/         https://a.com/path/                 https://a.compath/
https://a.com        ../             https://a.com/../                   https://a.com../
https://a.com        ../path         https://a.com/../path               https://a.com../path
https://a.com        ../path/        https://a.com/../path/              https://a.com../path/

Trailing slash
https://a.com/       .               https://a.com/
https://a.com/       ./              https://a.com/
https://a.com/       ./path          https://a.com/path
https://a.com/       path            https://a.com/path
https://a.com/       path/           https://a.com/path/
https://a.com/       ./path/         https://a.com/path/
https://a.com/       ../             https://a.com/../
https://a.com/       ../path         https://a.com/../path
https://a.com/       ../path/        https://a.com/../path/
Вы можете видеть, что Фактические сильно различаются для многих разрешений. Это также не полный набор потенциальных входных данных, а лишь некоторые из них, демонстрирующие проблему.
Что делает Python?
Кроме того, запуск то же самое в Python (здесь 3.11) с использованием urllib.parse дает другой результат

Код: Выделить всё

from urllib.parse import urljoin

FORMAT = "{:20s} {:15s} {:35s} {:35s}"

def main():
print(FORMAT.format("Base", "Resolve part", "Expected", "Actual (if different)"))
test("https://a.com", ".", "https://a.com/")
test("https://a.com", "./", "https://a.com/")
test("https://a.com", "./path", "https://a.com/path")
test("https://a.com", "path", "https://a.com/path")
test("https://a.com", "path/", "https://a.com/path/")
test("https://a.com", "./path/", "https://a.com/path/")
test("https://a.com", "../", "https://a.com/../")
test("https://a.com", "../path", "https://a.com/../path")
test("https://a.com", "../path/", "https://a.com/../path/")

print("\nTrailing slash")
test("https://a.com/", ".", "https://a.com/")
test("https://a.com/", "./", "https://a.com/")
test("https://a.com/", "./path", "https://a.com/path")
test("https://a.com/", "path", "https://a.com/path")
test("https://a.com/", "path/", "https://a.com/path/")
test("https://a.com/", "./path/", "https://a.com/path/")
test("https://a.com/", "../", "https://a.com/../")
test("https://a.com/", "../path", "https://a.com/../path")
test("https://a.com/", "../path/", "https://a.com/../path/")

def test(base, resolve, expected):
base_uri = urljoin(base, "")  # Ensure base is a proper URL
resolve_uri = urljoin("", resolve)  # Resolve treats empty string as base
actual = urljoin(base_uri, resolve_uri)
difference = "" if actual == expected else actual
print(FORMAT.format(base_uri, resolve_uri, expected, difference))

main()
Вывод:

Код: Выделить всё

Base                 Resolve part    Expected                            Actual (if different)
https://a.com        .               https://a.com/
https://a.com        ./              https://a.com/
https://a.com        ./path          https://a.com/path
https://a.com        path            https://a.com/path
https://a.com        path/           https://a.com/path/
https://a.com        ./path/         https://a.com/path/
https://a.com        ../             https://a.com/../                   https://a.com/
https://a.com        ../path         https://a.com/../path               https://a.com/path
https://a.com        ../path/        https://a.com/../path/              https://a.com/path/

Trailing slash
https://a.com/       .                https://a.com/
https://a.com/       ./              https://a.com/
https://a.com/       ./path          https://a.com/path
https://a.com/       path            https://a.com/path
https://a.com/       path/           https://a.com/path/
https://a.com/       ./path/         https://a.com/path/
https://a.com/       ../             https://a.com/../                   https://a.com/
https://a.com/       ../path         https://a.com/../path               https://a.com/path
https://a.com/       ../path/        https://a.com/../path/              https://a.com/path/
Выдает немного другой результат. Это может быть связано с разницей RFC между Java и Python или небольшой разницей в том, как работает нормализация, поскольку единственные различия заключаются в сегментах с двойной точкой.
ВопросКак мне создать метод безопасного разрешения Java 8, который будет работать для всех java.net.URI, несмотря на вышеупомянутую ошибку?

Подробнее здесь: https://stackoverflow.com/questions/793 ... th-jdk-bug
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»