From ed237e399e8ca740a8599d3a1f8d9667b3f126fd Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Fri, 24 May 2019 10:08:10 -0700 Subject: [PATCH 01/14] Add failing test showing that encoding happens more than once --- .../api/client/http/HttpRequestTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java b/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java index 946f5961f..e2bb32132 100644 --- a/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java +++ b/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java @@ -25,6 +25,7 @@ import com.google.api.client.util.BackOff; import com.google.api.client.util.Key; import com.google.api.client.util.LoggingStreamingContent; +import com.google.api.client.util.StreamingContent; import com.google.api.client.util.StringUtils; import com.google.api.client.util.Value; import com.google.common.base.Charsets; @@ -33,6 +34,7 @@ import com.google.common.collect.Lists; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.OutputStream; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; @@ -1264,4 +1266,56 @@ public void testExecute_curlLoggerWithContentEncoding() throws Exception { } assertTrue(found); } + + public void testExecute_shouldEncodeContentOnce() throws IOException { + class TestEncoding implements HttpEncoding { + + private int encodingCount = 0; + + @Override + public String getName() { + return "test-encoding"; + } + + @Override + public void encode(StreamingContent content, OutputStream out) throws IOException { + encodingCount++; + return; + } + + public int getEncodingCount() { + return encodingCount; + } + } + + class NullOutputStream extends OutputStream { + @Override + public void write(int b) throws IOException { + } + } + final LowLevelHttpRequest lowLevelHttpRequest = + new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() throws IOException { + // LowLevelRequest implementations will use writeTo for the request body + getStreamingContent().writeTo(new NullOutputStream()); + return super.execute(); + } + }; + HttpTransport transport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) throws IOException { + return lowLevelHttpRequest; + } + }; + HttpContent content = new EmptyContent(); + TestEncoding encoding = new TestEncoding(); + HttpRequest request = + transport.createRequestFactory().buildPostRequest(HttpTesting.SIMPLE_GENERIC_URL, content); + request.setEncoding(encoding); + request.execute(); + + assertEquals(1, encoding.getEncodingCount()); + } } From 331e250f242f4ca8939adffd06f5045e64398c53 Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Fri, 24 May 2019 10:48:28 -0700 Subject: [PATCH 02/14] Only encode the streaming content once. In order to calculate the contentLength, we must write the encode the data first. The encoded data is written to a buffer using a ByteArrayOutputStream implementation and we use that to figure out how many bytes of data is to be sent. Previously, this data was thrown away and the content was re-encoded when it was actually time to send the data. Instead, we now replace the content with a ByteArrayContent which contains the buffer we wrote to when calculating the size. We implemented a new CachingByteArrayOutputStream so that we can access the byte buffer directly rather than copying into a new byte array (for memory performance) --- .../google/api/client/http/HttpRequest.java | 11 ++++- .../util/CachingByteArrayOutputStream.java | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 google-http-client/src/main/java/com/google/api/client/util/CachingByteArrayOutputStream.java diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java b/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java index 05d6cc906..399ed8bac 100644 --- a/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java +++ b/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java @@ -15,7 +15,7 @@ package com.google.api.client.http; import com.google.api.client.util.Beta; -import com.google.api.client.util.IOUtils; +import com.google.api.client.util.CachingByteArrayOutputStream; import com.google.api.client.util.LoggingStreamingContent; import com.google.api.client.util.ObjectParser; import com.google.api.client.util.Preconditions; @@ -932,7 +932,14 @@ public HttpResponse execute() throws IOException { } else { contentEncoding = encoding.getName(); streamingContent = new HttpEncodingStreamingContent(streamingContent, encoding); - contentLength = contentRetrySupported ? IOUtils.computeLength(streamingContent) : -1; + if (contentRetrySupported) { + CachingByteArrayOutputStream outputStream = new CachingByteArrayOutputStream(); + streamingContent.writeTo(outputStream); + contentLength = outputStream.getContentLength(); + streamingContent = new ByteArrayContent(contentType, outputStream.getBuffer()); + } else { + contentLength = -1; + } } // append content headers to log buffer if (loggable) { diff --git a/google-http-client/src/main/java/com/google/api/client/util/CachingByteArrayOutputStream.java b/google-http-client/src/main/java/com/google/api/client/util/CachingByteArrayOutputStream.java new file mode 100644 index 000000000..73119a644 --- /dev/null +++ b/google-http-client/src/main/java/com/google/api/client/util/CachingByteArrayOutputStream.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.api.client.util; + +import java.io.ByteArrayOutputStream; + +/** + * Output stream that extends the built-in {@link ByteArrayOutputStream} to return the internal + * byte buffer rather than creating a copy. + */ +public class CachingByteArrayOutputStream extends ByteArrayOutputStream { + + /** + * Returns the content length of the buffer. + * + * @return tthe content length of the buffer. + */ + public int getContentLength() { + return count; + } + + /** + * Returns the buffer where the byte data is stored. + * + * @return the buffer where the byte data is stored. + */ + public byte[] getBuffer() { + return buf; + } + +} From 0604972eb32b675f2f8c427f5e18e7540e295f14 Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Fri, 24 May 2019 11:06:12 -0700 Subject: [PATCH 03/14] Remove assertion that the content is a HttpEncodingStreamingContent We really only care that the contents was encode and is correctly marked as such. --- .../test/java/com/google/api/client/http/HttpRequestTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java b/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java index e2bb32132..543dd1644 100644 --- a/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java +++ b/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java @@ -986,7 +986,6 @@ public LowLevelHttpRequest buildRequest(String method, String url) throws IOExce @Override public LowLevelHttpResponse execute() throws IOException { if (expectGZip) { - assertEquals(HttpEncodingStreamingContent.class, getStreamingContent().getClass()); assertEquals("gzip", getContentEncoding()); assertEquals(25, getContentLength()); } else { From c4f29bcf96d488c6f053c3fc6096ec7c5cfeb30a Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Sun, 26 May 2019 07:00:59 -0700 Subject: [PATCH 04/14] Fix a bunch of typos (#640) --- .../src/main/java/com/google/api/client/xml/Xml.java | 2 +- .../com/google/api/client/xml/XmlNamespaceDictionary.java | 2 +- .../main/java/com/google/api/client/http/HttpEncoding.java | 4 ++-- .../com/google/api/client/http/javanet/NetHttpRequest.java | 4 ++-- .../src/main/java/com/google/api/client/util/Key.java | 2 +- .../java/com/google/api/client/util/StreamingContent.java | 4 ++-- .../src/main/java/com/google/api/client/util/StringUtils.java | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/google-http-client-xml/src/main/java/com/google/api/client/xml/Xml.java b/google-http-client-xml/src/main/java/com/google/api/client/xml/Xml.java index 3955c5e18..4f9156d3c 100644 --- a/google-http-client-xml/src/main/java/com/google/api/client/xml/Xml.java +++ b/google-http-client-xml/src/main/java/com/google/api/client/xml/Xml.java @@ -195,7 +195,7 @@ public boolean stopAfterEndTag(String namespace, String localName) { /** * Parses an XML element using the given XML pull parser into the given destination object. * - *

Requires the the current event be {@link XmlPullParser#START_TAG} (skipping any initial + *

Requires the current event be {@link XmlPullParser#START_TAG} (skipping any initial * {@link XmlPullParser#START_DOCUMENT}) of the element being parsed. At normal parsing * completion, the current event will either be {@link XmlPullParser#END_TAG} of the element being * parsed, or the {@link XmlPullParser#START_TAG} of the requested {@code atom:entry}. diff --git a/google-http-client-xml/src/main/java/com/google/api/client/xml/XmlNamespaceDictionary.java b/google-http-client-xml/src/main/java/com/google/api/client/xml/XmlNamespaceDictionary.java index c500e2f83..6c04ef00f 100644 --- a/google-http-client-xml/src/main/java/com/google/api/client/xml/XmlNamespaceDictionary.java +++ b/google-http-client-xml/src/main/java/com/google/api/client/xml/XmlNamespaceDictionary.java @@ -283,7 +283,7 @@ private void computeAliases(Object element, SortedSet aliases) { * @return namespace URI, using a predictable made-up namespace URI if the namespace alias is not * recognized * @throws IllegalArgumentException if the namespace alias is not recognized and {@code - * errorOnUnkown} is {@code true} + * errorOnUnknown} is {@code true} */ String getNamespaceUriForAliasHandlingUnknown(boolean errorOnUnknown, String alias) { String result = getUriForAlias(alias); diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpEncoding.java b/google-http-client/src/main/java/com/google/api/client/http/HttpEncoding.java index 38702b82e..2720310f8 100644 --- a/google-http-client/src/main/java/com/google/api/client/http/HttpEncoding.java +++ b/google-http-client/src/main/java/com/google/api/client/http/HttpEncoding.java @@ -35,8 +35,8 @@ public interface HttpEncoding { * Encodes the streaming content into the output stream. * *

Implementations must not close the output stream, and instead should flush the output - * stream. Some callers may assume that the the output stream has not been closed, and will fail - * to work if it has been closed. + * stream. Some callers may assume that the output stream has not been closed, and will fail to + * work if it has been closed. * * @param content streaming content * @param out output stream diff --git a/google-http-client/src/main/java/com/google/api/client/http/javanet/NetHttpRequest.java b/google-http-client/src/main/java/com/google/api/client/http/javanet/NetHttpRequest.java index e497f882c..aa0d8e3e4 100644 --- a/google-http-client/src/main/java/com/google/api/client/http/javanet/NetHttpRequest.java +++ b/google-http-client/src/main/java/com/google/api/client/http/javanet/NetHttpRequest.java @@ -115,7 +115,7 @@ LowLevelHttpResponse execute(final OutputWriter outputWriter) throws IOException } catch (IOException e) { // If we've gotten a response back, continue on and try to parse the response. Otherwise, // re-throw the IOException - if (!hasReponse(connection)) { + if (!hasResponse(connection)) { throw e; } } finally { @@ -151,7 +151,7 @@ LowLevelHttpResponse execute(final OutputWriter outputWriter) throws IOException } } - private boolean hasReponse(HttpURLConnection connection) { + private boolean hasResponse(HttpURLConnection connection) { try { return connection.getResponseCode() > 0; } catch (IOException e) { diff --git a/google-http-client/src/main/java/com/google/api/client/util/Key.java b/google-http-client/src/main/java/com/google/api/client/util/Key.java index dfc0dd454..40094065c 100644 --- a/google-http-client/src/main/java/com/google/api/client/util/Key.java +++ b/google-http-client/src/main/java/com/google/api/client/util/Key.java @@ -34,7 +34,7 @@ * * // uses data key name of "some_other_name" * @Key("some_other_name") - * private String dataKeyNameIsOverriden; + * private String dataKeyNameIsOverridden; * * // not a data key * private String notADataKey; diff --git a/google-http-client/src/main/java/com/google/api/client/util/StreamingContent.java b/google-http-client/src/main/java/com/google/api/client/util/StreamingContent.java index a2a9f600d..8ae55bbf6 100644 --- a/google-http-client/src/main/java/com/google/api/client/util/StreamingContent.java +++ b/google-http-client/src/main/java/com/google/api/client/util/StreamingContent.java @@ -31,8 +31,8 @@ public interface StreamingContent { * Writes the byte content to the given output stream. * *

Implementations must not close the output stream, and instead should flush the output - * stream. Some callers may assume that the the output stream has not been closed, and will fail - * to work if it has been closed. + * stream. Some callers may assume that the output stream has not been closed, and will fail to + * work if it has been closed. * * @param out output stream */ diff --git a/google-http-client/src/main/java/com/google/api/client/util/StringUtils.java b/google-http-client/src/main/java/com/google/api/client/util/StringUtils.java index dc57990ef..0efb24674 100644 --- a/google-http-client/src/main/java/com/google/api/client/util/StringUtils.java +++ b/google-http-client/src/main/java/com/google/api/client/util/StringUtils.java @@ -39,7 +39,7 @@ public class StringUtils { * @param string the String to encode, may be null * @return encoded bytes, or null if the input string was null * @throws IllegalStateException Thrown when the charset is missing, which should be never - * according the the Java specification. + * according the Java specification. * @see Standard charsets * @since 1.8 From 1d4270dc2971d52780359d9e3411dd761696c4e6 Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Sun, 26 May 2019 07:26:47 -0700 Subject: [PATCH 05/14] Linting cleanup (#645) * Fix javadoc param name * Group serializeHeaders() overloads --- .../google/api/client/http/HttpHeaders.java | 30 +++++++++---------- .../com/google/api/client/util/Objects.java | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpHeaders.java b/google-http-client/src/main/java/com/google/api/client/http/HttpHeaders.java index caa88c99e..e43f09b0f 100644 --- a/google-http-client/src/main/java/com/google/api/client/http/HttpHeaders.java +++ b/google-http-client/src/main/java/com/google/api/client/http/HttpHeaders.java @@ -893,21 +893,6 @@ static void serializeHeaders( serializeHeaders(headers, logbuf, curlbuf, logger, lowLevelHttpRequest, null); } - /** - * Serializes headers to an {@link Writer} for Multi-part requests. - * - * @param headers HTTP headers - * @param logbuf log buffer or {@code null} for none - * @param logger logger or {@code null} for none. Logger must be specified if log buffer is - * specified - * @param writer Writer where HTTP headers will be serialized to or {@code null} for none - * @since 1.9 - */ - public static void serializeHeadersForMultipartRequests( - HttpHeaders headers, StringBuilder logbuf, Logger logger, Writer writer) throws IOException { - serializeHeaders(headers, logbuf, null, logger, null, writer); - } - static void serializeHeaders( HttpHeaders headers, StringBuilder logbuf, @@ -947,6 +932,21 @@ static void serializeHeaders( } } + /** + * Serializes headers to an {@link Writer} for Multi-part requests. + * + * @param headers HTTP headers + * @param logbuf log buffer or {@code null} for none + * @param logger logger or {@code null} for none. Logger must be specified if log buffer is + * specified + * @param writer Writer where HTTP headers will be serialized to or {@code null} for none + * @since 1.9 + */ + public static void serializeHeadersForMultipartRequests( + HttpHeaders headers, StringBuilder logbuf, Logger logger, Writer writer) throws IOException { + serializeHeaders(headers, logbuf, null, logger, null, writer); + } + /** * Puts all headers of the {@link LowLevelHttpResponse} into this {@link HttpHeaders} object. * diff --git a/google-http-client/src/main/java/com/google/api/client/util/Objects.java b/google-http-client/src/main/java/com/google/api/client/util/Objects.java index ab980d948..08da55d0b 100644 --- a/google-http-client/src/main/java/com/google/api/client/util/Objects.java +++ b/google-http-client/src/main/java/com/google/api/client/util/Objects.java @@ -88,7 +88,7 @@ public static final class ToStringHelper { private ValueHolder holderTail = holderHead; private boolean omitNullValues; - /** @param wrapped wrapped object */ + /** @param className wrapped object */ ToStringHelper(String className) { this.className = className; } From e64f72f9deccc243312dbf621de728fabf208750 Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Sun, 26 May 2019 07:27:27 -0700 Subject: [PATCH 06/14] Remove deprecated google-http-client-jackson artifact. (#647) * Remove deprecated google-http-client-jackson artifact. Jackson 1.x has been unsupported for a long time. Users should be using Jackson 2.x. the google-http-client-jackson artifact was deprecated in 1.28.0. * Fix assembly references to jackson --- google-http-client-assembly/assembly.xml | 17 --- google-http-client-assembly/pom.xml | 4 - .../google-http-client-jackson.jar.properties | 1 - .../jackson-core-asl.jar.properties | 1 - google-http-client-bom/pom.xml | 5 - google-http-client-jackson/pom.xml | 110 -------------- .../client/json/jackson/JacksonFactory.java | 117 --------------- .../client/json/jackson/JacksonGenerator.java | 134 ------------------ .../client/json/jackson/JacksonParser.java | 117 --------------- .../api/client/json/jackson/package-info.java | 23 --- .../json/jackson/JacksonFactoryTest.java | 82 ----------- .../json/jackson/JacksonGeneratorTest.java | 30 ---- pom.xml | 12 -- versions.txt | 1 - 14 files changed, 654 deletions(-) delete mode 100644 google-http-client-assembly/properties/google-http-client-jackson.jar.properties delete mode 100644 google-http-client-assembly/properties/jackson-core-asl.jar.properties delete mode 100644 google-http-client-jackson/pom.xml delete mode 100644 google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonFactory.java delete mode 100644 google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonGenerator.java delete mode 100644 google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonParser.java delete mode 100644 google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/package-info.java delete mode 100644 google-http-client-jackson/src/test/java/com/google/api/client/json/jackson/JacksonFactoryTest.java delete mode 100644 google-http-client-jackson/src/test/java/com/google/api/client/json/jackson/JacksonGeneratorTest.java diff --git a/google-http-client-assembly/assembly.xml b/google-http-client-assembly/assembly.xml index 45478f40a..5e8a4f708 100644 --- a/google-http-client-assembly/assembly.xml +++ b/google-http-client-assembly/assembly.xml @@ -50,12 +50,6 @@ google-http-java-client/libs true - - properties/google-http-client-jackson.jar.properties - google-http-client-jackson-${project.version}.jar.properties - google-http-java-client/libs - true - properties/google-http-client-jackson2.jar.properties google-http-client-jackson2-${project.version}.jar.properties @@ -86,12 +80,6 @@ google-http-java-client/libs true - - properties/jackson-core-asl.jar.properties - jackson-core-asl-${project.jackson-core-asl.version}.jar.properties - google-http-java-client/libs - true - properties/protobuf-java.jar.properties protobuf-java-${project.protobuf-java.version}.jar.properties @@ -119,11 +107,6 @@ google-http-client-gson-dependencies.html google-http-java-client/dependencies - - ../google-http-client-jackson/target/site/dependencies.html - google-http-client-jackson-dependencies.html - google-http-java-client/dependencies - ../google-http-client-jackson2/target/site/dependencies.html google-http-client-jackson2-dependencies.html diff --git a/google-http-client-assembly/pom.xml b/google-http-client-assembly/pom.xml index 1279fa067..6e009973d 100644 --- a/google-http-client-assembly/pom.xml +++ b/google-http-client-assembly/pom.xml @@ -34,10 +34,6 @@ com.google.http-client google-http-client-gson - - com.google.http-client - google-http-client-jackson - com.google.http-client google-http-client-jackson2 diff --git a/google-http-client-assembly/properties/google-http-client-jackson.jar.properties b/google-http-client-assembly/properties/google-http-client-jackson.jar.properties deleted file mode 100644 index a02a3062f..000000000 --- a/google-http-client-assembly/properties/google-http-client-jackson.jar.properties +++ /dev/null @@ -1 +0,0 @@ -src=../libs-sources/google-http-client-jackson-${project.version}-sources.jar diff --git a/google-http-client-assembly/properties/jackson-core-asl.jar.properties b/google-http-client-assembly/properties/jackson-core-asl.jar.properties deleted file mode 100644 index d613b8e65..000000000 --- a/google-http-client-assembly/properties/jackson-core-asl.jar.properties +++ /dev/null @@ -1 +0,0 @@ -src=../libs-sources/jackson-core-asl-${project.jackson-core-asl.version}-sources.jar diff --git a/google-http-client-bom/pom.xml b/google-http-client-bom/pom.xml index 9db27edc7..626ca25ad 100644 --- a/google-http-client-bom/pom.xml +++ b/google-http-client-bom/pom.xml @@ -90,11 +90,6 @@ google-http-client-gson 1.29.2-SNAPSHOT - - com.google.http-client - google-http-client-jackson - 1.29.2-SNAPSHOT - com.google.http-client google-http-client-jackson2 diff --git a/google-http-client-jackson/pom.xml b/google-http-client-jackson/pom.xml deleted file mode 100644 index 67a928cb4..000000000 --- a/google-http-client-jackson/pom.xml +++ /dev/null @@ -1,110 +0,0 @@ - - 4.0.0 - - com.google.http-client - google-http-client-parent - 1.29.2-SNAPSHOT - ../pom.xml - - google-http-client-jackson - 1.29.2-SNAPSHOT - Jackson extensions to the Google HTTP Client Library for Java. - - - - - maven-javadoc-plugin - - - http://download.oracle.com/javase/7/docs/api/ - https://jar-download.com/javaDoc/org.codehaus.jackson/jackson-core-asl/${project.jackson-core-asl.version} - - ${project.name} ${project.version} - ${project.artifactId} ${project.version} - - - - maven-source-plugin - - - source-jar - compile - - jar - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.5 - - - add-test-source - generate-test-sources - - add-test-source - - - - target/generated-test-sources - - - - - - - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - com.google.api.client.json.jackson - - - - - - org.apache.felix - maven-bundle-plugin - 2.5.4 - - - bundle-manifest - process-classes - - manifest - - - - - - - - - com.google.http-client - google-http-client - - - com.google.http-client - google-http-client-test - test - - - junit - junit - test - - - org.codehaus.jackson - jackson-core-asl - - - com.google.guava - guava - test - - - diff --git a/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonFactory.java b/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonFactory.java deleted file mode 100644 index c44ebc7fa..000000000 --- a/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonFactory.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.api.client.json.jackson; - -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.JsonGenerator; -import com.google.api.client.json.JsonParser; -import com.google.api.client.json.JsonToken; -import com.google.api.client.util.Preconditions; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; -import java.nio.charset.Charset; - -/** - * Low-level JSON library implementation based on Jackson. - * - *

Implementation is thread-safe, and sub-classes must be thread-safe. For maximum efficiency, - * applications should use a single globally-shared instance of the JSON factory. - * - * @since 1.3 - * @author Yaniv Inbar - * @deprecated As of release 1.28, please use Jackson2 and google-http-client-jackson2. - */ -@Deprecated -public final class JacksonFactory extends JsonFactory { - - /** JSON factory. */ - private final org.codehaus.jackson.JsonFactory factory = new org.codehaus.jackson.JsonFactory(); - - { - // don't auto-close JSON content in order to ensure consistent behavior across JSON factories - // TODO(rmistry): Should we disable the JsonGenerator.Feature.AUTO_CLOSE_TARGET feature? - factory.configure(org.codehaus.jackson.JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT, false); - } - - @Override - public JsonGenerator createJsonGenerator(OutputStream out, Charset enc) throws IOException { - return new JacksonGenerator( - this, factory.createJsonGenerator(out, org.codehaus.jackson.JsonEncoding.UTF8)); - } - - @Override - public JsonGenerator createJsonGenerator(Writer writer) throws IOException { - return new JacksonGenerator(this, factory.createJsonGenerator(writer)); - } - - @Override - public JsonParser createJsonParser(Reader reader) throws IOException { - Preconditions.checkNotNull(reader); - return new JacksonParser(this, factory.createJsonParser(reader)); - } - - @Override - public JsonParser createJsonParser(InputStream in) throws IOException { - Preconditions.checkNotNull(in); - return new JacksonParser(this, factory.createJsonParser(in)); - } - - @Override - public JsonParser createJsonParser(InputStream in, Charset charset) throws IOException { - Preconditions.checkNotNull(in); - return new JacksonParser(this, factory.createJsonParser(in)); - } - - @Override - public JsonParser createJsonParser(String value) throws IOException { - Preconditions.checkNotNull(value); - return new JacksonParser(this, factory.createJsonParser(value)); - } - - static JsonToken convert(org.codehaus.jackson.JsonToken token) { - if (token == null) { - return null; - } - switch (token) { - case END_ARRAY: - return JsonToken.END_ARRAY; - case START_ARRAY: - return JsonToken.START_ARRAY; - case END_OBJECT: - return JsonToken.END_OBJECT; - case START_OBJECT: - return JsonToken.START_OBJECT; - case VALUE_FALSE: - return JsonToken.VALUE_FALSE; - case VALUE_TRUE: - return JsonToken.VALUE_TRUE; - case VALUE_NULL: - return JsonToken.VALUE_NULL; - case VALUE_STRING: - return JsonToken.VALUE_STRING; - case VALUE_NUMBER_FLOAT: - return JsonToken.VALUE_NUMBER_FLOAT; - case VALUE_NUMBER_INT: - return JsonToken.VALUE_NUMBER_INT; - case FIELD_NAME: - return JsonToken.FIELD_NAME; - default: - return JsonToken.NOT_AVAILABLE; - } - } -} diff --git a/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonGenerator.java b/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonGenerator.java deleted file mode 100644 index 096b892ac..000000000 --- a/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonGenerator.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.api.client.json.jackson; - -import com.google.api.client.json.JsonGenerator; -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; - -/** - * Low-level JSON serializer implementation based on Jackson. - * - *

Implementation is not thread-safe. - * - * @author Yaniv Inbar - * @deprecated As of release 1.28, please use Jackson2 and google-http-client-jackson2. - */ -@Deprecated -final class JacksonGenerator extends JsonGenerator { - private final org.codehaus.jackson.JsonGenerator generator; - private final JacksonFactory factory; - - @Override - public JacksonFactory getFactory() { - return factory; - } - - JacksonGenerator(JacksonFactory factory, org.codehaus.jackson.JsonGenerator generator) { - this.factory = factory; - this.generator = generator; - } - - @Override - public void flush() throws IOException { - generator.flush(); - } - - @Override - public void close() throws IOException { - generator.close(); - } - - @Override - public void writeBoolean(boolean state) throws IOException { - generator.writeBoolean(state); - } - - @Override - public void writeEndArray() throws IOException { - generator.writeEndArray(); - } - - @Override - public void writeEndObject() throws IOException { - generator.writeEndObject(); - } - - @Override - public void writeFieldName(String name) throws IOException { - generator.writeFieldName(name); - } - - @Override - public void writeNull() throws IOException { - generator.writeNull(); - } - - @Override - public void writeNumber(int v) throws IOException { - generator.writeNumber(v); - } - - @Override - public void writeNumber(long v) throws IOException { - generator.writeNumber(v); - } - - @Override - public void writeNumber(BigInteger v) throws IOException { - generator.writeNumber(v); - } - - @Override - public void writeNumber(double v) throws IOException { - generator.writeNumber(v); - } - - @Override - public void writeNumber(float v) throws IOException { - generator.writeNumber(v); - } - - @Override - public void writeNumber(BigDecimal v) throws IOException { - generator.writeNumber(v); - } - - @Override - public void writeNumber(String encodedValue) throws IOException { - generator.writeNumber(encodedValue); - } - - @Override - public void writeStartArray() throws IOException { - generator.writeStartArray(); - } - - @Override - public void writeStartObject() throws IOException { - generator.writeStartObject(); - } - - @Override - public void writeString(String value) throws IOException { - generator.writeString(value); - } - - @Override - public void enablePrettyPrint() throws IOException { - generator.useDefaultPrettyPrinter(); - } -} diff --git a/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonParser.java b/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonParser.java deleted file mode 100644 index 529582075..000000000 --- a/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/JacksonParser.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.api.client.json.jackson; - -import com.google.api.client.json.JsonParser; -import com.google.api.client.json.JsonToken; -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; - -/** - * Low-level JSON serializer implementation based on Jackson. - * - *

Implementation is not thread-safe. - * - * @author Yaniv Inbar - * @deprecated As of release 1.28, please use Jackson2 and google-http-client-jackson2. - */ -@Deprecated -final class JacksonParser extends JsonParser { - - private final org.codehaus.jackson.JsonParser parser; - private final JacksonFactory factory; - - @Override - public JacksonFactory getFactory() { - return factory; - } - - JacksonParser(JacksonFactory factory, org.codehaus.jackson.JsonParser parser) { - this.factory = factory; - this.parser = parser; - } - - @Override - public void close() throws IOException { - parser.close(); - } - - @Override - public JsonToken nextToken() throws IOException { - return JacksonFactory.convert(parser.nextToken()); - } - - @Override - public String getCurrentName() throws IOException { - return parser.getCurrentName(); - } - - @Override - public JsonToken getCurrentToken() { - return JacksonFactory.convert(parser.getCurrentToken()); - } - - @Override - public JsonParser skipChildren() throws IOException { - parser.skipChildren(); - return this; - } - - @Override - public String getText() throws IOException { - return parser.getText(); - } - - @Override - public byte getByteValue() throws IOException { - return parser.getByteValue(); - } - - @Override - public float getFloatValue() throws IOException { - return parser.getFloatValue(); - } - - @Override - public int getIntValue() throws IOException { - return parser.getIntValue(); - } - - @Override - public short getShortValue() throws IOException { - return parser.getShortValue(); - } - - @Override - public BigInteger getBigIntegerValue() throws IOException { - return parser.getBigIntegerValue(); - } - - @Override - public BigDecimal getDecimalValue() throws IOException { - return parser.getDecimalValue(); - } - - @Override - public double getDoubleValue() throws IOException { - return parser.getDoubleValue(); - } - - @Override - public long getLongValue() throws IOException { - return parser.getLongValue(); - } -} diff --git a/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/package-info.java b/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/package-info.java deleted file mode 100644 index eabec34a6..000000000 --- a/google-http-client-jackson/src/main/java/com/google/api/client/json/jackson/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -/** - * Low-level implementation of the JSON parser library based on the Jackson JSON library. - * - * @since 1.3 - * @author Yaniv Inbar - * @deprecated As of release 1.28, please use Jackson2 and google-http-client-jackson2. - */ -package com.google.api.client.json.jackson; diff --git a/google-http-client-jackson/src/test/java/com/google/api/client/json/jackson/JacksonFactoryTest.java b/google-http-client-jackson/src/test/java/com/google/api/client/json/jackson/JacksonFactoryTest.java deleted file mode 100644 index 892d5b3b6..000000000 --- a/google-http-client-jackson/src/test/java/com/google/api/client/json/jackson/JacksonFactoryTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.api.client.json.jackson; - -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.JsonParser; -import com.google.api.client.test.json.AbstractJsonFactoryTest; -import com.google.api.client.util.StringUtils; -import com.google.common.base.Charsets; -import java.io.ByteArrayInputStream; -import java.util.ArrayList; - -/** - * Tests {@link JacksonFactory}. - * - * @author Yaniv Inbar - */ -public class JacksonFactoryTest extends AbstractJsonFactoryTest { - - private static final String JSON_ENTRY_PRETTY = - "{" + StringUtils.LINE_SEPARATOR + " \"title\" : \"foo\"" + StringUtils.LINE_SEPARATOR + "}"; - private static final String JSON_FEED_PRETTY = - "{" - + StringUtils.LINE_SEPARATOR - + " \"entries\" : [ {" - + StringUtils.LINE_SEPARATOR - + " \"title\" : \"foo\"" - + StringUtils.LINE_SEPARATOR - + " }, {" - + StringUtils.LINE_SEPARATOR - + " \"title\" : \"bar\"" - + StringUtils.LINE_SEPARATOR - + " } ]" - + StringUtils.LINE_SEPARATOR - + "}"; - - public JacksonFactoryTest(String name) { - super(name); - } - - @Override - protected JsonFactory newFactory() { - return new JacksonFactory(); - } - - public final void testToPrettyString_entry() throws Exception { - Entry entry = new Entry(); - entry.title = "foo"; - assertEquals(JSON_ENTRY_PRETTY, newFactory().toPrettyString(entry)); - } - - public final void testToPrettyString_Feed() throws Exception { - Feed feed = new Feed(); - Entry entryFoo = new Entry(); - entryFoo.title = "foo"; - Entry entryBar = new Entry(); - entryBar.title = "bar"; - feed.entries = new ArrayList(); - feed.entries.add(entryFoo); - feed.entries.add(entryBar); - assertEquals(JSON_FEED_PRETTY, newFactory().toPrettyString(feed)); - } - - public final void testParse_directValue() throws Exception { - byte[] jsonData = Charsets.UTF_8.encode("123").array(); - JsonParser jp = - newFactory().createJsonParser(new ByteArrayInputStream(jsonData), Charsets.UTF_8); - assertEquals(123, jp.parse(Integer.class, true)); - } -} diff --git a/google-http-client-jackson/src/test/java/com/google/api/client/json/jackson/JacksonGeneratorTest.java b/google-http-client-jackson/src/test/java/com/google/api/client/json/jackson/JacksonGeneratorTest.java deleted file mode 100644 index bfdfbfe28..000000000 --- a/google-http-client-jackson/src/test/java/com/google/api/client/json/jackson/JacksonGeneratorTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2018 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.api.client.json.jackson; - -import com.google.api.client.json.JsonGenerator; -import com.google.api.client.test.json.AbstractJsonGeneratorTest; -import java.io.IOException; -import java.io.Writer; - -public class JacksonGeneratorTest extends AbstractJsonGeneratorTest { - - private static final JacksonFactory FACTORY = new JacksonFactory(); - - @Override - protected JsonGenerator newGenerator(Writer writer) throws IOException { - return FACTORY.createJsonGenerator(writer); - } -} diff --git a/pom.xml b/pom.xml index b1d4d0bb6..56f3e7038 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,6 @@ google-http-client-apache-v2 google-http-client-protobuf google-http-client-gson - google-http-client-jackson google-http-client-jackson2 google-http-client-xml @@ -198,11 +197,6 @@ google-http-client-gson ${project.http-client.version} - - com.google.http-client - google-http-client-jackson - ${project.http-client.version} - com.google.http-client google-http-client-jackson2 @@ -402,7 +396,6 @@ http://download.oracle.com/javase/7/docs/api/ http://cloud.google.com/appengine/docs/java/javadoc - https://jar-download.com/javaDoc/org.codehaus.jackson/jackson-core-asl/${project.jackson-core-asl.version} http://fasterxml.github.com/jackson-core/javadoc/${project.jackson-core2.version}/ https://static.javadoc.io/doc/com.google.code.gson/gson/${project.gson.version} https://google.github.io/guava/releases/${project.guava.version}/api/docs/ @@ -431,10 +424,6 @@ google-http-client-gson com.google.api.client.json.gson* - - google-http-client-jackson - com.google.api.client.json.jackson.* - google-http-client-jackson2 com.google.api.client.json.jackson2.* @@ -557,7 +546,6 @@ UTF-8 3.0.2 2.1 - 1.9.13 2.9.6 3.6.1 26.0-android diff --git a/versions.txt b/versions.txt index d3e97b814..6cadb621b 100644 --- a/versions.txt +++ b/versions.txt @@ -11,7 +11,6 @@ google-http-client-appengine:1.29.1:1.29.2-SNAPSHOT google-http-client-assembly:1.29.1:1.29.2-SNAPSHOT google-http-client-findbugs:1.29.1:1.29.2-SNAPSHOT google-http-client-gson:1.29.1:1.29.2-SNAPSHOT -google-http-client-jackson:1.29.1:1.29.2-SNAPSHOT google-http-client-jackson2:1.29.1:1.29.2-SNAPSHOT google-http-client-jdo:1.29.1:1.29.2-SNAPSHOT google-http-client-protobuf:1.29.1:1.29.2-SNAPSHOT From 91cbfdb487ee39d46bf2daa5785b15b025f516cf Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Sun, 26 May 2019 07:27:50 -0700 Subject: [PATCH 07/14] Add Base64Test case for some base64 decoding edge cases (#644) * Add Base64Test case for some base64 decoding edge cases * Preserve decoding behavior for null decodeBase64(null) * Handle encoding with null inputs --- .../com/google/api/client/util/Base64.java | 11 +++- .../google/api/client/util/Base64Test.java | 65 +++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 google-http-client/src/test/java/com/google/api/client/util/Base64Test.java diff --git a/google-http-client/src/main/java/com/google/api/client/util/Base64.java b/google-http-client/src/main/java/com/google/api/client/util/Base64.java index 305ab688c..038156390 100644 --- a/google-http-client/src/main/java/com/google/api/client/util/Base64.java +++ b/google-http-client/src/main/java/com/google/api/client/util/Base64.java @@ -43,6 +43,9 @@ public static byte[] encodeBase64(byte[] binaryData) { * @return String containing Base64 characters or {@code null} for {@code null} input */ public static String encodeBase64String(byte[] binaryData) { + if (binaryData == null) { + return null; + } return BaseEncoding.base64().encode(binaryData); } @@ -66,6 +69,9 @@ public static byte[] encodeBase64URLSafe(byte[] binaryData) { * @return String containing Base64 characters or {@code null} for {@code null} input */ public static String encodeBase64URLSafeString(byte[] binaryData) { + if (binaryData == null) { + return null; + } return BaseEncoding.base64Url().omitPadding().encode(binaryData); } @@ -88,11 +94,14 @@ public static byte[] decodeBase64(byte[] base64Data) { * @return Array containing decoded data or {@code null} for {@code null} input */ public static byte[] decodeBase64(String base64String) { + if (base64String == null) { + return null; + } try { return BaseEncoding.base64().decode(base64String); } catch (IllegalArgumentException e) { if (e.getCause() instanceof DecodingException) { - return BaseEncoding.base64Url().decode(base64String); + return BaseEncoding.base64Url().decode(base64String.trim()); } throw e; } diff --git a/google-http-client/src/test/java/com/google/api/client/util/Base64Test.java b/google-http-client/src/test/java/com/google/api/client/util/Base64Test.java new file mode 100644 index 000000000..0ee174f9f --- /dev/null +++ b/google-http-client/src/test/java/com/google/api/client/util/Base64Test.java @@ -0,0 +1,65 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.api.client.util; + +import java.nio.charset.StandardCharsets; +import junit.framework.TestCase; + +/** + * Tests {@link Base64}. + * + * @author Jeff Ching + */ +public class Base64Test extends TestCase { + + public void test_decodeBase64_withPadding() { + String encoded = "Zm9vOmJhcg=="; + assertEquals("foo:bar", new String(Base64.decodeBase64(encoded), StandardCharsets.UTF_8)); + } + + public void test_decodeBase64_withoutPadding() { + String encoded = "Zm9vOmJhcg"; + assertEquals("foo:bar", new String(Base64.decodeBase64(encoded), StandardCharsets.UTF_8)); + } + + public void test_decodeBase64_withTrailingWhitespace() { + // Some internal use cases append extra space characters that apache-commons base64 decoding + // previously handled. + String encoded = "Zm9vOmJhcg==\r\n"; + assertEquals("foo:bar", new String(Base64.decodeBase64(encoded), StandardCharsets.UTF_8)); + } + + public void test_decodeBase64_withNullBytes_shouldReturnNull() { + byte[] encoded = null; + assertNull(Base64.decodeBase64(encoded)); + } + + public void test_decodeBase64_withNull_shouldReturnNull() { + String encoded = null; + assertNull(Base64.decodeBase64(encoded)); + } + + public void test_encodeBase64URLSafeString_withNull_shouldReturnNull() { + assertNull(Base64.encodeBase64URLSafeString(null)); + } + + public void test_encodeBase64URLSafe_withNull_shouldReturnNull() { + assertNull(Base64.encodeBase64URLSafe(null)); + } + + public void test_encodeBase64_withNull_shouldReturnNull() { + assertNull(Base64.encodeBase64(null)); + } +} From 1b18a6efb7acb01110d94a207cd7e9de25c21058 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 31 May 2019 19:55:02 +0200 Subject: [PATCH 08/14] Add renovate.json (#651) --- renovate.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 000000000..f45d8f110 --- /dev/null +++ b/renovate.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "config:base" + ] +} From 1a4a5cc087348d081cca05566bafc11414647b82 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 31 May 2019 20:08:24 +0200 Subject: [PATCH 09/14] Update dependency com.fasterxml.jackson.core:jackson-core to v2.9.9 (#653) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 56f3e7038..6c7e5897e 100644 --- a/pom.xml +++ b/pom.xml @@ -546,7 +546,7 @@ UTF-8 3.0.2 2.1 - 2.9.6 + 2.9.9 3.6.1 26.0-android 1.1.4c From b0d724593ce3962a751292bcf4f6e508e824bec8 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 31 May 2019 20:09:21 +0200 Subject: [PATCH 10/14] Update dependency com.coveo:fmt-maven-plugin to v2.9 (#652) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6c7e5897e..f91a2ab92 100644 --- a/pom.xml +++ b/pom.xml @@ -522,7 +522,7 @@ com.coveo fmt-maven-plugin - 2.6.0 + 2.9 true From 13731cdff2f9ff9c178ec7387ef1cf18aee51ab9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 31 May 2019 21:51:38 +0200 Subject: [PATCH 11/14] Update dependency com.google.code.gson:gson to v2.8.5 (#657) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f91a2ab92..6872e5cc4 100644 --- a/pom.xml +++ b/pom.xml @@ -545,7 +545,7 @@ 1.9.71 UTF-8 3.0.2 - 2.1 + 2.8.5 2.9.9 3.6.1 26.0-android From 78d49918c5b688ea2d4de80f73599c198c21b003 Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Fri, 24 May 2019 10:08:10 -0700 Subject: [PATCH 12/14] Add failing test showing that encoding happens more than once --- .../api/client/http/HttpRequestTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java b/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java index 946f5961f..e2bb32132 100644 --- a/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java +++ b/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java @@ -25,6 +25,7 @@ import com.google.api.client.util.BackOff; import com.google.api.client.util.Key; import com.google.api.client.util.LoggingStreamingContent; +import com.google.api.client.util.StreamingContent; import com.google.api.client.util.StringUtils; import com.google.api.client.util.Value; import com.google.common.base.Charsets; @@ -33,6 +34,7 @@ import com.google.common.collect.Lists; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.OutputStream; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; @@ -1264,4 +1266,56 @@ public void testExecute_curlLoggerWithContentEncoding() throws Exception { } assertTrue(found); } + + public void testExecute_shouldEncodeContentOnce() throws IOException { + class TestEncoding implements HttpEncoding { + + private int encodingCount = 0; + + @Override + public String getName() { + return "test-encoding"; + } + + @Override + public void encode(StreamingContent content, OutputStream out) throws IOException { + encodingCount++; + return; + } + + public int getEncodingCount() { + return encodingCount; + } + } + + class NullOutputStream extends OutputStream { + @Override + public void write(int b) throws IOException { + } + } + final LowLevelHttpRequest lowLevelHttpRequest = + new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() throws IOException { + // LowLevelRequest implementations will use writeTo for the request body + getStreamingContent().writeTo(new NullOutputStream()); + return super.execute(); + } + }; + HttpTransport transport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) throws IOException { + return lowLevelHttpRequest; + } + }; + HttpContent content = new EmptyContent(); + TestEncoding encoding = new TestEncoding(); + HttpRequest request = + transport.createRequestFactory().buildPostRequest(HttpTesting.SIMPLE_GENERIC_URL, content); + request.setEncoding(encoding); + request.execute(); + + assertEquals(1, encoding.getEncodingCount()); + } } From 4fa6b09561a67cd86840eabb46c74fc102a8f1bb Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Fri, 24 May 2019 10:48:28 -0700 Subject: [PATCH 13/14] Only encode the streaming content once. In order to calculate the contentLength, we must write the encode the data first. The encoded data is written to a buffer using a ByteArrayOutputStream implementation and we use that to figure out how many bytes of data is to be sent. Previously, this data was thrown away and the content was re-encoded when it was actually time to send the data. Instead, we now replace the content with a ByteArrayContent which contains the buffer we wrote to when calculating the size. We implemented a new CachingByteArrayOutputStream so that we can access the byte buffer directly rather than copying into a new byte array (for memory performance) --- .../google/api/client/http/HttpRequest.java | 11 ++++- .../util/CachingByteArrayOutputStream.java | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 google-http-client/src/main/java/com/google/api/client/util/CachingByteArrayOutputStream.java diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java b/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java index 05d6cc906..399ed8bac 100644 --- a/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java +++ b/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java @@ -15,7 +15,7 @@ package com.google.api.client.http; import com.google.api.client.util.Beta; -import com.google.api.client.util.IOUtils; +import com.google.api.client.util.CachingByteArrayOutputStream; import com.google.api.client.util.LoggingStreamingContent; import com.google.api.client.util.ObjectParser; import com.google.api.client.util.Preconditions; @@ -932,7 +932,14 @@ public HttpResponse execute() throws IOException { } else { contentEncoding = encoding.getName(); streamingContent = new HttpEncodingStreamingContent(streamingContent, encoding); - contentLength = contentRetrySupported ? IOUtils.computeLength(streamingContent) : -1; + if (contentRetrySupported) { + CachingByteArrayOutputStream outputStream = new CachingByteArrayOutputStream(); + streamingContent.writeTo(outputStream); + contentLength = outputStream.getContentLength(); + streamingContent = new ByteArrayContent(contentType, outputStream.getBuffer()); + } else { + contentLength = -1; + } } // append content headers to log buffer if (loggable) { diff --git a/google-http-client/src/main/java/com/google/api/client/util/CachingByteArrayOutputStream.java b/google-http-client/src/main/java/com/google/api/client/util/CachingByteArrayOutputStream.java new file mode 100644 index 000000000..73119a644 --- /dev/null +++ b/google-http-client/src/main/java/com/google/api/client/util/CachingByteArrayOutputStream.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.api.client.util; + +import java.io.ByteArrayOutputStream; + +/** + * Output stream that extends the built-in {@link ByteArrayOutputStream} to return the internal + * byte buffer rather than creating a copy. + */ +public class CachingByteArrayOutputStream extends ByteArrayOutputStream { + + /** + * Returns the content length of the buffer. + * + * @return tthe content length of the buffer. + */ + public int getContentLength() { + return count; + } + + /** + * Returns the buffer where the byte data is stored. + * + * @return the buffer where the byte data is stored. + */ + public byte[] getBuffer() { + return buf; + } + +} From 3d20d9a5a53684f93b3d12cae860512555fa764f Mon Sep 17 00:00:00 2001 From: Jeff Ching Date: Fri, 24 May 2019 11:06:12 -0700 Subject: [PATCH 14/14] Remove assertion that the content is a HttpEncodingStreamingContent We really only care that the contents was encode and is correctly marked as such. --- .../test/java/com/google/api/client/http/HttpRequestTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java b/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java index e2bb32132..543dd1644 100644 --- a/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java +++ b/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java @@ -986,7 +986,6 @@ public LowLevelHttpRequest buildRequest(String method, String url) throws IOExce @Override public LowLevelHttpResponse execute() throws IOException { if (expectGZip) { - assertEquals(HttpEncodingStreamingContent.class, getStreamingContent().getClass()); assertEquals("gzip", getContentEncoding()); assertEquals(25, getContentLength()); } else {