From 79d986bd35b49a819dc875cfec69ec8685517930 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Mon, 20 Mar 2023 17:52:13 +0000 Subject: [PATCH] fix: Use UTF-8 as default charset for HttpJson requests (#1477) Thank you for opening a Pull Request! For general contributing guidelines, please refer to [contributing guide](https://togithub.com/googleapis/gapic-generator-java/blob/main/CONTRIBUTING.md) Before submitting your PR, there are a few things you can do to make sure it goes smoothly: - [x] Make sure to open an issue as a [bug/issue](https://togithub.com/googleapis/gapic-generator-java/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [x] Ensure the tests and linter pass - [x] Code coverage does not decrease (if any source code was changed) - [x] Appropriate docs were updated (if necessary) Fixes #1437 --- .../api/gax/httpjson/HttpRequestRunnable.java | 2 +- .../gax/httpjson/HttpRequestRunnableTest.java | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpRequestRunnable.java b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpRequestRunnable.java index 2edb4ceb2e..cc0ca4c20d 100644 --- a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpRequestRunnable.java +++ b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpRequestRunnable.java @@ -172,7 +172,7 @@ HttpRequest createHttpRequest() throws IOException { jsonFactory.createJsonParser(requestBody).parse(tokenRequest); jsonHttpContent = new JsonHttpContent(jsonFactory, tokenRequest) - .setMediaType((new HttpMediaType("application/json"))); + .setMediaType((new HttpMediaType("application/json; charset=utf-8"))); } else { // Force underlying HTTP lib to set Content-Length header to avoid 411s. // See EmptyContent.java. diff --git a/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpRequestRunnableTest.java b/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpRequestRunnableTest.java index f68b11feba..4e825d679d 100644 --- a/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpRequestRunnableTest.java +++ b/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpRequestRunnableTest.java @@ -36,6 +36,8 @@ import com.google.longrunning.ListOperationsRequest; import com.google.protobuf.Empty; import com.google.protobuf.Field; +import com.google.protobuf.util.JsonFormat; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; @@ -177,4 +179,67 @@ public void testRequestUrlUnnormalizedPatch() throws IOException { Truth.assertThat(httpRequest.getRequestMethod()).isEqualTo("POST"); Truth.assertThat(httpRequest.getHeaders().get("X-HTTP-Method-Override")).isEqualTo("PATCH"); } + + /* + We use a separate RequestFormatter because formatting the body requests is what sets the charset to be UTF-8. + The other tests above do not have a set a body request and instead send an EmptyContent (null Type/ CharSet) + */ + @Test + public void testUnicodeValuesInBody() throws IOException { + HttpRequestFormatter bodyRequestFormatter = + ProtoMessageRequestFormatter.newBuilder() + .setPath( + "/name/{name=*}", + request -> { + Map fields = new HashMap<>(); + ProtoRestSerializer serializer = ProtoRestSerializer.create(); + serializer.putPathParam(fields, "name", request.getName()); + return fields; + }) + .setQueryParamsExtractor(request -> new HashMap<>()) + .setRequestBodyExtractor( + request -> + ProtoRestSerializer.create().toBody("*", request.toBuilder().build(), true)) + .build(); + + Field bodyRequestMessage = + Field.newBuilder() + .setName("feline ☺ → ←") + .setNumber(2) + .setDefaultValue("bird ☺ → ←") + .setJsonName("mouse ☺ → ←") + .setTypeUrl("small ☺ → ←") + .build(); + + ApiMethodDescriptor methodDescriptor = + ApiMethodDescriptor.newBuilder() + .setFullMethodName("house.cat.get") + .setHttpMethod("PUT") + .setRequestFormatter(bodyRequestFormatter) + .setResponseParser(responseParser) + .build(); + + HttpRequestRunnable httpRequestRunnable = + new HttpRequestRunnable<>( + bodyRequestMessage, + methodDescriptor, + "www.googleapis.com/animals/v1/projects", + HttpJsonCallOptions.newBuilder().build(), + new MockHttpTransport(), + HttpJsonMetadata.newBuilder().build(), + (result) -> {}); + + HttpRequest httpRequest = httpRequestRunnable.createHttpRequest(); + Truth.assertThat(httpRequest.getContent().getType()) + .isEqualTo("application/json; charset=utf-8"); + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { + // writeTo() uses the Charset when writing to the stream + httpRequest.getContent().writeTo(byteArrayOutputStream); + String output = byteArrayOutputStream.toString(); + Field.Builder expectedBuilder = Field.newBuilder(); + JsonFormat.parser().merge(output, expectedBuilder); + Field result = expectedBuilder.build(); + Truth.assertThat(result).isEqualTo(bodyRequestMessage); + } + } }