--- /dev/null
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <cstdlib>
+#include <string>
+
+#include "include/base/cef_bind.h"
+#include "include/cef_stream.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kTestUrl[] = "http://tests-srh/test.html";
+const size_t kReadBlockSize = 1024U; // 1k.
+
+// The usual network buffer size is about 32k. Choose a value that's larger.
+const size_t kReadDesiredSize = 100U * 1024U; // 100k
+
+class ReadHandler : public CefReadHandler {
+ public:
+ explicit ReadHandler(bool may_block)
+ : may_block_(may_block),
+ offset_(0),
+ expected_result_(0) {
+ }
+
+ void CreateContent() {
+ // To verify that the data transers successfully we're going to make a big
+ // math problem.
+ content_.reserve(kReadDesiredSize + 50U);
+ content_ = "<html><body><script>var myratherlongvariablename=0;";
+
+ while (content_.size() < kReadDesiredSize) {
+ content_ += "myratherlongvariablename=myratherlongvariablename+1;";
+ expected_result_++;
+ }
+
+ content_ += "window.testQuery({request:myratherlongvariablename+''});"
+ "</script></body></html>";
+ }
+
+ int GetExpectedResult() const {
+ return expected_result_;
+ }
+
+ size_t Read(void* ptr, size_t size, size_t n) override {
+ EXPECT_EQ(1U, size);
+
+ // Read the minimum of requested size, remaining size or kReadBlockSize.
+ const size_t read_bytes =
+ std::min(std::min(size * n, content_.size() - offset_), kReadBlockSize);
+ if (read_bytes > 0) {
+ memcpy(ptr, content_.c_str() + offset_, read_bytes);
+ offset_ += read_bytes;
+ }
+
+ return read_bytes;
+ }
+
+ int Seek(int64 offset, int whence) override {
+ EXPECT_TRUE(false); // Not reached.
+ return 0;
+ }
+
+ int64 Tell() override {
+ EXPECT_TRUE(false); // Not reached.
+ return 0;
+ }
+
+ int Eof() override {
+ EXPECT_TRUE(false); // Not reached.
+ return 0;
+ }
+
+ bool MayBlock() override {
+ return may_block_;
+ }
+
+ private:
+ const bool may_block_;
+ std::string content_;
+ size_t offset_;
+ int expected_result_;
+
+ IMPLEMENT_REFCOUNTING(ReadHandler);
+};
+
+class ReadTestHandler : public RoutingTestHandler {
+ public:
+ explicit ReadTestHandler(bool may_block)
+ : may_block_(may_block),
+ expected_result_(0) {}
+
+ void RunTest() override {
+ // Create the browser.
+ CreateBrowser(kTestUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ got_resource_handler_.yes();
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(kTestUrl, url.c_str());
+
+ CefRefPtr<ReadHandler> handler = new ReadHandler(may_block_);
+ handler->CreateContent();
+ expected_result_ = handler->GetExpectedResult();
+
+ CefRefPtr<CefStreamReader> stream =
+ CefStreamReader::CreateForHandler(handler.get());
+ return new CefStreamResourceHandler("text/html", stream);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ got_on_query_.yes();
+
+ const int actual_result = atoi(request.ToString().c_str());
+ EXPECT_EQ(expected_result_, actual_result);
+
+ DestroyTestIfDone();
+
+ return true;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (!isLoading) {
+ got_on_loading_state_change_done_.yes();
+ DestroyTestIfDone();
+ }
+ }
+
+ private:
+ void DestroyTestIfDone() {
+ if (got_on_query_ && got_on_loading_state_change_done_)
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_resource_handler_);
+ EXPECT_TRUE(got_on_query_);
+ EXPECT_TRUE(got_on_loading_state_change_done_);
+ RoutingTestHandler::DestroyTest();
+ }
+
+ const bool may_block_;
+
+ int expected_result_;
+ TrackCallback got_resource_handler_;
+ TrackCallback got_on_query_;
+ TrackCallback got_on_loading_state_change_done_;
+
+ IMPLEMENT_REFCOUNTING(ReadTestHandler);
+};
+
+} // namespace
+
+TEST(StreamResourceHandlerTest, ReadWillBlock) {
+ CefRefPtr<ReadTestHandler> handler = new ReadTestHandler(true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(StreamResourceHandlerTest, ReadWontBlock) {
+ CefRefPtr<ReadTestHandler> handler = new ReadTestHandler(false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}