httparsed 1.0.1

Fast betterC/nogc HTTP request/response parser


To use this package, run the following command in your project's root directory:

Manual usage
Put the following dependency into your project's dependences section:

httparsed

Actions Status Latest version Dub downloads license

Push parser of HTTP/1.x requests and responses. Other internet message like protocols (ie RTSP) are supported too.

Inspired by picohttpparser.

Features

  • doesn't allocate anything on it's own (nothrow @nogc)
  • works with betterC
  • uses compile time introspection to pass parsed message parts to callbacks
  • doesn't store any internal state
  • handles incomplete messages and can continue parsing from previous buffer index
  • no dependencies
  • uses SSE4.2 with LDC2 compiler and SSE4.2 enabled target CPU

Usage

// define our message content handler
struct Header
{
    const(char)[] name;
    const(char)[] value;
}

// Just store slices of parsed message header
struct Msg
{
    @safe pure nothrow @nogc:
    void onMethod(const(char)[] method) { this.method = method; }
    void onUri(const(char)[] uri) { this.uri = uri; }
    void onVersion(const(char)[] ver) { this.ver = ver; }
    void onHeader(const(char)[] name, const(char)[] value) {
        this.m_headers[m_headersLength].name = name;
        this.m_headers[m_headersLength++].value = value;
    }
    void onStatus(int status) { this.status = status; }
    void onStatusMsg(const(char)[] statusMsg) { this.statusMsg = statusMsg; }

    const(char)[] method;
    const(char)[] uri;
    const(char)[] ver;
    int status;
    const(char)[] statusMsg;

    private {
        Header[32] m_headers;
        size_t m_headersLength;
    }

    Header[] headers() return { return m_headers[0..m_headersLength]; }
}

// init parser
auto reqParser = initParser!Msg(); // or `MsgParser!MSG reqParser;`
auto resParser = initParser!Msg(); // or `MsgParser!MSG resParser;`

// parse request
string data = "GET /foo HTTP/1.1\r\nHost: 127.0.0.1:8090\r\n";
int res = reqParser.parseRequest(data);
assert(res == data.length); // returns parsed message header length when parsed sucessfully, 0 when there is no error, but message isn't complete yet, -errcode on error

// parse response
data = "HTTP/1.0 200 OK\r\n";
uint lastPos; // store last parsed position for next run
res = resParser.parseResponse(data, lastPos);
assert(res == 0); // no complete message header yet, but no error
data = "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 3\r\n\r\nfoo";
res = resParser.parseResponse(data, lastPos); // starts parsing from previous position
assert(res == data.length - 3); // whole message header parsed, body left to be handled based on actual header values

SSE4.2

To use SSE4.2 use this in your dub.sdl:

dflags "-mcpu=native" platform="ldc"

Performance

  • Tested on: AMD Ryzen 7 3700X 8-Core Processor
  • Best of 5 runs for each parser
  • tested parsers:
  • httparsed (noop) - this parser but with a provided message context with no callbacks - it just parses through requests, but doesn't use anything
  • httparsed - this parser with a simple msg struct as in example above
  • picohttpparser
  • http_parser
  • llhttp - replacement of http_parser
  • vibe-d - stripped down version of HTTP request parser used in vibe-d
  • arsd - stripped down HTTP request parser of arsd's cgi.d package

results

Authors:
  • Tomáš Chaloupka
Dependencies:
none
Versions:
1.2.1 2021-Jul-26
1.2.0 2020-Dec-16
1.1.1 2020-Dec-15
1.1.0 2020-Dec-15
1.0.1 2020-Dec-14
Show all 7 versions
Download Stats:
  • 13 downloads today

  • 50 downloads this week

  • 240 downloads this month

  • 45412 downloads total

Score:
3.6
Short URL:
httparsed.dub.pm