mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2025-02-20 08:53:19 +03:00
143 lines
3.9 KiB
C++
143 lines
3.9 KiB
C++
// Copyright 2020 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/socket/read_buffering_stream_socket.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "base/check_op.h"
|
|
#include "base/notreached.h"
|
|
#include "net/base/io_buffer.h"
|
|
|
|
namespace net {
|
|
|
|
ReadBufferingStreamSocket::ReadBufferingStreamSocket(
|
|
std::unique_ptr<StreamSocket> transport)
|
|
: WrappedStreamSocket(std::move(transport)) {}
|
|
|
|
ReadBufferingStreamSocket::~ReadBufferingStreamSocket() = default;
|
|
|
|
void ReadBufferingStreamSocket::BufferNextRead(int size) {
|
|
DCHECK(!user_read_buf_);
|
|
read_buffer_ = base::MakeRefCounted<GrowableIOBuffer>();
|
|
read_buffer_->SetCapacity(size);
|
|
buffer_full_ = false;
|
|
}
|
|
|
|
int ReadBufferingStreamSocket::Read(IOBuffer* buf,
|
|
int buf_len,
|
|
CompletionOnceCallback callback) {
|
|
DCHECK(!user_read_buf_);
|
|
if (!read_buffer_)
|
|
return transport_->Read(buf, buf_len, std::move(callback));
|
|
int rv = ReadIfReady(buf, buf_len, std::move(callback));
|
|
if (rv == ERR_IO_PENDING) {
|
|
user_read_buf_ = buf;
|
|
user_read_buf_len_ = buf_len;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
int ReadBufferingStreamSocket::ReadIfReady(IOBuffer* buf,
|
|
int buf_len,
|
|
CompletionOnceCallback callback) {
|
|
DCHECK(!user_read_buf_);
|
|
if (!read_buffer_)
|
|
return transport_->ReadIfReady(buf, buf_len, std::move(callback));
|
|
|
|
if (buffer_full_)
|
|
return CopyToCaller(buf, buf_len);
|
|
|
|
state_ = STATE_READ;
|
|
int rv = DoLoop(OK);
|
|
if (rv == OK) {
|
|
rv = CopyToCaller(buf, buf_len);
|
|
} else if (rv == ERR_IO_PENDING) {
|
|
user_read_callback_ = std::move(callback);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
int ReadBufferingStreamSocket::DoLoop(int result) {
|
|
int rv = result;
|
|
do {
|
|
State current_state = state_;
|
|
state_ = STATE_NONE;
|
|
switch (current_state) {
|
|
case STATE_READ:
|
|
rv = DoRead();
|
|
break;
|
|
case STATE_READ_COMPLETE:
|
|
rv = DoReadComplete(rv);
|
|
break;
|
|
case STATE_NONE:
|
|
default:
|
|
NOTREACHED() << "Unexpected state: " << current_state;
|
|
rv = ERR_UNEXPECTED;
|
|
break;
|
|
}
|
|
} while (rv != ERR_IO_PENDING && state_ != STATE_NONE);
|
|
return rv;
|
|
}
|
|
|
|
int ReadBufferingStreamSocket::DoRead() {
|
|
DCHECK(read_buffer_);
|
|
DCHECK(!buffer_full_);
|
|
|
|
state_ = STATE_READ_COMPLETE;
|
|
return transport_->Read(
|
|
read_buffer_.get(), read_buffer_->RemainingCapacity(),
|
|
base::BindOnce(&ReadBufferingStreamSocket::OnReadCompleted,
|
|
base::Unretained(this)));
|
|
}
|
|
|
|
int ReadBufferingStreamSocket::DoReadComplete(int result) {
|
|
state_ = STATE_NONE;
|
|
|
|
if (result <= 0)
|
|
return result;
|
|
|
|
read_buffer_->set_offset(read_buffer_->offset() + result);
|
|
if (read_buffer_->RemainingCapacity() > 0) {
|
|
// Keep reading until |read_buffer_| is full.
|
|
state_ = STATE_READ;
|
|
} else {
|
|
read_buffer_->set_offset(0);
|
|
buffer_full_ = true;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
void ReadBufferingStreamSocket::OnReadCompleted(int result) {
|
|
DCHECK_NE(ERR_IO_PENDING, result);
|
|
DCHECK(user_read_callback_);
|
|
|
|
result = DoLoop(result);
|
|
if (result == ERR_IO_PENDING)
|
|
return;
|
|
if (result == OK && user_read_buf_) {
|
|
// If the user called Read(), return the data to the caller.
|
|
result = CopyToCaller(user_read_buf_.get(), user_read_buf_len_);
|
|
user_read_buf_ = nullptr;
|
|
user_read_buf_len_ = 0;
|
|
}
|
|
std::move(user_read_callback_).Run(result);
|
|
}
|
|
|
|
int ReadBufferingStreamSocket::CopyToCaller(IOBuffer* buf, int buf_len) {
|
|
DCHECK(read_buffer_);
|
|
DCHECK(buffer_full_);
|
|
|
|
buf_len = std::min(buf_len, read_buffer_->RemainingCapacity());
|
|
memcpy(buf->data(), read_buffer_->data(), buf_len);
|
|
read_buffer_->set_offset(read_buffer_->offset() + buf_len);
|
|
if (read_buffer_->RemainingCapacity() == 0) {
|
|
read_buffer_ = nullptr;
|
|
buffer_full_ = false;
|
|
}
|
|
return buf_len;
|
|
}
|
|
|
|
} // namespace net
|