Chromium Code Reviews| Index: components/cronet/ios/cronet_c_for_grpc.cc |
| diff --git a/components/cronet/ios/cronet_c_for_grpc.cc b/components/cronet/ios/cronet_c_for_grpc.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ef09d1e6dbba09f07ee19eb04244e70ffba75da6 |
| --- /dev/null |
| +++ b/components/cronet/ios/cronet_c_for_grpc.cc |
| @@ -0,0 +1,268 @@ |
| +// Copyright 2016 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. |
| + |
| +#include "components/cronet/ios/cronet_c_for_grpc.h" |
| + |
| +#include <stdbool.h> |
| +#include <string> |
| +#include <vector> |
| + |
| +#include "base/bind.h" |
| +#include "base/location.h" |
| +#include "base/logging.h" |
| +#include "base/macros.h" |
| +#include "base/memory/ref_counted.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_split.h" |
| +#include "components/cronet/ios/cronet_bidirectional_stream.h" |
| +#include "components/cronet/ios/cronet_environment.h" |
| +#include "net/base/io_buffer.h" |
| +#include "net/base/net_errors.h" |
| +#include "net/base/request_priority.h" |
| +#include "net/http/bidirectional_stream.h" |
| +#include "net/http/bidirectional_stream_request_info.h" |
| +#include "net/http/http_network_session.h" |
| +#include "net/http/http_response_headers.h" |
| +#include "net/http/http_status_code.h" |
| +#include "net/http/http_transaction_factory.h" |
| +#include "net/http/http_util.h" |
| +#include "net/spdy/spdy_header_block.h" |
| +#include "net/ssl/ssl_info.h" |
| +#include "net/url_request/http_user_agent_settings.h" |
| +#include "net/url_request/url_request_context.h" |
| +#include "url/gurl.h" |
| + |
| +namespace { |
| + |
| +class HeadersArray : public cronet_bidirectional_stream_header_array { |
| + public: |
| + HeadersArray(const net::SpdyHeaderBlock& header_block); |
| + ~HeadersArray(); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(HeadersArray); |
| + base::StringPairs headers_strings_; |
| +}; |
| + |
| +HeadersArray::HeadersArray(const net::SpdyHeaderBlock& header_block) |
| + : headers_strings_(header_block.size()) { |
| + count = capacity = header_block.size(); |
| + headers = new cronet_bidirectional_stream_header[count]; |
| + size_t i = 0; |
| + // Copy headers into |headers_strings_| because string pieces are not |
| + // '\0'-terminated. |
| + for (const auto& it : header_block) { |
| + headers_strings_[i].first = it.first.as_string(); |
| + headers_strings_[i].second = it.second.as_string(); |
| + headers[i].key = headers_strings_[i].first.c_str(); |
| + headers[i].value = headers_strings_[i].second.c_str(); |
| + ++i; |
| + } |
| +} |
| + |
| +HeadersArray::~HeadersArray() { |
| + delete[] headers; |
| +} |
| + |
| +class CronetBidirectionalStreamAdapter |
| + : public cronet::CronetBidirectionalStream::Delegate { |
| + public: |
| + CronetBidirectionalStreamAdapter( |
| + cronet_engine* engine, |
| + cronet_bidirectional_stream* stream, |
| + cronet_bidirectional_stream_callback* callback); |
| + |
| + virtual ~CronetBidirectionalStreamAdapter(); |
| + |
| + void OnHeadersSent() override; |
| + |
| + void OnHeadersReceived(const net::SpdyHeaderBlock& headers_block, |
| + const char* negotiated_protocol) override; |
| + |
| + void OnDataRead(char* data, int size) override; |
| + |
| + void OnDataSent(const char* data) override; |
| + |
| + void OnTrailersReceived(const net::SpdyHeaderBlock& trailers_block) override; |
| + |
| + void OnSucceeded() override; |
| + |
| + void OnFailed(int error) override; |
| + |
| + void OnCanceled() override; |
| + |
| + static cronet::CronetBidirectionalStream* GetCronetStream( |
| + cronet_bidirectional_stream* stream); |
| + |
| + static void DestroyAdapterForStream(cronet_bidirectional_stream* stream); |
| + |
| + private: |
| + void DestroyOnNetworkThread(); |
| + |
| + // None of these objects are owned by |this|. |
| + cronet::CronetEnvironment* cronet_environment_; |
| + cronet::CronetBidirectionalStream* cronet_bidirectional_stream_; |
| + // C side |
| + cronet_bidirectional_stream* stream_; |
| + cronet_bidirectional_stream_callback* callback_; |
| +}; |
| + |
| +CronetBidirectionalStreamAdapter::CronetBidirectionalStreamAdapter( |
| + cronet_engine* engine, |
| + cronet_bidirectional_stream* stream, |
| + cronet_bidirectional_stream_callback* callback) |
| + : cronet_environment_( |
| + reinterpret_cast<cronet::CronetEnvironment*>(engine->obj)), |
| + stream_(stream), |
| + callback_(callback) { |
| + DCHECK(cronet_environment_); |
| + cronet_bidirectional_stream_ = |
| + new cronet::CronetBidirectionalStream(cronet_environment_, this); |
| +} |
| + |
| +CronetBidirectionalStreamAdapter::~CronetBidirectionalStreamAdapter() {} |
| + |
| +void CronetBidirectionalStreamAdapter::OnHeadersSent() { |
| + DCHECK(callback_->on_response_headers_received); |
| + callback_->on_request_headers_sent(stream_); |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::OnHeadersReceived( |
| + const net::SpdyHeaderBlock& headers_block, |
| + const char* negotiated_protocol) { |
| + DCHECK(callback_->on_response_headers_received); |
| + HeadersArray response_headers(headers_block); |
| + callback_->on_response_headers_received(stream_, &response_headers, |
| + negotiated_protocol); |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::OnDataRead(char* data, int size) { |
| + DCHECK(callback_->on_read_completed); |
| + callback_->on_read_completed(stream_, data, size); |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::OnDataSent(const char* data) { |
| + DCHECK(callback_->on_write_completed); |
| + callback_->on_write_completed(stream_, data); |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::OnTrailersReceived( |
| + const net::SpdyHeaderBlock& trailers_block) { |
| + DCHECK(callback_->on_response_trailers_received); |
| + HeadersArray response_trailers(trailers_block); |
| + callback_->on_response_trailers_received(stream_, &response_trailers); |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::OnSucceeded() { |
| + DCHECK(callback_->on_succeded); |
| + callback_->on_succeded(stream_); |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::OnFailed(int error) { |
| + DCHECK(callback_->on_failed); |
| + callback_->on_failed(stream_, error); |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::OnCanceled() { |
| + DCHECK(callback_->on_canceled); |
| + callback_->on_canceled(stream_); |
| +} |
| + |
| +cronet::CronetBidirectionalStream* |
| +CronetBidirectionalStreamAdapter::GetCronetStream( |
| + cronet_bidirectional_stream* stream) { |
| + DCHECK(stream); |
| + CronetBidirectionalStreamAdapter* adapter = |
| + static_cast<CronetBidirectionalStreamAdapter*>(stream->obj); |
| + DCHECK(adapter->stream_ == stream); |
| + DCHECK(adapter->cronet_bidirectional_stream_); |
| + return adapter->cronet_bidirectional_stream_; |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::DestroyAdapterForStream( |
| + cronet_bidirectional_stream* stream) { |
| + DCHECK(stream); |
| + CronetBidirectionalStreamAdapter* adapter = |
| + static_cast<CronetBidirectionalStreamAdapter*>(stream->obj); |
| + DCHECK(adapter->stream_ == stream); |
| + // Destroy could be called from any thread, including network thread (if |
| + // posting task to executor throws an exception), but is posted, so |this| |
| + // is valid until calling task is complete. |
| + adapter->cronet_bidirectional_stream_->Destroy(); |
| + adapter->cronet_environment_->PostToNetworkThread( |
| + FROM_HERE, |
| + base::Bind(&CronetBidirectionalStreamAdapter::DestroyOnNetworkThread, |
| + base::Unretained(adapter))); |
| +} |
| + |
| +void CronetBidirectionalStreamAdapter::DestroyOnNetworkThread() { |
| + DCHECK(cronet_environment_->IsOnNetworkThread()); |
| + delete this; |
| +} |
| + |
| +} // namespace |
| + |
| +cronet_bidirectional_stream* cronet_bidirectional_stream_create( |
| + cronet_engine* engine, |
| + void* annotation, |
| + cronet_bidirectional_stream_callback* callback) { |
| + // Allocate C |stream| object. |
| + cronet_bidirectional_stream* stream = new cronet_bidirectional_stream(); |
| + // Allocate new C++ adapter that will invoke |callback|. |
| + stream->obj = new CronetBidirectionalStreamAdapter(engine, stream, callback); |
| + stream->annotation = annotation; |
| + return stream; |
| +} |
| + |
| +int cronet_bidirectional_stream_start( |
| + cronet_bidirectional_stream* stream, |
| + const char* url, |
| + int priority, |
| + const char* method, |
| + const cronet_bidirectional_stream_header_array* headers, |
| + bool end_of_stream) { |
| + cronet::CronetBidirectionalStream* cronet_stream = |
| + CronetBidirectionalStreamAdapter::GetCronetStream(stream); |
| + net::HttpRequestHeaders request_headers; |
| + if (headers) { |
| + for (size_t i = 0; i < headers->count; ++i) { |
| + std::string name(headers->headers[i].key); |
| + std::string value(headers->headers[i].value); |
| + if (!net::HttpUtil::IsValidHeaderName(name) || |
| + !net::HttpUtil::IsValidHeaderValue(value)) { |
| + return i + 1; |
| + } |
| + request_headers.SetHeader(name, value); |
| + } |
| + } |
| + return cronet_stream->Start(url, priority, method, request_headers, |
| + end_of_stream); |
| +} |
| + |
| +int cronet_bidirectional_stream_read(cronet_bidirectional_stream* stream, |
| + char* buffer, |
| + int capacity) { |
| + return CronetBidirectionalStreamAdapter::GetCronetStream(stream)->ReadData( |
| + buffer, capacity); |
| +} |
| + |
| +int cronet_bidirectional_stream_write(cronet_bidirectional_stream* stream, |
| + const char* buffer, |
| + int count, |
| + bool end_of_stream) { |
| + return CronetBidirectionalStreamAdapter::GetCronetStream(stream)->WriteData( |
| + buffer, count, end_of_stream); |
| +} |
| + |
| +int cronet_bidirectional_stream_cancel(cronet_bidirectional_stream* stream) { |
| + CronetBidirectionalStreamAdapter::GetCronetStream(stream)->Cancel(); |
| + return 1; |
| +} |
| + |
| +int cronet_bidirectional_stream_destroy(cronet_bidirectional_stream* stream) { |
|
xunjieli
2016/04/08 14:43:15
Theses functions are in global namespace. Do we ne
mef
2016/04/08 16:43:03
C doesn't support namespaces. That's why they have
|
| + CronetBidirectionalStreamAdapter::DestroyAdapterForStream(stream); |
| + delete stream; |
| + return 1; |
| +} |