void CWebView::ConvertURL ( const CefString& url, SString& convertedURL ) { CefURLParts urlParts; if ( !CefParseURL ( url, urlParts ) ) { convertedURL = ""; return; } WString scheme = urlParts.scheme.str; if ( scheme == L"http" || scheme == L"https" ) { convertedURL = UTF16ToMbUTF8 ( urlParts.spec.str ); } else { // Get the file name (charsequence after last /) WString tempStr = urlParts.path.str; size_t pos = tempStr.find_last_of ( L"/" ); if ( pos != std::wstring::npos && pos < tempStr.size () ) convertedURL = UTF16ToMbUTF8 ( tempStr.SubStr ( pos + 1 ) ); else convertedURL = ""; } }
//////////////////////////////////////////////////////////////////// // // // Implementation: CefRequestHandler::OnBeforeResourceLoad // // http://magpcss.org/ceforum/apidocs3/projects/(default)/CefRequestHandler.html#OnBeforeResourceLoad(CefRefPtr%3CCefBrowser%3E,CefRefPtr%3CCefFrame%3E,CefRefPtr%3CCefRequest%3E) // // // //////////////////////////////////////////////////////////////////// bool CWebView::OnBeforeResourceLoad ( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request ) { // Mostly the same as CWebView::OnBeforeBrowse CefURLParts urlParts; if ( !CefParseURL ( request->GetURL (), urlParts ) ) return true; // Cancel if invalid URL (this line will normally not be executed) WString scheme = urlParts.scheme.str; if ( scheme == L"http" || scheme == L"https" ) { if ( IsLocal () ) return true; // Block remote requests in local mode generally if ( g_pCore->GetWebCore ()->GetURLState ( UTF16ToMbUTF8 ( urlParts.host.str ) ) != eURLState::WEBPAGE_ALLOWED ) return true; // Block if explicitly forbidden // Allow return false; } else if ( scheme == L"mtalocal" ) { // Allow :) return false; } // Block everything else return true; }
//////////////////////////////////////////////////////////////////// // // // Implementation: CefRequestHandler::OnBeforeBrowe // // http://magpcss.org/ceforum/apidocs3/projects/(default)/CefRequestHandler.html#OnBeforeBrowse(CefRefPtr%3CCefBrowser%3E,CefRefPtr%3CCefFrame%3E,CefRefPtr%3CCefRequest%3E,bool) // // // //////////////////////////////////////////////////////////////////// bool CWebView::OnBeforeBrowse ( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool isRedirect ) { /* From documentation: The |request| object cannot be modified in this callback. CefLoadHandler::OnLoadingStateChange will be called twice in all cases. If the navigation is allowed CefLoadHandler::OnLoadStart and CefLoadHandler::OnLoadEnd will be called. If the navigation is canceled CefLoadHandler::OnLoadError will be called with an |errorCode| value of ERR_ABORTED. */ CefURLParts urlParts; if ( !CefParseURL ( request->GetURL(), urlParts ) ) return true; // Cancel if invalid URL (this line will normally not be executed) WString scheme = urlParts.scheme.str; if ( scheme == L"http" || scheme == L"https" ) { if ( IsLocal () ) return true; // Block remote here requests generally if ( g_pCore->GetWebCore ()->GetURLState ( UTF16ToMbUTF8 ( urlParts.host.str ) ) != eURLState::WEBPAGE_ALLOWED ) return true; return false; } else if ( scheme == L"mtalocal" ) return false; // Block everything else return true; }
SString CWebCore::GetDomainFromURL ( const SString& strURL ) { CefURLParts urlParts; if ( !CefParseURL ( strURL, urlParts ) || !urlParts.host.str ) return ""; return UTF16ToMbUTF8 ( urlParts.host.str ); }
CefRefPtr<CefResourceHandler> VTFSchemeHandlerFactory::Create(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& scheme_name, CefRefPtr<CefRequest> request) { CefRefPtr<CefResourceHandler> pResourceHandler = NULL; CefURLParts parts; CefParseURL(request->GetURL(), parts); std::string strVtfPath = CefString(&parts.path); char vtfPath[MAX_PATH]; V_snprintf( vtfPath, sizeof( vtfPath ), "materials/%s", strVtfPath.c_str() ); V_FixupPathName( vtfPath, sizeof( vtfPath ), vtfPath ); if (!filesystem->FileExists(vtfPath)) { Warning( "VTFSchemeHandlerFactory: invalid vtf %s\n", vtfPath ); return NULL; } CUtlBuffer imageDataBuffer( 0, filesystem->Size(vtfPath), 0 ); if( !filesystem->ReadFile( vtfPath, NULL, imageDataBuffer ) ) { Warning( "VTFSchemeHandlerFactory: failed to read vtf %s\n", vtfPath ); return NULL; } IVTFTexture *pVTFTexture = CreateVTFTexture(); if( pVTFTexture->Unserialize( imageDataBuffer ) ) { pVTFTexture->ConvertImageFormat( IMAGE_FORMAT_RGB888, false, false ); if( pVTFTexture->Format() == IMAGE_FORMAT_RGB888 ) { uint8 *pImageData = pVTFTexture->ImageData(); CUtlBuffer buf; VTFHandler_ConvertImageToJPG( buf, pImageData, pVTFTexture->Width(), pVTFTexture->Height() ); if( buf.Size() > 0 ) { CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(static_cast<void*>(buf.Base()), buf.Size()); pResourceHandler = new CefStreamResourceHandler("image/jpeg", stream); } } else { Warning( "VTFSchemeHandlerFactory: unable to convert vtf %s to rgb format\n", vtfPath ); } } DestroyVTFTexture( pVTFTexture ); return pResourceHandler; }
CefRefPtr<CefResourceHandler> LocalSchemeHandlerFactory::Create(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& scheme_name, CefRefPtr<CefRequest> request) { CefRefPtr<CefResourceHandler> pResourceHandler = NULL; CefURLParts parts; CefParseURL(request->GetURL(), parts); if( CefString(&parts.path).size() < 2 ) { return NULL; } char path[MAX_PATH]; V_strncpy( path, CefString(&parts.path).ToString().c_str() + 1, sizeof(path) ); V_FixupPathName( path, sizeof( path ), path ); if( filesystem->IsDirectory( path ) ) { V_AppendSlash( path, sizeof( path ) ); V_strcat( path, "index.html", sizeof(path) ); } if( filesystem->FileExists( path, NULL ) ) { const char *pExtension = V_GetFileExtension( path ); if( cef_scheme_debug_local_handler.GetBool() ) { Msg( "Local scheme request => Path: %s, Extension: %s, Mime Type: %s, modified path: %s, exists: %d, resource type: %d\n", CefString(&parts.path).ToString().c_str(), pExtension, CefGetMimeType(pExtension).ToString().c_str(), path, filesystem->FileExists( path ), request->GetResourceType() ); } CUtlBuffer buf( 0, filesystem->Size( path, NULL ) ); if( filesystem->ReadFile( path, NULL, buf ) ) { CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData( buf.Base(), buf.TellPut() ); if( stream != NULL ) { pResourceHandler = new CefStreamResourceHandler( CefGetMimeType(pExtension), stream ); } } } return pResourceHandler; }
bool CWebView::LoadURL ( const SString& strURL, bool bFilterEnabled, const SString& strPostData, bool bURLEncoded ) { if ( !m_pWebView ) return false; CefURLParts urlParts; if ( !CefParseURL ( strURL, urlParts ) ) return false; // Invalid URL // Are we allowed to browse this website? if ( bFilterEnabled && g_pCore->GetWebCore ()->GetURLState ( UTF16ToMbUTF8 ( urlParts.host.str ), true ) != eURLState::WEBPAGE_ALLOWED ) return false; // Load it! auto pFrame = m_pWebView->GetMainFrame (); if ( strPostData.empty () ) { pFrame->LoadURL ( strURL ); } else { // Load URL first, see https://bitbucket.org/chromiumembedded/cef/issue/579 pFrame->LoadURL ( "about:blank" ); // Perform HTTP POST auto request = CefRequest::Create (); auto postData = CefPostData::Create (); auto postDataElement = CefPostDataElement::Create (); postDataElement->SetToBytes ( strPostData.size (), strPostData.c_str () ); postData->AddElement ( postDataElement ); if ( bURLEncoded ) { CefRequest::HeaderMap headerMap; headerMap.insert ( std::make_pair ( "Content-Type", "application/x-www-form-urlencoded" ) ); headerMap.insert ( std::make_pair ( "Content-Length", std::to_string ( strPostData.size () ) ) ); //headerMap.insert ( std::make_pair ( "Connection", "close" ) ); request->SetHeaderMap ( headerMap ); } request->SetURL ( strURL ); request->SetMethod ( "POST" ); request->SetPostData ( postData ); pFrame->LoadRequest ( request ); } return true; }
bool CWebView::LoadURL ( const SString& strURL, bool bFilterEnabled ) { if ( !m_pWebView ) return false; CefURLParts urlParts; if ( !CefParseURL ( strURL, urlParts ) ) return false; // Invalid URL // Are we allowed to browse this website? if ( bFilterEnabled && g_pCore->GetWebCore ()->GetURLState ( UTF16ToMbUTF8 ( urlParts.host.str ) ) != eURLState::WEBPAGE_ALLOWED ) return false; // Load it! m_pWebView->GetMainFrame ()->LoadURL ( strURL ); return true; }
// First method called bool BrowserSchemeHandler::ProcessRequest(CefRefPtr<CefRequest> request, CefRefPtr<CefCallback> callback) { CefURLParts parts; CefParseURL(request->GetURL(), parts); std::string path = CefString(&parts.path); fileName = path.substr(path.find_last_of("/") + 1); inputStream.open(path, std::ifstream::binary); if (!inputStream.is_open()) { callback->Cancel(); return false; } inputStream.seekg(0, std::ifstream::end); length = remaining = inputStream.tellg(); inputStream.seekg(0, std::ifstream::beg); callback->Continue(); return true; }
//////////////////////////////////////////////////////////////////// // // // Implementation: CefRequestHandler::OnBeforeBrowe // // http://magpcss.org/ceforum/apidocs3/projects/(default)/CefRequestHandler.html#OnBeforeBrowse(CefRefPtr%3CCefBrowser%3E,CefRefPtr%3CCefFrame%3E,CefRefPtr%3CCefRequest%3E,bool) // // // //////////////////////////////////////////////////////////////////// bool CWebView::OnBeforeBrowse ( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool isRedirect ) { /* From documentation: The |request| object cannot be modified in this callback. CefLoadHandler::OnLoadingStateChange will be called twice in all cases. If the navigation is allowed CefLoadHandler::OnLoadStart and CefLoadHandler::OnLoadEnd will be called. If the navigation is canceled CefLoadHandler::OnLoadError will be called with an |errorCode| value of ERR_ABORTED. */ CefURLParts urlParts; if ( !CefParseURL ( request->GetURL(), urlParts ) ) return true; // Cancel if invalid URL (this line will normally not be executed) bool bResult; WString scheme = urlParts.scheme.str; if ( scheme == L"http" || scheme == L"https" ) { 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; } else if ( scheme == L"mtalocal" ) bResult = false; // Allow mtalocal:// URLs else bResult = true; // Block other schemes // Queue event to run on the main thread auto func = std::bind ( &CWebBrowserEventsInterface::Events_OnNavigate, m_pEventsInterface, SString ( request->GetURL () ), bResult ); g_pCore->GetWebCore ()->AddEventToEventQueue ( func, this, "OnNavigate" ); // Return execution to CEF return bResult; }
CefRefPtr<CefResourceHandler> CCefApp::Create ( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& scheme_name, CefRefPtr<CefRequest> request ) { // browser or frame are NULL if the request does not orginate from a browser window // This is for exmaple true for the application cache or CEFURLRequests // (http://www.html5rocks.com/en/tutorials/appcache/beginner/) if ( !browser || !frame ) return nullptr; 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; }
//////////////////////////////////////////////////////////////////// // // // 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; }
virtual bool ProcessRequest(CefRefPtr<CefRequest> request, CefRefPtr<CefCallback> callback) { std::string url = request->GetURL(); std::wstring hostname; std::wstring path; uint16_t port; CefURLParts parts; CefParseURL(url, parts); hostname = CefString(&parts.host); path = CefString(&parts.path); if (hostname == L"game") { filename_ = "citizen:/"; filename_ += std::string(path.begin(), path.end()); } else { filename_ = "resources:/"; filename_ += std::string(hostname.begin(), hostname.end()) + "/"; filename_ += std::string(path.begin(), path.end()); } //filename_ = exeName + std::wstring(L"/citiv/ui/") + url.substr(11); // remove # parts auto hash = filename_.find_first_of(L'#'); if (hash != std::string::npos) { //filename_.resize(hash); filename_.erase(hash); } hash = filename_.find_first_of(L'?'); if (hash != std::string::npos) { //filename_.resize(hash); filename_.erase(hash); } //file_ = _wfopen(filename_.c_str(), "rb"); device_ = rage::fiDevice::GetDevice(filename_.c_str(), true); if (device_) { file_ = device_->open(filename_.c_str(), true); } // set mime type std::string ext = url.substr(url.rfind('.') + 1); mimeType_ = "text/html"; if (ext == "png") { mimeType_ = "image/png"; } else if (ext == "js") { mimeType_ = "application/javascript"; } else if (ext == "css") { mimeType_ = "text/css"; } callback->Continue(); return true; }