Class BowireMetadataKeys

Namespace
Kuestenlogik.Bowire
Assembly
Kuestenlogik.Bowire.dll

Metadata keys that mean something to a protocol plugin instead of being forwarded to the server.

public static class BowireMetadataKeys
Inheritance
BowireMetadataKeys
Inherited Members

Remarks

Per-call metadata is normally headers, but a few entries are configuration for the plugin itself and are stripped before anything reaches the wire. They live here because the two ends of that agreement cannot see each other: a plugin is loaded at runtime and referenced by nobody, so the host and the security scanner had no way to name a key except by repeating the literal — which is what BowireDiscoveryEndpoints was already doing with the transport marker.

The double underscores are not decoration. They mark a key as belonging to Bowire rather than to the caller, so a header genuinely named descriptors cannot collide with one of these.

Fields

GrpcDescriptorSet

A compiled gRPC descriptor set, for a server that does not answer Server Reflection (#653).

public const string GrpcDescriptorSet = "__bowireGrpcDescriptors__"

Field Value

string

Remarks

The value is either a path to a .protoset file or JSON with a path or base64 property. Produced by protoc --descriptor_set_out=api.protoset --include_imports.

GrpcTransport

gRPC transport selection (web for gRPC-Web).

public const string GrpcTransport = "__bowireGrpcTransport"

Field Value

string

Remarks

Also accepted as a query parameter on the server URL, because discovery had no metadata bag when that path was written.

InternalPrefix

The prefix every Bowire-internal metadata key starts with.

public const string InternalPrefix = "__bowire"

Field Value

string

PluginHint

The plugin the caller explicitly pinned with hint@url, if any.

public const string PluginHint = "__bowirePluginHint"

Field Value

string

Remarks

DiscoverAsync has no "was I explicitly asked for?" parameter, and some plugins need one. A plugin that discovers from a bundled schema rather than from the wire cannot probe: it would answer for every URL it is offered, so on the hint-less fan-out it invents services that are not there. The same is true of an ad-hoc separate-target fallback, which must not fire just because some unrelated endpoint happens to answer the right content type.

The hint itself cannot carry the answer: Parse(string?) consumes the hint@ prefix before the plugin is reached, so a plugin gating on that prefix is gating on something it can never see. The TacticalAPI plugin did exactly that and returned an empty list on every path, including the one its own sample depends on, while its unit test passed by calling DiscoverAsync with a prefix production never delivers.

So the core stitches the resolved plugin id onto the URL as this marker whenever a hint was given. One marker for every plugin, rather than the per-plugin ones SSE and SignalR each grew: those had to be kept aligned by hand across two files, and the next plugin to need the same bit either invents a third or, as here, gets it wrong.

Methods

IsInternal(string)

Whether key is a Bowire-internal marker rather than a header meant for the server.

public static bool IsInternal(string key)

Parameters

key string

Returns

bool

Remarks

Markers carry plugin configuration, and some of it is secret: the mTLS marker holds a private key, the SigV4 marker an AWS secret. Every path that turns metadata into wire headers skips these, including markers a given plugin does not itself understand; a plugin that only stripped its own sent the rest to the target as literal headers.

WireHeaders(IEnumerable<KeyValuePair<string, string>>?)

metadata without the Bowire-internal markers: what may go on the wire as headers. Empty for null.

public static IEnumerable<KeyValuePair<string, string>> WireHeaders(IEnumerable<KeyValuePair<string, string>>? metadata)

Parameters

metadata IEnumerable<KeyValuePair<string, string>>

Returns

IEnumerable<KeyValuePair<string, string>>