Skip to content

My two cents #1

@Boris-Barboris

Description

@Boris-Barboris

In continuation of our discussion here: vibe-d/vibe-core#48

baseline API with no dynamic per-request memory allocations

Well, it can't be completely avoided. I'd rather formulate in like this:

  • all the memory required to hold one http request with all of it's lookup optimization structures (header collection and all that stuff) and various contexts should be allocated efficiently and released after the response is built and control returned to the framework code.
  • all strings (header values etc.), contained in request, should span the request buffer

per-request memory must be safely managed (scoped and .dup'ed as soon as the user tries to escape it, either explicitly or implicitly)

I'm strongly against implicit copying. Marked with scope Non-copyable HTTPRequest and HTTPResponse structures that implement Stream interfaces themselves (no easily-accessable socket leakage this way, so no refcounting needed under the hood) as parameters to user callback, all "dangerous" fields and properties return something like

/// Doc-comment that warns the programmer about the lifetime of the memory behind m_val
struct RequestScoped(T)
{
    private T m_val;
    /// doc-comment that warns the programmer about the consequences
    ref T get() { return m_val; }
    T escape() { /* conveniently-written recursive duplication to GC-heap */ }
}

You cannot force user to write memory safe code. D does not support this. No, DIP1000 + "@safe" is not an enforcement. When something cannot be enforced, it is better to provide convenient and non-encumbering conventions, documentation and examples.

no stream proxy objects or dynamic dispatch by default - all combinations of encryption/encoding/compression streams must be instantiated as static types, need to keep in mind how to minimize the amount of template bloat this produces.

encoding - transport
encoding - compression - transport
encoding - compression - encryption - transport
Looks rather modest, templates should not be that terrible.

A drawback of this approach is that each API call would have to determine the static stream type all over again (e.g. ChunkedOutputStream(TLSStream(TCPConnection))).

Let's say dynamic dispatch between streams in the pipeline was collapsed, but this is the end. You need dynamic dispatch for HTTPInterchange.BodyReader\Writer, one way or another. Class will allow socket leak (again, only if you think a programmer is a baboon. Seriously, there is no hope if you escape a variable of heavily-documented type scope RequestScoped!BodyWriter). Or you can emulate VFT in a struct through function pointers, wich will keep uncopyability, but will look questionable.

I also don't think unified HTTPInterchange object is something good. Chained calls with staged callbacks:

  • looks ugly, IMO.
  • May perform worse, more indirection. On the freight trains of headers, sent by modern browsers, readHeaders may create more problems, than it solves. What should user do there, write a giant switch? How is switch over strings implemented by the compilers? Does it compare lengths first? Does it choose between an rb-tree and hash table, or does it build a state machine? I think an optimized and fine-tuned pre-built header lookup collection is more user-friendly and will be faster.
  • Writing straight back to response body without even looking at request is perfectly viable behaviour. Why shoud I call three bethods that do nothing to get it done? I have to write code that means nothing.
  • Body should already be read by vibe.d parser well before any user callback are invoked. Body start and length were found, CLRFs were found, all that rfc2616 stuff. All this validation and parsing should be already done before the client code. Client callbacks should not be ran if the request does not conform to HTTP standard. I don't see a benefit from forcing this specific order on the user.

I think the current form of HTTPServerRequestHandlerS callback is very nice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions