Delete unused code in httpbase and httpcommon.

Deleted features include HttpBase::GetDocumentStream(), and support for
other operations than GET.

Bug: webrtc:6424
Change-Id: Ib16537cd1db87de53150f8e9e30dd89778a20c2e
Reviewed-on: https://webrtc-review.googlesource.com/84140
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24102}
This commit is contained in:
Niels Möller 2018-06-25 10:41:46 +02:00 committed by Commit Bot
parent 7f5175a455
commit b4731ff9cb
7 changed files with 9 additions and 506 deletions

View File

@ -223,150 +223,12 @@ void HttpParser::complete(HttpError error) {
}
}
//////////////////////////////////////////////////////////////////////
// HttpBase::DocumentStream
//////////////////////////////////////////////////////////////////////
class BlockingMemoryStream : public ExternalMemoryStream {
public:
BlockingMemoryStream(char* buffer, size_t size)
: ExternalMemoryStream(buffer, size) {}
StreamResult DoReserve(size_t size, int* error) override {
return (buffer_length_ >= size) ? SR_SUCCESS : SR_BLOCK;
}
};
class HttpBase::DocumentStream : public StreamInterface {
public:
DocumentStream(HttpBase* base) : base_(base), error_(HE_DEFAULT) {}
StreamState GetState() const override {
if (nullptr == base_)
return SS_CLOSED;
if (HM_RECV == base_->mode_)
return SS_OPEN;
return SS_OPENING;
}
StreamResult Read(void* buffer,
size_t buffer_len,
size_t* read,
int* error) override {
if (!base_) {
if (error)
*error = error_;
return (HE_NONE == error_) ? SR_EOS : SR_ERROR;
}
if (HM_RECV != base_->mode_) {
return SR_BLOCK;
}
// DoReceiveLoop writes http document data to the StreamInterface* document
// member of HttpData. In this case, we want this data to be written
// directly to our buffer. To accomplish this, we wrap our buffer with a
// StreamInterface, and replace the existing document with our wrapper.
// When the method returns, we restore the old document. Ideally, we would
// pass our StreamInterface* to DoReceiveLoop, but due to the callbacks
// of HttpParser, we would still need to store the pointer temporarily.
std::unique_ptr<StreamInterface> stream(
new BlockingMemoryStream(reinterpret_cast<char*>(buffer), buffer_len));
// Replace the existing document with our wrapped buffer.
base_->data_->document.swap(stream);
// Pump the I/O loop. DoReceiveLoop is guaranteed not to attempt to
// complete the I/O process, which means that our wrapper is not in danger
// of being deleted. To ensure this, DoReceiveLoop returns true when it
// wants complete to be called. We make sure to uninstall our wrapper
// before calling complete().
HttpError http_error;
bool complete = base_->DoReceiveLoop(&http_error);
// Reinstall the original output document.
base_->data_->document.swap(stream);
// If we reach the end of the receive stream, we disconnect our stream
// adapter from the HttpBase, and further calls to read will either return
// EOS or ERROR, appropriately. Finally, we call complete().
StreamResult result = SR_BLOCK;
if (complete) {
HttpBase* base = Disconnect(http_error);
if (error)
*error = error_;
result = (HE_NONE == error_) ? SR_EOS : SR_ERROR;
base->complete(http_error);
}
// Even if we are complete, if some data was read we must return SUCCESS.
// Future Reads will return EOS or ERROR based on the error_ variable.
size_t position;
stream->GetPosition(&position);
if (position > 0) {
if (read)
*read = position;
result = SR_SUCCESS;
}
return result;
}
StreamResult Write(const void* data,
size_t data_len,
size_t* written,
int* error) override {
if (error)
*error = -1;
return SR_ERROR;
}
void Close() override {
if (base_) {
HttpBase* base = Disconnect(HE_NONE);
if (HM_RECV == base->mode_ && base->http_stream_) {
// Read I/O could have been stalled on the user of this DocumentStream,
// so restart the I/O process now that we've removed ourselves.
base->http_stream_->PostEvent(SE_READ, 0);
}
}
}
bool GetAvailable(size_t* size) const override {
if (!base_ || HM_RECV != base_->mode_)
return false;
size_t data_size = base_->GetDataRemaining();
if (SIZE_UNKNOWN == data_size)
return false;
if (size)
*size = data_size;
return true;
}
HttpBase* Disconnect(HttpError error) {
RTC_DCHECK(nullptr != base_);
RTC_DCHECK(nullptr != base_->doc_stream_);
HttpBase* base = base_;
base_->doc_stream_ = nullptr;
base_ = nullptr;
error_ = error;
return base;
}
private:
HttpBase* base_;
HttpError error_;
};
//////////////////////////////////////////////////////////////////////
// HttpBase
//////////////////////////////////////////////////////////////////////
HttpBase::HttpBase()
: mode_(HM_NONE),
data_(nullptr),
notify_(nullptr),
http_stream_(nullptr),
doc_stream_(nullptr) {}
: mode_(HM_NONE), data_(nullptr), notify_(nullptr), http_stream_(nullptr) {}
HttpBase::~HttpBase() {
RTC_DCHECK(HM_NONE == mode_);
@ -451,11 +313,7 @@ void HttpBase::recv(HttpData* data) {
ignore_data_ = chunk_data_ = false;
reset();
if (doc_stream_) {
doc_stream_->SignalEvent(doc_stream_, SE_OPEN | SE_READ, 0);
} else {
read_and_process_data();
}
read_and_process_data();
}
void HttpBase::abort(HttpError err) {
@ -467,13 +325,6 @@ void HttpBase::abort(HttpError err) {
}
}
StreamInterface* HttpBase::GetDocumentStream() {
if (doc_stream_)
return nullptr;
doc_stream_ = new DocumentStream(this);
return doc_stream_;
}
HttpError HttpBase::HandleStreamClose(int error) {
if (http_stream_ != nullptr) {
http_stream_->Close();
@ -730,13 +581,6 @@ void HttpBase::do_complete(HttpError err) {
data_->document->SignalEvent.disconnect(this);
}
data_ = nullptr;
if ((HM_RECV == mode) && doc_stream_) {
RTC_DCHECK(HE_NONE !=
err); // We should have Disconnected doc_stream_ already.
DocumentStream* ds = doc_stream_;
ds->Disconnect(err);
ds->SignalEvent(ds, SE_CLOSE, err);
}
if (notify_) {
notify_->onHttpComplete(mode, err);
}
@ -761,11 +605,7 @@ void HttpBase::OnHttpStreamEvent(StreamInterface* stream,
}
if ((events & SE_READ) && (mode_ == HM_RECV)) {
if (doc_stream_) {
doc_stream_->SignalEvent(doc_stream_, SE_READ, 0);
} else {
read_and_process_data();
}
read_and_process_data();
return;
}
@ -825,7 +665,6 @@ HttpParser::ProcessResult HttpBase::ProcessHeader(const char* name,
HttpParser::ProcessResult HttpBase::ProcessHeaderComplete(bool chunked,
size_t& data_size,
HttpError* error) {
StreamInterface* old_docstream = doc_stream_;
if (notify_) {
*error = notify_->onHttpHeaderComplete(chunked, data_size);
// The request must not be aborted as a result of this callback.
@ -837,10 +676,6 @@ HttpParser::ProcessResult HttpBase::ProcessHeaderComplete(bool chunked,
if (HE_NONE != *error) {
return PR_COMPLETE;
}
if (old_docstream != doc_stream_) {
// Break out of Process loop, since our I/O model just changed.
return PR_BLOCK;
}
return PR_CONTINUE;
}

View File

@ -119,11 +119,6 @@ class HttpBase : private HttpParser, public sigslot::has_slots<> {
void set_ignore_data(bool ignore) { ignore_data_ = ignore; }
bool ignore_data() const { return ignore_data_; }
// Obtaining this stream puts HttpBase into stream mode until the stream
// is closed. HttpBase can only expose one open stream interface at a time.
// Further calls will return null.
StreamInterface* GetDocumentStream();
protected:
// Do cleanup when the http stream closes (error may be 0 for a clean
// shutdown), and return the error code to signal.
@ -180,7 +175,6 @@ class HttpBase : private HttpParser, public sigslot::has_slots<> {
HttpData* data_;
IHttpNotify* notify_;
StreamInterface* http_stream_;
DocumentStream* doc_stream_;
char buffer_[kBufferSize];
size_t len_;

View File

@ -34,16 +34,6 @@ const char* const kHttpEmptyResponse =
"Proxy-Authorization: 42\r\n"
"\r\n";
const char* const kHttpResponsePrefix =
"HTTP/1.1 200\r\n"
"Connection: Keep-Alive\r\n"
"Content-Type: text/plain\r\n"
"Proxy-Authorization: 42\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"8\r\n"
"Goodbye!\r\n";
class HttpBaseTest : public testing::Test, public IHttpNotify {
public:
enum EventType { E_HEADER_COMPLETE, E_COMPLETE, E_CLOSED };
@ -54,7 +44,7 @@ class HttpBaseTest : public testing::Test, public IHttpNotify {
HttpMode mode;
HttpError err;
};
HttpBaseTest() : mem(nullptr), obtain_stream(false), http_stream(nullptr) {}
HttpBaseTest() : mem(nullptr), http_stream(nullptr) {}
void TearDown() override {
delete http_stream;
@ -66,9 +56,6 @@ class HttpBaseTest : public testing::Test, public IHttpNotify {
RTC_LOG_F(LS_VERBOSE) << "chunked: " << chunked << " size: " << data_size;
Event e = {E_HEADER_COMPLETE, chunked, data_size, HM_NONE, HE_NONE};
events.push_back(e);
if (obtain_stream) {
ObtainDocumentStream();
}
return HE_NONE;
}
void onHttpComplete(HttpMode mode, HttpError err) override {
@ -88,7 +75,6 @@ class HttpBaseTest : public testing::Test, public IHttpNotify {
void VerifyDocumentContents(const char* expected_data,
size_t expected_length = SIZE_UNKNOWN);
void ObtainDocumentStream();
void VerifyDocumentStreamIsOpening();
void VerifyDocumentStreamOpenEvent();
void ReadDocumentStreamData(const char* expected_data);
@ -108,8 +94,7 @@ class HttpBaseTest : public testing::Test, public IHttpNotify {
webrtc::testing::StreamSource src;
std::vector<Event> events;
// Document stream, and stream events
bool obtain_stream;
// Stream events
StreamInterface* http_stream;
webrtc::testing::StreamSink sink;
};
@ -184,15 +169,6 @@ void HttpBaseTest::VerifyDocumentContents(const char* expected_data,
RTC_LOG_F(LS_VERBOSE) << "Exit";
}
void HttpBaseTest::ObtainDocumentStream() {
RTC_LOG_F(LS_VERBOSE) << "Enter";
EXPECT_FALSE(http_stream);
http_stream = base.GetDocumentStream();
ASSERT_TRUE(nullptr != http_stream);
sink.Monitor(http_stream);
RTC_LOG_F(LS_VERBOSE) << "Exit";
}
void HttpBaseTest::VerifyDocumentStreamIsOpening() {
RTC_LOG_F(LS_VERBOSE) << "Enter";
ASSERT_TRUE(nullptr != http_stream);
@ -379,145 +355,4 @@ TEST_F(HttpBaseTest, SupportsReceiveViaDocumentPush) {
VerifyDocumentContents("Goodbye!");
}
TEST_F(HttpBaseTest, SupportsReceiveViaStreamPull) {
// Switch to pull mode
ObtainDocumentStream();
VerifyDocumentStreamIsOpening();
// Queue response document
SetupSource(kHttpResponse);
VerifyDocumentStreamIsOpening();
// Begin receive
base.recv(&data);
// Pull document data
VerifyDocumentStreamOpenEvent();
ReadDocumentStreamData("Goodbye!");
VerifyDocumentStreamIsEOS();
// Document completed successfully
VerifyHeaderComplete(2, false);
VerifyTransferComplete(HM_RECV, HE_NONE);
VerifyDocumentContents("");
}
TEST_F(HttpBaseTest, DISABLED_AllowsCloseStreamBeforeDocumentIsComplete) {
// TODO: Remove extra logging once test failure is understood
LoggingSeverity old_sev = rtc::LogMessage::GetLogToDebug();
rtc::LogMessage::LogToDebug(LS_VERBOSE);
// Switch to pull mode
ObtainDocumentStream();
VerifyDocumentStreamIsOpening();
// Queue response document
SetupSource(kHttpResponse);
VerifyDocumentStreamIsOpening();
// Begin receive
base.recv(&data);
// Pull some of the data
VerifyDocumentStreamOpenEvent();
ReadDocumentStreamData("Goodb");
// We've seen the header by now
VerifyHeaderComplete(1, false);
// Close the pull stream, this will transition back to push I/O.
http_stream->Close();
Thread::Current()->ProcessMessages(0);
// Remainder of document completed successfully
VerifyTransferComplete(HM_RECV, HE_NONE);
VerifyDocumentContents("ye!");
rtc::LogMessage::LogToDebug(old_sev);
}
TEST_F(HttpBaseTest, AllowsGetDocumentStreamInResponseToHttpHeader) {
// Queue response document
SetupSource(kHttpResponse);
// Switch to pull mode in response to header arrival
obtain_stream = true;
// Begin receive
base.recv(&data);
// We've already seen the header, but not data has arrived
VerifyHeaderComplete(1, false);
VerifyDocumentContents("");
// Pull the document data
ReadDocumentStreamData("Goodbye!");
VerifyDocumentStreamIsEOS();
// Document completed successfully
VerifyTransferComplete(HM_RECV, HE_NONE);
VerifyDocumentContents("");
}
TEST_F(HttpBaseTest, AllowsGetDocumentStreamWithEmptyDocumentBody) {
// Queue empty response document
SetupSource(kHttpEmptyResponse);
// Switch to pull mode in response to header arrival
obtain_stream = true;
// Begin receive
base.recv(&data);
// We've already seen the header, but not data has arrived
VerifyHeaderComplete(1, true);
VerifyDocumentContents("");
// The document is still open, until we attempt to read
ASSERT_TRUE(nullptr != http_stream);
EXPECT_EQ(SS_OPEN, http_stream->GetState());
// Attempt to read data, and discover EOS
VerifyDocumentStreamIsEOS();
// Document completed successfully
VerifyTransferComplete(HM_RECV, HE_NONE);
VerifyDocumentContents("");
}
TEST_F(HttpBaseTest, SignalsDocumentStreamCloseOnUnexpectedClose) {
// Switch to pull mode
ObtainDocumentStream();
VerifyDocumentStreamIsOpening();
// Queue response document
SetupSource(kHttpResponsePrefix);
VerifyDocumentStreamIsOpening();
// Begin receive
base.recv(&data);
// Pull document data
VerifyDocumentStreamOpenEvent();
ReadDocumentStreamData("Goodbye!");
// Simulate unexpected close
src.SetState(SS_CLOSED);
// Observe error event on document stream
EXPECT_EQ(webrtc::testing::SSE_ERROR, sink.Events(http_stream));
// Future reads give an error
int error = 0;
char buffer[5] = {0};
EXPECT_EQ(SR_ERROR,
http_stream->Read(buffer, sizeof(buffer), nullptr, &error));
EXPECT_EQ(HE_DISCONNECTED, error);
// Document completed with error
VerifyHeaderComplete(2, false);
VerifyTransferComplete(HM_RECV, HE_DISCONNECTED);
VerifyDocumentContents("");
}
} // namespace rtc

View File

@ -169,10 +169,6 @@ struct Enum {
static const char* kHttpVersions[HVER_LAST + 1] = {"1.0", "1.1", "Unknown"};
ENUM(HttpVersion, kHttpVersions);
static const char* kHttpVerbs[HV_LAST + 1] = {"GET", "POST", "PUT",
"DELETE", "CONNECT", "HEAD"};
ENUM(HttpVerb, kHttpVerbs);
static const char* kHttpHeaders[HH_LAST + 1] = {
"Age",
"Cache-Control",
@ -213,14 +209,6 @@ bool FromString(HttpVersion& version, const std::string& str) {
return Enum<HttpVersion>::Parse(version, str);
}
const char* ToString(HttpVerb verb) {
return Enum<HttpVerb>::Name(verb);
}
bool FromString(HttpVerb& verb, const std::string& str) {
return Enum<HttpVerb>::Parse(verb, str);
}
const char* ToString(HttpHeader header) {
return Enum<HttpHeader>::Name(header);
}
@ -229,25 +217,6 @@ bool FromString(HttpHeader& header, const std::string& str) {
return Enum<HttpHeader>::Parse(header, str);
}
bool HttpCodeHasBody(uint32_t code) {
return !HttpCodeIsInformational(code) && (code != HC_NO_CONTENT) &&
(code != HC_NOT_MODIFIED);
}
bool HttpCodeIsCacheable(uint32_t code) {
switch (code) {
case HC_OK:
case HC_NON_AUTHORITATIVE:
case HC_PARTIAL_CONTENT:
case HC_MULTIPLE_CHOICES:
case HC_MOVED_PERMANENTLY:
case HC_GONE:
return true;
default:
return false;
}
}
bool HttpHeaderIsEndToEnd(HttpHeader header) {
switch (header) {
case HH_CONNECTION:
@ -494,10 +463,6 @@ void HttpData::clear(bool release_document) {
}
}
void HttpData::copy(const HttpData& src) {
headers_ = src.headers_;
}
void HttpData::changeHeader(const std::string& name,
const std::string& value,
HeaderCombine combine) {
@ -572,21 +537,14 @@ void HttpData::setDocumentAndLength(StreamInterface* document) {
//
void HttpRequestData::clear(bool release_document) {
verb = HV_GET;
path.clear();
HttpData::clear(release_document);
}
void HttpRequestData::copy(const HttpRequestData& src) {
verb = src.verb;
path = src.path;
HttpData::copy(src);
}
size_t HttpRequestData::formatLeader(char* buffer, size_t size) const {
RTC_DCHECK(path.find(' ') == std::string::npos);
return sprintfn(buffer, size, "%s %.*s HTTP/%s", ToString(verb), path.size(),
path.data(), ToString(version));
return sprintfn(buffer, size, "GET %.*s HTTP/%s", path.size(), path.data(),
ToString(version));
}
HttpError HttpRequestData::parseLeader(const char* line, size_t len) {
@ -608,8 +566,7 @@ HttpError HttpRequestData::parseLeader(const char* line, size_t len) {
} else {
return HE_PROTOCOL;
}
std::string sverb(line, vend);
if (!FromString(verb, sverb.c_str())) {
if (vend != 3 || memcmp(line, "GET", 3)) {
return HE_PROTOCOL; // !?! HC_METHOD_NOT_SUPPORTED?
}
path.assign(line + dstart, line + dend);
@ -617,8 +574,6 @@ HttpError HttpRequestData::parseLeader(const char* line, size_t len) {
}
bool HttpRequestData::getAbsoluteUri(std::string* uri) const {
if (HV_CONNECT == verb)
return false;
Url<char> url(path);
if (url.valid()) {
uri->assign(path);
@ -635,8 +590,6 @@ bool HttpRequestData::getAbsoluteUri(std::string* uri) const {
bool HttpRequestData::getRelativeUri(std::string* host,
std::string* path) const {
if (HV_CONNECT == verb)
return false;
Url<char> url(this->path);
if (url.valid()) {
host->assign(url.address());
@ -659,34 +612,12 @@ void HttpResponseData::clear(bool release_document) {
HttpData::clear(release_document);
}
void HttpResponseData::copy(const HttpResponseData& src) {
scode = src.scode;
message = src.message;
HttpData::copy(src);
}
void HttpResponseData::set_success(uint32_t scode) {
this->scode = scode;
message.clear();
setHeader(HH_CONTENT_LENGTH, "0", false);
}
void HttpResponseData::set_success(const std::string& content_type,
StreamInterface* document,
uint32_t scode) {
this->scode = scode;
message.erase(message.begin(), message.end());
setContent(content_type, document);
}
void HttpResponseData::set_redirect(const std::string& location,
uint32_t scode) {
this->scode = scode;
message.clear();
setHeader(HH_LOCATION, location);
setHeader(HH_CONTENT_LENGTH, "0", false);
}
void HttpResponseData::set_error(uint32_t scode) {
this->scode = scode;
message.clear();

View File

@ -31,41 +31,11 @@ class SocketAddress;
enum HttpCode {
HC_OK = 200,
HC_NON_AUTHORITATIVE = 203,
HC_NO_CONTENT = 204,
HC_PARTIAL_CONTENT = 206,
HC_MULTIPLE_CHOICES = 300,
HC_MOVED_PERMANENTLY = 301,
HC_FOUND = 302,
HC_SEE_OTHER = 303,
HC_NOT_MODIFIED = 304,
HC_MOVED_TEMPORARILY = 307,
HC_BAD_REQUEST = 400,
HC_UNAUTHORIZED = 401,
HC_FORBIDDEN = 403,
HC_NOT_FOUND = 404,
HC_PROXY_AUTHENTICATION_REQUIRED = 407,
HC_GONE = 410,
HC_INTERNAL_SERVER_ERROR = 500,
HC_NOT_IMPLEMENTED = 501,
HC_SERVICE_UNAVAILABLE = 503,
};
enum HttpVersion { HVER_1_0, HVER_1_1, HVER_UNKNOWN, HVER_LAST = HVER_UNKNOWN };
enum HttpVerb {
HV_GET,
HV_POST,
HV_PUT,
HV_DELETE,
HV_CONNECT,
HV_HEAD,
HV_LAST = HV_HEAD
};
enum HttpError {
HE_NONE,
HE_PROTOCOL, // Received non-valid HTTP data
@ -121,37 +91,12 @@ const uint16_t HTTP_SECURE_PORT = 443;
// Utility Functions
//////////////////////////////////////////////////////////////////////
inline HttpError mkerr(HttpError err, HttpError def_err = HE_DEFAULT) {
return (err != HE_NONE) ? err : def_err;
}
const char* ToString(HttpVersion version);
bool FromString(HttpVersion& version, const std::string& str);
const char* ToString(HttpVerb verb);
bool FromString(HttpVerb& verb, const std::string& str);
const char* ToString(HttpHeader header);
bool FromString(HttpHeader& header, const std::string& str);
inline bool HttpCodeIsInformational(uint32_t code) {
return ((code / 100) == 1);
}
inline bool HttpCodeIsSuccessful(uint32_t code) {
return ((code / 100) == 2);
}
inline bool HttpCodeIsRedirection(uint32_t code) {
return ((code / 100) == 3);
}
inline bool HttpCodeIsClientError(uint32_t code) {
return ((code / 100) == 4);
}
inline bool HttpCodeIsServerError(uint32_t code) {
return ((code / 100) == 5);
}
bool HttpCodeHasBody(uint32_t code);
bool HttpCodeIsCacheable(uint32_t code);
bool HttpHeaderIsEndToEnd(HttpHeader header);
bool HttpHeaderIsCollapsible(HttpHeader header);
@ -382,20 +327,17 @@ struct HttpData {
protected:
virtual ~HttpData();
void clear(bool release_document);
void copy(const HttpData& src);
private:
HeaderMap headers_;
};
struct HttpRequestData : public HttpData {
HttpVerb verb;
std::string path;
HttpRequestData() : verb(HV_GET) {}
HttpRequestData() {}
void clear(bool release_document);
void copy(const HttpRequestData& src);
size_t formatLeader(char* buffer, size_t size) const override;
HttpError parseLeader(const char* line, size_t len) override;
@ -410,15 +352,9 @@ struct HttpResponseData : public HttpData {
HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) {}
void clear(bool release_document);
void copy(const HttpResponseData& src);
// Convenience methods
void set_success(uint32_t scode = HC_OK);
void set_success(const std::string& content_type,
StreamInterface* document,
uint32_t scode = HC_OK);
void set_redirect(const std::string& location,
uint32_t scode = HC_MOVED_TEMPORARILY);
void set_error(uint32_t scode);
size_t formatLeader(char* buffer, size_t size) const override;

View File

@ -552,22 +552,6 @@ StreamResult MemoryStream::DoReserve(size_t size, int* error) {
return SR_ERROR;
}
///////////////////////////////////////////////////////////////////////////////
ExternalMemoryStream::ExternalMemoryStream() {}
ExternalMemoryStream::ExternalMemoryStream(void* data, size_t length) {
SetData(data, length);
}
ExternalMemoryStream::~ExternalMemoryStream() {}
void ExternalMemoryStream::SetData(void* data, size_t length) {
data_length_ = buffer_length_ = length;
buffer_ = static_cast<char*>(data);
seek_position_ = 0;
}
///////////////////////////////////////////////////////////////////////////////
// FifoBuffer
///////////////////////////////////////////////////////////////////////////////

View File

@ -421,18 +421,6 @@ class MemoryStream : public MemoryStreamBase {
StreamResult DoReserve(size_t size, int* error) override;
};
// ExternalMemoryStream adapts an external memory buffer, so writes which would
// extend past the end of the buffer will return end-of-stream.
class ExternalMemoryStream : public MemoryStreamBase {
public:
ExternalMemoryStream();
ExternalMemoryStream(void* data, size_t length);
~ExternalMemoryStream() override;
void SetData(void* data, size_t length);
};
// FifoBuffer allows for efficient, thread-safe buffering of data between
// writer and reader. As the data can wrap around the end of the buffer,
// MemoryStreamBase can't help us here.