xref: /aosp_15_r20/external/aws-crt-java/src/native/http_request_utils.c (revision 3c7ae9de214676c52d19f01067dc1a404272dc11)
1*3c7ae9deSAndroid Build Coastguard Worker /**
2*3c7ae9deSAndroid Build Coastguard Worker  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3*3c7ae9deSAndroid Build Coastguard Worker  * SPDX-License-Identifier: Apache-2.0.
4*3c7ae9deSAndroid Build Coastguard Worker  */
5*3c7ae9deSAndroid Build Coastguard Worker 
6*3c7ae9deSAndroid Build Coastguard Worker #include "http_request_utils.h"
7*3c7ae9deSAndroid Build Coastguard Worker 
8*3c7ae9deSAndroid Build Coastguard Worker #include "crt.h"
9*3c7ae9deSAndroid Build Coastguard Worker #include "java_class_ids.h"
10*3c7ae9deSAndroid Build Coastguard Worker 
11*3c7ae9deSAndroid Build Coastguard Worker #include <aws/common/byte_order.h>
12*3c7ae9deSAndroid Build Coastguard Worker #include <aws/http/http.h>
13*3c7ae9deSAndroid Build Coastguard Worker #include <aws/http/request_response.h>
14*3c7ae9deSAndroid Build Coastguard Worker #include <aws/io/stream.h>
15*3c7ae9deSAndroid Build Coastguard Worker 
16*3c7ae9deSAndroid Build Coastguard Worker #if _MSC_VER
17*3c7ae9deSAndroid Build Coastguard Worker #    pragma warning(disable : 4204) /* non-constant aggregate initializer */
18*3c7ae9deSAndroid Build Coastguard Worker #endif
19*3c7ae9deSAndroid Build Coastguard Worker 
20*3c7ae9deSAndroid Build Coastguard Worker struct aws_http_request_body_stream_impl {
21*3c7ae9deSAndroid Build Coastguard Worker     struct aws_input_stream base;
22*3c7ae9deSAndroid Build Coastguard Worker     struct aws_allocator *allocator;
23*3c7ae9deSAndroid Build Coastguard Worker     JavaVM *jvm;
24*3c7ae9deSAndroid Build Coastguard Worker     jobject http_request_body_stream;
25*3c7ae9deSAndroid Build Coastguard Worker     bool body_done;
26*3c7ae9deSAndroid Build Coastguard Worker     bool is_valid;
27*3c7ae9deSAndroid Build Coastguard Worker };
28*3c7ae9deSAndroid Build Coastguard Worker 
s_aws_input_stream_seek(struct aws_input_stream * stream,int64_t offset,enum aws_stream_seek_basis basis)29*3c7ae9deSAndroid Build Coastguard Worker static int s_aws_input_stream_seek(struct aws_input_stream *stream, int64_t offset, enum aws_stream_seek_basis basis) {
30*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_request_body_stream_impl *impl =
31*3c7ae9deSAndroid Build Coastguard Worker         AWS_CONTAINER_OF(stream, struct aws_http_request_body_stream_impl, base);
32*3c7ae9deSAndroid Build Coastguard Worker 
33*3c7ae9deSAndroid Build Coastguard Worker     if (!impl->is_valid) {
34*3c7ae9deSAndroid Build Coastguard Worker         return aws_raise_error(AWS_ERROR_HTTP_INVALID_BODY_STREAM);
35*3c7ae9deSAndroid Build Coastguard Worker     }
36*3c7ae9deSAndroid Build Coastguard Worker 
37*3c7ae9deSAndroid Build Coastguard Worker     int result = AWS_OP_SUCCESS;
38*3c7ae9deSAndroid Build Coastguard Worker     if (impl->http_request_body_stream != NULL) {
39*3c7ae9deSAndroid Build Coastguard Worker         if (basis != AWS_SSB_BEGIN || offset != 0) {
40*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
41*3c7ae9deSAndroid Build Coastguard Worker         }
42*3c7ae9deSAndroid Build Coastguard Worker 
43*3c7ae9deSAndroid Build Coastguard Worker         /********** JNI ENV ACQUIRE **********/
44*3c7ae9deSAndroid Build Coastguard Worker         JNIEnv *env = aws_jni_acquire_thread_env(impl->jvm);
45*3c7ae9deSAndroid Build Coastguard Worker         if (env == NULL) {
46*3c7ae9deSAndroid Build Coastguard Worker             /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
47*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
48*3c7ae9deSAndroid Build Coastguard Worker         }
49*3c7ae9deSAndroid Build Coastguard Worker 
50*3c7ae9deSAndroid Build Coastguard Worker         if (!(*env)->CallBooleanMethod(
51*3c7ae9deSAndroid Build Coastguard Worker                 env, impl->http_request_body_stream, http_request_body_stream_properties.reset_position)) {
52*3c7ae9deSAndroid Build Coastguard Worker             result = aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
53*3c7ae9deSAndroid Build Coastguard Worker         }
54*3c7ae9deSAndroid Build Coastguard Worker 
55*3c7ae9deSAndroid Build Coastguard Worker         if (aws_jni_check_and_clear_exception(env)) {
56*3c7ae9deSAndroid Build Coastguard Worker             result = aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
57*3c7ae9deSAndroid Build Coastguard Worker         }
58*3c7ae9deSAndroid Build Coastguard Worker 
59*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_release_thread_env(impl->jvm, env);
60*3c7ae9deSAndroid Build Coastguard Worker         /********** JNI ENV RELEASE **********/
61*3c7ae9deSAndroid Build Coastguard Worker     }
62*3c7ae9deSAndroid Build Coastguard Worker 
63*3c7ae9deSAndroid Build Coastguard Worker     if (result == AWS_OP_SUCCESS) {
64*3c7ae9deSAndroid Build Coastguard Worker         impl->body_done = false;
65*3c7ae9deSAndroid Build Coastguard Worker     }
66*3c7ae9deSAndroid Build Coastguard Worker 
67*3c7ae9deSAndroid Build Coastguard Worker     return result;
68*3c7ae9deSAndroid Build Coastguard Worker }
69*3c7ae9deSAndroid Build Coastguard Worker 
s_aws_input_stream_read(struct aws_input_stream * stream,struct aws_byte_buf * dest)70*3c7ae9deSAndroid Build Coastguard Worker static int s_aws_input_stream_read(struct aws_input_stream *stream, struct aws_byte_buf *dest) {
71*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_request_body_stream_impl *impl =
72*3c7ae9deSAndroid Build Coastguard Worker         AWS_CONTAINER_OF(stream, struct aws_http_request_body_stream_impl, base);
73*3c7ae9deSAndroid Build Coastguard Worker 
74*3c7ae9deSAndroid Build Coastguard Worker     if (!impl->is_valid) {
75*3c7ae9deSAndroid Build Coastguard Worker         return aws_raise_error(AWS_ERROR_HTTP_INVALID_BODY_STREAM);
76*3c7ae9deSAndroid Build Coastguard Worker     }
77*3c7ae9deSAndroid Build Coastguard Worker 
78*3c7ae9deSAndroid Build Coastguard Worker     if (impl->http_request_body_stream == NULL) {
79*3c7ae9deSAndroid Build Coastguard Worker         impl->body_done = true;
80*3c7ae9deSAndroid Build Coastguard Worker         return AWS_OP_SUCCESS;
81*3c7ae9deSAndroid Build Coastguard Worker     }
82*3c7ae9deSAndroid Build Coastguard Worker 
83*3c7ae9deSAndroid Build Coastguard Worker     if (impl->body_done) {
84*3c7ae9deSAndroid Build Coastguard Worker         return AWS_OP_SUCCESS;
85*3c7ae9deSAndroid Build Coastguard Worker     }
86*3c7ae9deSAndroid Build Coastguard Worker 
87*3c7ae9deSAndroid Build Coastguard Worker     /********** JNI ENV ACQUIRE **********/
88*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env = aws_jni_acquire_thread_env(impl->jvm);
89*3c7ae9deSAndroid Build Coastguard Worker     if (env == NULL) {
90*3c7ae9deSAndroid Build Coastguard Worker         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
91*3c7ae9deSAndroid Build Coastguard Worker         return AWS_OP_ERR;
92*3c7ae9deSAndroid Build Coastguard Worker     }
93*3c7ae9deSAndroid Build Coastguard Worker 
94*3c7ae9deSAndroid Build Coastguard Worker     size_t out_remaining = dest->capacity - dest->len;
95*3c7ae9deSAndroid Build Coastguard Worker 
96*3c7ae9deSAndroid Build Coastguard Worker     jobject direct_buffer = aws_jni_direct_byte_buffer_from_raw_ptr(env, dest->buffer + dest->len, out_remaining);
97*3c7ae9deSAndroid Build Coastguard Worker 
98*3c7ae9deSAndroid Build Coastguard Worker     impl->body_done = (*env)->CallBooleanMethod(
99*3c7ae9deSAndroid Build Coastguard Worker         env, impl->http_request_body_stream, http_request_body_stream_properties.send_outgoing_body, direct_buffer);
100*3c7ae9deSAndroid Build Coastguard Worker 
101*3c7ae9deSAndroid Build Coastguard Worker     int result = AWS_OP_SUCCESS;
102*3c7ae9deSAndroid Build Coastguard Worker     if (aws_jni_check_and_clear_exception(env)) {
103*3c7ae9deSAndroid Build Coastguard Worker         result = aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
104*3c7ae9deSAndroid Build Coastguard Worker     } else {
105*3c7ae9deSAndroid Build Coastguard Worker         size_t amt_written = aws_jni_byte_buffer_get_position(env, direct_buffer);
106*3c7ae9deSAndroid Build Coastguard Worker         dest->len += amt_written;
107*3c7ae9deSAndroid Build Coastguard Worker     }
108*3c7ae9deSAndroid Build Coastguard Worker 
109*3c7ae9deSAndroid Build Coastguard Worker     (*env)->DeleteLocalRef(env, direct_buffer);
110*3c7ae9deSAndroid Build Coastguard Worker 
111*3c7ae9deSAndroid Build Coastguard Worker     aws_jni_release_thread_env(impl->jvm, env);
112*3c7ae9deSAndroid Build Coastguard Worker     /********** JNI ENV RELEASE **********/
113*3c7ae9deSAndroid Build Coastguard Worker 
114*3c7ae9deSAndroid Build Coastguard Worker     return result;
115*3c7ae9deSAndroid Build Coastguard Worker }
116*3c7ae9deSAndroid Build Coastguard Worker 
s_aws_input_stream_get_status(struct aws_input_stream * stream,struct aws_stream_status * status)117*3c7ae9deSAndroid Build Coastguard Worker static int s_aws_input_stream_get_status(struct aws_input_stream *stream, struct aws_stream_status *status) {
118*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_request_body_stream_impl *impl =
119*3c7ae9deSAndroid Build Coastguard Worker         AWS_CONTAINER_OF(stream, struct aws_http_request_body_stream_impl, base);
120*3c7ae9deSAndroid Build Coastguard Worker 
121*3c7ae9deSAndroid Build Coastguard Worker     status->is_end_of_stream = impl->body_done;
122*3c7ae9deSAndroid Build Coastguard Worker     status->is_valid = impl->is_valid;
123*3c7ae9deSAndroid Build Coastguard Worker 
124*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_SUCCESS;
125*3c7ae9deSAndroid Build Coastguard Worker }
126*3c7ae9deSAndroid Build Coastguard Worker 
s_aws_input_stream_get_length(struct aws_input_stream * stream,int64_t * length)127*3c7ae9deSAndroid Build Coastguard Worker static int s_aws_input_stream_get_length(struct aws_input_stream *stream, int64_t *length) {
128*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(length && "NULL length out param passed to JNI aws_input_stream_get_length");
129*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_request_body_stream_impl *impl =
130*3c7ae9deSAndroid Build Coastguard Worker         AWS_CONTAINER_OF(stream, struct aws_http_request_body_stream_impl, base);
131*3c7ae9deSAndroid Build Coastguard Worker 
132*3c7ae9deSAndroid Build Coastguard Worker     if (impl->http_request_body_stream != NULL) {
133*3c7ae9deSAndroid Build Coastguard Worker 
134*3c7ae9deSAndroid Build Coastguard Worker         /********** JNI ENV ACQUIRE **********/
135*3c7ae9deSAndroid Build Coastguard Worker         JNIEnv *env = aws_jni_acquire_thread_env(impl->jvm);
136*3c7ae9deSAndroid Build Coastguard Worker         if (env == NULL) {
137*3c7ae9deSAndroid Build Coastguard Worker             /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
138*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
139*3c7ae9deSAndroid Build Coastguard Worker         }
140*3c7ae9deSAndroid Build Coastguard Worker 
141*3c7ae9deSAndroid Build Coastguard Worker         *length =
142*3c7ae9deSAndroid Build Coastguard Worker             (*env)->CallLongMethod(env, impl->http_request_body_stream, http_request_body_stream_properties.get_length);
143*3c7ae9deSAndroid Build Coastguard Worker 
144*3c7ae9deSAndroid Build Coastguard Worker         int result = AWS_OP_SUCCESS;
145*3c7ae9deSAndroid Build Coastguard Worker         if (aws_jni_check_and_clear_exception(env)) {
146*3c7ae9deSAndroid Build Coastguard Worker             result = aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
147*3c7ae9deSAndroid Build Coastguard Worker         }
148*3c7ae9deSAndroid Build Coastguard Worker 
149*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_release_thread_env(impl->jvm, env);
150*3c7ae9deSAndroid Build Coastguard Worker         /********** JNI ENV RELEASE **********/
151*3c7ae9deSAndroid Build Coastguard Worker 
152*3c7ae9deSAndroid Build Coastguard Worker         return result;
153*3c7ae9deSAndroid Build Coastguard Worker     }
154*3c7ae9deSAndroid Build Coastguard Worker 
155*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_ERR;
156*3c7ae9deSAndroid Build Coastguard Worker }
157*3c7ae9deSAndroid Build Coastguard Worker 
s_aws_input_stream_destroy(struct aws_http_request_body_stream_impl * impl)158*3c7ae9deSAndroid Build Coastguard Worker static void s_aws_input_stream_destroy(struct aws_http_request_body_stream_impl *impl) {
159*3c7ae9deSAndroid Build Coastguard Worker 
160*3c7ae9deSAndroid Build Coastguard Worker     /********** JNI ENV ACQUIRE **********/
161*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env = aws_jni_acquire_thread_env(impl->jvm);
162*3c7ae9deSAndroid Build Coastguard Worker     if (env == NULL) {
163*3c7ae9deSAndroid Build Coastguard Worker         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
164*3c7ae9deSAndroid Build Coastguard Worker         return;
165*3c7ae9deSAndroid Build Coastguard Worker     }
166*3c7ae9deSAndroid Build Coastguard Worker 
167*3c7ae9deSAndroid Build Coastguard Worker     if (impl->http_request_body_stream != NULL) {
168*3c7ae9deSAndroid Build Coastguard Worker         (*env)->DeleteGlobalRef(env, impl->http_request_body_stream);
169*3c7ae9deSAndroid Build Coastguard Worker     }
170*3c7ae9deSAndroid Build Coastguard Worker 
171*3c7ae9deSAndroid Build Coastguard Worker     aws_jni_release_thread_env(impl->jvm, env);
172*3c7ae9deSAndroid Build Coastguard Worker     /********** JNI ENV RELEASE **********/
173*3c7ae9deSAndroid Build Coastguard Worker 
174*3c7ae9deSAndroid Build Coastguard Worker     aws_mem_release(impl->allocator, impl);
175*3c7ae9deSAndroid Build Coastguard Worker }
176*3c7ae9deSAndroid Build Coastguard Worker 
177*3c7ae9deSAndroid Build Coastguard Worker static struct aws_input_stream_vtable s_aws_input_stream_vtable = {
178*3c7ae9deSAndroid Build Coastguard Worker     .seek = s_aws_input_stream_seek,
179*3c7ae9deSAndroid Build Coastguard Worker     .read = s_aws_input_stream_read,
180*3c7ae9deSAndroid Build Coastguard Worker     .get_status = s_aws_input_stream_get_status,
181*3c7ae9deSAndroid Build Coastguard Worker     .get_length = s_aws_input_stream_get_length,
182*3c7ae9deSAndroid Build Coastguard Worker };
183*3c7ae9deSAndroid Build Coastguard Worker 
aws_input_stream_new_from_java_http_request_body_stream(struct aws_allocator * allocator,JNIEnv * env,jobject http_request_body_stream)184*3c7ae9deSAndroid Build Coastguard Worker struct aws_input_stream *aws_input_stream_new_from_java_http_request_body_stream(
185*3c7ae9deSAndroid Build Coastguard Worker     struct aws_allocator *allocator,
186*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
187*3c7ae9deSAndroid Build Coastguard Worker     jobject http_request_body_stream) {
188*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_request_body_stream_impl *impl =
189*3c7ae9deSAndroid Build Coastguard Worker         aws_mem_calloc(allocator, 1, sizeof(struct aws_http_request_body_stream_impl));
190*3c7ae9deSAndroid Build Coastguard Worker 
191*3c7ae9deSAndroid Build Coastguard Worker     impl->allocator = allocator;
192*3c7ae9deSAndroid Build Coastguard Worker     impl->base.vtable = &s_aws_input_stream_vtable;
193*3c7ae9deSAndroid Build Coastguard Worker     aws_ref_count_init(&impl->base.ref_count, impl, (aws_simple_completion_callback *)s_aws_input_stream_destroy);
194*3c7ae9deSAndroid Build Coastguard Worker 
195*3c7ae9deSAndroid Build Coastguard Worker     jint jvmresult = (*env)->GetJavaVM(env, &impl->jvm);
196*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(jvmresult == 0);
197*3c7ae9deSAndroid Build Coastguard Worker 
198*3c7ae9deSAndroid Build Coastguard Worker     impl->is_valid = true;
199*3c7ae9deSAndroid Build Coastguard Worker     if (http_request_body_stream != NULL) {
200*3c7ae9deSAndroid Build Coastguard Worker         impl->http_request_body_stream = (*env)->NewGlobalRef(env, http_request_body_stream);
201*3c7ae9deSAndroid Build Coastguard Worker         if (impl->http_request_body_stream == NULL) {
202*3c7ae9deSAndroid Build Coastguard Worker             goto on_error;
203*3c7ae9deSAndroid Build Coastguard Worker         }
204*3c7ae9deSAndroid Build Coastguard Worker     } else {
205*3c7ae9deSAndroid Build Coastguard Worker         impl->body_done = true;
206*3c7ae9deSAndroid Build Coastguard Worker     }
207*3c7ae9deSAndroid Build Coastguard Worker 
208*3c7ae9deSAndroid Build Coastguard Worker     return &impl->base;
209*3c7ae9deSAndroid Build Coastguard Worker 
210*3c7ae9deSAndroid Build Coastguard Worker on_error:
211*3c7ae9deSAndroid Build Coastguard Worker 
212*3c7ae9deSAndroid Build Coastguard Worker     aws_input_stream_release(&impl->base);
213*3c7ae9deSAndroid Build Coastguard Worker 
214*3c7ae9deSAndroid Build Coastguard Worker     return NULL;
215*3c7ae9deSAndroid Build Coastguard Worker }
216*3c7ae9deSAndroid Build Coastguard Worker 
s_marshal_http_header_to_buffer(struct aws_byte_buf * buf,const struct aws_byte_cursor * name,const struct aws_byte_cursor * value)217*3c7ae9deSAndroid Build Coastguard Worker static inline int s_marshal_http_header_to_buffer(
218*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_buf *buf,
219*3c7ae9deSAndroid Build Coastguard Worker     const struct aws_byte_cursor *name,
220*3c7ae9deSAndroid Build Coastguard Worker     const struct aws_byte_cursor *value) {
221*3c7ae9deSAndroid Build Coastguard Worker     if (aws_byte_buf_reserve_relative(buf, sizeof(int) + sizeof(int) + name->len + value->len)) {
222*3c7ae9deSAndroid Build Coastguard Worker         return AWS_OP_ERR;
223*3c7ae9deSAndroid Build Coastguard Worker     }
224*3c7ae9deSAndroid Build Coastguard Worker 
225*3c7ae9deSAndroid Build Coastguard Worker     /* This will append to the buffer without overwriting anything */
226*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_be32(buf, (uint32_t)name->len);
227*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_from_whole_cursor(buf, *name);
228*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_be32(buf, (uint32_t)value->len);
229*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_from_whole_cursor(buf, *value);
230*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_SUCCESS;
231*3c7ae9deSAndroid Build Coastguard Worker }
232*3c7ae9deSAndroid Build Coastguard Worker 
aws_marshal_http_headers_array_to_dynamic_buffer(struct aws_byte_buf * buf,const struct aws_http_header * header_array,size_t num_headers)233*3c7ae9deSAndroid Build Coastguard Worker int aws_marshal_http_headers_array_to_dynamic_buffer(
234*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_buf *buf,
235*3c7ae9deSAndroid Build Coastguard Worker     const struct aws_http_header *header_array,
236*3c7ae9deSAndroid Build Coastguard Worker     size_t num_headers) {
237*3c7ae9deSAndroid Build Coastguard Worker     for (size_t i = 0; i < num_headers; ++i) {
238*3c7ae9deSAndroid Build Coastguard Worker         if (s_marshal_http_header_to_buffer(buf, &header_array[i].name, &header_array[i].value)) {
239*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
240*3c7ae9deSAndroid Build Coastguard Worker         }
241*3c7ae9deSAndroid Build Coastguard Worker     }
242*3c7ae9deSAndroid Build Coastguard Worker 
243*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_SUCCESS;
244*3c7ae9deSAndroid Build Coastguard Worker }
245*3c7ae9deSAndroid Build Coastguard Worker 
aws_marshal_http_headers_to_dynamic_buffer(struct aws_byte_buf * buf,const struct aws_http_headers * headers)246*3c7ae9deSAndroid Build Coastguard Worker int aws_marshal_http_headers_to_dynamic_buffer(struct aws_byte_buf *buf, const struct aws_http_headers *headers) {
247*3c7ae9deSAndroid Build Coastguard Worker     for (size_t i = 0; i < aws_http_headers_count(headers); ++i) {
248*3c7ae9deSAndroid Build Coastguard Worker         struct aws_http_header header;
249*3c7ae9deSAndroid Build Coastguard Worker         aws_http_headers_get_index(headers, i, &header);
250*3c7ae9deSAndroid Build Coastguard Worker         if (s_marshal_http_header_to_buffer(buf, &header.name, &header.value)) {
251*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
252*3c7ae9deSAndroid Build Coastguard Worker         }
253*3c7ae9deSAndroid Build Coastguard Worker     }
254*3c7ae9deSAndroid Build Coastguard Worker 
255*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_SUCCESS;
256*3c7ae9deSAndroid Build Coastguard Worker }
257*3c7ae9deSAndroid Build Coastguard Worker 
258*3c7ae9deSAndroid Build Coastguard Worker /**
259*3c7ae9deSAndroid Build Coastguard Worker  * Unmarshal the request from java.
260*3c7ae9deSAndroid Build Coastguard Worker  *
261*3c7ae9deSAndroid Build Coastguard Worker  * Version is as int: [4-bytes BE]
262*3c7ae9deSAndroid Build Coastguard Worker  *
263*3c7ae9deSAndroid Build Coastguard Worker  * Each string field is: [4-bytes BE] [variable length bytes specified
264*3c7ae9deSAndroid Build Coastguard Worker  *          by the previous field]
265*3c7ae9deSAndroid Build Coastguard Worker  *
266*3c7ae9deSAndroid Build Coastguard Worker  * Each request is like: [version][method][path][header name-value
267*3c7ae9deSAndroid Build Coastguard Worker  *          pairs]
268*3c7ae9deSAndroid Build Coastguard Worker  *
269*3c7ae9deSAndroid Build Coastguard Worker  * s_unmarshal_http_request_to_get_version to get the version field, which is a 4 byte int.
270*3c7ae9deSAndroid Build Coastguard Worker  * s_unmarshal_http_request_without_version to get the whole request without version field.
271*3c7ae9deSAndroid Build Coastguard Worker  */
s_unmarshal_http_request_to_get_version(struct aws_byte_cursor * request_blob)272*3c7ae9deSAndroid Build Coastguard Worker static inline enum aws_http_version s_unmarshal_http_request_to_get_version(struct aws_byte_cursor *request_blob) {
273*3c7ae9deSAndroid Build Coastguard Worker     uint32_t version = 0;
274*3c7ae9deSAndroid Build Coastguard Worker     if (!aws_byte_cursor_read_be32(request_blob, &version)) {
275*3c7ae9deSAndroid Build Coastguard Worker         aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
276*3c7ae9deSAndroid Build Coastguard Worker     }
277*3c7ae9deSAndroid Build Coastguard Worker     return version;
278*3c7ae9deSAndroid Build Coastguard Worker }
279*3c7ae9deSAndroid Build Coastguard Worker 
s_unmarshal_http_request_without_version(struct aws_http_message * message,struct aws_byte_cursor * request_blob)280*3c7ae9deSAndroid Build Coastguard Worker static inline int s_unmarshal_http_request_without_version(
281*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_message *message,
282*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_cursor *request_blob) {
283*3c7ae9deSAndroid Build Coastguard Worker     uint32_t field_len = 0;
284*3c7ae9deSAndroid Build Coastguard Worker     if (aws_http_message_get_protocol_version(message) != AWS_HTTP_VERSION_2) {
285*3c7ae9deSAndroid Build Coastguard Worker         /* HTTP/1 puts method and path first, but those are empty in HTTP/2 */
286*3c7ae9deSAndroid Build Coastguard Worker         if (!aws_byte_cursor_read_be32(request_blob, &field_len)) {
287*3c7ae9deSAndroid Build Coastguard Worker             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
288*3c7ae9deSAndroid Build Coastguard Worker         }
289*3c7ae9deSAndroid Build Coastguard Worker 
290*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor method = aws_byte_cursor_advance(request_blob, field_len);
291*3c7ae9deSAndroid Build Coastguard Worker 
292*3c7ae9deSAndroid Build Coastguard Worker         int result = aws_http_message_set_request_method(message, method);
293*3c7ae9deSAndroid Build Coastguard Worker         if (result != AWS_OP_SUCCESS) {
294*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
295*3c7ae9deSAndroid Build Coastguard Worker         }
296*3c7ae9deSAndroid Build Coastguard Worker 
297*3c7ae9deSAndroid Build Coastguard Worker         if (!aws_byte_cursor_read_be32(request_blob, &field_len)) {
298*3c7ae9deSAndroid Build Coastguard Worker             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
299*3c7ae9deSAndroid Build Coastguard Worker         }
300*3c7ae9deSAndroid Build Coastguard Worker 
301*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor path = aws_byte_cursor_advance(request_blob, field_len);
302*3c7ae9deSAndroid Build Coastguard Worker 
303*3c7ae9deSAndroid Build Coastguard Worker         result = aws_http_message_set_request_path(message, path);
304*3c7ae9deSAndroid Build Coastguard Worker         if (result != AWS_OP_SUCCESS) {
305*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
306*3c7ae9deSAndroid Build Coastguard Worker         }
307*3c7ae9deSAndroid Build Coastguard Worker     } else {
308*3c7ae9deSAndroid Build Coastguard Worker         /* Read empty method and path from the marshalled request */
309*3c7ae9deSAndroid Build Coastguard Worker         if (!aws_byte_cursor_read_be32(request_blob, &field_len) || field_len) {
310*3c7ae9deSAndroid Build Coastguard Worker             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
311*3c7ae9deSAndroid Build Coastguard Worker         }
312*3c7ae9deSAndroid Build Coastguard Worker         if (!aws_byte_cursor_read_be32(request_blob, &field_len) || field_len) {
313*3c7ae9deSAndroid Build Coastguard Worker             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
314*3c7ae9deSAndroid Build Coastguard Worker         }
315*3c7ae9deSAndroid Build Coastguard Worker     }
316*3c7ae9deSAndroid Build Coastguard Worker     while (request_blob->len) {
317*3c7ae9deSAndroid Build Coastguard Worker         if (!aws_byte_cursor_read_be32(request_blob, &field_len)) {
318*3c7ae9deSAndroid Build Coastguard Worker             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
319*3c7ae9deSAndroid Build Coastguard Worker         }
320*3c7ae9deSAndroid Build Coastguard Worker 
321*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor header_name = aws_byte_cursor_advance(request_blob, field_len);
322*3c7ae9deSAndroid Build Coastguard Worker 
323*3c7ae9deSAndroid Build Coastguard Worker         if (!aws_byte_cursor_read_be32(request_blob, &field_len)) {
324*3c7ae9deSAndroid Build Coastguard Worker             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
325*3c7ae9deSAndroid Build Coastguard Worker         }
326*3c7ae9deSAndroid Build Coastguard Worker 
327*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor header_value = aws_byte_cursor_advance(request_blob, field_len);
328*3c7ae9deSAndroid Build Coastguard Worker 
329*3c7ae9deSAndroid Build Coastguard Worker         struct aws_http_header header = {
330*3c7ae9deSAndroid Build Coastguard Worker             .name = header_name,
331*3c7ae9deSAndroid Build Coastguard Worker             .value = header_value,
332*3c7ae9deSAndroid Build Coastguard Worker         };
333*3c7ae9deSAndroid Build Coastguard Worker 
334*3c7ae9deSAndroid Build Coastguard Worker         aws_http_message_add_header(message, header);
335*3c7ae9deSAndroid Build Coastguard Worker     }
336*3c7ae9deSAndroid Build Coastguard Worker 
337*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_SUCCESS;
338*3c7ae9deSAndroid Build Coastguard Worker }
339*3c7ae9deSAndroid Build Coastguard Worker 
s_unmarshal_http_headers(struct aws_http_headers * headers,struct aws_byte_cursor * request_blob)340*3c7ae9deSAndroid Build Coastguard Worker static inline int s_unmarshal_http_headers(struct aws_http_headers *headers, struct aws_byte_cursor *request_blob) {
341*3c7ae9deSAndroid Build Coastguard Worker     uint32_t field_len = 0;
342*3c7ae9deSAndroid Build Coastguard Worker     while (request_blob->len) {
343*3c7ae9deSAndroid Build Coastguard Worker         if (!aws_byte_cursor_read_be32(request_blob, &field_len)) {
344*3c7ae9deSAndroid Build Coastguard Worker             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
345*3c7ae9deSAndroid Build Coastguard Worker         }
346*3c7ae9deSAndroid Build Coastguard Worker 
347*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor header_name = aws_byte_cursor_advance(request_blob, field_len);
348*3c7ae9deSAndroid Build Coastguard Worker 
349*3c7ae9deSAndroid Build Coastguard Worker         if (!aws_byte_cursor_read_be32(request_blob, &field_len)) {
350*3c7ae9deSAndroid Build Coastguard Worker             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
351*3c7ae9deSAndroid Build Coastguard Worker         }
352*3c7ae9deSAndroid Build Coastguard Worker 
353*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor header_value = aws_byte_cursor_advance(request_blob, field_len);
354*3c7ae9deSAndroid Build Coastguard Worker 
355*3c7ae9deSAndroid Build Coastguard Worker         struct aws_http_header header = {
356*3c7ae9deSAndroid Build Coastguard Worker             .name = header_name,
357*3c7ae9deSAndroid Build Coastguard Worker             .value = header_value,
358*3c7ae9deSAndroid Build Coastguard Worker         };
359*3c7ae9deSAndroid Build Coastguard Worker 
360*3c7ae9deSAndroid Build Coastguard Worker         aws_http_headers_add_header(headers, &header);
361*3c7ae9deSAndroid Build Coastguard Worker     }
362*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_SUCCESS;
363*3c7ae9deSAndroid Build Coastguard Worker }
364*3c7ae9deSAndroid Build Coastguard Worker 
aws_apply_java_http_request_changes_to_native_request(JNIEnv * env,jbyteArray marshalled_request,jobject jni_body_stream,struct aws_http_message * message)365*3c7ae9deSAndroid Build Coastguard Worker int aws_apply_java_http_request_changes_to_native_request(
366*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
367*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray marshalled_request,
368*3c7ae9deSAndroid Build Coastguard Worker     jobject jni_body_stream,
369*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_message *message) {
370*3c7ae9deSAndroid Build Coastguard Worker 
371*3c7ae9deSAndroid Build Coastguard Worker     /* come back to this when we decide we need to. */
372*3c7ae9deSAndroid Build Coastguard Worker     (void)jni_body_stream;
373*3c7ae9deSAndroid Build Coastguard Worker 
374*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_headers *headers = aws_http_message_get_headers(message);
375*3c7ae9deSAndroid Build Coastguard Worker     aws_http_headers_clear(headers);
376*3c7ae9deSAndroid Build Coastguard Worker     int result = AWS_OP_SUCCESS;
377*3c7ae9deSAndroid Build Coastguard Worker 
378*3c7ae9deSAndroid Build Coastguard Worker     const size_t marshalled_request_length = (*env)->GetArrayLength(env, marshalled_request);
379*3c7ae9deSAndroid Build Coastguard Worker 
380*3c7ae9deSAndroid Build Coastguard Worker     uint8_t *marshalled_request_data = (*env)->GetPrimitiveArrayCritical(env, marshalled_request, NULL);
381*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_cursor marshalled_cur =
382*3c7ae9deSAndroid Build Coastguard Worker         aws_byte_cursor_from_array((uint8_t *)marshalled_request_data, marshalled_request_length);
383*3c7ae9deSAndroid Build Coastguard Worker 
384*3c7ae9deSAndroid Build Coastguard Worker     enum aws_http_version version = s_unmarshal_http_request_to_get_version(&marshalled_cur);
385*3c7ae9deSAndroid Build Coastguard Worker     if (version != aws_http_message_get_protocol_version(message)) {
386*3c7ae9deSAndroid Build Coastguard Worker         result = aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
387*3c7ae9deSAndroid Build Coastguard Worker     } else {
388*3c7ae9deSAndroid Build Coastguard Worker         result = s_unmarshal_http_request_without_version(message, &marshalled_cur);
389*3c7ae9deSAndroid Build Coastguard Worker     }
390*3c7ae9deSAndroid Build Coastguard Worker     (*env)->ReleasePrimitiveArrayCritical(env, marshalled_request, marshalled_request_data, 0);
391*3c7ae9deSAndroid Build Coastguard Worker 
392*3c7ae9deSAndroid Build Coastguard Worker     if (result) {
393*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(
394*3c7ae9deSAndroid Build Coastguard Worker             env, "HttpRequest.applyChangesToNativeRequest: %s\n", aws_error_debug_str(aws_last_error()));
395*3c7ae9deSAndroid Build Coastguard Worker         return result;
396*3c7ae9deSAndroid Build Coastguard Worker     }
397*3c7ae9deSAndroid Build Coastguard Worker 
398*3c7ae9deSAndroid Build Coastguard Worker     if (jni_body_stream) {
399*3c7ae9deSAndroid Build Coastguard Worker         struct aws_input_stream *body_stream =
400*3c7ae9deSAndroid Build Coastguard Worker             aws_input_stream_new_from_java_http_request_body_stream(aws_jni_get_allocator(), env, jni_body_stream);
401*3c7ae9deSAndroid Build Coastguard Worker 
402*3c7ae9deSAndroid Build Coastguard Worker         aws_http_message_set_body_stream(message, body_stream);
403*3c7ae9deSAndroid Build Coastguard Worker         /* request controls the lifetime of body stream fully */
404*3c7ae9deSAndroid Build Coastguard Worker         aws_input_stream_release(body_stream);
405*3c7ae9deSAndroid Build Coastguard Worker     }
406*3c7ae9deSAndroid Build Coastguard Worker 
407*3c7ae9deSAndroid Build Coastguard Worker     return result;
408*3c7ae9deSAndroid Build Coastguard Worker }
409*3c7ae9deSAndroid Build Coastguard Worker 
aws_http_request_new_from_java_http_request(JNIEnv * env,jbyteArray marshalled_request,jobject jni_body_stream)410*3c7ae9deSAndroid Build Coastguard Worker struct aws_http_message *aws_http_request_new_from_java_http_request(
411*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
412*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray marshalled_request,
413*3c7ae9deSAndroid Build Coastguard Worker     jobject jni_body_stream) {
414*3c7ae9deSAndroid Build Coastguard Worker     const char *exception_message = NULL;
415*3c7ae9deSAndroid Build Coastguard Worker     const size_t marshalled_request_length = (*env)->GetArrayLength(env, marshalled_request);
416*3c7ae9deSAndroid Build Coastguard Worker 
417*3c7ae9deSAndroid Build Coastguard Worker     jbyte *marshalled_request_data = (*env)->GetPrimitiveArrayCritical(env, marshalled_request, NULL);
418*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_cursor marshalled_cur =
419*3c7ae9deSAndroid Build Coastguard Worker         aws_byte_cursor_from_array((uint8_t *)marshalled_request_data, marshalled_request_length);
420*3c7ae9deSAndroid Build Coastguard Worker     enum aws_http_version version = s_unmarshal_http_request_to_get_version(&marshalled_cur);
421*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_message *request = version == AWS_HTTP_VERSION_2
422*3c7ae9deSAndroid Build Coastguard Worker                                            ? aws_http2_message_new_request(aws_jni_get_allocator())
423*3c7ae9deSAndroid Build Coastguard Worker                                            : aws_http_message_new_request(aws_jni_get_allocator());
424*3c7ae9deSAndroid Build Coastguard Worker 
425*3c7ae9deSAndroid Build Coastguard Worker     int result = AWS_OP_SUCCESS;
426*3c7ae9deSAndroid Build Coastguard Worker     if (version != aws_http_message_get_protocol_version(request)) {
427*3c7ae9deSAndroid Build Coastguard Worker         result = aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
428*3c7ae9deSAndroid Build Coastguard Worker     } else {
429*3c7ae9deSAndroid Build Coastguard Worker         result = s_unmarshal_http_request_without_version(request, &marshalled_cur);
430*3c7ae9deSAndroid Build Coastguard Worker     }
431*3c7ae9deSAndroid Build Coastguard Worker     (*env)->ReleasePrimitiveArrayCritical(env, marshalled_request, marshalled_request_data, 0);
432*3c7ae9deSAndroid Build Coastguard Worker 
433*3c7ae9deSAndroid Build Coastguard Worker     if (result) {
434*3c7ae9deSAndroid Build Coastguard Worker         exception_message = "aws_http_request_new_from_java_http_request: Invalid marshalled request data.";
435*3c7ae9deSAndroid Build Coastguard Worker         goto on_error;
436*3c7ae9deSAndroid Build Coastguard Worker     }
437*3c7ae9deSAndroid Build Coastguard Worker 
438*3c7ae9deSAndroid Build Coastguard Worker     if (jni_body_stream != NULL) {
439*3c7ae9deSAndroid Build Coastguard Worker         struct aws_input_stream *body_stream =
440*3c7ae9deSAndroid Build Coastguard Worker             aws_input_stream_new_from_java_http_request_body_stream(aws_jni_get_allocator(), env, jni_body_stream);
441*3c7ae9deSAndroid Build Coastguard Worker         if (body_stream == NULL) {
442*3c7ae9deSAndroid Build Coastguard Worker             exception_message = "aws_fill_out_request: Error building body stream";
443*3c7ae9deSAndroid Build Coastguard Worker             goto on_error;
444*3c7ae9deSAndroid Build Coastguard Worker         }
445*3c7ae9deSAndroid Build Coastguard Worker 
446*3c7ae9deSAndroid Build Coastguard Worker         aws_http_message_set_body_stream(request, body_stream);
447*3c7ae9deSAndroid Build Coastguard Worker         /* request controls the lifetime of body stream fully */
448*3c7ae9deSAndroid Build Coastguard Worker         aws_input_stream_release(body_stream);
449*3c7ae9deSAndroid Build Coastguard Worker     }
450*3c7ae9deSAndroid Build Coastguard Worker 
451*3c7ae9deSAndroid Build Coastguard Worker     return request;
452*3c7ae9deSAndroid Build Coastguard Worker 
453*3c7ae9deSAndroid Build Coastguard Worker on_error:
454*3c7ae9deSAndroid Build Coastguard Worker     if (exception_message) {
455*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(env, exception_message);
456*3c7ae9deSAndroid Build Coastguard Worker     }
457*3c7ae9deSAndroid Build Coastguard Worker 
458*3c7ae9deSAndroid Build Coastguard Worker     /* Don't need to destroy input stream since it's the last thing created */
459*3c7ae9deSAndroid Build Coastguard Worker     aws_http_message_destroy(request);
460*3c7ae9deSAndroid Build Coastguard Worker 
461*3c7ae9deSAndroid Build Coastguard Worker     return NULL;
462*3c7ae9deSAndroid Build Coastguard Worker }
463*3c7ae9deSAndroid Build Coastguard Worker 
aws_http_headers_new_from_java_http_headers(JNIEnv * env,jbyteArray marshalled_headers)464*3c7ae9deSAndroid Build Coastguard Worker struct aws_http_headers *aws_http_headers_new_from_java_http_headers(JNIEnv *env, jbyteArray marshalled_headers) {
465*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_headers *headers = aws_http_headers_new(aws_jni_get_allocator());
466*3c7ae9deSAndroid Build Coastguard Worker     if (headers == NULL) {
467*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(env, "aws_http_headers_new_from_java_http_headers: Unable to allocate headers");
468*3c7ae9deSAndroid Build Coastguard Worker         return NULL;
469*3c7ae9deSAndroid Build Coastguard Worker     }
470*3c7ae9deSAndroid Build Coastguard Worker     const size_t marshalled_headers_length = (*env)->GetArrayLength(env, marshalled_headers);
471*3c7ae9deSAndroid Build Coastguard Worker 
472*3c7ae9deSAndroid Build Coastguard Worker     jbyte *marshalled_headers_data = (*env)->GetPrimitiveArrayCritical(env, marshalled_headers, NULL);
473*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_cursor marshalled_cur =
474*3c7ae9deSAndroid Build Coastguard Worker         aws_byte_cursor_from_array((uint8_t *)marshalled_headers_data, marshalled_headers_length);
475*3c7ae9deSAndroid Build Coastguard Worker     int result = s_unmarshal_http_headers(headers, &marshalled_cur);
476*3c7ae9deSAndroid Build Coastguard Worker     (*env)->ReleasePrimitiveArrayCritical(env, marshalled_headers, marshalled_headers_data, 0);
477*3c7ae9deSAndroid Build Coastguard Worker 
478*3c7ae9deSAndroid Build Coastguard Worker     if (result) {
479*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(
480*3c7ae9deSAndroid Build Coastguard Worker             env, "aws_http_headers_new_from_java_http_headers: Invalid marshalled headers data.");
481*3c7ae9deSAndroid Build Coastguard Worker         goto on_error;
482*3c7ae9deSAndroid Build Coastguard Worker     }
483*3c7ae9deSAndroid Build Coastguard Worker 
484*3c7ae9deSAndroid Build Coastguard Worker     return headers;
485*3c7ae9deSAndroid Build Coastguard Worker 
486*3c7ae9deSAndroid Build Coastguard Worker on_error:
487*3c7ae9deSAndroid Build Coastguard Worker     aws_http_headers_release(headers);
488*3c7ae9deSAndroid Build Coastguard Worker     return NULL;
489*3c7ae9deSAndroid Build Coastguard Worker }
490*3c7ae9deSAndroid Build Coastguard Worker 
s_marshall_http_request(const struct aws_http_message * message,struct aws_byte_buf * request_buf)491*3c7ae9deSAndroid Build Coastguard Worker static inline int s_marshall_http_request(const struct aws_http_message *message, struct aws_byte_buf *request_buf) {
492*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_cursor method;
493*3c7ae9deSAndroid Build Coastguard Worker     AWS_ZERO_STRUCT(method);
494*3c7ae9deSAndroid Build Coastguard Worker 
495*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(!aws_http_message_get_request_method(message, &method));
496*3c7ae9deSAndroid Build Coastguard Worker 
497*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_cursor path;
498*3c7ae9deSAndroid Build Coastguard Worker     AWS_ZERO_STRUCT(path);
499*3c7ae9deSAndroid Build Coastguard Worker 
500*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(!aws_http_message_get_request_path(message, &path));
501*3c7ae9deSAndroid Build Coastguard Worker 
502*3c7ae9deSAndroid Build Coastguard Worker     if (aws_byte_buf_reserve_relative(request_buf, sizeof(int) + sizeof(int) + sizeof(int) + method.len + path.len)) {
503*3c7ae9deSAndroid Build Coastguard Worker         return AWS_OP_ERR;
504*3c7ae9deSAndroid Build Coastguard Worker     }
505*3c7ae9deSAndroid Build Coastguard Worker 
506*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_be32(request_buf, (uint32_t)aws_http_message_get_protocol_version(message));
507*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_be32(request_buf, (uint32_t)method.len);
508*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_from_whole_cursor(request_buf, method);
509*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_be32(request_buf, (uint32_t)path.len);
510*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_write_from_whole_cursor(request_buf, path);
511*3c7ae9deSAndroid Build Coastguard Worker 
512*3c7ae9deSAndroid Build Coastguard Worker     const struct aws_http_headers *headers = aws_http_message_get_const_headers(message);
513*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(headers);
514*3c7ae9deSAndroid Build Coastguard Worker     size_t header_count = aws_http_message_get_header_count(message);
515*3c7ae9deSAndroid Build Coastguard Worker     for (size_t i = 0; i < header_count; ++i) {
516*3c7ae9deSAndroid Build Coastguard Worker         struct aws_http_header header;
517*3c7ae9deSAndroid Build Coastguard Worker         AWS_ZERO_STRUCT(header);
518*3c7ae9deSAndroid Build Coastguard Worker 
519*3c7ae9deSAndroid Build Coastguard Worker         AWS_FATAL_ASSERT(!aws_http_headers_get_index(headers, i, &header));
520*3c7ae9deSAndroid Build Coastguard Worker         if (s_marshal_http_header_to_buffer(request_buf, &header.name, &header.value)) {
521*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
522*3c7ae9deSAndroid Build Coastguard Worker         }
523*3c7ae9deSAndroid Build Coastguard Worker     }
524*3c7ae9deSAndroid Build Coastguard Worker 
525*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_SUCCESS;
526*3c7ae9deSAndroid Build Coastguard Worker }
527*3c7ae9deSAndroid Build Coastguard Worker 
aws_java_http_request_from_native(JNIEnv * env,struct aws_http_message * message,jobject request_body_stream)528*3c7ae9deSAndroid Build Coastguard Worker jobject aws_java_http_request_from_native(JNIEnv *env, struct aws_http_message *message, jobject request_body_stream) {
529*3c7ae9deSAndroid Build Coastguard Worker     jobject jni_request_blob = NULL;
530*3c7ae9deSAndroid Build Coastguard Worker     jobject j_request = NULL;
531*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_buf marshaling_buf;
532*3c7ae9deSAndroid Build Coastguard Worker 
533*3c7ae9deSAndroid Build Coastguard Worker     if (aws_byte_buf_init(&marshaling_buf, aws_jni_get_allocator(), 1024)) {
534*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(env, "aws_java_http_request_from_native: allocation failed");
535*3c7ae9deSAndroid Build Coastguard Worker         return NULL;
536*3c7ae9deSAndroid Build Coastguard Worker     }
537*3c7ae9deSAndroid Build Coastguard Worker 
538*3c7ae9deSAndroid Build Coastguard Worker     if (s_marshall_http_request(message, &marshaling_buf)) {
539*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(
540*3c7ae9deSAndroid Build Coastguard Worker             env, "aws_java_http_request_from_native: %s.", aws_error_debug_str(aws_last_error()));
541*3c7ae9deSAndroid Build Coastguard Worker         goto done;
542*3c7ae9deSAndroid Build Coastguard Worker     }
543*3c7ae9deSAndroid Build Coastguard Worker 
544*3c7ae9deSAndroid Build Coastguard Worker     jni_request_blob = aws_jni_direct_byte_buffer_from_raw_ptr(env, marshaling_buf.buffer, marshaling_buf.len);
545*3c7ae9deSAndroid Build Coastguard Worker 
546*3c7ae9deSAndroid Build Coastguard Worker     /* Currently our only use case for this does not involve a body stream. We should come back and handle this
547*3c7ae9deSAndroid Build Coastguard Worker        when it's not time sensitive to do so. */
548*3c7ae9deSAndroid Build Coastguard Worker     j_request = (*env)->NewObject(
549*3c7ae9deSAndroid Build Coastguard Worker         env,
550*3c7ae9deSAndroid Build Coastguard Worker         http_request_properties.http_request_class,
551*3c7ae9deSAndroid Build Coastguard Worker         http_request_properties.constructor_method_id,
552*3c7ae9deSAndroid Build Coastguard Worker         jni_request_blob,
553*3c7ae9deSAndroid Build Coastguard Worker         request_body_stream);
554*3c7ae9deSAndroid Build Coastguard Worker 
555*3c7ae9deSAndroid Build Coastguard Worker     if (aws_jni_check_and_clear_exception(env)) {
556*3c7ae9deSAndroid Build Coastguard Worker         aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
557*3c7ae9deSAndroid Build Coastguard Worker         goto done;
558*3c7ae9deSAndroid Build Coastguard Worker     }
559*3c7ae9deSAndroid Build Coastguard Worker 
560*3c7ae9deSAndroid Build Coastguard Worker done:
561*3c7ae9deSAndroid Build Coastguard Worker     if (jni_request_blob) {
562*3c7ae9deSAndroid Build Coastguard Worker         (*env)->DeleteLocalRef(env, jni_request_blob);
563*3c7ae9deSAndroid Build Coastguard Worker     }
564*3c7ae9deSAndroid Build Coastguard Worker 
565*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_clean_up(&marshaling_buf);
566*3c7ae9deSAndroid Build Coastguard Worker     return j_request;
567*3c7ae9deSAndroid Build Coastguard Worker }
568