diff options
-rw-r--r-- | cui/source/dialogs/hlinettp.cxx | 8 | ||||
-rw-r--r-- | framework/qa/cppunit/services.cxx | 24 | ||||
-rw-r--r-- | sw/qa/uitest/writer_tests3/hyperlinkdialog.py | 21 | ||||
-rw-r--r-- | tools/qa/cppunit/test_urlobj.cxx | 27 | ||||
-rw-r--r-- | tools/source/fsys/urlobj.cxx | 30 |
5 files changed, 101 insertions, 9 deletions
diff --git a/cui/source/dialogs/hlinettp.cxx b/cui/source/dialogs/hlinettp.cxx index c26420d5703a..3a0f431acc17 100644 --- a/cui/source/dialogs/hlinettp.cxx +++ b/cui/source/dialogs/hlinettp.cxx @@ -158,13 +158,7 @@ OUString SvxHyperlinkInternetTp::CreateAbsoluteURL() const // erase leading and trailing whitespaces OUString aStrURL(m_xCbbTarget->get_active_text().trim()); - INetURLObject aURL(aStrURL); - - if( aURL.GetProtocol() == INetProtocol::NotValid ) - { - aURL.SetSmartProtocol( GetSmartProtocolFromButtons() ); - aURL.SetSmartURL(aStrURL); - } + INetURLObject aURL(aStrURL, GetSmartProtocolFromButtons()); // username and password for ftp-url if( aURL.GetProtocol() == INetProtocol::Ftp && !m_xEdLogin->get_text().isEmpty() ) diff --git a/framework/qa/cppunit/services.cxx b/framework/qa/cppunit/services.cxx index c75ce9f65633..873ea5938e4c 100644 --- a/framework/qa/cppunit/services.cxx +++ b/framework/qa/cppunit/services.cxx @@ -14,6 +14,7 @@ #include <com/sun/star/frame/XFrame.hpp> #include <com/sun/star/frame/XComponentLoader.hpp> #include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/util/URLTransformer.hpp> #include <comphelper/propertyvalue.hxx> #include <salhelper/thread.hxx> @@ -126,6 +127,29 @@ CPPUNIT_TEST_FIXTURE(Test, testLoadComponentFromURL) xThread->join(); } } + +CPPUNIT_TEST_FIXTURE(Test, testURLTransformer_parseSmart) +{ + // Without the accompanying fix in place, this test would have failed with + // "www.example.com:" treated as scheme, "/8080/foo/" as path, "bar?q=baz" + // as name, and "F" as fragment. + + css::util::URL aURL; + aURL.Complete = "www.example.com:8080/foo/bar?q=baz#F"; + css::uno::Reference xParser(css::util::URLTransformer::create(mxComponentContext)); + CPPUNIT_ASSERT(xParser->parseSmart(aURL, "http:")); + CPPUNIT_ASSERT_EQUAL(OUString("http://www.example.com:8080/foo/bar?q=baz#F"), aURL.Complete); + CPPUNIT_ASSERT_EQUAL(OUString("http://www.example.com:8080/foo/bar"), aURL.Main); + CPPUNIT_ASSERT_EQUAL(OUString("http://"), aURL.Protocol); + CPPUNIT_ASSERT(aURL.User.isEmpty()); + CPPUNIT_ASSERT(aURL.Password.isEmpty()); + CPPUNIT_ASSERT_EQUAL(OUString("www.example.com"), aURL.Server); + CPPUNIT_ASSERT_EQUAL(sal_Int16(8080), aURL.Port); + CPPUNIT_ASSERT_EQUAL(OUString("/foo/"), aURL.Path); + CPPUNIT_ASSERT_EQUAL(OUString("bar"), aURL.Name); + CPPUNIT_ASSERT_EQUAL(OUString("q=baz"), aURL.Arguments); + CPPUNIT_ASSERT_EQUAL(OUString("F"), aURL.Mark); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/qa/uitest/writer_tests3/hyperlinkdialog.py b/sw/qa/uitest/writer_tests3/hyperlinkdialog.py index c20a39b48f2a..c737f33ad1b8 100644 --- a/sw/qa/uitest/writer_tests3/hyperlinkdialog.py +++ b/sw/qa/uitest/writer_tests3/hyperlinkdialog.py @@ -72,6 +72,27 @@ class HyperlinkDialog(UITestCase): self.assertEqual(get_state_as_dict(xedit)["SelectedText"], "link") + def test_insert_hyperlink_without_scheme(self): + + with self.ui_test.create_doc_in_start_center("writer"): + xMainWindow = self.xUITest.getTopFocusWindow() + + with self.ui_test.execute_dialog_through_command(".uno:HyperlinkDialog") as xDialog: + + # insert link + xtab=xDialog.getChild("tabcontrol") + select_pos(xtab, "0") + + xtarget = xDialog.getChild("target") + xtarget.executeAction("TYPE", mkPropertyValues({"TEXT": "www.libreoffice.org:80"})) + + # Check that the link is added with http scheme + xMainWindow = self.xUITest.getTopFocusWindow() + xedit = xMainWindow.getChild("writer_edit") + xedit.executeAction("SELECT", mkPropertyValues({"START_POS": "0", "END_POS": "29"})) + self.assertEqual(get_state_as_dict(xedit)["SelectedText"], "http://www.libreoffice.org:80") + + def test_tdf141166(self): # Skip this test for --with-help=html and --with-help=online, as that would fail with a # DialogNotExecutedException("did not execute a dialog for a blocking action") thrown from diff --git a/tools/qa/cppunit/test_urlobj.cxx b/tools/qa/cppunit/test_urlobj.cxx index ec64b5d66777..abcd2fe1417b 100644 --- a/tools/qa/cppunit/test_urlobj.cxx +++ b/tools/qa/cppunit/test_urlobj.cxx @@ -319,6 +319,32 @@ namespace tools_urlobj obj.GetMainURL(INetURLObject::DecodeMechanism::NONE)); } + void testParseSmart() + { + { + // host:port must not be misinterpreted as scheme:path + INetURLObject obj("example.com:8080/foo", INetProtocol::Http); + CPPUNIT_ASSERT(!obj.HasError()); + CPPUNIT_ASSERT_EQUAL(OUString("http://example.com:8080/foo"), + obj.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + CPPUNIT_ASSERT_EQUAL(INetProtocol::Http, obj.GetProtocol()); + CPPUNIT_ASSERT_EQUAL(OUString("example.com"), obj.GetHost()); + CPPUNIT_ASSERT_EQUAL(sal_uInt32(8080), obj.GetPort()); + CPPUNIT_ASSERT_EQUAL(OUString("/foo"), obj.GetURLPath()); + } + { + // port may only contain decimal digits, so this must be treated as unknown scheme + INetURLObject obj("example.com:80a0/foo", INetProtocol::Http); + CPPUNIT_ASSERT(!obj.HasError()); + CPPUNIT_ASSERT_EQUAL(OUString("example.com:80a0/foo"), + obj.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + CPPUNIT_ASSERT_EQUAL(INetProtocol::Generic, obj.GetProtocol()); + CPPUNIT_ASSERT(obj.isSchemeEqualTo(u"example.com")); + CPPUNIT_ASSERT_EQUAL(OUString(""), obj.GetHost()); + CPPUNIT_ASSERT_EQUAL(OUString("80a0/foo"), obj.GetURLPath()); + } + } + // Change the following lines only, if you add, remove or rename // member functions of the current class, // because these macros are need by auto register mechanism. @@ -335,6 +361,7 @@ namespace tools_urlobj CPPUNIT_TEST( testSetExtension ); CPPUNIT_TEST( testChangeScheme ); CPPUNIT_TEST( testTd146382 ); + CPPUNIT_TEST( testParseSmart ); CPPUNIT_TEST_SUITE_END( ); }; // class createPool diff --git a/tools/source/fsys/urlobj.cxx b/tools/source/fsys/urlobj.cxx index 49d0500cabb0..1b171ad2ed8e 100644 --- a/tools/source/fsys/urlobj.cxx +++ b/tools/source/fsys/urlobj.cxx @@ -869,8 +869,34 @@ bool INetURLObject::setAbsURIRef(OUString const & rTheAbsURIRef, aSynScheme = parseScheme(&p1, pEnd, nFragmentDelimiter); if (!aSynScheme.isEmpty()) { - m_eScheme = INetProtocol::Generic; - pPos = p1; + if (bSmart && m_eSmartScheme != m_eScheme && p1 != pEnd && rtl::isAsciiDigit(*p1)) + { + // rTheAbsURIRef doesn't define a known scheme (handled by the "if (pPrefix)" + // branch above); but a known scheme is defined in m_eSmartScheme. If this + // scheme may have a port in authority component, then avoid misinterpreting + // URLs like www.foo.bar:123/baz as using unknown "www.foo.bar" scheme with + // 123/baz rootless path. For now, do not try to handle possible colons in + // user information, require such ambiguous URLs to have explicit scheme part. + // Also ignore possibility of empty port. + const SchemeInfo& rInfo = getSchemeInfo(m_eSmartScheme); + if (rInfo.m_bAuthority && rInfo.m_bPort) + { + // Make sure that all characters from colon to [/?#] or to EOL are digits. + // Or maybe make it simple, and just assume that "xyz:1..." is more likely + // to be host "xyz" and port "1...", than scheme "xyz" and path "1..."? + sal_Unicode const* p2 = p1 + 1; + while (p2 != pEnd && rtl::isAsciiDigit(*p2)) + ++p2; + if (p2 == pEnd || *p2 == '/' || *p2 == '?' || *p2 == '#') + m_eScheme = m_eSmartScheme; + } + } + + if (m_eScheme == INetProtocol::NotValid) + { + m_eScheme = INetProtocol::Generic; + pPos = p1; + } } } |