diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-01-23 15:28:33 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-02-04 20:20:49 +0100 |
commit | b2c6dfce78777a5ceb1ea9c14e890b884913c6bf (patch) | |
tree | d35510793e79bd6dac21a0c4661b57535e93c384 /src/core/profile_io_data_qt.cpp | |
parent | 4455081eabc8610112d1cce56a6f6fc64c0be236 (diff) |
Remove non-NetworkService support classes
Removes much of the specific code for non-networksupport, classes that
won't work or even compile with 78/79 based.
Change-Id: I150794a55164998fa3d0031757718081fa7d7d9a
Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
Diffstat (limited to 'src/core/profile_io_data_qt.cpp')
-rw-r--r-- | src/core/profile_io_data_qt.cpp | 448 |
1 files changed, 3 insertions, 445 deletions
diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp index aaaeb277b..ef8f30e10 100644 --- a/src/core/profile_io_data_qt.cpp +++ b/src/core/profile_io_data_qt.cpp @@ -40,137 +40,36 @@ #include "profile_io_data_qt.h" #include "base/task/post_task.h" -#include "chrome/common/chrome_constants.h" -#include "components/certificate_transparency/ct_known_logs.h" -#include "components/network_session_configurator/common/network_features.h" +#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/browsing_data_remover.h" -#include "content/public/browser/cookie_store_factory.h" #include "content/public/browser/shared_cors_origin_access_list.h" #include "content/public/common/content_features.h" -#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h" -#include "chrome/common/chrome_switches.h" #include "components/proxy_config/pref_proxy_config_tracker_impl.h" -#include "net/cert/cert_verifier.h" -#include "net/cert/ct_log_verifier.h" -#include "net/cert/ct_policy_enforcer.h" -#include "net/cert/multi_log_ct_verifier.h" -#include "net/cert_net/cert_net_fetcher_impl.h" -#include "net/ftp/ftp_auth_cache.h" -#include "net/dns/host_resolver_manager.h" -#include "net/http/http_auth_handler_factory.h" -#include "net/http/http_auth_scheme.h" -#include "net/http/http_auth_preferences.h" -#include "net/http/http_cache.h" -#include "net/http/http_server_properties_impl.h" -#include "net/http/http_network_session.h" -#include "net/http/transport_security_persister.h" -#include "net/proxy_resolution/dhcp_pac_file_fetcher_factory.h" -#include "net/proxy_resolution/pac_file_fetcher_impl.h" #include "net/proxy_resolution/proxy_config_service.h" #include "net/proxy_resolution/proxy_resolution_service.h" #include "net/ssl/ssl_config_service_defaults.h" -#include "net/url_request/data_protocol_handler.h" -#include "net/url_request/file_protocol_handler.h" -#include "net/url_request/ftp_protocol_handler.h" -#include "net/url_request/static_http_user_agent_settings.h" -#include "net/url_request/url_request_context_storage.h" -#include "net/url_request/url_request_job_factory_impl.h" -#include "net/url_request/url_request_intercepting_job_factory.h" #include "services/file/user_id_map.h" #include "services/network/proxy_service_mojo.h" -#include "services/network/restricted_cookie_manager.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/cors/origin_access_list.h" #include "net/client_cert_override.h" #include "net/client_cert_store_data.h" #include "net/cookie_monster_delegate_qt.h" -#include "net/custom_protocol_handler.h" -#include "net/network_delegate_qt.h" #include "net/proxy_config_service_qt.h" -#include "net/restricted_cookie_manager_qt.h" #include "net/system_network_context_manager.h" -#include "net/url_request_context_getter_qt.h" #include "profile_qt.h" #include "resource_context_qt.h" #include "type_conversion.h" -#if defined(USE_NSS_CERTS) -#include "net/cert_net/nss_ocsp.h" -#endif - -#if defined(OS_LINUX) || defined(OS_MACOSX) -#include "net/cert/cert_net_fetcher.h" -#include "net/cert_net/cert_net_fetcher_impl.h" -#endif - #include <mutex> #include <QVariant> namespace QtWebEngineCore { -static scoped_refptr<net::CertNetFetcherImpl> s_certNetFetcher; - -static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &first, - const net::HttpNetworkSession::Params &second) -{ - if (first.ignore_certificate_errors != second.ignore_certificate_errors) - return false; - return true; -} - -static bool doNetworkSessionContextMatch(const net::HttpNetworkSession::Context &first, - const net::HttpNetworkSession::Context &second) -{ - if (first.transport_security_state != second.transport_security_state) - return false; - if (first.cert_verifier != second.cert_verifier) - return false; - if (first.proxy_resolution_service != second.proxy_resolution_service) - return false; - if (first.ssl_config_service != second.ssl_config_service) - return false; - if (first.http_auth_handler_factory != second.http_auth_handler_factory) - return false; - if (first.http_user_agent_settings != second.http_user_agent_settings) - return false; - if (first.http_server_properties != second.http_server_properties) - return false; - if (first.host_resolver != second.host_resolver) - return false; - if (first.cert_transparency_verifier != second.cert_transparency_verifier) - return false; - if (first.ct_policy_enforcer != second.ct_policy_enforcer) - return false; - return true; -} - -static net::HttpNetworkSession::Context generateNetworkSessionContext(net::URLRequestContext *urlRequestContext) -{ - net::HttpNetworkSession::Context network_session_context; - network_session_context.transport_security_state = urlRequestContext->transport_security_state(); - network_session_context.cert_verifier = urlRequestContext->cert_verifier(); - network_session_context.proxy_resolution_service = urlRequestContext->proxy_resolution_service(); - network_session_context.ssl_config_service = urlRequestContext->ssl_config_service(); - network_session_context.http_auth_handler_factory = urlRequestContext->http_auth_handler_factory(); - network_session_context.http_user_agent_settings = urlRequestContext->http_user_agent_settings(); - network_session_context.http_server_properties = urlRequestContext->http_server_properties(); - network_session_context.host_resolver = urlRequestContext->host_resolver(); - network_session_context.cert_transparency_verifier = urlRequestContext->cert_transparency_verifier(); - network_session_context.ct_policy_enforcer = urlRequestContext->ct_policy_enforcer(); - return network_session_context; -} - -static net::HttpNetworkSession::Params generateNetworkSessionParams(bool ignoreCertificateErrors) -{ - net::HttpNetworkSession::Params network_session_params; - network_session_params.ignore_certificate_errors = ignoreCertificateErrors; - return network_session_params; -} - ProfileIODataQt::ProfileIODataQt(ProfileQt *profile) : m_profile(profile), #if QT_CONFIG(ssl) @@ -188,27 +87,7 @@ ProfileIODataQt::~ProfileIODataQt() if (content::BrowserThread::IsThreadInitialized(content::BrowserThread::IO)) DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - if (m_useForGlobalCertificateVerification) { -#if defined(USE_NSS_CERTS) - net::SetURLRequestContextForNSSHttpIO(nullptr); -#endif - if (s_certNetFetcher) { - s_certNetFetcher->Shutdown(); - s_certNetFetcher.reset(); - } - } - - if (m_urlRequestContext) { - if (m_urlRequestContext->proxy_resolution_service()) - m_urlRequestContext->proxy_resolution_service()->OnShutdown(); - m_restrictedCookieManagerBindings.CloseAllBindings(); - cancelAllUrlRequests(); - } - m_resourceContext.reset(); - if (m_cookieDelegate) - m_cookieDelegate->setCookieMonster(0); // this will let CookieMonsterDelegateQt be deleted - m_networkDelegate.reset(); delete m_proxyConfigService.fetchAndStoreAcquire(0); } @@ -239,7 +118,7 @@ net::URLRequestContext *ProfileIODataQt::urlRequestContext() DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (!m_initialized) initializeOnIOThread(); - return m_urlRequestContext.get(); + return nullptr; } content::ResourceContext *ProfileIODataQt::resourceContext() @@ -269,17 +148,11 @@ base::WeakPtr<ProfileIODataQt> ProfileIODataQt::getWeakPtrOnIOThread() void ProfileIODataQt::initializeOnIOThread() { - m_networkDelegate.reset(new NetworkDelegateQt(this)); - m_hostResolver = net::HostResolver::CreateStandaloneResolver(nullptr); - m_urlRequestContext.reset(new net::URLRequestContext()); - m_urlRequestContext->set_network_delegate(m_networkDelegate.get()); - m_urlRequestContext->set_enable_brotli(true); - m_urlRequestContext->set_host_resolver(m_hostResolver.get()); // this binds factory to io thread m_weakPtr = m_weakPtrFactory.GetWeakPtr(); const std::lock_guard<QRecursiveMutex> lock(m_mutex); generateAllStorage(); - generateJobFactory(); +// generateJobFactory(); setGlobalCertificateVerification(); m_initialized = true; } @@ -301,296 +174,16 @@ void ProfileIODataQt::initializeOnUIThread() createProxyConfig(); } -void ProfileIODataQt::cancelAllUrlRequests() -{ - Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - Q_ASSERT(m_urlRequestContext); - - const std::set<const net::URLRequest*> *url_requests = m_urlRequestContext->url_requests(); - std::set<const net::URLRequest*>::const_iterator it = url_requests->begin(); - std::set<const net::URLRequest*>::const_iterator end = url_requests->end(); - for ( ; it != end; ++it) { - net::URLRequest* request = const_cast<net::URLRequest*>(*it); - if (request) - request->Cancel(); - } -} - void ProfileIODataQt::generateAllStorage() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); const std::lock_guard<QRecursiveMutex> lock(m_mutex); - generateStorage(); - generateCookieStore(); - generateUserAgent(); - generateHttpCache(); m_updateAllStorage = false; } -void ProfileIODataQt::generateStorage() -{ - Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - Q_ASSERT(m_urlRequestContext); -// Q_ASSERT(!m_mutex.tryLock()); // assert locked - - // We must stop all requests before deleting their backends. - if (m_storage) { - m_urlRequestContext->proxy_resolution_service()->OnShutdown(); - m_restrictedCookieManagerBindings.CloseAllBindings(); - m_cookieDelegate->setCookieMonster(nullptr); - m_storage->set_cookie_store(nullptr); - cancelAllUrlRequests(); - // we need to get rid of dangling pointer due to coming storage deletion - m_urlRequestContext->set_http_transaction_factory(nullptr); - m_httpNetworkSession.reset(); - m_transportSecurityPersister.reset(); - } - - m_storage.reset(new net::URLRequestContextStorage(m_urlRequestContext.get())); - - net::ProxyConfigService *proxyConfigService = m_proxyConfigService.fetchAndStoreAcquire(0); - Q_ASSERT(proxyConfigService); - - std::unique_ptr<net::CertVerifier> cert_verifier = net::CertVerifier::CreateDefault(s_certNetFetcher); - net::CertVerifier::Config config; - // Enable revocation checking: - config.enable_rev_checking = true; - // Mirroring Android WebView (we have no beef with Symantec, and our users might use them): - config.disable_symantec_enforcement = true; - cert_verifier->SetConfig(config); - - m_storage->set_cert_verifier(std::move(cert_verifier)); - std::unique_ptr<net::MultiLogCTVerifier> ct_verifier(new net::MultiLogCTVerifier()); - std::vector<scoped_refptr<const net::CTLogVerifier>> ct_logs; - for (const auto &ct_log : certificate_transparency::GetKnownLogs()) { - scoped_refptr<const net::CTLogVerifier> log_verifier = - net::CTLogVerifier::Create(std::string(ct_log.log_key, ct_log.log_key_length), - ct_log.log_name); - if (!log_verifier) - continue; - ct_logs.push_back(std::move(log_verifier)); - } - ct_verifier->AddLogs(ct_logs); - m_storage->set_cert_transparency_verifier(std::move(ct_verifier)); - m_storage->set_ct_policy_enforcer(base::WrapUnique(new net::DefaultCTPolicyEnforcer())); - m_storage->set_ssl_config_service(std::make_unique<net::SSLConfigServiceDefaults>()); - if (!m_httpAuthPreferences) { - m_httpAuthPreferences.reset(new net::HttpAuthPreferences()); - std::string serverWhitelist = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kAuthServerWhitelist); - m_httpAuthPreferences->SetServerWhitelist(serverWhitelist); - } - m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerFactory::CreateDefault( - m_httpAuthPreferences.get())); - m_storage->set_transport_security_state(std::make_unique<net::TransportSecurityState>()); - - if (!m_dataPath.isEmpty()) { - scoped_refptr<base::SequencedTaskRunner> background_task_runner( - base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), - base::TaskPriority::BEST_EFFORT, - base::TaskShutdownBehavior::BLOCK_SHUTDOWN})); - m_transportSecurityPersister = - std::make_unique<net::TransportSecurityPersister>( - m_urlRequestContext->transport_security_state(), - toFilePath(m_dataPath), - background_task_runner); - }; - - m_storage->set_http_server_properties(std::unique_ptr<net::HttpServerProperties>( - new net::HttpServerPropertiesImpl)); - - // The System Proxy Resolver has issues on Windows with unconfigured network cards, - // which is why we want to use the v8 one - if (!m_dhcpPacFileFetcherFactory) - m_dhcpPacFileFetcherFactory.reset(new net::DhcpPacFileFetcherFactory); - - proxy_resolver::mojom::ProxyResolverFactoryPtr proxyResolver(std::move(m_proxyResolverFactoryInterface)); - m_storage->set_proxy_resolution_service(network::CreateProxyResolutionServiceUsingMojoFactory( - std::move(proxyResolver), - std::unique_ptr<net::ProxyConfigService>(proxyConfigService), - net::PacFileFetcherImpl::CreateWithFileUrlSupport(m_urlRequestContext.get()), - m_dhcpPacFileFetcherFactory->Create(m_urlRequestContext.get()), - m_urlRequestContext->host_resolver(), - nullptr /* NetLog */, - m_urlRequestContext->network_delegate())); - - m_storage->set_ftp_auth_cache(std::make_unique<net::FtpAuthCache>()); -} - - -void ProfileIODataQt::generateCookieStore() -{ - Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - Q_ASSERT(m_urlRequestContext); - - const std::lock_guard<QRecursiveMutex> lock(m_mutex); - - // FIXME: Add code to remove the old channel-id database. - // TODO(nharper): Remove the following when no longer needed - see - // crbug.com/903642. -// base::PostTaskWithTraits( -// FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, -// base::BindOnce(DeleteChannelIDFiles, path.Append(chrome::kChannelIDFilename))); - - std::unique_ptr<net::CookieStore> cookieStore; - switch (m_persistentCookiesPolicy) { - case ProfileAdapter::NoPersistentCookies: - cookieStore = content::CreateCookieStore( - content::CookieStoreConfig( - base::FilePath(), - false, - false, - nullptr), - nullptr); - break; - case ProfileAdapter::AllowPersistentCookies: - cookieStore = content::CreateCookieStore( - content::CookieStoreConfig( - toFilePath(m_cookiesPath), - false, - true, - nullptr), - nullptr); - break; - case ProfileAdapter::ForcePersistentCookies: - cookieStore = content::CreateCookieStore( - content::CookieStoreConfig( - toFilePath(m_cookiesPath), - true, - true, - nullptr), - nullptr); - break; - } - - net::CookieMonster * const cookieMonster = static_cast<net::CookieMonster*>(cookieStore.get()); - m_cookieDelegate->setCookieMonster(cookieMonster); - m_storage->set_cookie_store(std::move(cookieStore)); - - const std::vector<std::string> cookieableSchemes(kCookieableSchemes, - kCookieableSchemes + base::size(kCookieableSchemes)); - cookieMonster->SetCookieableSchemes(cookieableSchemes, base::DoNothing()); -} - -void ProfileIODataQt::generateUserAgent() -{ - Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - Q_ASSERT(m_urlRequestContext); - Q_ASSERT(m_storage); - - const std::lock_guard<QRecursiveMutex> lock(m_mutex); - m_storage->set_http_user_agent_settings(std::unique_ptr<net::HttpUserAgentSettings>( - new net::StaticHttpUserAgentSettings(m_httpAcceptLanguage.toStdString(), - m_httpUserAgent.toStdString()))); -} - -void ProfileIODataQt::generateHttpCache() -{ - Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - Q_ASSERT(m_urlRequestContext); - Q_ASSERT(m_storage); - - const std::lock_guard<QRecursiveMutex> lock(m_mutex); - - net::HttpCache::DefaultBackend* main_backend = 0; - switch (m_httpCacheType) { - case ProfileAdapter::MemoryHttpCache: - main_backend = - new net::HttpCache::DefaultBackend( - net::MEMORY_CACHE, - net::CACHE_BACKEND_DEFAULT, - base::FilePath(), - m_httpCacheMaxSize - ); - break; - case ProfileAdapter::DiskHttpCache: - main_backend = - new net::HttpCache::DefaultBackend( - net::DISK_CACHE, - net::CACHE_BACKEND_DEFAULT, - toFilePath(m_httpCachePath), - m_httpCacheMaxSize - ); - break; - case ProfileAdapter::NoCache: - // It's safe to not create BackendFactory. - break; - } - - net::HttpCache *cache = 0; - net::HttpNetworkSession::Context network_session_context = - generateNetworkSessionContext(m_urlRequestContext.get()); - net::HttpNetworkSession::Params network_session_params = - generateNetworkSessionParams(m_ignoreCertificateErrors); - - if (!m_httpNetworkSession - || !doNetworkSessionParamsMatch(network_session_params, m_httpNetworkSession->params()) - || !doNetworkSessionContextMatch(network_session_context, m_httpNetworkSession->context())) { - m_httpNetworkSession.reset(new net::HttpNetworkSession(network_session_params, - network_session_context)); - } - - cache = new net::HttpCache(m_httpNetworkSession.get(), - std::unique_ptr<net::HttpCache::DefaultBackend>(main_backend), false); - - m_storage->set_http_transaction_factory(std::unique_ptr<net::HttpCache>(cache)); -} - -void ProfileIODataQt::generateJobFactory() -{ - Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - Q_ASSERT(m_urlRequestContext); - Q_ASSERT(!m_jobFactory); - - const std::lock_guard<QRecursiveMutex> lock(m_mutex); - m_updateJobFactory = false; - - std::unique_ptr<net::URLRequestJobFactoryImpl> jobFactory(new net::URLRequestJobFactoryImpl()); - for (auto &it : m_protocolHandlers) - jobFactory->SetProtocolHandler(it.first, base::WrapUnique(it.second.release())); - m_protocolHandlers.clear(); - - jobFactory->SetProtocolHandler(url::kDataScheme, - std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>( - new net::DataProtocolHandler())); - scoped_refptr<base::TaskRunner> taskRunner(base::CreateTaskRunnerWithTraits({base::MayBlock(), - base::TaskPriority::BEST_EFFORT, - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); - jobFactory->SetProtocolHandler(url::kFileScheme, - std::make_unique<net::FileProtocolHandler>(taskRunner)); - jobFactory->SetProtocolHandler(url::kFtpScheme, - net::FtpProtocolHandler::Create(m_urlRequestContext->host_resolver(), m_urlRequestContext->ftp_auth_cache())); - - m_installedCustomSchemes = m_customUrlSchemes; - for (const QByteArray &scheme : qAsConst(m_installedCustomSchemes)) { - jobFactory->SetProtocolHandler(scheme.toStdString(), - std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>( - new CustomProtocolHandler(m_profileAdapter))); - } - - m_baseJobFactory = jobFactory.get(); - - // Set up interceptors in the reverse order. - std::unique_ptr<net::URLRequestJobFactory> topJobFactory = std::move(jobFactory); - content::URLRequestInterceptorScopedVector::reverse_iterator i; - for (i = m_requestInterceptors.rbegin(); i != m_requestInterceptors.rend(); ++i) { - topJobFactory.reset(new net::URLRequestInterceptingJobFactory(std::move(topJobFactory), - std::move(*i))); - } - - m_requestInterceptors.clear(); - - m_jobFactory = std::move(topJobFactory); - - m_urlRequestContext->set_job_factory(m_jobFactory.get()); -} - void ProfileIODataQt::regenerateJobFactory() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - Q_ASSERT(m_urlRequestContext); - Q_ASSERT(m_jobFactory); - Q_ASSERT(m_baseJobFactory); const std::lock_guard<QRecursiveMutex> lock(m_mutex); m_updateJobFactory = false; @@ -598,31 +191,13 @@ void ProfileIODataQt::regenerateJobFactory() if (m_customUrlSchemes == m_installedCustomSchemes) return; - for (const QByteArray &scheme : qAsConst(m_installedCustomSchemes)) { - m_baseJobFactory->SetProtocolHandler(scheme.toStdString(), nullptr); - } - m_installedCustomSchemes = m_customUrlSchemes; - for (const QByteArray &scheme : qAsConst(m_installedCustomSchemes)) { - m_baseJobFactory->SetProtocolHandler(scheme.toStdString(), - std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>( - new CustomProtocolHandler(m_profileAdapter))); - } } void ProfileIODataQt::setGlobalCertificateVerification() { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); const std::lock_guard<QRecursiveMutex> lock(m_mutex); - if (m_useForGlobalCertificateVerification) { -#if defined(USE_NSS_CERTS) - // Set request context used by NSS for OCSP requests. - net::SetURLRequestContextForNSSHttpIO(m_urlRequestContext.get()); -#endif - if (!s_certNetFetcher) - s_certNetFetcher = base::MakeRefCounted<net::CertNetFetcherImpl>(); - s_certNetFetcher->SetURLRequestContext(m_urlRequestContext.get()); - } } void ProfileIODataQt::setRequestContextData(content::ProtocolHandlerMap *protocolHandlers, @@ -835,23 +410,6 @@ std::unique_ptr<net::ClientCertStore> ProfileIODataQt::CreateClientCertStore() #endif } -void ProfileIODataQt::CreateRestrictedCookieManager(network::mojom::RestrictedCookieManagerRequest request, - network::mojom::RestrictedCookieManagerRole role, - const url::Origin &origin, - bool is_service_worker, - int32_t process_id, - int32_t routing_id) -{ - Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - m_restrictedCookieManagerBindings.AddBinding( - std::make_unique<RestrictedCookieManagerQt>( - m_weakPtr, - role, urlRequestContext()->cookie_store(), - &m_cookieSettings, origin, - is_service_worker, process_id, routing_id), - std::move(request)); -} - network::mojom::NetworkContextParamsPtr ProfileIODataQt::CreateNetworkContextParams() { updateStorageSettings(); |