CefRefPtr<CefResourceHandler> CCefApp::Create ( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& scheme_name, CefRefPtr<CefRequest> request ) { CWebCore* pWebCore = static_cast<CWebCore*> ( g_pCore->GetWebCore () ); auto pWebView = pWebCore->FindWebView ( browser ); if ( !pWebView || !pWebView->IsLocal () ) return nullptr; CefURLParts urlParts; if ( !CefParseURL ( request->GetURL (), urlParts ) ) return nullptr; if ( scheme_name == "mtalocal" ) // Backward compatibility { // Get full path SString path = UTF16ToMbUTF8 ( urlParts.path.str ).substr ( 2 ); // 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 ); // 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; SString resourceName = path.substr ( 0, slashPos ); SString resourcePath = path.substr ( slashPos + 1 ); if ( resourcePath.empty () ) return nullptr; // 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 ) ); // Make sure we provide a mime type, even // when we cannot deduct it from the file extension if ( mimeType.empty () ) mimeType = "application/octet-stream"; if ( pWebView->HasAjaxHandler ( resourcePath ) ) { std::vector<SString> vecGet; std::vector<SString> vecPost; if ( urlParts.query.str != nullptr ) { SString strGet = UTF16ToMbUTF8 ( urlParts.query.str ); std::vector<SString> 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<char[]> buffer { new char[bytesCount] }; post->GetBytes ( bytesCount, buffer.get () ); SStringX param ( buffer.get (), bytesCount ); // Parse POST data into vector std::vector<SString> 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; // Calculate absolute path if ( !pWebView->GetFullPathFromLocal ( path ) ) return nullptr; // 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; }
bool CLuaMain::LoadScriptFromBuffer ( const char* cpInBuffer, unsigned int uiInSize, const char* szFileName ) { SString strNiceFilename = ConformResourcePath( szFileName ); // Decrypt if required const char* cpBuffer; uint uiSize; if ( !g_pRealNetServer->DecryptScript( cpInBuffer, uiInSize, &cpBuffer, &uiSize, strNiceFilename ) ) { SString strMessage( "%s is invalid. Please re-compile at http://luac.mtasa.com/", *strNiceFilename ); g_pGame->GetScriptDebugging()->LogError ( m_luaVM, "Loading script failed: %s", *strMessage ); return false; } bool bUTF8; // UTF-8 BOM? Compare by checking the standard UTF-8 BOM if ( IsUTF8BOM( cpBuffer, uiSize ) == false ) { // Maybe not UTF-8, if we have a >80% heuristic detection confidence, assume it is bUTF8 = ( GetUTF8Confidence ( (const unsigned char*)cpBuffer, uiSize ) >= 80 ); } else { // If there's a BOM, load ignoring the first 3 bytes bUTF8 = true; cpBuffer += 3; uiSize -= 3; } // If compiled script, make sure correct chunkname is embedded EmbedChunkName( strNiceFilename, &cpBuffer, &uiSize ); if ( m_luaVM ) { // Are we not marked as UTF-8 already, and not precompiled? std::string strUTFScript; if ( !bUTF8 && !IsLuaCompiledScript( cpBuffer, uiSize ) ) { std::string strBuffer = std::string(cpBuffer, uiSize); #ifdef WIN32 std::setlocale(LC_CTYPE,""); // Temporarilly use locales to read the script strUTFScript = UTF16ToMbUTF8(ANSIToUTF16( strBuffer )); std::setlocale(LC_CTYPE,"C"); #else strUTFScript = UTF16ToMbUTF8(ANSIToUTF16( strBuffer )); #endif if ( uiSize != strUTFScript.size() ) { uiSize = strUTFScript.size(); g_pGame->GetScriptDebugging()->LogWarning ( m_luaVM, "Script '%s' is not encoded in UTF-8. Loading as ANSI...", strNiceFilename.c_str() ); } } else strUTFScript = std::string(cpBuffer, uiSize); // Run the script if ( CLuaMain::LuaLoadBuffer ( m_luaVM, bUTF8 ? cpBuffer : strUTFScript.c_str(), uiSize, SString ( "@%s", *strNiceFilename ) ) ) { // Print the error std::string strRes = lua_tostring( m_luaVM, -1 ); if ( strRes.length () ) { CLogger::LogPrintf ( "SCRIPT ERROR: %s\n", strRes.c_str () ); g_pGame->GetScriptDebugging()->LogError ( m_luaVM, "Loading script failed: %s", strRes.c_str () ); } else { CLogger::LogPrint ( "SCRIPT ERROR: Unknown\n" ); g_pGame->GetScriptDebugging()->LogError ( m_luaVM, "Loading script failed for unknown reason" ); } } else { ResetInstructionCount (); int luaSavedTop = lua_gettop ( m_luaVM ); int iret = this->PCall ( m_luaVM, 0, LUA_MULTRET, 0 ) ; if ( iret == LUA_ERRRUN || iret == LUA_ERRMEM ) { SString strRes = lua_tostring( m_luaVM, -1 ); g_pGame->GetScriptDebugging()->LogPCallError( m_luaVM, strRes, true ); } // Cleanup any return values if ( lua_gettop ( m_luaVM ) > luaSavedTop ) lua_settop( m_luaVM, luaSavedTop ); return true; } } return false; }
/////////////////////////////////////////////////////////////// // // CResourceChecker::CheckLuaSourceForIssues // // Look for function names not in comment blocks // Note: Ignores quotes // /////////////////////////////////////////////////////////////// void CResourceChecker::CheckLuaSourceForIssues ( string strLuaSource, const string& strFileName, const string& strResourceName, bool bClientScript, bool bCompiledScript, ECheckerModeType checkerMode, string* pstrOutResult ) { CHashMap < SString, long > doneWarningMap; long lLineNumber = 1; // Check if this is a UTF-8 script bool bUTF8 = IsUTF8BOM( strLuaSource.c_str(), strLuaSource.length() ); // If it's not a UTF8 script, does it contain foreign language characters that should be upgraded? if ( !bCompiledScript && !bUTF8 && GetUTF8Confidence ( (const unsigned char*)&strLuaSource.at ( 0 ), strLuaSource.length() ) < 80 ) { std::wstring strUTF16Script = ANSIToUTF16 ( strLuaSource ); #ifdef WIN32 std::setlocale(LC_CTYPE,""); // Temporarilly use locales to read the script std::string strUTFScript = UTF16ToMbUTF8 ( strUTF16Script ); std::setlocale(LC_CTYPE,"C"); #else std::string strUTFScript = UTF16ToMbUTF8 ( strUTF16Script ); #endif if ( strLuaSource.length () != strUTFScript.size() ) { // In-place upgrade... if ( checkerMode == ECheckerMode::UPGRADE ) { // Upgrade only if there is no problem ( setlocale() issue? ) if ( strUTF16Script != L"?" ) { // Convert our script to ANSI, appending a BOM at the beginning strLuaSource = "\xEF\xBB\xBF" + strUTFScript; } } if ( checkerMode == ECheckerMode::WARNINGS ) { m_ulDeprecatedWarningCount++; CLogger::LogPrintf ( "WARNING: %s/%s [%s] is encoded in ANSI instead of UTF-8. Please convert your file to UTF-8.\n", strResourceName.c_str (), strFileName.c_str (), bClientScript ? "Client" : "Server" ); } } } // Step through each identifier in the file. for ( long lPos = 0 ; lPos < (long)strLuaSource.length () ; lPos++ ) { long lNameLength; long lNameOffset = FindLuaIdentifier ( strLuaSource.c_str () + lPos, &lNameLength, &lLineNumber ); if ( lNameOffset == - 1 ) break; lNameOffset += lPos; // Make offset absolute from the start of the file lPos = lNameOffset + lNameLength; // Adjust so the next pass starts from just after this identifier string strIdentifierName( strLuaSource.c_str () + lNameOffset, lNameLength ); // In-place upgrade... if ( checkerMode == ECheckerMode::UPGRADE ) { assert ( !bCompiledScript ); string strUpgraded; if ( UpgradeLuaFunctionName( strIdentifierName, bClientScript, strUpgraded ) ) { // Old head string strHead( strLuaSource.c_str (), lNameOffset ); // Old tail string strTail( strLuaSource.c_str () + lNameOffset + lNameLength ); // New source strLuaSource = strHead + strUpgraded + strTail; lPos += -lNameLength + strUpgraded.length (); } CheckVersionRequirements ( strIdentifierName, bClientScript ); } // Log warnings... if ( checkerMode == ECheckerMode::WARNINGS ) { // Only do the identifier once per file if ( doneWarningMap.find ( strIdentifierName ) == doneWarningMap.end () ) { doneWarningMap[strIdentifierName] = 1; if ( !bCompiledScript ) // Don't issue deprecated function warnings if the script is compiled, because we can't upgrade it IssueLuaFunctionNameWarnings ( strIdentifierName, strFileName, strResourceName, bClientScript, lLineNumber ); CheckVersionRequirements ( strIdentifierName, bClientScript ); } } } if ( pstrOutResult ) *pstrOutResult = strLuaSource; }
//////////////////////////////////////////////////////////////////// // // // Implementation: CefDisplayHandler::OnTooltip // // http://magpcss.org/ceforum/apidocs3/projects/(default)/CefDisplayHandler.html#OnTooltip(CefRefPtr%3CCefBrowser%3E,CefString&) // // // //////////////////////////////////////////////////////////////////// bool CWebView::OnTooltip ( CefRefPtr<CefBrowser> browser, CefString& title ) { // Queue event to run on the main thread auto func = std::bind ( &CWebBrowserEventsInterface::Events_OnTooltip, m_pEventsInterface, UTF16ToMbUTF8 ( title ) ); g_pCore->GetWebCore ()->AddEventToEventQueue ( func, this, "OnTooltip" ); return true; }
//////////////////////////////////////////////////////////////////// // // // Implementation: CefDisplayHandler::OnTitleChange // // http://magpcss.org/ceforum/apidocs3/projects/(default)/CefDisplayHandler.html#OnTitleChange(CefRefPtr%3CCefBrowser%3E,constCefString&) // // // //////////////////////////////////////////////////////////////////// void CWebView::OnTitleChange ( CefRefPtr<CefBrowser> browser, const CefString& title ) { m_CurrentTitle = UTF16ToMbUTF8 ( title ); }
//////////////////////////////////////////////////////////////////// // // // Implementation: CefRequestHandler::OnBeforeResourceLoad // // http://magpcss.org/ceforum/apidocs3/projects/(default)/CefRequestHandler.html#OnBeforeResourceLoad(CefRefPtr%3CCefBrowser%3E,CefRefPtr%3CCefFrame%3E,CefRefPtr%3CCefRequest%3E) // // // //////////////////////////////////////////////////////////////////// CefRequestHandler::ReturnValue CWebView::OnBeforeResourceLoad ( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefRequestCallback> callback ) { // Mostly the same as CWebView::OnBeforeBrowse CefURLParts urlParts; if ( !CefParseURL ( request->GetURL (), urlParts ) ) return RV_CANCEL; // Cancel if invalid URL (this line will normally not be executed) // Add some information to the HTTP header { CefRequest::HeaderMap headerMap; request->GetHeaderMap ( headerMap ); auto iter = headerMap.find ( "User-Agent" ); if ( iter != headerMap.end () ) { // Add MTA:SA "watermark" iter->second = iter->second.ToString () + "; " MTA_CEF_USERAGENT; // Add 'Android' to get the mobile version SString strPropertyValue; if ( GetProperty ( "mobile", strPropertyValue ) && strPropertyValue == "1" ) iter->second = iter->second.ToString () + "; Mobile Android"; request->SetHeaderMap ( headerMap ); } } WString scheme = urlParts.scheme.str; if ( scheme == L"http" || scheme == L"https" ) { SString domain = UTF16ToMbUTF8 ( urlParts.host.str ); if ( domain != "mta" ) { if ( IsLocal () ) return RV_CANCEL; // Block remote requests in local mode generally 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" ); return RV_CANCEL; // Block if explicitly forbidden } // Allow return RV_CONTINUE; } else return RV_CONTINUE; } else if ( scheme == L"mtalocal" ) { // Allow :) return RV_CONTINUE; } // Trigger onClientBrowserResourceBlocked event auto func = std::bind ( &CWebBrowserEventsInterface::Events_OnResourceBlocked, m_pEventsInterface, SString ( request->GetURL () ), "", 2 ); // reason 1 := blocked protocol scheme g_pCore->GetWebCore ()->AddEventToEventQueue ( func, this, "OnResourceBlocked" ); // Block everything else return RV_CANCEL; }
int CLuaFunctionDefs::GetTok ( lua_State* luaVM ) { SString strInput = ""; unsigned int uiToken = 0; unsigned int uiDelimiter = 0; SString strDelimiter; CScriptArgReader argStream ( luaVM ); argStream.ReadString ( strInput ); argStream.ReadNumber ( uiToken ); if ( argStream.NextIsNumber ( ) ) { argStream.ReadNumber ( uiDelimiter ); wchar_t wUNICODE[2] = { uiDelimiter, '\0' }; strDelimiter = UTF16ToMbUTF8(wUNICODE); } else // It's already a string argStream.ReadString ( strDelimiter ); if ( !argStream.HasErrors ( ) ) { unsigned int uiCount = 0; if ( uiToken > 0 && uiToken < 1024 ) { unsigned int uiCount = 1; char* szText = new char [ strInput.length ( ) + 1 ]; strcpy ( szText, strInput ); char* szToken = strtok ( szText, strDelimiter ); // We're looking for the first part? if ( uiToken != 1 ) { // strtok count number of times do { uiCount++; szToken = strtok ( NULL, strDelimiter ); } while ( uiCount != uiToken ); } // Found it? if ( szToken ) { // Return it lua_pushstring ( luaVM, szToken ); delete [] szText; return 1; } // Delete the text delete [] szText; } else m_pScriptDebugging->LogWarning ( luaVM, "Token parameter sent to split must be greater than 0 and smaller than 1024" ); } else m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage() ); lua_pushboolean ( luaVM, false ); return 1; }