Add Optional to Forward.h.
[WebKit.git] / Source / WebCore / platform / network / SocketStreamHandleImpl.cpp
1 /*
2  * Copyright (C) 2017-2018 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 "SocketStreamHandleImpl.h"
28
29 #include "CookieRequestHeaderFieldProxy.h"
30 #include "NetworkStorageSession.h"
31 #include "SocketStreamHandleClient.h"
32 #include "StorageSessionProvider.h"
33 #include <wtf/Function.h>
34
35 namespace WebCore {
36
37 void SocketStreamHandleImpl::platformSend(const uint8_t* data, size_t length, Function<void(bool)>&& completionHandler)
38 {
39     if (!m_buffer.isEmpty()) {
40         if (m_buffer.size() + length > maxBufferSize) {
41             // FIXME: report error to indicate that buffer has no more space.
42             return completionHandler(false);
43         }
44         m_buffer.append(data, length);
45         m_client.didUpdateBufferedAmount(*this, bufferedAmount());
46         return completionHandler(true);
47     }
48     size_t bytesWritten = 0;
49     if (m_state == Open) {
50         if (auto result = platformSendInternal(data, length))
51             bytesWritten = result.value();
52         else
53             return completionHandler(false);
54     }
55     if (m_buffer.size() + length - bytesWritten > maxBufferSize) {
56         // FIXME: report error to indicate that buffer has no more space.
57         return completionHandler(false);
58     }
59     if (bytesWritten < length) {
60         m_buffer.append(data + bytesWritten, length - bytesWritten);
61         m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
62     }
63     return completionHandler(true);
64 }
65
66 static size_t removeTerminationCharacters(const uint8_t* data, size_t dataLength)
67 {
68 #ifndef NDEBUG
69     ASSERT(dataLength > 2);
70     ASSERT(data[dataLength - 2] == '\r');
71     ASSERT(data[dataLength - 1] == '\n');
72 #else
73     UNUSED_PARAM(data);
74 #endif
75
76     // Remove the terminating '\r\n'
77     return dataLength - 2;
78 }
79
80 static Optional<std::pair<Vector<uint8_t>, bool>> cookieDataForHandshake(const NetworkStorageSession* networkStorageSession, const CookieRequestHeaderFieldProxy& headerFieldProxy)
81 {
82     if (!networkStorageSession)
83         return WTF::nullopt;
84     
85     String cookieDataString;
86     bool secureCookiesAccessed = false;
87     std::tie(cookieDataString, secureCookiesAccessed) = networkStorageSession->cookieRequestHeaderFieldValue(headerFieldProxy);
88     if (cookieDataString.isEmpty())
89         return std::pair<Vector<uint8_t>, bool> { { }, secureCookiesAccessed };
90
91     CString cookieData = cookieDataString.utf8();
92
93     Vector<uint8_t> data = { 'C', 'o', 'o', 'k', 'i', 'e', ':', ' ' };
94     data.append(cookieData.data(), cookieData.length());
95     data.appendVector(Vector<uint8_t>({ '\r', '\n', '\r', '\n' }));
96
97     return std::pair<Vector<uint8_t>, bool> { data, secureCookiesAccessed };
98 }
99
100 void SocketStreamHandleImpl::platformSendHandshake(const uint8_t* data, size_t length, const Optional<CookieRequestHeaderFieldProxy>& headerFieldProxy, Function<void(bool, bool)>&& completionHandler)
101 {
102     Vector<uint8_t> cookieData;
103     bool secureCookiesAccessed = false;
104
105     if (headerFieldProxy) {
106         auto cookieDataFromNetworkSession = cookieDataForHandshake(m_storageSessionProvider ? m_storageSessionProvider->storageSession() : nullptr, *headerFieldProxy);
107         if (!cookieDataFromNetworkSession) {
108             completionHandler(false, false);
109             return;
110         }
111
112         std::tie(cookieData, secureCookiesAccessed) = *cookieDataFromNetworkSession;
113         if (cookieData.size())
114             length = removeTerminationCharacters(data, length);
115     }
116
117     if (!m_buffer.isEmpty()) {
118         if (m_buffer.size() + length + cookieData.size() > maxBufferSize) {
119             // FIXME: report error to indicate that buffer has no more space.
120             return completionHandler(false, secureCookiesAccessed);
121         }
122         m_buffer.append(data, length);
123         m_buffer.append(cookieData.data(), cookieData.size());
124         m_client.didUpdateBufferedAmount(*this, bufferedAmount());
125         return completionHandler(true, secureCookiesAccessed);
126     }
127     size_t bytesWritten = 0;
128     if (m_state == Open) {
129         // Unfortunately, we need to send the data in one buffer or else the handshake fails.
130         Vector<uint8_t> sendData;
131         sendData.reserveCapacity(length + cookieData.size());
132         sendData.append(data, length);
133         sendData.append(cookieData.data(), cookieData.size());
134
135         if (auto result = platformSendInternal(sendData.data(), sendData.size()))
136             bytesWritten = result.value();
137         else
138             return completionHandler(false, secureCookiesAccessed);
139     }
140     if (m_buffer.size() + length + cookieData.size() - bytesWritten > maxBufferSize) {
141         // FIXME: report error to indicate that buffer has no more space.
142         return completionHandler(false, secureCookiesAccessed);
143     }
144     if (bytesWritten < length + cookieData.size()) {
145         size_t cookieBytesWritten = 0;
146         if (bytesWritten < length)
147             m_buffer.append(data + bytesWritten, length - bytesWritten);
148         else
149             cookieBytesWritten = bytesWritten - length;
150         m_buffer.append(cookieData.data() + cookieBytesWritten, cookieData.size() - cookieBytesWritten);
151         m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
152     }
153     return completionHandler(true, secureCookiesAccessed);
154 }
155
156 bool SocketStreamHandleImpl::sendPendingData()
157 {
158     if (m_state != Open && m_state != Closing)
159         return false;
160     if (m_buffer.isEmpty()) {
161         if (m_state == Open)
162             return false;
163         if (m_state == Closing) {
164             disconnect();
165             return false;
166         }
167     }
168     bool pending;
169     do {
170         auto result = platformSendInternal(m_buffer.firstBlockData(), m_buffer.firstBlockSize());
171         if (!result)
172             return false;
173         size_t bytesWritten = result.value();
174         if (!bytesWritten)
175             return false;
176         pending = bytesWritten != m_buffer.firstBlockSize();
177         ASSERT(m_buffer.size() - bytesWritten <= maxBufferSize);
178         m_buffer.consume(bytesWritten);
179     } while (!pending && !m_buffer.isEmpty());
180     m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
181     return true;
182 }
183
184 size_t SocketStreamHandleImpl::bufferedAmount()
185 {
186     return m_buffer.size();
187 }
188
189 } // namespace WebCore