Repository: googleapis/google-http-java-client
Pull request #867 (2019-10-31 05:42:23)

Fix various paragraph issues in javadoc
Fixes the following warnings:

> [WARN] /home/anusien/opensource/google-http-java-client/google-http-client/src/main/java/com/google/api/client/testing/json/webtoken/TestCertificates.java:242: Empty line should be followed by <p> tag on the next line. [JavadocParagraph]

> [WARN] /home/anusien/opensource/google-http-java-client/google-http-client/src/main/java/com/google/api/client/http/AbstractInputStreamContent.java:32: <p> tag should be placed immediately before the first word, with no space after. [JavadocParagraph]

> [WARN] /home/anusien/opensource/google-http-java-client/google-http-client/src/main/java/com/google/api/client/http/ExponentialBackOffPolicy.java:33: Empty line should be followed by <p> tag on the next line. [JavadocParagraph]

> [WARN] /home/anusien/opensource/google-http-java-client/google-http-client/src/main/java/com/google/api/client/json/JsonString.java:34: Empty line should be followed by <p> tag on the next line. [JavadocParagraph]

> [WARN] /home/anusien/opensource/google-http-java-client/google-http-client/src/main/java/com/google/api/client/json/JsonString.java:42: Empty line should be followed by <p> tag on the next line. [JavadocParagraph]

> [WARN] /home/anusien/opensource/google-http-java-client/google-http-client/src/main/java/com/google/api/client/json/JsonString.java:53: Empty line should be followed by <p> tag on the next line. [JavadocParagraph]

> [WARN] /home/anusien/opensource/google-http-java-client/google-http-client/src/main/java/com/google/api/client/util/PemReader.java:39: <p> tag should be placed immediately before the first word, with no space after. [JavadocParagraph]



googlebot: 
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

:memo: **Please visit <https://cla.developers.google.com/> to sign.**

Once you've signed (or fixed any issues), please reply here with `@googlebot I signed it!` and we'll verify it.

----

#### What to do if you already signed the CLA

##### Individual signers

*   It's possible we don't have your GitHub username or you're using a different email address on your commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).

##### Corporate signers

*   Your company has a Point of Contact who decides which employees are authorized to participate. Ask your POC to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the Google project maintainer to [go/cla#troubleshoot](http://go/cla#troubleshoot) ([Public version](https://opensource.google/docs/cla/#troubleshoot)).
*   The email used to register you as an authorized contributor must be the email used for the Git commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).
*   The email used to register you as an authorized contributor must also be [attached to your GitHub account](https://github.com/settings/emails).
		

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fgoogle-http-java-client%2Fpull%2F867) for more info**.

<!-- need_sender_cla -->

Patch:
diff --git a/.github/release-please.yml b/.github/release-please.yml
index 82744682..dce2c845 100644
--- a/.github/release-please.yml
+++ b/.github/release-please.yml
@@ -1,1 +1,2 @@
 releaseType: java-yoshi
+bumpMinorPreMajor: true
\ No newline at end of file
diff --git a/.kokoro/build.sh b/.kokoro/build.sh
index fa132f41..dc2936ef 100755
--- a/.kokoro/build.sh
+++ b/.kokoro/build.sh
@@ -27,6 +27,7 @@ echo ${JOB_TYPE}
 mvn install -B -V \
   -DskipTests=true \
   -Dclirr.skip=true \
+  -Denforcer.skip=true \
   -Dmaven.javadoc.skip=true \
   -Dgcloud.download.skip=true \
   -T 1C
@@ -38,7 +39,7 @@ fi
 
 case ${JOB_TYPE} in
 test)
-    mvn test -B -Dclirr.skip=true
+    mvn test -B -Dclirr.skip=true -Denforcer.skip=true
     bash ${KOKORO_GFILE_DIR}/codecov.sh
     bash .kokoro/coerce_logs.sh
     ;;
@@ -49,12 +50,17 @@ javadoc)
     mvn javadoc:javadoc javadoc:test-javadoc
     ;;
 integration)
-    mvn -B ${INTEGRATION_TEST_ARGS} -DtrimStackTrace=false -Dclirr.skip=true -fae verify
+    mvn -B ${INTEGRATION_TEST_ARGS} \
+      -DtrimStackTrace=false \
+      -Dclirr.skip=true \
+      -Denforcer.skip=true \
+      -fae \
+      verify
     bash .kokoro/coerce_logs.sh
     ;;
 clirr)
-    mvn -B clirr:check
+    mvn -B -Denforcer.skip=true clirr:check
     ;;
 *)
     ;;
-esac
\ No newline at end of file
+esac
diff --git a/.kokoro/dependencies.sh b/.kokoro/dependencies.sh
index 8e909db9..ccd3fe69 100755
--- a/.kokoro/dependencies.sh
+++ b/.kokoro/dependencies.sh
@@ -23,5 +23,9 @@ echo $JOB_TYPE
 
 export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=128m"
 
-mvn install -DskipTests=true -B -V
+# this should run maven enforcer
+mvn install -B -V \
+  -DskipTests=true \
+  -Dclirr.skip=true
+
 mvn -B dependency:analyze -DfailOnWarning=true
diff --git a/.repo-metadata.json b/.repo-metadata.json
index 8825ad58..db2d1370 100644
--- a/.repo-metadata.json
+++ b/.repo-metadata.json
@@ -6,5 +6,5 @@
   "language": "java",
   "repo": "googleapis/google-http-java-client",
   "repo_short": "google-http-java-client",
-  "distribution_name": "google-http-java-client"
+  "distribution_name": "com.google.http-client:google-http-client"
 }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3165b015..8b8f96d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
 # Changelog
 
+## [1.34.0](https://www.github.com/googleapis/google-http-java-client/compare/v1.33.0...v1.34.0) (2019-12-17)
+
+
+### Features
+
+* add option to pass redirect Location: header value as-is without encoding, decoding, or escaping ([#871](https://www.github.com/googleapis/google-http-java-client/issues/871)) ([2c4f49e](https://www.github.com/googleapis/google-http-java-client/commit/2c4f49e0e5f9c6b8f21f35edae373eaada87119b))
+* decode uri path components correctly ([#913](https://www.github.com/googleapis/google-http-java-client/issues/913)) ([7d4a048](https://www.github.com/googleapis/google-http-java-client/commit/7d4a048233d0d3e7c0266b7faaac9f61141aeef9)), closes [#398](https://www.github.com/googleapis/google-http-java-client/issues/398)
+* support chunked transfer encoding ([#910](https://www.github.com/googleapis/google-http-java-client/issues/910)) ([b8d6abe](https://www.github.com/googleapis/google-http-java-client/commit/b8d6abe0367bd497b68831263753ad262914aa97)), closes [#648](https://www.github.com/googleapis/google-http-java-client/issues/648)
+
+
+### Bug Fixes
+
+* redirect on 308 (Permanent Redirect) too ([#876](https://www.github.com/googleapis/google-http-java-client/issues/876)) ([501ede8](https://www.github.com/googleapis/google-http-java-client/commit/501ede83ef332207f0ed67c3d7120b20a1416cec))
+* set mediaType to null if contentType cannot be parsed ([#911](https://www.github.com/googleapis/google-http-java-client/issues/911)) ([7ea53eb](https://www.github.com/googleapis/google-http-java-client/commit/7ea53ebdb641a9611cbf5736c55f08a83606101e))
+* update HttpRequest#getVersion to use stable logic ([#919](https://www.github.com/googleapis/google-http-java-client/issues/919)) ([853ab4b](https://www.github.com/googleapis/google-http-java-client/commit/853ab4ba1bd81420f7b236c2c8f40c4a253a482e)), closes [#892](https://www.github.com/googleapis/google-http-java-client/issues/892)
+
 ## [1.32.2](https://www.github.com/googleapis/google-http-java-client/compare/v1.32.1...v1.32.2) (2019-10-29)
 
 
diff --git a/docs/setup.md b/docs/setup.md
index d654e2ff..a9b03929 100644
--- a/docs/setup.md
+++ b/docs/setup.md
@@ -23,7 +23,7 @@ the `dependencyManagement` section of your `pom.xml`:
     <dependency>
       <groupId>com.google.cloud</groupId>
       <artifactId>libraries-bom</artifactId>
-      <version>2.7.1</version>
+      <version>3.3.0</version>
       <type>pom</type>
       <scope>import</scope>
      </dependency>
diff --git a/google-http-client-android/pom.xml b/google-http-client-android/pom.xml
index a4d6c05e..3fddf9b7 100644
--- a/google-http-client-android/pom.xml
+++ b/google-http-client-android/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-android</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-android:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-android:current} -->
   <name>Android Platform Extensions to the Google HTTP Client Library for Java.</name>
 
   <build>
diff --git a/google-http-client-apache-v2/pom.xml b/google-http-client-apache-v2/pom.xml
index 35f04ac9..eab63996 100644
--- a/google-http-client-apache-v2/pom.xml
+++ b/google-http-client-apache-v2/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-apache-v2</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-apache-v2:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-apache-v2:current} -->
   <name>Apache HTTP transport v2 for the Google HTTP Client Library for Java.</name>
 
   <build>
diff --git a/google-http-client-apache-v2/src/main/java/com/google/api/client/http/apache/v2/ApacheHttpRequest.java b/google-http-client-apache-v2/src/main/java/com/google/api/client/http/apache/v2/ApacheHttpRequest.java
index 29bd61ee..ae2aac76 100644
--- a/google-http-client-apache-v2/src/main/java/com/google/api/client/http/apache/v2/ApacheHttpRequest.java
+++ b/google-http-client-apache-v2/src/main/java/com/google/api/client/http/apache/v2/ApacheHttpRequest.java
@@ -23,9 +23,7 @@ import org.apache.http.client.HttpClient;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.HttpRequestBase;
 
-/**
- * @author Yaniv Inbar
- */
+/** @author Yaniv Inbar */
 final class ApacheHttpRequest extends LowLevelHttpRequest {
   private final HttpClient httpClient;
 
@@ -38,11 +36,12 @@ final class ApacheHttpRequest extends LowLevelHttpRequest {
     this.httpClient = httpClient;
     this.request = request;
     // disable redirects as google-http-client handles redirects
-    this.requestConfig = RequestConfig.custom()
-        .setRedirectsEnabled(false)
-        .setNormalizeUri(false)
-        // TODO(chingor): configure in HttpClientBuilder when available
-        .setStaleConnectionCheckEnabled(false);
+    this.requestConfig =
+        RequestConfig.custom()
+            .setRedirectsEnabled(false)
+            .setNormalizeUri(false)
+            // TODO(chingor): configure in HttpClientBuilder when available
+            .setStaleConnectionCheckEnabled(false);
   }
 
   @Override
@@ -52,19 +51,22 @@ final class ApacheHttpRequest extends LowLevelHttpRequest {
 
   @Override
   public void setTimeout(int connectTimeout, int readTimeout) throws IOException {
-    requestConfig.setConnectTimeout(connectTimeout)
-        .setSocketTimeout(readTimeout);
+    requestConfig.setConnectTimeout(connectTimeout).setSocketTimeout(readTimeout);
   }
 
   @Override
   public LowLevelHttpResponse execute() throws IOException {
     if (getStreamingContent() != null) {
-      Preconditions.checkArgument(request instanceof HttpEntityEnclosingRequest,
+      Preconditions.checkState(
+          request instanceof HttpEntityEnclosingRequest,
           "Apache HTTP client does not support %s requests with content.",
           request.getRequestLine().getMethod());
       ContentEntity entity = new ContentEntity(getContentLength(), getStreamingContent());
       entity.setContentEncoding(getContentEncoding());
       entity.setContentType(getContentType());
+      if (getContentLength() == -1) {
+        entity.setChunked(true);
+      }
       ((HttpEntityEnclosingRequest) request).setEntity(entity);
     }
     request.setConfig(requestConfig.build());
diff --git a/google-http-client-appengine/pom.xml b/google-http-client-appengine/pom.xml
index bad8c997..51626272 100644
--- a/google-http-client-appengine/pom.xml
+++ b/google-http-client-appengine/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-appengine</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-appengine:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-appengine:current} -->
   <name>Google App Engine extensions to the Google HTTP Client Library for Java.</name>
 
   <build>
diff --git a/google-http-client-assembly/classpath-include b/google-http-client-assembly/classpath-include
index b7201881..c1bd8032 100644
--- a/google-http-client-assembly/classpath-include
+++ b/google-http-client-assembly/classpath-include
@@ -3,7 +3,6 @@
 	<classpathentry kind="lib" path="libs/google-http-client-appengine-${project.version}.jar" sourcepath="libs-sources/google-http-client-appengine-${project.version}-sources.jar"/>
 	<classpathentry kind="lib" path="libs/google-http-client-protobuf-${project.version}.jar" sourcepath="libs-sources/google-http-client-protobuf-${project.version}-sources.jar"/>
 	<classpathentry kind="lib" path="libs/google-http-client-gson-${project.version}.jar" sourcepath="libs-sources/google-http-client-gson-${project.version}-sources.jar"/>
-	<classpathentry kind="lib" path="libs/google-http-client-jackson-${project.version}.jar" sourcepath="libs-sources/google-http-client-jackson-${project.version}-sources.jar"/>
 	<classpathentry kind="lib" path="libs/google-http-client-jackson2-${project.version}.jar" sourcepath="libs-sources/google-http-client-jackson2-${project.version}-sources.jar"/>
 	<classpathentry kind="lib" path="libs/google-http-client-xml-${project.version}.jar" sourcepath="libs-sources/google-http-client-xml-${project.version}-sources.jar"/>
 	<classpathentry kind="lib" path="libs/commons-logging-${project.commons-logging.version}.jar" sourcepath="libs-sources/commons-logging-${project.commons-logging.version}-sources.jar"/>
diff --git a/google-http-client-assembly/pom.xml b/google-http-client-assembly/pom.xml
index f87c5c51..8dd0401e 100644
--- a/google-http-client-assembly/pom.xml
+++ b/google-http-client-assembly/pom.xml
@@ -4,12 +4,12 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <groupId>com.google.http-client</groupId>
   <artifactId>google-http-client-assembly</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-assembly:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-assembly:current} -->
   <packaging>pom</packaging>
   <name>Assembly for the Google HTTP Client Library for Java</name>
 
diff --git a/google-http-client-bom/pom.xml b/google-http-client-bom/pom.xml
index e71a1000..712a4eb6 100644
--- a/google-http-client-bom/pom.xml
+++ b/google-http-client-bom/pom.xml
@@ -3,7 +3,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.google.http-client</groupId>
   <artifactId>google-http-client-bom</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-bom:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-bom:current} -->
   <packaging>pom</packaging>
 
   <name>Google HTTP Client Library for Java BOM</name>
@@ -63,52 +63,52 @@
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-android</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-android:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-android:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-apache-v2</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-apache-v2:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-apache-v2:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-appengine</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-appengine:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-appengine:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-findbugs</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-findbugs:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-findbugs:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-gson</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-gson:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-gson:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-jackson2</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-jackson2:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-jackson2:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-protobuf</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-protobuf:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-protobuf:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-test</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-test:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-test:current} -->
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
         <artifactId>google-http-client-xml</artifactId>
-        <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-xml:current} -->
+        <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-xml:current} -->
       </dependency>
     </dependencies>
   </dependencyManagement>
diff --git a/google-http-client-findbugs/pom.xml b/google-http-client-findbugs/pom.xml
index 4c1bfbd4..e6e433ad 100644
--- a/google-http-client-findbugs/pom.xml
+++ b/google-http-client-findbugs/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-findbugs</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-findbugs:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-findbugs:current} -->
   <name>Google APIs Client Library Findbugs custom plugin.</name>
 
   <build>
diff --git a/google-http-client-gson/pom.xml b/google-http-client-gson/pom.xml
index b4cd29b1..9bc78ddf 100644
--- a/google-http-client-gson/pom.xml
+++ b/google-http-client-gson/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-gson</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-gson:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-gson:current} -->
   <name>GSON extensions to the Google HTTP Client Library for Java.</name>
 
   <build>
diff --git a/google-http-client-jackson2/pom.xml b/google-http-client-jackson2/pom.xml
index a0ff9f4a..cfe69649 100644
--- a/google-http-client-jackson2/pom.xml
+++ b/google-http-client-jackson2/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-jackson2</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-jackson2:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-jackson2:current} -->
   <name>Jackson 2 extensions to the Google HTTP Client Library for Java.</name>
 
   <build>
diff --git a/google-http-client-protobuf/pom.xml b/google-http-client-protobuf/pom.xml
index fe577e0b..465d4c27 100644
--- a/google-http-client-protobuf/pom.xml
+++ b/google-http-client-protobuf/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-protobuf</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-protobuf:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-protobuf:current} -->
   <name>Protocol Buffer extensions to the Google HTTP Client Library for Java.</name>
 
   <build>
diff --git a/google-http-client-xml/pom.xml b/google-http-client-xml/pom.xml
index 6e79c4cb..0c46baef 100644
--- a/google-http-client-xml/pom.xml
+++ b/google-http-client-xml/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-xml</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-xml:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-xml:current} -->
   <name>XML extensions to the Google HTTP Client Library for Java.</name>
 
   <build>
diff --git a/google-http-client/pom.xml b/google-http-client/pom.xml
index aba47c3e..3d43747a 100644
--- a/google-http-client/pom.xml
+++ b/google-http-client/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client:current} -->
   <name>Google HTTP Client Library for Java</name>
   <description>
     Google HTTP Client Library for Java. Functionality that works on all supported Java platforms,
diff --git a/google-http-client/src/main/java/com/google/api/client/http/AbstractInputStreamContent.java b/google-http-client/src/main/java/com/google/api/client/http/AbstractInputStreamContent.java
index 789fab5e..96ed5019 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/AbstractInputStreamContent.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/AbstractInputStreamContent.java
@@ -29,8 +29,6 @@ import java.io.OutputStream;
  * amount of content read from the input stream, you may use {@link ByteStreams#limit(InputStream,
  * long)}.
  *
- * <p>
- *
  * <p>Implementations don't need to be thread-safe.
  *
  * @since 1.4
diff --git a/google-http-client/src/main/java/com/google/api/client/http/ExponentialBackOffPolicy.java b/google-http-client/src/main/java/com/google/api/client/http/ExponentialBackOffPolicy.java
index 2384c8a8..20d8859b 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/ExponentialBackOffPolicy.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/ExponentialBackOffPolicy.java
@@ -31,7 +31,7 @@ import java.io.IOException;
  *     retry_interval * (random value in range [1 - randomization_factor, 1 + randomization_factor])
  * </pre>
  *
- * In other words {@link #getNextBackOffMillis()} will range between the randomization factor
+ * <p>In other words {@link #getNextBackOffMillis()} will range between the randomization factor
  * percentage below and above the retry interval. For example, using 2 seconds as the base retry
  * interval and 0.5 as the randomization factor, the actual back off period used in the next retry
  * attempt will be between 1 and 3 seconds.
diff --git a/google-http-client/src/main/java/com/google/api/client/http/GenericUrl.java b/google-http-client/src/main/java/com/google/api/client/http/GenericUrl.java
index e18810c8..45e9d5ab 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/GenericUrl.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/GenericUrl.java
@@ -80,6 +80,13 @@ public class GenericUrl extends GenericData {
   /** Fragment component or {@code null} for none. */
   private String fragment;
 
+  /**
+   * If true, the URL string originally given is used as is (without encoding, decoding and
+   * escaping) whenever referenced; otherwise, part of the URL string may be encoded or decoded as
+   * deemed appropriate or necessary.
+   */
+  private boolean verbatim;
+
   public GenericUrl() {}
 
   /**
@@ -99,7 +106,24 @@ public class GenericUrl extends GenericData {
    * @throws IllegalArgumentException if URL has a syntax error
    */
   public GenericUrl(String encodedUrl) {
-    this(parseURL(encodedUrl));
+    this(encodedUrl, false);
+  }
+
+  /**
+   * Constructs from an encoded URL.
+   *
+   * <p>Any known query parameters with pre-defined fields as data keys are parsed based on their
+   * data type. Any unrecognized query parameter are always parsed as a string.
+   *
+   * <p>Any {@link MalformedURLException} is wrapped in an {@link IllegalArgumentException}.
+   *
+   * @param encodedUrl encoded URL, including any existing query parameters that should be parsed
+   * @param verbatim flag, to specify if URL should be used as is (without encoding, decoding and
+   *     escaping)
+   * @throws IllegalArgumentException if URL has a syntax error
+   */
+  public GenericUrl(String encodedUrl, boolean verbatim) {
+    this(parseURL(encodedUrl), verbatim);
   }
 
   /**
@@ -109,6 +133,17 @@ public class GenericUrl extends GenericData {
    * @since 1.14
    */
   public GenericUrl(URI uri) {
+    this(uri, false);
+  }
+
+  /**
+   * Constructs from a URI.
+   *
+   * @param uri URI
+   * @param verbatim flag, to specify if URL should be used as is (without encoding, decoding and
+   *     escaping)
+   */
+  public GenericUrl(URI uri, boolean verbatim) {
     this(
         uri.getScheme(),
         uri.getHost(),
@@ -116,7 +151,8 @@ public class GenericUrl extends GenericData {
         uri.getRawPath(),
         uri.getRawFragment(),
         uri.getRawQuery(),
-        uri.getRawUserInfo());
+        uri.getRawUserInfo(),
+        verbatim);
   }
 
   /**
@@ -126,6 +162,18 @@ public class GenericUrl extends GenericData {
    * @since 1.14
    */
   public GenericUrl(URL url) {
+    this(url, false);
+  }
+
+  /**
+   * Constructs from a URL.
+   *
+   * @param url URL
+   * @param verbatim flag, to specify if URL should be used as is (without encoding, decoding and
+   *     escaping)
+   * @since 1.14
+   */
+  public GenericUrl(URL url, boolean verbatim) {
     this(
         url.getProtocol(),
         url.getHost(),
@@ -133,7 +181,8 @@ public class GenericUrl extends GenericData {
         url.getPath(),
         url.getRef(),
         url.getQuery(),
-        url.getUserInfo());
+        url.getUserInfo(),
+        verbatim);
   }
 
   private GenericUrl(
@@ -143,16 +192,26 @@ public class GenericUrl extends GenericData {
       String path,
       String fragment,
       String query,
-      String userInfo) {
+      String userInfo,
+      boolean verbatim) {
     this.scheme = scheme.toLowerCase(Locale.US);
     this.host = host;
     this.port = port;
-    this.pathParts = toPathParts(path);
-    this.fragment = fragment != null ? CharEscapers.decodeUri(fragment) : null;
-    if (query != null) {
-      UrlEncodedParser.parse(query, this);
+    this.pathParts = toPathParts(path, verbatim);
+    this.verbatim = verbatim;
+    if (verbatim) {
+      this.fragment = fragment;
+      if (query != null) {
+        UrlEncodedParser.parse(query, this, false);
+      }
+      this.userInfo = userInfo;
+    } else {
+      this.fragment = fragment != null ? CharEscapers.decodeUri(fragment) : null;
+      if (query != null) {
+        UrlEncodedParser.parse(query, this);
+      }
+      this.userInfo = userInfo != null ? CharEscapers.decodeUri(userInfo) : null;
     }
-    this.userInfo = userInfo != null ? CharEscapers.decodeUri(userInfo) : null;
   }
 
   @Override
@@ -333,7 +392,7 @@ public class GenericUrl extends GenericData {
     buf.append(Preconditions.checkNotNull(scheme));
     buf.append("://");
     if (userInfo != null) {
-      buf.append(CharEscapers.escapeUriUserInfo(userInfo)).append('@');
+      buf.append(verbatim ? userInfo : CharEscapers.escapeUriUserInfo(userInfo)).append('@');
     }
     buf.append(Preconditions.checkNotNull(host));
     int port = this.port;
@@ -357,12 +416,12 @@ public class GenericUrl extends GenericData {
     if (pathParts != null) {
       appendRawPathFromParts(buf);
     }
-    addQueryParams(entrySet(), buf);
+    addQueryParams(entrySet(), buf, verbatim);
 
     // URL fragment
     String fragment = this.fragment;
     if (fragment != null) {
-      buf.append('#').append(URI_FRAGMENT_ESCAPER.escape(fragment));
+      buf.append('#').append(verbatim ? fragment : URI_FRAGMENT_ESCAPER.escape(fragment));
     }
     return buf.toString();
   }
@@ -467,7 +526,7 @@ public class GenericUrl extends GenericData {
    * @param encodedPath raw encoded path or {@code null} to set {@link #pathParts} to {@code null}
    */
   public void setRawPath(String encodedPath) {
-    pathParts = toPathParts(encodedPath);
+    pathParts = toPathParts(encodedPath, verbatim);
   }
 
   /**
@@ -482,7 +541,7 @@ public class GenericUrl extends GenericData {
    */
   public void appendRawPath(String encodedPath) {
     if (encodedPath != null && encodedPath.length() != 0) {
-      List<String> appendedPathParts = toPathParts(encodedPath);
+      List<String> appendedPathParts = toPathParts(encodedPath, verbatim);
       if (pathParts == null || pathParts.isEmpty()) {
         this.pathParts = appendedPathParts;
       } else {
@@ -492,7 +551,6 @@ public class GenericUrl extends GenericData {
       }
     }
   }
-
   /**
    * Returns the decoded path parts for the given encoded path.
    *
@@ -503,6 +561,21 @@ public class GenericUrl extends GenericData {
    *     or {@code ""} input
    */
   public static List<String> toPathParts(String encodedPath) {
+    return toPathParts(encodedPath, false);
+  }
+
+  /**
+   * Returns the path parts (decoded if not {@code verbatim}).
+   *
+   * @param encodedPath slash-prefixed encoded path, for example {@code
+   *     "/m8/feeds/contacts/default/full"}
+   * @param verbatim flag, to specify if URL should be used as is (without encoding, decoding and
+   *     escaping)
+   * @return path parts (decoded if not {@code verbatim}), with each part assumed to be preceded by
+   *     a {@code '/'}, for example {@code "", "m8", "feeds", "contacts", "default", "full"}, or
+   *     {@code null} for {@code null} or {@code ""} input
+   */
+  public static List<String> toPathParts(String encodedPath, boolean verbatim) {
     if (encodedPath == null || encodedPath.length() == 0) {
       return null;
     }
@@ -518,7 +591,7 @@ public class GenericUrl extends GenericData {
       } else {
         sub = encodedPath.substring(cur);
       }
-      result.add(CharEscapers.decodeUri(sub));
+      result.add(verbatim ? sub : CharEscapers.decodeUriPath(sub));
       cur = slash + 1;
     }
     return result;
@@ -532,32 +605,37 @@ public class GenericUrl extends GenericData {
         buf.append('/');
       }
       if (pathPart.length() != 0) {
-        buf.append(CharEscapers.escapeUriPath(pathPart));
+        buf.append(verbatim ? pathPart : CharEscapers.escapeUriPath(pathPart));
       }
     }
   }
 
   /** Adds query parameters from the provided entrySet into the buffer. */
-  static void addQueryParams(Set<Entry<String, Object>> entrySet, StringBuilder buf) {
+  static void addQueryParams(
+      Set<Entry<String, Object>> entrySet, StringBuilder buf, boolean verbatim) {
     // (similar to UrlEncodedContent)
     boolean first = true;
     for (Map.Entry<String, Object> nameValueEntry : entrySet) {
       Object value = nameValueEntry.getValue();
       if (value != null) {
-        String name = CharEscapers.escapeUriQuery(nameValueEntry.getKey());
+        String name =
+            verbatim
+                ? nameValueEntry.getKey()
+                : CharEscapers.escapeUriQuery(nameValueEntry.getKey());
         if (value instanceof Collection<?>) {
           Collection<?> collectionValue = (Collection<?>) value;
           for (Object repeatedValue : collectionValue) {
-            first = appendParam(first, buf, name, repeatedValue);
+            first = appendParam(first, buf, name, repeatedValue, verbatim);
           }
         } else {
-          first = appendParam(first, buf, name, value);
+          first = appendParam(first, buf, name, value, verbatim);
         }
       }
     }
   }
 
-  private static boolean appendParam(boolean first, StringBuilder buf, String name, Object value) {
+  private static boolean appendParam(
+      boolean first, StringBuilder buf, String name, Object value, boolean verbatim) {
     if (first) {
       first = false;
       buf.append('?');
@@ -565,7 +643,8 @@ public class GenericUrl extends GenericData {
       buf.append('&');
     }
     buf.append(name);
-    String stringValue = CharEscapers.escapeUriQuery(value.toString());
+    String stringValue =
+        verbatim ? value.toString() : CharEscapers.escapeUriQuery(value.toString());
     if (stringValue.length() != 0) {
       buf.append('=').append(stringValue);
     }
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 f6cd29ef..9124e490 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,6 @@
 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.LoggingStreamingContent;
 import com.google.api.client.util.ObjectParser;
 import com.google.api.client.util.Preconditions;
@@ -175,6 +174,9 @@ public final class HttpRequest {
   /** Whether to automatically follow redirects ({@code true} by default). */
   private boolean followRedirects = true;
 
+  /** Whether to use raw redirect URLs ({@code false} by default). */
+  private boolean useRawRedirectUrls = false;
+
   /**
    * Whether to throw an exception at the end of {@link #execute()} on an HTTP error code (non-2XX)
    * after all retries and response handlers have been exhausted ({@code true} by default).
@@ -695,6 +697,21 @@ public final class HttpRequest {
     return this;
   }
 
+  /** Return whether to use raw redirect URLs. */
+  public boolean getUseRawRedirectUrls() {
+    return useRawRedirectUrls;
+  }
+
+  /**
+   * Sets whether to use raw redirect URLs.
+   *
+   * <p>The default value is {@code false}.
+   */
+  public HttpRequest setUseRawRedirectUrls(boolean useRawRedirectUrls) {
+    this.useRawRedirectUrls = useRawRedirectUrls;
+    return this;
+  }
+
   /**
    * Returns whether to throw an exception at the end of {@link #execute()} on an HTTP error code
    * (non-2XX) after all retries and response handlers have been exhausted.
@@ -918,7 +935,7 @@ public final class HttpRequest {
       final boolean contentRetrySupported = streamingContent == null || content.retrySupported();
       if (streamingContent != null) {
         final String contentEncoding;
-        final long contentLength;
+        long contentLength = -1;
         final String contentType = content.getType();
         // log content
         if (loggable) {
@@ -933,7 +950,6 @@ public final class HttpRequest {
         } else {
           contentEncoding = encoding.getName();
           streamingContent = new HttpEncodingStreamingContent(streamingContent, encoding);
-          contentLength = contentRetrySupported ? IOUtils.computeLength(streamingContent) : -1;
         }
         // append content headers to log buffer
         if (loggable) {
@@ -1159,7 +1175,7 @@ public final class HttpRequest {
         && HttpStatusCodes.isRedirect(statusCode)
         && redirectLocation != null) {
       // resolve the redirect location relative to the current location
-      setUrl(new GenericUrl(url.toURL(redirectLocation)));
+      setUrl(new GenericUrl(url.toURL(redirectLocation), useRawRedirectUrls));
       // on 303 change method to GET
       if (statusCode == HttpStatusCodes.STATUS_CODE_SEE_OTHER) {
         setRequestMethod(HttpMethods.GET);
@@ -1202,21 +1218,19 @@ public final class HttpRequest {
       span.putAttribute(key, AttributeValue.stringAttributeValue(value));
     }
   }
-  
+
   private static String getVersion() {
-    String version = HttpRequest.class.getPackage().getImplementationVersion();
-    // in a non-packaged environment (local), there's no implementation version to read
-    if (version == null) {
-      // fall back to reading from a properties file - note this value is expected to be cached
-      try (InputStream inputStream = HttpRequest.class.getResourceAsStream("/google-http-client.properties")) {
-        if (inputStream != null) {
-          Properties properties = new Properties();
-          properties.load(inputStream);
-          version = properties.getProperty("google-http-client.version");
-        }
-      } catch (IOException e) {
-        // ignore
+    // attempt to read the library's version from a properties file generated during the build
+    // this value should be read and cached for later use
+    String version = "unknown-version";
+    try (InputStream inputStream = HttpRequest.class.getResourceAsStream("/google-http-client.properties")) {
+      if (inputStream != null) {
+        final Properties properties = new Properties();
+        properties.load(inputStream);
+        version = properties.getProperty("google-http-client.version");
       }
+    } catch (IOException e) {
+      // ignore
     }
     return version;
   }
diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpResponse.java b/google-http-client/src/main/java/com/google/api/client/http/HttpResponse.java
index 5273300f..3341720a 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/HttpResponse.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/HttpResponse.java
@@ -150,7 +150,7 @@ public final class HttpResponse {
       contentType = request.getResponseHeaders().getContentType();
     }
     this.contentType = contentType;
-    mediaType = contentType == null ? null : new HttpMediaType(contentType);
+    this.mediaType = parseMediaType(contentType);
 
     // log from buffer
     if (loggable) {
@@ -158,6 +158,22 @@ public final class HttpResponse {
     }
   }
 
+  /**
+   * Returns an {@link HttpMediaType} object parsed from {@link #contentType}, or {@code null} if
+   * if {@link #contentType} cannot be parsed or {@link #contentType} is {@code null}.
+   */
+  private static HttpMediaType parseMediaType(String contentType) {
+    if (contentType == null) {
+      return null;
+    }
+    try {
+      return new HttpMediaType(contentType);
+    } catch (IllegalArgumentException e) {
+      // contentType is invalid and cannot be parsed.
+      return null;
+    }
+  }
+
   /**
    * Returns the limit to the content size that will be logged during {@link #getContent()}.
    *
diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpStatusCodes.java b/google-http-client/src/main/java/com/google/api/client/http/HttpStatusCodes.java
index 1f46eaad..4f7e18be 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/HttpStatusCodes.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/HttpStatusCodes.java
@@ -57,6 +57,9 @@ public class HttpStatusCodes {
   /** Status code for a resource that has temporarily moved to a new URI. */
   public static final int STATUS_CODE_TEMPORARY_REDIRECT = 307;
 
+  /** Status code for a resource that has permanently moved to a new URI. */
+  private static final int STATUS_CODE_PERMANENT_REDIRECT = 308;
+
   /** Status code for a request that could not be understood by the server. */
   public static final int STATUS_CODE_BAD_REQUEST = 400;
 
@@ -109,7 +112,7 @@ public class HttpStatusCodes {
 
   /**
    * Returns whether the given HTTP response status code is a redirect code {@code 301, 302, 303,
-   * 307}.
+   * 307, 308}.
    *
    * @since 1.11
    */
@@ -119,6 +122,7 @@ public class HttpStatusCodes {
       case HttpStatusCodes.STATUS_CODE_FOUND: // 302
       case HttpStatusCodes.STATUS_CODE_SEE_OTHER: // 303
       case HttpStatusCodes.STATUS_CODE_TEMPORARY_REDIRECT: // 307
+      case HttpStatusCodes.STATUS_CODE_PERMANENT_REDIRECT: // 308
         return true;
       default:
         return false;
diff --git a/google-http-client/src/main/java/com/google/api/client/http/MultipartContent.java b/google-http-client/src/main/java/com/google/api/client/http/MultipartContent.java
index 4fdc0b58..43a58b44 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/MultipartContent.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/MultipartContent.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.UUID;
 
 /**
  * Serializes MIME multipart content as specified by <a
@@ -31,7 +32,7 @@ import java.util.Collections;
  * and <a href="http://tools.ietf.org/html/rfc1521#section-7.2.2">RFC 2046: Multipurpose Internet
  * Mail Extensions: The Multipart/mixed (primary) subtype</a>.
  *
- * <p>By default the media type is {@code "multipart/related; boundary=__END_OF_PART__"}, but this
+ * <p>By default the media type is {@code "multipart/related; boundary=__END_OF_PART__<random UUID>__"}, but this
  * may be customized by calling {@link #setMediaType(HttpMediaType)}, {@link #getMediaType()}, or
  * {@link #setBoundary(String)}.
  *
@@ -47,10 +48,14 @@ public class MultipartContent extends AbstractHttpContent {
   private static final String TWO_DASHES = "--";
 
   /** Parts of the HTTP multipart request. */
-  private ArrayList<Part> parts = new ArrayList<Part>();
+  private ArrayList<Part> parts = new ArrayList<>();
 
   public MultipartContent() {
-    super(new HttpMediaType("multipart/related").setParameter("boundary", "__END_OF_PART__"));
+    this("__END_OF_PART__" + UUID.randomUUID().toString() + "__");
+  }
+
+  public MultipartContent(String boundary) {
+    super(new HttpMediaType("multipart/related").setParameter("boundary", boundary));
   }
 
   public void writeTo(OutputStream out) throws IOException {
@@ -152,7 +157,7 @@ public class MultipartContent extends AbstractHttpContent {
    * changing the return type, but nothing else.
    */
   public MultipartContent setParts(Collection<Part> parts) {
-    this.parts = new ArrayList<Part>(parts);
+    this.parts = new ArrayList<>(parts);
     return this;
   }
 
@@ -164,7 +169,7 @@ public class MultipartContent extends AbstractHttpContent {
    * changing the return type, but nothing else.
    */
   public MultipartContent setContentParts(Collection<? extends HttpContent> contentParts) {
-    this.parts = new ArrayList<Part>(contentParts.size());
+    this.parts = new ArrayList<>(contentParts.size());
     for (HttpContent contentPart : contentParts) {
       addPart(new Part(contentPart));
     }
diff --git a/google-http-client/src/main/java/com/google/api/client/http/UriTemplate.java b/google-http-client/src/main/java/com/google/api/client/http/UriTemplate.java
index f3e7d63d..fcf25fa4 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/UriTemplate.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/UriTemplate.java
@@ -318,7 +318,7 @@ public class UriTemplate {
     }
     if (addUnusedParamsAsQueryParams) {
       // Add the parameters remaining in the variableMap as query parameters.
-      GenericUrl.addQueryParams(variableMap.entrySet(), pathBuf);
+      GenericUrl.addQueryParams(variableMap.entrySet(), pathBuf, false);
     }
     return pathBuf.toString();
   }
diff --git a/google-http-client/src/main/java/com/google/api/client/http/UrlEncodedParser.java b/google-http-client/src/main/java/com/google/api/client/http/UrlEncodedParser.java
index cd5e8a63..fb5ec537 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/UrlEncodedParser.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/UrlEncodedParser.java
@@ -73,7 +73,6 @@ public class UrlEncodedParser implements ObjectParser {
    */
   public static final String MEDIA_TYPE =
       new HttpMediaType(UrlEncodedParser.CONTENT_TYPE).setCharsetParameter(Charsets.UTF_8).build();
-
   /**
    * Parses the given URL-encoded content into the given data object of data key name/value pairs
    * using {@link #parse(Reader, Object)}.
@@ -82,17 +81,28 @@ public class UrlEncodedParser implements ObjectParser {
    * @param data data key name/value pairs
    */
   public static void parse(String content, Object data) {
+    parse(content, data, true);
+  }
+ 
+  /**
+   * Parses the given URL-encoded content into the given data object of data key name/value pairs
+   * using {@link #parse(Reader, Object)}.
+   *
+   * @param content URL-encoded content or {@code null} to ignore content
+   * @param data data key name/value pairs
+   * @param decodeEnabled flag that specifies whether decoding should be enabled.
+   */
+    public static void parse(String content, Object data, boolean decodeEnabled) {
     if (content == null) {
       return;
     }
     try {
-      parse(new StringReader(content), data);
+      parse(new StringReader(content), data, decodeEnabled);
     } catch (IOException exception) {
       // I/O exception not expected on a string
       throw Throwables.propagate(exception);
     }
   }
-
   /**
    * Parses the given URL-encoded content into the given data object of data key name/value pairs,
    * including support for repeating data key names.
@@ -113,7 +123,32 @@ public class UrlEncodedParser implements ObjectParser {
    * @param data data key name/value pairs
    * @since 1.14
    */
-  public static void parse(Reader reader, Object data) throws IOException {
+    public static void parse(Reader reader, Object data) throws IOException {
+      parse(reader, data, true);
+    }
+ 
+  /**
+   * Parses the given URL-encoded content into the given data object of data key name/value pairs,
+   * including support for repeating data key names.
+   *
+   * <p>Declared fields of a "primitive" type (as defined by {@link Data#isPrimitive(Type)} are
+   * parsed using {@link Data#parsePrimitiveValue(Type, String)} where the {@link Class} parameter
+   * is the declared field class. Declared fields of type {@link Collection} are used to support
+   * repeating data key names, so each member of the collection is an additional data key value.
+   * They are parsed the same as "primitive" fields, except that the generic type parameter of the
+   * collection is used as the {@link Class} parameter.
+   *
+   * <p>If there is no declared field for an input parameter name, it is ignored unless the
+   * input {@code data} parameter is a {@link Map}. If it is a map, the parameter value is 
+   * stored either as a string, or as a {@link ArrayList}&lt;String&gt; in the case of repeated
+   * parameters.
+   *
+   * @param reader URL-encoded reader
+   * @param data data key name/value pairs
+   * @param decodeEnabled flag that specifies whether data should be decoded.
+   * @since 1.14
+   */
+  public static void parse(Reader reader, Object data, boolean decodeEnabled) throws IOException {
     Class<?> clazz = data.getClass();
     ClassInfo classInfo = ClassInfo.of(clazz);
     List<Type> context = Arrays.<Type>asList(clazz);
@@ -132,9 +167,9 @@ public class UrlEncodedParser implements ObjectParser {
           // falls through
         case '&':
           // parse name/value pair
-          String name = CharEscapers.decodeUri(nameWriter.toString());
+          String name = decodeEnabled ?  CharEscapers.decodeUri(nameWriter.toString()) : nameWriter.toString();
           if (name.length() != 0) {
-            String stringValue = CharEscapers.decodeUri(valueWriter.toString());
+            String stringValue = decodeEnabled ? CharEscapers.decodeUri(valueWriter.toString()) : valueWriter.toString();
             // get the field from the type information
             FieldInfo fieldInfo = classInfo.getFieldInfo(name);
             if (fieldInfo != null) {
diff --git a/google-http-client/src/main/java/com/google/api/client/http/apache/ApacheHttpRequest.java b/google-http-client/src/main/java/com/google/api/client/http/apache/ApacheHttpRequest.java
index b31b2059..355acfcd 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/apache/ApacheHttpRequest.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/apache/ApacheHttpRequest.java
@@ -25,9 +25,7 @@ import org.apache.http.conn.params.ConnManagerParams;
 import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpParams;
 
-/**
- * @author Yaniv Inbar
- */
+/** @author Yaniv Inbar */
 final class ApacheHttpRequest extends LowLevelHttpRequest {
   private final HttpClient httpClient;
 
@@ -54,12 +52,16 @@ final class ApacheHttpRequest extends LowLevelHttpRequest {
   @Override
   public LowLevelHttpResponse execute() throws IOException {
     if (getStreamingContent() != null) {
-      Preconditions.checkArgument(request instanceof HttpEntityEnclosingRequest,
+      Preconditions.checkState(
+          request instanceof HttpEntityEnclosingRequest,
           "Apache HTTP client does not support %s requests with content.",
           request.getRequestLine().getMethod());
       ContentEntity entity = new ContentEntity(getContentLength(), getStreamingContent());
       entity.setContentEncoding(getContentEncoding());
       entity.setContentType(getContentType());
+      if (getContentLength() == -1) {
+        entity.setChunked(true);
+      }
       ((HttpEntityEnclosingRequest) request).setEntity(entity);
     }
     return new ApacheHttpResponse(request, httpClient.execute(request));
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 aa0d8e3e..1d043472 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
@@ -49,6 +49,11 @@ final class NetHttpRequest extends LowLevelHttpRequest {
     connection.addRequestProperty(name, value);
   }
 
+  @VisibleForTesting
+  String getRequestProperty(String name) {
+    return connection.getRequestProperty(name);
+  }
+
   @Override
   public void setTimeout(int connectTimeout, int readTimeout) {
     connection.setReadTimeout(readTimeout);
diff --git a/google-http-client/src/main/java/com/google/api/client/json/JsonParser.java b/google-http-client/src/main/java/com/google/api/client/json/JsonParser.java
index 9bb1184f..7ac07ff5 100644
--- a/google-http-client/src/main/java/com/google/api/client/json/JsonParser.java
+++ b/google-http-client/src/main/java/com/google/api/client/json/JsonParser.java
@@ -50,8 +50,6 @@ import java.util.concurrent.locks.ReentrantLock;
  * <p>Implementation has no fields and therefore thread-safe, but sub-classes are not necessarily
  * thread-safe.
  *
- * <p>
- *
  * <p>If a JSON map is encountered while using a destination class of type Map, then an {@link
  * java.util.ArrayMap} is used by default for the parsed values.
  *
diff --git a/google-http-client/src/main/java/com/google/api/client/json/JsonString.java b/google-http-client/src/main/java/com/google/api/client/json/JsonString.java
index 6b93bbe2..68b3b2f9 100644
--- a/google-http-client/src/main/java/com/google/api/client/json/JsonString.java
+++ b/google-http-client/src/main/java/com/google/api/client/json/JsonString.java
@@ -32,7 +32,7 @@ import java.lang.annotation.Target;
  * </code>
  * </pre>
  *
- * can be used for this JSON content:
+ * <p>can be used for this JSON content:
  *
  * <pre>
  * <code>
@@ -40,7 +40,7 @@ import java.lang.annotation.Target;
  * </code>
  * </pre>
  *
- * However, if instead the JSON content uses a JSON String to store the value, one needs to use the
+ * <p>However, if instead the JSON content uses a JSON String to store the value, one needs to use the
  * {@link JsonString} annotation. For example:
  *
  * <pre>
@@ -51,7 +51,7 @@ import java.lang.annotation.Target;
  * </code>
  * </pre>
  *
- * can be used for this JSON content:
+ * <p>can be used for this JSON content:
  *
  * <pre>
  * <code>
diff --git a/google-http-client/src/main/java/com/google/api/client/util/DateTime.java b/google-http-client/src/main/java/com/google/api/client/util/DateTime.java
index cd0dcd77..4caf768c 100644
--- a/google-http-client/src/main/java/com/google/api/client/util/DateTime.java
+++ b/google-http-client/src/main/java/com/google/api/client/util/DateTime.java
@@ -273,7 +273,7 @@ public final class DateTime implements Serializable {
    *     exception is thrown if {@code str} doesn't match {@code RFC3339_REGEX} or if it contains a
    *     time zone shift but no time.
    */
-  public static DateTime parseRfc3339(String str) throws NumberFormatException {
+  public static DateTime parseRfc3339(String str) {
     return parseRfc3339WithNanoSeconds(str).toDateTime();
   }
 
@@ -285,9 +285,9 @@ public final class DateTime implements Serializable {
    *     exception is thrown if {@code str} doesn't match {@code RFC3339_REGEX} or if it contains a
    *     time zone shift but no time.
    */
-  public static SecondsAndNanos parseRfc3339ToSecondsAndNanos(String str)
-      throws IllegalArgumentException {
-    return parseRfc3339WithNanoSeconds(str).toSecondsAndNanos();
+  public static SecondsAndNanos parseRfc3339ToSecondsAndNanos(String str) {
+    Rfc3339ParseResult time = parseRfc3339WithNanoSeconds(str);
+    return time.toSecondsAndNanos();
   }
 
   /** A timestamp represented as the number of seconds and nanoseconds since Epoch. */
@@ -335,7 +335,7 @@ public final class DateTime implements Serializable {
     }
   }
 
-  /** Result of parsing a Rfc3339 string. */
+  /** Result of parsing an RFC 3339 string. */
   private static class Rfc3339ParseResult implements Serializable {
     private final long seconds;
     private final int nanos;
@@ -400,6 +400,7 @@ public final class DateTime implements Serializable {
       }
     }
     Calendar dateTime = new GregorianCalendar(GMT);
+    dateTime.clear();
     dateTime.set(year, month, day, hourOfDay, minute, second);
     long value = dateTime.getTimeInMillis();
 
diff --git a/google-http-client/src/main/java/com/google/api/client/util/PemReader.java b/google-http-client/src/main/java/com/google/api/client/util/PemReader.java
index a1f06a3b..607d80de 100644
--- a/google-http-client/src/main/java/com/google/api/client/util/PemReader.java
+++ b/google-http-client/src/main/java/com/google/api/client/util/PemReader.java
@@ -36,9 +36,7 @@ import java.util.regex.Pattern;
  *
  * <p>Limitations:
  *
- * <p>
- *
- * <ul>
+ * <p><ul>
  *   <li>Assumes the PEM file section content is not encrypted and cannot handle the case of any
  *       headers inside the BEGIN and END tag.
  *   <li>It also ignores any attributes associated with any PEM file section.
diff --git a/google-http-client/src/main/java/com/google/api/client/util/escape/CharEscapers.java b/google-http-client/src/main/java/com/google/api/client/util/escape/CharEscapers.java
index b8ed2c11..b6172cc9 100644
--- a/google-http-client/src/main/java/com/google/api/client/util/escape/CharEscapers.java
+++ b/google-http-client/src/main/java/com/google/api/client/util/escape/CharEscapers.java
@@ -16,6 +16,8 @@ package com.google.api.client.util.escape;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Utility functions for dealing with {@code CharEscaper}s, and some commonly used {@code
@@ -83,7 +85,29 @@ public final class CharEscapers {
    */
   public static String decodeUri(String uri) {
     try {
-      return URLDecoder.decode(uri, "UTF-8");
+      return URLDecoder.decode(uri, StandardCharsets.UTF_8.name());
+    } catch (UnsupportedEncodingException e) {
+      // UTF-8 encoding guaranteed to be supported by JVM
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Decodes the path component of a URI. This must be done via a method that does not try to
+   * convert + into spaces(the behavior of {@link java.net.URLDecoder#decode(String, String)}). This
+   * method transforms URI encoded values into their decoded symbols.
+   *
+   * <p>i.e: {@code decodePath("%3Co%3E")} would return {@code "<o>"}
+   *
+   * @param path the value to be decoded
+   * @return decoded version of {@code path}
+   */
+  public static String decodeUriPath(String path) {
+    if (path == null) {
+      return null;
+    }
+    try {
+      return URLDecoder.decode(path.replace("+", "%2B"), StandardCharsets.UTF_8.name());
     } catch (UnsupportedEncodingException e) {
       // UTF-8 encoding guaranteed to be supported by JVM
       throw new RuntimeException(e);
diff --git a/google-http-client/src/main/java/com/google/api/client/util/escape/PercentEscaper.java b/google-http-client/src/main/java/com/google/api/client/util/escape/PercentEscaper.java
index cedd09af..a4437095 100644
--- a/google-http-client/src/main/java/com/google/api/client/util/escape/PercentEscaper.java
+++ b/google-http-client/src/main/java/com/google/api/client/util/escape/PercentEscaper.java
@@ -62,7 +62,7 @@ public class PercentEscaper extends UnicodeEscaper {
    * specified in RFC 3986. Note that some of these characters do need to be escaped when used in
    * other parts of the URI.
    */
-  public static final String SAFEPATHCHARS_URLENCODER = "-_.!~*'()@:$&,;=";
+  public static final String SAFEPATHCHARS_URLENCODER = "-_.!~*'()@:$&,;=+";
 
   /**
    * Contains the save characters plus all reserved characters. This happens to be the safe path
diff --git a/pom.xml b/pom.xml
index 376774de..7cb05adc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.google.http-client</groupId>
   <artifactId>google-http-client-parent</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
   <packaging>pom</packaging>
   <name>Parent for the Google HTTP Client Library for Java</name>
   <description>Google HTTP Client Library for Java</description>
@@ -118,7 +118,7 @@
       <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
-        <version>4.12</version>
+        <version>4.13</version>
       </dependency>
       <dependency>
         <groupId>com.google.truth</groupId>
@@ -298,7 +298,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-source-plugin</artifactId>
-          <version>3.1.0</version>
+          <version>3.2.1</version>
           <executions>
             <execution>
               <id>attach-sources</id>
@@ -324,7 +324,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
-          <version>3.1.2</version>
+          <version>3.2.0</version>
           <executions>
             <execution>
               <goals>
@@ -387,7 +387,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-enforcer-plugin</artifactId>
-        <version>3.0.0-M2</version><executions>
+        <version>3.0.0-M3</version><executions>
         <execution>
           <id>enforce-maven</id>
           <goals>
@@ -549,13 +549,13 @@
       - google-api-java-client/google-api-client-assembly/android-properties (make the filenames match the version here)
       - Internally, update the default features.json file
     -->
-    <project.http-client.version>1.33.1-SNAPSHOT</project.http-client.version><!-- {x-version-update:google-http-client-parent:current} -->
+    <project.http-client.version>1.34.1-SNAPSHOT</project.http-client.version><!-- {x-version-update:google-http-client-parent:current} -->
     <project.appengine.version>1.9.71</project.appengine.version>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <project.jsr305.version>3.0.2</project.jsr305.version>
     <project.gson.version>2.8.6</project.gson.version>
-    <project.jackson-core2.version>2.10.0</project.jackson-core2.version>
-    <project.protobuf-java.version>3.10.0</project.protobuf-java.version>
+    <project.jackson-core2.version>2.10.2</project.jackson-core2.version>
+    <project.protobuf-java.version>3.11.1</project.protobuf-java.version>
     <project.guava.version>28.1-android</project.guava.version>
     <project.xpp3.version>1.1.4c</project.xpp3.version>
     <project.commons-logging.version>1.2</project.commons-logging.version>
diff --git a/samples/dailymotion-simple-cmdline-sample/pom.xml b/samples/dailymotion-simple-cmdline-sample/pom.xml
index 2f90ac64..a30dfc32 100644
--- a/samples/dailymotion-simple-cmdline-sample/pom.xml
+++ b/samples/dailymotion-simple-cmdline-sample/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../../pom.xml</relativePath>
   </parent>
   <artifactId>dailymotion-simple-cmdline-sample</artifactId>
diff --git a/synth.metadata b/synth.metadata
index 635b2ec0..aa3ceb00 100644
--- a/synth.metadata
+++ b/synth.metadata
@@ -1,5 +1,5 @@
 {
-  "updateTime": "2019-10-26T07:51:02.270792Z",
+  "updateTime": "2019-11-21T08:36:32.990208Z",
   "sources": [
     {
       "template": {
diff --git a/versions.txt b/versions.txt
index 08ce6e97..250b4fa9 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,17 +1,17 @@
 # Format:
 # module:released-version:current-version
 
-google-http-client:1.33.0:1.33.1-SNAPSHOT
-google-http-client-bom:1.33.0:1.33.1-SNAPSHOT
-google-http-client-parent:1.33.0:1.33.1-SNAPSHOT
-google-http-client-android:1.33.0:1.33.1-SNAPSHOT
-google-http-client-android-test:1.33.0:1.33.1-SNAPSHOT
-google-http-client-apache-v2:1.33.0:1.33.1-SNAPSHOT
-google-http-client-appengine:1.33.0:1.33.1-SNAPSHOT
-google-http-client-assembly:1.33.0:1.33.1-SNAPSHOT
-google-http-client-findbugs:1.33.0:1.33.1-SNAPSHOT
-google-http-client-gson:1.33.0:1.33.1-SNAPSHOT
-google-http-client-jackson2:1.33.0:1.33.1-SNAPSHOT
-google-http-client-protobuf:1.33.0:1.33.1-SNAPSHOT
-google-http-client-test:1.33.0:1.33.1-SNAPSHOT
-google-http-client-xml:1.33.0:1.33.1-SNAPSHOT
+google-http-client:1.34.0:1.34.1-SNAPSHOT
+google-http-client-bom:1.34.0:1.34.1-SNAPSHOT
+google-http-client-parent:1.34.0:1.34.1-SNAPSHOT
+google-http-client-android:1.34.0:1.34.1-SNAPSHOT
+google-http-client-android-test:1.34.0:1.34.1-SNAPSHOT
+google-http-client-apache-v2:1.34.0:1.34.1-SNAPSHOT
+google-http-client-appengine:1.34.0:1.34.1-SNAPSHOT
+google-http-client-assembly:1.34.0:1.34.1-SNAPSHOT
+google-http-client-findbugs:1.34.0:1.34.1-SNAPSHOT
+google-http-client-gson:1.34.0:1.34.1-SNAPSHOT
+google-http-client-jackson2:1.34.0:1.34.1-SNAPSHOT
+google-http-client-protobuf:1.34.0:1.34.1-SNAPSHOT
+google-http-client-test:1.34.0:1.34.1-SNAPSHOT
+google-http-client-xml:1.34.0:1.34.1-SNAPSHOT


Test patch:
diff --git a/google-http-client-android-test/pom.xml b/google-http-client-android-test/pom.xml
index d5b44458..37bdde14 100644
--- a/google-http-client-android-test/pom.xml
+++ b/google-http-client-android-test/pom.xml
@@ -4,7 +4,7 @@
   <groupId>google-http-client</groupId>
   <artifactId>google-http-client-android-test</artifactId>
   <name>Test project for google-http-client-android.</name>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-android-test:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-android-test:current} -->
   <packaging>apk</packaging>
 
   <build>
@@ -53,7 +53,7 @@
     <dependency>
       <groupId>com.google.http-client</groupId>
       <artifactId>google-http-client-android</artifactId>
-      <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-android:current} -->
+      <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-android:current} -->
       <exclusions>
         <exclusion>
           <artifactId>android</artifactId>
@@ -72,7 +72,7 @@
     <dependency>
       <groupId>com.google.http-client</groupId>
       <artifactId>google-http-client-test</artifactId>
-      <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-test:current} -->
+      <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-test:current} -->
       <exclusions>
         <exclusion>
           <artifactId>junit</artifactId>
diff --git a/google-http-client-apache-v2/src/test/java/com/google/api/client/http/apache/v2/ApacheHttpRequestTest.java b/google-http-client-apache-v2/src/test/java/com/google/api/client/http/apache/v2/ApacheHttpRequestTest.java
new file mode 100644
index 00000000..74c97244
--- /dev/null
+++ b/google-http-client-apache-v2/src/test/java/com/google/api/client/http/apache/v2/ApacheHttpRequestTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.http.apache.v2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.api.client.http.ByteArrayContent;
+import com.google.api.client.http.HttpContent;
+import com.google.api.client.http.InputStreamContent;
+import com.google.api.client.testing.http.apache.MockHttpClient;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import org.junit.Test;
+
+public class ApacheHttpRequestTest {
+
+  @Test
+  public void testContentLengthSet() throws Exception {
+    HttpExtensionMethod base = new HttpExtensionMethod("POST", "http://www.google.com");
+    ApacheHttpRequest request = new ApacheHttpRequest(new MockHttpClient(), base);
+    HttpContent content =
+        new ByteArrayContent("text/plain", "sample".getBytes(StandardCharsets.UTF_8));
+    request.setStreamingContent(content);
+    request.setContentLength(content.getLength());
+    request.execute();
+
+    assertFalse(base.getEntity().isChunked());
+    assertEquals(6, base.getEntity().getContentLength());
+  }
+
+  @Test
+  public void testChunked() throws Exception {
+    byte[] buf = new byte[300];
+    Arrays.fill(buf, (byte) ' ');
+    HttpExtensionMethod base = new HttpExtensionMethod("POST", "http://www.google.com");
+    ApacheHttpRequest request = new ApacheHttpRequest(new MockHttpClient(), base);
+    HttpContent content = new InputStreamContent("text/plain", new ByteArrayInputStream(buf));
+    request.setStreamingContent(content);
+    request.execute();
+
+    assertTrue(base.getEntity().isChunked());
+    assertEquals(-1, base.getEntity().getContentLength());
+  }
+}
diff --git a/google-http-client-apache-v2/src/test/java/com/google/api/client/http/apache/v2/ApacheHttpTransportTest.java b/google-http-client-apache-v2/src/test/java/com/google/api/client/http/apache/v2/ApacheHttpTransportTest.java
index e6ca850c..e9b93e9b 100644
--- a/google-http-client-apache-v2/src/test/java/com/google/api/client/http/apache/v2/ApacheHttpTransportTest.java
+++ b/google-http-client-apache-v2/src/test/java/com/google/api/client/http/apache/v2/ApacheHttpTransportTest.java
@@ -34,7 +34,6 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.net.InetSocketAddress;
 import java.nio.charset.StandardCharsets;
-import java.util.Random;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.http.Header;
@@ -123,8 +122,8 @@ public class ApacheHttpTransportTest {
       throws IOException {
     try {
       execute(request);
-      fail("expected " + IllegalArgumentException.class);
-    } catch (IllegalArgumentException e) {
+      fail("expected " + IllegalStateException.class);
+    } catch (IllegalStateException e) {
       // expected
       assertEquals(e.getMessage(),
           "Apache HTTP client does not support " + method + " requests with content.");
diff --git a/google-http-client-test/pom.xml b/google-http-client-test/pom.xml
index fe6b8db8..d11c2ae2 100644
--- a/google-http-client-test/pom.xml
+++ b/google-http-client-test/pom.xml
@@ -4,11 +4,11 @@
   <parent>
     <groupId>com.google.http-client</groupId>
     <artifactId>google-http-client-parent</artifactId>
-    <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
+    <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-parent:current} -->
     <relativePath>../pom.xml</relativePath>
   </parent>
   <artifactId>google-http-client-test</artifactId>
-  <version>1.33.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-test:current} -->
+  <version>1.34.1-SNAPSHOT</version><!-- {x-version-update:google-http-client-test:current} -->
   <name>Shared classes used for testing of artifacts in the Google HTTP Client Library for Java.</name>
 
   <build>
diff --git a/google-http-client/src/main/java/com/google/api/client/testing/http/javanet/MockHttpURLConnection.java b/google-http-client/src/main/java/com/google/api/client/testing/http/javanet/MockHttpURLConnection.java
index 467f495f..2fba28b4 100644
--- a/google-http-client/src/main/java/com/google/api/client/testing/http/javanet/MockHttpURLConnection.java
+++ b/google-http-client/src/main/java/com/google/api/client/testing/http/javanet/MockHttpURLConnection.java
@@ -201,4 +201,8 @@ public class MockHttpURLConnection extends HttpURLConnection {
     List<String> values = headers.get(name);
     return values == null ? null : values.get(0);
   }
+
+  public int getChunkLength() {
+    return chunkLength;
+  }
 }
diff --git a/google-http-client/src/main/java/com/google/api/client/testing/json/webtoken/TestCertificates.java b/google-http-client/src/main/java/com/google/api/client/testing/json/webtoken/TestCertificates.java
index 5c3457af..2ae6b08c 100644
--- a/google-http-client/src/main/java/com/google/api/client/testing/json/webtoken/TestCertificates.java
+++ b/google-http-client/src/main/java/com/google/api/client/testing/json/webtoken/TestCertificates.java
@@ -240,7 +240,7 @@ public class TestCertificates {
    * {"foo":"bar"}
    * </pre>
    *
-   * The message is signed using {@code FOO_BAR_COM_KEY}.
+   * <p>The message is signed using {@code FOO_BAR_COM_KEY}.
    */
   public static final String JWS_SIGNATURE =
       "eyJhbGciOiJSUzI1NiIsIng1YyI6WyJNSUlDNlRDQ0FkRUNBU293RFFZSktvWklo"
diff --git a/google-http-client/src/test/java/com/google/api/client/http/GenericUrlTest.java b/google-http-client/src/test/java/com/google/api/client/http/GenericUrlTest.java
index 3ef97247..dbe1cc93 100644
--- a/google-http-client/src/test/java/com/google/api/client/http/GenericUrlTest.java
+++ b/google-http-client/src/test/java/com/google/api/client/http/GenericUrlTest.java
@@ -150,6 +150,10 @@ public class GenericUrlTest extends TestCase {
     public TestUrl(String encodedUrl) {
       super(encodedUrl);
     }
+
+    public TestUrl(String encodedUrl, boolean verbatim) {
+      super(encodedUrl, verbatim);
+    }
   }
 
   private static final String FULL =
@@ -193,6 +197,12 @@ public class GenericUrlTest extends TestCase {
     assertEquals("bar", url.foo);
   }
 
+  public void testParse_full_verbatim() {
+    TestUrl url = new TestUrl(FULL, true);
+    assertNull(url.hidden);
+    assertEquals("Go%3D%23/%25%26%20?%3Co%3Egle", url.getFirst("q"));
+  }
+
   public void testConstructor_url() throws MalformedURLException {
     GenericUrl url = new GenericUrl(new URL(FULL));
     subtestFull(url);
@@ -470,10 +480,12 @@ public class GenericUrlTest extends TestCase {
     subtestToPathParts("/path/to/resource", "", "path", "to", "resource");
     subtestToPathParts("/path/to/resource/", "", "path", "to", "resource", "");
     subtestToPathParts("/Go%3D%23%2F%25%26%20?%3Co%3Egle/2nd", "", "Go=#/%& ?<o>gle", "2nd");
+    subtestToPathParts("/plus+test/resource", "", "plus+test", "resource");
+    subtestToPathParts("/plus%2Btest/resource", "", "plus+test", "resource");
   }
 
   private void subtestToPathParts(String encodedPath, String... expectedDecodedParts) {
-    List<String> result = GenericUrl.toPathParts(encodedPath);
+    List<String> result = GenericUrl.toPathParts(encodedPath, false);
     if (encodedPath == null) {
       assertNull(result);
     } else {
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 a76b6385..bb47e98d 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
@@ -31,10 +31,6 @@ import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
-
-import java.util.regex.Pattern;
-import junit.framework.TestCase;
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.util.Arrays;
@@ -45,7 +41,8 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.logging.Level;
-
+import java.util.regex.Pattern;
+import junit.framework.TestCase;
 import org.junit.Assert;
 
 /**
@@ -990,7 +987,7 @@ public class HttpRequestTest extends TestCase {
             if (expectGZip) {
               assertEquals(HttpEncodingStreamingContent.class, getStreamingContent().getClass());
               assertEquals("gzip", getContentEncoding());
-              assertEquals(25, getContentLength());
+              assertEquals(-1, getContentLength());
             } else {
               assertFalse(
                   getStreamingContent().getClass().equals(HttpEncodingStreamingContent.class));
@@ -1230,7 +1227,9 @@ public class HttpRequestTest extends TestCase {
       if (message.startsWith("curl")) {
         found = true;
         assertTrue(message.contains("curl -v --compressed -H 'Accept-Encoding: gzip'"));
-        assertTrue(message.contains("-H 'User-Agent: Google-HTTP-Java-Client/" + HttpRequest.VERSION + " (gzip)'"));
+        assertTrue(
+            message.contains(
+                "-H 'User-Agent: Google-HTTP-Java-Client/" + HttpRequest.VERSION + " (gzip)'"));
         assertTrue(message.contains("' -- 'http://google.com/#q=a'\"'\"'b'\"'\"'c'"));
       }
     }
@@ -1261,10 +1260,22 @@ public class HttpRequestTest extends TestCase {
         found = true;
         assertTrue(message.contains("curl -v --compressed -X POST -H 'Accept-Encoding: gzip'"));
         assertTrue(message.contains("-H 'User-Agent: " + HttpRequest.USER_AGENT_SUFFIX + "'"));
-        assertTrue(message.contains("-H 'Content-Type: text/plain; charset=UTF-8' -H 'Content-Encoding: gzip'"));
+        assertTrue(
+            message.contains(
+                "-H 'Content-Type: text/plain; charset=UTF-8' -H 'Content-Encoding: gzip'"));
         assertTrue(message.contains("-d '@-' -- 'http://google.com/#q=a'\"'\"'b'\"'\"'c' << $$$"));
       }
     }
     assertTrue(found);
   }
+
+  public void testVersion_matchesAcceptablePatterns() throws Exception {
+    String acceptableVersionPattern =
+        "unknown-version|(?:\\d+\\.\\d+\\.\\d+(?:-.*?)?(?:-SNAPSHOT)?)";
+    String version = HttpRequest.VERSION;
+    assertTrue(
+        String.format("the loaded version '%s' did not match the acceptable pattern", version),
+        version.matches(acceptableVersionPattern)
+    );
+  }
 }
diff --git a/google-http-client/src/test/java/com/google/api/client/http/HttpResponseTest.java b/google-http-client/src/test/java/com/google/api/client/http/HttpResponseTest.java
index a3efdb30..f7638d67 100644
--- a/google-http-client/src/test/java/com/google/api/client/http/HttpResponseTest.java
+++ b/google-http-client/src/test/java/com/google/api/client/http/HttpResponseTest.java
@@ -58,6 +58,10 @@ public class HttpResponseTest extends TestCase {
 
   private static final String SAMPLE = "123\u05D9\u05e0\u05D9\u05D1";
   private static final String SAMPLE2 = "123abc";
+  private static final String VALID_CONTENT_TYPE = "text/plain";
+  private static final String VALID_CONTENT_TYPE_WITH_PARAMS =
+      "application/vnd.com.google.datastore.entity+json; charset=utf-8; version=v1; q=0.9";
+  private static final String INVALID_CONTENT_TYPE = "!!!invalid!!!";
 
   public void testParseAsString_utf8() throws Exception {
     HttpTransport transport =
@@ -102,6 +106,81 @@ public class HttpResponseTest extends TestCase {
     assertEquals(SAMPLE2, response.parseAsString());
   }
 
+  public void testParseAsString_validContentType() throws Exception {
+    HttpTransport transport =
+        new MockHttpTransport() {
+          @Override
+          public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
+            return new MockLowLevelHttpRequest() {
+              @Override
+              public LowLevelHttpResponse execute() throws IOException {
+                MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
+                result.setContent(SAMPLE2);
+                result.setContentType(VALID_CONTENT_TYPE);
+                return result;
+              }
+            };
+          }
+        };
+    HttpRequest request =
+        transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
+
+    HttpResponse response = request.execute();
+    assertEquals(SAMPLE2, response.parseAsString());
+    assertEquals(VALID_CONTENT_TYPE, response.getContentType());
+    assertNotNull(response.getMediaType());
+  }
+
+  public void testParseAsString_validContentTypeWithParams() throws Exception {
+    HttpTransport transport =
+        new MockHttpTransport() {
+          @Override
+          public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
+            return new MockLowLevelHttpRequest() {
+              @Override
+              public LowLevelHttpResponse execute() throws IOException {
+                MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
+                result.setContent(SAMPLE2);
+                result.setContentType(VALID_CONTENT_TYPE_WITH_PARAMS);
+                return result;
+              }
+            };
+          }
+        };
+    HttpRequest request =
+        transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
+
+    HttpResponse response = request.execute();
+    assertEquals(SAMPLE2, response.parseAsString());
+    assertEquals(VALID_CONTENT_TYPE_WITH_PARAMS, response.getContentType());
+    assertNotNull(response.getMediaType());
+  }
+
+  public void testParseAsString_invalidContentType() throws Exception {
+    HttpTransport transport =
+        new MockHttpTransport() {
+          @Override
+          public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
+            return new MockLowLevelHttpRequest() {
+              @Override
+              public LowLevelHttpResponse execute() throws IOException {
+                MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
+                result.setContent(SAMPLE2);
+                result.setContentType(INVALID_CONTENT_TYPE);
+                return result;
+              }
+            };
+          }
+        };
+    HttpRequest request =
+        transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
+
+    HttpResponse response = request.execute();
+    assertEquals(SAMPLE2, response.parseAsString());
+    assertEquals(INVALID_CONTENT_TYPE, response.getContentType());
+    assertNull(response.getMediaType());
+  }
+
   public void testStatusCode_negative_dontThrowException() throws Exception {
     subtestStatusCode_negative(false);
   }
diff --git a/google-http-client/src/test/java/com/google/api/client/http/HttpStatusCodesTest.java b/google-http-client/src/test/java/com/google/api/client/http/HttpStatusCodesTest.java
new file mode 100644
index 00000000..58b43f02
--- /dev/null
+++ b/google-http-client/src/test/java/com/google/api/client/http/HttpStatusCodesTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.http;
+
+import junit.framework.TestCase;
+
+/** Tests {@link HttpStatusCodes}. */
+public class HttpStatusCodesTest extends TestCase {
+
+  public void testIsRedirect_3xx() {
+    assertTrue(HttpStatusCodes.isRedirect(301));
+    assertTrue(HttpStatusCodes.isRedirect(302));
+    assertTrue(HttpStatusCodes.isRedirect(303));
+    assertTrue(HttpStatusCodes.isRedirect(307));
+    assertTrue(HttpStatusCodes.isRedirect(308));
+  }
+
+  public void testIsRedirect_non3xx() {
+    assertFalse(HttpStatusCodes.isRedirect(200));
+    assertFalse(HttpStatusCodes.isRedirect(401));
+    assertFalse(HttpStatusCodes.isRedirect(500));
+  }
+}
diff --git a/google-http-client/src/test/java/com/google/api/client/http/MultipartContentTest.java b/google-http-client/src/test/java/com/google/api/client/http/MultipartContentTest.java
index 76f725b6..14e0e599 100644
--- a/google-http-client/src/test/java/com/google/api/client/http/MultipartContentTest.java
+++ b/google-http-client/src/test/java/com/google/api/client/http/MultipartContentTest.java
@@ -15,6 +15,7 @@
 package com.google.api.client.http;
 
 import com.google.api.client.json.Json;
+import com.google.api.client.util.Charsets;
 import com.google.api.client.util.StringUtils;
 import java.io.ByteArrayOutputStream;
 import junit.framework.TestCase;
@@ -26,55 +27,76 @@ import junit.framework.TestCase;
  */
 public class MultipartContentTest extends TestCase {
 
+  private static final String BOUNDARY = "__END_OF_PART__";
   private static final String CRLF = "\r\n";
   private static final String CONTENT_TYPE = Json.MEDIA_TYPE;
-  private static final String HEADERS =
-      "Content-Length: 3"
-          + CRLF
-          + "Content-Type: application/json; charset=UTF-8"
-          + CRLF
-          + "content-transfer-encoding: binary"
-          + CRLF;
+  private static final String HEADERS = headers("application/json; charset=UTF-8", "foo");
+
+  private static String headers(String contentType, String value) {
+      return "Content-Length: " + value.length() + CRLF
+          + "Content-Type: " + contentType + CRLF
+          + "content-transfer-encoding: binary" + CRLF;
+  }
+
+  public void testRandomContent() throws Exception {
+    MultipartContent content = new MultipartContent();
+    String boundaryString = content.getBoundary();
+    assertNotNull(boundaryString);
+    assertTrue(boundaryString.startsWith(BOUNDARY));
+    assertTrue(boundaryString.endsWith("__"));
+    assertEquals("multipart/related; boundary=" + boundaryString, content.getType());
+
+    final String[][] VALUES = new String[][] {
+            {"Hello world", "text/plain"},
+            {"<xml>Hi</xml>", "application/xml"},
+            {"{x:1,y:2}", "application/json"}
+    };
+    StringBuilder expectedStringBuilder = new StringBuilder();
+    for (String[] valueTypePair: VALUES) {
+      String contentValue = valueTypePair[0];
+      String contentType = valueTypePair[1];
+      content.addPart(new MultipartContent.Part(ByteArrayContent.fromString(contentType, contentValue)));
+      expectedStringBuilder.append("--").append(boundaryString).append(CRLF)
+              .append(headers(contentType, contentValue)).append(CRLF)
+              .append(contentValue).append(CRLF);
+    }
+    expectedStringBuilder.append("--").append(boundaryString).append("--").append(CRLF);
+    // write to string
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    content.writeTo(out);
+    String expectedContent = expectedStringBuilder.toString();
+    assertEquals(expectedContent, out.toString(Charsets.UTF_8.name()));
+    assertEquals(StringUtils.getBytesUtf8(expectedContent).length, content.getLength());
+  }
 
   public void testContent() throws Exception {
-    subtestContent("--__END_OF_PART__--" + CRLF, null);
+    subtestContent("--" + BOUNDARY + "--" + CRLF, null);
     subtestContent(
-        "--__END_OF_PART__" + CRLF + HEADERS + CRLF + "foo" + CRLF + "--__END_OF_PART__--" + CRLF,
-        null,
+        "--" + BOUNDARY + CRLF
+                + HEADERS + CRLF
+                + "foo" + CRLF
+                + "--" + BOUNDARY + "--" + CRLF,
+            null,
         "foo");
     subtestContent(
-        "--__END_OF_PART__"
-            + CRLF
-            + HEADERS
-            + CRLF
-            + "foo"
-            + CRLF
-            + "--__END_OF_PART__"
-            + CRLF
-            + HEADERS
-            + CRLF
-            + "bar"
-            + CRLF
-            + "--__END_OF_PART__--"
-            + CRLF,
-        null,
+        "--" + BOUNDARY + CRLF
+            + HEADERS + CRLF
+            + "foo" + CRLF
+            + "--" + BOUNDARY + CRLF
+            + HEADERS + CRLF
+            + "bar" + CRLF
+            + "--" + BOUNDARY + "--" + CRLF,
+            null,
         "foo",
         "bar");
     subtestContent(
-        "--myboundary"
-            + CRLF
-            + HEADERS
-            + CRLF
-            + "foo"
-            + CRLF
-            + "--myboundary"
-            + CRLF
-            + HEADERS
-            + CRLF
-            + "bar"
-            + CRLF
-            + "--myboundary--"
-            + CRLF,
+        "--myboundary" + CRLF
+            + HEADERS + CRLF
+            + "foo" + CRLF
+            + "--myboundary" + CRLF
+            + HEADERS + CRLF
+            + "bar" + CRLF
+            + "--myboundary--" + CRLF,
         "myboundary",
         "foo",
         "bar");
@@ -83,7 +105,7 @@ public class MultipartContentTest extends TestCase {
   private void subtestContent(String expectedContent, String boundaryString, String... contents)
       throws Exception {
     // multipart content
-    MultipartContent content = new MultipartContent();
+    MultipartContent content = new MultipartContent(boundaryString == null ? BOUNDARY : boundaryString);
     for (String contentValue : contents) {
       content.addPart(
           new MultipartContent.Part(ByteArrayContent.fromString(CONTENT_TYPE, contentValue)));
@@ -94,11 +116,11 @@ public class MultipartContentTest extends TestCase {
     // write to string
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     content.writeTo(out);
-    assertEquals(expectedContent, out.toString());
+    assertEquals(expectedContent, out.toString(Charsets.UTF_8.name()));
     assertEquals(StringUtils.getBytesUtf8(expectedContent).length, content.getLength());
     assertEquals(
         boundaryString == null
-            ? "multipart/related; boundary=__END_OF_PART__"
+            ? "multipart/related; boundary=" + BOUNDARY
             : "multipart/related; boundary=" + boundaryString,
         content.getType());
   }
diff --git a/google-http-client/src/test/java/com/google/api/client/http/javanet/NetHttpRequestTest.java b/google-http-client/src/test/java/com/google/api/client/http/javanet/NetHttpRequestTest.java
index d4118328..ae3606ca 100644
--- a/google-http-client/src/test/java/com/google/api/client/http/javanet/NetHttpRequestTest.java
+++ b/google-http-client/src/test/java/com/google/api/client/http/javanet/NetHttpRequestTest.java
@@ -1,9 +1,8 @@
 package com.google.api.client.http.javanet;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 
+import com.google.api.client.http.ByteArrayContent;
 import com.google.api.client.http.HttpContent;
 import com.google.api.client.http.InputStreamContent;
 import com.google.api.client.http.LowLevelHttpResponse;
@@ -15,6 +14,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.util.concurrent.TimeoutException;
 import org.junit.Test;
 
@@ -203,4 +203,34 @@ public class NetHttpRequestTest {
       assertEquals("Error during close", e.getMessage());
     }
   }
+
+  @Test
+  public void testChunkedLengthSet() throws Exception {
+    MockHttpURLConnection connection = new MockHttpURLConnection(new URL(HttpTesting.SIMPLE_URL));
+    connection.setRequestMethod("POST");
+    NetHttpRequest request = new NetHttpRequest(connection);
+    InputStream is = NetHttpRequestTest.class.getClassLoader().getResourceAsStream("file.txt");
+    HttpContent content = new InputStreamContent("text/plain", is);
+    request.setStreamingContent(content);
+    request.setContentEncoding("gzip");
+    request.execute();
+
+    assertEquals(4096, connection.getChunkLength());
+    assertNull(request.getRequestProperty("Content-Length"));
+  }
+
+  @Test
+  public void testChunkedLengthNotSet() throws Exception {
+    MockHttpURLConnection connection = new MockHttpURLConnection(new URL(HttpTesting.SIMPLE_URL));
+    connection.setRequestMethod("POST");
+    NetHttpRequest request = new NetHttpRequest(connection);
+    HttpContent content =
+        new ByteArrayContent("text/plain", "sample".getBytes(StandardCharsets.UTF_8));
+    request.setStreamingContent(content);
+    request.setContentLength(content.getLength());
+    request.execute();
+
+    assertEquals(connection.getChunkLength(), -1);
+    assertEquals("6", request.getRequestProperty("Content-Length"));
+  }
 }
diff --git a/google-http-client/src/test/java/com/google/api/client/util/DateTimeTest.java b/google-http-client/src/test/java/com/google/api/client/util/DateTimeTest.java
index c8b9cd51..785ab40d 100644
--- a/google-http-client/src/test/java/com/google/api/client/util/DateTimeTest.java
+++ b/google-http-client/src/test/java/com/google/api/client/util/DateTimeTest.java
@@ -28,12 +28,6 @@ public class DateTimeTest extends TestCase {
 
   private TimeZone originalTimeZone;
 
-  public DateTimeTest() {}
-
-  public DateTimeTest(String testName) {
-    super(testName);
-  }
-
   @Override
   protected void setUp() throws Exception {
     originalTimeZone = TimeZone.getDefault();
@@ -154,6 +148,11 @@ public class DateTimeTest extends TestCase {
         DateTime.parseRfc3339(
             "2018-12-31T23:59:59.9999Z"), // This value would be truncated prior to version 1.30.2
         DateTime.parseRfc3339("2018-12-31T23:59:59.999Z"));
+
+    // The beginning of Gregorian Calendar
+    assertEquals(
+        -12219287774877L, // Result from Joda time's Instant.parse
+        DateTime.parseRfc3339("1582-10-15T01:23:45.123Z").getValue());
   }
 
   /**
@@ -225,8 +224,18 @@ public class DateTimeTest extends TestCase {
     assertParsedRfc3339(
         "2018-03-01T10:11:12.1000Z", SecondsAndNanos.ofSecondsAndNanos(1519899072L, 100000000));
   }
+  
+  public void testEpoch() {
+    assertParsedRfc3339(
+        "1970-01-01T00:00:00.000Z", SecondsAndNanos.ofSecondsAndNanos(0, 0));
+  }
+
+  public void testOneSecondBeforeEpoch() {
+    assertParsedRfc3339(
+        "1969-12-31T23:59:59.000Z", SecondsAndNanos.ofSecondsAndNanos(-1, 0));
+  }
 
-  private void assertParsedRfc3339(String input, SecondsAndNanos expected) {
+  private static void assertParsedRfc3339(String input, SecondsAndNanos expected) {
     SecondsAndNanos actual = DateTime.parseRfc3339ToSecondsAndNanos(input);
     assertEquals(
         "Seconds for " + input + " do not match", expected.getSeconds(), actual.getSeconds());
@@ -249,7 +258,7 @@ public class DateTimeTest extends TestCase {
     assertEquals(expected, output);
   }
 
-  private void expectExceptionForParseRfc3339(String input) {
+  private static void expectExceptionForParseRfc3339(String input) {
     try {
       DateTime.parseRfc3339(input);
       fail("expected NumberFormatException");
diff --git a/google-http-client/src/test/java/com/google/api/client/util/escape/CharEscapersTest.java b/google-http-client/src/test/java/com/google/api/client/util/escape/CharEscapersTest.java
new file mode 100644
index 00000000..0ad3d1e5
--- /dev/null
+++ b/google-http-client/src/test/java/com/google/api/client/util/escape/CharEscapersTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.escape;
+
+import junit.framework.TestCase;
+
+public class CharEscapersTest extends TestCase {
+
+  public void testDecodeUriPath() {
+    subtestDecodeUriPath(null, null);
+    subtestDecodeUriPath("", "");
+    subtestDecodeUriPath("abc", "abc");
+    subtestDecodeUriPath("a+b%2Bc", "a+b+c");
+    subtestDecodeUriPath("Go%3D%23%2F%25%26%20?%3Co%3Egle", "Go=#/%& ?<o>gle");
+  }
+
+  private void subtestDecodeUriPath(String input, String expected) {
+    String actual = CharEscapers.decodeUriPath(input);
+    assertEquals(expected, actual);
+  }
+
+  public void testDecodeUri_IllegalArgumentException() {
+    subtestDecodeUri_IllegalArgumentException("abc%-1abc");
+    subtestDecodeUri_IllegalArgumentException("%JJ");
+    subtestDecodeUri_IllegalArgumentException("abc%0");
+  }
+
+  private void subtestDecodeUri_IllegalArgumentException(String input) {
+    boolean thrown = false;
+    try {
+      CharEscapers.decodeUriPath(input);
+    } catch (IllegalArgumentException e) {
+      thrown = true;
+    }
+    assertTrue(thrown);
+  }
+}