public HeadersEncoder(int maxHeaderTableSize) { encoder = new Encoder(maxHeaderTableSize); }
public void encode(HttpMessage message, OutputStream out) throws IOException { String value = getMethod(message); if (value != null) { encoder.encodeHeader(out, Http2Header.METHOD.getName().getBytes(US_ASCII_CHARSET), value.getBytes(US_ASCII_CHARSET), encoder.encodeHeader(out, Http2Header.PATH.getName().getBytes(US_ASCII_CHARSET), value.getBytes(US_ASCII_CHARSET), encoder.encodeHeader(out, Http2Header.STATUS.getName().getBytes(US_ASCII_CHARSET), Integer.toString(((HttpResponse)message).getStatus().code()).getBytes(US_ASCII_CHARSET), encoder.encodeHeader(out, name.getBytes(US_ASCII_CHARSET), message.getHeaders().get(name).getBytes(US_ASCII_CHARSET),
int nameIndex = getNameIndex(name); encodeLiteral(out, name, value, IndexType.NEVER, nameIndex); return; if (staticTableIndex == -1) { int nameIndex = StaticTable.getIndex(name); encodeLiteral(out, name, value, IndexType.NONE, nameIndex); } else { encodeInteger(out, 0x80, 7, staticTableIndex); int nameIndex = getNameIndex(name); encodeLiteral(out, name, value, IndexType.NONE, nameIndex); return; HeaderEntry headerField = getEntry(name, value); if (headerField != null) { int index = getIndex(headerField.index) + StaticTable.length; encodeInteger(out, 0x80, 7, index); } else { int staticTableIndex = StaticTable.getIndex(name, value); if (staticTableIndex != -1) { encodeInteger(out, 0x80, 7, staticTableIndex); } else { int nameIndex = getNameIndex(name); if (useIndexing) { ensureCapacity(headerSize);
private byte[] getSerializedHeaders(List<Header> headers, boolean sensitive) throws IOException { Encoder encoder = new Encoder(4096); ByteArrayOutputStream outputStream = size.newOutputStream(); for (int i = 0; i < headers.size(); ++i) { Header header = headers.get(i); encoder.encodeHeader(outputStream, header.name, header.value, sensitive); } return outputStream.toByteArray(); } }
/** * Add the header field to the dynamic table. * Entries are evicted from the dynamic table until the size of the table * and the new header field is less than the table's capacity. * If the size of the new entry is larger than the table's capacity, * the dynamic table will be cleared. */ private void add(byte[] name, byte[] value) { int headerSize = HeaderField.sizeOf(name, value); // Clear the table if the header field size is larger than the capacity. if (headerSize > capacity) { clear(); return; } // Evict oldest entries until we have enough capacity. while (size + headerSize > capacity) { remove(); } // Copy name and value that modifications of original do not affect the dynamic table. name = Arrays.copyOf(name, name.length); value = Arrays.copyOf(value, value.length); int h = hash(name); int i = index(h); HeaderEntry old = headerFields[i]; HeaderEntry e = new HeaderEntry(h, name, value, head.before.index - 1, old); headerFields[i] = e; e.addBefore(head); size += headerSize; }
encoder.setMaxHeaderTableSize(out, maxHeaderTableSize); if (allowableHeaderTableSize != encoder.getMaxHeaderTableSize()) { encoder.setMaxHeaderTableSize(out, allowableHeaderTableSize); for (String crumb : value.split(";")) { byte[] valueBytes = crumb.trim().getBytes(StandardCharsets.UTF_8); encoder.encodeHeader(out, COOKIE, valueBytes, true); encoder.encodeHeader(out, nameBytes, EMPTY, false); } else { for (String value : values) { byte[] valueBytes = value.getBytes(StandardCharsets.UTF_8); encoder.encodeHeader(out, nameBytes, valueBytes, false);
/** * Set the maximum table size. */ public void setMaxHeaderTableSize(OutputStream out, int maxHeaderTableSize) throws IOException { if (maxHeaderTableSize < 0) { throw new IllegalArgumentException("Illegal Capacity: " + maxHeaderTableSize); } if (capacity == maxHeaderTableSize) { return; } capacity = maxHeaderTableSize; ensureCapacity(0); encodeInteger(out, 0x20, 5, maxHeaderTableSize); }
/** * Encode literal header field according to Section 6.2. */ private void encodeLiteral(OutputStream out, byte[] name, byte[] value, IndexType indexType, int nameIndex) throws IOException { int mask; int prefixBits; switch(indexType) { case INCREMENTAL: mask = 0x40; prefixBits = 6; break; case NONE: mask = 0x00; prefixBits = 4; break; case NEVER: mask = 0x10; prefixBits = 4; break; default: throw new IllegalStateException("should not reach here"); } encodeInteger(out, mask, prefixBits, nameIndex == -1 ? 0 : nameIndex); if (nameIndex == -1) { encodeStringLiteral(out, name); } encodeStringLiteral(out, value); }
/** * Encode string literal according to Section 5.2. */ private void encodeStringLiteral(OutputStream out, byte[] string) throws IOException { int huffmanLength = Huffman.ENCODER.getEncodedLength(string); if ((huffmanLength < string.length && !forceHuffmanOff) || forceHuffmanOn) { encodeInteger(out, 0x80, 7, huffmanLength); Huffman.ENCODER.encode(out, string); } else { encodeInteger(out, 0x00, 7, string.length); out.write(string, 0, string.length); } }
int nameIndex = getNameIndex(name); encodeLiteral(out, name, value, IndexType.NEVER, nameIndex); return; if (staticTableIndex == -1) { int nameIndex = StaticTable.getIndex(name); encodeLiteral(out, name, value, IndexType.NONE, nameIndex); } else { encodeInteger(out, 0x80, 7, staticTableIndex); int nameIndex = getNameIndex(name); encodeLiteral(out, name, value, IndexType.NONE, nameIndex); return; HeaderEntry headerField = getEntry(name, value); if (headerField != null) { int index = getIndex(headerField.index) + StaticTable.length; encodeInteger(out, 0x80, 7, index); } else { int staticTableIndex = StaticTable.getIndex(name, value); if (staticTableIndex != -1) { encodeInteger(out, 0x80, 7, staticTableIndex); } else { int nameIndex = getNameIndex(name); if (useIndexing) { ensureCapacity(headerSize);
@Benchmark @BenchmarkMode(Mode.Throughput) public void encode(Blackhole bh) throws IOException { Encoder encoder = new Encoder(maxTableSize); outputStream.reset(); if (duplicates) { // If duplicates is set, re-add the same header each time. Header header = headers.get(0); for (int i = 0; i < headers.size(); ++i) { encoder.encodeHeader(outputStream, header.name, header.value, sensitive); } } else { for (int i = 0; i < headers.size(); ++i) { Header header = headers.get(i); encoder.encodeHeader(outputStream, header.name, header.value, sensitive); } } bh.consume(outputStream); } }
/** * Add the header field to the dynamic table. * Entries are evicted from the dynamic table until the size of the table * and the new header field is less than the table's capacity. * If the size of the new entry is larger than the table's capacity, * the dynamic table will be cleared. */ private void add(byte[] name, byte[] value) { int headerSize = HeaderField.sizeOf(name, value); // Clear the table if the header field size is larger than the capacity. if (headerSize > capacity) { clear(); return; } // Evict oldest entries until we have enough capacity. while (size + headerSize > capacity) { remove(); } // Copy name and value that modifications of original do not affect the dynamic table. name = Arrays.copyOf(name, name.length); value = Arrays.copyOf(value, value.length); int h = hash(name); int i = index(h); HeaderEntry old = headerFields[i]; HeaderEntry e = new HeaderEntry(h, name, value, head.before.index - 1, old); headerFields[i] = e; e.addBefore(head); size += headerSize; }
/** * Set the maximum table size. */ public void setMaxHeaderTableSize(OutputStream out, int maxHeaderTableSize) throws IOException { if (maxHeaderTableSize < 0) { throw new IllegalArgumentException("Illegal Capacity: " + maxHeaderTableSize); } if (capacity == maxHeaderTableSize) { return; } capacity = maxHeaderTableSize; ensureCapacity(0); encodeInteger(out, 0x20, 5, maxHeaderTableSize); }
/** * Encode literal header field according to Section 6.2. */ private void encodeLiteral(OutputStream out, byte[] name, byte[] value, IndexType indexType, int nameIndex) throws IOException { int mask; int prefixBits; switch(indexType) { case INCREMENTAL: mask = 0x40; prefixBits = 6; break; case NONE: mask = 0x00; prefixBits = 4; break; case NEVER: mask = 0x10; prefixBits = 4; break; default: throw new IllegalStateException("should not reach here"); } encodeInteger(out, mask, prefixBits, nameIndex == -1 ? 0 : nameIndex); if (nameIndex == -1) { encodeStringLiteral(out, name); } encodeStringLiteral(out, value); }
/** * Encode string literal according to Section 5.2. */ private void encodeStringLiteral(OutputStream out, byte[] string) throws IOException { int huffmanLength = Huffman.ENCODER.getEncodedLength(string); if ((huffmanLength < string.length && !forceHuffmanOff) || forceHuffmanOn) { encodeInteger(out, 0x80, 7, huffmanLength); Huffman.ENCODER.encode(out, string); } else { encodeInteger(out, 0x00, 7, string.length); out.write(string, 0, string.length); } }
/** * Create a new instance. */ public HttpHeaderBlockEncoder(int maxHeaderTableSize) { encoderMaxHeaderTableSize = maxHeaderTableSize; decoderMaxHeaderTableSize = maxHeaderTableSize; this.maxHeaderTableSize = maxHeaderTableSize; encoder = new Encoder(maxHeaderTableSize); }