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