Storage Access API: Remove access for all frames under a page when the page is closed
[WebKit-https.git] / Source / WebKit / NetworkProcess / NetworkConnectionToWebProcess.cpp
1 /*
2  * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "NetworkConnectionToWebProcess.h"
28
29 #include "BlobDataFileReferenceWithSandboxExtension.h"
30 #include "CacheStorageEngineConnectionMessages.h"
31 #include "DataReference.h"
32 #include "NetworkBlobRegistry.h"
33 #include "NetworkCache.h"
34 #include "NetworkConnectionToWebProcessMessages.h"
35 #include "NetworkLoad.h"
36 #include "NetworkProcess.h"
37 #include "NetworkProcessConnectionMessages.h"
38 #include "NetworkRTCMonitorMessages.h"
39 #include "NetworkRTCProviderMessages.h"
40 #include "NetworkRTCSocketMessages.h"
41 #include "NetworkResourceLoadParameters.h"
42 #include "NetworkResourceLoader.h"
43 #include "NetworkResourceLoaderMessages.h"
44 #include "NetworkSocketStream.h"
45 #include "NetworkSocketStreamMessages.h"
46 #include "PreconnectTask.h"
47 #include "RemoteNetworkingContext.h"
48 #include "SessionTracker.h"
49 #include "WebCoreArgumentCoders.h"
50 #include "WebErrors.h"
51 #include "WebsiteDataStore.h"
52 #include "WebsiteDataStoreParameters.h"
53 #include <WebCore/NetworkStorageSession.h>
54 #include <WebCore/PingHandle.h>
55 #include <WebCore/PlatformCookieJar.h>
56 #include <WebCore/ResourceLoaderOptions.h>
57 #include <WebCore/ResourceRequest.h>
58 #include <pal/SessionID.h>
59
60 #if USE(NETWORK_SESSION)
61 #include "PingLoad.h"
62 #endif
63
64 using namespace WebCore;
65
66 namespace WebKit {
67
68 Ref<NetworkConnectionToWebProcess> NetworkConnectionToWebProcess::create(IPC::Connection::Identifier connectionIdentifier)
69 {
70     return adoptRef(*new NetworkConnectionToWebProcess(connectionIdentifier));
71 }
72
73 NetworkConnectionToWebProcess::NetworkConnectionToWebProcess(IPC::Connection::Identifier connectionIdentifier)
74     : m_connection(IPC::Connection::createServerConnection(connectionIdentifier, *this))
75 {
76     m_connection->open();
77 }
78
79 NetworkConnectionToWebProcess::~NetworkConnectionToWebProcess()
80 {
81     m_connection->invalidate();
82 #if USE(LIBWEBRTC)
83     if (m_rtcProvider)
84         m_rtcProvider->close();
85 #endif
86 }
87
88 void NetworkConnectionToWebProcess::didCleanupResourceLoader(NetworkResourceLoader& loader)
89 {
90     ASSERT(m_networkResourceLoaders.get(loader.identifier()) == &loader);
91
92     m_networkResourceLoaders.remove(loader.identifier());
93 }
94
95 void NetworkConnectionToWebProcess::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
96 {
97     if (decoder.messageReceiverName() == Messages::NetworkConnectionToWebProcess::messageReceiverName()) {
98         didReceiveNetworkConnectionToWebProcessMessage(connection, decoder);
99         return;
100     }
101
102     if (decoder.messageReceiverName() == Messages::NetworkResourceLoader::messageReceiverName()) {
103         auto loaderIterator = m_networkResourceLoaders.find(decoder.destinationID());
104         if (loaderIterator != m_networkResourceLoaders.end())
105             loaderIterator->value->didReceiveNetworkResourceLoaderMessage(connection, decoder);
106         return;
107     }
108
109     if (decoder.messageReceiverName() == Messages::NetworkSocketStream::messageReceiverName()) {
110         auto socketIterator = m_networkSocketStreams.find(decoder.destinationID());
111         if (socketIterator != m_networkSocketStreams.end()) {
112             socketIterator->value->didReceiveMessage(connection, decoder);
113             if (decoder.messageName() == Messages::NetworkSocketStream::Close::name())
114                 m_networkSocketStreams.remove(socketIterator);
115         }
116         return;
117     }
118
119 #if USE(LIBWEBRTC)
120     if (decoder.messageReceiverName() == Messages::NetworkRTCSocket::messageReceiverName()) {
121         rtcProvider().didReceiveNetworkRTCSocketMessage(connection, decoder);
122         return;
123     }
124     if (decoder.messageReceiverName() == Messages::NetworkRTCMonitor::messageReceiverName()) {
125         rtcProvider().didReceiveNetworkRTCMonitorMessage(connection, decoder);
126         return;
127     }
128     if (decoder.messageReceiverName() == Messages::NetworkRTCProvider::messageReceiverName()) {
129         rtcProvider().didReceiveMessage(connection, decoder);
130         return;
131     }
132 #endif
133
134     if (decoder.messageReceiverName() == Messages::CacheStorageEngineConnection::messageReceiverName()) {
135         cacheStorageConnection().didReceiveMessage(connection, decoder);
136         return;
137     }
138
139     ASSERT_NOT_REACHED();
140 }
141
142 #if USE(LIBWEBRTC)
143 NetworkRTCProvider& NetworkConnectionToWebProcess::rtcProvider()
144 {
145     if (!m_rtcProvider)
146         m_rtcProvider = NetworkRTCProvider::create(*this);
147     return *m_rtcProvider;
148 }
149 #endif
150
151 CacheStorageEngineConnection& NetworkConnectionToWebProcess::cacheStorageConnection()
152 {
153     if (!m_cacheStorageConnection)
154         m_cacheStorageConnection = CacheStorageEngineConnection::create(*this);
155     return *m_cacheStorageConnection;
156 }
157
158 void NetworkConnectionToWebProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& reply)
159 {
160     if (decoder.messageReceiverName() == Messages::NetworkConnectionToWebProcess::messageReceiverName()) {
161         didReceiveSyncNetworkConnectionToWebProcessMessage(connection, decoder, reply);
162         return;
163     }
164     ASSERT_NOT_REACHED();
165 }
166
167 void NetworkConnectionToWebProcess::didClose(IPC::Connection&)
168 {
169     // Protect ourself as we might be otherwise be deleted during this function.
170     Ref<NetworkConnectionToWebProcess> protector(*this);
171
172     for (auto& loader : copyToVector(m_networkResourceLoaders.values()))
173         loader->abort();
174     ASSERT(m_networkResourceLoaders.isEmpty());
175
176     NetworkBlobRegistry::singleton().connectionToWebProcessDidClose(this);
177     NetworkProcess::singleton().removeNetworkConnectionToWebProcess(this);
178
179 #if USE(LIBWEBRTC)
180     if (m_rtcProvider) {
181         m_rtcProvider->close();
182         m_rtcProvider = nullptr;
183     }
184 #endif
185 }
186
187 void NetworkConnectionToWebProcess::didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference, IPC::StringReference)
188 {
189 }
190
191 void NetworkConnectionToWebProcess::createSocketStream(URL&& url, PAL::SessionID sessionID, String cachePartition, uint64_t identifier)
192 {
193     ASSERT(!m_networkSocketStreams.contains(identifier));
194     WebCore::SourceApplicationAuditToken token = { };
195 #if PLATFORM(COCOA)
196     token = { NetworkProcess::singleton().sourceApplicationAuditData() };
197 #endif
198     m_networkSocketStreams.set(identifier, NetworkSocketStream::create(WTFMove(url), sessionID, cachePartition, identifier, m_connection, WTFMove(token)));
199 }
200
201 void NetworkConnectionToWebProcess::destroySocketStream(uint64_t identifier)
202 {
203     ASSERT(m_networkSocketStreams.get(identifier));
204     m_networkSocketStreams.remove(identifier);
205 }
206
207 void NetworkConnectionToWebProcess::cleanupForSuspension(Function<void()>&& completionHandler)
208 {
209 #if USE(LIBWEBRTC)
210     if (m_rtcProvider) {
211         m_rtcProvider->closeListeningSockets(WTFMove(completionHandler));
212         return;
213     }
214 #endif
215     completionHandler();
216 }
217
218 void NetworkConnectionToWebProcess::endSuspension()
219 {
220 #if USE(LIBWEBRTC)
221     if (m_rtcProvider)
222         m_rtcProvider->authorizeListeningSockets();
223 #endif
224 }
225
226 void NetworkConnectionToWebProcess::scheduleResourceLoad(const NetworkResourceLoadParameters& loadParameters)
227 {
228     auto loader = NetworkResourceLoader::create(loadParameters, *this);
229     m_networkResourceLoaders.add(loadParameters.identifier, loader.ptr());
230     loader->start();
231 }
232
233 void NetworkConnectionToWebProcess::performSynchronousLoad(const NetworkResourceLoadParameters& loadParameters, Ref<Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply>&& reply)
234 {
235     auto loader = NetworkResourceLoader::create(loadParameters, *this, WTFMove(reply));
236     m_networkResourceLoaders.add(loadParameters.identifier, loader.ptr());
237     loader->start();
238 }
239
240 void NetworkConnectionToWebProcess::loadPing(NetworkResourceLoadParameters&& loadParameters, HTTPHeaderMap&& originalRequestHeaders)
241 {
242     auto completionHandler = [this, protectedThis = makeRef(*this), identifier = loadParameters.identifier] (const ResourceError& error, const ResourceResponse& response) {
243         didFinishPingLoad(identifier, error, response);
244     };
245
246 #if USE(NETWORK_SESSION)
247     // PingLoad manages its own lifetime, deleting itself when its purpose has been fulfilled.
248     new PingLoad(WTFMove(loadParameters), WTFMove(originalRequestHeaders), WTFMove(completionHandler));
249 #else
250     UNUSED_PARAM(originalRequestHeaders);
251     auto context = RemoteNetworkingContext::create(loadParameters.sessionID, loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect);
252
253     // PingHandle manages its own lifetime, deleting itself when its purpose has been fulfilled.
254     new PingHandle(context.ptr(), loadParameters.request, loadParameters.storedCredentialsPolicy == StoredCredentialsPolicy::Use, loadParameters.shouldFollowRedirects, WTFMove(completionHandler));
255 #endif
256 }
257
258 void NetworkConnectionToWebProcess::didFinishPingLoad(uint64_t pingLoadIdentifier, const ResourceError& error, const ResourceResponse& response)
259 {
260     if (!m_connection->isValid())
261         return;
262
263     m_connection->send(Messages::NetworkProcessConnection::DidFinishPingLoad(pingLoadIdentifier, error, response), 0);
264 }
265
266 void NetworkConnectionToWebProcess::removeLoadIdentifier(ResourceLoadIdentifier identifier)
267 {
268     RefPtr<NetworkResourceLoader> loader = m_networkResourceLoaders.get(identifier);
269
270     // It's possible we have no loader for this identifier if the NetworkProcess crashed and this was a respawned NetworkProcess.
271     if (!loader)
272         return;
273
274     // Abort the load now, as the WebProcess won't be able to respond to messages any more which might lead
275     // to leaked loader resources (connections, threads, etc).
276     loader->abort();
277     ASSERT(!m_networkResourceLoaders.contains(identifier));
278 }
279
280 void NetworkConnectionToWebProcess::setDefersLoading(ResourceLoadIdentifier identifier, bool defers)
281 {
282     RefPtr<NetworkResourceLoader> loader = m_networkResourceLoaders.get(identifier);
283     if (!loader)
284         return;
285
286     loader->setDefersLoading(defers);
287 }
288
289 void NetworkConnectionToWebProcess::prefetchDNS(const String& hostname)
290 {
291     NetworkProcess::singleton().prefetchDNS(hostname);
292 }
293
294 void NetworkConnectionToWebProcess::preconnectTo(uint64_t preconnectionIdentifier, NetworkLoadParameters&& parameters)
295 {
296 #if ENABLE(SERVER_PRECONNECT)
297     new PreconnectTask(WTFMove(parameters), [this, protectedThis = makeRef(*this), identifier = preconnectionIdentifier] (const ResourceError& error) {
298         didFinishPreconnection(identifier, error);
299     });
300 #else
301     UNUSED_PARAM(parameters);
302     didFinishPreconnection(preconnectionIdentifier, internalError(parameters.request.url()));
303 #endif
304 }
305
306 void NetworkConnectionToWebProcess::didFinishPreconnection(uint64_t preconnectionIdentifier, const ResourceError& error)
307 {
308     if (!m_connection->isValid())
309         return;
310
311     m_connection->send(Messages::NetworkProcessConnection::DidFinishPreconnection(preconnectionIdentifier, error), 0);
312 }
313
314 static NetworkStorageSession& storageSession(PAL::SessionID sessionID)
315 {
316     ASSERT(sessionID.isValid());
317     if (sessionID != PAL::SessionID::defaultSessionID()) {
318         if (auto* storageSession = NetworkStorageSession::storageSession(sessionID))
319             return *storageSession;
320
321         // Some requests with private browsing mode requested may still be coming shortly after NetworkProcess was told to destroy its session.
322         // FIXME: Find a way to track private browsing sessions more rigorously.
323         LOG_ERROR("Non-default storage session was requested, but there was no session for it. Please file a bug unless you just disabled private browsing, in which case it's an expected race.");
324     }
325     return NetworkStorageSession::defaultStorageSession();
326 }
327
328 void NetworkConnectionToWebProcess::startDownload(PAL::SessionID sessionID, DownloadID downloadID, const ResourceRequest& request, const String& suggestedName)
329 {
330     NetworkProcess::singleton().downloadManager().startDownload(this, sessionID, downloadID, request, suggestedName);
331 }
332
333 void NetworkConnectionToWebProcess::convertMainResourceLoadToDownload(PAL::SessionID sessionID, uint64_t mainResourceLoadIdentifier, DownloadID downloadID, const ResourceRequest& request, const ResourceResponse& response)
334 {
335     auto& networkProcess = NetworkProcess::singleton();
336     if (!mainResourceLoadIdentifier) {
337         networkProcess.downloadManager().startDownload(this, sessionID, downloadID, request);
338         return;
339     }
340
341     NetworkResourceLoader* loader = m_networkResourceLoaders.get(mainResourceLoadIdentifier);
342     if (!loader) {
343         // If we're trying to download a blob here loader can be null.
344         return;
345     }
346
347     loader->convertToDownload(downloadID, request, response);
348 }
349
350 void NetworkConnectionToWebProcess::cookiesForDOM(PAL::SessionID sessionID, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, IncludeSecureCookies includeSecureCookies, String& cookieString, bool& secureCookiesAccessed)
351 {
352     std::tie(cookieString, secureCookiesAccessed) = WebCore::cookiesForDOM(storageSession(sessionID), firstParty, url, frameID, pageID, includeSecureCookies);
353 }
354
355 void NetworkConnectionToWebProcess::setCookiesFromDOM(PAL::SessionID sessionID, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, const String& cookieString)
356 {
357     WebCore::setCookiesFromDOM(storageSession(sessionID), firstParty, url, frameID, pageID, cookieString);
358 }
359
360 void NetworkConnectionToWebProcess::cookiesEnabled(PAL::SessionID sessionID, bool& result)
361 {
362     result = WebCore::cookiesEnabled(storageSession(sessionID));
363 }
364
365 void NetworkConnectionToWebProcess::cookieRequestHeaderFieldValue(PAL::SessionID sessionID, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, IncludeSecureCookies includeSecureCookies, String& cookieString, bool& secureCookiesAccessed)
366 {
367     std::tie(cookieString, secureCookiesAccessed) = WebCore::cookieRequestHeaderFieldValue(storageSession(sessionID), firstParty, url, frameID, pageID, includeSecureCookies);
368 }
369
370 void NetworkConnectionToWebProcess::getRawCookies(PAL::SessionID sessionID, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, Vector<Cookie>& result)
371 {
372     WebCore::getRawCookies(storageSession(sessionID), firstParty, url, frameID, pageID, result);
373 }
374
375 void NetworkConnectionToWebProcess::deleteCookie(PAL::SessionID sessionID, const URL& url, const String& cookieName)
376 {
377     WebCore::deleteCookie(storageSession(sessionID), url, cookieName);
378 }
379
380 void NetworkConnectionToWebProcess::registerFileBlobURL(const URL& url, const String& path, SandboxExtension::Handle&& extensionHandle, const String& contentType)
381 {
382     RefPtr<SandboxExtension> extension = SandboxExtension::create(WTFMove(extensionHandle));
383
384     NetworkBlobRegistry::singleton().registerFileBlobURL(this, url, path, WTFMove(extension), contentType);
385 }
386
387 void NetworkConnectionToWebProcess::registerBlobURL(const URL& url, Vector<BlobPart>&& blobParts, const String& contentType)
388 {
389     NetworkBlobRegistry::singleton().registerBlobURL(this, url, WTFMove(blobParts), contentType);
390 }
391
392 void NetworkConnectionToWebProcess::registerBlobURLFromURL(const URL& url, const URL& srcURL, bool shouldBypassConnectionCheck)
393 {
394     NetworkBlobRegistry::singleton().registerBlobURL(this, url, srcURL, shouldBypassConnectionCheck);
395 }
396
397 void NetworkConnectionToWebProcess::preregisterSandboxExtensionsForOptionallyFileBackedBlob(const Vector<String>& filePaths, SandboxExtension::HandleArray&& handles)
398 {
399 #if ENABLE(SANDBOX_EXTENSIONS)
400     ASSERT(filePaths.size() == handles.size());
401
402     for (size_t i = 0; i < filePaths.size(); ++i)
403         m_blobDataFileReferences.add(filePaths[i], BlobDataFileReferenceWithSandboxExtension::create(filePaths[i], SandboxExtension::create(WTFMove(handles[i]))));
404 #else
405     for (size_t i = 0; i < filePaths.size(); ++i)
406         m_blobDataFileReferences.add(filePaths[i], BlobDataFileReferenceWithSandboxExtension::create(filePaths[i], nullptr));
407 #endif
408 }
409
410 RefPtr<WebCore::BlobDataFileReference> NetworkConnectionToWebProcess::getBlobDataFileReferenceForPath(const String& path)
411 {
412     ASSERT(m_blobDataFileReferences.contains(path));
413     return m_blobDataFileReferences.get(path);
414 }
415
416 void NetworkConnectionToWebProcess::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath, const String& contentType)
417 {
418     NetworkBlobRegistry::singleton().registerBlobURLOptionallyFileBacked(this, url, srcURL, fileBackedPath, contentType);
419 }
420
421 void NetworkConnectionToWebProcess::registerBlobURLForSlice(const URL& url, const URL& srcURL, int64_t start, int64_t end)
422 {
423     NetworkBlobRegistry::singleton().registerBlobURLForSlice(this, url, srcURL, start, end);
424 }
425
426 void NetworkConnectionToWebProcess::unregisterBlobURL(const URL& url)
427 {
428     NetworkBlobRegistry::singleton().unregisterBlobURL(this, url);
429 }
430
431 void NetworkConnectionToWebProcess::blobSize(const URL& url, uint64_t& resultSize)
432 {
433     resultSize = NetworkBlobRegistry::singleton().blobSize(this, url);
434 }
435
436 void NetworkConnectionToWebProcess::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, uint64_t requestIdentifier)
437 {
438     Vector<RefPtr<BlobDataFileReference>> fileReferences;
439     for (auto& url : blobURLs)
440         fileReferences.appendVector(NetworkBlobRegistry::singleton().filesInBlob(*this, { ParsedURLString, url }));
441
442     for (auto& file : fileReferences)
443         file->prepareForFileAccess();
444
445     NetworkBlobRegistry::singleton().writeBlobsToTemporaryFiles(blobURLs, [this, protectedThis = makeRef(*this), requestIdentifier, fileReferences = WTFMove(fileReferences)](auto& fileNames) mutable {
446         for (auto& file : fileReferences)
447             file->revokeFileAccess();
448
449         NetworkProcess::singleton().grantSandboxExtensionsToStorageProcessForBlobs(fileNames, [this, protectedThis = WTFMove(protectedThis), requestIdentifier, fileNames]() {
450             if (!m_connection->isValid())
451                 return;
452
453             m_connection->send(Messages::NetworkProcessConnection::DidWriteBlobsToTemporaryFiles(requestIdentifier, fileNames), 0);
454         });
455     });
456 }
457
458 void NetworkConnectionToWebProcess::storeDerivedDataToCache(const WebKit::NetworkCache::DataKey& dataKey, const IPC::DataReference& data)
459 {
460     if (auto* cache = NetworkProcess::singleton().cache())
461         cache->storeData(dataKey, data.data(), data.size());
462 }
463
464 void NetworkConnectionToWebProcess::setCaptureExtraNetworkLoadMetricsEnabled(bool enabled)
465 {
466     m_captureExtraNetworkLoadMetricsEnabled = enabled;
467 }
468
469 void NetworkConnectionToWebProcess::ensureLegacyPrivateBrowsingSession()
470 {
471     NetworkProcess::singleton().addWebsiteDataStore(WebsiteDataStoreParameters::legacyPrivateSessionParameters());
472 }
473
474 void NetworkConnectionToWebProcess::removeStorageAccessForFrame(PAL::SessionID sessionID, uint64_t frameID, uint64_t pageID)
475 {
476 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
477     storageSession(sessionID).removeStorageAccessForFrame(frameID, pageID);
478 #else
479     UNUSED_PARAM(sessionID);
480     UNUSED_PARAM(frameID);
481     UNUSED_PARAM(pageID);
482 #endif
483 }
484
485 void NetworkConnectionToWebProcess::removeStorageAccessForAllFramesOnPage(PAL::SessionID sessionID, uint64_t pageID)
486 {
487 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
488     storageSession(sessionID).removeStorageAccessForAllFramesOnPage(pageID);
489 #else
490     UNUSED_PARAM(sessionID);
491     UNUSED_PARAM(pageID);
492 #endif
493 }
494
495 } // namespace WebKit