diff --git a/codec/src/main/java/io/netty/handler/codec/DefaultTextHeaders.java b/codec/src/main/java/io/netty/handler/codec/DefaultTextHeaders.java index 9d36a957a0..a6d3504d77 100644 --- a/codec/src/main/java/io/netty/handler/codec/DefaultTextHeaders.java +++ b/codec/src/main/java/io/netty/handler/codec/DefaultTextHeaders.java @@ -459,6 +459,158 @@ public class DefaultTextHeaders implements TextHeaders { return HttpHeaderDateFormat.get().parse(v.toString(), defaultValue); } + @Override + public CharSequence getUnconvertedAndRemove(CharSequence name) { + if (name == null) { + throw new NullPointerException("name"); + } + int h = hashCode(name); + int i = index(h); + HeaderEntry e = entries[i]; + if (e == null) { + return null; + } + + CharSequence value = null; + for (;;) { + if (e.hash == h && nameEquals(e.name, name)) { + value = e.value; + e.remove(); + HeaderEntry next = e.next; + if (next != null) { + entries[i] = next; + e = next; + } else { + entries[i] = null; + return value; + } + } else { + break; + } + } + + for (;;) { + HeaderEntry next = e.next; + if (next == null) { + break; + } + if (next.hash == h && nameEquals(next.name, name)) { + value = next.value; + e.next = next.next; + next.remove(); + } else { + e = next; + } + } + + if (value != null) { + return value; + } + return null; + } + + @Override + public String getAndRemove(CharSequence name) { + CharSequence v = getUnconvertedAndRemove(name); + if (v == null) { + return null; + } + return v.toString(); + } + + @Override + public String getAndRemove(CharSequence name, String defaultValue) { + CharSequence v = getUnconvertedAndRemove(name); + if (v == null) { + return defaultValue; + } + return v.toString(); + } + + @Override + public int getIntAndRemove(CharSequence name) { + CharSequence v = getUnconvertedAndRemove(name); + if (v == null) { + throw new NoSuchElementException(String.valueOf(name)); + } + + if (v instanceof AsciiString) { + return ((AsciiString) v).parseInt(); + } else { + return Integer.parseInt(v.toString()); + } + } + + @Override + public int getIntAndRemove(CharSequence name, int defaultValue) { + CharSequence v = getUnconvertedAndRemove(name); + if (v == null) { + return defaultValue; + } + + try { + if (v instanceof AsciiString) { + return ((AsciiString) v).parseInt(); + } else { + return Integer.parseInt(v.toString()); + } + } catch (NumberFormatException ignored) { + return defaultValue; + } + } + + @Override + public long getLongAndRemove(CharSequence name) { + CharSequence v = getUnconvertedAndRemove(name); + if (v == null) { + throw new NoSuchElementException(String.valueOf(name)); + } + + if (v instanceof AsciiString) { + return ((AsciiString) v).parseLong(); + } else { + return Long.parseLong(v.toString()); + } + } + + @Override + public long getLongAndRemove(CharSequence name, long defaultValue) { + CharSequence v = getUnconvertedAndRemove(name); + if (v == null) { + return defaultValue; + } + + try { + if (v instanceof AsciiString) { + return ((AsciiString) v).parseLong(); + } else { + return Long.parseLong(v.toString()); + } + } catch (NumberFormatException ignored) { + return defaultValue; + } + } + + @Override + public long getTimeMillisAndRemove(CharSequence name) { + CharSequence v = getUnconvertedAndRemove(name); + if (v == null) { + throw new NoSuchElementException(String.valueOf(name)); + } + + return HttpHeaderDateFormat.get().parse(v.toString()); + } + + @Override + public long getTimeMillisAndRemove(CharSequence name, long defaultValue) { + CharSequence v = getUnconvertedAndRemove(name); + if (v == null) { + return defaultValue; + } + + return HttpHeaderDateFormat.get().parse(v.toString(), defaultValue); + } + @Override public List getAllUnconverted(CharSequence name) { if (name == null) { @@ -501,6 +653,104 @@ public class DefaultTextHeaders implements TextHeaders { return values; } + @Override + public List getAllAndRemove(CharSequence name) { + if (name == null) { + throw new NullPointerException("name"); + } + int h = hashCode(name); + int i = index(h); + HeaderEntry e = entries[i]; + if (e == null) { + return null; + } + + List values = new ArrayList(4); + for (;;) { + if (e.hash == h && nameEquals(e.name, name)) { + values.add(e.getValue().toString()); + e.remove(); + HeaderEntry next = e.next; + if (next != null) { + entries[i] = next; + e = next; + } else { + entries[i] = null; + Collections.reverse(values); + return values; + } + } else { + break; + } + } + + for (;;) { + HeaderEntry next = e.next; + if (next == null) { + break; + } + if (next.hash == h && nameEquals(next.name, name)) { + values.add(next.getValue().toString()); + e.next = next.next; + next.remove(); + } else { + e = next; + } + } + + Collections.reverse(values); + return values; + } + + @Override + public List getAllUnconvertedAndRemove(CharSequence name) { + if (name == null) { + throw new NullPointerException("name"); + } + int h = hashCode(name); + int i = index(h); + HeaderEntry e = entries[i]; + if (e == null) { + return null; + } + + List values = new ArrayList(4); + for (;;) { + if (e.hash == h && nameEquals(e.name, name)) { + values.add(e.getValue()); + e.remove(); + HeaderEntry next = e.next; + if (next != null) { + entries[i] = next; + e = next; + } else { + entries[i] = null; + Collections.reverse(values); + return values; + } + } else { + break; + } + } + + for (;;) { + HeaderEntry next = e.next; + if (next == null) { + break; + } + if (next.hash == h && nameEquals(next.name, name)) { + values.add(next.getValue()); + e.next = next.next; + next.remove(); + } else { + e = next; + } + } + + Collections.reverse(values); + return values; + } + @Override public List> entries() { int cnt = 0; diff --git a/codec/src/main/java/io/netty/handler/codec/EmptyTextHeaders.java b/codec/src/main/java/io/netty/handler/codec/EmptyTextHeaders.java index e2e5ebf8fd..b0249083d0 100644 --- a/codec/src/main/java/io/netty/handler/codec/EmptyTextHeaders.java +++ b/codec/src/main/java/io/netty/handler/codec/EmptyTextHeaders.java @@ -67,11 +67,56 @@ public class EmptyTextHeaders implements TextHeaders { return defaultValue; } + @Override + public String getAndRemove(CharSequence name) { + return null; + } + + @Override + public String getAndRemove(CharSequence name, String defaultValue) { + return defaultValue; + } + + @Override + public int getIntAndRemove(CharSequence name) { + throw new NoSuchElementException(String.valueOf(name)); + } + + @Override + public int getIntAndRemove(CharSequence name, int defaultValue) { + return defaultValue; + } + + @Override + public long getLongAndRemove(CharSequence name) { + throw new NoSuchElementException(String.valueOf(name)); + } + + @Override + public long getLongAndRemove(CharSequence name, long defaultValue) { + return defaultValue; + } + + @Override + public long getTimeMillisAndRemove(CharSequence name) { + throw new NoSuchElementException(String.valueOf(name)); + } + + @Override + public long getTimeMillisAndRemove(CharSequence name, long defaultValue) { + return defaultValue; + } + @Override public CharSequence getUnconverted(CharSequence name) { return null; } + @Override + public CharSequence getUnconvertedAndRemove(CharSequence name) { + return null; + } + @Override public List getAll(CharSequence name) { return Collections.emptyList(); @@ -82,6 +127,16 @@ public class EmptyTextHeaders implements TextHeaders { return Collections.emptyList(); } + @Override + public List getAllAndRemove(CharSequence name) { + return Collections.emptyList(); + } + + @Override + public List getAllUnconvertedAndRemove(CharSequence name) { + return Collections.emptyList(); + } + @Override public List> entries() { return Collections.emptyList(); diff --git a/codec/src/main/java/io/netty/handler/codec/TextHeaders.java b/codec/src/main/java/io/netty/handler/codec/TextHeaders.java index d84b250182..97d9740f5e 100644 --- a/codec/src/main/java/io/netty/handler/codec/TextHeaders.java +++ b/codec/src/main/java/io/netty/handler/codec/TextHeaders.java @@ -48,6 +48,94 @@ public interface TextHeaders extends Iterable> { long getTimeMillis(CharSequence name); long getTimeMillis(CharSequence name, long defaultValue); + /** + * Returns and Removes the value of a header with the specified name. If there are + * more than one values for the specified name, the first value is returned. + * + * @param name The name of the header to search + * @return The first header value or {@code null} if there is no such header + */ + String getAndRemove(CharSequence name); + + /** + * Returns and Removes the value of a header with the specified name. If there are + * more than one values for the specified name, the first value is returned. + * + * @param name The name of the header to search + * @param defaultValue default value + * @return The first header value or {@code defaultValue} if there is no such header + */ + String getAndRemove(CharSequence name, String defaultValue); + + /** + * Returns and Removes the integer value of a header with the specified name. If there are + * more than one values for the specified name, the first value is returned. + * + * @param name The name of the header to search + * @return The first header value + * @throws java.util.NoSuchElementException + * if no such header + * @throws NumberFormatException + * if the value of header is not number + */ + int getIntAndRemove(CharSequence name); + + /** + * Returns and Removes the integer value of a header with the specified name. If there are more than one values for + * the specified name, the first value is returned. + * + * @param name The name of the header to search + * @param defaultValue default value + * @return The first header value or {@code defaultValue} if there is no such header or the value of header is not + * number + */ + int getIntAndRemove(CharSequence name, int defaultValue); + + /** + * Returns and Removes the long value of a header with the specified name. If there are + * more than one values for the specified name, the first value is returned. + * + * @param name The name of the header to search + * @return The first header value + * @throws java.util.NoSuchElementException + * if no such header + * @throws NumberFormatException + * if the value of header is not number + */ + long getLongAndRemove(CharSequence name); + + /** + * Returns and Removes the long value of a header with the specified name. If there are more than one values for + * the specified name, the first value is returned. + * + * @param name The name of the header to search + * @param defaultValue default value + * @return The first header value or {@code defaultValue} if there is no such header or the value of header is not + * number + */ + long getLongAndRemove(CharSequence name, long defaultValue); + + /** + * Returns and Removes the millisecond value of a header with the specified name. If there are + * more than one values for the specified name, the first value is returned. + * + * @param name The name of the header to search + * @return The first header value + * @throws java.util.NoSuchElementException + * if no such header + */ + long getTimeMillisAndRemove(CharSequence name); + + /** + * Returns and Removes the millisecond value of a header with the specified name. If there are more than one values + * for the specified name, the first value is returned. + * + * @param name The name of the header to search + * @param defaultValue default value + * @return The first header value or {@code defaultValue} if there is no such header + */ + long getTimeMillisAndRemove(CharSequence name, long defaultValue); + /** * Returns the value of a header with the specified name. If there are * more than one values for the specified name, the first value is returned. @@ -57,6 +145,15 @@ public interface TextHeaders extends Iterable> { */ CharSequence getUnconverted(CharSequence name); + /** + * Returns and Removes the value of a header with the specified name. If there are + * more than one values for the specified name, the first value is returned. + * + * @param name The name of the header to search + * @return The first header value or {@code null} if there is no such header + */ + CharSequence getUnconvertedAndRemove(CharSequence name); + /** * Returns the values of headers with the specified name * @@ -73,6 +170,22 @@ public interface TextHeaders extends Iterable> { */ List getAllUnconverted(CharSequence name); + /** + * Returns and Removes the values of headers with the specified name + * + * @param name The name of the headers to search + * @return A {@link List} of header values which will be empty if no values are found + */ + List getAllAndRemove(CharSequence name); + + /** + * Returns and Removes the values of headers with the specified name + * + * @param name The name of the headers to search + * @return A {@link List} of header values which will be empty if no values are found + */ + List getAllUnconvertedAndRemove(CharSequence name); + /** * Returns a new {@link List} that contains all headers in this object. Note that modifying the * returned {@link List} will not affect the state of this object. If you intend to enumerate over the header