From e937b49acb3c583cd1ff430cc49db6cb368d90b2 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Sat, 27 Nov 2021 16:56:02 -0800 Subject: [PATCH 01/25] Revert "Allow ByteBuffer.position() to be used for the data length. (#1906)" This reverts commit ab51d6881d28e60ab5268ae319b9951d9bbeae63. Signed-off-by: Jose Nino --- library/common/jni/jni_interface.cc | 31 ++-- library/common/jni/jni_utility.cc | 15 +- library/common/jni/jni_utility.h | 4 - .../envoymobile/engine/EnvoyHTTPStream.java | 24 +-- .../envoymobile/engine/JniLibrary.java | 10 +- .../io/envoyproxy/envoymobile/Stream.kt | 23 +-- .../envoyproxy/envoymobile/StreamPrototype.kt | 14 +- .../envoymobile/mocks/MockStream.kt | 2 +- .../integration/AndroidEnvoyFlowTest.java | 175 +++--------------- 9 files changed, 59 insertions(+), 239 deletions(-) diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index 8fc8309831..0e9e5d1629 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -903,35 +903,28 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra return read_data(static_cast(stream_handle), byte_count); } -// Note: JLjava_nio_ByteBuffer_2IZ is the mangled signature of the java method. +// Note: JLjava_nio_ByteBuffer_2Z is the mangled signature of the java method. // https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html -// The Java counterpart guarantees to invoke this method with a non-null direct ByteBuffer where the -// provided length is between 0 and ByteBuffer.capacity(), inclusively. extern "C" JNIEXPORT jint JNICALL -Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendData__JLjava_nio_ByteBuffer_2IZ( - JNIEnv* env, jclass, jlong stream_handle, jobject data, jint length, jboolean end_stream) { - if (end_stream) { - jni_log("[Envoy]", "jvm_send_data_end_stream"); - } +Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendData__JLjava_nio_ByteBuffer_2Z( + JNIEnv* env, jclass, jlong stream_handle, jobject data, jboolean end_stream) { - return send_data(static_cast(stream_handle), - buffer_to_native_data(env, data, length), end_stream); + // TODO: check for null pointer in envoy_data.bytes - we could copy or raise an exception. + return send_data(static_cast(stream_handle), buffer_to_native_data(env, data), + end_stream); } -// Note: J_3BIZ is the mangled signature of the java method. +// Note: J_3BZ is the mangled signature of the java method. // https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html -// The Java counterpart guarantees to invoke this method with a non-null jbyteArray where the -// provided length is between 0 and the size of the jbyteArray, inclusively. And given that this -// jbyteArray comes from a ByteBuffer, it is also guaranteed that its length will not be greater -// than 2^31 - this is why the length type is jint. -extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendData__J_3BIZ( - JNIEnv* env, jclass, jlong stream_handle, jbyteArray data, jint length, jboolean end_stream) { +extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendData__J_3BZ( + JNIEnv* env, jclass, jlong stream_handle, jbyteArray data, jboolean end_stream) { if (end_stream) { jni_log("[Envoy]", "jvm_send_data_end_stream"); } - return send_data(static_cast(stream_handle), - array_to_native_data(env, data, length), end_stream); + // TODO: check for null pointer in envoy_data.bytes - we could copy or raise an exception. + return send_data(static_cast(stream_handle), array_to_native_data(env, data), + end_stream); } extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendHeaders( diff --git a/library/common/jni/jni_utility.cc b/library/common/jni/jni_utility.cc index 4268e081ba..1d8f397aa2 100644 --- a/library/common/jni/jni_utility.cc +++ b/library/common/jni/jni_utility.cc @@ -53,11 +53,7 @@ int unbox_integer(JNIEnv* env, jobject boxedInteger) { } envoy_data array_to_native_data(JNIEnv* env, jbyteArray j_data) { - size_t data_length = static_cast(env->GetArrayLength(j_data)); - return array_to_native_data(env, j_data, data_length); -} - -envoy_data array_to_native_data(JNIEnv* env, jbyteArray j_data, size_t data_length) { + size_t data_length = env->GetArrayLength(j_data); uint8_t* native_bytes = static_cast(safe_malloc(data_length)); void* critical_data = env->GetPrimitiveArrayCritical(j_data, 0); memcpy(native_bytes, critical_data, data_length); // NOLINT(safe-memcpy) @@ -113,11 +109,6 @@ jobject native_map_to_map(JNIEnv* env, envoy_map map) { } envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data) { - size_t data_length = static_cast(env->GetDirectBufferCapacity(j_data)); - return buffer_to_native_data(env, j_data, data_length); -} - -envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data, size_t data_length) { uint8_t* direct_address = static_cast(env->GetDirectBufferAddress(j_data)); if (direct_address == nullptr) { @@ -129,14 +120,14 @@ envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data, size_t data_length jbyteArray array = static_cast(env->CallObjectMethod(j_data, jmid_array)); env->DeleteLocalRef(jcls_ByteBuffer); - envoy_data native_data = array_to_native_data(env, array, data_length); + envoy_data native_data = array_to_native_data(env, array); env->DeleteLocalRef(array); return native_data; } envoy_data native_data; native_data.bytes = direct_address; - native_data.length = data_length; + native_data.length = env->GetDirectBufferCapacity(j_data); native_data.release = jni_delete_global_ref; native_data.context = env->NewGlobalRef(j_data); diff --git a/library/common/jni/jni_utility.h b/library/common/jni/jni_utility.h index 908e247c8f..8d4fd2d4e5 100644 --- a/library/common/jni/jni_utility.h +++ b/library/common/jni/jni_utility.h @@ -21,8 +21,6 @@ int unbox_integer(JNIEnv* env, jobject boxedInteger); envoy_data array_to_native_data(JNIEnv* env, jbyteArray j_data); -envoy_data array_to_native_data(JNIEnv* env, jbyteArray j_data, size_t data_length); - /** * Utility function that copies envoy_data to jbyteArray. * @@ -49,8 +47,6 @@ jstring native_data_to_string(JNIEnv* env, envoy_data data); envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data); -envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data, size_t data_length); - envoy_data* buffer_to_native_data_ptr(JNIEnv* env, jobject j_data); envoy_headers to_native_headers(JNIEnv* env, jobjectArray headers); diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyHTTPStream.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyHTTPStream.java index c7da58a64a..bab3acfdad 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyHTTPStream.java +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyHTTPStream.java @@ -42,39 +42,21 @@ public void sendHeaders(Map> headers, boolean endStream) { JniLibrary.sendHeaders(streamHandle, JniBridgeUtility.toJniHeaders(headers), endStream); } - /** - * Send data over an open HTTP streamHandle. This method can be invoked multiple - * times. The data length is the {@link ByteBuffer#capacity}. - * - * @param data, the data to send. - * @param endStream, supplies whether this is the last data in the streamHandle. - * @throws UnsupportedOperationException - if the provided buffer is neither a - * direct ByteBuffer nor backed by an - * on-heap byte array. - */ - public void sendData(ByteBuffer data, boolean endStream) { - sendData(data, data.capacity(), endStream); - } - /** * Send data over an open HTTP streamHandle. This method can be invoked multiple * times. * * @param data, the data to send. - * @param length, number of bytes to send: 0 <= length <= ByteBuffer.capacity() * @param endStream, supplies whether this is the last data in the streamHandle. * @throws UnsupportedOperationException - if the provided buffer is neither a * direct ByteBuffer nor backed by an * on-heap byte array. */ - public void sendData(ByteBuffer data, int length, boolean endStream) { - if (length < 0 || length > data.capacity()) { - throw new IllegalArgumentException("Length out of bound"); - } + public void sendData(ByteBuffer data, boolean endStream) { if (data.isDirect()) { - JniLibrary.sendData(streamHandle, data, length, endStream); + JniLibrary.sendData(streamHandle, data, endStream); } else if (data.hasArray()) { - JniLibrary.sendData(streamHandle, data.array(), length, endStream); + JniLibrary.sendData(streamHandle, data.array(), endStream); } else { throw new UnsupportedOperationException("Unsupported ByteBuffer implementation."); } diff --git a/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java b/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java index 7fa8836eb2..835cd99f88 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java @@ -85,11 +85,10 @@ protected static native int startStream(long stream, JvmCallbackContext context, * * @param stream, the stream to send data over. * @param data, the data to send. - * @param length, the size in bytes of the data to send. 0 <= length <= data.length * @param endStream, supplies whether this is the last data in the stream. - * @return int, the resulting status of the operation. + * @return int, the resulting status of the operation. */ - protected static native int sendData(long stream, byte[] data, int length, boolean endStream); + protected static native int sendData(long stream, byte[] data, boolean endStream); /** * Send data over an open HTTP stream. This method can be invoked multiple @@ -97,11 +96,10 @@ protected static native int startStream(long stream, JvmCallbackContext context, * * @param stream, the stream to send data over. * @param data, the data to send; must be a direct ByteBuffer. - * @param length, the size in bytes of the data to send. 0 <= length <= data.capacity() * @param endStream, supplies whether this is the last data in the stream. - * @return int, the resulting status of the operation. + * @return int, the resulting status of the operation. */ - protected static native int sendData(long stream, ByteBuffer data, int length, boolean endStream); + protected static native int sendData(long stream, ByteBuffer data, boolean endStream); /** * Read data from the response stream. Returns immediately. diff --git a/library/kotlin/io/envoyproxy/envoymobile/Stream.kt b/library/kotlin/io/envoyproxy/envoymobile/Stream.kt index b51fe23b6a..122b7d6fd8 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/Stream.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/Stream.kt @@ -9,8 +9,7 @@ import java.nio.ByteBuffer * Constructed using `StreamPrototype`, and used to write to the network. */ open class Stream( - private val underlyingStream: EnvoyHTTPStream, - private val useByteBufferPosition: Boolean + private val underlyingStream: EnvoyHTTPStream ) { /** * Send headers over the stream. @@ -36,19 +35,13 @@ open class Stream( } /** - * For sending data to an associated stream. By default, the length sent is the - * **[ByteBuffer.capacity]**. However, the length will rather be **[ByteBuffer.position]** - * if the Stream was configured to do so - see **[StreamPrototype.useByteBufferPosition]**. - * - * Note: the provided ByteBuffer won't be mutated in any case. On the other hand, until the - * stream is closed, any further mutations may lead to an unpredictable outcome. + * For sending data to an associated stream. * * @param data Data to send over the stream. * @return This stream, for chaining syntax. */ open fun sendData(data: ByteBuffer): Stream { - var length = if (useByteBufferPosition) data.position() else data.capacity() - underlyingStream.sendData(data, length, false) + underlyingStream.sendData(data, false) return this } @@ -62,18 +55,12 @@ open class Stream( } /** - * Close the stream with a data frame. By default, the length sent is the - * **[ByteBuffer.capacity]**. However, the length will rather be **[ByteBuffer.position]** - * if the Stream was configured to do so - see **[StreamPrototype.useByteBufferPosition]**. - * - * Note: the provided ByteBuffer won't be mutated in any case. On the other hand, until the - * stream is closed, any further mutations may lead to an unpredictable outcome. + * Close the stream with a data frame. * * @param data Data with which to close the stream. */ open fun close(data: ByteBuffer) { - var length = if (useByteBufferPosition) data.position() else data.capacity() - underlyingStream.sendData(data, length, true) + underlyingStream.sendData(data, true) } /** diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt index f7fb49745d..e140177827 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt @@ -16,7 +16,6 @@ import java.util.concurrent.Executors open class StreamPrototype(private val engine: EnvoyEngine) { private val callbacks = StreamCallbacks() private var explicitFlowControl = false - private var useByteBufferPosition = false /** * Start a new stream. @@ -26,7 +25,7 @@ open class StreamPrototype(private val engine: EnvoyEngine) { */ open fun start(executor: Executor = Executors.newSingleThreadExecutor()): Stream { val engineStream = engine.startStream(createCallbacks(executor), explicitFlowControl) - return Stream(engineStream, useByteBufferPosition) + return Stream(engineStream) } /** @@ -45,17 +44,6 @@ open class StreamPrototype(private val engine: EnvoyEngine) { return this } - /** - * Specify how to determine the length of data to send for a given ByteBuffer. - * - * @param enabled Use ByteBuffer's position when true, otherwise use its capacity. - * @return This stream, for chaining syntax. - */ - fun setUseByteBufferPosition(enabled: Boolean): StreamPrototype { - this.useByteBufferPosition = enabled - return this - } - /** * Specify a callback for when response headers are received by the stream. * diff --git a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt index b85cf0c8fd..2643fb2087 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt @@ -7,7 +7,7 @@ import java.nio.ByteBuffer * Mock implementation of `Stream` that also provides an interface for sending * mocked responses through to the stream's callbacks. Created via `MockStreamPrototype`. */ -class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : Stream(underlyingStream, useByteBufferPosition = false) { +class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : Stream(underlyingStream) { private val mockStream: MockEnvoyHTTPStream = underlyingStream private val mockStreamIntel = object : EnvoyStreamIntel { diff --git a/test/java/integration/AndroidEnvoyFlowTest.java b/test/java/integration/AndroidEnvoyFlowTest.java index 7d1bf250c9..528be83055 100644 --- a/test/java/integration/AndroidEnvoyFlowTest.java +++ b/test/java/integration/AndroidEnvoyFlowTest.java @@ -45,30 +45,39 @@ @RunWith(RobolectricTestRunner.class) public class AndroidEnvoyFlowTest { + private static Engine engine; + private final MockWebServer mockWebServer = new MockWebServer(); - private Engine engine; @BeforeClass public static void loadJniLibrary() { AndroidJniLibrary.loadTestLibrary(); } + @AfterClass + public static void shutdownEngine() { + if (engine != null) { + engine.terminate(); + } + } + @Before public void setUpEngine() throws Exception { - CountDownLatch latch = new CountDownLatch(1); - Context appContext = ApplicationProvider.getApplicationContext(); - engine = new AndroidEngineBuilder(appContext) - .setOnEngineRunning(() -> { - latch.countDown(); - return null; - }) - .build(); - latch.await(); // Don't launch a request before initialization has completed. + if (engine == null) { + CountDownLatch latch = new CountDownLatch(1); + Context appContext = ApplicationProvider.getApplicationContext(); + engine = new AndroidEngineBuilder(appContext) + .setOnEngineRunning(() -> { + latch.countDown(); + return null; + }) + .build(); + latch.await(); // Don't launch a request before initialization has completed. + } } @After - public void shutdown() throws IOException { - engine.terminate(); + public void shutdownMockWebServer() throws IOException { mockWebServer.shutdown(); } @@ -147,61 +156,6 @@ public MockResponse dispatch(RecordedRequest recordedRequest) { assertThat(response.getEnvoyError()).isNull(); } - @Test - public void post_simple_withoutByteBufferPosition() throws Exception { - mockWebServer.setDispatcher(new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest recordedRequest) { - assertThat(recordedRequest.getMethod()).isEqualTo(RequestMethod.POST.name()); - assertThat(recordedRequest.getBody().readUtf8()).isEqualTo("55555"); - return new MockResponse().setBody("This is my response Body"); - } - }); - ByteBuffer requestBody = ByteBuffer.allocateDirect(5); - requestBody.put("55555".getBytes()); - requestBody.position(3); // The position should be ignored - only capacity matters. - mockWebServer.start(); - RequestScenario requestScenario = new RequestScenario() - .setHttpMethod(RequestMethod.POST) - .setUrl(mockWebServer.url("get/flowers").toString()) - .addBody(requestBody) - .closeBodyStream(); - - Response response = sendRequest(requestScenario); - - assertThat(response.getHeaders().getHttpStatus()).isEqualTo(200); - assertThat(response.getBodyAsString()).isEqualTo("This is my response Body"); - assertThat(response.getEnvoyError()).isNull(); - } - - @Test - public void post_simple_withByteBufferPosition() throws Exception { - mockWebServer.setDispatcher(new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest recordedRequest) { - assertThat(recordedRequest.getMethod()).isEqualTo(RequestMethod.POST.name()); - assertThat(recordedRequest.getBody().readUtf8()).isEqualTo("This is my request body"); - return new MockResponse().setBody("This is my response Body"); - } - }); - ByteBuffer requestBody = ByteBuffer.allocateDirect(100); - requestBody.put("This is my request body with spurious data".getBytes()); - requestBody.position(23); // Only the first 23 bytes should be sent - the String size is 42. - mockWebServer.start(); - RequestScenario requestScenario = new RequestScenario() - .useByteBufferPosition() - .setHttpMethod(RequestMethod.POST) - .setUrl(mockWebServer.url("get/flowers").toString()) - .addBody("This is my request body") - .closeBodyStream(); - - Response response = sendRequest(requestScenario); - - assertThat(response.getHeaders().getHttpStatus()).isEqualTo(200); - assertThat(response.getBodyAsString()).isEqualTo("This is my response Body"); - assertThat(response.getEnvoyError()).isNull(); - } - @Test public void post_chunkedBody() throws Exception { mockWebServer.setDispatcher(new Dispatcher() { @@ -209,7 +163,7 @@ public void post_chunkedBody() throws Exception { public MockResponse dispatch(RecordedRequest recordedRequest) { assertThat(recordedRequest.getMethod()).isEqualTo(RequestMethod.POST.name()); assertThat(recordedRequest.getBody().readUtf8()) - .isEqualTo("This is the first part of my body. This is the second part of my body."); + .isEqualTo("This is the first part of by body. This is the second part of by body."); return new MockResponse().setBody("This is my response Body"); } }); @@ -218,8 +172,8 @@ public MockResponse dispatch(RecordedRequest recordedRequest) { new RequestScenario() .setHttpMethod(RequestMethod.POST) .setUrl(mockWebServer.url("get/flowers").toString()) - .addBody("This is the first part of my body. ") - .addBody("This is the second part of my body.") + .addBody("This is the first part of by body. ") + .addBody("This is the second part of by body.") .closeBodyStream(); // Content-Length is not provided; must be closed explicitly. Response response = sendRequest(requestScenario); @@ -229,60 +183,12 @@ public MockResponse dispatch(RecordedRequest recordedRequest) { assertThat(response.getEnvoyError()).isNull(); } - @Test - public void post_chunkedBody_withBufferPosition() throws Exception { - String firstChunk = "This is the first chunk of my request body. "; - String secondChunk = "This is the second chunk."; - mockWebServer.setDispatcher(new Dispatcher() { - @Override - public MockResponse dispatch(RecordedRequest recordedRequest) { - assertThat(recordedRequest.getBody().readUtf8()).isEqualTo(firstChunk + secondChunk); - return new MockResponse().setBody("This is my response Body"); - } - }); - mockWebServer.start(); - ByteBuffer requestBodyFirstChunk = ByteBuffer.allocateDirect(1024); - requestBodyFirstChunk.put((firstChunk + "spurious data that should be ignored").getBytes()); - requestBodyFirstChunk.position(firstChunk.length()); - ByteBuffer requestBodySecondChunk = ByteBuffer.allocateDirect(100); - requestBodySecondChunk.put((secondChunk + "data beyond ByteBuffer.position()").getBytes()); - requestBodySecondChunk.position(secondChunk.length()); - RequestScenario requestScenario = - new RequestScenario() - .useByteBufferPosition() - .setHttpMethod(RequestMethod.POST) - .setUrl(mockWebServer.url("get/flowers").toString()) - .addBody(requestBodyFirstChunk) - .addBody(requestBodySecondChunk) - .closeBodyStream(); // Content-Length is not provided; must be closed explicitly. - - Response response = sendRequest(requestScenario); - - assertThat(response.getHeaders().getHttpStatus()).isEqualTo(200); - assertThat(response.getBodyAsString()).isEqualTo("This is my response Body"); - assertThat(response.getEnvoyError()).isNull(); - } - - @Test - public void post_cancelBeforeSendingRequestBody() throws Exception { - RequestScenario requestScenario = new RequestScenario() - .setHttpMethod(RequestMethod.POST) - .setUrl(mockWebServer.url("get/flowers").toString()) - .addBody("Request body") - .cancelBeforeSendingRequestBody(); - - Response response = sendRequest(requestScenario); - - assertThat(response.isCancelled()).isTrue(); - } - private Response sendRequest(RequestScenario requestScenario) throws Exception { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference response = new AtomicReference<>(new Response()); Stream stream = engine.streamClient() .newStreamPrototype() - .setUseByteBufferPosition(requestScenario.useByteBufferPosition) .setOnResponseHeaders((responseHeaders, endStream, ignored) -> { response.get().setHeaders(responseHeaders); if (endStream) { @@ -314,12 +220,8 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { }) .start(Executors.newSingleThreadExecutor()) .sendHeaders(requestScenario.getHeaders(), !requestScenario.hasBody()); - if (requestScenario.cancelBeforeSendingRequestBody) { - stream.cancel(); - } else { - requestScenario.getBodyChunks().forEach(stream::sendData); - requestScenario.getClosingBodyChunk().ifPresent(stream::close); - } + requestScenario.getBodyChunks().forEach(stream::sendData); + requestScenario.getClosingBodyChunk().ifPresent(stream::close); latch.await(); response.get().throwAssertionErrorIfAny(); @@ -327,14 +229,11 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { } private static class RequestScenario { - private URL url; private RequestMethod method = null; private final List bodyChunks = new ArrayList<>(); private final List> headers = new ArrayList<>(); private boolean closeBodyStream = false; - private boolean cancelBeforeSendingRequestBody = false; - private boolean useByteBufferPosition; RequestHeaders getHeaders() { RequestHeadersBuilder requestHeadersBuilder = @@ -367,19 +266,15 @@ RequestScenario setUrl(String url) throws MalformedURLException { return this; } - RequestScenario addBody(String requestBodyChunk) { - return addBody(requestBodyChunk.getBytes()); - } - RequestScenario addBody(byte[] requestBodyChunk) { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(requestBodyChunk.length); byteBuffer.put(requestBodyChunk); - return addBody(byteBuffer); + bodyChunks.add(byteBuffer); + return this; } - RequestScenario addBody(ByteBuffer requestBodyChunk) { - bodyChunks.add(requestBodyChunk); - return this; + RequestScenario addBody(String requestBodyChunk) { + return addBody(requestBodyChunk.getBytes()); } RequestScenario addHeader(String key, String value) { @@ -391,16 +286,6 @@ RequestScenario closeBodyStream() { closeBodyStream = true; return this; } - - RequestScenario cancelBeforeSendingRequestBody() { - cancelBeforeSendingRequestBody = true; - return this; - } - - RequestScenario useByteBufferPosition() { - useByteBufferPosition = true; - return this; - } } private static class Response { From 8025b5141f2193ccf76a7e624f0882c811fd0e9e Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Mon, 29 Nov 2021 12:45:51 -0800 Subject: [PATCH 02/25] working Signed-off-by: Jose Nino --- library/common/config/config.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/library/common/config/config.cc b/library/common/config/config.cc index 7ed22ad4bb..bd7409acda 100644 --- a/library/common/config/config.cc +++ b/library/common/config/config.cc @@ -39,6 +39,8 @@ const std::string config_header = R"( - &dns_fail_max_interval 10s - &dns_query_timeout 25s - &dns_preresolve_hostnames [] +- &dns_resolvers [{"socket_address":{"address":"8.8.8.8"}}] +- &dns_use_resolvers_as_fallback true - &enable_interface_binding false - &h2_connection_keepalive_idle_interval 100000s - &h2_connection_keepalive_timeout 10s @@ -196,6 +198,13 @@ const char* config_template = R"( address: socket_address: { address: 127.0.0.1, port_value: 10101 } +typed_dns_resolver_config: + name: envoy.network.dns_resolver.cares + typed_config: + "@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig + resolvers: *dns_resolvers + use_resolvers_as_fallback: *dns_use_resolvers_as_fallback + static_resources: listeners: #{custom_listeners} @@ -267,6 +276,12 @@ R"( base_interval: *dns_fail_base_interval max_interval: *dns_fail_max_interval dns_query_timeout: *dns_query_timeout + typed_dns_resolver_config: + name: envoy.network.dns_resolver.cares + typed_config: + "@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig + resolvers: *dns_resolvers + use_resolvers_as_fallback: *dns_use_resolvers_as_fallback # TODO: make this configurable for users. - name: envoy.filters.http.decompressor typed_config: From 7c14dbf527864a03b3a19899798f1b5fadfa2a03 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Mon, 29 Nov 2021 22:34:42 -0800 Subject: [PATCH 03/25] looking ok Signed-off-by: Jose Nino --- envoy | 2 +- library/common/config/config.cc | 25 ++++++++----------- library/common/config/templates.h | 2 ++ library/common/jni/jni_interface.cc | 8 ++++++ .../engine/EnvoyConfiguration.java | 9 +++++-- .../envoymobile/engine/EnvoyEngineImpl.java | 2 +- .../envoymobile/engine/JniLibrary.java | 2 ++ 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/envoy b/envoy index 23e5fc2939..3c5500d6b9 160000 --- a/envoy +++ b/envoy @@ -1 +1 @@ -Subproject commit 23e5fc2939e1782416155509edfca323150e8a59 +Subproject commit 3c5500d6b997677963f697084b2675f7ad47c1e0 diff --git a/library/common/config/config.cc b/library/common/config/config.cc index bd7409acda..bbd7f25fd1 100644 --- a/library/common/config/config.cc +++ b/library/common/config/config.cc @@ -24,6 +24,15 @@ const char* native_filter_template = R"( typed_config: {{ native_filter_typed_config }} )"; +const char* dns_template = R"( + typed_dns_resolver_config: + name: envoy.network.dns_resolver.cares + typed_config: + "@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig + resolvers: {{ dns_resolvers }} + use_resolvers_as_fallback: {{ dns_use_resolvers_as_fallback }} +)"; + const char* route_cache_reset_filter_insert = R"( - name: envoy.filters.http.route_cache_reset typed_config: @@ -39,8 +48,6 @@ const std::string config_header = R"( - &dns_fail_max_interval 10s - &dns_query_timeout 25s - &dns_preresolve_hostnames [] -- &dns_resolvers [{"socket_address":{"address":"8.8.8.8"}}] -- &dns_use_resolvers_as_fallback true - &enable_interface_binding false - &h2_connection_keepalive_idle_interval 100000s - &h2_connection_keepalive_timeout 10s @@ -198,13 +205,6 @@ const char* config_template = R"( address: socket_address: { address: 127.0.0.1, port_value: 10101 } -typed_dns_resolver_config: - name: envoy.network.dns_resolver.cares - typed_config: - "@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig - resolvers: *dns_resolvers - use_resolvers_as_fallback: *dns_use_resolvers_as_fallback - static_resources: listeners: #{custom_listeners} @@ -276,12 +276,7 @@ R"( base_interval: *dns_fail_base_interval max_interval: *dns_fail_max_interval dns_query_timeout: *dns_query_timeout - typed_dns_resolver_config: - name: envoy.network.dns_resolver.cares - typed_config: - "@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig - resolvers: *dns_resolvers - use_resolvers_as_fallback: *dns_use_resolvers_as_fallback +#{dns_resolver_config} # TODO: make this configurable for users. - name: envoy.filters.http.decompressor typed_config: diff --git a/library/common/config/templates.h b/library/common/config/templates.h index 5b51cddeef..2e1c6a4659 100644 --- a/library/common/config/templates.h +++ b/library/common/config/templates.h @@ -19,6 +19,8 @@ extern const char* platform_filter_template; */ extern const char* native_filter_template; +extern const char* dns_template; + /** * Number of spaces to indent custom cluster entries. */ diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index 0e9e5d1629..258853eb23 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -150,6 +150,14 @@ Java_io_envoyproxy_envoymobile_engine_JniLibrary_nativeFilterTemplateString(JNIE return result; } +extern "C" JNIEXPORT jstring JNICALL +Java_io_envoyproxy_envoymobile_engine_JniLibrary_dnsTemplateString(JNIEnv* env, + jclass // class +) { + jstring result = env->NewStringUTF(dns_template); + return result; +} + extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_recordCounterInc( JNIEnv* env, jclass, // class diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java index 87a16a2c70..8530dade85 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java @@ -109,7 +109,7 @@ public EnvoyConfiguration(Boolean adminInterfaceEnabled, String grpcStatsDomain, * resolved. */ String resolveTemplate(final String templateYAML, final String platformFilterTemplateYAML, - final String nativeFilterTemplateYAML) { + final String nativeFilterTemplateYAML, final String dnsTemplateYAML) { final StringBuilder customFiltersBuilder = new StringBuilder(); for (EnvoyHTTPFilterFactory filterFactory : httpPlatformFilterFactories) { @@ -125,9 +125,14 @@ String resolveTemplate(final String templateYAML, final String platformFilterTem customFiltersBuilder.append(filterConfig); } - String processedTemplate = + String firstProcess = templateYAML.replace("#{custom_filters}", customFiltersBuilder.toString()); + String dnsResolverConfigFirst = dnsTemplateYAML.replace("{{ dns_resolvers }}", "[{\"socket_address\":{\"address\":\"8.8.8.8\"}}]"); + String dnsResolverConfig = dnsResolverConfigFirst.replace("{{ dns_use_resolvers_as_fallback }}", "true"); + + String processedTemplate = firstProcess.replace("#{dns_resolver_config}", dnsResolverConfig); + StringBuilder configBuilder = new StringBuilder("!ignore platform_defs:\n"); configBuilder.append(String.format("- &connect_timeout %ss\n", connectTimeoutSeconds)) .append(String.format("- &dns_refresh_rate %ss\n", dnsRefreshSeconds)) diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java index 84f44522cb..f5da955c6e 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java @@ -83,7 +83,7 @@ public int runWithTemplate(String configurationYAML, EnvoyConfiguration envoyCon return runWithResolvedYAML(envoyConfiguration.resolveTemplate( configurationYAML, JniLibrary.platformFilterTemplateString(), - JniLibrary.nativeFilterTemplateString()), + JniLibrary.nativeFilterTemplateString(), JniLibrary.dnsTemplateString()), logLevel); } diff --git a/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java b/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java index 835cd99f88..04bcea7105 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java @@ -282,6 +282,8 @@ protected static native int recordHistogramValue(long engine, String elements, b */ public static native String nativeFilterTemplateString(); + public static native String dnsTemplateString(); + /** * Register a string accessor to get strings from the platform. * From f733c70fbb2221839f9b53f32acab3347758d1a2 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Tue, 30 Nov 2021 10:21:14 -0800 Subject: [PATCH 04/25] working Signed-off-by: Jose Nino --- envoy | 2 +- .../envoymobile/engine/EnvoyConfiguration.java | 12 ++++++++---- .../envoymobile/engine/EnvoyEngineImpl.java | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/envoy b/envoy index 3c5500d6b9..eb04828a83 160000 --- a/envoy +++ b/envoy @@ -1 +1 @@ -Subproject commit 3c5500d6b997677963f697084b2675f7ad47c1e0 +Subproject commit eb04828a83df7da3dc305c5ef1e4040d05ccd740 diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java index 8530dade85..d6a4df735e 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java @@ -125,13 +125,17 @@ String resolveTemplate(final String templateYAML, final String platformFilterTem customFiltersBuilder.append(filterConfig); } - String firstProcess = + String addedCustomFilters = templateYAML.replace("#{custom_filters}", customFiltersBuilder.toString()); - String dnsResolverConfigFirst = dnsTemplateYAML.replace("{{ dns_resolvers }}", "[{\"socket_address\":{\"address\":\"8.8.8.8\"}}]"); - String dnsResolverConfig = dnsResolverConfigFirst.replace("{{ dns_use_resolvers_as_fallback }}", "true"); + // TODO: use defaults for now. Subsequent PR will add user ability to override. These defaults + // are a noop. + String dnsResolverConfigFirst = dnsTemplateYAML.replace("{{ dns_resolvers }}", "[]"); + String dnsResolverConfig = + dnsResolverConfigFirst.replace("{{ dns_use_resolvers_as_fallback }}", "false"); - String processedTemplate = firstProcess.replace("#{dns_resolver_config}", dnsResolverConfig); + String processedTemplate = + addedCustomFilters.replace("#{dns_resolver_config}", dnsResolverConfig); StringBuilder configBuilder = new StringBuilder("!ignore platform_defs:\n"); configBuilder.append(String.format("- &connect_timeout %ss\n", connectTimeoutSeconds)) diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java index f5da955c6e..2260a00229 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java @@ -83,7 +83,8 @@ public int runWithTemplate(String configurationYAML, EnvoyConfiguration envoyCon return runWithResolvedYAML(envoyConfiguration.resolveTemplate( configurationYAML, JniLibrary.platformFilterTemplateString(), - JniLibrary.nativeFilterTemplateString(), JniLibrary.dnsTemplateString()), + JniLibrary.nativeFilterTemplateString(), + JniLibrary.dnsTemplateString()), logLevel); } From df16b302f0b64454e1c9255cd755c719d59881a9 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Tue, 30 Nov 2021 10:22:20 -0800 Subject: [PATCH 05/25] Revert "Revert "Allow ByteBuffer.position() to be used for the data length. (#1906)"" This reverts commit 8da335b0db6a4ec88fa3fc069a09e45e2bece8ed. Signed-off-by: Jose Nino --- library/common/jni/jni_interface.cc | 31 ++-- library/common/jni/jni_utility.cc | 15 +- library/common/jni/jni_utility.h | 4 + .../envoymobile/engine/EnvoyHTTPStream.java | 24 ++- .../envoymobile/engine/JniLibrary.java | 10 +- .../io/envoyproxy/envoymobile/Stream.kt | 23 ++- .../envoyproxy/envoymobile/StreamPrototype.kt | 14 +- .../envoymobile/mocks/MockStream.kt | 2 +- .../integration/AndroidEnvoyFlowTest.java | 175 +++++++++++++++--- 9 files changed, 239 insertions(+), 59 deletions(-) diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index 258853eb23..0f900458e9 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -911,28 +911,35 @@ extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibra return read_data(static_cast(stream_handle), byte_count); } -// Note: JLjava_nio_ByteBuffer_2Z is the mangled signature of the java method. +// Note: JLjava_nio_ByteBuffer_2IZ is the mangled signature of the java method. // https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html +// The Java counterpart guarantees to invoke this method with a non-null direct ByteBuffer where the +// provided length is between 0 and ByteBuffer.capacity(), inclusively. extern "C" JNIEXPORT jint JNICALL -Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendData__JLjava_nio_ByteBuffer_2Z( - JNIEnv* env, jclass, jlong stream_handle, jobject data, jboolean end_stream) { +Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendData__JLjava_nio_ByteBuffer_2IZ( + JNIEnv* env, jclass, jlong stream_handle, jobject data, jint length, jboolean end_stream) { + if (end_stream) { + jni_log("[Envoy]", "jvm_send_data_end_stream"); + } - // TODO: check for null pointer in envoy_data.bytes - we could copy or raise an exception. - return send_data(static_cast(stream_handle), buffer_to_native_data(env, data), - end_stream); + return send_data(static_cast(stream_handle), + buffer_to_native_data(env, data, length), end_stream); } -// Note: J_3BZ is the mangled signature of the java method. +// Note: J_3BIZ is the mangled signature of the java method. // https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html -extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendData__J_3BZ( - JNIEnv* env, jclass, jlong stream_handle, jbyteArray data, jboolean end_stream) { +// The Java counterpart guarantees to invoke this method with a non-null jbyteArray where the +// provided length is between 0 and the size of the jbyteArray, inclusively. And given that this +// jbyteArray comes from a ByteBuffer, it is also guaranteed that its length will not be greater +// than 2^31 - this is why the length type is jint. +extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendData__J_3BIZ( + JNIEnv* env, jclass, jlong stream_handle, jbyteArray data, jint length, jboolean end_stream) { if (end_stream) { jni_log("[Envoy]", "jvm_send_data_end_stream"); } - // TODO: check for null pointer in envoy_data.bytes - we could copy or raise an exception. - return send_data(static_cast(stream_handle), array_to_native_data(env, data), - end_stream); + return send_data(static_cast(stream_handle), + array_to_native_data(env, data, length), end_stream); } extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_sendHeaders( diff --git a/library/common/jni/jni_utility.cc b/library/common/jni/jni_utility.cc index 1d8f397aa2..4268e081ba 100644 --- a/library/common/jni/jni_utility.cc +++ b/library/common/jni/jni_utility.cc @@ -53,7 +53,11 @@ int unbox_integer(JNIEnv* env, jobject boxedInteger) { } envoy_data array_to_native_data(JNIEnv* env, jbyteArray j_data) { - size_t data_length = env->GetArrayLength(j_data); + size_t data_length = static_cast(env->GetArrayLength(j_data)); + return array_to_native_data(env, j_data, data_length); +} + +envoy_data array_to_native_data(JNIEnv* env, jbyteArray j_data, size_t data_length) { uint8_t* native_bytes = static_cast(safe_malloc(data_length)); void* critical_data = env->GetPrimitiveArrayCritical(j_data, 0); memcpy(native_bytes, critical_data, data_length); // NOLINT(safe-memcpy) @@ -109,6 +113,11 @@ jobject native_map_to_map(JNIEnv* env, envoy_map map) { } envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data) { + size_t data_length = static_cast(env->GetDirectBufferCapacity(j_data)); + return buffer_to_native_data(env, j_data, data_length); +} + +envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data, size_t data_length) { uint8_t* direct_address = static_cast(env->GetDirectBufferAddress(j_data)); if (direct_address == nullptr) { @@ -120,14 +129,14 @@ envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data) { jbyteArray array = static_cast(env->CallObjectMethod(j_data, jmid_array)); env->DeleteLocalRef(jcls_ByteBuffer); - envoy_data native_data = array_to_native_data(env, array); + envoy_data native_data = array_to_native_data(env, array, data_length); env->DeleteLocalRef(array); return native_data; } envoy_data native_data; native_data.bytes = direct_address; - native_data.length = env->GetDirectBufferCapacity(j_data); + native_data.length = data_length; native_data.release = jni_delete_global_ref; native_data.context = env->NewGlobalRef(j_data); diff --git a/library/common/jni/jni_utility.h b/library/common/jni/jni_utility.h index 8d4fd2d4e5..908e247c8f 100644 --- a/library/common/jni/jni_utility.h +++ b/library/common/jni/jni_utility.h @@ -21,6 +21,8 @@ int unbox_integer(JNIEnv* env, jobject boxedInteger); envoy_data array_to_native_data(JNIEnv* env, jbyteArray j_data); +envoy_data array_to_native_data(JNIEnv* env, jbyteArray j_data, size_t data_length); + /** * Utility function that copies envoy_data to jbyteArray. * @@ -47,6 +49,8 @@ jstring native_data_to_string(JNIEnv* env, envoy_data data); envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data); +envoy_data buffer_to_native_data(JNIEnv* env, jobject j_data, size_t data_length); + envoy_data* buffer_to_native_data_ptr(JNIEnv* env, jobject j_data); envoy_headers to_native_headers(JNIEnv* env, jobjectArray headers); diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyHTTPStream.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyHTTPStream.java index bab3acfdad..c7da58a64a 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyHTTPStream.java +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyHTTPStream.java @@ -44,7 +44,7 @@ public void sendHeaders(Map> headers, boolean endStream) { /** * Send data over an open HTTP streamHandle. This method can be invoked multiple - * times. + * times. The data length is the {@link ByteBuffer#capacity}. * * @param data, the data to send. * @param endStream, supplies whether this is the last data in the streamHandle. @@ -53,10 +53,28 @@ public void sendHeaders(Map> headers, boolean endStream) { * on-heap byte array. */ public void sendData(ByteBuffer data, boolean endStream) { + sendData(data, data.capacity(), endStream); + } + + /** + * Send data over an open HTTP streamHandle. This method can be invoked multiple + * times. + * + * @param data, the data to send. + * @param length, number of bytes to send: 0 <= length <= ByteBuffer.capacity() + * @param endStream, supplies whether this is the last data in the streamHandle. + * @throws UnsupportedOperationException - if the provided buffer is neither a + * direct ByteBuffer nor backed by an + * on-heap byte array. + */ + public void sendData(ByteBuffer data, int length, boolean endStream) { + if (length < 0 || length > data.capacity()) { + throw new IllegalArgumentException("Length out of bound"); + } if (data.isDirect()) { - JniLibrary.sendData(streamHandle, data, endStream); + JniLibrary.sendData(streamHandle, data, length, endStream); } else if (data.hasArray()) { - JniLibrary.sendData(streamHandle, data.array(), endStream); + JniLibrary.sendData(streamHandle, data.array(), length, endStream); } else { throw new UnsupportedOperationException("Unsupported ByteBuffer implementation."); } diff --git a/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java b/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java index 04bcea7105..5b4e7e444d 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java @@ -85,10 +85,11 @@ protected static native int startStream(long stream, JvmCallbackContext context, * * @param stream, the stream to send data over. * @param data, the data to send. + * @param length, the size in bytes of the data to send. 0 <= length <= data.length * @param endStream, supplies whether this is the last data in the stream. - * @return int, the resulting status of the operation. + * @return int, the resulting status of the operation. */ - protected static native int sendData(long stream, byte[] data, boolean endStream); + protected static native int sendData(long stream, byte[] data, int length, boolean endStream); /** * Send data over an open HTTP stream. This method can be invoked multiple @@ -96,10 +97,11 @@ protected static native int startStream(long stream, JvmCallbackContext context, * * @param stream, the stream to send data over. * @param data, the data to send; must be a direct ByteBuffer. + * @param length, the size in bytes of the data to send. 0 <= length <= data.capacity() * @param endStream, supplies whether this is the last data in the stream. - * @return int, the resulting status of the operation. + * @return int, the resulting status of the operation. */ - protected static native int sendData(long stream, ByteBuffer data, boolean endStream); + protected static native int sendData(long stream, ByteBuffer data, int length, boolean endStream); /** * Read data from the response stream. Returns immediately. diff --git a/library/kotlin/io/envoyproxy/envoymobile/Stream.kt b/library/kotlin/io/envoyproxy/envoymobile/Stream.kt index 122b7d6fd8..b51fe23b6a 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/Stream.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/Stream.kt @@ -9,7 +9,8 @@ import java.nio.ByteBuffer * Constructed using `StreamPrototype`, and used to write to the network. */ open class Stream( - private val underlyingStream: EnvoyHTTPStream + private val underlyingStream: EnvoyHTTPStream, + private val useByteBufferPosition: Boolean ) { /** * Send headers over the stream. @@ -35,13 +36,19 @@ open class Stream( } /** - * For sending data to an associated stream. + * For sending data to an associated stream. By default, the length sent is the + * **[ByteBuffer.capacity]**. However, the length will rather be **[ByteBuffer.position]** + * if the Stream was configured to do so - see **[StreamPrototype.useByteBufferPosition]**. + * + * Note: the provided ByteBuffer won't be mutated in any case. On the other hand, until the + * stream is closed, any further mutations may lead to an unpredictable outcome. * * @param data Data to send over the stream. * @return This stream, for chaining syntax. */ open fun sendData(data: ByteBuffer): Stream { - underlyingStream.sendData(data, false) + var length = if (useByteBufferPosition) data.position() else data.capacity() + underlyingStream.sendData(data, length, false) return this } @@ -55,12 +62,18 @@ open class Stream( } /** - * Close the stream with a data frame. + * Close the stream with a data frame. By default, the length sent is the + * **[ByteBuffer.capacity]**. However, the length will rather be **[ByteBuffer.position]** + * if the Stream was configured to do so - see **[StreamPrototype.useByteBufferPosition]**. + * + * Note: the provided ByteBuffer won't be mutated in any case. On the other hand, until the + * stream is closed, any further mutations may lead to an unpredictable outcome. * * @param data Data with which to close the stream. */ open fun close(data: ByteBuffer) { - underlyingStream.sendData(data, true) + var length = if (useByteBufferPosition) data.position() else data.capacity() + underlyingStream.sendData(data, length, true) } /** diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt index e140177827..f7fb49745d 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt @@ -16,6 +16,7 @@ import java.util.concurrent.Executors open class StreamPrototype(private val engine: EnvoyEngine) { private val callbacks = StreamCallbacks() private var explicitFlowControl = false + private var useByteBufferPosition = false /** * Start a new stream. @@ -25,7 +26,7 @@ open class StreamPrototype(private val engine: EnvoyEngine) { */ open fun start(executor: Executor = Executors.newSingleThreadExecutor()): Stream { val engineStream = engine.startStream(createCallbacks(executor), explicitFlowControl) - return Stream(engineStream) + return Stream(engineStream, useByteBufferPosition) } /** @@ -44,6 +45,17 @@ open class StreamPrototype(private val engine: EnvoyEngine) { return this } + /** + * Specify how to determine the length of data to send for a given ByteBuffer. + * + * @param enabled Use ByteBuffer's position when true, otherwise use its capacity. + * @return This stream, for chaining syntax. + */ + fun setUseByteBufferPosition(enabled: Boolean): StreamPrototype { + this.useByteBufferPosition = enabled + return this + } + /** * Specify a callback for when response headers are received by the stream. * diff --git a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt index 2643fb2087..b85cf0c8fd 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt @@ -7,7 +7,7 @@ import java.nio.ByteBuffer * Mock implementation of `Stream` that also provides an interface for sending * mocked responses through to the stream's callbacks. Created via `MockStreamPrototype`. */ -class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : Stream(underlyingStream) { +class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : Stream(underlyingStream, useByteBufferPosition = false) { private val mockStream: MockEnvoyHTTPStream = underlyingStream private val mockStreamIntel = object : EnvoyStreamIntel { diff --git a/test/java/integration/AndroidEnvoyFlowTest.java b/test/java/integration/AndroidEnvoyFlowTest.java index 528be83055..7d1bf250c9 100644 --- a/test/java/integration/AndroidEnvoyFlowTest.java +++ b/test/java/integration/AndroidEnvoyFlowTest.java @@ -45,39 +45,30 @@ @RunWith(RobolectricTestRunner.class) public class AndroidEnvoyFlowTest { - private static Engine engine; - private final MockWebServer mockWebServer = new MockWebServer(); + private Engine engine; @BeforeClass public static void loadJniLibrary() { AndroidJniLibrary.loadTestLibrary(); } - @AfterClass - public static void shutdownEngine() { - if (engine != null) { - engine.terminate(); - } - } - @Before public void setUpEngine() throws Exception { - if (engine == null) { - CountDownLatch latch = new CountDownLatch(1); - Context appContext = ApplicationProvider.getApplicationContext(); - engine = new AndroidEngineBuilder(appContext) - .setOnEngineRunning(() -> { - latch.countDown(); - return null; - }) - .build(); - latch.await(); // Don't launch a request before initialization has completed. - } + CountDownLatch latch = new CountDownLatch(1); + Context appContext = ApplicationProvider.getApplicationContext(); + engine = new AndroidEngineBuilder(appContext) + .setOnEngineRunning(() -> { + latch.countDown(); + return null; + }) + .build(); + latch.await(); // Don't launch a request before initialization has completed. } @After - public void shutdownMockWebServer() throws IOException { + public void shutdown() throws IOException { + engine.terminate(); mockWebServer.shutdown(); } @@ -156,6 +147,61 @@ public MockResponse dispatch(RecordedRequest recordedRequest) { assertThat(response.getEnvoyError()).isNull(); } + @Test + public void post_simple_withoutByteBufferPosition() throws Exception { + mockWebServer.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest recordedRequest) { + assertThat(recordedRequest.getMethod()).isEqualTo(RequestMethod.POST.name()); + assertThat(recordedRequest.getBody().readUtf8()).isEqualTo("55555"); + return new MockResponse().setBody("This is my response Body"); + } + }); + ByteBuffer requestBody = ByteBuffer.allocateDirect(5); + requestBody.put("55555".getBytes()); + requestBody.position(3); // The position should be ignored - only capacity matters. + mockWebServer.start(); + RequestScenario requestScenario = new RequestScenario() + .setHttpMethod(RequestMethod.POST) + .setUrl(mockWebServer.url("get/flowers").toString()) + .addBody(requestBody) + .closeBodyStream(); + + Response response = sendRequest(requestScenario); + + assertThat(response.getHeaders().getHttpStatus()).isEqualTo(200); + assertThat(response.getBodyAsString()).isEqualTo("This is my response Body"); + assertThat(response.getEnvoyError()).isNull(); + } + + @Test + public void post_simple_withByteBufferPosition() throws Exception { + mockWebServer.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest recordedRequest) { + assertThat(recordedRequest.getMethod()).isEqualTo(RequestMethod.POST.name()); + assertThat(recordedRequest.getBody().readUtf8()).isEqualTo("This is my request body"); + return new MockResponse().setBody("This is my response Body"); + } + }); + ByteBuffer requestBody = ByteBuffer.allocateDirect(100); + requestBody.put("This is my request body with spurious data".getBytes()); + requestBody.position(23); // Only the first 23 bytes should be sent - the String size is 42. + mockWebServer.start(); + RequestScenario requestScenario = new RequestScenario() + .useByteBufferPosition() + .setHttpMethod(RequestMethod.POST) + .setUrl(mockWebServer.url("get/flowers").toString()) + .addBody("This is my request body") + .closeBodyStream(); + + Response response = sendRequest(requestScenario); + + assertThat(response.getHeaders().getHttpStatus()).isEqualTo(200); + assertThat(response.getBodyAsString()).isEqualTo("This is my response Body"); + assertThat(response.getEnvoyError()).isNull(); + } + @Test public void post_chunkedBody() throws Exception { mockWebServer.setDispatcher(new Dispatcher() { @@ -163,7 +209,7 @@ public void post_chunkedBody() throws Exception { public MockResponse dispatch(RecordedRequest recordedRequest) { assertThat(recordedRequest.getMethod()).isEqualTo(RequestMethod.POST.name()); assertThat(recordedRequest.getBody().readUtf8()) - .isEqualTo("This is the first part of by body. This is the second part of by body."); + .isEqualTo("This is the first part of my body. This is the second part of my body."); return new MockResponse().setBody("This is my response Body"); } }); @@ -172,8 +218,8 @@ public MockResponse dispatch(RecordedRequest recordedRequest) { new RequestScenario() .setHttpMethod(RequestMethod.POST) .setUrl(mockWebServer.url("get/flowers").toString()) - .addBody("This is the first part of by body. ") - .addBody("This is the second part of by body.") + .addBody("This is the first part of my body. ") + .addBody("This is the second part of my body.") .closeBodyStream(); // Content-Length is not provided; must be closed explicitly. Response response = sendRequest(requestScenario); @@ -183,12 +229,60 @@ public MockResponse dispatch(RecordedRequest recordedRequest) { assertThat(response.getEnvoyError()).isNull(); } + @Test + public void post_chunkedBody_withBufferPosition() throws Exception { + String firstChunk = "This is the first chunk of my request body. "; + String secondChunk = "This is the second chunk."; + mockWebServer.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest recordedRequest) { + assertThat(recordedRequest.getBody().readUtf8()).isEqualTo(firstChunk + secondChunk); + return new MockResponse().setBody("This is my response Body"); + } + }); + mockWebServer.start(); + ByteBuffer requestBodyFirstChunk = ByteBuffer.allocateDirect(1024); + requestBodyFirstChunk.put((firstChunk + "spurious data that should be ignored").getBytes()); + requestBodyFirstChunk.position(firstChunk.length()); + ByteBuffer requestBodySecondChunk = ByteBuffer.allocateDirect(100); + requestBodySecondChunk.put((secondChunk + "data beyond ByteBuffer.position()").getBytes()); + requestBodySecondChunk.position(secondChunk.length()); + RequestScenario requestScenario = + new RequestScenario() + .useByteBufferPosition() + .setHttpMethod(RequestMethod.POST) + .setUrl(mockWebServer.url("get/flowers").toString()) + .addBody(requestBodyFirstChunk) + .addBody(requestBodySecondChunk) + .closeBodyStream(); // Content-Length is not provided; must be closed explicitly. + + Response response = sendRequest(requestScenario); + + assertThat(response.getHeaders().getHttpStatus()).isEqualTo(200); + assertThat(response.getBodyAsString()).isEqualTo("This is my response Body"); + assertThat(response.getEnvoyError()).isNull(); + } + + @Test + public void post_cancelBeforeSendingRequestBody() throws Exception { + RequestScenario requestScenario = new RequestScenario() + .setHttpMethod(RequestMethod.POST) + .setUrl(mockWebServer.url("get/flowers").toString()) + .addBody("Request body") + .cancelBeforeSendingRequestBody(); + + Response response = sendRequest(requestScenario); + + assertThat(response.isCancelled()).isTrue(); + } + private Response sendRequest(RequestScenario requestScenario) throws Exception { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference response = new AtomicReference<>(new Response()); Stream stream = engine.streamClient() .newStreamPrototype() + .setUseByteBufferPosition(requestScenario.useByteBufferPosition) .setOnResponseHeaders((responseHeaders, endStream, ignored) -> { response.get().setHeaders(responseHeaders); if (endStream) { @@ -220,8 +314,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { }) .start(Executors.newSingleThreadExecutor()) .sendHeaders(requestScenario.getHeaders(), !requestScenario.hasBody()); - requestScenario.getBodyChunks().forEach(stream::sendData); - requestScenario.getClosingBodyChunk().ifPresent(stream::close); + if (requestScenario.cancelBeforeSendingRequestBody) { + stream.cancel(); + } else { + requestScenario.getBodyChunks().forEach(stream::sendData); + requestScenario.getClosingBodyChunk().ifPresent(stream::close); + } latch.await(); response.get().throwAssertionErrorIfAny(); @@ -229,11 +327,14 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { } private static class RequestScenario { + private URL url; private RequestMethod method = null; private final List bodyChunks = new ArrayList<>(); private final List> headers = new ArrayList<>(); private boolean closeBodyStream = false; + private boolean cancelBeforeSendingRequestBody = false; + private boolean useByteBufferPosition; RequestHeaders getHeaders() { RequestHeadersBuilder requestHeadersBuilder = @@ -266,15 +367,19 @@ RequestScenario setUrl(String url) throws MalformedURLException { return this; } + RequestScenario addBody(String requestBodyChunk) { + return addBody(requestBodyChunk.getBytes()); + } + RequestScenario addBody(byte[] requestBodyChunk) { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(requestBodyChunk.length); byteBuffer.put(requestBodyChunk); - bodyChunks.add(byteBuffer); - return this; + return addBody(byteBuffer); } - RequestScenario addBody(String requestBodyChunk) { - return addBody(requestBodyChunk.getBytes()); + RequestScenario addBody(ByteBuffer requestBodyChunk) { + bodyChunks.add(requestBodyChunk); + return this; } RequestScenario addHeader(String key, String value) { @@ -286,6 +391,16 @@ RequestScenario closeBodyStream() { closeBodyStream = true; return this; } + + RequestScenario cancelBeforeSendingRequestBody() { + cancelBeforeSendingRequestBody = true; + return this; + } + + RequestScenario useByteBufferPosition() { + useByteBufferPosition = true; + return this; + } } private static class Response { From c967e28c509cc2f522b4ad0eb9a5dd00c27fbd17 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Tue, 30 Nov 2021 10:30:05 -0800 Subject: [PATCH 06/25] add no-op ios Signed-off-by: Jose Nino --- library/objective-c/EnvoyConfiguration.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/objective-c/EnvoyConfiguration.m b/library/objective-c/EnvoyConfiguration.m index 13ace6dbd8..498b293782 100644 --- a/library/objective-c/EnvoyConfiguration.m +++ b/library/objective-c/EnvoyConfiguration.m @@ -106,6 +106,9 @@ - (nullable NSString *)resolveTemplate:(NSString *)templateYAML { withString:customRoutes]; templateYAML = [templateYAML stringByReplacingOccurrencesOfString:@"#{custom_filters}" withString:customFilters]; + // No template is currently needed for Apple-based DNS resolver. + templateYAML = [templateYAML stringByReplacingOccurrencesOfString:@"#{dns_resolver_config}" + withString:@""]; NSMutableString *definitions = [[NSMutableString alloc] initWithString:@"!ignore platform_defs:\n"]; From e279b305ce2c65613da9c56d08ab08b47d52b26a Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Tue, 30 Nov 2021 15:41:15 -0800 Subject: [PATCH 07/25] Revert "incompletely used APIs for final stream metrics (#1937)" This reverts commit b41131b77f9d3f3d50667bce320351a39a110d7c. --- examples/java/hello_world/MainActivity.java | 2 +- .../kotlin/hello_world/AsyncDemoFilter.kt | 13 +-- .../kotlin/hello_world/BufferDemoFilter.kt | 13 +-- examples/kotlin/hello_world/DemoFilter.kt | 13 +-- examples/kotlin/hello_world/MainActivity.kt | 2 +- library/cc/stream_callbacks.cc | 7 +- .../filters/http/platform_bridge/c_types.h | 5 +- .../filters/http/platform_bridge/filter.cc | 16 +--- .../filters/http/platform_bridge/filter.h | 1 - library/common/http/client.cc | 84 +---------------- library/common/http/client.h | 19 +--- library/common/jni/jni_interface.cc | 68 ++++---------- library/common/jni/jni_utility.cc | 27 ------ library/common/jni/jni_utility.h | 3 - library/common/types/c_types.h | 52 +--------- .../io/envoyproxy/envoymobile/engine/BUILD | 1 - .../engine/EnvoyFinalStreamIntelImpl.java | 94 ------------------- .../engine/JvmCallbackContext.java | 44 ++------- .../envoymobile/engine/JvmFilterContext.java | 28 +----- .../envoyproxy/envoymobile/engine/types/BUILD | 1 - .../engine/types/EnvoyFinalStreamIntel.java | 67 ------------- .../engine/types/EnvoyHTTPCallbacks.java | 18 +--- .../engine/types/EnvoyHTTPFilter.java | 20 +--- .../chromium/net/impl/CronetUrlRequest.java | 8 +- .../kotlin/io/envoyproxy/envoymobile/BUILD | 1 - .../envoymobile/FinalStreamIntel.kt | 57 ----------- .../envoyproxy/envoymobile/StreamCallbacks.kt | 22 ++--- .../envoyproxy/envoymobile/StreamPrototype.kt | 27 +----- .../envoyproxy/envoymobile/filters/Filter.kt | 15 +-- .../envoymobile/filters/ResponseFilter.kt | 17 +--- .../envoymobile/grpc/GRPCStreamPrototype.kt | 4 +- .../envoymobile/mocks/MockStream.kt | 21 +---- .../platform_bridge_filter_test.cc | 2 +- test/common/http/client_test.cc | 18 ++-- .../integration/client_integration_test.cc | 6 +- test/common/main_interface_test.cc | 30 +++--- .../AndroidEnvoyExplicitFlowTest.java | 4 +- .../integration/AndroidEnvoyFlowTest.java | 4 +- test/kotlin/integration/CancelStreamTest.kt | 8 +- .../integration/DrainConnectionsTest.kt | 4 +- .../integration/GRPCReceiveErrorTest.kt | 12 +-- test/kotlin/integration/ReceiveDataTest.kt | 2 +- test/kotlin/integration/ReceiveErrorTest.kt | 12 +-- test/kotlin/integration/SendDataTest.kt | 2 +- test/kotlin/integration/SendHeadersTest.kt | 2 +- test/kotlin/integration/SendTrailersTest.kt | 2 +- .../integration/StreamIdleTimeoutTest.kt | 8 +- 47 files changed, 128 insertions(+), 758 deletions(-) delete mode 100644 library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java delete mode 100644 library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java delete mode 100644 library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt diff --git a/examples/java/hello_world/MainActivity.java b/examples/java/hello_world/MainActivity.java index cf121e56eb..5d1ebcd4ac 100644 --- a/examples/java/hello_world/MainActivity.java +++ b/examples/java/hello_world/MainActivity.java @@ -125,7 +125,7 @@ private void makeRequest() { } return Unit.INSTANCE; }) - .setOnError((error, ignored, also_ignored) -> { + .setOnError((error, ignored) -> { String message = "failed with error after " + error.getAttemptCount() + " attempts: " + error.getMessage(); Log.d("MainActivity", message); diff --git a/examples/kotlin/hello_world/AsyncDemoFilter.kt b/examples/kotlin/hello_world/AsyncDemoFilter.kt index 72f6ab8463..214e01bdb6 100644 --- a/examples/kotlin/hello_world/AsyncDemoFilter.kt +++ b/examples/kotlin/hello_world/AsyncDemoFilter.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterResumeStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilterCallbacks import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -79,18 +78,10 @@ class AsyncDemoFilter : AsyncResponseFilter { } @Suppress("EmptyFunctionBlock") - override fun onError( - error: EnvoyError, - streamIntel: StreamIntel, - finalStreamIntel: FinalStreamIntel - ) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { } @Suppress("EmptyFunctionBlock") - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { - } - - @Suppress("EmptyFunctionBlock") - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { } } diff --git a/examples/kotlin/hello_world/BufferDemoFilter.kt b/examples/kotlin/hello_world/BufferDemoFilter.kt index dee61511e5..de6151dcdb 100644 --- a/examples/kotlin/hello_world/BufferDemoFilter.kt +++ b/examples/kotlin/hello_world/BufferDemoFilter.kt @@ -4,7 +4,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -57,18 +56,10 @@ class BufferDemoFilter : ResponseFilter { } @Suppress("EmptyFunctionBlock") - override fun onError( - error: EnvoyError, - streamIntel: StreamIntel, - finalStreamIntel: FinalStreamIntel - ) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { } @Suppress("EmptyFunctionBlock") - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { - } - - @Suppress("EmptyFunctionBlock") - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { } } diff --git a/examples/kotlin/hello_world/DemoFilter.kt b/examples/kotlin/hello_world/DemoFilter.kt index f9c005f997..a0f12eac69 100644 --- a/examples/kotlin/hello_world/DemoFilter.kt +++ b/examples/kotlin/hello_world/DemoFilter.kt @@ -5,7 +5,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -41,19 +40,11 @@ class DemoFilter : ResponseFilter { return FilterTrailersStatus.Continue(trailers) } - override fun onError( - error: EnvoyError, - streamIntel: StreamIntel, - finalStreamIntel: FinalStreamIntel - ) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { Log.d("DemoFilter", "On error!") } - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { Log.d("DemoFilter", "On cancel!") } - - @Suppress("EmptyFunctionBlock") - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { - } } diff --git a/examples/kotlin/hello_world/MainActivity.kt b/examples/kotlin/hello_world/MainActivity.kt index 7fc060ee25..d58c7b40c1 100644 --- a/examples/kotlin/hello_world/MainActivity.kt +++ b/examples/kotlin/hello_world/MainActivity.kt @@ -135,7 +135,7 @@ class MainActivity : Activity() { recyclerView.post { viewAdapter.add(Failure(message)) } } } - .setOnError { error, _, _ -> + .setOnError { error, _ -> val attemptCount = error.attemptCount ?: -1 val message = "failed with error after $attemptCount attempts: ${error.message}" Log.d("MainActivity", message) diff --git a/library/cc/stream_callbacks.cc b/library/cc/stream_callbacks.cc index 1a6203f9cd..ece9ce32a0 100644 --- a/library/cc/stream_callbacks.cc +++ b/library/cc/stream_callbacks.cc @@ -50,8 +50,7 @@ void* c_on_trailers(envoy_headers metadata, envoy_stream_intel, void* context) { return context; } -void* c_on_error(envoy_error raw_error, envoy_stream_intel, envoy_final_stream_intel, - void* context) { +void* c_on_error(envoy_error raw_error, envoy_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_error.has_value()) { @@ -66,7 +65,7 @@ void* c_on_error(envoy_error raw_error, envoy_stream_intel, envoy_final_stream_i return nullptr; } -void* c_on_complete(envoy_stream_intel, envoy_final_stream_intel, void* context) { +void* c_on_complete(envoy_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_complete.has_value()) { @@ -77,7 +76,7 @@ void* c_on_complete(envoy_stream_intel, envoy_final_stream_intel, void* context) return nullptr; } -void* c_on_cancel(envoy_stream_intel, envoy_final_stream_intel, void* context) { +void* c_on_cancel(envoy_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_cancel.has_value()) { diff --git a/library/common/extensions/filters/http/platform_bridge/c_types.h b/library/common/extensions/filters/http/platform_bridge/c_types.h index 00154db773..d0849ceb14 100644 --- a/library/common/extensions/filters/http/platform_bridge/c_types.h +++ b/library/common/extensions/filters/http/platform_bridge/c_types.h @@ -137,15 +137,12 @@ typedef envoy_filter_resume_status (*envoy_filter_on_resume_f)( /** * Function signature for on-cancellation filter invocations. */ -typedef void (*envoy_filter_on_cancel_f)(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, - const void* context); +typedef void (*envoy_filter_on_cancel_f)(envoy_stream_intel stream_intel, const void* context); /** * Function signature for on-error filter invocations. */ typedef void (*envoy_filter_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, const void* context); /** diff --git a/library/common/extensions/filters/http/platform_bridge/filter.cc b/library/common/extensions/filters/http/platform_bridge/filter.cc index 19cdba7d17..4ca94f0c5e 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.cc +++ b/library/common/extensions/filters/http/platform_bridge/filter.cc @@ -152,8 +152,7 @@ void PlatformBridgeFilter::onDestroy() { // If the filter chain is destroyed before a response is received, treat as cancellation. if (!response_filter_base_->state_.stream_complete_ && platform_filter_.on_cancel) { ENVOY_LOG(trace, "PlatformBridgeFilter({})->on_cancel", filter_name_); - platform_filter_.on_cancel(streamIntel(), finalStreamIntel(), - platform_filter_.instance_context); + platform_filter_.on_cancel(streamIntel(), platform_filter_.instance_context); } // Allow nullptr as no-op only if nothing was initialized. @@ -182,21 +181,12 @@ Http::LocalErrorStatus PlatformBridgeFilter::onLocalReply(const LocalReplyData& envoy_data error_message = Data::Utility::copyToBridgeData(reply.details_); int32_t attempts = static_cast(info.attemptCount().value_or(0)); platform_filter_.on_error({error_code, error_message, attempts}, streamIntel(), - finalStreamIntel(), platform_filter_.instance_context); + platform_filter_.instance_context); } return Http::LocalErrorStatus::ContinueAndResetStream; } -envoy_final_stream_intel PlatformBridgeFilter::finalStreamIntel() { - RELEASE_ASSERT(decoder_callbacks_, "StreamInfo accessed before filter callbacks are set"); - // FIXME: Stream handle cannot currently be set from the filter context. - envoy_final_stream_intel final_stream_intel; - memset(&final_stream_intel, 0, sizeof(final_stream_intel)); - // TODO(alyssawilk) set stream intel from a shared helper function. - return final_stream_intel; -} - envoy_stream_intel PlatformBridgeFilter::streamIntel() { RELEASE_ASSERT(decoder_callbacks_, "StreamInfo accessed before filter callbacks are set"); auto& info = decoder_callbacks_->streamInfo(); @@ -473,7 +463,7 @@ Http::FilterHeadersStatus PlatformBridgeFilter::encodeHeaders(Http::ResponseHead if (platform_filter_.on_error) { platform_filter_.on_error({error_code, error_message, attempt_count}, streamIntel(), - finalStreamIntel(), platform_filter_.instance_context); + platform_filter_.instance_context); } else { release_envoy_data(error_message); } diff --git a/library/common/extensions/filters/http/platform_bridge/filter.h b/library/common/extensions/filters/http/platform_bridge/filter.h index 0a495363c8..84e00182d5 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.h +++ b/library/common/extensions/filters/http/platform_bridge/filter.h @@ -87,7 +87,6 @@ class PlatformBridgeFilter final : public Http::PassThroughFilter, void dumpState(std::ostream& os, int indent_level = 0) const override; // Common stream instrumentation. - envoy_final_stream_intel finalStreamIntel(); envoy_stream_intel streamIntel(); // Filter state. diff --git a/library/common/http/client.cc b/library/common/http/client.cc index 5bba847be6..0bdf7c153c 100644 --- a/library/common/http/client.cc +++ b/library/common/http/client.cc @@ -18,29 +18,6 @@ namespace Envoy { namespace Http { -namespace { - -void setFromOptional(uint64_t& to_set, const absl::optional& time) { - if (time.has_value()) { - to_set = std::chrono::duration_cast(time.value().time_since_epoch()) - .count(); - } -} - -void setFromOptional(long& to_set, absl::optional time, long offset) { - if (time.has_value()) { - to_set = offset + std::chrono::duration_cast(time.value()).count(); - } -} - -void setFromOptional(long& to_set, const absl::optional& time) { - if (time.has_value()) { - to_set = std::chrono::duration_cast(time.value().time_since_epoch()) - .count(); - } -} - -} // namespace /** * IMPORTANT: stream closure semantics in envoy mobile depends on the fact that the HCM fires a @@ -183,29 +160,6 @@ void Client::DirectStreamCallbacks::sendTrailersToBridge(const ResponseTrailerMa onComplete(); } -void Client::DirectStreamCallbacks::setFinalStreamIntel(envoy_final_stream_intel& final_intel) { - memset(&final_intel, 0, sizeof(envoy_final_stream_intel)); - - final_intel.request_start_ms = direct_stream_.latency_info_.request_start_ms; - if (direct_stream_.latency_info_.upstream_info_) { - const StreamInfo::UpstreamTiming& timing = - direct_stream_.latency_info_.upstream_info_->upstreamTiming(); - setFromOptional(final_intel.sending_start_ms, timing.first_upstream_tx_byte_sent_); - setFromOptional(final_intel.sending_end_ms, timing.last_upstream_tx_byte_sent_); - setFromOptional(final_intel.response_start_ms, timing.first_upstream_rx_byte_received_); - setFromOptional(final_intel.connect_start_ms, timing.upstream_connect_start_); - setFromOptional(final_intel.connect_end_ms, timing.upstream_connect_complete_); - setFromOptional(final_intel.ssl_start_ms, timing.upstream_connect_complete_); - setFromOptional(final_intel.ssl_end_ms, timing.upstream_handshake_complete_); - } - final_intel.dns_start_ms = direct_stream_.latency_info_.dns_start_ms; - final_intel.dns_end_ms = direct_stream_.latency_info_.dns_end_ms; - final_intel.request_end_ms = direct_stream_.latency_info_.request_end_ms; - final_intel.socket_reused = 0; // TODO(alyssawilk) set. - final_intel.sent_byte_count = direct_stream_.latency_info_.sent_byte_count; - final_intel.received_byte_count = direct_stream_.latency_info_.received_byte_count; -} - void Client::DirectStreamCallbacks::resumeData(int32_t bytes_to_send) { ASSERT(explicit_flow_control_); ASSERT(bytes_to_send > 0); @@ -255,10 +209,7 @@ void Client::DirectStreamCallbacks::onComplete() { } else { http_client_.stats().stream_failure_.inc(); } - - envoy_final_stream_intel final_intel; - setFinalStreamIntel(final_intel); - bridge_callbacks_.on_complete(streamIntel(), final_intel, bridge_callbacks_.context); + bridge_callbacks_.on_complete(streamIntel(), bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onError() { @@ -285,9 +236,7 @@ void Client::DirectStreamCallbacks::onError() { direct_stream_.stream_handle_); http_client_.stats().stream_failure_.inc(); - envoy_final_stream_intel final_intel; - setFinalStreamIntel(final_intel); - bridge_callbacks_.on_error(error_.value(), streamIntel(), final_intel, bridge_callbacks_.context); + bridge_callbacks_.on_error(error_.value(), streamIntel(), bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onSendWindowAvailable() { @@ -297,12 +246,9 @@ void Client::DirectStreamCallbacks::onSendWindowAvailable() { void Client::DirectStreamCallbacks::onCancel() { ScopeTrackerScopeState scope(&direct_stream_, http_client_.scopeTracker()); - ENVOY_LOG(debug, "[S{}] dispatching to platform cancel stream", direct_stream_.stream_handle_); http_client_.stats().stream_cancel_.inc(); - envoy_final_stream_intel final_intel; - setFinalStreamIntel(final_intel); - bridge_callbacks_.on_cancel(streamIntel(), final_intel, bridge_callbacks_.context); + bridge_callbacks_.on_cancel(streamIntel(), bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onHasBufferedData() { @@ -328,29 +274,6 @@ void Client::DirectStream::saveLatestStreamIntel() { stream_intel_.connection_id = info.upstreamConnectionId().value_or(-1); stream_intel_.stream_id = static_cast(stream_handle_); stream_intel_.attempt_count = info.attemptCount().value_or(0); - saveFinalStreamIntel(); -} - -void Client::DirectStream::saveFinalStreamIntel() { - const auto& info = request_decoder_->streamInfo(); - latency_info_.request_start_ms = std::chrono::duration_cast( - info.startTimeMonotonic().time_since_epoch()) - .count(); - latency_info_.sent_byte_count = info.bytesSent(); - latency_info_.received_byte_count = info.bytesReceived(); - setFromOptional(latency_info_.request_end_ms, info.lastDownstreamRxByteReceived(), - latency_info_.request_start_ms); - setFromOptional(latency_info_.dns_start_ms, - request_decoder_->streamInfo().downstreamTiming().getValue( - "envoy.dynamic_forward_proxy.dns_start_ms")); - setFromOptional(latency_info_.dns_end_ms, - request_decoder_->streamInfo().downstreamTiming().getValue( - "envoy.dynamic_forward_proxy.dns_end_ms")); - // TODO(alyssawilk) sort out why upstream info is problematic for cronvoy tests. - return; - if (info.upstreamInfo().has_value()) { - latency_info_.upstream_info_ = request_decoder_->streamInfo().upstreamInfo(); - } } envoy_error Client::DirectStreamCallbacks::streamError() { @@ -386,7 +309,6 @@ void Client::DirectStream::resetStream(StreamResetReason reason) { // This seems in line with other codec implementations, and so the assumption is that this is in // line with upstream expectations. // TODO(goaway): explore an upstream fix to get the HCM to clean up ActiveStream itself. - saveFinalStreamIntel(); runResetCallbacks(reason); if (!parent_.getStream(stream_handle_, GetStreamFilters::ALLOW_FOR_ALL_STREAMS)) { // We don't assert here, because Envoy will issue a stream reset if a stream closes remotely diff --git a/library/common/http/client.h b/library/common/http/client.h index 982fc0cba1..455f67fdc5 100644 --- a/library/common/http/client.h +++ b/library/common/http/client.h @@ -37,17 +37,6 @@ struct HttpClientStats { ALL_HTTP_CLIENT_STATS(GENERATE_COUNTER_STRUCT) }; -struct LatencyInfo { - long request_start_ms = 0; - long request_end_ms = 0; - long dns_start_ms = 0; - long dns_end_ms = 0; - long sent_byte_count = 0; - long received_byte_count = 0; - // Latest latency info received from StreamInfo. - std::shared_ptr upstream_info_{}; -}; - /** * Manages HTTP streams, and provides an interface to interact with them. */ @@ -177,8 +166,6 @@ class Client : public Logger::Loggable { // than bytes_to_send. void resumeData(int32_t bytes_to_send); - void setFinalStreamIntel(envoy_final_stream_intel& final_intel); - private: bool hasBufferedData() { return response_data_.get() && response_data_->length() != 0; } @@ -254,12 +241,9 @@ class Client : public Logger::Loggable { response_details_ = response_details; } - // Latches stream information as it may not be available when accessed. + // Saves latest "Intel" data as it may not be available when accessed. void saveLatestStreamIntel(); - // Latches latency info from stream info before it goes away. - void saveFinalStreamIntel(); - const envoy_stream_t stream_handle_; // Used to issue outgoing HTTP stream operations. @@ -287,7 +271,6 @@ class Client : public Logger::Loggable { bool explicit_flow_control_ = false; // Latest intel data retrieved from the StreamInfo. envoy_stream_intel stream_intel_; - LatencyInfo latency_info_; StreamInfo::BytesMeterSharedPtr bytes_meter_; }; diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index 1905824087..0f900458e9 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -673,62 +673,40 @@ jvm_http_filter_on_resume_response(envoy_headers* headers, envoy_data* data, stream_intel, context); } -static void* call_jvm_on_complete(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - jni_log("[Envoy]", "jvm_on_complete"); - - JNIEnv* env = get_env(); - jobject j_context = static_cast(context); - - jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); - jmethodID jmid_onComplete = - env->GetMethodID(jcls_JvmObserverContext, "onComplete", "([J[J)Ljava/lang/Object;"); - - jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); - jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); - jobject result = - env->CallObjectMethod(j_context, jmid_onComplete, j_stream_intel, j_final_stream_intel); - - env->DeleteLocalRef(j_stream_intel); - env->DeleteLocalRef(j_final_stream_intel); - env->DeleteLocalRef(jcls_JvmObserverContext); - return result; +static void* jvm_on_complete(envoy_stream_intel, void* context) { + jni_delete_global_ref(context); + return NULL; } -static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { +static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_error"); JNIEnv* env = get_env(); jobject j_context = static_cast(context); jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); jmethodID jmid_onError = - env->GetMethodID(jcls_JvmObserverContext, "onError", "(I[BI[J[J)Ljava/lang/Object;"); + env->GetMethodID(jcls_JvmObserverContext, "onError", "(I[BI[J)Ljava/lang/Object;"); jbyteArray j_error_message = native_data_to_array(env, error.message); jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); - jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); jobject result = env->CallObjectMethod(j_context, jmid_onError, error.error_code, j_error_message, - error.attempt_count, j_stream_intel, j_final_stream_intel); + error.attempt_count, j_stream_intel); env->DeleteLocalRef(j_stream_intel); - env->DeleteLocalRef(j_final_stream_intel); env->DeleteLocalRef(j_error_message); env->DeleteLocalRef(jcls_JvmObserverContext); release_envoy_error(error); return result; } -static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_error(error, stream_intel, final_stream_intel, context); +static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, void* context) { + void* result = call_jvm_on_error(error, stream_intel, context); jni_delete_global_ref(context); return result; } -static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { +static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_cancel"); JNIEnv* env = get_env(); @@ -736,44 +714,30 @@ static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); jmethodID jmid_onCancel = - env->GetMethodID(jcls_JvmObserverContext, "onCancel", "([J[J)Ljava/lang/Object;"); + env->GetMethodID(jcls_JvmObserverContext, "onCancel", "([J)Ljava/lang/Object;"); jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); - jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); - jobject result = - env->CallObjectMethod(j_context, jmid_onCancel, j_stream_intel, j_final_stream_intel); + jobject result = env->CallObjectMethod(j_context, jmid_onCancel, j_stream_intel); env->DeleteLocalRef(j_stream_intel); - env->DeleteLocalRef(j_final_stream_intel); env->DeleteLocalRef(jcls_JvmObserverContext); return result; } -static void* jvm_on_complete(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_complete(stream_intel, final_stream_intel, context); - jni_delete_global_ref(context); - return result; -} - -static void* jvm_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_cancel(stream_intel, final_stream_intel, context); +static void* jvm_on_cancel(envoy_stream_intel stream_intel, void* context) { + void* result = call_jvm_on_cancel(stream_intel, context); jni_delete_global_ref(context); return result; } static void jvm_http_filter_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, const void* context) { - call_jvm_on_error(error, stream_intel, final_stream_intel, const_cast(context)); + call_jvm_on_error(error, stream_intel, const_cast(context)); } -static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, - const void* context) { - call_jvm_on_cancel(stream_intel, final_stream_intel, const_cast(context)); +static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, const void* context) { + call_jvm_on_cancel(stream_intel, const_cast(context)); } static void* jvm_on_send_window_available(envoy_stream_intel stream_intel, void* context) { diff --git a/library/common/jni/jni_utility.cc b/library/common/jni/jni_utility.cc index 7362673d59..ccb970c722 100644 --- a/library/common/jni/jni_utility.cc +++ b/library/common/jni/jni_utility.cc @@ -97,33 +97,6 @@ jlongArray native_stream_intel_to_array(JNIEnv* env, envoy_stream_intel stream_i return j_array; } -jlongArray native_final_stream_intel_to_array(JNIEnv* env, - envoy_final_stream_intel final_stream_intel) { - jlongArray j_array = env->NewLongArray(14); - jlong* critical_array = static_cast(env->GetPrimitiveArrayCritical(j_array, nullptr)); - RELEASE_ASSERT(critical_array != nullptr, "unable to allocate memory in jni_utility"); - - critical_array[0] = static_cast(final_stream_intel.request_start_ms); - critical_array[1] = static_cast(final_stream_intel.dns_start_ms); - critical_array[2] = static_cast(final_stream_intel.dns_end_ms); - critical_array[3] = static_cast(final_stream_intel.connect_start_ms); - critical_array[4] = static_cast(final_stream_intel.connect_end_ms); - critical_array[5] = static_cast(final_stream_intel.ssl_start_ms); - critical_array[6] = static_cast(final_stream_intel.ssl_end_ms); - critical_array[7] = static_cast(final_stream_intel.sending_start_ms); - critical_array[8] = static_cast(final_stream_intel.sending_end_ms); - critical_array[9] = static_cast(final_stream_intel.response_start_ms); - critical_array[10] = static_cast(final_stream_intel.request_end_ms); - critical_array[11] = static_cast(final_stream_intel.socket_reused); - critical_array[12] = static_cast(final_stream_intel.sent_byte_count); - critical_array[13] = static_cast(final_stream_intel.received_byte_count); - - // Here '0' (for which there is no named constant) indicates we want to commit the changes back - // to the JVM and free the c array, where applicable. - env->ReleasePrimitiveArrayCritical(j_array, critical_array, 0); - return j_array; -} - jobject native_map_to_map(JNIEnv* env, envoy_map map) { jclass jcls_hashMap = env->FindClass("java/util/HashMap"); jmethodID jmid_hashMapInit = env->GetMethodID(jcls_hashMap, "", "(I)V"); diff --git a/library/common/jni/jni_utility.h b/library/common/jni/jni_utility.h index f75529a3a5..908e247c8f 100644 --- a/library/common/jni/jni_utility.h +++ b/library/common/jni/jni_utility.h @@ -35,9 +35,6 @@ jbyteArray native_data_to_array(JNIEnv* env, envoy_data data); jlongArray native_stream_intel_to_array(JNIEnv* env, envoy_stream_intel stream_intel); -jlongArray native_final_stream_intel_to_array(JNIEnv* env, - envoy_final_stream_intel final_stream_intel); - /** * Utility function that copies envoy_map to a java HashMap jobject. * diff --git a/library/common/types/c_types.h b/library/common/types/c_types.h index 417a1872aa..318a0f0af7 100644 --- a/library/common/types/c_types.h +++ b/library/common/types/c_types.h @@ -141,8 +141,7 @@ typedef struct { } envoy_error; /** - * Contains internal HTTP stream metrics, context, and other details which are - * sent with most callbacks. + * Contains internal HTTP stream metrics, context, and other details. * * Note these values may change over the lifecycle of a stream. */ @@ -155,44 +154,6 @@ typedef struct { uint64_t attempt_count; } envoy_stream_intel; -/** - * Contains internal HTTP stream metrics which sent at stream end. - */ -typedef struct { - // The time the request started, in ms since the epoch. - uint64_t request_start_ms; - // The time the DNS resolution for this request started, in ms since the epoch. - uint64_t dns_start_ms; - // The time the DNS resolution for this request completed, in ms since the epoch. - uint64_t dns_end_ms; - // The time the upstream connection started, in ms since the epoch. - // This may not be set if socket_reused is false. - uint64_t connect_start_ms; - // The time the upstream connection completed, in ms since the epoch. - // This may not be set if socket_reused is false. - uint64_t connect_end_ms; - // The time the SSL handshake started, in ms since the epoch. - // This may not be set if socket_reused is false. - uint64_t ssl_start_ms; - // The time the SSL handshake completed, in ms since the epoch. - // This may not be set if socket_reused is false. - uint64_t ssl_end_ms; - // The time the first byte of the request was sent upstream, in ms since the epoch. - uint64_t sending_start_ms; - // The time the last byte of the request was sent upstream, in ms since the epoch. - uint64_t sending_end_ms; - // The time the first byte of the response was received, in ms since the epoch. - uint64_t response_start_ms; - // The time the last byte of the request was received, in ms since the epoch. - uint64_t request_end_ms; - // True if the upstream socket had been used previously. - uint64_t socket_reused; - // The number of bytes sent upstream. - uint64_t sent_byte_count; - // The number of bytes received from upstream. - uint64_t received_byte_count; -} envoy_final_stream_intel; - #ifdef __cplusplus extern "C" { // utility functions #endif @@ -337,13 +298,12 @@ typedef void* (*envoy_on_trailers_f)(envoy_headers trailers, envoy_stream_intel * * @param envoy_error, the error received/caused by the async HTTP stream. * @param stream_intel, contains internal stream metrics, context, and other details. - * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); + void* context); /** * Callback signature for when an HTTP stream bi-directionally completes without error. @@ -351,13 +311,11 @@ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_i * This is a TERMINAL callback. Exactly one terminal callback will be called per stream. * * @param stream_intel, contains internal stream metrics, context, and other details. - * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); +typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, void* context); /** * Callback signature for when an HTTP stream is cancelled. @@ -365,13 +323,11 @@ typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, * This is a TERMINAL callback. Exactly one terminal callback will be called per stream. * * @param stream_intel, contains internal stream metrics, context, and other details. - * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); +typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, void* context); /** * Called when the envoy engine is exiting. diff --git a/library/java/io/envoyproxy/envoymobile/engine/BUILD b/library/java/io/envoyproxy/envoymobile/engine/BUILD index 3b0f29c85e..7fbf08cf5f 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/BUILD +++ b/library/java/io/envoyproxy/envoymobile/engine/BUILD @@ -25,7 +25,6 @@ java_library( "EnvoyConfiguration.java", "EnvoyEngine.java", "EnvoyEngineImpl.java", - "EnvoyFinalStreamIntelImpl.java", "EnvoyHTTPFilterCallbacksImpl.java", "EnvoyHTTPStream.java", "EnvoyNativeFilterConfig.java", diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java deleted file mode 100644 index 050cede043..0000000000 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java +++ /dev/null @@ -1,94 +0,0 @@ -package io.envoyproxy.envoymobile.engine; - -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel; - -class EnvoyFinalStreamIntelImpl implements EnvoyFinalStreamIntel { - private long requestStartMs; - private long dnsStartMs; - private long dnsEndMs; - private long connectStartMs; - private long connectEndMs; - private long sslStartMs; - private long sslEndMs; - private long sendingStartMs; - private long sendingEndMs; - private long responseStartMs; - private long requestEndMs; - private boolean socketReused; - private long sentByteCount; - private long receivedByteCount; - - EnvoyFinalStreamIntelImpl(long[] values) { - requestStartMs = values[0]; - dnsStartMs = values[1]; - dnsEndMs = values[2]; - connectStartMs = values[3]; - connectEndMs = values[4]; - sslStartMs = values[5]; - sslEndMs = values[6]; - sendingStartMs = values[7]; - sendingEndMs = values[8]; - responseStartMs = values[9]; - requestEndMs = values[10]; - socketReused = values[11] != 0; - sentByteCount = values[12]; - receivedByteCount = values[13]; - } - - @Override - public long getRequestStartMs() { - return requestStartMs; - } - @Override - public long getDnsStartMs() { - return dnsStartMs; - } - @Override - public long getDnsEndMs() { - return dnsEndMs; - } - @Override - public long getConnectStartMs() { - return connectStartMs; - } - @Override - public long getConnectEndMs() { - return connectEndMs; - } - @Override - public long getSslStartMs() { - return sslStartMs; - } - @Override - public long getSslEndMs() { - return sslEndMs; - } - @Override - public long getSendingStartMs() { - return sendingStartMs; - } - @Override - public long getSendingEndMs() { - return sendingEndMs; - } - @Override - public long getResponseStartMs() { - return responseStartMs; - } - @Override - public long getRequestEndMs() { - return requestEndMs; - } - @Override - public boolean getSocketReused() { - return socketReused; - } - @Override - public long getSentByteCount() { - return sentByteCount; - } - @Override - public long getReceivedByteCount() { - return receivedByteCount; - } -} diff --git a/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java b/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java index e37972fd3b..b93ab7f390 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java @@ -90,22 +90,18 @@ public void run() { /** * Dispatches error received from the JNI layer up to the platform. * - * @param errorCode, the error code. - * @param message, the error message. - * @param attemptCount, the number of times an operation was attempted before firing this - * error. - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. - * @return Object, not used for response callbacks. + * @param errorCode, the error code. + * @param message, the error message. + * @param attemptCount, the number of times an operation was attempted before firing this error. + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @return Object, not used for response callbacks. */ - public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel, - long[] finalStreamIntel) { + public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel) { callbacks.getExecutor().execute(new Runnable() { public void run() { String errorMessage = new String(message); callbacks.onError(errorCode, errorMessage, attemptCount, - new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + new EnvoyStreamIntelImpl(streamIntel)); } }); @@ -115,16 +111,14 @@ public void run() { /** * Dispatches cancellation notice up to the platform * - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. + * @param streamIntel, internal HTTP stream metrics, context, and other details. * @return Object, not used for response callbacks. */ - public Object onCancel(long[] streamIntel, long[] finalStreamIntel) { + public Object onCancel(long[] streamIntel) { callbacks.getExecutor().execute(new Runnable() { public void run() { // This call is atomically gated at the call-site and will only happen once. - callbacks.onCancel(new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + callbacks.onCancel(new EnvoyStreamIntelImpl(streamIntel)); } }); @@ -145,24 +139,6 @@ public void run() { } }); - return null; - } - /** - * Called with all stream metrics after the final headers/data/trailers call. - * - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics for the end of stream. - * @return Object, not used for response callbacks. - */ - public Object onComplete(long[] streamIntel, long[] finalStreamIntel) { - callbacks.getExecutor().execute(new Runnable() { - public void run() { - // This call is atomically gated at the call-site and will only happen once. - callbacks.onComplete(new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); - } - }); - return null; } } diff --git a/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java b/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java index 4c1921ce26..e334a4af34 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java @@ -211,40 +211,22 @@ public void setResponseFilterCallbacks(long callbackHandle) { * @param message, the error message. * @param attemptCount, the number of times an operation was attempted before firing this error. * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. * @return Object, not used in HTTP filters. */ - public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel, - long[] finalStreamIntel) { + public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel) { String errorMessage = new String(message); - filter.onError(errorCode, errorMessage, attemptCount, new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + filter.onError(errorCode, errorMessage, attemptCount, new EnvoyStreamIntelImpl(streamIntel)); return null; } /** * Dispatches cancellation notice up to the platform. * - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. - * @return Object, not used in HTTP filters. - */ - public Object onCancel(long[] streamIntel, long[] finalStreamIntel) { - filter.onCancel(new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); - return null; - } - - /** - * Dispatches stream completion notice up to the platform. - * - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. + * @param streamIntel, internal HTTP stream metrics, context, and other details. * @return Object, not used in HTTP filters. */ - public Object onComplete(long[] streamIntel, long[] finalStreamIntel) { - filter.onComplete(new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + public Object onCancel(long[] streamIntel) { + filter.onCancel(new EnvoyStreamIntelImpl(streamIntel)); return null; } diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/BUILD b/library/java/io/envoyproxy/envoymobile/engine/types/BUILD index 3a0010dd53..0bb2abbc90 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/BUILD +++ b/library/java/io/envoyproxy/envoymobile/engine/types/BUILD @@ -6,7 +6,6 @@ java_library( name = "envoy_c_types_lib", srcs = [ "EnvoyEventTracker.java", - "EnvoyFinalStreamIntel.java", "EnvoyHTTPCallbacks.java", "EnvoyHTTPFilter.java", "EnvoyHTTPFilterCallbacks.java", diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java deleted file mode 100644 index 4936176a56..0000000000 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.envoyproxy.envoymobile.engine.types; - -/** - * Exposes internal HTTP stream metrics, context, and other details sent once on stream end. - */ -public interface EnvoyFinalStreamIntel { - /* - * The time the request started, in ms since the epoch. - */ - public long getRequestStartMs(); - /* - * The time the DNS resolution for this request started, in ms since the epoch. - */ - public long getDnsStartMs(); - /* - * The time the DNS resolution for this request completed, in ms since the epoch. - */ - public long getDnsEndMs(); - /* - * The time the upstream connection started, in ms since the epoch. - * This may not be set if socket_reused is false. - */ - public long getConnectStartMs(); - /* - * The time the upstream connection completed, in ms since the epoch. - * This may not be set if socket_reused is false. - */ - public long getConnectEndMs(); - /* - * The time the SSL handshake started, in ms since the epoch. - * This may not be set if socket_reused is false. - */ - public long getSslStartMs(); - /* - * The time the SSL handshake completed, in ms since the epoch. - * This may not be set if socket_reused is false. - */ - public long getSslEndMs(); - /* - * The time the first byte of the request was sent upstream, in ms since the epoch. - */ - public long getSendingStartMs(); - /* - * The time the last byte of the request was sent upstream, in ms since the epoch. - */ - public long getSendingEndMs(); - /* - * The time the first byte of the response was received, in ms since the epoch. - */ - public long getResponseStartMs(); - /* - * The time the last byte of the request was received, in ms since the epoch. - */ - public long getRequestEndMs(); - /* - * True if the upstream socket had been used previously. - */ - public boolean getSocketReused(); - /* - * The number of bytes sent upstream. - */ - public long getSentByteCount(); - /* - * The number of bytes received from upstream. - */ - public long getReceivedByteCount(); -} diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java index eef91e1413..8f7aa15847 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java @@ -48,19 +48,13 @@ void onHeaders(Map> headers, boolean endStream, * count for an error. This is different from 0, which intentionally conveys * that the action was _not_ executed. * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. */ - void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel, - EnvoyFinalStreamIntel finalStreamIntel); + void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel); /** * Called when the async HTTP stream is canceled. - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. */ - void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel); + void onCancel(EnvoyStreamIntel streamIntel); /** * Callback signature which notify when there is buffer available for request body upload. @@ -72,12 +66,4 @@ void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel s * @param streamIntel, contains internal HTTP stream metrics, context, and other details. */ void onSendWindowAvailable(EnvoyStreamIntel streamIntel); - - /** - * Called once after the final data for the stream has been received. - * - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics. - */ - void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel); } diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java index 17ba29d651..f94e89362d 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java @@ -110,27 +110,13 @@ Object[] onResumeResponse(Map> headers, ByteBuffer data, * count for an error. This is different from 0, which intentionally conveys * that the action was _not_ executed. * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. */ - void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel, - EnvoyFinalStreamIntel finalStreamIntel); + void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel); /** * Called when the async HTTP stream is canceled. * - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. - */ - void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalSteamIntel); - - /** - * Called when the async HTTP stream is complete. - * - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. */ - void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalSteamIntel); + void onCancel(EnvoyStreamIntel streamIntel); } diff --git a/library/java/org/chromium/net/impl/CronetUrlRequest.java b/library/java/org/chromium/net/impl/CronetUrlRequest.java index c02e3d0d28..259fce4665 100644 --- a/library/java/org/chromium/net/impl/CronetUrlRequest.java +++ b/library/java/org/chromium/net/impl/CronetUrlRequest.java @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.engine.EnvoyHTTPStream; import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks; import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel; -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.MalformedURLException; @@ -772,7 +771,7 @@ public void onTrailers(Map> trailers, EnvoyStreamIntel stre @Override public void onError(int errorCode, String message, int attemptCount, - EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) { + EnvoyStreamIntel streamIntel) { if (isAbandoned()) { return; } @@ -794,7 +793,7 @@ public void onError(int errorCode, String message, int attemptCount, } @Override - public void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) { + public void onCancel(EnvoyStreamIntel streamIntel) { if (isAbandoned()) { return; } @@ -834,9 +833,6 @@ public void onSendWindowAvailable(EnvoyStreamIntel streamIntel) { mUploadDataStream.readDataReady(); // Have the next request body chunk to be sent. } - @Override - public void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) {} - /** * Sends one chunk of the request body if the state permits. This method is not re-entrant, but * by contract this method can only be invoked once for the first chunk, and then once per diff --git a/library/kotlin/io/envoyproxy/envoymobile/BUILD b/library/kotlin/io/envoyproxy/envoymobile/BUILD index 66d5c9f271..e28ae2863c 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/BUILD +++ b/library/kotlin/io/envoyproxy/envoymobile/BUILD @@ -61,7 +61,6 @@ envoy_mobile_kt_library( "StreamClient.kt", "StreamClientImpl.kt", "StreamIntel.kt", - "FinalStreamIntel.kt", "StreamPrototype.kt", "StringAccessor.kt", "Trailers.kt", diff --git a/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt b/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt deleted file mode 100644 index 5375146578..0000000000 --- a/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt +++ /dev/null @@ -1,57 +0,0 @@ -package io.envoyproxy.envoymobile - -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel - -/** - * Exposes one time HTTP stream metrics, context, and other details. - * @param requestStartMs The time the request started, in ms since the epoch. - * @param dnsStartMs The time the DNS resolution for this request started, in ms since the epoch. - * @param dnsEndMs The time the DNS resolution for this request completed, in ms since the epoch. - * @param connectStartMsThe time the upstream connection started, in ms since the epoch. - * This may not be set if socket_reused is false. - * @param connectEndMs The time the upstream connection completed, in ms since the epoch. - * This may not be set if socket_reused is false. - * @param sslStartMs The time the SSL handshake started, in ms since the epoch. - * This may not be set if socket_reused is false. - * @param sslEndMs The time the SSL handshake completed, in ms since the epoch. - * This may not be set if socket_reused is false. - * @param sendingStartMs The time the first byte of the request was sent upstream, - * in ms since the epoch. - * @param sendingEndMs The time the last byte of the request was sent upstream, in ms since the - * epoch. - * @param responseStartMs The time the first byte of the response was received, in ms since the - * epoch. - * @param @param requestEndMs The time the last byte of the request was received, in ms since the - * epoch. - * @param socket_reused True if the upstream socket had been used previously. - * @param sentByteCount The number of bytes sent upstream. - * @param receivedByteCount The number of bytes received from upstream. - */ -@Suppress("LongParameterList") -class FinalStreamIntel constructor( - val requestStartMs: Long, - val dnsStartMs: Long, - val dnsEndMs: Long, - val connectStartMs: Long, - val connectEndMs: Long, - val sslStartMs: Long, - val sslEndMs: Long, - val sendingStartMs: Long, - val sendingEndMs: Long, - val responseStartMs: Long, - val requestEndMs: Long, - val socketReused: Boolean, - val sentByteCount: Long, - val receivedByteCount: Long -) { - constructor(base: EnvoyFinalStreamIntel) : this( - base.requestStartMs, base.dnsStartMs, - base.dnsEndMs, base.connectStartMs, - base.connectEndMs, base.sslStartMs, - base.sslEndMs, base.sendingStartMs, - base.sendingEndMs, - base.responseStartMs, base.requestEndMs, - base.socketReused, base.sentByteCount, - base.receivedByteCount - ) -} diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt index 43e3251a9d..67fcf84dbe 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt @@ -1,6 +1,5 @@ package io.envoyproxy.envoymobile -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel import java.nio.ByteBuffer @@ -18,12 +17,9 @@ internal class StreamCallbacks { )? = null var onData: ((data: ByteBuffer, endStream: Boolean, streamIntel: StreamIntel) -> Unit)? = null var onTrailers: ((trailers: ResponseTrailers, streamIntel: StreamIntel) -> Unit)? = null - var onCancel: ((streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit)? = null - var onError: ( - (error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit - )? = null + var onCancel: ((streamIntel: StreamIntel) -> Unit)? = null + var onError: ((error: EnvoyError, streamIntel: StreamIntel) -> Unit)? = null var onSendWindowAvailable: ((streamIntel: StreamIntel) -> Unit)? = null - var onComplete: ((streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit)? = null } /** @@ -58,25 +54,19 @@ internal class EnvoyHTTPCallbacksAdapter( errorCode: Int, message: String, attemptCount: Int, - streamIntel: EnvoyStreamIntel, - finalStreamIntel: EnvoyFinalStreamIntel + streamIntel: EnvoyStreamIntel ) { callbacks.onError?.invoke( EnvoyError(errorCode, message, attemptCount), - StreamIntel(streamIntel), - FinalStreamIntel(finalStreamIntel) + StreamIntel(streamIntel) ) } - override fun onCancel(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { - callbacks.onCancel?.invoke(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + override fun onCancel(streamIntel: EnvoyStreamIntel) { + callbacks.onCancel?.invoke(StreamIntel(streamIntel)) } override fun onSendWindowAvailable(streamIntel: EnvoyStreamIntel) { callbacks.onSendWindowAvailable?.invoke(StreamIntel(streamIntel)) } - - override fun onComplete(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { - callbacks.onComplete?.invoke(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) - } } diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt index 863e3e009c..f7fb49745d 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt @@ -25,10 +25,7 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return The new stream. */ open fun start(executor: Executor = Executors.newSingleThreadExecutor()): Stream { - val engineStream = engine.startStream( - createCallbacks(executor), - explicitFlowControl - ) + val engineStream = engine.startStream(createCallbacks(executor), explicitFlowControl) return Stream(engineStream, useByteBufferPosition) } @@ -110,30 +107,12 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return This stream, for chaining syntax. */ fun setOnError( - closure: ( - error: EnvoyError, - streamIntel: StreamIntel, - finalStreamIntel: FinalStreamIntel - ) -> Unit + closure: (error: EnvoyError, streamIntel: StreamIntel) -> Unit ): StreamPrototype { callbacks.onError = closure return this } -/** - * Specify a callback for when a stream is complete. - * If the closure is called, the stream is complete. - * - * @param closure Closure which will be called when an error occurs. - * @return This stream, for chaining syntax. - */ - fun setOnComplete( - closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit - ): StreamPrototype { - callbacks.onComplete = closure - return this - } - /** * Specify a callback for when the stream is canceled. * If the closure is called, the stream is complete. @@ -142,7 +121,7 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return This stream, for chaining syntax. */ fun setOnCancel( - closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + closure: (streamIntel: StreamIntel) -> Unit ): StreamPrototype { callbacks.onCancel = closure return this diff --git a/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt b/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt index 1741b85f2b..02ab7a5e24 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt @@ -1,6 +1,5 @@ package io.envoyproxy.envoymobile -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilter import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterCallbacks import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterFactory @@ -100,21 +99,15 @@ internal class EnvoyHTTPFilterAdapter( return arrayOf(0, trailers) } - override fun onError(errorCode: Int, message: String, attemptCount: Int, streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + override fun onError(errorCode: Int, message: String, attemptCount: Int, streamIntel: EnvoyStreamIntel) { (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onError(EnvoyError(errorCode, message, attemptCount), StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + responseFilter.onError(EnvoyError(errorCode, message, attemptCount), StreamIntel(streamIntel)) } } - override fun onCancel(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + override fun onCancel(streamIntel: EnvoyStreamIntel) { (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onCancel(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) - } - } - - override fun onComplete(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { - (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onComplete(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + responseFilter.onCancel(StreamIntel(streamIntel)) } } diff --git a/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt b/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt index c8dbcf7b6e..2c025164ce 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt @@ -55,9 +55,8 @@ interface ResponseFilter : Filter { * * @param error: The error that occurred within Envoy. * @param streamIntel: Internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. */ - fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) + fun onError(error: EnvoyError, streamIntel: StreamIntel) /** * Called at most once when the client cancels the stream. @@ -66,18 +65,6 @@ interface ResponseFilter : Filter { * `stopIteration{...}`. * * @param streamIntel: Internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. */ - fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) - -/** - * Called at most once when the stream is complete. - * - * This should be considered a terminal state, and invalidates any previous attempts to - * `stopIteration{...}`. - * - * @param streamIntel: Internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. - */ - fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) + fun onCancel(streamIntel: StreamIntel) } diff --git a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt index 78618658af..87aafbdc12 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt @@ -89,7 +89,7 @@ class GRPCStreamPrototype( * @return This stream, for chaining syntax. */ fun setOnError( - closure: (error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + closure: (error: EnvoyError, streamIntel: StreamIntel) -> Unit ): GRPCStreamPrototype { underlyingStream.setOnError(closure) return this @@ -103,7 +103,7 @@ class GRPCStreamPrototype( * @return This stream, for chaining syntax. */ fun setOnCancel( - closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + closure: (streamIntel: StreamIntel) -> Unit ): GRPCStreamPrototype { underlyingStream.setOnCancel(closure) return this diff --git a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt index 7f326d22ab..b85cf0c8fd 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt @@ -1,6 +1,5 @@ package io.envoyproxy.envoymobile -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel import java.nio.ByteBuffer @@ -17,22 +16,6 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S override fun getAttemptCount(): Long { return 0 } } - private val mockFinalStreamIntel = object : EnvoyFinalStreamIntel { - override fun getRequestStartMs(): Long { return 0 } - override fun getDnsStartMs(): Long { return 0 } - override fun getDnsEndMs(): Long { return 0 } - override fun getConnectStartMs(): Long { return 0 } - override fun getConnectEndMs(): Long { return 0 } - override fun getSslStartMs(): Long { return 0 } - override fun getSslEndMs(): Long { return 0 } - override fun getSendingStartMs(): Long { return 0 } - override fun getSendingEndMs(): Long { return 0 } - override fun getResponseStartMs(): Long { return 0 } - override fun getRequestEndMs(): Long { return 0 } - override fun getSocketReused(): Boolean { return false } - override fun getSentByteCount(): Long { return 0 } - override fun getReceivedByteCount(): Long { return 0 } - } /** * Closure that will be called when request headers are sent. */ @@ -105,7 +88,7 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S * Simulate the stream receiving a cancellation signal from Envoy. */ fun receiveCancel() { - mockStream.callbacks.onCancel(mockStreamIntel, mockFinalStreamIntel) + mockStream.callbacks.onCancel(mockStreamIntel) } /** @@ -114,6 +97,6 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S * @param error The error to receive. */ fun receiveError(error: EnvoyError) { - mockStream.callbacks.onError(error.errorCode, error.message, error.attemptCount ?: 0, mockStreamIntel, mockFinalStreamIntel) + mockStream.callbacks.onError(error.errorCode, error.message, error.attemptCount ?: 0, mockStreamIntel) } } diff --git a/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc b/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc index 8ed9a651c3..801e4cea4e 100644 --- a/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc +++ b/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc @@ -676,7 +676,7 @@ TEST_F(PlatformBridgeFilterTest, BasicError) { release_envoy_data(c_data); return {kEnvoyFilterDataStatusStopIterationNoBuffer, envoy_nodata, nullptr}; }; - platform_filter.on_error = [](envoy_error c_error, envoy_stream_intel, envoy_final_stream_intel, + platform_filter.on_error = [](envoy_error c_error, envoy_stream_intel, const void* context) -> void { filter_invocations* invocations = static_cast(const_cast(context)); invocations->on_error_calls++; diff --git a/test/common/http/client_test.cc b/test/common/http/client_test.cc index 33f6467ef0..1b624b6608 100644 --- a/test/common/http/client_test.cc +++ b/test/common/http/client_test.cc @@ -63,8 +63,7 @@ class ClientTest : public testing::TestWithParam { bridge_callbacks_.context = &cc_; // Set up default bridge callbacks. Indivividual tests can override. - bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_complete = [](envoy_stream_intel, void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; return nullptr; @@ -78,8 +77,7 @@ class ClientTest : public testing::TestWithParam { cc->on_headers_calls++; return nullptr; }; - bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_error_calls++; return nullptr; @@ -92,8 +90,7 @@ class ClientTest : public testing::TestWithParam { release_envoy_data(c_data); return nullptr; }; - bridge_callbacks_.on_cancel = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_cancel = [](envoy_stream_intel, void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_cancel_calls++; return nullptr; @@ -456,8 +453,7 @@ TEST_P(ClientTest, MultipleStreams) { *on_headers_called2 = true; return nullptr; }; - bridge_callbacks_2.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_2.on_complete = [](envoy_stream_intel, void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; return nullptr; @@ -506,8 +502,7 @@ TEST_P(ClientTest, MultipleStreams) { TEST_P(ClientTest, EnvoyLocalError) { // Override the on_error default with some custom checks. - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { EXPECT_EQ(error.error_code, ENVOY_CONNECTION_FAILURE); EXPECT_EQ(error.attempt_count, 123); callbacks_called* cc = static_cast(context); @@ -580,8 +575,7 @@ TEST_P(ClientTest, DoubleResetStreamLocal) { TEST_P(ClientTest, RemoteResetAfterStreamStart) { cc_.end_stream_with_headers_ = false; - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { EXPECT_EQ(error.error_code, ENVOY_STREAM_RESET); EXPECT_EQ(error.message.length, 0); EXPECT_EQ(error.attempt_count, 0); diff --git a/test/common/integration/client_integration_test.cc b/test/common/integration/client_integration_test.cc index 52480f7e67..88f98210b1 100644 --- a/test/common/integration/client_integration_test.cc +++ b/test/common/integration/client_integration_test.cc @@ -77,15 +77,13 @@ class ClientIntegrationTest : public BaseIntegrationTest, release_envoy_data(c_data); return nullptr; }; - bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_complete = [](envoy_stream_intel, void* context) -> void* { callbacks_called* cc_ = static_cast(context); cc_->on_complete_calls++; cc_->terminal_callback->setReady(); return nullptr; }; - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { release_envoy_error(error); callbacks_called* cc_ = static_cast(context); cc_->on_error_calls++; diff --git a/test/common/main_interface_test.cc b/test/common/main_interface_test.cc index 474a080a36..1a85e7dbfd 100644 --- a/test/common/main_interface_test.cc +++ b/test/common/main_interface_test.cc @@ -154,7 +154,7 @@ TEST(MainInterfaceTest, BasicStream) { nullptr /* on_metadata */, nullptr /* on_trailers */, nullptr /* on_error */, - [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { + [](envoy_stream_intel, void* context) -> void* { auto* on_complete_notification = static_cast(context); on_complete_notification->Notify(); return nullptr; @@ -249,20 +249,20 @@ TEST(MainInterfaceTest, ResetStream) { engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); absl::Notification on_cancel_notification; - envoy_http_callbacks stream_cbs{ - nullptr /* on_headers */, - nullptr /* on_data */, - nullptr /* on_metadata */, - nullptr /* on_trailers */, - nullptr /* on_error */, - nullptr /* on_complete */, - [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { - auto* on_cancel_notification = static_cast(context); - on_cancel_notification->Notify(); - return nullptr; - } /* on_cancel */, - nullptr /* on_send_window_available */, - &on_cancel_notification /* context */}; + envoy_http_callbacks stream_cbs{nullptr /* on_headers */, + nullptr /* on_data */, + nullptr /* on_metadata */, + nullptr /* on_trailers */, + nullptr /* on_error */, + nullptr /* on_complete */, + [](envoy_stream_intel, void* context) -> void* { + auto* on_cancel_notification = + static_cast(context); + on_cancel_notification->Notify(); + return nullptr; + } /* on_cancel */, + nullptr /* on_send_window_available */, + &on_cancel_notification /* context */}; envoy_stream_t stream = init_stream(0); diff --git a/test/java/integration/AndroidEnvoyExplicitFlowTest.java b/test/java/integration/AndroidEnvoyExplicitFlowTest.java index ccc17de98c..6f00f59171 100644 --- a/test/java/integration/AndroidEnvoyExplicitFlowTest.java +++ b/test/java/integration/AndroidEnvoyExplicitFlowTest.java @@ -393,12 +393,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { latch.countDown(); return null; }) - .setOnError((error, ignored, also_ignored) -> { + .setOnError((error, ignored) -> { response.get().setEnvoyError(error); latch.countDown(); return null; }) - .setOnCancel((ignored, also_ignored) -> { + .setOnCancel((ignored) -> { response.get().setCancelled(); latch.countDown(); return null; diff --git a/test/java/integration/AndroidEnvoyFlowTest.java b/test/java/integration/AndroidEnvoyFlowTest.java index a1a57e8904..7d1bf250c9 100644 --- a/test/java/integration/AndroidEnvoyFlowTest.java +++ b/test/java/integration/AndroidEnvoyFlowTest.java @@ -302,12 +302,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { latch.countDown(); return null; }) - .setOnError((error, ignored, also_ignored) -> { + .setOnError((error, ignored) -> { response.get().setEnvoyError(error); latch.countDown(); return null; }) - .setOnCancel((ignored, also_ignored) -> { + .setOnCancel((ignored) -> { response.get().setCancelled(); latch.countDown(); return null; diff --git a/test/kotlin/integration/CancelStreamTest.kt b/test/kotlin/integration/CancelStreamTest.kt index 31321010fd..e8d883ccd4 100644 --- a/test/kotlin/integration/CancelStreamTest.kt +++ b/test/kotlin/integration/CancelStreamTest.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.RequestHeadersBuilder import io.envoyproxy.envoymobile.RequestMethod import io.envoyproxy.envoymobile.ResponseFilter @@ -109,10 +108,9 @@ class CancelStreamTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} + override fun onError(error: EnvoyError, streamIntel: StreamIntel) {} - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { latch.countDown() } } @@ -139,7 +137,7 @@ class CancelStreamTest { .build() client.newStreamPrototype() - .setOnCancel { _, _ -> + .setOnCancel { runExpectation.countDown() } .start(Executors.newSingleThreadExecutor()) diff --git a/test/kotlin/integration/DrainConnectionsTest.kt b/test/kotlin/integration/DrainConnectionsTest.kt index f43c04a2a4..597c659120 100644 --- a/test/kotlin/integration/DrainConnectionsTest.kt +++ b/test/kotlin/integration/DrainConnectionsTest.kt @@ -85,7 +85,7 @@ class DrainConnectionsTest { resultEndStream1 = endStream headersExpectation.countDown() } - .setOnError { _, _, _ -> fail("Unexpected error") } + .setOnError { _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) @@ -101,7 +101,7 @@ class DrainConnectionsTest { resultEndStream2 = endStream headersExpectation.countDown() } - .setOnError { _, _, _ -> fail("Unexpected error") } + .setOnError { _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/GRPCReceiveErrorTest.kt b/test/kotlin/integration/GRPCReceiveErrorTest.kt index e83c87382f..c998706184 100644 --- a/test/kotlin/integration/GRPCReceiveErrorTest.kt +++ b/test/kotlin/integration/GRPCReceiveErrorTest.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.GRPCClient import io.envoyproxy.envoymobile.GRPCRequestHeadersBuilder import io.envoyproxy.envoymobile.ResponseFilter @@ -96,12 +95,11 @@ class GRPCReceiveErrorTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { receivedError.countDown() } - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { notCancelled.countDown() } } @@ -126,12 +124,10 @@ class GRPCReceiveErrorTest { .newGRPCStreamPrototype() .setOnResponseHeaders { _, _, _ -> } .setOnResponseMessage { _, _ -> } - .setOnError { _, _, _ -> + .setOnError { _, _ -> callbackReceivedError.countDown() } - .setOnCancel { _, _ -> - fail("Unexpected call to onCancel response callback") - } + .setOnCancel { fail("Unexpected call to onCancel response callback") } .start() .sendHeaders(requestHeader, false) .sendMessage(ByteBuffer.wrap(ByteArray(5))) diff --git a/test/kotlin/integration/ReceiveDataTest.kt b/test/kotlin/integration/ReceiveDataTest.kt index 36702adbf5..4059e14587 100644 --- a/test/kotlin/integration/ReceiveDataTest.kt +++ b/test/kotlin/integration/ReceiveDataTest.kt @@ -94,7 +94,7 @@ class ReceiveDataTest { body = data dataExpectation.countDown() } - .setOnError { _, _, _ -> fail("Unexpected error") } + .setOnError { _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/ReceiveErrorTest.kt b/test/kotlin/integration/ReceiveErrorTest.kt index b7f61b239f..ed87a1e076 100644 --- a/test/kotlin/integration/ReceiveErrorTest.kt +++ b/test/kotlin/integration/ReceiveErrorTest.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.GRPCRequestHeadersBuilder import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders @@ -93,12 +92,11 @@ class ReceiveErrorTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { receivedError.countDown() } - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { notCancelled.countDown() } } @@ -127,13 +125,11 @@ class ReceiveErrorTest { .setOnResponseData { _, _, _ -> fail("Data received instead of expected error") } // The unmatched expectation will cause a local reply which gets translated in Envoy Mobile to // an error. - .setOnError { error, _, _ -> + .setOnError { error, _ -> errorCode = error.errorCode callbackReceivedError.countDown() } - .setOnCancel { _, _ -> - fail("Unexpected call to onCancel response callback") - } + .setOnCancel { fail("Unexpected call to onCancel response callback") } .start() .sendHeaders(requestHeader, true) diff --git a/test/kotlin/integration/SendDataTest.kt b/test/kotlin/integration/SendDataTest.kt index 1fe9075a8a..925e9f3bea 100644 --- a/test/kotlin/integration/SendDataTest.kt +++ b/test/kotlin/integration/SendDataTest.kt @@ -93,7 +93,7 @@ class SendDataTest { responseHeadersEndStream = endStream expectation.countDown() } - .setOnError { _, _, _ -> + .setOnError { _, _ -> fail("Unexpected error") } .start() diff --git a/test/kotlin/integration/SendHeadersTest.kt b/test/kotlin/integration/SendHeadersTest.kt index 823a524d7a..20cdb99f01 100644 --- a/test/kotlin/integration/SendHeadersTest.kt +++ b/test/kotlin/integration/SendHeadersTest.kt @@ -85,7 +85,7 @@ class SendHeadersTest { resultEndStream = endStream headersExpectation.countDown() } - .setOnError { _, _, _ -> fail("Unexpected error") } + .setOnError { _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/SendTrailersTest.kt b/test/kotlin/integration/SendTrailersTest.kt index 1391ced880..1392583e19 100644 --- a/test/kotlin/integration/SendTrailersTest.kt +++ b/test/kotlin/integration/SendTrailersTest.kt @@ -98,7 +98,7 @@ class SendTrailersTest { responseStatus = headers.httpStatus expectation.countDown() } - .setOnError { _, _, _ -> + .setOnError { _, _ -> fail("Unexpected error") } .start() diff --git a/test/kotlin/integration/StreamIdleTimeoutTest.kt b/test/kotlin/integration/StreamIdleTimeoutTest.kt index 8d1117961f..74205b32cb 100644 --- a/test/kotlin/integration/StreamIdleTimeoutTest.kt +++ b/test/kotlin/integration/StreamIdleTimeoutTest.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.RequestHeadersBuilder import io.envoyproxy.envoymobile.RequestMethod import io.envoyproxy.envoymobile.ResponseFilter @@ -132,13 +131,12 @@ class CancelStreamTest { return FilterTrailersStatus.StopIteration() } - override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { assertThat(error.errorCode).isEqualTo(4) latch.countDown() } - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { fail("Unexpected call to onCancel filter callback") } } @@ -165,7 +163,7 @@ class CancelStreamTest { .build() client.newStreamPrototype() - .setOnError { error, _, _ -> + .setOnError { error, _ -> assertThat(error.errorCode).isEqualTo(4) callbackExpectation.countDown() } From 97f828082e882bedc7255eec3a738e31440e2913 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Thu, 2 Dec 2021 15:27:46 -0800 Subject: [PATCH 08/25] update Signed-off-by: Jose Nino --- library/common/config/config.cc | 14 ++++---------- library/common/config/templates.h | 2 -- library/common/jni/jni_interface.cc | 8 -------- .../envoymobile/engine/EnvoyConfiguration.java | 15 ++++++--------- .../envoymobile/engine/EnvoyEngineImpl.java | 3 +-- .../envoyproxy/envoymobile/engine/JniLibrary.java | 2 -- 6 files changed, 11 insertions(+), 33 deletions(-) diff --git a/library/common/config/config.cc b/library/common/config/config.cc index bbd7f25fd1..c41f9a15e2 100644 --- a/library/common/config/config.cc +++ b/library/common/config/config.cc @@ -24,15 +24,6 @@ const char* native_filter_template = R"( typed_config: {{ native_filter_typed_config }} )"; -const char* dns_template = R"( - typed_dns_resolver_config: - name: envoy.network.dns_resolver.cares - typed_config: - "@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig - resolvers: {{ dns_resolvers }} - use_resolvers_as_fallback: {{ dns_use_resolvers_as_fallback }} -)"; - const char* route_cache_reset_filter_insert = R"( - name: envoy.filters.http.route_cache_reset typed_config: @@ -48,6 +39,7 @@ const std::string config_header = R"( - &dns_fail_max_interval 10s - &dns_query_timeout 25s - &dns_preresolve_hostnames [] +- &dns_resolver_config {} - &enable_interface_binding false - &h2_connection_keepalive_idle_interval 100000s - &h2_connection_keepalive_timeout 10s @@ -276,7 +268,9 @@ R"( base_interval: *dns_fail_base_interval max_interval: *dns_fail_max_interval dns_query_timeout: *dns_query_timeout -#{dns_resolver_config} + typed_dns_resolver_config: + name: *dns_resolver_name + typed_config: *dns_resolver_config # TODO: make this configurable for users. - name: envoy.filters.http.decompressor typed_config: diff --git a/library/common/config/templates.h b/library/common/config/templates.h index 2e1c6a4659..5b51cddeef 100644 --- a/library/common/config/templates.h +++ b/library/common/config/templates.h @@ -19,8 +19,6 @@ extern const char* platform_filter_template; */ extern const char* native_filter_template; -extern const char* dns_template; - /** * Number of spaces to indent custom cluster entries. */ diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index 0f900458e9..8fc8309831 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -150,14 +150,6 @@ Java_io_envoyproxy_envoymobile_engine_JniLibrary_nativeFilterTemplateString(JNIE return result; } -extern "C" JNIEXPORT jstring JNICALL -Java_io_envoyproxy_envoymobile_engine_JniLibrary_dnsTemplateString(JNIEnv* env, - jclass // class -) { - jstring result = env->NewStringUTF(dns_template); - return result; -} - extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_recordCounterInc( JNIEnv* env, jclass, // class diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java index d6a4df735e..9b4fdd384f 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyConfiguration.java @@ -109,7 +109,7 @@ public EnvoyConfiguration(Boolean adminInterfaceEnabled, String grpcStatsDomain, * resolved. */ String resolveTemplate(final String templateYAML, final String platformFilterTemplateYAML, - final String nativeFilterTemplateYAML, final String dnsTemplateYAML) { + final String nativeFilterTemplateYAML) { final StringBuilder customFiltersBuilder = new StringBuilder(); for (EnvoyHTTPFilterFactory filterFactory : httpPlatformFilterFactories) { @@ -125,17 +125,12 @@ String resolveTemplate(final String templateYAML, final String platformFilterTem customFiltersBuilder.append(filterConfig); } - String addedCustomFilters = + String processedTemplate = templateYAML.replace("#{custom_filters}", customFiltersBuilder.toString()); - // TODO: use defaults for now. Subsequent PR will add user ability to override. These defaults - // are a noop. - String dnsResolverConfigFirst = dnsTemplateYAML.replace("{{ dns_resolvers }}", "[]"); + // TODO: using default no-op. Subsequent change will allow user override. String dnsResolverConfig = - dnsResolverConfigFirst.replace("{{ dns_use_resolvers_as_fallback }}", "false"); - - String processedTemplate = - addedCustomFilters.replace("#{dns_resolver_config}", dnsResolverConfig); + "{\"@type\":\"type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig\",\"resolvers\":[],\"use_resolvers_as_fallback\": false}"; StringBuilder configBuilder = new StringBuilder("!ignore platform_defs:\n"); configBuilder.append(String.format("- &connect_timeout %ss\n", connectTimeoutSeconds)) @@ -144,6 +139,8 @@ String resolveTemplate(final String templateYAML, final String platformFilterTem .append(String.format("- &dns_fail_max_interval %ss\n", dnsFailureRefreshSecondsMax)) .append(String.format("- &dns_query_timeout %ss\n", dnsQueryTimeoutSeconds)) .append(String.format("- &dns_preresolve_hostnames %s\n", dnsPreresolveHostnames)) + .append("- &dns_resolver_name envoy.network.dns_resolver.cares\n") + .append(String.format("- &dns_resolver_config %s\n", dnsResolverConfig)) .append(String.format("- &enable_interface_binding %s\n", enableInterfaceBinding ? "true" : "false")) .append(String.format("- &h2_connection_keepalive_idle_interval %ss\n", diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java index 2260a00229..84f44522cb 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyEngineImpl.java @@ -83,8 +83,7 @@ public int runWithTemplate(String configurationYAML, EnvoyConfiguration envoyCon return runWithResolvedYAML(envoyConfiguration.resolveTemplate( configurationYAML, JniLibrary.platformFilterTemplateString(), - JniLibrary.nativeFilterTemplateString(), - JniLibrary.dnsTemplateString()), + JniLibrary.nativeFilterTemplateString()), logLevel); } diff --git a/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java b/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java index 5b4e7e444d..7fa8836eb2 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JniLibrary.java @@ -284,8 +284,6 @@ protected static native int recordHistogramValue(long engine, String elements, b */ public static native String nativeFilterTemplateString(); - public static native String dnsTemplateString(); - /** * Register a string accessor to get strings from the platform. * From 232bb61d17899b5a22de7a6fc3412d8a24aa6233 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Thu, 2 Dec 2021 15:44:29 -0800 Subject: [PATCH 09/25] iOS Signed-off-by: Jose Nino --- library/common/http/header_utility.cc | 2 +- library/objective-c/EnvoyConfiguration.m | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/common/http/header_utility.cc b/library/common/http/header_utility.cc index ddb4c54c19..09449de6f1 100644 --- a/library/common/http/header_utility.cc +++ b/library/common/http/header_utility.cc @@ -26,7 +26,7 @@ RequestHeaderMapPtr toRequestHeaders(envoy_headers headers) { auto transformed_headers = RequestHeaderMapImpl::create(); transformed_headers->setFormatter( std::make_unique< - Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>()); + Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>(false)); toEnvoyHeaders(*transformed_headers, headers); return transformed_headers; } diff --git a/library/objective-c/EnvoyConfiguration.m b/library/objective-c/EnvoyConfiguration.m index 498b293782..bd1721884c 100644 --- a/library/objective-c/EnvoyConfiguration.m +++ b/library/objective-c/EnvoyConfiguration.m @@ -106,9 +106,6 @@ - (nullable NSString *)resolveTemplate:(NSString *)templateYAML { withString:customRoutes]; templateYAML = [templateYAML stringByReplacingOccurrencesOfString:@"#{custom_filters}" withString:customFilters]; - // No template is currently needed for Apple-based DNS resolver. - templateYAML = [templateYAML stringByReplacingOccurrencesOfString:@"#{dns_resolver_config}" - withString:@""]; NSMutableString *definitions = [[NSMutableString alloc] initWithString:@"!ignore platform_defs:\n"]; @@ -123,6 +120,9 @@ - (nullable NSString *)resolveTemplate:(NSString *)templateYAML { [definitions appendFormat:@"- &dns_query_timeout %lus\n", (unsigned long)self.dnsQueryTimeoutSeconds]; [definitions appendFormat:@"- &dns_preresolve_hostnames %@\n", self.dnsPreresolveHostnames]; + [definitions appendFormat:@"- &dns_resolver_name envoy.network.dns_resolver.apple\n"]; + // No additional values are currently needed for Apple-based DNS resolver. + [definitions appendFormat:@"- &dns_resolver_config {}\n"]; [definitions appendFormat:@"- &enable_interface_binding %@\n", self.enableInterfaceBinding ? @"true" : @"false"]; [definitions appendFormat:@"- &h2_connection_keepalive_idle_interval %.*fs\n", 3, From 3cfa846d09ccefc62b3c7546b8b32de1761dc3dc Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Thu, 2 Dec 2021 15:44:55 -0800 Subject: [PATCH 10/25] Revert "Revert "incompletely used APIs for final stream metrics (#1937)"" This reverts commit e279b305ce2c65613da9c56d08ab08b47d52b26a. Signed-off-by: Jose Nino --- examples/java/hello_world/MainActivity.java | 2 +- .../kotlin/hello_world/AsyncDemoFilter.kt | 13 ++- .../kotlin/hello_world/BufferDemoFilter.kt | 13 ++- examples/kotlin/hello_world/DemoFilter.kt | 13 ++- examples/kotlin/hello_world/MainActivity.kt | 2 +- library/cc/stream_callbacks.cc | 7 +- .../filters/http/platform_bridge/c_types.h | 5 +- .../filters/http/platform_bridge/filter.cc | 16 +++- .../filters/http/platform_bridge/filter.h | 1 + library/common/http/client.cc | 84 ++++++++++++++++- library/common/http/client.h | 19 +++- library/common/jni/jni_interface.cc | 68 ++++++++++---- library/common/jni/jni_utility.cc | 27 ++++++ library/common/jni/jni_utility.h | 3 + library/common/types/c_types.h | 52 +++++++++- .../io/envoyproxy/envoymobile/engine/BUILD | 1 + .../engine/EnvoyFinalStreamIntelImpl.java | 94 +++++++++++++++++++ .../engine/JvmCallbackContext.java | 44 +++++++-- .../envoymobile/engine/JvmFilterContext.java | 28 +++++- .../envoyproxy/envoymobile/engine/types/BUILD | 1 + .../engine/types/EnvoyFinalStreamIntel.java | 67 +++++++++++++ .../engine/types/EnvoyHTTPCallbacks.java | 18 +++- .../engine/types/EnvoyHTTPFilter.java | 20 +++- .../chromium/net/impl/CronetUrlRequest.java | 8 +- .../kotlin/io/envoyproxy/envoymobile/BUILD | 1 + .../envoymobile/FinalStreamIntel.kt | 57 +++++++++++ .../envoyproxy/envoymobile/StreamCallbacks.kt | 22 +++-- .../envoyproxy/envoymobile/StreamPrototype.kt | 27 +++++- .../envoyproxy/envoymobile/filters/Filter.kt | 15 ++- .../envoymobile/filters/ResponseFilter.kt | 17 +++- .../envoymobile/grpc/GRPCStreamPrototype.kt | 4 +- .../envoymobile/mocks/MockStream.kt | 21 ++++- .../platform_bridge_filter_test.cc | 2 +- test/common/http/client_test.cc | 18 ++-- .../integration/client_integration_test.cc | 6 +- test/common/main_interface_test.cc | 30 +++--- .../AndroidEnvoyExplicitFlowTest.java | 4 +- .../integration/AndroidEnvoyFlowTest.java | 4 +- test/kotlin/integration/CancelStreamTest.kt | 8 +- .../integration/DrainConnectionsTest.kt | 4 +- .../integration/GRPCReceiveErrorTest.kt | 12 ++- test/kotlin/integration/ReceiveDataTest.kt | 2 +- test/kotlin/integration/ReceiveErrorTest.kt | 12 ++- test/kotlin/integration/SendDataTest.kt | 2 +- test/kotlin/integration/SendHeadersTest.kt | 2 +- test/kotlin/integration/SendTrailersTest.kt | 2 +- .../integration/StreamIdleTimeoutTest.kt | 8 +- 47 files changed, 758 insertions(+), 128 deletions(-) create mode 100644 library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java create mode 100644 library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java create mode 100644 library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt diff --git a/examples/java/hello_world/MainActivity.java b/examples/java/hello_world/MainActivity.java index 5d1ebcd4ac..cf121e56eb 100644 --- a/examples/java/hello_world/MainActivity.java +++ b/examples/java/hello_world/MainActivity.java @@ -125,7 +125,7 @@ private void makeRequest() { } return Unit.INSTANCE; }) - .setOnError((error, ignored) -> { + .setOnError((error, ignored, also_ignored) -> { String message = "failed with error after " + error.getAttemptCount() + " attempts: " + error.getMessage(); Log.d("MainActivity", message); diff --git a/examples/kotlin/hello_world/AsyncDemoFilter.kt b/examples/kotlin/hello_world/AsyncDemoFilter.kt index 214e01bdb6..72f6ab8463 100644 --- a/examples/kotlin/hello_world/AsyncDemoFilter.kt +++ b/examples/kotlin/hello_world/AsyncDemoFilter.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterResumeStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilterCallbacks import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -78,10 +79,18 @@ class AsyncDemoFilter : AsyncResponseFilter { } @Suppress("EmptyFunctionBlock") - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError( + error: EnvoyError, + streamIntel: StreamIntel, + finalStreamIntel: FinalStreamIntel + ) { } @Suppress("EmptyFunctionBlock") - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + } + + @Suppress("EmptyFunctionBlock") + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { } } diff --git a/examples/kotlin/hello_world/BufferDemoFilter.kt b/examples/kotlin/hello_world/BufferDemoFilter.kt index de6151dcdb..dee61511e5 100644 --- a/examples/kotlin/hello_world/BufferDemoFilter.kt +++ b/examples/kotlin/hello_world/BufferDemoFilter.kt @@ -4,6 +4,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -56,10 +57,18 @@ class BufferDemoFilter : ResponseFilter { } @Suppress("EmptyFunctionBlock") - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError( + error: EnvoyError, + streamIntel: StreamIntel, + finalStreamIntel: FinalStreamIntel + ) { } @Suppress("EmptyFunctionBlock") - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + } + + @Suppress("EmptyFunctionBlock") + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { } } diff --git a/examples/kotlin/hello_world/DemoFilter.kt b/examples/kotlin/hello_world/DemoFilter.kt index a0f12eac69..f9c005f997 100644 --- a/examples/kotlin/hello_world/DemoFilter.kt +++ b/examples/kotlin/hello_world/DemoFilter.kt @@ -5,6 +5,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -40,11 +41,19 @@ class DemoFilter : ResponseFilter { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError( + error: EnvoyError, + streamIntel: StreamIntel, + finalStreamIntel: FinalStreamIntel + ) { Log.d("DemoFilter", "On error!") } - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { Log.d("DemoFilter", "On cancel!") } + + @Suppress("EmptyFunctionBlock") + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + } } diff --git a/examples/kotlin/hello_world/MainActivity.kt b/examples/kotlin/hello_world/MainActivity.kt index d58c7b40c1..7fc060ee25 100644 --- a/examples/kotlin/hello_world/MainActivity.kt +++ b/examples/kotlin/hello_world/MainActivity.kt @@ -135,7 +135,7 @@ class MainActivity : Activity() { recyclerView.post { viewAdapter.add(Failure(message)) } } } - .setOnError { error, _ -> + .setOnError { error, _, _ -> val attemptCount = error.attemptCount ?: -1 val message = "failed with error after $attemptCount attempts: ${error.message}" Log.d("MainActivity", message) diff --git a/library/cc/stream_callbacks.cc b/library/cc/stream_callbacks.cc index ece9ce32a0..1a6203f9cd 100644 --- a/library/cc/stream_callbacks.cc +++ b/library/cc/stream_callbacks.cc @@ -50,7 +50,8 @@ void* c_on_trailers(envoy_headers metadata, envoy_stream_intel, void* context) { return context; } -void* c_on_error(envoy_error raw_error, envoy_stream_intel, void* context) { +void* c_on_error(envoy_error raw_error, envoy_stream_intel, envoy_final_stream_intel, + void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_error.has_value()) { @@ -65,7 +66,7 @@ void* c_on_error(envoy_error raw_error, envoy_stream_intel, void* context) { return nullptr; } -void* c_on_complete(envoy_stream_intel, void* context) { +void* c_on_complete(envoy_stream_intel, envoy_final_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_complete.has_value()) { @@ -76,7 +77,7 @@ void* c_on_complete(envoy_stream_intel, void* context) { return nullptr; } -void* c_on_cancel(envoy_stream_intel, void* context) { +void* c_on_cancel(envoy_stream_intel, envoy_final_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_cancel.has_value()) { diff --git a/library/common/extensions/filters/http/platform_bridge/c_types.h b/library/common/extensions/filters/http/platform_bridge/c_types.h index d0849ceb14..00154db773 100644 --- a/library/common/extensions/filters/http/platform_bridge/c_types.h +++ b/library/common/extensions/filters/http/platform_bridge/c_types.h @@ -137,12 +137,15 @@ typedef envoy_filter_resume_status (*envoy_filter_on_resume_f)( /** * Function signature for on-cancellation filter invocations. */ -typedef void (*envoy_filter_on_cancel_f)(envoy_stream_intel stream_intel, const void* context); +typedef void (*envoy_filter_on_cancel_f)(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, + const void* context); /** * Function signature for on-error filter invocations. */ typedef void (*envoy_filter_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, const void* context); /** diff --git a/library/common/extensions/filters/http/platform_bridge/filter.cc b/library/common/extensions/filters/http/platform_bridge/filter.cc index 4ca94f0c5e..19cdba7d17 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.cc +++ b/library/common/extensions/filters/http/platform_bridge/filter.cc @@ -152,7 +152,8 @@ void PlatformBridgeFilter::onDestroy() { // If the filter chain is destroyed before a response is received, treat as cancellation. if (!response_filter_base_->state_.stream_complete_ && platform_filter_.on_cancel) { ENVOY_LOG(trace, "PlatformBridgeFilter({})->on_cancel", filter_name_); - platform_filter_.on_cancel(streamIntel(), platform_filter_.instance_context); + platform_filter_.on_cancel(streamIntel(), finalStreamIntel(), + platform_filter_.instance_context); } // Allow nullptr as no-op only if nothing was initialized. @@ -181,12 +182,21 @@ Http::LocalErrorStatus PlatformBridgeFilter::onLocalReply(const LocalReplyData& envoy_data error_message = Data::Utility::copyToBridgeData(reply.details_); int32_t attempts = static_cast(info.attemptCount().value_or(0)); platform_filter_.on_error({error_code, error_message, attempts}, streamIntel(), - platform_filter_.instance_context); + finalStreamIntel(), platform_filter_.instance_context); } return Http::LocalErrorStatus::ContinueAndResetStream; } +envoy_final_stream_intel PlatformBridgeFilter::finalStreamIntel() { + RELEASE_ASSERT(decoder_callbacks_, "StreamInfo accessed before filter callbacks are set"); + // FIXME: Stream handle cannot currently be set from the filter context. + envoy_final_stream_intel final_stream_intel; + memset(&final_stream_intel, 0, sizeof(final_stream_intel)); + // TODO(alyssawilk) set stream intel from a shared helper function. + return final_stream_intel; +} + envoy_stream_intel PlatformBridgeFilter::streamIntel() { RELEASE_ASSERT(decoder_callbacks_, "StreamInfo accessed before filter callbacks are set"); auto& info = decoder_callbacks_->streamInfo(); @@ -463,7 +473,7 @@ Http::FilterHeadersStatus PlatformBridgeFilter::encodeHeaders(Http::ResponseHead if (platform_filter_.on_error) { platform_filter_.on_error({error_code, error_message, attempt_count}, streamIntel(), - platform_filter_.instance_context); + finalStreamIntel(), platform_filter_.instance_context); } else { release_envoy_data(error_message); } diff --git a/library/common/extensions/filters/http/platform_bridge/filter.h b/library/common/extensions/filters/http/platform_bridge/filter.h index 84e00182d5..0a495363c8 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.h +++ b/library/common/extensions/filters/http/platform_bridge/filter.h @@ -87,6 +87,7 @@ class PlatformBridgeFilter final : public Http::PassThroughFilter, void dumpState(std::ostream& os, int indent_level = 0) const override; // Common stream instrumentation. + envoy_final_stream_intel finalStreamIntel(); envoy_stream_intel streamIntel(); // Filter state. diff --git a/library/common/http/client.cc b/library/common/http/client.cc index 0bdf7c153c..5bba847be6 100644 --- a/library/common/http/client.cc +++ b/library/common/http/client.cc @@ -18,6 +18,29 @@ namespace Envoy { namespace Http { +namespace { + +void setFromOptional(uint64_t& to_set, const absl::optional& time) { + if (time.has_value()) { + to_set = std::chrono::duration_cast(time.value().time_since_epoch()) + .count(); + } +} + +void setFromOptional(long& to_set, absl::optional time, long offset) { + if (time.has_value()) { + to_set = offset + std::chrono::duration_cast(time.value()).count(); + } +} + +void setFromOptional(long& to_set, const absl::optional& time) { + if (time.has_value()) { + to_set = std::chrono::duration_cast(time.value().time_since_epoch()) + .count(); + } +} + +} // namespace /** * IMPORTANT: stream closure semantics in envoy mobile depends on the fact that the HCM fires a @@ -160,6 +183,29 @@ void Client::DirectStreamCallbacks::sendTrailersToBridge(const ResponseTrailerMa onComplete(); } +void Client::DirectStreamCallbacks::setFinalStreamIntel(envoy_final_stream_intel& final_intel) { + memset(&final_intel, 0, sizeof(envoy_final_stream_intel)); + + final_intel.request_start_ms = direct_stream_.latency_info_.request_start_ms; + if (direct_stream_.latency_info_.upstream_info_) { + const StreamInfo::UpstreamTiming& timing = + direct_stream_.latency_info_.upstream_info_->upstreamTiming(); + setFromOptional(final_intel.sending_start_ms, timing.first_upstream_tx_byte_sent_); + setFromOptional(final_intel.sending_end_ms, timing.last_upstream_tx_byte_sent_); + setFromOptional(final_intel.response_start_ms, timing.first_upstream_rx_byte_received_); + setFromOptional(final_intel.connect_start_ms, timing.upstream_connect_start_); + setFromOptional(final_intel.connect_end_ms, timing.upstream_connect_complete_); + setFromOptional(final_intel.ssl_start_ms, timing.upstream_connect_complete_); + setFromOptional(final_intel.ssl_end_ms, timing.upstream_handshake_complete_); + } + final_intel.dns_start_ms = direct_stream_.latency_info_.dns_start_ms; + final_intel.dns_end_ms = direct_stream_.latency_info_.dns_end_ms; + final_intel.request_end_ms = direct_stream_.latency_info_.request_end_ms; + final_intel.socket_reused = 0; // TODO(alyssawilk) set. + final_intel.sent_byte_count = direct_stream_.latency_info_.sent_byte_count; + final_intel.received_byte_count = direct_stream_.latency_info_.received_byte_count; +} + void Client::DirectStreamCallbacks::resumeData(int32_t bytes_to_send) { ASSERT(explicit_flow_control_); ASSERT(bytes_to_send > 0); @@ -209,7 +255,10 @@ void Client::DirectStreamCallbacks::onComplete() { } else { http_client_.stats().stream_failure_.inc(); } - bridge_callbacks_.on_complete(streamIntel(), bridge_callbacks_.context); + + envoy_final_stream_intel final_intel; + setFinalStreamIntel(final_intel); + bridge_callbacks_.on_complete(streamIntel(), final_intel, bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onError() { @@ -236,7 +285,9 @@ void Client::DirectStreamCallbacks::onError() { direct_stream_.stream_handle_); http_client_.stats().stream_failure_.inc(); - bridge_callbacks_.on_error(error_.value(), streamIntel(), bridge_callbacks_.context); + envoy_final_stream_intel final_intel; + setFinalStreamIntel(final_intel); + bridge_callbacks_.on_error(error_.value(), streamIntel(), final_intel, bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onSendWindowAvailable() { @@ -246,9 +297,12 @@ void Client::DirectStreamCallbacks::onSendWindowAvailable() { void Client::DirectStreamCallbacks::onCancel() { ScopeTrackerScopeState scope(&direct_stream_, http_client_.scopeTracker()); + ENVOY_LOG(debug, "[S{}] dispatching to platform cancel stream", direct_stream_.stream_handle_); http_client_.stats().stream_cancel_.inc(); - bridge_callbacks_.on_cancel(streamIntel(), bridge_callbacks_.context); + envoy_final_stream_intel final_intel; + setFinalStreamIntel(final_intel); + bridge_callbacks_.on_cancel(streamIntel(), final_intel, bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onHasBufferedData() { @@ -274,6 +328,29 @@ void Client::DirectStream::saveLatestStreamIntel() { stream_intel_.connection_id = info.upstreamConnectionId().value_or(-1); stream_intel_.stream_id = static_cast(stream_handle_); stream_intel_.attempt_count = info.attemptCount().value_or(0); + saveFinalStreamIntel(); +} + +void Client::DirectStream::saveFinalStreamIntel() { + const auto& info = request_decoder_->streamInfo(); + latency_info_.request_start_ms = std::chrono::duration_cast( + info.startTimeMonotonic().time_since_epoch()) + .count(); + latency_info_.sent_byte_count = info.bytesSent(); + latency_info_.received_byte_count = info.bytesReceived(); + setFromOptional(latency_info_.request_end_ms, info.lastDownstreamRxByteReceived(), + latency_info_.request_start_ms); + setFromOptional(latency_info_.dns_start_ms, + request_decoder_->streamInfo().downstreamTiming().getValue( + "envoy.dynamic_forward_proxy.dns_start_ms")); + setFromOptional(latency_info_.dns_end_ms, + request_decoder_->streamInfo().downstreamTiming().getValue( + "envoy.dynamic_forward_proxy.dns_end_ms")); + // TODO(alyssawilk) sort out why upstream info is problematic for cronvoy tests. + return; + if (info.upstreamInfo().has_value()) { + latency_info_.upstream_info_ = request_decoder_->streamInfo().upstreamInfo(); + } } envoy_error Client::DirectStreamCallbacks::streamError() { @@ -309,6 +386,7 @@ void Client::DirectStream::resetStream(StreamResetReason reason) { // This seems in line with other codec implementations, and so the assumption is that this is in // line with upstream expectations. // TODO(goaway): explore an upstream fix to get the HCM to clean up ActiveStream itself. + saveFinalStreamIntel(); runResetCallbacks(reason); if (!parent_.getStream(stream_handle_, GetStreamFilters::ALLOW_FOR_ALL_STREAMS)) { // We don't assert here, because Envoy will issue a stream reset if a stream closes remotely diff --git a/library/common/http/client.h b/library/common/http/client.h index 455f67fdc5..982fc0cba1 100644 --- a/library/common/http/client.h +++ b/library/common/http/client.h @@ -37,6 +37,17 @@ struct HttpClientStats { ALL_HTTP_CLIENT_STATS(GENERATE_COUNTER_STRUCT) }; +struct LatencyInfo { + long request_start_ms = 0; + long request_end_ms = 0; + long dns_start_ms = 0; + long dns_end_ms = 0; + long sent_byte_count = 0; + long received_byte_count = 0; + // Latest latency info received from StreamInfo. + std::shared_ptr upstream_info_{}; +}; + /** * Manages HTTP streams, and provides an interface to interact with them. */ @@ -166,6 +177,8 @@ class Client : public Logger::Loggable { // than bytes_to_send. void resumeData(int32_t bytes_to_send); + void setFinalStreamIntel(envoy_final_stream_intel& final_intel); + private: bool hasBufferedData() { return response_data_.get() && response_data_->length() != 0; } @@ -241,9 +254,12 @@ class Client : public Logger::Loggable { response_details_ = response_details; } - // Saves latest "Intel" data as it may not be available when accessed. + // Latches stream information as it may not be available when accessed. void saveLatestStreamIntel(); + // Latches latency info from stream info before it goes away. + void saveFinalStreamIntel(); + const envoy_stream_t stream_handle_; // Used to issue outgoing HTTP stream operations. @@ -271,6 +287,7 @@ class Client : public Logger::Loggable { bool explicit_flow_control_ = false; // Latest intel data retrieved from the StreamInfo. envoy_stream_intel stream_intel_; + LatencyInfo latency_info_; StreamInfo::BytesMeterSharedPtr bytes_meter_; }; diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index 8fc8309831..c036ebf78e 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -665,40 +665,62 @@ jvm_http_filter_on_resume_response(envoy_headers* headers, envoy_data* data, stream_intel, context); } -static void* jvm_on_complete(envoy_stream_intel, void* context) { - jni_delete_global_ref(context); - return NULL; +static void* call_jvm_on_complete(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + jni_log("[Envoy]", "jvm_on_complete"); + + JNIEnv* env = get_env(); + jobject j_context = static_cast(context); + + jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); + jmethodID jmid_onComplete = + env->GetMethodID(jcls_JvmObserverContext, "onComplete", "([J[J)Ljava/lang/Object;"); + + jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); + jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); + jobject result = + env->CallObjectMethod(j_context, jmid_onComplete, j_stream_intel, j_final_stream_intel); + + env->DeleteLocalRef(j_stream_intel); + env->DeleteLocalRef(j_final_stream_intel); + env->DeleteLocalRef(jcls_JvmObserverContext); + return result; } -static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, void* context) { +static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_error"); JNIEnv* env = get_env(); jobject j_context = static_cast(context); jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); jmethodID jmid_onError = - env->GetMethodID(jcls_JvmObserverContext, "onError", "(I[BI[J)Ljava/lang/Object;"); + env->GetMethodID(jcls_JvmObserverContext, "onError", "(I[BI[J[J)Ljava/lang/Object;"); jbyteArray j_error_message = native_data_to_array(env, error.message); jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); + jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); jobject result = env->CallObjectMethod(j_context, jmid_onError, error.error_code, j_error_message, - error.attempt_count, j_stream_intel); + error.attempt_count, j_stream_intel, j_final_stream_intel); env->DeleteLocalRef(j_stream_intel); + env->DeleteLocalRef(j_final_stream_intel); env->DeleteLocalRef(j_error_message); env->DeleteLocalRef(jcls_JvmObserverContext); release_envoy_error(error); return result; } -static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, void* context) { - void* result = call_jvm_on_error(error, stream_intel, context); +static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + void* result = call_jvm_on_error(error, stream_intel, final_stream_intel, context); jni_delete_global_ref(context); return result; } -static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, void* context) { +static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_cancel"); JNIEnv* env = get_env(); @@ -706,30 +728,44 @@ static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, void* context) jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); jmethodID jmid_onCancel = - env->GetMethodID(jcls_JvmObserverContext, "onCancel", "([J)Ljava/lang/Object;"); + env->GetMethodID(jcls_JvmObserverContext, "onCancel", "([J[J)Ljava/lang/Object;"); jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); + jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); - jobject result = env->CallObjectMethod(j_context, jmid_onCancel, j_stream_intel); + jobject result = + env->CallObjectMethod(j_context, jmid_onCancel, j_stream_intel, j_final_stream_intel); env->DeleteLocalRef(j_stream_intel); + env->DeleteLocalRef(j_final_stream_intel); env->DeleteLocalRef(jcls_JvmObserverContext); return result; } -static void* jvm_on_cancel(envoy_stream_intel stream_intel, void* context) { - void* result = call_jvm_on_cancel(stream_intel, context); +static void* jvm_on_complete(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + void* result = call_jvm_on_complete(stream_intel, final_stream_intel, context); + jni_delete_global_ref(context); + return result; +} + +static void* jvm_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + void* result = call_jvm_on_cancel(stream_intel, final_stream_intel, context); jni_delete_global_ref(context); return result; } static void jvm_http_filter_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, const void* context) { - call_jvm_on_error(error, stream_intel, const_cast(context)); + call_jvm_on_error(error, stream_intel, final_stream_intel, const_cast(context)); } -static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, const void* context) { - call_jvm_on_cancel(stream_intel, const_cast(context)); +static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, + const void* context) { + call_jvm_on_cancel(stream_intel, final_stream_intel, const_cast(context)); } static void* jvm_on_send_window_available(envoy_stream_intel stream_intel, void* context) { diff --git a/library/common/jni/jni_utility.cc b/library/common/jni/jni_utility.cc index ccb970c722..7362673d59 100644 --- a/library/common/jni/jni_utility.cc +++ b/library/common/jni/jni_utility.cc @@ -97,6 +97,33 @@ jlongArray native_stream_intel_to_array(JNIEnv* env, envoy_stream_intel stream_i return j_array; } +jlongArray native_final_stream_intel_to_array(JNIEnv* env, + envoy_final_stream_intel final_stream_intel) { + jlongArray j_array = env->NewLongArray(14); + jlong* critical_array = static_cast(env->GetPrimitiveArrayCritical(j_array, nullptr)); + RELEASE_ASSERT(critical_array != nullptr, "unable to allocate memory in jni_utility"); + + critical_array[0] = static_cast(final_stream_intel.request_start_ms); + critical_array[1] = static_cast(final_stream_intel.dns_start_ms); + critical_array[2] = static_cast(final_stream_intel.dns_end_ms); + critical_array[3] = static_cast(final_stream_intel.connect_start_ms); + critical_array[4] = static_cast(final_stream_intel.connect_end_ms); + critical_array[5] = static_cast(final_stream_intel.ssl_start_ms); + critical_array[6] = static_cast(final_stream_intel.ssl_end_ms); + critical_array[7] = static_cast(final_stream_intel.sending_start_ms); + critical_array[8] = static_cast(final_stream_intel.sending_end_ms); + critical_array[9] = static_cast(final_stream_intel.response_start_ms); + critical_array[10] = static_cast(final_stream_intel.request_end_ms); + critical_array[11] = static_cast(final_stream_intel.socket_reused); + critical_array[12] = static_cast(final_stream_intel.sent_byte_count); + critical_array[13] = static_cast(final_stream_intel.received_byte_count); + + // Here '0' (for which there is no named constant) indicates we want to commit the changes back + // to the JVM and free the c array, where applicable. + env->ReleasePrimitiveArrayCritical(j_array, critical_array, 0); + return j_array; +} + jobject native_map_to_map(JNIEnv* env, envoy_map map) { jclass jcls_hashMap = env->FindClass("java/util/HashMap"); jmethodID jmid_hashMapInit = env->GetMethodID(jcls_hashMap, "", "(I)V"); diff --git a/library/common/jni/jni_utility.h b/library/common/jni/jni_utility.h index 908e247c8f..f75529a3a5 100644 --- a/library/common/jni/jni_utility.h +++ b/library/common/jni/jni_utility.h @@ -35,6 +35,9 @@ jbyteArray native_data_to_array(JNIEnv* env, envoy_data data); jlongArray native_stream_intel_to_array(JNIEnv* env, envoy_stream_intel stream_intel); +jlongArray native_final_stream_intel_to_array(JNIEnv* env, + envoy_final_stream_intel final_stream_intel); + /** * Utility function that copies envoy_map to a java HashMap jobject. * diff --git a/library/common/types/c_types.h b/library/common/types/c_types.h index 318a0f0af7..417a1872aa 100644 --- a/library/common/types/c_types.h +++ b/library/common/types/c_types.h @@ -141,7 +141,8 @@ typedef struct { } envoy_error; /** - * Contains internal HTTP stream metrics, context, and other details. + * Contains internal HTTP stream metrics, context, and other details which are + * sent with most callbacks. * * Note these values may change over the lifecycle of a stream. */ @@ -154,6 +155,44 @@ typedef struct { uint64_t attempt_count; } envoy_stream_intel; +/** + * Contains internal HTTP stream metrics which sent at stream end. + */ +typedef struct { + // The time the request started, in ms since the epoch. + uint64_t request_start_ms; + // The time the DNS resolution for this request started, in ms since the epoch. + uint64_t dns_start_ms; + // The time the DNS resolution for this request completed, in ms since the epoch. + uint64_t dns_end_ms; + // The time the upstream connection started, in ms since the epoch. + // This may not be set if socket_reused is false. + uint64_t connect_start_ms; + // The time the upstream connection completed, in ms since the epoch. + // This may not be set if socket_reused is false. + uint64_t connect_end_ms; + // The time the SSL handshake started, in ms since the epoch. + // This may not be set if socket_reused is false. + uint64_t ssl_start_ms; + // The time the SSL handshake completed, in ms since the epoch. + // This may not be set if socket_reused is false. + uint64_t ssl_end_ms; + // The time the first byte of the request was sent upstream, in ms since the epoch. + uint64_t sending_start_ms; + // The time the last byte of the request was sent upstream, in ms since the epoch. + uint64_t sending_end_ms; + // The time the first byte of the response was received, in ms since the epoch. + uint64_t response_start_ms; + // The time the last byte of the request was received, in ms since the epoch. + uint64_t request_end_ms; + // True if the upstream socket had been used previously. + uint64_t socket_reused; + // The number of bytes sent upstream. + uint64_t sent_byte_count; + // The number of bytes received from upstream. + uint64_t received_byte_count; +} envoy_final_stream_intel; + #ifdef __cplusplus extern "C" { // utility functions #endif @@ -298,12 +337,13 @@ typedef void* (*envoy_on_trailers_f)(envoy_headers trailers, envoy_stream_intel * * @param envoy_error, the error received/caused by the async HTTP stream. * @param stream_intel, contains internal stream metrics, context, and other details. + * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, - void* context); + envoy_final_stream_intel final_stream_intel, void* context); /** * Callback signature for when an HTTP stream bi-directionally completes without error. @@ -311,11 +351,13 @@ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_i * This is a TERMINAL callback. Exactly one terminal callback will be called per stream. * * @param stream_intel, contains internal stream metrics, context, and other details. + * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, void* context); +typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context); /** * Callback signature for when an HTTP stream is cancelled. @@ -323,11 +365,13 @@ typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, void* cont * This is a TERMINAL callback. Exactly one terminal callback will be called per stream. * * @param stream_intel, contains internal stream metrics, context, and other details. + * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, void* context); +typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context); /** * Called when the envoy engine is exiting. diff --git a/library/java/io/envoyproxy/envoymobile/engine/BUILD b/library/java/io/envoyproxy/envoymobile/engine/BUILD index 7fbf08cf5f..3b0f29c85e 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/BUILD +++ b/library/java/io/envoyproxy/envoymobile/engine/BUILD @@ -25,6 +25,7 @@ java_library( "EnvoyConfiguration.java", "EnvoyEngine.java", "EnvoyEngineImpl.java", + "EnvoyFinalStreamIntelImpl.java", "EnvoyHTTPFilterCallbacksImpl.java", "EnvoyHTTPStream.java", "EnvoyNativeFilterConfig.java", diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java new file mode 100644 index 0000000000..050cede043 --- /dev/null +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java @@ -0,0 +1,94 @@ +package io.envoyproxy.envoymobile.engine; + +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel; + +class EnvoyFinalStreamIntelImpl implements EnvoyFinalStreamIntel { + private long requestStartMs; + private long dnsStartMs; + private long dnsEndMs; + private long connectStartMs; + private long connectEndMs; + private long sslStartMs; + private long sslEndMs; + private long sendingStartMs; + private long sendingEndMs; + private long responseStartMs; + private long requestEndMs; + private boolean socketReused; + private long sentByteCount; + private long receivedByteCount; + + EnvoyFinalStreamIntelImpl(long[] values) { + requestStartMs = values[0]; + dnsStartMs = values[1]; + dnsEndMs = values[2]; + connectStartMs = values[3]; + connectEndMs = values[4]; + sslStartMs = values[5]; + sslEndMs = values[6]; + sendingStartMs = values[7]; + sendingEndMs = values[8]; + responseStartMs = values[9]; + requestEndMs = values[10]; + socketReused = values[11] != 0; + sentByteCount = values[12]; + receivedByteCount = values[13]; + } + + @Override + public long getRequestStartMs() { + return requestStartMs; + } + @Override + public long getDnsStartMs() { + return dnsStartMs; + } + @Override + public long getDnsEndMs() { + return dnsEndMs; + } + @Override + public long getConnectStartMs() { + return connectStartMs; + } + @Override + public long getConnectEndMs() { + return connectEndMs; + } + @Override + public long getSslStartMs() { + return sslStartMs; + } + @Override + public long getSslEndMs() { + return sslEndMs; + } + @Override + public long getSendingStartMs() { + return sendingStartMs; + } + @Override + public long getSendingEndMs() { + return sendingEndMs; + } + @Override + public long getResponseStartMs() { + return responseStartMs; + } + @Override + public long getRequestEndMs() { + return requestEndMs; + } + @Override + public boolean getSocketReused() { + return socketReused; + } + @Override + public long getSentByteCount() { + return sentByteCount; + } + @Override + public long getReceivedByteCount() { + return receivedByteCount; + } +} diff --git a/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java b/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java index b93ab7f390..e37972fd3b 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java @@ -90,18 +90,22 @@ public void run() { /** * Dispatches error received from the JNI layer up to the platform. * - * @param errorCode, the error code. - * @param message, the error message. - * @param attemptCount, the number of times an operation was attempted before firing this error. - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @return Object, not used for response callbacks. + * @param errorCode, the error code. + * @param message, the error message. + * @param attemptCount, the number of times an operation was attempted before firing this + * error. + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. + * @return Object, not used for response callbacks. */ - public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel) { + public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel, + long[] finalStreamIntel) { callbacks.getExecutor().execute(new Runnable() { public void run() { String errorMessage = new String(message); callbacks.onError(errorCode, errorMessage, attemptCount, - new EnvoyStreamIntelImpl(streamIntel)); + new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); } }); @@ -111,14 +115,16 @@ public void run() { /** * Dispatches cancellation notice up to the platform * - * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. * @return Object, not used for response callbacks. */ - public Object onCancel(long[] streamIntel) { + public Object onCancel(long[] streamIntel, long[] finalStreamIntel) { callbacks.getExecutor().execute(new Runnable() { public void run() { // This call is atomically gated at the call-site and will only happen once. - callbacks.onCancel(new EnvoyStreamIntelImpl(streamIntel)); + callbacks.onCancel(new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); } }); @@ -139,6 +145,24 @@ public void run() { } }); + return null; + } + /** + * Called with all stream metrics after the final headers/data/trailers call. + * + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics for the end of stream. + * @return Object, not used for response callbacks. + */ + public Object onComplete(long[] streamIntel, long[] finalStreamIntel) { + callbacks.getExecutor().execute(new Runnable() { + public void run() { + // This call is atomically gated at the call-site and will only happen once. + callbacks.onComplete(new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + } + }); + return null; } } diff --git a/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java b/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java index e334a4af34..4c1921ce26 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java @@ -211,22 +211,40 @@ public void setResponseFilterCallbacks(long callbackHandle) { * @param message, the error message. * @param attemptCount, the number of times an operation was attempted before firing this error. * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. * @return Object, not used in HTTP filters. */ - public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel) { + public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel, + long[] finalStreamIntel) { String errorMessage = new String(message); - filter.onError(errorCode, errorMessage, attemptCount, new EnvoyStreamIntelImpl(streamIntel)); + filter.onError(errorCode, errorMessage, attemptCount, new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); return null; } /** * Dispatches cancellation notice up to the platform. * - * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. + * @return Object, not used in HTTP filters. + */ + public Object onCancel(long[] streamIntel, long[] finalStreamIntel) { + filter.onCancel(new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + return null; + } + + /** + * Dispatches stream completion notice up to the platform. + * + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. * @return Object, not used in HTTP filters. */ - public Object onCancel(long[] streamIntel) { - filter.onCancel(new EnvoyStreamIntelImpl(streamIntel)); + public Object onComplete(long[] streamIntel, long[] finalStreamIntel) { + filter.onComplete(new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); return null; } diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/BUILD b/library/java/io/envoyproxy/envoymobile/engine/types/BUILD index 0bb2abbc90..3a0010dd53 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/BUILD +++ b/library/java/io/envoyproxy/envoymobile/engine/types/BUILD @@ -6,6 +6,7 @@ java_library( name = "envoy_c_types_lib", srcs = [ "EnvoyEventTracker.java", + "EnvoyFinalStreamIntel.java", "EnvoyHTTPCallbacks.java", "EnvoyHTTPFilter.java", "EnvoyHTTPFilterCallbacks.java", diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java new file mode 100644 index 0000000000..4936176a56 --- /dev/null +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java @@ -0,0 +1,67 @@ +package io.envoyproxy.envoymobile.engine.types; + +/** + * Exposes internal HTTP stream metrics, context, and other details sent once on stream end. + */ +public interface EnvoyFinalStreamIntel { + /* + * The time the request started, in ms since the epoch. + */ + public long getRequestStartMs(); + /* + * The time the DNS resolution for this request started, in ms since the epoch. + */ + public long getDnsStartMs(); + /* + * The time the DNS resolution for this request completed, in ms since the epoch. + */ + public long getDnsEndMs(); + /* + * The time the upstream connection started, in ms since the epoch. + * This may not be set if socket_reused is false. + */ + public long getConnectStartMs(); + /* + * The time the upstream connection completed, in ms since the epoch. + * This may not be set if socket_reused is false. + */ + public long getConnectEndMs(); + /* + * The time the SSL handshake started, in ms since the epoch. + * This may not be set if socket_reused is false. + */ + public long getSslStartMs(); + /* + * The time the SSL handshake completed, in ms since the epoch. + * This may not be set if socket_reused is false. + */ + public long getSslEndMs(); + /* + * The time the first byte of the request was sent upstream, in ms since the epoch. + */ + public long getSendingStartMs(); + /* + * The time the last byte of the request was sent upstream, in ms since the epoch. + */ + public long getSendingEndMs(); + /* + * The time the first byte of the response was received, in ms since the epoch. + */ + public long getResponseStartMs(); + /* + * The time the last byte of the request was received, in ms since the epoch. + */ + public long getRequestEndMs(); + /* + * True if the upstream socket had been used previously. + */ + public boolean getSocketReused(); + /* + * The number of bytes sent upstream. + */ + public long getSentByteCount(); + /* + * The number of bytes received from upstream. + */ + public long getReceivedByteCount(); +} diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java index 8f7aa15847..eef91e1413 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java @@ -48,13 +48,19 @@ void onHeaders(Map> headers, boolean endStream, * count for an error. This is different from 0, which intentionally conveys * that the action was _not_ executed. * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. */ - void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel); + void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel, + EnvoyFinalStreamIntel finalStreamIntel); /** * Called when the async HTTP stream is canceled. + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. */ - void onCancel(EnvoyStreamIntel streamIntel); + void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel); /** * Callback signature which notify when there is buffer available for request body upload. @@ -66,4 +72,12 @@ void onHeaders(Map> headers, boolean endStream, * @param streamIntel, contains internal HTTP stream metrics, context, and other details. */ void onSendWindowAvailable(EnvoyStreamIntel streamIntel); + + /** + * Called once after the final data for the stream has been received. + * + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics. + */ + void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel); } diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java index f94e89362d..17ba29d651 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java @@ -110,13 +110,27 @@ Object[] onResumeResponse(Map> headers, ByteBuffer data, * count for an error. This is different from 0, which intentionally conveys * that the action was _not_ executed. * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. */ - void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel); + void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel, + EnvoyFinalStreamIntel finalStreamIntel); /** * Called when the async HTTP stream is canceled. * - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. + */ + void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalSteamIntel); + + /** + * Called when the async HTTP stream is complete. + * + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. */ - void onCancel(EnvoyStreamIntel streamIntel); + void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalSteamIntel); } diff --git a/library/java/org/chromium/net/impl/CronetUrlRequest.java b/library/java/org/chromium/net/impl/CronetUrlRequest.java index 259fce4665..c02e3d0d28 100644 --- a/library/java/org/chromium/net/impl/CronetUrlRequest.java +++ b/library/java/org/chromium/net/impl/CronetUrlRequest.java @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.engine.EnvoyHTTPStream; import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks; import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel; +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.MalformedURLException; @@ -771,7 +772,7 @@ public void onTrailers(Map> trailers, EnvoyStreamIntel stre @Override public void onError(int errorCode, String message, int attemptCount, - EnvoyStreamIntel streamIntel) { + EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) { if (isAbandoned()) { return; } @@ -793,7 +794,7 @@ public void onError(int errorCode, String message, int attemptCount, } @Override - public void onCancel(EnvoyStreamIntel streamIntel) { + public void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) { if (isAbandoned()) { return; } @@ -833,6 +834,9 @@ public void onSendWindowAvailable(EnvoyStreamIntel streamIntel) { mUploadDataStream.readDataReady(); // Have the next request body chunk to be sent. } + @Override + public void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) {} + /** * Sends one chunk of the request body if the state permits. This method is not re-entrant, but * by contract this method can only be invoked once for the first chunk, and then once per diff --git a/library/kotlin/io/envoyproxy/envoymobile/BUILD b/library/kotlin/io/envoyproxy/envoymobile/BUILD index e28ae2863c..66d5c9f271 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/BUILD +++ b/library/kotlin/io/envoyproxy/envoymobile/BUILD @@ -61,6 +61,7 @@ envoy_mobile_kt_library( "StreamClient.kt", "StreamClientImpl.kt", "StreamIntel.kt", + "FinalStreamIntel.kt", "StreamPrototype.kt", "StringAccessor.kt", "Trailers.kt", diff --git a/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt b/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt new file mode 100644 index 0000000000..5375146578 --- /dev/null +++ b/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt @@ -0,0 +1,57 @@ +package io.envoyproxy.envoymobile + +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel + +/** + * Exposes one time HTTP stream metrics, context, and other details. + * @param requestStartMs The time the request started, in ms since the epoch. + * @param dnsStartMs The time the DNS resolution for this request started, in ms since the epoch. + * @param dnsEndMs The time the DNS resolution for this request completed, in ms since the epoch. + * @param connectStartMsThe time the upstream connection started, in ms since the epoch. + * This may not be set if socket_reused is false. + * @param connectEndMs The time the upstream connection completed, in ms since the epoch. + * This may not be set if socket_reused is false. + * @param sslStartMs The time the SSL handshake started, in ms since the epoch. + * This may not be set if socket_reused is false. + * @param sslEndMs The time the SSL handshake completed, in ms since the epoch. + * This may not be set if socket_reused is false. + * @param sendingStartMs The time the first byte of the request was sent upstream, + * in ms since the epoch. + * @param sendingEndMs The time the last byte of the request was sent upstream, in ms since the + * epoch. + * @param responseStartMs The time the first byte of the response was received, in ms since the + * epoch. + * @param @param requestEndMs The time the last byte of the request was received, in ms since the + * epoch. + * @param socket_reused True if the upstream socket had been used previously. + * @param sentByteCount The number of bytes sent upstream. + * @param receivedByteCount The number of bytes received from upstream. + */ +@Suppress("LongParameterList") +class FinalStreamIntel constructor( + val requestStartMs: Long, + val dnsStartMs: Long, + val dnsEndMs: Long, + val connectStartMs: Long, + val connectEndMs: Long, + val sslStartMs: Long, + val sslEndMs: Long, + val sendingStartMs: Long, + val sendingEndMs: Long, + val responseStartMs: Long, + val requestEndMs: Long, + val socketReused: Boolean, + val sentByteCount: Long, + val receivedByteCount: Long +) { + constructor(base: EnvoyFinalStreamIntel) : this( + base.requestStartMs, base.dnsStartMs, + base.dnsEndMs, base.connectStartMs, + base.connectEndMs, base.sslStartMs, + base.sslEndMs, base.sendingStartMs, + base.sendingEndMs, + base.responseStartMs, base.requestEndMs, + base.socketReused, base.sentByteCount, + base.receivedByteCount + ) +} diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt index 67fcf84dbe..43e3251a9d 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt @@ -1,5 +1,6 @@ package io.envoyproxy.envoymobile +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel import java.nio.ByteBuffer @@ -17,9 +18,12 @@ internal class StreamCallbacks { )? = null var onData: ((data: ByteBuffer, endStream: Boolean, streamIntel: StreamIntel) -> Unit)? = null var onTrailers: ((trailers: ResponseTrailers, streamIntel: StreamIntel) -> Unit)? = null - var onCancel: ((streamIntel: StreamIntel) -> Unit)? = null - var onError: ((error: EnvoyError, streamIntel: StreamIntel) -> Unit)? = null + var onCancel: ((streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit)? = null + var onError: ( + (error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + )? = null var onSendWindowAvailable: ((streamIntel: StreamIntel) -> Unit)? = null + var onComplete: ((streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit)? = null } /** @@ -54,19 +58,25 @@ internal class EnvoyHTTPCallbacksAdapter( errorCode: Int, message: String, attemptCount: Int, - streamIntel: EnvoyStreamIntel + streamIntel: EnvoyStreamIntel, + finalStreamIntel: EnvoyFinalStreamIntel ) { callbacks.onError?.invoke( EnvoyError(errorCode, message, attemptCount), - StreamIntel(streamIntel) + StreamIntel(streamIntel), + FinalStreamIntel(finalStreamIntel) ) } - override fun onCancel(streamIntel: EnvoyStreamIntel) { - callbacks.onCancel?.invoke(StreamIntel(streamIntel)) + override fun onCancel(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + callbacks.onCancel?.invoke(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) } override fun onSendWindowAvailable(streamIntel: EnvoyStreamIntel) { callbacks.onSendWindowAvailable?.invoke(StreamIntel(streamIntel)) } + + override fun onComplete(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + callbacks.onComplete?.invoke(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + } } diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt index f7fb49745d..863e3e009c 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt @@ -25,7 +25,10 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return The new stream. */ open fun start(executor: Executor = Executors.newSingleThreadExecutor()): Stream { - val engineStream = engine.startStream(createCallbacks(executor), explicitFlowControl) + val engineStream = engine.startStream( + createCallbacks(executor), + explicitFlowControl + ) return Stream(engineStream, useByteBufferPosition) } @@ -107,12 +110,30 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return This stream, for chaining syntax. */ fun setOnError( - closure: (error: EnvoyError, streamIntel: StreamIntel) -> Unit + closure: ( + error: EnvoyError, + streamIntel: StreamIntel, + finalStreamIntel: FinalStreamIntel + ) -> Unit ): StreamPrototype { callbacks.onError = closure return this } +/** + * Specify a callback for when a stream is complete. + * If the closure is called, the stream is complete. + * + * @param closure Closure which will be called when an error occurs. + * @return This stream, for chaining syntax. + */ + fun setOnComplete( + closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + ): StreamPrototype { + callbacks.onComplete = closure + return this + } + /** * Specify a callback for when the stream is canceled. * If the closure is called, the stream is complete. @@ -121,7 +142,7 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return This stream, for chaining syntax. */ fun setOnCancel( - closure: (streamIntel: StreamIntel) -> Unit + closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit ): StreamPrototype { callbacks.onCancel = closure return this diff --git a/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt b/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt index 02ab7a5e24..1741b85f2b 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt @@ -1,5 +1,6 @@ package io.envoyproxy.envoymobile +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilter import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterCallbacks import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterFactory @@ -99,15 +100,21 @@ internal class EnvoyHTTPFilterAdapter( return arrayOf(0, trailers) } - override fun onError(errorCode: Int, message: String, attemptCount: Int, streamIntel: EnvoyStreamIntel) { + override fun onError(errorCode: Int, message: String, attemptCount: Int, streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onError(EnvoyError(errorCode, message, attemptCount), StreamIntel(streamIntel)) + responseFilter.onError(EnvoyError(errorCode, message, attemptCount), StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) } } - override fun onCancel(streamIntel: EnvoyStreamIntel) { + override fun onCancel(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onCancel(StreamIntel(streamIntel)) + responseFilter.onCancel(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + } + } + + override fun onComplete(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + (filter as? ResponseFilter)?.let { responseFilter -> + responseFilter.onComplete(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) } } diff --git a/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt b/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt index 2c025164ce..c8dbcf7b6e 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt @@ -55,8 +55,9 @@ interface ResponseFilter : Filter { * * @param error: The error that occurred within Envoy. * @param streamIntel: Internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. */ - fun onError(error: EnvoyError, streamIntel: StreamIntel) + fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) /** * Called at most once when the client cancels the stream. @@ -65,6 +66,18 @@ interface ResponseFilter : Filter { * `stopIteration{...}`. * * @param streamIntel: Internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. */ - fun onCancel(streamIntel: StreamIntel) + fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) + +/** + * Called at most once when the stream is complete. + * + * This should be considered a terminal state, and invalidates any previous attempts to + * `stopIteration{...}`. + * + * @param streamIntel: Internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. + */ + fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) } diff --git a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt index 87aafbdc12..78618658af 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt @@ -89,7 +89,7 @@ class GRPCStreamPrototype( * @return This stream, for chaining syntax. */ fun setOnError( - closure: (error: EnvoyError, streamIntel: StreamIntel) -> Unit + closure: (error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit ): GRPCStreamPrototype { underlyingStream.setOnError(closure) return this @@ -103,7 +103,7 @@ class GRPCStreamPrototype( * @return This stream, for chaining syntax. */ fun setOnCancel( - closure: (streamIntel: StreamIntel) -> Unit + closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit ): GRPCStreamPrototype { underlyingStream.setOnCancel(closure) return this diff --git a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt index b85cf0c8fd..7f326d22ab 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt @@ -1,5 +1,6 @@ package io.envoyproxy.envoymobile +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel import java.nio.ByteBuffer @@ -16,6 +17,22 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S override fun getAttemptCount(): Long { return 0 } } + private val mockFinalStreamIntel = object : EnvoyFinalStreamIntel { + override fun getRequestStartMs(): Long { return 0 } + override fun getDnsStartMs(): Long { return 0 } + override fun getDnsEndMs(): Long { return 0 } + override fun getConnectStartMs(): Long { return 0 } + override fun getConnectEndMs(): Long { return 0 } + override fun getSslStartMs(): Long { return 0 } + override fun getSslEndMs(): Long { return 0 } + override fun getSendingStartMs(): Long { return 0 } + override fun getSendingEndMs(): Long { return 0 } + override fun getResponseStartMs(): Long { return 0 } + override fun getRequestEndMs(): Long { return 0 } + override fun getSocketReused(): Boolean { return false } + override fun getSentByteCount(): Long { return 0 } + override fun getReceivedByteCount(): Long { return 0 } + } /** * Closure that will be called when request headers are sent. */ @@ -88,7 +105,7 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S * Simulate the stream receiving a cancellation signal from Envoy. */ fun receiveCancel() { - mockStream.callbacks.onCancel(mockStreamIntel) + mockStream.callbacks.onCancel(mockStreamIntel, mockFinalStreamIntel) } /** @@ -97,6 +114,6 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S * @param error The error to receive. */ fun receiveError(error: EnvoyError) { - mockStream.callbacks.onError(error.errorCode, error.message, error.attemptCount ?: 0, mockStreamIntel) + mockStream.callbacks.onError(error.errorCode, error.message, error.attemptCount ?: 0, mockStreamIntel, mockFinalStreamIntel) } } diff --git a/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc b/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc index 801e4cea4e..8ed9a651c3 100644 --- a/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc +++ b/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc @@ -676,7 +676,7 @@ TEST_F(PlatformBridgeFilterTest, BasicError) { release_envoy_data(c_data); return {kEnvoyFilterDataStatusStopIterationNoBuffer, envoy_nodata, nullptr}; }; - platform_filter.on_error = [](envoy_error c_error, envoy_stream_intel, + platform_filter.on_error = [](envoy_error c_error, envoy_stream_intel, envoy_final_stream_intel, const void* context) -> void { filter_invocations* invocations = static_cast(const_cast(context)); invocations->on_error_calls++; diff --git a/test/common/http/client_test.cc b/test/common/http/client_test.cc index 1b624b6608..33f6467ef0 100644 --- a/test/common/http/client_test.cc +++ b/test/common/http/client_test.cc @@ -63,7 +63,8 @@ class ClientTest : public testing::TestWithParam { bridge_callbacks_.context = &cc_; // Set up default bridge callbacks. Indivividual tests can override. - bridge_callbacks_.on_complete = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; return nullptr; @@ -77,7 +78,8 @@ class ClientTest : public testing::TestWithParam { cc->on_headers_calls++; return nullptr; }; - bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_error_calls++; return nullptr; @@ -90,7 +92,8 @@ class ClientTest : public testing::TestWithParam { release_envoy_data(c_data); return nullptr; }; - bridge_callbacks_.on_cancel = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_cancel = [](envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_cancel_calls++; return nullptr; @@ -453,7 +456,8 @@ TEST_P(ClientTest, MultipleStreams) { *on_headers_called2 = true; return nullptr; }; - bridge_callbacks_2.on_complete = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_2.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; return nullptr; @@ -502,7 +506,8 @@ TEST_P(ClientTest, MultipleStreams) { TEST_P(ClientTest, EnvoyLocalError) { // Override the on_error default with some custom checks. - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { EXPECT_EQ(error.error_code, ENVOY_CONNECTION_FAILURE); EXPECT_EQ(error.attempt_count, 123); callbacks_called* cc = static_cast(context); @@ -575,7 +580,8 @@ TEST_P(ClientTest, DoubleResetStreamLocal) { TEST_P(ClientTest, RemoteResetAfterStreamStart) { cc_.end_stream_with_headers_ = false; - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { EXPECT_EQ(error.error_code, ENVOY_STREAM_RESET); EXPECT_EQ(error.message.length, 0); EXPECT_EQ(error.attempt_count, 0); diff --git a/test/common/integration/client_integration_test.cc b/test/common/integration/client_integration_test.cc index 88f98210b1..52480f7e67 100644 --- a/test/common/integration/client_integration_test.cc +++ b/test/common/integration/client_integration_test.cc @@ -77,13 +77,15 @@ class ClientIntegrationTest : public BaseIntegrationTest, release_envoy_data(c_data); return nullptr; }; - bridge_callbacks_.on_complete = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc_ = static_cast(context); cc_->on_complete_calls++; cc_->terminal_callback->setReady(); return nullptr; }; - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { release_envoy_error(error); callbacks_called* cc_ = static_cast(context); cc_->on_error_calls++; diff --git a/test/common/main_interface_test.cc b/test/common/main_interface_test.cc index 1a85e7dbfd..474a080a36 100644 --- a/test/common/main_interface_test.cc +++ b/test/common/main_interface_test.cc @@ -154,7 +154,7 @@ TEST(MainInterfaceTest, BasicStream) { nullptr /* on_metadata */, nullptr /* on_trailers */, nullptr /* on_error */, - [](envoy_stream_intel, void* context) -> void* { + [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { auto* on_complete_notification = static_cast(context); on_complete_notification->Notify(); return nullptr; @@ -249,20 +249,20 @@ TEST(MainInterfaceTest, ResetStream) { engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); absl::Notification on_cancel_notification; - envoy_http_callbacks stream_cbs{nullptr /* on_headers */, - nullptr /* on_data */, - nullptr /* on_metadata */, - nullptr /* on_trailers */, - nullptr /* on_error */, - nullptr /* on_complete */, - [](envoy_stream_intel, void* context) -> void* { - auto* on_cancel_notification = - static_cast(context); - on_cancel_notification->Notify(); - return nullptr; - } /* on_cancel */, - nullptr /* on_send_window_available */, - &on_cancel_notification /* context */}; + envoy_http_callbacks stream_cbs{ + nullptr /* on_headers */, + nullptr /* on_data */, + nullptr /* on_metadata */, + nullptr /* on_trailers */, + nullptr /* on_error */, + nullptr /* on_complete */, + [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { + auto* on_cancel_notification = static_cast(context); + on_cancel_notification->Notify(); + return nullptr; + } /* on_cancel */, + nullptr /* on_send_window_available */, + &on_cancel_notification /* context */}; envoy_stream_t stream = init_stream(0); diff --git a/test/java/integration/AndroidEnvoyExplicitFlowTest.java b/test/java/integration/AndroidEnvoyExplicitFlowTest.java index 6f00f59171..ccc17de98c 100644 --- a/test/java/integration/AndroidEnvoyExplicitFlowTest.java +++ b/test/java/integration/AndroidEnvoyExplicitFlowTest.java @@ -393,12 +393,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { latch.countDown(); return null; }) - .setOnError((error, ignored) -> { + .setOnError((error, ignored, also_ignored) -> { response.get().setEnvoyError(error); latch.countDown(); return null; }) - .setOnCancel((ignored) -> { + .setOnCancel((ignored, also_ignored) -> { response.get().setCancelled(); latch.countDown(); return null; diff --git a/test/java/integration/AndroidEnvoyFlowTest.java b/test/java/integration/AndroidEnvoyFlowTest.java index 7d1bf250c9..a1a57e8904 100644 --- a/test/java/integration/AndroidEnvoyFlowTest.java +++ b/test/java/integration/AndroidEnvoyFlowTest.java @@ -302,12 +302,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { latch.countDown(); return null; }) - .setOnError((error, ignored) -> { + .setOnError((error, ignored, also_ignored) -> { response.get().setEnvoyError(error); latch.countDown(); return null; }) - .setOnCancel((ignored) -> { + .setOnCancel((ignored, also_ignored) -> { response.get().setCancelled(); latch.countDown(); return null; diff --git a/test/kotlin/integration/CancelStreamTest.kt b/test/kotlin/integration/CancelStreamTest.kt index e8d883ccd4..31321010fd 100644 --- a/test/kotlin/integration/CancelStreamTest.kt +++ b/test/kotlin/integration/CancelStreamTest.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.RequestHeadersBuilder import io.envoyproxy.envoymobile.RequestMethod import io.envoyproxy.envoymobile.ResponseFilter @@ -108,9 +109,10 @@ class CancelStreamTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) {} + override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { latch.countDown() } } @@ -137,7 +139,7 @@ class CancelStreamTest { .build() client.newStreamPrototype() - .setOnCancel { + .setOnCancel { _, _ -> runExpectation.countDown() } .start(Executors.newSingleThreadExecutor()) diff --git a/test/kotlin/integration/DrainConnectionsTest.kt b/test/kotlin/integration/DrainConnectionsTest.kt index 597c659120..f43c04a2a4 100644 --- a/test/kotlin/integration/DrainConnectionsTest.kt +++ b/test/kotlin/integration/DrainConnectionsTest.kt @@ -85,7 +85,7 @@ class DrainConnectionsTest { resultEndStream1 = endStream headersExpectation.countDown() } - .setOnError { _, _ -> fail("Unexpected error") } + .setOnError { _, _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) @@ -101,7 +101,7 @@ class DrainConnectionsTest { resultEndStream2 = endStream headersExpectation.countDown() } - .setOnError { _, _ -> fail("Unexpected error") } + .setOnError { _, _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/GRPCReceiveErrorTest.kt b/test/kotlin/integration/GRPCReceiveErrorTest.kt index c998706184..e83c87382f 100644 --- a/test/kotlin/integration/GRPCReceiveErrorTest.kt +++ b/test/kotlin/integration/GRPCReceiveErrorTest.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.GRPCClient import io.envoyproxy.envoymobile.GRPCRequestHeadersBuilder import io.envoyproxy.envoymobile.ResponseFilter @@ -95,11 +96,12 @@ class GRPCReceiveErrorTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { receivedError.countDown() } + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { notCancelled.countDown() } } @@ -124,10 +126,12 @@ class GRPCReceiveErrorTest { .newGRPCStreamPrototype() .setOnResponseHeaders { _, _, _ -> } .setOnResponseMessage { _, _ -> } - .setOnError { _, _ -> + .setOnError { _, _, _ -> callbackReceivedError.countDown() } - .setOnCancel { fail("Unexpected call to onCancel response callback") } + .setOnCancel { _, _ -> + fail("Unexpected call to onCancel response callback") + } .start() .sendHeaders(requestHeader, false) .sendMessage(ByteBuffer.wrap(ByteArray(5))) diff --git a/test/kotlin/integration/ReceiveDataTest.kt b/test/kotlin/integration/ReceiveDataTest.kt index 4059e14587..36702adbf5 100644 --- a/test/kotlin/integration/ReceiveDataTest.kt +++ b/test/kotlin/integration/ReceiveDataTest.kt @@ -94,7 +94,7 @@ class ReceiveDataTest { body = data dataExpectation.countDown() } - .setOnError { _, _ -> fail("Unexpected error") } + .setOnError { _, _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/ReceiveErrorTest.kt b/test/kotlin/integration/ReceiveErrorTest.kt index ed87a1e076..b7f61b239f 100644 --- a/test/kotlin/integration/ReceiveErrorTest.kt +++ b/test/kotlin/integration/ReceiveErrorTest.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.GRPCRequestHeadersBuilder import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders @@ -92,11 +93,12 @@ class ReceiveErrorTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { receivedError.countDown() } + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { notCancelled.countDown() } } @@ -125,11 +127,13 @@ class ReceiveErrorTest { .setOnResponseData { _, _, _ -> fail("Data received instead of expected error") } // The unmatched expectation will cause a local reply which gets translated in Envoy Mobile to // an error. - .setOnError { error, _ -> + .setOnError { error, _, _ -> errorCode = error.errorCode callbackReceivedError.countDown() } - .setOnCancel { fail("Unexpected call to onCancel response callback") } + .setOnCancel { _, _ -> + fail("Unexpected call to onCancel response callback") + } .start() .sendHeaders(requestHeader, true) diff --git a/test/kotlin/integration/SendDataTest.kt b/test/kotlin/integration/SendDataTest.kt index 925e9f3bea..1fe9075a8a 100644 --- a/test/kotlin/integration/SendDataTest.kt +++ b/test/kotlin/integration/SendDataTest.kt @@ -93,7 +93,7 @@ class SendDataTest { responseHeadersEndStream = endStream expectation.countDown() } - .setOnError { _, _ -> + .setOnError { _, _, _ -> fail("Unexpected error") } .start() diff --git a/test/kotlin/integration/SendHeadersTest.kt b/test/kotlin/integration/SendHeadersTest.kt index 20cdb99f01..823a524d7a 100644 --- a/test/kotlin/integration/SendHeadersTest.kt +++ b/test/kotlin/integration/SendHeadersTest.kt @@ -85,7 +85,7 @@ class SendHeadersTest { resultEndStream = endStream headersExpectation.countDown() } - .setOnError { _, _ -> fail("Unexpected error") } + .setOnError { _, _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/SendTrailersTest.kt b/test/kotlin/integration/SendTrailersTest.kt index 1392583e19..1391ced880 100644 --- a/test/kotlin/integration/SendTrailersTest.kt +++ b/test/kotlin/integration/SendTrailersTest.kt @@ -98,7 +98,7 @@ class SendTrailersTest { responseStatus = headers.httpStatus expectation.countDown() } - .setOnError { _, _ -> + .setOnError { _, _, _ -> fail("Unexpected error") } .start() diff --git a/test/kotlin/integration/StreamIdleTimeoutTest.kt b/test/kotlin/integration/StreamIdleTimeoutTest.kt index 74205b32cb..8d1117961f 100644 --- a/test/kotlin/integration/StreamIdleTimeoutTest.kt +++ b/test/kotlin/integration/StreamIdleTimeoutTest.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.RequestHeadersBuilder import io.envoyproxy.envoymobile.RequestMethod import io.envoyproxy.envoymobile.ResponseFilter @@ -131,12 +132,13 @@ class CancelStreamTest { return FilterTrailersStatus.StopIteration() } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { assertThat(error.errorCode).isEqualTo(4) latch.countDown() } + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { fail("Unexpected call to onCancel filter callback") } } @@ -163,7 +165,7 @@ class CancelStreamTest { .build() client.newStreamPrototype() - .setOnError { error, _ -> + .setOnError { error, _, _ -> assertThat(error.errorCode).isEqualTo(4) callbackExpectation.countDown() } From fa155622547359dfef2a69d7279a4d0700303773 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Fri, 3 Dec 2021 13:20:01 -0800 Subject: [PATCH 11/25] default Signed-off-by: Jose Nino --- library/common/config/config.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/library/common/config/config.cc b/library/common/config/config.cc index c41f9a15e2..ee56568e67 100644 --- a/library/common/config/config.cc +++ b/library/common/config/config.cc @@ -39,6 +39,7 @@ const std::string config_header = R"( - &dns_fail_max_interval 10s - &dns_query_timeout 25s - &dns_preresolve_hostnames [] +- &dns_resolver_name envoy.network.dns_resolver.cares - &dns_resolver_config {} - &enable_interface_binding false - &h2_connection_keepalive_idle_interval 100000s From ec5810027f2ce0f2dd12f8c37e39065df8cccd98 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Fri, 3 Dec 2021 13:20:21 -0800 Subject: [PATCH 12/25] update envoy Signed-off-by: Jose Nino --- envoy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/envoy b/envoy index eb04828a83..5a19106401 160000 --- a/envoy +++ b/envoy @@ -1 +1 @@ -Subproject commit eb04828a83df7da3dc305c5ef1e4040d05ccd740 +Subproject commit 5a19106401b6f6dfdd44eb1b6fae76a168aff77b From 4d550e4fdb4e958e8349857b46b8b3b8008cae25 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Mon, 6 Dec 2021 14:15:41 -0800 Subject: [PATCH 13/25] Revert "Revert "Revert "incompletely used APIs for final stream metrics (#1937)""" This reverts commit 3cfa846d09ccefc62b3c7546b8b32de1761dc3dc. Signed-off-by: Jose Nino --- examples/java/hello_world/MainActivity.java | 2 +- .../kotlin/hello_world/AsyncDemoFilter.kt | 13 +-- .../kotlin/hello_world/BufferDemoFilter.kt | 13 +-- examples/kotlin/hello_world/DemoFilter.kt | 13 +-- examples/kotlin/hello_world/MainActivity.kt | 2 +- library/cc/stream_callbacks.cc | 7 +- .../filters/http/platform_bridge/c_types.h | 5 +- .../filters/http/platform_bridge/filter.cc | 16 +--- .../filters/http/platform_bridge/filter.h | 1 - library/common/http/client.cc | 84 +---------------- library/common/http/client.h | 19 +--- library/common/jni/jni_interface.cc | 68 ++++---------- library/common/jni/jni_utility.cc | 27 ------ library/common/jni/jni_utility.h | 3 - library/common/types/c_types.h | 52 +--------- .../io/envoyproxy/envoymobile/engine/BUILD | 1 - .../engine/EnvoyFinalStreamIntelImpl.java | 94 ------------------- .../engine/JvmCallbackContext.java | 44 ++------- .../envoymobile/engine/JvmFilterContext.java | 28 +----- .../envoyproxy/envoymobile/engine/types/BUILD | 1 - .../engine/types/EnvoyFinalStreamIntel.java | 67 ------------- .../engine/types/EnvoyHTTPCallbacks.java | 18 +--- .../engine/types/EnvoyHTTPFilter.java | 20 +--- .../chromium/net/impl/CronetUrlRequest.java | 8 +- .../kotlin/io/envoyproxy/envoymobile/BUILD | 1 - .../envoymobile/FinalStreamIntel.kt | 57 ----------- .../envoyproxy/envoymobile/StreamCallbacks.kt | 22 ++--- .../envoyproxy/envoymobile/StreamPrototype.kt | 27 +----- .../envoyproxy/envoymobile/filters/Filter.kt | 15 +-- .../envoymobile/filters/ResponseFilter.kt | 17 +--- .../envoymobile/grpc/GRPCStreamPrototype.kt | 4 +- .../envoymobile/mocks/MockStream.kt | 21 +---- .../platform_bridge_filter_test.cc | 2 +- test/common/http/client_test.cc | 18 ++-- .../integration/client_integration_test.cc | 6 +- test/common/main_interface_test.cc | 30 +++--- .../AndroidEnvoyExplicitFlowTest.java | 4 +- .../integration/AndroidEnvoyFlowTest.java | 4 +- test/kotlin/integration/CancelStreamTest.kt | 8 +- .../integration/DrainConnectionsTest.kt | 4 +- .../integration/GRPCReceiveErrorTest.kt | 12 +-- test/kotlin/integration/ReceiveDataTest.kt | 2 +- test/kotlin/integration/ReceiveErrorTest.kt | 12 +-- test/kotlin/integration/SendDataTest.kt | 2 +- test/kotlin/integration/SendHeadersTest.kt | 2 +- test/kotlin/integration/SendTrailersTest.kt | 2 +- .../integration/StreamIdleTimeoutTest.kt | 8 +- 47 files changed, 128 insertions(+), 758 deletions(-) delete mode 100644 library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java delete mode 100644 library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java delete mode 100644 library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt diff --git a/examples/java/hello_world/MainActivity.java b/examples/java/hello_world/MainActivity.java index cf121e56eb..5d1ebcd4ac 100644 --- a/examples/java/hello_world/MainActivity.java +++ b/examples/java/hello_world/MainActivity.java @@ -125,7 +125,7 @@ private void makeRequest() { } return Unit.INSTANCE; }) - .setOnError((error, ignored, also_ignored) -> { + .setOnError((error, ignored) -> { String message = "failed with error after " + error.getAttemptCount() + " attempts: " + error.getMessage(); Log.d("MainActivity", message); diff --git a/examples/kotlin/hello_world/AsyncDemoFilter.kt b/examples/kotlin/hello_world/AsyncDemoFilter.kt index 72f6ab8463..214e01bdb6 100644 --- a/examples/kotlin/hello_world/AsyncDemoFilter.kt +++ b/examples/kotlin/hello_world/AsyncDemoFilter.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterResumeStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilterCallbacks import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -79,18 +78,10 @@ class AsyncDemoFilter : AsyncResponseFilter { } @Suppress("EmptyFunctionBlock") - override fun onError( - error: EnvoyError, - streamIntel: StreamIntel, - finalStreamIntel: FinalStreamIntel - ) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { } @Suppress("EmptyFunctionBlock") - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { - } - - @Suppress("EmptyFunctionBlock") - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { } } diff --git a/examples/kotlin/hello_world/BufferDemoFilter.kt b/examples/kotlin/hello_world/BufferDemoFilter.kt index dee61511e5..de6151dcdb 100644 --- a/examples/kotlin/hello_world/BufferDemoFilter.kt +++ b/examples/kotlin/hello_world/BufferDemoFilter.kt @@ -4,7 +4,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -57,18 +56,10 @@ class BufferDemoFilter : ResponseFilter { } @Suppress("EmptyFunctionBlock") - override fun onError( - error: EnvoyError, - streamIntel: StreamIntel, - finalStreamIntel: FinalStreamIntel - ) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { } @Suppress("EmptyFunctionBlock") - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { - } - - @Suppress("EmptyFunctionBlock") - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { } } diff --git a/examples/kotlin/hello_world/DemoFilter.kt b/examples/kotlin/hello_world/DemoFilter.kt index f9c005f997..a0f12eac69 100644 --- a/examples/kotlin/hello_world/DemoFilter.kt +++ b/examples/kotlin/hello_world/DemoFilter.kt @@ -5,7 +5,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -41,19 +40,11 @@ class DemoFilter : ResponseFilter { return FilterTrailersStatus.Continue(trailers) } - override fun onError( - error: EnvoyError, - streamIntel: StreamIntel, - finalStreamIntel: FinalStreamIntel - ) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { Log.d("DemoFilter", "On error!") } - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { Log.d("DemoFilter", "On cancel!") } - - @Suppress("EmptyFunctionBlock") - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { - } } diff --git a/examples/kotlin/hello_world/MainActivity.kt b/examples/kotlin/hello_world/MainActivity.kt index 7fc060ee25..d58c7b40c1 100644 --- a/examples/kotlin/hello_world/MainActivity.kt +++ b/examples/kotlin/hello_world/MainActivity.kt @@ -135,7 +135,7 @@ class MainActivity : Activity() { recyclerView.post { viewAdapter.add(Failure(message)) } } } - .setOnError { error, _, _ -> + .setOnError { error, _ -> val attemptCount = error.attemptCount ?: -1 val message = "failed with error after $attemptCount attempts: ${error.message}" Log.d("MainActivity", message) diff --git a/library/cc/stream_callbacks.cc b/library/cc/stream_callbacks.cc index 1a6203f9cd..ece9ce32a0 100644 --- a/library/cc/stream_callbacks.cc +++ b/library/cc/stream_callbacks.cc @@ -50,8 +50,7 @@ void* c_on_trailers(envoy_headers metadata, envoy_stream_intel, void* context) { return context; } -void* c_on_error(envoy_error raw_error, envoy_stream_intel, envoy_final_stream_intel, - void* context) { +void* c_on_error(envoy_error raw_error, envoy_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_error.has_value()) { @@ -66,7 +65,7 @@ void* c_on_error(envoy_error raw_error, envoy_stream_intel, envoy_final_stream_i return nullptr; } -void* c_on_complete(envoy_stream_intel, envoy_final_stream_intel, void* context) { +void* c_on_complete(envoy_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_complete.has_value()) { @@ -77,7 +76,7 @@ void* c_on_complete(envoy_stream_intel, envoy_final_stream_intel, void* context) return nullptr; } -void* c_on_cancel(envoy_stream_intel, envoy_final_stream_intel, void* context) { +void* c_on_cancel(envoy_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_cancel.has_value()) { diff --git a/library/common/extensions/filters/http/platform_bridge/c_types.h b/library/common/extensions/filters/http/platform_bridge/c_types.h index 00154db773..d0849ceb14 100644 --- a/library/common/extensions/filters/http/platform_bridge/c_types.h +++ b/library/common/extensions/filters/http/platform_bridge/c_types.h @@ -137,15 +137,12 @@ typedef envoy_filter_resume_status (*envoy_filter_on_resume_f)( /** * Function signature for on-cancellation filter invocations. */ -typedef void (*envoy_filter_on_cancel_f)(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, - const void* context); +typedef void (*envoy_filter_on_cancel_f)(envoy_stream_intel stream_intel, const void* context); /** * Function signature for on-error filter invocations. */ typedef void (*envoy_filter_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, const void* context); /** diff --git a/library/common/extensions/filters/http/platform_bridge/filter.cc b/library/common/extensions/filters/http/platform_bridge/filter.cc index 19cdba7d17..4ca94f0c5e 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.cc +++ b/library/common/extensions/filters/http/platform_bridge/filter.cc @@ -152,8 +152,7 @@ void PlatformBridgeFilter::onDestroy() { // If the filter chain is destroyed before a response is received, treat as cancellation. if (!response_filter_base_->state_.stream_complete_ && platform_filter_.on_cancel) { ENVOY_LOG(trace, "PlatformBridgeFilter({})->on_cancel", filter_name_); - platform_filter_.on_cancel(streamIntel(), finalStreamIntel(), - platform_filter_.instance_context); + platform_filter_.on_cancel(streamIntel(), platform_filter_.instance_context); } // Allow nullptr as no-op only if nothing was initialized. @@ -182,21 +181,12 @@ Http::LocalErrorStatus PlatformBridgeFilter::onLocalReply(const LocalReplyData& envoy_data error_message = Data::Utility::copyToBridgeData(reply.details_); int32_t attempts = static_cast(info.attemptCount().value_or(0)); platform_filter_.on_error({error_code, error_message, attempts}, streamIntel(), - finalStreamIntel(), platform_filter_.instance_context); + platform_filter_.instance_context); } return Http::LocalErrorStatus::ContinueAndResetStream; } -envoy_final_stream_intel PlatformBridgeFilter::finalStreamIntel() { - RELEASE_ASSERT(decoder_callbacks_, "StreamInfo accessed before filter callbacks are set"); - // FIXME: Stream handle cannot currently be set from the filter context. - envoy_final_stream_intel final_stream_intel; - memset(&final_stream_intel, 0, sizeof(final_stream_intel)); - // TODO(alyssawilk) set stream intel from a shared helper function. - return final_stream_intel; -} - envoy_stream_intel PlatformBridgeFilter::streamIntel() { RELEASE_ASSERT(decoder_callbacks_, "StreamInfo accessed before filter callbacks are set"); auto& info = decoder_callbacks_->streamInfo(); @@ -473,7 +463,7 @@ Http::FilterHeadersStatus PlatformBridgeFilter::encodeHeaders(Http::ResponseHead if (platform_filter_.on_error) { platform_filter_.on_error({error_code, error_message, attempt_count}, streamIntel(), - finalStreamIntel(), platform_filter_.instance_context); + platform_filter_.instance_context); } else { release_envoy_data(error_message); } diff --git a/library/common/extensions/filters/http/platform_bridge/filter.h b/library/common/extensions/filters/http/platform_bridge/filter.h index 0a495363c8..84e00182d5 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.h +++ b/library/common/extensions/filters/http/platform_bridge/filter.h @@ -87,7 +87,6 @@ class PlatformBridgeFilter final : public Http::PassThroughFilter, void dumpState(std::ostream& os, int indent_level = 0) const override; // Common stream instrumentation. - envoy_final_stream_intel finalStreamIntel(); envoy_stream_intel streamIntel(); // Filter state. diff --git a/library/common/http/client.cc b/library/common/http/client.cc index 5bba847be6..0bdf7c153c 100644 --- a/library/common/http/client.cc +++ b/library/common/http/client.cc @@ -18,29 +18,6 @@ namespace Envoy { namespace Http { -namespace { - -void setFromOptional(uint64_t& to_set, const absl::optional& time) { - if (time.has_value()) { - to_set = std::chrono::duration_cast(time.value().time_since_epoch()) - .count(); - } -} - -void setFromOptional(long& to_set, absl::optional time, long offset) { - if (time.has_value()) { - to_set = offset + std::chrono::duration_cast(time.value()).count(); - } -} - -void setFromOptional(long& to_set, const absl::optional& time) { - if (time.has_value()) { - to_set = std::chrono::duration_cast(time.value().time_since_epoch()) - .count(); - } -} - -} // namespace /** * IMPORTANT: stream closure semantics in envoy mobile depends on the fact that the HCM fires a @@ -183,29 +160,6 @@ void Client::DirectStreamCallbacks::sendTrailersToBridge(const ResponseTrailerMa onComplete(); } -void Client::DirectStreamCallbacks::setFinalStreamIntel(envoy_final_stream_intel& final_intel) { - memset(&final_intel, 0, sizeof(envoy_final_stream_intel)); - - final_intel.request_start_ms = direct_stream_.latency_info_.request_start_ms; - if (direct_stream_.latency_info_.upstream_info_) { - const StreamInfo::UpstreamTiming& timing = - direct_stream_.latency_info_.upstream_info_->upstreamTiming(); - setFromOptional(final_intel.sending_start_ms, timing.first_upstream_tx_byte_sent_); - setFromOptional(final_intel.sending_end_ms, timing.last_upstream_tx_byte_sent_); - setFromOptional(final_intel.response_start_ms, timing.first_upstream_rx_byte_received_); - setFromOptional(final_intel.connect_start_ms, timing.upstream_connect_start_); - setFromOptional(final_intel.connect_end_ms, timing.upstream_connect_complete_); - setFromOptional(final_intel.ssl_start_ms, timing.upstream_connect_complete_); - setFromOptional(final_intel.ssl_end_ms, timing.upstream_handshake_complete_); - } - final_intel.dns_start_ms = direct_stream_.latency_info_.dns_start_ms; - final_intel.dns_end_ms = direct_stream_.latency_info_.dns_end_ms; - final_intel.request_end_ms = direct_stream_.latency_info_.request_end_ms; - final_intel.socket_reused = 0; // TODO(alyssawilk) set. - final_intel.sent_byte_count = direct_stream_.latency_info_.sent_byte_count; - final_intel.received_byte_count = direct_stream_.latency_info_.received_byte_count; -} - void Client::DirectStreamCallbacks::resumeData(int32_t bytes_to_send) { ASSERT(explicit_flow_control_); ASSERT(bytes_to_send > 0); @@ -255,10 +209,7 @@ void Client::DirectStreamCallbacks::onComplete() { } else { http_client_.stats().stream_failure_.inc(); } - - envoy_final_stream_intel final_intel; - setFinalStreamIntel(final_intel); - bridge_callbacks_.on_complete(streamIntel(), final_intel, bridge_callbacks_.context); + bridge_callbacks_.on_complete(streamIntel(), bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onError() { @@ -285,9 +236,7 @@ void Client::DirectStreamCallbacks::onError() { direct_stream_.stream_handle_); http_client_.stats().stream_failure_.inc(); - envoy_final_stream_intel final_intel; - setFinalStreamIntel(final_intel); - bridge_callbacks_.on_error(error_.value(), streamIntel(), final_intel, bridge_callbacks_.context); + bridge_callbacks_.on_error(error_.value(), streamIntel(), bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onSendWindowAvailable() { @@ -297,12 +246,9 @@ void Client::DirectStreamCallbacks::onSendWindowAvailable() { void Client::DirectStreamCallbacks::onCancel() { ScopeTrackerScopeState scope(&direct_stream_, http_client_.scopeTracker()); - ENVOY_LOG(debug, "[S{}] dispatching to platform cancel stream", direct_stream_.stream_handle_); http_client_.stats().stream_cancel_.inc(); - envoy_final_stream_intel final_intel; - setFinalStreamIntel(final_intel); - bridge_callbacks_.on_cancel(streamIntel(), final_intel, bridge_callbacks_.context); + bridge_callbacks_.on_cancel(streamIntel(), bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onHasBufferedData() { @@ -328,29 +274,6 @@ void Client::DirectStream::saveLatestStreamIntel() { stream_intel_.connection_id = info.upstreamConnectionId().value_or(-1); stream_intel_.stream_id = static_cast(stream_handle_); stream_intel_.attempt_count = info.attemptCount().value_or(0); - saveFinalStreamIntel(); -} - -void Client::DirectStream::saveFinalStreamIntel() { - const auto& info = request_decoder_->streamInfo(); - latency_info_.request_start_ms = std::chrono::duration_cast( - info.startTimeMonotonic().time_since_epoch()) - .count(); - latency_info_.sent_byte_count = info.bytesSent(); - latency_info_.received_byte_count = info.bytesReceived(); - setFromOptional(latency_info_.request_end_ms, info.lastDownstreamRxByteReceived(), - latency_info_.request_start_ms); - setFromOptional(latency_info_.dns_start_ms, - request_decoder_->streamInfo().downstreamTiming().getValue( - "envoy.dynamic_forward_proxy.dns_start_ms")); - setFromOptional(latency_info_.dns_end_ms, - request_decoder_->streamInfo().downstreamTiming().getValue( - "envoy.dynamic_forward_proxy.dns_end_ms")); - // TODO(alyssawilk) sort out why upstream info is problematic for cronvoy tests. - return; - if (info.upstreamInfo().has_value()) { - latency_info_.upstream_info_ = request_decoder_->streamInfo().upstreamInfo(); - } } envoy_error Client::DirectStreamCallbacks::streamError() { @@ -386,7 +309,6 @@ void Client::DirectStream::resetStream(StreamResetReason reason) { // This seems in line with other codec implementations, and so the assumption is that this is in // line with upstream expectations. // TODO(goaway): explore an upstream fix to get the HCM to clean up ActiveStream itself. - saveFinalStreamIntel(); runResetCallbacks(reason); if (!parent_.getStream(stream_handle_, GetStreamFilters::ALLOW_FOR_ALL_STREAMS)) { // We don't assert here, because Envoy will issue a stream reset if a stream closes remotely diff --git a/library/common/http/client.h b/library/common/http/client.h index 982fc0cba1..455f67fdc5 100644 --- a/library/common/http/client.h +++ b/library/common/http/client.h @@ -37,17 +37,6 @@ struct HttpClientStats { ALL_HTTP_CLIENT_STATS(GENERATE_COUNTER_STRUCT) }; -struct LatencyInfo { - long request_start_ms = 0; - long request_end_ms = 0; - long dns_start_ms = 0; - long dns_end_ms = 0; - long sent_byte_count = 0; - long received_byte_count = 0; - // Latest latency info received from StreamInfo. - std::shared_ptr upstream_info_{}; -}; - /** * Manages HTTP streams, and provides an interface to interact with them. */ @@ -177,8 +166,6 @@ class Client : public Logger::Loggable { // than bytes_to_send. void resumeData(int32_t bytes_to_send); - void setFinalStreamIntel(envoy_final_stream_intel& final_intel); - private: bool hasBufferedData() { return response_data_.get() && response_data_->length() != 0; } @@ -254,12 +241,9 @@ class Client : public Logger::Loggable { response_details_ = response_details; } - // Latches stream information as it may not be available when accessed. + // Saves latest "Intel" data as it may not be available when accessed. void saveLatestStreamIntel(); - // Latches latency info from stream info before it goes away. - void saveFinalStreamIntel(); - const envoy_stream_t stream_handle_; // Used to issue outgoing HTTP stream operations. @@ -287,7 +271,6 @@ class Client : public Logger::Loggable { bool explicit_flow_control_ = false; // Latest intel data retrieved from the StreamInfo. envoy_stream_intel stream_intel_; - LatencyInfo latency_info_; StreamInfo::BytesMeterSharedPtr bytes_meter_; }; diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index c036ebf78e..8fc8309831 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -665,62 +665,40 @@ jvm_http_filter_on_resume_response(envoy_headers* headers, envoy_data* data, stream_intel, context); } -static void* call_jvm_on_complete(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - jni_log("[Envoy]", "jvm_on_complete"); - - JNIEnv* env = get_env(); - jobject j_context = static_cast(context); - - jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); - jmethodID jmid_onComplete = - env->GetMethodID(jcls_JvmObserverContext, "onComplete", "([J[J)Ljava/lang/Object;"); - - jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); - jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); - jobject result = - env->CallObjectMethod(j_context, jmid_onComplete, j_stream_intel, j_final_stream_intel); - - env->DeleteLocalRef(j_stream_intel); - env->DeleteLocalRef(j_final_stream_intel); - env->DeleteLocalRef(jcls_JvmObserverContext); - return result; +static void* jvm_on_complete(envoy_stream_intel, void* context) { + jni_delete_global_ref(context); + return NULL; } -static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { +static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_error"); JNIEnv* env = get_env(); jobject j_context = static_cast(context); jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); jmethodID jmid_onError = - env->GetMethodID(jcls_JvmObserverContext, "onError", "(I[BI[J[J)Ljava/lang/Object;"); + env->GetMethodID(jcls_JvmObserverContext, "onError", "(I[BI[J)Ljava/lang/Object;"); jbyteArray j_error_message = native_data_to_array(env, error.message); jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); - jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); jobject result = env->CallObjectMethod(j_context, jmid_onError, error.error_code, j_error_message, - error.attempt_count, j_stream_intel, j_final_stream_intel); + error.attempt_count, j_stream_intel); env->DeleteLocalRef(j_stream_intel); - env->DeleteLocalRef(j_final_stream_intel); env->DeleteLocalRef(j_error_message); env->DeleteLocalRef(jcls_JvmObserverContext); release_envoy_error(error); return result; } -static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_error(error, stream_intel, final_stream_intel, context); +static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, void* context) { + void* result = call_jvm_on_error(error, stream_intel, context); jni_delete_global_ref(context); return result; } -static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { +static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_cancel"); JNIEnv* env = get_env(); @@ -728,44 +706,30 @@ static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); jmethodID jmid_onCancel = - env->GetMethodID(jcls_JvmObserverContext, "onCancel", "([J[J)Ljava/lang/Object;"); + env->GetMethodID(jcls_JvmObserverContext, "onCancel", "([J)Ljava/lang/Object;"); jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); - jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); - jobject result = - env->CallObjectMethod(j_context, jmid_onCancel, j_stream_intel, j_final_stream_intel); + jobject result = env->CallObjectMethod(j_context, jmid_onCancel, j_stream_intel); env->DeleteLocalRef(j_stream_intel); - env->DeleteLocalRef(j_final_stream_intel); env->DeleteLocalRef(jcls_JvmObserverContext); return result; } -static void* jvm_on_complete(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_complete(stream_intel, final_stream_intel, context); - jni_delete_global_ref(context); - return result; -} - -static void* jvm_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context) { - void* result = call_jvm_on_cancel(stream_intel, final_stream_intel, context); +static void* jvm_on_cancel(envoy_stream_intel stream_intel, void* context) { + void* result = call_jvm_on_cancel(stream_intel, context); jni_delete_global_ref(context); return result; } static void jvm_http_filter_on_error(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, const void* context) { - call_jvm_on_error(error, stream_intel, final_stream_intel, const_cast(context)); + call_jvm_on_error(error, stream_intel, const_cast(context)); } -static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, - const void* context) { - call_jvm_on_cancel(stream_intel, final_stream_intel, const_cast(context)); +static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, const void* context) { + call_jvm_on_cancel(stream_intel, const_cast(context)); } static void* jvm_on_send_window_available(envoy_stream_intel stream_intel, void* context) { diff --git a/library/common/jni/jni_utility.cc b/library/common/jni/jni_utility.cc index 7362673d59..ccb970c722 100644 --- a/library/common/jni/jni_utility.cc +++ b/library/common/jni/jni_utility.cc @@ -97,33 +97,6 @@ jlongArray native_stream_intel_to_array(JNIEnv* env, envoy_stream_intel stream_i return j_array; } -jlongArray native_final_stream_intel_to_array(JNIEnv* env, - envoy_final_stream_intel final_stream_intel) { - jlongArray j_array = env->NewLongArray(14); - jlong* critical_array = static_cast(env->GetPrimitiveArrayCritical(j_array, nullptr)); - RELEASE_ASSERT(critical_array != nullptr, "unable to allocate memory in jni_utility"); - - critical_array[0] = static_cast(final_stream_intel.request_start_ms); - critical_array[1] = static_cast(final_stream_intel.dns_start_ms); - critical_array[2] = static_cast(final_stream_intel.dns_end_ms); - critical_array[3] = static_cast(final_stream_intel.connect_start_ms); - critical_array[4] = static_cast(final_stream_intel.connect_end_ms); - critical_array[5] = static_cast(final_stream_intel.ssl_start_ms); - critical_array[6] = static_cast(final_stream_intel.ssl_end_ms); - critical_array[7] = static_cast(final_stream_intel.sending_start_ms); - critical_array[8] = static_cast(final_stream_intel.sending_end_ms); - critical_array[9] = static_cast(final_stream_intel.response_start_ms); - critical_array[10] = static_cast(final_stream_intel.request_end_ms); - critical_array[11] = static_cast(final_stream_intel.socket_reused); - critical_array[12] = static_cast(final_stream_intel.sent_byte_count); - critical_array[13] = static_cast(final_stream_intel.received_byte_count); - - // Here '0' (for which there is no named constant) indicates we want to commit the changes back - // to the JVM and free the c array, where applicable. - env->ReleasePrimitiveArrayCritical(j_array, critical_array, 0); - return j_array; -} - jobject native_map_to_map(JNIEnv* env, envoy_map map) { jclass jcls_hashMap = env->FindClass("java/util/HashMap"); jmethodID jmid_hashMapInit = env->GetMethodID(jcls_hashMap, "", "(I)V"); diff --git a/library/common/jni/jni_utility.h b/library/common/jni/jni_utility.h index f75529a3a5..908e247c8f 100644 --- a/library/common/jni/jni_utility.h +++ b/library/common/jni/jni_utility.h @@ -35,9 +35,6 @@ jbyteArray native_data_to_array(JNIEnv* env, envoy_data data); jlongArray native_stream_intel_to_array(JNIEnv* env, envoy_stream_intel stream_intel); -jlongArray native_final_stream_intel_to_array(JNIEnv* env, - envoy_final_stream_intel final_stream_intel); - /** * Utility function that copies envoy_map to a java HashMap jobject. * diff --git a/library/common/types/c_types.h b/library/common/types/c_types.h index 417a1872aa..318a0f0af7 100644 --- a/library/common/types/c_types.h +++ b/library/common/types/c_types.h @@ -141,8 +141,7 @@ typedef struct { } envoy_error; /** - * Contains internal HTTP stream metrics, context, and other details which are - * sent with most callbacks. + * Contains internal HTTP stream metrics, context, and other details. * * Note these values may change over the lifecycle of a stream. */ @@ -155,44 +154,6 @@ typedef struct { uint64_t attempt_count; } envoy_stream_intel; -/** - * Contains internal HTTP stream metrics which sent at stream end. - */ -typedef struct { - // The time the request started, in ms since the epoch. - uint64_t request_start_ms; - // The time the DNS resolution for this request started, in ms since the epoch. - uint64_t dns_start_ms; - // The time the DNS resolution for this request completed, in ms since the epoch. - uint64_t dns_end_ms; - // The time the upstream connection started, in ms since the epoch. - // This may not be set if socket_reused is false. - uint64_t connect_start_ms; - // The time the upstream connection completed, in ms since the epoch. - // This may not be set if socket_reused is false. - uint64_t connect_end_ms; - // The time the SSL handshake started, in ms since the epoch. - // This may not be set if socket_reused is false. - uint64_t ssl_start_ms; - // The time the SSL handshake completed, in ms since the epoch. - // This may not be set if socket_reused is false. - uint64_t ssl_end_ms; - // The time the first byte of the request was sent upstream, in ms since the epoch. - uint64_t sending_start_ms; - // The time the last byte of the request was sent upstream, in ms since the epoch. - uint64_t sending_end_ms; - // The time the first byte of the response was received, in ms since the epoch. - uint64_t response_start_ms; - // The time the last byte of the request was received, in ms since the epoch. - uint64_t request_end_ms; - // True if the upstream socket had been used previously. - uint64_t socket_reused; - // The number of bytes sent upstream. - uint64_t sent_byte_count; - // The number of bytes received from upstream. - uint64_t received_byte_count; -} envoy_final_stream_intel; - #ifdef __cplusplus extern "C" { // utility functions #endif @@ -337,13 +298,12 @@ typedef void* (*envoy_on_trailers_f)(envoy_headers trailers, envoy_stream_intel * * @param envoy_error, the error received/caused by the async HTTP stream. * @param stream_intel, contains internal stream metrics, context, and other details. - * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); + void* context); /** * Callback signature for when an HTTP stream bi-directionally completes without error. @@ -351,13 +311,11 @@ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_i * This is a TERMINAL callback. Exactly one terminal callback will be called per stream. * * @param stream_intel, contains internal stream metrics, context, and other details. - * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); +typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, void* context); /** * Callback signature for when an HTTP stream is cancelled. @@ -365,13 +323,11 @@ typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, * This is a TERMINAL callback. Exactly one terminal callback will be called per stream. * * @param stream_intel, contains internal stream metrics, context, and other details. - * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, - envoy_final_stream_intel final_stream_intel, void* context); +typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, void* context); /** * Called when the envoy engine is exiting. diff --git a/library/java/io/envoyproxy/envoymobile/engine/BUILD b/library/java/io/envoyproxy/envoymobile/engine/BUILD index 3b0f29c85e..7fbf08cf5f 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/BUILD +++ b/library/java/io/envoyproxy/envoymobile/engine/BUILD @@ -25,7 +25,6 @@ java_library( "EnvoyConfiguration.java", "EnvoyEngine.java", "EnvoyEngineImpl.java", - "EnvoyFinalStreamIntelImpl.java", "EnvoyHTTPFilterCallbacksImpl.java", "EnvoyHTTPStream.java", "EnvoyNativeFilterConfig.java", diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java deleted file mode 100644 index 050cede043..0000000000 --- a/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java +++ /dev/null @@ -1,94 +0,0 @@ -package io.envoyproxy.envoymobile.engine; - -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel; - -class EnvoyFinalStreamIntelImpl implements EnvoyFinalStreamIntel { - private long requestStartMs; - private long dnsStartMs; - private long dnsEndMs; - private long connectStartMs; - private long connectEndMs; - private long sslStartMs; - private long sslEndMs; - private long sendingStartMs; - private long sendingEndMs; - private long responseStartMs; - private long requestEndMs; - private boolean socketReused; - private long sentByteCount; - private long receivedByteCount; - - EnvoyFinalStreamIntelImpl(long[] values) { - requestStartMs = values[0]; - dnsStartMs = values[1]; - dnsEndMs = values[2]; - connectStartMs = values[3]; - connectEndMs = values[4]; - sslStartMs = values[5]; - sslEndMs = values[6]; - sendingStartMs = values[7]; - sendingEndMs = values[8]; - responseStartMs = values[9]; - requestEndMs = values[10]; - socketReused = values[11] != 0; - sentByteCount = values[12]; - receivedByteCount = values[13]; - } - - @Override - public long getRequestStartMs() { - return requestStartMs; - } - @Override - public long getDnsStartMs() { - return dnsStartMs; - } - @Override - public long getDnsEndMs() { - return dnsEndMs; - } - @Override - public long getConnectStartMs() { - return connectStartMs; - } - @Override - public long getConnectEndMs() { - return connectEndMs; - } - @Override - public long getSslStartMs() { - return sslStartMs; - } - @Override - public long getSslEndMs() { - return sslEndMs; - } - @Override - public long getSendingStartMs() { - return sendingStartMs; - } - @Override - public long getSendingEndMs() { - return sendingEndMs; - } - @Override - public long getResponseStartMs() { - return responseStartMs; - } - @Override - public long getRequestEndMs() { - return requestEndMs; - } - @Override - public boolean getSocketReused() { - return socketReused; - } - @Override - public long getSentByteCount() { - return sentByteCount; - } - @Override - public long getReceivedByteCount() { - return receivedByteCount; - } -} diff --git a/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java b/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java index e37972fd3b..b93ab7f390 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java @@ -90,22 +90,18 @@ public void run() { /** * Dispatches error received from the JNI layer up to the platform. * - * @param errorCode, the error code. - * @param message, the error message. - * @param attemptCount, the number of times an operation was attempted before firing this - * error. - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. - * @return Object, not used for response callbacks. + * @param errorCode, the error code. + * @param message, the error message. + * @param attemptCount, the number of times an operation was attempted before firing this error. + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @return Object, not used for response callbacks. */ - public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel, - long[] finalStreamIntel) { + public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel) { callbacks.getExecutor().execute(new Runnable() { public void run() { String errorMessage = new String(message); callbacks.onError(errorCode, errorMessage, attemptCount, - new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + new EnvoyStreamIntelImpl(streamIntel)); } }); @@ -115,16 +111,14 @@ public void run() { /** * Dispatches cancellation notice up to the platform * - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. + * @param streamIntel, internal HTTP stream metrics, context, and other details. * @return Object, not used for response callbacks. */ - public Object onCancel(long[] streamIntel, long[] finalStreamIntel) { + public Object onCancel(long[] streamIntel) { callbacks.getExecutor().execute(new Runnable() { public void run() { // This call is atomically gated at the call-site and will only happen once. - callbacks.onCancel(new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + callbacks.onCancel(new EnvoyStreamIntelImpl(streamIntel)); } }); @@ -145,24 +139,6 @@ public void run() { } }); - return null; - } - /** - * Called with all stream metrics after the final headers/data/trailers call. - * - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics for the end of stream. - * @return Object, not used for response callbacks. - */ - public Object onComplete(long[] streamIntel, long[] finalStreamIntel) { - callbacks.getExecutor().execute(new Runnable() { - public void run() { - // This call is atomically gated at the call-site and will only happen once. - callbacks.onComplete(new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); - } - }); - return null; } } diff --git a/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java b/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java index 4c1921ce26..e334a4af34 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java @@ -211,40 +211,22 @@ public void setResponseFilterCallbacks(long callbackHandle) { * @param message, the error message. * @param attemptCount, the number of times an operation was attempted before firing this error. * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. * @return Object, not used in HTTP filters. */ - public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel, - long[] finalStreamIntel) { + public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel) { String errorMessage = new String(message); - filter.onError(errorCode, errorMessage, attemptCount, new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + filter.onError(errorCode, errorMessage, attemptCount, new EnvoyStreamIntelImpl(streamIntel)); return null; } /** * Dispatches cancellation notice up to the platform. * - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. - * @return Object, not used in HTTP filters. - */ - public Object onCancel(long[] streamIntel, long[] finalStreamIntel) { - filter.onCancel(new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); - return null; - } - - /** - * Dispatches stream completion notice up to the platform. - * - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. + * @param streamIntel, internal HTTP stream metrics, context, and other details. * @return Object, not used in HTTP filters. */ - public Object onComplete(long[] streamIntel, long[] finalStreamIntel) { - filter.onComplete(new EnvoyStreamIntelImpl(streamIntel), - new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + public Object onCancel(long[] streamIntel) { + filter.onCancel(new EnvoyStreamIntelImpl(streamIntel)); return null; } diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/BUILD b/library/java/io/envoyproxy/envoymobile/engine/types/BUILD index 3a0010dd53..0bb2abbc90 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/BUILD +++ b/library/java/io/envoyproxy/envoymobile/engine/types/BUILD @@ -6,7 +6,6 @@ java_library( name = "envoy_c_types_lib", srcs = [ "EnvoyEventTracker.java", - "EnvoyFinalStreamIntel.java", "EnvoyHTTPCallbacks.java", "EnvoyHTTPFilter.java", "EnvoyHTTPFilterCallbacks.java", diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java deleted file mode 100644 index 4936176a56..0000000000 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.envoyproxy.envoymobile.engine.types; - -/** - * Exposes internal HTTP stream metrics, context, and other details sent once on stream end. - */ -public interface EnvoyFinalStreamIntel { - /* - * The time the request started, in ms since the epoch. - */ - public long getRequestStartMs(); - /* - * The time the DNS resolution for this request started, in ms since the epoch. - */ - public long getDnsStartMs(); - /* - * The time the DNS resolution for this request completed, in ms since the epoch. - */ - public long getDnsEndMs(); - /* - * The time the upstream connection started, in ms since the epoch. - * This may not be set if socket_reused is false. - */ - public long getConnectStartMs(); - /* - * The time the upstream connection completed, in ms since the epoch. - * This may not be set if socket_reused is false. - */ - public long getConnectEndMs(); - /* - * The time the SSL handshake started, in ms since the epoch. - * This may not be set if socket_reused is false. - */ - public long getSslStartMs(); - /* - * The time the SSL handshake completed, in ms since the epoch. - * This may not be set if socket_reused is false. - */ - public long getSslEndMs(); - /* - * The time the first byte of the request was sent upstream, in ms since the epoch. - */ - public long getSendingStartMs(); - /* - * The time the last byte of the request was sent upstream, in ms since the epoch. - */ - public long getSendingEndMs(); - /* - * The time the first byte of the response was received, in ms since the epoch. - */ - public long getResponseStartMs(); - /* - * The time the last byte of the request was received, in ms since the epoch. - */ - public long getRequestEndMs(); - /* - * True if the upstream socket had been used previously. - */ - public boolean getSocketReused(); - /* - * The number of bytes sent upstream. - */ - public long getSentByteCount(); - /* - * The number of bytes received from upstream. - */ - public long getReceivedByteCount(); -} diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java index eef91e1413..8f7aa15847 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java @@ -48,19 +48,13 @@ void onHeaders(Map> headers, boolean endStream, * count for an error. This is different from 0, which intentionally conveys * that the action was _not_ executed. * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. */ - void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel, - EnvoyFinalStreamIntel finalStreamIntel); + void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel); /** * Called when the async HTTP stream is canceled. - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. */ - void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel); + void onCancel(EnvoyStreamIntel streamIntel); /** * Callback signature which notify when there is buffer available for request body upload. @@ -72,12 +66,4 @@ void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel s * @param streamIntel, contains internal HTTP stream metrics, context, and other details. */ void onSendWindowAvailable(EnvoyStreamIntel streamIntel); - - /** - * Called once after the final data for the stream has been received. - * - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics. - */ - void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel); } diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java index 17ba29d651..f94e89362d 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java @@ -110,27 +110,13 @@ Object[] onResumeResponse(Map> headers, ByteBuffer data, * count for an error. This is different from 0, which intentionally conveys * that the action was _not_ executed. * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. */ - void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel, - EnvoyFinalStreamIntel finalStreamIntel); + void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel); /** * Called when the async HTTP stream is canceled. * - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. - */ - void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalSteamIntel); - - /** - * Called when the async HTTP stream is complete. - * - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other - * details. + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. */ - void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalSteamIntel); + void onCancel(EnvoyStreamIntel streamIntel); } diff --git a/library/java/org/chromium/net/impl/CronetUrlRequest.java b/library/java/org/chromium/net/impl/CronetUrlRequest.java index c02e3d0d28..259fce4665 100644 --- a/library/java/org/chromium/net/impl/CronetUrlRequest.java +++ b/library/java/org/chromium/net/impl/CronetUrlRequest.java @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.engine.EnvoyHTTPStream; import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks; import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel; -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.MalformedURLException; @@ -772,7 +771,7 @@ public void onTrailers(Map> trailers, EnvoyStreamIntel stre @Override public void onError(int errorCode, String message, int attemptCount, - EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) { + EnvoyStreamIntel streamIntel) { if (isAbandoned()) { return; } @@ -794,7 +793,7 @@ public void onError(int errorCode, String message, int attemptCount, } @Override - public void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) { + public void onCancel(EnvoyStreamIntel streamIntel) { if (isAbandoned()) { return; } @@ -834,9 +833,6 @@ public void onSendWindowAvailable(EnvoyStreamIntel streamIntel) { mUploadDataStream.readDataReady(); // Have the next request body chunk to be sent. } - @Override - public void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) {} - /** * Sends one chunk of the request body if the state permits. This method is not re-entrant, but * by contract this method can only be invoked once for the first chunk, and then once per diff --git a/library/kotlin/io/envoyproxy/envoymobile/BUILD b/library/kotlin/io/envoyproxy/envoymobile/BUILD index 66d5c9f271..e28ae2863c 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/BUILD +++ b/library/kotlin/io/envoyproxy/envoymobile/BUILD @@ -61,7 +61,6 @@ envoy_mobile_kt_library( "StreamClient.kt", "StreamClientImpl.kt", "StreamIntel.kt", - "FinalStreamIntel.kt", "StreamPrototype.kt", "StringAccessor.kt", "Trailers.kt", diff --git a/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt b/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt deleted file mode 100644 index 5375146578..0000000000 --- a/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt +++ /dev/null @@ -1,57 +0,0 @@ -package io.envoyproxy.envoymobile - -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel - -/** - * Exposes one time HTTP stream metrics, context, and other details. - * @param requestStartMs The time the request started, in ms since the epoch. - * @param dnsStartMs The time the DNS resolution for this request started, in ms since the epoch. - * @param dnsEndMs The time the DNS resolution for this request completed, in ms since the epoch. - * @param connectStartMsThe time the upstream connection started, in ms since the epoch. - * This may not be set if socket_reused is false. - * @param connectEndMs The time the upstream connection completed, in ms since the epoch. - * This may not be set if socket_reused is false. - * @param sslStartMs The time the SSL handshake started, in ms since the epoch. - * This may not be set if socket_reused is false. - * @param sslEndMs The time the SSL handshake completed, in ms since the epoch. - * This may not be set if socket_reused is false. - * @param sendingStartMs The time the first byte of the request was sent upstream, - * in ms since the epoch. - * @param sendingEndMs The time the last byte of the request was sent upstream, in ms since the - * epoch. - * @param responseStartMs The time the first byte of the response was received, in ms since the - * epoch. - * @param @param requestEndMs The time the last byte of the request was received, in ms since the - * epoch. - * @param socket_reused True if the upstream socket had been used previously. - * @param sentByteCount The number of bytes sent upstream. - * @param receivedByteCount The number of bytes received from upstream. - */ -@Suppress("LongParameterList") -class FinalStreamIntel constructor( - val requestStartMs: Long, - val dnsStartMs: Long, - val dnsEndMs: Long, - val connectStartMs: Long, - val connectEndMs: Long, - val sslStartMs: Long, - val sslEndMs: Long, - val sendingStartMs: Long, - val sendingEndMs: Long, - val responseStartMs: Long, - val requestEndMs: Long, - val socketReused: Boolean, - val sentByteCount: Long, - val receivedByteCount: Long -) { - constructor(base: EnvoyFinalStreamIntel) : this( - base.requestStartMs, base.dnsStartMs, - base.dnsEndMs, base.connectStartMs, - base.connectEndMs, base.sslStartMs, - base.sslEndMs, base.sendingStartMs, - base.sendingEndMs, - base.responseStartMs, base.requestEndMs, - base.socketReused, base.sentByteCount, - base.receivedByteCount - ) -} diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt index 43e3251a9d..67fcf84dbe 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt @@ -1,6 +1,5 @@ package io.envoyproxy.envoymobile -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel import java.nio.ByteBuffer @@ -18,12 +17,9 @@ internal class StreamCallbacks { )? = null var onData: ((data: ByteBuffer, endStream: Boolean, streamIntel: StreamIntel) -> Unit)? = null var onTrailers: ((trailers: ResponseTrailers, streamIntel: StreamIntel) -> Unit)? = null - var onCancel: ((streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit)? = null - var onError: ( - (error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit - )? = null + var onCancel: ((streamIntel: StreamIntel) -> Unit)? = null + var onError: ((error: EnvoyError, streamIntel: StreamIntel) -> Unit)? = null var onSendWindowAvailable: ((streamIntel: StreamIntel) -> Unit)? = null - var onComplete: ((streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit)? = null } /** @@ -58,25 +54,19 @@ internal class EnvoyHTTPCallbacksAdapter( errorCode: Int, message: String, attemptCount: Int, - streamIntel: EnvoyStreamIntel, - finalStreamIntel: EnvoyFinalStreamIntel + streamIntel: EnvoyStreamIntel ) { callbacks.onError?.invoke( EnvoyError(errorCode, message, attemptCount), - StreamIntel(streamIntel), - FinalStreamIntel(finalStreamIntel) + StreamIntel(streamIntel) ) } - override fun onCancel(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { - callbacks.onCancel?.invoke(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + override fun onCancel(streamIntel: EnvoyStreamIntel) { + callbacks.onCancel?.invoke(StreamIntel(streamIntel)) } override fun onSendWindowAvailable(streamIntel: EnvoyStreamIntel) { callbacks.onSendWindowAvailable?.invoke(StreamIntel(streamIntel)) } - - override fun onComplete(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { - callbacks.onComplete?.invoke(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) - } } diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt index 863e3e009c..f7fb49745d 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt @@ -25,10 +25,7 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return The new stream. */ open fun start(executor: Executor = Executors.newSingleThreadExecutor()): Stream { - val engineStream = engine.startStream( - createCallbacks(executor), - explicitFlowControl - ) + val engineStream = engine.startStream(createCallbacks(executor), explicitFlowControl) return Stream(engineStream, useByteBufferPosition) } @@ -110,30 +107,12 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return This stream, for chaining syntax. */ fun setOnError( - closure: ( - error: EnvoyError, - streamIntel: StreamIntel, - finalStreamIntel: FinalStreamIntel - ) -> Unit + closure: (error: EnvoyError, streamIntel: StreamIntel) -> Unit ): StreamPrototype { callbacks.onError = closure return this } -/** - * Specify a callback for when a stream is complete. - * If the closure is called, the stream is complete. - * - * @param closure Closure which will be called when an error occurs. - * @return This stream, for chaining syntax. - */ - fun setOnComplete( - closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit - ): StreamPrototype { - callbacks.onComplete = closure - return this - } - /** * Specify a callback for when the stream is canceled. * If the closure is called, the stream is complete. @@ -142,7 +121,7 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return This stream, for chaining syntax. */ fun setOnCancel( - closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + closure: (streamIntel: StreamIntel) -> Unit ): StreamPrototype { callbacks.onCancel = closure return this diff --git a/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt b/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt index 1741b85f2b..02ab7a5e24 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt @@ -1,6 +1,5 @@ package io.envoyproxy.envoymobile -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilter import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterCallbacks import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterFactory @@ -100,21 +99,15 @@ internal class EnvoyHTTPFilterAdapter( return arrayOf(0, trailers) } - override fun onError(errorCode: Int, message: String, attemptCount: Int, streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + override fun onError(errorCode: Int, message: String, attemptCount: Int, streamIntel: EnvoyStreamIntel) { (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onError(EnvoyError(errorCode, message, attemptCount), StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + responseFilter.onError(EnvoyError(errorCode, message, attemptCount), StreamIntel(streamIntel)) } } - override fun onCancel(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + override fun onCancel(streamIntel: EnvoyStreamIntel) { (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onCancel(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) - } - } - - override fun onComplete(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { - (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onComplete(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + responseFilter.onCancel(StreamIntel(streamIntel)) } } diff --git a/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt b/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt index c8dbcf7b6e..2c025164ce 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt @@ -55,9 +55,8 @@ interface ResponseFilter : Filter { * * @param error: The error that occurred within Envoy. * @param streamIntel: Internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. */ - fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) + fun onError(error: EnvoyError, streamIntel: StreamIntel) /** * Called at most once when the client cancels the stream. @@ -66,18 +65,6 @@ interface ResponseFilter : Filter { * `stopIteration{...}`. * * @param streamIntel: Internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. */ - fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) - -/** - * Called at most once when the stream is complete. - * - * This should be considered a terminal state, and invalidates any previous attempts to - * `stopIteration{...}`. - * - * @param streamIntel: Internal HTTP stream metrics, context, and other details. - * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. - */ - fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) + fun onCancel(streamIntel: StreamIntel) } diff --git a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt index 78618658af..87aafbdc12 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt @@ -89,7 +89,7 @@ class GRPCStreamPrototype( * @return This stream, for chaining syntax. */ fun setOnError( - closure: (error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + closure: (error: EnvoyError, streamIntel: StreamIntel) -> Unit ): GRPCStreamPrototype { underlyingStream.setOnError(closure) return this @@ -103,7 +103,7 @@ class GRPCStreamPrototype( * @return This stream, for chaining syntax. */ fun setOnCancel( - closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + closure: (streamIntel: StreamIntel) -> Unit ): GRPCStreamPrototype { underlyingStream.setOnCancel(closure) return this diff --git a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt index 7f326d22ab..b85cf0c8fd 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt @@ -1,6 +1,5 @@ package io.envoyproxy.envoymobile -import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel import java.nio.ByteBuffer @@ -17,22 +16,6 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S override fun getAttemptCount(): Long { return 0 } } - private val mockFinalStreamIntel = object : EnvoyFinalStreamIntel { - override fun getRequestStartMs(): Long { return 0 } - override fun getDnsStartMs(): Long { return 0 } - override fun getDnsEndMs(): Long { return 0 } - override fun getConnectStartMs(): Long { return 0 } - override fun getConnectEndMs(): Long { return 0 } - override fun getSslStartMs(): Long { return 0 } - override fun getSslEndMs(): Long { return 0 } - override fun getSendingStartMs(): Long { return 0 } - override fun getSendingEndMs(): Long { return 0 } - override fun getResponseStartMs(): Long { return 0 } - override fun getRequestEndMs(): Long { return 0 } - override fun getSocketReused(): Boolean { return false } - override fun getSentByteCount(): Long { return 0 } - override fun getReceivedByteCount(): Long { return 0 } - } /** * Closure that will be called when request headers are sent. */ @@ -105,7 +88,7 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S * Simulate the stream receiving a cancellation signal from Envoy. */ fun receiveCancel() { - mockStream.callbacks.onCancel(mockStreamIntel, mockFinalStreamIntel) + mockStream.callbacks.onCancel(mockStreamIntel) } /** @@ -114,6 +97,6 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S * @param error The error to receive. */ fun receiveError(error: EnvoyError) { - mockStream.callbacks.onError(error.errorCode, error.message, error.attemptCount ?: 0, mockStreamIntel, mockFinalStreamIntel) + mockStream.callbacks.onError(error.errorCode, error.message, error.attemptCount ?: 0, mockStreamIntel) } } diff --git a/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc b/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc index 8ed9a651c3..801e4cea4e 100644 --- a/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc +++ b/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc @@ -676,7 +676,7 @@ TEST_F(PlatformBridgeFilterTest, BasicError) { release_envoy_data(c_data); return {kEnvoyFilterDataStatusStopIterationNoBuffer, envoy_nodata, nullptr}; }; - platform_filter.on_error = [](envoy_error c_error, envoy_stream_intel, envoy_final_stream_intel, + platform_filter.on_error = [](envoy_error c_error, envoy_stream_intel, const void* context) -> void { filter_invocations* invocations = static_cast(const_cast(context)); invocations->on_error_calls++; diff --git a/test/common/http/client_test.cc b/test/common/http/client_test.cc index 33f6467ef0..1b624b6608 100644 --- a/test/common/http/client_test.cc +++ b/test/common/http/client_test.cc @@ -63,8 +63,7 @@ class ClientTest : public testing::TestWithParam { bridge_callbacks_.context = &cc_; // Set up default bridge callbacks. Indivividual tests can override. - bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_complete = [](envoy_stream_intel, void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; return nullptr; @@ -78,8 +77,7 @@ class ClientTest : public testing::TestWithParam { cc->on_headers_calls++; return nullptr; }; - bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_error_calls++; return nullptr; @@ -92,8 +90,7 @@ class ClientTest : public testing::TestWithParam { release_envoy_data(c_data); return nullptr; }; - bridge_callbacks_.on_cancel = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_cancel = [](envoy_stream_intel, void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_cancel_calls++; return nullptr; @@ -456,8 +453,7 @@ TEST_P(ClientTest, MultipleStreams) { *on_headers_called2 = true; return nullptr; }; - bridge_callbacks_2.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_2.on_complete = [](envoy_stream_intel, void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; return nullptr; @@ -506,8 +502,7 @@ TEST_P(ClientTest, MultipleStreams) { TEST_P(ClientTest, EnvoyLocalError) { // Override the on_error default with some custom checks. - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { EXPECT_EQ(error.error_code, ENVOY_CONNECTION_FAILURE); EXPECT_EQ(error.attempt_count, 123); callbacks_called* cc = static_cast(context); @@ -580,8 +575,7 @@ TEST_P(ClientTest, DoubleResetStreamLocal) { TEST_P(ClientTest, RemoteResetAfterStreamStart) { cc_.end_stream_with_headers_ = false; - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { EXPECT_EQ(error.error_code, ENVOY_STREAM_RESET); EXPECT_EQ(error.message.length, 0); EXPECT_EQ(error.attempt_count, 0); diff --git a/test/common/integration/client_integration_test.cc b/test/common/integration/client_integration_test.cc index 52480f7e67..88f98210b1 100644 --- a/test/common/integration/client_integration_test.cc +++ b/test/common/integration/client_integration_test.cc @@ -77,15 +77,13 @@ class ClientIntegrationTest : public BaseIntegrationTest, release_envoy_data(c_data); return nullptr; }; - bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_complete = [](envoy_stream_intel, void* context) -> void* { callbacks_called* cc_ = static_cast(context); cc_->on_complete_calls++; cc_->terminal_callback->setReady(); return nullptr; }; - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, - void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { release_envoy_error(error); callbacks_called* cc_ = static_cast(context); cc_->on_error_calls++; diff --git a/test/common/main_interface_test.cc b/test/common/main_interface_test.cc index 474a080a36..1a85e7dbfd 100644 --- a/test/common/main_interface_test.cc +++ b/test/common/main_interface_test.cc @@ -154,7 +154,7 @@ TEST(MainInterfaceTest, BasicStream) { nullptr /* on_metadata */, nullptr /* on_trailers */, nullptr /* on_error */, - [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { + [](envoy_stream_intel, void* context) -> void* { auto* on_complete_notification = static_cast(context); on_complete_notification->Notify(); return nullptr; @@ -249,20 +249,20 @@ TEST(MainInterfaceTest, ResetStream) { engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); absl::Notification on_cancel_notification; - envoy_http_callbacks stream_cbs{ - nullptr /* on_headers */, - nullptr /* on_data */, - nullptr /* on_metadata */, - nullptr /* on_trailers */, - nullptr /* on_error */, - nullptr /* on_complete */, - [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { - auto* on_cancel_notification = static_cast(context); - on_cancel_notification->Notify(); - return nullptr; - } /* on_cancel */, - nullptr /* on_send_window_available */, - &on_cancel_notification /* context */}; + envoy_http_callbacks stream_cbs{nullptr /* on_headers */, + nullptr /* on_data */, + nullptr /* on_metadata */, + nullptr /* on_trailers */, + nullptr /* on_error */, + nullptr /* on_complete */, + [](envoy_stream_intel, void* context) -> void* { + auto* on_cancel_notification = + static_cast(context); + on_cancel_notification->Notify(); + return nullptr; + } /* on_cancel */, + nullptr /* on_send_window_available */, + &on_cancel_notification /* context */}; envoy_stream_t stream = init_stream(0); diff --git a/test/java/integration/AndroidEnvoyExplicitFlowTest.java b/test/java/integration/AndroidEnvoyExplicitFlowTest.java index ccc17de98c..6f00f59171 100644 --- a/test/java/integration/AndroidEnvoyExplicitFlowTest.java +++ b/test/java/integration/AndroidEnvoyExplicitFlowTest.java @@ -393,12 +393,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { latch.countDown(); return null; }) - .setOnError((error, ignored, also_ignored) -> { + .setOnError((error, ignored) -> { response.get().setEnvoyError(error); latch.countDown(); return null; }) - .setOnCancel((ignored, also_ignored) -> { + .setOnCancel((ignored) -> { response.get().setCancelled(); latch.countDown(); return null; diff --git a/test/java/integration/AndroidEnvoyFlowTest.java b/test/java/integration/AndroidEnvoyFlowTest.java index a1a57e8904..7d1bf250c9 100644 --- a/test/java/integration/AndroidEnvoyFlowTest.java +++ b/test/java/integration/AndroidEnvoyFlowTest.java @@ -302,12 +302,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { latch.countDown(); return null; }) - .setOnError((error, ignored, also_ignored) -> { + .setOnError((error, ignored) -> { response.get().setEnvoyError(error); latch.countDown(); return null; }) - .setOnCancel((ignored, also_ignored) -> { + .setOnCancel((ignored) -> { response.get().setCancelled(); latch.countDown(); return null; diff --git a/test/kotlin/integration/CancelStreamTest.kt b/test/kotlin/integration/CancelStreamTest.kt index 31321010fd..e8d883ccd4 100644 --- a/test/kotlin/integration/CancelStreamTest.kt +++ b/test/kotlin/integration/CancelStreamTest.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.RequestHeadersBuilder import io.envoyproxy.envoymobile.RequestMethod import io.envoyproxy.envoymobile.ResponseFilter @@ -109,10 +108,9 @@ class CancelStreamTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} + override fun onError(error: EnvoyError, streamIntel: StreamIntel) {} - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { latch.countDown() } } @@ -139,7 +137,7 @@ class CancelStreamTest { .build() client.newStreamPrototype() - .setOnCancel { _, _ -> + .setOnCancel { runExpectation.countDown() } .start(Executors.newSingleThreadExecutor()) diff --git a/test/kotlin/integration/DrainConnectionsTest.kt b/test/kotlin/integration/DrainConnectionsTest.kt index f43c04a2a4..597c659120 100644 --- a/test/kotlin/integration/DrainConnectionsTest.kt +++ b/test/kotlin/integration/DrainConnectionsTest.kt @@ -85,7 +85,7 @@ class DrainConnectionsTest { resultEndStream1 = endStream headersExpectation.countDown() } - .setOnError { _, _, _ -> fail("Unexpected error") } + .setOnError { _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) @@ -101,7 +101,7 @@ class DrainConnectionsTest { resultEndStream2 = endStream headersExpectation.countDown() } - .setOnError { _, _, _ -> fail("Unexpected error") } + .setOnError { _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/GRPCReceiveErrorTest.kt b/test/kotlin/integration/GRPCReceiveErrorTest.kt index e83c87382f..c998706184 100644 --- a/test/kotlin/integration/GRPCReceiveErrorTest.kt +++ b/test/kotlin/integration/GRPCReceiveErrorTest.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.GRPCClient import io.envoyproxy.envoymobile.GRPCRequestHeadersBuilder import io.envoyproxy.envoymobile.ResponseFilter @@ -96,12 +95,11 @@ class GRPCReceiveErrorTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { receivedError.countDown() } - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { notCancelled.countDown() } } @@ -126,12 +124,10 @@ class GRPCReceiveErrorTest { .newGRPCStreamPrototype() .setOnResponseHeaders { _, _, _ -> } .setOnResponseMessage { _, _ -> } - .setOnError { _, _, _ -> + .setOnError { _, _ -> callbackReceivedError.countDown() } - .setOnCancel { _, _ -> - fail("Unexpected call to onCancel response callback") - } + .setOnCancel { fail("Unexpected call to onCancel response callback") } .start() .sendHeaders(requestHeader, false) .sendMessage(ByteBuffer.wrap(ByteArray(5))) diff --git a/test/kotlin/integration/ReceiveDataTest.kt b/test/kotlin/integration/ReceiveDataTest.kt index 36702adbf5..4059e14587 100644 --- a/test/kotlin/integration/ReceiveDataTest.kt +++ b/test/kotlin/integration/ReceiveDataTest.kt @@ -94,7 +94,7 @@ class ReceiveDataTest { body = data dataExpectation.countDown() } - .setOnError { _, _, _ -> fail("Unexpected error") } + .setOnError { _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/ReceiveErrorTest.kt b/test/kotlin/integration/ReceiveErrorTest.kt index b7f61b239f..ed87a1e076 100644 --- a/test/kotlin/integration/ReceiveErrorTest.kt +++ b/test/kotlin/integration/ReceiveErrorTest.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.GRPCRequestHeadersBuilder import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders @@ -93,12 +92,11 @@ class ReceiveErrorTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { receivedError.countDown() } - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { notCancelled.countDown() } } @@ -127,13 +125,11 @@ class ReceiveErrorTest { .setOnResponseData { _, _, _ -> fail("Data received instead of expected error") } // The unmatched expectation will cause a local reply which gets translated in Envoy Mobile to // an error. - .setOnError { error, _, _ -> + .setOnError { error, _ -> errorCode = error.errorCode callbackReceivedError.countDown() } - .setOnCancel { _, _ -> - fail("Unexpected call to onCancel response callback") - } + .setOnCancel { fail("Unexpected call to onCancel response callback") } .start() .sendHeaders(requestHeader, true) diff --git a/test/kotlin/integration/SendDataTest.kt b/test/kotlin/integration/SendDataTest.kt index 1fe9075a8a..925e9f3bea 100644 --- a/test/kotlin/integration/SendDataTest.kt +++ b/test/kotlin/integration/SendDataTest.kt @@ -93,7 +93,7 @@ class SendDataTest { responseHeadersEndStream = endStream expectation.countDown() } - .setOnError { _, _, _ -> + .setOnError { _, _ -> fail("Unexpected error") } .start() diff --git a/test/kotlin/integration/SendHeadersTest.kt b/test/kotlin/integration/SendHeadersTest.kt index 823a524d7a..20cdb99f01 100644 --- a/test/kotlin/integration/SendHeadersTest.kt +++ b/test/kotlin/integration/SendHeadersTest.kt @@ -85,7 +85,7 @@ class SendHeadersTest { resultEndStream = endStream headersExpectation.countDown() } - .setOnError { _, _, _ -> fail("Unexpected error") } + .setOnError { _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/SendTrailersTest.kt b/test/kotlin/integration/SendTrailersTest.kt index 1391ced880..1392583e19 100644 --- a/test/kotlin/integration/SendTrailersTest.kt +++ b/test/kotlin/integration/SendTrailersTest.kt @@ -98,7 +98,7 @@ class SendTrailersTest { responseStatus = headers.httpStatus expectation.countDown() } - .setOnError { _, _, _ -> + .setOnError { _, _ -> fail("Unexpected error") } .start() diff --git a/test/kotlin/integration/StreamIdleTimeoutTest.kt b/test/kotlin/integration/StreamIdleTimeoutTest.kt index 8d1117961f..74205b32cb 100644 --- a/test/kotlin/integration/StreamIdleTimeoutTest.kt +++ b/test/kotlin/integration/StreamIdleTimeoutTest.kt @@ -6,7 +6,6 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus -import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.RequestHeadersBuilder import io.envoyproxy.envoymobile.RequestMethod import io.envoyproxy.envoymobile.ResponseFilter @@ -132,13 +131,12 @@ class CancelStreamTest { return FilterTrailersStatus.StopIteration() } - override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel) { assertThat(error.errorCode).isEqualTo(4) latch.countDown() } - override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + override fun onCancel(streamIntel: StreamIntel) { fail("Unexpected call to onCancel filter callback") } } @@ -165,7 +163,7 @@ class CancelStreamTest { .build() client.newStreamPrototype() - .setOnError { error, _, _ -> + .setOnError { error, _ -> assertThat(error.errorCode).isEqualTo(4) callbackExpectation.countDown() } From 502ccb2d91bec6e3c3badeee334371a7f4a80c72 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 1 Dec 2021 10:24:17 -0800 Subject: [PATCH 14/25] bazel: add bazelw wrapper (#1935) This wrapper allows developers to quickly get off the ground without having to install bazel or bazelisk manually. Signed-off-by: Keith Smiley --- .github/workflows/android_build.yml | 10 ++--- .github/workflows/android_tests.yml | 6 +-- .github/workflows/artifacts.yml | 4 +- .github/workflows/asan.yml | 2 +- .github/workflows/cc_tests.yml | 2 +- .github/workflows/core.yml | 2 +- .github/workflows/format.yml | 4 +- .github/workflows/ios_build.yml | 16 ++++---- .github/workflows/ios_tests.yml | 2 +- .github/workflows/python_tests.yml | 2 +- .github/workflows/tsan.yml | 2 +- bazelw | 38 +++++++++++++++++++ .../development/debugging/android_local.rst | 2 +- .../development/performance/binary_size.rst | 2 +- .../performance/cpu_battery_impact.rst | 6 +-- .../performance/device_connectivity.rst | 2 +- docs/root/development/testing/testing.rst | 8 ++-- docs/root/development/tools/intellij.rst | 7 ++-- docs/root/development/tools/tulsi.rst | 2 +- docs/root/start/building/building.rst | 15 ++++---- docs/root/start/examples/hello_world.rst | 8 ++-- 21 files changed, 90 insertions(+), 52 deletions(-) create mode 100755 bazelw diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index bcf21186ca..edfadb63c2 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -38,7 +38,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazelisk build \ + ./bazelw build \ --config=remote-ci-macos \ --remote_header="Authorization=Bearer $GITHUB_TOKEN" \ --fat_apk_cpu=x86 \ @@ -70,13 +70,13 @@ jobs: - name: 'Start simulator' run: ./ci/mac_start_emulator.sh # Return to using: - # bazelisk mobile-install --fat_apk_cpu=x86 --start_app //examples/java/hello_world:hello_envoy + # ./bazelw mobile-install --fat_apk_cpu=x86 --start_app //examples/java/hello_world:hello_envoy # When https://github.com/lyft/envoy-mobile/issues/853 is fixed. - name: 'Start java app' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazelisk build \ + ./bazelw build \ --config=remote-ci-macos \ --remote_header="Authorization=Bearer $GITHUB_TOKEN" \ --fat_apk_cpu=x86 \ @@ -113,13 +113,13 @@ jobs: - name: 'Start simulator' run: ./ci/mac_start_emulator.sh # Return to using: - # bazelisk mobile-install --fat_apk_cpu=x86 --start_app //examples/kotlin/hello_world:hello_envoy_kt + # ./bazelw mobile-install --fat_apk_cpu=x86 --start_app //examples/kotlin/hello_world:hello_envoy_kt # When https://github.com/lyft/envoy-mobile/issues/853 is fixed. - name: 'Start kotlin app' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazelisk build \ + ./bazelw build \ --config=remote-ci-macos \ --remote_header="Authorization=Bearer $GITHUB_TOKEN" \ --fat_apk_cpu=x86 \ diff --git a/.github/workflows/android_tests.yml b/.github/workflows/android_tests.yml index 7bef820774..6b16e0e5af 100644 --- a/.github/workflows/android_tests.yml +++ b/.github/workflows/android_tests.yml @@ -42,7 +42,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazel test \ + ./bazelw test \ --test_output=all \ --build_tests_only \ --config=remote-ci-macos \ @@ -81,7 +81,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazel test \ + ./bazelw test \ --test_output=all \ --build_tests_only \ --config=remote-ci-macos \ @@ -125,7 +125,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazel test \ + ./bazelw test \ --test_output=all \ --build_tests_only \ --config=remote-ci-linux-clang \ diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index 15a34932cd..c402b338d3 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -26,7 +26,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | current_release_version=$(git describe --tag --abbrev=0) - bazelisk build \ + ./bazelw build \ --config=release-android \ --fat_apk_cpu=x86 \ --define=pom_version=$current_release_version \ @@ -114,7 +114,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazelisk build \ + ./bazelw build \ --config=release-ios \ --ios_multi_cpus=i386,x86_64,armv7,arm64 \ --config=remote-ci-macos \ diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml index 67dca42db6..417a0ee86e 100644 --- a/.github/workflows/asan.yml +++ b/.github/workflows/asan.yml @@ -41,7 +41,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} if: steps.check_context.outputs.run_tests == 'true' run: | - bazel test --test_output=all \ + ./bazelw test --test_output=all \ --test_env=ENVOY_IP_TEST_VERSIONS=v4only \ --remote_header="Authorization=Bearer $GITHUB_TOKEN" \ --config=remote-ci-linux-asan \ diff --git a/.github/workflows/cc_tests.yml b/.github/workflows/cc_tests.yml index 214506078b..76f4318675 100644 --- a/.github/workflows/cc_tests.yml +++ b/.github/workflows/cc_tests.yml @@ -20,4 +20,4 @@ jobs: - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} name: 'Run tests' - run: bazel test --action_env=LD_LIBRARY_PATH --test_output=all --config=remote-ci-linux --remote_header="Authorization=Bearer $GITHUB_TOKEN" //test/cc/... + run: ./bazelw test --action_env=LD_LIBRARY_PATH --test_output=all --config=remote-ci-linux --remote_header="Authorization=Bearer $GITHUB_TOKEN" //test/cc/... diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index f8adc66b5d..ae4dfe384a 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -20,4 +20,4 @@ jobs: - name: 'Run tests' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bazelisk test --test_output=all --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //test/common/... + run: ./bazelw test --test_output=all --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //test/common/... diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 123d4ef465..f23f31eec8 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -63,10 +63,10 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazel build \ + ./bazelw build \ --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" \ //library/kotlin/io/envoyproxy/envoymobile:envoy_lib_lint \ //examples/kotlin/hello_world:hello_envoy_kt_lint - name: 'Run Kotlin Formatter (ktlint)' run: | - bazel build kotlin_format + ./bazelw build kotlin_format diff --git a/.github/workflows/ios_build.yml b/.github/workflows/ios_build.yml index 212667eff3..5ec62bb7d4 100644 --- a/.github/workflows/ios_build.yml +++ b/.github/workflows/ios_build.yml @@ -30,8 +30,8 @@ jobs: - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazelisk shutdown - bazelisk build --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //:ios_dist + ./bazelw shutdown + ./bazelw build --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //:ios_dist if: steps.check-cache.outputs.cache-hit != 'true' name: 'Build Envoy.framework distributable' swifthelloworld: @@ -56,12 +56,12 @@ jobs: name: 'Short-circuit' - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bazelisk build --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/swift/hello_world:app + run: ./bazelw build --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/swift/hello_world:app name: 'Build swift app' # Run the app in the background and redirect logs. - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bazelisk run --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/swift/hello_world:app &> /tmp/envoy.log & + run: ./bazelw run --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/swift/hello_world:app &> /tmp/envoy.log & name: 'Run swift app' - run: sed '/received headers with status 200/q' <(touch /tmp/envoy.log && tail -F /tmp/envoy.log) name: 'Check connectivity' @@ -90,12 +90,12 @@ jobs: name: 'Short-circuit' - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bazelisk build --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/swift/async_await:app + run: ./bazelw build --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/swift/async_await:app name: 'Build swift app' # Run the app in the background and redirect logs. - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bazelisk run --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/swift/async_await:app &> /tmp/envoy.log & + run: ./bazelw run --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/swift/async_await:app &> /tmp/envoy.log & name: 'Run swift app' - run: sed '/\[2\] Uploaded 7 MB of data/q' <(touch /tmp/envoy.log && tail -F /tmp/envoy.log) name: 'Check upload succeeded' @@ -124,12 +124,12 @@ jobs: name: 'Short-circuit' - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bazelisk build --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/objective-c/hello_world:app + run: ./bazelw build --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/objective-c/hello_world:app name: 'Build objective-c app' # Run the app in the background and redirect logs. - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bazelisk run --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/objective-c/hello_world:app &> /tmp/envoy.log & + run: ./bazelw run --config=ios --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //examples/objective-c/hello_world:app &> /tmp/envoy.log & name: 'Run objective-c app' - run: sed '/received headers with status 200/q' <(touch /tmp/envoy.log && tail -F /tmp/envoy.log) name: 'Check connectivity' diff --git a/.github/workflows/ios_tests.yml b/.github/workflows/ios_tests.yml index 1930cf27c3..d13aaba7a5 100644 --- a/.github/workflows/ios_tests.yml +++ b/.github/workflows/ios_tests.yml @@ -31,4 +31,4 @@ jobs: if: steps.check_context.outputs.run_tests == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bazelisk test --test_output=all --config=ios --build_tests_only --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //test/swift/... + run: ./bazelw test --test_output=all --config=ios --build_tests_only --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //test/swift/... diff --git a/.github/workflows/python_tests.yml b/.github/workflows/python_tests.yml index 9c2b09380e..1c7ce932db 100644 --- a/.github/workflows/python_tests.yml +++ b/.github/workflows/python_tests.yml @@ -32,7 +32,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazel test \ + ./bazelw test \ --action_env=LD_LIBRARY_PATH \ --test_output=all \ --config=remote-ci-linux \ diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml index c7d1a75e78..d305c7801b 100644 --- a/.github/workflows/tsan.yml +++ b/.github/workflows/tsan.yml @@ -41,7 +41,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} if: steps.check_context.outputs.run_tests == 'true' run: | - bazel test --test_output=all \ + ./bazelw test --test_output=all \ --test_env=ENVOY_IP_TEST_VERSIONS=v4only \ --remote_header="Authorization=Bearer $GITHUB_TOKEN" \ --config=remote-ci-linux-tsan \ diff --git a/bazelw b/bazelw new file mode 100755 index 0000000000..e9e44c76fd --- /dev/null +++ b/bazelw @@ -0,0 +1,38 @@ +#!/bin/bash + +set -euo pipefail + +readonly bazelisk_version="1.10.1" +if [[ $OSTYPE == darwin* ]]; then + # TODO: Support M1 once https://github.com/envoyproxy/envoy/issues/16482 + readonly bazel_platform="darwin-amd64" + readonly bazel_version_sha="e485bbf84532d02a60b0eb23c702610b5408df3a199087a4f2b5e0995bbf2d5a" +else + readonly bazel_platform="linux-amd64" + readonly bazel_version_sha="4cb534c52cdd47a6223d4596d530e7c9c785438ab3b0a49ff347e991c210b2cd" +fi + +readonly bazel_version_url="https://github.com/bazelbuild/bazelisk/releases/download/v$bazelisk_version/bazelisk-$bazel_platform" +script_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly bazelisk="$script_root/tmp/bazel/versions/bazelisk-$bazelisk_version-$bazel_platform" + +if [[ ! -x "$bazelisk" ]]; then + echo "Installing bazelisk..." >&2 + mkdir -p "$(dirname "$bazelisk")" + + download_bazelisk() { + curl --fail -L --retry 5 --retry-connrefused --silent --progress-bar \ + --output "$bazelisk" "$bazel_version_url" + } + + download_bazelisk || download_bazelisk + if echo "$bazel_version_sha $bazelisk" | shasum --check --status; then + chmod +x "$bazelisk" + else + echo "Bazelisk sha mismatch" >&2 + rm -f "$bazelisk" + exit 1 + fi +fi + +exec "$bazelisk" "$@" diff --git a/docs/root/development/debugging/android_local.rst b/docs/root/development/debugging/android_local.rst index eba4e59507..061e2b593f 100644 --- a/docs/root/development/debugging/android_local.rst +++ b/docs/root/development/debugging/android_local.rst @@ -56,7 +56,7 @@ With the project ready, you can now start debugging with Android Studio. For example: :: - $ bazelisk build android_dist --config=android --fat_apk_cpu=x86 -c dbg + $ ./bazelw build android_dist --config=android --fat_apk_cpu=x86 -c dbg Android supported archs are `arm64_v8a`, `armeabi-v7a`, `x86`, `x86_64`. diff --git a/docs/root/development/performance/binary_size.rst b/docs/root/development/performance/binary_size.rst index 204bfb66c0..c509422d7d 100644 --- a/docs/root/development/performance/binary_size.rst +++ b/docs/root/development/performance/binary_size.rst @@ -63,7 +63,7 @@ necessary tools:: The binary being compiled is ``//test/performance:test_binary_size``. The binary is getting built with the following build command:: - bazelisk build //test/performance:test_binary_size --config=sizeopt --copt=-ggdb3 --linkopt=-fuse-ld=lld + ./bazelw build //test/performance:test_binary_size --config=sizeopt --copt=-ggdb3 --linkopt=-fuse-ld=lld Thus the binary is compiled with the following flags pertinent to reducing binary size: diff --git a/docs/root/development/performance/cpu_battery_impact.rst b/docs/root/development/performance/cpu_battery_impact.rst index 322354ed04..9989a9ed32 100644 --- a/docs/root/development/performance/cpu_battery_impact.rst +++ b/docs/root/development/performance/cpu_battery_impact.rst @@ -86,9 +86,9 @@ Modified versions of the "hello world" example apps were used to run these exper Getting the build: -1. Build the library using ``bazelisk build android_dist --config=android --fat_apk_cpu=armeabi-v7a`` -2. Control: ``bazel mobile-install //examples/kotlin/control:hello_control_kt`` -3. Envoy: ``bazel mobile-install //examples/kotlin/hello_world:hello_envoy_kt --fat_apk_cpu=armeabi-v7a`` +1. Build the library using ``./bazelw build android_dist --config=android --fat_apk_cpu=armeabi-v7a`` +2. Control: ``./bazelw mobile-install //examples/kotlin/control:hello_control_kt`` +3. Envoy: ``./bazelw mobile-install //examples/kotlin/hello_world:hello_envoy_kt --fat_apk_cpu=armeabi-v7a`` Battery usage experiment steps: diff --git a/docs/root/development/performance/device_connectivity.rst b/docs/root/development/performance/device_connectivity.rst index 27771963cc..4875eb6370 100644 --- a/docs/root/development/performance/device_connectivity.rst +++ b/docs/root/development/performance/device_connectivity.rst @@ -72,7 +72,7 @@ Android configuration 2. Build and run the example app: -``bazelisk mobile-install //examples/kotlin/hello_world:hello_envoy_kt --fat_apk_cpu=armeabi-v7a`` +``./bazelw mobile-install //examples/kotlin/hello_world:hello_envoy_kt --fat_apk_cpu=armeabi-v7a`` ~~~~~~~~~~~ Open issues diff --git a/docs/root/development/testing/testing.rst b/docs/root/development/testing/testing.rst index ac7b7bfc6f..be3cae5c20 100644 --- a/docs/root/development/testing/testing.rst +++ b/docs/root/development/testing/testing.rst @@ -23,7 +23,7 @@ Common (C/C++) tests To run the entire C/C++ test suite locally, use the following Bazel command: -``bazelisk test --test_output=all //test/common/...`` +``./bazelw test --test_output=all //test/common/...`` ---------- Java tests @@ -31,7 +31,7 @@ Java tests To run the entire Java unit test suite locally, use the following Bazel command: -``bazelisk test --test_output=all --build_tests_only //test/java/...`` +``./bazelw test --test_output=all --build_tests_only //test/java/...`` ------------ Kotlin tests @@ -39,7 +39,7 @@ Kotlin tests To run the entire Kotlin unit test suite locally, use the following Bazel command: -``bazelisk test --test_output=all --build_tests_only //test/kotlin/...`` +``./bazelw test --test_output=all --build_tests_only //test/kotlin/...`` ----------- Swift tests @@ -47,7 +47,7 @@ Swift tests To run the entire Swift unit test suite locally, use the following Bazel command: -``bazelisk test --config=ios --test_output=all --build_tests_only //test/swift/...`` +``./bazelw test --config=ios --test_output=all --build_tests_only //test/swift/...`` -------- Coverage diff --git a/docs/root/development/tools/intellij.rst b/docs/root/development/tools/intellij.rst index 47dd69de00..16ad06be76 100644 --- a/docs/root/development/tools/intellij.rst +++ b/docs/root/development/tools/intellij.rst @@ -10,10 +10,9 @@ Using IntelliJ with Envoy Mobile To get started using IntelliJ with Envoy Mobile: -1. Locally install `Bazel `_ -2. Download a supported `IntelliJ version `_ supported by the Bazel plugin -3. Apply local hacks to make IntelliJ work using the branch `hack-for-intellij `_ -4. Open up the Envoy Mobile project using the Bazel import project wizard +1. Download a supported `IntelliJ version `_ supported by the Bazel plugin +2. Apply local hacks to make IntelliJ work using the branch `hack-for-intellij `_ +3. Open up the Envoy Mobile project using the Bazel import project wizard Known issues diff --git a/docs/root/development/tools/tulsi.rst b/docs/root/development/tools/tulsi.rst index f9dc8c7173..b90b045e35 100644 --- a/docs/root/development/tools/tulsi.rst +++ b/docs/root/development/tools/tulsi.rst @@ -19,7 +19,7 @@ To get started using Tulsi with Envoy Mobile: 1. Download and `install Tulsi `_ 2. Open the :repo:`envoy-mobile.tulsiproj ` file -3. From the ``Packages`` tab, click ``Bazel..`` and select the ``bazelw`` binary from at the root of the Envoy Mobile directory (to ensure you're building with the local version of Bazel) +3. From the ``Packages`` tab, click ``Bazel..`` and select the ``bazelw`` binary from at the root of the Envoy Mobile directory (to ensure you're building with the correct version of Bazel) 4. Click on the ``Configs`` tab in Tulsi, and click ``Generate`` 5. Open up the Xcode project, and build diff --git a/docs/root/start/building/building.rst b/docs/root/start/building/building.rst index 164df6bf32..2bf9d8faf1 100644 --- a/docs/root/start/building/building.rst +++ b/docs/root/start/building/building.rst @@ -24,8 +24,9 @@ Bazel requirements Envoy Mobile is compiled using the version of Bazel specified in the :repo:`.bazelversion <.bazelversion>` file. -To simplify build consistency across environments, bazelisk is used. -Follow `these Envoy instructions `_ to install bazelisk as bazel. +To simplify build consistency across environments, the `./bazelw` script manages +using the correct version. Instead of using `bazel build ...` use `./bazelw build ...` +for all bazel commands. -------------------- Java requirements @@ -67,7 +68,7 @@ Android AAR Envoy Mobile can be compiled into an ``.aar`` file for use with Android apps. This command is defined in the main :repo:`BUILD ` file of the repo, and may be run locally: -``bazelisk build android_dist --config=android --fat_apk_cpu=`` +``./bazelw build android_dist --config=android --fat_apk_cpu=`` Upon completion of the build, you'll see an ``envoy.aar`` file at :repo:`dist/envoy.aar `. @@ -80,7 +81,7 @@ an example of how this artifact may be used. **When building the artifact for release** (usage outside of development), be sure to include the ``--config=release-android`` option, along with the architectures for which the artifact is being built: -``bazelisk build android_dist --config=release-android --fat_apk_cpu=x86,armeabi-v7a,arm64-v8a`` +``./bazelw build android_dist --config=release-android --fat_apk_cpu=x86,armeabi-v7a,arm64-v8a`` For a demo of a working app using this artifact, see the :ref:`hello_world` example. @@ -93,7 +94,7 @@ iOS static framework Envoy Mobile supports being compiled into a ``.framework`` for consumption by iOS apps. This command is defined in the main :repo:`BUILD ` file of the repo, and may be run locally: -``bazelisk build ios_dist --config=ios`` +``./bazelw build ios_dist --config=ios`` Upon completion of the build, you'll see a ``Envoy.framework`` directory at :repo:`dist/Envoy.framework `. @@ -107,7 +108,7 @@ example of how this artifact may be used. **When building the artifact for release** (usage outside of development), be sure to include the ``--config=release-ios`` option, along with the architectures for which the artifact is being built: -``bazelisk build ios_dist --config=release-ios --ios_multi_cpus=i386,x86_64,armv7,arm64`` +``./bazelw build ios_dist --config=release-ios --ios_multi_cpus=i386,x86_64,armv7,arm64`` For a demo of a working app using this artifact, see the :ref:`hello_world` example. @@ -171,7 +172,7 @@ Android To deploy Envoy Mobile's aar to your local maven repository, run the following commands:: # To build Envoy Mobile. --fat_apk_cpu takes in a list of architectures: [x86|armeabi-v7a|arm64-v8a]. - bazelisk build android_dist --config=android --fat_apk_cpu=x86 + ./bazelw build android_dist --config=android --fat_apk_cpu=x86 # To publish to local maven. dist/sonatype_nexus_upload.py --files dist/envoy.aar dist/envoy-pom.xml --local diff --git a/docs/root/start/examples/hello_world.rst b/docs/root/start/examples/hello_world.rst index ad5c9996f7..3ec06d4e5c 100644 --- a/docs/root/start/examples/hello_world.rst +++ b/docs/root/start/examples/hello_world.rst @@ -23,7 +23,7 @@ Next, make sure you have an Android simulator running. Run the :repo:`sample app ` using the following Bazel build rule: -``bazelisk mobile-install //examples/java/hello_world:hello_envoy --fat_apk_cpu=`` +``./bazelw mobile-install //examples/java/hello_world:hello_envoy --fat_apk_cpu=`` You should see a new app installed on your simulator called ``Hello Envoy``. Open it up, and requests will start flowing! @@ -38,7 +38,7 @@ Next, make sure you have an Android simulator running. Run the :repo:`sample app ` using the following Bazel build rule: -``bazelisk mobile-install //examples/kotlin/hello_world:hello_envoy_kt --fat_apk_cpu=`` +``./bazelw mobile-install //examples/kotlin/hello_world:hello_envoy_kt --fat_apk_cpu=`` You should see a new app installed on your simulator called ``Hello Envoy Kotlin``. Open it up, and requests will start flowing! @@ -51,7 +51,7 @@ First, build the :ref:`ios_framework` artifact. Next, run the :repo:`sample app ` using the following Bazel build rule: -``bazelisk run //examples/objective-c/hello_world:app --config=ios`` +``./bazelw run //examples/objective-c/hello_world:app --config=ios`` This will start a simulator and open a new app. You should see requests start flowing! @@ -63,6 +63,6 @@ First, build the :ref:`ios_framework` artifact. Next, run the :repo:`sample app ` using the following Bazel build rule: -``bazelisk run //examples/swift/hello_world:app --config=ios`` +``./bazelw run //examples/swift/hello_world:app --config=ios`` This will start a simulator and open a new app. You should see requests start flowing! From e07a0bc30453f4a3661bc7dc8a39162bb9bf131e Mon Sep 17 00:00:00 2001 From: JP Simard Date: Wed, 1 Dec 2021 15:53:37 -0500 Subject: [PATCH 15/25] Update Objective-C on error/cancel to include final_stream_intel (#1954) Description: This is a followup to https://github.com/envoyproxy/envoy-mobile/pull/1937. Risk Level: I believe these extra parameters are safe to ignore if we don't need to propagate them to the Objective-C interface, but would like someone else to confirm that. (Confirmed.) Testing: Example apps still work, and downstream (closed source) consumers now compile again. Signed-off-by: JP Simard --- library/objective-c/EnvoyEngineImpl.m | 5 ++++- library/objective-c/EnvoyHTTPStreamImpl.m | 22 +++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/library/objective-c/EnvoyEngineImpl.m b/library/objective-c/EnvoyEngineImpl.m index 471b4ce3a9..0314c9badd 100644 --- a/library/objective-c/EnvoyEngineImpl.m +++ b/library/objective-c/EnvoyEngineImpl.m @@ -332,7 +332,9 @@ static void ios_http_filter_set_response_callbacks(envoy_http_filter_callbacks c } } -static void ios_http_filter_on_cancel(envoy_stream_intel stream_intel, const void *context) { +static void ios_http_filter_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, + const void *context) { // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block // is necessary to act as a breaker for any Objective-C allocation that happens. @autoreleasepool { @@ -345,6 +347,7 @@ static void ios_http_filter_on_cancel(envoy_stream_intel stream_intel, const voi } static void ios_http_filter_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, const void *context) { // This code block runs inside the Envoy event loop. Therefore, an explicit autoreleasepool block // is necessary to act as a breaker for any Objective-C allocation that happens. diff --git a/library/objective-c/EnvoyHTTPStreamImpl.m b/library/objective-c/EnvoyHTTPStreamImpl.m index 7568c08417..9c737d07c7 100644 --- a/library/objective-c/EnvoyHTTPStreamImpl.m +++ b/library/objective-c/EnvoyHTTPStreamImpl.m @@ -62,7 +62,8 @@ return NULL; } -static void *ios_on_complete(envoy_stream_intel stream_intel, void *context) { +static void *ios_on_complete(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void *context) { ios_context *c = (ios_context *)context; EnvoyHTTPCallbacks *callbacks = c->callbacks; EnvoyHTTPStreamImpl *stream = c->stream; @@ -74,7 +75,13 @@ return NULL; } -static void *ios_on_cancel(envoy_stream_intel stream_intel, void *context) { +// TODO(goaway) fix this up to call ios_on_send_window_available +static void *ios_on_send_window_available(envoy_stream_intel stream_intel, void *context) { + return NULL; +} + +static void *ios_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void *context) { // This call is atomically gated at the call-site and will only happen once. It may still fire // after a complete response or error callback, but no other callbacks for the stream will ever // fire AFTER the cancellation callback. @@ -93,7 +100,8 @@ return NULL; } -static void *ios_on_error(envoy_error error, envoy_stream_intel stream_intel, void *context) { +static void *ios_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void *context) { ios_context *c = (ios_context *)context; EnvoyHTTPCallbacks *callbacks = c->callbacks; EnvoyHTTPStreamImpl *stream = c->stream; @@ -142,10 +150,10 @@ - (instancetype)initWithHandle:(envoy_stream_t)handle atomic_store(context->closed, NO); // Create native callbacks - // TODO(goaway) fix this up to call ios_on_send_window_available - envoy_http_callbacks native_callbacks = {ios_on_headers, ios_on_data, ios_on_metadata, - ios_on_trailers, ios_on_error, ios_on_complete, - ios_on_cancel, ios_on_cancel, context}; + envoy_http_callbacks native_callbacks = { + ios_on_headers, ios_on_data, ios_on_metadata, ios_on_trailers, + ios_on_error, ios_on_complete, ios_on_cancel, ios_on_send_window_available, + context}; _nativeCallbacks = native_callbacks; // We need create the native-held strong ref on this stream before we call start_stream because From 99d101c632b0e218c2f3c4f949db2f0ebc6c3659 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 2 Dec 2021 11:45:35 -0800 Subject: [PATCH 16/25] ci: Change last bazel references to bazelw (#1956) Signed-off-by: Keith Smiley --- .github/workflows/perf.yml | 4 ++-- ci/mac_ci_setup.sh | 11 +---------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/.github/workflows/perf.yml b/.github/workflows/perf.yml index 72e6915518..2acafe9e6c 100644 --- a/.github/workflows/perf.yml +++ b/.github/workflows/perf.yml @@ -24,7 +24,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - bazel build \ + ./bazelw build \ --config=sizeopt \ --config=remote-ci-linux-clang \ --remote_header="Authorization=Bearer $GITHUB_TOKEN" \ @@ -51,7 +51,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git checkout main && git pull origin main && git submodule update - bazel build \ + ./bazelw build \ --config=sizeopt \ --config=remote-ci-linux-clang \ --remote_header="Authorization=Bearer $GITHUB_TOKEN" \ diff --git a/ci/mac_ci_setup.sh b/ci/mac_ci_setup.sh index c84c52e4e1..b5be3f94e3 100755 --- a/ci/mac_ci_setup.sh +++ b/ci/mac_ci_setup.sh @@ -41,16 +41,7 @@ if [ -n "$CIRCLECI" ]; then mv ~/.gitconfig ~/.gitconfig_save fi -# Required as bazel and a foreign bazelisk are installed in the latest macos vm image, we have -# to unlink/overwrite them to install bazelisk -echo "Installing bazelisk" -brew reinstall --force bazelisk -if ! brew link --overwrite bazelisk; then - echo "Failed to install and link bazelisk" - exit 1 -fi - -bazel version +./bazelw version pip3 install slackclient # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-11-Readme.md#xcode From 18aed78103fb53b316b139c1c658f33b95bd2601 Mon Sep 17 00:00:00 2001 From: JP Simard Date: Thu, 2 Dec 2021 17:20:15 -0500 Subject: [PATCH 17/25] [EnvoyBridgeUtility] Fix NSString to envoy_data conversion (#1958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description: Fix NSString to envoy_data conversion for non-ascii strings such as '台灣大哥大'. -length is the number of UTF-16 code units in the receiver whereas -lengthOfBytesUsingEncoding: is the number of UTF8 bytes. Using the latter is necessary since we're using this value to determine how many bytes to copy from the string. Risk Level: Low. Testing: Added an Objective-C unit test, and enabled running on CI. Signed-off-by: JP Simard --- .github/workflows/ios_tests.yml | 25 +++++++++++++++++++++++ library/objective-c/EnvoyBridgeUtility.h | 2 +- test/objective-c/EnvoyBridgeUtilityTest.m | 9 +++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ios_tests.yml b/.github/workflows/ios_tests.yml index d13aaba7a5..763c5b08b3 100644 --- a/.github/workflows/ios_tests.yml +++ b/.github/workflows/ios_tests.yml @@ -32,3 +32,28 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: ./bazelw test --test_output=all --config=ios --build_tests_only --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //test/swift/... + objctests: + name: objc_tests + runs-on: macos-11 + timeout-minutes: 120 + steps: + - uses: actions/checkout@v1 + with: + submodules: true + - id: check_context + name: 'Check whether to run' + run: | + if git rev-parse --abbrev-ref HEAD | grep -q ^main$ || git diff --name-only origin/main | grep -qe common/ -e objective-c/ -e swift/ -e bazel/ -e ^\.bazelrc$ -e ^envoy$ -e ^WORKSPACE$ -e ^.github/workflows/ios_tests.yml$ ; then + echo "Tests will run." + echo "::set-output name=run_tests::true" + else + echo "Skipping tests." + echo "::set-output name=run_tests::false" + fi + - name: 'Install dependencies' + run: ./ci/mac_ci_setup.sh + - name: 'Run Objective-C library tests' + if: steps.check_context.outputs.run_tests == 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./bazelw test --test_output=all --config=ios --build_tests_only --config=remote-ci-macos --remote_header="Authorization=Bearer $GITHUB_TOKEN" //test/objective-c/... diff --git a/library/objective-c/EnvoyBridgeUtility.h b/library/objective-c/EnvoyBridgeUtility.h index 52644be4de..1cb3429528 100644 --- a/library/objective-c/EnvoyBridgeUtility.h +++ b/library/objective-c/EnvoyBridgeUtility.h @@ -24,7 +24,7 @@ static inline envoy_data *toNativeDataPtr(NSData *data) { } static inline envoy_data toManagedNativeString(NSString *s) { - size_t length = s.length; + size_t length = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; uint8_t *native_string = (uint8_t *)safe_malloc(sizeof(uint8_t) * length); memcpy(native_string, s.UTF8String, length); // NOLINT(safe-memcpy) envoy_data ret = {length, native_string, free, native_string}; diff --git a/test/objective-c/EnvoyBridgeUtilityTest.m b/test/objective-c/EnvoyBridgeUtilityTest.m index 103f2d0ad3..85596f7c96 100644 --- a/test/objective-c/EnvoyBridgeUtilityTest.m +++ b/test/objective-c/EnvoyBridgeUtilityTest.m @@ -1,8 +1,8 @@ #import typedef NSDictionary *> EnvoyHeaders; - typedef NSDictionary EnvoyTags; +typedef NSDictionary EnvoyEvent; #import "library/objective-c/EnvoyBridgeUtility.h" @@ -18,4 +18,11 @@ - (void)testToNativeData { XCTAssertEqual(memcmp(nativeData.bytes, testData.bytes, 3), 0); } +- (void)testToManagedNativeStringUsingUTF8Chars { + NSString *testString = @"台灣大哥大"; + envoy_data stringData = toManagedNativeString(testString); + NSString *roundtripString = to_ios_string(stringData); + XCTAssertEqual([testString compare:roundtripString options:0], NSOrderedSame); +} + @end From ff2786d83288373a6b11657926ff3e9ff6fb04d5 Mon Sep 17 00:00:00 2001 From: JP Simard Date: Thu, 2 Dec 2021 17:20:31 -0500 Subject: [PATCH 18/25] Fix V6 interface binding logging (#1959) Description: Both v4_interfaces and v6_interfaces were using V4 interfaces likely due to a typo. This is a follow-up to #1897. Risk Level: Low, just fixing a log. Signed-off-by: JP Simard --- library/common/engine.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/common/engine.cc b/library/common/engine.cc index 68a687738d..08cfa031ad 100644 --- a/library/common/engine.cc +++ b/library/common/engine.cc @@ -105,7 +105,7 @@ envoy_status_t Engine::main(const std::string config, const std::string log_leve network_configurator_ = Network::ConfiguratorFactory{server_->serverFactoryContext()}.get(); auto v4_interfaces = network_configurator_->enumerateV4Interfaces(); - auto v6_interfaces = network_configurator_->enumerateV4Interfaces(); + auto v6_interfaces = network_configurator_->enumerateV6Interfaces(); logInterfaces("netconf_get_v4_interfaces", v4_interfaces); logInterfaces("netconf_get_v6_interfaces", v6_interfaces); client_scope_ = server_->serverFactoryContext().scope().createScope("pulse."); From d249559cf808d18ebaff1e115d7c23d203513a3a Mon Sep 17 00:00:00 2001 From: JP Simard Date: Tue, 14 Dec 2021 13:24:27 -0500 Subject: [PATCH 19/25] Update Envoy to 70a5f29 (#1962) Changes: envoyproxy/envoy@23e5fc2...70a5f29 Signed-off-by: JP Simard --- envoy | 2 +- library/common/engine.cc | 2 + library/common/network/BUILD | 6 +- library/common/network/android.cc | 78 +++++++++++++++++++ library/common/network/android.h | 15 ++++ library/common/network/configurator.cc | 48 ++++-------- .../integration/client_integration_test.cc | 4 +- test/common/network/configurator_test.cc | 1 + 8 files changed, 119 insertions(+), 37 deletions(-) create mode 100644 library/common/network/android.cc create mode 100644 library/common/network/android.h diff --git a/envoy b/envoy index 5a19106401..b1219ef0de 160000 --- a/envoy +++ b/envoy @@ -1 +1 @@ -Subproject commit 5a19106401b6f6dfdd44eb1b6fae76a168aff77b +Subproject commit b1219ef0decc22040d45fe8bf2fa86bd16ea4e3c diff --git a/library/common/engine.cc b/library/common/engine.cc index 08cfa031ad..92042d9f4c 100644 --- a/library/common/engine.cc +++ b/library/common/engine.cc @@ -7,6 +7,7 @@ #include "library/common/bridge/utility.h" #include "library/common/config/internal.h" #include "library/common/data/utility.h" +#include "library/common/network/android.h" #include "library/common/stats/utility.h" namespace Envoy { @@ -104,6 +105,7 @@ envoy_status_t Engine::main(const std::string config, const std::string log_leve network_configurator_ = Network::ConfiguratorFactory{server_->serverFactoryContext()}.get(); + Envoy::Network::Android::Utility::setAlternateGetifaddrs(); auto v4_interfaces = network_configurator_->enumerateV4Interfaces(); auto v6_interfaces = network_configurator_->enumerateV6Interfaces(); logInterfaces("netconf_get_v4_interfaces", v4_interfaces); diff --git a/library/common/network/BUILD b/library/common/network/BUILD index 79bbb2df6b..e7d023b0b1 100644 --- a/library/common/network/BUILD +++ b/library/common/network/BUILD @@ -8,6 +8,7 @@ envoy_cc_library( name = "configurator_lib", srcs = [ "configurator.cc", + "android.cc", ] + select({ "//bazel:include_ifaddrs": [ "//third_party:android/ifaddrs-android.h", @@ -16,7 +17,10 @@ envoy_cc_library( ], "//conditions:default": [], }), - hdrs = ["configurator.h"], + hdrs = [ + "android.h", + "configurator.h", + ], copts = select({ "//bazel:include_ifaddrs": ["-DINCLUDE_IFADDRS"], "//conditions:default": [], diff --git a/library/common/network/android.cc b/library/common/network/android.cc new file mode 100644 index 0000000000..5c9a5ec8bd --- /dev/null +++ b/library/common/network/android.cc @@ -0,0 +1,78 @@ +#include "library/common/network/android.h" + +#include + +#include "envoy/common/platform.h" + +#include "source/common/api/os_sys_calls_impl.h" +#include "source/common/common/assert.h" +#include "source/common/common/scalar_to_byte_vector.h" +#include "source/common/common/utility.h" +#include "source/common/network/addr_family_aware_socket_option_impl.h" +#include "source/common/network/address_impl.h" +#include "source/extensions/common/dynamic_forward_proxy/dns_cache_manager_impl.h" + +#include "library/common/network/src_addr_socket_option_impl.h" + +namespace Envoy { +namespace Network { +namespace Android { +namespace Utility { + +#if defined(INCLUDE_IFADDRS) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +namespace { +#include "third_party/android/ifaddrs-android.h" +} +#pragma clang diagnostic pop +#endif + +void setAlternateGetifaddrs() { +#if defined(INCLUDE_IFADDRS) + auto& os_syscalls = Api::OsSysCallsSingleton::get(); + ENVOY_BUG(!os_syscalls.supportsGetifaddrs(), + "setAlternateGetifaddrs should only be called when supportsGetifaddrs is false"); + + Api::AlternateGetifaddrs android_getifaddrs = + [](Api::InterfaceAddressVector& interfaces) -> Api::SysCallIntResult { + struct ifaddrs* ifaddr; + struct ifaddrs* ifa; + + const int rc = getifaddrs(&ifaddr); + if (rc == -1) { + return {rc, errno}; + } + + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == nullptr) { + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) { + const sockaddr_storage* ss = reinterpret_cast(ifa->ifa_addr); + size_t ss_len = + ifa->ifa_addr->sa_family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); + StatusOr address = + Address::addressFromSockAddr(*ss, ss_len, ifa->ifa_addr->sa_family == AF_INET6); + if (address.ok()) { + interfaces.emplace_back(ifa->ifa_name, ifa->ifa_flags, *address); + } + } + } + + if (ifaddr) { + freeifaddrs(ifaddr); + } + + return {rc, 0}; + }; + + os_syscalls.setAlternateGetifaddrs(android_getifaddrs); +#endif +} + +} // namespace Utility +} // namespace Android +} // namespace Network +} // namespace Envoy diff --git a/library/common/network/android.h b/library/common/network/android.h new file mode 100644 index 0000000000..148cbcb97e --- /dev/null +++ b/library/common/network/android.h @@ -0,0 +1,15 @@ +#pragma once + +namespace Envoy { +namespace Network { +namespace Android { +namespace Utility { +/** + * Sets an alternate `getifaddrs` implementation than the one defined + * in Envoy by default. + */ +void setAlternateGetifaddrs(); +} // namespace Utility +} // namespace Android +} // namespace Network +} // namespace Envoy diff --git a/library/common/network/configurator.cc b/library/common/network/configurator.cc index 60c93942d7..981c9682b0 100644 --- a/library/common/network/configurator.cc +++ b/library/common/network/configurator.cc @@ -4,6 +4,7 @@ #include "envoy/common/platform.h" +#include "source/common/api/os_sys_calls_impl.h" #include "source/common/common/assert.h" #include "source/common/common/scalar_to_byte_vector.h" #include "source/common/common/utility.h" @@ -49,10 +50,6 @@ #define DEFAULT_IP_TTL 64 -#ifdef SUPPORTS_GETIFADDRS -#include -#endif - // Prefixes used to prefer well-known interface names. #if defined(__APPLE__) constexpr absl::string_view WlanPrefix = "en"; @@ -69,16 +66,6 @@ constexpr absl::string_view WwanPrefix = ""; namespace Envoy { namespace Network { -#if !defined(SUPPORTS_GETIFADDRS) && defined(INCLUDE_IFADDRS) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wold-style-cast" -namespace { -#include "third_party/android/ifaddrs-android.h" -} -#pragma clang diagnostic pop -#define SUPPORTS_GETIFADDRS -#endif - SINGLETON_MANAGER_REGISTRATION(network_configurator); constexpr absl::string_view BaseDnsCache = "base_dns_cache"; @@ -329,33 +316,28 @@ Configurator::enumerateInterfaces([[maybe_unused]] unsigned short family, [[maybe_unused]] unsigned int reject_flags) { std::vector pairs{}; -#ifdef SUPPORTS_GETIFADDRS - struct ifaddrs* interfaces = nullptr; - struct ifaddrs* ifa = nullptr; + if (!Api::OsSysCallsSingleton::get().supportsGetifaddrs()) { + return pairs; + } - const int rc = getifaddrs(&interfaces); - RELEASE_ASSERT(!rc, "getifaddrs failed"); + Api::InterfaceAddressVector interface_addresses{}; + const Api::SysCallIntResult rc = Api::OsSysCallsSingleton::get().getifaddrs(interface_addresses); + RELEASE_ASSERT(!rc.return_value_, fmt::format("getiffaddrs error: {}", rc.errno_)); - for (ifa = interfaces; ifa != nullptr; ifa = ifa->ifa_next) { - if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != family) { - continue; - } - if ((ifa->ifa_flags & (select_flags ^ reject_flags)) != select_flags) { + for (const auto& interface_address : interface_addresses) { + const auto family_version = family == AF_INET ? Envoy::Network::Address::IpVersion::v4 + : Envoy::Network::Address::IpVersion::v6; + if (interface_address.interface_addr_->ip()->version() != family_version) { continue; } - const sockaddr_storage* ss = reinterpret_cast(ifa->ifa_addr); - size_t ss_len = family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6); - StatusOr address = - Address::addressFromSockAddr(*ss, ss_len, family == AF_INET6); - if (!address.ok()) { + if ((interface_address.interface_flags_ & (select_flags ^ reject_flags)) != select_flags) { continue; } - pairs.push_back(std::make_pair(std::string{ifa->ifa_name}, *address)); - } - freeifaddrs(interfaces); -#endif // SUPPORTS_GETIFADDRS + pairs.push_back( + std::make_pair(interface_address.interface_name_, interface_address.interface_addr_)); + } return pairs; } diff --git a/test/common/integration/client_integration_test.cc b/test/common/integration/client_integration_test.cc index 88f98210b1..89b49a92b7 100644 --- a/test/common/integration/client_integration_test.cc +++ b/test/common/integration/client_integration_test.cc @@ -25,7 +25,7 @@ Http::ResponseHeaderMapPtr toResponseHeaders(envoy_headers headers) { Http::ResponseHeaderMapImpl::create(); transformed_headers->setFormatter( std::make_unique< - Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>()); + Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>(false)); Http::Utility::toEnvoyHeaders(*transformed_headers, headers); return transformed_headers; } @@ -333,7 +333,7 @@ TEST_P(ClientIntegrationTest, CaseSensitive) { Http::TestRequestHeaderMapImpl headers{{"FoO", "bar"}}; headers.header_map_->setFormatter( std::make_unique< - Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>()); + Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>(false)); headers.header_map_->formatter().value().get().processKey("FoO"); HttpTestUtility::addDefaultHeaders(headers); envoy_headers c_headers = Http::Utility::toBridgeHeaders(headers); diff --git a/test/common/network/configurator_test.cc b/test/common/network/configurator_test.cc index d0f6f532f9..d3bd529c63 100644 --- a/test/common/network/configurator_test.cc +++ b/test/common/network/configurator_test.cc @@ -124,6 +124,7 @@ TEST_F(ConfiguratorTest, ReportNetworkUsageDisregardsCallsWithStaleConfiguration TEST_F(ConfiguratorTest, EnumerateInterfacesFiltersByFlags) { // Select loopback. auto loopbacks = configurator_->enumerateInterfaces(AF_INET, IFF_LOOPBACK, 0); + EXPECT_EQ(loopbacks.size(), 1); EXPECT_EQ(std::get(loopbacks[0]).rfind("lo", 0), 0); // Reject loopback. From 040f545efa4bcd1abf8cb70115dceb031687b759 Mon Sep 17 00:00:00 2001 From: alyssawilk Date: Tue, 14 Dec 2021 19:28:51 -0500 Subject: [PATCH 20/25] Bumping Envoy to 247deb39110eca961af1ee8147a1cbb373c6cced247d (#1968) Signed-off-by: Alyssa Wilk --- .../http/network_configuration/filter.cc | 7 +++-- .../filters/http/platform_bridge/filter.cc | 4 ++- .../network_configuration/predicate.cc | 4 ++- library/common/http/BUILD | 1 + library/common/http/client.cc | 29 ++++++++++++++++++- library/common/http/client.h | 5 ++-- 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/library/common/extensions/filters/http/network_configuration/filter.cc b/library/common/extensions/filters/http/network_configuration/filter.cc index 8a15bfddf6..8108be8fb7 100644 --- a/library/common/extensions/filters/http/network_configuration/filter.cc +++ b/library/common/extensions/filters/http/network_configuration/filter.cc @@ -46,8 +46,11 @@ Http::LocalErrorStatus NetworkConfigurationFilter::onLocalReply(const LocalReply // errors, this code interprets any local error where a stream received no bytes from the upstream // as a network fault. This status is passed to the configurator below when we report network // usage, where it may be factored into future socket configuration. - bool network_fault = !success_status && - !decoder_callbacks_->streamInfo().firstUpstreamRxByteReceived().has_value(); + bool network_fault = !success_status && (!decoder_callbacks_->streamInfo().upstreamInfo() || + !decoder_callbacks_->streamInfo() + .upstreamInfo() + ->upstreamTiming() + .first_upstream_rx_byte_received_.has_value()); // Report request status to network configurator, so that socket configuration may be adapted // to current network conditions. network_configurator_->reportNetworkUsage(extra_stream_info_->configuration_key_.value(), diff --git a/library/common/extensions/filters/http/platform_bridge/filter.cc b/library/common/extensions/filters/http/platform_bridge/filter.cc index 4ca94f0c5e..bcc73d4014 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.cc +++ b/library/common/extensions/filters/http/platform_bridge/filter.cc @@ -192,7 +192,9 @@ envoy_stream_intel PlatformBridgeFilter::streamIntel() { auto& info = decoder_callbacks_->streamInfo(); // FIXME: Stream handle cannot currently be set from the filter context. envoy_stream_intel stream_intel{-1, -1, 0}; - stream_intel.connection_id = info.upstreamConnectionId().value_or(-1); + if (info.upstreamInfo()) { + stream_intel.connection_id = info.upstreamInfo()->upstreamConnectionId().value_or(-1); + } stream_intel.attempt_count = info.attemptCount().value_or(0); return stream_intel; } diff --git a/library/common/extensions/retry/options/network_configuration/predicate.cc b/library/common/extensions/retry/options/network_configuration/predicate.cc index 4b0ba42e1f..bb75bf3135 100644 --- a/library/common/extensions/retry/options/network_configuration/predicate.cc +++ b/library/common/extensions/retry/options/network_configuration/predicate.cc @@ -48,7 +48,9 @@ NetworkConfigurationRetryOptionsPredicate::updateOptions( // where a stream received no bytes from the upstream as a network fault. This status is passed to // the configurator below when we report network usage, where it may be factored into future // socket configuration. - bool network_fault = !stream_info.firstUpstreamRxByteReceived().has_value(); + bool network_fault = + !stream_info.upstreamInfo() || + !stream_info.upstreamInfo()->upstreamTiming().first_upstream_rx_byte_received_.has_value(); // Report request status to network configurator, so that socket configuration may be adapted // to current network conditions. diff --git a/library/common/http/BUILD b/library/common/http/BUILD index 22fcf0b4a6..1b28005d0b 100644 --- a/library/common/http/BUILD +++ b/library/common/http/BUILD @@ -39,6 +39,7 @@ envoy_cc_library( "@envoy//source/common/http:header_map_lib", "@envoy//source/common/http:headers_lib", "@envoy//source/common/http:utility_lib", + "@envoy//source/common/stream_info:utility_lib", ], ) diff --git a/library/common/http/client.cc b/library/common/http/client.cc index 0bdf7c153c..203d57eed0 100644 --- a/library/common/http/client.cc +++ b/library/common/http/client.cc @@ -7,6 +7,7 @@ #include "source/common/http/header_map_impl.h" #include "source/common/http/headers.h" #include "source/common/http/utility.h" +#include "source/common/stream_info/utility.h" #include "library/common/bridge/utility.h" #include "library/common/buffer/bridge_fragment.h" @@ -271,9 +272,35 @@ envoy_stream_intel Client::DirectStreamCallbacks::streamIntel() { void Client::DirectStream::saveLatestStreamIntel() { const auto& info = request_decoder_->streamInfo(); - stream_intel_.connection_id = info.upstreamConnectionId().value_or(-1); + if (info.upstreamInfo()) { + stream_intel_.connection_id = info.upstreamInfo()->upstreamConnectionId().value_or(-1); + } stream_intel_.stream_id = static_cast(stream_handle_); stream_intel_.attempt_count = info.attemptCount().value_or(0); + saveFinalStreamIntel(); +} + +void Client::DirectStream::saveFinalStreamIntel() { + const auto& info = request_decoder_->streamInfo(); + latency_info_.request_start_ms = std::chrono::duration_cast( + info.startTimeMonotonic().time_since_epoch()) + .count(); + latency_info_.sent_byte_count = info.bytesSent(); + latency_info_.received_byte_count = info.bytesReceived(); + StreamInfo::TimingUtility timing(info); + setFromOptional(latency_info_.request_end_ms, timing.lastDownstreamRxByteReceived(), + latency_info_.request_start_ms); + setFromOptional(latency_info_.dns_start_ms, + request_decoder_->streamInfo().downstreamTiming().getValue( + "envoy.dynamic_forward_proxy.dns_start_ms")); + setFromOptional(latency_info_.dns_end_ms, + request_decoder_->streamInfo().downstreamTiming().getValue( + "envoy.dynamic_forward_proxy.dns_end_ms")); + // TODO(alyssawilk) sort out why upstream info is problematic for cronvoy tests. + return; + if (info.upstreamInfo().has_value()) { + latency_info_.upstream_info_ = request_decoder_->streamInfo().upstreamInfo(); + } } envoy_error Client::DirectStreamCallbacks::streamError() { diff --git a/library/common/http/client.h b/library/common/http/client.h index 455f67fdc5..10f1ff146a 100644 --- a/library/common/http/client.h +++ b/library/common/http/client.h @@ -110,7 +110,7 @@ class Client : public Logger::Loggable { // Used to fill response code details for streams that are cancelled via cancelStream. const std::string& getCancelDetails() { - CONSTRUCT_ON_FIRST_USE(std::string, "client cancelled stream"); + CONSTRUCT_ON_FIRST_USE(std::string, "client_cancelled_stream"); } private: @@ -270,7 +270,8 @@ class Client : public Logger::Loggable { // read faster than the mobile caller can process it. bool explicit_flow_control_ = false; // Latest intel data retrieved from the StreamInfo. - envoy_stream_intel stream_intel_; + envoy_stream_intel stream_intel_{-1, -1, 0}; + LatencyInfo latency_info_; StreamInfo::BytesMeterSharedPtr bytes_meter_; }; From 88ac9d3fc3a83e0f396830b5310ccc35a5753900 Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Tue, 14 Dec 2021 16:39:15 -0800 Subject: [PATCH 21/25] Revert "Revert "Revert "Revert "incompletely used APIs for final stream metrics (#1937)"""" This reverts commit 04b18640847e19c9c2917d8942ec2e7a120b457d. Signed-off-by: Jose Nino --- examples/java/hello_world/MainActivity.java | 2 +- .../kotlin/hello_world/AsyncDemoFilter.kt | 13 ++- .../kotlin/hello_world/BufferDemoFilter.kt | 13 ++- examples/kotlin/hello_world/DemoFilter.kt | 13 ++- examples/kotlin/hello_world/MainActivity.kt | 2 +- library/cc/stream_callbacks.cc | 7 +- .../filters/http/platform_bridge/c_types.h | 5 +- .../filters/http/platform_bridge/filter.cc | 16 +++- .../filters/http/platform_bridge/filter.h | 1 + library/common/http/client.cc | 61 +++++++++++- library/common/http/client.h | 18 +++- library/common/jni/jni_interface.cc | 68 ++++++++++---- library/common/jni/jni_utility.cc | 27 ++++++ library/common/jni/jni_utility.h | 3 + library/common/types/c_types.h | 52 +++++++++- .../io/envoyproxy/envoymobile/engine/BUILD | 1 + .../engine/EnvoyFinalStreamIntelImpl.java | 94 +++++++++++++++++++ .../engine/JvmCallbackContext.java | 44 +++++++-- .../envoymobile/engine/JvmFilterContext.java | 28 +++++- .../envoyproxy/envoymobile/engine/types/BUILD | 1 + .../engine/types/EnvoyFinalStreamIntel.java | 67 +++++++++++++ .../engine/types/EnvoyHTTPCallbacks.java | 18 +++- .../engine/types/EnvoyHTTPFilter.java | 20 +++- .../chromium/net/impl/CronetUrlRequest.java | 8 +- .../kotlin/io/envoyproxy/envoymobile/BUILD | 1 + .../envoymobile/FinalStreamIntel.kt | 57 +++++++++++ .../envoyproxy/envoymobile/StreamCallbacks.kt | 22 +++-- .../envoyproxy/envoymobile/StreamPrototype.kt | 27 +++++- .../envoyproxy/envoymobile/filters/Filter.kt | 15 ++- .../envoymobile/filters/ResponseFilter.kt | 17 +++- .../envoymobile/grpc/GRPCStreamPrototype.kt | 4 +- .../envoymobile/mocks/MockStream.kt | 21 ++++- .../platform_bridge_filter_test.cc | 2 +- test/common/http/client_test.cc | 18 ++-- .../integration/client_integration_test.cc | 6 +- test/common/main_interface_test.cc | 30 +++--- .../AndroidEnvoyExplicitFlowTest.java | 4 +- .../integration/AndroidEnvoyFlowTest.java | 4 +- test/kotlin/integration/CancelStreamTest.kt | 8 +- .../integration/DrainConnectionsTest.kt | 4 +- .../integration/GRPCReceiveErrorTest.kt | 12 ++- test/kotlin/integration/ReceiveDataTest.kt | 2 +- test/kotlin/integration/ReceiveErrorTest.kt | 12 ++- test/kotlin/integration/SendDataTest.kt | 2 +- test/kotlin/integration/SendHeadersTest.kt | 2 +- test/kotlin/integration/SendTrailersTest.kt | 2 +- .../integration/StreamIdleTimeoutTest.kt | 8 +- 47 files changed, 734 insertions(+), 128 deletions(-) create mode 100644 library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java create mode 100644 library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java create mode 100644 library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt diff --git a/examples/java/hello_world/MainActivity.java b/examples/java/hello_world/MainActivity.java index 5d1ebcd4ac..cf121e56eb 100644 --- a/examples/java/hello_world/MainActivity.java +++ b/examples/java/hello_world/MainActivity.java @@ -125,7 +125,7 @@ private void makeRequest() { } return Unit.INSTANCE; }) - .setOnError((error, ignored) -> { + .setOnError((error, ignored, also_ignored) -> { String message = "failed with error after " + error.getAttemptCount() + " attempts: " + error.getMessage(); Log.d("MainActivity", message); diff --git a/examples/kotlin/hello_world/AsyncDemoFilter.kt b/examples/kotlin/hello_world/AsyncDemoFilter.kt index 214e01bdb6..72f6ab8463 100644 --- a/examples/kotlin/hello_world/AsyncDemoFilter.kt +++ b/examples/kotlin/hello_world/AsyncDemoFilter.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterResumeStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilterCallbacks import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -78,10 +79,18 @@ class AsyncDemoFilter : AsyncResponseFilter { } @Suppress("EmptyFunctionBlock") - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError( + error: EnvoyError, + streamIntel: StreamIntel, + finalStreamIntel: FinalStreamIntel + ) { } @Suppress("EmptyFunctionBlock") - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + } + + @Suppress("EmptyFunctionBlock") + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { } } diff --git a/examples/kotlin/hello_world/BufferDemoFilter.kt b/examples/kotlin/hello_world/BufferDemoFilter.kt index de6151dcdb..dee61511e5 100644 --- a/examples/kotlin/hello_world/BufferDemoFilter.kt +++ b/examples/kotlin/hello_world/BufferDemoFilter.kt @@ -4,6 +4,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -56,10 +57,18 @@ class BufferDemoFilter : ResponseFilter { } @Suppress("EmptyFunctionBlock") - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError( + error: EnvoyError, + streamIntel: StreamIntel, + finalStreamIntel: FinalStreamIntel + ) { } @Suppress("EmptyFunctionBlock") - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + } + + @Suppress("EmptyFunctionBlock") + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { } } diff --git a/examples/kotlin/hello_world/DemoFilter.kt b/examples/kotlin/hello_world/DemoFilter.kt index a0f12eac69..f9c005f997 100644 --- a/examples/kotlin/hello_world/DemoFilter.kt +++ b/examples/kotlin/hello_world/DemoFilter.kt @@ -5,6 +5,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders import io.envoyproxy.envoymobile.ResponseTrailers @@ -40,11 +41,19 @@ class DemoFilter : ResponseFilter { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError( + error: EnvoyError, + streamIntel: StreamIntel, + finalStreamIntel: FinalStreamIntel + ) { Log.d("DemoFilter", "On error!") } - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { Log.d("DemoFilter", "On cancel!") } + + @Suppress("EmptyFunctionBlock") + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { + } } diff --git a/examples/kotlin/hello_world/MainActivity.kt b/examples/kotlin/hello_world/MainActivity.kt index d58c7b40c1..7fc060ee25 100644 --- a/examples/kotlin/hello_world/MainActivity.kt +++ b/examples/kotlin/hello_world/MainActivity.kt @@ -135,7 +135,7 @@ class MainActivity : Activity() { recyclerView.post { viewAdapter.add(Failure(message)) } } } - .setOnError { error, _ -> + .setOnError { error, _, _ -> val attemptCount = error.attemptCount ?: -1 val message = "failed with error after $attemptCount attempts: ${error.message}" Log.d("MainActivity", message) diff --git a/library/cc/stream_callbacks.cc b/library/cc/stream_callbacks.cc index ece9ce32a0..1a6203f9cd 100644 --- a/library/cc/stream_callbacks.cc +++ b/library/cc/stream_callbacks.cc @@ -50,7 +50,8 @@ void* c_on_trailers(envoy_headers metadata, envoy_stream_intel, void* context) { return context; } -void* c_on_error(envoy_error raw_error, envoy_stream_intel, void* context) { +void* c_on_error(envoy_error raw_error, envoy_stream_intel, envoy_final_stream_intel, + void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_error.has_value()) { @@ -65,7 +66,7 @@ void* c_on_error(envoy_error raw_error, envoy_stream_intel, void* context) { return nullptr; } -void* c_on_complete(envoy_stream_intel, void* context) { +void* c_on_complete(envoy_stream_intel, envoy_final_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_complete.has_value()) { @@ -76,7 +77,7 @@ void* c_on_complete(envoy_stream_intel, void* context) { return nullptr; } -void* c_on_cancel(envoy_stream_intel, void* context) { +void* c_on_cancel(envoy_stream_intel, envoy_final_stream_intel, void* context) { auto stream_callbacks_ptr = static_cast(context); auto stream_callbacks = *stream_callbacks_ptr; if (stream_callbacks->on_cancel.has_value()) { diff --git a/library/common/extensions/filters/http/platform_bridge/c_types.h b/library/common/extensions/filters/http/platform_bridge/c_types.h index d0849ceb14..00154db773 100644 --- a/library/common/extensions/filters/http/platform_bridge/c_types.h +++ b/library/common/extensions/filters/http/platform_bridge/c_types.h @@ -137,12 +137,15 @@ typedef envoy_filter_resume_status (*envoy_filter_on_resume_f)( /** * Function signature for on-cancellation filter invocations. */ -typedef void (*envoy_filter_on_cancel_f)(envoy_stream_intel stream_intel, const void* context); +typedef void (*envoy_filter_on_cancel_f)(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, + const void* context); /** * Function signature for on-error filter invocations. */ typedef void (*envoy_filter_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, const void* context); /** diff --git a/library/common/extensions/filters/http/platform_bridge/filter.cc b/library/common/extensions/filters/http/platform_bridge/filter.cc index bcc73d4014..f249423309 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.cc +++ b/library/common/extensions/filters/http/platform_bridge/filter.cc @@ -152,7 +152,8 @@ void PlatformBridgeFilter::onDestroy() { // If the filter chain is destroyed before a response is received, treat as cancellation. if (!response_filter_base_->state_.stream_complete_ && platform_filter_.on_cancel) { ENVOY_LOG(trace, "PlatformBridgeFilter({})->on_cancel", filter_name_); - platform_filter_.on_cancel(streamIntel(), platform_filter_.instance_context); + platform_filter_.on_cancel(streamIntel(), finalStreamIntel(), + platform_filter_.instance_context); } // Allow nullptr as no-op only if nothing was initialized. @@ -181,12 +182,21 @@ Http::LocalErrorStatus PlatformBridgeFilter::onLocalReply(const LocalReplyData& envoy_data error_message = Data::Utility::copyToBridgeData(reply.details_); int32_t attempts = static_cast(info.attemptCount().value_or(0)); platform_filter_.on_error({error_code, error_message, attempts}, streamIntel(), - platform_filter_.instance_context); + finalStreamIntel(), platform_filter_.instance_context); } return Http::LocalErrorStatus::ContinueAndResetStream; } +envoy_final_stream_intel PlatformBridgeFilter::finalStreamIntel() { + RELEASE_ASSERT(decoder_callbacks_, "StreamInfo accessed before filter callbacks are set"); + // FIXME: Stream handle cannot currently be set from the filter context. + envoy_final_stream_intel final_stream_intel; + memset(&final_stream_intel, 0, sizeof(final_stream_intel)); + // TODO(alyssawilk) set stream intel from a shared helper function. + return final_stream_intel; +} + envoy_stream_intel PlatformBridgeFilter::streamIntel() { RELEASE_ASSERT(decoder_callbacks_, "StreamInfo accessed before filter callbacks are set"); auto& info = decoder_callbacks_->streamInfo(); @@ -465,7 +475,7 @@ Http::FilterHeadersStatus PlatformBridgeFilter::encodeHeaders(Http::ResponseHead if (platform_filter_.on_error) { platform_filter_.on_error({error_code, error_message, attempt_count}, streamIntel(), - platform_filter_.instance_context); + finalStreamIntel(), platform_filter_.instance_context); } else { release_envoy_data(error_message); } diff --git a/library/common/extensions/filters/http/platform_bridge/filter.h b/library/common/extensions/filters/http/platform_bridge/filter.h index 84e00182d5..0a495363c8 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.h +++ b/library/common/extensions/filters/http/platform_bridge/filter.h @@ -87,6 +87,7 @@ class PlatformBridgeFilter final : public Http::PassThroughFilter, void dumpState(std::ostream& os, int indent_level = 0) const override; // Common stream instrumentation. + envoy_final_stream_intel finalStreamIntel(); envoy_stream_intel streamIntel(); // Filter state. diff --git a/library/common/http/client.cc b/library/common/http/client.cc index 203d57eed0..c87a61879a 100644 --- a/library/common/http/client.cc +++ b/library/common/http/client.cc @@ -19,6 +19,29 @@ namespace Envoy { namespace Http { +namespace { + +void setFromOptional(uint64_t& to_set, const absl::optional& time) { + if (time.has_value()) { + to_set = std::chrono::duration_cast(time.value().time_since_epoch()) + .count(); + } +} + +void setFromOptional(long& to_set, absl::optional time, long offset) { + if (time.has_value()) { + to_set = offset + std::chrono::duration_cast(time.value()).count(); + } +} + +void setFromOptional(long& to_set, const absl::optional& time) { + if (time.has_value()) { + to_set = std::chrono::duration_cast(time.value().time_since_epoch()) + .count(); + } +} + +} // namespace /** * IMPORTANT: stream closure semantics in envoy mobile depends on the fact that the HCM fires a @@ -161,6 +184,29 @@ void Client::DirectStreamCallbacks::sendTrailersToBridge(const ResponseTrailerMa onComplete(); } +void Client::DirectStreamCallbacks::setFinalStreamIntel(envoy_final_stream_intel& final_intel) { + memset(&final_intel, 0, sizeof(envoy_final_stream_intel)); + + final_intel.request_start_ms = direct_stream_.latency_info_.request_start_ms; + if (direct_stream_.latency_info_.upstream_info_) { + const StreamInfo::UpstreamTiming& timing = + direct_stream_.latency_info_.upstream_info_->upstreamTiming(); + setFromOptional(final_intel.sending_start_ms, timing.first_upstream_tx_byte_sent_); + setFromOptional(final_intel.sending_end_ms, timing.last_upstream_tx_byte_sent_); + setFromOptional(final_intel.response_start_ms, timing.first_upstream_rx_byte_received_); + setFromOptional(final_intel.connect_start_ms, timing.upstream_connect_start_); + setFromOptional(final_intel.connect_end_ms, timing.upstream_connect_complete_); + setFromOptional(final_intel.ssl_start_ms, timing.upstream_connect_complete_); + setFromOptional(final_intel.ssl_end_ms, timing.upstream_handshake_complete_); + } + final_intel.dns_start_ms = direct_stream_.latency_info_.dns_start_ms; + final_intel.dns_end_ms = direct_stream_.latency_info_.dns_end_ms; + final_intel.request_end_ms = direct_stream_.latency_info_.request_end_ms; + final_intel.socket_reused = 0; // TODO(alyssawilk) set. + final_intel.sent_byte_count = direct_stream_.latency_info_.sent_byte_count; + final_intel.received_byte_count = direct_stream_.latency_info_.received_byte_count; +} + void Client::DirectStreamCallbacks::resumeData(int32_t bytes_to_send) { ASSERT(explicit_flow_control_); ASSERT(bytes_to_send > 0); @@ -210,7 +256,10 @@ void Client::DirectStreamCallbacks::onComplete() { } else { http_client_.stats().stream_failure_.inc(); } - bridge_callbacks_.on_complete(streamIntel(), bridge_callbacks_.context); + + envoy_final_stream_intel final_intel; + setFinalStreamIntel(final_intel); + bridge_callbacks_.on_complete(streamIntel(), final_intel, bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onError() { @@ -237,7 +286,9 @@ void Client::DirectStreamCallbacks::onError() { direct_stream_.stream_handle_); http_client_.stats().stream_failure_.inc(); - bridge_callbacks_.on_error(error_.value(), streamIntel(), bridge_callbacks_.context); + envoy_final_stream_intel final_intel; + setFinalStreamIntel(final_intel); + bridge_callbacks_.on_error(error_.value(), streamIntel(), final_intel, bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onSendWindowAvailable() { @@ -247,9 +298,12 @@ void Client::DirectStreamCallbacks::onSendWindowAvailable() { void Client::DirectStreamCallbacks::onCancel() { ScopeTrackerScopeState scope(&direct_stream_, http_client_.scopeTracker()); + ENVOY_LOG(debug, "[S{}] dispatching to platform cancel stream", direct_stream_.stream_handle_); http_client_.stats().stream_cancel_.inc(); - bridge_callbacks_.on_cancel(streamIntel(), bridge_callbacks_.context); + envoy_final_stream_intel final_intel; + setFinalStreamIntel(final_intel); + bridge_callbacks_.on_cancel(streamIntel(), final_intel, bridge_callbacks_.context); } void Client::DirectStreamCallbacks::onHasBufferedData() { @@ -336,6 +390,7 @@ void Client::DirectStream::resetStream(StreamResetReason reason) { // This seems in line with other codec implementations, and so the assumption is that this is in // line with upstream expectations. // TODO(goaway): explore an upstream fix to get the HCM to clean up ActiveStream itself. + saveFinalStreamIntel(); runResetCallbacks(reason); if (!parent_.getStream(stream_handle_, GetStreamFilters::ALLOW_FOR_ALL_STREAMS)) { // We don't assert here, because Envoy will issue a stream reset if a stream closes remotely diff --git a/library/common/http/client.h b/library/common/http/client.h index 10f1ff146a..7029224ae1 100644 --- a/library/common/http/client.h +++ b/library/common/http/client.h @@ -37,6 +37,17 @@ struct HttpClientStats { ALL_HTTP_CLIENT_STATS(GENERATE_COUNTER_STRUCT) }; +struct LatencyInfo { + long request_start_ms = 0; + long request_end_ms = 0; + long dns_start_ms = 0; + long dns_end_ms = 0; + long sent_byte_count = 0; + long received_byte_count = 0; + // Latest latency info received from StreamInfo. + std::shared_ptr upstream_info_{}; +}; + /** * Manages HTTP streams, and provides an interface to interact with them. */ @@ -166,6 +177,8 @@ class Client : public Logger::Loggable { // than bytes_to_send. void resumeData(int32_t bytes_to_send); + void setFinalStreamIntel(envoy_final_stream_intel& final_intel); + private: bool hasBufferedData() { return response_data_.get() && response_data_->length() != 0; } @@ -241,9 +254,12 @@ class Client : public Logger::Loggable { response_details_ = response_details; } - // Saves latest "Intel" data as it may not be available when accessed. + // Latches stream information as it may not be available when accessed. void saveLatestStreamIntel(); + // Latches latency info from stream info before it goes away. + void saveFinalStreamIntel(); + const envoy_stream_t stream_handle_; // Used to issue outgoing HTTP stream operations. diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index 8fc8309831..c036ebf78e 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -665,40 +665,62 @@ jvm_http_filter_on_resume_response(envoy_headers* headers, envoy_data* data, stream_intel, context); } -static void* jvm_on_complete(envoy_stream_intel, void* context) { - jni_delete_global_ref(context); - return NULL; +static void* call_jvm_on_complete(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + jni_log("[Envoy]", "jvm_on_complete"); + + JNIEnv* env = get_env(); + jobject j_context = static_cast(context); + + jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); + jmethodID jmid_onComplete = + env->GetMethodID(jcls_JvmObserverContext, "onComplete", "([J[J)Ljava/lang/Object;"); + + jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); + jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); + jobject result = + env->CallObjectMethod(j_context, jmid_onComplete, j_stream_intel, j_final_stream_intel); + + env->DeleteLocalRef(j_stream_intel); + env->DeleteLocalRef(j_final_stream_intel); + env->DeleteLocalRef(jcls_JvmObserverContext); + return result; } -static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, void* context) { +static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_error"); JNIEnv* env = get_env(); jobject j_context = static_cast(context); jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); jmethodID jmid_onError = - env->GetMethodID(jcls_JvmObserverContext, "onError", "(I[BI[J)Ljava/lang/Object;"); + env->GetMethodID(jcls_JvmObserverContext, "onError", "(I[BI[J[J)Ljava/lang/Object;"); jbyteArray j_error_message = native_data_to_array(env, error.message); jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); + jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); jobject result = env->CallObjectMethod(j_context, jmid_onError, error.error_code, j_error_message, - error.attempt_count, j_stream_intel); + error.attempt_count, j_stream_intel, j_final_stream_intel); env->DeleteLocalRef(j_stream_intel); + env->DeleteLocalRef(j_final_stream_intel); env->DeleteLocalRef(j_error_message); env->DeleteLocalRef(jcls_JvmObserverContext); release_envoy_error(error); return result; } -static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, void* context) { - void* result = call_jvm_on_error(error, stream_intel, context); +static void* jvm_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + void* result = call_jvm_on_error(error, stream_intel, final_stream_intel, context); jni_delete_global_ref(context); return result; } -static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, void* context) { +static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { jni_log("[Envoy]", "jvm_on_cancel"); JNIEnv* env = get_env(); @@ -706,30 +728,44 @@ static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, void* context) jclass jcls_JvmObserverContext = env->GetObjectClass(j_context); jmethodID jmid_onCancel = - env->GetMethodID(jcls_JvmObserverContext, "onCancel", "([J)Ljava/lang/Object;"); + env->GetMethodID(jcls_JvmObserverContext, "onCancel", "([J[J)Ljava/lang/Object;"); jlongArray j_stream_intel = native_stream_intel_to_array(env, stream_intel); + jlongArray j_final_stream_intel = native_final_stream_intel_to_array(env, final_stream_intel); - jobject result = env->CallObjectMethod(j_context, jmid_onCancel, j_stream_intel); + jobject result = + env->CallObjectMethod(j_context, jmid_onCancel, j_stream_intel, j_final_stream_intel); env->DeleteLocalRef(j_stream_intel); + env->DeleteLocalRef(j_final_stream_intel); env->DeleteLocalRef(jcls_JvmObserverContext); return result; } -static void* jvm_on_cancel(envoy_stream_intel stream_intel, void* context) { - void* result = call_jvm_on_cancel(stream_intel, context); +static void* jvm_on_complete(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + void* result = call_jvm_on_complete(stream_intel, final_stream_intel, context); + jni_delete_global_ref(context); + return result; +} + +static void* jvm_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context) { + void* result = call_jvm_on_cancel(stream_intel, final_stream_intel, context); jni_delete_global_ref(context); return result; } static void jvm_http_filter_on_error(envoy_error error, envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, const void* context) { - call_jvm_on_error(error, stream_intel, const_cast(context)); + call_jvm_on_error(error, stream_intel, final_stream_intel, const_cast(context)); } -static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, const void* context) { - call_jvm_on_cancel(stream_intel, const_cast(context)); +static void jvm_http_filter_on_cancel(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, + const void* context) { + call_jvm_on_cancel(stream_intel, final_stream_intel, const_cast(context)); } static void* jvm_on_send_window_available(envoy_stream_intel stream_intel, void* context) { diff --git a/library/common/jni/jni_utility.cc b/library/common/jni/jni_utility.cc index ccb970c722..7362673d59 100644 --- a/library/common/jni/jni_utility.cc +++ b/library/common/jni/jni_utility.cc @@ -97,6 +97,33 @@ jlongArray native_stream_intel_to_array(JNIEnv* env, envoy_stream_intel stream_i return j_array; } +jlongArray native_final_stream_intel_to_array(JNIEnv* env, + envoy_final_stream_intel final_stream_intel) { + jlongArray j_array = env->NewLongArray(14); + jlong* critical_array = static_cast(env->GetPrimitiveArrayCritical(j_array, nullptr)); + RELEASE_ASSERT(critical_array != nullptr, "unable to allocate memory in jni_utility"); + + critical_array[0] = static_cast(final_stream_intel.request_start_ms); + critical_array[1] = static_cast(final_stream_intel.dns_start_ms); + critical_array[2] = static_cast(final_stream_intel.dns_end_ms); + critical_array[3] = static_cast(final_stream_intel.connect_start_ms); + critical_array[4] = static_cast(final_stream_intel.connect_end_ms); + critical_array[5] = static_cast(final_stream_intel.ssl_start_ms); + critical_array[6] = static_cast(final_stream_intel.ssl_end_ms); + critical_array[7] = static_cast(final_stream_intel.sending_start_ms); + critical_array[8] = static_cast(final_stream_intel.sending_end_ms); + critical_array[9] = static_cast(final_stream_intel.response_start_ms); + critical_array[10] = static_cast(final_stream_intel.request_end_ms); + critical_array[11] = static_cast(final_stream_intel.socket_reused); + critical_array[12] = static_cast(final_stream_intel.sent_byte_count); + critical_array[13] = static_cast(final_stream_intel.received_byte_count); + + // Here '0' (for which there is no named constant) indicates we want to commit the changes back + // to the JVM and free the c array, where applicable. + env->ReleasePrimitiveArrayCritical(j_array, critical_array, 0); + return j_array; +} + jobject native_map_to_map(JNIEnv* env, envoy_map map) { jclass jcls_hashMap = env->FindClass("java/util/HashMap"); jmethodID jmid_hashMapInit = env->GetMethodID(jcls_hashMap, "", "(I)V"); diff --git a/library/common/jni/jni_utility.h b/library/common/jni/jni_utility.h index 908e247c8f..f75529a3a5 100644 --- a/library/common/jni/jni_utility.h +++ b/library/common/jni/jni_utility.h @@ -35,6 +35,9 @@ jbyteArray native_data_to_array(JNIEnv* env, envoy_data data); jlongArray native_stream_intel_to_array(JNIEnv* env, envoy_stream_intel stream_intel); +jlongArray native_final_stream_intel_to_array(JNIEnv* env, + envoy_final_stream_intel final_stream_intel); + /** * Utility function that copies envoy_map to a java HashMap jobject. * diff --git a/library/common/types/c_types.h b/library/common/types/c_types.h index 318a0f0af7..417a1872aa 100644 --- a/library/common/types/c_types.h +++ b/library/common/types/c_types.h @@ -141,7 +141,8 @@ typedef struct { } envoy_error; /** - * Contains internal HTTP stream metrics, context, and other details. + * Contains internal HTTP stream metrics, context, and other details which are + * sent with most callbacks. * * Note these values may change over the lifecycle of a stream. */ @@ -154,6 +155,44 @@ typedef struct { uint64_t attempt_count; } envoy_stream_intel; +/** + * Contains internal HTTP stream metrics which sent at stream end. + */ +typedef struct { + // The time the request started, in ms since the epoch. + uint64_t request_start_ms; + // The time the DNS resolution for this request started, in ms since the epoch. + uint64_t dns_start_ms; + // The time the DNS resolution for this request completed, in ms since the epoch. + uint64_t dns_end_ms; + // The time the upstream connection started, in ms since the epoch. + // This may not be set if socket_reused is false. + uint64_t connect_start_ms; + // The time the upstream connection completed, in ms since the epoch. + // This may not be set if socket_reused is false. + uint64_t connect_end_ms; + // The time the SSL handshake started, in ms since the epoch. + // This may not be set if socket_reused is false. + uint64_t ssl_start_ms; + // The time the SSL handshake completed, in ms since the epoch. + // This may not be set if socket_reused is false. + uint64_t ssl_end_ms; + // The time the first byte of the request was sent upstream, in ms since the epoch. + uint64_t sending_start_ms; + // The time the last byte of the request was sent upstream, in ms since the epoch. + uint64_t sending_end_ms; + // The time the first byte of the response was received, in ms since the epoch. + uint64_t response_start_ms; + // The time the last byte of the request was received, in ms since the epoch. + uint64_t request_end_ms; + // True if the upstream socket had been used previously. + uint64_t socket_reused; + // The number of bytes sent upstream. + uint64_t sent_byte_count; + // The number of bytes received from upstream. + uint64_t received_byte_count; +} envoy_final_stream_intel; + #ifdef __cplusplus extern "C" { // utility functions #endif @@ -298,12 +337,13 @@ typedef void* (*envoy_on_trailers_f)(envoy_headers trailers, envoy_stream_intel * * @param envoy_error, the error received/caused by the async HTTP stream. * @param stream_intel, contains internal stream metrics, context, and other details. + * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_intel, - void* context); + envoy_final_stream_intel final_stream_intel, void* context); /** * Callback signature for when an HTTP stream bi-directionally completes without error. @@ -311,11 +351,13 @@ typedef void* (*envoy_on_error_f)(envoy_error error, envoy_stream_intel stream_i * This is a TERMINAL callback. Exactly one terminal callback will be called per stream. * * @param stream_intel, contains internal stream metrics, context, and other details. + * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, void* context); +typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context); /** * Callback signature for when an HTTP stream is cancelled. @@ -323,11 +365,13 @@ typedef void* (*envoy_on_complete_f)(envoy_stream_intel stream_intel, void* cont * This is a TERMINAL callback. Exactly one terminal callback will be called per stream. * * @param stream_intel, contains internal stream metrics, context, and other details. + * @param final_stream_intel, contains final internal stream metrics, context, and other details. * @param context, contains the necessary state to carry out platform-specific dispatch and * execution. * @return void*, return context (may be unused). */ -typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, void* context); +typedef void* (*envoy_on_cancel_f)(envoy_stream_intel stream_intel, + envoy_final_stream_intel final_stream_intel, void* context); /** * Called when the envoy engine is exiting. diff --git a/library/java/io/envoyproxy/envoymobile/engine/BUILD b/library/java/io/envoyproxy/envoymobile/engine/BUILD index 7fbf08cf5f..3b0f29c85e 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/BUILD +++ b/library/java/io/envoyproxy/envoymobile/engine/BUILD @@ -25,6 +25,7 @@ java_library( "EnvoyConfiguration.java", "EnvoyEngine.java", "EnvoyEngineImpl.java", + "EnvoyFinalStreamIntelImpl.java", "EnvoyHTTPFilterCallbacksImpl.java", "EnvoyHTTPStream.java", "EnvoyNativeFilterConfig.java", diff --git a/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java b/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java new file mode 100644 index 0000000000..050cede043 --- /dev/null +++ b/library/java/io/envoyproxy/envoymobile/engine/EnvoyFinalStreamIntelImpl.java @@ -0,0 +1,94 @@ +package io.envoyproxy.envoymobile.engine; + +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel; + +class EnvoyFinalStreamIntelImpl implements EnvoyFinalStreamIntel { + private long requestStartMs; + private long dnsStartMs; + private long dnsEndMs; + private long connectStartMs; + private long connectEndMs; + private long sslStartMs; + private long sslEndMs; + private long sendingStartMs; + private long sendingEndMs; + private long responseStartMs; + private long requestEndMs; + private boolean socketReused; + private long sentByteCount; + private long receivedByteCount; + + EnvoyFinalStreamIntelImpl(long[] values) { + requestStartMs = values[0]; + dnsStartMs = values[1]; + dnsEndMs = values[2]; + connectStartMs = values[3]; + connectEndMs = values[4]; + sslStartMs = values[5]; + sslEndMs = values[6]; + sendingStartMs = values[7]; + sendingEndMs = values[8]; + responseStartMs = values[9]; + requestEndMs = values[10]; + socketReused = values[11] != 0; + sentByteCount = values[12]; + receivedByteCount = values[13]; + } + + @Override + public long getRequestStartMs() { + return requestStartMs; + } + @Override + public long getDnsStartMs() { + return dnsStartMs; + } + @Override + public long getDnsEndMs() { + return dnsEndMs; + } + @Override + public long getConnectStartMs() { + return connectStartMs; + } + @Override + public long getConnectEndMs() { + return connectEndMs; + } + @Override + public long getSslStartMs() { + return sslStartMs; + } + @Override + public long getSslEndMs() { + return sslEndMs; + } + @Override + public long getSendingStartMs() { + return sendingStartMs; + } + @Override + public long getSendingEndMs() { + return sendingEndMs; + } + @Override + public long getResponseStartMs() { + return responseStartMs; + } + @Override + public long getRequestEndMs() { + return requestEndMs; + } + @Override + public boolean getSocketReused() { + return socketReused; + } + @Override + public long getSentByteCount() { + return sentByteCount; + } + @Override + public long getReceivedByteCount() { + return receivedByteCount; + } +} diff --git a/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java b/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java index b93ab7f390..e37972fd3b 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JvmCallbackContext.java @@ -90,18 +90,22 @@ public void run() { /** * Dispatches error received from the JNI layer up to the platform. * - * @param errorCode, the error code. - * @param message, the error message. - * @param attemptCount, the number of times an operation was attempted before firing this error. - * @param streamIntel, internal HTTP stream metrics, context, and other details. - * @return Object, not used for response callbacks. + * @param errorCode, the error code. + * @param message, the error message. + * @param attemptCount, the number of times an operation was attempted before firing this + * error. + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. + * @return Object, not used for response callbacks. */ - public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel) { + public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel, + long[] finalStreamIntel) { callbacks.getExecutor().execute(new Runnable() { public void run() { String errorMessage = new String(message); callbacks.onError(errorCode, errorMessage, attemptCount, - new EnvoyStreamIntelImpl(streamIntel)); + new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); } }); @@ -111,14 +115,16 @@ public void run() { /** * Dispatches cancellation notice up to the platform * - * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. * @return Object, not used for response callbacks. */ - public Object onCancel(long[] streamIntel) { + public Object onCancel(long[] streamIntel, long[] finalStreamIntel) { callbacks.getExecutor().execute(new Runnable() { public void run() { // This call is atomically gated at the call-site and will only happen once. - callbacks.onCancel(new EnvoyStreamIntelImpl(streamIntel)); + callbacks.onCancel(new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); } }); @@ -139,6 +145,24 @@ public void run() { } }); + return null; + } + /** + * Called with all stream metrics after the final headers/data/trailers call. + * + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics for the end of stream. + * @return Object, not used for response callbacks. + */ + public Object onComplete(long[] streamIntel, long[] finalStreamIntel) { + callbacks.getExecutor().execute(new Runnable() { + public void run() { + // This call is atomically gated at the call-site and will only happen once. + callbacks.onComplete(new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + } + }); + return null; } } diff --git a/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java b/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java index e334a4af34..4c1921ce26 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java +++ b/library/java/io/envoyproxy/envoymobile/engine/JvmFilterContext.java @@ -211,22 +211,40 @@ public void setResponseFilterCallbacks(long callbackHandle) { * @param message, the error message. * @param attemptCount, the number of times an operation was attempted before firing this error. * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. * @return Object, not used in HTTP filters. */ - public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel) { + public Object onError(int errorCode, byte[] message, int attemptCount, long[] streamIntel, + long[] finalStreamIntel) { String errorMessage = new String(message); - filter.onError(errorCode, errorMessage, attemptCount, new EnvoyStreamIntelImpl(streamIntel)); + filter.onError(errorCode, errorMessage, attemptCount, new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); return null; } /** * Dispatches cancellation notice up to the platform. * - * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. + * @return Object, not used in HTTP filters. + */ + public Object onCancel(long[] streamIntel, long[] finalStreamIntel) { + filter.onCancel(new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); + return null; + } + + /** + * Dispatches stream completion notice up to the platform. + * + * @param streamIntel, internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, final internal HTTP stream metrics, context, and other details. * @return Object, not used in HTTP filters. */ - public Object onCancel(long[] streamIntel) { - filter.onCancel(new EnvoyStreamIntelImpl(streamIntel)); + public Object onComplete(long[] streamIntel, long[] finalStreamIntel) { + filter.onComplete(new EnvoyStreamIntelImpl(streamIntel), + new EnvoyFinalStreamIntelImpl(finalStreamIntel)); return null; } diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/BUILD b/library/java/io/envoyproxy/envoymobile/engine/types/BUILD index 0bb2abbc90..3a0010dd53 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/BUILD +++ b/library/java/io/envoyproxy/envoymobile/engine/types/BUILD @@ -6,6 +6,7 @@ java_library( name = "envoy_c_types_lib", srcs = [ "EnvoyEventTracker.java", + "EnvoyFinalStreamIntel.java", "EnvoyHTTPCallbacks.java", "EnvoyHTTPFilter.java", "EnvoyHTTPFilterCallbacks.java", diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java new file mode 100644 index 0000000000..4936176a56 --- /dev/null +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyFinalStreamIntel.java @@ -0,0 +1,67 @@ +package io.envoyproxy.envoymobile.engine.types; + +/** + * Exposes internal HTTP stream metrics, context, and other details sent once on stream end. + */ +public interface EnvoyFinalStreamIntel { + /* + * The time the request started, in ms since the epoch. + */ + public long getRequestStartMs(); + /* + * The time the DNS resolution for this request started, in ms since the epoch. + */ + public long getDnsStartMs(); + /* + * The time the DNS resolution for this request completed, in ms since the epoch. + */ + public long getDnsEndMs(); + /* + * The time the upstream connection started, in ms since the epoch. + * This may not be set if socket_reused is false. + */ + public long getConnectStartMs(); + /* + * The time the upstream connection completed, in ms since the epoch. + * This may not be set if socket_reused is false. + */ + public long getConnectEndMs(); + /* + * The time the SSL handshake started, in ms since the epoch. + * This may not be set if socket_reused is false. + */ + public long getSslStartMs(); + /* + * The time the SSL handshake completed, in ms since the epoch. + * This may not be set if socket_reused is false. + */ + public long getSslEndMs(); + /* + * The time the first byte of the request was sent upstream, in ms since the epoch. + */ + public long getSendingStartMs(); + /* + * The time the last byte of the request was sent upstream, in ms since the epoch. + */ + public long getSendingEndMs(); + /* + * The time the first byte of the response was received, in ms since the epoch. + */ + public long getResponseStartMs(); + /* + * The time the last byte of the request was received, in ms since the epoch. + */ + public long getRequestEndMs(); + /* + * True if the upstream socket had been used previously. + */ + public boolean getSocketReused(); + /* + * The number of bytes sent upstream. + */ + public long getSentByteCount(); + /* + * The number of bytes received from upstream. + */ + public long getReceivedByteCount(); +} diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java index 8f7aa15847..eef91e1413 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPCallbacks.java @@ -48,13 +48,19 @@ void onHeaders(Map> headers, boolean endStream, * count for an error. This is different from 0, which intentionally conveys * that the action was _not_ executed. * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. */ - void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel); + void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel, + EnvoyFinalStreamIntel finalStreamIntel); /** * Called when the async HTTP stream is canceled. + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. */ - void onCancel(EnvoyStreamIntel streamIntel); + void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel); /** * Callback signature which notify when there is buffer available for request body upload. @@ -66,4 +72,12 @@ void onHeaders(Map> headers, boolean endStream, * @param streamIntel, contains internal HTTP stream metrics, context, and other details. */ void onSendWindowAvailable(EnvoyStreamIntel streamIntel); + + /** + * Called once after the final data for the stream has been received. + * + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics. + */ + void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel); } diff --git a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java index f94e89362d..17ba29d651 100644 --- a/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java +++ b/library/java/io/envoyproxy/envoymobile/engine/types/EnvoyHTTPFilter.java @@ -110,13 +110,27 @@ Object[] onResumeResponse(Map> headers, ByteBuffer data, * count for an error. This is different from 0, which intentionally conveys * that the action was _not_ executed. * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. */ - void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel); + void onError(int errorCode, String message, int attemptCount, EnvoyStreamIntel streamIntel, + EnvoyFinalStreamIntel finalStreamIntel); /** * Called when the async HTTP stream is canceled. * - * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. + */ + void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalSteamIntel); + + /** + * Called when the async HTTP stream is complete. + * + * @param streamIntel, contains internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel, contains final internal HTTP stream metrics, context, and other + * details. */ - void onCancel(EnvoyStreamIntel streamIntel); + void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalSteamIntel); } diff --git a/library/java/org/chromium/net/impl/CronetUrlRequest.java b/library/java/org/chromium/net/impl/CronetUrlRequest.java index 259fce4665..c02e3d0d28 100644 --- a/library/java/org/chromium/net/impl/CronetUrlRequest.java +++ b/library/java/org/chromium/net/impl/CronetUrlRequest.java @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.engine.EnvoyHTTPStream; import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks; import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel; +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.MalformedURLException; @@ -771,7 +772,7 @@ public void onTrailers(Map> trailers, EnvoyStreamIntel stre @Override public void onError(int errorCode, String message, int attemptCount, - EnvoyStreamIntel streamIntel) { + EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) { if (isAbandoned()) { return; } @@ -793,7 +794,7 @@ public void onError(int errorCode, String message, int attemptCount, } @Override - public void onCancel(EnvoyStreamIntel streamIntel) { + public void onCancel(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) { if (isAbandoned()) { return; } @@ -833,6 +834,9 @@ public void onSendWindowAvailable(EnvoyStreamIntel streamIntel) { mUploadDataStream.readDataReady(); // Have the next request body chunk to be sent. } + @Override + public void onComplete(EnvoyStreamIntel streamIntel, EnvoyFinalStreamIntel finalStreamIntel) {} + /** * Sends one chunk of the request body if the state permits. This method is not re-entrant, but * by contract this method can only be invoked once for the first chunk, and then once per diff --git a/library/kotlin/io/envoyproxy/envoymobile/BUILD b/library/kotlin/io/envoyproxy/envoymobile/BUILD index e28ae2863c..66d5c9f271 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/BUILD +++ b/library/kotlin/io/envoyproxy/envoymobile/BUILD @@ -61,6 +61,7 @@ envoy_mobile_kt_library( "StreamClient.kt", "StreamClientImpl.kt", "StreamIntel.kt", + "FinalStreamIntel.kt", "StreamPrototype.kt", "StringAccessor.kt", "Trailers.kt", diff --git a/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt b/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt new file mode 100644 index 0000000000..5375146578 --- /dev/null +++ b/library/kotlin/io/envoyproxy/envoymobile/FinalStreamIntel.kt @@ -0,0 +1,57 @@ +package io.envoyproxy.envoymobile + +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel + +/** + * Exposes one time HTTP stream metrics, context, and other details. + * @param requestStartMs The time the request started, in ms since the epoch. + * @param dnsStartMs The time the DNS resolution for this request started, in ms since the epoch. + * @param dnsEndMs The time the DNS resolution for this request completed, in ms since the epoch. + * @param connectStartMsThe time the upstream connection started, in ms since the epoch. + * This may not be set if socket_reused is false. + * @param connectEndMs The time the upstream connection completed, in ms since the epoch. + * This may not be set if socket_reused is false. + * @param sslStartMs The time the SSL handshake started, in ms since the epoch. + * This may not be set if socket_reused is false. + * @param sslEndMs The time the SSL handshake completed, in ms since the epoch. + * This may not be set if socket_reused is false. + * @param sendingStartMs The time the first byte of the request was sent upstream, + * in ms since the epoch. + * @param sendingEndMs The time the last byte of the request was sent upstream, in ms since the + * epoch. + * @param responseStartMs The time the first byte of the response was received, in ms since the + * epoch. + * @param @param requestEndMs The time the last byte of the request was received, in ms since the + * epoch. + * @param socket_reused True if the upstream socket had been used previously. + * @param sentByteCount The number of bytes sent upstream. + * @param receivedByteCount The number of bytes received from upstream. + */ +@Suppress("LongParameterList") +class FinalStreamIntel constructor( + val requestStartMs: Long, + val dnsStartMs: Long, + val dnsEndMs: Long, + val connectStartMs: Long, + val connectEndMs: Long, + val sslStartMs: Long, + val sslEndMs: Long, + val sendingStartMs: Long, + val sendingEndMs: Long, + val responseStartMs: Long, + val requestEndMs: Long, + val socketReused: Boolean, + val sentByteCount: Long, + val receivedByteCount: Long +) { + constructor(base: EnvoyFinalStreamIntel) : this( + base.requestStartMs, base.dnsStartMs, + base.dnsEndMs, base.connectStartMs, + base.connectEndMs, base.sslStartMs, + base.sslEndMs, base.sendingStartMs, + base.sendingEndMs, + base.responseStartMs, base.requestEndMs, + base.socketReused, base.sentByteCount, + base.receivedByteCount + ) +} diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt index 67fcf84dbe..43e3251a9d 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamCallbacks.kt @@ -1,5 +1,6 @@ package io.envoyproxy.envoymobile +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPCallbacks import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel import java.nio.ByteBuffer @@ -17,9 +18,12 @@ internal class StreamCallbacks { )? = null var onData: ((data: ByteBuffer, endStream: Boolean, streamIntel: StreamIntel) -> Unit)? = null var onTrailers: ((trailers: ResponseTrailers, streamIntel: StreamIntel) -> Unit)? = null - var onCancel: ((streamIntel: StreamIntel) -> Unit)? = null - var onError: ((error: EnvoyError, streamIntel: StreamIntel) -> Unit)? = null + var onCancel: ((streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit)? = null + var onError: ( + (error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + )? = null var onSendWindowAvailable: ((streamIntel: StreamIntel) -> Unit)? = null + var onComplete: ((streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit)? = null } /** @@ -54,19 +58,25 @@ internal class EnvoyHTTPCallbacksAdapter( errorCode: Int, message: String, attemptCount: Int, - streamIntel: EnvoyStreamIntel + streamIntel: EnvoyStreamIntel, + finalStreamIntel: EnvoyFinalStreamIntel ) { callbacks.onError?.invoke( EnvoyError(errorCode, message, attemptCount), - StreamIntel(streamIntel) + StreamIntel(streamIntel), + FinalStreamIntel(finalStreamIntel) ) } - override fun onCancel(streamIntel: EnvoyStreamIntel) { - callbacks.onCancel?.invoke(StreamIntel(streamIntel)) + override fun onCancel(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + callbacks.onCancel?.invoke(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) } override fun onSendWindowAvailable(streamIntel: EnvoyStreamIntel) { callbacks.onSendWindowAvailable?.invoke(StreamIntel(streamIntel)) } + + override fun onComplete(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + callbacks.onComplete?.invoke(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + } } diff --git a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt index f7fb49745d..863e3e009c 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/StreamPrototype.kt @@ -25,7 +25,10 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return The new stream. */ open fun start(executor: Executor = Executors.newSingleThreadExecutor()): Stream { - val engineStream = engine.startStream(createCallbacks(executor), explicitFlowControl) + val engineStream = engine.startStream( + createCallbacks(executor), + explicitFlowControl + ) return Stream(engineStream, useByteBufferPosition) } @@ -107,12 +110,30 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return This stream, for chaining syntax. */ fun setOnError( - closure: (error: EnvoyError, streamIntel: StreamIntel) -> Unit + closure: ( + error: EnvoyError, + streamIntel: StreamIntel, + finalStreamIntel: FinalStreamIntel + ) -> Unit ): StreamPrototype { callbacks.onError = closure return this } +/** + * Specify a callback for when a stream is complete. + * If the closure is called, the stream is complete. + * + * @param closure Closure which will be called when an error occurs. + * @return This stream, for chaining syntax. + */ + fun setOnComplete( + closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit + ): StreamPrototype { + callbacks.onComplete = closure + return this + } + /** * Specify a callback for when the stream is canceled. * If the closure is called, the stream is complete. @@ -121,7 +142,7 @@ open class StreamPrototype(private val engine: EnvoyEngine) { * @return This stream, for chaining syntax. */ fun setOnCancel( - closure: (streamIntel: StreamIntel) -> Unit + closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit ): StreamPrototype { callbacks.onCancel = closure return this diff --git a/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt b/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt index 02ab7a5e24..1741b85f2b 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/filters/Filter.kt @@ -1,5 +1,6 @@ package io.envoyproxy.envoymobile +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilter import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterCallbacks import io.envoyproxy.envoymobile.engine.types.EnvoyHTTPFilterFactory @@ -99,15 +100,21 @@ internal class EnvoyHTTPFilterAdapter( return arrayOf(0, trailers) } - override fun onError(errorCode: Int, message: String, attemptCount: Int, streamIntel: EnvoyStreamIntel) { + override fun onError(errorCode: Int, message: String, attemptCount: Int, streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onError(EnvoyError(errorCode, message, attemptCount), StreamIntel(streamIntel)) + responseFilter.onError(EnvoyError(errorCode, message, attemptCount), StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) } } - override fun onCancel(streamIntel: EnvoyStreamIntel) { + override fun onCancel(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { (filter as? ResponseFilter)?.let { responseFilter -> - responseFilter.onCancel(StreamIntel(streamIntel)) + responseFilter.onCancel(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) + } + } + + override fun onComplete(streamIntel: EnvoyStreamIntel, finalStreamIntel: EnvoyFinalStreamIntel) { + (filter as? ResponseFilter)?.let { responseFilter -> + responseFilter.onComplete(StreamIntel(streamIntel), FinalStreamIntel(finalStreamIntel)) } } diff --git a/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt b/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt index 2c025164ce..c8dbcf7b6e 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/filters/ResponseFilter.kt @@ -55,8 +55,9 @@ interface ResponseFilter : Filter { * * @param error: The error that occurred within Envoy. * @param streamIntel: Internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. */ - fun onError(error: EnvoyError, streamIntel: StreamIntel) + fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) /** * Called at most once when the client cancels the stream. @@ -65,6 +66,18 @@ interface ResponseFilter : Filter { * `stopIteration{...}`. * * @param streamIntel: Internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. */ - fun onCancel(streamIntel: StreamIntel) + fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) + +/** + * Called at most once when the stream is complete. + * + * This should be considered a terminal state, and invalidates any previous attempts to + * `stopIteration{...}`. + * + * @param streamIntel: Internal HTTP stream metrics, context, and other details. + * @param finalStreamIntel: Final internal HTTP stream metrics, context, and other details. + */ + fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) } diff --git a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt index 87aafbdc12..78618658af 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt @@ -89,7 +89,7 @@ class GRPCStreamPrototype( * @return This stream, for chaining syntax. */ fun setOnError( - closure: (error: EnvoyError, streamIntel: StreamIntel) -> Unit + closure: (error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit ): GRPCStreamPrototype { underlyingStream.setOnError(closure) return this @@ -103,7 +103,7 @@ class GRPCStreamPrototype( * @return This stream, for chaining syntax. */ fun setOnCancel( - closure: (streamIntel: StreamIntel) -> Unit + closure: (streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) -> Unit ): GRPCStreamPrototype { underlyingStream.setOnCancel(closure) return this diff --git a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt index b85cf0c8fd..7f326d22ab 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/mocks/MockStream.kt @@ -1,5 +1,6 @@ package io.envoyproxy.envoymobile +import io.envoyproxy.envoymobile.engine.types.EnvoyFinalStreamIntel import io.envoyproxy.envoymobile.engine.types.EnvoyStreamIntel import java.nio.ByteBuffer @@ -16,6 +17,22 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S override fun getAttemptCount(): Long { return 0 } } + private val mockFinalStreamIntel = object : EnvoyFinalStreamIntel { + override fun getRequestStartMs(): Long { return 0 } + override fun getDnsStartMs(): Long { return 0 } + override fun getDnsEndMs(): Long { return 0 } + override fun getConnectStartMs(): Long { return 0 } + override fun getConnectEndMs(): Long { return 0 } + override fun getSslStartMs(): Long { return 0 } + override fun getSslEndMs(): Long { return 0 } + override fun getSendingStartMs(): Long { return 0 } + override fun getSendingEndMs(): Long { return 0 } + override fun getResponseStartMs(): Long { return 0 } + override fun getRequestEndMs(): Long { return 0 } + override fun getSocketReused(): Boolean { return false } + override fun getSentByteCount(): Long { return 0 } + override fun getReceivedByteCount(): Long { return 0 } + } /** * Closure that will be called when request headers are sent. */ @@ -88,7 +105,7 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S * Simulate the stream receiving a cancellation signal from Envoy. */ fun receiveCancel() { - mockStream.callbacks.onCancel(mockStreamIntel) + mockStream.callbacks.onCancel(mockStreamIntel, mockFinalStreamIntel) } /** @@ -97,6 +114,6 @@ class MockStream internal constructor(underlyingStream: MockEnvoyHTTPStream) : S * @param error The error to receive. */ fun receiveError(error: EnvoyError) { - mockStream.callbacks.onError(error.errorCode, error.message, error.attemptCount ?: 0, mockStreamIntel) + mockStream.callbacks.onError(error.errorCode, error.message, error.attemptCount ?: 0, mockStreamIntel, mockFinalStreamIntel) } } diff --git a/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc b/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc index 801e4cea4e..8ed9a651c3 100644 --- a/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc +++ b/test/common/extensions/filters/http/platform_bridge/platform_bridge_filter_test.cc @@ -676,7 +676,7 @@ TEST_F(PlatformBridgeFilterTest, BasicError) { release_envoy_data(c_data); return {kEnvoyFilterDataStatusStopIterationNoBuffer, envoy_nodata, nullptr}; }; - platform_filter.on_error = [](envoy_error c_error, envoy_stream_intel, + platform_filter.on_error = [](envoy_error c_error, envoy_stream_intel, envoy_final_stream_intel, const void* context) -> void { filter_invocations* invocations = static_cast(const_cast(context)); invocations->on_error_calls++; diff --git a/test/common/http/client_test.cc b/test/common/http/client_test.cc index 1b624b6608..33f6467ef0 100644 --- a/test/common/http/client_test.cc +++ b/test/common/http/client_test.cc @@ -63,7 +63,8 @@ class ClientTest : public testing::TestWithParam { bridge_callbacks_.context = &cc_; // Set up default bridge callbacks. Indivividual tests can override. - bridge_callbacks_.on_complete = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; return nullptr; @@ -77,7 +78,8 @@ class ClientTest : public testing::TestWithParam { cc->on_headers_calls++; return nullptr; }; - bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error, envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_error_calls++; return nullptr; @@ -90,7 +92,8 @@ class ClientTest : public testing::TestWithParam { release_envoy_data(c_data); return nullptr; }; - bridge_callbacks_.on_cancel = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_cancel = [](envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_cancel_calls++; return nullptr; @@ -453,7 +456,8 @@ TEST_P(ClientTest, MultipleStreams) { *on_headers_called2 = true; return nullptr; }; - bridge_callbacks_2.on_complete = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_2.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc = static_cast(context); cc->on_complete_calls++; return nullptr; @@ -502,7 +506,8 @@ TEST_P(ClientTest, MultipleStreams) { TEST_P(ClientTest, EnvoyLocalError) { // Override the on_error default with some custom checks. - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { EXPECT_EQ(error.error_code, ENVOY_CONNECTION_FAILURE); EXPECT_EQ(error.attempt_count, 123); callbacks_called* cc = static_cast(context); @@ -575,7 +580,8 @@ TEST_P(ClientTest, DoubleResetStreamLocal) { TEST_P(ClientTest, RemoteResetAfterStreamStart) { cc_.end_stream_with_headers_ = false; - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { EXPECT_EQ(error.error_code, ENVOY_STREAM_RESET); EXPECT_EQ(error.message.length, 0); EXPECT_EQ(error.attempt_count, 0); diff --git a/test/common/integration/client_integration_test.cc b/test/common/integration/client_integration_test.cc index 89b49a92b7..6e104cd2bb 100644 --- a/test/common/integration/client_integration_test.cc +++ b/test/common/integration/client_integration_test.cc @@ -77,13 +77,15 @@ class ClientIntegrationTest : public BaseIntegrationTest, release_envoy_data(c_data); return nullptr; }; - bridge_callbacks_.on_complete = [](envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_complete = [](envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { callbacks_called* cc_ = static_cast(context); cc_->on_complete_calls++; cc_->terminal_callback->setReady(); return nullptr; }; - bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, void* context) -> void* { + bridge_callbacks_.on_error = [](envoy_error error, envoy_stream_intel, envoy_final_stream_intel, + void* context) -> void* { release_envoy_error(error); callbacks_called* cc_ = static_cast(context); cc_->on_error_calls++; diff --git a/test/common/main_interface_test.cc b/test/common/main_interface_test.cc index 1a85e7dbfd..474a080a36 100644 --- a/test/common/main_interface_test.cc +++ b/test/common/main_interface_test.cc @@ -154,7 +154,7 @@ TEST(MainInterfaceTest, BasicStream) { nullptr /* on_metadata */, nullptr /* on_trailers */, nullptr /* on_error */, - [](envoy_stream_intel, void* context) -> void* { + [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { auto* on_complete_notification = static_cast(context); on_complete_notification->Notify(); return nullptr; @@ -249,20 +249,20 @@ TEST(MainInterfaceTest, ResetStream) { engine_cbs_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(10))); absl::Notification on_cancel_notification; - envoy_http_callbacks stream_cbs{nullptr /* on_headers */, - nullptr /* on_data */, - nullptr /* on_metadata */, - nullptr /* on_trailers */, - nullptr /* on_error */, - nullptr /* on_complete */, - [](envoy_stream_intel, void* context) -> void* { - auto* on_cancel_notification = - static_cast(context); - on_cancel_notification->Notify(); - return nullptr; - } /* on_cancel */, - nullptr /* on_send_window_available */, - &on_cancel_notification /* context */}; + envoy_http_callbacks stream_cbs{ + nullptr /* on_headers */, + nullptr /* on_data */, + nullptr /* on_metadata */, + nullptr /* on_trailers */, + nullptr /* on_error */, + nullptr /* on_complete */, + [](envoy_stream_intel, envoy_final_stream_intel, void* context) -> void* { + auto* on_cancel_notification = static_cast(context); + on_cancel_notification->Notify(); + return nullptr; + } /* on_cancel */, + nullptr /* on_send_window_available */, + &on_cancel_notification /* context */}; envoy_stream_t stream = init_stream(0); diff --git a/test/java/integration/AndroidEnvoyExplicitFlowTest.java b/test/java/integration/AndroidEnvoyExplicitFlowTest.java index 6f00f59171..ccc17de98c 100644 --- a/test/java/integration/AndroidEnvoyExplicitFlowTest.java +++ b/test/java/integration/AndroidEnvoyExplicitFlowTest.java @@ -393,12 +393,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { latch.countDown(); return null; }) - .setOnError((error, ignored) -> { + .setOnError((error, ignored, also_ignored) -> { response.get().setEnvoyError(error); latch.countDown(); return null; }) - .setOnCancel((ignored) -> { + .setOnCancel((ignored, also_ignored) -> { response.get().setCancelled(); latch.countDown(); return null; diff --git a/test/java/integration/AndroidEnvoyFlowTest.java b/test/java/integration/AndroidEnvoyFlowTest.java index 7d1bf250c9..a1a57e8904 100644 --- a/test/java/integration/AndroidEnvoyFlowTest.java +++ b/test/java/integration/AndroidEnvoyFlowTest.java @@ -302,12 +302,12 @@ private Response sendRequest(RequestScenario requestScenario) throws Exception { latch.countDown(); return null; }) - .setOnError((error, ignored) -> { + .setOnError((error, ignored, also_ignored) -> { response.get().setEnvoyError(error); latch.countDown(); return null; }) - .setOnCancel((ignored) -> { + .setOnCancel((ignored, also_ignored) -> { response.get().setCancelled(); latch.countDown(); return null; diff --git a/test/kotlin/integration/CancelStreamTest.kt b/test/kotlin/integration/CancelStreamTest.kt index e8d883ccd4..31321010fd 100644 --- a/test/kotlin/integration/CancelStreamTest.kt +++ b/test/kotlin/integration/CancelStreamTest.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.RequestHeadersBuilder import io.envoyproxy.envoymobile.RequestMethod import io.envoyproxy.envoymobile.ResponseFilter @@ -108,9 +109,10 @@ class CancelStreamTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) {} + override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { latch.countDown() } } @@ -137,7 +139,7 @@ class CancelStreamTest { .build() client.newStreamPrototype() - .setOnCancel { + .setOnCancel { _, _ -> runExpectation.countDown() } .start(Executors.newSingleThreadExecutor()) diff --git a/test/kotlin/integration/DrainConnectionsTest.kt b/test/kotlin/integration/DrainConnectionsTest.kt index 597c659120..f43c04a2a4 100644 --- a/test/kotlin/integration/DrainConnectionsTest.kt +++ b/test/kotlin/integration/DrainConnectionsTest.kt @@ -85,7 +85,7 @@ class DrainConnectionsTest { resultEndStream1 = endStream headersExpectation.countDown() } - .setOnError { _, _ -> fail("Unexpected error") } + .setOnError { _, _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) @@ -101,7 +101,7 @@ class DrainConnectionsTest { resultEndStream2 = endStream headersExpectation.countDown() } - .setOnError { _, _ -> fail("Unexpected error") } + .setOnError { _, _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/GRPCReceiveErrorTest.kt b/test/kotlin/integration/GRPCReceiveErrorTest.kt index c998706184..e83c87382f 100644 --- a/test/kotlin/integration/GRPCReceiveErrorTest.kt +++ b/test/kotlin/integration/GRPCReceiveErrorTest.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.GRPCClient import io.envoyproxy.envoymobile.GRPCRequestHeadersBuilder import io.envoyproxy.envoymobile.ResponseFilter @@ -95,11 +96,12 @@ class GRPCReceiveErrorTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { receivedError.countDown() } + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { notCancelled.countDown() } } @@ -124,10 +126,12 @@ class GRPCReceiveErrorTest { .newGRPCStreamPrototype() .setOnResponseHeaders { _, _, _ -> } .setOnResponseMessage { _, _ -> } - .setOnError { _, _ -> + .setOnError { _, _, _ -> callbackReceivedError.countDown() } - .setOnCancel { fail("Unexpected call to onCancel response callback") } + .setOnCancel { _, _ -> + fail("Unexpected call to onCancel response callback") + } .start() .sendHeaders(requestHeader, false) .sendMessage(ByteBuffer.wrap(ByteArray(5))) diff --git a/test/kotlin/integration/ReceiveDataTest.kt b/test/kotlin/integration/ReceiveDataTest.kt index 4059e14587..36702adbf5 100644 --- a/test/kotlin/integration/ReceiveDataTest.kt +++ b/test/kotlin/integration/ReceiveDataTest.kt @@ -94,7 +94,7 @@ class ReceiveDataTest { body = data dataExpectation.countDown() } - .setOnError { _, _ -> fail("Unexpected error") } + .setOnError { _, _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/ReceiveErrorTest.kt b/test/kotlin/integration/ReceiveErrorTest.kt index ed87a1e076..b7f61b239f 100644 --- a/test/kotlin/integration/ReceiveErrorTest.kt +++ b/test/kotlin/integration/ReceiveErrorTest.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.GRPCRequestHeadersBuilder import io.envoyproxy.envoymobile.ResponseFilter import io.envoyproxy.envoymobile.ResponseHeaders @@ -92,11 +93,12 @@ class ReceiveErrorTest { return FilterTrailersStatus.Continue(trailers) } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { receivedError.countDown() } + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { notCancelled.countDown() } } @@ -125,11 +127,13 @@ class ReceiveErrorTest { .setOnResponseData { _, _, _ -> fail("Data received instead of expected error") } // The unmatched expectation will cause a local reply which gets translated in Envoy Mobile to // an error. - .setOnError { error, _ -> + .setOnError { error, _, _ -> errorCode = error.errorCode callbackReceivedError.countDown() } - .setOnCancel { fail("Unexpected call to onCancel response callback") } + .setOnCancel { _, _ -> + fail("Unexpected call to onCancel response callback") + } .start() .sendHeaders(requestHeader, true) diff --git a/test/kotlin/integration/SendDataTest.kt b/test/kotlin/integration/SendDataTest.kt index 925e9f3bea..1fe9075a8a 100644 --- a/test/kotlin/integration/SendDataTest.kt +++ b/test/kotlin/integration/SendDataTest.kt @@ -93,7 +93,7 @@ class SendDataTest { responseHeadersEndStream = endStream expectation.countDown() } - .setOnError { _, _ -> + .setOnError { _, _, _ -> fail("Unexpected error") } .start() diff --git a/test/kotlin/integration/SendHeadersTest.kt b/test/kotlin/integration/SendHeadersTest.kt index 20cdb99f01..823a524d7a 100644 --- a/test/kotlin/integration/SendHeadersTest.kt +++ b/test/kotlin/integration/SendHeadersTest.kt @@ -85,7 +85,7 @@ class SendHeadersTest { resultEndStream = endStream headersExpectation.countDown() } - .setOnError { _, _ -> fail("Unexpected error") } + .setOnError { _, _, _ -> fail("Unexpected error") } .start() .sendHeaders(requestHeaders, true) diff --git a/test/kotlin/integration/SendTrailersTest.kt b/test/kotlin/integration/SendTrailersTest.kt index 1392583e19..1391ced880 100644 --- a/test/kotlin/integration/SendTrailersTest.kt +++ b/test/kotlin/integration/SendTrailersTest.kt @@ -98,7 +98,7 @@ class SendTrailersTest { responseStatus = headers.httpStatus expectation.countDown() } - .setOnError { _, _ -> + .setOnError { _, _, _ -> fail("Unexpected error") } .start() diff --git a/test/kotlin/integration/StreamIdleTimeoutTest.kt b/test/kotlin/integration/StreamIdleTimeoutTest.kt index 74205b32cb..8d1117961f 100644 --- a/test/kotlin/integration/StreamIdleTimeoutTest.kt +++ b/test/kotlin/integration/StreamIdleTimeoutTest.kt @@ -6,6 +6,7 @@ import io.envoyproxy.envoymobile.EnvoyError import io.envoyproxy.envoymobile.FilterDataStatus import io.envoyproxy.envoymobile.FilterHeadersStatus import io.envoyproxy.envoymobile.FilterTrailersStatus +import io.envoyproxy.envoymobile.FinalStreamIntel import io.envoyproxy.envoymobile.RequestHeadersBuilder import io.envoyproxy.envoymobile.RequestMethod import io.envoyproxy.envoymobile.ResponseFilter @@ -131,12 +132,13 @@ class CancelStreamTest { return FilterTrailersStatus.StopIteration() } - override fun onError(error: EnvoyError, streamIntel: StreamIntel) { + override fun onError(error: EnvoyError, streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { assertThat(error.errorCode).isEqualTo(4) latch.countDown() } + override fun onComplete(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) {} - override fun onCancel(streamIntel: StreamIntel) { + override fun onCancel(streamIntel: StreamIntel, finalStreamIntel: FinalStreamIntel) { fail("Unexpected call to onCancel filter callback") } } @@ -163,7 +165,7 @@ class CancelStreamTest { .build() client.newStreamPrototype() - .setOnError { error, _ -> + .setOnError { error, _, _ -> assertThat(error.errorCode).isEqualTo(4) callbackExpectation.countDown() } From 8b09ad7db1fc327d39ad33b93f20d7a5d4f2ff9b Mon Sep 17 00:00:00 2001 From: Jose Ulises Nino Rivera Date: Tue, 14 Dec 2021 17:00:47 -0800 Subject: [PATCH 22/25] envoy: b1219ef0d (#1970) Signed-off-by: Jose Nino From 53a927d3898eec1f395796b196e38af3218e6c8a Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Wed, 15 Dec 2021 11:55:14 -0800 Subject: [PATCH 23/25] python Signed-off-by: Jose Nino --- library/cc/engine_builder.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/cc/engine_builder.cc b/library/cc/engine_builder.cc index 5bf0897578..ff14a46178 100644 --- a/library/cc/engine_builder.cc +++ b/library/cc/engine_builder.cc @@ -100,6 +100,8 @@ std::string EngineBuilder::generateConfigStr() { {"dns_preresolve_hostnames", this->dns_preresolve_hostnames_}, {"dns_refresh_rate", fmt::format("{}s", this->dns_refresh_seconds_)}, {"dns_query_timeout", fmt::format("{}s", this->dns_query_timeout_seconds_)}, + {"dns_resolver_name", "envoy.network.dns_resolver.cares"}, + {"dns_resolver_config", "{\"@type\":\"type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig\"}"}, {"h2_connection_keepalive_idle_interval", fmt::format("{}s", this->h2_connection_keepalive_idle_interval_milliseconds_ / 1000.0)}, {"h2_connection_keepalive_timeout", From 280ed93eb42582de4242e9da8d1b8bb14320d72c Mon Sep 17 00:00:00 2001 From: Jose Nino Date: Wed, 15 Dec 2021 12:13:11 -0800 Subject: [PATCH 24/25] fmt Signed-off-by: Jose Nino --- library/cc/engine_builder.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/cc/engine_builder.cc b/library/cc/engine_builder.cc index ff14a46178..94d5120871 100644 --- a/library/cc/engine_builder.cc +++ b/library/cc/engine_builder.cc @@ -101,7 +101,9 @@ std::string EngineBuilder::generateConfigStr() { {"dns_refresh_rate", fmt::format("{}s", this->dns_refresh_seconds_)}, {"dns_query_timeout", fmt::format("{}s", this->dns_query_timeout_seconds_)}, {"dns_resolver_name", "envoy.network.dns_resolver.cares"}, - {"dns_resolver_config", "{\"@type\":\"type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig\"}"}, + {"dns_resolver_config", + "{\"@type\":\"type.googleapis.com/" + "envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig\"}"}, {"h2_connection_keepalive_idle_interval", fmt::format("{}s", this->h2_connection_keepalive_idle_interval_milliseconds_ / 1000.0)}, {"h2_connection_keepalive_timeout", From 2da39858d59b0d271d40a6ee5f6941c4a2f9aca4 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Wed, 15 Dec 2021 11:04:53 -0800 Subject: [PATCH 25/25] docs: replace old lyft URL (NFC) (#1957) Signed-off-by: Keith Smiley --- .github/workflows/android_build.yml | 4 ++-- CONTRIBUTING.md | 2 +- EnvoyMobile.podspec | 2 +- STYLE.md | 2 +- bazel/envoy_mobile_repositories.bzl | 4 ++-- bazel/pom_template.xml | 8 ++++---- dist/BUILD | 2 +- docs/conf.py | 6 +++--- docs/root/development/performance/binary_size.rst | 2 +- .../development/performance/cpu_battery_impact.rst | 2 +- .../development/performance/device_connectivity.rst | 2 +- docs/root/development/releasing/releasing.rst | 4 ++-- docs/root/development/testing/local_stats.rst | 8 ++++---- docs/root/development/tools/intellij.rst | 2 +- docs/root/intro/getting_help.rst | 2 +- docs/root/intro/version_history.rst | 2 +- docs/root/start/building/building.rst | 4 ++-- examples/objective-c/hello_world/ViewController.m | 2 +- library/common/api/external.cc | 2 +- library/common/config/config.cc | 2 +- library/common/engine.cc | 4 ++-- library/common/engine_common.cc | 6 +++--- library/common/engine_handle.cc | 4 ++-- .../filters/http/platform_bridge/filter.cc | 2 +- library/common/http/client.cc | 6 +++--- library/common/jni/jni_interface.cc | 8 ++++---- library/common/main_interface.cc | 12 ++++++------ .../envoymobile/grpc/GRPCStreamPrototype.kt | 2 +- library/objective-c/EnvoyBridgeUtility.h | 2 +- library/objective-c/EnvoyEngineImpl.m | 10 +++++----- library/swift/EngineBuilder.swift | 2 +- library/swift/grpc/GRPCStreamPrototype.swift | 2 +- test/common/main_interface_test.cc | 2 +- test/swift/integration/README.md | 2 +- 34 files changed, 64 insertions(+), 64 deletions(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index edfadb63c2..2c6fc1496d 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -71,7 +71,7 @@ jobs: run: ./ci/mac_start_emulator.sh # Return to using: # ./bazelw mobile-install --fat_apk_cpu=x86 --start_app //examples/java/hello_world:hello_envoy - # When https://github.com/lyft/envoy-mobile/issues/853 is fixed. + # When https://github.com/envoyproxy/envoy-mobile/issues/853 is fixed. - name: 'Start java app' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -114,7 +114,7 @@ jobs: run: ./ci/mac_start_emulator.sh # Return to using: # ./bazelw mobile-install --fat_apk_cpu=x86 --start_app //examples/kotlin/hello_world:hello_envoy_kt - # When https://github.com/lyft/envoy-mobile/issues/853 is fixed. + # When https://github.com/envoyproxy/envoy-mobile/issues/853 is fixed. - name: 'Start kotlin app' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e09a32b178..c59fb03699 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,7 +39,7 @@ following guidelines for all code, APIs, and documentation: # Submitting a PR * Fork the repo. -* [[TODO: add bootstrap script for prepush hook](https://github.com/lyft/envoy-mobile/issues/185)] +* [[TODO: add bootstrap script for prepush hook](https://github.com/envoyproxy/envoy-mobile/issues/185)] * Create your PR. * Tests will automatically run for you. * We will **not** merge any PR that is not passing tests. diff --git a/EnvoyMobile.podspec b/EnvoyMobile.podspec index b4ca64e9f5..524ed9b6ba 100644 --- a/EnvoyMobile.podspec +++ b/EnvoyMobile.podspec @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.swift_versions = ['5.5'] s.libraries = 'resolv.9', 'c++' s.frameworks = 'Network', 'SystemConfiguration', 'UIKit' - s.source = { http: "https://github.com/lyft/envoy-mobile/releases/download/v#{s.version}/envoy_ios_cocoapods.zip" } + s.source = { http: "https://github.com/envoyproxy/envoy-mobile/releases/download/v#{s.version}/envoy_ios_cocoapods.zip" } s.vendored_frameworks = 'Envoy.framework' s.source_files = 'Envoy.framework/Headers/*.h', 'Envoy.framework/Swift/*.swift' end diff --git a/STYLE.md b/STYLE.md index 1914cde4b9..108560a335 100644 --- a/STYLE.md +++ b/STYLE.md @@ -42,4 +42,4 @@ to provide some enforced consistency, we've adopted the convention of defining t lowest applicable layer (core/bridge) of the library, and then declaring public `extern const` values defined in terms of the enumeration, to be shared across bridge and platform code. See, for example: -https://github.com/lyft/envoy-mobile/blob/2a1b53427100d94878551b55bb564e9117f83fe6/library/common/types/c_types.h#L25 +https://github.com/envoyproxy/envoy-mobile/blob/2a1b53427100d94878551b55bb564e9117f83fe6/library/common/types/c_types.h#L25 diff --git a/bazel/envoy_mobile_repositories.bzl b/bazel/envoy_mobile_repositories.bzl index 68ddd4d7db..b779dea9aa 100644 --- a/bazel/envoy_mobile_repositories.bzl +++ b/bazel/envoy_mobile_repositories.bzl @@ -27,7 +27,7 @@ def upstream_envoy_overrides(): urls = ["https://github.com/protocolbuffers/protobuf/releases/download/v3.16.0/protobuf-all-3.16.0.tar.gz"], ) - # Workaround old NDK version breakages https://github.com/lyft/envoy-mobile/issues/934 + # Workaround old NDK version breakages https://github.com/envoyproxy/envoy-mobile/issues/934 http_archive( name = "com_github_libevent_libevent", urls = ["https://github.com/libevent/libevent/archive/0d7d85c2083f7a4c9efe01c061486f332b576d28.tar.gz"], @@ -38,7 +38,7 @@ def upstream_envoy_overrides(): # Patch upstream Abseil to prevent Foundation dependency from leaking into Android builds. # Workaround for https://github.com/abseil/abseil-cpp/issues/326. - # TODO: Should be removed in https://github.com/lyft/envoy-mobile/issues/136 once rules_android + # TODO: Should be removed in https://github.com/envoyproxy/envoy-mobile/issues/136 once rules_android # supports platform toolchains. http_archive( name = "com_google_absl", diff --git a/bazel/pom_template.xml b/bazel/pom_template.xml index 82f04aca70..38ebb8da00 100644 --- a/bazel/pom_template.xml +++ b/bazel/pom_template.xml @@ -14,7 +14,7 @@ Envoy Mobile Client networking libraries based on the Envoy project. - https://github.com/lyft/envoy-mobile + https://github.com/envoyproxy/envoy-mobile @@ -46,9 +46,9 @@ - https://github.com/lyft/envoy-mobile - scm:git:git@github.com:lyft/envoy-mobile.git - scm:git:git@github.com:lyft/envoy-mobile.git + https://github.com/envoyproxy/envoy-mobile + scm:git:git@github.com:envoyproxy/envoy-mobile.git + scm:git:git@github.com:envoyproxy/envoy-mobile.git HEAD diff --git a/dist/BUILD b/dist/BUILD index 91f357b3c0..2657e4bc00 100644 --- a/dist/BUILD +++ b/dist/BUILD @@ -6,7 +6,7 @@ licenses(["notice"]) # Apache 2 # NOTE: You must first build the top-level targets //:ios_dist and //:android_dist to use the # artifacts referenced here. # You can also download the distributables referenced here from envoy-mobile's releases page: -# https://github.com/lyft/envoy-mobile/releases +# https://github.com/envoyproxy/envoy-mobile/releases aar_import( name = "envoy_mobile_android", diff --git a/docs/conf.py b/docs/conf.py index d7f8016e32..3e7e11cccd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -69,9 +69,9 @@ def setup(app): # ones. extensions = ['sphinxcontrib.httpdomain', 'sphinx.ext.extlinks', 'sphinx.ext.ifconfig'] extlinks = { - 'issue': ('https://github.com/lyft/envoy-mobile/issues/%s', ''), - 'repo': ('https://github.com/lyft/envoy-mobile/blob/{}/%s'.format(blob_sha), ''), - 'tree': ('https://github.com/lyft/envoy-mobile/tree/%s', ''), + 'issue': ('https://github.com/envoyproxy/envoy-mobile/issues/%s', ''), + 'repo': ('https://github.com/envoyproxy/envoy-mobile/blob/{}/%s'.format(blob_sha), ''), + 'tree': ('https://github.com/envoyproxy/envoy-mobile/tree/%s', ''), } # Set up global substitutions diff --git a/docs/root/development/performance/binary_size.rst b/docs/root/development/performance/binary_size.rst index c509422d7d..c86d094a31 100644 --- a/docs/root/development/performance/binary_size.rst +++ b/docs/root/development/performance/binary_size.rst @@ -154,7 +154,7 @@ Open issues regarding size ``perf/size`` is a label tagging all current open issues that can improve binary size. Check out the issues `here -`_. After performing +`_. After performing any change that tries to address these issues you should run through the analysis pipeline described above, and make sure your changes match expectations. diff --git a/docs/root/development/performance/cpu_battery_impact.rst b/docs/root/development/performance/cpu_battery_impact.rst index 9989a9ed32..1822627002 100644 --- a/docs/root/development/performance/cpu_battery_impact.rst +++ b/docs/root/development/performance/cpu_battery_impact.rst @@ -116,4 +116,4 @@ Open issues ~~~~~~~~~~~ For current issues with CPU/battery, please see issues with the -`perf/cpu label `_. +`perf/cpu label `_. diff --git a/docs/root/development/performance/device_connectivity.rst b/docs/root/development/performance/device_connectivity.rst index 4875eb6370..3669eb4850 100644 --- a/docs/root/development/performance/device_connectivity.rst +++ b/docs/root/development/performance/device_connectivity.rst @@ -79,4 +79,4 @@ Open issues ~~~~~~~~~~~ For current issues with device conditions, please see issues with the -`perf/device label `_. +`perf/device label `_. diff --git a/docs/root/development/releasing/releasing.rst b/docs/root/development/releasing/releasing.rst index c02d99e13b..001f18ae34 100644 --- a/docs/root/development/releasing/releasing.rst +++ b/docs/root/development/releasing/releasing.rst @@ -4,7 +4,7 @@ Releasing ========= The following workflow should be followed to create and publish a new Envoy Mobile -`release `_. +`release `_. Prepare for release ------------------- @@ -19,7 +19,7 @@ Publish release and artifacts ----------------------------- After merging the above changes, a new release may be -`tagged `_. +`tagged `_. When tagging a release, it should contain all the artifacts built by CI on the main commit being tagged as the new version. These artifacts may be downloaded by clicking on the CI status of the diff --git a/docs/root/development/testing/local_stats.rst b/docs/root/development/testing/local_stats.rst index 5b26b7aa20..1b04c2f84c 100644 --- a/docs/root/development/testing/local_stats.rst +++ b/docs/root/development/testing/local_stats.rst @@ -3,7 +3,7 @@ Local Stats =========== -The `local-stats` `branch `_ allows a +The `local-stats` `branch `_ allows a developer to run a local statsd server, and see stats emissions from a client running in the simulator/emulator. Unless network tunneling is set up this is not going to work in a physical device, as the statsd server is running on the computer's local network. @@ -12,9 +12,9 @@ device, as the statsd server is running on the computer's local network. Config ------ -The `config template `_ +The `config template `_ has already been updated to use a local statsd server. However, if you are using Android to test, -the `static address `_ +the `static address `_ used for the server should be changed to ``10.0.2.2`` per the `Set up Android Emulator networking `_ docs. @@ -28,7 +28,7 @@ Steps node stats.js config.js - An example ``config.js`` file. Note that the port must match the port in the `config_template `_:: + An example ``config.js`` file. Note that the port must match the port in the `config_template `_:: { port: 8125 diff --git a/docs/root/development/tools/intellij.rst b/docs/root/development/tools/intellij.rst index 16ad06be76..00e73f527f 100644 --- a/docs/root/development/tools/intellij.rst +++ b/docs/root/development/tools/intellij.rst @@ -11,7 +11,7 @@ Using IntelliJ with Envoy Mobile To get started using IntelliJ with Envoy Mobile: 1. Download a supported `IntelliJ version `_ supported by the Bazel plugin -2. Apply local hacks to make IntelliJ work using the branch `hack-for-intellij `_ +2. Apply local hacks to make IntelliJ work using the branch `hack-for-intellij `_ 3. Open up the Envoy Mobile project using the Bazel import project wizard diff --git a/docs/root/intro/getting_help.rst b/docs/root/intro/getting_help.rst index aa73634a3e..5145eb2e47 100644 --- a/docs/root/intro/getting_help.rst +++ b/docs/root/intro/getting_help.rst @@ -6,4 +6,4 @@ Getting help We are very interested in building a community around Envoy Mobile. Please reach out to us if you are interested in using it and need help or want to contribute. -Please see `contact info `_. +Please see `contact info `_. diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index d646e121bf..cbb3de0d63 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -85,7 +85,7 @@ Extensibility: - Introduces platform filter interfaces and bridging (:issue:`#795 <795>`, :issue:`#840 <840>`, :issue:`#858 <858>`, :issue:`#913 <913>`, :issue:`#940 <940>`, :issue:`#955 <955>`, :issue:`#943 <943>`, :issue:`#962 <962>`) - Introduces Envoy's extension platform (:issue:`#860 <860>`) -Lastly, and perhaps most importantly, we have adopted a formal `inclusive language policy `_ +Lastly, and perhaps most importantly, we have adopted a formal `inclusive language policy `_ (:issue:`#948 <948>`) and updated all necessary locations (:issue:`#944 <944>`, :issue:`#945 <945>`, :issue:`#946 <946>`) 0.3.0 (Mar 26, 2020) diff --git a/docs/root/start/building/building.rst b/docs/root/start/building/building.rst index 2bf9d8faf1..734738ef7c 100644 --- a/docs/root/start/building/building.rst +++ b/docs/root/start/building/building.rst @@ -9,13 +9,13 @@ To get started, you can use `this quick start guide Ensure that the ``envoy`` **submodule** is initialized when cloning by using ``--recursive``: -``git clone https://github.com/lyft/envoy-mobile.git --recursive`` +``git clone https://github.com/envoyproxy/envoy-mobile.git --recursive`` If the repo was not initially cloned recursively, you can manually initialize the Envoy submodule: ``git submodule update --init`` -.. _releases: https://github.com/lyft/envoy-mobile/releases +.. _releases: https://github.com/envoyproxy/envoy-mobile/releases ------------------ Bazel requirements diff --git a/examples/objective-c/hello_world/ViewController.m b/examples/objective-c/hello_world/ViewController.m index 8c01f37304..1aa00768c3 100644 --- a/examples/objective-c/hello_world/ViewController.m +++ b/examples/objective-c/hello_world/ViewController.m @@ -104,7 +104,7 @@ - (void)performRequest { [weakSelf addResponseMessage:message headerMessage:headerMessage error:nil]; }]; [prototype setOnErrorWithClosure:^(EnvoyError *error, StreamIntel *ignored) { - // TODO: expose attemptCount. https://github.com/lyft/envoy-mobile/issues/823 + // TODO: expose attemptCount. https://github.com/envoyproxy/envoy-mobile/issues/823 NSString *message = [NSString stringWithFormat:@"failed within Envoy library %@", error.message]; NSLog(@"%@", message); diff --git a/library/common/api/external.cc b/library/common/api/external.cc index 9e78a90e40..18810fdd81 100644 --- a/library/common/api/external.cc +++ b/library/common/api/external.cc @@ -9,7 +9,7 @@ namespace Api { namespace External { // TODO(goaway): This needs to be updated not to leak once multiple engines are supported. -// See https://github.com/lyft/envoy-mobile/issues/332 +// See https://github.com/envoyproxy/envoy-mobile/issues/332 static absl::flat_hash_map registry_{}; // TODO(goaway): To expose this for general usage, it will need to be made thread-safe. For now it diff --git a/library/common/config/config.cc b/library/common/config/config.cc index ee56568e67..eb17ef6e8b 100644 --- a/library/common/config/config.cc +++ b/library/common/config/config.cc @@ -254,7 +254,7 @@ const char* config_template = R"( // https://github.com/envoyproxy/envoy-mobile/issues/1534 R"( preresolve_hostnames: *dns_preresolve_hostnames -)" // TODO: Support IPV6 https://github.com/lyft/envoy-mobile/issues/1022 +)" // TODO: Support IPV6 https://github.com/envoyproxy/envoy-mobile/issues/1022 R"( dns_lookup_family: V4_PREFERRED )" // On mobile, backgrounding might cause the host to be past its TTL without good diff --git a/library/common/engine.cc b/library/common/engine.cc index 92042d9f4c..7dc5cb7e09 100644 --- a/library/common/engine.cc +++ b/library/common/engine.cc @@ -18,12 +18,12 @@ Engine::Engine(envoy_engine_callbacks callbacks, envoy_logger logger, dispatcher_(std::make_unique()) { // Ensure static factory registration occurs on time. // TODO: ensure this is only called one time once multiple Engine objects can be allocated. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 ExtensionRegistry::registerFactories(); // TODO(Augustyniak): Capturing an address of event_tracker_ and registering it in the API // registry may lead to crashes at Engine shutdown. To be figured out as part of - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 Envoy::Api::External::registerApi(std::string(envoy_event_tracker_api_name), &event_tracker_); } diff --git a/library/common/engine_common.cc b/library/common/engine_common.cc index 576a8169e8..b20b31f147 100644 --- a/library/common/engine_common.cc +++ b/library/common/engine_common.cc @@ -14,9 +14,9 @@ EngineCommon::EngineCommon(int argc, const char* const* argv) // not_ listen for termination signals such as SIGTERM, SIGINT, etc // (https://github.com/envoyproxy/envoy/blob/048f4231310fbbead0cbe03d43ffb4307fff0517/source/server/server.cc#L519). // Previous crashes in iOS were experienced due to early event loop exit as described in - // https://github.com/lyft/envoy-mobile/issues/831. Ignoring termination signals makes it more - // likely that the event loop will only exit due to Engine destruction - // https://github.com/lyft/envoy-mobile/blob/a72a51e64543882ea05fba3c76178b5784d39cdc/library/common/engine.cc#L105. + // https://github.com/envoyproxy/envoy-mobile/issues/831. Ignoring termination signals makes it + // more likely that the event loop will only exit due to Engine destruction + // https://github.com/envoyproxy/envoy-mobile/blob/a72a51e64543882ea05fba3c76178b5784d39cdc/library/common/engine.cc#L105. options_.setSignalHandling(false); } diff --git a/library/common/engine_handle.cc b/library/common/engine_handle.cc index 6097054544..8cccdce1b9 100644 --- a/library/common/engine_handle.cc +++ b/library/common/engine_handle.cc @@ -17,7 +17,7 @@ envoy_status_t EngineHandle::runOnEngineDispatcher(envoy_engine_t, envoy_engine_t EngineHandle::initEngine(envoy_engine_callbacks callbacks, envoy_logger logger, envoy_event_tracker event_tracker) { // TODO(goaway): return new handle once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 strong_engine_ = std::make_shared(callbacks, logger, event_tracker); engine_ = strong_engine_; return 1; @@ -25,7 +25,7 @@ envoy_engine_t EngineHandle::initEngine(envoy_engine_callbacks callbacks, envoy_ envoy_status_t EngineHandle::runEngine(envoy_engine_t, const char* config, const char* log_level) { // This will change once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 if (auto e = engine()) { e->run(config, log_level); return ENVOY_SUCCESS; diff --git a/library/common/extensions/filters/http/platform_bridge/filter.cc b/library/common/extensions/filters/http/platform_bridge/filter.cc index f249423309..774f906ec1 100644 --- a/library/common/extensions/filters/http/platform_bridge/filter.cc +++ b/library/common/extensions/filters/http/platform_bridge/filter.cc @@ -537,7 +537,7 @@ void PlatformBridgeFilter::resumeDecoding() { // 1) adding support to Envoy for (optionally) retaining the dispatcher, or // 2) retaining the engine to transitively retain the dispatcher via Envoy's ownership graph, or // 3) dispatching via a safe intermediary - // Relevant: https://github.com/lyft/envoy-mobile/issues/332 + // Relevant: https://github.com/envoyproxy/envoy-mobile/issues/332 dispatcher_.post([weak_self]() -> void { if (auto self = weak_self.lock()) { // Delegate to base implementation for request and response path. diff --git a/library/common/http/client.cc b/library/common/http/client.cc index c87a61879a..9d23ee9d63 100644 --- a/library/common/http/client.cc +++ b/library/common/http/client.cc @@ -450,7 +450,7 @@ void Client::sendHeaders(envoy_stream_t stream, envoy_headers headers, bool end_ // TODO: handle potential race condition with cancellation or failure get a stream in the // first place. Additionally it is possible to get a nullptr due to bogus envoy_stream_t // from the caller. - // https://github.com/lyft/envoy-mobile/issues/301 + // https://github.com/envoyproxy/envoy-mobile/issues/301 if (direct_stream) { ScopeTrackerScopeState scope(direct_stream.get(), scopeTracker()); RequestHeaderMapPtr internal_headers = Utility::toRequestHeaders(headers); @@ -497,7 +497,7 @@ void Client::sendData(envoy_stream_t stream, envoy_data data, bool end_stream) { // TODO: handle potential race condition with cancellation or failure get a stream in the // first place. Additionally it is possible to get a nullptr due to bogus envoy_stream_t // from the caller. - // https://github.com/lyft/envoy-mobile/issues/301 + // https://github.com/envoyproxy/envoy-mobile/issues/301 if (direct_stream) { ScopeTrackerScopeState scope(direct_stream.get(), scopeTracker()); // The buffer is moved internally, in a synchronous fashion, so we don't need the lifetime @@ -535,7 +535,7 @@ void Client::sendTrailers(envoy_stream_t stream, envoy_headers trailers) { // TODO: handle potential race condition with cancellation or failure get a stream in the // first place. Additionally it is possible to get a nullptr due to bogus envoy_stream_t // from the caller. - // https://github.com/lyft/envoy-mobile/issues/301 + // https://github.com/envoyproxy/envoy-mobile/issues/301 if (direct_stream) { ScopeTrackerScopeState scope(direct_stream.get(), scopeTracker()); RequestTrailerMapPtr internal_trailers = Utility::toRequestTrailers(trailers); diff --git a/library/common/jni/jni_interface.cc b/library/common/jni/jni_interface.cc index c036ebf78e..bba603c72b 100644 --- a/library/common/jni/jni_interface.cc +++ b/library/common/jni/jni_interface.cc @@ -39,7 +39,7 @@ static void jvm_on_engine_running(void* context) { env->DeleteLocalRef(jcls_JvmonEngineRunningContext); // TODO(goaway): This isn't re-used by other engine callbacks, so it's safe to delete here. - // This will need to be updated for https://github.com/lyft/envoy-mobile/issues/332 + // This will need to be updated for https://github.com/envoyproxy/envoy-mobile/issues/332 env->DeleteGlobalRef(j_context); } @@ -105,7 +105,7 @@ extern "C" JNIEXPORT jlong JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibr envoy_event_tracker event_tracker = {nullptr, nullptr}; if (j_event_tracker != nullptr) { // TODO(goaway): The retained_context leaks, but it's tied to the life of the engine. - // This will need to be updated for https://github.com/lyft/envoy-mobile/issues/332. + // This will need to be updated for https://github.com/envoyproxy/envoy-mobile/issues/332. jobject retained_context = env->NewGlobalRef(j_event_tracker); jni_log_fmt("[Envoy]", "retained_context: %p", retained_context); event_tracker.track = jvm_on_track; @@ -868,7 +868,7 @@ Java_io_envoyproxy_envoymobile_engine_JniLibrary_registerFilterFactory(JNIEnv* e jobject j_context) { // TODO(goaway): Everything here leaks, but it's all be tied to the life of the engine. - // This will need to be updated for https://github.com/lyft/envoy-mobile/issues/332 + // This will need to be updated for https://github.com/envoyproxy/envoy-mobile/issues/332 jni_log("[Envoy]", "registerFilterFactory"); jni_log_fmt("[Envoy]", "j_context: %p", j_context); jobject retained_context = env->NewGlobalRef(j_context); @@ -998,7 +998,7 @@ Java_io_envoyproxy_envoymobile_engine_JniLibrary_registerStringAccessor(JNIEnv* jobject j_context) { // TODO(goaway): The retained_context leaks, but it's tied to the life of the engine. - // This will need to be updated for https://github.com/lyft/envoy-mobile/issues/332. + // This will need to be updated for https://github.com/envoyproxy/envoy-mobile/issues/332. jobject retained_context = env->NewGlobalRef(j_context); envoy_string_accessor* string_accessor = diff --git a/library/common/main_interface.cc b/library/common/main_interface.cc index 025996897b..6c64062400 100644 --- a/library/common/main_interface.cc +++ b/library/common/main_interface.cc @@ -74,7 +74,7 @@ envoy_status_t set_preferred_network(envoy_network_t network) { envoy_status_t record_counter_inc(envoy_engine_t e, const char* elements, envoy_stats_tags tags, uint64_t count) { // TODO: use specific engine once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 return Envoy::EngineHandle::runOnEngineDispatcher( e, [name = std::string(elements), tags, count](auto& engine) -> void { engine.recordCounterInc(name, tags, count); @@ -84,7 +84,7 @@ envoy_status_t record_counter_inc(envoy_engine_t e, const char* elements, envoy_ envoy_status_t record_gauge_set(envoy_engine_t e, const char* elements, envoy_stats_tags tags, uint64_t value) { // TODO: use specific engine once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 return Envoy::EngineHandle::runOnEngineDispatcher( e, [name = std::string(elements), tags, value](auto& engine) -> void { engine.recordGaugeSet(name, tags, value); @@ -94,7 +94,7 @@ envoy_status_t record_gauge_set(envoy_engine_t e, const char* elements, envoy_st envoy_status_t record_gauge_add(envoy_engine_t e, const char* elements, envoy_stats_tags tags, uint64_t amount) { // TODO: use specific engine once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 return Envoy::EngineHandle::runOnEngineDispatcher( e, [name = std::string(elements), tags, amount](auto& engine) -> void { engine.recordGaugeAdd(name, tags, amount); @@ -104,7 +104,7 @@ envoy_status_t record_gauge_add(envoy_engine_t e, const char* elements, envoy_st envoy_status_t record_gauge_sub(envoy_engine_t e, const char* elements, envoy_stats_tags tags, uint64_t amount) { // TODO: use specific engine once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 return Envoy::EngineHandle::runOnEngineDispatcher( e, [name = std::string(elements), tags, amount](auto& engine) -> void { engine.recordGaugeSub(name, tags, amount); @@ -114,7 +114,7 @@ envoy_status_t record_gauge_sub(envoy_engine_t e, const char* elements, envoy_st envoy_status_t record_histogram_value(envoy_engine_t e, const char* elements, envoy_stats_tags tags, uint64_t value, envoy_histogram_stat_unit_t unit_measure) { // TODO: use specific engine once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 return Envoy::EngineHandle::runOnEngineDispatcher( e, [name = std::string(elements), tags, value, unit_measure](auto& engine) -> void { engine.recordHistogramValue(name, tags, value, unit_measure); @@ -197,7 +197,7 @@ void terminate_engine(envoy_engine_t engine) { Envoy::EngineHandle::terminateEng envoy_status_t drain_connections(envoy_engine_t e) { // This will change once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 return Envoy::EngineHandle::runOnEngineDispatcher( e, [](auto& engine) { engine.drainConnections(); }); } diff --git a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt index 78618658af..6192c7d4d3 100644 --- a/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt +++ b/library/kotlin/io/envoyproxy/envoymobile/grpc/GRPCStreamPrototype.kt @@ -151,7 +151,7 @@ private class GRPCMessageProcessor { } val compressionFlag = byteArray[0] - // TODO: Support gRPC compression https://github.com/lyft/envoy-mobile/issues/501. + // TODO: Support gRPC compression https://github.com/envoyproxy/envoy-mobile/issues/501. if (compressionFlag.compareTo(0) != 0) { bufferedStream.reset() } diff --git a/library/objective-c/EnvoyBridgeUtility.h b/library/objective-c/EnvoyBridgeUtility.h index 1cb3429528..9eaa9d746e 100644 --- a/library/objective-c/EnvoyBridgeUtility.h +++ b/library/objective-c/EnvoyBridgeUtility.h @@ -86,7 +86,7 @@ static inline envoy_stats_tags toNativeStatsTags(EnvoyTags *tags) { static inline NSData *to_ios_data(envoy_data data) { // TODO: we are copying from envoy_data to NSData. - // https://github.com/lyft/envoy-mobile/issues/398 + // https://github.com/envoyproxy/envoy-mobile/issues/398 NSData *platformData = [NSData dataWithBytes:(void *)data.bytes length:data.length]; release_envoy_data(data); return platformData; diff --git a/library/objective-c/EnvoyEngineImpl.m b/library/objective-c/EnvoyEngineImpl.m index 0314c9badd..5744c72aa0 100644 --- a/library/objective-c/EnvoyEngineImpl.m +++ b/library/objective-c/EnvoyEngineImpl.m @@ -412,7 +412,7 @@ - (instancetype)initWithRunningCallback:(nullable void (^)())onEngineRunning } // TODO(Augustyniak): Everything here leaks, but it's all tied to the life of the engine. - // This will need to be updated for https://github.com/lyft/envoy-mobile/issues/332. + // This will need to be updated for https://github.com/envoyproxy/envoy-mobile/issues/332. envoy_event_tracker native_event_tracker = {NULL, NULL}; if (eventTracker) { EnvoyEventTracker *objcEventTracker = @@ -444,7 +444,7 @@ - (void)dealloc { - (int)registerFilterFactory:(EnvoyHTTPFilterFactory *)filterFactory { // TODO(goaway): Everything here leaks, but it's all be tied to the life of the engine. - // This will need to be updated for https://github.com/lyft/envoy-mobile/issues/332 + // This will need to be updated for https://github.com/envoyproxy/envoy-mobile/issues/332 envoy_http_filter *api = safe_malloc(sizeof(envoy_http_filter)); api->init_filter = ios_http_filter_init; api->on_request_headers = ios_http_filter_on_request_headers; @@ -469,7 +469,7 @@ - (int)registerFilterFactory:(EnvoyHTTPFilterFactory *)filterFactory { - (int)registerStringAccessor:(NSString *)name accessor:(EnvoyStringAccessor *)accessor { // TODO(goaway): Everything here leaks, but it's all tied to the life of the engine. - // This will need to be updated for https://github.com/lyft/envoy-mobile/issues/332 + // This will need to be updated for https://github.com/envoyproxy/envoy-mobile/issues/332 envoy_string_accessor *accessorStruct = safe_malloc(sizeof(envoy_string_accessor)); accessorStruct->get_string = ios_get_string; accessorStruct->context = CFBridgingRetain(accessor); @@ -581,8 +581,8 @@ - (void)drainConnections { #pragma mark - Private - (void)startObservingLifecycleNotifications { - // re-enable lifecycle-based stat flushing when https://github.com/lyft/envoy-mobile/issues/748 - // gets fixed. + // re-enable lifecycle-based stat flushing when + // https://github.com/envoyproxy/envoy-mobile/issues/748 gets fixed. NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver:self selector:@selector(terminateNotification:) diff --git a/library/swift/EngineBuilder.swift b/library/swift/EngineBuilder.swift index 8dadbf3291..be21401cbc 100644 --- a/library/swift/EngineBuilder.swift +++ b/library/swift/EngineBuilder.swift @@ -398,7 +398,7 @@ open class EngineBuilder: NSObject { /// Add a specific implementation of `EnvoyEngine` to use for starting Envoy. /// A new instance of this engine will be created when `build()` is called. /// Used for testing, as initializing with `EnvoyEngine.Type` results in a - /// segfault: https://github.com/lyft/envoy-mobile/issues/334 + /// segfault: https://github.com/envoyproxy/envoy-mobile/issues/334 @discardableResult func addEngineType(_ engineType: EnvoyEngine.Type) -> Self { self.engineType = engineType diff --git a/library/swift/grpc/GRPCStreamPrototype.swift b/library/swift/grpc/GRPCStreamPrototype.swift index f4e1e3b2ed..c69c1234a1 100644 --- a/library/swift/grpc/GRPCStreamPrototype.swift +++ b/library/swift/grpc/GRPCStreamPrototype.swift @@ -135,7 +135,7 @@ private enum GRPCMessageProcessor { } guard compressionFlag == 0 else { - // TODO: Support gRPC compression https://github.com/lyft/envoy-mobile/issues/501 + // TODO: Support gRPC compression https://github.com/envoyproxy/envoy-mobile/issues/501 buffer.removeAll() state = .expectingCompressionFlag return diff --git a/test/common/main_interface_test.cc b/test/common/main_interface_test.cc index 474a080a36..909b0dfe63 100644 --- a/test/common/main_interface_test.cc +++ b/test/common/main_interface_test.cc @@ -329,7 +329,7 @@ TEST(MainInterfaceTest, RegisterPlatformApi) { TEST(MainInterfaceTest, InitEngineReturns1) { // TODO(goaway): return new handle once multiple engine support is in place. - // https://github.com/lyft/envoy-mobile/issues/332 + // https://github.com/envoyproxy/envoy-mobile/issues/332 engine_test_context test_context{}; envoy_engine_callbacks engine_cbs{[](void* context) -> void { auto* engine_running = diff --git a/test/swift/integration/README.md b/test/swift/integration/README.md index 4b46a271ad..140a87444e 100644 --- a/test/swift/integration/README.md +++ b/test/swift/integration/README.md @@ -5,7 +5,7 @@ side via the ` setOnResponse{...}` functions. TODO: These tests are broken apart into different suites and bazel targets in order to tear down app state -- and thus static lifetime objects like the Envoy engine -- between tests. When -multiple engine support (https://github.com/lyft/envoy-mobile/issues/332) lands, all of these +multiple engine support (https://github.com/envoyproxy/envoy-mobile/issues/332) lands, all of these tests can be collapsed to the same suite/target. TODO: setOnTrailers is not tested as the neither the `direct_response` pathway, nor the router