Copy http2-hpack files into http3-qpack.

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2021-02-03 12:03:30 +11:00 committed by Simone Bordet
parent 4b6bcca529
commit ee042b173a
55 changed files with 136545 additions and 1 deletions

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-parent</artifactId>
<version>10.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>http3-qpack</artifactId>
<name>Jetty :: HTTP3 :: QPACK</name>
<properties>
<bundle-symbolic-name>${project.groupId}.qpack</bundle-symbolic-name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-Description>Http3 Qpack</Bundle-Description>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder</Provide-Capability>
<_nouses>true</_nouses>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-http-tools</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util-ajax</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,24 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
import org.eclipse.jetty.http.HttpFieldPreEncoder;
module org.eclipse.jetty.http3.qpack
{
exports org.eclipse.jetty.http3.qpack;
requires transitive org.eclipse.jetty.http;
requires org.slf4j;
provides HttpFieldPreEncoder with HpackFieldPreEncoder;
}

View File

@ -0,0 +1,36 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpHeader;
/**
*
*/
public class AuthorityHttpField extends HostPortHttpField
{
public static final String AUTHORITY = HpackContext.STATIC_TABLE[1][0];
public AuthorityHttpField(String authority)
{
super(HttpHeader.C_AUTHORITY, AUTHORITY, authority);
}
@Override
public String toString()
{
return String.format("%s(preparsed h=%s p=%d)", super.toString(), getHost(), getPort());
}
}

View File

@ -0,0 +1,497 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* HPACK - Header Compression for HTTP/2
* <p>This class maintains the compression context for a single HTTP/2
* connection. Specifically it holds the static and dynamic Header Field Tables
* and the associated sizes and limits.
* </p>
* <p>It is compliant with draft 11 of the specification</p>
*/
public class HpackContext
{
public static final Logger LOG = LoggerFactory.getLogger(HpackContext.class);
private static final String EMPTY = "";
public static final String[][] STATIC_TABLE =
{
{null, null},
/* 1 */ {":authority", EMPTY},
/* 2 */ {":method", "GET"},
/* 3 */ {":method", "POST"},
/* 4 */ {":path", "/"},
/* 5 */ {":path", "/index.html"},
/* 6 */ {":scheme", "http"},
/* 7 */ {":scheme", "https"},
/* 8 */ {":status", "200"},
/* 9 */ {":status", "204"},
/* 10 */ {":status", "206"},
/* 11 */ {":status", "304"},
/* 12 */ {":status", "400"},
/* 13 */ {":status", "404"},
/* 14 */ {":status", "500"},
/* 15 */ {"accept-charset", EMPTY},
/* 16 */ {"accept-encoding", "gzip, deflate"},
/* 17 */ {"accept-language", EMPTY},
/* 18 */ {"accept-ranges", EMPTY},
/* 19 */ {"accept", EMPTY},
/* 20 */ {"access-control-allow-origin", EMPTY},
/* 21 */ {"age", EMPTY},
/* 22 */ {"allow", EMPTY},
/* 23 */ {"authorization", EMPTY},
/* 24 */ {"cache-control", EMPTY},
/* 25 */ {"content-disposition", EMPTY},
/* 26 */ {"content-encoding", EMPTY},
/* 27 */ {"content-language", EMPTY},
/* 28 */ {"content-length", EMPTY},
/* 29 */ {"content-location", EMPTY},
/* 30 */ {"content-range", EMPTY},
/* 31 */ {"content-type", EMPTY},
/* 32 */ {"cookie", EMPTY},
/* 33 */ {"date", EMPTY},
/* 34 */ {"etag", EMPTY},
/* 35 */ {"expect", EMPTY},
/* 36 */ {"expires", EMPTY},
/* 37 */ {"from", EMPTY},
/* 38 */ {"host", EMPTY},
/* 39 */ {"if-match", EMPTY},
/* 40 */ {"if-modified-since", EMPTY},
/* 41 */ {"if-none-match", EMPTY},
/* 42 */ {"if-range", EMPTY},
/* 43 */ {"if-unmodified-since", EMPTY},
/* 44 */ {"last-modified", EMPTY},
/* 45 */ {"link", EMPTY},
/* 46 */ {"location", EMPTY},
/* 47 */ {"max-forwards", EMPTY},
/* 48 */ {"proxy-authenticate", EMPTY},
/* 49 */ {"proxy-authorization", EMPTY},
/* 50 */ {"range", EMPTY},
/* 51 */ {"referer", EMPTY},
/* 52 */ {"refresh", EMPTY},
/* 53 */ {"retry-after", EMPTY},
/* 54 */ {"server", EMPTY},
/* 55 */ {"set-cookie", EMPTY},
/* 56 */ {"strict-transport-security", EMPTY},
/* 57 */ {"transfer-encoding", EMPTY},
/* 58 */ {"user-agent", EMPTY},
/* 59 */ {"vary", EMPTY},
/* 60 */ {"via", EMPTY},
/* 61 */ {"www-authenticate", EMPTY}
};
private static final Map<HttpField, Entry> __staticFieldMap = new HashMap<>();
private static final Index<StaticEntry> __staticNameMap;
private static final StaticEntry[] __staticTableByHeader = new StaticEntry[HttpHeader.values().length];
private static final StaticEntry[] __staticTable = new StaticEntry[STATIC_TABLE.length];
public static final int STATIC_SIZE = STATIC_TABLE.length - 1;
static
{
Index.Builder<StaticEntry> staticNameMapBuilder = new Index.Builder<StaticEntry>().caseSensitive(false);
Set<String> added = new HashSet<>();
for (int i = 1; i < STATIC_TABLE.length; i++)
{
StaticEntry entry = null;
String name = STATIC_TABLE[i][0];
String value = STATIC_TABLE[i][1];
HttpHeader header = HttpHeader.CACHE.get(name);
if (header != null && value != null)
{
switch (header)
{
case C_METHOD:
{
HttpMethod method = HttpMethod.CACHE.get(value);
if (method != null)
entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, method));
break;
}
case C_SCHEME:
{
HttpScheme scheme = HttpScheme.CACHE.get(value);
if (scheme != null)
entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, scheme));
break;
}
case C_STATUS:
{
entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, value));
break;
}
default:
break;
}
}
if (entry == null)
entry = new StaticEntry(i, header == null ? new HttpField(STATIC_TABLE[i][0], value) : new HttpField(header, name, value));
__staticTable[i] = entry;
if (entry._field.getValue() != null)
__staticFieldMap.put(entry._field, entry);
if (!added.contains(entry._field.getName()))
{
added.add(entry._field.getName());
staticNameMapBuilder.with(entry._field.getName(), entry);
}
}
__staticNameMap = staticNameMapBuilder.build();
for (HttpHeader h : HttpHeader.values())
{
StaticEntry entry = __staticNameMap.get(h.asString());
if (entry != null)
__staticTableByHeader[h.ordinal()] = entry;
}
}
private int _maxDynamicTableSizeInBytes;
private int _dynamicTableSizeInBytes;
private final DynamicTable _dynamicTable;
private final Map<HttpField, Entry> _fieldMap = new HashMap<>();
private final Map<String, Entry> _nameMap = new HashMap<>();
HpackContext(int maxDynamicTableSize)
{
_maxDynamicTableSizeInBytes = maxDynamicTableSize;
int guesstimateEntries = 10 + maxDynamicTableSize / (32 + 10 + 10);
_dynamicTable = new DynamicTable(guesstimateEntries);
if (LOG.isDebugEnabled())
LOG.debug(String.format("HdrTbl[%x] created max=%d", hashCode(), maxDynamicTableSize));
}
public void resize(int newMaxDynamicTableSize)
{
if (LOG.isDebugEnabled())
LOG.debug(String.format("HdrTbl[%x] resized max=%d->%d", hashCode(), _maxDynamicTableSizeInBytes, newMaxDynamicTableSize));
_maxDynamicTableSizeInBytes = newMaxDynamicTableSize;
_dynamicTable.evict();
}
public Entry get(HttpField field)
{
Entry entry = _fieldMap.get(field);
if (entry == null)
entry = __staticFieldMap.get(field);
return entry;
}
public Entry get(String name)
{
Entry entry = __staticNameMap.get(name);
if (entry != null)
return entry;
return _nameMap.get(StringUtil.asciiToLowerCase(name));
}
public Entry get(int index)
{
if (index <= STATIC_SIZE)
return __staticTable[index];
return _dynamicTable.get(index);
}
public Entry get(HttpHeader header)
{
Entry e = __staticTableByHeader[header.ordinal()];
if (e == null)
return get(header.asString());
return e;
}
public static Entry getStatic(HttpHeader header)
{
return __staticTableByHeader[header.ordinal()];
}
public Entry add(HttpField field)
{
Entry entry = new Entry(field);
int size = entry.getSize();
if (size > _maxDynamicTableSizeInBytes)
{
if (LOG.isDebugEnabled())
LOG.debug(String.format("HdrTbl[%x] !added size %d>%d", hashCode(), size, _maxDynamicTableSizeInBytes));
_dynamicTable.evictAll();
return null;
}
_dynamicTableSizeInBytes += size;
_dynamicTable.add(entry);
_fieldMap.put(field, entry);
_nameMap.put(field.getLowerCaseName(), entry);
if (LOG.isDebugEnabled())
LOG.debug(String.format("HdrTbl[%x] added %s", hashCode(), entry));
_dynamicTable.evict();
return entry;
}
/**
* @return Current dynamic table size in entries
*/
public int size()
{
return _dynamicTable.size();
}
/**
* @return Current Dynamic table size in Octets
*/
public int getDynamicTableSize()
{
return _dynamicTableSizeInBytes;
}
/**
* @return Max Dynamic table size in Octets
*/
public int getMaxDynamicTableSize()
{
return _maxDynamicTableSizeInBytes;
}
public int index(Entry entry)
{
if (entry._slot < 0)
return 0;
if (entry.isStatic())
return entry._slot;
return _dynamicTable.index(entry);
}
public static int staticIndex(HttpHeader header)
{
if (header == null)
return 0;
Entry entry = __staticNameMap.get(header.asString());
if (entry == null)
return 0;
return entry._slot;
}
@Override
public String toString()
{
return String.format("HpackContext@%x{entries=%d,size=%d,max=%d}", hashCode(), _dynamicTable.size(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes);
}
private class DynamicTable
{
Entry[] _entries;
int _size;
int _offset;
int _growby;
private DynamicTable(int initCapacity)
{
_entries = new Entry[initCapacity];
_growby = initCapacity;
}
public void add(Entry entry)
{
if (_size == _entries.length)
{
Entry[] entries = new Entry[_entries.length + _growby];
for (int i = 0; i < _size; i++)
{
int slot = (_offset + i) % _entries.length;
entries[i] = _entries[slot];
entries[i]._slot = i;
}
_entries = entries;
_offset = 0;
}
int slot = (_size++ + _offset) % _entries.length;
_entries[slot] = entry;
entry._slot = slot;
}
public int index(Entry entry)
{
return STATIC_SIZE + _size - (entry._slot - _offset + _entries.length) % _entries.length;
}
public Entry get(int index)
{
int d = index - STATIC_SIZE - 1;
if (d < 0 || d >= _size)
return null;
int slot = (_offset + _size - d - 1) % _entries.length;
return _entries[slot];
}
public int size()
{
return _size;
}
private void evict()
{
while (_dynamicTableSizeInBytes > _maxDynamicTableSizeInBytes)
{
Entry entry = _entries[_offset];
_entries[_offset] = null;
_offset = (_offset + 1) % _entries.length;
_size--;
if (LOG.isDebugEnabled())
LOG.debug(String.format("HdrTbl[%x] evict %s", HpackContext.this.hashCode(), entry));
_dynamicTableSizeInBytes -= entry.getSize();
entry._slot = -1;
_fieldMap.remove(entry.getHttpField());
String lc = entry.getHttpField().getLowerCaseName();
if (entry == _nameMap.get(lc))
_nameMap.remove(lc);
}
if (LOG.isDebugEnabled())
LOG.debug(String.format("HdrTbl[%x] entries=%d, size=%d, max=%d", HpackContext.this.hashCode(), _dynamicTable.size(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes));
}
private void evictAll()
{
if (LOG.isDebugEnabled())
LOG.debug(String.format("HdrTbl[%x] evictAll", HpackContext.this.hashCode()));
if (size() > 0)
{
_fieldMap.clear();
_nameMap.clear();
_offset = 0;
_size = 0;
_dynamicTableSizeInBytes = 0;
Arrays.fill(_entries, null);
}
}
}
public static class Entry
{
final HttpField _field;
int _slot; // The index within it's array
Entry()
{
_slot = -1;
_field = null;
}
Entry(HttpField field)
{
_field = field;
}
public int getSize()
{
String value = _field.getValue();
return 32 + _field.getName().length() + (value == null ? 0 : value.length());
}
public HttpField getHttpField()
{
return _field;
}
public boolean isStatic()
{
return false;
}
public byte[] getStaticHuffmanValue()
{
return null;
}
@Override
public String toString()
{
return String.format("{%s,%d,%s,%x}", isStatic() ? "S" : "D", _slot, _field, hashCode());
}
}
public static class StaticEntry extends Entry
{
private final byte[] _huffmanValue;
private final byte _encodedField;
StaticEntry(int index, HttpField field)
{
super(field);
_slot = index;
String value = field.getValue();
if (value != null && value.length() > 0)
{
int huffmanLen = Huffman.octetsNeeded(value);
if (huffmanLen < 0)
throw new IllegalStateException("bad value");
int lenLen = NBitInteger.octectsNeeded(7, huffmanLen);
_huffmanValue = new byte[1 + lenLen + huffmanLen];
ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue);
// Indicate Huffman
buffer.put((byte)0x80);
// Add huffman length
NBitInteger.encode(buffer, 7, huffmanLen);
// Encode value
Huffman.encode(buffer, value);
}
else
_huffmanValue = null;
_encodedField = (byte)(0x80 | index);
}
@Override
public boolean isStatic()
{
return true;
}
@Override
public byte[] getStaticHuffmanValue()
{
return _huffmanValue;
}
public byte getEncodedField()
{
return _encodedField;
}
}
}

View File

@ -0,0 +1,285 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpTokens;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http3.qpack.HpackContext.Entry;
import org.eclipse.jetty.util.BufferUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Hpack Decoder
* <p>This is not thread safe and may only be called by 1 thread at a time.</p>
*/
public class HpackDecoder
{
public static final Logger LOG = LoggerFactory.getLogger(HpackDecoder.class);
public static final HttpField.LongValueHttpField CONTENT_LENGTH_0 =
new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH, 0L);
private final HpackContext _context;
private final MetaDataBuilder _builder;
private int _localMaxDynamicTableSize;
/**
* @param localMaxDynamicTableSize The maximum allowed size of the local dynamic header field table.
* @param maxHeaderSize The maximum allowed size of a headers block, expressed as total of all name and value characters, plus 32 per field
*/
public HpackDecoder(int localMaxDynamicTableSize, int maxHeaderSize)
{
_context = new HpackContext(localMaxDynamicTableSize);
_localMaxDynamicTableSize = localMaxDynamicTableSize;
_builder = new MetaDataBuilder(maxHeaderSize);
}
public HpackContext getHpackContext()
{
return _context;
}
public void setLocalMaxDynamicTableSize(int localMaxdynamciTableSize)
{
_localMaxDynamicTableSize = localMaxdynamciTableSize;
}
public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException, HpackException.StreamException
{
if (LOG.isDebugEnabled())
LOG.debug(String.format("CtxTbl[%x] decoding %d octets", _context.hashCode(), buffer.remaining()));
// If the buffer is big, don't even think about decoding it
if (buffer.remaining() > _builder.getMaxSize())
throw new HpackException.SessionException("431 Request Header Fields too large");
boolean emitted = false;
while (buffer.hasRemaining())
{
if (LOG.isDebugEnabled())
LOG.debug("decode {}", BufferUtil.toHexString(buffer));
byte b = buffer.get();
if (b < 0)
{
// 7.1 indexed if the high bit is set
int index = NBitInteger.decode(buffer, 7);
Entry entry = _context.get(index);
if (entry == null)
throw new HpackException.SessionException("Unknown index %d", index);
if (entry.isStatic())
{
if (LOG.isDebugEnabled())
LOG.debug("decode IdxStatic {}", entry);
// emit field
emitted = true;
_builder.emit(entry.getHttpField());
// TODO copy and add to reference set if there is room
// _context.add(entry.getHttpField());
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("decode Idx {}", entry);
// emit
emitted = true;
_builder.emit(entry.getHttpField());
}
}
else
{
// look at the first nibble in detail
byte f = (byte)((b & 0xF0) >> 4);
String name;
HttpHeader header;
String value;
boolean indexed;
int nameIndex;
switch (f)
{
case 2: // 7.3
case 3: // 7.3
// change table size
int size = NBitInteger.decode(buffer, 5);
if (LOG.isDebugEnabled())
LOG.debug("decode resize={}", size);
if (size > _localMaxDynamicTableSize)
throw new IllegalArgumentException();
if (emitted)
throw new HpackException.CompressionException("Dynamic table resize after fields");
_context.resize(size);
continue;
case 0: // 7.2.2
case 1: // 7.2.3
indexed = false;
nameIndex = NBitInteger.decode(buffer, 4);
break;
case 4: // 7.2.1
case 5: // 7.2.1
case 6: // 7.2.1
case 7: // 7.2.1
indexed = true;
nameIndex = NBitInteger.decode(buffer, 6);
break;
default:
throw new IllegalStateException();
}
boolean huffmanName = false;
// decode the name
if (nameIndex > 0)
{
Entry nameEntry = _context.get(nameIndex);
name = nameEntry.getHttpField().getName();
header = nameEntry.getHttpField().getHeader();
}
else
{
huffmanName = (buffer.get() & 0x80) == 0x80;
int length = NBitInteger.decode(buffer, 7);
_builder.checkSize(length, huffmanName);
if (huffmanName)
name = Huffman.decode(buffer, length);
else
name = toASCIIString(buffer, length);
check:
for (int i = name.length(); i-- > 0; )
{
char c = name.charAt(i);
if (c > 0xff)
{
_builder.streamException("Illegal header name %s", name);
break;
}
HttpTokens.Token token = HttpTokens.TOKENS[0xFF & c];
switch (token.getType())
{
case ALPHA:
if (c >= 'A' && c <= 'Z')
{
_builder.streamException("Uppercase header name %s", name);
break check;
}
break;
case COLON:
case TCHAR:
case DIGIT:
break;
default:
_builder.streamException("Illegal header name %s", name);
break check;
}
}
header = HttpHeader.CACHE.get(name);
}
// decode the value
boolean huffmanValue = (buffer.get() & 0x80) == 0x80;
int length = NBitInteger.decode(buffer, 7);
_builder.checkSize(length, huffmanValue);
if (huffmanValue)
value = Huffman.decode(buffer, length);
else
value = toASCIIString(buffer, length);
// Make the new field
HttpField field;
if (header == null)
{
// just make a normal field and bypass header name lookup
field = new HttpField(null, name, value);
}
else
{
// might be worthwhile to create a value HttpField if it is indexed
// and/or of a type that may be looked up multiple times.
switch (header)
{
case C_STATUS:
if (indexed)
field = new HttpField.IntValueHttpField(header, name, value);
else
field = new HttpField(header, name, value);
break;
case C_AUTHORITY:
field = new AuthorityHttpField(value);
break;
case CONTENT_LENGTH:
if ("0".equals(value))
field = CONTENT_LENGTH_0;
else
field = new HttpField.LongValueHttpField(header, name, value);
break;
default:
field = new HttpField(header, name, value);
break;
}
}
if (LOG.isDebugEnabled())
{
LOG.debug("decoded '{}' by {}/{}/{}",
field,
nameIndex > 0 ? "IdxName" : (huffmanName ? "HuffName" : "LitName"),
huffmanValue ? "HuffVal" : "LitVal",
indexed ? "Idx" : "");
}
// emit the field
emitted = true;
_builder.emit(field);
// if indexed add to dynamic table
if (indexed)
_context.add(field);
}
}
return _builder.build();
}
public static String toASCIIString(ByteBuffer buffer, int length)
{
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; ++i)
{
builder.append((char)(0x7F & buffer.get()));
}
return builder.toString();
}
@Override
public String toString()
{
return String.format("HpackDecoder@%x{%s}", hashCode(), _context);
}
}

View File

@ -0,0 +1,493 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.http3.qpack.HpackContext.Entry;
import org.eclipse.jetty.http3.qpack.HpackContext.StaticEntry;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HpackEncoder
{
private static final Logger LOG = LoggerFactory.getLogger(HpackEncoder.class);
private static final HttpField[] STATUSES = new HttpField[599];
static final EnumSet<HttpHeader> DO_NOT_HUFFMAN =
EnumSet.of(
HttpHeader.AUTHORIZATION,
HttpHeader.CONTENT_MD5,
HttpHeader.PROXY_AUTHENTICATE,
HttpHeader.PROXY_AUTHORIZATION);
static final EnumSet<HttpHeader> DO_NOT_INDEX =
EnumSet.of(
// HttpHeader.C_PATH, // TODO more data needed
// HttpHeader.DATE, // TODO more data needed
HttpHeader.AUTHORIZATION,
HttpHeader.CONTENT_MD5,
HttpHeader.CONTENT_RANGE,
HttpHeader.ETAG,
HttpHeader.IF_MODIFIED_SINCE,
HttpHeader.IF_UNMODIFIED_SINCE,
HttpHeader.IF_NONE_MATCH,
HttpHeader.IF_RANGE,
HttpHeader.IF_MATCH,
HttpHeader.LOCATION,
HttpHeader.RANGE,
HttpHeader.RETRY_AFTER,
// HttpHeader.EXPIRES,
HttpHeader.LAST_MODIFIED,
HttpHeader.SET_COOKIE,
HttpHeader.SET_COOKIE2);
static final EnumSet<HttpHeader> NEVER_INDEX =
EnumSet.of(
HttpHeader.AUTHORIZATION,
HttpHeader.SET_COOKIE,
HttpHeader.SET_COOKIE2);
private static final EnumSet<HttpHeader> IGNORED_HEADERS = EnumSet.of(HttpHeader.CONNECTION, HttpHeader.KEEP_ALIVE,
HttpHeader.PROXY_CONNECTION, HttpHeader.TRANSFER_ENCODING, HttpHeader.UPGRADE);
private static final PreEncodedHttpField TE_TRAILERS = new PreEncodedHttpField(HttpHeader.TE, "trailers");
private static final PreEncodedHttpField C_SCHEME_HTTP = new PreEncodedHttpField(HttpHeader.C_SCHEME, "http");
private static final PreEncodedHttpField C_SCHEME_HTTPS = new PreEncodedHttpField(HttpHeader.C_SCHEME, "https");
private static final EnumMap<HttpMethod, PreEncodedHttpField> C_METHODS = new EnumMap<>(HttpMethod.class);
static
{
for (HttpStatus.Code code : HttpStatus.Code.values())
{
STATUSES[code.getCode()] = new PreEncodedHttpField(HttpHeader.C_STATUS, Integer.toString(code.getCode()));
}
for (HttpMethod method : HttpMethod.values())
{
C_METHODS.put(method, new PreEncodedHttpField(HttpHeader.C_METHOD, method.asString()));
}
}
private final HpackContext _context;
private final boolean _debug;
private int _remoteMaxDynamicTableSize;
private int _localMaxDynamicTableSize;
private int _maxHeaderListSize;
private int _headerListSize;
private boolean _validateEncoding = true;
public HpackEncoder()
{
this(4096, 4096, -1);
}
public HpackEncoder(int localMaxDynamicTableSize)
{
this(localMaxDynamicTableSize, 4096, -1);
}
public HpackEncoder(int localMaxDynamicTableSize, int remoteMaxDynamicTableSize)
{
this(localMaxDynamicTableSize, remoteMaxDynamicTableSize, -1);
}
public HpackEncoder(int localMaxDynamicTableSize, int remoteMaxDynamicTableSize, int maxHeaderListSize)
{
_context = new HpackContext(remoteMaxDynamicTableSize);
_remoteMaxDynamicTableSize = remoteMaxDynamicTableSize;
_localMaxDynamicTableSize = localMaxDynamicTableSize;
_maxHeaderListSize = maxHeaderListSize;
_debug = LOG.isDebugEnabled();
}
public int getMaxHeaderListSize()
{
return _maxHeaderListSize;
}
public void setMaxHeaderListSize(int maxHeaderListSize)
{
_maxHeaderListSize = maxHeaderListSize;
}
public HpackContext getHpackContext()
{
return _context;
}
public void setRemoteMaxDynamicTableSize(int remoteMaxDynamicTableSize)
{
_remoteMaxDynamicTableSize = remoteMaxDynamicTableSize;
}
public void setLocalMaxDynamicTableSize(int localMaxDynamicTableSize)
{
_localMaxDynamicTableSize = localMaxDynamicTableSize;
}
public boolean isValidateEncoding()
{
return _validateEncoding;
}
public void setValidateEncoding(boolean validateEncoding)
{
_validateEncoding = validateEncoding;
}
public void encode(ByteBuffer buffer, MetaData metadata) throws HpackException
{
try
{
if (LOG.isDebugEnabled())
LOG.debug(String.format("CtxTbl[%x] encoding", _context.hashCode()));
HttpFields fields = metadata.getFields();
// Verify that we can encode without errors.
if (isValidateEncoding() && fields != null)
{
for (HttpField field : fields)
{
String name = field.getName();
char firstChar = name.charAt(0);
if (firstChar <= ' ' || firstChar == ':')
throw new HpackException.StreamException("Invalid header name: '%s'", name);
}
}
_headerListSize = 0;
int pos = buffer.position();
// Check the dynamic table sizes!
int maxDynamicTableSize = Math.min(_remoteMaxDynamicTableSize, _localMaxDynamicTableSize);
if (maxDynamicTableSize != _context.getMaxDynamicTableSize())
encodeMaxDynamicTableSize(buffer, maxDynamicTableSize);
// Add Request/response meta fields
if (metadata.isRequest())
{
MetaData.Request request = (MetaData.Request)metadata;
String method = request.getMethod();
HttpMethod httpMethod = method == null ? null : HttpMethod.fromString(method);
HttpField methodField = C_METHODS.get(httpMethod);
encode(buffer, methodField == null ? new HttpField(HttpHeader.C_METHOD, method) : methodField);
encode(buffer, new HttpField(HttpHeader.C_AUTHORITY, request.getURI().getAuthority()));
boolean isConnect = HttpMethod.CONNECT.is(request.getMethod());
String protocol = request.getProtocol();
if (!isConnect || protocol != null)
{
String scheme = request.getURI().getScheme();
encode(buffer, HttpScheme.HTTPS.is(scheme) ? C_SCHEME_HTTPS : C_SCHEME_HTTP);
encode(buffer, new HttpField(HttpHeader.C_PATH, request.getURI().getPathQuery()));
if (protocol != null)
encode(buffer,new HttpField(HttpHeader.C_PROTOCOL,protocol));
}
}
else if (metadata.isResponse())
{
MetaData.Response response = (MetaData.Response)metadata;
int code = response.getStatus();
HttpField status = code < STATUSES.length ? STATUSES[code] : null;
if (status == null)
status = new HttpField.IntValueHttpField(HttpHeader.C_STATUS, code);
encode(buffer, status);
}
// Remove fields as specified in RFC 7540, 8.1.2.2.
if (fields != null)
{
// Remove the headers specified in the Connection header,
// for example: Connection: Close, TE, Upgrade, Custom.
Set<String> hopHeaders = null;
for (String value : fields.getCSV(HttpHeader.CONNECTION, false))
{
if (hopHeaders == null)
hopHeaders = new HashSet<>();
hopHeaders.add(StringUtil.asciiToLowerCase(value));
}
boolean contentLengthEncoded = false;
for (HttpField field : fields)
{
HttpHeader header = field.getHeader();
if (header != null && IGNORED_HEADERS.contains(header))
continue;
if (header == HttpHeader.TE)
{
if (field.contains("trailers"))
encode(buffer, TE_TRAILERS);
continue;
}
String name = field.getLowerCaseName();
if (hopHeaders != null && hopHeaders.contains(name))
continue;
if (header == HttpHeader.CONTENT_LENGTH)
contentLengthEncoded = true;
encode(buffer, field);
}
if (!contentLengthEncoded)
{
long contentLength = metadata.getContentLength();
if (contentLength >= 0)
encode(buffer, new HttpField(HttpHeader.CONTENT_LENGTH, String.valueOf(contentLength)));
}
}
// Check size
if (_maxHeaderListSize > 0 && _headerListSize > _maxHeaderListSize)
{
if (LOG.isDebugEnabled())
LOG.warn("Header list size too large {} > {} metadata={}", _headerListSize, _maxHeaderListSize, metadata);
else
LOG.warn("Header list size too large {} > {}", _headerListSize, _maxHeaderListSize);
}
if (LOG.isDebugEnabled())
LOG.debug(String.format("CtxTbl[%x] encoded %d octets", _context.hashCode(), buffer.position() - pos));
}
catch (HpackException x)
{
throw x;
}
catch (Throwable x)
{
HpackException.SessionException failure = new HpackException.SessionException("Could not hpack encode %s", metadata);
failure.initCause(x);
throw failure;
}
}
public void encodeMaxDynamicTableSize(ByteBuffer buffer, int maxDynamicTableSize)
{
if (maxDynamicTableSize > _remoteMaxDynamicTableSize)
throw new IllegalArgumentException();
buffer.put((byte)0x20);
NBitInteger.encode(buffer, 5, maxDynamicTableSize);
_context.resize(maxDynamicTableSize);
}
public void encode(ByteBuffer buffer, HttpField field)
{
if (field.getValue() == null)
field = new HttpField(field.getHeader(), field.getName(), "");
int fieldSize = field.getName().length() + field.getValue().length();
_headerListSize += fieldSize + 32;
String encoding = null;
// Is there an index entry for the field?
Entry entry = _context.get(field);
if (entry != null)
{
// This is a known indexed field, send as static or dynamic indexed.
if (entry.isStatic())
{
buffer.put(((StaticEntry)entry).getEncodedField());
if (_debug)
encoding = "IdxFieldS1";
}
else
{
int index = _context.index(entry);
buffer.put((byte)0x80);
NBitInteger.encode(buffer, 7, index);
if (_debug)
encoding = "IdxField" + (entry.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(7, index));
}
}
else
{
// Unknown field entry, so we will have to send literally, but perhaps add an index.
final boolean indexed;
// Do we know its name?
HttpHeader header = field.getHeader();
// Select encoding strategy
if (header == null)
{
// Select encoding strategy for unknown header names
Entry name = _context.get(field.getName());
if (field instanceof PreEncodedHttpField)
{
int i = buffer.position();
((PreEncodedHttpField)field).putTo(buffer, HttpVersion.HTTP_2);
byte b = buffer.get(i);
indexed = b < 0 || b >= 0x40;
if (_debug)
encoding = indexed ? "PreEncodedIdx" : "PreEncoded";
}
else if (name == null && fieldSize < _context.getMaxDynamicTableSize())
{
// unknown name and value that will fit in dynamic table, so let's index
// this just in case it is the first time we have seen a custom name or a
// custom field. Unless the name is once only, this is worthwhile
indexed = true;
encodeName(buffer, (byte)0x40, 6, field.getName(), null);
encodeValue(buffer, true, field.getValue());
if (_debug)
encoding = "LitHuffNHuffVIdx";
}
else
{
// Known name, but different value.
// This is probably a custom field with changing value, so don't index.
indexed = false;
encodeName(buffer, (byte)0x00, 4, field.getName(), null);
encodeValue(buffer, true, field.getValue());
if (_debug)
encoding = "LitHuffNHuffV!Idx";
}
}
else
{
// Select encoding strategy for known header names
Entry name = _context.get(header);
if (field instanceof PreEncodedHttpField)
{
// Preencoded field
int i = buffer.position();
((PreEncodedHttpField)field).putTo(buffer, HttpVersion.HTTP_2);
byte b = buffer.get(i);
indexed = b < 0 || b >= 0x40;
if (_debug)
encoding = indexed ? "PreEncodedIdx" : "PreEncoded";
}
else if (DO_NOT_INDEX.contains(header))
{
// Non indexed field
indexed = false;
boolean neverIndex = NEVER_INDEX.contains(header);
boolean huffman = !DO_NOT_HUFFMAN.contains(header);
encodeName(buffer, neverIndex ? (byte)0x10 : (byte)0x00, 4, header.asString(), name);
encodeValue(buffer, huffman, field.getValue());
if (_debug)
encoding = "Lit" +
((name == null) ? "HuffN" : ("IdxN" + (name.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(4, _context.index(name))))) +
(huffman ? "HuffV" : "LitV") +
(neverIndex ? "!!Idx" : "!Idx");
}
else if (fieldSize >= _context.getMaxDynamicTableSize() || header == HttpHeader.CONTENT_LENGTH && !"0".equals(field.getValue()))
{
// The field is too large or a non zero content length, so do not index.
indexed = false;
encodeName(buffer, (byte)0x00, 4, header.asString(), name);
encodeValue(buffer, true, field.getValue());
if (_debug)
encoding = "Lit" +
((name == null) ? "HuffN" : "IdxNS" + (1 + NBitInteger.octectsNeeded(4, _context.index(name)))) +
"HuffV!Idx";
}
else
{
// indexed
indexed = true;
boolean huffman = !DO_NOT_HUFFMAN.contains(header);
encodeName(buffer, (byte)0x40, 6, header.asString(), name);
encodeValue(buffer, huffman, field.getValue());
if (_debug)
encoding = ((name == null) ? "LitHuffN" : ("LitIdxN" + (name.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(6, _context.index(name))))) +
(huffman ? "HuffVIdx" : "LitVIdx");
}
}
// If we want the field referenced, then we add it to our table and reference set.
if (indexed)
_context.add(field);
}
if (_debug)
{
if (LOG.isDebugEnabled())
LOG.debug("encode {}:'{}' to '{}'", encoding, field, BufferUtil.toHexString(buffer.duplicate().flip()));
}
}
private void encodeName(ByteBuffer buffer, byte mask, int bits, String name, Entry entry)
{
buffer.put(mask);
if (entry == null)
{
// leave name index bits as 0
// Encode the name always with lowercase huffman
buffer.put((byte)0x80);
NBitInteger.encode(buffer, 7, Huffman.octetsNeededLC(name));
Huffman.encodeLC(buffer, name);
}
else
{
NBitInteger.encode(buffer, bits, _context.index(entry));
}
}
static void encodeValue(ByteBuffer buffer, boolean huffman, String value)
{
if (huffman)
{
// huffman literal value
buffer.put((byte)0x80);
int needed = Huffman.octetsNeeded(value);
if (needed >= 0)
{
NBitInteger.encode(buffer, 7, needed);
Huffman.encode(buffer, value);
}
else
{
// Not iso_8859_1
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
NBitInteger.encode(buffer, 7, Huffman.octetsNeeded(bytes));
Huffman.encode(buffer, bytes);
}
}
else
{
// add literal assuming iso_8859_1
buffer.put((byte)0x00).mark();
NBitInteger.encode(buffer, 7, value.length());
for (int i = 0; i < value.length(); i++)
{
char c = value.charAt(i);
if (c < ' ' || c > 127)
{
// Not iso_8859_1, so re-encode as UTF-8
buffer.reset();
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
NBitInteger.encode(buffer, 7, bytes.length);
buffer.put(bytes, 0, bytes.length);
return;
}
buffer.put((byte)c);
}
}
}
}

View File

@ -0,0 +1,59 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
@SuppressWarnings("serial")
public abstract class HpackException extends Exception
{
HpackException(String messageFormat, Object... args)
{
super(String.format(messageFormat, args));
}
/**
* A Stream HPACK exception.
* <p>Stream exceptions are not fatal to the connection and the
* hpack state is complete and able to continue handling other
* decoding/encoding for the session.
* </p>
*/
public static class StreamException extends HpackException
{
StreamException(String messageFormat, Object... args)
{
super(messageFormat, args);
}
}
/**
* A Session HPACK Exception.
* <p>Session exceptions are fatal for the stream and the HPACK
* state is unable to decode/encode further. </p>
*/
public static class SessionException extends HpackException
{
SessionException(String messageFormat, Object... args)
{
super(messageFormat, args);
}
}
public static class CompressionException extends SessionException
{
public CompressionException(String messageFormat, Object... args)
{
super(messageFormat, args);
}
}
}

View File

@ -0,0 +1,83 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import org.eclipse.jetty.http.HttpFieldPreEncoder;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.util.BufferUtil;
/**
*
*/
public class HpackFieldPreEncoder implements HttpFieldPreEncoder
{
@Override
public HttpVersion getHttpVersion()
{
return HttpVersion.HTTP_2;
}
@Override
public byte[] getEncodedField(HttpHeader header, String name, String value)
{
boolean notIndexed = HpackEncoder.DO_NOT_INDEX.contains(header);
ByteBuffer buffer = BufferUtil.allocate(name.length() + value.length() + 10);
BufferUtil.clearToFill(buffer);
boolean huffman;
int bits;
if (notIndexed)
{
// Non indexed field
boolean neverIndex = HpackEncoder.NEVER_INDEX.contains(header);
huffman = !HpackEncoder.DO_NOT_HUFFMAN.contains(header);
buffer.put(neverIndex ? (byte)0x10 : (byte)0x00);
bits = 4;
}
else if (header == HttpHeader.CONTENT_LENGTH && value.length() > 1)
{
// Non indexed content length for 2 digits or more
buffer.put((byte)0x00);
huffman = true;
bits = 4;
}
else
{
// indexed
buffer.put((byte)0x40);
huffman = !HpackEncoder.DO_NOT_HUFFMAN.contains(header);
bits = 6;
}
int nameIdx = HpackContext.staticIndex(header);
if (nameIdx > 0)
NBitInteger.encode(buffer, bits, nameIdx);
else
{
buffer.put((byte)0x80);
NBitInteger.encode(buffer, 7, Huffman.octetsNeededLC(name));
Huffman.encodeLC(buffer, name);
}
HpackEncoder.encodeValue(buffer, huffman, value);
BufferUtil.flipToFlush(buffer, 0);
return BufferUtil.toArray(buffer);
}
}

View File

@ -0,0 +1,546 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.Utf8StringBuilder;
public class Huffman
{
// Appendix C: Huffman Codes
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C
static final int[][] CODES =
{
/* ( 0) |11111111|11000 */ {0x1ff8, 13},
/* ( 1) |11111111|11111111|1011000 */ {0x7fffd8, 23},
/* ( 2) |11111111|11111111|11111110|0010 */ {0xfffffe2, 28},
/* ( 3) |11111111|11111111|11111110|0011 */ {0xfffffe3, 28},
/* ( 4) |11111111|11111111|11111110|0100 */ {0xfffffe4, 28},
/* ( 5) |11111111|11111111|11111110|0101 */ {0xfffffe5, 28},
/* ( 6) |11111111|11111111|11111110|0110 */ {0xfffffe6, 28},
/* ( 7) |11111111|11111111|11111110|0111 */ {0xfffffe7, 28},
/* ( 8) |11111111|11111111|11111110|1000 */ {0xfffffe8, 28},
/* ( 9) |11111111|11111111|11101010 */ {0xffffea, 24},
/* ( 10) |11111111|11111111|11111111|111100 */ {0x3ffffffc, 30},
/* ( 11) |11111111|11111111|11111110|1001 */ {0xfffffe9, 28},
/* ( 12) |11111111|11111111|11111110|1010 */ {0xfffffea, 28},
/* ( 13) |11111111|11111111|11111111|111101 */ {0x3ffffffd, 30},
/* ( 14) |11111111|11111111|11111110|1011 */ {0xfffffeb, 28},
/* ( 15) |11111111|11111111|11111110|1100 */ {0xfffffec, 28},
/* ( 16) |11111111|11111111|11111110|1101 */ {0xfffffed, 28},
/* ( 17) |11111111|11111111|11111110|1110 */ {0xfffffee, 28},
/* ( 18) |11111111|11111111|11111110|1111 */ {0xfffffef, 28},
/* ( 19) |11111111|11111111|11111111|0000 */ {0xffffff0, 28},
/* ( 20) |11111111|11111111|11111111|0001 */ {0xffffff1, 28},
/* ( 21) |11111111|11111111|11111111|0010 */ {0xffffff2, 28},
/* ( 22) |11111111|11111111|11111111|111110 */ {0x3ffffffe, 30},
/* ( 23) |11111111|11111111|11111111|0011 */ {0xffffff3, 28},
/* ( 24) |11111111|11111111|11111111|0100 */ {0xffffff4, 28},
/* ( 25) |11111111|11111111|11111111|0101 */ {0xffffff5, 28},
/* ( 26) |11111111|11111111|11111111|0110 */ {0xffffff6, 28},
/* ( 27) |11111111|11111111|11111111|0111 */ {0xffffff7, 28},
/* ( 28) |11111111|11111111|11111111|1000 */ {0xffffff8, 28},
/* ( 29) |11111111|11111111|11111111|1001 */ {0xffffff9, 28},
/* ( 30) |11111111|11111111|11111111|1010 */ {0xffffffa, 28},
/* ( 31) |11111111|11111111|11111111|1011 */ {0xffffffb, 28},
/*' ' ( 32) |010100 */ {0x14, 6},
/*'!' ( 33) |11111110|00 */ {0x3f8, 10},
/*'"' ( 34) |11111110|01 */ {0x3f9, 10},
/*'#' ( 35) |11111111|1010 */ {0xffa, 12},
/*'$' ( 36) |11111111|11001 */ {0x1ff9, 13},
/*'%' ( 37) |010101 */ {0x15, 6},
/*'&' ( 38) |11111000 */ {0xf8, 8},
/*''' ( 39) |11111111|010 */ {0x7fa, 11},
/*'(' ( 40) |11111110|10 */ {0x3fa, 10},
/*')' ( 41) |11111110|11 */ {0x3fb, 10},
/*'*' ( 42) |11111001 */ {0xf9, 8},
/*'+' ( 43) |11111111|011 */ {0x7fb, 11},
/*',' ( 44) |11111010 */ {0xfa, 8},
/*'-' ( 45) |010110 */ {0x16, 6},
/*'.' ( 46) |010111 */ {0x17, 6},
/*'/' ( 47) |011000 */ {0x18, 6},
/*'0' ( 48) |00000 */ {0x0, 5},
/*'1' ( 49) |00001 */ {0x1, 5},
/*'2' ( 50) |00010 */ {0x2, 5},
/*'3' ( 51) |011001 */ {0x19, 6},
/*'4' ( 52) |011010 */ {0x1a, 6},
/*'5' ( 53) |011011 */ {0x1b, 6},
/*'6' ( 54) |011100 */ {0x1c, 6},
/*'7' ( 55) |011101 */ {0x1d, 6},
/*'8' ( 56) |011110 */ {0x1e, 6},
/*'9' ( 57) |011111 */ {0x1f, 6},
/*':' ( 58) |1011100 */ {0x5c, 7},
/*';' ( 59) |11111011 */ {0xfb, 8},
/*'<' ( 60) |11111111|1111100 */ {0x7ffc, 15},
/*'=' ( 61) |100000 */ {0x20, 6},
/*'>' ( 62) |11111111|1011 */ {0xffb, 12},
/*'?' ( 63) |11111111|00 */ {0x3fc, 10},
/*'@' ( 64) |11111111|11010 */ {0x1ffa, 13},
/*'A' ( 65) |100001 */ {0x21, 6},
/*'B' ( 66) |1011101 */ {0x5d, 7},
/*'C' ( 67) |1011110 */ {0x5e, 7},
/*'D' ( 68) |1011111 */ {0x5f, 7},
/*'E' ( 69) |1100000 */ {0x60, 7},
/*'F' ( 70) |1100001 */ {0x61, 7},
/*'G' ( 71) |1100010 */ {0x62, 7},
/*'H' ( 72) |1100011 */ {0x63, 7},
/*'I' ( 73) |1100100 */ {0x64, 7},
/*'J' ( 74) |1100101 */ {0x65, 7},
/*'K' ( 75) |1100110 */ {0x66, 7},
/*'L' ( 76) |1100111 */ {0x67, 7},
/*'M' ( 77) |1101000 */ {0x68, 7},
/*'N' ( 78) |1101001 */ {0x69, 7},
/*'O' ( 79) |1101010 */ {0x6a, 7},
/*'P' ( 80) |1101011 */ {0x6b, 7},
/*'Q' ( 81) |1101100 */ {0x6c, 7},
/*'R' ( 82) |1101101 */ {0x6d, 7},
/*'S' ( 83) |1101110 */ {0x6e, 7},
/*'T' ( 84) |1101111 */ {0x6f, 7},
/*'U' ( 85) |1110000 */ {0x70, 7},
/*'V' ( 86) |1110001 */ {0x71, 7},
/*'W' ( 87) |1110010 */ {0x72, 7},
/*'X' ( 88) |11111100 */ {0xfc, 8},
/*'Y' ( 89) |1110011 */ {0x73, 7},
/*'Z' ( 90) |11111101 */ {0xfd, 8},
/*'[' ( 91) |11111111|11011 */ {0x1ffb, 13},
/*'\' ( 92) |11111111|11111110|000 */ {0x7fff0, 19},
/*']' ( 93) |11111111|11100 */ {0x1ffc, 13},
/*'^' ( 94) |11111111|111100 */ {0x3ffc, 14},
/*'_' ( 95) |100010 */ {0x22, 6},
/*'`' ( 96) |11111111|1111101 */ {0x7ffd, 15},
/*'a' ( 97) |00011 */ {0x3, 5},
/*'b' ( 98) |100011 */ {0x23, 6},
/*'c' ( 99) |00100 */ {0x4, 5},
/*'d' (100) |100100 */ {0x24, 6},
/*'e' (101) |00101 */ {0x5, 5},
/*'f' (102) |100101 */ {0x25, 6},
/*'g' (103) |100110 */ {0x26, 6},
/*'h' (104) |100111 */ {0x27, 6},
/*'i' (105) |00110 */ {0x6, 5},
/*'j' (106) |1110100 */ {0x74, 7},
/*'k' (107) |1110101 */ {0x75, 7},
/*'l' (108) |101000 */ {0x28, 6},
/*'m' (109) |101001 */ {0x29, 6},
/*'n' (110) |101010 */ {0x2a, 6},
/*'o' (111) |00111 */ {0x7, 5},
/*'p' (112) |101011 */ {0x2b, 6},
/*'q' (113) |1110110 */ {0x76, 7},
/*'r' (114) |101100 */ {0x2c, 6},
/*'s' (115) |01000 */ {0x8, 5},
/*'t' (116) |01001 */ {0x9, 5},
/*'u' (117) |101101 */ {0x2d, 6},
/*'v' (118) |1110111 */ {0x77, 7},
/*'w' (119) |1111000 */ {0x78, 7},
/*'x' (120) |1111001 */ {0x79, 7},
/*'y' (121) |1111010 */ {0x7a, 7},
/*'z' (122) |1111011 */ {0x7b, 7},
/*'{' (123) |11111111|1111110 */ {0x7ffe, 15},
/*'|' (124) |11111111|100 */ {0x7fc, 11},
/*'}' (125) |11111111|111101 */ {0x3ffd, 14},
/*'~' (126) |11111111|11101 */ {0x1ffd, 13},
/* (127) |11111111|11111111|11111111|1100 */ {0xffffffc, 28},
/* (128) |11111111|11111110|0110 */ {0xfffe6, 20},
/* (129) |11111111|11111111|010010 */ {0x3fffd2, 22},
/* (130) |11111111|11111110|0111 */ {0xfffe7, 20},
/* (131) |11111111|11111110|1000 */ {0xfffe8, 20},
/* (132) |11111111|11111111|010011 */ {0x3fffd3, 22},
/* (133) |11111111|11111111|010100 */ {0x3fffd4, 22},
/* (134) |11111111|11111111|010101 */ {0x3fffd5, 22},
/* (135) |11111111|11111111|1011001 */ {0x7fffd9, 23},
/* (136) |11111111|11111111|010110 */ {0x3fffd6, 22},
/* (137) |11111111|11111111|1011010 */ {0x7fffda, 23},
/* (138) |11111111|11111111|1011011 */ {0x7fffdb, 23},
/* (139) |11111111|11111111|1011100 */ {0x7fffdc, 23},
/* (140) |11111111|11111111|1011101 */ {0x7fffdd, 23},
/* (141) |11111111|11111111|1011110 */ {0x7fffde, 23},
/* (142) |11111111|11111111|11101011 */ {0xffffeb, 24},
/* (143) |11111111|11111111|1011111 */ {0x7fffdf, 23},
/* (144) |11111111|11111111|11101100 */ {0xffffec, 24},
/* (145) |11111111|11111111|11101101 */ {0xffffed, 24},
/* (146) |11111111|11111111|010111 */ {0x3fffd7, 22},
/* (147) |11111111|11111111|1100000 */ {0x7fffe0, 23},
/* (148) |11111111|11111111|11101110 */ {0xffffee, 24},
/* (149) |11111111|11111111|1100001 */ {0x7fffe1, 23},
/* (150) |11111111|11111111|1100010 */ {0x7fffe2, 23},
/* (151) |11111111|11111111|1100011 */ {0x7fffe3, 23},
/* (152) |11111111|11111111|1100100 */ {0x7fffe4, 23},
/* (153) |11111111|11111110|11100 */ {0x1fffdc, 21},
/* (154) |11111111|11111111|011000 */ {0x3fffd8, 22},
/* (155) |11111111|11111111|1100101 */ {0x7fffe5, 23},
/* (156) |11111111|11111111|011001 */ {0x3fffd9, 22},
/* (157) |11111111|11111111|1100110 */ {0x7fffe6, 23},
/* (158) |11111111|11111111|1100111 */ {0x7fffe7, 23},
/* (159) |11111111|11111111|11101111 */ {0xffffef, 24},
/* (160) |11111111|11111111|011010 */ {0x3fffda, 22},
/* (161) |11111111|11111110|11101 */ {0x1fffdd, 21},
/* (162) |11111111|11111110|1001 */ {0xfffe9, 20},
/* (163) |11111111|11111111|011011 */ {0x3fffdb, 22},
/* (164) |11111111|11111111|011100 */ {0x3fffdc, 22},
/* (165) |11111111|11111111|1101000 */ {0x7fffe8, 23},
/* (166) |11111111|11111111|1101001 */ {0x7fffe9, 23},
/* (167) |11111111|11111110|11110 */ {0x1fffde, 21},
/* (168) |11111111|11111111|1101010 */ {0x7fffea, 23},
/* (169) |11111111|11111111|011101 */ {0x3fffdd, 22},
/* (170) |11111111|11111111|011110 */ {0x3fffde, 22},
/* (171) |11111111|11111111|11110000 */ {0xfffff0, 24},
/* (172) |11111111|11111110|11111 */ {0x1fffdf, 21},
/* (173) |11111111|11111111|011111 */ {0x3fffdf, 22},
/* (174) |11111111|11111111|1101011 */ {0x7fffeb, 23},
/* (175) |11111111|11111111|1101100 */ {0x7fffec, 23},
/* (176) |11111111|11111111|00000 */ {0x1fffe0, 21},
/* (177) |11111111|11111111|00001 */ {0x1fffe1, 21},
/* (178) |11111111|11111111|100000 */ {0x3fffe0, 22},
/* (179) |11111111|11111111|00010 */ {0x1fffe2, 21},
/* (180) |11111111|11111111|1101101 */ {0x7fffed, 23},
/* (181) |11111111|11111111|100001 */ {0x3fffe1, 22},
/* (182) |11111111|11111111|1101110 */ {0x7fffee, 23},
/* (183) |11111111|11111111|1101111 */ {0x7fffef, 23},
/* (184) |11111111|11111110|1010 */ {0xfffea, 20},
/* (185) |11111111|11111111|100010 */ {0x3fffe2, 22},
/* (186) |11111111|11111111|100011 */ {0x3fffe3, 22},
/* (187) |11111111|11111111|100100 */ {0x3fffe4, 22},
/* (188) |11111111|11111111|1110000 */ {0x7ffff0, 23},
/* (189) |11111111|11111111|100101 */ {0x3fffe5, 22},
/* (190) |11111111|11111111|100110 */ {0x3fffe6, 22},
/* (191) |11111111|11111111|1110001 */ {0x7ffff1, 23},
/* (192) |11111111|11111111|11111000|00 */ {0x3ffffe0, 26},
/* (193) |11111111|11111111|11111000|01 */ {0x3ffffe1, 26},
/* (194) |11111111|11111110|1011 */ {0xfffeb, 20},
/* (195) |11111111|11111110|001 */ {0x7fff1, 19},
/* (196) |11111111|11111111|100111 */ {0x3fffe7, 22},
/* (197) |11111111|11111111|1110010 */ {0x7ffff2, 23},
/* (198) |11111111|11111111|101000 */ {0x3fffe8, 22},
/* (199) |11111111|11111111|11110110|0 */ {0x1ffffec, 25},
/* (200) |11111111|11111111|11111000|10 */ {0x3ffffe2, 26},
/* (201) |11111111|11111111|11111000|11 */ {0x3ffffe3, 26},
/* (202) |11111111|11111111|11111001|00 */ {0x3ffffe4, 26},
/* (203) |11111111|11111111|11111011|110 */ {0x7ffffde, 27},
/* (204) |11111111|11111111|11111011|111 */ {0x7ffffdf, 27},
/* (205) |11111111|11111111|11111001|01 */ {0x3ffffe5, 26},
/* (206) |11111111|11111111|11110001 */ {0xfffff1, 24},
/* (207) |11111111|11111111|11110110|1 */ {0x1ffffed, 25},
/* (208) |11111111|11111110|010 */ {0x7fff2, 19},
/* (209) |11111111|11111111|00011 */ {0x1fffe3, 21},
/* (210) |11111111|11111111|11111001|10 */ {0x3ffffe6, 26},
/* (211) |11111111|11111111|11111100|000 */ {0x7ffffe0, 27},
/* (212) |11111111|11111111|11111100|001 */ {0x7ffffe1, 27},
/* (213) |11111111|11111111|11111001|11 */ {0x3ffffe7, 26},
/* (214) |11111111|11111111|11111100|010 */ {0x7ffffe2, 27},
/* (215) |11111111|11111111|11110010 */ {0xfffff2, 24},
/* (216) |11111111|11111111|00100 */ {0x1fffe4, 21},
/* (217) |11111111|11111111|00101 */ {0x1fffe5, 21},
/* (218) |11111111|11111111|11111010|00 */ {0x3ffffe8, 26},
/* (219) |11111111|11111111|11111010|01 */ {0x3ffffe9, 26},
/* (220) |11111111|11111111|11111111|1101 */ {0xffffffd, 28},
/* (221) |11111111|11111111|11111100|011 */ {0x7ffffe3, 27},
/* (222) |11111111|11111111|11111100|100 */ {0x7ffffe4, 27},
/* (223) |11111111|11111111|11111100|101 */ {0x7ffffe5, 27},
/* (224) |11111111|11111110|1100 */ {0xfffec, 20},
/* (225) |11111111|11111111|11110011 */ {0xfffff3, 24},
/* (226) |11111111|11111110|1101 */ {0xfffed, 20},
/* (227) |11111111|11111111|00110 */ {0x1fffe6, 21},
/* (228) |11111111|11111111|101001 */ {0x3fffe9, 22},
/* (229) |11111111|11111111|00111 */ {0x1fffe7, 21},
/* (230) |11111111|11111111|01000 */ {0x1fffe8, 21},
/* (231) |11111111|11111111|1110011 */ {0x7ffff3, 23},
/* (232) |11111111|11111111|101010 */ {0x3fffea, 22},
/* (233) |11111111|11111111|101011 */ {0x3fffeb, 22},
/* (234) |11111111|11111111|11110111|0 */ {0x1ffffee, 25},
/* (235) |11111111|11111111|11110111|1 */ {0x1ffffef, 25},
/* (236) |11111111|11111111|11110100 */ {0xfffff4, 24},
/* (237) |11111111|11111111|11110101 */ {0xfffff5, 24},
/* (238) |11111111|11111111|11111010|10 */ {0x3ffffea, 26},
/* (239) |11111111|11111111|1110100 */ {0x7ffff4, 23},
/* (240) |11111111|11111111|11111010|11 */ {0x3ffffeb, 26},
/* (241) |11111111|11111111|11111100|110 */ {0x7ffffe6, 27},
/* (242) |11111111|11111111|11111011|00 */ {0x3ffffec, 26},
/* (243) |11111111|11111111|11111011|01 */ {0x3ffffed, 26},
/* (244) |11111111|11111111|11111100|111 */ {0x7ffffe7, 27},
/* (245) |11111111|11111111|11111101|000 */ {0x7ffffe8, 27},
/* (246) |11111111|11111111|11111101|001 */ {0x7ffffe9, 27},
/* (247) |11111111|11111111|11111101|010 */ {0x7ffffea, 27},
/* (248) |11111111|11111111|11111101|011 */ {0x7ffffeb, 27},
/* (249) |11111111|11111111|11111111|1110 */ {0xffffffe, 28},
/* (250) |11111111|11111111|11111101|100 */ {0x7ffffec, 27},
/* (251) |11111111|11111111|11111101|101 */ {0x7ffffed, 27},
/* (252) |11111111|11111111|11111101|110 */ {0x7ffffee, 27},
/* (253) |11111111|11111111|11111101|111 */ {0x7ffffef, 27},
/* (254) |11111111|11111111|11111110|000 */ {0x7fffff0, 27},
/* (255) |11111111|11111111|11111011|10 */ {0x3ffffee, 26},
/*EOS (256) |11111111|11111111|11111111|111111 */ {0x3fffffff, 30}
};
static final int[][] LCCODES = new int[CODES.length][];
static final char EOS = 256;
// Huffman decode tree stored in a flattened char array for good
// locality of reference.
static final char[] tree;
static final char[] rowsym;
static final byte[] rowbits;
// Build the Huffman lookup tree and LC TABLE
static
{
System.arraycopy(CODES, 0, LCCODES, 0, CODES.length);
for (int i = 'A'; i <= 'Z'; i++)
{
LCCODES[i] = LCCODES['a' + i - 'A'];
}
int r = 0;
for (int i = 0; i < CODES.length; i++)
{
r += (CODES[i][1] + 7) / 8;
}
tree = new char[r * 256];
rowsym = new char[r];
rowbits = new byte[r];
r = 0;
for (int sym = 0; sym < CODES.length; sym++)
{
int code = CODES[sym][0];
int len = CODES[sym][1];
int current = 0;
while (len > 8)
{
len -= 8;
int i = ((code >>> len) & 0xFF);
int t = current * 256 + i;
current = tree[t];
if (current == 0)
{
tree[t] = (char)++r;
current = r;
}
}
int terminal = ++r;
rowsym[r] = (char)sym;
int b = len & 0x07;
int terminalBits = b == 0 ? 8 : b;
rowbits[r] = (byte)terminalBits;
int shift = 8 - len;
int start = current * 256 + ((code << shift) & 0xFF);
int end = start + (1 << shift);
for (int i = start; i < end; i++)
{
tree[i] = (char)terminal;
}
}
}
public static String decode(ByteBuffer buffer) throws HpackException.CompressionException
{
return decode(buffer, buffer.remaining());
}
public static String decode(ByteBuffer buffer, int length) throws HpackException.CompressionException
{
Utf8StringBuilder utf8 = new Utf8StringBuilder(length * 2);
int node = 0;
int current = 0;
int bits = 0;
for (int i = 0; i < length; i++)
{
int b = buffer.get() & 0xFF;
current = (current << 8) | b;
bits += 8;
while (bits >= 8)
{
int c = (current >>> (bits - 8)) & 0xFF;
node = tree[node * 256 + c];
if (rowbits[node] != 0)
{
if (rowsym[node] == EOS)
throw new HpackException.CompressionException("EOS in content");
// terminal node
utf8.append((byte)(0xFF & rowsym[node]));
bits -= rowbits[node];
node = 0;
}
else
{
// non-terminal node
bits -= 8;
}
}
}
while (bits > 0)
{
int c = (current << (8 - bits)) & 0xFF;
int lastNode = node;
node = tree[node * 256 + c];
if (rowbits[node] == 0 || rowbits[node] > bits)
{
int requiredPadding = 0;
for (int i = 0; i < bits; i++)
{
requiredPadding = (requiredPadding << 1) | 1;
}
if ((c >> (8 - bits)) != requiredPadding)
throw new HpackException.CompressionException("Incorrect padding");
node = lastNode;
break;
}
utf8.append((byte)(0xFF & rowsym[node]));
bits -= rowbits[node];
node = 0;
}
if (node != 0)
throw new HpackException.CompressionException("Bad termination");
return utf8.toString();
}
public static int octetsNeeded(String s)
{
return octetsNeeded(CODES, s);
}
public static int octetsNeeded(byte[] b)
{
return octetsNeeded(CODES, b);
}
public static void encode(ByteBuffer buffer, String s)
{
encode(CODES, buffer, s);
}
public static void encode(ByteBuffer buffer, byte[] b)
{
encode(CODES, buffer, b);
}
public static int octetsNeededLC(String s)
{
return octetsNeeded(LCCODES, s);
}
public static void encodeLC(ByteBuffer buffer, String s)
{
encode(LCCODES, buffer, s);
}
private static int octetsNeeded(final int[][] table, String s)
{
int needed = 0;
int len = s.length();
for (int i = 0; i < len; i++)
{
char c = s.charAt(i);
if (c >= 128 || c < ' ')
return -1;
needed += table[c][1];
}
return (needed + 7) / 8;
}
private static int octetsNeeded(final int[][] table, byte[] b)
{
int needed = 0;
int len = b.length;
for (int i = 0; i < len; i++)
{
int c = 0xFF & b[i];
needed += table[c][1];
}
return (needed + 7) / 8;
}
/**
* @param table The table to encode by
* @param buffer The buffer to encode to
* @param s The string to encode
*/
private static void encode(final int[][] table, ByteBuffer buffer, String s)
{
long current = 0;
int n = 0;
int len = s.length();
for (int i = 0; i < len; i++)
{
char c = s.charAt(i);
if (c >= 128 || c < ' ')
throw new IllegalArgumentException();
int code = table[c][0];
int bits = table[c][1];
current <<= bits;
current |= code;
n += bits;
while (n >= 8)
{
n -= 8;
buffer.put((byte)(current >> n));
}
}
if (n > 0)
{
current <<= (8 - n);
current |= (0xFF >>> n);
buffer.put((byte)(current));
}
}
private static void encode(final int[][] table, ByteBuffer buffer, byte[] b)
{
long current = 0;
int n = 0;
int len = b.length;
for (int i = 0; i < len; i++)
{
int c = 0xFF & b[i];
int code = table[c][0];
int bits = table[c][1];
current <<= bits;
current |= code;
n += bits;
while (n >= 8)
{
n -= 8;
buffer.put((byte)(current >> n));
}
}
if (n > 0)
{
current <<= (8 - n);
current |= (0xFF >>> n);
buffer.put((byte)(current));
}
}
}

View File

@ -0,0 +1,299 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http3.qpack.HpackException.SessionException;
public class MetaDataBuilder
{
private final int _maxSize;
private final HttpFields.Mutable _fields = HttpFields.build();
private int _size;
private Integer _status;
private String _method;
private HttpScheme _scheme;
private HostPortHttpField _authority;
private String _path;
private String _protocol;
private long _contentLength = Long.MIN_VALUE;
private HpackException.StreamException _streamException;
private boolean _request;
private boolean _response;
/**
* @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters.
*/
protected MetaDataBuilder(int maxHeadersSize)
{
_maxSize = maxHeadersSize;
}
/**
* Get the maxSize.
*
* @return the maxSize
*/
public int getMaxSize()
{
return _maxSize;
}
/**
* Get the size.
*
* @return the current size in bytes
*/
public int getSize()
{
return _size;
}
public void emit(HttpField field) throws HpackException.SessionException
{
HttpHeader header = field.getHeader();
String name = field.getName();
if (name == null || name.length() == 0)
throw new HpackException.SessionException("Header size 0");
String value = field.getValue();
int fieldSize = name.length() + (value == null ? 0 : value.length());
_size += fieldSize + 32;
if (_size > _maxSize)
throw new HpackException.SessionException("Header size %d > %d", _size, _maxSize);
if (field instanceof StaticTableHttpField)
{
StaticTableHttpField staticField = (StaticTableHttpField)field;
switch (header)
{
case C_STATUS:
if (checkPseudoHeader(header, _status))
_status = staticField.getIntValue();
_response = true;
break;
case C_METHOD:
if (checkPseudoHeader(header, _method))
_method = value;
_request = true;
break;
case C_SCHEME:
if (checkPseudoHeader(header, _scheme))
_scheme = (HttpScheme)staticField.getStaticValue();
_request = true;
break;
default:
throw new IllegalArgumentException(name);
}
}
else if (header != null)
{
switch (header)
{
case C_STATUS:
if (checkPseudoHeader(header, _status))
_status = field.getIntValue();
_response = true;
break;
case C_METHOD:
if (checkPseudoHeader(header, _method))
_method = value;
_request = true;
break;
case C_SCHEME:
if (checkPseudoHeader(header, _scheme) && value != null)
_scheme = HttpScheme.CACHE.get(value);
_request = true;
break;
case C_AUTHORITY:
if (checkPseudoHeader(header, _authority))
{
if (field instanceof HostPortHttpField)
_authority = (HostPortHttpField)field;
else if (value != null)
_authority = new AuthorityHttpField(value);
}
_request = true;
break;
case C_PATH:
if (checkPseudoHeader(header, _path))
{
if (value != null && value.length() > 0)
_path = value;
else
streamException("No Path");
}
_request = true;
break;
case C_PROTOCOL:
if (checkPseudoHeader(header, _protocol))
_protocol = value;
_request = true;
break;
case HOST:
_fields.add(field);
break;
case CONTENT_LENGTH:
_contentLength = field.getLongValue();
_fields.add(field);
break;
case TE:
if ("trailers".equalsIgnoreCase(value))
_fields.add(field);
else
streamException("Unsupported TE value '%s'", value);
break;
case CONNECTION:
if ("TE".equalsIgnoreCase(value))
_fields.add(field);
else
streamException("Connection specific field '%s'", header);
break;
default:
if (name.charAt(0) == ':')
streamException("Unknown pseudo header '%s'", name);
else
_fields.add(field);
break;
}
}
else
{
if (name.charAt(0) == ':')
streamException("Unknown pseudo header '%s'", name);
else
_fields.add(field);
}
}
protected void streamException(String messageFormat, Object... args)
{
HpackException.StreamException stream = new HpackException.StreamException(messageFormat, args);
if (_streamException == null)
_streamException = stream;
else
_streamException.addSuppressed(stream);
}
protected boolean checkPseudoHeader(HttpHeader header, Object value)
{
if (_fields.size() > 0)
{
streamException("Pseudo header %s after fields", header.asString());
return false;
}
if (value == null)
return true;
streamException("Duplicate pseudo header %s", header.asString());
return false;
}
public MetaData build() throws HpackException.StreamException
{
if (_streamException != null)
{
_streamException.addSuppressed(new Throwable());
throw _streamException;
}
if (_request && _response)
throw new HpackException.StreamException("Request and Response headers");
HttpFields.Mutable fields = _fields;
try
{
if (_request)
{
if (_method == null)
throw new HpackException.StreamException("No Method");
boolean isConnect = HttpMethod.CONNECT.is(_method);
if (!isConnect || _protocol != null)
{
if (_scheme == null)
throw new HpackException.StreamException("No Scheme");
if (_path == null)
throw new HpackException.StreamException("No Path");
}
if (isConnect)
return new MetaData.ConnectRequest(_scheme, _authority, _path, fields, _protocol);
else
return new MetaData.Request(
_method,
_scheme == null ? HttpScheme.HTTP.asString() : _scheme.asString(),
_authority,
_path,
HttpVersion.HTTP_2,
fields,
_contentLength);
}
if (_response)
{
if (_status == null)
throw new HpackException.StreamException("No Status");
return new MetaData.Response(HttpVersion.HTTP_2, _status, fields, _contentLength);
}
return new MetaData(HttpVersion.HTTP_2, fields, _contentLength);
}
finally
{
_fields.clear();
_request = false;
_response = false;
_status = null;
_method = null;
_scheme = null;
_authority = null;
_path = null;
_protocol = null;
_size = 0;
_contentLength = Long.MIN_VALUE;
}
}
/**
* Check that the max size will not be exceeded.
*
* @param length the length
* @param huffman the huffman name
* @throws SessionException in case of size errors
*/
public void checkSize(int length, boolean huffman) throws SessionException
{
// Apply a huffman fudge factor
if (huffman)
length = (length * 4) / 3;
if ((_size + length) > _maxSize)
throw new HpackException.SessionException("Header too large %d > %d", _size + length, _maxSize);
}
}

View File

@ -0,0 +1,146 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
public class NBitInteger
{
public static int octectsNeeded(int n, int i)
{
if (n == 8)
{
int nbits = 0xFF;
i = i - nbits;
if (i < 0)
return 1;
if (i == 0)
return 2;
int lz = Integer.numberOfLeadingZeros(i);
int log = 32 - lz;
return 1 + (log + 6) / 7;
}
int nbits = 0xFF >>> (8 - n);
i = i - nbits;
if (i < 0)
return 0;
if (i == 0)
return 1;
int lz = Integer.numberOfLeadingZeros(i);
int log = 32 - lz;
return (log + 6) / 7;
}
public static void encode(ByteBuffer buf, int n, int i)
{
if (n == 8)
{
if (i < 0xFF)
{
buf.put((byte)i);
}
else
{
buf.put((byte)0xFF);
int length = i - 0xFF;
while (true)
{
if ((length & ~0x7F) == 0)
{
buf.put((byte)length);
return;
}
else
{
buf.put((byte)((length & 0x7F) | 0x80));
length >>>= 7;
}
}
}
}
else
{
int p = buf.position() - 1;
int bits = 0xFF >>> (8 - n);
if (i < bits)
{
buf.put(p, (byte)((buf.get(p) & ~bits) | i));
}
else
{
buf.put(p, (byte)(buf.get(p) | bits));
int length = i - bits;
while (true)
{
if ((length & ~0x7F) == 0)
{
buf.put((byte)length);
return;
}
else
{
buf.put((byte)((length & 0x7F) | 0x80));
length >>>= 7;
}
}
}
}
}
public static int decode(ByteBuffer buffer, int n)
{
if (n == 8)
{
int nbits = 0xFF;
int i = buffer.get() & 0xff;
if (i == nbits)
{
int m = 1;
int b;
do
{
b = 0xff & buffer.get();
i = i + (b & 127) * m;
m = m * 128;
}
while ((b & 128) == 128);
}
return i;
}
int nbits = 0xFF >>> (8 - n);
int i = buffer.get(buffer.position() - 1) & nbits;
if (i == nbits)
{
int m = 1;
int b;
do
{
b = 0xff & buffer.get();
i = i + (b & 127) * m;
m = m * 128;
}
while ((b & 128) == 128);
}
return i;
}
}

View File

@ -0,0 +1,54 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
public class StaticTableHttpField extends HttpField
{
private final Object _value;
public StaticTableHttpField(HttpHeader header, String name, String valueString, Object value)
{
super(header, name, valueString);
if (value == null)
throw new IllegalArgumentException();
_value = value;
}
public StaticTableHttpField(HttpHeader header, String valueString, Object value)
{
this(header, header.asString(), valueString, value);
}
public StaticTableHttpField(String name, String valueString, Object value)
{
super(name, valueString);
if (value == null)
throw new IllegalArgumentException();
_value = value;
}
public Object getStaticValue()
{
return _value;
}
@Override
public String toString()
{
return super.toString() + "(evaluated)";
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.http3.qpack.HpackFieldPreEncoder

View File

@ -0,0 +1,448 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http3.qpack.HpackContext.Entry;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
*
*/
public class HpackContextTest
{
@Test
public void testStaticName()
{
HpackContext ctx = new HpackContext(4096);
Entry entry = ctx.get(":method");
assertEquals(":method", entry.getHttpField().getName());
assertTrue(entry.isStatic());
assertThat(entry.toString(), Matchers.startsWith("{S,2,:method: "));
}
@Test
public void testEmptyAdd()
{
HpackContext ctx = new HpackContext(0);
HttpField field = new HttpField("foo", "bar");
assertNull(ctx.add(field));
}
@Test
public void testTooBigAdd()
{
HpackContext ctx = new HpackContext(37);
HttpField field = new HttpField("foo", "bar");
assertNull(ctx.add(field));
}
@Test
public void testJustRight()
{
HpackContext ctx = new HpackContext(38);
HttpField field = new HttpField("foo", "bar");
Entry entry = ctx.add(field);
assertNotNull(entry);
assertThat(entry.toString(), Matchers.startsWith("{D,0,foo: bar,"));
}
@Test
public void testEvictOne()
{
HpackContext ctx = new HpackContext(38);
HttpField field0 = new HttpField("foo", "bar");
assertEquals(field0, ctx.add(field0).getHttpField());
assertEquals(field0, ctx.get("foo").getHttpField());
HttpField field1 = new HttpField("xxx", "yyy");
assertEquals(field1, ctx.add(field1).getHttpField());
assertNull(ctx.get(field0));
assertNull(ctx.get("foo"));
assertEquals(field1, ctx.get(field1).getHttpField());
assertEquals(field1, ctx.get("xxx").getHttpField());
}
@Test
public void testEvictNames()
{
HpackContext ctx = new HpackContext(38 * 2);
HttpField[] field =
{
new HttpField("name", "v0"),
new HttpField("name", "v1"),
new HttpField("name", "v2"),
new HttpField("name", "v3"),
new HttpField("name", "v4"),
new HttpField("name", "v5"),
};
Entry[] entry = new Entry[field.length];
// Add 2 name entries to fill table
for (int i = 0; i <= 1; i++)
{
entry[i] = ctx.add(field[i]);
}
// check there is a name reference and it is the most recent added
assertEquals(entry[1], ctx.get("name"));
// Add 1 other entry to table and evict 1
ctx.add(new HttpField("xxx", "yyy"));
// check the name reference has been not been evicted
assertEquals(entry[1], ctx.get("name"));
// Add 1 other entry to table and evict 1
ctx.add(new HttpField("foo", "bar"));
// name is evicted
assertNull(ctx.get("name"));
}
@Test
@SuppressWarnings("ReferenceEquality")
public void testGetAddStatic()
{
HpackContext ctx = new HpackContext(4096);
// Look for the field. Should find static version.
HttpField methodGet = new HttpField(":method", "GET");
assertEquals(methodGet, ctx.get(methodGet).getHttpField());
assertTrue(ctx.get(methodGet).isStatic());
// Add static version to dynamic table
Entry e0 = ctx.add(ctx.get(methodGet).getHttpField());
// Look again and should see dynamic version
assertEquals(methodGet, ctx.get(methodGet).getHttpField());
assertFalse(methodGet == ctx.get(methodGet).getHttpField());
assertFalse(ctx.get(methodGet).isStatic());
// Duplicates allows
Entry e1 = ctx.add(ctx.get(methodGet).getHttpField());
// Look again and should see dynamic version
assertEquals(methodGet, ctx.get(methodGet).getHttpField());
assertFalse(methodGet == ctx.get(methodGet).getHttpField());
assertFalse(ctx.get(methodGet).isStatic());
assertFalse(e0 == e1);
}
@Test
public void testGetAddStaticName()
{
HpackContext ctx = new HpackContext(4096);
HttpField methodOther = new HttpField(":method", "OTHER");
// Look for the field by name. Should find static version.
assertEquals(":method", ctx.get(":method").getHttpField().getName());
assertTrue(ctx.get(":method").isStatic());
// Add dynamic entry with method
ctx.add(methodOther);
// Look for the field by name. Should find static version.
assertEquals(":method", ctx.get(":method").getHttpField().getName());
assertTrue(ctx.get(":method").isStatic());
}
@Test
public void testIndexes()
{
// Only enough space for 5 entries
HpackContext ctx = new HpackContext(38 * 5);
HttpField methodPost = new HttpField(":method", "POST");
HttpField[] field =
{
new HttpField("fo0", "b0r"),
new HttpField("fo1", "b1r"),
new HttpField("fo2", "b2r"),
new HttpField("fo3", "b3r"),
new HttpField("fo4", "b4r"),
new HttpField("fo5", "b5r"),
new HttpField("fo6", "b6r"),
new HttpField("fo7", "b7r"),
new HttpField("fo8", "b8r"),
new HttpField("fo9", "b9r"),
new HttpField("foA", "bAr"),
};
Entry[] entry = new Entry[100];
// Lookup the index of a static field
assertEquals(0, ctx.size());
assertEquals(":authority", ctx.get(1).getHttpField().getName());
assertEquals(3, ctx.index(ctx.get(methodPost)));
assertEquals(methodPost, ctx.get(3).getHttpField());
assertEquals("www-authenticate", ctx.get(61).getHttpField().getName());
assertEquals(null, ctx.get(62));
// Add a single entry
entry[0] = ctx.add(field[0]);
// Check new entry is 62
assertEquals(1, ctx.size());
assertEquals(62, ctx.index(entry[0]));
assertEquals(entry[0], ctx.get(62));
// and statics still OK
assertEquals(":authority", ctx.get(1).getHttpField().getName());
assertEquals(3, ctx.index(ctx.get(methodPost)));
assertEquals(methodPost, ctx.get(3).getHttpField());
assertEquals("www-authenticate", ctx.get(61).getHttpField().getName());
assertEquals(null, ctx.get(62 + ctx.size()));
// Add 4 more entries
for (int i = 1; i <= 4; i++)
{
entry[i] = ctx.add(field[i]);
}
// Check newest entry is at 62 oldest at 66
assertEquals(5, ctx.size());
int index = 66;
for (int i = 0; i <= 4; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
// and statics still OK
assertEquals(":authority", ctx.get(1).getHttpField().getName());
assertEquals(3, ctx.index(ctx.get(methodPost)));
assertEquals(methodPost, ctx.get(3).getHttpField());
assertEquals("www-authenticate", ctx.get(61).getHttpField().getName());
assertEquals(null, ctx.get(62 + ctx.size()));
// add 1 more entry and this should cause an eviction!
entry[5] = ctx.add(field[5]);
// Check newest entry is at 1 oldest at 5
index = 66;
for (int i = 1; i <= 5; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
// check entry 0 evicted
assertNull(ctx.get(field[0]));
assertEquals(0, ctx.index(entry[0]));
// and statics still OK
assertEquals(":authority", ctx.get(1).getHttpField().getName());
assertEquals(3, ctx.index(ctx.get(methodPost)));
assertEquals(methodPost, ctx.get(3).getHttpField());
assertEquals("www-authenticate", ctx.get(61).getHttpField().getName());
assertEquals(null, ctx.get(62 + ctx.size()));
// Add 4 more entries
for (int i = 6; i <= 9; i++)
{
entry[i] = ctx.add(field[i]);
}
// Check newest entry is at 1 oldest at 5
index = 66;
for (int i = 5; i <= 9; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
// check entry 0-4 evicted
for (int i = 0; i <= 4; i++)
{
assertNull(ctx.get(field[i]));
assertEquals(0, ctx.index(entry[i]));
}
// Add new entries enough so that array queue will wrap
for (int i = 10; i <= 52; i++)
{
entry[i] = ctx.add(new HttpField("n" + i, "v" + i));
}
index = 66;
for (int i = 48; i <= 52; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
}
@Test
public void testResize()
{
// Only enough space for 5 entries
HpackContext ctx = new HpackContext(38 * 5);
HttpField[] field =
{
new HttpField("fo0", "b0r"),
new HttpField("fo1", "b1r"),
new HttpField("fo2", "b2r"),
new HttpField("fo3", "b3r"),
new HttpField("fo4", "b4r"),
new HttpField("fo5", "b5r"),
new HttpField("fo6", "b6r"),
new HttpField("fo7", "b7r"),
new HttpField("fo8", "b8r"),
new HttpField("fo9", "b9r"),
new HttpField("foA", "bAr"),
};
Entry[] entry = new Entry[field.length];
// Add 5 entries
for (int i = 0; i <= 4; i++)
{
entry[i] = ctx.add(field[i]);
}
assertEquals(5, ctx.size());
// check indexes
int index = 66;
for (int i = 0; i <= 4; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
// resize so that only 2 entries may be held
ctx.resize(38 * 2);
assertEquals(2, ctx.size());
// check indexes
index = 63;
for (int i = 3; i <= 4; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
// resize so that 6.5 entries may be held
ctx.resize(38 * 6 + 19);
assertEquals(2, ctx.size());
// check indexes
index = 63;
for (int i = 3; i <= 4; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
// Add 5 entries
for (int i = 5; i <= 9; i++)
{
entry[i] = ctx.add(field[i]);
}
assertEquals(6, ctx.size());
// check indexes
index = 67;
for (int i = 4; i <= 9; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
// resize so that only 100 entries may be held
ctx.resize(38 * 100);
assertEquals(6, ctx.size());
// check indexes
index = 67;
for (int i = 4; i <= 9; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
// add 50 fields
for (int i = 0; i < 50; i++)
{
ctx.add(new HttpField("n" + i, "v" + i));
}
// check indexes
index = 67 + 50;
for (int i = 4; i <= 9; i++)
{
assertEquals(index, ctx.index(entry[i]));
assertEquals(entry[i], ctx.get(index));
index--;
}
}
@Test
public void testStaticHuffmanValues() throws Exception
{
HpackContext ctx = new HpackContext(4096);
for (int i = 2; i <= 14; i++)
{
Entry entry = ctx.get(i);
assertTrue(entry.isStatic());
ByteBuffer buffer = ByteBuffer.wrap(entry.getStaticHuffmanValue());
int huff = 0xff & buffer.get();
assertTrue((0x80 & huff) == 0x80);
int len = NBitInteger.decode(buffer, 7);
assertEquals(len, buffer.remaining());
String value = Huffman.decode(buffer);
assertEquals(entry.getHttpField().getValue(), value);
}
}
@Test
public void testNameInsensitivity()
{
HpackContext ctx = new HpackContext(4096);
assertEquals("content-length", ctx.get("content-length").getHttpField().getName());
assertEquals("content-length", ctx.get("Content-Length").getHttpField().getName());
assertTrue(ctx.get("Content-Length").isStatic());
assertTrue(ctx.get("Content-Type").isStatic());
ctx.add(new HttpField("Wibble", "Wobble"));
assertEquals("Wibble", ctx.get("wibble").getHttpField().getName());
assertEquals("Wibble", ctx.get("Wibble").getHttpField().getName());
}
}

View File

@ -0,0 +1,565 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import java.util.Iterator;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http3.qpack.HpackException.CompressionException;
import org.eclipse.jetty.http3.qpack.HpackException.SessionException;
import org.eclipse.jetty.http3.qpack.HpackException.StreamException;
import org.eclipse.jetty.util.TypeUtil;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import static org.eclipse.jetty.http.tools.matchers.HttpFieldsMatchers.containsHeaderValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class HpackDecoderTest
{
/*
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 |
+---+---+-----------------------+
| H | Name Length (7+) |
+---+---------------------------+
| Name String (Length octets) |
+---+---------------------------+
| H | Value Length (7+) |
+---+---------------------------+
| Value String (Length octets) |
+-------------------------------+
*/
@Test
public void testDecodeD3() throws Exception
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
// First request
String encoded = "828684410f7777772e6578616d706c652e636f6d";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme());
assertEquals("/", request.getURI().getPath());
assertEquals("www.example.com", request.getURI().getHost());
assertFalse(request.iterator().hasNext());
// Second request
encoded = "828684be58086e6f2d6361636865";
buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme());
assertEquals("/", request.getURI().getPath());
assertEquals("www.example.com", request.getURI().getHost());
Iterator<HttpField> iterator = request.iterator();
assertTrue(iterator.hasNext());
assertEquals(new HttpField("cache-control", "no-cache"), iterator.next());
assertFalse(iterator.hasNext());
// Third request
encoded = "828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565";
buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTPS.asString(), request.getURI().getScheme());
assertEquals("/index.html", request.getURI().getPath());
assertEquals("www.example.com", request.getURI().getHost());
iterator = request.iterator();
assertTrue(iterator.hasNext());
assertEquals(new HttpField("custom-key", "custom-value"), iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testDecodeD4() throws Exception
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
// First request
String encoded = "828684418cf1e3c2e5f23a6ba0ab90f4ff";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme());
assertEquals("/", request.getURI().getPath());
assertEquals("www.example.com", request.getURI().getHost());
assertFalse(request.iterator().hasNext());
// Second request
encoded = "828684be5886a8eb10649cbf";
buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme());
assertEquals("/", request.getURI().getPath());
assertEquals("www.example.com", request.getURI().getHost());
Iterator<HttpField> iterator = request.iterator();
assertTrue(iterator.hasNext());
assertEquals(new HttpField("cache-control", "no-cache"), iterator.next());
assertFalse(iterator.hasNext());
}
@Test
public void testDecodeWithArrayOffset() throws Exception
{
String value = "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==";
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "8682418cF1E3C2E5F23a6bA0Ab90F4Ff841f0822426173696320515778685a475270626a70766347567549484e6c633246745a513d3d";
byte[] bytes = TypeUtil.fromHexString(encoded);
byte[] array = new byte[bytes.length + 1];
System.arraycopy(bytes, 0, array, 1, bytes.length);
ByteBuffer buffer = ByteBuffer.wrap(array, 1, bytes.length).slice();
MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme());
assertEquals("/", request.getURI().getPath());
assertEquals("www.example.com", request.getURI().getHost());
assertEquals(1, request.getFields().size());
HttpField field = request.iterator().next();
assertEquals(HttpHeader.AUTHORIZATION, field.getHeader());
assertEquals(value, field.getValue());
}
@Test
public void testDecodeHuffmanWithArrayOffset() throws Exception
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "8286418cf1e3c2e5f23a6ba0ab90f4ff84";
byte[] bytes = TypeUtil.fromHexString(encoded);
byte[] array = new byte[bytes.length + 1];
System.arraycopy(bytes, 0, array, 1, bytes.length);
ByteBuffer buffer = ByteBuffer.wrap(array, 1, bytes.length).slice();
MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme());
assertEquals("/", request.getURI().getPath());
assertEquals("www.example.com", request.getURI().getHost());
assertFalse(request.iterator().hasNext());
}
@Test
public void testNghttpx() throws Exception
{
// Response encoded by nghttpx
String encoded = "886196C361Be940b6a65B6850400B8A00571972e080a62D1Bf5f87497cA589D34d1f9a0f0d0234327690Aa69D29aFcA954D3A5358980Ae112e0f7c880aE152A9A74a6bF3";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
HpackDecoder decoder = new HpackDecoder(4096, 8192);
MetaData.Response response = (MetaData.Response)decoder.decode(buffer);
assertThat(response.getStatus(), is(200));
assertThat(response.getFields().size(), is(6));
assertThat(response.getFields(), containsHeaderValue(HttpHeader.DATE, "Fri, 15 Jul 2016 02:36:20 GMT"));
assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_TYPE, "text/html"));
assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_ENCODING, ""));
assertThat(response.getFields(), containsHeaderValue(HttpHeader.CONTENT_LENGTH, "42"));
assertThat(response.getFields(), containsHeaderValue(HttpHeader.SERVER, "nghttpx nghttp2/1.12.0"));
assertThat(response.getFields(), containsHeaderValue(HttpHeader.VIA, "1.1 nghttpx"));
}
@Test
public void testResize() throws Exception
{
String encoded = "203f136687A0E41d139d090760881c6490B2Cd39Ba7f";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
HpackDecoder decoder = new HpackDecoder(4096, 8192);
MetaData metaData = decoder.decode(buffer);
assertThat(metaData.getFields().get(HttpHeader.HOST), is("localhost0"));
assertThat(metaData.getFields().get(HttpHeader.COOKIE), is("abcdefghij"));
assertThat(decoder.getHpackContext().getMaxDynamicTableSize(), is(50));
assertThat(decoder.getHpackContext().size(), is(1));
}
@Test
public void testBadResize() throws Exception
{
/*
4. Dynamic Table Management
4.2. Maximum Table Size
× 1: Sends a dynamic table size update at the end of header block
-> The endpoint MUST treat this as a decoding error.
Expected: GOAWAY Frame (Error Code: COMPRESSION_ERROR)
Connection closed
*/
String encoded = "203f136687A0E41d139d090760881c6490B2Cd39Ba7f20";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
HpackDecoder decoder = new HpackDecoder(4096, 8192);
try
{
decoder.decode(buffer);
fail();
}
catch (CompressionException e)
{
assertThat(e.getMessage(), Matchers.containsString("Dynamic table resize after fields"));
}
}
@Test
public void testTooBigToIndex() throws Exception
{
String encoded = "3f610f17FfEc02Df3990A190A0D4Ee5b3d2940Ec98Aa4a62D127D29e273a0aA20dEcAa190a503b262d8a2671D4A2672a927aA874988a2471D05510750c951139EdA2452a3a548cAa1aA90bE4B228342864A9E0D450A5474a92992a1aA513395448E3A0Aa17B96cFe3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f14E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F353F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F54f";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
HpackDecoder decoder = new HpackDecoder(128, 8192);
MetaData metaData = decoder.decode(buffer);
assertThat(decoder.getHpackContext().getDynamicTableSize(), is(0));
assertThat(metaData.getFields().get("host"), Matchers.startsWith("This is a very large field"));
}
@Test
public void testUnknownIndex() throws Exception
{
String encoded = "BE";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
HpackDecoder decoder = new HpackDecoder(128, 8192);
try
{
decoder.decode(buffer);
fail();
}
catch (SessionException e)
{
assertThat(e.getMessage(), Matchers.startsWith("Unknown index"));
}
}
/* 8.1.2.1. Pseudo-Header Fields */
@Test
public void test8121PseudoHeaderFields() throws Exception
{
// 1:Sends a HEADERS frame that contains a unknown pseudo-header field
MetaDataBuilder mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(":unknown", "value"));
try
{
mdb.build();
fail();
}
catch (StreamException ex)
{
assertThat(ex.getMessage(), Matchers.containsString("Unknown pseudo header"));
}
// 2: Sends a HEADERS frame that contains the pseudo-header field defined for response
mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_PATH, "/path"));
mdb.emit(new HttpField(HttpHeader.C_STATUS, "100"));
try
{
mdb.build();
fail();
}
catch (StreamException ex)
{
assertThat(ex.getMessage(), Matchers.containsString("Request and Response headers"));
}
// 3: Sends a HEADERS frame that contains a pseudo-header field as trailers
// 4: Sends a HEADERS frame that contains a pseudo-header field that appears in a header block after a regular header field
mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_PATH, "/path"));
mdb.emit(new HttpField("Accept", "No Compromise"));
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost"));
try
{
mdb.build();
fail();
}
catch (StreamException ex)
{
assertThat(ex.getMessage(), Matchers.containsString("Pseudo header :authority after fields"));
}
}
@Test
public void test8122ConnectionSpecificHeaderFields() throws Exception
{
MetaDataBuilder mdb;
// 1: Sends a HEADERS frame that contains the connection-specific header field
mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.CONNECTION, "value"));
try
{
mdb.build();
fail();
}
catch (StreamException ex)
{
assertThat(ex.getMessage(), Matchers.containsString("Connection specific field 'Connection'"));
}
// 2: Sends a HEADERS frame that contains the TE header field with any value other than "trailers"
mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.TE, "not_trailers"));
try
{
mdb.build();
fail();
}
catch (StreamException ex)
{
assertThat(ex.getMessage(), Matchers.containsString("Unsupported TE value 'not_trailers'"));
}
mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.CONNECTION, "TE"));
mdb.emit(new HttpField(HttpHeader.TE, "trailers"));
assertNotNull(mdb.build());
}
@Test
public void test8123RequestPseudoHeaderFields() throws Exception
{
{
MetaDataBuilder mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
assertThat(mdb.build(), Matchers.instanceOf(MetaData.Request.class));
}
{
// 1: Sends a HEADERS frame with empty ":path" pseudo-header field
final MetaDataBuilder mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
mdb.emit(new HttpField(HttpHeader.C_PATH, ""));
StreamException ex = assertThrows(StreamException.class, mdb::build);
assertThat(ex.getMessage(), Matchers.containsString("No Path"));
}
{
// 2: Sends a HEADERS frame that omits ":method" pseudo-header field
final MetaDataBuilder mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
StreamException ex = assertThrows(StreamException.class, mdb::build);
assertThat(ex.getMessage(), Matchers.containsString("No Method"));
}
{
// 3: Sends a HEADERS frame that omits ":scheme" pseudo-header field
final MetaDataBuilder mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
StreamException ex = assertThrows(StreamException.class, mdb::build);
assertThat(ex.getMessage(), Matchers.containsString("No Scheme"));
}
{
// 4: Sends a HEADERS frame that omits ":path" pseudo-header field
final MetaDataBuilder mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
StreamException ex = assertThrows(StreamException.class, mdb::build);
assertThat(ex.getMessage(), Matchers.containsString("No Path"));
}
{
// 5: Sends a HEADERS frame with duplicated ":method" pseudo-header field
final MetaDataBuilder mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
StreamException ex = assertThrows(StreamException.class, mdb::build);
assertThat(ex.getMessage(), Matchers.containsString("Duplicate"));
}
{
// 6: Sends a HEADERS frame with duplicated ":scheme" pseudo-header field
final MetaDataBuilder mdb = new MetaDataBuilder(4096);
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
StreamException ex = assertThrows(StreamException.class, mdb::build);
assertThat(ex.getMessage(), Matchers.containsString("Duplicate"));
}
}
@Test
public void testHuffmanEncodedStandard() throws Exception
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "82868441" + "83" + "49509F";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(), request.getURI().getScheme());
assertEquals("/", request.getURI().getPath());
assertEquals("test", request.getURI().getHost());
assertFalse(request.iterator().hasNext());
}
/* 5.2.1: Sends a Huffman-encoded string literal representation with padding longer than 7 bits */
@Test
public void testHuffmanEncodedExtraPadding()
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "82868441" + "84" + "49509FFF";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer));
assertThat(ex.getMessage(), Matchers.containsString("Bad termination"));
}
/* 5.2.2: Sends a Huffman-encoded string literal representation padded by zero */
@Test
public void testHuffmanEncodedZeroPadding()
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "82868441" + "83" + "495090";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer));
assertThat(ex.getMessage(), Matchers.containsString("Incorrect padding"));
}
/* 5.2.3: Sends a Huffman-encoded string literal representation containing the EOS symbol */
@Test
public void testHuffmanEncodedWithEOS()
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "82868441" + "87" + "497FFFFFFF427F";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer));
assertThat(ex.getMessage(), Matchers.containsString("EOS in content"));
}
@Test
public void testHuffmanEncodedOneIncompleteOctet()
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "82868441" + "81" + "FE";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer));
assertThat(ex.getMessage(), Matchers.containsString("Bad termination"));
}
@Test
public void testHuffmanEncodedTwoIncompleteOctet()
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "82868441" + "82" + "FFFE";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer));
assertThat(ex.getMessage(), Matchers.containsString("Bad termination"));
}
@Test
public void testZeroLengthName()
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "00000130";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
SessionException ex = assertThrows(SessionException.class, () -> decoder.decode(buffer));
assertThat(ex.getMessage(), Matchers.containsString("Header size 0"));
}
@Test
public void testZeroLengthValue() throws Exception
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "00016800";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
MetaData metaData = decoder.decode(buffer);
assertThat(metaData.getFields().size(), is(1));
assertThat(metaData.getFields().get("h"), is(""));
}
@Test
public void testUpperCaseName()
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "0001480130";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
StreamException ex = assertThrows(StreamException.class, () -> decoder.decode(buffer));
assertThat(ex.getMessage(), Matchers.containsString("Uppercase header"));
}
@Test
public void testWhiteSpaceName()
{
HpackDecoder decoder = new HpackDecoder(4096, 8192);
String encoded = "0001200130";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
StreamException ex = assertThrows(StreamException.class, () -> decoder.decode(buffer));
assertThat(ex.getMessage(), Matchers.containsString("Illegal header"));
}
}

View File

@ -0,0 +1,309 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.util.BufferUtil;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class HpackEncoderTest
{
@Test
public void testUnknownFieldsContextManagement() throws Exception
{
HpackEncoder encoder = new HpackEncoder(38 * 5);
HttpFields.Mutable fields = HttpFields.build();
HttpField[] field =
{
new HttpField("fo0", "b0r"),
new HttpField("fo1", "b1r"),
new HttpField("fo2", "b2r"),
new HttpField("fo3", "b3r"),
new HttpField("fo4", "b4r"),
new HttpField("fo5", "b5r"),
new HttpField("fo6", "b6r"),
new HttpField("fo7", "b7r"),
new HttpField("fo8", "b8r"),
new HttpField("fo9", "b9r"),
new HttpField("foA", "bAr"),
};
// Add 4 entries
for (int i = 0; i <= 3; i++)
{
fields.add(field[i]);
}
// encode them
ByteBuffer buffer = BufferUtil.allocate(4096);
int pos = BufferUtil.flipToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, pos);
// something was encoded!
assertThat(buffer.remaining(), Matchers.greaterThan(0));
// All are in the dynamic table
assertEquals(4, encoder.getHpackContext().size());
// encode exact same fields again!
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, 0);
// All are in the dynamic table
assertEquals(4, encoder.getHpackContext().size());
// Add 4 more fields
for (int i = 4; i <= 7; i++)
{
fields.add(field[i]);
}
// encode
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, 0);
// something was encoded!
assertThat(buffer.remaining(), Matchers.greaterThan(0));
// max dynamic table size reached
assertEquals(5, encoder.getHpackContext().size());
// remove some fields
for (int i = 0; i <= 7; i += 2)
{
fields.remove(field[i].getName());
}
// encode
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, 0);
// something was encoded!
assertThat(buffer.remaining(), Matchers.greaterThan(0));
// max dynamic table size reached
assertEquals(5, encoder.getHpackContext().size());
// remove another fields
fields.remove(field[1].getName());
// encode
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, 0);
// something was encoded!
assertThat(buffer.remaining(), Matchers.greaterThan(0));
// max dynamic table size reached
assertEquals(5, encoder.getHpackContext().size());
// re add the field
fields.add(field[1]);
// encode
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, 0);
// something was encoded!
assertThat(buffer.remaining(), Matchers.greaterThan(0));
// max dynamic table size reached
assertEquals(5, encoder.getHpackContext().size());
}
@Test
public void testLargeFieldsNotIndexed()
{
HpackEncoder encoder = new HpackEncoder(38 * 5);
HpackContext ctx = encoder.getHpackContext();
ByteBuffer buffer = BufferUtil.allocate(4096);
// Index little fields
int pos = BufferUtil.flipToFill(buffer);
encoder.encode(buffer, new HttpField("Name", "Value"));
BufferUtil.flipToFlush(buffer, pos);
int dynamicTableSize = ctx.getDynamicTableSize();
assertThat(dynamicTableSize, Matchers.greaterThan(0));
// Do not index big field
StringBuilder largeName = new StringBuilder("largeName-");
String filler = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
while (largeName.length() < ctx.getMaxDynamicTableSize())
largeName.append(filler, 0, Math.min(filler.length(), ctx.getMaxDynamicTableSize() - largeName.length()));
pos = BufferUtil.flipToFill(buffer);
encoder.encode(buffer, new HttpField(largeName.toString(), "Value"));
BufferUtil.flipToFlush(buffer, pos);
assertThat(ctx.getDynamicTableSize(), Matchers.is(dynamicTableSize));
}
@Test
public void testIndexContentLength()
{
HpackEncoder encoder = new HpackEncoder(38 * 5);
HpackContext ctx = encoder.getHpackContext();
ByteBuffer buffer = BufferUtil.allocate(4096);
// Index zero content length
int pos = BufferUtil.flipToFill(buffer);
encoder.encode(buffer, new HttpField(HttpHeader.CONTENT_LENGTH, "0"));
BufferUtil.flipToFlush(buffer, pos);
int dynamicTableSize = ctx.getDynamicTableSize();
assertThat(dynamicTableSize, Matchers.greaterThan(0));
// Do not index non zero content length
pos = BufferUtil.flipToFill(buffer);
encoder.encode(buffer, new HttpField(HttpHeader.CONTENT_LENGTH, "42"));
BufferUtil.flipToFlush(buffer, pos);
assertThat(ctx.getDynamicTableSize(), Matchers.is(dynamicTableSize));
}
@Test
public void testNeverIndexSetCookie() throws Exception
{
HpackEncoder encoder = new HpackEncoder(38 * 5);
ByteBuffer buffer = BufferUtil.allocate(4096);
HttpFields.Mutable fields = HttpFields.build()
.put("set-cookie", "some cookie value");
// encode
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, 0);
// something was encoded!
assertThat(buffer.remaining(), Matchers.greaterThan(0));
// empty dynamic table
assertEquals(0, encoder.getHpackContext().size());
// encode again
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, 0);
// something was encoded!
assertThat(buffer.remaining(), Matchers.greaterThan(0));
// empty dynamic table
assertEquals(0, encoder.getHpackContext().size());
}
@Test
public void testFieldLargerThanTable() throws Exception
{
HttpFields.Mutable fields = HttpFields.build();
HpackEncoder encoder = new HpackEncoder(128);
ByteBuffer buffer0 = BufferUtil.allocate(4096);
int pos = BufferUtil.flipToFill(buffer0);
encoder.encode(buffer0, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer0, pos);
encoder = new HpackEncoder(128);
fields.add(new HttpField("user-agent", "jetty/test"));
ByteBuffer buffer1 = BufferUtil.allocate(4096);
pos = BufferUtil.flipToFill(buffer1);
encoder.encode(buffer1, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer1, pos);
encoder = new HpackEncoder(128);
encoder.setValidateEncoding(false);
fields.add(new HttpField(":path",
"This is a very large field, whose size is larger than the dynamic table so it should not be indexed as it will not fit in the table ever!" +
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX " +
"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY " +
"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ "));
ByteBuffer buffer2 = BufferUtil.allocate(4096);
pos = BufferUtil.flipToFill(buffer2);
encoder.encode(buffer2, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer2, pos);
encoder = new HpackEncoder(128);
encoder.setValidateEncoding(false);
fields.add(new HttpField("host", "somehost"));
ByteBuffer buffer = BufferUtil.allocate(4096);
pos = BufferUtil.flipToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, pos);
//System.err.println(BufferUtil.toHexString(buffer0));
//System.err.println(BufferUtil.toHexString(buffer1));
//System.err.println(BufferUtil.toHexString(buffer2));
//System.err.println(BufferUtil.toHexString(buffer));
// something was encoded!
assertThat(buffer.remaining(), Matchers.greaterThan(0));
// check first field is static index name and dynamic index body
assertThat((buffer.get(buffer0.remaining()) & 0xFF) >> 6, equalTo(1));
// check first field is static index name and literal body
assertThat((buffer.get(buffer1.remaining()) & 0xFF) >> 4, equalTo(0));
// check first field is static index name and dynamic index body
assertThat((buffer.get(buffer2.remaining()) & 0xFF) >> 6, equalTo(1));
// Only first and third fields are put in the table
HpackContext context = encoder.getHpackContext();
assertThat(context.size(), equalTo(2));
assertThat(context.get(HpackContext.STATIC_SIZE + 1).getHttpField().getName(), equalTo("host"));
assertThat(context.get(HpackContext.STATIC_SIZE + 2).getHttpField().getName(), equalTo("user-agent"));
assertThat(context.getDynamicTableSize(), equalTo(
context.get(HpackContext.STATIC_SIZE + 1).getSize() + context.get(HpackContext.STATIC_SIZE + 2).getSize()));
}
@Test
public void testResize() throws Exception
{
HttpFields fields = HttpFields.build()
.add("host", "localhost0")
.add("cookie", "abcdefghij");
HpackEncoder encoder = new HpackEncoder(4096);
ByteBuffer buffer = BufferUtil.allocate(4096);
int pos = BufferUtil.flipToFill(buffer);
encoder.encodeMaxDynamicTableSize(buffer, 0);
encoder.setRemoteMaxDynamicTableSize(50);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, pos);
HpackContext context = encoder.getHpackContext();
assertThat(context.getMaxDynamicTableSize(), Matchers.is(50));
assertThat(context.size(), Matchers.is(1));
}
}

View File

@ -0,0 +1,123 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.io.File;
import java.io.FileReader;
import java.nio.ByteBuffer;
import java.util.Map;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.ajax.JSON;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class HpackPerfTest
{
int _maxDynamicTableSize = 4 * 1024;
int _unencodedSize;
int _encodedSize;
@BeforeEach
public void before()
{
_unencodedSize = 0;
_encodedSize = 0;
}
@AfterEach
public void after()
{
System.err.printf("dynamictable=%d unencoded=%d encoded=%d p=%3.1f%%%n", _maxDynamicTableSize, _unencodedSize, _encodedSize, 100.0 * _encodedSize / _unencodedSize);
}
@Test
public void simpleTest() throws Exception
{
runStories();
}
private void runStories() throws Exception
{
// Find files
File data = MavenTestingUtils.getTestResourceDir("data");
String[] files = data.list((dir, name) -> name.startsWith("story_"));
assertNotNull(files);
// Parse JSON
@SuppressWarnings("unchecked")
Map<String, Object>[] stories = new Map[files.length];
int i = 0;
for (String file : files)
{
@SuppressWarnings("unchecked")
var story = (Map<String, Object>)new JSON().fromJSON(new FileReader(new File(data, file)));
stories[i++] = story;
}
ByteBuffer buffer = BufferUtil.allocate(256 * 1024);
// Encode all the requests
encodeStories(buffer, stories, "request");
// clear table
BufferUtil.clearToFill(buffer);
BufferUtil.flipToFlush(buffer, 0);
// Encode all the responses
encodeStories(buffer, stories, "response");
}
private void encodeStories(ByteBuffer buffer, Map<String, Object>[] stories, String type) throws Exception
{
for (Map<String, Object> story : stories)
{
if (type.equals(story.get("context")))
{
HpackEncoder encoder = new HpackEncoder(_maxDynamicTableSize, _maxDynamicTableSize);
encoder.setValidateEncoding(false);
Object[] cases = (Object[])story.get("cases");
for (Object c : cases)
{
@SuppressWarnings("unchecked")
var kase = (Map<String, Object>)c;
Object[] headers = (Object[])kase.get("headers");
// System.err.println(" "+headers);
HttpFields.Mutable fields = HttpFields.build();
for (Object header : headers)
{
@SuppressWarnings("unchecked")
var h = (Map<String, String>)header;
Map.Entry<String, String> e = h.entrySet().iterator().next();
fields.add(e.getKey(), e.getValue());
_unencodedSize += e.getKey().length() + e.getValue().length();
}
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields));
BufferUtil.flipToFlush(buffer, 0);
_encodedSize += buffer.remaining();
}
}
}
}
}

View File

@ -0,0 +1,303 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.http.DateGenerator;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http.MetaData.Response;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.util.BufferUtil;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
public class HpackTest
{
static final HttpField ServerJetty = new PreEncodedHttpField(HttpHeader.SERVER, "jetty");
static final HttpField XPowerJetty = new PreEncodedHttpField(HttpHeader.X_POWERED_BY, "jetty");
static final HttpField Date = new PreEncodedHttpField(HttpHeader.DATE, DateGenerator.formatDate(TimeUnit.NANOSECONDS.toMillis(System.nanoTime())));
@Test
public void encodeDecodeResponseTest() throws Exception
{
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 8192);
ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024);
HttpFields.Mutable fields0 = HttpFields.build()
.add(HttpHeader.CONTENT_TYPE, "text/html")
.add(HttpHeader.CONTENT_LENGTH, "1024")
.add(new HttpField(HttpHeader.CONTENT_ENCODING, (String)null))
.add(ServerJetty)
.add(XPowerJetty)
.add(Date)
.add(HttpHeader.SET_COOKIE, "abcdefghijklmnopqrstuvwxyz")
.add("custom-key", "custom-value");
Response original0 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields0);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original0);
BufferUtil.flipToFlush(buffer, 0);
Response decoded0 = (Response)decoder.decode(buffer);
Response nullToEmpty = new MetaData.Response(HttpVersion.HTTP_2, 200,
fields0.put(new HttpField(HttpHeader.CONTENT_ENCODING, "")));
assertMetaDataResponseSame(nullToEmpty, decoded0);
// Same again?
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original0);
BufferUtil.flipToFlush(buffer, 0);
Response decoded0b = (Response)decoder.decode(buffer);
assertMetaDataResponseSame(nullToEmpty, decoded0b);
HttpFields.Mutable fields1 = HttpFields.build()
.add(HttpHeader.CONTENT_TYPE, "text/plain")
.add(HttpHeader.CONTENT_LENGTH, "1234")
.add(HttpHeader.CONTENT_ENCODING, " ")
.add(ServerJetty)
.add(XPowerJetty)
.add(Date)
.add("Custom-Key", "Other-Value");
Response original1 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields1);
// Same again?
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original1);
BufferUtil.flipToFlush(buffer, 0);
Response decoded1 = (Response)decoder.decode(buffer);
assertMetaDataResponseSame(original1, decoded1);
assertEquals("custom-key", decoded1.getFields().getField("Custom-Key").getName());
}
@Test
public void encodeDecodeTooLargeTest() throws Exception
{
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 164);
ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024);
HttpFields fields0 = HttpFields.build()
.add("1234567890", "1234567890123456789012345678901234567890")
.add("Cookie", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR");
MetaData original0 = new MetaData(HttpVersion.HTTP_2, fields0);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original0);
BufferUtil.flipToFlush(buffer, 0);
MetaData decoded0 = decoder.decode(buffer);
assertMetaDataSame(original0, decoded0);
HttpFields fields1 = HttpFields.build()
.add("1234567890", "1234567890123456789012345678901234567890")
.add("Cookie", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR")
.add("x", "y");
MetaData original1 = new MetaData(HttpVersion.HTTP_2, fields1);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original1);
BufferUtil.flipToFlush(buffer, 0);
try
{
decoder.decode(buffer);
fail();
}
catch (HpackException.SessionException e)
{
assertThat(e.getMessage(), containsString("Header too large"));
}
}
@Test
public void encodeDecodeNonAscii() throws Exception
{
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 8192);
ByteBuffer buffer = BufferUtil.allocate(16 * 1024);
HttpFields fields0 = HttpFields.build()
// @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck
.add("Cookie", "[\uD842\uDF9F]")
.add("custom-key", "[\uD842\uDF9F]");
Response original0 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields0);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original0);
BufferUtil.flipToFlush(buffer, 0);
Response decoded0 = (Response)decoder.decode(buffer);
assertMetaDataSame(original0, decoded0);
}
@Test
public void evictReferencedFieldTest() throws Exception
{
HpackEncoder encoder = new HpackEncoder(200, 200);
HpackDecoder decoder = new HpackDecoder(200, 1024);
ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024);
String longEnoughToBeEvicted = "012345678901234567890123456789012345678901234567890";
HttpFields fields0 = HttpFields.build()
.add(longEnoughToBeEvicted, "value")
.add("foo", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
MetaData original0 = new MetaData(HttpVersion.HTTP_2, fields0);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original0);
BufferUtil.flipToFlush(buffer, 0);
MetaData decoded0 = decoder.decode(buffer);
assertEquals(2, encoder.getHpackContext().size());
assertEquals(2, decoder.getHpackContext().size());
assertEquals(longEnoughToBeEvicted, encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length + 1).getHttpField().getName());
assertEquals("foo", encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length).getHttpField().getName());
assertMetaDataSame(original0, decoded0);
HttpFields fields1 = HttpFields.build()
.add(longEnoughToBeEvicted, "other_value")
.add("x", "y");
MetaData original1 = new MetaData(HttpVersion.HTTP_2, fields1);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, original1);
BufferUtil.flipToFlush(buffer, 0);
MetaData decoded1 = decoder.decode(buffer);
assertMetaDataSame(original1, decoded1);
assertEquals(2, encoder.getHpackContext().size());
assertEquals(2, decoder.getHpackContext().size());
assertEquals("x", encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length).getHttpField().getName());
assertEquals("foo", encoder.getHpackContext().get(HpackContext.STATIC_TABLE.length + 1).getHttpField().getName());
}
@Test
public void testHopHeadersAreRemoved() throws Exception
{
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 16384);
HttpFields input = HttpFields.build()
.add(HttpHeader.ACCEPT, "*")
.add(HttpHeader.CONNECTION, "TE, Upgrade, Custom")
.add("Custom", "Pizza")
.add(HttpHeader.KEEP_ALIVE, "true")
.add(HttpHeader.PROXY_CONNECTION, "foo")
.add(HttpHeader.TE, "1234567890abcdef")
.add(HttpHeader.TRANSFER_ENCODING, "chunked")
.add(HttpHeader.UPGRADE, "gold");
ByteBuffer buffer = BufferUtil.allocate(2048);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, input));
BufferUtil.flipToFlush(buffer, 0);
MetaData metaData = decoder.decode(buffer);
HttpFields output = metaData.getFields();
assertEquals(1, output.size());
assertEquals("*", output.get(HttpHeader.ACCEPT));
}
@Test
public void testTETrailers() throws Exception
{
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 16384);
String teValue = "trailers";
String trailerValue = "Custom";
HttpFields input = HttpFields.build()
.add(HttpHeader.CONNECTION, "TE")
.add(HttpHeader.TE, teValue)
.add(HttpHeader.TRAILER, trailerValue);
ByteBuffer buffer = BufferUtil.allocate(2048);
BufferUtil.clearToFill(buffer);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, input));
BufferUtil.flipToFlush(buffer, 0);
MetaData metaData = decoder.decode(buffer);
HttpFields output = metaData.getFields();
assertEquals(2, output.size());
assertEquals(teValue, output.get(HttpHeader.TE));
assertEquals(trailerValue, output.get(HttpHeader.TRAILER));
}
@Test
public void testColonHeaders() throws Exception
{
HpackEncoder encoder = new HpackEncoder();
HpackDecoder decoder = new HpackDecoder(4096, 16384);
HttpFields input = HttpFields.build()
.add(":status", "200")
.add(":custom", "special");
ByteBuffer buffer = BufferUtil.allocate(2048);
BufferUtil.clearToFill(buffer);
assertThrows(HpackException.StreamException.class, () -> encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, input)));
encoder.setValidateEncoding(false);
encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, input));
BufferUtil.flipToFlush(buffer, 0);
assertThrows(HpackException.StreamException.class, () -> decoder.decode(buffer));
}
private void assertMetaDataResponseSame(MetaData.Response expected, MetaData.Response actual)
{
assertThat("Response.status", actual.getStatus(), is(expected.getStatus()));
assertThat("Response.reason", actual.getReason(), is(expected.getReason()));
assertMetaDataSame(expected, actual);
}
private void assertMetaDataSame(MetaData expected, MetaData actual)
{
assertThat("Metadata.contentLength", actual.getContentLength(), is(expected.getContentLength()));
assertThat("Metadata.version" + ".version", actual.getHttpVersion(), is(expected.getHttpVersion()));
assertHttpFieldsSame(expected.getFields(), actual.getFields());
}
private void assertHttpFieldsSame(HttpFields expected, HttpFields actual)
{
assertThat("metaData.fields.size", actual.size(), is(expected.size()));
for (HttpField actualField : actual)
{
if ("DATE".equalsIgnoreCase(actualField.getName()))
{
// skip comparison on Date, as these values can often differ by 1 second
// during testing.
continue;
}
assertThat("metaData.fields.contains(" + actualField + ")", expected.contains(actualField), is(true));
}
}
}

View File

@ -0,0 +1,82 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.stream.Stream;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.hamcrest.Matchers;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class HuffmanTest
{
public static Stream<Arguments> data()
{
return Stream.of(
new String[][]{
{"D.4.1", "f1e3c2e5f23a6ba0ab90f4ff", "www.example.com"},
{"D.4.2", "a8eb10649cbf", "no-cache"},
{"D.6.1k", "6402", "302"},
{"D.6.1v", "aec3771a4b", "private"},
{"D.6.1d", "d07abe941054d444a8200595040b8166e082a62d1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
{"D.6.1l", "9d29ad171863c78f0b97c8e9ae82ae43d3", "https://www.example.com"},
{"D.6.2te", "640cff", "303"},
}).map(Arguments::of);
}
@ParameterizedTest(name = "[{index}] spec={0}")
@MethodSource("data")
public void testDecode(String specSection, String hex, String expected) throws Exception
{
byte[] encoded = TypeUtil.fromHexString(hex);
String decoded = Huffman.decode(ByteBuffer.wrap(encoded));
assertEquals(expected, decoded, specSection);
}
@ParameterizedTest(name = "[{index}] spec={0}")
@MethodSource("data")
public void testEncode(String specSection, String hex, String expected)
{
ByteBuffer buf = BufferUtil.allocate(1024);
int pos = BufferUtil.flipToFill(buf);
Huffman.encode(buf, expected);
BufferUtil.flipToFlush(buf, pos);
String encoded = TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase(Locale.ENGLISH);
assertEquals(hex, encoded, specSection);
assertEquals(hex.length() / 2, Huffman.octetsNeeded(expected));
}
@ParameterizedTest(name = "[{index}]") // don't include unprintable character in test display-name
@ValueSource(chars = {(char)128, (char)0, (char)-1, ' ' - 1})
public void testEncode8859Only(char bad)
{
String s = "bad '" + bad + "'";
assertThat(Huffman.octetsNeeded(s), Matchers.is(-1));
assertThrows(BufferOverflowException.class,
() -> Huffman.encode(BufferUtil.allocate(32), s));
}
}

View File

@ -0,0 +1,199 @@
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.http3.qpack;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class NBitIntegerTest
{
@Test
public void testOctetsNeeded()
{
assertEquals(0, NBitInteger.octectsNeeded(5, 10));
assertEquals(2, NBitInteger.octectsNeeded(5, 1337));
assertEquals(1, NBitInteger.octectsNeeded(8, 42));
assertEquals(3, NBitInteger.octectsNeeded(8, 1337));
assertEquals(0, NBitInteger.octectsNeeded(6, 62));
assertEquals(1, NBitInteger.octectsNeeded(6, 63));
assertEquals(1, NBitInteger.octectsNeeded(6, 64));
assertEquals(2, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x01));
assertEquals(3, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x80));
assertEquals(4, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x80 * 0x80));
}
@Test
public void testEncode()
{
testEncode(6, 0, "00");
testEncode(6, 1, "01");
testEncode(6, 62, "3e");
testEncode(6, 63, "3f00");
testEncode(6, 63 + 1, "3f01");
testEncode(6, 63 + 0x7e, "3f7e");
testEncode(6, 63 + 0x7f, "3f7f");
testEncode(6, 63 + 0x00 + 0x80 * 0x01, "3f8001");
testEncode(6, 63 + 0x01 + 0x80 * 0x01, "3f8101");
testEncode(6, 63 + 0x7f + 0x80 * 0x01, "3fFf01");
testEncode(6, 63 + 0x00 + 0x80 * 0x02, "3f8002");
testEncode(6, 63 + 0x01 + 0x80 * 0x02, "3f8102");
testEncode(6, 63 + 0x7f + 0x80 * 0x7f, "3fFf7f");
testEncode(6, 63 + 0x00 + 0x80 * 0x80, "3f808001");
testEncode(6, 63 + 0x7f + 0x80 * 0x80 * 0x7f, "3fFf807f");
testEncode(6, 63 + 0x00 + 0x80 * 0x80 * 0x80, "3f80808001");
testEncode(8, 0, "00");
testEncode(8, 1, "01");
testEncode(8, 128, "80");
testEncode(8, 254, "Fe");
testEncode(8, 255, "Ff00");
testEncode(8, 255 + 1, "Ff01");
testEncode(8, 255 + 0x7e, "Ff7e");
testEncode(8, 255 + 0x7f, "Ff7f");
testEncode(8, 255 + 0x80, "Ff8001");
testEncode(8, 255 + 0x00 + 0x80 * 0x80, "Ff808001");
}
public void testEncode(int n, int i, String expected)
{
ByteBuffer buf = BufferUtil.allocate(16);
int p = BufferUtil.flipToFill(buf);
if (n < 8)
buf.put((byte)0x00);
NBitInteger.encode(buf, n, i);
BufferUtil.flipToFlush(buf, p);
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
assertEquals(expected, r);
assertEquals(expected.length() / 2, (n < 8 ? 1 : 0) + NBitInteger.octectsNeeded(n, i));
}
@Test
public void testDecode()
{
testDecode(6, 0, "00");
testDecode(6, 1, "01");
testDecode(6, 62, "3e");
testDecode(6, 63, "3f00");
testDecode(6, 63 + 1, "3f01");
testDecode(6, 63 + 0x7e, "3f7e");
testDecode(6, 63 + 0x7f, "3f7f");
testDecode(6, 63 + 0x80, "3f8001");
testDecode(6, 63 + 0x81, "3f8101");
testDecode(6, 63 + 0x7f + 0x80 * 0x01, "3fFf01");
testDecode(6, 63 + 0x00 + 0x80 * 0x02, "3f8002");
testDecode(6, 63 + 0x01 + 0x80 * 0x02, "3f8102");
testDecode(6, 63 + 0x7f + 0x80 * 0x7f, "3fFf7f");
testDecode(6, 63 + 0x00 + 0x80 * 0x80, "3f808001");
testDecode(6, 63 + 0x7f + 0x80 * 0x80 * 0x7f, "3fFf807f");
testDecode(6, 63 + 0x00 + 0x80 * 0x80 * 0x80, "3f80808001");
testDecode(8, 0, "00");
testDecode(8, 1, "01");
testDecode(8, 128, "80");
testDecode(8, 254, "Fe");
testDecode(8, 255, "Ff00");
testDecode(8, 255 + 1, "Ff01");
testDecode(8, 255 + 0x7e, "Ff7e");
testDecode(8, 255 + 0x7f, "Ff7f");
testDecode(8, 255 + 0x80, "Ff8001");
testDecode(8, 255 + 0x00 + 0x80 * 0x80, "Ff808001");
}
public void testDecode(int n, int expected, String encoded)
{
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
buf.position(n == 8 ? 0 : 1);
assertEquals(expected, NBitInteger.decode(buf, n));
}
@Test
public void testEncodeExampleD11()
{
ByteBuffer buf = BufferUtil.allocate(16);
int p = BufferUtil.flipToFill(buf);
buf.put((byte)0x77);
buf.put((byte)0xFF);
NBitInteger.encode(buf, 5, 10);
BufferUtil.flipToFlush(buf, p);
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
assertEquals("77Ea", r);
}
@Test
public void testDecodeExampleD11()
{
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF"));
buf.position(2);
assertEquals(10, NBitInteger.decode(buf, 5));
}
@Test
public void testEncodeExampleD12()
{
ByteBuffer buf = BufferUtil.allocate(16);
int p = BufferUtil.flipToFill(buf);
buf.put((byte)0x88);
buf.put((byte)0x00);
NBitInteger.encode(buf, 5, 1337);
BufferUtil.flipToFlush(buf, p);
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
assertEquals("881f9a0a", r);
}
@Test
public void testDecodeExampleD12()
{
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff"));
buf.position(2);
assertEquals(1337, NBitInteger.decode(buf, 5));
}
@Test
public void testEncodeExampleD13()
{
ByteBuffer buf = BufferUtil.allocate(16);
int p = BufferUtil.flipToFill(buf);
buf.put((byte)0x88);
buf.put((byte)0xFF);
NBitInteger.encode(buf, 8, 42);
BufferUtil.flipToFlush(buf, p);
String r = TypeUtil.toHexString(BufferUtil.toArray(buf));
assertEquals("88Ff2a", r);
}
@Test
public void testDecodeExampleD13()
{
ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf"));
buf.position(1);
assertEquals(42, NBitInteger.decode(buf, 8));
}
}

View File

@ -0,0 +1,53 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yahoo.co.jp"
},
{
":path": "/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.yahoo.co.jp"
},
{
":path": "/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "k.yimg.jp"
},
{
":path": "/images/top/sp2/cmn/logo-ns-130528.png"
}
]
}
]
}

View File

@ -0,0 +1,52 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":scheme": "https"
},
{
":authority": "example.com"
},
{
":path": "/"
},
{
":method": "GET"
},
{
"user-agent": "hpack-test"
},
{
"cookie": "xxxxxxx1"
},
{
"x-hello": "world"
}
]
},
{
"headers": [
{
":scheme": "https"
},
{
":authority": "example.com"
},
{
":path": "/"
},
{
":method": "GET"
},
{
"user-agent": "hpack-test"
},
{
"cookie": "xxxxxxx2"
}
]
}
]
}

View File

@ -0,0 +1,339 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "amazon.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "g-ecx.images-amazon.com"
},
{
":path": "/images/G/01/gno/beacon/BeaconSprite-US-01._V401903535_.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.amazon.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "g-ecx.images-amazon.com"
},
{
":path": "/images/G/01/x-locale/common/transparent-pixel._V386942464_.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.amazon.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "g-ecx.images-amazon.com"
},
{
":path": "/images/G/01/img12/other/disaster-relief/300-column/sandy-relief_300x75._V400689491_.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.amazon.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.amazon.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "g-ecx.images-amazon.com"
},
{
":path": "/images/G/01/x-locale/common/transparent-pixel._V192234675_.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.amazon.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "g-ecx.images-amazon.com"
},
{
":path": "/images/G/01/img12/shoes/sales_events/11_nov/1030_AccessoriesPROMO_GWright._V400626950_.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.amazon.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "g-ecx.images-amazon.com"
},
{
":path": "/images/G/01/Automotive/rotos/Duracell600_120._V192204764_.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.amazon.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "g-ecx.images-amazon.com"
},
{
":path": "/images/G/01/ui/loadIndicators/loadIndicator-large._V192195480_.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.amazon.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "ecx.images-amazon.com"
},
{
":path": "/images/I/41HZ-ND-SUL._SL135_.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.amazon.com/"
}
]
}
]
}

View File

@ -0,0 +1,342 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "baidu.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "baidu.com"
},
{
":path": "/favicon.ico"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.baidu.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.baidu.com"
},
{
":path": "/img/baidu_sylogo1.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
},
{
"cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.baidu.com"
},
{
":path": "/cache/global/img/gs.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
},
{
"cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s1.bdstatic.com"
},
{
":path": "/r/www/cache/global/js/tangram-1.3.4c1.0.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s1.bdstatic.com"
},
{
":path": "/r/www/cache/global/js/home-1.8.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s1.bdstatic.com"
},
{
":path": "/r/www/cache/user/js/u-1.3.4.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s1.bdstatic.com"
},
{
":path": "/r/www/img/i-1.0.0.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.baidu.com"
},
{
":path": "/favicon.ico"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
}
]
}
]
}

View File

@ -0,0 +1,342 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "baidu.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "baidu.com"
},
{
":path": "/favicon.ico"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.baidu.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.baidu.com"
},
{
":path": "/img/baidu_sylogo1.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
},
{
"cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.baidu.com"
},
{
":path": "/cache/global/img/gs.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
},
{
"cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s1.bdstatic.com"
},
{
":path": "/r/www/cache/global/js/tangram-1.3.4c1.0.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s1.bdstatic.com"
},
{
":path": "/r/www/cache/global/js/home-1.8.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s1.bdstatic.com"
},
{
":path": "/r/www/cache/user/js/u-1.3.4.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s1.bdstatic.com"
},
{
":path": "/r/www/img/i-1.0.0.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.baidu.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.baidu.com"
},
{
":path": "/favicon.ico"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "BAIDUID=B6136AC10EBE0A8FCD216EB64C4C1A5C:FG=1"
}
]
}
]
}

View File

@ -0,0 +1,366 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "geo.craigslist.org"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.craigslist.org"
},
{
":path": "/about/sites/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.craigslist.org"
},
{
":path": "/styles/countries.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.craigslist.org/about/sites/"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.craigslist.org"
},
{
":path": "/js/formats.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.craigslist.org/about/sites/"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.craigslist.org"
},
{
":path": "/js/jquery-1.4.2.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.craigslist.org/about/sites/"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.craigslist.org"
},
{
":path": "/favicon.ico"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "shoals.craigslist.org"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.craigslist.org/about/sites/"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.craigslist.org"
},
{
":path": "/styles/craigslist.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://shoals.craigslist.org/"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.craigslist.org"
},
{
":path": "/js/formats.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://shoals.craigslist.org/"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.craigslist.org"
},
{
":path": "/js/homepage.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://shoals.craigslist.org/"
},
{
"cookie": "cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals"
}
]
}
]
}

View File

@ -0,0 +1,342 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "ebay.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.ebay.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "ebay-stories.com"
},
{
":path": "/wp-content/uploads/2012/11/Iso-65.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.ebay.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "rover.ebay.com"
},
{
":path": "/roversync/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.ebay.com/"
},
{
"cookie": "ebay=%5Esbf%3D%23%5E; dp1=bpbf/%238000000000005276504d^u1p/QEBfX0BAX19AQA**5276504d^; cssg=c67883f113a0a56964e646c6ffaa1abe; s=CgAD4ACBQlm5NYzY3ODgzZjExM2EwYTU2OTY0ZTY0NmM2ZmZhYTFhYmUBSgAYUJZuTTUwOTUxY2NkLjAuMS4zLjE1MS4zLjAuMeN+7JE*; nonsession=CgAFMABhSdlBNNTA5NTFjY2QuMC4xLjEuMTQ5LjMuMC4xAMoAIFn7Hk1jNjc4ODNmMTEzYTBhNTY5NjRlNjQ2YzZmZmFhMWFjMQDLAAFQlSPVMX8u5Z8*"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "p.ebaystatic.com"
},
{
":path": "/aw/pics/s.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.ebay.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "p.ebaystatic.com"
},
{
":path": "/aw/pics/mops/2012_doodles/Holiday/DS3/ImgWeek_1_Penguin_Small_150x30.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.ebay.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "p.ebaystatic.com"
},
{
":path": "/aw/pics/globalHeader/facebook/g12.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.ebay.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "p.ebaystatic.com"
},
{
":path": "/aw/pics/globalHeader/twitter/g12.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.ebay.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "p.ebaystatic.com"
},
{
":path": "/aw/pics/globalHeader/icon_mobile_gray_11x16.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.ebay.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "srx.main.ebayrtm.com"
},
{
":path": "/rtm"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.ebay.com/"
}
]
}
]
}

View File

@ -0,0 +1,345 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yb/r/GsNJNwuI-UM.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.facebook.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yY/r/u8iA3kXb8Y1.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.facebook.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yI/r/qANVTsC52fp.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.facebook.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yt/r/FZaMKqARgC6.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.facebook.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yZ/r/jlKDoX15kHG.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.facebook.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yO/r/_MRarphcCIq.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.facebook.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yP/r/CRkiDDWTd1u.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.facebook.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yX/x/Qq6L1haQrYr.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://static.ak.fbcdn.net/rsrc.php/v2/yI/r/qANVTsC52fp.css"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/yN/r/EarbWo_mDU-.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.facebook.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "static.ak.fbcdn.net"
},
{
":path": "/rsrc.php/v2/y7/x/9jt7oVdF7z3.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://static.ak.fbcdn.net/rsrc.php/v2/yO/r/_MRarphcCIq.css"
}
]
}
]
}

View File

@ -0,0 +1,363 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "flickr.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.flickr.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "us.adserver.yahoo.com"
},
{
":path": "/a"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.flickr.com/"
},
{
"cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.flickr.com"
},
{
":path": "/images/share-this-icons-sprite.png.v6"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus"
},
{
"referer": "http://www.flickr.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.flickr.com"
},
{
":path": "/images/flickr-sprite.png.v4"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.flickr.com/"
},
{
"cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.flickr.com"
},
{
":path": "/flanal_event.gne"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus; ywadp10001561398679=1956875541"
},
{
"referer": "http://www.flickr.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "y.analytics.yahoo.com"
},
{
":path": "/fpc.pl"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.flickr.com/"
},
{
"cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "d.yimg.com"
},
{
":path": "/ce/soup/soup_generated_fragment.gne"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.flickr.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "geo.yahoo.com"
},
{
":path": "/b"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.flickr.com/"
},
{
"cookie": "B=4m2rqu589a507&b=3&s=1v; k_visit=1; MSC=t=1351947310X; CH=AgBQlRQgADwDIAAbDSAAGrIgADpuIAAoriAALMQgAAs0IAA7CCAAJ0MgABo3; ucs=bnas=0"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.flickr.com"
},
{
":path": "/photos/nasacommons/4940913342/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus; ywadp10001561398679=1956875541; fl_v=souhp; fpc10001561398679=Qvv1ikW_|aUqazlyMaa|fses10001561398679=|aUqazlyMaa|Qvv1ikW_|fvis10001561398679=Zj1odHRwJTNBJTJGJTJGd3d3LmZsaWNrci5jb20lMkYmdD0xMzUxOTUwMDc1JmI9JTJGaW5kZXhfc291cC5nbmU=|8M1871YYH0|8M1871YYH0|8M1871YYH0|8|8M1871YYH0|8M1871YYH0"
},
{
"referer": "http://www.flickr.com/"
}
]
}
]
}

View File

@ -0,0 +1,345 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "linkedin.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.linkedin.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s.c.lnkd.licdn.com"
},
{
":path": "/scds/concat/common/js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.linkedin.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s.c.lnkd.licdn.com"
},
{
":path": "/scds/concat/common/css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.linkedin.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s.c.lnkd.licdn.com"
},
{
":path": "/scds/concat/common/js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.linkedin.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s.c.lnkd.licdn.com"
},
{
":path": "/scds/concat/common/css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.linkedin.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s.c.lnkd.licdn.com"
},
{
":path": "/scds/concat/common/css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.linkedin.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s.c.lnkd.licdn.com"
},
{
":path": "/scds/concat/common/js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.linkedin.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.linkedin.com"
},
{
":path": "/analytics/noauthtracker"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"x-requested-with": "XMLHttpRequest"
},
{
"referer": "http://www.linkedin.com/"
},
{
"cookie": "bcookie=\"v=2&bae845a5-83ed-4590-becf-f0f3d586432b\"; leo_auth_token=\"GST:UDbWFFpLLdcS6gHJ7NJa3XYRsc7W_gDwutbWnlWLfo7G_2Y4jfLH-H:1351948419:4b5c0f1309310a9b659b97d8960e64fdd635526b\"; JSESSIONID=\"ajax:0608630266152992729\"; visit=\"v=1&G\"; X-LI-IDC=C1"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "s.c.lnkd.licdn.com"
},
{
":path": "/scds/common/u/img/favicon_v3.ico"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.linkedin.com/"
}
]
}
]
}

View File

@ -0,0 +1,339 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "msn.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.msn.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "ads1.msads.net"
},
{
":path": "/library/primedns.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.msn.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "col.stj.s-msn.com"
},
{
":path": "/primedns.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.msn.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "blu.stc.s-msn.com"
},
{
":path": "/as/wea3/i/en-us/law/39.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.msn.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "col.stj.s-msn.com"
},
{
":path": "/primedns.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.msn.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "col.stc.s-msn.com"
},
{
":path": "/br/sc/i/ff/adchoices_gif2.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.msn.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "col.stb00.s-msn.com"
},
{
":path": "/i/80/53CAC6A10B6248682CF221B24A92.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.msn.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "col.stb01.s-msn.com"
},
{
":path": "/i/E0/A6C312635EF0A355668C820EB5343.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.msn.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "col.stb00.s-msn.com"
},
{
":path": "/i/BB/B1F619A1AD4D4AA6B0648BDBBCDEED.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.msn.com/"
}
]
}
]
}

View File

@ -0,0 +1,369 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "nytimes.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "t.pointroll.com"
},
{
":path": "/PointRoll/Track/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.bbc.co.uk/news/business-20178000"
},
{
"cookie": "PRbu=EzZdduhgq; PRgo=BBBAAFMnA; PRti4CD975E46CAEA=B"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "t.pointroll.com"
},
{
":path": "/PointRoll/Track/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.bbc.co.uk/news/business-20178000"
},
{
"cookie": "PRbu=EzZdduhgq; PRgo=BBBAAFMnA; PRti4CD975E46CAEA=B"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "graphics8.nytimes.com"
},
{
":path": "/packages/css/multimedia/bundles/projects/2012/HPLiveDebateFlex.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.nytimes.com/"
},
{
"cookie": "RMID=007f010022166047bee9002b; adxcs=-"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "graphics8.nytimes.com"
},
{
":path": "/js/app/common/slideshow/embeddedSlideshowBuilder.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.nytimes.com/"
},
{
"cookie": "RMID=007f010022166047bee9002b; adxcs=-"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "graphics8.nytimes.com"
},
{
":path": "/css/0.1/screen/slideshow/modules/slidingGallery.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.nytimes.com/"
},
{
"cookie": "RMID=007f010022166047bee9002b; adxcs=-"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "graphics8.nytimes.com"
},
{
":path": "/adx/images/ADS/31/46/ad.314668/NYT_MBM_IPHON_LEFT_Oct11.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.nytimes.com/"
},
{
"cookie": "RMID=007f010022166047bee9002b; adxcs=-"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "graphics8.nytimes.com"
},
{
":path": "/packages/js/multimedia/bundles/projects/2012/HPLiveDebateFlex.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.nytimes.com/"
},
{
"cookie": "RMID=007f010022166047bee9002b; adxcs=-"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "graphics8.nytimes.com"
},
{
":path": "/packages/js/multimedia/data/FilmStripPromo/2012_election_filmstrip.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.nytimes.com/"
},
{
"cookie": "RMID=007f010022166047bee9002b; adxcs=-"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "graphics8.nytimes.com"
},
{
":path": "/packages/js/elections/2012/debates/videostrip/filmstrip.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.nytimes.com/"
},
{
"cookie": "RMID=007f010022166047bee9002b; adxcs=-"
}
]
}
]
}

View File

@ -0,0 +1,369 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "pinterest.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/164311086374323731_DhZSfIfc_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/161637074097583855_SNjDRMKe_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/273593746083022624_FCoEkXsC_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/52917364342893663_qtPmJgkx_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/116952921544035902_KyTWinzm_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/283445370267774252_AttBMVfT_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/237142736599025827_ufDEHdRe_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/224194887669533381_UBmi659g_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "media-cache-lt0.pinterest.com"
},
{
":path": "/upload/274156696036479907_A1ezgnsj_b.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://pinterest.com/"
},
{
"cookie": "_pinterest_sess=\"eJyLMnSMyghISi53cnEMyqgo9ElPya0M1jdw9/S0tY8vycxNtfUN8TX0Dck28A9JrvQPtLVVK04tLs5MsfXM9az0C3HKicpKN/JzSa/yrQrKiswKNY3MijSJzMrI8M1KN/bNDTT1rQo08Uy3tQUAm3EkCA==\""
}
]
}
]
}

View File

@ -0,0 +1,342 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "qq.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mat1.gtimg.com"
},
{
":path": "/www/images/qq2012/followme.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mat1.gtimg.com"
},
{
":path": "/www/images/qq2012/sosologo.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mat1.gtimg.com"
},
{
":path": "/www/images/qq2012/festival/da18search.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mat1.gtimg.com"
},
{
":path": "/www/images/qq2012/festival/da18bodybg05.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mat1.gtimg.com"
},
{
":path": "/www/images/qq2012/loginall_1.2.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mat1.gtimg.com"
},
{
":path": "/www/images/qq2012/aikanLoading1.1.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mat1.gtimg.com"
},
{
":path": "/joke/Koala/Qfast1.0.1.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mat1.gtimg.com"
},
{
":path": "/www/images/qq2012/mobileNews.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "img1.gtimg.com"
},
{
":path": "/v/pics/hv1/241/117/1186/77149726.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.qq.com/"
}
]
}
]
}

View File

@ -0,0 +1,339 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "sina.com.cn"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.sina.com.cn"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "news.sina.com.cn"
},
{
":path": "/js/87/20121024/201218ConfTop.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.sina.com.cn/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "int.dpool.sina.com.cn"
},
{
":path": "/iplookup/iplookup.php"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.sina.com.cn/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "i3.sinaimg.cn"
},
{
":path": "/video/2012/1103/U7805P167DT20121103211853.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.sina.com.cn/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "i3.sinaimg.cn"
},
{
":path": "/home/2012/1102/U6041P30DT20121102122146.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.sina.com.cn/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "i3.sinaimg.cn"
},
{
":path": "/home/deco/2009/0330/logo_home.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.sina.com.cn/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "d1.sina.com.cn"
},
{
":path": "/shh/lechan/20121016sina/logo1.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.sina.com.cn/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "i0.sinaimg.cn"
},
{
":path": "/home/2012/1103/U8551P30DT20121103063734.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.sina.com.cn/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "i1.sinaimg.cn"
},
{
":path": "/home/2012/1101/U6648P30DT20121101141432.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.sina.com.cn/"
}
]
}
]
}

View File

@ -0,0 +1,336 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "taobao.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.taobao.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.taobao.com"
},
{
":path": "/index_global.php"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "a.tbcdn.cn"
},
{
":path": "/p/fp/2011a/assets/space.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.taobao.com/index_global.php"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "a.tbcdn.cn"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.taobao.com/index_global.php"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "a.tbcdn.cn"
},
{
":path": "/p/fp/2011hk/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.taobao.com/index_global.php"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "a.tbcdn.cn"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.taobao.com/index_global.php"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "a.tbcdn.cn"
},
{
":path": "/p/fp/2010c/js/fp-direct-promo-min.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.taobao.com/index_global.php"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "img01.taobaocdn.com"
},
{
":path": "/tps/i1/T1fqY2XilfXXahsVgc-1000-40.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.taobao.com/index_global.php"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "img01.taobaocdn.com"
},
{
":path": "/tps/i1/T1rZiwXgtfXXXXXXXX-110-135.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.taobao.com/index_global.php"
}
]
}
]
}

View File

@ -0,0 +1,375 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "en.wikipedia.org"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "centralnotice_bucket=1; clicktracking-session=eJko6IiUcEm69ehQfaakQlJfiLy9lShNP; mediaWiki.user.bucket%3Aext.articleFeedback-tracking=10%3Atrack; mediaWiki.user.id=EM83jsjaqPzIMLwBTiKF3aLiiTKeweez; mediaWiki.user.bucket%3Aext.articleFeedback-options=8%3Ashow"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "en.wikipedia.org"
},
{
":path": "/wiki/Main_Page"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "centralnotice_bucket=1; clicktracking-session=eJko6IiUcEm69ehQfaakQlJfiLy9lShNP; mediaWiki.user.bucket%3Aext.articleFeedback-tracking=10%3Atrack; mediaWiki.user.id=EM83jsjaqPzIMLwBTiKF3aLiiTKeweez; mediaWiki.user.bucket%3Aext.articleFeedback-options=8%3Ashow"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "bits.wikimedia.org"
},
{
":path": "/en.wikipedia.org/load.php"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://en.wikipedia.org/wiki/Main_Page"
},
{
"if-modified-since": "Wed, 31 Oct 2012 17:52:04 GMT"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "bits.wikimedia.org"
},
{
":path": "/en.wikipedia.org/load.php"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://en.wikipedia.org/wiki/Main_Page"
},
{
"if-modified-since": "Thu, 01 Nov 2012 09:33:27 GMT"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "bits.wikimedia.org"
},
{
":path": "/en.wikipedia.org/load.php"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://en.wikipedia.org/wiki/Main_Page"
},
{
"if-modified-since": "Sat, 03 Nov 2012 12:53:27 GMT"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "bits.wikimedia.org"
},
{
":path": "/en.wikipedia.org/load.php"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://en.wikipedia.org/wiki/Main_Page"
},
{
"if-modified-since": "Wed, 31 Oct 2012 17:52:04 GMT"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "bits.wikimedia.org"
},
{
":path": "/en.wikipedia.org/load.php"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://en.wikipedia.org/wiki/Main_Page"
},
{
"if-modified-since": "Thu, 01 Nov 2012 09:33:27 GMT"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "upload.wikimedia.org"
},
{
":path": "/wikipedia/en/c/ca/Kanthirava_cropped.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://en.wikipedia.org/wiki/Main_Page"
},
{
"if-modified-since": "Fri, 02 Nov 2012 23:46:59 GMT"
},
{
"if-none-match": "288bdb2fd5e5a4f7272f58fcb083a7e1"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "upload.wikimedia.org"
},
{
":path": "/wikipedia/commons/thumb/d/d2/Dancing_girl_ajanta_%28cropped%29.jpg/72px-Dancing_girl_ajanta_%28cropped%29.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://en.wikipedia.org/wiki/Main_Page"
},
{
"if-modified-since": "Tue, 30 Oct 2012 17:37:15 GMT"
},
{
"if-none-match": "6e8d56df9be35494b4d9f0ea72ed1a3e"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "bits.wikimedia.org"
},
{
":path": "/en.wikipedia.org/load.php"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://en.wikipedia.org/wiki/Main_Page"
},
{
"if-modified-since": "Sat, 03 Nov 2012 12:53:27 GMT"
}
]
}
]
}

View File

@ -0,0 +1,348 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yahoo.co.jp"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "B=76j09a189a6h4&b=3&s=0b"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.yahoo.co.jp"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "B=76j09a189a6h4&b=3&s=0b"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "k.yimg.jp"
},
{
":path": "/images/top/sp2/clr/1/clr-121025.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yahoo.co.jp/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "k.yimg.jp"
},
{
":path": "/images/top/sp/logo.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yahoo.co.jp/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "k.yimg.jp"
},
{
":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_1.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yahoo.co.jp/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yjaxc.yahoo.co.jp"
},
{
":path": "/oi"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yahoo.co.jp/"
},
{
"cookie": "B=76j09a189a6h4&b=3&s=0b"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "k.yimg.jp"
},
{
":path": "/images/weather/general/transparent_s/clouds.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yahoo.co.jp/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "k.yimg.jp"
},
{
":path": "/images/weather/general/transparent_s/sun.gif"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yahoo.co.jp/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "k.yimg.jp"
},
{
":path": "/images/bookstore/common/special/2012/0829_05/banner/84x84_2.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yahoo.co.jp/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "k.yimg.jp"
},
{
":path": "/images/premium/contents/bnr/2012/50x50/0928_store_supernatural.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yahoo.co.jp/"
}
]
}
]
}

View File

@ -0,0 +1,351 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yahoo.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "d.yimg.com"
},
{
":path": "/hd/ch7news/7_world/1103_0700_nat_elephant_sml_1898chj-1898chl.jpg"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://au.yahoo.com/?p=us"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "au.yahoo.com"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"cookie": "B=4m2rqu589a507&b=3&s=1v"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "d.yimg.com"
},
{
":path": "/mi/ywa.js"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://au.yahoo.com/?p=us"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yui.yahooapis.com"
},
{
":path": "/combo"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://au.yahoo.com/?p=us"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "secure-au.imrworldwide.com"
},
{
":path": "/cgi-bin/m"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://au.yahoo.com/?p=us"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "chart.finance.yahoo.com"
},
{
":path": "/instrument/1.0/%5Eaxjo/chart;range=5d/image;size=179x98"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://au.yahoo.com/?p=us"
},
{
"cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "chart.finance.yahoo.com"
},
{
":path": "/instrument/1.0/%5Eaord/chart;range=5d/image;size=179x98"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://au.yahoo.com/?p=us"
},
{
"cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "chart.finance.yahoo.com"
},
{
":path": "/instrument/1.0/audusd=x/chart;range=5d/image;size=179x98"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://au.yahoo.com/?p=us"
},
{
"cookie": "B=4m2rqu589a507&b=3&s=1v; session_start_time=1351947275160; k_visit=1; push_time_start=1351947295160"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "cm.au.yahoo.overture.com"
},
{
":path": "/js_flat_1_0/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "*/*"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://au.yahoo.com/?p=us"
}
]
}
]
}

View File

@ -0,0 +1,345 @@
{
"context": "request",
"cases": [
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yandex.ru"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "www.yandex.ru"
},
{
":path": "/"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yabs.yandex.ru"
},
{
":path": "/count/Vnw_3zF2dkO40002Zhl8KGa5KPK2cmPfMeYpO2zG0vAeOuAefZIAgoA2KAe2fPOOP96yq4ba1fDKGQC1hlDVeQN8GfVD17e7"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yandex.ru/"
},
{
"cookie": "t=p; yandexuid=6410453771351949451"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yabs.yandex.ru"
},
{
":path": "/count/Vnw_3mft8wq40000Zhl8KGa5KP6yq4ba1fDKhlDVeQN8GfVD17a3=qcOn49K2cmPfMcbQagXZWgYAgoA2KAMM66IcD7W3"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yandex.ru/"
},
{
"cookie": "t=p; yandexuid=6410453771351949451"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yandex.st"
},
{
":path": "/lego/_/pDu9OWAQKB0s2J9IojKpiS_Eho.ico"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yandex.st"
},
{
":path": "/www/1.359/www/i/yandex3.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yandex.ru/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yandex.st"
},
{
":path": "/morda-logo/i/logo.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yandex.ru/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "mc.yandex.ru"
},
{
":path": "/watch/722545"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yandex.ru/"
},
{
"cookie": "t=p; yandexuid=6410453771351949451"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yandex.st"
},
{
":path": "/www/1.359/www/pages-desktop/www-css/_www-css.css"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "text/css,*/*;q=0.1"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yandex.ru/"
}
]
},
{
"headers": [
{
":method": "GET"
},
{
":scheme": "http"
},
{
":authority": "yandex.st"
},
{
":path": "/www/_/_r7pp-b-hKoDbgyGYy0IB3wlkno.png"
},
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"
},
{
"accept": "image/png,image/*;q=0.8,*/*;q=0.5"
},
{
"accept-language": "en-US,en;q=0.5"
},
{
"accept-encoding": "gzip, deflate"
},
{
"connection": "keep-alive"
},
{
"referer": "http://www.yandex.ru/"
}
]
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
# Jetty Logging using jetty-slf4j-impl
#org.eclipse.jetty.http2.LEVEL=DEBUG
#org.eclipse.jetty.http2.hpack.LEVEL=DEBUG

19
jetty-http3/pom.xml Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId>
<version>10.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-parent</artifactId>
<packaging>pom</packaging>
<name>Jetty :: HTTP3</name>
<modules>
<module>http3-qpack</module>
</modules>
</project>

View File

@ -197,9 +197,10 @@
<module>jetty-util</module>
<module>jetty-jmx</module>
<module>jetty-io</module>
<module>jetty-quic</module>
<module>jetty-http</module>
<module>jetty-http2</module>
<module>jetty-quic</module>
<module>jetty-http3</module>
<module>jetty-server</module>
<module>jetty-xml</module>
<module>jetty-security</module>