| Index: net/http/http_transaction_test_util.cc
|
| diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc
|
| index 556033a0580d4a5a9b77875fb3ee2a3e3d441fa3..8b31842b00fb2972d7adc91ab104589c9fa619b7 100644
|
| --- a/net/http/http_transaction_test_util.cc
|
| +++ b/net/http/http_transaction_test_util.cc
|
| @@ -148,6 +148,13 @@ MockHttpRequest::MockHttpRequest(const MockTransaction& t) {
|
| load_flags = t.load_flags;
|
| }
|
|
|
| +Context::Context() : result(ERR_IO_PENDING) {}
|
| +Context::~Context() {
|
| + if (trans.get()) {
|
| + trans->Orphan(std::move(trans));
|
| + }
|
| +}
|
| +
|
| //-----------------------------------------------------------------------------
|
|
|
| // static
|
| @@ -163,6 +170,7 @@ TestTransactionConsumer::TestTransactionConsumer(
|
| }
|
|
|
| TestTransactionConsumer::~TestTransactionConsumer() {
|
| + trans_->Orphan(std::move(trans_));
|
| }
|
|
|
| void TestTransactionConsumer::Start(const HttpRequestInfo* request,
|
| @@ -250,6 +258,10 @@ int MockNetworkTransaction::Start(const HttpRequestInfo* request,
|
| return StartInternal(request, callback, net_log);
|
| }
|
|
|
| +void MockNetworkTransaction::Orphan(std::unique_ptr<HttpTransaction> trans) {
|
| + trans.reset();
|
| +}
|
| +
|
| int MockNetworkTransaction::RestartIgnoringLastError(
|
| const CompletionCallback& callback) {
|
| return ERR_FAILED;
|
| @@ -487,7 +499,7 @@ int MockNetworkTransaction::ResumeNetworkStart() {
|
|
|
| void MockNetworkTransaction::GetConnectionAttempts(
|
| ConnectionAttempts* out) const {
|
| - NOTIMPLEMENTED();
|
| + return;
|
| }
|
|
|
| void MockNetworkTransaction::CallbackLater(const CompletionCallback& callback,
|
| @@ -581,4 +593,242 @@ int ReadTransaction(HttpTransaction* trans, std::string* result) {
|
| return OK;
|
| }
|
|
|
| +// The 1st transaction reads from the network and the subsequent transactions
|
| +// are able to read from the cache even before the complete response is written
|
| +// to the cache.
|
| +int ReadSharedWritersCacheRead(std::vector<Context*>& context_list,
|
| + std::vector<std::string>& results) {
|
| + int rv;
|
| +
|
| + size_t i = 0;
|
| + HttpTransaction* trans = nullptr;
|
| + do {
|
| + Context* c = context_list.at(i);
|
| + trans = c->trans.get();
|
| + scoped_refptr<IOBuffer> buf(new IOBuffer(256));
|
| + rv = trans->Read(buf.get(), 256, c->callback.callback());
|
| + if (rv == ERR_IO_PENDING)
|
| + rv = c->callback.WaitForResult();
|
| +
|
| + if (rv > 0)
|
| + results.at(i).append(buf->data(), rv);
|
| + else if (rv < 0)
|
| + return rv;
|
| +
|
| + i = (i == context_list.size() - 1) ? 0 : i + 1;
|
| + } while (rv > 0);
|
| +
|
| + return OK;
|
| +}
|
| +
|
| +// The 1st transaction reads from the network and read is invoked on other
|
| +// transactions even before the 1st one's io callback is invoked. The other
|
| +// transactions should have data written in their read buffers as part
|
| +// of the 1st transaction's callback.
|
| +int ReadSharedWritersJoinedRead(std::vector<Context*>& context_list,
|
| + std::vector<std::string>& results) {
|
| + int rv = 0;
|
| + do {
|
| + // Invoke Read for all transactions.
|
| + std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
|
| + for (size_t i = 0; i < context_list.size(); i++) {
|
| + HttpTransaction* trans = context_list[i]->trans.get();
|
| + buffers[i] = new IOBuffer(30);
|
| + rv = trans->Read(buffers[i].get(), 30,
|
| + context_list[i]->callback.callback());
|
| + // Invoking stop caching here should not have any impact since there are
|
| + // multiple transactions waiting for this resource.
|
| + if (i == 0)
|
| + trans->StopCaching();
|
| + }
|
| + if (rv == ERR_IO_PENDING) {
|
| + Context* ct = *(context_list.begin());
|
| + rv = ct->callback.WaitForResult();
|
| + }
|
| +
|
| + if (rv > 0) {
|
| + for (size_t i = 0; i < results.size(); i++) {
|
| + results[i].append(buffers[i]->data(), rv);
|
| + }
|
| + } else if (rv < 0)
|
| + return rv;
|
| +
|
| + } while (rv > 0);
|
| +
|
| + return OK;
|
| +}
|
| +
|
| +int ReadSharedWritersJoinedReadDoneReading(std::vector<Context*>& context_list,
|
| + std::vector<std::string>& results) {
|
| + int rv = 0;
|
| + int cnt = 0;
|
| + do {
|
| + // Invoke Read for all transactions.
|
| + std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
|
| + for (size_t i = 0; i < context_list.size(); i++) {
|
| + HttpTransaction* trans = context_list[i]->trans.get();
|
| + buffers[i] = new IOBuffer(30);
|
| + rv = trans->Read(buffers[i].get(), 30,
|
| + context_list[i]->callback.callback());
|
| + }
|
| + if (rv == ERR_IO_PENDING) {
|
| + Context* ct = *(context_list.begin());
|
| + rv = ct->callback.WaitForResult();
|
| + }
|
| +
|
| + if (rv > 0) {
|
| + for (size_t i = 0; i < results.size(); i++) {
|
| + results[i].append(buffers[i]->data(), rv);
|
| + }
|
| + } else if (rv < 0)
|
| + return rv;
|
| +
|
| + cnt++;
|
| + if (cnt == 2) {
|
| + context_list[0]->trans.get()->DoneReading();
|
| + }
|
| + } while (cnt < 2);
|
| +
|
| + return OK;
|
| +}
|
| +
|
| +// The 1st transaction reads from the network and read is invoked on other
|
| +// transactions even before the 1st one's io callback is invoked. Also, the
|
| +// first transaction is deleted before the io callback is invoked. The other
|
| +// transactions should have data written in their read buffers as part
|
| +// of the 1st transaction's callback.
|
| +int ReadSharedWritersJoinedReadDoomCurrentWriter(
|
| + std::vector<Context*>& context_list,
|
| + std::vector<std::string>& results) {
|
| + int rv = 0;
|
| + bool first_iter = true;
|
| + do {
|
| + // Invoke Read for all transactions.
|
| + std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
|
| + for (size_t i = 0; i < context_list.size(); i++) {
|
| + HttpTransaction* trans = context_list[i]->trans.get();
|
| + buffers[i] = new IOBuffer(30);
|
| + rv = trans->Read(buffers[i].get(), 30,
|
| + context_list[i]->callback.callback());
|
| + }
|
| +
|
| + // Delete the 1st transaction.
|
| + if (first_iter) {
|
| + Context* c = context_list[0];
|
| + context_list.erase(context_list.begin());
|
| + delete c;
|
| + buffers.erase(buffers.begin());
|
| + }
|
| +
|
| + if (rv == ERR_IO_PENDING) {
|
| + Context* ct = *(context_list.begin());
|
| + rv = ct->callback.WaitForResult();
|
| + }
|
| +
|
| + if (rv > 0) {
|
| + for (size_t i = 0; i < context_list.size(); i++) {
|
| + results[i].append(buffers[i]->data(), rv);
|
| + }
|
| + } else if (rv < 0)
|
| + return rv;
|
| +
|
| + first_iter = false;
|
| + } while (rv > 0);
|
| +
|
| + return OK;
|
| +}
|
| +
|
| +int ReadSharedWritersJoinedReadDeleteWaitingWriter(
|
| + std::vector<Context*>& context_list,
|
| + std::vector<std::string>& results) {
|
| + int rv = 0;
|
| + bool first_iter = true;
|
| + do {
|
| + // Invoke Read for all transactions.
|
| + std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
|
| + for (size_t i = 0; i < context_list.size(); i++) {
|
| + HttpTransaction* trans = context_list[i]->trans.get();
|
| + buffers[i] = new IOBuffer(30);
|
| + rv = trans->Read(buffers[i].get(), 30,
|
| + context_list[i]->callback.callback());
|
| + }
|
| +
|
| + // Remove a waiting writer transaction.
|
| + if (first_iter) {
|
| + auto it = context_list.begin();
|
| + it++;
|
| + if (it != context_list.end()) {
|
| + Context* c = *it;
|
| + context_list.erase(it);
|
| + delete c;
|
| + auto it1 = buffers.begin();
|
| + it1++;
|
| + buffers.erase(it1);
|
| + }
|
| + }
|
| +
|
| + if (rv == ERR_IO_PENDING) {
|
| + Context* ct = *(context_list.begin());
|
| + rv = ct->callback.WaitForResult();
|
| + }
|
| +
|
| + if (rv > 0) {
|
| + for (size_t i = 0; i < context_list.size(); i++) {
|
| + results[i].append(buffers[i]->data(), rv);
|
| + }
|
| + } else if (rv < 0)
|
| + return rv;
|
| +
|
| + first_iter = false;
|
| + } while (rv > 0);
|
| +
|
| + return OK;
|
| +}
|
| +
|
| +int ReadSharedWritersJoinedReadDeleteIdleWriter(
|
| + std::vector<Context*>& context_list,
|
| + std::vector<std::string>& results) {
|
| + int rv = 0;
|
| + bool first_iter = true;
|
| + do {
|
| + // Invoke Read for all transactions.
|
| + std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
|
| + for (size_t i = 0; i < context_list.size(); i++) {
|
| + HttpTransaction* trans = context_list[i]->trans.get();
|
| + buffers[i] = new IOBuffer(30);
|
| + // Do not invoke Read on the first transaction.
|
| + if (first_iter && i == 0)
|
| + continue;
|
| + rv = trans->Read(buffers[i].get(), 30,
|
| + context_list[i]->callback.callback());
|
| + }
|
| +
|
| + // Remove the idle writer transaction.
|
| + if (first_iter) {
|
| + auto it = context_list.begin();
|
| + Context* c = *it;
|
| + context_list.erase(it);
|
| + delete c;
|
| + auto it1 = buffers.begin();
|
| + buffers.erase(it1);
|
| + }
|
| +
|
| + if (rv == ERR_IO_PENDING) {
|
| + Context* ct = *(context_list.begin());
|
| + rv = ct->callback.WaitForResult();
|
| + }
|
| +
|
| + if (rv > 0) {
|
| + for (size_t i = 0; i < context_list.size(); i++) {
|
| + results[i].append(buffers[i]->data(), rv);
|
| + }
|
| + } else if (rv < 0)
|
| + return rv;
|
| +
|
| + first_iter = false;
|
| + } while (rv > 0);
|
| +
|
| + return OK;
|
| +}
|
| +
|
| } // namespace net
|
|
|