diff --git a/MTA10/core/CWebCore.cpp b/MTA10/core/CWebCore.cpp index f2cd060eea..16c7d469c9 100644 --- a/MTA10/core/CWebCore.cpp +++ b/MTA10/core/CWebCore.cpp @@ -51,7 +51,7 @@ bool CWebCore::Initialise () { CefMainArgs mainArgs; void* sandboxInfo = nullptr; - CefRefPtr app = new CCefApp; + CefRefPtr app { new CCefApp }; #if CEF_ENABLE_SANDBOX CefScopedSandboxInfo scopedSandbox; @@ -88,6 +88,7 @@ bool CWebCore::Initialise () // Register custom scheme handler factory CefRegisterSchemeHandlerFactory ( "mtalocal", "", app ); + CefRegisterSchemeHandlerFactory ( "http", "mta", app ); return state; } @@ -784,10 +785,7 @@ void CCefApp::OnRegisterCustomSchemes ( CefRefPtr < CefSchemeRegistrar > registr CefRefPtr CCefApp::Create ( CefRefPtr browser, CefRefPtr frame, const CefString& scheme_name, CefRefPtr request ) { - if (scheme_name != "mtalocal") - return nullptr; - - CWebCore* pWebCore = static_cast(g_pCore->GetWebCore ()); + CWebCore* pWebCore = static_cast ( g_pCore->GetWebCore () ); auto pWebView = pWebCore->FindWebView ( browser ); if ( !pWebView || !pWebView->IsLocal () ) return nullptr; @@ -796,64 +794,137 @@ CefRefPtr CCefApp::Create ( CefRefPtr browser, C if ( !CefParseURL ( request->GetURL (), urlParts ) ) return nullptr; - // Get full path - SString path = UTF16ToMbUTF8 ( urlParts.path.str ).substr ( 2 ); + if ( scheme_name == "mtalocal" ) // Backward compatibility + { + // Get full path + SString path = UTF16ToMbUTF8 ( urlParts.path.str ).substr ( 2 ); - // Get mime type from extension - CefString mimeType; - size_t pos = path.find_last_of ( '.' ); - if ( pos != std::string::npos ) - mimeType = CefGetMimeType ( path.substr ( pos + 1 ) ); + // Check if we're dealing with an external resource + if ( path[0] == ':' ) + { + size_t end = path.find_first_of ( '/' ); + if ( end != std::string::npos ) + { + SString resourceName = path.substr ( 1, end-1 ); + SString resourcePath = path.substr ( end ); - // Make sure we provide a mime type, even - // when we cannot deduct it from the file extension - if ( mimeType.empty () ) - mimeType = "application/octet-stream"; + // Call this function recursively and use the mta scheme instead + request->SetURL ( "http://mta/local/" + resourceName + resourcePath ); + return Create ( browser, frame, "http", request ); + } + return nullptr; + } + + // Redirect mtalocal://* to http://mta/local/*, call recursively + request->SetURL ( "http://mta/local/" + path ); + return Create ( browser, frame, "http", request ); + } + + SString host = UTF16ToMbUTF8 ( urlParts.host.str ); + if ( scheme_name == "http" && host == "mta" ) + { + // Scheme format: http://mta/resourceName/file.html or http://mta/local/file.html for the current resource + // Get resource name and path + SString path = UTF16ToMbUTF8 ( urlParts.path.str ).substr ( 1 ); // Remove slash at the front + size_t slashPos = path.find ( '/' ); + if ( slashPos == std::string::npos ) + return nullptr; - if( pWebView->HasAjaxHandler ( path ) ) - { - std::vector vecGet; - std::vector vecPost; + SString resourceName = path.substr ( 0, slashPos ); + SString resourcePath = path.substr ( slashPos + 1 ); - SString strGet = UTF16ToMbUTF8(urlParts.query.str); - std::vector vecTmp; - strGet.Split ( "&", vecTmp, 0, 0 ); + if ( resourcePath.empty () ) + return nullptr; - SString key; SString value; - for ( auto&& param : vecTmp ) - { - param.Split ( "=", &key, &value ); - vecGet.push_back ( key ); - vecGet.push_back ( value ); - } + // Get mime type from extension + CefString mimeType; + size_t pos = resourcePath.find_last_of ( '.' ); + if ( pos != std::string::npos ) + mimeType = CefGetMimeType ( resourcePath.substr ( pos + 1 ) ); - // ToDo: POST Information is Empty for non-standard URI schemes - // Getting POST parameters into Lua will require changing - // mtalocal:// to a standard scheme first - /* - CefPostData::ElementVector vecPostElements; - request->GetPostData ().get ()->GetElements ( vecPostElements ); + // Make sure we provide a mime type, even + // when we cannot deduct it from the file extension + if ( mimeType.empty () ) + mimeType = "application/octet-stream"; - for ( auto&& post : vecPostElements ) + if ( pWebView->HasAjaxHandler ( resourcePath ) ) { - // ToDo: Parse POST data into our vector + std::vector vecGet; + std::vector vecPost; + + if ( urlParts.query.str != nullptr ) + { + SString strGet = UTF16ToMbUTF8 ( urlParts.query.str ); + std::vector vecTmp; + strGet.Split ( "&", vecTmp ); + + SString key; SString value; + for ( auto&& param : vecTmp ) + { + param.Split ( "=", &key, &value ); + vecGet.push_back ( key ); + vecGet.push_back ( value ); + } + } + + CefPostData::ElementVector vecPostElements; + auto postData = request->GetPostData (); + if ( postData.get () ) + { + request->GetPostData ()->GetElements ( vecPostElements ); + + SString key; SString value; + for ( auto&& post : vecPostElements ) + { + // Limit to 5MiB and allow byte data only + size_t bytesCount = post->GetBytesCount (); + if ( bytesCount > 5*1024*1024 || post->GetType () != CefPostDataElement::Type::PDE_TYPE_BYTES ) + continue; + + // Make string from buffer + std::unique_ptr buffer { new char[bytesCount] }; + post->GetBytes ( bytesCount, buffer.get () ); + SStringX param ( buffer.get (), bytesCount ); + + // Parse POST data into vector + std::vector vecTmp; + param.Split ( "&", vecTmp ); + + for ( auto&& param : vecTmp ) + { + param.Split ( "=", &key, &value ); + vecPost.push_back ( key ); + vecPost.push_back ( value ); + } + } + } + + auto handler = new CAjaxResourceHandler ( vecGet, vecPost, mimeType ); + pWebView->HandleAjaxRequest ( resourcePath, handler ); + return handler; } - */ + else + { + // Calculate MTA resource path + if ( resourceName != "local" ) + path = ":" + resourceName + "/" + resourcePath; + else + path = resourcePath; - auto handler = new CAjaxResourceHandler ( vecGet, vecPost, mimeType ); - pWebView->HandleAjaxRequest ( path, handler ); - return handler; - } - else - { - if ( !pWebView->GetFullPathFromLocal ( path ) ) - return nullptr; + // Calculate absolute path + if ( !pWebView->GetFullPathFromLocal ( path ) ) + return nullptr; - auto stream = CefStreamReader::CreateForFile ( path ); - if ( stream.get () ) - return new CefStreamResourceHandler ( mimeType, stream ); + // Finally, load the file stream + auto stream = CefStreamReader::CreateForFile ( path ); + if ( stream.get () ) + return new CefStreamResourceHandler ( mimeType, stream ); + } + + return nullptr; } + // Return null if there is no matching scheme return nullptr; } diff --git a/MTA10/core/CWebView.cpp b/MTA10/core/CWebView.cpp index 88acc532fc..a02f9992e1 100644 --- a/MTA10/core/CWebView.cpp +++ b/MTA10/core/CWebView.cpp @@ -603,10 +603,16 @@ bool CWebView::OnBeforeBrowse ( CefRefPtr browser, CefRefPtrGetWebCore ()->GetURLState ( UTF16ToMbUTF8 ( urlParts.host.str ), true ) != eURLState::WEBPAGE_ALLOWED ) - bResult = true; // Block remote here + SString host = UTF16ToMbUTF8 ( urlParts.host.str ); + if ( host != "mta" ) + { + if ( IsLocal () || g_pCore->GetWebCore ()->GetURLState ( host, true ) != eURLState::WEBPAGE_ALLOWED ) + bResult = true; // Block remote here + else + bResult = false; // Allow + } else - bResult = false; // Allow + bResult = false; } else if ( scheme == L"mtalocal" ) bResult = false; // Allow mtalocal:// URLs @@ -658,22 +664,27 @@ CefRequestHandler::ReturnValue CWebView::OnBeforeResourceLoad ( CefRefPtrGetWebCore ()->GetURLState ( domain, true ); - if ( urlState != eURLState::WEBPAGE_ALLOWED ) + if ( domain != "mta" ) { - // Trigger onClientBrowserResourceBlocked event - auto func = std::bind ( &CWebBrowserEventsInterface::Events_OnResourceBlocked, m_pEventsInterface, - SString ( request->GetURL () ), domain, urlState == eURLState::WEBPAGE_NOT_LISTED ? 0 : 1 ); - g_pCore->GetWebCore ()->AddEventToEventQueue ( func, this, "OnResourceBlocked" ); + if ( IsLocal () ) + return RV_CANCEL; // Block remote requests in local mode generally - return RV_CANCEL; // Block if explicitly forbidden - } + eURLState urlState = g_pCore->GetWebCore ()->GetURLState ( domain, true ); + if ( urlState != eURLState::WEBPAGE_ALLOWED ) + { + // Trigger onClientBrowserResourceBlocked event + auto func = std::bind ( &CWebBrowserEventsInterface::Events_OnResourceBlocked, m_pEventsInterface, + SString ( request->GetURL () ), domain, urlState == eURLState::WEBPAGE_NOT_LISTED ? 0 : 1 ); + g_pCore->GetWebCore ()->AddEventToEventQueue ( func, this, "OnResourceBlocked" ); - // Allow - return RV_CONTINUE; + return RV_CANCEL; // Block if explicitly forbidden + } + + // Allow + return RV_CONTINUE; + } + else + return RV_CONTINUE; } else if ( scheme == L"mtalocal" ) { diff --git a/MTA10/mods/shared_logic/lua/CLuaFunctionDefs.Browser.cpp b/MTA10/mods/shared_logic/lua/CLuaFunctionDefs.Browser.cpp index e279618422..c49782becb 100644 --- a/MTA10/mods/shared_logic/lua/CLuaFunctionDefs.Browser.cpp +++ b/MTA10/mods/shared_logic/lua/CLuaFunctionDefs.Browser.cpp @@ -101,7 +101,14 @@ int CLuaFunctionDefs::LoadBrowserURL ( lua_State* luaVM ) // Are we dealing with a remote website? if ( strURL.substr ( 0, 7 ) == "http://" || strURL.substr ( 0, 8 ) == "https://" ) { - lua_pushboolean ( luaVM, pWebBrowser->LoadURL ( strURL, true, strPostData, bURLEncoded ) ); + bool isLocalURL = strURL.substr ( 0, 11 ) == "http://mta/"; + if ( pWebBrowser->IsLocal () != isLocalURL ) + { + lua_pushboolean ( luaVM, false ); + return 1; + } + + lua_pushboolean ( luaVM, pWebBrowser->LoadURL ( strURL, !isLocalURL, strPostData, bURLEncoded ) ); return 1; } @@ -114,6 +121,9 @@ int CLuaFunctionDefs::LoadBrowserURL ( lua_State* luaVM ) CResource* pResource = pLuaMain->GetResource (); if ( CResourceManager::ParseResourcePathInput ( strURL, pResource, strAbsPath ) && pWebBrowser->IsLocal () ) { + // Output deprecated warning, TODO: Remove this at a later point + m_pScriptDebugging->LogWarning ( luaVM, "This URL scheme is deprecated and may not work in future versions. Please consider using http://mta/* instead. See https://wiki.mtasa.com/wiki/LoadBrowserURL for details" ); + pWebBrowser->SetTempURL ( strURL ); lua_pushboolean ( luaVM, pWebBrowser->LoadURL ( "mtalocal://" + strURL, false, strPostData, bURLEncoded ) ); return 1;