Class HeaderMap

java.lang.Object
dev.relism.flash.models.HeaderMap

public class HeaderMap extends Object
Lazy, zero-copy header access backed directly by the request parser's byte buffer. Strings are allocated only when first(java.lang.String) / all(java.lang.String) / view(java.lang.String) is called; the raw bytes are never copied at parse time.

Lifetime contract — read carefully

One HeaderMap instance lives on the connection (not per-request). On every keep-alive request reset(byte[], int, int) is called to slide the window over the new header section of the same reused buffer. This has two critical implications:
  1. Do not retain the HeaderMap beyond the handler. After the handler returns, the next request reuses and overwrites the buffer. Any String values retrieved via first(java.lang.String)/all(java.lang.String) are safe (they are independent heap copies); the HeaderMap object itself is not.
  2. view(java.lang.String) returns a zero-copy ByteView slice into the live buffer. Storing this view and reading it after the handler returns (e.g. in an async callback, a CompletableFuture continuation, or a virtual-thread handoff) is a data race — the bytes may have been overwritten by the next request. Copy to a String or byte[] before leaving the synchronous handler scope.
  • Constructor Details

    • HeaderMap

      public HeaderMap()
  • Method Details

    • reset

      public void reset(byte[] buffer, int sectionStart, int sectionEnd)
      Resets this map to the header section buffer[sectionStart, sectionEnd).
    • forEach

      public void forEach(HeaderMap.HeaderConsumer consumer)
      Visits every header in declaration order without allocating — no per-header String/ByteView/list-entry object, unlike all(). name/ value are the same two ByteView instances on every call, repositioned in place; they are valid only for the duration of that single HeaderMap.HeaderConsumer.accept(dev.relism.fpr.core.ByteView, dev.relism.fpr.core.ByteView) call — same "do not retain past the handler" rule as view(java.lang.String), just per-invocation instead of per-request. Prefer a non-capturing or field-reusing HeaderMap.HeaderConsumer (see its javadoc) if the call site itself needs to stay allocation-free too.

      Exists for callers that must handle an open-ended set of header names — e.g. a reverse proxy forwarding whatever the client sent — where first(java.lang.String)/all(java.lang.String)'s per-name lookup isn't usable because the set of names isn't known upfront.

    • first

      public String first(String name)
      Returns the first value of header name (case-insensitive), or null.
    • all

      public List<String> all(String name)
      Returns all values of header name in declaration order, or an empty list.
    • all

      public List<String> all()
      Returns all header values in declaration order.
    • valueEqualsIgnoreCase

      public boolean valueEqualsIgnoreCase(String name, String value)
      Case-insensitive comparison of the first value of name against value.
    • view

      public dev.relism.fpr.core.ByteView view(String name)
      Returns a zero-copy ByteView over the first value of name, or null.