From a104ec11d0ef9d5a9eb49b68e3c52e91fa95d6da Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Fri, 13 Oct 2023 01:11:38 +0200
Subject: [PATCH] SL-20422 Unit-tests fix

---
 indra/newview/llslurl.cpp            | 823 +++++++++++++--------------
 indra/newview/tests/llslurl_test.cpp |   6 +
 2 files changed, 412 insertions(+), 417 deletions(-)

diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index a9b7b0e4179..3858a1b9cea 100644
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -1,4 +1,4 @@
-/** 
+/**
  * @file llurlsimstring.cpp (was llsimurlstring.cpp)
  * @brief Handles "SLURL fragments" like Ahern/123/45 for
  * startup processing, login screen, prefs, etc.
@@ -6,21 +6,21 @@
  * $LicenseInfo:firstyear=2010&license=viewerlgpl$
  * Second Life Viewer Source Code
  * Copyright (C) 2010, Linden Research, Inc.
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation;
  * version 2.1 of the License only.
- * 
+ *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
+ *
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
@@ -36,7 +36,7 @@
 #include "curl/curl.h"
 const char* LLSLURL::SLURL_HTTP_SCHEME		 = "http";
 const char* LLSLURL::SLURL_HTTPS_SCHEME		 = "https";
-const char* LLSLURL::SLURL_SECONDLIFE_SCHEME	 = "secondlife";
+const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife";
 const char* LLSLURL::SLURL_SECONDLIFE_PATH	 = "secondlife";
 const char* LLSLURL::SLURL_COM		         = "slurl.com";
 // For DnD - even though www.slurl.com redirects to slurl.com in a browser, you  can copy and drag
@@ -54,480 +54,469 @@ const char* LLSLURL::SIM_LOCATION_LAST           = "last";
 // resolve a simstring from a slurl
 LLSLURL::LLSLURL(const std::string& slurl)
 {
-	// by default we go to agni.
-	mType = INVALID;
-
-	if(slurl == SIM_LOCATION_HOME)
-	{
-		mType = HOME_LOCATION;
-	}
-	else if(slurl.empty() || (slurl == SIM_LOCATION_LAST))
-	{
-		mType = LAST_LOCATION;
-	}
-	else
-	{
-		LLURI slurl_uri;
-		// parse the slurl as a uri
-		if(slurl.find(':') == std::string::npos)
-		{
-			// There may be no scheme ('secondlife:' etc.) passed in.  In that case
-			// we want to normalize the slurl by putting the appropriate scheme
-			// in front of the slurl.  So, we grab the appropriate slurl base
-			// from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or
-			// https://<hostname>/region/ for Standalone grid (the word region, not the region name)
-			// these slurls are typically passed in from the 'starting location' box on the login panel,
-			// where the user can type in <regionname>/<x>/<y>/<z>
-			std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase();
-
-			// the slurl that was passed in might have a prepended /, or not.  So,
-			// we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife/<region>/<x>/<y>/<z>
-			// or some such.
-			
-			if(slurl[0] == '/')
-		    {
-				fixed_slurl += slurl.substr(1);
-		    }
-			else
-		    {
-				fixed_slurl += slurl;
-		    }
-			// We then load the slurl into a LLURI form
-			slurl_uri = LLURI(fixed_slurl);
-		}
-		else
-		{
-		    // as we did have a scheme, implying a URI style slurl, we
-		    // simply parse it as a URI
-		    slurl_uri = LLURI(slurl);
-		}
-		
-		LLSD path_array = slurl_uri.pathArray();
-		
-		// determine whether it's a maingrid URI or an Standalone/open style URI
-		// by looking at the scheme.  If it's a 'secondlife:' slurl scheme or
-		// 'sl:' scheme, we know it's maingrid
-		
-		// At the end of this if/else block, we'll have determined the grid,
-		// and the slurl type (APP or LOCATION)
-		if(slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
-		{
-			if (path_array.size() == 0)
-			{
-				// um, we need a path...
-				mType = EMPTY;
-				return;
-			}
-
-			// parse a maingrid style slurl.  We know the grid is maingrid
-			// so grab it.
-			// A location slurl for maingrid (with the special schemes) can be in the form
-			// secondlife://<regionname>/<x>/<y>/<z>
-			// or
-			// secondlife://<Grid>/secondlife/<region>/<x>/<y>/<z>
-			// where if grid is empty, it specifies Agni
-			
-			// An app style slurl for maingrid can be
-			// secondlife://<Grid>/app/<app parameters>
-			// where an empty grid implies Agni
-			
-			// we'll start by checking the top of the 'path' which will be 
-			// either 'app', 'secondlife', or <x>.
-			
-			// default to maingrid
-			
-			mGrid = MAINGRID;
-			
-			if ((path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) ||
-				(path_array[0].asString() == LLSLURL::SLURL_APP_PATH))
-		    {
-				// it's in the form secondlife://<grid>/(app|secondlife)
-				// so parse the grid name to derive the grid ID
-				if (!slurl_uri.hostName().empty())
-				{
-					mGrid = LLGridManager::getInstance()->getGridId(slurl_uri.hostName());
-				}
-				else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
-				{
-					// If the slurl is in the form secondlife:///secondlife/<region> form, 
-					// then we are in fact on maingrid.  
-					mGrid = MAINGRID;
-				}
-				else if(path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
-				{
-					// for app style slurls, where no grid name is specified, assume the currently
-					// selected or logged in grid.
-					mGrid =  LLGridManager::getInstance()->getGridId();
-				}
-
-				if(mGrid.empty())
-				{
-					// we couldn't find the grid in the grid manager, so bail
-					LL_WARNS("AppInit")<<"unable to find grid"<<LL_ENDL;
-					return;
-				}
-				// set the type as appropriate.
-				if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
-				{
-					mType = LOCATION;
-				}
-				else
-				{
-					mType = APP;
-				}
-				path_array.erase(0);
-		    }
-			else
-		    {
-				if(slurl_uri.hostName() == LLSLURL::SLURL_APP_PATH)
+    // by default we go to agni.
+    mType = INVALID;
+
+    if (slurl.empty() || (slurl == SIM_LOCATION_LAST))
+    {
+        mType = LAST_LOCATION;
+    }
+    else if (slurl == SIM_LOCATION_HOME)
+    {
+        mType = HOME_LOCATION;
+    }
+    else
+    {
+        LLURI slurl_uri;
+        // parse the slurl as a uri
+        if (slurl.find(':') == std::string::npos)
+        {
+            // There may be no scheme ('secondlife:' etc.) passed in.  In that case
+            // we want to normalize the slurl by putting the appropriate scheme
+            // in front of the slurl.  So, we grab the appropriate slurl base
+            // from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or
+            // https://<hostname>/region/ for Standalone grid (the word region, not the region name)
+            // these slurls are typically passed in from the 'starting location' box on the login panel,
+            // where the user can type in <regionname>/<x>/<y>/<z>
+            std::string fixed_slurl = LLGridManager::getInstance()->getSLURLBase();
+
+            // the slurl that was passed in might have a prepended /, or not.  So,
+            // we strip off the prepended '/' so we don't end up with http://slurl.com/secondlife/<region>/<x>/<y>/<z>
+            // or some such.
+
+            if (slurl[0] == '/')
+            {
+                fixed_slurl += slurl.substr(1);
+            }
+            else
+            {
+                fixed_slurl += slurl;
+            }
+            // We then load the slurl into a LLURI form
+            slurl_uri = LLURI(fixed_slurl);
+        }
+        else
+        {
+            // as we did have a scheme, implying a URI style slurl, we
+            // simply parse it as a URI
+            slurl_uri = LLURI(slurl);
+        }
+
+        LLSD path_array = slurl_uri.pathArray();
+
+        // determine whether it's a maingrid URI or an Standalone/open style URI
+        // by looking at the scheme.  If it's a 'secondlife:' slurl scheme or
+        // 'sl:' scheme, we know it's maingrid
+
+        // At the end of this if/else block, we'll have determined the grid,
+        // and the slurl type (APP or LOCATION)
+        if (slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
+        {
+            if (path_array.size() == 0)
+            {
+                if (slurl_uri.authority().empty() && slurl_uri.escapedQuery().empty())
+                {
+                    mType = EMPTY;
+                }
+                // um, we need a path...
+                return;
+            }
+
+            // parse a maingrid style slurl.  We know the grid is maingrid
+            // so grab it.
+            // A location slurl for maingrid (with the special schemes) can be in the form
+            // secondlife://<regionname>/<x>/<y>/<z>
+            // or
+            // secondlife://<Grid>/secondlife/<region>/<x>/<y>/<z>
+            // where if grid is empty, it specifies Agni
+
+            // An app style slurl for maingrid can be
+            // secondlife://<Grid>/app/<app parameters>
+            // where an empty grid implies Agni
+
+            // we'll start by checking the top of the 'path' which will be
+            // either 'app', 'secondlife', or <x>.
+
+            // default to maingrid
+
+            mGrid = MAINGRID;
+
+            if ((path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH) ||
+                (path_array[0].asString() == LLSLURL::SLURL_APP_PATH))
+            {
+                // it's in the form secondlife://<grid>/(app|secondlife)
+                // so parse the grid name to derive the grid ID
+                if (!slurl_uri.hostName().empty())
+                {
+                    mGrid = LLGridManager::getInstance()->getGridId(slurl_uri.hostName());
+                }
+                else if(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
+                {
+                    // If the slurl is in the form secondlife:///secondlife/<region> form,
+                    // then we are in fact on maingrid.
+                    mGrid = MAINGRID;
+                }
+                else if(path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
+                {
+                    // for app style slurls, where no grid name is specified, assume the currently
+                    // selected or logged in grid.
+                    mGrid =  LLGridManager::getInstance()->getGridId();
+                }
+
+                if (mGrid.empty())
+                {
+                    // we couldn't find the grid in the grid manager, so bail
+                    LL_WARNS("AppInit")<<"unable to find grid"<<LL_ENDL;
+                    return;
+                }
+                // set the type as appropriate.
+                if (path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH)
+                {
+                    mType = LOCATION;
+                }
+                else
+                {
+                    mType = APP;
+                }
+                path_array.erase(0);
+            }
+            else
+            {
+                if (slurl_uri.hostName() == LLSLURL::SLURL_APP_PATH)
                 {
                     mType = APP;
                 }
                 else
                 {
                     // it wasn't a /secondlife/<region> or /app/<params>, so it must be secondlife://<region>
-				// therefore the hostname will be the region name, and it's a location type
-				mType = LOCATION;
-				// 'normalize' it so the region name is in fact the head of the path_array
-				path_array.insert(0, slurl_uri.hostName());
+                    // therefore the hostname will be the region name, and it's a location type
+                    mType = LOCATION;
+                    // 'normalize' it so the region name is in fact the head of the path_array
+                    path_array.insert(0, slurl_uri.hostName());
+                }
+            }
+        }
+        else if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME) ||
+            (slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) ||
+            (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME))
+        {
+            // We're dealing with either a Standalone style slurl or slurl.com slurl
+            if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) ||
+                (slurl_uri.hostName() == LLSLURL::WWW_SLURL_COM) ||
+                (slurl_uri.hostName() == LLSLURL::MAPS_SECONDLIFE_COM))
+            {
+                // slurl.com implies maingrid
+                mGrid = MAINGRID;
+            }
+            else
+            {
+                // Don't try to match any old http://<host>/ URL as a SLurl.
+                // SLE SLurls will have the grid hostname in the URL, so only
+                // match http URLs if the hostname matches the grid hostname
+                // (or its a slurl.com or maps.secondlife.com URL).
+                if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME ||
+                     slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) &&
+                    slurl_uri.hostName() != LLGridManager::getInstance()->getGrid())
+                {
+                    return;
                 }
-		    }
-		}
-		else if((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME) ||
-		   (slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) || 
-		   (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME))
-		{
-		    // We're dealing with either a Standalone style slurl or slurl.com slurl
-		  if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) ||
-		      (slurl_uri.hostName() == LLSLURL::WWW_SLURL_COM) || 
-		      (slurl_uri.hostName() == LLSLURL::MAPS_SECONDLIFE_COM))
-			{
-				// slurl.com implies maingrid
-				mGrid = MAINGRID;
-			}
-		    else
-			{
-				// Don't try to match any old http://<host>/ URL as a SLurl.
-				// SLE SLurls will have the grid hostname in the URL, so only
-				// match http URLs if the hostname matches the grid hostname
-				// (or its a slurl.com or maps.secondlife.com URL).
-				if ((slurl_uri.scheme() == LLSLURL::SLURL_HTTP_SCHEME ||
-					 slurl_uri.scheme() == LLSLURL::SLURL_HTTPS_SCHEME) &&
-					slurl_uri.hostName() != LLGridManager::getInstance()->getGrid())
-				{
-					return;
-				}
-
-				// As it's a Standalone grid/open, we will always have a hostname, as Standalone/open  style
-				// urls are properly formed, unlike the stinky maingrid style
-				mGrid = slurl_uri.hostName();
-			}
-		    if (path_array.size() == 0)
-			{
-				// um, we need a path...
-				return;
-			}
-			
-			// we need to normalize the urls so
-			// the path portion starts with the 'command' that we want to do
-			// it can either be region or app.  
-		    if ((path_array[0].asString() == LLSLURL::SLURL_REGION_PATH) ||
-				(path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH))
-			{
-				// strip off 'region' or 'secondlife'
-				path_array.erase(0);
-				// it's a location
-				mType = LOCATION;
-			}
-			else if (path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
-			{
-				mType = APP;
-				path_array.erase(0);
-				// leave app appended.  
-			}
-			else
-			{
-				// not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL
-				return;
-			}
-		}
-		else
-		{
-		    // invalid scheme, so bail
-		    return;
-		}
-		
-		
-		if(path_array.size() == 0)
-		{
-			// we gotta have some stuff after the specifier as to whether it's a region or command
-			return;
-		}
-		
-		// now that we know whether it's an app slurl or a location slurl,
-		// parse the slurl into the proper data structures.
-		if(mType == APP)
-		{		
-			// grab the app command type and strip it (could be a command to jump somewhere, 
-			// or whatever )
-			mAppCmd = path_array[0].asString();
-			path_array.erase(0);
-			
-			// Grab the parameters
-			mAppPath = path_array;
-			// and the query
-			mAppQuery = slurl_uri.query();
-			mAppQueryMap = slurl_uri.queryMap();
-			return;
-		}
-		else if(mType == LOCATION)
-		{
-			// at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z 
-			// are collectively optional
-			// are optional
-
-			mRegion = LLURI::unescape(path_array[0].asString());
-
-			if(LLStringUtil::containsNonprintable(mRegion))
-			{
-				LLStringUtil::stripNonprintable(mRegion);
-			}
-
-			path_array.erase(0);
-			
-			// parse the x, y, and optionally z
-			if(path_array.size() >= 2)
-			{	
-			  
-			  mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)
-			  if((F32(mPosition[VX]) < 0.f) || 
-                             (mPosition[VX] > REGION_WIDTH_METERS) ||
-			     (F32(mPosition[VY]) < 0.f) || 
-                             (mPosition[VY] > REGION_WIDTH_METERS) ||
-			     (F32(mPosition[VZ]) < 0.f) || 
-                             (mPosition[VZ] > REGION_HEIGHT_METERS))
-			    {
-			      mType = INVALID;
-			      return;
-			    }
- 
-			}
-			else
-			{
-				// if x, y and z were not fully passed in, go to the middle of the region.
-				// teleport will adjust the actual location to make sure you're on the ground
-				// and such
-				mPosition = LLVector3(REGION_WIDTH_METERS/2, REGION_WIDTH_METERS/2, 0);
-			}
-		}
-	}
-}
 
+                // As it's a Standalone grid/open, we will always have a hostname, as Standalone/open  style
+                // urls are properly formed, unlike the stinky maingrid style
+                mGrid = slurl_uri.hostName();
+            }
+            if (path_array.size() == 0)
+            {
+                // um, we need a path...
+                return;
+            }
+
+            // we need to normalize the urls so
+            // the path portion starts with the 'command' that we want to do
+            // it can either be region or app.
+            if ((path_array[0].asString() == LLSLURL::SLURL_REGION_PATH) ||
+                (path_array[0].asString() == LLSLURL::SLURL_SECONDLIFE_PATH))
+            {
+                // strip off 'region' or 'secondlife'
+                path_array.erase(0);
+                // it's a location
+                mType = LOCATION;
+            }
+            else if (path_array[0].asString() == LLSLURL::SLURL_APP_PATH)
+            {
+                mType = APP;
+                path_array.erase(0);
+                // leave app appended.
+            }
+            else
+            {
+                // not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL
+                return;
+            }
+        }
+        else
+        {
+            // invalid scheme, so bail
+            return;
+        }
+
+        if (path_array.size() == 0)
+        {
+            // we gotta have some stuff after the specifier as to whether it's a region or command
+            return;
+        }
+
+        // now that we know whether it's an app slurl or a location slurl,
+        // parse the slurl into the proper data structures.
+        if (mType == APP)
+        {
+            // grab the app command type and strip it (could be a command to jump somewhere,
+            // or whatever )
+            mAppCmd = path_array[0].asString();
+            path_array.erase(0);
+
+            // Grab the parameters
+            mAppPath = path_array;
+            // and the query
+            mAppQuery = slurl_uri.query();
+            mAppQueryMap = slurl_uri.queryMap();
+            return;
+        }
+        else if (mType == LOCATION)
+        {
+            // at this point, head of the path array should be [ <region>, <x>, <y>, <z> ] where x, y and z
+            // are collectively optional
+            // are optional
+
+            mRegion = LLURI::unescape(path_array[0].asString());
+
+            if (LLStringUtil::containsNonprintable(mRegion))
+            {
+                LLStringUtil::stripNonprintable(mRegion);
+            }
+
+            path_array.erase(0);
+
+            // parse the x, y, and optionally z
+            if (path_array.size() >= 2)
+            {
+                mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)
+                if ((F32(mPosition[VX]) < 0.f) || (mPosition[VX] > REGION_WIDTH_METERS) ||
+                    (F32(mPosition[VY]) < 0.f) || (mPosition[VY] > REGION_WIDTH_METERS) ||
+                    (F32(mPosition[VZ]) < 0.f) || (mPosition[VZ] > REGION_HEIGHT_METERS))
+                {
+                    mType = INVALID;
+                    return;
+                }
+            }
+            else
+            {
+                // if x, y and z were not fully passed in, go to the middle of the region.
+                // teleport will adjust the actual location to make sure you're on the ground
+                // and such
+                mPosition = LLVector3(REGION_WIDTH_METERS / 2, REGION_WIDTH_METERS / 2, 0);
+            }
+        }
+    }
+}
 
 // Create a slurl for the middle of the region
-LLSLURL::LLSLURL(const std::string& grid, 
-				 const std::string& region)
+LLSLURL::LLSLURL(const std::string& grid, const std::string& region)
 {
-	mGrid = grid;
-	mRegion = region;
-	mType = LOCATION;
-	mPosition = LLVector3((F64)REGION_WIDTH_METERS/2, (F64)REGION_WIDTH_METERS/2, 0);
+    mGrid = grid;
+    mRegion = region;
+    mType = LOCATION;
+    mPosition = LLVector3((F64)REGION_WIDTH_METERS / 2, (F64)REGION_WIDTH_METERS / 2, 0);
 }
 
-
-
 // create a slurl given the position.  The position will be modded with the region
 // width handling global positions as well
-LLSLURL::LLSLURL(const std::string& grid, 
-		 const std::string& region, 
-		 const LLVector3& position)
+LLSLURL::LLSLURL(const std::string& grid,
+        const std::string& region,
+        const LLVector3& position)
 {
-	mGrid = grid;
-	mRegion = region;
-	S32 x = ll_round( (F32)fmod( position[VX], (F32)REGION_WIDTH_METERS ) );
-	S32 y = ll_round( (F32)fmod( position[VY], (F32)REGION_WIDTH_METERS ) );
-	S32 z = ll_round( (F32)position[VZ] );
-	mType = LOCATION;
-	mPosition = LLVector3(x, y, z);
+    mGrid = grid;
+    mRegion = region;
+    S32 x = ll_round((F32)fmod(position[VX], (F32)REGION_WIDTH_METERS));
+    S32 y = ll_round((F32)fmod(position[VY], (F32)REGION_WIDTH_METERS));
+    S32 z = ll_round((F32)position[VZ]);
+    mType = LOCATION;
+    mPosition = LLVector3(x, y, z);
 }
 
-
 // create a simstring
-LLSLURL::LLSLURL(const std::string& region, 
-		 const LLVector3& position)
+LLSLURL::LLSLURL(const std::string& region,
+        const LLVector3& position)
 {
-  *this = LLSLURL(LLGridManager::getInstance()->getGridId(),
-		  region, position);
+    *this = LLSLURL(LLGridManager::getInstance()->getGridId(), region, position);
 }
 
 // create a slurl from a global position
-LLSLURL::LLSLURL(const std::string& grid, 
-		 const std::string& region, 
-		 const LLVector3d& global_position)
+LLSLURL::LLSLURL(const std::string& grid,
+         const std::string& region,
+         const LLVector3d& global_position)
 {
-	*this = LLSLURL(LLGridManager::getInstance()->getGridId(grid),
-		  region, LLVector3(global_position.mdV[VX],
-				    global_position.mdV[VY],
-				    global_position.mdV[VZ]));
+    *this = LLSLURL(LLGridManager::getInstance()->getGridId(grid), region,
+        LLVector3(global_position.mdV[VX], global_position.mdV[VY], global_position.mdV[VZ]));
 }
 
 // create a slurl from a global position
-LLSLURL::LLSLURL(const std::string& region, 
-		 const LLVector3d& global_position)
+LLSLURL::LLSLURL(const std::string& region,
+        const LLVector3d& global_position)
 {
-  *this = LLSLURL(LLGridManager::getInstance()->getGridId(),
-		  region, global_position);
+    *this = LLSLURL(LLGridManager::getInstance()->getGridId(),
+        region, global_position);
 }
 
 LLSLURL::LLSLURL(const std::string& command, const LLUUID&id, const std::string& verb)
 {
-  mType = APP;
-  mAppCmd = command;
-  mAppPath = LLSD::emptyArray();
-  mAppPath.append(LLSD(id));
-  mAppPath.append(LLSD(verb));
+    mType = APP;
+    mAppCmd = command;
+    mAppPath = LLSD::emptyArray();
+    mAppPath.append(LLSD(id));
+    mAppPath.append(LLSD(verb));
 }
 
-
 std::string LLSLURL::getSLURLString() const
 {
-	switch(mType)
-	{
-		case HOME_LOCATION:
-			return SIM_LOCATION_HOME;
-		case LAST_LOCATION:
-			return SIM_LOCATION_LAST;
-		case LOCATION:
-			{
-				// lookup the grid
-				S32 x = ll_round( (F32)mPosition[VX] );
-				S32 y = ll_round( (F32)mPosition[VY] );
-				S32 z = ll_round( (F32)mPosition[VZ] );	
-				return LLGridManager::getInstance()->getSLURLBase(mGrid) + 
-				LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); 
-			}
-		case APP:
-		{
-			std::ostringstream app_url;
-			app_url << LLGridManager::getInstance()->getAppSLURLBase() << "/" << mAppCmd;
-			for(LLSD::array_const_iterator i = mAppPath.beginArray();
-				i != mAppPath.endArray();
-				i++)
-			{
-				app_url << "/" << i->asString();
-			}
-			if(mAppQuery.length() > 0)
-			{
-				app_url << "?" << mAppQuery;
-			}
-			return app_url.str();
-		}	
-		default:
-			LL_WARNS("AppInit") << "Unexpected SLURL type for SLURL string" << (int)mType << LL_ENDL;			
-			return std::string();
-	}
+    switch (mType)
+    {
+        case HOME_LOCATION:
+            return SIM_LOCATION_HOME;
+        case LAST_LOCATION:
+            return SIM_LOCATION_LAST;
+        case LOCATION:
+        {
+            // lookup the grid
+            S32 x = ll_round((F32)mPosition[VX]);
+            S32 y = ll_round((F32)mPosition[VY]);
+            S32 z = ll_round((F32)mPosition[VZ]);
+            return LLGridManager::getInstance()->getSLURLBase(mGrid) +
+                LLURI::escape(mRegion) + llformat("/%d/%d/%d", x, y, z);
+        }
+        case APP:
+        {
+            std::ostringstream app_url;
+            app_url << LLGridManager::getInstance()->getAppSLURLBase() << "/" << mAppCmd;
+            for (LLSD::array_const_iterator i = mAppPath.beginArray();
+                i != mAppPath.endArray();
+                i++)
+            {
+                app_url << "/" << i->asString();
+            }
+            if (mAppQuery.length() > 0)
+            {
+                app_url << "?" << mAppQuery;
+            }
+            return app_url.str();
+        }
+        default:
+            LL_WARNS("AppInit") << "Unexpected SLURL type for SLURL string" << (int)mType << LL_ENDL;
+            return std::string();
+    }
 }
 
 std::string LLSLURL::getLoginString() const
 {
-	
-	std::stringstream unescaped_start;
-	switch(mType)
-	{
-		case LOCATION:
-			unescaped_start << "uri:" 
-			<< mRegion << "&" 
-			<< ll_round(mPosition[0]) << "&" 
-			<< ll_round(mPosition[1]) << "&" 
-			<< ll_round(mPosition[2]);
-			break;
-		case HOME_LOCATION:
-			unescaped_start << "home";
-			break;
-		case LAST_LOCATION:
-			unescaped_start << "last";
-			break;
-		default:
-			LL_WARNS("AppInit") << "Unexpected SLURL type ("<<(int)mType <<")for login string"<< LL_ENDL;
-			break;
-	}
-	return  xml_escape_string(unescaped_start.str());
+    std::stringstream unescaped_start;
+    switch (mType)
+    {
+        case LOCATION:
+            unescaped_start << "uri:"
+                << mRegion << "&"
+                << ll_round(mPosition[0]) << "&"
+                << ll_round(mPosition[1]) << "&"
+                << ll_round(mPosition[2]);
+            break;
+        case HOME_LOCATION:
+            unescaped_start << "home";
+            break;
+        case LAST_LOCATION:
+            unescaped_start << "last";
+            break;
+        default:
+            LL_WARNS("AppInit") << "Unexpected SLURL type (" << (int)mType << ")for login string" << LL_ENDL;
+            break;
+    }
+    return  xml_escape_string(unescaped_start.str());
 }
 
-bool LLSLURL::operator==(const LLSLURL& rhs)
+bool LLSLURL::operator ==(const LLSLURL& rhs)
 {
-	if(rhs.mType != mType) return false;
-	switch(mType)
-	{
-		case LOCATION:
-			return ((mGrid == rhs.mGrid) &&
-					(mRegion == rhs.mRegion) &&
-					(mPosition == rhs.mPosition));
-		case APP:
-			return getSLURLString() == rhs.getSLURLString();
-			
-		case HOME_LOCATION:
-		case LAST_LOCATION:
-			return true;
-		default:
-			return false;
-	}
+    if (rhs.mType != mType)
+        return false;
+
+    switch (mType)
+    {
+        case LOCATION:
+            return (mGrid == rhs.mGrid) &&
+                    (mRegion == rhs.mRegion) &&
+                    (mPosition == rhs.mPosition);
+
+        case APP:
+            return getSLURLString() == rhs.getSLURLString();
+
+        case HOME_LOCATION:
+        case LAST_LOCATION:
+            return true;
+    }
+
+    return false;
 }
 
 bool LLSLURL::operator !=(const LLSLURL& rhs)
 {
-	return !(*this == rhs);
+    return !(*this == rhs);
 }
 
 std::string LLSLURL::getLocationString() const
 {
-	return llformat("%s/%d/%d/%d",
-					mRegion.c_str(),
-					(int)ll_round(mPosition[0]),
-					(int)ll_round(mPosition[1]),
-					(int)ll_round(mPosition[2]));						 
+    return llformat("%s/%d/%d/%d",
+        mRegion.c_str(),
+        (int)ll_round(mPosition[0]),
+        (int)ll_round(mPosition[1]),
+        (int)ll_round(mPosition[2]));
 }
 
 // static
-const std::string LLSLURL::typeName[NUM_SLURL_TYPES] = 
+const std::string LLSLURL::typeName[NUM_SLURL_TYPES] =
 {
-	"INVALID", 
-	"LOCATION",
-	"HOME_LOCATION",
-	"LAST_LOCATION",
-	"APP",
-	"HELP"
+    "INVALID",
+    "LOCATION",
+    "HOME_LOCATION",
+    "LAST_LOCATION",
+    "APP",
+    "HELP",
+    "EMPTY"
 };
-		
+
 std::string LLSLURL::getTypeString(SLURL_TYPE type)
 {
-	std::string name;
-	if ( type >= INVALID && type < NUM_SLURL_TYPES )
-	{
-		name = LLSLURL::typeName[type];
-	}
-	else
-	{
-		name = llformat("Out of Range (%d)",type);
-	}
-	return name;
+    std::string name;
+    if (type >= INVALID && type < NUM_SLURL_TYPES)
+    {
+        name = LLSLURL::typeName[type];
+    }
+    else
+    {
+        name = llformat("Out of Range (%d)", type);
+    }
+    return name;
 }
 
-
 std::string LLSLURL::asString() const
 {
     std::ostringstream result;
     result
-		<< "   mType: " << LLSLURL::getTypeString(mType)
-		<< "   mGrid: " + getGrid()
-		<< "   mRegion: " + getRegion()
-		<< "   mPosition: " << mPosition
-		<< "   mAppCmd:"  << getAppCmd()
-		<< "   mAppPath:" + getAppPath().asString()
-		<< "   mAppQueryMap:" + getAppQueryMap().asString()
-		<< "   mAppQuery: " + getAppQuery()
-		;
-	
+        << "   mType: " << LLSLURL::getTypeString(mType)
+        << "   mGrid: " + getGrid()
+        << "   mRegion: " + getRegion()
+        << "   mPosition: " << mPosition
+        << "   mAppCmd:"  << getAppCmd()
+        << "   mAppPath:" + getAppPath().asString()
+        << "   mAppQueryMap:" + getAppQueryMap().asString()
+        << "   mAppQuery: " + getAppQuery()
+        ;
+
     return result.str();
 }
-
diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp
index eabf9228755..8d21b6ed696 100644
--- a/indra/newview/tests/llslurl_test.cpp
+++ b/indra/newview/tests/llslurl_test.cpp
@@ -187,6 +187,12 @@ namespace tut
 		ensure_equals("maps.secondlife.com slurl, region + coords", slurl.getSLURLString(),
 					  "http://maps.secondlife.com/secondlife/myregion/1/2/3");
 
+		slurl = LLSLURL("secondlife://");
+		ensure_equals("secondlife: slurl, empty - type", slurl.getType(), LLSLURL::EMPTY);
+
+		slurl = LLSLURL("secondlife:///");
+		ensure_equals("secondlife: slurl, root - type", slurl.getType(), LLSLURL::EMPTY);
+
 		slurl = LLSLURL("secondlife://myregion");
 		ensure_equals("secondlife: slurl, region only - type", slurl.getType(), LLSLURL::LOCATION);
 		ensure_equals("secondlife: slurl, region only", slurl.getSLURLString(),
-- 
GitLab