mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
[windows] fix(http2) (#8734)
* fix win http2 * add includes * cleanup * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1286,7 +1286,9 @@ else()
|
||||
endif()
|
||||
|
||||
if(USE_CUSTOM_LSHPACK)
|
||||
include_directories(${BUN_DEPS_DIR}/ls-hpack)
|
||||
if(WIN32)
|
||||
include_directories(${BUN_DEPS_DIR}/ls-hpack/compat/queue)
|
||||
target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/lshpack.lib")
|
||||
else()
|
||||
target_link_libraries(${bun} PRIVATE "${BUN_DEPS_OUT_DIR}/liblshpack.a")
|
||||
@@ -1332,4 +1334,4 @@ endif()
|
||||
|
||||
if(NO_CODEGEN)
|
||||
message(STATUS "NOTE: NO_CODEGEN is ON, this build expects ./codegen to exist")
|
||||
endif()
|
||||
endif()
|
||||
@@ -5,7 +5,7 @@ const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const JSC = bun.JSC;
|
||||
const MutableString = bun.MutableString;
|
||||
const lshpack = @import("./lshpack.translated.zig");
|
||||
const lshpack = @import("./lshpack.zig");
|
||||
|
||||
const JSValue = JSC.JSValue;
|
||||
|
||||
@@ -540,10 +540,15 @@ pub const H2FrameParser = struct {
|
||||
// used window size for the connection
|
||||
usedWindowSize: u32 = 0,
|
||||
lastStreamID: u32 = 0,
|
||||
firstSettingsACK: bool = false,
|
||||
// we buffer requests until we get the first settings ACK
|
||||
writeBuffer: bun.ByteList = .{},
|
||||
|
||||
streams: bun.U32HashMap(Stream),
|
||||
|
||||
decoder: lshpack.lshpack_dec = undefined,
|
||||
encoder: lshpack.lshpack_enc = undefined,
|
||||
hpack: ?*lshpack.HPACK = null,
|
||||
|
||||
threadlocal var shared_request_buffer: [16384]u8 = undefined;
|
||||
|
||||
const Stream = struct {
|
||||
id: u32 = 0,
|
||||
@@ -620,50 +625,18 @@ pub const H2FrameParser = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const HeaderValue = struct {
|
||||
name: []const u8,
|
||||
value: []const u8,
|
||||
next: usize,
|
||||
};
|
||||
const HeaderValue = lshpack.HPACK.DecodeResult;
|
||||
|
||||
pub fn decode(this: *H2FrameParser, header_buffer: *[MAX_HPACK_HEADER_SIZE]u8, src_buffer: []const u8) !HeaderValue {
|
||||
var xhdr: lshpack.lsxpack_header = .{};
|
||||
|
||||
lshpack.lsxpack_header_prepare_decode(&xhdr, header_buffer.ptr, 0, header_buffer.len);
|
||||
const next = try lshpack.lshpack_decode(&this.decoder, src_buffer.ptr, src_buffer.len, &xhdr);
|
||||
|
||||
const name = lshpack.lsxpack_header_get_name(&xhdr);
|
||||
if (name.len == 0) {
|
||||
return error.EmptyHeaderName;
|
||||
pub fn decode(this: *H2FrameParser, src_buffer: []const u8) !HeaderValue {
|
||||
if (this.hpack) |hpack| {
|
||||
return try hpack.decode(src_buffer);
|
||||
}
|
||||
|
||||
return .{
|
||||
.name = name,
|
||||
.value = lshpack.lsxpack_header_get_value(&xhdr),
|
||||
.next = next,
|
||||
};
|
||||
return error.UnableToDecode;
|
||||
}
|
||||
|
||||
pub fn encode(this: *H2FrameParser, header_buffer: *[MAX_HPACK_HEADER_SIZE]u8, dst_buffer: []const u8, name: []const u8, value: []const u8, never_index: bool) !usize {
|
||||
var xhdr: lshpack.lsxpack_header = .{ .indexed_type = if (never_index) 2 else 0 };
|
||||
const size = name.len + value.len;
|
||||
if (size > MAX_HPACK_HEADER_SIZE) {
|
||||
return error.HeaderTooLarge;
|
||||
}
|
||||
|
||||
@memcpy(header_buffer[0..name.len], name);
|
||||
@memcpy(header_buffer[name.len..size], value);
|
||||
lshpack.lsxpack_header_set_offset2(&xhdr, header_buffer.ptr, 0, name.len, name.len, value.len);
|
||||
if (never_index) {
|
||||
xhdr.indexed_type = 2;
|
||||
}
|
||||
|
||||
const start = @intFromPtr(dst_buffer.ptr);
|
||||
log("encode xhdr name {} {} val {} {}", .{ xhdr.name_offset, xhdr.name_len, xhdr.val_offset, xhdr.val_len });
|
||||
const ptr = lshpack.lshpack_enc_encode(&this.encoder, dst_buffer.ptr, @ptrFromInt(start + dst_buffer.len), &xhdr);
|
||||
const end = @intFromPtr(ptr) - start;
|
||||
if (end > 0) {
|
||||
return end;
|
||||
pub fn encode(this: *H2FrameParser, dst_buffer: []u8, dst_offset: usize, name: []const u8, value: []const u8, never_index: bool) !usize {
|
||||
if (this.hpack) |hpack| {
|
||||
return try hpack.encode(name, value, never_index, dst_buffer, dst_offset);
|
||||
}
|
||||
return error.UnableToEncode;
|
||||
}
|
||||
@@ -846,6 +819,7 @@ pub const H2FrameParser = struct {
|
||||
JSC.markBinding(@src());
|
||||
const ctx_value = this.strong_ctx.get() orelse return;
|
||||
value.ensureStillAlive();
|
||||
extra.ensureStillAlive();
|
||||
_ = this.handlers.callEventHandler(event, ctx_value, &[_]JSC.JSValue{ ctx_value, value, extra });
|
||||
}
|
||||
|
||||
@@ -853,13 +827,19 @@ pub const H2FrameParser = struct {
|
||||
JSC.markBinding(@src());
|
||||
const ctx_value = this.strong_ctx.get() orelse return;
|
||||
value.ensureStillAlive();
|
||||
extra.ensureStillAlive();
|
||||
extra2.ensureStillAlive();
|
||||
_ = this.handlers.callEventHandler(event, ctx_value, &[_]JSC.JSValue{ ctx_value, value, extra, extra2 });
|
||||
}
|
||||
|
||||
fn bufferWrite(this: *H2FrameParser, bytes: []const u8) void {
|
||||
log("bufferWrite", .{});
|
||||
_ = this.writeBuffer.write(this.allocator, bytes) catch 0;
|
||||
}
|
||||
|
||||
pub fn write(this: *H2FrameParser, bytes: []const u8) void {
|
||||
JSC.markBinding(@src());
|
||||
log("write", .{});
|
||||
|
||||
const output_value = this.handlers.binary_type.toJS(bytes, this.handlers.globalObject);
|
||||
this.dispatch(.onWrite, output_value);
|
||||
}
|
||||
@@ -877,7 +857,7 @@ pub const H2FrameParser = struct {
|
||||
this.remainingLength -= @intCast(end);
|
||||
if (this.remainingLength > 0) {
|
||||
// buffer more data
|
||||
_ = this.readBuffer.appendSlice(payload) catch @panic("OOM");
|
||||
_ = this.readBuffer.appendSlice(payload) catch bun.outOfMemory();
|
||||
return null;
|
||||
} else if (this.remainingLength < 0) {
|
||||
this.sendGoAway(streamIdentifier, ErrorCode.FRAME_SIZE_ERROR, "Invalid frame size", this.lastStreamID);
|
||||
@@ -885,6 +865,16 @@ pub const H2FrameParser = struct {
|
||||
}
|
||||
|
||||
this.currentFrame = null;
|
||||
|
||||
if (this.readBuffer.list.items.len > 0) {
|
||||
// return buffered data
|
||||
_ = this.readBuffer.appendSlice(payload) catch bun.outOfMemory();
|
||||
return .{
|
||||
.data = this.readBuffer.list.items,
|
||||
.end = end,
|
||||
};
|
||||
}
|
||||
|
||||
return .{
|
||||
.data = payload,
|
||||
.end = end,
|
||||
@@ -919,14 +909,13 @@ pub const H2FrameParser = struct {
|
||||
pub fn decodeHeaderBlock(this: *H2FrameParser, payload: []const u8, stream_id: u32, flags: u8) void {
|
||||
log("decodeHeaderBlock", .{});
|
||||
|
||||
var header_buffer: [MAX_HPACK_HEADER_SIZE]u8 = undefined;
|
||||
var offset: usize = 0;
|
||||
|
||||
const globalObject = this.handlers.globalObject;
|
||||
|
||||
const headers = JSC.JSValue.createEmptyObject(globalObject, 0);
|
||||
while (true) {
|
||||
const header = this.decode(&header_buffer, payload[offset..]) catch break;
|
||||
const header = this.decode(payload[offset..]) catch break;
|
||||
offset += header.next;
|
||||
log("header {s} {s}", .{ header.name, header.value });
|
||||
const value = JSC.ZigString.fromUTF8(header.value).toValueGC(globalObject);
|
||||
@@ -1042,12 +1031,12 @@ pub const H2FrameParser = struct {
|
||||
const last_stream_id: u32 = @intCast(UInt31WithReserved.fromBytes(payload[0..4]).uint31);
|
||||
const error_code = UInt31WithReserved.fromBytes(payload[4..8]).toUInt32();
|
||||
const chunk = this.handlers.binary_type.toJS(payload[8..], this.handlers.globalObject);
|
||||
this.readBuffer.reset();
|
||||
if (error_code != @intFromEnum(ErrorCode.NO_ERROR)) {
|
||||
this.dispatchWith2Extra(.onGoAway, JSC.JSValue.jsNumber(error_code), JSC.JSValue.jsNumber(last_stream_id), chunk);
|
||||
} else {
|
||||
this.dispatchWithExtra(.onGoAway, JSC.JSValue.jsNumber(last_stream_id), chunk);
|
||||
}
|
||||
this.readBuffer.reset();
|
||||
return content.end;
|
||||
}
|
||||
return data.len;
|
||||
@@ -1096,12 +1085,13 @@ pub const H2FrameParser = struct {
|
||||
if (handleIncommingPayload(this, data, frame.streamIdentifier)) |content| {
|
||||
const payload = content.data;
|
||||
const isNotACK = frame.flags & @intFromEnum(PingFrameFlags.ACK) == 0;
|
||||
this.dispatchWithExtra(.onPing, this.handlers.binary_type.toJS(payload, this.handlers.globalObject), JSC.JSValue.jsBoolean(!isNotACK));
|
||||
// if is not ACK send response
|
||||
if (isNotACK) {
|
||||
this.sendPing(true, payload);
|
||||
}
|
||||
const buffer = this.handlers.binary_type.toJS(payload, this.handlers.globalObject);
|
||||
this.readBuffer.reset();
|
||||
this.dispatchWithExtra(.onPing, buffer, JSC.JSValue.jsBoolean(!isNotACK));
|
||||
return content.end;
|
||||
}
|
||||
return data.len;
|
||||
@@ -1156,7 +1146,6 @@ pub const H2FrameParser = struct {
|
||||
stream.isWaitingMoreHeaders = false;
|
||||
}
|
||||
|
||||
this.readBuffer.reset();
|
||||
return content.end;
|
||||
}
|
||||
|
||||
@@ -1196,10 +1185,12 @@ pub const H2FrameParser = struct {
|
||||
}
|
||||
const end = payload.len - padding;
|
||||
if (offset > end) {
|
||||
this.readBuffer.reset();
|
||||
this.sendGoAway(frame.streamIdentifier, ErrorCode.FRAME_SIZE_ERROR, "invalid Headers frame size", this.lastStreamID);
|
||||
return data.len;
|
||||
}
|
||||
this.decodeHeaderBlock(payload[offset..end], stream.id, frame.flags);
|
||||
this.readBuffer.reset();
|
||||
stream.isWaitingMoreHeaders = frame.flags & @intFromEnum(HeadersFrameFlags.END_HEADERS) == 0;
|
||||
if (frame.flags & @intFromEnum(HeadersFrameFlags.END_STREAM) != 0) {
|
||||
if (stream.isWaitingMoreHeaders) {
|
||||
@@ -1214,8 +1205,6 @@ pub const H2FrameParser = struct {
|
||||
if (stream.endAfterHeaders) {
|
||||
this.endStream(stream, ErrorCode.NO_ERROR);
|
||||
}
|
||||
|
||||
this.readBuffer.reset();
|
||||
return content.end;
|
||||
}
|
||||
|
||||
@@ -1239,6 +1228,9 @@ pub const H2FrameParser = struct {
|
||||
if (frame.flags & 0x1 != 0) {
|
||||
// we received an ACK
|
||||
log("settings frame ACK", .{});
|
||||
// we can now write any request
|
||||
this.firstSettingsACK = true;
|
||||
this.flush();
|
||||
this.remoteSettings = this.localSettings;
|
||||
this.dispatch(.onLocalSettings, this.localSettings.toJS(this.handlers.globalObject));
|
||||
}
|
||||
@@ -1282,7 +1274,7 @@ pub const H2FrameParser = struct {
|
||||
|
||||
// new stream open
|
||||
const settings = this.remoteSettings orelse this.localSettings;
|
||||
const entry = this.streams.getOrPut(streamIdentifier) catch @panic("OOM");
|
||||
const entry = this.streams.getOrPut(streamIdentifier) catch bun.outOfMemory();
|
||||
entry.value_ptr.* = Stream.init(streamIdentifier, settings.initialWindowSize, this);
|
||||
|
||||
this.dispatch(.onStreamStart, JSC.JSValue.jsNumber(streamIdentifier));
|
||||
@@ -1295,16 +1287,16 @@ pub const H2FrameParser = struct {
|
||||
log("current frame {} {} {} {}", .{ header.type, header.length, header.flags, header.streamIdentifier });
|
||||
|
||||
const stream = this.handleReceivedStreamID(header.streamIdentifier);
|
||||
return switch (@as(FrameType, @enumFromInt(header.type))) {
|
||||
FrameType.HTTP_FRAME_SETTINGS => this.handleSettingsFrame(header, bytes),
|
||||
FrameType.HTTP_FRAME_WINDOW_UPDATE => this.handleWindowUpdateFrame(header, bytes, stream),
|
||||
FrameType.HTTP_FRAME_HEADERS => this.handleHeadersFrame(header, bytes, stream),
|
||||
FrameType.HTTP_FRAME_DATA => this.handleDataFrame(header, bytes, stream),
|
||||
FrameType.HTTP_FRAME_CONTINUATION => this.handleContinuationFrame(header, bytes, stream),
|
||||
FrameType.HTTP_FRAME_PRIORITY => this.handlePriorityFrame(header, bytes, stream),
|
||||
FrameType.HTTP_FRAME_PING => this.handlePingFrame(header, bytes, stream),
|
||||
FrameType.HTTP_FRAME_GOAWAY => this.handleGoAwayFrame(header, bytes, stream),
|
||||
FrameType.HTTP_FRAME_RST_STREAM => this.handleRSTStreamFrame(header, bytes, stream),
|
||||
return switch (header.type) {
|
||||
@intFromEnum(FrameType.HTTP_FRAME_SETTINGS) => this.handleSettingsFrame(header, bytes),
|
||||
@intFromEnum(FrameType.HTTP_FRAME_WINDOW_UPDATE) => this.handleWindowUpdateFrame(header, bytes, stream),
|
||||
@intFromEnum(FrameType.HTTP_FRAME_HEADERS) => this.handleHeadersFrame(header, bytes, stream),
|
||||
@intFromEnum(FrameType.HTTP_FRAME_DATA) => this.handleDataFrame(header, bytes, stream),
|
||||
@intFromEnum(FrameType.HTTP_FRAME_CONTINUATION) => this.handleContinuationFrame(header, bytes, stream),
|
||||
@intFromEnum(FrameType.HTTP_FRAME_PRIORITY) => this.handlePriorityFrame(header, bytes, stream),
|
||||
@intFromEnum(FrameType.HTTP_FRAME_PING) => this.handlePingFrame(header, bytes, stream),
|
||||
@intFromEnum(FrameType.HTTP_FRAME_GOAWAY) => this.handleGoAwayFrame(header, bytes, stream),
|
||||
@intFromEnum(FrameType.HTTP_FRAME_RST_STREAM) => this.handleRSTStreamFrame(header, bytes, stream),
|
||||
else => {
|
||||
this.sendGoAway(header.streamIdentifier, ErrorCode.PROTOCOL_ERROR, "Unknown frame type", this.lastStreamID);
|
||||
return bytes.len;
|
||||
@@ -1323,7 +1315,7 @@ pub const H2FrameParser = struct {
|
||||
const total = buffered_data + bytes.len;
|
||||
if (total < FrameHeader.byteSize) {
|
||||
// buffer more data
|
||||
_ = this.readBuffer.appendSlice(bytes) catch @panic("OOM");
|
||||
_ = this.readBuffer.appendSlice(bytes) catch bun.outOfMemory();
|
||||
return bytes.len;
|
||||
}
|
||||
FrameHeader.from(&header, this.readBuffer.list.items[0..buffered_data], 0, false);
|
||||
@@ -1340,16 +1332,16 @@ pub const H2FrameParser = struct {
|
||||
log("new frame {} {} {} {}", .{ header.type, header.length, header.flags, header.streamIdentifier });
|
||||
const stream = this.handleReceivedStreamID(header.streamIdentifier);
|
||||
this.ajustWindowSize(stream, header.length);
|
||||
return switch (@as(FrameType, @enumFromInt(header.type))) {
|
||||
FrameType.HTTP_FRAME_SETTINGS => this.handleSettingsFrame(header, bytes[needed..]) + needed,
|
||||
FrameType.HTTP_FRAME_WINDOW_UPDATE => this.handleWindowUpdateFrame(header, bytes[needed..], stream) + needed,
|
||||
FrameType.HTTP_FRAME_HEADERS => this.handleHeadersFrame(header, bytes[needed..], stream) + needed,
|
||||
FrameType.HTTP_FRAME_DATA => this.handleDataFrame(header, bytes[needed..], stream) + needed,
|
||||
FrameType.HTTP_FRAME_CONTINUATION => this.handleContinuationFrame(header, bytes[needed..], stream) + needed,
|
||||
FrameType.HTTP_FRAME_PRIORITY => this.handlePriorityFrame(header, bytes[needed..], stream) + needed,
|
||||
FrameType.HTTP_FRAME_PING => this.handlePingFrame(header, bytes[needed..], stream) + needed,
|
||||
FrameType.HTTP_FRAME_GOAWAY => this.handleGoAwayFrame(header, bytes[needed..], stream) + needed,
|
||||
FrameType.HTTP_FRAME_RST_STREAM => this.handleRSTStreamFrame(header, bytes[needed..], stream) + needed,
|
||||
return switch (header.type) {
|
||||
@intFromEnum(FrameType.HTTP_FRAME_SETTINGS) => this.handleSettingsFrame(header, bytes[needed..]) + needed,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_WINDOW_UPDATE) => this.handleWindowUpdateFrame(header, bytes[needed..], stream) + needed,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_HEADERS) => this.handleHeadersFrame(header, bytes[needed..], stream) + needed,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_DATA) => this.handleDataFrame(header, bytes[needed..], stream) + needed,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_CONTINUATION) => this.handleContinuationFrame(header, bytes[needed..], stream) + needed,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_PRIORITY) => this.handlePriorityFrame(header, bytes[needed..], stream) + needed,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_PING) => this.handlePingFrame(header, bytes[needed..], stream) + needed,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_GOAWAY) => this.handleGoAwayFrame(header, bytes[needed..], stream) + needed,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_RST_STREAM) => this.handleRSTStreamFrame(header, bytes[needed..], stream) + needed,
|
||||
else => {
|
||||
this.sendGoAway(header.streamIdentifier, ErrorCode.PROTOCOL_ERROR, "Unknown frame type", this.lastStreamID);
|
||||
return bytes.len;
|
||||
@@ -1359,7 +1351,7 @@ pub const H2FrameParser = struct {
|
||||
|
||||
if (bytes.len < FrameHeader.byteSize) {
|
||||
// buffer more dheaderata
|
||||
this.readBuffer.appendSlice(bytes) catch @panic("OOM");
|
||||
this.readBuffer.appendSlice(bytes) catch bun.outOfMemory();
|
||||
return bytes.len;
|
||||
}
|
||||
|
||||
@@ -1370,16 +1362,16 @@ pub const H2FrameParser = struct {
|
||||
this.remainingLength = header.length;
|
||||
const stream = this.handleReceivedStreamID(header.streamIdentifier);
|
||||
this.ajustWindowSize(stream, header.length);
|
||||
return switch (@as(FrameType, @enumFromInt(header.type))) {
|
||||
FrameType.HTTP_FRAME_SETTINGS => this.handleSettingsFrame(header, bytes[FrameHeader.byteSize..]) + FrameHeader.byteSize,
|
||||
FrameType.HTTP_FRAME_WINDOW_UPDATE => this.handleWindowUpdateFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
FrameType.HTTP_FRAME_HEADERS => this.handleHeadersFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
FrameType.HTTP_FRAME_DATA => this.handleDataFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
FrameType.HTTP_FRAME_CONTINUATION => this.handleContinuationFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
FrameType.HTTP_FRAME_PRIORITY => this.handlePriorityFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
FrameType.HTTP_FRAME_PING => this.handlePingFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
FrameType.HTTP_FRAME_GOAWAY => this.handleGoAwayFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
FrameType.HTTP_FRAME_RST_STREAM => this.handleRSTStreamFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
return switch (header.type) {
|
||||
@intFromEnum(FrameType.HTTP_FRAME_SETTINGS) => this.handleSettingsFrame(header, bytes[FrameHeader.byteSize..]) + FrameHeader.byteSize,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_WINDOW_UPDATE) => this.handleWindowUpdateFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_HEADERS) => this.handleHeadersFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_DATA) => this.handleDataFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_CONTINUATION) => this.handleContinuationFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_PRIORITY) => this.handlePriorityFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_PING) => this.handlePingFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_GOAWAY) => this.handleGoAwayFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
@intFromEnum(FrameType.HTTP_FRAME_RST_STREAM) => this.handleRSTStreamFrame(header, bytes[FrameHeader.byteSize..], stream) + FrameHeader.byteSize,
|
||||
else => {
|
||||
this.sendGoAway(header.streamIdentifier, ErrorCode.PROTOCOL_ERROR, "Unknown frame type", this.lastStreamID);
|
||||
return bytes.len;
|
||||
@@ -1389,15 +1381,34 @@ pub const H2FrameParser = struct {
|
||||
|
||||
const DirectWriterStruct = struct {
|
||||
writer: *H2FrameParser,
|
||||
shouldBuffer: bool = true,
|
||||
pub fn write(this: *const DirectWriterStruct, data: []const u8) !bool {
|
||||
if (this.shouldBuffer) {
|
||||
_ = this.writer.writeBuffer.write(this.writer.allocator, data) catch return false;
|
||||
return true;
|
||||
}
|
||||
this.writer.write(data);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
fn toWriter(this: *H2FrameParser) DirectWriterStruct {
|
||||
return DirectWriterStruct{ .writer = this };
|
||||
return DirectWriterStruct{ .writer = this, .shouldBuffer = false };
|
||||
}
|
||||
|
||||
fn getBufferWriter(this: *H2FrameParser) DirectWriterStruct {
|
||||
return DirectWriterStruct{ .writer = this, .shouldBuffer = true };
|
||||
}
|
||||
|
||||
fn flush(this: *H2FrameParser) void {
|
||||
if (this.writeBuffer.len > 0) {
|
||||
const slice = this.writeBuffer.slice();
|
||||
this.write(slice);
|
||||
// we will only flush one time
|
||||
this.writeBuffer.deinitWithAllocator(this.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setEncoding(this: *H2FrameParser, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
|
||||
JSC.markBinding(@src());
|
||||
const args_list = callframe.arguments(1);
|
||||
@@ -1887,7 +1898,9 @@ pub const H2FrameParser = struct {
|
||||
return JSC.JSValue.jsBoolean(true);
|
||||
}
|
||||
fn sendData(this: *H2FrameParser, stream_id: u32, payload: []const u8, close: bool) void {
|
||||
const writer = this.toWriter();
|
||||
log("sendData({}, {}, {})", .{ stream_id, payload.len, close });
|
||||
|
||||
const writer = if (this.firstSettingsACK) this.toWriter() else this.getBufferWriter();
|
||||
if (payload.len == 0) {
|
||||
// empty payload we still need to send a frame
|
||||
var dataHeader: FrameHeader = .{
|
||||
@@ -1914,7 +1927,7 @@ pub const H2FrameParser = struct {
|
||||
.length = size,
|
||||
};
|
||||
dataHeader.write(@TypeOf(writer), writer);
|
||||
this.write(slice);
|
||||
_ = writer.write(slice) catch 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1958,9 +1971,7 @@ pub const H2FrameParser = struct {
|
||||
}
|
||||
|
||||
// max frame size will be always at least 16384
|
||||
var buffer: [16384 - FrameHeader.byteSize]u8 = undefined;
|
||||
var header_buffer: [MAX_HPACK_HEADER_SIZE]u8 = undefined;
|
||||
@memset(&buffer, 0);
|
||||
var buffer = shared_request_buffer[0 .. shared_request_buffer.len - FrameHeader.byteSize];
|
||||
|
||||
var encoded_size: usize = 0;
|
||||
|
||||
@@ -2016,7 +2027,7 @@ pub const H2FrameParser = struct {
|
||||
defer value_slice.deinit();
|
||||
const value = value_slice.slice();
|
||||
log("encode header {s} {s}", .{ name, value });
|
||||
encoded_size += this.encode(&header_buffer, buffer[encoded_size..], name, value_slice.slice(), never_index) catch {
|
||||
encoded_size += this.encode(buffer, encoded_size, name, value, never_index) catch {
|
||||
stream.state = .CLOSED;
|
||||
stream.rstCode = @intFromEnum(ErrorCode.COMPRESSION_ERROR);
|
||||
this.dispatchWithExtra(.onStreamError, JSC.JSValue.jsNumber(stream_id), JSC.JSValue.jsNumber(stream.rstCode));
|
||||
@@ -2036,7 +2047,7 @@ pub const H2FrameParser = struct {
|
||||
defer value_slice.deinit();
|
||||
const value = value_slice.slice();
|
||||
log("encode header {s} {s}", .{ name, value });
|
||||
encoded_size += this.encode(&header_buffer, buffer[encoded_size..], name, value_slice.slice(), never_index) catch {
|
||||
encoded_size += this.encode(buffer, encoded_size, name, value, never_index) catch {
|
||||
stream.state = .CLOSED;
|
||||
stream.rstCode = @intFromEnum(ErrorCode.COMPRESSION_ERROR);
|
||||
this.dispatchWithExtra(.onStreamError, JSC.JSValue.jsNumber(stream_id), JSC.JSValue.jsNumber(stream.rstCode));
|
||||
@@ -2053,9 +2064,9 @@ pub const H2FrameParser = struct {
|
||||
.streamIdentifier = stream.id,
|
||||
.length = @intCast(encoded_size),
|
||||
};
|
||||
const writer = this.toWriter();
|
||||
const writer = if (this.firstSettingsACK) this.toWriter() else this.getBufferWriter();
|
||||
frame.write(@TypeOf(writer), writer);
|
||||
this.write(buffer[0..encoded_size]);
|
||||
_ = writer.write(buffer[0..encoded_size]) catch 0;
|
||||
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
@@ -2154,9 +2165,7 @@ pub const H2FrameParser = struct {
|
||||
}
|
||||
|
||||
// max frame size will be always at least 16384
|
||||
var buffer: [16384 - FrameHeader.byteSize - 5]u8 = undefined;
|
||||
var header_buffer: [MAX_HPACK_HEADER_SIZE]u8 = undefined;
|
||||
@memset(&buffer, 0);
|
||||
var buffer = shared_request_buffer[0 .. shared_request_buffer.len - FrameHeader.byteSize - 5];
|
||||
|
||||
var encoded_size: usize = 0;
|
||||
|
||||
@@ -2227,7 +2236,7 @@ pub const H2FrameParser = struct {
|
||||
defer value_slice.deinit();
|
||||
const value = value_slice.slice();
|
||||
log("encode header {s} {s}", .{ name, value });
|
||||
encoded_size += this.encode(&header_buffer, buffer[encoded_size..], name, value_slice.slice(), never_index) catch {
|
||||
encoded_size += this.encode(buffer, encoded_size, name, value, never_index) catch {
|
||||
const stream = this.handleReceivedStreamID(stream_id) orelse {
|
||||
return JSC.JSValue.jsNumber(-1);
|
||||
};
|
||||
@@ -2251,7 +2260,7 @@ pub const H2FrameParser = struct {
|
||||
defer value_slice.deinit();
|
||||
const value = value_slice.slice();
|
||||
log("encode header {s} {s}", .{ name, value });
|
||||
encoded_size += this.encode(&header_buffer, buffer[encoded_size..], name, value_slice.slice(), never_index) catch {
|
||||
encoded_size += this.encode(buffer, encoded_size, name, value, never_index) catch {
|
||||
const stream = this.handleReceivedStreamID(stream_id) orelse {
|
||||
return JSC.JSValue.jsNumber(-1);
|
||||
};
|
||||
@@ -2374,7 +2383,8 @@ pub const H2FrameParser = struct {
|
||||
.streamIdentifier = stream.id,
|
||||
.length = @intCast(encoded_size),
|
||||
};
|
||||
const writer = this.toWriter();
|
||||
|
||||
const writer = if (this.firstSettingsACK) this.toWriter() else this.getBufferWriter();
|
||||
frame.write(@TypeOf(writer), writer);
|
||||
//https://datatracker.ietf.org/doc/html/rfc7540#section-6.2
|
||||
if (has_priority) {
|
||||
@@ -2391,7 +2401,7 @@ pub const H2FrameParser = struct {
|
||||
priority.write(@TypeOf(writer), writer);
|
||||
}
|
||||
|
||||
this.write(buffer[0..encoded_size]);
|
||||
_ = writer.write(buffer[0..encoded_size]) catch 0;
|
||||
|
||||
if (end_stream) {
|
||||
stream.state = .HALF_CLOSED_LOCAL;
|
||||
@@ -2414,9 +2424,9 @@ pub const H2FrameParser = struct {
|
||||
return .zero;
|
||||
}
|
||||
const buffer = args_list.ptr[0];
|
||||
buffer.ensureStillAlive();
|
||||
if (buffer.asArrayBuffer(globalObject)) |array_buffer| {
|
||||
var bytes = array_buffer.byteSlice();
|
||||
|
||||
// read all the bytes
|
||||
while (bytes.len > 0) {
|
||||
const result = this.readBytes(bytes);
|
||||
@@ -2482,13 +2492,7 @@ pub const H2FrameParser = struct {
|
||||
|
||||
this.strong_ctx.set(globalObject, context_obj);
|
||||
|
||||
if (lshpack.lshpack_enc_init(&this.encoder) != 0) {
|
||||
@panic("OOM");
|
||||
}
|
||||
lshpack.lshpack_dec_init(&this.decoder);
|
||||
lshpack.lshpack_enc_set_max_capacity(&this.encoder, this.localSettings.headerTableSize);
|
||||
lshpack.lshpack_dec_set_max_capacity(&this.decoder, this.localSettings.headerTableSize);
|
||||
|
||||
this.hpack = lshpack.HPACK.init(this.localSettings.headerTableSize);
|
||||
this.sendPrefaceAndSettings();
|
||||
return this;
|
||||
}
|
||||
@@ -2499,9 +2503,12 @@ pub const H2FrameParser = struct {
|
||||
this.strong_ctx.deinit();
|
||||
this.handlers.deinit();
|
||||
this.readBuffer.deinit();
|
||||
this.writeBuffer.deinitWithAllocator(allocator);
|
||||
|
||||
lshpack.lshpack_dec_cleanup(&this.decoder);
|
||||
lshpack.lshpack_enc_cleanup(&this.encoder);
|
||||
if (this.hpack) |hpack| {
|
||||
hpack.deinit();
|
||||
this.hpack = null;
|
||||
}
|
||||
|
||||
var it = this.streams.iterator();
|
||||
while (it.next()) |*entry| {
|
||||
|
||||
@@ -1,448 +0,0 @@
|
||||
pub const __builtin_bswap16 = @import("std").zig.c_builtins.__builtin_bswap16;
|
||||
pub const __builtin_bswap32 = @import("std").zig.c_builtins.__builtin_bswap32;
|
||||
pub const __builtin_bswap64 = @import("std").zig.c_builtins.__builtin_bswap64;
|
||||
pub const __builtin_signbit = @import("std").zig.c_builtins.__builtin_signbit;
|
||||
pub const __builtin_signbitf = @import("std").zig.c_builtins.__builtin_signbitf;
|
||||
pub const __builtin_popcount = @import("std").zig.c_builtins.__builtin_popcount;
|
||||
pub const __builtin_ctz = @import("std").zig.c_builtins.__builtin_ctz;
|
||||
pub const __builtin_clz = @import("std").zig.c_builtins.__builtin_clz;
|
||||
pub const __builtin_sqrt = @import("std").zig.c_builtins.__builtin_sqrt;
|
||||
pub const __builtin_sqrtf = @import("std").zig.c_builtins.__builtin_sqrtf;
|
||||
pub const __builtin_sin = @import("std").zig.c_builtins.__builtin_sin;
|
||||
pub const __builtin_sinf = @import("std").zig.c_builtins.__builtin_sinf;
|
||||
pub const __builtin_cos = @import("std").zig.c_builtins.__builtin_cos;
|
||||
pub const __builtin_cosf = @import("std").zig.c_builtins.__builtin_cosf;
|
||||
pub const __builtin_exp = @import("std").zig.c_builtins.__builtin_exp;
|
||||
pub const __builtin_expf = @import("std").zig.c_builtins.__builtin_expf;
|
||||
pub const __builtin_exp2 = @import("std").zig.c_builtins.__builtin_exp2;
|
||||
pub const __builtin_exp2f = @import("std").zig.c_builtins.__builtin_exp2f;
|
||||
pub const __builtin_log = @import("std").zig.c_builtins.__builtin_log;
|
||||
pub const __builtin_logf = @import("std").zig.c_builtins.__builtin_logf;
|
||||
pub const __builtin_log2 = @import("std").zig.c_builtins.__builtin_log2;
|
||||
pub const __builtin_log2f = @import("std").zig.c_builtins.__builtin_log2f;
|
||||
pub const __builtin_log10 = @import("std").zig.c_builtins.__builtin_log10;
|
||||
pub const __builtin_log10f = @import("std").zig.c_builtins.__builtin_log10f;
|
||||
pub const __builtin_abs = @import("std").zig.c_builtins.__builtin_abs;
|
||||
pub const __builtin_fabs = @import("std").zig.c_builtins.__builtin_fabs;
|
||||
pub const __builtin_fabsf = @import("std").zig.c_builtins.__builtin_fabsf;
|
||||
pub const __builtin_floor = @import("std").zig.c_builtins.__builtin_floor;
|
||||
pub const __builtin_floorf = @import("std").zig.c_builtins.__builtin_floorf;
|
||||
pub const __builtin_ceil = @import("std").zig.c_builtins.__builtin_ceil;
|
||||
pub const __builtin_ceilf = @import("std").zig.c_builtins.__builtin_ceilf;
|
||||
pub const __builtin_trunc = @import("std").zig.c_builtins.__builtin_trunc;
|
||||
pub const __builtin_truncf = @import("std").zig.c_builtins.__builtin_truncf;
|
||||
pub const __builtin_round = @import("std").zig.c_builtins.__builtin_round;
|
||||
pub const __builtin_roundf = @import("std").zig.c_builtins.__builtin_roundf;
|
||||
pub const __builtin_strlen = @import("std").zig.c_builtins.__builtin_strlen;
|
||||
pub const __builtin_strcmp = @import("std").zig.c_builtins.__builtin_strcmp;
|
||||
pub const __builtin_object_size = @import("std").zig.c_builtins.__builtin_object_size;
|
||||
pub const __builtin___memset_chk = @import("std").zig.c_builtins.__builtin___memset_chk;
|
||||
pub const __builtin_memset = @import("std").zig.c_builtins.__builtin_memset;
|
||||
pub const __builtin___memcpy_chk = @import("std").zig.c_builtins.__builtin___memcpy_chk;
|
||||
pub const __builtin_memcpy = @import("std").zig.c_builtins.__builtin_memcpy;
|
||||
pub const __builtin_expect = @import("std").zig.c_builtins.__builtin_expect;
|
||||
pub const __builtin_nanf = @import("std").zig.c_builtins.__builtin_nanf;
|
||||
pub const __builtin_huge_valf = @import("std").zig.c_builtins.__builtin_huge_valf;
|
||||
pub const __builtin_inff = @import("std").zig.c_builtins.__builtin_inff;
|
||||
pub const __builtin_isnan = @import("std").zig.c_builtins.__builtin_isnan;
|
||||
pub const __builtin_isinf = @import("std").zig.c_builtins.__builtin_isinf;
|
||||
pub const __builtin_isinf_sign = @import("std").zig.c_builtins.__builtin_isinf_sign;
|
||||
pub const __has_builtin = @import("std").zig.c_builtins.__has_builtin;
|
||||
pub const __builtin_assume = @import("std").zig.c_builtins.__builtin_assume;
|
||||
pub const __builtin_unreachable = @import("std").zig.c_builtins.__builtin_unreachable;
|
||||
pub const __builtin_constant_p = @import("std").zig.c_builtins.__builtin_constant_p;
|
||||
pub const __builtin_mul_overflow = @import("std").zig.c_builtins.__builtin_mul_overflow;
|
||||
pub const __u_char = u8;
|
||||
pub const __u_short = c_ushort;
|
||||
pub const __u_int = c_uint;
|
||||
pub const __u_long = c_ulong;
|
||||
pub const __int8_t = i8;
|
||||
pub const __uint8_t = u8;
|
||||
pub const __int16_t = c_short;
|
||||
pub const __uint16_t = c_ushort;
|
||||
pub const __int32_t = i32;
|
||||
pub const __uint32_t = u32;
|
||||
pub const __int64_t = i64;
|
||||
pub const __uint64_t = u64;
|
||||
pub const __int_least8_t = __int8_t;
|
||||
pub const __uint_least8_t = __uint8_t;
|
||||
pub const __int_least16_t = __int16_t;
|
||||
pub const __uint_least16_t = __uint16_t;
|
||||
pub const __int_least32_t = __int32_t;
|
||||
pub const __uint_least32_t = __uint32_t;
|
||||
pub const __int_least64_t = __int64_t;
|
||||
pub const __uint_least64_t = __uint64_t;
|
||||
pub const __quad_t = c_long;
|
||||
pub const __u_quad_t = c_ulong;
|
||||
pub const __intmax_t = c_long;
|
||||
pub const __uintmax_t = c_ulong;
|
||||
pub const __dev_t = c_ulong;
|
||||
pub const __uid_t = c_uint;
|
||||
pub const __gid_t = c_uint;
|
||||
pub const __ino_t = c_ulong;
|
||||
pub const __ino64_t = c_ulong;
|
||||
pub const __mode_t = c_uint;
|
||||
pub const __nlink_t = c_ulong;
|
||||
pub const __off_t = c_long;
|
||||
pub const __off64_t = c_long;
|
||||
pub const __pid_t = c_int;
|
||||
pub const __fsid_t = extern struct {
|
||||
__val: [2]c_int,
|
||||
};
|
||||
pub const __clock_t = c_long;
|
||||
pub const __rlim_t = c_ulong;
|
||||
pub const __rlim64_t = c_ulong;
|
||||
pub const __id_t = c_uint;
|
||||
pub const __time_t = c_long;
|
||||
pub const __useconds_t = c_uint;
|
||||
pub const __suseconds_t = c_long;
|
||||
pub const __suseconds64_t = c_long;
|
||||
pub const __daddr_t = c_int;
|
||||
pub const __key_t = c_int;
|
||||
pub const __clockid_t = c_int;
|
||||
pub const __timer_t = ?*anyopaque;
|
||||
pub const __blksize_t = c_long;
|
||||
pub const __blkcnt_t = c_long;
|
||||
pub const __blkcnt64_t = c_long;
|
||||
pub const __fsblkcnt_t = c_ulong;
|
||||
pub const __fsblkcnt64_t = c_ulong;
|
||||
pub const __fsfilcnt_t = c_ulong;
|
||||
pub const __fsfilcnt64_t = c_ulong;
|
||||
pub const __fsword_t = c_long;
|
||||
pub const __ssize_t = c_long;
|
||||
pub const __syscall_slong_t = c_long;
|
||||
pub const __syscall_ulong_t = c_ulong;
|
||||
pub const __loff_t = __off64_t;
|
||||
pub const __caddr_t = [*c]u8;
|
||||
pub const __intptr_t = c_long;
|
||||
pub const __socklen_t = c_uint;
|
||||
pub const __sig_atomic_t = c_int;
|
||||
pub const int_least8_t = __int_least8_t;
|
||||
pub const int_least16_t = __int_least16_t;
|
||||
pub const int_least32_t = __int_least32_t;
|
||||
pub const int_least64_t = __int_least64_t;
|
||||
pub const uint_least8_t = __uint_least8_t;
|
||||
pub const uint_least16_t = __uint_least16_t;
|
||||
pub const uint_least32_t = __uint_least32_t;
|
||||
pub const uint_least64_t = __uint_least64_t;
|
||||
pub const int_fast8_t = i8;
|
||||
pub const int_fast16_t = c_long;
|
||||
pub const int_fast32_t = c_long;
|
||||
pub const int_fast64_t = c_long;
|
||||
pub const uint_fast8_t = u8;
|
||||
pub const uint_fast16_t = c_ulong;
|
||||
pub const uint_fast32_t = c_ulong;
|
||||
pub const uint_fast64_t = c_ulong;
|
||||
pub const intmax_t = __intmax_t;
|
||||
pub const uintmax_t = __uintmax_t;
|
||||
pub const lsxpack_strlen_t = u16;
|
||||
pub const lsxpack_offset_t = i32;
|
||||
pub const LSXPACK_HPACK_VAL_MATCHED: c_int = 1;
|
||||
pub const LSXPACK_QPACK_IDX: c_int = 2;
|
||||
pub const LSXPACK_APP_IDX: c_int = 4;
|
||||
pub const LSXPACK_NAME_HASH: c_int = 8;
|
||||
pub const LSXPACK_NAMEVAL_HASH: c_int = 16;
|
||||
pub const LSXPACK_VAL_MATCHED: c_int = 32;
|
||||
pub const LSXPACK_NEVER_INDEX: c_int = 64;
|
||||
pub const enum_lsxpack_flag = c_uint;
|
||||
|
||||
// /// When header are decoded, it should be stored to @buf starting from @name_offset,
|
||||
// /// <name>: <value>\r\n
|
||||
// /// So, it can be used directly as HTTP/1.1 header. there are 4 extra characters
|
||||
// /// added.
|
||||
// ///
|
||||
// /// limitation: we currently does not support total header size > 64KB.
|
||||
pub const struct_lsxpack_header = extern struct {
|
||||
/// the buffer for headers
|
||||
buf: ?[*]u8 = null,
|
||||
/// hash value for name
|
||||
name_hash: __uint32_t = 0,
|
||||
/// hash value for name + value
|
||||
nameval_hash: __uint32_t = 0,
|
||||
/// the offset for name in the buffer
|
||||
name_offset: lsxpack_offset_t = 0,
|
||||
/// the offset for value in the buffer
|
||||
val_offset: lsxpack_offset_t = 0,
|
||||
/// the length of name
|
||||
name_len: lsxpack_strlen_t = 0,
|
||||
/// the length of value
|
||||
val_len: lsxpack_strlen_t = 0,
|
||||
/// mainly for cookie value chain
|
||||
chain_next_idx: __uint16_t = 0,
|
||||
/// HPACK static table index
|
||||
hpack_index: __uint8_t = 0,
|
||||
/// QPACK static table index
|
||||
qpack_index: __uint8_t = 0,
|
||||
/// APP header index
|
||||
app_index: __uint8_t = 0,
|
||||
/// combination of lsxpack_flag
|
||||
flags: u8 = 0,
|
||||
/// control to disable index or not
|
||||
indexed_type: __uint8_t = 0,
|
||||
/// num of extra bytes written to decoded buffer
|
||||
dec_overhead: __uint8_t = 0,
|
||||
};
|
||||
pub const lsxpack_header_t = struct_lsxpack_header;
|
||||
|
||||
pub fn lsxpack_header_set_offset2(arg_hdr: *lsxpack_header_t, arg_buf: [*c]u8, arg_name_offset: usize, arg_name_len: usize, arg_val_offset: usize, arg_val_len: usize) callconv(.C) void {
|
||||
arg_hdr.* = .{};
|
||||
arg_hdr.buf = arg_buf;
|
||||
arg_hdr.name_offset = @intCast(arg_name_offset);
|
||||
arg_hdr.val_offset = @intCast(arg_val_offset);
|
||||
arg_hdr.name_len = @truncate(arg_name_len);
|
||||
arg_hdr.val_len = @truncate(arg_val_len);
|
||||
}
|
||||
|
||||
pub fn lsxpack_header_prepare_decode(arg_hdr: *lsxpack_header_t, arg_out: [*c]u8, arg_offset: usize, arg_len: usize) callconv(.C) void {
|
||||
arg_hdr.* = .{};
|
||||
arg_hdr.buf = arg_out;
|
||||
arg_hdr.name_offset = @intCast(arg_offset);
|
||||
if (arg_len > LSXPACK_MAX_STRLEN) {
|
||||
arg_hdr.val_len = LSXPACK_MAX_STRLEN;
|
||||
} else {
|
||||
arg_hdr.val_len = @truncate(arg_len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lsxpack_header_get_name(hdr: *lsxpack_header_t) []const u8 {
|
||||
if (hdr.name_len != 0) return hdr.buf.?[@as(usize, @intCast(hdr.name_offset)) .. @as(usize, @intCast(hdr.name_offset)) + hdr.name_len];
|
||||
return "";
|
||||
}
|
||||
pub fn lsxpack_header_get_value(hdr: *lsxpack_header_t) []const u8 {
|
||||
if (hdr.val_len != 0) return hdr.buf.?[@as(usize, @intCast(hdr.val_offset)) .. @as(usize, @intCast(hdr.val_offset)) + hdr.val_len];
|
||||
return "";
|
||||
}
|
||||
pub fn lsxpack_header_get_dec_size(hdr: ?*const lsxpack_header_t) callconv(.C) usize {
|
||||
return @as(usize, @bitCast(@as(c_long, (@as(c_int, @bitCast(@as(c_uint, hdr.*.name_len))) + @as(c_int, @bitCast(@as(c_uint, hdr.*.val_len)))) + @as(c_int, @bitCast(@as(c_uint, hdr.*.dec_overhead))))));
|
||||
}
|
||||
pub fn lsxpack_header_mark_val_changed(hdr: ?*lsxpack_header_t) callconv(.C) void {
|
||||
hdr.*.flags = @as(c_uint, @bitCast(@as(c_int, @bitCast(hdr.*.flags)) & ~((LSXPACK_HPACK_VAL_MATCHED | LSXPACK_VAL_MATCHED) | LSXPACK_NAMEVAL_HASH)));
|
||||
}
|
||||
pub const struct_lshpack_enc_table_entry = opaque {};
|
||||
pub const struct_lshpack_enc_head = extern struct {
|
||||
stqh_first: ?*struct_lshpack_enc_table_entry = @import("std").mem.zeroes(?*struct_lshpack_enc_table_entry),
|
||||
stqh_last: [*c]?*struct_lshpack_enc_table_entry = @import("std").mem.zeroes([*c]?*struct_lshpack_enc_table_entry),
|
||||
};
|
||||
pub const struct_lshpack_double_enc_head = opaque {};
|
||||
pub const LSHPACK_ENC_USE_HIST: c_int = 1;
|
||||
const enum_unnamed_1 = c_uint;
|
||||
pub const struct_lshpack_enc = extern struct {
|
||||
hpe_cur_capacity: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpe_max_capacity: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpe_next_id: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpe_nelem: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpe_nbits: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpe_all_entries: struct_lshpack_enc_head = @import("std").mem.zeroes(struct_lshpack_enc_head),
|
||||
hpe_buckets: ?*struct_lshpack_double_enc_head = @import("std").mem.zeroes(?*struct_lshpack_double_enc_head),
|
||||
hpe_hist_buf: [*c]u32 = @import("std").mem.zeroes([*c]u32),
|
||||
hpe_hist_size: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpe_hist_idx: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpe_hist_wrapped: c_int = @import("std").mem.zeroes(c_int),
|
||||
hpe_flags: enum_unnamed_1 = @import("std").mem.zeroes(enum_unnamed_1),
|
||||
};
|
||||
pub const struct_lshpack_arr = extern struct {
|
||||
nalloc: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
nelem: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
off: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
els: [*c]usize = @import("std").mem.zeroes([*c]usize),
|
||||
};
|
||||
pub const struct_lshpack_dec = extern struct {
|
||||
hpd_dyn_table: struct_lshpack_arr = @import("std").mem.zeroes(struct_lshpack_arr),
|
||||
hpd_max_capacity: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpd_cur_max_capacity: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpd_cur_capacity: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
hpd_state: c_uint = @import("std").mem.zeroes(c_uint),
|
||||
};
|
||||
pub const LSHPACK_HDR_UNKNOWN: c_int = 0;
|
||||
pub const LSHPACK_HDR_AUTHORITY: c_int = 1;
|
||||
pub const LSHPACK_HDR_METHOD_GET: c_int = 2;
|
||||
pub const LSHPACK_HDR_METHOD_POST: c_int = 3;
|
||||
pub const LSHPACK_HDR_PATH: c_int = 4;
|
||||
pub const LSHPACK_HDR_PATH_INDEX_HTML: c_int = 5;
|
||||
pub const LSHPACK_HDR_SCHEME_HTTP: c_int = 6;
|
||||
pub const LSHPACK_HDR_SCHEME_HTTPS: c_int = 7;
|
||||
pub const LSHPACK_HDR_STATUS_200: c_int = 8;
|
||||
pub const LSHPACK_HDR_STATUS_204: c_int = 9;
|
||||
pub const LSHPACK_HDR_STATUS_206: c_int = 10;
|
||||
pub const LSHPACK_HDR_STATUS_304: c_int = 11;
|
||||
pub const LSHPACK_HDR_STATUS_400: c_int = 12;
|
||||
pub const LSHPACK_HDR_STATUS_404: c_int = 13;
|
||||
pub const LSHPACK_HDR_STATUS_500: c_int = 14;
|
||||
pub const LSHPACK_HDR_ACCEPT_CHARSET: c_int = 15;
|
||||
pub const LSHPACK_HDR_ACCEPT_ENCODING: c_int = 16;
|
||||
pub const LSHPACK_HDR_ACCEPT_LANGUAGE: c_int = 17;
|
||||
pub const LSHPACK_HDR_ACCEPT_RANGES: c_int = 18;
|
||||
pub const LSHPACK_HDR_ACCEPT: c_int = 19;
|
||||
pub const LSHPACK_HDR_ACCESS_CONTROL_ALLOW_ORIGIN: c_int = 20;
|
||||
pub const LSHPACK_HDR_AGE: c_int = 21;
|
||||
pub const LSHPACK_HDR_ALLOW: c_int = 22;
|
||||
pub const LSHPACK_HDR_AUTHORIZATION: c_int = 23;
|
||||
pub const LSHPACK_HDR_CACHE_CONTROL: c_int = 24;
|
||||
pub const LSHPACK_HDR_CONTENT_DISPOSITION: c_int = 25;
|
||||
pub const LSHPACK_HDR_CONTENT_ENCODING: c_int = 26;
|
||||
pub const LSHPACK_HDR_CONTENT_LANGUAGE: c_int = 27;
|
||||
pub const LSHPACK_HDR_CONTENT_LENGTH: c_int = 28;
|
||||
pub const LSHPACK_HDR_CONTENT_LOCATION: c_int = 29;
|
||||
pub const LSHPACK_HDR_CONTENT_RANGE: c_int = 30;
|
||||
pub const LSHPACK_HDR_CONTENT_TYPE: c_int = 31;
|
||||
pub const LSHPACK_HDR_COOKIE: c_int = 32;
|
||||
pub const LSHPACK_HDR_DATE: c_int = 33;
|
||||
pub const LSHPACK_HDR_ETAG: c_int = 34;
|
||||
pub const LSHPACK_HDR_EXPECT: c_int = 35;
|
||||
pub const LSHPACK_HDR_EXPIRES: c_int = 36;
|
||||
pub const LSHPACK_HDR_FROM: c_int = 37;
|
||||
pub const LSHPACK_HDR_HOST: c_int = 38;
|
||||
pub const LSHPACK_HDR_IF_MATCH: c_int = 39;
|
||||
pub const LSHPACK_HDR_IF_MODIFIED_SINCE: c_int = 40;
|
||||
pub const LSHPACK_HDR_IF_NONE_MATCH: c_int = 41;
|
||||
pub const LSHPACK_HDR_IF_RANGE: c_int = 42;
|
||||
pub const LSHPACK_HDR_IF_UNMODIFIED_SINCE: c_int = 43;
|
||||
pub const LSHPACK_HDR_LAST_MODIFIED: c_int = 44;
|
||||
pub const LSHPACK_HDR_LINK: c_int = 45;
|
||||
pub const LSHPACK_HDR_LOCATION: c_int = 46;
|
||||
pub const LSHPACK_HDR_MAX_FORWARDS: c_int = 47;
|
||||
pub const LSHPACK_HDR_PROXY_AUTHENTICATE: c_int = 48;
|
||||
pub const LSHPACK_HDR_PROXY_AUTHORIZATION: c_int = 49;
|
||||
pub const LSHPACK_HDR_RANGE: c_int = 50;
|
||||
pub const LSHPACK_HDR_REFERER: c_int = 51;
|
||||
pub const LSHPACK_HDR_REFRESH: c_int = 52;
|
||||
pub const LSHPACK_HDR_RETRY_AFTER: c_int = 53;
|
||||
pub const LSHPACK_HDR_SERVER: c_int = 54;
|
||||
pub const LSHPACK_HDR_SET_COOKIE: c_int = 55;
|
||||
pub const LSHPACK_HDR_STRICT_TRANSPORT_SECURITY: c_int = 56;
|
||||
pub const LSHPACK_HDR_TRANSFER_ENCODING: c_int = 57;
|
||||
pub const LSHPACK_HDR_USER_AGENT: c_int = 58;
|
||||
pub const LSHPACK_HDR_VARY: c_int = 59;
|
||||
pub const LSHPACK_HDR_VIA: c_int = 60;
|
||||
pub const LSHPACK_HDR_WWW_AUTHENTICATE: c_int = 61;
|
||||
pub const LSHPACK_HDR_TOBE_INDEXED: c_int = 255;
|
||||
pub const enum_lshpack_static_hdr_idx = c_uint;
|
||||
pub extern fn lshpack_enc_init([*c]struct_lshpack_enc) c_int;
|
||||
pub extern fn lshpack_enc_cleanup([*c]struct_lshpack_enc) void;
|
||||
pub extern fn lshpack_enc_encode(henc: [*c]struct_lshpack_enc, dst: [*c]const u8, dst_end: [*c]u8, input: ?*struct_lsxpack_header) [*c]u8;
|
||||
pub extern fn lshpack_enc_set_max_capacity([*c]struct_lshpack_enc, c_uint) void;
|
||||
pub extern fn lshpack_enc_use_hist([*c]struct_lshpack_enc, on: c_int) c_int;
|
||||
pub extern fn lshpack_enc_hist_used([*c]const struct_lshpack_enc) c_int;
|
||||
pub extern fn lshpack_dec_init([*c]struct_lshpack_dec) void;
|
||||
pub extern fn lshpack_dec_cleanup([*c]struct_lshpack_dec) void;
|
||||
pub extern fn lshpack_dec_decode(dec: [*c]struct_lshpack_dec, src: *[*c]const u8, src_end: [*c]const u8, output: ?*struct_lsxpack_header) c_int;
|
||||
pub extern fn lshpack_dec_set_max_capacity([*c]struct_lshpack_dec, c_uint) void;
|
||||
pub extern fn lshpack_enc_get_stx_tab_id(?*struct_lsxpack_header) c_uint;
|
||||
pub fn lshpack_decode(dec: [*c]struct_lshpack_dec, src: [*]const u8, src_len: usize, output: ?*struct_lsxpack_header) !usize {
|
||||
var s: [*c]const u8 = src;
|
||||
const rc: c_int = lshpack_dec_decode(dec, &s, s + src_len, output);
|
||||
if (rc != 0) {
|
||||
return error.UnableToDecode;
|
||||
}
|
||||
return @intFromPtr(s) - @intFromPtr(src);
|
||||
}
|
||||
pub const __INT64_C = @import("std").zig.c_translation.Macros.L_SUFFIX;
|
||||
pub const __UINT64_C = @import("std").zig.c_translation.Macros.UL_SUFFIX;
|
||||
pub const INT8_MIN = -@as(c_int, 128);
|
||||
pub const INT16_MIN = -@as(c_int, 32767) - @as(c_int, 1);
|
||||
pub const INT32_MIN = -@import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal) - @as(c_int, 1);
|
||||
pub const INT64_MIN = -__INT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 9223372036854775807, .decimal)) - @as(c_int, 1);
|
||||
pub const INT8_MAX = @as(c_int, 127);
|
||||
pub const INT16_MAX = @as(c_int, 32767);
|
||||
pub const INT32_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
|
||||
pub const INT64_MAX = __INT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 9223372036854775807, .decimal));
|
||||
pub const UINT8_MAX = @as(c_int, 255);
|
||||
pub const UINT16_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 65535, .decimal);
|
||||
pub const UINT32_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_uint, 4294967295, .decimal);
|
||||
pub const UINT64_MAX = __UINT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 18446744073709551615, .decimal));
|
||||
pub const INT_LEAST8_MIN = -@as(c_int, 128);
|
||||
pub const INT_LEAST16_MIN = -@as(c_int, 32767) - @as(c_int, 1);
|
||||
pub const INT_LEAST32_MIN = -@import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal) - @as(c_int, 1);
|
||||
pub const INT_LEAST64_MIN = -__INT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 9223372036854775807, .decimal)) - @as(c_int, 1);
|
||||
pub const INT_LEAST8_MAX = @as(c_int, 127);
|
||||
pub const INT_LEAST16_MAX = @as(c_int, 32767);
|
||||
pub const INT_LEAST32_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
|
||||
pub const INT_LEAST64_MAX = __INT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 9223372036854775807, .decimal));
|
||||
pub const UINT_LEAST8_MAX = @as(c_int, 255);
|
||||
pub const UINT_LEAST16_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 65535, .decimal);
|
||||
pub const UINT_LEAST32_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_uint, 4294967295, .decimal);
|
||||
pub const UINT_LEAST64_MAX = __UINT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 18446744073709551615, .decimal));
|
||||
pub const INT_FAST8_MIN = -@as(c_int, 128);
|
||||
pub const INT_FAST16_MIN = -@import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal) - @as(c_int, 1);
|
||||
pub const INT_FAST32_MIN = -@import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal) - @as(c_int, 1);
|
||||
pub const INT_FAST64_MIN = -__INT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 9223372036854775807, .decimal)) - @as(c_int, 1);
|
||||
pub const INT_FAST8_MAX = @as(c_int, 127);
|
||||
pub const INT_FAST16_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
|
||||
pub const INT_FAST32_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
|
||||
pub const INT_FAST64_MAX = __INT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 9223372036854775807, .decimal));
|
||||
pub const UINT_FAST8_MAX = @as(c_int, 255);
|
||||
pub const UINT_FAST16_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
|
||||
pub const UINT_FAST32_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
|
||||
pub const UINT_FAST64_MAX = __UINT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 18446744073709551615, .decimal));
|
||||
pub const INTPTR_MIN = -@import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal) - @as(c_int, 1);
|
||||
pub const INTPTR_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
|
||||
pub const UINTPTR_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
|
||||
pub const INTMAX_MIN = -__INT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 9223372036854775807, .decimal)) - @as(c_int, 1);
|
||||
pub const INTMAX_MAX = __INT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 9223372036854775807, .decimal));
|
||||
pub const UINTMAX_MAX = __UINT64_C(@import("std").zig.c_translation.promoteIntLiteral(c_int, 18446744073709551615, .decimal));
|
||||
pub const PTRDIFF_MIN = -@import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal) - @as(c_int, 1);
|
||||
pub const PTRDIFF_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
|
||||
pub const SIG_ATOMIC_MIN = -@import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal) - @as(c_int, 1);
|
||||
pub const SIG_ATOMIC_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
|
||||
pub const SIZE_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
|
||||
pub const WINT_MIN = @as(c_uint, 0);
|
||||
pub const WINT_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_uint, 4294967295, .decimal);
|
||||
pub inline fn INT8_C(c: anytype) @TypeOf(c) {
|
||||
return c;
|
||||
}
|
||||
pub inline fn INT16_C(c: anytype) @TypeOf(c) {
|
||||
return c;
|
||||
}
|
||||
pub inline fn INT32_C(c: anytype) @TypeOf(c) {
|
||||
return c;
|
||||
}
|
||||
pub const INT64_C = @import("std").zig.c_translation.Macros.L_SUFFIX;
|
||||
pub inline fn UINT8_C(c: anytype) @TypeOf(c) {
|
||||
return c;
|
||||
}
|
||||
pub inline fn UINT16_C(c: anytype) @TypeOf(c) {
|
||||
return c;
|
||||
}
|
||||
pub const UINT32_C = @import("std").zig.c_translation.Macros.U_SUFFIX;
|
||||
pub const UINT64_C = @import("std").zig.c_translation.Macros.UL_SUFFIX;
|
||||
pub const INTMAX_C = @import("std").zig.c_translation.Macros.L_SUFFIX;
|
||||
pub const UINTMAX_C = @import("std").zig.c_translation.Macros.UL_SUFFIX;
|
||||
pub const LSXPACK_HEADER_H_v206 = "";
|
||||
pub const _ASSERT_H = @as(c_int, 1);
|
||||
pub const _ASSERT_H_DECLS = "";
|
||||
pub const _STRING_H = @as(c_int, 1);
|
||||
pub const __need_size_t = "";
|
||||
pub const __need_NULL = "";
|
||||
pub const _SIZE_T = "";
|
||||
pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0));
|
||||
pub const _BITS_TYPES_LOCALE_T_H = @as(c_int, 1);
|
||||
pub const _BITS_TYPES___LOCALE_T_H = @as(c_int, 1);
|
||||
pub const _STRINGS_H = @as(c_int, 1);
|
||||
pub const LSXPACK_MAX_STRLEN = UINT16_MAX;
|
||||
pub const LSXPACK_DEL = @import("std").zig.c_translation.cast([*c]u8, NULL);
|
||||
pub const LSHPACK_MAJOR_VERSION = @as(c_int, 2);
|
||||
pub const LSHPACK_MINOR_VERSION = @as(c_int, 3);
|
||||
pub const LSHPACK_PATCH_VERSION = @as(c_int, 0);
|
||||
pub const lshpack_strlen_t = lsxpack_strlen_t;
|
||||
pub const LSHPACK_MAX_STRLEN = LSXPACK_MAX_STRLEN;
|
||||
pub const LSHPACK_DEC_HTTP1X_OUTPUT = @as(c_int, 1);
|
||||
pub const LSHPACK_DEC_CALC_HASH = @as(c_int, 1);
|
||||
pub const LSHPACK_MAX_INDEX = @as(c_int, 61);
|
||||
pub const LSHPACK_ERR_MORE_BUF = -@as(c_int, 3);
|
||||
pub const LSHPACK_ERR_TOO_LARGE = -@as(c_int, 2);
|
||||
pub const LSHPACK_ERR_BAD_DATA = -@as(c_int, 1);
|
||||
pub const LSHPACK_OK = @as(c_int, 0);
|
||||
pub const LSHPACK_DEC_HTTP1X_EXTRA = @as(c_int, 2);
|
||||
pub inline fn lshpack_dec_extra_bytes(dec_: anytype) @TypeOf(@as(c_int, 4)) {
|
||||
_ = @TypeOf(dec_);
|
||||
return @as(c_int, 4);
|
||||
}
|
||||
pub const lsxpack_flag = enum_lsxpack_flag;
|
||||
pub const lsxpack_header = struct_lsxpack_header;
|
||||
pub const lshpack_enc_table_entry = struct_lshpack_enc_table_entry;
|
||||
pub const lshpack_enc_head = struct_lshpack_enc_head;
|
||||
pub const lshpack_double_enc_head = struct_lshpack_double_enc_head;
|
||||
pub const lshpack_enc = struct_lshpack_enc;
|
||||
pub const lshpack_arr = struct_lshpack_arr;
|
||||
pub const lshpack_dec = struct_lshpack_dec;
|
||||
pub const lshpack_static_hdr_idx = enum_lshpack_static_hdr_idx;
|
||||
61
src/bun.js/api/bun/lshpack.zig
Normal file
61
src/bun.js/api/bun/lshpack.zig
Normal file
@@ -0,0 +1,61 @@
|
||||
const bun = @import("root").bun;
|
||||
|
||||
const lshpack_header = extern struct {
|
||||
name: [*]const u8 = undefined,
|
||||
name_len: usize = 0,
|
||||
value: [*]const u8 = undefined,
|
||||
value_len: usize = 0,
|
||||
};
|
||||
|
||||
/// wrapper implemented at src/bun.js/bindings/c-bindings.cpp
|
||||
pub const HPACK = extern struct {
|
||||
self: *anyopaque,
|
||||
|
||||
const mimalloc = @import("../../../allocators/mimalloc.zig");
|
||||
|
||||
pub const DecodeResult = struct {
|
||||
name: []const u8,
|
||||
value: []const u8,
|
||||
// offset of the next header position in src
|
||||
next: usize,
|
||||
};
|
||||
|
||||
pub const LSHPACK_MAX_HEADER_SIZE: usize = 65536;
|
||||
|
||||
pub fn init(max_capacity: u32) *HPACK {
|
||||
return lshpack_wrapper_init(mimalloc.mi_malloc, mimalloc.mi_free, max_capacity) orelse bun.outOfMemory();
|
||||
}
|
||||
|
||||
/// DecodeResult name and value uses a thread_local shared buffer and should be copy/cloned before the next decode/encode call
|
||||
pub fn decode(self: *HPACK, src: []const u8) !DecodeResult {
|
||||
var header: lshpack_header = .{};
|
||||
const offset = lshpack_wrapper_decode(self, src.ptr, src.len, &header);
|
||||
if (offset == 0) return error.UnableToDecode;
|
||||
if (header.name_len == 0) return error.EmptyHeaderName;
|
||||
|
||||
return .{
|
||||
.name = header.name[0..header.name_len],
|
||||
.value = header.value[0..header.value_len],
|
||||
.next = offset,
|
||||
};
|
||||
}
|
||||
|
||||
/// encode name, value with never_index option into dst_buffer
|
||||
/// if name + value length is greater than LSHPACK_MAX_HEADER_SIZE this will return UnableToEncode
|
||||
pub fn encode(self: *HPACK, name: []const u8, value: []const u8, never_index: bool, dst_buffer: []u8, dst_buffer_offset: usize) !usize {
|
||||
const offset = lshpack_wrapper_encode(self, name.ptr, name.len, value.ptr, value.len, @intFromBool(never_index), dst_buffer.ptr, dst_buffer.len, dst_buffer_offset);
|
||||
if (offset <= 0) return error.UnableToEncode;
|
||||
return offset;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *HPACK) void {
|
||||
lshpack_wrapper_deinit(self);
|
||||
}
|
||||
};
|
||||
|
||||
const lshpack_wrapper_alloc = ?*const fn (size: usize) callconv(.C) ?*anyopaque;
|
||||
const lshpack_wrapper_free = ?*const fn (ptr: ?*anyopaque) callconv(.C) void;
|
||||
extern fn lshpack_wrapper_init(alloc: lshpack_wrapper_alloc, free: lshpack_wrapper_free, capacity: usize) ?*HPACK;
|
||||
extern fn lshpack_wrapper_deinit(self: *HPACK) void;
|
||||
extern fn lshpack_wrapper_decode(self: *HPACK, src: [*]const u8, src_len: usize, output: *lshpack_header) usize;
|
||||
extern fn lshpack_wrapper_encode(self: *HPACK, name: [*]const u8, name_len: usize, value: [*]const u8, value_len: usize, never_index: c_int, buffer: [*]u8, buffer_len: usize, buffer_offset: usize) usize;
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <uv.h>
|
||||
#include <windows.h>
|
||||
#endif // !OS(WINDOWS)
|
||||
#include <lshpack.h>
|
||||
|
||||
#if CPU(X86_64) && !OS(WINDOWS)
|
||||
extern "C" void bun_warn_avx_missing(const char* url)
|
||||
@@ -183,4 +184,91 @@ extern "C" void on_before_reload_process_linux()
|
||||
sigprocmask(SIG_SETMASK, &signal_set, nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LSHPACK_MAX_HEADER_SIZE 65536
|
||||
|
||||
static thread_local char shared_header_buffer[LSHPACK_MAX_HEADER_SIZE];
|
||||
|
||||
extern "C" {
|
||||
typedef void* (*lshpack_wrapper_alloc)(size_t size);
|
||||
typedef void (*lshpack_wrapper_free)(void*);
|
||||
typedef struct {
|
||||
struct lshpack_enc enc;
|
||||
struct lshpack_dec dec;
|
||||
lshpack_wrapper_free free;
|
||||
} lshpack_wrapper;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
size_t name_len;
|
||||
const char* value;
|
||||
size_t value_len;
|
||||
} lshpack_header;
|
||||
|
||||
lshpack_wrapper* lshpack_wrapper_init(lshpack_wrapper_alloc alloc, lshpack_wrapper_free free, unsigned max_capacity)
|
||||
{
|
||||
lshpack_wrapper* coders = (lshpack_wrapper*)alloc(sizeof(lshpack_wrapper));
|
||||
if (!coders)
|
||||
return nullptr;
|
||||
coders->free = free;
|
||||
if (lshpack_enc_init(&coders->enc) != 0)
|
||||
return nullptr;
|
||||
lshpack_dec_init(&coders->dec);
|
||||
lshpack_enc_set_max_capacity(&coders->enc, max_capacity);
|
||||
lshpack_dec_set_max_capacity(&coders->dec, max_capacity);
|
||||
return coders;
|
||||
}
|
||||
|
||||
size_t lshpack_wrapper_encode(lshpack_wrapper* self,
|
||||
const unsigned char* name, size_t name_len,
|
||||
const unsigned char* val, size_t val_len,
|
||||
int never_index,
|
||||
unsigned char* buffer, size_t buffer_len, size_t buffer_offset)
|
||||
{
|
||||
if (name_len + val_len > LSHPACK_MAX_HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
lsxpack_header_t hdr;
|
||||
memset(&hdr, 0, sizeof(lsxpack_header_t));
|
||||
memcpy(&shared_header_buffer[0], name, name_len);
|
||||
memcpy(&shared_header_buffer[name_len], val, val_len);
|
||||
lsxpack_header_set_offset2(&hdr, &shared_header_buffer[0], 0, name_len, name_len, val_len);
|
||||
if (never_index) {
|
||||
hdr.indexed_type = 2;
|
||||
}
|
||||
auto* start = buffer + buffer_offset;
|
||||
auto* ptr = lshpack_enc_encode(&self->enc, start, buffer + buffer_len, &hdr);
|
||||
if (!ptr)
|
||||
return 0;
|
||||
return ptr - start;
|
||||
}
|
||||
|
||||
size_t lshpack_wrapper_decode(lshpack_wrapper* self,
|
||||
const unsigned char* src, size_t src_len,
|
||||
lshpack_header* output)
|
||||
{
|
||||
lsxpack_header_t hdr;
|
||||
memset(&hdr, 0, sizeof(lsxpack_header_t));
|
||||
lsxpack_header_prepare_decode(&hdr, &shared_header_buffer[0], 0, LSHPACK_MAX_HEADER_SIZE);
|
||||
|
||||
const unsigned char* s = src;
|
||||
|
||||
auto rc = lshpack_dec_decode(&self->dec, &s, s + src_len, &hdr);
|
||||
if (rc != 0)
|
||||
return 0;
|
||||
|
||||
output->name = lsxpack_header_get_name(&hdr);
|
||||
output->name_len = hdr.name_len;
|
||||
output->value = lsxpack_header_get_value(&hdr);
|
||||
output->value_len = hdr.val_len;
|
||||
return s - src;
|
||||
}
|
||||
|
||||
void lshpack_wrapper_deinit(lshpack_wrapper* self)
|
||||
{
|
||||
lshpack_dec_cleanup(&self->dec);
|
||||
lshpack_enc_cleanup(&self->enc);
|
||||
self->free(self);
|
||||
}
|
||||
}
|
||||
@@ -679,7 +679,10 @@ function emitAbortedNT(self, streams, streamId, error) {
|
||||
self.emit("streamError", error_instance);
|
||||
}
|
||||
class ClientHttp2Session extends Http2Session {
|
||||
/// close indicates that we called closed
|
||||
#closed: boolean = false;
|
||||
/// connected indicates that the connection/socket is connected
|
||||
#connected: boolean = false;
|
||||
#queue: Array<Buffer> = [];
|
||||
#connections: number = 0;
|
||||
[bunHTTP2Socket]: TLSSocket | Socket | null;
|
||||
@@ -763,33 +766,33 @@ class ClientHttp2Session extends Http2Session {
|
||||
) {
|
||||
if (!self) return;
|
||||
var stream = self.#streams.get(streamId);
|
||||
if (stream) {
|
||||
let status: string | number = headers[":status"] as string;
|
||||
if (status) {
|
||||
// client status is always number
|
||||
status = parseInt(status as string, 10);
|
||||
(headers as Record<string, string | number>)[":status"] = status;
|
||||
}
|
||||
if (!stream) return;
|
||||
|
||||
let set_cookies = headers["set-cookie"];
|
||||
if (typeof set_cookies === "string") {
|
||||
(headers as Record<string, string | string[]>)["set-cookie"] = [set_cookies];
|
||||
}
|
||||
let status: string | number = headers[":status"] as string;
|
||||
if (status) {
|
||||
// client status is always number
|
||||
status = parseInt(status as string, 10);
|
||||
(headers as Record<string, string | number>)[":status"] = status;
|
||||
}
|
||||
|
||||
let cookie = headers["cookie"];
|
||||
if ($isArray(cookie)) {
|
||||
headers["cookie"] = (headers["cookie"] as string[]).join(";");
|
||||
}
|
||||
if (stream[bunHTTP2StreamResponded]) {
|
||||
try {
|
||||
stream.emit("trailers", headers, flags);
|
||||
} catch {
|
||||
process.nextTick(emitStreamErrorNT, self, self.#streams, streamId, constants.NGHTTP2_PROTOCOL_ERROR, true);
|
||||
}
|
||||
} else {
|
||||
stream[bunHTTP2StreamResponded] = true;
|
||||
stream.emit("response", headers, flags);
|
||||
let set_cookies = headers["set-cookie"];
|
||||
if (typeof set_cookies === "string") {
|
||||
(headers as Record<string, string | string[]>)["set-cookie"] = [set_cookies];
|
||||
}
|
||||
|
||||
let cookie = headers["cookie"];
|
||||
if ($isArray(cookie)) {
|
||||
headers["cookie"] = (headers["cookie"] as string[]).join(";");
|
||||
}
|
||||
if (stream[bunHTTP2StreamResponded]) {
|
||||
try {
|
||||
stream.emit("trailers", headers, flags);
|
||||
} catch {
|
||||
process.nextTick(emitStreamErrorNT, self, self.#streams, streamId, constants.NGHTTP2_PROTOCOL_ERROR, true);
|
||||
}
|
||||
} else {
|
||||
stream[bunHTTP2StreamResponded] = true;
|
||||
stream.emit("response", headers, flags);
|
||||
}
|
||||
},
|
||||
localSettings(self: ClientHttp2Session, settings: Settings) {
|
||||
@@ -874,12 +877,13 @@ class ClientHttp2Session extends Http2Session {
|
||||
write(self: ClientHttp2Session, buffer: Buffer) {
|
||||
if (!self) return;
|
||||
const socket = self[bunHTTP2Socket];
|
||||
if (self.#closed) {
|
||||
//queue
|
||||
self.#queue.push(buffer);
|
||||
} else {
|
||||
if (!socket) return;
|
||||
if (self.#connected) {
|
||||
// redirect writes to socket
|
||||
socket.write(buffer);
|
||||
} else {
|
||||
//queue
|
||||
self.#queue.push(buffer);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -899,6 +903,7 @@ class ClientHttp2Session extends Http2Session {
|
||||
#onConnect() {
|
||||
const socket = this[bunHTTP2Socket];
|
||||
if (!socket) return;
|
||||
this.#connected = true;
|
||||
// check if h2 is supported only for TLSSocket
|
||||
if (socket instanceof TLSSocket) {
|
||||
if (socket.alpnProtocol !== "h2") {
|
||||
@@ -918,6 +923,7 @@ class ClientHttp2Session extends Http2Session {
|
||||
|
||||
// TODO: make a native bindings on data and write and fallback to non-native
|
||||
socket.on("data", this.#onRead.bind(this));
|
||||
|
||||
// redirect the queued buffers
|
||||
const queue = this.#queue;
|
||||
while (queue.length) {
|
||||
@@ -1129,6 +1135,7 @@ class ClientHttp2Session extends Http2Session {
|
||||
destroy(error?: Error, code?: number) {
|
||||
const socket = this[bunHTTP2Socket];
|
||||
this.#closed = true;
|
||||
this.#connected = false;
|
||||
code = code || constants.NGHTTP2_NO_ERROR;
|
||||
if (socket) {
|
||||
this.goaway(code, 0, Buffer.alloc(0));
|
||||
|
||||
@@ -1064,7 +1064,7 @@ describe("Client Basics", () => {
|
||||
const settings = new http2utils.SettingsFrame(true);
|
||||
socket.write(settings.data);
|
||||
const frame = new http2utils.Frame(7, 7, 0, 0).data;
|
||||
socket.end(Buffer.concat([frame, Buffer.alloc(7)]));
|
||||
socket.write(Buffer.concat([frame, Buffer.alloc(7)]));
|
||||
});
|
||||
server.listen(0, "127.0.0.1", async () => {
|
||||
const url = `http://127.0.0.1:${server.address().port}`;
|
||||
@@ -1095,7 +1095,7 @@ describe("Client Basics", () => {
|
||||
socket.write(settings.data);
|
||||
await waitToWrite;
|
||||
const frame = new http2utils.DataFrame(1, Buffer.alloc(16384 * 2), 0, 1).data;
|
||||
socket.end(frame);
|
||||
socket.write(frame);
|
||||
});
|
||||
server.listen(0, "127.0.0.1", async () => {
|
||||
const url = `http://127.0.0.1:${server.address().port}`;
|
||||
@@ -1127,7 +1127,7 @@ describe("Client Basics", () => {
|
||||
socket.write(settings.data);
|
||||
await waitToWrite;
|
||||
const frame = new http2utils.Frame(4, 3, 0, 0).data;
|
||||
socket.end(Buffer.concat([frame, Buffer.alloc(4)]));
|
||||
socket.write(Buffer.concat([frame, Buffer.alloc(4)]));
|
||||
});
|
||||
server.listen(0, "127.0.0.1", async () => {
|
||||
const url = `http://127.0.0.1:${server.address().port}`;
|
||||
@@ -1159,7 +1159,7 @@ describe("Client Basics", () => {
|
||||
socket.write(settings.data);
|
||||
await waitToWrite;
|
||||
const frame = new http2utils.Frame(3, 3, 0, 1).data;
|
||||
socket.end(Buffer.concat([frame, Buffer.alloc(3)]));
|
||||
socket.write(Buffer.concat([frame, Buffer.alloc(3)]));
|
||||
});
|
||||
server.listen(0, "127.0.0.1", async () => {
|
||||
const url = `http://127.0.0.1:${server.address().port}`;
|
||||
@@ -1192,7 +1192,7 @@ describe("Client Basics", () => {
|
||||
await waitToWrite;
|
||||
const buffer = Buffer.alloc(16384 * 2);
|
||||
const frame = new http2utils.Frame(buffer.byteLength, 3, 0, 1).data;
|
||||
socket.end(Buffer.concat([frame, buffer]));
|
||||
socket.write(Buffer.concat([frame, buffer]));
|
||||
});
|
||||
server.listen(0, "127.0.0.1", async () => {
|
||||
const url = `http://127.0.0.1:${server.address().port}`;
|
||||
@@ -1262,7 +1262,7 @@ describe("Client Basics", () => {
|
||||
await waitToWrite;
|
||||
|
||||
const frame = new http2utils.Frame(4, 2, 0, 1).data;
|
||||
socket.end(Buffer.concat([frame, Buffer.alloc(4)]));
|
||||
socket.write(Buffer.concat([frame, Buffer.alloc(4)]));
|
||||
});
|
||||
server.listen(0, "127.0.0.1", async () => {
|
||||
const url = `http://127.0.0.1:${server.address().port}`;
|
||||
|
||||
Reference in New Issue
Block a user