Skip to content

Commit 9463497

Browse files
committed
use basic compression for outbound headers
1 parent 8ccbd5f commit 9463497

File tree

1 file changed

+62
-9
lines changed

1 file changed

+62
-9
lines changed

src/main/java/robaho/net/httpserver/http2/hpack/HPackContext.java

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import robaho.net.httpserver.http2.HTTP2Exception;
1111

1212
import java.util.List;
13+
import java.util.Map;
1314

1415
import com.sun.net.httpserver.Headers;
1516

@@ -117,8 +118,6 @@ private int decodeDynamicTableSizeUpdate(byte[] buffer, int index) throws HTTP2E
117118
int size = pair.value;
118119
index = pair.index;
119120

120-
System.out.println("updating dynamic table size to "+size);
121-
122121
if (size > 4096) { // Assuming 4096 is the maximum size for the dynamic table
123122
throw new HTTP2Exception(HTTP2ErrorCode.COMPRESSION_ERROR, "Dynamic table size update too large: " + size);
124123
}
@@ -233,18 +232,27 @@ private static byte[] encodeHeadersFrame(Headers headers) {
233232
}
234233

235234
private static byte[] encodeHeader(String name, String value) {
236-
byte[] nameBytes = name.getBytes();
237-
byte[] valueBytes = value.getBytes();
235+
if(":status".equals(name)) {
236+
byte[] result = RFC7541Parser.STATUSES.get(value);
237+
if(result!=null) return result;
238+
}
239+
var index = RFC7541Parser.getIndex(name);
240+
238241
byte[] buffer = new byte[1];
239242
buffer[0]=0x00; // Literal Header Field without Indexing
240243

241-
// Encode header name
242-
byte[] header = encodeString(nameBytes);
243-
buffer = Arrays.copyOf(buffer, buffer.length + header.length);
244-
System.arraycopy(header, 0, buffer, buffer.length - header.length, header.length);
244+
if(index!=null) {
245+
buffer = encodeIndexedField(index,4);
246+
} else {
247+
byte[] nameBytes = name.getBytes();
248+
byte[] header = encodeString(nameBytes);
249+
buffer = Arrays.copyOf(buffer, buffer.length + header.length);
250+
System.arraycopy(header, 0, buffer, buffer.length - header.length, header.length);
251+
}
245252

246253
// Encode header value
247-
header = encodeString(valueBytes);
254+
byte[] valueBytes = value.getBytes();
255+
byte[] header = encodeString(valueBytes);
248256
buffer = Arrays.copyOf(buffer, buffer.length + header.length);
249257
System.arraycopy(header, 0, buffer, buffer.length - header.length, header.length);
250258

@@ -267,11 +275,44 @@ private static byte[] encodeString(byte[] value) {
267275
return buffer;
268276
}
269277

278+
private static byte[] encodeIndexedField(int index, int prefixBits) {
279+
byte[] buffer = new byte[1];
280+
int mask = (1 << prefixBits) - 1;
281+
if (index < mask) {
282+
buffer[0] = (byte) index;
283+
return buffer;
284+
}
285+
buffer[0] = (byte) mask;
286+
index -= mask;
287+
while (index >= 128) {
288+
buffer = Arrays.copyOf(buffer, buffer.length + 1);
289+
buffer[buffer.length - 1] = (byte) ((index & 0x7F) | 0x80);
290+
index >>>= 7;
291+
}
292+
buffer = Arrays.copyOf(buffer, buffer.length + 1);
293+
buffer[buffer.length - 1] = (byte) index;
294+
return buffer;
295+
}
296+
270297
}
271298

272299
class RFC7541Parser {
273300

274301
private static final HTTP2HeaderField[] STATIC_HEADER_TABLE = new HTTP2HeaderField[62];
302+
static final Map<String,byte[]> STATUSES = Map.of(
303+
"200",indexedField(8),
304+
"204",indexedField(9),
305+
"206",indexedField(10),
306+
"304",indexedField(11),
307+
"400",indexedField(12),
308+
"404",indexedField(13),
309+
"500",indexedField(13));
310+
311+
private static byte[] indexedField(int index) {
312+
byte[] buffer = new byte[1];
313+
buffer[0] = (byte) (0x80 | index);
314+
return buffer;
315+
}
275316

276317
static {
277318
STATIC_HEADER_TABLE[1] = new HTTP2HeaderField(":authority", null);
@@ -337,6 +378,18 @@ class RFC7541Parser {
337378
STATIC_HEADER_TABLE[61] = new HTTP2HeaderField("www-authenticate", null);
338379
}
339380

381+
private static final Map<String, Integer> STATIC_HEADER_NAME_TO_INDEX = Arrays.stream(STATIC_HEADER_TABLE)
382+
.filter(f -> f != null)
383+
.collect(java.util.stream.Collectors.toMap(
384+
f -> f.name,
385+
f -> Arrays.asList(STATIC_HEADER_TABLE).indexOf(f),
386+
(a, b) -> a
387+
));
388+
389+
public static Integer getIndex(String name) {
390+
return STATIC_HEADER_NAME_TO_INDEX.get(name);
391+
}
392+
340393
public static HTTP2HeaderField getHeaderField(int index) {
341394
if (index < 1 || index >= STATIC_HEADER_TABLE.length) {
342395
return null;

0 commit comments

Comments
 (0)