xref: /aosp_15_r20/external/aws-crt-java/src/native/http_request_response.c (revision 3c7ae9de214676c52d19f01067dc1a404272dc11)
1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 
6 #include <jni.h>
7 
8 #include "crt.h"
9 #include "http_connection_manager.h"
10 #include "http_request_response.h"
11 #include "http_request_utils.h"
12 #include "java_class_ids.h"
13 
14 #include <aws/common/atomics.h>
15 #include <aws/common/mutex.h>
16 #include <aws/http/connection.h>
17 #include <aws/http/http.h>
18 #include <aws/http/request_response.h>
19 #include <aws/io/logging.h>
20 #include <aws/io/stream.h>
21 
22 #if _MSC_VER
23 #    pragma warning(disable : 4204) /* non-constant aggregate initializer */
24 #endif
25 
26 /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
27 #if UINTPTR_MAX == 0xffffffff
28 #    if defined(_MSC_VER)
29 #        pragma warning(push)
30 #        pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
31 #    else
32 #        pragma GCC diagnostic push
33 #        pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
34 #        pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
35 #    endif
36 #endif
37 
aws_java_http_stream_from_native_new(JNIEnv * env,void * opaque,int version)38 jobject aws_java_http_stream_from_native_new(JNIEnv *env, void *opaque, int version) {
39     jlong jni_native_ptr = (jlong)opaque;
40     AWS_ASSERT(jni_native_ptr);
41     jobject stream = NULL;
42     switch (version) {
43         case AWS_HTTP_VERSION_2:
44             stream = (*env)->NewObject(
45                 env, http2_stream_properties.stream_class, http2_stream_properties.constructor, jni_native_ptr);
46             break;
47         case AWS_HTTP_VERSION_1_0:
48         case AWS_HTTP_VERSION_1_1:
49             stream = (*env)->NewObject(
50                 env, http_stream_properties.stream_class, http_stream_properties.constructor, jni_native_ptr);
51             break;
52         default:
53             aws_jni_throw_runtime_exception(env, "Unsupported HTTP protocol.");
54             aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
55     }
56     return stream;
57 }
58 
aws_java_http_stream_from_native_delete(JNIEnv * env,jobject jHttpStream)59 void aws_java_http_stream_from_native_delete(JNIEnv *env, jobject jHttpStream) {
60     /* Delete our reference to the HttpStream Object from the JVM. */
61     (*env)->DeleteGlobalRef(env, jHttpStream);
62 }
63 
64 /*******************************************************************************
65  * http_stream_binding - Jni native represent of the Java HTTP stream object
66  ******************************************************************************/
67 
s_http_stream_binding_destroy(JNIEnv * env,struct http_stream_binding * binding)68 static void s_http_stream_binding_destroy(JNIEnv *env, struct http_stream_binding *binding) {
69 
70     if (binding->java_http_stream_base) {
71         aws_java_http_stream_from_native_delete(env, binding->java_http_stream_base);
72     }
73 
74     if (binding->java_http_response_stream_handler != NULL) {
75         (*env)->DeleteGlobalRef(env, binding->java_http_response_stream_handler);
76     }
77 
78     if (binding->native_request) {
79         aws_http_message_release(binding->native_request);
80     }
81     aws_byte_buf_clean_up(&binding->headers_buf);
82     aws_mem_release(aws_jni_get_allocator(), binding);
83 }
84 
aws_http_stream_binding_acquire(struct http_stream_binding * binding)85 void *aws_http_stream_binding_acquire(struct http_stream_binding *binding) {
86     if (binding == NULL) {
87         return NULL;
88     }
89     aws_atomic_fetch_add(&binding->ref, 1);
90     return binding;
91 }
92 
aws_http_stream_binding_release(JNIEnv * env,struct http_stream_binding * binding)93 void *aws_http_stream_binding_release(JNIEnv *env, struct http_stream_binding *binding) {
94     if (binding == NULL) {
95         return NULL;
96     }
97     size_t pre_ref = aws_atomic_fetch_sub(&binding->ref, 1);
98     AWS_ASSERT(pre_ref > 0 && "stream binding refcount has gone negative");
99     if (pre_ref == 1) {
100         s_http_stream_binding_destroy(env, binding);
101     }
102     return NULL;
103 }
104 
105 // If error occurs, A Java exception is thrown and NULL is returned.
aws_http_stream_binding_new(JNIEnv * env,jobject java_callback_handler)106 struct http_stream_binding *aws_http_stream_binding_new(JNIEnv *env, jobject java_callback_handler) {
107 
108     struct aws_allocator *allocator = aws_jni_get_allocator();
109     struct http_stream_binding *binding = aws_mem_calloc(allocator, 1, sizeof(struct http_stream_binding));
110     AWS_FATAL_ASSERT(binding);
111 
112     // GetJavaVM() reference doesn't need a NewGlobalRef() call since it's global by default
113     jint jvmresult = (*env)->GetJavaVM(env, &binding->jvm);
114     (void)jvmresult;
115     AWS_FATAL_ASSERT(jvmresult == 0);
116 
117     binding->java_http_response_stream_handler = (*env)->NewGlobalRef(env, java_callback_handler);
118     AWS_FATAL_ASSERT(binding->java_http_response_stream_handler);
119     AWS_FATAL_ASSERT(!aws_byte_buf_init(&binding->headers_buf, allocator, 1024));
120 
121     aws_atomic_init_int(&binding->ref, 1);
122 
123     return binding;
124 }
125 
aws_java_http_stream_on_incoming_headers_fn(struct aws_http_stream * stream,enum aws_http_header_block block_type,const struct aws_http_header * header_array,size_t num_headers,void * user_data)126 int aws_java_http_stream_on_incoming_headers_fn(
127     struct aws_http_stream *stream,
128     enum aws_http_header_block block_type,
129     const struct aws_http_header *header_array,
130     size_t num_headers,
131     void *user_data) {
132     (void)block_type;
133 
134     struct http_stream_binding *binding = (struct http_stream_binding *)user_data;
135     int resp_status = -1;
136     int err_code = aws_http_stream_get_incoming_response_status(stream, &resp_status);
137     if (err_code != AWS_OP_SUCCESS) {
138         AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=%p: Invalid Incoming Response Status", (void *)stream);
139         return AWS_OP_ERR;
140     }
141 
142     binding->response_status = resp_status;
143 
144     if (aws_marshal_http_headers_array_to_dynamic_buffer(&binding->headers_buf, header_array, num_headers)) {
145         AWS_LOGF_ERROR(
146             AWS_LS_HTTP_STREAM, "id=%p: Failed to allocate buffer space for incoming headers", (void *)stream);
147         return AWS_OP_ERR;
148     }
149 
150     return AWS_OP_SUCCESS;
151 }
152 
aws_java_http_stream_on_incoming_header_block_done_fn(struct aws_http_stream * stream,enum aws_http_header_block block_type,void * user_data)153 int aws_java_http_stream_on_incoming_header_block_done_fn(
154     struct aws_http_stream *stream,
155     enum aws_http_header_block block_type,
156     void *user_data) {
157     (void)stream;
158 
159     struct http_stream_binding *binding = (struct http_stream_binding *)user_data;
160 
161     /********** JNI ENV ACQUIRE **********/
162     JNIEnv *env = aws_jni_acquire_thread_env(binding->jvm);
163     if (env == NULL) {
164         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
165         return AWS_OP_ERR;
166     }
167 
168     int result = AWS_OP_ERR;
169     jint jni_block_type = block_type;
170 
171     jobject jni_headers_buf =
172         aws_jni_direct_byte_buffer_from_raw_ptr(env, binding->headers_buf.buffer, binding->headers_buf.len);
173 
174     (*env)->CallVoidMethod(
175         env,
176         binding->java_http_response_stream_handler,
177         http_stream_response_handler_properties.onResponseHeaders,
178         binding->java_http_stream_base,
179         (jint)binding->response_status,
180         (jint)block_type,
181         jni_headers_buf);
182 
183     if (aws_jni_check_and_clear_exception(env)) {
184         (*env)->DeleteLocalRef(env, jni_headers_buf);
185         aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
186         goto done;
187     }
188 
189     /* instead of cleaning it up here, reset it in case another block is encountered */
190     aws_byte_buf_reset(&binding->headers_buf, false);
191     (*env)->DeleteLocalRef(env, jni_headers_buf);
192 
193     (*env)->CallVoidMethod(
194         env,
195         binding->java_http_response_stream_handler,
196         http_stream_response_handler_properties.onResponseHeadersDone,
197         binding->java_http_stream_base,
198         jni_block_type);
199 
200     if (aws_jni_check_and_clear_exception(env)) {
201         aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
202         goto done;
203     }
204 
205     result = AWS_OP_SUCCESS;
206 
207 done:
208 
209     aws_jni_release_thread_env(binding->jvm, env);
210     /********** JNI ENV RELEASE **********/
211 
212     return result;
213 }
214 
aws_java_http_stream_on_incoming_body_fn(struct aws_http_stream * stream,const struct aws_byte_cursor * data,void * user_data)215 int aws_java_http_stream_on_incoming_body_fn(
216     struct aws_http_stream *stream,
217     const struct aws_byte_cursor *data,
218     void *user_data) {
219     struct http_stream_binding *binding = (struct http_stream_binding *)user_data;
220 
221     size_t total_window_increment = 0;
222 
223     /********** JNI ENV ACQUIRE **********/
224     JNIEnv *env = aws_jni_acquire_thread_env(binding->jvm);
225     if (env == NULL) {
226         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
227         return AWS_OP_ERR;
228     }
229 
230     int result = AWS_OP_ERR;
231 
232     jobject jni_payload = aws_jni_direct_byte_buffer_from_raw_ptr(env, data->ptr, data->len);
233 
234     jint window_increment = (*env)->CallIntMethod(
235         env,
236         binding->java_http_response_stream_handler,
237         http_stream_response_handler_properties.onResponseBody,
238         binding->java_http_stream_base,
239         jni_payload);
240 
241     (*env)->DeleteLocalRef(env, jni_payload);
242 
243     if (aws_jni_check_and_clear_exception(env)) {
244         AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=%p: Received Exception from onResponseBody", (void *)stream);
245         aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
246         goto done;
247     }
248 
249     if (window_increment < 0) {
250         AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=%p: Window Increment from onResponseBody < 0", (void *)stream);
251         aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
252         goto done;
253     }
254 
255     total_window_increment += window_increment;
256 
257     if (total_window_increment > 0) {
258         aws_http_stream_update_window(stream, total_window_increment);
259     }
260 
261     result = AWS_OP_SUCCESS;
262 
263 done:
264 
265     aws_jni_release_thread_env(binding->jvm, env);
266     /********** JNI ENV RELEASE **********/
267 
268     return result;
269 }
270 
aws_java_http_stream_on_stream_complete_fn(struct aws_http_stream * stream,int error_code,void * user_data)271 void aws_java_http_stream_on_stream_complete_fn(struct aws_http_stream *stream, int error_code, void *user_data) {
272     struct http_stream_binding *binding = (struct http_stream_binding *)user_data;
273 
274     /********** JNI ENV ACQUIRE **********/
275     JNIEnv *env = aws_jni_acquire_thread_env(binding->jvm);
276     if (env == NULL) {
277         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
278         return;
279     }
280 
281     /* Don't invoke Java callbacks if Java HttpStream failed to completely setup */
282     jint jErrorCode = error_code;
283     (*env)->CallVoidMethod(
284         env,
285         binding->java_http_response_stream_handler,
286         http_stream_response_handler_properties.onResponseComplete,
287         binding->java_http_stream_base,
288         jErrorCode);
289 
290     if (aws_jni_check_and_clear_exception(env)) {
291         /* Close the Connection if the Java Callback throws an Exception */
292         aws_http_connection_close(aws_http_stream_get_connection(stream));
293     }
294 
295     aws_jni_release_thread_env(binding->jvm, env);
296     /********** JNI ENV RELEASE **********/
297 }
298 
aws_java_http_stream_on_stream_destroy_fn(void * user_data)299 void aws_java_http_stream_on_stream_destroy_fn(void *user_data) {
300     struct http_stream_binding *binding = (struct http_stream_binding *)user_data;
301 
302     /********** JNI ENV ACQUIRE **********/
303     JNIEnv *env = aws_jni_acquire_thread_env(binding->jvm);
304     if (env == NULL) {
305         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
306         return;
307     }
308     /* Native stream destroyed, release the binding. */
309     aws_http_stream_binding_release(env, binding);
310     aws_jni_release_thread_env(binding->jvm, env);
311     /********** JNI ENV RELEASE **********/
312 }
313 
aws_java_http_stream_on_stream_metrics_fn(struct aws_http_stream * stream,const struct aws_http_stream_metrics * metrics,void * user_data)314 void aws_java_http_stream_on_stream_metrics_fn(
315     struct aws_http_stream *stream,
316     const struct aws_http_stream_metrics *metrics,
317     void *user_data) {
318     struct http_stream_binding *binding = (struct http_stream_binding *)user_data;
319 
320     /********** JNI ENV ACQUIRE **********/
321     JNIEnv *env = aws_jni_acquire_thread_env(binding->jvm);
322     if (env == NULL) {
323         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
324         return;
325     }
326 
327     /* Convert metrics to Java HttpStreamMetrics obj */
328     jobject jni_metrics = (*env)->NewObject(
329         env,
330         http_stream_metrics_properties.http_stream_metrics_class,
331         http_stream_metrics_properties.constructor_id,
332         (jlong)metrics->send_start_timestamp_ns,
333         (jlong)metrics->send_end_timestamp_ns,
334         (jlong)metrics->sending_duration_ns,
335         (jlong)metrics->receive_start_timestamp_ns,
336         (jlong)metrics->receive_end_timestamp_ns,
337         (jlong)metrics->receiving_duration_ns,
338 
339         /* Stream IDs are 31-bit unsigned integers, which fits into Java's regular (signed) 32-bit int */
340         (jint)metrics->stream_id);
341 
342     (*env)->CallVoidMethod(
343         env,
344         binding->java_http_response_stream_handler,
345         http_stream_response_handler_properties.onMetrics,
346         binding->java_http_stream_base,
347         jni_metrics);
348 
349     /* Delete local reference to metrics object */
350     (*env)->DeleteLocalRef(env, jni_metrics);
351 
352     if (aws_jni_check_and_clear_exception(env)) {
353         /* Close the Connection if the Java Callback throws an Exception */
354         aws_http_connection_close(aws_http_stream_get_connection(stream));
355 
356         AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=%p: Received Exception from onMetrics", (void *)stream);
357         aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
358     }
359 
360     aws_jni_release_thread_env(binding->jvm, env);
361     /********** JNI ENV RELEASE **********/
362 }
363 
aws_java_http_headers_from_native(JNIEnv * env,struct aws_http_headers * headers)364 jobjectArray aws_java_http_headers_from_native(JNIEnv *env, struct aws_http_headers *headers) {
365     (void)headers;
366     jobjectArray ret;
367     const size_t header_count = aws_http_headers_count(headers);
368 
369     ret = (jobjectArray)(*env)->NewObjectArray(
370         env, (jsize)header_count, http_header_properties.http_header_class, (void *)NULL);
371 
372     for (size_t index = 0; index < header_count; index += 1) {
373         struct aws_http_header header;
374         aws_http_headers_get_index(headers, index, &header);
375         jbyteArray header_name = aws_jni_byte_array_from_cursor(env, &header.name);
376         jbyteArray header_value = aws_jni_byte_array_from_cursor(env, &header.value);
377 
378         jobject java_http_header = (*env)->NewObject(
379             env,
380             http_header_properties.http_header_class,
381             http_header_properties.constructor_method_id,
382             header_name,
383             header_value);
384 
385         (*env)->SetObjectArrayElement(env, ret, (jsize)index, java_http_header);
386     }
387 
388     return (ret);
389 }
390 
s_make_request_general(JNIEnv * env,jlong jni_connection,jbyteArray marshalled_request,jobject jni_http_request_body_stream,jobject jni_http_response_callback_handler,enum aws_http_version version)391 static jobject s_make_request_general(
392     JNIEnv *env,
393     jlong jni_connection,
394     jbyteArray marshalled_request,
395     jobject jni_http_request_body_stream,
396     jobject jni_http_response_callback_handler,
397     enum aws_http_version version) {
398 
399     struct aws_http_connection_binding *connection_binding = (struct aws_http_connection_binding *)jni_connection;
400     struct aws_http_connection *native_conn = connection_binding->connection;
401 
402     if (!native_conn) {
403         aws_jni_throw_null_pointer_exception(env, "HttpClientConnection.MakeRequest: Invalid aws_http_connection");
404         return (jobject)NULL;
405     }
406 
407     if (!jni_http_response_callback_handler) {
408         aws_jni_throw_illegal_argument_exception(
409             env, "HttpClientConnection.MakeRequest: Invalid jni_http_response_callback_handler");
410         return (jobject)NULL;
411     }
412 
413     /* initial refcount created for the Java object */
414     struct http_stream_binding *stream_binding = aws_http_stream_binding_new(env, jni_http_response_callback_handler);
415     if (!stream_binding) {
416         /* Exception already thrown */
417         return (jobject)NULL;
418     }
419 
420     stream_binding->native_request =
421         aws_http_request_new_from_java_http_request(env, marshalled_request, jni_http_request_body_stream);
422     if (stream_binding->native_request == NULL) {
423         /* Exception already thrown */
424         goto error;
425     }
426 
427     struct aws_http_make_request_options request_options = {
428         .self_size = sizeof(request_options),
429         .request = stream_binding->native_request,
430         /* Set Callbacks */
431         .on_response_headers = aws_java_http_stream_on_incoming_headers_fn,
432         .on_response_header_block_done = aws_java_http_stream_on_incoming_header_block_done_fn,
433         .on_response_body = aws_java_http_stream_on_incoming_body_fn,
434         .on_complete = aws_java_http_stream_on_stream_complete_fn,
435         .on_destroy = aws_java_http_stream_on_stream_destroy_fn,
436         .on_metrics = aws_java_http_stream_on_stream_metrics_fn,
437         .user_data = stream_binding,
438     };
439 
440     stream_binding->native_stream = aws_http_connection_make_request(native_conn, &request_options);
441     if (stream_binding->native_stream == NULL) {
442         AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "Stream Request Failed. conn: %p", (void *)native_conn);
443         aws_jni_throw_runtime_exception(env, "HttpClientConnection.MakeRequest: Unable to Execute Request");
444         goto error;
445     }
446 
447     /* Stream created successfully, acquire on binding for the native stream lifetime. */
448     aws_http_stream_binding_acquire(stream_binding);
449 
450     jobject jHttpStreamBase = aws_java_http_stream_from_native_new(env, stream_binding, version);
451     if (jHttpStreamBase == NULL) {
452         goto error;
453     }
454 
455     AWS_LOGF_TRACE(
456         AWS_LS_HTTP_CONNECTION,
457         "Opened new Stream on Connection. conn: %p, stream: %p",
458         (void *)native_conn,
459         (void *)stream_binding->native_stream);
460 
461     return jHttpStreamBase;
462 
463 error:
464     aws_http_stream_release(stream_binding->native_stream);
465     aws_http_stream_binding_release(env, stream_binding);
466     return NULL;
467 }
468 
Java_software_amazon_awssdk_crt_http_HttpClientConnection_httpClientConnectionMakeRequest(JNIEnv * env,jclass jni_class,jlong jni_connection,jbyteArray marshalled_request,jobject jni_http_request_body_stream,jobject jni_http_response_callback_handler)469 JNIEXPORT jobject JNICALL Java_software_amazon_awssdk_crt_http_HttpClientConnection_httpClientConnectionMakeRequest(
470     JNIEnv *env,
471     jclass jni_class,
472     jlong jni_connection,
473     jbyteArray marshalled_request,
474     jobject jni_http_request_body_stream,
475     jobject jni_http_response_callback_handler) {
476     (void)jni_class;
477     aws_cache_jni_ids(env);
478 
479     return s_make_request_general(
480         env,
481         jni_connection,
482         marshalled_request,
483         jni_http_request_body_stream,
484         jni_http_response_callback_handler,
485         AWS_HTTP_VERSION_1_1);
486 }
487 
Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionMakeRequest(JNIEnv * env,jclass jni_class,jlong jni_connection,jbyteArray marshalled_request,jobject jni_http_request_body_stream,jobject jni_http_response_callback_handler)488 JNIEXPORT jobject JNICALL Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionMakeRequest(
489     JNIEnv *env,
490     jclass jni_class,
491     jlong jni_connection,
492     jbyteArray marshalled_request,
493     jobject jni_http_request_body_stream,
494     jobject jni_http_response_callback_handler) {
495     (void)jni_class;
496     aws_cache_jni_ids(env);
497 
498     return s_make_request_general(
499         env,
500         jni_connection,
501         marshalled_request,
502         jni_http_request_body_stream,
503         jni_http_response_callback_handler,
504         AWS_HTTP_VERSION_2);
505 }
506 
507 struct http_stream_chunked_callback_data {
508     struct http_stream_binding *stream_cb_data;
509     struct aws_byte_buf chunk_data;
510     struct aws_input_stream *chunk_stream;
511     jobject completion_callback;
512 };
513 
s_cleanup_chunked_callback_data(JNIEnv * env,struct http_stream_chunked_callback_data * chunked_callback_data)514 static void s_cleanup_chunked_callback_data(
515     JNIEnv *env,
516     struct http_stream_chunked_callback_data *chunked_callback_data) {
517     aws_input_stream_destroy(chunked_callback_data->chunk_stream);
518     aws_byte_buf_clean_up(&chunked_callback_data->chunk_data);
519     (*env)->DeleteGlobalRef(env, chunked_callback_data->completion_callback);
520     aws_mem_release(aws_jni_get_allocator(), chunked_callback_data);
521 }
522 
s_write_chunk_complete(struct aws_http_stream * stream,int error_code,void * user_data)523 static void s_write_chunk_complete(struct aws_http_stream *stream, int error_code, void *user_data) {
524     (void)stream;
525 
526     struct http_stream_chunked_callback_data *chunked_callback_data = user_data;
527 
528     /********** JNI ENV ACQUIRE **********/
529     JNIEnv *env = aws_jni_acquire_thread_env(chunked_callback_data->stream_cb_data->jvm);
530     if (env == NULL) {
531         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
532         return;
533     }
534 
535     (*env)->CallVoidMethod(
536         env,
537         chunked_callback_data->completion_callback,
538         http_stream_write_chunk_completion_properties.callback,
539         error_code);
540     aws_jni_check_and_clear_exception(env);
541 
542     JavaVM *jvm = chunked_callback_data->stream_cb_data->jvm;
543     s_cleanup_chunked_callback_data(env, chunked_callback_data);
544     aws_jni_release_thread_env(jvm, env);
545     /********** JNI ENV RELEASE **********/
546 }
547 
Java_software_amazon_awssdk_crt_http_HttpStream_httpStreamWriteChunk(JNIEnv * env,jclass jni_class,jlong jni_cb_data,jbyteArray chunk_data,jboolean is_final_chunk,jobject completion_callback)548 JNIEXPORT jint JNICALL Java_software_amazon_awssdk_crt_http_HttpStream_httpStreamWriteChunk(
549     JNIEnv *env,
550     jclass jni_class,
551     jlong jni_cb_data,
552     jbyteArray chunk_data,
553     jboolean is_final_chunk,
554     jobject completion_callback) {
555     (void)jni_class;
556     aws_cache_jni_ids(env);
557 
558     struct http_stream_binding *cb_data = (struct http_stream_binding *)jni_cb_data;
559     struct aws_http_stream *stream = cb_data->native_stream;
560 
561     struct http_stream_chunked_callback_data *chunked_callback_data =
562         aws_mem_calloc(aws_jni_get_allocator(), 1, sizeof(struct http_stream_chunked_callback_data));
563 
564     chunked_callback_data->stream_cb_data = cb_data;
565     chunked_callback_data->completion_callback = (*env)->NewGlobalRef(env, completion_callback);
566 
567     struct aws_byte_cursor chunk_cur = aws_jni_byte_cursor_from_jbyteArray_acquire(env, chunk_data);
568     aws_byte_buf_init_copy_from_cursor(&chunked_callback_data->chunk_data, aws_jni_get_allocator(), chunk_cur);
569     aws_jni_byte_cursor_from_jbyteArray_release(env, chunk_data, chunk_cur);
570 
571     struct aws_http1_chunk_options chunk_options = {
572         .chunk_data_size = chunked_callback_data->chunk_data.len,
573         .user_data = chunked_callback_data,
574         .on_complete = s_write_chunk_complete,
575     };
576 
577     chunk_cur = aws_byte_cursor_from_buf(&chunked_callback_data->chunk_data);
578     chunked_callback_data->chunk_stream = aws_input_stream_new_from_cursor(aws_jni_get_allocator(), &chunk_cur);
579     chunk_options.chunk_data = chunked_callback_data->chunk_stream;
580 
581     if (aws_http1_stream_write_chunk(stream, &chunk_options)) {
582         s_cleanup_chunked_callback_data(env, chunked_callback_data);
583         return AWS_OP_ERR;
584     }
585 
586     if (is_final_chunk) {
587         struct aws_http1_chunk_options final_chunk_options = {
588             .chunk_data_size = 0,
589         };
590 
591         if (aws_http1_stream_write_chunk(stream, &final_chunk_options)) {
592             return AWS_OP_ERR;
593         }
594     }
595 
596     return AWS_OP_SUCCESS;
597 }
598 
Java_software_amazon_awssdk_crt_http_HttpStreamBase_httpStreamBaseActivate(JNIEnv * env,jclass jni_class,jlong jni_stream_binding,jobject j_http_stream_base)599 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_HttpStreamBase_httpStreamBaseActivate(
600     JNIEnv *env,
601     jclass jni_class,
602     jlong jni_stream_binding,
603     jobject j_http_stream_base) {
604     (void)jni_class;
605     aws_cache_jni_ids(env);
606 
607     struct http_stream_binding *binding = (struct http_stream_binding *)jni_stream_binding;
608     struct aws_http_stream *stream = binding->native_stream;
609 
610     if (stream == NULL) {
611         aws_jni_throw_runtime_exception(env, "HttpStream is null.");
612         return;
613     }
614 
615     AWS_LOGF_TRACE(AWS_LS_HTTP_STREAM, "Activating Stream. stream: %p", (void *)stream);
616 
617     /* global ref this because now the callbacks will be firing, and they will release their reference when the
618      * stream callback sequence completes. */
619     binding->java_http_stream_base = (*env)->NewGlobalRef(env, j_http_stream_base);
620     if (aws_http_stream_activate(stream)) {
621         (*env)->DeleteGlobalRef(env, binding->java_http_stream_base);
622         aws_jni_throw_runtime_exception(
623             env, "HttpStream activate failed with error %s\n", aws_error_str(aws_last_error()));
624     }
625 }
626 
Java_software_amazon_awssdk_crt_http_HttpStreamBase_httpStreamBaseRelease(JNIEnv * env,jclass jni_class,jlong jni_binding)627 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_HttpStreamBase_httpStreamBaseRelease(
628     JNIEnv *env,
629     jclass jni_class,
630     jlong jni_binding) {
631 
632     (void)jni_class;
633     aws_cache_jni_ids(env);
634 
635     struct http_stream_binding *binding = (struct http_stream_binding *)jni_binding;
636     struct aws_http_stream *stream = binding->native_stream;
637 
638     if (stream == NULL) {
639         aws_jni_throw_runtime_exception(env, "HttpStream is null.");
640         return;
641     }
642     AWS_LOGF_TRACE(AWS_LS_HTTP_STREAM, "Releasing Stream. stream: %p", (void *)stream);
643     aws_http_stream_release(stream);
644 
645     aws_http_stream_binding_release(env, binding);
646 }
647 
Java_software_amazon_awssdk_crt_http_HttpStreamBase_httpStreamBaseGetResponseStatusCode(JNIEnv * env,jclass jni_class,jlong jni_binding)648 JNIEXPORT jint JNICALL Java_software_amazon_awssdk_crt_http_HttpStreamBase_httpStreamBaseGetResponseStatusCode(
649     JNIEnv *env,
650     jclass jni_class,
651     jlong jni_binding) {
652 
653     (void)jni_class;
654     aws_cache_jni_ids(env);
655 
656     struct http_stream_binding *binding = (struct http_stream_binding *)jni_binding;
657     struct aws_http_stream *stream = binding->native_stream;
658 
659     if (stream == NULL) {
660         aws_jni_throw_runtime_exception(env, "HttpStream is null.");
661         return -1;
662     }
663 
664     int status = -1;
665     int err_code = aws_http_stream_get_incoming_response_status(stream, &status);
666 
667     if (err_code != AWS_OP_SUCCESS) {
668         aws_jni_throw_runtime_exception(env, "Error Getting Response Status Code from HttpStream.");
669         return -1;
670     }
671 
672     return (jint)status;
673 }
674 
Java_software_amazon_awssdk_crt_http_HttpStreamBase_httpStreamBaseIncrementWindow(JNIEnv * env,jclass jni_class,jlong jni_binding,jint window_update)675 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_HttpStreamBase_httpStreamBaseIncrementWindow(
676     JNIEnv *env,
677     jclass jni_class,
678     jlong jni_binding,
679     jint window_update) {
680 
681     (void)jni_class;
682     aws_cache_jni_ids(env);
683 
684     struct http_stream_binding *binding = (struct http_stream_binding *)jni_binding;
685     struct aws_http_stream *stream = binding->native_stream;
686 
687     if (stream == NULL) {
688         aws_jni_throw_runtime_exception(env, "HttpStream is null.");
689         return;
690     }
691 
692     if (window_update < 0) {
693         aws_jni_throw_runtime_exception(env, "Window Update is < 0");
694         return;
695     }
696 
697     AWS_LOGF_TRACE(
698         AWS_LS_HTTP_STREAM, "Updating Stream Window. stream: %p, update: %d", (void *)stream, (int)window_update);
699     aws_http_stream_update_window(stream, window_update);
700 }
701 
Java_software_amazon_awssdk_crt_http_Http2Stream_http2StreamResetStream(JNIEnv * env,jclass jni_class,jlong jni_cb_data,jint error_code)702 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_Http2Stream_http2StreamResetStream(
703     JNIEnv *env,
704     jclass jni_class,
705     jlong jni_cb_data,
706     jint error_code) {
707 
708     (void)jni_class;
709     aws_cache_jni_ids(env);
710 
711     struct http_stream_binding *binding = (struct http_stream_binding *)jni_cb_data;
712     struct aws_http_stream *stream = binding->native_stream;
713 
714     if (stream == NULL) {
715         aws_jni_throw_null_pointer_exception(env, "Http2Stream is null.");
716         return;
717     }
718 
719     AWS_LOGF_TRACE(AWS_LS_HTTP_STREAM, "Resetting Stream. stream: %p", (void *)stream);
720     if (aws_http2_stream_reset(stream, error_code)) {
721         aws_jni_throw_runtime_exception(
722             env, "reset stream failed with error %d(%s).", aws_last_error(), aws_error_debug_str(aws_last_error()));
723         return;
724     }
725 }
726 
Java_software_amazon_awssdk_crt_http_HttpClientConnection_httpClientConnectionShutdown(JNIEnv * env,jclass jni_class,jlong jni_connection)727 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_HttpClientConnection_httpClientConnectionShutdown(
728     JNIEnv *env,
729     jclass jni_class,
730     jlong jni_connection) {
731 
732     (void)jni_class;
733     aws_cache_jni_ids(env);
734 
735     struct aws_http_connection_binding *connection_binding = (struct aws_http_connection_binding *)jni_connection;
736     struct aws_http_connection *native_conn = connection_binding->connection;
737 
738     if (!native_conn) {
739         aws_jni_throw_runtime_exception(env, "HttpClientConnection.Shutdown: Invalid aws_http_connection");
740         return;
741     }
742 
743     aws_http_connection_close(native_conn);
744 }
745 
Java_software_amazon_awssdk_crt_http_HttpClientConnection_httpClientConnectionIsOpen(JNIEnv * env,jclass jni_class,jlong jni_connection)746 JNIEXPORT jboolean JNICALL Java_software_amazon_awssdk_crt_http_HttpClientConnection_httpClientConnectionIsOpen(
747     JNIEnv *env,
748     jclass jni_class,
749     jlong jni_connection) {
750 
751     (void)jni_class;
752     aws_cache_jni_ids(env);
753 
754     struct aws_http_connection_binding *connection_binding = (struct aws_http_connection_binding *)jni_connection;
755     struct aws_http_connection *native_conn = connection_binding->connection;
756 
757     if (!native_conn) {
758         aws_jni_throw_runtime_exception(env, "HttpClientConnection.isOpen: Invalid aws_http_connection");
759         return false;
760     }
761 
762     return aws_http_connection_is_open(native_conn);
763 }
764 
Java_software_amazon_awssdk_crt_http_HttpClientConnection_httpClientConnectionGetVersion(JNIEnv * env,jclass jni_class,jlong jni_connection)765 JNIEXPORT jshort JNICALL Java_software_amazon_awssdk_crt_http_HttpClientConnection_httpClientConnectionGetVersion(
766     JNIEnv *env,
767     jclass jni_class,
768     jlong jni_connection) {
769 
770     (void)jni_class;
771     aws_cache_jni_ids(env);
772 
773     struct aws_http_connection_binding *connection_binding = (struct aws_http_connection_binding *)jni_connection;
774     struct aws_http_connection *native_conn = connection_binding->connection;
775 
776     if (!native_conn) {
777         aws_jni_throw_runtime_exception(env, "HttpClientConnection.getVersion: Invalid aws_http_connection");
778         return 0;
779     }
780     return (jshort)aws_http_connection_get_version(native_conn);
781 }
782 
Java_software_amazon_awssdk_crt_http_HttpClientConnection_isErrorRetryable(JNIEnv * env,jclass jni_class,jint error_code)783 JNIEXPORT jboolean JNICALL Java_software_amazon_awssdk_crt_http_HttpClientConnection_isErrorRetryable(
784     JNIEnv *env,
785     jclass jni_class,
786     jint error_code) {
787 
788     (void)jni_class;
789     (void)env;
790     aws_cache_jni_ids(env);
791 
792     switch (error_code) {
793         case AWS_ERROR_HTTP_HEADER_NOT_FOUND:
794         case AWS_ERROR_HTTP_INVALID_HEADER_FIELD:
795         case AWS_ERROR_HTTP_INVALID_HEADER_NAME:
796         case AWS_ERROR_HTTP_INVALID_HEADER_VALUE:
797         case AWS_ERROR_HTTP_INVALID_METHOD:
798         case AWS_ERROR_HTTP_INVALID_PATH:
799         case AWS_ERROR_HTTP_INVALID_STATUS_CODE:
800         case AWS_ERROR_HTTP_MISSING_BODY_STREAM:
801         case AWS_ERROR_HTTP_INVALID_BODY_STREAM:
802         case AWS_ERROR_HTTP_OUTGOING_STREAM_LENGTH_INCORRECT:
803         case AWS_ERROR_HTTP_CALLBACK_FAILURE:
804         case AWS_ERROR_HTTP_STREAM_MANAGER_SHUTTING_DOWN:
805         case AWS_HTTP2_ERR_CANCEL:
806             return false;
807         default:
808             return true;
809     }
810 }
811 
812 struct aws_http2_callback_data {
813     JavaVM *jvm;
814     jobject async_callback;
815 };
816 
s_cleanup_http2_callback_data(struct aws_http2_callback_data * callback_data,JNIEnv * env)817 static void s_cleanup_http2_callback_data(struct aws_http2_callback_data *callback_data, JNIEnv *env) {
818     if (callback_data == NULL || env == NULL) {
819         return;
820     }
821 
822     if (callback_data->async_callback) {
823         (*env)->DeleteGlobalRef(env, callback_data->async_callback);
824     }
825 
826     aws_mem_release(aws_jni_get_allocator(), callback_data);
827 }
828 
s_new_http2_callback_data(JNIEnv * env,struct aws_allocator * allocator,jobject async_callback)829 static struct aws_http2_callback_data *s_new_http2_callback_data(
830     JNIEnv *env,
831     struct aws_allocator *allocator,
832     jobject async_callback) {
833     struct aws_http2_callback_data *callback_data =
834         aws_mem_calloc(allocator, 1, sizeof(struct aws_http2_callback_data));
835 
836     jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
837     AWS_FATAL_ASSERT(jvmresult == 0);
838     callback_data->async_callback = async_callback ? (*env)->NewGlobalRef(env, async_callback) : NULL;
839     AWS_FATAL_ASSERT(callback_data->async_callback != NULL);
840 
841     return callback_data;
842 }
843 
s_on_settings_completed(struct aws_http_connection * http2_connection,int error_code,void * user_data)844 static void s_on_settings_completed(struct aws_http_connection *http2_connection, int error_code, void *user_data) {
845     (void)http2_connection;
846     struct aws_http2_callback_data *callback_data = user_data;
847 
848     /********** JNI ENV ACQUIRE **********/
849     JavaVM *jvm = callback_data->jvm;
850     JNIEnv *env = aws_jni_acquire_thread_env(jvm);
851     if (env == NULL) {
852         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
853         return;
854     }
855 
856     if (error_code) {
857         jobject crt_exception = aws_jni_new_crt_exception_from_error_code(env, error_code);
858         (*env)->CallVoidMethod(env, callback_data->async_callback, async_callback_properties.on_failure, crt_exception);
859         (*env)->DeleteLocalRef(env, crt_exception);
860     } else {
861         (*env)->CallVoidMethod(env, callback_data->async_callback, async_callback_properties.on_success);
862     }
863     AWS_FATAL_ASSERT(!aws_jni_check_and_clear_exception(env));
864     s_cleanup_http2_callback_data(callback_data, env);
865 
866     aws_jni_release_thread_env(jvm, env);
867     /********** JNI ENV RELEASE **********/
868 }
869 
Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionUpdateSettings(JNIEnv * env,jclass jni_class,jlong jni_connection,jobject java_async_callback,jlongArray java_marshalled_settings)870 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionUpdateSettings(
871     JNIEnv *env,
872     jclass jni_class,
873     jlong jni_connection,
874     jobject java_async_callback,
875     jlongArray java_marshalled_settings) {
876 
877     (void)jni_class;
878     aws_cache_jni_ids(env);
879 
880     struct aws_http_connection_binding *connection_binding = (struct aws_http_connection_binding *)jni_connection;
881     struct aws_http_connection *native_conn = connection_binding->connection;
882 
883     if (!native_conn) {
884         aws_jni_throw_null_pointer_exception(
885             env, "Http2ClientConnection.http2ClientConnectionUpdateSettings: Invalid aws_http_connection");
886         return;
887     }
888     if (!java_async_callback) {
889         aws_jni_throw_illegal_argument_exception(
890             env, "Http2ClientConnection.http2ClientConnectionUpdateSettings: Invalid async callback");
891         return;
892     }
893     struct aws_allocator *allocator = aws_jni_get_allocator();
894     struct aws_http2_callback_data *callback_data = s_new_http2_callback_data(env, allocator, java_async_callback);
895 
896     /* We marshalled each setting to two long integers, the long list will be number of settings times two */
897     const size_t len = (*env)->GetArrayLength(env, java_marshalled_settings);
898     AWS_ASSERT(len % 2 == 0);
899     const size_t settings_len = len / 2;
900     struct aws_http2_setting *settings =
901         settings_len ? aws_mem_calloc(allocator, settings_len, sizeof(struct aws_http2_setting)) : NULL;
902     int success = false;
903     jlong *marshalled_settings = (*env)->GetLongArrayElements(env, java_marshalled_settings, NULL);
904     for (size_t i = 0; i < settings_len; i++) {
905         jlong id = marshalled_settings[i * 2];
906         settings[i].id = id;
907         jlong value = marshalled_settings[i * 2 + 1];
908         settings[i].value = (uint32_t)value;
909     }
910 
911     if (aws_http2_connection_change_settings(
912             native_conn, settings, settings_len, s_on_settings_completed, callback_data)) {
913         aws_jni_throw_runtime_exception(
914             env, "Http2ClientConnection.http2ClientConnectionUpdateSettings: failed to change settings");
915         goto done;
916     }
917     success = true;
918 done:
919     aws_mem_release(allocator, settings);
920     (*env)->ReleaseLongArrayElements(env, java_marshalled_settings, (jlong *)marshalled_settings, JNI_ABORT);
921     if (!success) {
922         s_cleanup_http2_callback_data(callback_data, env);
923     }
924     return;
925 }
926 
s_on_ping_completed(struct aws_http_connection * http2_connection,uint64_t round_trip_time_ns,int error_code,void * user_data)927 static void s_on_ping_completed(
928     struct aws_http_connection *http2_connection,
929     uint64_t round_trip_time_ns,
930     int error_code,
931     void *user_data) {
932     (void)http2_connection;
933     struct aws_http2_callback_data *callback_data = user_data;
934 
935     /********** JNI ENV ACQUIRE **********/
936     JavaVM *jvm = callback_data->jvm;
937     JNIEnv *env = aws_jni_acquire_thread_env(jvm);
938     if (env == NULL) {
939         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
940         return;
941     }
942 
943     if (error_code) {
944         jobject crt_exception = aws_jni_new_crt_exception_from_error_code(env, error_code);
945         (*env)->CallVoidMethod(env, callback_data->async_callback, async_callback_properties.on_failure, crt_exception);
946         (*env)->DeleteLocalRef(env, crt_exception);
947     } else {
948         jobject java_round_trip_time_ns = (*env)->NewObject(
949             env, boxed_long_properties.long_class, boxed_long_properties.constructor, (jlong)round_trip_time_ns);
950         (*env)->CallVoidMethod(
951             env,
952             callback_data->async_callback,
953             async_callback_properties.on_success_with_object,
954             java_round_trip_time_ns);
955         (*env)->DeleteLocalRef(env, java_round_trip_time_ns);
956     }
957     AWS_FATAL_ASSERT(!aws_jni_check_and_clear_exception(env));
958     s_cleanup_http2_callback_data(callback_data, env);
959 
960     aws_jni_release_thread_env(jvm, env);
961     /********** JNI ENV RELEASE **********/
962 }
963 
Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionSendPing(JNIEnv * env,jclass jni_class,jlong jni_connection,jobject java_async_callback,jbyteArray ping_data)964 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionSendPing(
965     JNIEnv *env,
966     jclass jni_class,
967     jlong jni_connection,
968     jobject java_async_callback,
969     jbyteArray ping_data) {
970 
971     (void)jni_class;
972     aws_cache_jni_ids(env);
973 
974     struct aws_http_connection_binding *connection_binding = (struct aws_http_connection_binding *)jni_connection;
975     struct aws_http_connection *native_conn = connection_binding->connection;
976 
977     if (!native_conn) {
978         aws_jni_throw_null_pointer_exception(
979             env, "Http2ClientConnection.http2ClientConnectionSendPing: Invalid aws_http_connection");
980         return;
981     }
982     if (!java_async_callback) {
983         aws_jni_throw_illegal_argument_exception(
984             env, "Http2ClientConnection.http2ClientConnectionSendPing: Invalid async callback");
985         return;
986     }
987     bool success = false;
988     struct aws_allocator *allocator = aws_jni_get_allocator();
989     struct aws_byte_cursor *ping_cur_pointer = NULL;
990     struct aws_byte_cursor ping_cur;
991     AWS_ZERO_STRUCT(ping_cur);
992     struct aws_http2_callback_data *callback_data = s_new_http2_callback_data(env, allocator, java_async_callback);
993 
994     if (ping_data) {
995         ping_cur = aws_jni_byte_cursor_from_jbyteArray_acquire(env, ping_data);
996         ping_cur_pointer = &ping_cur;
997     }
998     if (aws_http2_connection_ping(native_conn, ping_cur_pointer, s_on_ping_completed, callback_data)) {
999         aws_jni_throw_runtime_exception(env, "Failed to send ping");
1000         goto done;
1001     }
1002     success = true;
1003 done:
1004     if (ping_cur_pointer) {
1005         aws_jni_byte_cursor_from_jbyteArray_release(env, ping_data, ping_cur);
1006     }
1007     if (!success) {
1008         s_cleanup_http2_callback_data(callback_data, env);
1009     }
1010     return;
1011 }
1012 
Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionSendGoAway(JNIEnv * env,jclass jni_class,jlong jni_connection,jlong h2_error_code,jboolean allow_more_streams,jbyteArray debug_data)1013 JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionSendGoAway(
1014     JNIEnv *env,
1015     jclass jni_class,
1016     jlong jni_connection,
1017     jlong h2_error_code,
1018     jboolean allow_more_streams,
1019     jbyteArray debug_data) {
1020 
1021     (void)jni_class;
1022     aws_cache_jni_ids(env);
1023 
1024     struct aws_http_connection_binding *connection_binding = (struct aws_http_connection_binding *)jni_connection;
1025     struct aws_http_connection *native_conn = connection_binding->connection;
1026     struct aws_byte_cursor *debug_cur_pointer = NULL;
1027     struct aws_byte_cursor debug_cur;
1028     AWS_ZERO_STRUCT(debug_cur);
1029 
1030     if (!native_conn) {
1031         aws_jni_throw_runtime_exception(
1032             env, "Http2ClientConnection.http2ClientConnectionSendGoAway: Invalid aws_http_connection");
1033         return;
1034     }
1035     if (debug_data) {
1036         debug_cur = aws_jni_byte_cursor_from_jbyteArray_acquire(env, debug_data);
1037         debug_cur_pointer = &debug_cur;
1038     }
1039     aws_http2_connection_send_goaway(native_conn, (uint32_t)h2_error_code, allow_more_streams, debug_cur_pointer);
1040     if (debug_cur_pointer) {
1041         aws_jni_byte_cursor_from_jbyteArray_release(env, debug_data, debug_cur);
1042     }
1043     return;
1044 }
1045 
1046 JNIEXPORT void JNICALL
Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionUpdateConnectionWindow(JNIEnv * env,jclass jni_class,jlong jni_connection,jlong increment_size)1047     Java_software_amazon_awssdk_crt_http_Http2ClientConnection_http2ClientConnectionUpdateConnectionWindow(
1048         JNIEnv *env,
1049         jclass jni_class,
1050         jlong jni_connection,
1051         jlong increment_size) {
1052 
1053     (void)jni_class;
1054     aws_cache_jni_ids(env);
1055 
1056     struct aws_http_connection_binding *connection_binding = (struct aws_http_connection_binding *)jni_connection;
1057     struct aws_http_connection *native_conn = connection_binding->connection;
1058 
1059     if (!native_conn) {
1060         aws_jni_throw_runtime_exception(
1061             env, "Http2ClientConnection.http2ClientConnectionUpdateConnectionWindow: Invalid aws_http_connection");
1062         return;
1063     }
1064     /* We did range check in Java already. */
1065     aws_http2_connection_update_window(native_conn, (uint32_t)increment_size);
1066     return;
1067 }
1068 
1069 #if UINTPTR_MAX == 0xffffffff
1070 #    if defined(_MSC_VER)
1071 #        pragma warning(pop)
1072 #    else
1073 #        pragma GCC diagnostic pop
1074 #    endif
1075 #endif
1076