LINUX.ORG.RU

Текстовый документ QTextDocument преобразует ссылки в Url Percent Encode. Как это обойти?

 , , , ,


0

1

Я использую QTextEdit для редактирования Rich-текста.

В нем содержится QTextDocument, который я заполняю через метод insertHtml() кодом, который выдает браузер через буфер обмена.

При такой вставке происходит искажение URL. Например, если был такой URL:

http://www.forkosh.com/cgi-bin/mimetex.cgi?\depth~\Large~f=b_o+\frac{a_1}{b_1+\frac{a_2}{b_2+\frac{a_3}{b_3+a_4}}}

То он превратится в такой:
http://www.forkosh.com/cgi-bin/mimetex.cgi?%5Cdepth%7E%5CLarge%7Ef=b_o+%5Cfrac%7Ba_1%7D%7Bb_1+%5Cfrac%7Ba_2%7D%7Bb_2+%5Cfrac%7Ba_3%7D%7Bb_3+a_4%7D%7D%7D

И далее возникает проблема: если web-сервер, с которого берется текст, не умеет работать с Percent Encode, то при попытке выкачивания картинки с Percent Encode URL он нужную картинку не отдаст. Серверу нужен именно такой URL, который прописан в его HTML-странице, а не что-то «почти то же самое, но преобразованное».

Проблема еще в том, что веб-сервер может быть настроен так, что при запросе Percent Encode URL он вместо того, чтобы ответить кодом 404 или еще какой ошибкой, он делает редирект, причем не на страницу с кодом 404, а на вполне нормальную страницу с кодом 200 (как в вышеприведенным URL). То есть, невозможно сделать реакцию на ошибку, и сделать запрос на URL с Percent Decode, который, скорее всего, сработал бы.

То есть, задача - это заставить QTextDocument хранить в своих фрагментах исходные URL. Как это можно сделать? Или как можно обойти проблему?

★★★★★

Ответ на: комментарий от EXL

В любом случае нужно будет смотреть в сторону:
https://doc.qt.io/qt-5/qurl.html#ComponentFormattingOption-enum

Я поискал все места в документации, где этот Enum используется, и нашел только класс QHstsPolicy...

Пока что вырисовывается такая картина.

QNetworkAccessManager имеет загадочный метод:

void QNetworkAccessManager::addStrictTransportSecurityHosts(const QVector<QHstsPolicy> &knownHosts)

В его описании говорится, что через него добавляются известные хосты, которые имеют QHstsPolicy-информацию. Очень странно, что по сигнатуре добавляться должен список правил (список Policy), но его называют списком хостов.

Далее странности продолжаются. Совершенно непонятно, как правилу выставить ComponentFormattingOption. Его невозможно выставить через полный конструктор:
QHstsPolicy(const QDateTime &expiry, QHstsPolicy::PolicyFlags flags, const QString &host, QUrl::ParsingMode mode = QUrl::DecodedMode)

Здесь нет типа ComponentFormattingOption.

И при этом сеттер и геттер для хоста не зеркальны:
void 
setHost(const QString &host, QUrl::ParsingMode mode = QUrl::DecodedMode)

QString 
host(QUrl::ComponentFormattingOptions options = QUrl::FullyDecoded) const

Вроде как можно на это забить, создать QHstsPolicy чрез полный конструктор, задать ему значение QUrl::ParsingMode, потому что нам вроде как нужно имеено оно а не QUrl::ComponentFormattingOptions.

Но у меня складывается впечатление, что QUrl::ParsingMode в четвертом параметра конструктора - это не правила парсинга URL в HTML-содержимом, а правила преобразования самого указанного URL-а.

Моих знаний английского не хватает чтобы понять все эти тонкости. А гуголтранслейт генерит невнятный техт.

UPD: На самом деле Геттер и Сеттер зеркальны, просто так сделаны, что через сеттер задается QUrl::ParsingMode, а через геттер QUrl::ParsingMode запрашивается gj-ltajkne, но можно запросить и другие параметры. Не это все равсно понимания не добавляет.

Xintrea ★★★★★ ()
Последнее исправление: Xintrea (всего исправлений: 1)
Ответ на: комментарий от Xintrea

Я поискал все места в документации, где этот Enum используется, и нашел только класс QHstsPolicy … QNetworkAccessManager

А нахрена ты туда полез? Как я понимаю, тебе нужно на каком-то там сигнале у QTextEdit ловить в слот текст, детектить в нём Url’ы и переводить их с помощью конструкции вида:

#include <QString>
#include <QDebug>
#include <QUrl>

int main(int argc, char *argv[])
{
    QString url = "http://www.forkosh.com/cgi-bin/mimetex.cgi?%5Cdepth%7E%5CLarge%7Ef=b_o+%5Cfrac%7Ba_1%7D%7Bb_1+%5Cfrac%7Ba_2%7D%7Bb_2+%5Cfrac%7Ba_3%7D%7Bb_3+a_4%7D%7D%7D";
    qDebug() << QUrl(url).toDisplayString(QUrl::FullyDecoded);
    // Output: http://www.forkosh.com/cgi-bin/mimetex.cgi?\\depth~\\Large~f=b_o+\\frac{a_1}{b_1+\\frac{a_2}{b_2+\\frac{a_3}{b_3+a_4}}}
}

В нормальный вид.

Возможно есть более красивый способ решения проблемы, типа отнаследоваться от QTextEdit и что-то там перегрузить, отвечающее за детект и декорирование ссылок. Но что-то я сильно сомневаюсь, что там подобное имеется.

EXL ★★★★★ ()
Ответ на: комментарий от Xintrea

Уточнение: Геттер и Сеттер так сделаны, что через сеттер задается QUrl::ParsingMode, а через геттер по-умолчанию запрашивается QUrl::FullyDecoded, но можно запросить и другие параметры, которые хранятся в ComponentFormattingOptions. Проблема в том, что в нем нет QUrl::ParsingMode. Кароче вообще странные вещи сделаны.

Xintrea ★★★★★ ()
Ответ на: комментарий от EXL

Как я понимаю, тебе нужно на каком-то там сигнале у QTextEdit ловить в слот текст, детектить в нём Url’ы и переводить их с помощью конструкции вида:
В нормальный вид.

Нет, в том то и дело, что что такое «нормальный вид» мы не знаем. Мы не знаем какой вид нужен серверу. Нам нужны именно те URL-ы, которые используются в исходном HTML. А они искажаются.

Xintrea ★★★★★ ()