SocketStreamHandleImpl.cpp [plain text]
#include "config.h"
#include "SocketStreamHandleImpl.h"
#if !USE(SOUP)
#include "CookieRequestHeaderFieldProxy.h"
#include "NetworkStorageSession.h"
#include "SocketStreamHandleClient.h"
#include "StorageSessionProvider.h"
#include <wtf/Function.h>
namespace WebCore {
void SocketStreamHandleImpl::platformSend(const uint8_t* data, size_t length, Function<void(bool)>&& completionHandler)
{
if (!m_buffer.isEmpty()) {
if (m_buffer.size() + length > maxBufferSize) {
return completionHandler(false);
}
m_buffer.append(data, length);
m_client.didUpdateBufferedAmount(*this, bufferedAmount());
return completionHandler(true);
}
size_t bytesWritten = 0;
if (m_state == Open) {
if (auto result = platformSendInternal(data, length))
bytesWritten = result.value();
else
return completionHandler(false);
}
if (m_buffer.size() + length - bytesWritten > maxBufferSize) {
return completionHandler(false);
}
if (bytesWritten < length) {
m_buffer.append(data + bytesWritten, length - bytesWritten);
m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
}
return completionHandler(true);
}
static size_t removeTerminationCharacters(const uint8_t* data, size_t dataLength)
{
#ifndef NDEBUG
ASSERT(dataLength > 2);
ASSERT(data[dataLength - 2] == '\r');
ASSERT(data[dataLength - 1] == '\n');
#else
UNUSED_PARAM(data);
#endif
return dataLength - 2;
}
static Optional<std::pair<Vector<uint8_t>, bool>> cookieDataForHandshake(const NetworkStorageSession* networkStorageSession, const CookieRequestHeaderFieldProxy& headerFieldProxy)
{
if (!networkStorageSession)
return WTF::nullopt;
auto [cookieDataString, secureCookiesAccessed] = networkStorageSession->cookieRequestHeaderFieldValue(headerFieldProxy);
if (cookieDataString.isEmpty())
return std::pair<Vector<uint8_t>, bool> { { }, secureCookiesAccessed };
CString cookieData = cookieDataString.utf8();
Vector<uint8_t> data = { 'C', 'o', 'o', 'k', 'i', 'e', ':', ' ' };
data.append(cookieData.data(), cookieData.length());
data.appendVector(Vector<uint8_t>({ '\r', '\n', '\r', '\n' }));
return std::pair<Vector<uint8_t>, bool> { data, secureCookiesAccessed };
}
void SocketStreamHandleImpl::platformSendHandshake(const uint8_t* data, size_t length, const Optional<CookieRequestHeaderFieldProxy>& headerFieldProxy, Function<void(bool, bool)>&& completionHandler)
{
Vector<uint8_t> cookieData;
bool secureCookiesAccessed = false;
if (headerFieldProxy) {
auto cookieDataFromNetworkSession = cookieDataForHandshake(m_storageSessionProvider ? m_storageSessionProvider->storageSession() : nullptr, *headerFieldProxy);
if (!cookieDataFromNetworkSession) {
completionHandler(false, false);
return;
}
std::tie(cookieData, secureCookiesAccessed) = *cookieDataFromNetworkSession;
if (cookieData.size())
length = removeTerminationCharacters(data, length);
}
if (!m_buffer.isEmpty()) {
if (m_buffer.size() + length + cookieData.size() > maxBufferSize) {
return completionHandler(false, secureCookiesAccessed);
}
m_buffer.append(data, length);
m_buffer.append(cookieData.data(), cookieData.size());
m_client.didUpdateBufferedAmount(*this, bufferedAmount());
return completionHandler(true, secureCookiesAccessed);
}
size_t bytesWritten = 0;
if (m_state == Open) {
Vector<uint8_t> sendData;
sendData.reserveCapacity(length + cookieData.size());
sendData.append(data, length);
sendData.append(cookieData.data(), cookieData.size());
if (auto result = platformSendInternal(sendData.data(), sendData.size()))
bytesWritten = result.value();
else
return completionHandler(false, secureCookiesAccessed);
}
if (m_buffer.size() + length + cookieData.size() - bytesWritten > maxBufferSize) {
return completionHandler(false, secureCookiesAccessed);
}
if (bytesWritten < length + cookieData.size()) {
size_t cookieBytesWritten = 0;
if (bytesWritten < length)
m_buffer.append(data + bytesWritten, length - bytesWritten);
else
cookieBytesWritten = bytesWritten - length;
m_buffer.append(cookieData.data() + cookieBytesWritten, cookieData.size() - cookieBytesWritten);
m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
}
return completionHandler(true, secureCookiesAccessed);
}
bool SocketStreamHandleImpl::sendPendingData()
{
if (m_state != Open && m_state != Closing)
return false;
if (m_buffer.isEmpty()) {
if (m_state == Open)
return false;
if (m_state == Closing) {
disconnect();
return false;
}
}
bool pending;
do {
auto result = platformSendInternal(m_buffer.firstBlockData(), m_buffer.firstBlockSize());
if (!result)
return false;
size_t bytesWritten = result.value();
if (!bytesWritten)
return false;
pending = bytesWritten != m_buffer.firstBlockSize();
ASSERT(m_buffer.size() - bytesWritten <= maxBufferSize);
m_buffer.consume(bytesWritten);
} while (!pending && !m_buffer.isEmpty());
m_client.didUpdateBufferedAmount(static_cast<SocketStreamHandle&>(*this), bufferedAmount());
return true;
}
size_t SocketStreamHandleImpl::bufferedAmount()
{
return m_buffer.size();
}
}
#endif // !USE(SOUP)