Commit 6db997ed authored by wang's avatar wang

cronet 130.0.6700.0

parent ca71225c
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
# cronet-go
Cronet is the Chromium network stack made available as a library. Cronet takes advantage of multiple
technologies that reduce the latency and increase the throughput of the network requests.
The Cronet Library handles the requests of apps used by millions of people on a daily basis, such as YouTube, Google
App, Google Photos, and Maps - Navigation & Transit.
This experimental project ported Cronet to golang. To learn how to use the Cronet Library in
your app, see the [examples](./examples).
## Build Cronet Library
Follow all the [Get the Code](https://www.chromium.org/developers/how-tos/get-the-code/) instructions for your target platform up to and including running hooks.
Apply weblifeio customization:
```sh
git remote add weblifeio https://github.com/weblifeio/chromium
git fetch weblifeio
git cherry-pick weblifeio/develop ^weblifeio/main
```
Follow the [instructions](https://chromium.googlesource.com/chromium/src/+/master/components/cronet/build_instructions.md#desktop-builds-targets-the-current-os) for Desktop builds.
## Install Cronet Library
The following instructions assume you have switched to the `chromium/src` directory:
```sh
mkdir /usr/local/include/cronet_lib
mkdir /usr/local/lib/cronet_lib
cp out/Cronet/cronet_lib/include/* /usr/local/include/cronet_lib
cp out/Cronet/*.dylib /usr/local/lib/cronet_lib
CRONET_VERSION=$(build/util/version.py -f out/Cronet/cronet_lib/VERSION -t "@MAJOR@.@MINOR@.@BUILD@.@PATCH@") \
&& ln -sf /usr/local/lib/cronet_lib/libcronet.${CRONET_VERSION}.dylib /usr/local/lib/cronet_lib/libcronet.124.0.6344.0.dylib \
&& ln -sf /usr/local/lib/cronet_lib/libcronet.${CRONET_VERSION}.dylib /usr/local/lib/libcronet.124.0.6344.0.dylib \
&& ln -sf /usr/local/lib/cronet_lib/libcronet.${CRONET_VERSION}.dylib /usr/local/lib/libcronet.${CRONET_VERSION}.dylib
```
Replace `.dylib` to `.so` if you're on Linux.
## Use cronet-go
```
import (
"github.com/weblifeio/cronet-go"
)
```
When building your project set these environment variables:
```sh
export set CGO_CFLAGS="-I/usr/local/include/cronet"
export set CGO_LDFLAGS="-Wl,-rpath,/usr/local/lib/cronet -L/usr/local/lib/cronet -lcronet"
go build <your-project-here>
```
package cronet
func BBB() {
}
package cronet
import (
"context"
"errors"
"io"
"net"
"os"
"strconv"
"sync"
"time"
)
// BidirectionalConn is a wrapper from BidirectionalStream to net.Conn
type BidirectionalConn struct {
stream BidirectionalStream
readWaitHeaders bool
writeWaitHeaders bool
access sync.Mutex
close chan struct{}
done chan struct{}
err error
ready chan struct{}
handshake chan struct{}
read chan int
write chan struct{}
headers map[string]string
}
func (e StreamEngine) CreateConn(readWaitHeaders bool, writeWaitHeaders bool) *BidirectionalConn {
conn := &BidirectionalConn{
readWaitHeaders: readWaitHeaders,
writeWaitHeaders: writeWaitHeaders,
close: make(chan struct{}),
done: make(chan struct{}),
ready: make(chan struct{}),
handshake: make(chan struct{}),
read: make(chan int),
write: make(chan struct{}),
}
conn.stream = e.CreateStream(&bidirectionalHandler{conn})
return conn
}
func (c *BidirectionalConn) Start(method string, url string, headers map[string]string, priority int, endOfStream bool) error {
c.access.Lock()
defer c.access.Unlock()
select {
case <-c.close:
return net.ErrClosed
case <-c.done:
return net.ErrClosed
default:
}
if !c.stream.Start(method, url, headers, priority, endOfStream) {
return os.ErrInvalid
}
return nil
}
// Read implements io.Reader
func (c *BidirectionalConn) Read(p []byte) (n int, err error) {
select {
case <-c.close:
return 0, net.ErrClosed
case <-c.done:
return 0, net.ErrClosed
default:
}
if c.readWaitHeaders {
select {
case <-c.handshake:
break
case <-c.done:
return 0, c.err
}
} else {
select {
case <-c.ready:
break
case <-c.done:
return 0, c.err
}
}
c.access.Lock()
select {
case <-c.close:
return 0, net.ErrClosed
case <-c.done:
return 0, net.ErrClosed
default:
}
c.stream.Read(p)
c.access.Unlock()
select {
case bytesRead := <-c.read:
return bytesRead, nil
case <-c.done:
return 0, c.err
}
}
// Write implements io.Writer
func (c *BidirectionalConn) Write(p []byte) (n int, err error) {
select {
case <-c.close:
return 0, net.ErrClosed
case <-c.done:
return 0, net.ErrClosed
default:
}
if c.writeWaitHeaders {
select {
case <-c.handshake:
break
case <-c.done:
return 0, c.err
}
} else {
select {
case <-c.ready:
break
case <-c.done:
return 0, c.err
}
}
c.access.Lock()
select {
case <-c.close:
return 0, net.ErrClosed
case <-c.done:
return 0, net.ErrClosed
default:
}
c.stream.Write(p, false)
c.access.Unlock()
select {
case <-c.write:
return len(p), nil
case <-c.done:
return 0, c.err
}
}
// Done implements context.Context
func (c *BidirectionalConn) Done() <-chan struct{} {
return c.done
}
// Err implements context.Context
func (c *BidirectionalConn) Err() error {
return c.err
}
// Close implements io.Closer
func (c *BidirectionalConn) Close() error {
c.access.Lock()
defer c.access.Unlock()
select {
case <-c.close:
return net.ErrClosed
case <-c.done:
return net.ErrClosed
default:
}
close(c.close)
c.stream.Cancel()
return nil
}
// LocalAddr implements net.Conn
func (c *BidirectionalConn) LocalAddr() net.Addr {
return nil
}
// RemoteAddr implements net.Conn
func (c *BidirectionalConn) RemoteAddr() net.Addr {
return nil
}
// SetDeadline implements net.Conn
func (c *BidirectionalConn) SetDeadline(t time.Time) error {
return os.ErrInvalid
}
// SetReadDeadline implements net.Conn
func (c *BidirectionalConn) SetReadDeadline(t time.Time) error {
return os.ErrInvalid
}
// SetWriteDeadline implements net.Conn
func (c *BidirectionalConn) SetWriteDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *BidirectionalConn) WaitForHeaders() (map[string]string, error) {
select {
case <-c.close:
return nil, net.ErrClosed
case <-c.done:
return nil, net.ErrClosed
default:
}
select {
case <-c.handshake:
return c.headers, nil
case <-c.done:
return nil, c.err
}
}
type bidirectionalHandler struct {
*BidirectionalConn
}
func (c *bidirectionalHandler) OnStreamReady(stream BidirectionalStream) {
close(c.ready)
}
func (c *bidirectionalHandler) OnResponseHeadersReceived(stream BidirectionalStream, headers map[string]string, negotiatedProtocol string) {
c.headers = headers
close(c.handshake)
}
func (c *bidirectionalHandler) OnReadCompleted(stream BidirectionalStream, bytesRead int) {
c.access.Lock()
if c.err != nil {
c.access.Unlock()
return
}
if bytesRead == 0 {
c.access.Unlock()
c.Close(stream, io.EOF)
return
}
select {
case <-c.close:
case <-c.done:
case c.read <- bytesRead:
}
c.access.Unlock()
}
func (c *bidirectionalHandler) OnWriteCompleted(stream BidirectionalStream) {
c.access.Lock()
defer c.access.Unlock()
if c.err != nil {
return
}
select {
case <-c.close:
case <-c.done:
case c.write <- struct{}{}:
}
}
func (c *bidirectionalHandler) OnResponseTrailersReceived(stream BidirectionalStream, trailers map[string]string) {
}
func (c *bidirectionalHandler) OnSucceeded(stream BidirectionalStream) {
c.Close(stream, io.EOF)
}
func (c *bidirectionalHandler) OnFailed(stream BidirectionalStream, netError int) {
c.Close(stream, errors.New("network error "+strconv.Itoa(netError)))
}
func (c *bidirectionalHandler) OnCanceled(stream BidirectionalStream) {
c.Close(stream, context.Canceled)
}
func (c *bidirectionalHandler) Close(stream BidirectionalStream, err error) {
c.access.Lock()
defer c.access.Unlock()
select {
case <-c.done:
return
default:
}
c.err = err
close(c.done)
stream.Destroy()
}
package cronet
// #include <stdbool.h>
// #include <stdlib.h>
// #include <cronet_c.h>
// #include <bidirectional_stream_c.h>
import "C"
import (
"unsafe"
)
// StreamEngine
// Opaque object representing a Bidirectional stream creating engine. Created
// and configured outside of this API to facilitate sharing with other
// components
type StreamEngine struct {
ptr *C.stream_engine
}
func (e Engine) StreamEngine() StreamEngine {
return StreamEngine{C.Cronet_Engine_GetStreamEngine(e.ptr)}
}
// BidirectionalStream
// Opaque object representing Bidirectional Stream
type BidirectionalStream struct {
ptr *C.bidirectional_stream
}
// BidirectionalStreamCallback
// Set of callbacks used to receive callbacks from bidirectional stream.
type BidirectionalStreamCallback interface {
// OnStreamReady
// Invoked when the stream is ready for reading and writing.
// Consumer may call BidirectionalStream.Read() to start reading data.
// Consumer may call BidirectionalStream.Write() to start writing
// data.
OnStreamReady(stream BidirectionalStream)
// OnResponseHeadersReceived
// Invoked when initial response headers are received.
// Consumer must call BidirectionalStream.Read() to start reading.
// Consumer may call BidirectionalStream.Write() to start writing or
// close the stream. Contents of |headers| is valid for duration of the call.
///
OnResponseHeadersReceived(stream BidirectionalStream, headers map[string]string, negotiatedProtocol string)
// OnReadCompleted
// Invoked when data is read into the buffer passed to
// BidirectionalStream.Read(). Only part of the buffer may be
// populated. To continue reading, call BidirectionalStream.Read().
// It may be invoked after on_response_trailers_received()}, if there was
// pending read data before trailers were received.
//
// If |bytesRead| is 0, it means the remote side has signaled that it will
// send no more data; future calls to BidirectionalStream.Read()
// will result in the OnReadCompleted() callback or OnSucceeded() callback if
// BidirectionalStream.Write() was invoked with endOfStream set to
// true.
OnReadCompleted(stream BidirectionalStream, bytesRead int)
// OnWriteCompleted
// Invoked when all data passed to BidirectionalStream.Write() is
// sent. To continue writing, call BidirectionalStream.Write().
OnWriteCompleted(stream BidirectionalStream)
// OnResponseTrailersReceived
// Invoked when trailers are received before closing the stream. Only invoked
// when server sends trailers, which it may not. May be invoked while there is
// read data remaining in local buffer. Contents of |trailers| is valid for
// duration of the call.
OnResponseTrailersReceived(stream BidirectionalStream, trailers map[string]string)
// OnSucceeded
// Invoked when there is no data to be read or written and the stream is
// closed successfully remotely and locally. Once invoked, no further callback
// methods will be invoked.
OnSucceeded(stream BidirectionalStream)
// OnFailed
// Invoked if the stream failed for any reason after
// BidirectionalStream.Start(). HTTP/2 error codes are
// mapped to chrome net error codes. Once invoked, no further callback methods
// will be invoked.
OnFailed(stream BidirectionalStream, netError int)
// OnCanceled
// Invoked if the stream was canceled via
// BidirectionalStream.Cancel(). Once invoked, no further callback
// methods will be invoked.
OnCanceled(stream BidirectionalStream)
}
// CreateStream
// Creates a new stream object that uses |engine| and |callback|. All stream
// tasks are performed asynchronously on the |engine| network thread. |callback|
// methods are invoked synchronously on the |engine| network thread, but must
// not run tasks on the current thread to prevent blocking networking operations
// and causing exceptions during shutdown. The |annotation| is stored in
// bidirectional stream for arbitrary use by application.
//
// Returned |bidirectional_stream*| is owned by the caller, and must be
// destroyed using |bidirectional_stream_destroy|.
//
// Both |calback| and |engine| must remain valid until stream is destroyed.
func (e StreamEngine) CreateStream(callback BidirectionalStreamCallback) BidirectionalStream {
ptr := C.bidirectional_stream_create(e.ptr, nil, &bidirectionalStreamCallback)
bidirectionalStreamAccess.Lock()
bidirectionalStreamMap[uintptr(unsafe.Pointer(ptr))] = callback
bidirectionalStreamAccess.Unlock()
return BidirectionalStream{ptr}
}
// Destroy destroys stream object. Destroy could be called from any thread, including
// network thread, but is posted, so |stream| is valid until calling task is
// complete.
func (c BidirectionalStream) Destroy() bool {
bidirectionalStreamAccess.Lock()
delete(bidirectionalStreamMap, uintptr(unsafe.Pointer(c.ptr)))
bidirectionalStreamAccess.Unlock()
return C.bidirectional_stream_destroy(c.ptr) == 0
}
// DisableAutoFlush disables or enables auto flush. By default, data is flushed after
// every Write(). If the auto flush is disabled,
// the client should explicitly call Flush() to flush
// the data.
func (c BidirectionalStream) DisableAutoFlush(disable bool) {
C.bidirectional_stream_disable_auto_flush(c.ptr, C.bool(disable))
}
// DelayRequestHeadersUntilFlush delays sending request headers until Flush()
// is called. This flag is currently only respected when QUIC is negotiated.
// When true, QUIC will send request header frame along with data frame(s)
// as a single packet when possible.
func (c BidirectionalStream) DelayRequestHeadersUntilFlush(delay bool) {
C.bidirectional_stream_delay_request_headers_until_flush(c.ptr, C.bool(delay))
}
// Start starts the stream by sending request to |url| using |method| and |headers|.
// If |endOfStream| is true, then no data is expected to be written. The
// |method| is HTTP verb.
// noinspection GoDeferInLoop
func (c BidirectionalStream) Start(method string, url string, headers map[string]string, priority int, endOfStream bool) bool {
var headerArray C.bidirectional_stream_header_array
headerLen := len(headers)
if headerLen > 0 {
cHeadersPtr := C.malloc(C.size_t(int(C.sizeof_struct_bidirectional_stream_header) * headerLen))
defer C.free(cHeadersPtr)
var cType *C.bidirectional_stream_header
cType = (*C.bidirectional_stream_header)(cHeadersPtr)
cHeaders := unsafe.Slice(cType, headerLen)
var index int
for key, value := range headers {
cKey := C.CString(key)
defer C.free(unsafe.Pointer(cKey))
cValue := C.CString(value)
defer C.free(unsafe.Pointer(cValue))
cHeaders[index].key = cKey
cHeaders[index].value = cValue
index++
}
headerArray = C.bidirectional_stream_header_array{
C.size_t(headerLen), C.size_t(headerLen), &cHeaders[0],
}
}
cMethod := C.CString(method)
defer C.free(unsafe.Pointer(cMethod))
cURL := C.CString(url)
defer C.free(unsafe.Pointer(cURL))
return C.bidirectional_stream_start(c.ptr, cURL, C.int(priority), cMethod, &headerArray, C.bool(endOfStream)) == 0
}
// Read reads response data into |buffer|. Must only be called
// at most once in response to each invocation of the
// OnStreamReady()/OnResponseHeaderReceived() and OnReadCompleted()
// methods of the BidirectionalStreamCallback.
// Each call will result in an invocation of the callback's
// OnReadCompleted() method if data is read, or its OnFailed() method if
// there's an error. The callback's OnSucceeded() method is also invoked if
// there is no more data to read and |end_of_stream| was previously sent.
func (c BidirectionalStream) Read(buffer []byte) int {
return int(C.bidirectional_stream_read(c.ptr, (*C.char)((unsafe.Pointer)(&buffer[0])), C.int(len(buffer))))
}
// Write Writes request data from |buffer| If auto flush is
// disabled, data will be sent only after Flush() is
// called.
// Each call will result in an invocation the callback's BidirectionalStreamCallback.OnWriteCompleted()
// method if data is sent, or its BidirectionalStreamCallback.OnFailed() method if there's an error.
// The callback's BidirectionalStreamCallback.OnSucceeded() method is also invoked if |endOfStream| is
// set and all response data has been read.
func (c BidirectionalStream) Write(buffer []byte, endOfStream bool) int {
return int(C.bidirectional_stream_write(c.ptr, (*C.char)(unsafe.Pointer(&buffer[0])), C.int(len(buffer)), C.bool(endOfStream)))
}
// Flush Flushes pending writes. This method should not be called before invocation of
// BidirectionalStreamCallback.OnStreamReady() method.
// For each previously called Write()
// a corresponding OnWriteCompleted() callback will be invoked when the buffer
// is sent.BidirectionalStream
func (c BidirectionalStream) Flush() {
C.bidirectional_stream_flush(c.ptr)
}
// Cancel cancels the stream. Can be called at any time after
// Start(). The BidirectionalStreamCallback.OnCanceled() method will be invoked when cancellation
// is complete and no further callback methods will be invoked. If the
// stream has completed or has not started, calling
// Cancel() has no effect and BidirectionalStreamCallback.OnCanceled() will not
// be invoked. At most one callback method may be invoked after
// Cancel() has completed.
func (c BidirectionalStream) Cancel() {
C.bidirectional_stream_cancel(c.ptr)
}
package cronet
// #include <stdbool.h>
// #include <stdlib.h>
// #include <cronet_c.h>
// #include <bidirectional_stream_c.h>
// extern void cronetBidirectionalStreamOnStreamReady(bidirectional_stream* stream);
// extern void cronetBidirectionalStreamOnResponseHeadersReceived(bidirectional_stream* stream, bidirectional_stream_header_array* headers, char* negotiated_protocol);
// extern void cronetBidirectionalStreamOnReadCompleted(bidirectional_stream* stream, char* data, int bytes_read);
// extern void cronetBidirectionalStreamOnWriteCompleted(bidirectional_stream* stream, char* data);
// extern void cronetBidirectionalStreamOnResponseTrailersReceived(bidirectional_stream* stream, bidirectional_stream_header_array* trailers);
// extern void cronetBidirectionalStreamOnSucceed(bidirectional_stream* stream);
// extern void cronetBidirectionalStreamOnFailed(bidirectional_stream* stream, int net_error);
// extern void cronetBidirectionalStreamOnCanceled(bidirectional_stream* stream);
import "C"
import (
"sync"
"unsafe"
)
var (
bidirectionalStreamAccess sync.RWMutex
bidirectionalStreamMap map[uintptr]BidirectionalStreamCallback
bidirectionalStreamCallback C.bidirectional_stream_callback
)
func init() {
bidirectionalStreamMap = make(map[uintptr]BidirectionalStreamCallback)
bidirectionalStreamCallback.on_stream_ready = (*[0]byte)(C.cronetBidirectionalStreamOnStreamReady)
bidirectionalStreamCallback.on_response_headers_received = (*[0]byte)(C.cronetBidirectionalStreamOnResponseHeadersReceived)
bidirectionalStreamCallback.on_read_completed = (*[0]byte)(C.cronetBidirectionalStreamOnReadCompleted)
bidirectionalStreamCallback.on_write_completed = (*[0]byte)(C.cronetBidirectionalStreamOnWriteCompleted)
bidirectionalStreamCallback.on_response_trailers_received = (*[0]byte)(C.cronetBidirectionalStreamOnResponseTrailersReceived)
bidirectionalStreamCallback.on_succeded = (*[0]byte)(C.cronetBidirectionalStreamOnSucceed)
bidirectionalStreamCallback.on_failed = (*[0]byte)(C.cronetBidirectionalStreamOnFailed)
bidirectionalStreamCallback.on_canceled = (*[0]byte)(C.cronetBidirectionalStreamOnCanceled)
}
func instanceOfBidirectionalStream(stream *C.bidirectional_stream) BidirectionalStreamCallback {
bidirectionalStreamAccess.RLock()
defer bidirectionalStreamAccess.RUnlock()
return bidirectionalStreamMap[uintptr(unsafe.Pointer(stream))]
}
//export cronetBidirectionalStreamOnStreamReady
func cronetBidirectionalStreamOnStreamReady(stream *C.bidirectional_stream) {
callback := instanceOfBidirectionalStream(stream)
if callback == nil {
return
}
callback.OnStreamReady(BidirectionalStream{stream})
}
//export cronetBidirectionalStreamOnResponseHeadersReceived
func cronetBidirectionalStreamOnResponseHeadersReceived(stream *C.bidirectional_stream, headers *C.bidirectional_stream_header_array, negotiatedProtocol *C.char) {
callback := instanceOfBidirectionalStream(stream)
if callback == nil {
return
}
headerMap := make(map[string]string, int(headers.count))
var hdrP *C.bidirectional_stream_header
hdrP = headers.headers
headersSlice := unsafe.Slice(hdrP, int(headers.count))
for _, header := range headersSlice {
key := C.GoString(header.key)
if len(key) == 0 {
continue
}
headerMap[key] = C.GoString(header.value)
}
callback.OnResponseHeadersReceived(BidirectionalStream{stream}, headerMap, C.GoString(negotiatedProtocol))
}
//export cronetBidirectionalStreamOnReadCompleted
func cronetBidirectionalStreamOnReadCompleted(stream *C.bidirectional_stream, data *C.char, bytesRead C.int) {
callback := instanceOfBidirectionalStream(stream)
if callback == nil {
return
}
callback.OnReadCompleted(BidirectionalStream{stream}, int(bytesRead))
}
//export cronetBidirectionalStreamOnWriteCompleted
func cronetBidirectionalStreamOnWriteCompleted(stream *C.bidirectional_stream, data *C.char) {
callback := instanceOfBidirectionalStream(stream)
if callback == nil {
return
}
callback.OnWriteCompleted(BidirectionalStream{stream})
}
//export cronetBidirectionalStreamOnResponseTrailersReceived
func cronetBidirectionalStreamOnResponseTrailersReceived(stream *C.bidirectional_stream, trailers *C.bidirectional_stream_header_array) {
callback := instanceOfBidirectionalStream(stream)
if callback == nil {
return
}
trailersMap := make(map[string]string, int(trailers.count))
var hdrP *C.bidirectional_stream_header
hdrP = trailers.headers
headersSlice := unsafe.Slice(hdrP, int(trailers.count))
for _, header := range headersSlice {
key := C.GoString(header.key)
if len(key) == 0 {
continue
}
trailersMap[key] = C.GoString(header.value)
}
callback.OnResponseTrailersReceived(BidirectionalStream{stream}, trailersMap)
}
//export cronetBidirectionalStreamOnSucceed
func cronetBidirectionalStreamOnSucceed(stream *C.bidirectional_stream) {
callback := instanceOfBidirectionalStream(stream)
if callback == nil {
return
}
callback.OnSucceeded(BidirectionalStream{stream})
}
//export cronetBidirectionalStreamOnFailed
func cronetBidirectionalStreamOnFailed(stream *C.bidirectional_stream, netError C.int) {
callback := instanceOfBidirectionalStream(stream)
if callback == nil {
return
}
callback.OnFailed(BidirectionalStream{stream}, int(netError))
}
//export cronetBidirectionalStreamOnCanceled
func cronetBidirectionalStreamOnCanceled(stream *C.bidirectional_stream) {
callback := instanceOfBidirectionalStream(stream)
if callback == nil {
return
}
callback.OnCanceled(BidirectionalStream{stream})
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import (
"reflect"
"unsafe"
)
// Buffer provided by the application to read and write data.
type Buffer struct {
ptr C.Cronet_BufferPtr
}
func NewBuffer() Buffer {
return Buffer{C.Cronet_Buffer_Create()}
}
func (b Buffer) Destroy() {
C.Cronet_Buffer_Destroy(b.ptr)
}
// InitWithDataAndCallback initialize Buffer with raw buffer |data| of |size| allocated by the app.
// The |callback| is invoked when buffer is destroyed.
func (b Buffer) InitWithDataAndCallback(data []byte, callback BufferCallback) {
C.Cronet_Buffer_InitWithDataAndCallback(b.ptr, C.Cronet_RawDataPtr(unsafe.Pointer(&data[0])), C.uint64_t(len(data)), callback.ptr)
}
// InitWithAlloc initialize Buffer by allocating buffer of |size|.
// The content of allocated data is not initialized.
func (b Buffer) InitWithAlloc(size int64) {
C.Cronet_Buffer_InitWithAlloc(b.ptr, C.uint64_t(size))
}
// Size return size of data owned by this buffer.
func (b Buffer) Size() int64 {
return int64(C.Cronet_Buffer_GetSize(b.ptr))
}
// Data return raw pointer to |data| owned by this buffer.
func (b Buffer) Data() unsafe.Pointer {
return unsafe.Pointer(C.Cronet_Buffer_GetData(b.ptr))
}
func (b Buffer) DataSlice() []byte {
size := int(b.Size())
hdr := reflect.SliceHeader{
Data: uintptr(b.Data()),
Len: size,
Cap: size,
}
return *(*[]byte)(unsafe.Pointer(&hdr))
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// BufferCallbackFunc invoked when |buffer| is destroyed so its app-allocated |data| can
// be freed. If a URLRequest has ownership of a Buffer and the UrlRequest is destroyed
// (e.g. URLRequest.Destroy() is called), then Cronet will call BufferCallbackFunc().
type BufferCallbackFunc func(callback BufferCallback, buffer Buffer)
// BufferCallback is app-provided callback passed to Buffer.InitWithDataAndCallback that gets invoked
// when Buffer is destroyed.
type BufferCallback struct {
ptr C.Cronet_BufferCallbackPtr
}
func (c BufferCallback) Destroy() {
C.Cronet_BufferCallback_Destroy(c.ptr)
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
// extern void cronetBufferCallbackOnDestroy(Cronet_BufferCallbackPtr self,Cronet_BufferPtr buffer);
import "C"
import (
"sync"
"unsafe"
)
func NewBufferCallback(callbackFunc BufferCallbackFunc) BufferCallback {
ptr := C.Cronet_BufferCallback_CreateWith((*[0]byte)(C.cronetBufferCallbackOnDestroy))
if callbackFunc != nil {
bufferCallbackAccess.Lock()
bufferCallbackMap[uintptr(unsafe.Pointer(ptr))] = callbackFunc
bufferCallbackAccess.Unlock()
}
return BufferCallback{ptr}
}
var (
bufferCallbackAccess sync.Mutex
bufferCallbackMap map[uintptr]BufferCallbackFunc
)
func init() {
bufferCallbackMap = make(map[uintptr]BufferCallbackFunc)
}
//export cronetBufferCallbackOnDestroy
func cronetBufferCallbackOnDestroy(self C.Cronet_BufferCallbackPtr, buffer C.Cronet_BufferPtr) {
ptrInt := uintptr(unsafe.Pointer(self))
bufferCallbackAccess.Lock()
callback := bufferCallbackMap[ptrInt]
delete(bufferCallbackMap, ptrInt)
bufferCallbackAccess.Unlock()
if callback != nil {
callback(BufferCallback{self}, Buffer{buffer})
}
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import "time"
// DateTime
// Represents a date and time expressed as the number of milliseconds since the UNIX epoch.
type DateTime struct {
ptr C.Cronet_DateTimePtr
}
func NewDateTime() DateTime {
return DateTime{C.Cronet_DateTime_Create()}
}
func (t DateTime) Destroy() {
C.Cronet_DateTime_Destroy(t.ptr)
}
// SetValue
// Number of milliseconds since the UNIX epoch.
func (t DateTime) SetValue(value time.Time) {
C.Cronet_DateTime_value_set(t.ptr, C.int64_t(value.UnixMilli()))
}
func (t DateTime) Value() time.Time {
return time.UnixMilli(int64(C.Cronet_DateTime_value_get(t.ptr)))
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import (
"unsafe"
)
// Engine is an engine to process URLRequest, which uses the best HTTP stack
// available on the current platform. An instance of this class can be started
// using StartWithParams.
type Engine struct {
ptr C.Cronet_EnginePtr
}
func NewEngine() Engine {
return Engine{C.Cronet_Engine_Create()}
}
func (e Engine) Destroy() {
C.Cronet_Engine_Destroy(e.ptr)
}
// StartWithParams starts Engine using given |params|. The engine must be started once
// and only once before other methods can be used.
func (e Engine) StartWithParams(params EngineParams) Result {
return Result(C.Cronet_Engine_StartWithParams(e.ptr, params.ptr))
}
// StartNetLogToFile starts NetLog logging to a file. The NetLog will contain events emitted
// by all live Engines. The NetLog is useful for debugging.
// The file can be viewed using a Chrome browser navigated to
// chrome://net-internals/#import
// Returns |true| if netlog has started successfully, |false| otherwise.
// Parameter |fileName| the complete file path. It must not be empty. If the file
// exists, it is truncated before starting. If actively logging, this method is ignored.
// Parameter |logAll| to include basic events, user cookies, credentials and all transferred
// bytes in the log. This option presentsa privacy risk, since it exposes the user's credentials,
// and should only be used with the user's consent and in situations where the log won't be public.
// false to just include basic events.
func (e Engine) StartNetLogToFile(fileName string, logAll bool) bool {
cPath := C.CString(fileName)
result := C.Cronet_Engine_StartNetLogToFile(e.ptr, cPath, C.bool(logAll))
C.free(unsafe.Pointer(cPath))
return bool(result)
}
// StopNetLog Stops NetLog logging and flushes file to disk. If a logging session is
// not in progress, this call is ignored. This method blocks until the log is
// closed to ensure that log file is complete and available.
func (e Engine) StopNetLog() {
C.Cronet_Engine_StopNetLog(e.ptr)
}
// Shutdown shuts down the Engine if there are no active requests,
// otherwise returns a failure Result.
//
// Cannot be called on network thread - the thread Cronet calls into
// Executor on (which is different from the thread the Executor invokes
// callbacks on). This method blocks until all the Engine's resources have
// been cleaned up.
func (e Engine) Shutdown() Result {
return Result(C.Cronet_Engine_Shutdown(e.ptr))
}
// Version returns a human-readable version string of the engine.
func (e Engine) Version() string {
return C.GoString(C.Cronet_Engine_GetVersionString(e.ptr))
}
// DefaultUserAgent Returns default human-readable version string of the engine. Can be used
// before StartWithParams() is called.
func (e Engine) DefaultUserAgent() string {
return C.GoString(C.Cronet_Engine_GetDefaultUserAgent(e.ptr))
}
// AddRequestFinishedListener registers a listener that gets called at the end of each request.
//
// The listener is called on Executor.
//
// The listener is called before URLRequestCallbackHandler.OnCanceled(),
// URLRequestCallbackHandler.OnFailed() or
// URLRequestCallbackHandler.OnSucceeded() is called -- note that if Executor
// runs the listener asynchronously, the actual call to the listener
// may happen after a URLRequestCallbackHandler method is called.
//
// Listeners are only guaranteed to be called for requests that are started
// after the listener is added.
//
// Ownership is **not** taken for listener or Executor.
//
// Assuming the listener won't run again (there are no pending requests with
// the listener attached, either via Engine or UrlRequest),
// the app may destroy it once its OnRequestFinished() has started,
// even inside that method.
//
// Similarly, the app may destroy executor in or after OnRequestFinished()}.
//
// It's also OK to destroy executor in or after one of
// URLRequestCallbackHandler.OnCanceled(), URLRequestCallbackHandler.OnFailed() or
// URLRequestCallbackHandler.OnSucceeded().
//
// Of course, both of these are only true if listener won't run again
// and executor isn't being used for anything else that might start
// running in the future.
//
// @param listener the listener for finished requests.
// @param executor the executor upon which to run listener.
func (e Engine) AddRequestFinishedListener(listener URLRequestFinishedInfoListener, executor Executor) {
C.Cronet_Engine_AddRequestFinishedListener(e.ptr, listener.ptr, executor.ptr)
}
// RemoveRequestFinishedListener unregisters a RequestFinishedInfoListener,
// including its association with its registered Executor.
func (e Engine) RemoveRequestFinishedListener(listener URLRequestFinishedInfoListener) {
C.Cronet_Engine_RemoveRequestFinishedListener(e.ptr, listener.ptr)
}
// SetClientCertificate Configures all subsequent connections to server designated with {@code hostPortPair}
// to authenticate with {@code client_cert_data} and {@code private_key_data} when requested.
// {@code clientCertData} can be PEM/DER encoded.
// {@code privateKeyData} is supposed to be PEM encoded.
//
// The method can be called only after the engine is started.
//func (e Engine) SetClientCertificate(hostPortPair string, clientCertData []byte, privateKeyData []byte) {
// cHostPortPair := C.CString(hostPortPair)
// clientCertBuffer := NewBuffer()
// clientCertBuffer.InitWithDataAndCallback(clientCertData, NewBufferCallback(nil))
// privateKeyBuffer := NewBuffer()
// privateKeyBuffer.InitWithDataAndCallback(privateKeyData, NewBufferCallback(nil))
// C.Cronet_Engine_SetClientCertificate(e.ptr, cHostPortPair, clientCertBuffer.ptr, privateKeyBuffer.ptr)
// clientCertBuffer.Destroy()
// privateKeyBuffer.Destroy()
// C.free(unsafe.Pointer(cHostPortPair))
//}
// ClearClientCertificate Clears a client certificate preference for server designated with {@code hostPortPair}
// set by SetClientCertificate(). Returns true if one was removed and false otherwise.
//
// The method can be called only after the engine is started.
//func (e Engine) ClearClientCertificate(hostPortPair string) Result {
// cHostPortPair := C.CString(hostPortPair)
// result := C.Cronet_Engine_ClearClientCertificate(e.ptr, cHostPortPair)
// C.free(unsafe.Pointer(cHostPortPair))
// return Result(result)
//}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import (
"fmt"
url2 "net/url"
"unsafe"
)
// EngineParams is the parameters for Engine, which allows its configuration before start.
// Configuration options are set on the EngineParams and
// then Engine.StartWithParams is called to start the Engine.
type EngineParams struct {
ptr C.Cronet_EngineParamsPtr
}
func NewEngineParams() EngineParams {
return EngineParams{C.Cronet_EngineParams_Create()}
}
func (p EngineParams) Destroy() {
C.Cronet_EngineParams_Destroy(p.ptr)
}
// SetEnableCheckResult override strict result checking for all operations that return RESULT.
// If set to true, then failed result will cause native crash via SIGABRT.
func (p EngineParams) SetEnableCheckResult(enable bool) {
C.Cronet_EngineParams_enable_check_result_set(p.ptr, C.bool(enable))
}
func (p EngineParams) EnableCheckResult() bool {
return bool(C.Cronet_EngineParams_enable_check_result_get(p.ptr))
}
// SetUserAgent override of the User-Agent header for all requests. An explicitly
// set User-Agent header will override a value set using this param.
func (p EngineParams) SetUserAgent(userAgent string) {
cUserAgent := C.CString(userAgent)
C.Cronet_EngineParams_user_agent_set(p.ptr, cUserAgent)
C.free(unsafe.Pointer(cUserAgent))
}
func (p EngineParams) UserAgent() string {
return C.GoString(C.Cronet_EngineParams_user_agent_get(p.ptr))
}
// SetAccentLanguage sets a default value for the Accept-Language header value for UrlRequests
// created by this engine. Explicitly setting the Accept-Language header
// value for individual UrlRequests will override this value.
func (p EngineParams) SetAccentLanguage(acceptLanguage string) {
cAcceptLanguage := C.CString(acceptLanguage)
C.Cronet_EngineParams_accept_language_set(p.ptr, cAcceptLanguage)
C.free(unsafe.Pointer(cAcceptLanguage))
}
func (p EngineParams) AccentLanguage() string {
return C.GoString(C.Cronet_EngineParams_accept_language_get(p.ptr))
}
// SetStoragePath sets directory for HTTP Cache and Prefs Storage. The directory must exist.
func (p EngineParams) SetStoragePath(storagePath string) {
cStoragePath := C.CString(storagePath)
C.Cronet_EngineParams_storage_path_set(p.ptr, cStoragePath)
C.free(unsafe.Pointer(cStoragePath))
}
func (p EngineParams) StoragePath() string {
return C.GoString(C.Cronet_EngineParams_storage_path_get(p.ptr))
}
// SetEnableQuic sets whether <a href="https://www.chromium.org/quic">QUIC</a> protocol
// is enabled. If QUIC is enabled, then QUIC User Agent Id
// containing application name and Cronet version is sent to the server.
func (p EngineParams) SetEnableQuic(enable bool) {
C.Cronet_EngineParams_enable_quic_set(p.ptr, C.bool(enable))
}
func (p EngineParams) EnableQuic() bool {
return bool(C.Cronet_EngineParams_enable_quic_get(p.ptr))
}
// SetEnableHTTP2 sets whether <a href="https://tools.ietf.org/html/rfc7540">HTTP/2</a>
// protocol is enabled.
func (p EngineParams) SetEnableHTTP2(enable bool) {
C.Cronet_EngineParams_enable_http2_set(p.ptr, C.bool(enable))
}
func (p EngineParams) EnableHTTP2() bool {
return bool(C.Cronet_EngineParams_enable_http2_get(p.ptr))
}
// SetEnableBrotli sets whether <a href="https://tools.ietf.org/html/rfc7932">Brotli</a> compression is
// enabled. If enabled, Brotli will be advertised in Accept-Encoding request headers.
func (p EngineParams) SetEnableBrotli(enable bool) {
C.Cronet_EngineParams_enable_brotli_set(p.ptr, C.bool(enable))
}
func (p EngineParams) EnableBrotli() bool {
return bool(C.Cronet_EngineParams_enable_brotli_get(p.ptr))
}
// HTTPCacheMode enables or disables caching of HTTP data and other information like QUIC
// server information.
type HTTPCacheMode int
const (
// HTTPCacheModeDisabled Disable HTTP cache. Some data may still be temporarily stored in memory.
HTTPCacheModeDisabled HTTPCacheMode = 0
// HTTPCacheModeInMemory Enable in-memory HTTP cache, including HTTP data.
HTTPCacheModeInMemory HTTPCacheMode = 1
// HTTPCacheModeDiskNoHTTP Enable on-disk cache, excluding HTTP data.
// |storagePath| must be set to existing directory.
HTTPCacheModeDiskNoHTTP HTTPCacheMode = 2
// HTTPCacheModeDisk Enable on-disk cache, including HTTP data.
// |storagePath| must be set to existing directory.
HTTPCacheModeDisk HTTPCacheMode = 3
)
// SetHTTPCacheMode enables or disables caching of HTTP data and other information like QUIC
// server information.
func (p EngineParams) SetHTTPCacheMode(mode HTTPCacheMode) {
C.Cronet_EngineParams_http_cache_mode_set(p.ptr, C.Cronet_EngineParams_HTTP_CACHE_MODE(mode))
}
func (p EngineParams) HTTPCacheMode() HTTPCacheMode {
return HTTPCacheMode(C.Cronet_EngineParams_http_cache_mode_get(p.ptr))
}
// SetHTTPCacheMaxSize sets Maximum size in bytes used to cache data (advisory and maybe exceeded at
// times)
func (p EngineParams) SetHTTPCacheMaxSize(maxSize int64) {
C.Cronet_EngineParams_http_cache_max_size_set(p.ptr, C.int64_t(maxSize))
}
func (p EngineParams) HTTPCacheMaxSize() int64 {
return int64(C.Cronet_EngineParams_http_cache_max_size_get(p.ptr))
}
// AddQuicHint add hints that hosts support QUIC.
func (p EngineParams) AddQuicHint(element QuicHint) {
C.Cronet_EngineParams_quic_hints_add(p.ptr, element.ptr)
}
func (p EngineParams) QuicHintSize() int {
return int(C.Cronet_EngineParams_quic_hints_size(p.ptr))
}
func (p EngineParams) QuicHintAt(index int) QuicHint {
return QuicHint{C.Cronet_EngineParams_quic_hints_at(p.ptr, C.uint32_t(index))}
}
func (p EngineParams) ClearQuicHints() {
C.Cronet_EngineParams_quic_hints_clear(p.ptr)
}
// AddPublicKeyPins pins a set of public keys for given hosts. See PublicKeyPins for explanation.
func (p EngineParams) AddPublicKeyPins(element PublicKeyPins) {
C.Cronet_EngineParams_public_key_pins_add(p.ptr, element.ptr)
}
func (p EngineParams) PublicKeyPinsSize() int {
return int(C.Cronet_EngineParams_public_key_pins_size(p.ptr))
}
func (p EngineParams) PublicKeyPinsAt(index int) PublicKeyPins {
return PublicKeyPins{C.Cronet_EngineParams_public_key_pins_at(p.ptr, C.uint32_t(index))}
}
func (p EngineParams) ClearPublicKeyPins() {
C.Cronet_EngineParams_public_key_pins_clear(p.ptr)
}
// SetEnablePublicKeyPinningBypassForLocalTrustAnchors enables or disables public key pinning bypass for local trust anchors. Disabling the
// bypass for local trust anchors is highly discouraged since it may prohibit the app
// from communicating with the pinned hosts. E.g., a user may want to send all traffic
// through an SSL enabled proxy by changing the device proxy settings and adding the
// proxy certificate to the list of local trust anchor. Disabling the bypass will most
// likely prevent the app from sending any traffic to the pinned hosts. For more
// information see 'How does key pinning interact with local proxies and filters?' at
// https://www.chromium.org/Home/chromium-security/security-faq
func (p EngineParams) SetEnablePublicKeyPinningBypassForLocalTrustAnchors(enable bool) {
C.Cronet_EngineParams_enable_public_key_pinning_bypass_for_local_trust_anchors_set(p.ptr, C.bool(enable))
}
func (p EngineParams) EnablePublicKeyPinningBypassForLocalTrustAnchors() bool {
return bool(C.Cronet_EngineParams_enable_public_key_pinning_bypass_for_local_trust_anchors_get(p.ptr))
}
// SetNetworkThreadPriority set optional network thread priority. NAN indicates unset, use default.
// On Android, corresponds to android.os.Process.setThreadPriority() values.
// On iOS, corresponds to NSThread::setThreadPriority values.
// Do not specify for other platforms.
func (p EngineParams) SetNetworkThreadPriority(priority int) {
C.Cronet_EngineParams_network_thread_priority_set(p.ptr, C.double(priority))
}
func (p EngineParams) NetworkThreadPriority() int {
return int(C.Cronet_EngineParams_network_thread_priority_get(p.ptr))
}
// SetExperimentalOptions set JSON formatted experimental options to be used in Cronet Engine.
func (p EngineParams) SetExperimentalOptions(options string) {
cOptions := C.CString(options)
C.Cronet_EngineParams_experimental_options_set(p.ptr, cOptions)
C.free(unsafe.Pointer(cOptions))
}
// SetProxyUsername set JSON formatted experimental options to be used in Cronet Engine.
func (p EngineParams) SetProxyUsername(options string) {
cOptions := C.CString(options)
C.Cronet_EngineParams_proxy_username_set(p.ptr, cOptions)
C.free(unsafe.Pointer(cOptions))
}
// SetExperimentalOptions set JSON formatted experimental options to be used in Cronet Engine.
//
// func (p EngineParams) SetProxyPassword(options string) {
// cOptions := C.CString(options)
// C.Cronet_EngineParams_proxy_password_set(p.ptr, cOptions)
// C.free(unsafe.Pointer(cOptions))
// }
func (p EngineParams) ExperimentalOptions() string {
return C.GoString(C.Cronet_EngineParams_experimental_options_get(p.ptr))
}
// SetProxyServer sets a default value for the Proxy Server to be used for UrlRequests
// created by this engine. Cronet will forward this requests to destination
// using this proxy.
func (p EngineParams) SetProxyServer(options string) {
cOptions := C.CString(options)
auth := ""
uri, err := url2.Parse(options)
if err == nil {
user := uri.User.Username()
pwd, pwdErr := uri.User.Password()
if user != "" && pwdErr == true {
auth = fmt.Sprintf("%s:%s", user, pwd)
}
}
fmt.Println("auth", auth)
p.SetProxyUsername(auth)
C.Cronet_EngineParams_proxy_rules_set(p.ptr, cOptions)
C.Cronet_EngineParams_proxy_password_set(p.ptr, cOptions)
C.free(unsafe.Pointer(cOptions))
}
//func (p EngineParams) ProxyServer() string {
// return C.GoString(C.Cronet_EngineParams_proxy_server_get(p.ptr))
//}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// Error is the base error passed to URLRequestCallbackHandler.OnFailed().
type Error struct {
ptr C.Cronet_ErrorPtr
}
type ErrorCode int
const (
// ErrorCodeErrorCallback indicating the error returned by app callback.
ErrorCodeErrorCallback ErrorCode = 0
// ErrorCodeErrorHostnameNotResolved indicating the host being sent the request could not be resolved to an IP address.
ErrorCodeErrorHostnameNotResolved ErrorCode = 1
// ErrorCodeErrorInternetDisconnected indicating the device was not connected to any network.
ErrorCodeErrorInternetDisconnected ErrorCode = 2
// ErrorCodeErrorNetworkChanged indicating that as the request was processed the network configuration changed.
ErrorCodeErrorNetworkChanged ErrorCode = 3
// ErrorCodeErrorTimedOut indicating a timeout expired. Timeouts expiring while attempting to connect will
// be reported as the more specific ErrorCodeErrorConnectionTimedOut.
ErrorCodeErrorTimedOut ErrorCode = 4
// ErrorCodeErrorConnectionClosed indicating the connection was closed unexpectedly.
ErrorCodeErrorConnectionClosed ErrorCode = 5
// ErrorCodeErrorConnectionTimedOut indicating the connection attempt timed out.
ErrorCodeErrorConnectionTimedOut ErrorCode = 6
// ErrorCodeErrorConnectionRefused indicating the connection attempt was refused.
ErrorCodeErrorConnectionRefused ErrorCode = 7
// ErrorCodeErrorConnectionReset indicating the connection was unexpectedly reset.
ErrorCodeErrorConnectionReset ErrorCode = 8
// ErrorCodeErrorAddressUnreachable indicating the IP address being contacted is unreachable,
// meaning there is no route to the specified host or network.
ErrorCodeErrorAddressUnreachable ErrorCode = 9
// ErrorCodeErrorQuicProtocolFailed indicating an error related to the <a href="https://www.chromium.org/quic">
// <a>QUIC</a> protocol. When Error.ErrorCode() is this code, see
// Error.QuicDetailedErrorCode() for more information.
ErrorCodeErrorQuicProtocolFailed ErrorCode = 10
// ErrorCodeErrorOther indicating another type of error was encountered.
// |Error.InternalErrorCode()| can be consulted to get a more specific cause.
ErrorCodeErrorOther ErrorCode = 11
)
// ErrorCode return the error code, one of ErrorCode values.
func (e Error) ErrorCode() ErrorCode {
return ErrorCode(C.Cronet_Error_error_code_get(e.ptr))
}
// Message explaining the error.
func (e Error) Message() string {
return C.GoString(C.Cronet_Error_message_get(e.ptr))
}
// InternalErrorCode is the cronet_lib internal error code. This may provide more specific error
// diagnosis than ErrorCode(), but the constant values may change over time.
// See
// <a href=https://chromium.googlesource.com/chromium/src/+/main/net/base/net_error_list.h> here</a>
// for the latest list of values.
func (e Error) InternalErrorCode() int {
return int(C.Cronet_Error_internal_error_code_get(e.ptr))
}
// Retryable |true| if retrying this request right away might succeed, |false|
// otherwise. For example, is |true| when ErrorCode() is ErrorCodeErrorNetworkChanged
// because trying the request might succeed using the new
// network configuration, but |false| when ErrorCode() is
// ErrorCodeErrorInternetDisconnected because retrying the request right away will
// encounter the same failure (instead retrying should be delayed until device regains
// network connectivity).
func (e Error) Retryable() bool {
return bool(C.Cronet_Error_immediately_retryable_get(e.ptr))
}
// QuicDetailedErrorCode contains detailed <a href="https://www.chromium.org/quic">QUIC</a> error code from
// <a href="https://cs.chromium.org/search/?q=symbol:%5CbQuicErrorCode%5Cb">
// QuicErrorCode</a> when the ErrorCode() code is ErrorCodeErrorQuicProtocolFailed.
func (e Error) QuicDetailedErrorCode() int {
return int(C.Cronet_Error_quic_detailed_error_code_get(e.ptr))
}
package cronet
type ErrorGo struct {
ErrorCode ErrorCode
Message string
InternalErrorCode int
Retryable bool
QuicDetailedErrorCode int
}
func (e *ErrorGo) Error() string {
return e.Message
}
func (e *ErrorGo) Timeout() bool {
return e.ErrorCode == ErrorCodeErrorConnectionTimedOut
}
func (e *ErrorGo) Temporary() bool {
return e.Retryable
}
func ErrorFromError(error Error) *ErrorGo {
return &ErrorGo{
ErrorCode: error.ErrorCode(),
Message: error.Message(),
InternalErrorCode: error.InternalErrorCode(),
Retryable: error.Retryable(),
QuicDetailedErrorCode: error.QuicDetailedErrorCode(),
}
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// ExecutorExecuteFunc takes ownership of |command| and runs it synchronously or asynchronously.
// Destroys the |command| after execution, or if executor is shutting down.
type ExecutorExecuteFunc func(executor Executor, command Runnable)
// Executor is an interface provided by the app to run |command| asynchronously.
type Executor struct {
ptr C.Cronet_ExecutorPtr
}
func (e Executor) Execute(command Runnable) {
C.Cronet_Executor_Execute(e.ptr, command.ptr)
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
// extern void cronetExecutorExecute(Cronet_ExecutorPtr self,Cronet_RunnablePtr command);
import "C"
import (
"sync"
"unsafe"
)
var (
executorAccess sync.RWMutex
executors = make(map[uintptr]ExecutorExecuteFunc)
)
func NewExecutor(executeFunc ExecutorExecuteFunc) Executor {
ptr := C.Cronet_Executor_CreateWith((*[0]byte)(C.cronetExecutorExecute))
executorAccess.Lock()
executors[uintptr(unsafe.Pointer(ptr))] = executeFunc
executorAccess.Unlock()
return Executor{ptr}
}
func (e Executor) Destroy() {
C.Cronet_Executor_Destroy(e.ptr)
executorAccess.Lock()
delete(executors, uintptr(unsafe.Pointer(e.ptr)))
executorAccess.Unlock()
}
//export cronetExecutorExecute
func cronetExecutorExecute(self C.Cronet_ExecutorPtr, command C.Cronet_RunnablePtr) {
executorAccess.RLock()
executeFunc := executors[uintptr(unsafe.Pointer(self))]
executorAccess.RUnlock()
if executeFunc != nil {
executeFunc(Executor{self}, Runnable{command})
}
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import "unsafe"
// HTTPHeader is a single HTTP request or response header
type HTTPHeader struct {
ptr C.Cronet_HttpHeaderPtr
}
func NewHTTPHeader() HTTPHeader {
return HTTPHeader{C.Cronet_HttpHeader_Create()}
}
func (h HTTPHeader) Destroy() {
C.Cronet_HttpHeader_Destroy(h.ptr)
}
// SetName sets header name
func (h HTTPHeader) SetName(name string) {
cName := C.CString(name)
C.Cronet_HttpHeader_name_set(h.ptr, cName)
C.free(unsafe.Pointer(cName))
}
func (h HTTPHeader) Name() string {
return C.GoString(C.Cronet_HttpHeader_name_get(h.ptr))
}
// SetValue sts header value
func (h HTTPHeader) SetValue(value string) {
cValue := C.CString(value)
C.Cronet_HttpHeader_value_set(h.ptr, cValue)
C.free(unsafe.Pointer(cValue))
}
func (h HTTPHeader) Value() string {
return C.GoString(C.Cronet_HttpHeader_value_get(h.ptr))
}
package cronet
func isTokenChar(c byte) bool {
return !(c >= 0x7F || c <= 0x20 || c == '(' || c == ')' || c == '<' ||
c == '>' || c == '@' || c == ',' || c == ';' || c == ':' ||
c == '\\' || c == '"' || c == '/' || c == '[' || c == ']' ||
c == '?' || c == '=' || c == '{' || c == '}')
}
func isToken(str string) bool {
if len(str) == 0 {
return false
}
for _, c := range str {
if !isTokenChar(byte(c)) {
return false
}
}
return true
}
func IsValidHeaderName(value string) bool {
return isToken(value)
}
func IsValidHeaderValue(value string) bool {
if len(value) == 0 {
return false
}
for _, c := range value {
if c == '\x00' || c == '\r' || c == '\n' {
return false
}
}
return true
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// Metrics
// Represents metrics collected for a single request. Most of these metrics are
// timestamps for events during the lifetime of the request, which can be used
// to build a detailed timeline for investigating performance.
//
// Represents metrics collected for a single request. Most of these metrics are
// timestamps for events during the lifetime of the request, which can be used
// to build a detailed timeline for investigating performance.
//
// Events happen in this order:
// <ol>
// <li>#request_start request start</li>
// <li>#dns_start DNS start</li>
// <li>#dns_end DNS end</li>
// <li>#connect_start connect start</li>
// <li>#ssl_start SSL start</li>
// <li>#ssl_end SSL end</li>
// <li>#connect_end connect end</li>
// <li>#sending_start sending start</li>
// <li>#sending_end sending end</li>
// <li>#response_start response start</li>
// <li>#request_end request end</li>
// </ol>
//
// Start times are reported as the time when a request started blocking on the
// event, not when the event actually occurred, with the exception of push
// start and end. If a metric is not meaningful or not available, including
// cases when a request finished before reaching that stage, start and end
// times will be null. If no time was spent blocking on an event, start and end
// will be the same time.
//
// Timestamps are recorded using a clock that is guaranteed not to run
// backwards. All timestamps are correct relative to the system clock at the
// time of request start, and taking the difference between two timestamps will
// give the correct difference between the events. In order to preserve this
// property, timestamps for events other than request start are not guaranteed
// to match the system clock at the times they represent.
//
// Most timing metrics are taken from
// <a
// href="https://cs.chromium.org/chromium/src/net/base/load_timing_info.h">LoadTimingInfo</a>,
// which holds the information for <a href="http://w3c.github.io/navigation-timing/"></a> and
// <a href="https://www.w3.org/TR/resource-timing/"></a>.
type Metrics struct {
ptr C.Cronet_MetricsPtr
}
// RequestStart
// Time when the request started, which corresponds to calling
// Cronet_UrlRequest_Start(). This timestamp will match the system clock at
// the time it represents.
func (m Metrics) RequestStart() DateTime {
return DateTime{C.Cronet_Metrics_request_start_get(m.ptr)}
}
// DNSStart
// Time when DNS lookup started. This and DNSEnd will be set to
// non-null regardless of whether the result came from a DNS server or the
// local cache. Will equal null if the socket was reused (see SocketReused).
func (m Metrics) DNSStart() DateTime {
return DateTime{C.Cronet_Metrics_dns_start_get(m.ptr)}
}
// DNSEnd
// Time when DNS lookup finished. This and DNSStart will return
// non-null regardless of whether the result came from a DNS server or the
// local cache. Will equal null if the socket was reused (see SocketReused).
func (m Metrics) DNSEnd() DateTime {
return DateTime{C.Cronet_Metrics_dns_end_get(m.ptr)}
}
// ConnectStart
// Time when connection establishment started, typically when DNS resolution
// finishes. Will equal null if the socket was reused (see SocketReused).
func (m Metrics) ConnectStart() DateTime {
return DateTime{C.Cronet_Metrics_connect_start_get(m.ptr)}
}
// ConnectEnd
// Time when connection establishment finished, after TCP connection is
// established and, if using HTTPS, SSL handshake is completed. For QUIC
// 0-RTT, this represents the time of handshake confirmation and might happen
// later than SendingStart. Will equal null if the socket was
// reused (see SocketReused).
func (m Metrics) ConnectEnd() DateTime {
return DateTime{C.Cronet_Metrics_connect_end_get(m.ptr)}
}
// SSLStart
// Time when SSL handshake started. For QUIC, this will be the same time as
// ConnectStart. Will equal null if SSL is not used or if the
// socket was reused (see SocketReused).
func (m Metrics) SSLStart() DateTime {
return DateTime{C.Cronet_Metrics_ssl_start_get(m.ptr)}
}
// SSLEnd
// Time when SSL handshake finished. For QUIC, this will be the same time as
// ConnectEnd. Will equal null if SSL is not used or if the socket
// was reused (see SocketReused).
func (m Metrics) SSLEnd() DateTime {
return DateTime{C.Cronet_Metrics_ssl_end_get(m.ptr)}
}
// SendingStart
// Time when sending HTTP request headers started.
//
// Will equal null if the request failed or was canceled before sending
// started.
func (m Metrics) SendingStart() DateTime {
return DateTime{C.Cronet_Metrics_sending_start_get(m.ptr)}
}
// SendingEnd
// Time when sending HTTP request body finished. (Sending request body
// happens after sending request headers.)
//
// Will equal null if the request failed or was canceled before sending
// ended.
func (m Metrics) SendingEnd() DateTime {
return DateTime{C.Cronet_Metrics_sending_end_get(m.ptr)}
}
// PushStart
// Time when first byte of HTTP/2 server push was received. Will equal
// null if server push is not used.
func (m Metrics) PushStart() DateTime {
return DateTime{C.Cronet_Metrics_push_start_get(m.ptr)}
}
// PushEnd
// Time when last byte of HTTP/2 server push was received. Will equal
// null if server push is not used.
func (m Metrics) PushEnd() DateTime {
return DateTime{C.Cronet_Metrics_push_end_get(m.ptr)}
}
// ResponseStart
// Time when the end of the response headers was received.
//
// Will equal null if the request failed or was canceled before the response
// started.
func (m Metrics) ResponseStart() DateTime {
return DateTime{C.Cronet_Metrics_response_start_get(m.ptr)}
}
// ResponseEnd
// Time when the request finished.
func (m Metrics) ResponseEnd() DateTime {
return DateTime{C.Cronet_Metrics_request_end_get(m.ptr)}
}
// SocketReused
// True if the socket was reused from a previous request, false otherwise.
// In HTTP/2 or QUIC, if streams are multiplexed in a single connection, this
// will be {@code true} for all streams after the first. When {@code true},
// DNS, connection, and SSL times will be null.
func (m Metrics) SocketReused() bool {
return bool(C.Cronet_Metrics_socket_reused_get(m.ptr))
}
// SentByteCount
// Returns total bytes sent over the network transport layer, or -1 if not
// collected.
func (m Metrics) SentByteCount() int64 {
return int64(C.Cronet_Metrics_sent_byte_count_get(m.ptr))
}
// ReceivedByteCount
// Total bytes received over the network transport layer, or -1 if not
// collected. Number of bytes does not include any previous redirects.
func (m Metrics) ReceivedByteCount() int64 {
return int64(C.Cronet_Metrics_received_byte_count_get(m.ptr))
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import (
"unsafe"
)
// PublicKeyPins is a set of public keys for a given |host|. By pinning a set of public keys,
// |pinsSha256|, communication with |host| is required to
// authenticate with a certificate with a public key from the set of pinned ones.
// An app can pin the public key of the root certificate, any of the intermediate
// certificates or the end-entry certificate. Authentication will fail and secure
// communication will not be established if none of the public keys is present in the
// host's certificate chain, even if the host attempts to authenticate with a
// certificate allowed by the device's trusted store of certificates.
// *
// More information about the public key pinning can be found in
// <a href="https://tools.ietf.org/html/rfc7469">RFC 7469</a>.
type PublicKeyPins struct {
ptr C.Cronet_PublicKeyPinsPtr
}
func NewPublicKeyPins() PublicKeyPins {
return PublicKeyPins{C.Cronet_PublicKeyPins_Create()}
}
func (p PublicKeyPins) Destroy() {
C.Cronet_PublicKeyPins_Destroy(p.ptr)
}
// SetHost set name of the host to which the public keys should be pinned. A host that
// consists only of digits and the dot character is treated as invalid.
func (p PublicKeyPins) SetHost(host string) {
cHost := C.CString(host)
C.Cronet_PublicKeyPins_host_set(p.ptr, cHost)
C.free(unsafe.Pointer(cHost))
}
func (p PublicKeyPins) Host() string {
return C.GoString(C.Cronet_PublicKeyPins_host_get(p.ptr))
}
// AddPinnedSHA256 add pins. each pin is the SHA-256 cryptographic
// hash (in the form of "sha256/<base64-hash-value>") of the DER-encoded ASN.1
// representation of the Subject Public Key Info (SPKI) of the host's X.509 certificate.
// Although, the method does not mandate the presence of the backup pin
// that can be used if the control of the primary private key has been
// lost, it is highly recommended to supply one.
func (p PublicKeyPins) AddPinnedSHA256(hash string) {
cHash := C.CString(hash)
C.Cronet_PublicKeyPins_pins_sha256_add(p.ptr, cHash)
C.free(unsafe.Pointer(cHash))
}
func (p PublicKeyPins) PinnedSHA256Size() int {
return int(C.Cronet_PublicKeyPins_pins_sha256_size(p.ptr))
}
func (p PublicKeyPins) PinnedSHA256At(index int) string {
return C.GoString(C.Cronet_PublicKeyPins_pins_sha256_at(p.ptr, C.uint32_t(index)))
}
func (p PublicKeyPins) ClearPinnedSHA256() {
C.Cronet_PublicKeyPins_pins_sha256_clear(p.ptr)
}
// SetIncludeSubdomains set whether the pinning policy should be applied to subdomains of |host|.
func (p PublicKeyPins) SetIncludeSubdomains(includeSubdomains bool) {
C.Cronet_PublicKeyPins_include_subdomains_set(p.ptr, C.bool(includeSubdomains))
}
func (p PublicKeyPins) IncludeSubdomains() bool {
return bool(C.Cronet_PublicKeyPins_include_subdomains_get(p.ptr))
}
// SetExpirationDate set the expiration date for the pins in milliseconds since epoch (as in java.util.Date).
func (p PublicKeyPins) SetExpirationDate(date int64) {
C.Cronet_PublicKeyPins_expiration_date_set(p.ptr, C.int64_t(date))
}
func (p PublicKeyPins) ExpirationDate() int64 {
return int64(C.Cronet_PublicKeyPins_expiration_date_get(p.ptr))
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import (
"unsafe"
)
// QuicHint hint that |host| supports QUIC.
type QuicHint struct {
ptr C.Cronet_QuicHintPtr
}
func NewQuicHint() QuicHint {
return QuicHint{C.Cronet_QuicHint_Create()}
}
func (h QuicHint) Destroy() {
C.Cronet_QuicHint_Destroy(h.ptr)
}
// SetHost set name of the host that supports QUIC.
func (h QuicHint) SetHost(host string) {
cHost := C.CString(host)
C.Cronet_QuicHint_host_set(h.ptr, cHost)
C.free(unsafe.Pointer(cHost))
}
func (h QuicHint) Host() string {
return C.GoString(C.Cronet_QuicHint_host_get(h.ptr))
}
// SetPort set port of the server that supports QUIC.
func (h QuicHint) SetPort(port int32) {
C.Cronet_QuicHint_port_set(h.ptr, C.int32_t(port))
}
func (h QuicHint) Port() int32 {
return int32(C.Cronet_QuicHint_port_get(h.ptr))
}
// SetAlternatePort set alternate port to use for QUIC
func (h QuicHint) SetAlternatePort(port int32) {
C.Cronet_QuicHint_alternate_port_set(h.ptr, C.int32_t(port))
}
func (h QuicHint) AlternatePort() int32 {
return int32(C.Cronet_QuicHint_alternate_port_get(h.ptr))
}
package cronet
// Result is runtime result code returned by Engine and URLRequest. Equivalent to
// runtime exceptions in Android Java API. All results except SUCCESS trigger
// native crash (via SIGABRT triggered by CHECK failure) unless
// EngineParams.EnableCheckResult is set to false.
type Result int
const (
// ResultSuccess Operation completed successfully
ResultSuccess Result = 0
// ResultIllegalArgument Illegal argument
ResultIllegalArgument Result = -100
// ResultIllegalArgumentStoragePathMustExist Storage path must be set to existing directory
ResultIllegalArgumentStoragePathMustExist Result = -101
// ResultIllegalArgumentInvalidPin Public key pin is invalid
ResultIllegalArgumentInvalidPin Result = -102
// ResultIllegalArgumentInvalidHostname Host name is invalid
ResultIllegalArgumentInvalidHostname Result = -103
// ResultIllegalArgumentInvalidHttpMethod Invalid http method
ResultIllegalArgumentInvalidHttpMethod Result = -104
// ResultIllegalArgumentInvalidHttpHeader Invalid http header
ResultIllegalArgumentInvalidHttpHeader Result = -105
// ResultIllegalState Illegal state
ResultIllegalState Result = -200
// ResultIllegalStateStoragePathInUse Storage path is used by another engine
ResultIllegalStateStoragePathInUse Result = -201
// ResultIllegalStateCannotShutdownEngineFromNetworkThread Cannot shutdown engine from network thread
ResultIllegalStateCannotShutdownEngineFromNetworkThread Result = -202
// ResultIllegalStateEngineAlreadyStarted The engine has already started
ResultIllegalStateEngineAlreadyStarted Result = -203
// ResultIllegalStateRequestAlreadyStarted The request has already started
ResultIllegalStateRequestAlreadyStarted Result = -204
// ResultIllegalStateRequestNotInitialized The request is not initialized
ResultIllegalStateRequestNotInitialized Result = -205
// ResultIllegalStateRequestAlreadyInitialized The request is already initialized
ResultIllegalStateRequestAlreadyInitialized Result = -206
// ResultIllegalStateRequestNotStarted The request is not started
ResultIllegalStateRequestNotStarted Result = -207
// ResultIllegalStateUnexpectedRedirect No redirect to follow
ResultIllegalStateUnexpectedRedirect Result = -208
// ResultIllegalStateUnexpectedRead Unexpected read attempt
ResultIllegalStateUnexpectedRead Result = -209
// ResultIllegalStateReadFailed Unexpected read failure
ResultIllegalStateReadFailed Result = -210
// ResultNullPointer Null pointer or empty data
ResultNullPointer Result = -300
// ResultNullPointerHostname The hostname cannot be null
ResultNullPointerHostname Result = -301
// ResultNullPointerSha256Pins The set of SHA256 pins cannot be null
ResultNullPointerSha256Pins Result = -302
// ResultNullPointerExpirationDate The pin expiration date cannot be null
ResultNullPointerExpirationDate Result = -303
// ResultNullPointerEngine Engine is required
ResultNullPointerEngine Result = -304
// ResultNullPointerURL URL is required
ResultNullPointerURL Result = -305
// ResultNullPointerCallback Callback is required
ResultNullPointerCallback Result = -306
// ResultNullPointerExecutor Executor is required
ResultNullPointerExecutor Result = -307
// ResultNullPointerMethod Method is required
ResultNullPointerMethod Result = -308
// ResultNullPointerHeaderName Invalid header name
ResultNullPointerHeaderName Result = -309
// ResultNullPointerHeaderValue Invalid header value
ResultNullPointerHeaderValue Result = -310
// ResultNullPointerParams Params is required
ResultNullPointerParams Result = -311
// ResultNullPointerRequestFinishedInfoListenerExecutor Executor for RequestFinishedInfoListener is required
ResultNullPointerRequestFinishedInfoListenerExecutor Result = -312
)
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// Runnable is an interface to run commands on the Executor.
//
// Note: In general creating Runnables should only be done by Cronet. Runnables
// created by the app don't have the ability to perform operations when the
// Runnable is being destroyed (i.e. by Cronet_Runnable_Destroy) so resource
// leaks are possible if the Runnable is posted to an Executor that is being
// shutdown with unexecuted Runnables. In controlled testing environments
// deallocation of associated resources can be performed in Run() if the
// runnable can be assumed to always be executed.
// */
type Runnable struct {
ptr C.Cronet_RunnablePtr
}
func (r Runnable) Destroy() {
C.Cronet_Runnable_Destroy(r.ptr)
}
func (r Runnable) Run() {
C.Cronet_Runnable_Run(r.ptr)
}
package cronet
import (
"context"
"errors"
"io"
"net"
"net/http"
"net/textproto"
"os"
"runtime"
"slices"
"strconv"
"strings"
"sync"
)
var asyncExecutor Executor
var syncExecutor Executor
func init() {
asyncExecutor = NewExecutor(func(executor Executor, command Runnable) {
go func() {
command.Run()
command.Destroy()
}()
})
syncExecutor = NewExecutor(func(executor Executor, command Runnable) {
command.Run()
command.Destroy()
})
runtime.SetFinalizer(&asyncExecutor, (*Executor).Destroy)
runtime.SetFinalizer(&syncExecutor, (*Executor).Destroy)
}
// RoundTripper is a wrapper from URLRequest to http.RoundTripper
type RoundTripper struct {
FollowRedirect bool
Engine Engine
closeEngine bool
}
func NewCronetTransport(params EngineParams, FollowRedirect bool) *RoundTripper {
t := &RoundTripper{
FollowRedirect: FollowRedirect,
}
t.Engine = NewEngine()
t.Engine.StartWithParams(params)
params.Destroy()
t.closeEngine = true
runtime.SetFinalizer(t, (*RoundTripper).Close)
return t
}
func NewCronetTransportWithDefaultParams() *RoundTripper {
engineParams := NewEngineParams()
engineParams.SetEnableHTTP2(true)
engineParams.SetEnableQuic(true)
engineParams.SetEnableBrotli(true)
engineParams.SetUserAgent("Go-cronet_lib-http-client")
return NewCronetTransport(engineParams, true)
}
func (t *RoundTripper) Close() error {
if t.closeEngine {
result := t.Engine.Shutdown()
if result != ResultSuccess {
return errors.New("engine still has active requests, so couldn't shutdown")
}
t.Engine.Destroy()
t.closeEngine = false
}
return nil
}
func (t *RoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
requestParams := NewURLRequestParams()
if request.Method == "" {
requestParams.SetMethod("GET")
} else {
requestParams.SetMethod(request.Method)
}
for key, values := range request.Header {
for _, value := range values {
header := NewHTTPHeader()
header.SetName(key)
header.SetValue(value)
requestParams.AddHeader(header)
header.Destroy()
}
}
if request.Body != nil {
uploadProvider := NewUploadDataProvider(&bodyUploadProvider{request.Body, request.GetBody, request.ContentLength})
requestParams.SetUploadDataProvider(uploadProvider)
requestParams.SetUploadDataExecutor(syncExecutor)
}
m := &sync.Mutex{}
responseHandler := urlResponse{
FollowRedirect: t.FollowRedirect,
response: http.Response{
Request: request,
Proto: request.Proto,
ProtoMajor: request.ProtoMajor,
ProtoMinor: request.ProtoMinor,
Header: make(http.Header),
},
readyToRead: sync.NewCond(m),
read: make(chan int),
cancel: make(chan struct{}),
done: make(chan struct{}),
}
responseHandler.response.Body = &responseHandler
go responseHandler.monitorContext(request.Context())
callback := NewURLRequestCallback(&responseHandler)
urlRequest := NewURLRequest()
responseHandler.request = urlRequest
cronetResult := urlRequest.InitWithParams(t.Engine, request.URL.String(), requestParams, callback, asyncExecutor)
if cronetResult != ResultSuccess {
return nil, errors.New("failed to init request, cronet_result_code : " + strconv.Itoa(int(cronetResult)))
}
requestParams.Destroy()
cronetResult = urlRequest.Start()
if cronetResult != ResultSuccess {
return nil, errors.New("failed to start request, cronet_result_code : " + strconv.Itoa(int(cronetResult)))
}
m.Lock()
responseHandler.readyToRead.Wait()
return &responseHandler.response, responseHandler.err
}
type urlResponse struct {
FollowRedirect bool
readyToRead *sync.Cond
request URLRequest
response http.Response
err error
access sync.Mutex
read chan int
readBuffer Buffer
cancel chan struct{}
done chan struct{}
}
func (r *urlResponse) monitorContext(ctx context.Context) {
if ctx.Done() == nil {
return
}
select {
case <-r.cancel:
case <-r.done:
case <-ctx.Done():
r.err = ctx.Err()
r.Close()
}
}
func (r *urlResponse) Read(p []byte) (n int, err error) {
select {
case <-r.done:
return 0, r.err
default:
}
r.access.Lock()
select {
case <-r.done:
r.access.Unlock()
return 0, r.err
default:
}
r.readBuffer = NewBuffer()
r.readBuffer.InitWithDataAndCallback(p, NewBufferCallback(nil))
cronetResult := r.request.Read(r.readBuffer)
r.access.Unlock()
if cronetResult != ResultSuccess {
return 0, errors.New("failed to read body, cronet_result_code : " + strconv.Itoa(int(cronetResult)))
}
select {
case bytesRead := <-r.read:
return bytesRead, nil
case <-r.cancel:
return 0, net.ErrClosed
case <-r.done:
return 0, r.err
}
}
func (r *urlResponse) Close() error {
r.access.Lock()
defer r.access.Unlock()
select {
case <-r.cancel:
return os.ErrClosed
case <-r.done:
return nil
default:
close(r.cancel)
r.request.Cancel()
}
return nil
}
// Cronet automatically decompresses body content if one of these encodings is used
var cronetEncodings = []string{"br", "deflate", "gzip", "x-gzip", "zstd"}
func (r *urlResponse) OnRedirectReceived(self URLRequestCallback, request URLRequest, info URLResponseInfo, newLocationUrl string) {
if r.FollowRedirect {
request.FollowRedirect()
return
}
// No need to let cronet_lib follow further redirect after first HTTP response
r.response.Status = info.StatusText()
r.response.StatusCode = info.StatusCode()
headerLen := info.HeaderSize()
for i := 0; i < headerLen; i++ {
header := info.HeaderAt(i)
r.response.Header.Add(header.Name(), header.Value())
}
r.response.Body = io.NopCloser(io.MultiReader())
request.Cancel()
r.readyToRead.Signal()
}
func (r *urlResponse) OnResponseStarted(self URLRequestCallback, request URLRequest, info URLResponseInfo) {
r.response.Status = info.StatusText()
r.response.StatusCode = info.StatusCode()
headerLen := info.HeaderSize()
resetContentLength := false
for i := 0; i < headerLen; i++ {
header := info.HeaderAt(i)
// Drop Content-Encoding header if body has been decompressed already
// and reset Content-Length to unknown after loop completes
if textproto.CanonicalMIMEHeaderKey(header.Name()) == "Content-Encoding" &&
slices.Contains(cronetEncodings, strings.ToLower(header.Value())) {
resetContentLength = true
continue
}
r.response.Header.Add(header.Name(), header.Value())
}
if resetContentLength {
r.response.Uncompressed = true
r.response.ContentLength = -1
r.response.Header.Del("Content-Length")
} else {
r.response.ContentLength, _ = strconv.ParseInt(r.response.Header.Get("Content-Length"), 10, 64)
}
r.response.TransferEncoding = r.response.Header.Values("Content-Transfer-Encoding")
r.response.Close = true
r.readyToRead.Signal()
}
func (r *urlResponse) OnReadCompleted(self URLRequestCallback, request URLRequest, info URLResponseInfo, buffer Buffer, bytesRead int64) {
r.access.Lock()
defer r.access.Unlock()
if bytesRead == 0 {
r.OnSucceeded(self, request, info)
return
}
select {
case <-r.cancel:
case <-r.done:
case r.read <- int(bytesRead):
r.readBuffer.Destroy()
r.readBuffer = Buffer{}
}
}
func (r *urlResponse) OnSucceeded(self URLRequestCallback, request URLRequest, info URLResponseInfo) {
r.close(request, io.EOF)
}
func (r *urlResponse) OnFailed(self URLRequestCallback, request URLRequest, info URLResponseInfo, error Error) {
r.close(request, ErrorFromError(error))
}
func (r *urlResponse) OnCanceled(self URLRequestCallback, request URLRequest, info URLResponseInfo) {
r.close(request, context.Canceled)
}
func (r *urlResponse) close(request URLRequest, err error) {
r.access.Lock()
defer r.access.Unlock()
select {
case <-r.done:
return
default:
}
if r.err == nil {
r.err = err
}
close(r.done)
r.readyToRead.Signal()
request.Destroy()
}
type bodyUploadProvider struct {
body io.ReadCloser
getBody func() (io.ReadCloser, error)
contentLength int64
}
func (p *bodyUploadProvider) Length(self UploadDataProvider) int64 {
return p.contentLength
}
func (p *bodyUploadProvider) Read(self UploadDataProvider, sink UploadDataSink, buffer Buffer) {
n, err := p.body.Read(buffer.DataSlice())
if err != nil {
if err == io.EOF {
if p.contentLength == -1 {
// Case for chunked uploads
sink.OnReadSucceeded(0, true)
} else {
sink.OnReadSucceeded(int64(n), false)
}
return
}
sink.OnReadError(err.Error())
} else {
sink.OnReadSucceeded(int64(n), false)
}
}
func (p *bodyUploadProvider) Rewind(self UploadDataProvider, sink UploadDataSink) {
if p.getBody == nil {
sink.OnRewindError("unsupported")
return
}
p.body.Close()
newBody, err := p.getBody()
if err != nil {
sink.OnRewindError(err.Error())
return
}
p.body = newBody
sink.OnRewindSucceeded()
}
func (p *bodyUploadProvider) Close(self UploadDataProvider) {
self.Destroy()
p.body.Close()
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// UploadDataProvider
// The interface allowing the embedder to provide an upload body to
// URLRequest. It supports both non-chunked (size known in advanced) and
// chunked (size not known in advance) uploads. Be aware that not all servers
// support chunked uploads.
//
// An upload is either always chunked, across multiple uploads if the data
// ends up being sent more than once, or never chunked.
type UploadDataProvider struct {
ptr C.Cronet_UploadDataProviderPtr
}
type UploadDataProviderHandler interface {
// Length
// If this is a non-chunked upload, returns the length of the upload. Must
// always return -1 if this is a chunked upload.
Length(self UploadDataProvider) int64
// Read
// Reads upload data into |buffer|. Each call of this method must be followed be a
// single call, either synchronous or asynchronous, to
// UploadDataSink.OnReadSucceeded() on success
// or UploadDataSink.OnReadError() on failure. Neither read nor rewind
// will be called until one of those methods or the other is called. Even if
// the associated UrlRequest is canceled, one or the other must
// still be called before resources can be safely freed.
//
// @param sink The object to notify when the read has completed,
// successfully or otherwise.
// @param buffer The buffer to copy the read bytes into.
Read(self UploadDataProvider, sink UploadDataSink, buffer Buffer)
// Rewind
// Rewinds upload data. Each call must be followed be a single
// call, either synchronous or asynchronous, to
// UploadDataSink.OnRewindSucceeded() on success or
// UploadDataSink.OnRewindError() on failure. Neither read nor rewind
// will be called until one of those methods or the other is called.
// Even if the associated UrlRequest is canceled, one or the other
// must still be called before resources can be safely freed.
//
// If rewinding is not supported, this should call
// UploadDataSink.OnRewindError(). Note that rewinding is required to
// follow redirects that preserve the upload body, and for retrying when the
// server times out stale sockets.
//
// @param sink The object to notify when the rewind operation has
// completed, successfully or otherwise.
Rewind(self UploadDataProvider, sink UploadDataSink)
// Close
// Called when this UploadDataProvider is no longer needed by a request, so that resources
// (like a file) can be explicitly released.
Close(self UploadDataProvider)
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
// extern int64_t cronetUploadDataProviderGetLength(Cronet_UploadDataProviderPtr self);
// extern void cronetUploadDataProviderRead(Cronet_UploadDataProviderPtr self, Cronet_UploadDataSinkPtr upload_data_sink, Cronet_BufferPtr buffer);
// extern void cronetUploadDataProviderRewind(Cronet_UploadDataProviderPtr self, Cronet_UploadDataSinkPtr upload_data_sink);
// extern void cronetUploadDataProviderClose(Cronet_UploadDataProviderPtr self);
import "C"
import (
"sync"
"unsafe"
)
func NewUploadDataProvider(handler UploadDataProviderHandler) UploadDataProvider {
ptr := C.Cronet_UploadDataProvider_CreateWith(
(*[0]byte)(C.cronetUploadDataProviderGetLength),
(*[0]byte)(C.cronetUploadDataProviderRead),
(*[0]byte)(C.cronetUploadDataProviderRewind),
(*[0]byte)(C.cronetUploadDataProviderClose),
)
uploadDataAccess.Lock()
uploadDataProviderMap[uintptr(unsafe.Pointer(ptr))] = handler
uploadDataAccess.Unlock()
return UploadDataProvider{ptr}
}
func (p UploadDataProvider) Destroy() {
C.Cronet_UploadDataProvider_Destroy(p.ptr)
uploadDataAccess.Lock()
delete(uploadDataProviderMap, uintptr(unsafe.Pointer(p.ptr)))
uploadDataAccess.Unlock()
}
var (
uploadDataAccess sync.RWMutex
uploadDataProviderMap map[uintptr]UploadDataProviderHandler
)
func init() {
uploadDataProviderMap = make(map[uintptr]UploadDataProviderHandler)
}
func instanceOfUploadDataProvider(self C.Cronet_UploadDataProviderPtr) UploadDataProviderHandler {
uploadDataAccess.RLock()
defer uploadDataAccess.RUnlock()
provider := uploadDataProviderMap[uintptr(unsafe.Pointer(self))]
if provider == nil {
panic("nil data provider")
}
return provider
}
//export cronetUploadDataProviderGetLength
func cronetUploadDataProviderGetLength(self C.Cronet_UploadDataProviderPtr) C.int64_t {
return C.int64_t(instanceOfUploadDataProvider(self).Length(UploadDataProvider{self}))
}
//export cronetUploadDataProviderRead
func cronetUploadDataProviderRead(self C.Cronet_UploadDataProviderPtr, sink C.Cronet_UploadDataSinkPtr, buffer C.Cronet_BufferPtr) {
instanceOfUploadDataProvider(self).Read(UploadDataProvider{self}, UploadDataSink{sink}, Buffer{buffer})
}
//export cronetUploadDataProviderRewind
func cronetUploadDataProviderRewind(self C.Cronet_UploadDataProviderPtr, sink C.Cronet_UploadDataSinkPtr) {
instanceOfUploadDataProvider(self).Rewind(UploadDataProvider{self}, UploadDataSink{sink})
}
//export cronetUploadDataProviderClose
func cronetUploadDataProviderClose(self C.Cronet_UploadDataProviderPtr) {
instanceOfUploadDataProvider(self).Close(UploadDataProvider{self})
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import "unsafe"
// UploadDataSink
//
// Defines callbacks methods for UploadDataProvider. All methods
// may be called synchronously or asynchronously, on any thread.
type UploadDataSink struct {
ptr C.Cronet_UploadDataSinkPtr
}
// OnReadSucceeded
//
// Called by UploadDataProviderHandler when a read succeeds.
//
// @param bytesRead number of bytes read into buffer passed to UploadDataProviderHandler.Read().
// @param finalChunk For chunked uploads, |true| if this is the final
//
// read. It must be |false| for non-chunked uploads.
func (s UploadDataSink) OnReadSucceeded(bytesRead int64, finalChunk bool) {
C.Cronet_UploadDataSink_OnReadSucceeded(s.ptr, C.uint64_t(bytesRead), C.bool(finalChunk))
}
// OnReadError
// Called by UploadDataProviderHandler when a read fails.
// @param message to pass on to URLRequestCallbackHandler.OnFailed().
func (s UploadDataSink) OnReadError(message string) {
cMessage := C.CString(message)
C.Cronet_UploadDataSink_OnReadError(s.ptr, cMessage)
C.free(unsafe.Pointer(cMessage))
}
// OnRewindSucceeded
// Called by UploadDataProviderHandler when a rewind succeeds.
func (s UploadDataSink) OnRewindSucceeded() {
C.Cronet_UploadDataSink_OnRewindSucceeded(s.ptr)
}
// OnRewindError
// Called by UploadDataProviderHandler when a rewind fails, or if rewinding
// uploads is not supported.
// * @param message to pass on to URLRequestCallbackHandler.OnFailed().
func (s UploadDataSink) OnRewindError(message string) {
cMessage := C.CString(message)
C.Cronet_UploadDataSink_OnRewindError(s.ptr, cMessage)
C.free(unsafe.Pointer(cMessage))
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import "unsafe"
// URLRequest
// Controls an HTTP request (GET, PUT, POST etc).
// Initialized by InitWithParams().
// Note: All methods must be called on the Executor passed to InitWithParams().
type URLRequest struct {
ptr C.Cronet_UrlRequestPtr
}
func NewURLRequest() URLRequest {
return URLRequest{C.Cronet_UrlRequest_Create()}
}
func (r URLRequest) Destroy() {
C.Cronet_UrlRequest_Destroy(r.ptr)
}
// InitWithParams
// Initialized URLRequest to |url| with |params|. All methods of |callback| for
// request will be invoked on |executor|. The |executor| must not run tasks on
// the thread calling Executor.Execute() to prevent blocking networking
// operations and causing failure RESULTs during shutdown.
//
// @param engine Engine to process the request.
// @param url URL for the request.
// @param params additional parameters for the request, like headers and priority.
// @param callback Callback that gets invoked on different events.
// @param executor Executor on which all callbacks will be invoked.
func (r URLRequest) InitWithParams(engine Engine, url string, params URLRequestParams, callback URLRequestCallback, executor Executor) Result {
cURL := C.CString(url)
defer C.free(unsafe.Pointer(cURL))
return Result(C.Cronet_UrlRequest_InitWithParams(r.ptr, engine.ptr, cURL, params.ptr, callback.ptr, executor.ptr))
}
// Start starts the request, all callbacks go to URLRequestCallbackHandler. May only be called
// once. May not be called if Cancel() has been called.
func (r URLRequest) Start() Result {
return Result(C.Cronet_UrlRequest_Start(r.ptr))
}
// FollowRedirect
// Follows a pending redirect. Must only be called at most once for each
// invocation of URLRequestCallbackHandler.OnRedirectReceived().
func (r URLRequest) FollowRedirect() Result {
return Result(C.Cronet_UrlRequest_FollowRedirect(r.ptr))
}
// Read
// Attempts to read part of the response body into the provided buffer.
// Must only be called at most once in response to each invocation of the
// URLRequestCallbackHandler.OnResponseStarted() and
// URLRequestCallbackHandler.OnReadCompleted()} methods of the URLRequestCallbackHandler.
// Each call will result in an asynchronous call to
// either the URLRequestCallbackHandler.OnReadCompleted() method if data
// is read, its URLRequestCallbackHandler.OnSucceeded() method if
// there's no more data to read, or its URLRequestCallbackHandler.OnFailed()
// method if there's an error.
// This method transfers ownership of |buffer| to Cronet, and app should
// not access it until one of these callbacks is invoked.
//
// @param buffer to write response body to. The app must not read or
//
// modify buffer's position, limit, or data between its position and
// limit until the request calls back into the URLRequestCallbackHandler.
func (r URLRequest) Read(buffer Buffer) Result {
return Result(C.Cronet_UrlRequest_Read(r.ptr, buffer.ptr))
}
// Cancel
// cancels the request. Can be called at any time.
// URLRequestCallbackHandler.OnCanceled() will be invoked when cancellation
// is complete and no further callback methods will be invoked. If the
// request has completed or has not started, calling Cancel() has no
// effect and URLRequestCallbackHandler.OnCanceled() will not be invoked. If the
// Executor passed in to UrlRequest.InitWithParams() runs
// tasks on a single thread, and Cancel() is called on that thread,
// no callback methods (besides URLRequestCallbackHandler.OnCanceled() will be invoked after
// Cancel() is called. Otherwise, at most one callback method may be
// invoked after Cancel() has completed.
func (r URLRequest) Cancel() {
C.Cronet_UrlRequest_Cancel(r.ptr)
}
// IsDone
// Returns true if the request was successfully started and is now
// finished (completed, canceled, or failed).
func (r URLRequest) IsDone() bool {
return bool(C.Cronet_UrlRequest_IsDone(r.ptr))
}
// GetStatus
// Queries the status of the request.
// @param listener a URLRequestStatusListener that will be invoked with
//
// the request's current status. Listener will be invoked
// back on the Executor passed in when the request was
// created.
func (r URLRequest) GetStatus(listener URLRequestStatusListener) {
C.Cronet_UrlRequest_GetStatus(r.ptr, listener.ptr)
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// URLRequestCallback
// Users of Cronet implement this interface to receive callbacks indicating the
// progress of a URLRequest being processed. An instance of this interface
// is passed in to URLRequest.InitWithParams().
//
// Note: All methods will be invoked on the Executor passed to URLRequest.InitWithParams();
type URLRequestCallback struct {
ptr C.Cronet_UrlRequestCallbackPtr
}
type URLRequestCallbackHandler interface {
// OnRedirectReceived
// Invoked whenever a redirect is encountered. This will only be invoked
// between the call to URLRequest.Start() and
// URLRequestCallbackHandler.OnResponseStarted().
// The body of the redirect response, if it has one, will be ignored.
//
// The redirect will not be followed until the URLRequest.FollowRedirect()
// method is called, either synchronously or asynchronously.
//
// @param request Request being redirected.
// @param info Response information.
// @param newLocationUrl Location where request is redirected.
OnRedirectReceived(self URLRequestCallback, request URLRequest, info URLResponseInfo, newLocationUrl string)
// OnResponseStarted
// Invoked when the final set of headers, after all redirects, is received.
// Will only be invoked once for each request.
//
// With the exception of URLRequestCallbackHandler.OnCanceled(),
// no other URLRequestCallbackHandler method will be invoked for the request,
// including URLRequestCallbackHandler.OnSucceeded() and
// URLRequestCallbackHandler.OnFailed(), until URLRequest.Read() is called to attempt
// to start reading the response body.
//
// @param request Request that started to get response.
// @param info Response information.
OnResponseStarted(self URLRequestCallback, request URLRequest, info URLResponseInfo)
// OnReadCompleted
// Invoked whenever part of the response body has been read. Only part of
// the buffer may be populated, even if the entire response body has not yet
// been consumed. This callback transfers ownership of |buffer| back to the app,
// and Cronet guarantees not to access it.
//
// With the exception of URLRequestCallbackHandler.OnCanceled(),
// no other URLRequestCallbackHandler method will be invoked for the request,
// including URLRequestCallbackHandler.OnSucceeded() and
// URLRequestCallbackHandler.OnFailed(), until URLRequest.Read() is called to attempt
// to continue reading the response body.
//
// @param request Request that received data.
// @param info Response information.
// @param buffer The buffer that was passed in to URLRequest.Read(), now
// containing the received data.
// @param bytesRead The number of bytes read into buffer.
OnReadCompleted(self URLRequestCallback, request URLRequest, info URLResponseInfo, buffer Buffer, bytesRead int64)
// OnSucceeded
// Invoked when request is completed successfully. Once invoked, no other
// URLRequestCallbackHandler methods will be invoked.
//
// Implementations of OnSucceeded() are allowed to call
// URLRequest.Destroy(), but note that destroying request destroys info.
//
// @param request Request that succeeded.
// @param info Response information. NOTE: this is owned by request.
OnSucceeded(self URLRequestCallback, request URLRequest, info URLResponseInfo)
// OnFailed
// Invoked if request failed for any reason after URLRequest.Start().
// Once invoked, no other URLRequestCallbackHandler methods will be invoked.
// |error| provides information about the failure.
//
// Implementations of URLRequestCallbackHandler.OnFailed are allowed to call
// URLRequest.Destroy(), but note that destroying request destroys info and error.
//
// @param request Request that failed.
// @param info Response information. May be null if no response was
// received. NOTE: this is owned by request.
// @param error information about error. NOTE: this is owned by request
OnFailed(self URLRequestCallback, request URLRequest, info URLResponseInfo, error Error)
// OnCanceled
// Invoked if request was canceled via URLRequest.Cancel(). Once
// invoked, no other UrlRequestCallback methods will be invoked.
//
// Implementations of URLRequestCallbackHandler.OnCanceled are allowed to call
// URLRequest.Destroy(), but note that destroying request destroys info and error.
//
// @param request Request that was canceled.
// @param info Response information. May be null if no response was
// received. NOTE: this is owned by request.
OnCanceled(self URLRequestCallback, request URLRequest, info URLResponseInfo)
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
// extern void cronetURLRequestCallbackOnRedirectReceived(Cronet_UrlRequestCallbackPtr self, Cronet_UrlRequestPtr request, Cronet_UrlResponseInfoPtr info, Cronet_String new_location_url);
// extern void cronetURLRequestCallbackOnResponseStarted(Cronet_UrlRequestCallbackPtr self, Cronet_UrlRequestPtr request, Cronet_UrlResponseInfoPtr info);
// extern void cronetURLRequestCallbackOnReadCompleted(Cronet_UrlRequestCallbackPtr self, Cronet_UrlRequestPtr request, Cronet_UrlResponseInfoPtr info, Cronet_BufferPtr buffer, uint64_t bytes_read);
// extern void cronetURLRequestCallbackOnSucceeded(Cronet_UrlRequestCallbackPtr self, Cronet_UrlRequestPtr request, Cronet_UrlResponseInfoPtr info);
// extern void cronetURLRequestCallbackOnFailed(Cronet_UrlRequestCallbackPtr self, Cronet_UrlRequestPtr request, Cronet_UrlResponseInfoPtr info, Cronet_ErrorPtr error);
// extern void cronetURLRequestCallbackOnCanceled(Cronet_UrlRequestCallbackPtr self, Cronet_UrlRequestPtr request, Cronet_UrlResponseInfoPtr info);
import "C"
import (
"sync"
"unsafe"
)
func NewURLRequestCallback(handler URLRequestCallbackHandler) URLRequestCallback {
ptr := C.Cronet_UrlRequestCallback_CreateWith(
(*[0]byte)(C.cronetURLRequestCallbackOnRedirectReceived),
(*[0]byte)(C.cronetURLRequestCallbackOnResponseStarted),
(*[0]byte)(C.cronetURLRequestCallbackOnReadCompleted),
(*[0]byte)(C.cronetURLRequestCallbackOnSucceeded),
(*[0]byte)(C.cronetURLRequestCallbackOnFailed),
(*[0]byte)(C.cronetURLRequestCallbackOnCanceled),
)
urlRequestCallbackAccess.Lock()
urlRequestCallbackMap[uintptr(unsafe.Pointer(ptr))] = handler
urlRequestCallbackAccess.Unlock()
return URLRequestCallback{ptr}
}
func (l URLRequestCallback) Destroy() {
C.Cronet_UrlRequestCallback_Destroy(l.ptr)
urlRequestCallbackAccess.Lock()
delete(urlRequestCallbackMap, uintptr(unsafe.Pointer(l.ptr)))
urlRequestCallbackAccess.RUnlock()
}
var (
urlRequestCallbackAccess sync.RWMutex
urlRequestCallbackMap map[uintptr]URLRequestCallbackHandler
)
func init() {
urlRequestCallbackMap = make(map[uintptr]URLRequestCallbackHandler)
}
func instanceOfURLRequestCallback(self C.Cronet_UrlRequestCallbackPtr) URLRequestCallbackHandler {
urlRequestCallbackAccess.RLock()
defer urlRequestCallbackAccess.RUnlock()
callback := urlRequestCallbackMap[uintptr(unsafe.Pointer(self))]
if callback == nil {
panic("nil url request callback")
}
return callback
}
//export cronetURLRequestCallbackOnRedirectReceived
func cronetURLRequestCallbackOnRedirectReceived(self C.Cronet_UrlRequestCallbackPtr, request C.Cronet_UrlRequestPtr, info C.Cronet_UrlResponseInfoPtr, newLocationUrl C.Cronet_String) {
instanceOfURLRequestCallback(self).OnRedirectReceived(URLRequestCallback{self}, URLRequest{request}, URLResponseInfo{info}, C.GoString(newLocationUrl))
}
//export cronetURLRequestCallbackOnResponseStarted
func cronetURLRequestCallbackOnResponseStarted(self C.Cronet_UrlRequestCallbackPtr, request C.Cronet_UrlRequestPtr, info C.Cronet_UrlResponseInfoPtr) {
instanceOfURLRequestCallback(self).OnResponseStarted(URLRequestCallback{self}, URLRequest{request}, URLResponseInfo{info})
}
//export cronetURLRequestCallbackOnReadCompleted
func cronetURLRequestCallbackOnReadCompleted(self C.Cronet_UrlRequestCallbackPtr, request C.Cronet_UrlRequestPtr, info C.Cronet_UrlResponseInfoPtr, buffer C.Cronet_BufferPtr, bytesRead C.uint64_t) {
instanceOfURLRequestCallback(self).OnReadCompleted(URLRequestCallback{self}, URLRequest{request}, URLResponseInfo{info}, Buffer{buffer}, int64(bytesRead))
}
//export cronetURLRequestCallbackOnSucceeded
func cronetURLRequestCallbackOnSucceeded(self C.Cronet_UrlRequestCallbackPtr, request C.Cronet_UrlRequestPtr, info C.Cronet_UrlResponseInfoPtr) {
instanceOfURLRequestCallback(self).OnSucceeded(URLRequestCallback{self}, URLRequest{request}, URLResponseInfo{info})
}
//export cronetURLRequestCallbackOnFailed
func cronetURLRequestCallbackOnFailed(self C.Cronet_UrlRequestCallbackPtr, request C.Cronet_UrlRequestPtr, info C.Cronet_UrlResponseInfoPtr, error C.Cronet_ErrorPtr) {
instanceOfURLRequestCallback(self).OnFailed(URLRequestCallback{self}, URLRequest{request}, URLResponseInfo{info}, Error{error})
}
//export cronetURLRequestCallbackOnCanceled
func cronetURLRequestCallbackOnCanceled(self C.Cronet_UrlRequestCallbackPtr, request C.Cronet_UrlRequestPtr, info C.Cronet_UrlResponseInfoPtr) {
instanceOfURLRequestCallback(self).OnCanceled(URLRequestCallback{self}, URLRequest{request}, URLResponseInfo{info})
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import "unsafe"
// URLRequestFinishedInfo
// Information about a finished request.
type URLRequestFinishedInfo struct {
ptr C.Cronet_RequestFinishedInfoPtr
}
func (i URLRequestFinishedInfo) Destroy() {
C.Cronet_RequestFinishedInfo_Destroy(i.ptr)
}
// URLRequestFinishedInfoFinishedReason
// The reason why the request finished.
type URLRequestFinishedInfoFinishedReason int
const (
// URLRequestFinishedInfoFinishedReasonSucceeded
// The request succeeded.
URLRequestFinishedInfoFinishedReasonSucceeded URLRequestFinishedInfoFinishedReason = 0
// URLRequestFinishedInfoFinishedReasonFailed
// The request failed or returned an error.
URLRequestFinishedInfoFinishedReasonFailed URLRequestFinishedInfoFinishedReason = 1
// URLRequestFinishedInfoFinishedReasonCanceled
// The request was canceled.
URLRequestFinishedInfoFinishedReasonCanceled URLRequestFinishedInfoFinishedReason = 2
)
// Metrics
// Metrics collected for this request.
func (i URLRequestFinishedInfo) Metrics() Metrics {
return Metrics{C.Cronet_RequestFinishedInfo_metrics_get(i.ptr)}
}
// AnnotationSize
// The objects that the caller has supplied when initiating the request,
// using URLRequestParams.AddAnnotation
//
// Annotations can be used to associate a RequestFinishedInfo with
// the original request or type of request.
func (i URLRequestFinishedInfo) AnnotationSize() int {
return int(C.Cronet_RequestFinishedInfo_annotations_size(i.ptr))
}
func (i URLRequestFinishedInfo) AnnotationAt(index int) unsafe.Pointer {
return unsafe.Pointer(C.Cronet_RequestFinishedInfo_annotations_at(i.ptr, C.uint32_t(index)))
}
// FinishedReason
// Returns the reason why the request finished.
func (i URLRequestFinishedInfo) FinishedReason() URLRequestFinishedInfoFinishedReason {
return URLRequestFinishedInfoFinishedReason(C.Cronet_RequestFinishedInfo_finished_reason_get(i.ptr))
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
// extern void cronetURLRequestFinishedInfoListenerOnRequestFinished(Cronet_RequestFinishedInfoListenerPtr self, Cronet_RequestFinishedInfoPtr request_info, Cronet_UrlResponseInfoPtr response_info, Cronet_ErrorPtr error);
import "C"
import (
"sync"
"unsafe"
)
func NewURLRequestFinishedInfoListener(finishedFunc URLRequestFinishedInfoListenerOnRequestFinishedFunc) URLRequestFinishedInfoListener {
ptr := C.Cronet_RequestFinishedInfoListener_CreateWith((*[0]byte)(C.cronetURLRequestFinishedInfoListenerOnRequestFinished))
urlRequestFinishedInfoListenerAccess.Lock()
urlRequestFinishedInfoListenerMap[uintptr(unsafe.Pointer(ptr))] = finishedFunc
urlRequestFinishedInfoListenerAccess.Unlock()
return URLRequestFinishedInfoListener{ptr}
}
func (l URLRequestFinishedInfoListener) Destroy() {
C.Cronet_RequestFinishedInfoListener_Destroy(l.ptr)
}
var (
urlRequestFinishedInfoListenerAccess sync.RWMutex
urlRequestFinishedInfoListenerMap map[uintptr]URLRequestFinishedInfoListenerOnRequestFinishedFunc
)
func init() {
urlRequestFinishedInfoListenerMap = make(map[uintptr]URLRequestFinishedInfoListenerOnRequestFinishedFunc)
}
//export cronetURLRequestFinishedInfoListenerOnRequestFinished
func cronetURLRequestFinishedInfoListenerOnRequestFinished(self C.Cronet_RequestFinishedInfoListenerPtr, requestInfo C.Cronet_RequestFinishedInfoPtr, responseInfo C.Cronet_UrlResponseInfoPtr, error C.Cronet_ErrorPtr) {
urlRequestFinishedInfoListenerAccess.RLock()
listener := urlRequestFinishedInfoListenerMap[uintptr(unsafe.Pointer(self))]
urlRequestFinishedInfoListenerAccess.RUnlock()
if listener == nil {
panic("nil url request finished info listener")
}
listener(URLRequestFinishedInfoListener{self}, URLRequestFinishedInfo{requestInfo}, URLResponseInfo{responseInfo}, Error{error})
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// URLRequestFinishedInfoListener
// Listens for finished requests for the purpose of collecting metrics.
type URLRequestFinishedInfoListener struct {
ptr C.Cronet_RequestFinishedInfoListenerPtr
}
// URLRequestFinishedInfoListenerOnRequestFinishedFunc
// Will be called in a task submitted to the Executor passed with
// this URLRequestFinishedInfoListener.
//
// The listener is called before URLRequestCallbackHandler.OnCanceled(),
// URLRequestCallbackHandler.OnFailed() or
// URLRequestCallbackHandler.OnSucceeded() is called -- note that if the executor
// runs the listener asyncronously, the actual call to the listener may
// happen after a URLRequestCallbackHandler method is called.
//
// @param request_info RequestFinishedInfo for finished request.
//
// Ownership is *not* transferred by this call, do not destroy
// request_info.
//
// URLRequest
// that created it hasn't been destroyed -- **additionally**, it will
// also always be valid for the duration of URLRequestFinishedInfoListenerOnRequestFinishedFunc(),
// even if the URLRequest has been destroyed.
//
// This is accomplished by ownership being shared between the
// URLRequest and the code that calls this listener.
//
// @param responseInfo A pointer to the same UrlResponseInfo passed to
//
// URLRequestCallbackHandler.OnCanceled(), {@link
// URLRequestCallbackHandler.OnFailed()} or {@link
// URLRequestCallbackHandler.OnSucceeded()}. The lifetime and ownership of
// requestInfo.
//
// @param error A pointer to the same Error passed to
//
// URLRequestCallbackHandler.OnFailed(), or null if there was no error.
// The lifetime and ownership of error works the same as for
// requestInfo.
//
// /
type URLRequestFinishedInfoListenerOnRequestFinishedFunc func(listener URLRequestFinishedInfoListener, requestInfo URLRequestFinishedInfo, responseInfo URLResponseInfo, error Error)
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
import "unsafe"
type URLRequestParamsRequestPriority int
const (
// URLRequestParamsRequestPriorityIdle
// Lowest request priority.
URLRequestParamsRequestPriorityIdle URLRequestParamsRequestPriority = 0
// URLRequestParamsRequestPriorityLowest
// Very low request priority.
URLRequestParamsRequestPriorityLowest URLRequestParamsRequestPriority = 1
// URLRequestParamsRequestPriorityLow
// Low request priority.
URLRequestParamsRequestPriorityLow URLRequestParamsRequestPriority = 2
// URLRequestParamsRequestPriorityMedium
// Medium request priority. This is the default priority given to the request.
URLRequestParamsRequestPriorityMedium URLRequestParamsRequestPriority = 3
// URLRequestParamsRequestPriorityHighest
// Highest request priority.
URLRequestParamsRequestPriorityHighest URLRequestParamsRequestPriority = 4
)
// URLRequestParams
// Parameters for UrlRequest. Allows configuring requests before initializing them
// with URLRequest.InitWithParams().
type URLRequestParams struct {
ptr C.Cronet_UrlRequestParamsPtr
}
func NewURLRequestParams() URLRequestParams {
return URLRequestParams{C.Cronet_UrlRequestParams_Create()}
}
func (p URLRequestParams) Destroy() {
C.Cronet_UrlRequestParams_Destroy(p.ptr)
}
// SetMethod
// The HTTP method verb to use for this request.
//
// The default when this value is not set is "GET" if the request has
// no body or "POST" if it does.
//
// Allowed methods are "GET", "HEAD", "DELETE", "POST", "PUT" and "CONNECT".
func (p URLRequestParams) SetMethod(method string) {
cMethod := C.CString(method)
C.Cronet_UrlRequestParams_http_method_set(p.ptr, cMethod)
C.free(unsafe.Pointer(cMethod))
}
func (p URLRequestParams) Method() string {
return C.GoString(C.Cronet_UrlRequestParams_http_method_get(p.ptr))
}
// AddHeader
// Add HTTP header for this request
func (p URLRequestParams) AddHeader(header HTTPHeader) {
C.Cronet_UrlRequestParams_request_headers_add(p.ptr, header.ptr)
}
func (p URLRequestParams) HeaderSize() int {
return int(C.Cronet_UrlRequestParams_request_headers_size(p.ptr))
}
func (p URLRequestParams) HeaderAt(index int) HTTPHeader {
return HTTPHeader{C.Cronet_UrlRequestParams_request_headers_at(p.ptr, C.uint32_t(index))}
}
func (p URLRequestParams) ClearHeaders() {
C.Cronet_UrlRequestParams_request_headers_clear(p.ptr)
}
// SetDisableCache
// Disables cache for the request. If context is not set up to use cache,
// this call has no effect.
func (p URLRequestParams) SetDisableCache(disable bool) {
C.Cronet_UrlRequestParams_disable_cache_set(p.ptr, C.bool(disable))
}
func (p URLRequestParams) DisableCache() bool {
return bool(C.Cronet_UrlRequestParams_disable_cache_get(p.ptr))
}
// SetPriority
// Priority of the request which should be one of the URLRequestParamsRequestPriority values.
func (p URLRequestParams) SetPriority(priority URLRequestParamsRequestPriority) {
C.Cronet_UrlRequestParams_priority_set(p.ptr, C.Cronet_UrlRequestParams_REQUEST_PRIORITY(priority))
}
func (p URLRequestParams) Priority() URLRequestParamsRequestPriority {
return URLRequestParamsRequestPriority(C.Cronet_UrlRequestParams_priority_get(p.ptr))
}
// SetUploadDataProvider
// Upload data provider. Setting this value switches method to "POST" if not
// explicitly set. Starting the request will fail if a Content-Type header is not set.
func (p URLRequestParams) SetUploadDataProvider(provider UploadDataProvider) {
C.Cronet_UrlRequestParams_upload_data_provider_set(p.ptr, provider.ptr)
}
func (p URLRequestParams) UploadDataProvider() UploadDataProvider {
return UploadDataProvider{C.Cronet_UrlRequestParams_upload_data_provider_get(p.ptr)}
}
// SetUploadDataExecutor
// Upload data provider executor that will be used to invoke uploadDataProvider.
func (p URLRequestParams) SetUploadDataExecutor(executor Executor) {
C.Cronet_UrlRequestParams_upload_data_provider_executor_set(p.ptr, executor.ptr)
}
func (p URLRequestParams) UploadDataExecutor() Executor {
return Executor{C.Cronet_UrlRequestParams_upload_data_provider_executor_get(p.ptr)}
}
// SetAllowDirectExecutor
// Marks that the executors this request will use to notify callbacks (for
// UploadDataProvider and URLRequestCallback) is intentionally performing
// inline execution without switching to another thread.
//
// <p><b>Warning:</b> This option makes it easy to accidentally block the network thread.
// It should not be used if your callbacks perform disk I/O, acquire locks, or call into
// other code you don't carefully control and audit.
func (p URLRequestParams) SetAllowDirectExecutor(allow bool) {
C.Cronet_UrlRequestParams_allow_direct_executor_set(p.ptr, C.bool(allow))
}
func (p URLRequestParams) AllocDirectExecutor() bool {
return bool(C.Cronet_UrlRequestParams_allow_direct_executor_get(p.ptr))
}
// AddAnnotation
// Associates the annotation object with this request. May add more than one.
// Passed through to a RequestFinishedInfoListener.
func (p URLRequestParams) AddAnnotation(annotation unsafe.Pointer) {
C.Cronet_UrlRequestParams_annotations_add(p.ptr, C.Cronet_RawDataPtr(annotation))
}
func (p URLRequestParams) AnnotationSize() int {
return int(C.Cronet_UrlRequestParams_annotations_size(p.ptr))
}
func (p URLRequestParams) AnnotationAt(index int) unsafe.Pointer {
return unsafe.Pointer(C.Cronet_UrlRequestParams_annotations_at(p.ptr, C.uint32_t(index)))
}
func (p URLRequestParams) ClearAnnotations() {
C.Cronet_UrlRequestParams_annotations_clear(p.ptr)
}
// SetRequestFinishedListener
// A listener that gets invoked at the end of each request.
//
// The listener is invoked with the request finished info on RequestFinishedExecutor, which must be set.
//
// The listener is called before URLRequestCallbackHandler.OnCanceled(),
// URLRequestCallbackHandler.OnFailed() or
// URLRequestCallbackHandler.OnSucceeded() is called -- note that if
// RequestFinishedListener runs the listener asynchronously, the actual
// call to the listener may happen after a {@code URLRequestCallbackHandler} method
// is called.
//
// Ownership is **not** taken.
//
// Assuming the listener won't run again (there are no pending requests with
// the listener attached, either via Engine or @code URLRequest),
// the app may destroy it once its URLRequestFinishedInfoListenerOnRequestFinishedFunc has started,
// even inside that method.
func (p URLRequestParams) SetRequestFinishedListener(listener URLRequestFinishedInfoListener) {
C.Cronet_UrlRequestParams_request_finished_listener_set(p.ptr, listener.ptr)
}
func (p URLRequestParams) RequestFinishedListener() URLRequestFinishedInfoListener {
return URLRequestFinishedInfoListener{C.Cronet_UrlRequestParams_request_finished_listener_get(p.ptr)}
}
// SetRequestFinishedExecutor
// The Executor used to run the RequestFinishedListener.
//
// Ownership is **not** taken.
//
// # Similar to RequestFinishedListener, the app may destroy RequestFinishedExecutor in or after URLRequestFinishedInfoListenerOnRequestFinishedFunc
//
// It's also OK to destroy RequestFinishedExecutor in or after one
// of {@link URLRequestCallbackHandler.OnCanceled()}, {@link
// URLRequestCallbackHandler.OnFailed()} or {@link
// URLRequestCallbackHandler.OnSucceeded()}.
//
// Of course, both of these are only true if {@code
// request_finished_executor} isn't being used for anything else that might
// start running in the future.
func (p URLRequestParams) SetRequestFinishedExecutor(executor Executor) {
C.Cronet_UrlRequestParams_request_finished_executor_set(p.ptr, executor.ptr)
}
func (p URLRequestParams) RequestFinishedExecutor() Executor {
return Executor{C.Cronet_UrlRequestParams_request_finished_executor_get(p.ptr)}
}
type URLRequestParamsIdempotency int
const (
URLRequestParamsIdempotencyDefaultIdempotency URLRequestParamsIdempotency = 0
URLRequestParamsIdempotencyIdempotent URLRequestParamsIdempotency = 1
URLRequestParamsIdempotencyNotIdempotent URLRequestParamsIdempotency = 2
)
// SetIdempotency
// Idempotency of the request, which determines that if it is safe to enable
// 0-RTT for the Cronet request. By default, 0-RTT is only enabled for safe
// HTTP methods, i.e., GET, HEAD, OPTIONS, and TRACE. For other methods,
// enabling 0-RTT may cause security issues since a network observer can
// replay the request. If the request has any side effects, those effects can
// happen multiple times. It is only safe to enable the 0-RTT if it is known
// that the request is idempotent.
func (p URLRequestParams) SetIdempotency(idempotency URLRequestParamsIdempotency) {
C.Cronet_UrlRequestParams_idempotency_set(p.ptr, C.Cronet_UrlRequestParams_IDEMPOTENCY(idempotency))
}
func (p URLRequestParams) Idempotency() URLRequestParamsIdempotency {
return URLRequestParamsIdempotency(C.Cronet_UrlRequestParams_idempotency_get(p.ptr))
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
// URLRequestStatusListener listener class used with URLRequest.GetStatus() to receive the status of a
// URLRequest.
type URLRequestStatusListener struct {
ptr C.Cronet_UrlRequestStatusListenerPtr
}
// URLRequestStatusListenerOnStatusFunc invoked on UrlRequest's Executor when request status is obtained.
// |status| is representing the status of the request.
type URLRequestStatusListenerOnStatusFunc func(self URLRequestStatusListener, status URLRequestStatusListenerStatus)
type URLRequestStatusListenerStatus int
const (
// URLRequestStatusListenerStatusInvalid
// This state indicates that the request is completed, canceled, or is not
// started.
URLRequestStatusListenerStatusInvalid URLRequestStatusListenerStatus = -1
// URLRequestStatusListenerStatusIdle
// This state corresponds to a resource load that has either not yet begun
// or is idle waiting for the consumer to do something to move things along
// (e.g. when the consumer of a URLRequest has not called
// URLRequest.read() yet).
URLRequestStatusListenerStatusIdle URLRequestStatusListenerStatus = 0
// URLRequestStatusListenerStatusWaitingForStalledSocketPool
// When a socket pool group is below the maximum number of sockets allowed
// per group, but a new socket cannot be created due to the per-pool socket
// limit, this state is returned by all requests for the group waiting on an
// idle connection, except those that may be serviced by a pending new
// connection.
URLRequestStatusListenerStatusWaitingForStalledSocketPool URLRequestStatusListenerStatus = 1
// URLRequestStatusListenerStatusWaitingForAvailableSocket
// When a socket pool group has reached the maximum number of sockets
// allowed per group, this state is returned for all requests that don't
// have a socket, except those that correspond to a pending new connection.
URLRequestStatusListenerStatusWaitingForAvailableSocket URLRequestStatusListenerStatus = 2
// URLRequestStatusListenerStatusWaitingForDelegate
// This state indicates that the URLRequest delegate has chosen to block
// this request before it was sent over the network.
URLRequestStatusListenerStatusWaitingForDelegate URLRequestStatusListenerStatus = 3
// URLRequestStatusListenerStatusWaitingForCache
// This state corresponds to a resource load that is blocked waiting for
// access to a resource in the cache. If multiple requests are made for the
// same resource, the first request will be responsible for writing (or
// updating) the cache entry and the second request will be deferred until
// the first completes. This may be done to optimize for cache reuse.
URLRequestStatusListenerStatusWaitingForCache URLRequestStatusListenerStatus = 4
// URLRequestStatusListenerStatusDownloadingPacFile
// This state corresponds to a resource being blocked waiting for the
// PAC script to be downloaded.
URLRequestStatusListenerStatusDownloadingPacFile URLRequestStatusListenerStatus = 5
// URLRequestStatusListenerStatusResolvingProxyForUrl
// This state corresponds to a resource load that is blocked waiting for a
// proxy autoconfig script to return a proxy server to use.
URLRequestStatusListenerStatusResolvingProxyForUrl URLRequestStatusListenerStatus = 6
// URLRequestStatusListenerStatusResolvingHostInPacFile
// This state corresponds to a resource load that is blocked waiting for a
// proxy autoconfig script to return a proxy server to use, but that proxy
// script is busy resolving the IP address of a host.
URLRequestStatusListenerStatusResolvingHostInPacFile URLRequestStatusListenerStatus = 7
// URLRequestStatusListenerStatusEstablishingProxyTunnel
// This state indicates that we're in the process of establishing a tunnel
// through the proxy server.
URLRequestStatusListenerStatusEstablishingProxyTunnel URLRequestStatusListenerStatus = 8
// URLRequestStatusListenerStatusResolvingHost
// This state corresponds to a resource load that is blocked waiting for a
// host name to be resolved. This could either indicate resolution of the
// origin server corresponding to the resource or to the host name of a
// proxy server used to fetch the resource.
URLRequestStatusListenerStatusResolvingHost URLRequestStatusListenerStatus = 9
// URLRequestStatusListenerStatusConnecting
// This state corresponds to a resource load that is blocked waiting for a
// TCP connection (or other network connection) to be established. HTTP
// requests that reuse a keep-alive connection skip this state.
URLRequestStatusListenerStatusConnecting URLRequestStatusListenerStatus = 10
// URLRequestStatusListenerStatusSslHandshake
// This state corresponds to a resource load that is blocked waiting for the
// SSL handshake to complete.
URLRequestStatusListenerStatusSslHandshake URLRequestStatusListenerStatus = 11
// URLRequestStatusListenerStatusSendingRequest
// This state corresponds to a resource load that is blocked waiting to
// completely upload a request to a server. In the case of a HTTP POST
// request, this state includes the period of time during which the message
// body is being uploaded.
URLRequestStatusListenerStatusSendingRequest URLRequestStatusListenerStatus = 12
// URLRequestStatusListenerStatusWaitingForResponse
// This state corresponds to a resource load that is blocked waiting for the
// response to a network request. In the case of a HTTP transaction, this
// corresponds to the period after the request is sent and before all of the
// response headers have been received.
URLRequestStatusListenerStatusWaitingForResponse URLRequestStatusListenerStatus = 13
// URLRequestStatusListenerStatusReadingResponse
// This state corresponds to a resource load that is blocked waiting for a
// read to complete. In the case of a HTTP transaction, this corresponds to
// the period after the response headers have been received and before all
// of the response body has been downloaded. (NOTE: This state only applies
// for an URLRequest while there is an outstanding
// URLRequest.Read() operation.)
URLRequestStatusListenerStatusReadingResponse URLRequestStatusListenerStatus = 14
)
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
// extern void cronetURLRequestStatusListenerOnStatus(Cronet_UrlRequestStatusListenerPtr self, Cronet_UrlRequestStatusListener_Status status);
import "C"
import (
"sync"
"unsafe"
)
func NewURLRequestStatusListener(onStatusFunc URLRequestStatusListenerOnStatusFunc) URLRequestStatusListener {
ptr := C.Cronet_UrlRequestStatusListener_CreateWith((*[0]byte)(C.cronetURLRequestStatusListenerOnStatus))
urlRequestStatusListenerAccess.Lock()
urlRequestStatusListenerMap[uintptr(unsafe.Pointer(ptr))] = onStatusFunc
urlRequestStatusListenerAccess.Unlock()
return URLRequestStatusListener{ptr}
}
func (l URLRequestStatusListener) Destroy() {
C.Cronet_UrlRequestStatusListener_Destroy(l.ptr)
}
var (
urlRequestStatusListenerAccess sync.Mutex
urlRequestStatusListenerMap map[uintptr]URLRequestStatusListenerOnStatusFunc
)
func init() {
urlRequestStatusListenerMap = make(map[uintptr]URLRequestStatusListenerOnStatusFunc)
}
//export cronetURLRequestStatusListenerOnStatus
func cronetURLRequestStatusListenerOnStatus(self C.Cronet_UrlRequestStatusListenerPtr, status C.Cronet_UrlRequestStatusListener_Status) {
ptr := uintptr(unsafe.Pointer(self))
urlRequestStatusListenerAccess.Lock()
listener := urlRequestStatusListenerMap[ptr]
delete(urlRequestCallbackMap, ptr)
urlRequestStatusListenerAccess.Unlock()
if listener == nil {
panic("nil url status listener")
}
listener(URLRequestStatusListener{self}, URLRequestStatusListenerStatus(status))
}
package cronet
// #include <stdlib.h>
// #include <stdbool.h>
// #include <cronet_c.h>
import "C"
type URLResponseInfo struct {
ptr C.Cronet_UrlResponseInfoPtr
}
func (i URLResponseInfo) Destroy() {
C.Cronet_UrlResponseInfo_Destroy(i.ptr)
}
// The URL the response is for. This is the URL after following
// redirects, so it may not be the originally requested URL
func (i URLResponseInfo) URL() string {
return C.GoString(C.Cronet_UrlResponseInfo_url_get(i.ptr))
}
// URLChainSize The URL chain. The first entry is the originally requested URL;
// the following entries are redirects followed.
func (i URLResponseInfo) URLChainSize() int {
return int(C.Cronet_UrlResponseInfo_url_chain_size(i.ptr))
}
func (i URLResponseInfo) URLChainAt(index int) string {
return C.GoString(C.Cronet_UrlResponseInfo_url_chain_at(i.ptr, C.uint32_t(index)))
}
// StatusCode is the HTTP status code. When a resource is retrieved from the cache,
// whether it was revalidated or not, the original status code is returned.
func (i URLResponseInfo) StatusCode() int {
return int(C.Cronet_UrlResponseInfo_http_status_code_get(i.ptr))
}
// StatusText is the HTTP status text of the status line. For example, if the
// request received a "HTTP/1.1 200 OK" response, this method returns "OK".
func (i URLResponseInfo) StatusText() string {
return C.GoString(C.Cronet_UrlResponseInfo_http_status_text_get(i.ptr))
}
// HeaderSize list size of response header field and value pairs.
// The headers are in the same order they are received over the wire.
func (i URLResponseInfo) HeaderSize() int {
return int(C.Cronet_UrlResponseInfo_all_headers_list_size(i.ptr))
}
func (i URLResponseInfo) HeaderAt(index int) HTTPHeader {
return HTTPHeader{C.Cronet_UrlResponseInfo_all_headers_list_at(i.ptr, C.uint32_t(index))}
}
// Cached true if the response came from the cache, including
// requests that were revalidated over the network before being retrieved
// from the cache, failed otherwise.
func (i URLResponseInfo) Cached() bool {
return bool(C.Cronet_UrlResponseInfo_was_cached_get(i.ptr))
}
// NegotiatedProtocol is the protocol (for example 'quic/1+spdy/3') negotiated with the server.
// An empty string if no protocol was negotiated, the protocol is
// not known, or when using plain HTTP or HTTPS.
func (i URLResponseInfo) NegotiatedProtocol() string {
return C.GoString(C.Cronet_UrlResponseInfo_negotiated_protocol_get(i.ptr))
}
// ProxyServer is the proxy server that was used for the request.
func (i URLResponseInfo) ProxyServer() string {
return C.GoString(C.Cronet_UrlResponseInfo_proxy_server_get(i.ptr))
}
// ReceivedByteCount is a minimum count of bytes received from the network to process this
// request. This count may ignore certain overheads (for example IP and
// TCP/UDP framing, SSL handshake and framing, proxy handling). This count is
// taken prior to decompression (for example GZIP and Brotli) and includes
// headers and data from all redirects.
func (i URLResponseInfo) ReceivedByteCount() int64 {
return int64(C.Cronet_UrlResponseInfo_received_byte_count_get(i.ptr))
}
This diff is collapsed.
This diff is collapsed.
MAJOR=126 MAJOR=130
MINOR=0 MINOR=0
BUILD=6462 BUILD=6700
PATCH=0 PATCH=0
...@@ -794,7 +794,7 @@ void Cronet_EngineParams_enable_check_result_set( ...@@ -794,7 +794,7 @@ void Cronet_EngineParams_enable_check_result_set(
CRONET_EXPORT CRONET_EXPORT
void Cronet_EngineParams_user_agent_set(Cronet_EngineParamsPtr self, void Cronet_EngineParams_user_agent_set(Cronet_EngineParamsPtr self,
const Cronet_String user_agent); const Cronet_String user_agent);
CRONET_EXPORT
CRONET_EXPORT CRONET_EXPORT
void Cronet_EngineParams_proxy_rules_set(Cronet_EngineParamsPtr self, void Cronet_EngineParams_proxy_rules_set(Cronet_EngineParamsPtr self,
const Cronet_String proxy_rules); const Cronet_String proxy_rules);
...@@ -804,13 +804,10 @@ CRONET_EXPORT ...@@ -804,13 +804,10 @@ CRONET_EXPORT
void Cronet_EngineParams_proxy_username_set( void Cronet_EngineParams_proxy_username_set(
Cronet_EngineParamsPtr self, Cronet_EngineParamsPtr self,
const Cronet_String proxy_user); const Cronet_String proxy_user);
CRONET_EXPORT
CRONET_EXPORT CRONET_EXPORT
void Cronet_EngineParams_proxy_password_set( void Cronet_EngineParams_proxy_password_set(
Cronet_EngineParamsPtr self, Cronet_EngineParamsPtr self,
const Cronet_String proxy_password); const Cronet_String proxy_password);
CRONET_EXPORT
CRONET_EXPORT CRONET_EXPORT
...@@ -856,7 +853,6 @@ CRONET_EXPORT ...@@ -856,7 +853,6 @@ CRONET_EXPORT
void Cronet_EngineParams_experimental_options_set( void Cronet_EngineParams_experimental_options_set(
Cronet_EngineParamsPtr self, Cronet_EngineParamsPtr self,
const Cronet_String experimental_options); const Cronet_String experimental_options);
// Cronet_EngineParams getters. // Cronet_EngineParams getters.
CRONET_EXPORT CRONET_EXPORT
bool Cronet_EngineParams_enable_check_result_get( bool Cronet_EngineParams_enable_check_result_get(
...@@ -865,9 +861,6 @@ CRONET_EXPORT ...@@ -865,9 +861,6 @@ CRONET_EXPORT
Cronet_String Cronet_EngineParams_user_agent_get( Cronet_String Cronet_EngineParams_user_agent_get(
const Cronet_EngineParamsPtr self); const Cronet_EngineParamsPtr self);
CRONET_EXPORT CRONET_EXPORT
Cronet_String Cronet_EngineParams_proxy_rules_get(
const Cronet_EngineParamsPtr self);
CRONET_EXPORT
Cronet_String Cronet_EngineParams_accept_language_get( Cronet_String Cronet_EngineParams_accept_language_get(
const Cronet_EngineParamsPtr self); const Cronet_EngineParamsPtr self);
CRONET_EXPORT CRONET_EXPORT
......
...@@ -9,7 +9,6 @@ require ( ...@@ -9,7 +9,6 @@ require (
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
github.com/natefinch/lumberjack v2.0.0+incompatible github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/wmm1996528/cronet-go v1.4.0
) )
require ( require (
......
...@@ -140,14 +140,6 @@ github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU ...@@ -140,14 +140,6 @@ github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/wmm1996528/cronet-go v1.1.2 h1:eA4mtAJIkKC4phDQ9GWRgk6bvWEPkPbWVAH2JYPFsgM=
github.com/wmm1996528/cronet-go v1.1.2/go.mod h1:cgCEgPXbA06M5DycAmbNeFH02pPOhwMq1x7u3e8Weh8=
github.com/wmm1996528/cronet-go v1.2.0 h1:vIQMuRrkZHVDhJ+jpdpVZMwJH4AEb5TG1WcMiOn/BjQ=
github.com/wmm1996528/cronet-go v1.2.0/go.mod h1:vacFQkKetDHpZzdrvmfY+X6cbv+ncBS0i4CtKoQ5uNI=
github.com/wmm1996528/cronet-go v1.3.0 h1:ofRe2gWx//uXaLcmCevy+qrKpRpTmDAM11wBZYWKGnY=
github.com/wmm1996528/cronet-go v1.3.0/go.mod h1:vacFQkKetDHpZzdrvmfY+X6cbv+ncBS0i4CtKoQ5uNI=
github.com/wmm1996528/cronet-go v1.4.0 h1:66Z2qtMCPJnBINf0XA3MbJtGIN5NApQeIJTd2IAmvO0=
github.com/wmm1996528/cronet-go v1.4.0/go.mod h1:vacFQkKetDHpZzdrvmfY+X6cbv+ncBS0i4CtKoQ5uNI=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
......
...@@ -12,13 +12,13 @@ import ( ...@@ -12,13 +12,13 @@ import (
"github.com/andybalholm/brotli" "github.com/andybalholm/brotli"
"github.com/bogdanfinn/tls-client/profiles" "github.com/bogdanfinn/tls-client/profiles"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/wmm1996528/cronet-go"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"net/http" "net/http"
"net/http/cookiejar" "net/http/cookiejar"
"net/url" "net/url"
"strings" "strings"
"tls-forward/cronet"
) )
type Client struct { type Client struct {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment