diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 1a183d61f35811e9e9c44ad5fa6043670a66859d..c9bfc1d2968ec9aeac1be05669e8774164d284f7 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1523,6 +1523,19 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
 		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
 		{
 			LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL;
+
+			if(getNavState() == MEDIANAVSTATE_BEGUN)
+			{
+				setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED);
+			}
+			else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN)
+			{
+				setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED);
+			}
+			else
+			{
+				// all other cases need to leave the state alone.
+			}
 		}
 		break;
 		
@@ -1725,9 +1738,11 @@ void LLViewerMediaImpl::setNavState(EMediaNavState state)
 		case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break;
 		case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break;
 		case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break;
+		case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break;
 		case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break;
 		case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break;
 		case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break;
+		case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break;
 	}
 }
 
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 05c67eda4714a408fe06d3dc56cb7acd71e8afb1..fc2776ee91eeca10e69a72e08c0a6531081b5ffa 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -243,12 +243,14 @@ class LLViewerMediaImpl
 	
 	typedef enum 
 	{
-		MEDIANAVSTATE_NONE,								// State is outside what we need to track for navigation.
-		MEDIANAVSTATE_BEGUN,							// a MEDIA_EVENT_NAVIGATE_BEGIN has been received which was not server-directed
-		MEDIANAVSTATE_FIRST_LOCATION_CHANGED,			// first LOCATION_CHANGED event after a non-server-directed BEGIN
-		MEDIANAVSTATE_SERVER_SENT,						// server-directed nav has been requested, but MEDIA_EVENT_NAVIGATE_BEGIN hasn't been received yet
-		MEDIANAVSTATE_SERVER_BEGUN,						// MEDIA_EVENT_NAVIGATE_BEGIN has been received which was server-directed
-		MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED		// first LOCATION_CHANGED event after a server-directed BEGIN
+		MEDIANAVSTATE_NONE,										// State is outside what we need to track for navigation.
+		MEDIANAVSTATE_BEGUN,									// a MEDIA_EVENT_NAVIGATE_BEGIN has been received which was not server-directed
+		MEDIANAVSTATE_FIRST_LOCATION_CHANGED,					// first LOCATION_CHANGED event after a non-server-directed BEGIN
+		MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED,			// we received a NAVIGATE_COMPLETE event before the first LOCATION_CHANGED
+		MEDIANAVSTATE_SERVER_SENT,								// server-directed nav has been requested, but MEDIA_EVENT_NAVIGATE_BEGIN hasn't been received yet
+		MEDIANAVSTATE_SERVER_BEGUN,								// MEDIA_EVENT_NAVIGATE_BEGIN has been received which was server-directed
+		MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED,			// first LOCATION_CHANGED event after a server-directed BEGIN
+		MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED	// we received a NAVIGATE_COMPLETE event before the first LOCATION_CHANGED
 		
 	}EMediaNavState;
     
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 1704f633765c81db865f78d1149b55540c724300..98b3ba8f45251a086bf0ef1ae41d0590a084a7c8 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1834,6 +1834,53 @@ bool LLVOVolume::hasNavigatePermission(const LLMediaEntry* media_entry)
     
 }
 
+void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location)
+{
+	bool block_navigation = false;
+	// FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed
+	// to deal with multiple face indices.
+	int face_index = getFaceIndexWithMediaImpl(impl, -1);
+	
+	// Find the media entry for this navigate
+	LLMediaEntry* mep = NULL;
+	LLTextureEntry *te = getTE(face_index);
+	if(te)
+	{
+		mep = te->getMediaData();
+	}
+	
+	if(mep)
+	{
+		if(!mep->checkCandidateUrl(new_location))
+		{
+			block_navigation = true;
+		}
+		if (!block_navigation && !hasNavigatePermission(mep))
+		{
+			block_navigation = true;
+		}
+	}
+	else
+	{
+		llwarns << "Couldn't find media entry!" << llendl;
+	}
+						
+	if(block_navigation)
+	{
+		llinfos << "blocking navigate to URI " << new_location << llendl;
+
+		// "bounce back" to the current URL from the media entry
+		mediaNavigateBounceBack(face_index);
+	}
+	else
+	{
+		
+		llinfos << "broadcasting navigate with URI " << new_location << llendl;
+
+		sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this), face_index, new_location);
+	}
+}
+
 void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event)
 {
 	switch(event)
@@ -1845,52 +1892,8 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
 			{
 				case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED:
 				{
-					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast.
-
-					bool block_navigation = false;
-					// FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed
-					// to deal with multiple face indices.
-					int face_index = getFaceIndexWithMediaImpl(impl, -1);
-					std::string new_location = plugin->getLocation();
-					
-					// Find the media entry for this navigate
-					LLMediaEntry* mep = NULL;
-					LLTextureEntry *te = getTE(face_index);
-					if(te)
-					{
-						mep = te->getMediaData();
-					}
-					
-					if(mep)
-					{
-						if(!mep->checkCandidateUrl(new_location))
-						{
-							block_navigation = true;
-						}
-                        if (!block_navigation && !hasNavigatePermission(mep))
-                        {
-                            block_navigation = true;
-                        }
-					}
-					else
-					{
-						llwarns << "Couldn't find media entry!" << llendl;
-					}
-										
-					if(block_navigation)
-					{
-						llinfos << "blocking navigate to URI " << new_location << llendl;
-
-						// "bounce back" to the current URL from the media entry
-						mediaNavigateBounceBack(face_index);
-					}
-					else
-					{
-						
-						llinfos << "broadcasting navigate with URI " << new_location << llendl;
-
-						sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this), face_index, new_location);
-					}
+					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast or bounced back.
+					mediaNavigated(impl, plugin, plugin->getLocation());
 				}
 				break;
 				
@@ -1907,6 +1910,29 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
 		}
 		break;
 		
+		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
+		{
+			switch(impl->getNavState())
+			{
+				case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED:
+				{
+					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast or bounced back.
+					mediaNavigated(impl, plugin, plugin->getNavigateURI());
+				}
+				break;
+				
+				case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED:
+					// This is the the navigate complete event from a server-directed nav.  Don't broadcast it.
+					llinfos << "	NOT broadcasting navigate (server-directed)" << llendl;
+				break;
+				
+				default:
+					// For all other states, the navigate should have been handled by LOCATION_CHANGED events already.
+				break;
+			}
+		}
+		break;
+		
 		default:
 		break;
 	}
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 90dfa2204bec2396b21dbf0ab612a51f95e92a8d..d8ae9a545315e6da68f566abd91112d11e4eb716 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -245,6 +245,7 @@ class LLVOVolume : public LLViewerObject
     // Returns whether or not this object has permission to navigate the given media entry
     bool hasNavigatePermission(const LLMediaEntry* media_entry);
     
+	void mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location);
 	void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event);
 
 	// Sync the given media data with the impl and the given te