DefaultHttpHeader.names().toArray(...) may throw ArrayStoreException
Motivation: DefaultHttpHeader.names() exposes HTTP header names as a Set<String>. Converting the resulting set to an array using toArray(String[]) throws an exception: java.lang.ArrayStoreException: io.netty.util.AsciiString. Modifications: - Remove our custom implementation of toArray(...) (and others) by just extending AbstractCollection. - Add unit test Result: Fixes [#7428].
This commit is contained in:
parent
7d213240ca
commit
7aca99f986
@ -23,16 +23,13 @@ import org.junit.Test;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static io.netty.handler.codec.http.HttpHeadersTestUtils.of;
|
import static io.netty.handler.codec.http.HttpHeadersTestUtils.of;
|
||||||
import static io.netty.util.AsciiString.contentEquals;
|
import static io.netty.util.AsciiString.contentEquals;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class DefaultHttpHeadersTest {
|
public class DefaultHttpHeadersTest {
|
||||||
private static final CharSequence HEADER_NAME = "testHeader";
|
private static final CharSequence HEADER_NAME = "testHeader";
|
||||||
@ -229,6 +226,16 @@ public class DefaultHttpHeadersTest {
|
|||||||
.toString());
|
.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void providesHeaderNamesAsArray() throws Exception {
|
||||||
|
Set<String> nettyHeaders = new DefaultHttpHeaders()
|
||||||
|
.add(HttpHeaderNames.CONTENT_LENGTH, 10)
|
||||||
|
.names();
|
||||||
|
|
||||||
|
String[] namesArray = nettyHeaders.toArray(new String[nettyHeaders.size()]);
|
||||||
|
assertArrayEquals(namesArray, new String[] { HttpHeaderNames.CONTENT_LENGTH.toString() });
|
||||||
|
}
|
||||||
|
|
||||||
private static void assertDefaultValues(final DefaultHttpHeaders headers, final HeaderValue headerValue) {
|
private static void assertDefaultValues(final DefaultHttpHeaders headers, final HeaderValue headerValue) {
|
||||||
assertTrue(contentEquals(headerValue.asList().get(0), headers.get(HEADER_NAME)));
|
assertTrue(contentEquals(headerValue.asList().get(0), headers.get(HEADER_NAME)));
|
||||||
List<CharSequence> expected = headerValue.asList();
|
List<CharSequence> expected = headerValue.asList();
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.codec;
|
package io.netty.handler.codec;
|
||||||
|
|
||||||
|
import java.util.AbstractCollection;
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -109,7 +110,7 @@ public final class HeadersUtils {
|
|||||||
private static final class StringEntryIterator implements Iterator<Entry<String, String>> {
|
private static final class StringEntryIterator implements Iterator<Entry<String, String>> {
|
||||||
private final Iterator<Entry<CharSequence, CharSequence>> iter;
|
private final Iterator<Entry<CharSequence, CharSequence>> iter;
|
||||||
|
|
||||||
public StringEntryIterator(Iterator<Entry<CharSequence, CharSequence>> iter) {
|
StringEntryIterator(Iterator<Entry<CharSequence, CharSequence>> iter) {
|
||||||
this.iter = iter;
|
this.iter = iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +171,7 @@ public final class HeadersUtils {
|
|||||||
private static final class StringIterator<T> implements Iterator<String> {
|
private static final class StringIterator<T> implements Iterator<String> {
|
||||||
private final Iterator<T> iter;
|
private final Iterator<T> iter;
|
||||||
|
|
||||||
public StringIterator(Iterator<T> iter) {
|
StringIterator(Iterator<T> iter) {
|
||||||
this.iter = iter;
|
this.iter = iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +193,7 @@ public final class HeadersUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class CharSequenceDelegatingStringSet extends DelegatingStringSet<CharSequence> {
|
private static final class CharSequenceDelegatingStringSet extends DelegatingStringSet<CharSequence> {
|
||||||
public CharSequenceDelegatingStringSet(Set<CharSequence> allNames) {
|
CharSequenceDelegatingStringSet(Set<CharSequence> allNames) {
|
||||||
super(allNames);
|
super(allNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,10 +208,10 @@ public final class HeadersUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract static class DelegatingStringSet<T> implements Set<String> {
|
private abstract static class DelegatingStringSet<T> extends AbstractCollection<String> implements Set<String> {
|
||||||
protected final Set<T> allNames;
|
protected final Set<T> allNames;
|
||||||
|
|
||||||
public DelegatingStringSet(Set<T> allNames) {
|
DelegatingStringSet(Set<T> allNames) {
|
||||||
this.allNames = checkNotNull(allNames, "allNames");
|
this.allNames = checkNotNull(allNames, "allNames");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,71 +235,11 @@ public final class HeadersUtils {
|
|||||||
return new StringIterator<T>(allNames.iterator());
|
return new StringIterator<T>(allNames.iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] toArray() {
|
|
||||||
Object[] arr = new Object[size()];
|
|
||||||
fillArray(arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public <X> X[] toArray(X[] a) {
|
|
||||||
if (a == null || a.length < size()) {
|
|
||||||
X[] arr = (X[]) new Object[size()];
|
|
||||||
fillArray(arr);
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
fillArray(a);
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fillArray(Object[] arr) {
|
|
||||||
Iterator<T> itr = allNames.iterator();
|
|
||||||
for (int i = 0; i < size(); ++i) {
|
|
||||||
arr[i] = itr.next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean remove(Object o) {
|
public boolean remove(Object o) {
|
||||||
return allNames.remove(o);
|
return allNames.remove(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsAll(Collection<?> c) {
|
|
||||||
for (Object o : c) {
|
|
||||||
if (!contains(o)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeAll(Collection<?> c) {
|
|
||||||
boolean modified = false;
|
|
||||||
for (Object o : c) {
|
|
||||||
if (remove(o)) {
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean retainAll(Collection<?> c) {
|
|
||||||
boolean modified = false;
|
|
||||||
Iterator<String> it = iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
if (!c.contains(it.next())) {
|
|
||||||
it.remove();
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
allNames.clear();
|
allNames.clear();
|
||||||
|
Loading…
Reference in New Issue
Block a user