Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -101,6 +101,8 @@ 256CBDBC1ADD107200BC6CDC /* RegisterContextLinux_mips64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 256CBDB81ADD107200BC6CDC /* RegisterContextLinux_mips64.cpp */; }; 256CBDC01ADD11C000BC6CDC /* RegisterContextPOSIX_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 256CBDBE1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.cpp */; }; 257E47171AA56C2000A62F81 /* ModuleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 257E47151AA56C2000A62F81 /* ModuleCache.cpp */; }; + 259323B71B7D8EF300C11BD6 /* UrlEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 259323B51B7D8EF300C11BD6 /* UrlEncoder.cpp */; }; + 259323B81B7D8EF300C11BD6 /* UrlEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 259323B61B7D8EF300C11BD6 /* UrlEncoder.h */; }; 25EF23781AC09B3700908DF0 /* AdbClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25EF23751AC09AD800908DF0 /* AdbClient.cpp */; }; 260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; 260157C81885F53100F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; @@ -1176,6 +1178,8 @@ 256CBDBF1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextPOSIX_arm.h; path = Utility/RegisterContextPOSIX_arm.h; sourceTree = ""; }; 257E47151AA56C2000A62F81 /* ModuleCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleCache.cpp; path = source/Utility/ModuleCache.cpp; sourceTree = ""; }; 257E47161AA56C2000A62F81 /* ModuleCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleCache.h; path = source/Utility/ModuleCache.h; sourceTree = ""; }; + 259323B51B7D8EF300C11BD6 /* UrlEncoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UrlEncoder.cpp; path = source/Utility/UrlEncoder.cpp; sourceTree = ""; }; + 259323B61B7D8EF300C11BD6 /* UrlEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UrlEncoder.h; path = source/Utility/UrlEncoder.h; sourceTree = ""; }; 25EF23751AC09AD800908DF0 /* AdbClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdbClient.cpp; sourceTree = ""; }; 25EF23761AC09AD800908DF0 /* AdbClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdbClient.h; sourceTree = ""; }; 260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = ""; }; @@ -3526,6 +3530,8 @@ 2682F168115ED9C800CCFF99 /* Utility */ = { isa = PBXGroup; children = ( + 259323B51B7D8EF300C11BD6 /* UrlEncoder.cpp */, + 259323B61B7D8EF300C11BD6 /* UrlEncoder.h */, 257E47151AA56C2000A62F81 /* ModuleCache.cpp */, 257E47161AA56C2000A62F81 /* ModuleCache.h */, 33064C9B1A5C7A490033D415 /* UriParser.h */, @@ -5473,6 +5479,7 @@ buildActionMask = 2147483647; files = ( 260A63171861008E00FECF8E /* IOHandler.h in Headers */, + 259323B81B7D8EF300C11BD6 /* UrlEncoder.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6306,6 +6313,7 @@ 942AFF0519F84ABF007B43B4 /* LibCxxVector.cpp in Sources */, 268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */, 268900F413353E6F00698AC0 /* StackFrameList.cpp in Sources */, + 259323B71B7D8EF300C11BD6 /* UrlEncoder.cpp in Sources */, 268900F513353E6F00698AC0 /* StackID.cpp in Sources */, 268900F613353E6F00698AC0 /* StopInfo.cpp in Sources */, 256CBDB41ADD0EFD00BC6CDC /* RegisterContextPOSIXCore_arm.cpp in Sources */, Index: source/Host/posix/ConnectionFileDescriptorPosix.cpp =================================================================== --- source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -33,6 +33,8 @@ #endif // C++ Includes +#include + // Other libraries and framework includes #include "llvm/Support/ErrorHandling.h" #if defined(__APPLE__) @@ -46,6 +48,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/Socket.h" #include "lldb/Interpreter/Args.h" +#include "Utility/UriParser.h" using namespace lldb; using namespace lldb_private; @@ -169,10 +172,16 @@ else if (strstr(s, "adb://") == s) { int port = -1; - sscanf(s, "adb://%*[^:]:%d", &port); - char host_and_port[sizeof("localhost:65535")]; - snprintf(host_and_port, sizeof(host_and_port), "localhost:%d", port); - return ConnectTCP(host_and_port, error_ptr); + std::string scheme, host, path; + if (!UriParser::Parse(s, scheme, host, port, path)) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("Failed to parse URL '%s'", s); + return eConnectionStatusError; + } + std::ostringstream host_and_port; + host_and_port << "localhost:" << port; + return ConnectTCP(host_and_port.str().c_str(), error_ptr); } else if (strstr(s, "connect://") == s) { Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -31,6 +31,7 @@ #include "lldb/Target/Target.h" #include "Utility/UriParser.h" +#include "Utility/UrlEncoder.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" @@ -49,10 +50,14 @@ const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; + + const std::string encoded_hostname = UrlEncoder::Encode( + override_hostname ? override_hostname : platform_hostname.c_str()); + StreamString result; result.Printf("%s://%s:%u", override_scheme ? override_scheme : platform_scheme.c_str(), - override_hostname ? override_hostname : platform_hostname.c_str(), + encoded_hostname.c_str(), port + port_offset); return result.GetString(); } Index: source/Utility/CMakeLists.txt =================================================================== --- source/Utility/CMakeLists.txt +++ source/Utility/CMakeLists.txt @@ -18,4 +18,5 @@ StringLexer.cpp TimeSpecTimeout.cpp UriParser.cpp + UrlEncoder.cpp ) Index: source/Utility/UriParser.cpp =================================================================== --- source/Utility/UriParser.cpp +++ source/Utility/UriParser.cpp @@ -14,9 +14,11 @@ #include // C++ Includes + // Other libraries and framework includes // Project includes #include "lldb/Host/StringConvert.h" +#include "Utility/UrlEncoder.h" using namespace lldb_private; @@ -35,18 +37,18 @@ char hostname_buf[256] = {0}; char port_buf[11] = {0}; // 10==strlen(2^32) char path_buf[2049] = {'/', 0}; - + bool ok = false; - if (4==sscanf(uri, "%99[^:/]://%255[^/:]:%10[^/]/%2047s", scheme_buf, hostname_buf, port_buf, path_buf+1)) { ok = true; } - else if (3==sscanf(uri, "%99[^:/]://%255[^/:]:%10[^/]", scheme_buf, hostname_buf, port_buf)) { ok = true; } - else if (3==sscanf(uri, "%99[^:/]://%255[^/]/%2047s", scheme_buf, hostname_buf, path_buf+1)) { ok = true; } - else if (2==sscanf(uri, "%99[^:/]://%255[^/]", scheme_buf, hostname_buf)) { ok = true; } + if (4 == sscanf(uri, "%99[^:/]://%255[^/:]:%10[^/]/%2047s", scheme_buf, hostname_buf, port_buf, path_buf+1)) { ok = true; } + else if (3 == sscanf(uri, "%99[^:/]://%255[^/:]:%10[^/]", scheme_buf, hostname_buf, port_buf)) { ok = true; } + else if (3 == sscanf(uri, "%99[^:/]://%255[^/]/%2047s", scheme_buf, hostname_buf, path_buf+1)) { ok = true; } + else if (2 == sscanf(uri, "%99[^:/]://%255[^/]", scheme_buf, hostname_buf)) { ok = true; } bool success = false; int port_tmp = -1; if (port_buf[0]) { - port_tmp = StringConvert::ToUInt32(port_buf, UINT32_MAX, 10, &success); + port_tmp = StringConvert::ToUInt32(UrlEncoder::Decode(port_buf).c_str(), UINT32_MAX, 10, &success); if (!success || port_tmp > 65535) { // there are invalid characters in port_buf @@ -57,10 +59,9 @@ if (ok) { scheme.assign(scheme_buf); - hostname.assign(hostname_buf); + hostname.assign(UrlEncoder::Decode(hostname_buf)); port = port_tmp; - path.assign(path_buf); + path.assign(UrlEncoder::Decode(path_buf)); } return ok; } - Index: source/Utility/UrlEncoder.h =================================================================== --- /dev/null +++ source/Utility/UrlEncoder.h @@ -0,0 +1,27 @@ +//===-- UrlEncoder.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_UrlEncoder_h_ +#define utility_UrlEncoder_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes + +class UrlEncoder +{ +public: + static std::string Encode(const std::string& url); + static std::string Decode(const std::string& url); +}; + +#endif // utility_UrlEncoder_h_ Index: source/Utility/UrlEncoder.cpp =================================================================== --- /dev/null +++ source/Utility/UrlEncoder.cpp @@ -0,0 +1,72 @@ +//===-- UrlEncoder.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Utility/UrlEncoder.h" + +// C++ Includes +#include + +namespace { + +const char kUrlSpecialSyms[] = {'!', '*', '\'', '(', ')', ';', ':', '@', '&', '=', '+', '$', ',', '/', '?', '%', '#', '[', ']'}; + +bool +IsSpecialUrlSymbol(const char ch) +{ + for (const char sym: kUrlSpecialSyms) + { + if (sym == ch) + return true; + } + return false; +} + +} + +std::string +UrlEncoder::Encode(const std::string& url) +{ + std::ostringstream result; + char sym_fmt[3]; + + for (const char sym: url) + { + if (IsSpecialUrlSymbol(sym)) + { + sprintf(sym_fmt, "%02X", uint16_t(sym)); + result << "%" << sym_fmt; + } + else + result << sym; + } + return result.str(); +} + +std::string +UrlEncoder::Decode(const std::string& url) +{ + std::ostringstream result; + + for (int i = 0, len = url.length(); i < len; ++i) + { + if (url[i] == '%' && + (i + 2) < len && + isxdigit(url[i + 1]) && isxdigit(url[i + 2])) + { + int decoded = 0; + sscanf(url.substr(i + 1, 2).c_str(), "%x", &decoded); + result << static_cast(decoded); + i += 2; + } + else + result << url[i]; + } + + return result.str(); +} Index: unittests/Utility/CMakeLists.txt =================================================================== --- unittests/Utility/CMakeLists.txt +++ unittests/Utility/CMakeLists.txt @@ -1,4 +1,5 @@ add_lldb_unittest(UtilityTests StringExtractorTest.cpp UriParserTest.cpp + UrlEncoderTest.cpp ) Index: unittests/Utility/UriParserTest.cpp =================================================================== --- unittests/Utility/UriParserTest.cpp +++ unittests/Utility/UriParserTest.cpp @@ -85,6 +85,12 @@ VALIDATE } +TEST_F (UriParserTest, AdbHostPortSerial) +{ + const UriTestCase testCase("adb://192.168.100.132%3A5555:5432/", "adb", "192.168.100.132:5555", 5432, "/"); + VALIDATE +} + TEST_F (UriParserTest, SchemeHostSeparator) { const UriTestCase testCase("x:/y"); @@ -132,4 +138,3 @@ const UriTestCase testCase("x://y:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/"); VALIDATE } - Index: unittests/Utility/UrlEncoderTest.cpp =================================================================== --- /dev/null +++ unittests/Utility/UrlEncoderTest.cpp @@ -0,0 +1,31 @@ +#include "gtest/gtest.h" +#include "Utility/UrlEncoder.h" + +namespace +{ + class UrlEncoderTest: public ::testing::Test + { + }; +} + +TEST_F (UrlEncoderTest, EncodeHostPort) +{ + EXPECT_EQ("192.168.100.132%3A5555", UrlEncoder::Encode("192.168.100.132:5555")); +} + +TEST_F (UrlEncoderTest, DecodeHostPort) +{ + EXPECT_EQ("192.168.100.132:5555", UrlEncoder::Decode("192.168.100.132%3A5555")); +} + +TEST_F (UrlEncoderTest, DecodeBrokenInput) +{ + EXPECT_EQ("192.168.100.132%3", UrlEncoder::Decode("192.168.100.132%3")); +} + +TEST_F (UrlEncoderTest, EncodeDecodeAscii) +{ + const char* url = "192.168.100.132"; + EXPECT_EQ(url, UrlEncoder::Encode(url)); + EXPECT_EQ(url, UrlEncoder::Decode(url)); +}