You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2018/01/03 18:47:25 UTC
[1/4] httpcomponents-client git commit: Moved ByteArrayBuilder class
(no functional changes)
Repository: httpcomponents-client
Updated Branches:
refs/heads/master eb1cab46e -> 47a0eb8b6
Moved ByteArrayBuilder class (no functional changes)
Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/db4b6db7
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/db4b6db7
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/db4b6db7
Branch: refs/heads/master
Commit: db4b6db79fbb7f36d02d2b401658f36a91a47028
Parents: eb1cab4
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Wed Jan 3 14:35:51 2018 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Wed Jan 3 14:36:20 2018 +0100
----------------------------------------------------------------------
.../hc/client5/http/auth/ByteArrayBuilder.java | 211 +++++++++++++++++++
.../http/auth/util/ByteArrayBuilder.java | 211 -------------------
.../hc/client5/http/impl/auth/BasicScheme.java | 2 +-
.../hc/client5/http/impl/auth/DigestScheme.java | 2 +-
.../client5/http/impl/auth/NTLMEngineImpl.java | 2 +-
.../http/auth/util/TestByteArrayBuilder.java | 1 +
6 files changed, 215 insertions(+), 214 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/db4b6db7/httpclient5/src/main/java/org/apache/hc/client5/http/auth/ByteArrayBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/ByteArrayBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/ByteArrayBuilder.java
new file mode 100644
index 0000000..1d12878
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/ByteArrayBuilder.java
@@ -0,0 +1,211 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.client5.http.auth;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.ThreadingBehavior;
+
+/**
+ * Builder class for sequences of bytes.
+ *
+ * @since 5.0
+ */
+@Contract(threading = ThreadingBehavior.IMMUTABLE)
+public final class ByteArrayBuilder {
+
+ private CharsetEncoder charsetEncoder;
+ private ByteBuffer buffer;
+
+ public ByteArrayBuilder() {
+ }
+
+ public ByteArrayBuilder(final int initialCapacity) {
+ this.buffer = ByteBuffer.allocate(initialCapacity);
+ }
+
+ public int capacity() {
+ return this.buffer != null ? this.buffer.capacity() : 0;
+ }
+
+ static ByteBuffer ensureFreeCapacity(final ByteBuffer buffer, final int capacity) {
+ if (buffer == null) {
+ return ByteBuffer.allocate(capacity);
+ }
+ if (buffer.remaining() < capacity) {
+ final ByteBuffer newBuffer = ByteBuffer.allocate(buffer.position() + capacity);
+ buffer.flip();
+ newBuffer.put(buffer);
+ return newBuffer;
+ }
+ return buffer;
+ }
+
+ static ByteBuffer encode(
+ final ByteBuffer buffer, final CharBuffer in, final CharsetEncoder encoder) throws CharacterCodingException {
+
+ final int capacity = (int) (in.remaining() * encoder.averageBytesPerChar());
+ ByteBuffer out = ensureFreeCapacity(buffer, capacity);
+ for (;;) {
+ CoderResult result = in.hasRemaining() ? encoder.encode(in, out, true) : CoderResult.UNDERFLOW;
+ if (result.isError()) {
+ result.throwException();
+ }
+ if (result.isUnderflow()) {
+ result = encoder.flush(out);
+ }
+ if (result.isUnderflow()) {
+ break;
+ }
+ if (result.isOverflow()) {
+ out = ensureFreeCapacity(out, capacity);
+ }
+ }
+ return out;
+ }
+
+ public void ensureFreeCapacity(final int freeCapacity) {
+ this.buffer = ensureFreeCapacity(this.buffer, freeCapacity);
+ }
+
+ private void doAppend(final CharBuffer charBuffer) {
+ if (this.charsetEncoder == null) {
+ this.charsetEncoder = StandardCharsets.US_ASCII.newEncoder()
+ .onMalformedInput(CodingErrorAction.IGNORE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+ this.charsetEncoder.reset();
+ try {
+ this.buffer = encode(this.buffer, charBuffer, this.charsetEncoder);
+ } catch (final CharacterCodingException ex) {
+ // Should never happen
+ throw new IllegalStateException("Unexpected character coding error", ex);
+ }
+ }
+
+ public ByteArrayBuilder charset(final Charset charset) {
+ if (charset == null) {
+ this.charsetEncoder = null;
+ } else {
+ this.charsetEncoder = charset.newEncoder()
+ .onMalformedInput(CodingErrorAction.IGNORE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+ return this;
+ }
+
+ public ByteArrayBuilder append(final byte[] b, final int off, final int len) {
+ if (b == null) {
+ return this;
+ }
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) < 0) || ((off + len) > b.length)) {
+ throw new IndexOutOfBoundsException("off: " + off + " len: " + len + " b.length: " + b.length);
+ }
+ ensureFreeCapacity(len);
+ this.buffer.put(b, off, len);
+ return this;
+ }
+
+ public ByteArrayBuilder append(final byte[] b) {
+ if (b == null) {
+ return this;
+ }
+ return append(b, 0, b.length);
+ }
+
+ public ByteArrayBuilder append(final CharBuffer charBuffer) {
+ if (charBuffer == null) {
+ return this;
+ }
+ doAppend(charBuffer);
+ return this;
+ }
+
+ public ByteArrayBuilder append(final char[] b, final int off, final int len) {
+ if (b == null) {
+ return this;
+ }
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) < 0) || ((off + len) > b.length)) {
+ throw new IndexOutOfBoundsException("off: " + off + " len: " + len + " b.length: " + b.length);
+ }
+ return append(CharBuffer.wrap(b, off, len));
+ }
+
+ public ByteArrayBuilder append(final char[] b) {
+ if (b == null) {
+ return this;
+ }
+ return append(b, 0, b.length);
+ }
+
+ public ByteArrayBuilder append(final String s) {
+ if (s == null) {
+ return this;
+ }
+ return append(CharBuffer.wrap(s));
+ }
+
+ public ByteBuffer toByteBuffer() {
+ return this.buffer != null ? this.buffer.duplicate() : ByteBuffer.allocate(0);
+ }
+
+ public byte[] toByteArray() {
+ if (this.buffer == null) {
+ return new byte[] {};
+ }
+ this.buffer.flip();
+ final byte[] b = new byte[this.buffer.remaining()];
+ this.buffer.get(b);
+ this.buffer.clear();
+ return b;
+ }
+
+ public void reset() {
+ if (this.charsetEncoder != null) {
+ this.charsetEncoder.reset();
+ }
+ if (this.buffer != null) {
+ this.buffer.clear();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return this.buffer != null ? this.buffer.toString() : "null";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/db4b6db7/httpclient5/src/main/java/org/apache/hc/client5/http/auth/util/ByteArrayBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/util/ByteArrayBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/util/ByteArrayBuilder.java
deleted file mode 100644
index 138f681..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/util/ByteArrayBuilder.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.hc.client5.http.auth.util;
-
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-
-/**
- * Builder class for sequences of bytes.
- *
- * @since 5.0
- */
-@Contract(threading = ThreadingBehavior.IMMUTABLE)
-public class ByteArrayBuilder {
-
- private CharsetEncoder charsetEncoder;
- private ByteBuffer buffer;
-
- public ByteArrayBuilder() {
- }
-
- public ByteArrayBuilder(final int initialCapacity) {
- this.buffer = ByteBuffer.allocate(initialCapacity);
- }
-
- public int capacity() {
- return this.buffer != null ? this.buffer.capacity() : 0;
- }
-
- static ByteBuffer ensureFreeCapacity(final ByteBuffer buffer, final int capacity) {
- if (buffer == null) {
- return ByteBuffer.allocate(capacity);
- }
- if (buffer.remaining() < capacity) {
- final ByteBuffer newBuffer = ByteBuffer.allocate(buffer.position() + capacity);
- buffer.flip();
- newBuffer.put(buffer);
- return newBuffer;
- }
- return buffer;
- }
-
- static ByteBuffer encode(
- final ByteBuffer buffer, final CharBuffer in, final CharsetEncoder encoder) throws CharacterCodingException {
-
- final int capacity = (int) (in.remaining() * encoder.averageBytesPerChar());
- ByteBuffer out = ensureFreeCapacity(buffer, capacity);
- for (;;) {
- CoderResult result = in.hasRemaining() ? encoder.encode(in, out, true) : CoderResult.UNDERFLOW;
- if (result.isError()) {
- result.throwException();
- }
- if (result.isUnderflow()) {
- result = encoder.flush(out);
- }
- if (result.isUnderflow()) {
- break;
- }
- if (result.isOverflow()) {
- out = ensureFreeCapacity(out, capacity);
- }
- }
- return out;
- }
-
- public void ensureFreeCapacity(final int freeCapacity) {
- this.buffer = ensureFreeCapacity(this.buffer, freeCapacity);
- }
-
- private void doAppend(final CharBuffer charBuffer) {
- if (this.charsetEncoder == null) {
- this.charsetEncoder = StandardCharsets.US_ASCII.newEncoder()
- .onMalformedInput(CodingErrorAction.IGNORE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- }
- this.charsetEncoder.reset();
- try {
- this.buffer = encode(this.buffer, charBuffer, this.charsetEncoder);
- } catch (final CharacterCodingException ex) {
- // Should never happen
- throw new IllegalStateException("Unexpected character coding error", ex);
- }
- }
-
- public ByteArrayBuilder charset(final Charset charset) {
- if (charset == null) {
- this.charsetEncoder = null;
- } else {
- this.charsetEncoder = charset.newEncoder()
- .onMalformedInput(CodingErrorAction.IGNORE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- }
- return this;
- }
-
- public ByteArrayBuilder append(final byte[] b, final int off, final int len) {
- if (b == null) {
- return this;
- }
- if ((off < 0) || (off > b.length) || (len < 0) ||
- ((off + len) < 0) || ((off + len) > b.length)) {
- throw new IndexOutOfBoundsException("off: " + off + " len: " + len + " b.length: " + b.length);
- }
- ensureFreeCapacity(len);
- this.buffer.put(b, off, len);
- return this;
- }
-
- public ByteArrayBuilder append(final byte[] b) {
- if (b == null) {
- return this;
- }
- return append(b, 0, b.length);
- }
-
- public ByteArrayBuilder append(final CharBuffer charBuffer) {
- if (charBuffer == null) {
- return this;
- }
- doAppend(charBuffer);
- return this;
- }
-
- public ByteArrayBuilder append(final char[] b, final int off, final int len) {
- if (b == null) {
- return this;
- }
- if ((off < 0) || (off > b.length) || (len < 0) ||
- ((off + len) < 0) || ((off + len) > b.length)) {
- throw new IndexOutOfBoundsException("off: " + off + " len: " + len + " b.length: " + b.length);
- }
- return append(CharBuffer.wrap(b, off, len));
- }
-
- public ByteArrayBuilder append(final char[] b) {
- if (b == null) {
- return this;
- }
- return append(b, 0, b.length);
- }
-
- public ByteArrayBuilder append(final String s) {
- if (s == null) {
- return this;
- }
- return append(CharBuffer.wrap(s));
- }
-
- public ByteBuffer toByteBuffer() {
- return this.buffer != null ? this.buffer.duplicate() : ByteBuffer.allocate(0);
- }
-
- public byte[] toByteArray() {
- if (this.buffer == null) {
- return new byte[] {};
- }
- this.buffer.flip();
- final byte[] b = new byte[this.buffer.remaining()];
- this.buffer.get(b);
- this.buffer.clear();
- return b;
- }
-
- public void reset() {
- if (this.charsetEncoder != null) {
- this.charsetEncoder.reset();
- }
- if (this.buffer != null) {
- this.buffer.clear();
- }
- }
-
- @Override
- public String toString() {
- return this.buffer != null ? this.buffer.toString() : "null";
- }
-
-}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/db4b6db7/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
index d700184..a198b8f 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
@@ -48,7 +48,7 @@ import org.apache.hc.client5.http.auth.AuthenticationException;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.MalformedChallengeException;
-import org.apache.hc.client5.http.auth.util.ByteArrayBuilder;
+import org.apache.hc.client5.http.auth.ByteArrayBuilder;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.NameValuePair;
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/db4b6db7/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java
index 2c754f1..ed87755 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java
@@ -51,7 +51,7 @@ import org.apache.hc.client5.http.auth.AuthenticationException;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.MalformedChallengeException;
-import org.apache.hc.client5.http.auth.util.ByteArrayBuilder;
+import org.apache.hc.client5.http.auth.ByteArrayBuilder;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpHost;
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/db4b6db7/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
index c8e5db0..e3a4dc3 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
@@ -41,7 +41,7 @@ import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
-import org.apache.hc.client5.http.auth.util.ByteArrayBuilder;
+import org.apache.hc.client5.http.auth.ByteArrayBuilder;
/**
* Provides an implementation for NTLMv1, NTLMv2, and NTLM2 Session forms of the NTLM
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/db4b6db7/httpclient5/src/test/java/org/apache/hc/client5/http/auth/util/TestByteArrayBuilder.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/auth/util/TestByteArrayBuilder.java b/httpclient5/src/test/java/org/apache/hc/client5/http/auth/util/TestByteArrayBuilder.java
index 3438ad9..a6a2f4e 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/auth/util/TestByteArrayBuilder.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/auth/util/TestByteArrayBuilder.java
@@ -29,6 +29,7 @@ package org.apache.hc.client5.http.auth.util;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import org.apache.hc.client5.http.auth.ByteArrayBuilder;
import org.junit.Assert;
import org.junit.Test;
[3/4] httpcomponents-client git commit: Improved flaky test case
Posted by ol...@apache.org.
Improved flaky test case
Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/71060c7e
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/71060c7e
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/71060c7e
Branch: refs/heads/master
Commit: 71060c7ee147e6de5540fd6b72f1eefcd868ff23
Parents: b45b72e
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Wed Jan 3 15:58:34 2018 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Wed Jan 3 19:37:19 2018 +0100
----------------------------------------------------------------------
.../testing/async/AbstractHttpAsyncFundamentalsTest.java | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/71060c7e/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java
index dc8839a..6f36fd8 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java
@@ -179,7 +179,9 @@ public abstract class AbstractHttpAsyncFundamentalsTest<T extends CloseableHttpA
@Override
public void run() {
- httpclient.execute(SimpleHttpRequest.get(target, "/random/2048"), callback);
+ if (!Thread.currentThread().isInterrupted()) {
+ httpclient.execute(SimpleHttpRequest.get(target, "/random/2048"), callback);
+ }
}
});
@@ -187,6 +189,9 @@ public abstract class AbstractHttpAsyncFundamentalsTest<T extends CloseableHttpA
Assert.assertThat(countDownLatch.await(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit()), CoreMatchers.equalTo(true));
+ executorService.shutdownNow();
+ executorService.awaitTermination(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
+
for (;;) {
final SimpleHttpResponse response = resultQueue.poll();
if (response == null) {
[2/4] httpcomponents-client git commit: Added HTTP routing support
class; simplified HttpRoutePlanner API
Posted by ol...@apache.org.
Added HTTP routing support class; simplified HttpRoutePlanner API
Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/b45b72ef
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/b45b72ef
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/b45b72ef
Branch: refs/heads/master
Commit: b45b72ef774dce7df3ec594bd92122fa6ba70b1c
Parents: db4b6db
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Wed Jan 3 15:36:27 2018 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Wed Jan 3 19:37:12 2018 +0100
----------------------------------------------------------------------
.../hc/client5/http/SchemePortResolver.java | 2 +-
.../http/impl/DefaultSchemePortResolver.java | 5 +-
.../impl/async/InternalHttp2AsyncClient.java | 5 +-
.../impl/async/InternalHttpAsyncClient.java | 5 +-
.../client5/http/impl/auth/BasicAuthCache.java | 27 +++-----
.../http/impl/classic/InternalHttpClient.java | 3 +-
.../http/impl/classic/MinimalHttpClient.java | 10 +--
.../DefaultAsyncClientConnectionOperator.java | 11 +---
.../http/impl/routing/DefaultRoutePlanner.java | 37 ++---------
.../client5/http/routing/HttpRoutePlanner.java | 14 ----
.../hc/client5/http/routing/RoutingSupport.java | 68 ++++++++++++++++++++
.../http/impl/auth/TestBasicAuthCache.java | 20 ------
.../impl/routing/TestDefaultRoutePlanner.java | 26 --------
.../http/impl/routing/TestRoutingSupport.java | 62 ++++++++++++++++++
14 files changed, 159 insertions(+), 136 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/SchemePortResolver.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/SchemePortResolver.java b/httpclient5/src/main/java/org/apache/hc/client5/http/SchemePortResolver.java
index 7c10e04..c3caa83 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/SchemePortResolver.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/SchemePortResolver.java
@@ -38,6 +38,6 @@ public interface SchemePortResolver {
/**
* Returns the actual port for the host based on the protocol scheme.
*/
- int resolve(HttpHost host) throws UnsupportedSchemeException;
+ int resolve(HttpHost host);
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultSchemePortResolver.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultSchemePortResolver.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultSchemePortResolver.java
index 4611b08..37555f7 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultSchemePortResolver.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultSchemePortResolver.java
@@ -27,7 +27,6 @@
package org.apache.hc.client5.http.impl;
import org.apache.hc.client5.http.SchemePortResolver;
-import org.apache.hc.client5.http.UnsupportedSchemeException;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.HttpHost;
@@ -44,7 +43,7 @@ public class DefaultSchemePortResolver implements SchemePortResolver {
public static final DefaultSchemePortResolver INSTANCE = new DefaultSchemePortResolver();
@Override
- public int resolve(final HttpHost host) throws UnsupportedSchemeException {
+ public int resolve(final HttpHost host) {
Args.notNull(host, "HTTP host");
final int port = host.getPort();
if (port > 0) {
@@ -56,7 +55,7 @@ public class DefaultSchemePortResolver implements SchemePortResolver {
} else if (name.equalsIgnoreCase("https")) {
return 443;
} else {
- throw new UnsupportedSchemeException(name + " protocol is not supported");
+ return -1;
}
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncClient.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncClient.java
index f68c69a..8be84b5 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttp2AsyncClient.java
@@ -39,8 +39,8 @@ import org.apache.hc.client5.http.cookie.CookieSpecProvider;
import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.config.Lookup;
import org.apache.hc.core5.http2.nio.pool.H2ConnPool;
@@ -77,8 +77,7 @@ class InternalHttp2AsyncClient extends InternalAbstractHttpAsyncClient {
@Override
HttpRoute determineRoute(final HttpRequest request, final HttpClientContext clientContext) throws HttpException {
- final HttpHost target = routePlanner.determineTargetHost(request, clientContext);
- final HttpRoute route = routePlanner.determineRoute(target, clientContext);
+ final HttpRoute route = routePlanner.determineRoute(RoutingSupport.determineHost(request), clientContext);
if (route.isTunnelled()) {
throw new HttpException("HTTP/2 tunneling not supported");
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java
index 8d23479..eed92f1 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalHttpAsyncClient.java
@@ -40,8 +40,8 @@ import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpVersion;
import org.apache.hc.core5.http.ProtocolVersion;
@@ -83,8 +83,7 @@ class InternalHttpAsyncClient extends InternalAbstractHttpAsyncClient {
@Override
HttpRoute determineRoute(final HttpRequest request, final HttpClientContext clientContext) throws HttpException {
- final HttpHost target = routePlanner.determineTargetHost(request, clientContext);
- final HttpRoute route = routePlanner.determineRoute(target, clientContext);
+ final HttpRoute route = routePlanner.determineRoute(RoutingSupport.determineHost(request), clientContext);
final ProtocolVersion protocolVersion = clientContext.getProtocolVersion();
if (route.isTunnelled() && protocolVersion.greaterEquals(HttpVersion.HTTP_2_0)) {
throw new HttpException("HTTP/2 tunneling not supported");
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicAuthCache.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicAuthCache.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicAuthCache.java
index dfd1aa4..d9b2980 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicAuthCache.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicAuthCache.java
@@ -36,10 +36,10 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.hc.client5.http.SchemePortResolver;
-import org.apache.hc.client5.http.UnsupportedSchemeException;
import org.apache.hc.client5.http.auth.AuthCache;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.HttpHost;
@@ -73,27 +73,13 @@ public class BasicAuthCache implements AuthCache {
public BasicAuthCache(final SchemePortResolver schemePortResolver) {
super();
this.map = new ConcurrentHashMap<>();
- this.schemePortResolver = schemePortResolver != null ? schemePortResolver :
- DefaultSchemePortResolver.INSTANCE;
+ this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
}
public BasicAuthCache() {
this(null);
}
- protected HttpHost getKey(final HttpHost host) {
- if (host.getPort() <= 0) {
- final int port;
- try {
- port = schemePortResolver.resolve(host);
- } catch (final UnsupportedSchemeException ignore) {
- return host;
- }
- return new HttpHost(host.getHostName(), port, host.getSchemeName());
- }
- return host;
- }
-
@Override
public void put(final HttpHost host, final AuthScheme authScheme) {
Args.notNull(host, "HTTP host");
@@ -106,7 +92,8 @@ public class BasicAuthCache implements AuthCache {
try (final ObjectOutputStream out = new ObjectOutputStream(buf)) {
out.writeObject(authScheme);
}
- this.map.put(getKey(host), buf.toByteArray());
+ final HttpHost key = RoutingSupport.normalize(host, schemePortResolver);
+ this.map.put(key, buf.toByteArray());
} catch (final IOException ex) {
if (log.isWarnEnabled()) {
log.warn("Unexpected I/O error while serializing auth scheme", ex);
@@ -122,7 +109,8 @@ public class BasicAuthCache implements AuthCache {
@Override
public AuthScheme get(final HttpHost host) {
Args.notNull(host, "HTTP host");
- final byte[] bytes = this.map.get(getKey(host));
+ final HttpHost key = RoutingSupport.normalize(host, schemePortResolver);
+ final byte[] bytes = this.map.get(key);
if (bytes != null) {
try {
final ByteArrayInputStream buf = new ByteArrayInputStream(bytes);
@@ -147,7 +135,8 @@ public class BasicAuthCache implements AuthCache {
@Override
public void remove(final HttpHost host) {
Args.notNull(host, "HTTP host");
- this.map.remove(getKey(host));
+ final HttpHost key = RoutingSupport.normalize(host, schemePortResolver);
+ this.map.remove(key);
}
@Override
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/InternalHttpClient.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/InternalHttpClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/InternalHttpClient.java
index 795938a..46d99e1 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/InternalHttpClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/InternalHttpClient.java
@@ -46,6 +46,7 @@ import org.apache.hc.client5.http.impl.ExecSupport;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.ClassicHttpRequest;
@@ -111,7 +112,7 @@ class InternalHttpClient extends CloseableHttpClient implements Configurable {
final HttpHost host,
final HttpRequest request,
final HttpContext context) throws HttpException {
- final HttpHost target = host != null ? host : this.routePlanner.determineTargetHost(request, context);
+ final HttpHost target = host != null ? host : RoutingSupport.determineHost(request);
return this.routePlanner.determineRoute(target, context);
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/MinimalHttpClient.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/MinimalHttpClient.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/MinimalHttpClient.java
index e335abd..4c39405 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/MinimalHttpClient.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/MinimalHttpClient.java
@@ -33,6 +33,7 @@ import java.io.InterruptedIOException;
import org.apache.hc.client5.http.CancellableAware;
import org.apache.hc.client5.http.ClientProtocolException;
import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.classic.ExecRuntime;
import org.apache.hc.client5.http.config.Configurable;
import org.apache.hc.client5.http.config.RequestConfig;
@@ -41,6 +42,7 @@ import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.protocol.RequestClientConnControl;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.ClassicHttpRequest;
@@ -77,6 +79,7 @@ public class MinimalHttpClient extends CloseableHttpClient {
private final HttpClientConnectionManager connManager;
private final ConnectionReuseStrategy reuseStrategy;
+ private final SchemePortResolver schemePortResolver;
private final HttpRequestExecutor requestExecutor;
private final HttpProcessor httpProcessor;
@@ -84,6 +87,7 @@ public class MinimalHttpClient extends CloseableHttpClient {
super();
this.connManager = Args.notNull(connManager, "HTTP connection manager");
this.reuseStrategy = DefaultConnectionReuseStrategy.INSTANCE;
+ this.schemePortResolver = DefaultSchemePortResolver.INSTANCE;
this.requestExecutor = new HttpRequestExecutor(this.reuseStrategy);
this.httpProcessor = new DefaultHttpProcessor(
new RequestContent(),
@@ -116,11 +120,7 @@ public class MinimalHttpClient extends CloseableHttpClient {
clientContext.setRequestConfig(config);
}
- final HttpRoute route = new HttpRoute(target.getPort() > 0 ? target : new HttpHost(
- target.getHostName(),
- DefaultSchemePortResolver.INSTANCE.resolve(target),
- target.getSchemeName()));
-
+ final HttpRoute route = new HttpRoute(RoutingSupport.normalize(target, schemePortResolver));
final ExecRuntime execRuntime = new ExecRuntimeImpl(log, connManager, requestExecutor,
request instanceof CancellableAware ? (CancellableAware) request : null);
try {
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
index 75b285a..33503da 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/DefaultAsyncClientConnectionOperator.java
@@ -34,10 +34,10 @@ import java.util.concurrent.Future;
import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.SchemePortResolver;
-import org.apache.hc.client5.http.UnsupportedSchemeException;
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator;
import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.annotation.Internal;
import org.apache.hc.core5.concurrent.ComplexFuture;
import org.apache.hc.core5.concurrent.FutureCallback;
@@ -81,14 +81,7 @@ final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectio
Args.notNull(connectionInitiator, "Connection initiator");
Args.notNull(host, "Host");
final ComplexFuture<ManagedAsyncClientConnection> future = new ComplexFuture<>(callback);
- final HttpHost remoteEndpoint;
- try {
- remoteEndpoint = host.getPort() > 0 ? host :
- new HttpHost(host.getHostName(), schemePortResolver.resolve(host), host.getSchemeName());
- } catch (final UnsupportedSchemeException ex) {
- future.failed(ex);
- return future;
- }
+ final HttpHost remoteEndpoint = RoutingSupport.normalize(host, schemePortResolver);
final InetAddress remoteAddress = host.getAddress();
final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
final Future<IOSession> sessionFuture = sessionRequester.connect(
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java
index 02cc5ab..513d8a1 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/routing/DefaultRoutePlanner.java
@@ -31,19 +31,17 @@ import java.net.InetAddress;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver;
-import org.apache.hc.client5.http.UnsupportedSchemeException;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.ProtocolException;
import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.net.URIAuthority;
/**
* Default implementation of an {@link HttpRoutePlanner}. It will not make use of
@@ -58,8 +56,7 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
public DefaultRoutePlanner(final SchemePortResolver schemePortResolver) {
super();
- this.schemePortResolver = schemePortResolver != null ? schemePortResolver :
- DefaultSchemePortResolver.INSTANCE;
+ this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
}
@Override
@@ -73,19 +70,9 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
if (proxy == null) {
proxy = determineProxy(host, context);
}
-
- final HttpHost target;
- if (host.getPort() <= 0) {
- try {
- target = new HttpHost(
- host.getHostName(),
- this.schemePortResolver.resolve(host),
- host.getSchemeName());
- } catch (final UnsupportedSchemeException ex) {
- throw new HttpException(ex.getMessage());
- }
- } else {
- target = host;
+ final HttpHost target = RoutingSupport.normalize(host, schemePortResolver);
+ if (target.getPort() < 0) {
+ throw new ProtocolException("Unroutable protocol scheme: " + target);
}
final boolean secure = target.getSchemeName().equalsIgnoreCase("https");
if (proxy == null) {
@@ -95,20 +82,6 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
}
}
- @Override
- public final HttpHost determineTargetHost(final HttpRequest request, final HttpContext context) throws HttpException {
- final URIAuthority authority = request.getAuthority();
- if (authority != null) {
- final String scheme = request.getScheme();
- if (scheme == null) {
- throw new ProtocolException("Protocol scheme is not specified");
- }
- return new HttpHost(authority, scheme);
- } else {
- return null;
- }
- }
-
/**
* This implementation returns null.
*
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/routing/HttpRoutePlanner.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/routing/HttpRoutePlanner.java b/httpclient5/src/main/java/org/apache/hc/client5/http/routing/HttpRoutePlanner.java
index 8dade56..03b6599 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/routing/HttpRoutePlanner.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/routing/HttpRoutePlanner.java
@@ -30,7 +30,6 @@ package org.apache.hc.client5.http.routing;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.protocol.HttpContext;
/**
@@ -60,17 +59,4 @@ public interface HttpRoutePlanner {
*/
HttpRoute determineRoute(HttpHost target, HttpContext context) throws HttpException;
- /**
- * Determines the target host for the given request.
- *
- * @param request the request to be executed
- * @param context the context to use for the subsequent execution.
- * Implementations may accept {@code null}.
- *
- * @return the route that the request should take
- *
- * @throws HttpException in case of a problem
- */
- HttpHost determineTargetHost(HttpRequest request, HttpContext context) throws HttpException;
-
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/main/java/org/apache/hc/client5/http/routing/RoutingSupport.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/routing/RoutingSupport.java b/httpclient5/src/main/java/org/apache/hc/client5/http/routing/RoutingSupport.java
new file mode 100644
index 0000000..946ac14
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/routing/RoutingSupport.java
@@ -0,0 +1,68 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.client5.http.routing;
+
+import org.apache.hc.client5.http.SchemePortResolver;
+import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.net.URIAuthority;
+
+public final class RoutingSupport {
+
+ public static HttpHost determineHost(final HttpRequest request) throws HttpException {
+ if (request == null) {
+ return null;
+ }
+ final URIAuthority authority = request.getAuthority();
+ if (authority != null) {
+ final String scheme = request.getScheme();
+ if (scheme == null) {
+ throw new ProtocolException("Protocol scheme is not specified");
+ }
+ return new HttpHost(authority, scheme);
+ } else {
+ return null;
+ }
+ }
+
+ public static HttpHost normalize(final HttpHost host, final SchemePortResolver schemePortResolver) {
+ if (host == null) {
+ return null;
+ }
+ if (host.getPort() < 0) {
+ final int port = (schemePortResolver != null ? schemePortResolver: DefaultSchemePortResolver.INSTANCE).resolve(host);
+ if (port > 0) {
+ return new HttpHost(host.getHostName(), port, host.getSchemeName());
+ }
+ }
+ return host;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicAuthCache.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicAuthCache.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicAuthCache.java
index 7a37dfb..6279805 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicAuthCache.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicAuthCache.java
@@ -27,12 +27,10 @@
package org.apache.hc.client5.http.impl.auth;
-import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.core5.http.HttpHost;
import org.junit.Assert;
import org.junit.Test;
-import org.mockito.Mockito;
/**
* Unit tests for {@link BasicAuthCache}.
@@ -68,24 +66,6 @@ public class TestBasicAuthCache {
}
@Test
- public void testGetKey() throws Exception {
- final BasicAuthCache cache = new BasicAuthCache();
- final HttpHost target = new HttpHost("localhost", 443, "https");
- Assert.assertSame(target, cache.getKey(target));
- Assert.assertEquals(target, cache.getKey(new HttpHost("localhost", -1, "https")));
- }
-
- @Test
- public void testGetKeyWithSchemeRegistry() throws Exception {
- final SchemePortResolver schemePortResolver = Mockito.mock(SchemePortResolver.class);
- final BasicAuthCache cache = new BasicAuthCache(schemePortResolver);
- Mockito.when(schemePortResolver.resolve(new HttpHost("localhost", -1, "https"))).thenReturn(443);
- final HttpHost target = new HttpHost("localhost", 443, "https");
- Assert.assertSame(target, cache.getKey(target));
- Assert.assertEquals(target, cache.getKey(new HttpHost("localhost", -1, "https")));
- }
-
- @Test
public void testStoreNonserializable() throws Exception {
final BasicAuthCache cache = new BasicAuthCache();
final AuthScheme authScheme = new NTLMScheme();
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestDefaultRoutePlanner.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestDefaultRoutePlanner.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestDefaultRoutePlanner.java
index 0ca9166..6ec2e1f 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestDefaultRoutePlanner.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestDefaultRoutePlanner.java
@@ -27,20 +27,14 @@
package org.apache.hc.client5.http.impl.routing;
-import java.net.URI;
-
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.ProtocolException;
-import org.apache.hc.core5.http.message.BasicHttpRequest;
import org.apache.hc.core5.http.protocol.BasicHttpContext;
import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.net.URIAuthority;
-import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -109,24 +103,4 @@ public class TestDefaultRoutePlanner {
routePlanner.determineRoute(null, context);
}
- @Test
- public void testDetermineHost() throws Exception {
- final HttpContext context = new BasicHttpContext();
- final HttpRequest request1 = new BasicHttpRequest("GET", "/");
- final HttpHost host1 = routePlanner.determineTargetHost(request1, context);
- Assert.assertThat(host1, CoreMatchers.nullValue());
-
- final HttpRequest request2 = new BasicHttpRequest("GET", new URI("https://somehost:8443/"));
- final HttpHost host2 = routePlanner.determineTargetHost(request2, context);
- Assert.assertThat(host2, CoreMatchers.equalTo(new HttpHost("somehost", 8443, "https")));
- }
-
- @Test(expected = ProtocolException.class)
- public void testDetermineHostMissingScheme() throws Exception {
- final HttpContext context = new BasicHttpContext();
- final HttpRequest request1 = new BasicHttpRequest("GET", "/");
- request1.setAuthority(new URIAuthority("host"));
- routePlanner.determineTargetHost(request1, context);
- }
-
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/b45b72ef/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestRoutingSupport.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestRoutingSupport.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestRoutingSupport.java
new file mode 100644
index 0000000..57b4f51
--- /dev/null
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/routing/TestRoutingSupport.java
@@ -0,0 +1,62 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.client5.http.impl.routing;
+
+import java.net.URI;
+
+import org.apache.hc.client5.http.routing.RoutingSupport;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.message.BasicHttpRequest;
+import org.apache.hc.core5.net.URIAuthority;
+import org.hamcrest.CoreMatchers;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestRoutingSupport {
+
+ @Test
+ public void testDetermineHost() throws Exception {
+ final HttpRequest request1 = new BasicHttpRequest("GET", "/");
+ final HttpHost host1 = RoutingSupport.determineHost(request1);
+ Assert.assertThat(host1, CoreMatchers.nullValue());
+
+ final HttpRequest request2 = new BasicHttpRequest("GET", new URI("https://somehost:8443/"));
+ final HttpHost host2 = RoutingSupport.determineHost(request2);
+ Assert.assertThat(host2, CoreMatchers.equalTo(new HttpHost("somehost", 8443, "https")));
+ }
+
+ @Test(expected = ProtocolException.class)
+ public void testDetermineHostMissingScheme() throws Exception {
+ final HttpRequest request1 = new BasicHttpRequest("GET", "/");
+ request1.setAuthority(new URIAuthority("host"));
+ RoutingSupport.determineHost(request1);
+ }
+
+}
[4/4] httpcomponents-client git commit: HTTPCLIENT-1893: Moved
HttpContext state logic out of DefaultRedirectStrategy to the redirect
execution interceptors; redesigned RedirectLocations class;
refactored classic redirect execution interceptor unit tests
Posted by ol...@apache.org.
HTTPCLIENT-1893: Moved HttpContext state logic out of DefaultRedirectStrategy to the redirect execution interceptors; redesigned RedirectLocations class; refactored classic redirect execution interceptor unit tests
Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/47a0eb8b
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/47a0eb8b
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/47a0eb8b
Branch: refs/heads/master
Commit: 47a0eb8b65c2a98b50567bf6e0b4229a08035098
Parents: 71060c7
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Wed Jan 3 19:36:04 2018 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Wed Jan 3 19:37:19 2018 +0100
----------------------------------------------------------------------
.../sync/TestClientRequestExecution.java | 6 +-
.../hc/client5/testing/sync/TestRedirects.java | 9 +-
.../http/impl/DefaultRedirectStrategy.java | 46 +---
.../http/impl/async/AsyncRedirectExec.java | 63 ++++--
.../client5/http/impl/classic/RedirectExec.java | 64 ++++--
.../http/protocol/HttpClientContext.java | 9 +-
.../http/protocol/RedirectLocations.java | 121 +---------
.../http/impl/TestDefaultRedirectStrategy.java | 49 ----
.../http/impl/classic/TestRedirectExec.java | 226 +++++++++++--------
.../http/protocol/TestRedirectLocation.java | 12 +-
10 files changed, 227 insertions(+), 378 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java
index f89d4a1..d0dd55d 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java
@@ -29,12 +29,12 @@ package org.apache.hc.client5.testing.sync;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
-import java.util.List;
import org.apache.hc.client5.http.HttpRequestRetryHandler;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.protocol.RedirectLocations;
import org.apache.hc.client5.http.utils.URIUtils;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
@@ -252,8 +252,8 @@ public class TestClientRequestExecution extends LocalServerTestBase {
final HttpRequest request = context.getRequest();
Assert.assertEquals("/stuff", request.getRequestUri());
- final List<URI> redirectLocations = context.getRedirectLocations();
- final URI location = URIUtils.resolve(uri, target, redirectLocations);
+ final RedirectLocations redirectLocations = context.getRedirectLocations();
+ final URI location = URIUtils.resolve(uri, target, redirectLocations.getAll());
Assert.assertEquals(uri, location);
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java
----------------------------------------------------------------------
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java
index ab8ec57..aedefd6 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java
@@ -30,7 +30,6 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
-import java.util.List;
import org.apache.hc.client5.http.CircularRedirectException;
import org.apache.hc.client5.http.ClientProtocolException;
@@ -42,6 +41,7 @@ import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.protocol.RedirectLocations;
import org.apache.hc.client5.http.utils.URIUtils;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
@@ -282,8 +282,9 @@ public class TestRedirects extends LocalServerTestBase {
Assert.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getCode());
Assert.assertEquals(URIUtils.create(target, "/oldlocation/"), reqWrapper.getUri());
- final List<URI> redirects = context.getRedirectLocations();
- Assert.assertNull(redirects);
+ final RedirectLocations redirects = context.getRedirectLocations();
+ Assert.assertNotNull(redirects);
+ Assert.assertEquals(0, redirects.size());
}
@Test
@@ -304,7 +305,7 @@ public class TestRedirects extends LocalServerTestBase {
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri());
- final List<URI> redirects = context.getRedirectLocations();
+ final RedirectLocations redirects = context.getRedirectLocations();
Assert.assertNotNull(redirects);
Assert.assertEquals(1, redirects.size());
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultRedirectStrategy.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultRedirectStrategy.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultRedirectStrategy.java
index 75c3cda..54c9048 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultRedirectStrategy.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultRedirectStrategy.java
@@ -30,13 +30,7 @@ package org.apache.hc.client5.http.impl;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import org.apache.hc.client5.http.CircularRedirectException;
-import org.apache.hc.client5.http.config.RequestConfig;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.client5.http.protocol.RedirectLocations;
import org.apache.hc.client5.http.protocol.RedirectStrategy;
import org.apache.hc.client5.http.utils.URIUtils;
import org.apache.hc.core5.annotation.Contract;
@@ -52,8 +46,6 @@ import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.net.URIBuilder;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.TextUtils;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
/**
* Default implementation of {@link RedirectStrategy}. This strategy honors the restrictions
@@ -64,27 +56,11 @@ import org.apache.logging.log4j.Logger;
*
* @since 4.1
*/
-@Contract(threading = ThreadingBehavior.IMMUTABLE)
+@Contract(threading = ThreadingBehavior.STATELESS)
public class DefaultRedirectStrategy implements RedirectStrategy {
- private final Logger log = LogManager.getLogger(getClass());
-
public static final DefaultRedirectStrategy INSTANCE = new DefaultRedirectStrategy();
- private final ConcurrentMap<String, Boolean> safeMethods;
-
- public DefaultRedirectStrategy(final String... safeMethods) {
- super();
- this.safeMethods = new ConcurrentHashMap<>();
- for (final String safeMethod: safeMethods) {
- this.safeMethods.put(safeMethod.toUpperCase(Locale.ROOT), Boolean.TRUE);
- }
- }
-
- public DefaultRedirectStrategy() {
- this("GET", "HEAD", "OPTIONS", "TRACE");
- }
-
@Override
public boolean isRedirected(
final HttpRequest request,
@@ -117,20 +93,12 @@ public class DefaultRedirectStrategy implements RedirectStrategy {
Args.notNull(response, "HTTP response");
Args.notNull(context, "HTTP context");
- final HttpClientContext clientContext = HttpClientContext.adapt(context);
-
//get the location header to find out where to redirect to
final Header locationHeader = response.getFirstHeader("location");
if (locationHeader == null) {
throw new HttpException("Redirect location is missing");
}
final String location = locationHeader.getValue();
- if (this.log.isDebugEnabled()) {
- this.log.debug("Redirect requested to location '" + location + "'");
- }
-
- final RequestConfig config = clientContext.getRequestConfig();
-
URI uri = createLocationURI(location);
try {
if (!uri.isAbsolute()) {
@@ -141,18 +109,6 @@ public class DefaultRedirectStrategy implements RedirectStrategy {
throw new ProtocolException(ex.getMessage(), ex);
}
- RedirectLocations redirectLocations = (RedirectLocations) clientContext.getAttribute(
- HttpClientContext.REDIRECT_LOCATIONS);
- if (redirectLocations == null) {
- redirectLocations = new RedirectLocations();
- context.setAttribute(HttpClientContext.REDIRECT_LOCATIONS, redirectLocations);
- }
- if (!config.isCircularRedirectsAllowed()) {
- if (redirectLocations.contains(uri)) {
- throw new CircularRedirectException("Circular redirect to '" + uri + "'");
- }
- }
- redirectLocations.add(uri);
return uri;
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
index 4f34bf6..cdd86b5 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncRedirectExec.java
@@ -28,8 +28,8 @@ package org.apache.hc.client5.http.impl.async;
import java.io.IOException;
import java.net.URI;
-import java.util.List;
+import org.apache.hc.client5.http.CircularRedirectException;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.RedirectException;
import org.apache.hc.client5.http.StandardMethods;
@@ -40,6 +40,7 @@ import org.apache.hc.client5.http.auth.AuthExchange;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.protocol.RedirectLocations;
import org.apache.hc.client5.http.protocol.RedirectStrategy;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.client5.http.utils.URIUtils;
@@ -53,6 +54,7 @@ import org.apache.hc.core5.http.ProtocolException;
import org.apache.hc.core5.http.message.BasicHttpRequest;
import org.apache.hc.core5.http.nio.AsyncDataConsumer;
import org.apache.hc.core5.http.nio.AsyncEntityProducer;
+import org.apache.hc.core5.util.LangUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -75,6 +77,7 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
volatile int redirectCount;
volatile HttpRequest currentRequest;
volatile AsyncEntityProducer currentEntityProducer;
+ volatile RedirectLocations redirectLocations;
volatile AsyncExecChain.Scope currentScope;
volatile boolean reroute;
@@ -107,6 +110,16 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
state.redirectCount++;
final URI redirectUri = redirectStrategy.getLocationURI(request, response, clientContext);
+ if (log.isDebugEnabled()) {
+ log.debug("Redirect requested to location '" + redirectUri + "'");
+ }
+ if (!config.isCircularRedirectsAllowed()) {
+ if (state.redirectLocations.contains(redirectUri)) {
+ throw new CircularRedirectException("Circular redirect to '" + redirectUri + "'");
+ }
+ }
+ state.redirectLocations.add(redirectUri);
+
final int statusCode = response.getCode();
switch (statusCode) {
@@ -128,27 +141,27 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
throw new ProtocolException("Redirect URI does not specify a valid host name: " + redirectUri);
}
- if (!currentRoute.getTargetHost().equals(newTarget)) {
- log.debug("New route required");
- state.reroute = true;
- final AuthExchange targetAuthExchange = clientContext.getAuthExchange(currentRoute.getTargetHost());
- log.debug("Resetting target auth state");
- targetAuthExchange.reset();
- if (currentRoute.getProxyHost() != null) {
- final AuthExchange proxyAuthExchange = clientContext.getAuthExchange(currentRoute.getProxyHost());
- final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
- if (authScheme != null && authScheme.isConnectionBased()) {
- log.debug("Resetting proxy auth state");
- proxyAuthExchange.reset();
+ state.reroute = false;
+ state.redirectURI = redirectUri;
+
+ if (!LangUtils.equals(currentRoute.getTargetHost(), newTarget)) {
+ final HttpRoute newRoute = routePlanner.determineRoute(newTarget, clientContext);
+ if (!LangUtils.equals(currentRoute, newRoute)) {
+ state.reroute = true;
+ final AuthExchange targetAuthExchange = clientContext.getAuthExchange(currentRoute.getTargetHost());
+ log.debug("Resetting target auth state");
+ targetAuthExchange.reset();
+ if (currentRoute.getProxyHost() != null) {
+ final AuthExchange proxyAuthExchange = clientContext.getAuthExchange(currentRoute.getProxyHost());
+ final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
+ if (authScheme != null && authScheme.isConnectionBased()) {
+ log.debug("Resetting proxy auth state");
+ proxyAuthExchange.reset();
+ }
}
+ state.currentScope = new AsyncExecChain.Scope(scope.exchangeId, newRoute,
+ scope.originalRequest, scope.future, clientContext, scope.execRuntime);
}
- final HttpRoute newRoute = routePlanner.determineRoute(newTarget, clientContext);
- state.currentScope = new AsyncExecChain.Scope(scope.exchangeId, newRoute,
- scope.originalRequest, scope.future, clientContext, scope.execRuntime);
- state.redirectURI = redirectUri;
- } else {
- state.reroute = false;
- state.redirectURI = redirectUri;
}
}
if (state.redirectURI != null) {
@@ -200,10 +213,13 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
final AsyncExecChain chain,
final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
final HttpClientContext clientContext = scope.clientContext;
- final List<URI> redirectLocations = clientContext.getRedirectLocations();
- if (redirectLocations != null) {
- redirectLocations.clear();
+ RedirectLocations redirectLocations = clientContext.getRedirectLocations();
+ if (redirectLocations == null) {
+ redirectLocations = new RedirectLocations();
+ clientContext.setAttribute(HttpClientContext.REDIRECT_LOCATIONS, redirectLocations);
}
+ redirectLocations.clear();
+
final RequestConfig config = clientContext.getRequestConfig();
final State state = new State();
@@ -211,6 +227,7 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
state.redirectCount = 0;
state.currentRequest = request;
state.currentEntityProducer = entityProducer;
+ state.redirectLocations = redirectLocations;
state.currentScope = scope;
internalExecute(state, chain, asyncExecCallback);
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/RedirectExec.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/RedirectExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/RedirectExec.java
index 99b02cb..80e5cbf 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/RedirectExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/RedirectExec.java
@@ -29,8 +29,8 @@ package org.apache.hc.client5.http.impl.classic;
import java.io.IOException;
import java.net.URI;
-import java.util.List;
+import org.apache.hc.client5.http.CircularRedirectException;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.RedirectException;
import org.apache.hc.client5.http.StandardMethods;
@@ -42,6 +42,7 @@ import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.RequestBuilder;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.protocol.RedirectLocations;
import org.apache.hc.client5.http.protocol.RedirectStrategy;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.client5.http.utils.URIUtils;
@@ -56,6 +57,7 @@ import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.ProtocolException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.LangUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -97,11 +99,12 @@ final class RedirectExec implements ExecChainHandler {
Args.notNull(scope, "Scope");
final HttpClientContext context = scope.clientContext;
-
- final List<URI> redirectLocations = context.getRedirectLocations();
- if (redirectLocations != null) {
- redirectLocations.clear();
+ RedirectLocations redirectLocations = context.getRedirectLocations();
+ if (redirectLocations == null) {
+ redirectLocations = new RedirectLocations();
+ context.setAttribute(HttpClientContext.REDIRECT_LOCATIONS, redirectLocations);
}
+ redirectLocations.clear();
final RequestConfig config = context.getRequestConfig();
final int maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
@@ -122,6 +125,16 @@ final class RedirectExec implements ExecChainHandler {
redirectCount++;
final URI redirectUri = this.redirectStrategy.getLocationURI(currentRequest, response, context);
+ if (this.log.isDebugEnabled()) {
+ this.log.debug("Redirect requested to location '" + redirectUri + "'");
+ }
+ if (!config.isCircularRedirectsAllowed()) {
+ if (redirectLocations.contains(redirectUri)) {
+ throw new CircularRedirectException("Circular redirect to '" + redirectUri + "'");
+ }
+ }
+ redirectLocations.add(redirectUri);
+
final ClassicHttpRequest originalRequest = scope.originalRequest;
ClassicHttpRequest redirect = null;
final int statusCode = response.getCode();
@@ -147,28 +160,29 @@ final class RedirectExec implements ExecChainHandler {
redirectUri);
}
- HttpRoute currentRoute = currentScope.route;
- final boolean crossSiteRedirect = !currentRoute.getTargetHost().equals(newTarget);
- if (crossSiteRedirect) {
-
- final AuthExchange targetAuthExchange = context.getAuthExchange(currentRoute.getTargetHost());
- this.log.debug("Resetting target auth state");
- targetAuthExchange.reset();
- if (currentRoute.getProxyHost() != null) {
- final AuthExchange proxyAuthExchange = context.getAuthExchange(currentRoute.getProxyHost());
- final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
- if (authScheme != null && authScheme.isConnectionBased()) {
- this.log.debug("Resetting proxy auth state");
- proxyAuthExchange.reset();
+ final HttpRoute currentRoute = currentScope.route;
+ if (!LangUtils.equals(currentRoute.getTargetHost(), newTarget)) {
+ final HttpRoute newRoute = this.routePlanner.determineRoute(newTarget, context);
+ if (!LangUtils.equals(currentRoute, newRoute)) {
+ log.debug("New route required");
+ final AuthExchange targetAuthExchange = context.getAuthExchange(currentRoute.getTargetHost());
+ this.log.debug("Resetting target auth state");
+ targetAuthExchange.reset();
+ if (currentRoute.getProxyHost() != null) {
+ final AuthExchange proxyAuthExchange = context.getAuthExchange(currentRoute.getProxyHost());
+ final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
+ if (authScheme != null && authScheme.isConnectionBased()) {
+ this.log.debug("Resetting proxy auth state");
+ proxyAuthExchange.reset();
+ }
}
+ currentScope = new ExecChain.Scope(
+ currentScope.exchangeId,
+ newRoute,
+ currentScope.originalRequest,
+ currentScope.execRuntime,
+ currentScope.clientContext);
}
- currentRoute = this.routePlanner.determineRoute(newTarget, context);
- currentScope = new ExecChain.Scope(
- currentScope.exchangeId,
- currentRoute,
- currentScope.originalRequest,
- currentScope.execRuntime,
- currentScope.clientContext);
}
if (this.log.isDebugEnabled()) {
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java
index e717a90..7be4c16 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java
@@ -27,9 +27,7 @@
package org.apache.hc.client5.http.protocol;
-import java.net.URI;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import org.apache.hc.client5.http.HttpRoute;
@@ -67,7 +65,7 @@ public class HttpClientContext extends HttpCoreContext {
public static final String HTTP_ROUTE = "http.route";
/**
- * Attribute name of a {@link List} object that represents a collection of all
+ * Attribute name of a {@link RedirectLocations} object that represents a collection of all
* redirect locations received in the process of request execution.
*/
public static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
@@ -156,9 +154,8 @@ public class HttpClientContext extends HttpCoreContext {
return getAttribute(HTTP_ROUTE, HttpRoute.class);
}
- @SuppressWarnings("unchecked")
- public List<URI> getRedirectLocations() {
- return getAttribute(REDIRECT_LOCATIONS, List.class);
+ public RedirectLocations getRedirectLocations() {
+ return getAttribute(REDIRECT_LOCATIONS, RedirectLocations.class);
}
public CookieStore getCookieStore() {
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RedirectLocations.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RedirectLocations.java b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RedirectLocations.java
index effcbee..22fb6ff 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RedirectLocations.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RedirectLocations.java
@@ -28,10 +28,8 @@
package org.apache.hc.client5.http.protocol;
import java.net.URI;
-import java.util.AbstractList;
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -41,7 +39,7 @@ import java.util.Set;
*
* @since 4.0
*/
-public class RedirectLocations extends AbstractList<Object> {
+public final class RedirectLocations {
private final Set<URI> unique;
private final List<URI> all;
@@ -68,23 +66,6 @@ public class RedirectLocations extends AbstractList<Object> {
}
/**
- * Removes a URI from the collection.
- */
- public boolean remove(final URI uri) {
- final boolean removed = this.unique.remove(uri);
- if (removed) {
- final Iterator<URI> it = this.all.iterator();
- while (it.hasNext()) {
- final URI current = it.next();
- if (current.equals(uri)) {
- it.remove();
- }
- }
- }
- return removed;
- }
-
- /**
* Returns all redirect {@link URI}s in the order they were added to the collection.
*
* @return list of all URIs
@@ -106,7 +87,6 @@ public class RedirectLocations extends AbstractList<Object> {
* {@code index < 0 || index >= size()})
* @since 4.3
*/
- @Override
public URI get(final int index) {
return this.all.get(index);
}
@@ -119,106 +99,13 @@ public class RedirectLocations extends AbstractList<Object> {
* @return the number of elements in this list
* @since 4.3
*/
- @Override
public int size() {
return this.all.size();
}
- /**
- * Replaces the URI at the specified position in this list with the
- * specified element (must be a URI).
- *
- * @param index
- * index of the element to replace
- * @param element
- * URI to be stored at the specified position
- * @return the URI previously at the specified position
- * @throws UnsupportedOperationException
- * if the {@code set} operation is not supported by this list
- * @throws ClassCastException
- * if the element is not a {@link URI}
- * @throws NullPointerException
- * if the specified element is null and this list does not
- * permit null elements
- * @throws IndexOutOfBoundsException
- * if the index is out of range (
- * {@code index < 0 || index >= size()})
- * @since 4.3
- */
- @Override
- public Object set(final int index, final Object element) {
- final URI removed = this.all.set(index, (URI) element);
- this.unique.remove(removed);
- this.unique.add((URI) element);
- if (this.all.size() != this.unique.size()) {
- this.unique.addAll(this.all);
- }
- return removed;
- }
-
- /**
- * Inserts the specified element at the specified position in this list
- * (must be a URI). Shifts the URI currently at that position (if any) and
- * any subsequent URIs to the right (adds one to their indices).
- *
- * @param index
- * index at which the specified element is to be inserted
- * @param element
- * URI to be inserted
- * @throws UnsupportedOperationException
- * if the {@code add} operation is not supported by this list
- * @throws ClassCastException
- * if the element is not a {@link URI}
- * @throws NullPointerException
- * if the specified element is null and this list does not
- * permit null elements
- * @throws IndexOutOfBoundsException
- * if the index is out of range (
- * {@code index < 0 || index > size()})
- * @since 4.3
- */
- @Override
- public void add(final int index, final Object element) {
- this.all.add(index, (URI) element);
- this.unique.add((URI) element);
- }
-
- /**
- * Removes the URI at the specified position in this list. Shifts any
- * subsequent URIs to the left (subtracts one from their indices). Returns
- * the URI that was removed from the list.
- *
- * @param index
- * the index of the URI to be removed
- * @return the URI previously at the specified position
- * @throws IndexOutOfBoundsException
- * if the index is out of range (
- * {@code index < 0 || index >= size()})
- * @since 4.3
- */
- @Override
- public URI remove(final int index) {
- final URI removed = this.all.remove(index);
- this.unique.remove(removed);
- if (this.all.size() != this.unique.size()) {
- this.unique.addAll(this.all);
- }
- return removed;
- }
-
- /**
- * Returns {@code true} if this collection contains the specified element.
- * More formally, returns {@code true} if and only if this collection
- * contains at least one element {@code e} such that
- * {@code (o==null ? e==null : o.equals(e))}.
- *
- * @param o element whose presence in this collection is to be tested
- * @return {@code true} if this collection contains the specified
- * element
- */
- @Override
- public boolean contains(final Object o) {
- return this.unique.contains(o);
+ public void clear() {
+ unique.clear();
+ all.clear();
}
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultRedirectStrategy.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultRedirectStrategy.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultRedirectStrategy.java
index 1fc2eb2..6ca7e60 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultRedirectStrategy.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultRedirectStrategy.java
@@ -27,11 +27,9 @@
package org.apache.hc.client5.http.impl;
import java.net.URI;
-import java.util.List;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
-import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHeaders;
@@ -201,53 +199,6 @@ public class TestDefaultRedirectStrategy {
}
@Test
- public void testGetLocationUriAllowCircularRedirects() throws Exception {
- final DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
- final HttpClientContext context = HttpClientContext.create();
- final RequestConfig config = RequestConfig.custom().setCircularRedirectsAllowed(true).build();
- context.setRequestConfig(config);
- final URI uri1 = URI.create("http://localhost/stuff1");
- final URI uri2 = URI.create("http://localhost/stuff2");
- final URI uri3 = URI.create("http://localhost/stuff3");
- final HttpGet httpget1 = new HttpGet("http://localhost/");
- final HttpResponse response1 = new BasicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY, "Redirect");
- response1.addHeader("Location", uri1.toASCIIString());
- final HttpGet httpget2 = new HttpGet(uri1.toASCIIString());
- final HttpResponse response2 = new BasicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY, "Redirect");
- response2.addHeader("Location", uri2.toASCIIString());
- final HttpGet httpget3 = new HttpGet(uri2.toASCIIString());
- final HttpResponse response3 = new BasicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY, "Redirect");
- response3.addHeader("Location", uri3.toASCIIString());
- Assert.assertEquals(uri1, redirectStrategy.getLocationURI(httpget1, response1, context));
- Assert.assertEquals(uri2, redirectStrategy.getLocationURI(httpget2, response2, context));
- Assert.assertEquals(uri3, redirectStrategy.getLocationURI(httpget3, response3, context));
-
- final List<URI> uris = context.getRedirectLocations();
- Assert.assertNotNull(uris);
- Assert.assertTrue(uris.contains(uri1));
- Assert.assertTrue(uris.contains(uri2));
- Assert.assertTrue(uris.contains(uri3));
- Assert.assertEquals(3, uris.size());
- Assert.assertEquals(uri1, uris.get(0));
- Assert.assertEquals(uri2, uris.get(1));
- Assert.assertEquals(uri3, uris.get(2));
- }
-
- @Test(expected=ProtocolException.class)
- public void testGetLocationUriDisallowCircularRedirects() throws Exception {
- final DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
- final HttpClientContext context = HttpClientContext.create();
- final HttpGet httpget = new HttpGet("http://localhost/stuff");
- final RequestConfig config = RequestConfig.custom().setCircularRedirectsAllowed(false).build();
- context.setRequestConfig(config);
- final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY, "Redirect");
- response.addHeader("Location", "http://localhost/stuff");
- final URI uri = URI.create("http://localhost/stuff");
- Assert.assertEquals(uri, redirectStrategy.getLocationURI(httpget, response, context));
- redirectStrategy.getLocationURI(httpget, response, context);
- }
-
- @Test
public void testGetLocationUriInvalidInput() throws Exception {
final DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
final HttpClientContext context = HttpClientContext.create();
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestRedirectExec.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestRedirectExec.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestRedirectExec.java
index 7fdb4cc..80cca6a 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestRedirectExec.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestRedirectExec.java
@@ -30,8 +30,10 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Arrays;
import java.util.List;
+import org.apache.hc.client5.http.CircularRedirectException;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.RedirectException;
import org.apache.hc.client5.http.auth.AuthExchange;
@@ -40,48 +42,52 @@ import org.apache.hc.client5.http.classic.ExecRuntime;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.entity.EntityBuilder;
+import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
import org.apache.hc.client5.http.impl.auth.BasicScheme;
import org.apache.hc.client5.http.impl.auth.NTLMScheme;
import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.protocol.RedirectLocations;
import org.apache.hc.client5.http.protocol.RedirectStrategy;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.ProtocolException;
+import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
-@SuppressWarnings({"boxing","static-access"}) // test code
+@RunWith(MockitoJUnitRunner.class)
public class TestRedirectExec {
@Mock
private HttpRoutePlanner httpRoutePlanner;
@Mock
- private RedirectStrategy redirectStrategy;
- @Mock
private ExecChain chain;
@Mock
private ExecRuntime endpoint;
+ private RedirectStrategy redirectStrategy;
private RedirectExec redirectExec;
private HttpHost target;
@Before
public void setup() throws Exception {
- MockitoAnnotations.initMocks(this);
- redirectExec = new RedirectExec(httpRoutePlanner, redirectStrategy);
target = new HttpHost("localhost", 80);
+ redirectStrategy = Mockito.spy(new DefaultRedirectStrategy());
+ redirectExec = new RedirectExec(httpRoutePlanner, redirectStrategy);
}
@Test
@@ -90,19 +96,20 @@ public class TestRedirectExec {
final HttpGet request = new HttpGet("/test");
final HttpClientContext context = HttpClientContext.create();
- final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
+ final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
+ final URI redirect = new URI("http://localhost:80/redirect");
+ response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
final HttpEntity entity1 = EntityBuilder.create()
.setStream(instream1)
.build();
- Mockito.when(response1.getEntity()).thenReturn(entity1);
- final ClassicHttpResponse response2 = Mockito.mock(ClassicHttpResponse.class);
+ response1.setEntity(entity1);
+ final ClassicHttpResponse response2 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_OK));
final InputStream instream2 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
final HttpEntity entity2 = EntityBuilder.create()
.setStream(instream2)
.build();
- Mockito.when(response2.getEntity()).thenReturn(entity2);
- final URI redirect = new URI("http://localhost:80/redirect");
+ response2.setEntity(entity2);
Mockito.when(chain.proceed(
Mockito.same(request),
@@ -110,26 +117,12 @@ public class TestRedirectExec {
Mockito.when(chain.proceed(
HttpRequestMatcher.matchesRequestUri(redirect),
Mockito.<ExecChain.Scope>any())).thenReturn(response2);
- Mockito.when(redirectStrategy.isRedirected(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
- Mockito.when(redirectStrategy.getLocationURI(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any())).thenReturn(redirect);
- Mockito.when(httpRoutePlanner.determineRoute(
- Mockito.eq(target),
- Mockito.<HttpClientContext>any())).thenReturn(route);
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
redirectExec.execute(request, scope, chain);
- final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(
- ClassicHttpRequest.class);
- Mockito.verify(chain, Mockito.times(2)).proceed(
- reqCaptor.capture(),
- Mockito.same(scope));
+ final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
+ Mockito.verify(chain, Mockito.times(2)).proceed(reqCaptor.capture(), Mockito.same(scope));
final List<ClassicHttpRequest> allValues = reqCaptor.getAllValues();
Assert.assertNotNull(allValues);
@@ -137,7 +130,7 @@ public class TestRedirectExec {
Assert.assertSame(request, allValues.get(0));
Mockito.verify(response1, Mockito.times(1)).close();
- Mockito.verify(instream1, Mockito.times(1)).close();
+ Mockito.verify(instream1, Mockito.times(2)).close();
Mockito.verify(response2, Mockito.never()).close();
Mockito.verify(instream2, Mockito.never()).close();
}
@@ -153,23 +146,11 @@ public class TestRedirectExec {
.build();
context.setRequestConfig(config);
- final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
+ final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
final URI redirect = new URI("http://localhost:80/redirect");
+ response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
- Mockito.when(chain.proceed(
- Mockito.<ClassicHttpRequest>any(),
- Mockito.<ExecChain.Scope>any())).thenReturn(response1);
- Mockito.when(redirectStrategy.isRedirected(
- Mockito.<ClassicHttpRequest>any(),
- Mockito.<HttpResponse>any(),
- Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
- Mockito.when(redirectStrategy.getLocationURI(
- Mockito.<ClassicHttpRequest>any(),
- Mockito.<HttpResponse>any(),
- Mockito.<HttpClientContext>any())).thenReturn(redirect);
- Mockito.when(httpRoutePlanner.determineRoute(
- Mockito.eq(target),
- Mockito.<HttpClientContext>any())).thenReturn(route);
+ Mockito.when(chain.proceed(Mockito.<ClassicHttpRequest>any(), Mockito.<ExecChain.Scope>any())).thenReturn(response1);
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
redirectExec.execute(request, scope, chain);
@@ -181,26 +162,12 @@ public class TestRedirectExec {
final HttpGet request = new HttpGet("/test");
final HttpClientContext context = HttpClientContext.create();
- final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
- final ClassicHttpResponse response2 = Mockito.mock(ClassicHttpResponse.class);
+ final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
final URI redirect = new URI("/redirect");
+ response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
Mockito.when(chain.proceed(
Mockito.same(request),
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
- Mockito.when(chain.proceed(
- HttpRequestMatcher.matchesRequestUri(redirect),
- Mockito.<ExecChain.Scope>any())).thenReturn(response2);
- Mockito.when(redirectStrategy.isRedirected(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
- Mockito.when(redirectStrategy.getLocationURI(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any())).thenReturn(redirect);
- Mockito.when(httpRoutePlanner.determineRoute(
- Mockito.eq(target),
- Mockito.<HttpClientContext>any())).thenReturn(route);
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
redirectExec.execute(request, scope, chain);
@@ -223,27 +190,17 @@ public class TestRedirectExec {
context.setAuthExchange(target, targetAuthExchange);
context.setAuthExchange(proxy, proxyAuthExchange);
- final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
- final ClassicHttpResponse response2 = Mockito.mock(ClassicHttpResponse.class);
- final HttpHost otherHost = new HttpHost("otherhost", 8888);
+ final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
final URI redirect = new URI("http://otherhost:8888/redirect");
+ response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
+ final ClassicHttpResponse response2 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_OK));
+ final HttpHost otherHost = new HttpHost("otherhost", 8888);
Mockito.when(chain.proceed(
Mockito.same(request),
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
Mockito.when(chain.proceed(
HttpRequestMatcher.matchesRequestUri(redirect),
Mockito.<ExecChain.Scope>any())).thenReturn(response2);
- Mockito.when(redirectStrategy.isRedirected(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
- Mockito.when(redirectStrategy.getLocationURI(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any())).thenReturn(redirect);
- Mockito.when(httpRoutePlanner.determineRoute(
- Mockito.eq(target),
- Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(target));
Mockito.when(httpRoutePlanner.determineRoute(
Mockito.eq(otherHost),
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(otherHost));
@@ -261,24 +218,101 @@ public class TestRedirectExec {
Assert.assertEquals(null, authExchange2.getAuthScheme());
}
+ @Test
+ public void testAllowCircularRedirects() throws Exception {
+ final HttpRoute route = new HttpRoute(target);
+ final HttpClientContext context = HttpClientContext.create();
+ context.setRequestConfig(RequestConfig.custom()
+ .setCircularRedirectsAllowed(true)
+ .build());
+
+ final URI uri = URI.create("http://localhost/");
+ final HttpGet request = new HttpGet(uri);
+
+ final URI uri1 = URI.create("http://localhost/stuff1");
+ final URI uri2 = URI.create("http://localhost/stuff2");
+ final ClassicHttpResponse response1 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
+ response1.addHeader("Location", uri1.toASCIIString());
+ final ClassicHttpResponse response2 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
+ response2.addHeader("Location", uri2.toASCIIString());
+ final ClassicHttpResponse response3 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
+ response3.addHeader("Location", uri1.toASCIIString());
+ final ClassicHttpResponse response4 = new BasicClassicHttpResponse(HttpStatus.SC_OK);
+
+ Mockito.when(chain.proceed(
+ HttpRequestMatcher.matchesRequestUri(uri),
+ Mockito.<ExecChain.Scope>any())).thenReturn(response1);
+ Mockito.when(chain.proceed(
+ HttpRequestMatcher.matchesRequestUri(uri1),
+ Mockito.<ExecChain.Scope>any())).thenReturn(response2, response4);
+ Mockito.when(chain.proceed(
+ HttpRequestMatcher.matchesRequestUri(uri2),
+ Mockito.<ExecChain.Scope>any())).thenReturn(response3);
+ Mockito.when(httpRoutePlanner.determineRoute(
+ Mockito.eq(new HttpHost("localhost")),
+ Mockito.<HttpClientContext>any())).thenReturn(route);
+
+ final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
+ redirectExec.execute(request, scope, chain);
+
+ final RedirectLocations uris = context.getRedirectLocations();
+ Assert.assertNotNull(uris);
+ Assert.assertEquals(Arrays.asList(uri1, uri2, uri1), uris.getAll());
+ }
+
+ @Test(expected=CircularRedirectException.class)
+ public void testGetLocationUriDisallowCircularRedirects() throws Exception {
+ final HttpRoute route = new HttpRoute(target);
+ final HttpClientContext context = HttpClientContext.create();
+ context.setRequestConfig(RequestConfig.custom()
+ .setCircularRedirectsAllowed(false)
+ .build());
+
+ final URI uri = URI.create("http://localhost/");
+ final HttpGet request = new HttpGet(uri);
+
+ final URI uri1 = URI.create("http://localhost/stuff1");
+ final URI uri2 = URI.create("http://localhost/stuff2");
+ final ClassicHttpResponse response1 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
+ response1.addHeader("Location", uri1.toASCIIString());
+ final ClassicHttpResponse response2 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
+ response2.addHeader("Location", uri2.toASCIIString());
+ final ClassicHttpResponse response3 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
+ response3.addHeader("Location", uri1.toASCIIString());
+ Mockito.when(httpRoutePlanner.determineRoute(
+ Mockito.eq(new HttpHost("localhost")),
+ Mockito.<HttpClientContext>any())).thenReturn(route);
+
+ Mockito.when(chain.proceed(
+ HttpRequestMatcher.matchesRequestUri(uri),
+ Mockito.<ExecChain.Scope>any())).thenReturn(response1);
+ Mockito.when(chain.proceed(
+ HttpRequestMatcher.matchesRequestUri(uri1),
+ Mockito.<ExecChain.Scope>any())).thenReturn(response2);
+ Mockito.when(chain.proceed(
+ HttpRequestMatcher.matchesRequestUri(uri2),
+ Mockito.<ExecChain.Scope>any())).thenReturn(response3);
+
+ final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
+ redirectExec.execute(request, scope, chain);
+ }
+
@Test(expected = RuntimeException.class)
public void testRedirectRuntimeException() throws Exception {
final HttpRoute route = new HttpRoute(target);
final HttpGet request = new HttpGet("/test");
final HttpClientContext context = HttpClientContext.create();
- final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
+ final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
+ final URI redirect = new URI("http://localhost:80/redirect");
+ response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
Mockito.when(chain.proceed(
Mockito.same(request),
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
- Mockito.when(redirectStrategy.isRedirected(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
- Mockito.doThrow(new RuntimeException("Oppsie")).when(redirectStrategy.getLocationURI(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any()));
+ Mockito.doThrow(new RuntimeException("Oppsie")).when(redirectStrategy).getLocationURI(
+ Mockito.<ClassicHttpRequest>any(),
+ Mockito.<ClassicHttpResponse>any(),
+ Mockito.<HttpClientContext>any());
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
try {
@@ -295,29 +329,27 @@ public class TestRedirectExec {
final HttpGet request = new HttpGet("/test");
final HttpClientContext context = HttpClientContext.create();
- final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
+ final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
+ final URI redirect = new URI("http://localhost:80/redirect");
+ response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
final HttpEntity entity1 = EntityBuilder.create()
.setStream(instream1)
.build();
- Mockito.when(response1.getEntity()).thenReturn(entity1);
+ response1.setEntity(entity1);
Mockito.when(chain.proceed(
Mockito.same(request),
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
- Mockito.when(redirectStrategy.isRedirected(
- Mockito.same(request),
- Mockito.same(response1),
- Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.doThrow(new ProtocolException("Oppsie")).when(redirectStrategy).getLocationURI(
- Mockito.same(request),
- Mockito.same(response1),
+ Mockito.<ClassicHttpRequest>any(),
+ Mockito.<ClassicHttpResponse>any(),
Mockito.<HttpClientContext>any());
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
try {
redirectExec.execute(request, scope, chain);
} catch (final Exception ex) {
- Mockito.verify(instream1).close();
+ Mockito.verify(instream1, Mockito.times(2)).close();
Mockito.verify(response1).close();
throw ex;
}
@@ -325,17 +357,21 @@ public class TestRedirectExec {
private static class HttpRequestMatcher implements ArgumentMatcher<ClassicHttpRequest> {
- private final URI requestUri;
+ private final URI expectedRequestUri;
HttpRequestMatcher(final URI requestUri) {
super();
- this.requestUri = requestUri;
+ this.expectedRequestUri = requestUri;
}
@Override
public boolean matches(final ClassicHttpRequest argument) {
+ if (argument == null) {
+ return false;
+ }
try {
- return requestUri.equals(argument.getUri());
+ final URI requestUri = argument.getUri();
+ return this.expectedRequestUri.equals(requestUri);
} catch (final URISyntaxException ex) {
return false;
}
http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/47a0eb8b/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRedirectLocation.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRedirectLocation.java b/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRedirectLocation.java
index 95f4693..3923afc 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRedirectLocation.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/protocol/TestRedirectLocation.java
@@ -56,7 +56,7 @@ public class TestRedirectLocation {
Assert.assertTrue(locations.contains(uri3));
Assert.assertFalse(locations.contains(new URI("/")));
- List<URI> list = locations.getAll();
+ final List<URI> list = locations.getAll();
Assert.assertNotNull(list);
Assert.assertEquals(5, list.size());
Assert.assertEquals(uri1, list.get(0));
@@ -64,16 +64,6 @@ public class TestRedirectLocation {
Assert.assertEquals(uri2, list.get(2));
Assert.assertEquals(uri3, list.get(3));
Assert.assertEquals(uri3, list.get(4));
-
- Assert.assertTrue(locations.remove(uri3));
- Assert.assertTrue(locations.remove(uri1));
- Assert.assertFalse(locations.remove(new URI("/")));
-
- list = locations.getAll();
- Assert.assertNotNull(list);
- Assert.assertEquals(2, list.size());
- Assert.assertEquals(uri2, list.get(0));
- Assert.assertEquals(uri2, list.get(1));
}
}