Add Cronet bidirectional example

This commit is contained in:
klzgrad 2022-05-02 17:09:36 +08:00
parent 7743b2c008
commit 1c54cb2c86
9 changed files with 179 additions and 201 deletions

View File

@ -134,6 +134,7 @@ jobs:
- run: ccache -s - run: ccache -s
- run: ../tests/basic.sh out/Release/naive - run: ../tests/basic.sh out/Release/naive
- run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }} - run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }}
- run: cp out/Release/libcronet.* components/cronet/native/generated/cronet.idl_c.h components/cronet/native/include/*.h components/grpc_support/include/*.h components/cronet/native/sample/bidi_example.cc ${{ env.BUNDLE }}
- run: tar cJf ../${{ env.BUNDLE }}.tar.xz ${{ env.BUNDLE }} - run: tar cJf ../${{ env.BUNDLE }}.tar.xz ${{ env.BUNDLE }}
- uses: actions/upload-release-asset@v1 - uses: actions/upload-release-asset@v1
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}
@ -204,6 +205,7 @@ jobs:
# qemu-user segfaults with x64 or x86 android builds here. # qemu-user segfaults with x64 or x86 android builds here.
if: ${{ matrix.arch != 'x64' && matrix.arch != 'x86' }} if: ${{ matrix.arch != 'x64' && matrix.arch != 'x86' }}
- run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }} - run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }}
- run: cp out/Release/libcronet.* components/cronet/native/generated/cronet.idl_c.h components/cronet/native/include/*.h components/grpc_support/include/*.h components/cronet/native/sample/bidi_example.cc ${{ env.BUNDLE }}
- run: tar cJf ../${{ env.BUNDLE }}.tar.xz ${{ env.BUNDLE }} - run: tar cJf ../${{ env.BUNDLE }}.tar.xz ${{ env.BUNDLE }}
- uses: actions/upload-release-asset@v1 - uses: actions/upload-release-asset@v1
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}
@ -269,6 +271,7 @@ jobs:
# No real or emulated environment is available to test this. # No real or emulated environment is available to test this.
if: ${{ matrix.arch != 'arm64' }} if: ${{ matrix.arch != 'arm64' }}
- run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive.exe config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }} - run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive.exe config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }}
- run: cp out/Release/libcronet.* components/cronet/native/generated/cronet.idl_c.h components/cronet/native/include/*.h components/grpc_support/include/*.h components/cronet/native/sample/bidi_example.cc ${{ env.BUNDLE }}
- run: 7z a ../${{ env.BUNDLE }}.zip ${{ env.BUNDLE }} - run: 7z a ../${{ env.BUNDLE }}.zip ${{ env.BUNDLE }}
- uses: actions/upload-release-asset@v1 - uses: actions/upload-release-asset@v1
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}
@ -323,6 +326,7 @@ jobs:
# No real or emulated environment is available to test this. # No real or emulated environment is available to test this.
if: ${{ matrix.arch != 'arm64' }} if: ${{ matrix.arch != 'arm64' }}
- run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }} - run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }}
- run: cp out/Release/libcronet.* components/cronet/native/generated/cronet.idl_c.h components/cronet/native/include/*.h components/grpc_support/include/*.h components/cronet/native/sample/bidi_example.cc ${{ env.BUNDLE }}
- run: tar cJf ../${{ env.BUNDLE }}.tar.xz ${{ env.BUNDLE }} - run: tar cJf ../${{ env.BUNDLE }}.tar.xz ${{ env.BUNDLE }}
- uses: actions/upload-release-asset@v1 - uses: actions/upload-release-asset@v1
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}
@ -476,6 +480,7 @@ jobs:
- run: ccache -s - run: ccache -s
- run: ../tests/basic.sh out/Release/naive - run: ../tests/basic.sh out/Release/naive
- run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }} - run: mkdir ${{ env.BUNDLE }} && cp out/Release/naive config.json ../LICENSE ../USAGE.txt ${{ env.BUNDLE }}
- run: cp out/Release/libcronet.* components/cronet/native/generated/cronet.idl_c.h components/cronet/native/include/*.h components/grpc_support/include/*.h components/cronet/native/sample/bidi_example.cc ${{ env.BUNDLE }}
- run: tar cJf ../${{ env.BUNDLE }}.tar.xz ${{ env.BUNDLE }} - run: tar cJf ../${{ env.BUNDLE }}.tar.xz ${{ env.BUNDLE }}
- uses: actions/upload-release-asset@v1 - uses: actions/upload-release-asset@v1
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}

View File

@ -53,6 +53,7 @@ group("gn_all") {
deps = [ deps = [
":gn_visibility", ":gn_visibility",
"//net", "//net",
"//components/cronet",
] ]
} }

View File

@ -13,6 +13,7 @@ if [ "$1" = debug ]; then
else else
out=out/Release out=out/Release
flags=" flags="
use_thin_lto=false is_cfi=false
is_official_build=true is_official_build=true
exclude_unwind_tables=true exclude_unwind_tables=true
enable_resource_allowlist_generation=false enable_resource_allowlist_generation=false
@ -68,4 +69,4 @@ export DEPOT_TOOLS_WIN_TOOLCHAIN=0
./gn/out/gn gen "$out" --args="$flags $EXTRA_FLAGS" --script-executable=$PYTHON ./gn/out/gn gen "$out" --args="$flags $EXTRA_FLAGS" --script-executable=$PYTHON
ninja -C "$out" naive ninja -C "$out" naive cronet

View File

@ -9,11 +9,10 @@ import("//build/util/process_version.gni")
import("//build/util/version.gni") import("//build/util/version.gni")
import("//components/cronet/native/include/headers.gni") import("//components/cronet/native/include/headers.gni")
import("//components/grpc_support/include/headers.gni") import("//components/grpc_support/include/headers.gni")
import("//testing/test.gni")
declare_args() { declare_args() {
# If set to true, this will remove histogram manager to reduce binary size. # If set to true, this will remove histogram manager to reduce binary size.
disable_histogram_support = is_mac || is_win disable_histogram_support = true
} }
# Disable histogram support is not allowed on Android. # Disable histogram support is not allowed on Android.
@ -59,7 +58,6 @@ source_set("cronet_common") {
"//base", "//base",
"//components/prefs:prefs", "//components/prefs:prefs",
"//net", "//net",
"//third_party/metrics_proto",
] ]
if (!disable_histogram_support) { if (!disable_histogram_support) {
@ -75,23 +73,6 @@ source_set("metrics_util") {
deps = [ "//base" ] deps = [ "//base" ]
} }
# Unit tests for Cronet common implementation.
source_set("cronet_common_unittests") {
testonly = true
deps = [
":cronet_common",
"//components/prefs:test_support",
"//net:test_support",
]
sources = [
"host_cache_persistence_manager_unittest.cc",
"stale_host_resolver_unittest.cc",
"url_request_context_config_unittest.cc",
]
}
# For platforms on which the native Cronet library is used, build the library, # For platforms on which the native Cronet library is used, build the library,
# a cronet_tests binary that exercises it, and a unit-tests binary. # a cronet_tests binary that exercises it, and a unit-tests binary.
# Android and iOS have their own platform-specific rules to build Cronet. # Android and iOS have their own platform-specific rules to build Cronet.
@ -138,50 +119,6 @@ if (is_android) {
} }
} }
test("cronet_tests") {
deps = [
":cronet_common",
"//base",
"//base/test:test_support",
"//components/cronet/native:cronet_native_impl",
"//components/cronet/native/test:cronet_native_tests",
"//net",
]
sources = [
"cronet_global_state_stubs.cc",
"run_all_unittests.cc",
]
defines = [ "CRONET_TESTS_IMPLEMENTATION" ]
if ((is_linux || is_chromeos) && !is_component_build) {
public_configs = [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
}
if (is_fuchsia) {
use_cfv2 = false
additional_manifest_fragments =
[ "//build/config/fuchsia/test/network_capabilities.test-cmx" ]
}
}
test("cronet_unittests") {
deps = [
":cronet_common",
":cronet_common_unittests",
"//base",
"//base/test:test_support",
"//components/cronet/native:cronet_native_unittests",
"//net",
]
sources = [
"cronet_global_state_stubs.cc",
"run_all_unittests.cc",
]
}
_package_dir = "$root_out_dir/cronet" _package_dir = "$root_out_dir/cronet"
# Generate LICENSE file by recursively joining all dependent licenses. # Generate LICENSE file by recursively joining all dependent licenses.
@ -227,30 +164,10 @@ if (is_android) {
] ]
} }
executable("cronet_native_perf_test") {
testonly = true
sources = [
"native/perftest/main.cc",
"native/perftest/perf_test.cc",
]
deps = [
"//base",
"//components/cronet",
"//components/cronet/native:cronet_native_headers",
"//components/cronet/native/test:cronet_native_tests",
"//components/cronet/native/test:cronet_native_testutil",
"//net:test_support",
]
}
executable("cronet_sample") { executable("cronet_sample") {
testonly = true testonly = true
sources = [ sources = [
"native/sample/main.cc", "native/sample/main.cc",
"native/sample/sample_executor.cc",
"native/sample/sample_executor.h",
"native/sample/sample_url_request_callback.cc",
"native/sample/sample_url_request_callback.h",
] ]
deps = [ deps = [
"//components/cronet", "//components/cronet",
@ -260,12 +177,4 @@ if (is_android) {
public_configs = [ "//build/config/gcc:rpath_for_built_shared_libraries" ] public_configs = [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
} }
} }
test("cronet_sample_test") {
sources = [ "native/sample/test/sample_test.cc" ]
deps = [
":cronet_sample",
"//testing/gtest:gtest",
]
}
} }

View File

@ -4,7 +4,6 @@
import("//components/cronet/native/include/headers.gni") import("//components/cronet/native/include/headers.gni")
import("//components/grpc_support/include/headers.gni") import("//components/grpc_support/include/headers.gni")
import("//testing/test.gni")
config("cronet_native_include_config") { config("cronet_native_include_config") {
include_dirs = [ include_dirs = [
@ -71,28 +70,3 @@ source_set("cronet_native_impl") {
] ]
} }
# Unit tests for Cronet native API. Depends on cronet_native_impl to test
# implementation details.
source_set("cronet_native_unittests") {
testonly = true
deps = [
":cronet_native_impl",
"//base/test:test_support",
"//components/cronet/native/test:cronet_native_testutil",
"//net:test_support",
"//testing/gtest",
]
configs += [ ":cronet_native_include_config" ]
sources = [
"engine_unittest.cc",
"native_metrics_util_test.cc",
"runnables_unittest.cc",
# Generated from cronet.idl.
"generated/cronet.idl_impl_interface_unittest.cc",
"generated/cronet.idl_impl_struct_unittest.cc",
]
}

View File

@ -0,0 +1,165 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ninja -C out/Release cronet
// g++ components/cronet/native/sample/bidi_example.cc -I
// components/cronet/native/generated -I components/cronet/native/include -I
// components/grpc_support/include/ out/Release/libcronet.100.0.4896.60.so
// LD_LIBRARY_PATH=out/Release ./a.out
#include <atomic>
#include <iostream>
#include <string>
#include <thread>
#include "bidirectional_stream_c.h"
#include "cronet_c.h"
class BidirectionalStreamCallback {
public:
bidirectional_stream* stream = nullptr;
std::string write_data;
std::string read_buffer;
std::atomic<bool> done = false;
bidirectional_stream_callback* callback() const { return &s_callback; }
private:
static BidirectionalStreamCallback* FromStream(bidirectional_stream* stream) {
return reinterpret_cast<BidirectionalStreamCallback*>(stream->annotation);
}
// C callbacks.
static void on_stream_ready_callback(bidirectional_stream* stream) {
std::cout << "on_stream_ready_callback" << std::endl;
BidirectionalStreamCallback* self = FromStream(stream);
bidirectional_stream_write(stream, self->write_data.data(),
self->write_data.size(), true);
bidirectional_stream_flush(stream);
}
static void on_response_headers_received_callback(
bidirectional_stream* stream,
const bidirectional_stream_header_array* headers,
const char* negotiated_protocol) {
std::cout << "on_response_headers_received_callback negotiated_protocol="
<< negotiated_protocol << "\n";
BidirectionalStreamCallback* self = FromStream(stream);
for (size_t i = 0; i < headers->count; ++i) {
if (headers->headers[i].key[0] == '\0')
continue;
std::cout << headers->headers[i].key << ": " << headers->headers[i].value
<< std::endl;
}
self->read_buffer.resize(32768);
bidirectional_stream_read(stream, self->read_buffer.data(),
self->read_buffer.size());
}
static void on_read_completed_callback(bidirectional_stream* stream,
char* data,
int count) {
std::cout << "on_read_completed_callback " << count << "\n";
BidirectionalStreamCallback* self = FromStream(stream);
if (count == 0)
return;
std::cout.write(data, count);
std::cout << "\n";
bidirectional_stream_read(stream, self->read_buffer.data(),
self->read_buffer.size());
}
static void on_write_completed_callback(bidirectional_stream* stream,
const char* data) {
std::cout << "on_write_completed_callback\n";
}
static void on_response_trailers_received_callback(
bidirectional_stream* stream,
const bidirectional_stream_header_array* trailers) {
std::cout << "on_response_trailers_received_callback\n";
for (size_t i = 0; i < trailers->count; ++i) {
std::cout << trailers->headers[i].key << ": "
<< trailers->headers[i].value << std::endl;
}
}
static void on_succeded_callback(bidirectional_stream* stream) {
std::cout << "on_succeded_callback\n";
BidirectionalStreamCallback* self = FromStream(stream);
self->done = true;
}
static void on_failed_callback(bidirectional_stream* stream, int net_error) {
std::cout << "on_failed_callback " << net_error << "\n";
BidirectionalStreamCallback* self = FromStream(stream);
self->done = true;
}
static void on_canceled_callback(bidirectional_stream* stream) {
std::cout << "on_canceled_callback\n";
BidirectionalStreamCallback* self = FromStream(stream);
self->done = true;
}
static bidirectional_stream_callback s_callback;
};
bidirectional_stream_callback BidirectionalStreamCallback::s_callback = {
on_stream_ready_callback,
on_response_headers_received_callback,
on_read_completed_callback,
on_write_completed_callback,
on_response_trailers_received_callback,
on_succeded_callback,
on_failed_callback,
on_canceled_callback,
};
Cronet_EnginePtr CreateCronetEngine() {
Cronet_EnginePtr cronet_engine = Cronet_Engine_Create();
Cronet_EngineParamsPtr engine_params = Cronet_EngineParams_Create();
Cronet_EngineParams_user_agent_set(engine_params, "CronetSample/1");
Cronet_EngineParams_experimental_options_set(engine_params, R"(
{"ssl_key_log_file": "/tmp/keys"}
)");
Cronet_Engine_StartWithParams(cronet_engine, engine_params);
Cronet_EngineParams_Destroy(engine_params);
return cronet_engine;
}
int main(int argc, const char* argv[]) {
if (argc != 3) {
std::cout << "Usage: " << argv[0]
<< " https://my-caddy-forwardproxy.com \"Basic $(printf "
"user:pass | base64)\"\n";
return 1;
}
const char* proxy_server = argv[1];
const char* password_base64 = argv[2];
Cronet_EnginePtr cronet_engine = CreateCronetEngine();
stream_engine* cronet_stream_engine =
Cronet_Engine_GetStreamEngine(cronet_engine);
BidirectionalStreamCallback stream_callback;
stream_callback.write_data = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
stream_callback.stream = bidirectional_stream_create(
cronet_stream_engine, &stream_callback, stream_callback.callback());
bidirectional_stream_header headers[2] = {
{"proxy-authorization", password_base64},
{"real-authority", "example.com:80"},
};
bidirectional_stream_header_array header_array = {2, 2, headers};
bidirectional_stream_start(stream_callback.stream, proxy_server, 0, "CONNECT",
&header_array, false);
std::cout << "bidirectional_stream_start" << std::endl;
while (!stream_callback.done) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
bidirectional_stream_destroy(stream_callback.stream);
Cronet_Engine_Shutdown(cronet_engine);
Cronet_Engine_Destroy(cronet_engine);
return 0;
}

View File

@ -18,32 +18,3 @@ source_set("grpc_support") {
] ]
} }
# Depends on ":grpc_support" implementation.
source_set("bidirectional_stream_unittest") {
testonly = true
sources = [ "bidirectional_stream_unittest.cc" ]
deps = [
":grpc_support",
"//base",
"//net",
"//net:test_support",
]
public_deps = [ "//components/grpc_support/test:get_stream_engine_header" ]
}
# Depends on ":headers" to avoid ":grpc_support" implementation.
source_set("bidirectional_stream_test") {
testonly = true
sources = [ "bidirectional_stream_unittest.cc" ]
deps = [
":headers",
"//base",
"//net",
"//net:test_support",
]
public_deps = [ "//components/grpc_support/test:get_stream_engine_header" ]
}

View File

@ -66,55 +66,3 @@ component("prefs") {
deps += [ "android:jni_headers" ] deps += [ "android:jni_headers" ]
} }
} }
static_library("test_support") {
testonly = true
sources = [
"mock_pref_change_callback.cc",
"mock_pref_change_callback.h",
"pref_store_observer_mock.cc",
"pref_store_observer_mock.h",
"pref_test_utils.cc",
"pref_test_utils.h",
"testing_pref_service.cc",
"testing_pref_service.h",
"testing_pref_store.cc",
"testing_pref_store.h",
]
public_deps = [ ":prefs" ]
deps = [
"//base",
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
]
}
source_set("unit_tests") {
testonly = true
sources = [
"default_pref_store_unittest.cc",
"in_memory_pref_store_unittest.cc",
"json_pref_store_unittest.cc",
"overlay_user_pref_store_unittest.cc",
"persistent_pref_store_unittest.cc",
"persistent_pref_store_unittest.h",
"pref_change_registrar_unittest.cc",
"pref_member_unittest.cc",
"pref_notifier_impl_unittest.cc",
"pref_service_unittest.cc",
"pref_value_map_unittest.cc",
"pref_value_store_unittest.cc",
"scoped_user_pref_update_unittest.cc",
"segregated_pref_store_unittest.cc",
]
deps = [
":test_support",
"//base",
"//base/test:test_support",
"//testing/gmock",
"//testing/gtest",
]
}

View File

@ -107,6 +107,10 @@ void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info,
HttpRequestHeaders::Iterator it(request_headers); HttpRequestHeaders::Iterator it(request_headers);
while (it.GetNext()) { while (it.GetNext()) {
std::string name = base::ToLowerASCII(it.name()); std::string name = base::ToLowerASCII(it.name());
if (info.method == "CONNECT" && name == "_real_authority") {
(*headers)[spdy::kHttp2AuthorityHeader] = it.value();
continue;
}
if (name.empty() || name[0] == ':' || name == "connection" || if (name.empty() || name[0] == ':' || name == "connection" ||
name == "proxy-connection" || name == "transfer-encoding" || name == "proxy-connection" || name == "transfer-encoding" ||
name == "host") { name == "host") {