2 * Copyright (C) 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "ResourceHandle.h"
29 #include "ResourceHandleClient.h"
31 #include <wtf/CompletionHandler.h>
35 // This class triggers asynchronous loads independent of the networking context staying alive (i.e., auditing pingbacks).
36 // The object just needs to live long enough to ensure the message was actually sent.
37 // As soon as any callback is received from the ResourceHandle, this class will cancel the load and delete itself.
39 class PingHandle final : private ResourceHandleClient {
40 WTF_MAKE_NONCOPYABLE(PingHandle); WTF_MAKE_FAST_ALLOCATED;
42 enum class UsesAsyncCallbacks {
47 PingHandle(NetworkingContext* networkingContext, const ResourceRequest& request, bool shouldUseCredentialStorage, UsesAsyncCallbacks useAsyncCallbacks, bool shouldFollowRedirects, WTF::CompletionHandler<void(const ResourceError&)>&& completionHandler)
48 : m_currentRequest(request)
49 , m_timeoutTimer(*this, &PingHandle::timeoutTimerFired)
50 , m_shouldUseCredentialStorage(shouldUseCredentialStorage)
51 , m_shouldFollowRedirects(shouldFollowRedirects)
52 , m_usesAsyncCallbacks(useAsyncCallbacks)
53 , m_completionHandler(WTFMove(completionHandler))
55 m_handle = ResourceHandle::create(networkingContext, request, this, false, false);
57 // If the server never responds, this object will hang around forever.
58 // Set a very generous timeout, just in case.
59 m_timeoutTimer.startOneShot(60000_s);
63 ResourceRequest willSendRequest(ResourceHandle*, ResourceRequest&& request, ResourceResponse&&) final
65 return m_shouldFollowRedirects ? request : ResourceRequest();
67 void willSendRequestAsync(ResourceHandle* handle, ResourceRequest&& request, ResourceResponse&&) final
69 m_currentRequest = WTFMove(request);
70 if (m_shouldFollowRedirects) {
71 handle->continueWillSendRequest(ResourceRequest { m_currentRequest });
74 pingLoadComplete(ResourceError { String(), 0, m_currentRequest.url(), ASCIILiteral("Not allowed to follow redirects"), ResourceError::Type::AccessControl });
76 void didReceiveResponse(ResourceHandle*, ResourceResponse&&) final { pingLoadComplete(); }
77 void didReceiveBuffer(ResourceHandle*, Ref<SharedBuffer>&&, int) final { pingLoadComplete(); }
78 void didFinishLoading(ResourceHandle*) final { pingLoadComplete(); }
79 void didFail(ResourceHandle*, const ResourceError& error) final { pingLoadComplete(error); }
80 bool shouldUseCredentialStorage(ResourceHandle*) final { return m_shouldUseCredentialStorage; }
81 bool usesAsyncCallbacks() final { return m_usesAsyncCallbacks == UsesAsyncCallbacks::Yes; }
82 void timeoutTimerFired() { pingLoadComplete(ResourceError { String(), 0, m_currentRequest.url(), ASCIILiteral("Load timed out"), ResourceError::Type::Timeout }); }
84 void pingLoadComplete(const ResourceError& error = { })
86 if (auto completionHandler = std::exchange(m_completionHandler, nullptr))
87 completionHandler(error);
93 ASSERT(!m_completionHandler);
95 ASSERT(m_handle->client() == this);
96 m_handle->clearClient();
101 RefPtr<ResourceHandle> m_handle;
102 ResourceRequest m_currentRequest;
103 Timer m_timeoutTimer;
104 bool m_shouldUseCredentialStorage;
105 bool m_shouldFollowRedirects;
106 UsesAsyncCallbacks m_usesAsyncCallbacks;
107 WTF::CompletionHandler<void(const ResourceError&)> m_completionHandler;
110 } // namespace WebCore