hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r1695156 - in /httpcomponents/httpclient/trunk/httpclient/src: main/java/org/apache/http/auth/util/ main/java/org/apache/http/impl/auth/ test/java/org/apache/http/auth/util/ test/java/org/apache/http/impl/auth/
Date Mon, 10 Aug 2015 19:44:09 GMT
Author: olegk
Date: Mon Aug 10 19:44:09 2015
New Revision: 1695156

URL: http://svn.apache.org/r1695156
Log:
ByteArrayBuilder class to build byte sequences; BasicScheme and DigestScheme optimized to
generate less intermediate garbage

Added:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/ByteArrayBuilder.java
  (with props)
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/TestByteArrayBuilder.java
  (with props)
Modified:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/ByteArrayBuilder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/ByteArrayBuilder.java?rev=1695156&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/ByteArrayBuilder.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/ByteArrayBuilder.java
Mon Aug 10 19:44:09 2015
@@ -0,0 +1,212 @@
+/*
+ * ====================================================================
+ * 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.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 org.apache.http.Consts;
+import org.apache.http.annotation.Immutable;
+
+/**
+ * Builder class for sequences of bytes.
+ *
+ * @since 5.0
+ */
+@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;
+        } else {
+            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 = Consts.ASCII.newEncoder()
+                    .onMalformedInput(CodingErrorAction.IGNORE)
+                    .onUnmappableCharacter(CodingErrorAction.REPLACE);
+        }
+        this.charsetEncoder.reset();
+        try {
+            this.buffer = encode(this.buffer, charBuffer, this.charsetEncoder);
+        } catch (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[] {};
+        } else {
+            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";
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/ByteArrayBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/ByteArrayBuilder.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/auth/util/ByteArrayBuilder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java?rev=1695156&r1=1695155&r2=1695156&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
Mon Aug 10 19:44:09 2015
@@ -51,10 +51,10 @@ import org.apache.http.auth.Authenticati
 import org.apache.http.auth.Credentials;
 import org.apache.http.auth.CredentialsProvider;
 import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.auth.util.ByteArrayBuilder;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.Args;
 import org.apache.http.util.CharsetUtils;
-import org.apache.http.util.EncodingUtils;
 
 /**
  * Basic authentication scheme as defined in RFC 2617.
@@ -68,7 +68,10 @@ public class BasicScheme implements Auth
 
     private final Map<String, String> paramMap;
     private transient Charset charset;
+    private transient ByteArrayBuilder buffer;
+    private transient Base64 base64codec;
     private boolean complete;
+
     private String username;
     private String password;
 
@@ -160,12 +163,17 @@ public class BasicScheme implements Auth
             final HttpHost host,
             final HttpRequest request,
             final HttpContext context) throws AuthenticationException {
-        final StringBuilder buffer = new StringBuilder();
-        buffer.append(this.username);
-        buffer.append(":");
-        buffer.append(this.password);
-        final Base64 base64codec = new Base64(0);
-        final byte[] encodedCreds = base64codec.encode(EncodingUtils.getBytes(buffer.toString(),
charset.name()));
+        if (this.buffer == null) {
+            this.buffer = new ByteArrayBuilder(64).charset(this.charset);
+        } else {
+            this.buffer.reset();
+        }
+        this.buffer.append(this.username).append(":").append(this.password);
+        if (this.base64codec == null) {
+            this.base64codec = new Base64(0);
+        }
+        final byte[] encodedCreds = this.base64codec.encode(this.buffer.toByteArray());
+        this.buffer.reset();
         return "Basic " + new String(encodedCreds, 0, encodedCreds.length, Consts.ASCII);
     }
 

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java?rev=1695156&r1=1695155&r2=1695156&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
Mon Aug 10 19:44:09 2015
@@ -28,6 +28,7 @@ package org.apache.http.impl.auth;
 
 import java.io.IOException;
 import java.io.Serializable;
+import java.nio.charset.Charset;
 import java.security.MessageDigest;
 import java.security.Principal;
 import java.security.SecureRandom;
@@ -41,6 +42,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
 
+import org.apache.http.Consts;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpEntityEnclosingRequest;
 import org.apache.http.HttpHost;
@@ -54,12 +56,13 @@ import org.apache.http.auth.Authenticati
 import org.apache.http.auth.Credentials;
 import org.apache.http.auth.CredentialsProvider;
 import org.apache.http.auth.MalformedChallengeException;
+import org.apache.http.auth.util.ByteArrayBuilder;
 import org.apache.http.message.BasicHeaderValueFormatter;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.Args;
 import org.apache.http.util.CharArrayBuffer;
-import org.apache.http.util.EncodingUtils;
+import org.apache.http.util.CharsetUtils;
 
 /**
  * Digest authentication scheme as defined in RFC 2617.
@@ -84,7 +87,7 @@ public class DigestScheme implements Aut
      * Hexa values used when creating 32 character long digest in HTTP DigestScheme
      * in case of authentication.
      *
-     * @see #encode(byte[])
+     * @see #formatHex(byte[])
      */
     private static final char[] HEXADECIMAL = {
         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
@@ -98,11 +101,13 @@ public class DigestScheme implements Aut
 
     private final Map<String, String> paramMap;
     private boolean complete;
+    private transient ByteArrayBuilder buffer;
+
     private String lastNonce;
     private long nounceCount;
     private String cnonce;
-    private String a1;
-    private String a2;
+    private byte[] a1;
+    private byte[] a2;
 
     private String username;
     private String password;
@@ -251,9 +256,10 @@ public class DigestScheme implements Aut
             throw new AuthenticationException("None of the qop methods is supported: " +
qoplist);
         }
 
-        String charset = this.paramMap.get("charset");
+        final String charsetName = this.paramMap.get("charset");
+        Charset charset = charsetName != null ? CharsetUtils.lookup(charsetName) : null;
         if (charset == null) {
-            charset = "ISO-8859-1";
+            charset = Consts.ISO_8859_1;
         }
 
         String digAlg = algorithm;
@@ -275,15 +281,23 @@ public class DigestScheme implements Aut
             cnonce = null;
             lastNonce = nonce;
         }
-        final StringBuilder sb = new StringBuilder(256);
+
+        final StringBuilder sb = new StringBuilder(8);
         final Formatter formatter = new Formatter(sb, Locale.US);
-        formatter.format("%08x", Long.valueOf(nounceCount));
+        formatter.format("%08x", nounceCount);
         formatter.close();
         final String nc = sb.toString();
 
         if (cnonce == null) {
-            cnonce = createCnonce();
+            cnonce = formatHex(createCnonce());
+        }
+
+        if (buffer == null) {
+            buffer = new ByteArrayBuilder();
+        } else {
+            buffer.reset();
         }
+        buffer.charset(charset);
 
         a1 = null;
         a2 = null;
@@ -294,24 +308,23 @@ public class DigestScheme implements Aut
             //      ":" unq(cnonce-value)
 
             // calculated one per session
-            sb.setLength(0);
-            sb.append(username).append(':').append(realm).append(':').append(password);
-            final String checksum = encode(digester.digest(EncodingUtils.getBytes(sb.toString(),
charset)));
-            sb.setLength(0);
-            sb.append(checksum).append(':').append(nonce).append(':').append(cnonce);
-            a1 = sb.toString();
+            buffer.append(username).append(":").append(realm).append(":").append(password);
+            final String checksum = formatHex(digester.digest(this.buffer.toByteArray()));
+            buffer.reset();
+            buffer.append(checksum).append(":").append(nonce).append(":").append(cnonce);
+            a1 = buffer.toByteArray();
         } else {
             // unq(username-value) ":" unq(realm-value) ":" passwd
-            sb.setLength(0);
-            sb.append(username).append(':').append(realm).append(':').append(password);
-            a1 = sb.toString();
+            buffer.append(username).append(":").append(realm).append(":").append(password);
+            a1 = buffer.toByteArray();
         }
 
-        final String hasha1 = encode(digester.digest(EncodingUtils.getBytes(a1, charset)));
+        final String hasha1 = formatHex(digester.digest(a1));
+        buffer.reset();
 
         if (qop == QOP_AUTH) {
             // Method ":" digest-uri-value
-            a2 = method + ':' + uri;
+            a2 = buffer.append(method).append(":").append(uri).toByteArray();
         } else if (qop == QOP_AUTH_INT) {
             // Method ":" digest-uri-value ":" H(entity-body)
             HttpEntity entity = null;
@@ -322,7 +335,7 @@ public class DigestScheme implements Aut
                 // If the entity is not repeatable, try falling back onto QOP_AUTH
                 if (qopset.contains("auth")) {
                     qop = QOP_AUTH;
-                    a2 = method + ':' + uri;
+                    a2 = buffer.append(method).append(":").append(uri).toByteArray();
                 } else {
                     throw new AuthenticationException("Qop auth-int cannot be used with "
+
                             "a non-repeatable entity");
@@ -337,30 +350,31 @@ public class DigestScheme implements Aut
                 } catch (final IOException ex) {
                     throw new AuthenticationException("I/O error reading entity content",
ex);
                 }
-                a2 = method + ':' + uri + ':' + encode(entityDigester.getDigest());
+                a2 = buffer.append(method).append(":").append(uri)
+                        .append(":").append(formatHex(entityDigester.getDigest())).toByteArray();
             }
         } else {
-            a2 = method + ':' + uri;
+            a2 = buffer.append(method).append(":").append(uri).toByteArray();
         }
 
-        final String hasha2 = encode(digester.digest(EncodingUtils.getBytes(a2, charset)));
+        final String hasha2 = formatHex(digester.digest(a2));
+        buffer.reset();
 
         // 3.2.2.1
 
-        final String digestValue;
+        final byte[] digestInput;
         if (qop == QOP_MISSING) {
-            sb.setLength(0);
-            sb.append(hasha1).append(':').append(nonce).append(':').append(hasha2);
-            digestValue = sb.toString();
+            buffer.append(hasha1).append(":").append(nonce).append(":").append(hasha2);
+            digestInput = buffer.toByteArray();
         } else {
-            sb.setLength(0);
-            sb.append(hasha1).append(':').append(nonce).append(':').append(nc).append(':')
-                .append(cnonce).append(':').append(qop == QOP_AUTH_INT ? "auth-int" : "auth")
-                .append(':').append(hasha2);
-            digestValue = sb.toString();
+            buffer.append(hasha1).append(":").append(nonce).append(":").append(nc).append(":")
+                .append(cnonce).append(":").append(qop == QOP_AUTH_INT ? "auth-int" : "auth")
+                .append(":").append(hasha2);
+            digestInput = buffer.toByteArray();
         }
+        buffer.reset();
 
-        final String digest = encode(digester.digest(EncodingUtils.getAsciiBytes(digestValue)));
+        final String digest = formatHex(digester.digest(digestInput));
 
         final CharArrayBuffer buffer = new CharArrayBuffer(128);
         buffer.append("Digest ");
@@ -401,11 +415,11 @@ public class DigestScheme implements Aut
     }
 
     String getA1() {
-        return a1;
+        return a1 != null ? new String(a1, Consts.ASCII) : null;
     }
 
     String getA2() {
-        return a2;
+        return a2 != null ? new String(a2, Consts.ASCII) : null;
     }
 
     /**
@@ -415,7 +429,7 @@ public class DigestScheme implements Aut
      * @param binaryData array containing the digest
      * @return encoded MD5, or <CODE>null</CODE> if encoding failed
      */
-    static String encode(final byte[] binaryData) {
+    static String formatHex(final byte[] binaryData) {
         final int n = binaryData.length;
         final char[] buffer = new char[n * 2];
         for (int i = 0; i < n; i++) {
@@ -433,11 +447,11 @@ public class DigestScheme implements Aut
      *
      * @return The cnonce value as String.
      */
-    public static String createCnonce() {
+    static byte[] createCnonce() {
         final SecureRandom rnd = new SecureRandom();
         final byte[] tmp = new byte[8];
         rnd.nextBytes(tmp);
-        return encode(tmp);
+        return tmp;
     }
 
     @Override

Added: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/TestByteArrayBuilder.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/TestByteArrayBuilder.java?rev=1695156&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/TestByteArrayBuilder.java
(added)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/TestByteArrayBuilder.java
Mon Aug 10 19:44:09 2015
@@ -0,0 +1,214 @@
+/*
+ * ====================================================================
+ * 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.http.auth.util;
+
+import java.nio.ByteBuffer;
+
+import org.apache.http.Consts;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * {@link ByteArrayBuilder} test cases.
+ */
+public class TestByteArrayBuilder {
+
+    @Test
+    public void testEmptyBuffer() throws Exception {
+        final ByteArrayBuilder buffer = new ByteArrayBuilder();
+        final ByteBuffer byteBuffer = buffer.toByteBuffer();
+        Assert.assertNotNull(byteBuffer);
+        Assert.assertEquals(0, byteBuffer.capacity());
+
+        final byte[] bytes = buffer.toByteArray();
+        Assert.assertNotNull(bytes);
+        Assert.assertEquals(0, bytes.length);
+    }
+
+    @Test
+    public void testAppendBytes() throws Exception {
+        final ByteArrayBuilder buffer = new ByteArrayBuilder();
+        buffer.append(new byte[]{1, 2, 3, 4, 5});
+        buffer.append(new byte[]{3, 4, 5, 6, 7, 8, 9, 10, 11}, 3, 5);
+        buffer.append((byte[]) null);
+
+        final byte[] bytes = buffer.toByteArray();
+        Assert.assertNotNull(bytes);
+        Assert.assertArrayEquals(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, bytes);
+    }
+
+    @Test
+    public void testInvalidAppendBytes() throws Exception {
+        final ByteArrayBuilder buffer = new ByteArrayBuilder();
+        buffer.append((byte[])null, 0, 0);
+
+        final byte[] tmp = new byte[] { 1, 2, 3, 4};
+        try {
+            buffer.append(tmp, -1, 0);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 0, -1);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 0, 8);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 10, Integer.MAX_VALUE);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 2, 4);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testEnsureCapacity() throws Exception {
+        final ByteArrayBuilder buffer = new ByteArrayBuilder();
+        buffer.ensureFreeCapacity(10);
+        Assert.assertEquals(10, buffer.capacity());
+        buffer.ensureFreeCapacity(5);
+        Assert.assertEquals(10, buffer.capacity());
+        buffer.append(new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
+        buffer.ensureFreeCapacity(5);
+        Assert.assertEquals(13, buffer.capacity());
+        buffer.ensureFreeCapacity(15);
+        Assert.assertEquals(23, buffer.capacity());
+    }
+
+    @Test
+    public void testAppendText() throws Exception {
+        final ByteArrayBuilder buffer = new ByteArrayBuilder();
+        buffer.append(new char[]{'1', '2', '3', '4', '5'});
+        buffer.append(new char[]{'3', '4', '5', '6', '7', '8', '9', 'a', 'b'}, 3, 5);
+        buffer.append("bcd");
+        buffer.append("e");
+        buffer.append("f");
+        buffer.append((String) null);
+        buffer.append((char[]) null);
+
+        final byte[] bytes = buffer.toByteArray();
+        Assert.assertNotNull(bytes);
+        Assert.assertEquals("123456789abcdef", new String(bytes, Consts.ASCII));
+    }
+
+    @Test
+    public void testInvalidAppendChars() throws Exception {
+        final ByteArrayBuilder buffer = new ByteArrayBuilder();
+        buffer.append((char[])null, 0, 0);
+
+        final char[] tmp = new char[] { 1, 2, 3, 4};
+        try {
+            buffer.append(tmp, -1, 0);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 0, -1);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 0, 8);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 10, Integer.MAX_VALUE);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+        try {
+            buffer.append(tmp, 2, 4);
+            Assert.fail("IndexOutOfBoundsException should have been thrown");
+        } catch (final IndexOutOfBoundsException ex) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testReset() throws Exception {
+        final ByteArrayBuilder buffer = new ByteArrayBuilder();
+        buffer.append("abcd");
+        buffer.append("e");
+        buffer.append("f");
+
+        final byte[] bytes1 = buffer.toByteArray();
+        Assert.assertNotNull(bytes1);
+        Assert.assertEquals("abcdef", new String(bytes1, Consts.ASCII));
+
+        buffer.reset();
+
+        final byte[] bytes2 = buffer.toByteArray();
+        Assert.assertNotNull(bytes2);
+        Assert.assertEquals("", new String(bytes2, Consts.ASCII));
+    }
+
+    @Test
+    public void testNonAsciiCharset() throws Exception {
+        final int[] germanChars = { 0xE4, 0x2D, 0xF6, 0x2D, 0xFc };
+        final StringBuilder tmp = new StringBuilder();
+        for (final int germanChar : germanChars) {
+            tmp.append((char) germanChar);
+        }
+        final String umlauts = tmp.toString();
+
+
+        final ByteArrayBuilder buffer = new ByteArrayBuilder();
+        buffer.append(umlauts);
+
+        final byte[] bytes1 = buffer.toByteArray();
+        Assert.assertNotNull(bytes1);
+        Assert.assertEquals("?-?-?", new String(bytes1, Consts.ASCII));
+
+        buffer.reset();
+        buffer.charset(Consts.UTF_8);
+        buffer.append(umlauts);
+
+        final byte[] bytes2 = buffer.toByteArray();
+        Assert.assertNotNull(bytes2);
+        Assert.assertEquals(umlauts, new String(bytes2, Consts.UTF_8));
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/TestByteArrayBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/TestByteArrayBuilder.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/auth/util/TestByteArrayBuilder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java?rev=1695156&r1=1695155&r2=1695156&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java
(original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java
Mon Aug 10 19:44:09 2015
@@ -567,7 +567,7 @@ public class TestDigestScheme {
         digester.write(new byte[] { 'a', 'b', 'c'});
         Assert.assertNull(digester.getDigest());
         digester.close();
-        Assert.assertEquals("acd2b59cd01c7737d8069015584c6cac", DigestScheme.encode(digester.getDigest()));
+        Assert.assertEquals("acd2b59cd01c7737d8069015584c6cac", DigestScheme.formatHex(digester.getDigest()));
         try {
             digester.write('a');
             Assert.fail("IOException should have been thrown");



Mime
View raw message