Skip to content

Instantly share code, notes, and snippets.

@jpf91 jpf91/http.d
Created Mar 25, 2011

Embed
What would you like to do?
final class HeaderCollection
{
private:
struct Entry
{
//Case preserved
string Key;
string Value;
}
Entry[string] storage;
void append(string key, string value)
{
auto lk = tolower(key);
if(lk !in storage)
{
Entry ent;
ent.Key = key;
ent.Value = value;
storage[lk] = ent;
}
else
{
auto ent = storage[lk];
ent.Value ~= "," ~ value;
}
}
//TODO: toCurl
public:
this(string[string] hash)
{
foreach(key; hash.keys)
{
auto lk = tolower(key);
assert(lk !in storage);
Entry ent;
ent.Key = key;
ent.Value = hash[key];
storage[lk] = ent;
}
}
this()
{
}
bool hasHeader(T)(T key)
if(is(T == string))
{
return (tolower(key) in storage) ? true : false;
}
bool hasHeader(T)()
if(isHeader!T)
{
return (tolower(T.Key) in storage) ? true : false;
}
void setHeader(T)(T key, T value)
if(is(T == string))
{
Entry ent;
ent.Key = key;
ent.Value = value;
storage[tolower(key)] = ent;
}
void setHeader(T)(T head)
if(isHeader!T && canFormatHeader!T)
{
Entry ent;
ent.Key = T.Key;
ent.Value = formatHeaderValue(head);
storage[tolower(T.Key)] = ent;
}
string getHeaderString(T)(T key)
if(is(T == string))
{
auto lk = tolower(key);
if(lk !in storage)
{
//Correct Exception type?
throw new Exception("");
}
return storage[lk].Value;
}
string getHeaderString(T)()
if(isHeader!T)
{
return getHeaderString(T.Key);
}
T getHeader(T)()
if(isHeader!T && canParseHeader!T)
{
return parseHeaderValue!T(getHeaderString(T.Key));
}
@property size_t length()
{
return storage.length;
}
T opCast(T)()
if(is(T == string[string]))
{
string[string] tmp;
foreach(val; storage.values)
{
tmp[val.Key] = val.Value;
}
return tmp;
}
override bool opEquals(Object obj)
{
auto other = cast(HeaderCollection)obj;
if(!other)
return false;
foreach(key; this.storage.keys)
{
if(key !in other.storage)
return false;
if(this.storage[key].Value != other.storage[key].Value)
return false;
}
return true;
}
string opIndex(string key)
{
return getHeaderString(key);
}
void opIndexAssign(string val, string key)
{
return setHeader(key, val);
}
//Doesn't work with current dmd
/*
bool opBinary(string type, T)()
if(type == "in" && isHeader(T))
{
return hasHeader!T;
}
bool opBinary(string type, T)(T val)
if(type == "in" && is(T == string))
{
return hasHeader!(val);
}*/
}
unittest
{
HeaderCollection col = new HeaderCollection(["Content-Length": "1234", "Content-Type" : "text/html"]);
string[string] test = cast(string[string])col;
assert(test == ["Content-Length": "1234", "Content-Type" : "text/html"]);
assert(test.length == 2);
//Not implemented in dmd?
//assert("Content-Length" in col);
//assert("content-length" in col);
assert(col["content-length"] == "1234");
col["content-length"] = "5678";
assert(col["content-length"] == "5678");
test = cast(string[string])col;
assert(test == ["content-length": "5678", "Content-Type" : "text/html"]);
HeaderCollection col2 = new HeaderCollection(["Content-Length": "5678", "Content-Type" : "text/html"]);
assert(col2 == col);
string length = col2.getHeaderString!ContentLengthHeader;
assert(length == "5678");
length = col2.getHeaderString("ContEnt-LEngTH");
assert(length == "5678");
auto plength = col2.getHeader!ContentLengthHeader;
assert(plength.Length == 5678);
assert(col2.hasHeader("ContEnt-LEngTH"));
assert(col2.hasHeader!ContentLengthHeader);
IfModifiedSinceHeader head;
head.Date = SysTime(DateTime(2011, 3, 24, 19, 21, 0), UTC());
col2.setHeader(head);
assert(col2.hasHeader("If-Modified-Since"));
assert(col2["If-Modified-Since"] == "Thu, 24 Mar 2011 19:21:00 GMT");
col2.setHeader("If-Modified-Since", "Thu, 17 Mar 2011 19:21:00 GMT");
assert(col2.hasHeader("If-Modified-Since"));
assert(col2["If-Modified-Since"] == "Thu, 17 Mar 2011 19:21:00 GMT");
}
/**
* This module contains parsers, formatters and data types for the _http
* protocol.
*
* Headers from rfc2616 which are currently not implemented:
* $(UL
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.8, AuthorizationHeader))
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.9, CacheControlHeader))
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.33, ProxyAuthenticateHeader))
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.34, ProxyAuthorizationHeader))
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.38, ServerHeader))
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.43, UserAgentHeader))
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.45, ViaHeader))
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.46, WarningHeader))
* $(LI $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.47, WWWAuthenticateHeader))
* )
* Synopsis:
* ---------------------------------------
* //Formatting a header
* IfModifiedSinceHeader head;
* head.Date = SysTime(DateTime(2011, 3, 24, 19, 21, 0), UTC());
* string headerString = formatHeaderValue(head);
* assert(headerString == "Thu, 24 Mar 2011 19:21:00 GMT");
* headerString = formatHeader(head);
* assert(headerString == "If-Modified-Since: Thu, 24 Mar 2011 19:21:00 GMT");
*
* //Parsing a response
* auto resp = parseResponse("HTTP/1.2 200 OK\r\n");
* assert(resp.Type == ResponseType.StatusLine);
* assert(resp.Line == "HTTP/1.2 200 OK\r\n");
*
* auto sline = StatusLine.parse(resp.Line);
* assert(sline.Major == 1);
* assert(sline.Minor == 2);
* assert(sline.StatusCode == 200);
* assert(sline.Reason == "OK");
*
* resp = parseResponse("Content-Length: 348\r\n");
* assert(resp.Type == ResponseType.Header);
* assert(resp.Key == "Content-Length");
* auto header = parseHeaderValue!(ContentLengthHeader)(resp.Value);
* assert (header.Length == 348);
* ---------------------------------------
* Standards: Conforms to $(LINK2 http://tools.ietf.org/html/rfc2616,rfc2616)
* License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>
* Authors: Johannes Pfau
* Copyright: Copyright Johannes Pfau 2011.
*/
/* Copyright Johannes Pfau 2011.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module std.protocol.http;
#line 53 "http.d.rl"
import std.array, std.base64, std.conv, std.datetime, std.format;
import std.range, std.string, std.traits;
/*
* Helper data types follow.
* Names according to rfc2616
*/
/**
* Data type holding a http
* $(LINK2 http://tools.ietf.org/html/rfc2616#section-6, response message)
*/
struct Response
{
///The response line type
ResponseType Type;
union
{
///The raw value for unknown responses and StatusLine responses
string Line;
///The key in a header response
string Key;
}
///The value in a header response
string Value;
}
/**
* $(LINK2 http://tools.ietf.org/html/rfc2616#section-6,
* HTTP response message type)
*/
enum ResponseType : ushort
{
/**
* $(LINK2 http://tools.ietf.org/html/rfc2616#section-6.1, status line)
*/
StatusLine,
/**
* $(LINK2 http://tools.ietf.org/html/rfc2616#section-6.2, response-header),
* $(LINK2 http://tools.ietf.org/html/rfc2616#section-7.1, entity-header) or
* $(LINK2 http://tools.ietf.org/html/rfc2616#section-4.5, general-header)
*/
Header,
/**
* Empty line [CRLF]
*/
Empty,
/**
* Unknown line
*/
Other
}
/**
* Data type holding a http
* $(LINK2 http://tools.ietf.org/html/rfc2616#section-6.1, status line)
*/
struct StatusLine
{
///HTTP-Version
uint Major, Minor;
///
uint StatusCode;
///
string Reason;
/**
* Parses a string
*
* Examples:
* ---------------------------------------
* auto resp = parseResponse("HTTP/1.2 200 OK\r\n");
* assert(resp.Type == ResponseType.StatusLine);
* assert(resp.Line == "HTTP/1.2 200 OK\r\n");
* auto sline = StatusLine.parse(resp.Line);
*
* assert(sline.Major == 1);
* assert(sline.Minor == 2);
* assert(sline.StatusCode == 200);
* assert(sline.Reason == "OK");
* ---------------------------------------
*/
static StatusLine parse(string line)
{
StatusLine sline;
const(char)* numstart;
mixin(initParser!());
#line 147 "http.d"
{
cs = parseStatusLine_start;
}
#line 152 "http.d"
{
if ( p == pe )
goto _test_eof;
switch ( cs )
{
case 1:
if ( (*p) == 72u )
goto st2;
goto st0;
st0:
cs = 0;
goto _out;
st2:
if ( ++p == pe )
goto _test_eof2;
case 2:
if ( (*p) == 84u )
goto st3;
goto st0;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
if ( (*p) == 84u )
goto st4;
goto st0;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
if ( (*p) == 80u )
goto st5;
goto st0;
st5:
if ( ++p == pe )
goto _test_eof5;
case 5:
if ( (*p) == 47u )
goto st6;
goto st0;
st6:
if ( ++p == pe )
goto _test_eof6;
case 6:
if ( 48u <= (*p) && (*p) <= 57u )
goto tr6;
goto st0;
tr6:
#line 3116 "http.d.rl"
{{
numstart = p;
}}
goto st7;
st7:
if ( ++p == pe )
goto _test_eof7;
case 7:
#line 210 "http.d"
if ( (*p) == 46u )
goto tr7;
if ( 48u <= (*p) && (*p) <= 57u )
goto st7;
goto st0;
tr7:
#line 3108 "http.d.rl"
{{
sline.Major = std.conv.parse!(uint)(line[(numstart - line.ptr)
.. (p - line.ptr)]);
}}
goto st8;
st8:
if ( ++p == pe )
goto _test_eof8;
case 8:
#line 227 "http.d"
if ( 48u <= (*p) && (*p) <= 57u )
goto tr9;
goto st0;
tr9:
#line 3116 "http.d.rl"
{{
numstart = p;
}}
goto st9;
st9:
if ( ++p == pe )
goto _test_eof9;
case 9:
#line 241 "http.d"
if ( (*p) == 32u )
goto tr10;
if ( 48u <= (*p) && (*p) <= 57u )
goto st9;
goto st0;
tr10:
#line 3112 "http.d.rl"
{{
sline.Minor = std.conv.parse!(uint)(line[(numstart - line.ptr)
.. (p - line.ptr)]);
}}
goto st10;
st10:
if ( ++p == pe )
goto _test_eof10;
case 10:
#line 258 "http.d"
if ( 48u <= (*p) && (*p) <= 57u )
goto st11;
goto st0;
st11:
if ( ++p == pe )
goto _test_eof11;
case 11:
if ( 48u <= (*p) && (*p) <= 57u )
goto st12;
goto st0;
st12:
if ( ++p == pe )
goto _test_eof12;
case 12:
if ( 48u <= (*p) && (*p) <= 57u )
goto st13;
goto st0;
st13:
if ( ++p == pe )
goto _test_eof13;
case 13:
if ( (*p) == 32u )
goto tr15;
goto st0;
tr15:
#line 3119 "http.d.rl"
{{
sline.StatusCode = std.conv.parse!(uint)(line[(p - line.ptr -3)
.. (p - line.ptr)]);
}}
goto st14;
st14:
if ( ++p == pe )
goto _test_eof14;
case 14:
#line 294 "http.d"
switch( (*p) ) {
case 13u: goto tr17;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto tr16;
tr16:
#line 3116 "http.d.rl"
{{
numstart = p;
}}
goto st15;
st15:
if ( ++p == pe )
goto _test_eof15;
case 15:
#line 316 "http.d"
switch( (*p) ) {
case 13u: goto tr19;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto st15;
tr17:
#line 3116 "http.d.rl"
{{
numstart = p;
}}
#line 3123 "http.d.rl"
{{
sline.Reason = line[(numstart - line.ptr)
.. (p - line.ptr)];
}}
goto st16;
tr19:
#line 3123 "http.d.rl"
{{
sline.Reason = line[(numstart - line.ptr)
.. (p - line.ptr)];
}}
goto st16;
st16:
if ( ++p == pe )
goto _test_eof16;
case 16:
#line 350 "http.d"
if ( (*p) == 10u )
goto st17;
goto st0;
st17:
if ( ++p == pe )
goto _test_eof17;
case 17:
switch( (*p) ) {
case 9u: goto st15;
case 32u: goto st15;
default: break;
}
goto st0;
default: break;
}
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof4: cs = 4; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
_test_eof6: cs = 6; goto _test_eof;
_test_eof7: cs = 7; goto _test_eof;
_test_eof8: cs = 8; goto _test_eof;
_test_eof9: cs = 9; goto _test_eof;
_test_eof10: cs = 10; goto _test_eof;
_test_eof11: cs = 11; goto _test_eof;
_test_eof12: cs = 12; goto _test_eof;
_test_eof13: cs = 13; goto _test_eof;
_test_eof14: cs = 14; goto _test_eof;
_test_eof15: cs = 15; goto _test_eof;
_test_eof16: cs = 16; goto _test_eof;
_test_eof17: cs = 17; goto _test_eof;
_test_eof: {}
_out: {}
}
#line 147 "http.d.rl"
mixin(finishParser!"parseStatusLine");
return sline;
}
/**
* Formats the StatusLine and writes it to the OutputRange writer.
* Note: There is no newline appended at the end!
*
* Examples:
* ---------------------------------------
* StatusLine sline;
* sline.Major = 1;
* sline.Minor = 1;
* sline.StatusCode = 200;
* sline.Reason = "OK";
* assert(sline.formatString() == "HTTP/1.1 200 OK");
* ---------------------------------------
*
* ---------------------------------------
* StatusLine sline;
* sline.Major = 1;
* sline.Minor = 1;
* sline.StatusCode = 200;
* sline.Reason = "OK";
* auto writer = appender!string();
* this.format(writer);
* assert(writer.data == "HTTP/1.1 200 OK");
* ---------------------------------------
*/
void format(T)(T writer) if (isOutputRange!(T, string))
{
assert(this.StatusCode < 1000, "StatusCode must be max 3 digits");
assert(isText(this.Reason), "Reason must be TEXT according to rfc2616");
assert(indexOf(this.Reason, '\r') == -1, "Reason must not contain '\\r'");
assert(indexOf(this.Reason, '\n') == -1, "Reason must not contain '\\n'");
formattedWrite(writer, "HTTP/%s.%s %03s %s", this.Major, this.Minor,
this.StatusCode, this.Reason);
}
///ditto
string formatString()
{
auto writer = appender!string();
this.format(writer);
return writer.data;
}
}
unittest
{
auto resp = parseResponse("HTTP/1.2 200 OK\r\n");
assert(resp.Type == ResponseType.StatusLine);
assert(resp.Line == "HTTP/1.2 200 OK\r\n");
auto sline = StatusLine.parse(resp.Line);
assert(sline.Major == 1);
assert(sline.Minor == 2);
assert(sline.StatusCode == 200);
assert(sline.Reason == "OK");
}
unittest
{
StatusLine sline;
sline.Major = 1;
sline.Minor = 1;
sline.StatusCode = 200;
sline.Reason = "OK";
assert(sline.formatString() == "HTTP/1.1 200 OK");
sline.Reason = "";
assert(sline.formatString() == "HTTP/1.1 200 ");
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.1, media-range)
struct MediaRange
{
///
string Type;
///
string SubType;
///
string[string] Parameters;
///
float AcceptParam = -1f;
///
string[string] AcceptExtension;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.2, charset / q combination)
struct Charset
{
///
string Name;
///
float Q = -1f;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.2, content-coding / q combination)
struct ContentCoding
{
///
enum : ushort
{
///
Compress,
///
Gzip,
///
Deflate,
///
Identity,
///
Other
}
///
typeof(ContentCoding.Other) Type;
///
float Q = -1f;
///If Type is ContentCoding.Other this field contains the raw value
string Raw;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.4, language-range / q combination)
struct LanguageRange
{
///
string Main;
///
string Sub;
///
float Q = -1f;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-3.12, range-unit)
struct RangeUnit
{
///
enum : ushort
{
///
Bytes,
///
Other
}
///
typeof(RangeUnit.Other) Type;
///If Type is RangeUnit.Other this field contains the raw value
string Raw;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-5.1.1, http methods)
struct Method
{
enum : ushort
{
///
OPTIONS,
///
GET,
///
HEAD,
///
POST,
///
PUT,
///
DELETE,
///
TRACE,
///
CONNECT,
///
Other
}
///
typeof(Method.CONNECT) Type;
///
public this(typeof(Method.CONNECT) method)
{
this.Type = method;
}
///If Type is Method.Other this field contains the raw value
string Raw;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.10, connection-token)
struct ConnectionToken
{
enum : ushort
{
///
Close,
///
Other
}
///
typeof(ConnectionToken.Other) Type;
///If Type is ConnectionToken.Other this field contains the raw value
string Raw;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.4, language-range / q combination)
struct LanguageTag
{
///
string Main;
///
string Sub;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.16, positions used with content-range-spec)
struct BytePos
{
///
bool Unknown = false;
///
ulong Value;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.16, content-range-spec)
struct ContentRangeSpec
{
///
BytePos From;
///
BytePos To;
///
BytePos Length;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-3.7, media-type)
struct MediaType
{
///
string Type;
///
string SubType;
///
string[string] Parameters;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-3.11, entity-tag)
struct EntityTag
{
///
bool Weak = false;
///
string Value;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.20, expectation)
struct Expectation
{
enum : ushort
{
Other,
Continue
}
typeof(Expectation.Continue) Type;
string ExtensionKey;
string ExtensionValue;
string[string] ExtensionParameters;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.32, pragma-directive)
struct PragmaDirective
{
enum : ushort
{
///
NoCache,
///
Extension
}
///
typeof(PragmaDirective.Extension) Type;
///
string ExtensionKey;
///
string ExtensionValue;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.35.1, byte-range-spec)
struct ByteRangeSpec
{
union
{
///
long First;
///
long Suffix;
}
enum : ushort
{
SuffixSpec,
ByteSpec
}
typeof(ByteRangeSpec.ByteSpec) Type;
///
BytePos Last;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-3.8, product)
struct Product
{
///
string Name;
///
string Version;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-14.39, t-codings)
struct TCoding
{
///
bool Trailers = false;
///
string[string] Parameters, AcceptParameters;
///
string Extension;
///
float Q = -1f;
}
///$(LINK2 http://tools.ietf.org/html/rfc2616#section-3.6, transfer-coding)
struct TransferCoding
{
enum : ushort
{
///
Chunked,
///
Custom
}
///
typeof(TransferCoding.Custom) Type;
///
string Raw;
///
string[string] Parameters;
}
/*
* Header types follow
*/
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.1,
* "Accept" header)
*
* Type:
* request-header
*/
struct AcceptHeader
{
public:
///
MediaRange[] Media;
static string Key = "Accept";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, range; Media)
{
debug
{
if(range.SubType != "*")
assert(range.Type != "*");
}
assert(isToken(range.Type));
assert(isToken(range.SubType));
formattedWrite(writer, "%s/%s", range.Type, range.SubType);
foreach(key, value; range.Parameters)
{
writeParameter(writer, key, value);
}
if(range.AcceptParam >= 0)
{
assert(range.AcceptParam <= 1);
formattedWrite(writer, ";q=%.3f", range.AcceptParam);
foreach(key, value; range.AcceptExtension)
{
writeParameter(writer, key, value);
}
}
if(i != Media.length - 1)
writer.put(", ");
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.2,
* "Accept-Charset" header)
*
* Type:
* request-header
*/
struct AcceptCharsetHeader
{
public:
///
Charset[] Charsets;
static string Key = "Accept-Charset";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, charset; Charsets)
{
assert(isToken(charset.Name));
writer.put(charset.Name);
if(charset.Q >= 0)
{
assert(charset.Q <= 1);
formattedWrite(writer, ";q=%.3f", charset.Q);
}
if(i != Charsets.length - 1)
writer.put(", ");
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.3,
* "Accept-Encoding" header)
*
* Type:
* request-header
*/
struct AcceptEncodingHeader
{
public:
///
ContentCoding[] Codings;
static string Key = "Accept-Encoding";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Codings)
{
final switch(entry.Type)
{
case ContentCodingType.Compress:
writer.put("compress");
break;
case ContentCodingType.Deflate:
writer.put("deflate");
break;
case ContentCodingType.Gzip:
writer.put("gzip");
break;
case ContentCodingType.Identity:
writer.put("identity");
break;
case ContentCodingType.Other:
assert(isToken(entry.Raw));
writer.put(entry.Coding.Raw);
break;
}
if(entry.Q >= 0)
{
assert(entry.Q <= 1);
formattedWrite(writer, ";q=%.3f", entry.Q);
}
if(i != Codings.length - 1)
writer.put(", ");
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.4,
* "Accept-Language" header)
*
* Type:
* request-header
*/
struct AcceptLanguageHeader
{
public:
///
LanguageRange[] Languages;
static string Key = "Accept-Language";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Languages)
{
assert(entry.Main.length <= 8);
assert(entry.Sub.length <= 8);
debug
{
if(entry.Tag.Main != "*")
{
assert(isalpha(entry.Sub));
assert(isalpha(entry.Main));
}
else
{
assert(entry.Tag.Sub == "");
}
}
writer.put(entry.Main);
if(entry.Sub != "")
{
writer.put("-");
writer.put(entry.Sub);
}
if(entry.Q >= 0)
{
assert(entry.Q <= 1);
formattedWrite(writer, ";q=%.3f", entry.Q);
}
if(i != Languages.length - 1)
writer.put(", ");
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.5,
* "Accept-Ranges" header)
*
* Type:
* response-header
*/
struct AcceptRangesHeader
{
public:
///
bool None = false;
///
RangeUnit[] AcceptableRanges;
static string Key = "Accept-Ranges";
void format(T)(T writer) if (isOutputRange!(T, string))
{
if(this.None)
{
writer.put("none");
return;
}
foreach(i, entry; AcceptableRanges)
{
if(entry.Type == RangeUnit.Bytes)
writer.put("bytes");
else
{
assert(isToken(entry.Raw));
writer.put(entry.Raw);
}
if(i != AcceptableRanges.length - 1)
writer.put(", ");
}
}
static AcceptRangesHeader parse(string line)
{
string[] list = parseCommaList(line);
AcceptRangesHeader hdr;
if(list.length == 1 && list[0] == "none")
{
hdr.None = true;
return hdr;
}
foreach(entry; list)
{
RangeUnit unit;
if(entry == "bytes")
unit.Type = RangeUnit.Bytes;
else
{
unit.Type = RangeUnit.Other;
unit.Raw = entry;
}
hdr.AcceptableRanges ~= unit;
}
return hdr;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.6,
* "Age" header)
*
* Type:
* response-header
*/
struct AgeHeader
{
public:
///delta in seconds
ulong Age;
///
public this(ulong age)
{
this.Age = age;
}
static string Key = "Age";
void format(T)(T writer) if (isOutputRange!(T, string))
{
write(writer, Age);
}
static AgeHeader parse(string line)
{
return AgeHeader(std.conv.parse!ulong(line));
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.7,
* "Allow" header)
*
* Type:
* entity-header
*/
struct AllowHeader
{
public:
///
Method[] Methods;
static string Key = "Allow";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Methods)
{
final switch(entry.Type)
{
case Method.OPTIONS:
writer.put("OPTIONS");
break;
case Method.GET:
writer.put("GET");
break;
case Method.HEAD:
writer.put("HEAD");
break;
case Method.POST:
writer.put("POST");
break;
case Method.PUT:
writer.put("PUT");
break;
case Method.DELETE:
writer.put("DELETE");
break;
case Method.TRACE:
writer.put("TRACE");
break;
case Method.CONNECT:
writer.put("CONNECT");
break;
case Method.Other:
assert(entry.Raw != "");
assert(isToken(entry.Raw));
writer.put(entry.Raw);
break;
}
if(i != Methods.length - 1)
writer.put(", ");
}
}
static AllowHeader parse(string line)
{
string[] list = parseCommaList(line);
AllowHeader allow;
foreach(entry; list)
{
switch(entry)
{
case "OPTIONS":
allow.Methods ~= Method(Method.OPTIONS);
break;
case "GET":
allow.Methods ~= Method(Method.GET);
break;
case "HEAD":
allow.Methods ~= Method(Method.HEAD);
break;
case "POST":
allow.Methods ~= Method(Method.POST);
break;
case "PUT":
allow.Methods ~= Method(Method.PUT);
break;
case "DELETE":
allow.Methods ~= Method(Method.DELETE);
break;
case "TRACE":
allow.Methods ~= Method(Method.TRACE);
break;
case "CONNECT":
allow.Methods ~= Method(Method.CONNECT);
break;
default:
auto m = Method(Method.Other);
m.Raw = entry;
allow.Methods ~= m;
break;
}
}
return allow;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.10,
* "Connection" header)
*
* Type:
* general-header
*/
struct ConnectionHeader
{
public:
///
ConnectionToken[] Options;
static string Key = "Connection";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Options)
{
if(entry.Type == ConnectionToken.Close)
{
writer.put("close");
assert(entry.Raw == "");
}
else
{
assert(entry.Raw != "");
assert(isToken(entry.Raw));
writer.put(entry.Raw);
}
if(i != Options.length - 1)
writer.put(", ");
}
}
static ConnectionHeader parse(string line)
{
ConnectionHeader con;
string[] list = parseCommaList(line);
foreach(entry; list)
{
switch(tolower(entry))
{
case "close":
ConnectionToken token;
token.Type = ConnectionToken.Close;
con.Options ~= token;
break;
default:
ConnectionToken token;
token.Type = ConnectionToken.Other;
token.Raw = entry;
con.Options ~= token;
break;
}
}
return con;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.11,
* "Content-Encoding" header)
*
* Type:
* entity-header
*/
struct ContentEncodingHeader
{
public:
///
ContentCoding[] Codings;
static string Key = "Content-Encoding";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Codings)
{
final switch(entry.Type)
{
case ContentCoding.Compress:
assert(entry.Raw == "");
writer.put("compress");
break;
case ContentCoding.Gzip:
assert(entry.Raw == "");
writer.put("gzip");
break;
case ContentCoding.Deflate:
assert(entry.Raw == "");
writer.put("deflate");
break;
case ContentCoding.Identity:
assert(entry.Raw == "");
writer.put("identity");
break;
case ContentCoding.Other:
assert(entry.Raw != "");
assert(isToken(entry.Raw));
writer.put(entry.Raw);
break;
}
if(i != Codings.length - 1)
writer.put(", ");
}
}
static ContentEncodingHeader parse(string line)
{
ContentEncodingHeader enc;
string[] list = parseCommaList(line);
foreach(entry; list)
{
ContentCoding coding;
switch(tolower(entry))
{
case "compress":
coding.Type = ContentCoding.Compress;
enc.Codings ~= coding;
break;
case "deflate":
coding.Type = ContentCoding.Deflate;
enc.Codings ~= coding;
break;
case "gzip":
coding.Type = ContentCoding.Gzip;
enc.Codings ~= coding;
break;
case "identity":
coding.Type = ContentCoding.Identity;
enc.Codings ~= coding;
break;
default:
coding.Type = ContentCoding.Other;
coding.Raw = entry;
enc.Codings ~= coding;
break;
}
}
return enc;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.12,
* "Content-Language" header)
*
* Type:
* entity-header
*/
struct ContentLanguageHeader
{
public:
///
LanguageTag[] Tags;
static string Key = "Content-Language";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Tags)
{
assert(isToken(entry.Main));
writer.put(entry.Main);
if(entry.Sub != "")
{
assert(isToken(entry.Sub));
writer.put("-");
writer.put(entry.Sub);
}
if(i != Tags.length - 1)
writer.put(", ");
}
}
static ContentLanguageHeader parse(string line)
{
ContentLanguageHeader lang;
string[] list = parseCommaList(line);
foreach(entry; list)
{
LanguageTag tag;
size_t i;
if((i = indexOf(entry, '-')) != -1)
{
tag.Main = strip(entry[0 .. i]);
tag.Sub = strip(entry[i+1 .. $]);
}
else
{
tag.Main = strip(entry);
}
lang.Tags ~= tag;
}
return lang;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.13,
* "Content-Length" header)
*
* Type:
* entity-header
*/
struct ContentLengthHeader
{
public:
///
ulong Length;
static string Key = "Content-Length";
void format(T)(T writer) if (isOutputRange!(T, string))
{
write(writer, Length);
}
static ContentLengthHeader parse(string line)
{
ContentLengthHeader len;
len.Length = std.conv.parse!ulong(line);
return len;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.14,
* "Content-Location" header)
*
* Type:
* entity-header
*/
struct ContentLocationHeader
{
public:
///
string Location;
static string Key = "Content-Location";
void format(T)(T writer) if (isOutputRange!(T, string))
{
//TODO: verify URI in debug mode
writer.put(Location);
}
static ContentLocationHeader parse(string line)
{
ContentLocationHeader loc;
loc.Location = line;
return loc;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.15,
* "Content-MD5" header)
*
* Type:
* entity-header
*/
struct ContentMD5Header
{
public:
///
ubyte[16] MD5;
static string Key = "Content-MD5";
void format(T)(T writer) if (isOutputRange!(T, string))
{
char[24] buf;
writer.put(encode(this.MD5, buf));
}
static ContentMD5Header parse(string line)
{
ContentMD5Header cmd5;
//strip trailing '=' for length calculation
size_t nlength;
for(nlength = line.length - 1; nlength >= 0; nlength--)
{
if(line[nlength] != '=')
break;
}
if(Base64.decodeLength(nlength) > 16)
return cmd5;
ubyte[24] buf;
Base64.decode!(string, ubyte[])(line, buf);
cmd5.MD5 = buf[0 .. 16];
return cmd5;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.16,
* "Content-Range" header)
*
* Type:
* entity-header
*/
struct ContentRangeHeader
{
public:
///
ContentRangeSpec Range;
static string Key = "Content-Range";
void format(T)(T writer) if (isOutputRange!(T, string))
{
writer.put("bytes ");
if(Range.From.Unknown || Range.To.Unknown)
{
writer.put("*");
}
else
{
formattedWrite(writer, "%s", Range.From.Value);
writer.put("-");
formattedWrite(writer, "%s", Range.To.Value);
}
writer.put("/");
if(Range.Length.Unknown)
{
writer.put("*");
}
else
{
formattedWrite(writer, "%s", Range.Length.Value);
}
}
static ContentRangeHeader parse(string line)
{
ContentRangeHeader head;
const(char)* start;
mixin(initParser!());
#line 1422 "http.d"
{
cs = parseContentRangeHeader_start;
}
#line 1427 "http.d"
{
if ( p == pe )
goto _test_eof;
switch ( cs )
{
case 1:
switch( (*p) ) {
case 66u: goto st2;
case 98u: goto st2;
default: break;
}
goto st0;
st0:
cs = 0;
goto _out;
st2:
if ( ++p == pe )
goto _test_eof2;
case 2:
switch( (*p) ) {
case 89u: goto st3;
case 121u: goto st3;
default: break;
}
goto st0;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
switch( (*p) ) {
case 84u: goto st4;
case 116u: goto st4;
default: break;
}
goto st0;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
switch( (*p) ) {
case 69u: goto st5;
case 101u: goto st5;
default: break;
}
goto st0;
st5:
if ( ++p == pe )
goto _test_eof5;
case 5:
switch( (*p) ) {
case 83u: goto st6;
case 115u: goto st6;
default: break;
}
goto st0;
st6:
if ( ++p == pe )
goto _test_eof6;
case 6:
if ( (*p) == 32u )
goto st7;
goto st0;
st7:
if ( ++p == pe )
goto _test_eof7;
case 7:
if ( (*p) == 42u )
goto st8;
if ( 48u <= (*p) && (*p) <= 57u )
goto tr8;
goto st0;
st8:
if ( ++p == pe )
goto _test_eof8;
case 8:
if ( (*p) == 47u )
goto tr9;
goto st0;
tr9:
#line 3204 "http.d.rl"
{{
head.Range.To.Unknown = true;
head.Range.From.Unknown = true;
}}
goto st9;
tr15:
#line 3190 "http.d.rl"
{{
head.Range.To.Value = std.conv.parse!ulong(line[(start - line.ptr)
.. (p - line.ptr)]);
}}
goto st9;
st9:
if ( ++p == pe )
goto _test_eof9;
case 9:
#line 1524 "http.d"
if ( (*p) == 42u )
goto st13;
if ( 48u <= (*p) && (*p) <= 57u )
goto tr11;
goto st0;
st13:
if ( ++p == pe )
goto _test_eof13;
case 13:
goto st0;
tr11:
#line 3181 "http.d.rl"
{{
start = p;
}}
goto st14;
st14:
if ( ++p == pe )
goto _test_eof14;
case 14:
#line 1545 "http.d"
if ( 48u <= (*p) && (*p) <= 57u )
goto st14;
goto st0;
tr8:
#line 3181 "http.d.rl"
{{
start = p;
}}
goto st10;
st10:
if ( ++p == pe )
goto _test_eof10;
case 10:
#line 1559 "http.d"
if ( (*p) == 45u )
goto tr12;
if ( 48u <= (*p) && (*p) <= 57u )
goto st10;
goto st0;
tr12:
#line 3185 "http.d.rl"
{{
head.Range.From.Value = std.conv.parse!ulong(line[(start - line.ptr)
.. (p - line.ptr)]);
}}
goto st11;
st11:
if ( ++p == pe )
goto _test_eof11;
case 11:
#line 1576 "http.d"
if ( 48u <= (*p) && (*p) <= 57u )
goto tr14;
goto st0;
tr14:
#line 3181 "http.d.rl"
{{
start = p;
}}
goto st12;
st12:
if ( ++p == pe )
goto _test_eof12;
case 12:
#line 1590 "http.d"
if ( (*p) == 47u )
goto tr15;
if ( 48u <= (*p) && (*p) <= 57u )
goto st12;
goto st0;
default: break;
}
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof4: cs = 4; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
_test_eof6: cs = 6; goto _test_eof;
_test_eof7: cs = 7; goto _test_eof;
_test_eof8: cs = 8; goto _test_eof;
_test_eof9: cs = 9; goto _test_eof;
_test_eof13: cs = 13; goto _test_eof;
_test_eof14: cs = 14; goto _test_eof;
_test_eof10: cs = 10; goto _test_eof;
_test_eof11: cs = 11; goto _test_eof;
_test_eof12: cs = 12; goto _test_eof;
_test_eof: {}
if ( p == eof )
{
switch ( cs ) {
case 14:
#line 3195 "http.d.rl"
{{
head.Range.Length.Value = std.conv.parse!ulong(line[(start - line.ptr)
.. (p - line.ptr)]);
}}
break;
case 13:
#line 3200 "http.d.rl"
{{
head.Range.Length.Unknown = true;
}}
break;
#line 1629 "http.d"
default: break;
}
}
_out: {}
}
#line 1184 "http.d.rl"
mixin(finishParser!"parseContentRangeHeader");
return head;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.17,
* "Content-Type" header)
*
* Type:
* entity-header
*/
struct ContentTypeHeader
{
public:
///
MediaType Type;
static string Key = "Content-Type";
void format(T)(T writer) if (isOutputRange!(T, string))
{
assert(isToken(Type.Type));
assert(isToken(Type.SubType));
writer.put(Type.Type);
writer.put("/");
writer.put(Type.SubType);
foreach(key, value; media.Parameters)
writeParameter(writer, key, value);
}
static ContentTypeHeader parse(string line)
{
ContentTypeHeader ctype;
MediaType ret;
const(char)* start;
mixin(initParser!());
#line 1676 "http.d"
{
cs = parseContentTypeHeader_start;
}
#line 1681 "http.d"
{
if ( p == pe )
goto _test_eof;
switch ( cs )
{
case 1:
switch( (*p) ) {
case 33u: goto tr0;
case 124u: goto tr0;
case 126u: goto tr0;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto tr0;
} else if ( (*p) >= 35u )
goto tr0;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto tr0;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto tr0;
} else
goto tr0;
} else
goto tr0;
goto st0;
st0:
cs = 0;
goto _out;
tr0:
#line 3219 "http.d.rl"
{{
start = p;
}}
goto st2;
st2:
if ( ++p == pe )
goto _test_eof2;
case 2:
#line 1725 "http.d"
switch( (*p) ) {
case 33u: goto st2;
case 47u: goto tr3;
case 124u: goto st2;
case 126u: goto st2;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto st2;
} else if ( (*p) >= 35u )
goto st2;
} else if ( (*p) > 57u ) {
if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto st2;
} else if ( (*p) >= 65u )
goto st2;
} else
goto st2;
goto st0;
tr3:
#line 3223 "http.d.rl"
{{
ret.Type = line[(start - line.ptr) .. (p - line.ptr)];
}}
goto st3;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
#line 1758 "http.d"
switch( (*p) ) {
case 33u: goto tr4;
case 124u: goto tr4;
case 126u: goto tr4;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto tr4;
} else if ( (*p) >= 35u )
goto tr4;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto tr4;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto tr4;
} else
goto tr4;
} else
goto tr4;
goto st0;
tr4:
#line 3219 "http.d.rl"
{{
start = p;
}}
goto st6;
st6:
if ( ++p == pe )
goto _test_eof6;
case 6:
#line 1793 "http.d"
switch( (*p) ) {
case 9u: goto tr7;
case 13u: goto tr8;
case 32u: goto tr7;
case 33u: goto st6;
case 59u: goto tr10;
case 124u: goto st6;
case 126u: goto st6;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto st6;
} else if ( (*p) >= 35u )
goto st6;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto st6;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto st6;
} else
goto st6;
} else
goto st6;
goto st0;
tr7:
#line 3227 "http.d.rl"
{{
ret.SubType = line[(start - line.ptr) .. (p - line.ptr)];
}}
goto st7;
st7:
if ( ++p == pe )
goto _test_eof7;
case 7:
#line 1832 "http.d"
switch( (*p) ) {
case 9u: goto st7;
case 13u: goto st4;
case 32u: goto st7;
case 59u: goto tr12;
default: break;
}
goto st0;
tr8:
#line 3227 "http.d.rl"
{{
ret.SubType = line[(start - line.ptr) .. (p - line.ptr)];
}}
goto st4;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
#line 1851 "http.d"
if ( (*p) == 10u )
goto st5;
goto st0;
st5:
if ( ++p == pe )
goto _test_eof5;
case 5:
switch( (*p) ) {
case 9u: goto st7;
case 32u: goto st7;
default: break;
}
goto st0;
tr12:
#line 3219 "http.d.rl"
{{
start = p;
}}
goto st8;
tr10:
#line 3227 "http.d.rl"
{{
ret.SubType = line[(start - line.ptr) .. (p - line.ptr)];
}}
#line 3219 "http.d.rl"
{{
start = p;
}}
goto st8;
st8:
if ( ++p == pe )
goto _test_eof8;
case 8:
#line 1885 "http.d"
goto st8;
default: break;
}
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof6: cs = 6; goto _test_eof;
_test_eof7: cs = 7; goto _test_eof;
_test_eof4: cs = 4; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
_test_eof8: cs = 8; goto _test_eof;
_test_eof: {}
if ( p == eof )
{
switch ( cs ) {
case 6:
#line 3227 "http.d.rl"
{{
ret.SubType = line[(start - line.ptr) .. (p - line.ptr)];
}}
break;
case 8:
#line 3231 "http.d.rl"
{{
ret.Parameters = parseParameterList(line[(start - line.ptr)
.. (p - line.ptr)]);
}}
break;
#line 1914 "http.d"
default: break;
}
}
_out: {}
}
#line 1225 "http.d.rl"
mixin(finishParser!"parseContentTypeHeader");
ctype.Type = ret;
return ctype;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.18,
* "Date" header)
*
* Type:
* general-header
*/
struct DateHeader
{
public:
///
SysTime Date;
static string Key = "Date";
void format(T)(T writer) if (isOutputRange!(T, string))
{
formatDate(Date);
}
static DateHeader parse(string line)
{
DateHeader head;
head.Date = parseDate(line);
return head;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.19,
* "ETag" header)
*
* Type:
* response-header
*/
struct ETagHeader
{
public:
///
public EntityTag Tag;
static string Key = "ETag";
void format(T)(T writer) if (isOutputRange!(T, string))
{
formatEntityTag(writer, Tag);
}
static ETagHeader parse(string line)
{
ETagHeader head;
EntityTag tag;
const(char)* start;
mixin(initParser!());
#line 1982 "http.d"
{
cs = parseETag_start;
}
#line 1987 "http.d"
{
if ( p == pe )
goto _test_eof;
switch ( cs )
{
case 1:
switch( (*p) ) {
case 34u: goto tr2;
case 87u: goto tr3;
case 124u: goto tr0;
case 126u: goto tr0;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto tr0;
} else if ( (*p) >= 33u )
goto tr0;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto tr0;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto tr0;
} else
goto tr0;
} else
goto tr0;
goto st0;
st0:
cs = 0;
goto _out;
tr0:
#line 3279 "http.d.rl"
{{
start = p;
}}
goto st8;
tr11:
#line 3275 "http.d.rl"
{{
tag.Weak = true;
}}
#line 3279 "http.d.rl"
{{
start = p;
}}
goto st8;
st8:
if ( ++p == pe )
goto _test_eof8;
case 8:
#line 2042 "http.d"
switch( (*p) ) {
case 33u: goto st8;
case 124u: goto st8;
case 126u: goto st8;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto st8;
} else if ( (*p) >= 35u )
goto st8;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto st8;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto st8;
} else
goto st8;
} else
goto st8;
goto st0;
tr2:
#line 3279 "http.d.rl"
{{
start = p;
}}
goto st2;
tr12:
#line 3275 "http.d.rl"
{{
tag.Weak = true;
}}
#line 3279 "http.d.rl"
{{
start = p;
}}
goto st2;
st2:
if ( ++p == pe )
goto _test_eof2;
case 2:
#line 2087 "http.d"
switch( (*p) ) {
case 13u: goto st3;
case 34u: goto st9;
case 92u: goto st5;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto st2;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
if ( (*p) == 10u )
goto st4;
goto st0;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
switch( (*p) ) {
case 9u: goto st2;
case 32u: goto st2;
default: break;
}
goto st0;
st9:
if ( ++p == pe )
goto _test_eof9;
case 9:
goto st0;
st5:
if ( ++p == pe )
goto _test_eof5;
case 5:
switch( (*p) ) {
case 13u: goto st6;
case 34u: goto st10;
case 92u: goto st5;
default: break;
}
goto st2;
st6:
if ( ++p == pe )
goto _test_eof6;
case 6:
switch( (*p) ) {
case 10u: goto st4;
case 13u: goto st3;
case 34u: goto st9;
case 92u: goto st5;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 11u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto st2;
st10:
if ( ++p == pe )
goto _test_eof10;
case 10:
switch( (*p) ) {
case 13u: goto st3;
case 34u: goto st9;
case 92u: goto st5;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto st2;
tr3:
#line 3279 "http.d.rl"
{{
start = p;
}}
goto st11;
st11:
if ( ++p == pe )
goto _test_eof11;
case 11:
#line 2179 "http.d"
switch( (*p) ) {
case 33u: goto st8;
case 47u: goto st7;
case 124u: goto st8;
case 126u: goto st8;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto st8;
} else if ( (*p) >= 35u )
goto st8;
} else if ( (*p) > 57u ) {
if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto st8;
} else if ( (*p) >= 65u )
goto st8;
} else
goto st8;
goto st0;
st7:
if ( ++p == pe )
goto _test_eof7;
case 7:
switch( (*p) ) {
case 34u: goto tr12;
case 124u: goto tr11;
case 126u: goto tr11;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto tr11;
} else if ( (*p) >= 33u )
goto tr11;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto tr11;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto tr11;
} else
goto tr11;
} else
goto tr11;
goto st0;
default: break;
}
_test_eof8: cs = 8; goto _test_eof;
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof4: cs = 4; goto _test_eof;
_test_eof9: cs = 9; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
_test_eof6: cs = 6; goto _test_eof;
_test_eof10: cs = 10; goto _test_eof;
_test_eof11: cs = 11; goto _test_eof;
_test_eof7: cs = 7; goto _test_eof;
_test_eof: {}
if ( p == eof )
{
switch ( cs ) {
case 8:
case 9:
case 10:
case 11:
#line 3282 "http.d.rl"
{{
tag.Value = prepareValue(line[(start - line.ptr) .. (p - line.ptr)]);
}}
break;
#line 2256 "http.d"
default: break;
}
}
_out: {}
}
#line 1287 "http.d.rl"
mixin(finishParser!"parseETag");
head.Tag = tag;
return head;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.20,
* "Expect" header)
*
* Type:
* request-header
*/
struct ExpectHeader
{
public:
///
Expectation[] Expect;
static string Key = "Expect";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Expect)
{
if(entry.Type == Expectation.Continue)
{
assert(entry.ExtensionKey == "");
assert(entry.ExtensionValue == "");
assert(entry.ExtensionParameters.length == 0);
writer.put("100-continue");
}
else
{
assert(entry.ExtensionKey != "");
assert(isToken(entry.ExtensionKey));
writer.put(entry.ExtensionKey);
if(entry.ExtensionValue != "")
{
writer.put("=");
if(isToken(entry.ExtensionValue))
writer.put(entry.ExtensionValue);
else
writer.put(quote(entry.ExtensionValue));
}
foreach(key, value; entry.ExtensionParameters)
{
writeParameter(writer, key, value);
}
}
if(i != Expect.length - 1)
writer.put(", ");
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.21,
* "Expires" header)
*
* Type:
* entity-header
*/
struct ExpiresHeader
{
public:
///
SysTime Date;
static string Key = "Expires";
void format(T)(T writer) if (isOutputRange!(T, string))
{
formatDate(writer, Date);
}
static ExpiresHeader parse(string line)
{
ExpiresHeader head;
head.Date = parseDate(line);
return head;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.22,
* "From" header)
*
* Type:
* request-header
*/
struct FromHeader
{
public:
///
string Email;
static string Key = "From";
void format(T)(T writer) if (isOutputRange!(T, string))
{
//TODO: Chek in debug with isemail
writer.put(this.email);
}
static FromHeader parse(string line)
{
FromHeader from;
from.Email = line;
return from;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.23,
* "Host" header)
*
* Type:
* request-header
*/
struct HostHeader
{
public:
///
string Host;
///
bool DefaultPort = true;
///
ushort Port;
static string Key = "Host";
void format(T)(T writer) if (isOutputRange!(T, string))
{
//TODO: check host in debug mode
assert(host != "");
writer.put(host);
if(!DefaultPort)
{
writer.put(':');
formattedWrite(writer, "%s", Port);
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.24,
* "If-Match" header)
*
* Type:
* request-header
*/
struct IfMatchHeader
{
public:
///
bool All;
///
EntityTag[] Tags;
static string Key = "If-Match";
void format(T)(T writer) if (isOutputRange!(T, string))
{
if(All)
{
writer.put("*");
assert(Tags.length == 0);
}
else
{
assert(Tags.length > 0);
foreach(i, entry; Tags)
{
formatEntityTag(entry, writer);
if(i != header.Specific.length - 1)
writer.put(", ");
}
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.25,
* "If-Modified-Since" header)
*
* Type:
* request-header
*/
struct IfModifiedSinceHeader
{
public:
///
SysTime Date;
static string Key = "If-Modified-Since";
void format(T)(T writer) if (isOutputRange!(T, string))
{
formatDate(writer, Date);
}
static IfModifiedSinceHeader parse(string line)
{
IfModifiedSinceHeader head;
head.Date = parseDate(line);
return head;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.26,
* "If-None-Match" header)
*
* Type:
* request-header
*/
struct IfNoneMatchHeader
{
public:
///
bool All;
///
EntityTag[] Tags;
static string Key = "If-None-Match";
void format(T)(T writer) if (isOutputRange!(T, string))
{
if(All)
{
writer.put("*");
assert(Tags.length == 0);
}
else
{
assert(Tags.length > 0);
foreach(i, entry; Tags)
{
formatEntityTag(entry, writer);
if(i != header.Specific.length - 1)
writer.put(", ");
}
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.27,
* "If-Range" header)
*
* Type:
* request-header
*/
struct IfRangeHeader
{
public:
///
SysTime Time;
///
EntityTag Tag;
///Use a time value in the If-Range header instead of an EntityTag
bool useTime;
static string Key = "If-Range";
void format(T)(T writer) if (isOutputRange!(T, string))
{
if(useTime)
{
formatDate(entry, Date);
}
else
{
formatEntityTag(writer, Tag);
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.28,
* "If-Unmodified-Since" header)
*
* Type:
* request-header
*/
struct IfUnmodifiedSinceHeader
{
public:
///
SysTime Date;
static string Key = "If-Unmodified-Since";
void format(T)(T writer) if (isOutputRange!(T, string))
{
formatDate(writer, Date);
}
static IfUnmodifiedSinceHeader parse(string line)
{
IfUnmodifiedSinceHeader head;
head.Date = parseDate(line);
return head;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.29,
* "Last-Modified" header)
*
* Type:
* entity-header
*/
struct LastModifiedHeader
{
public:
///
SysTime Date;
static string Key = "Last-Modified";
void format(T)(T writer) if (isOutputRange!(T, string))
{
formatDate(writer, Date);
}
static LastModifiedHeader parse(string line)
{
LastModifiedHeader head;
head.Date = parseDate(line);
return head;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.30,
* "Location" header)
*
* Type:
* response-header
*/
struct LocationHeader
{
public:
///
string Location;
static string Key = "Location";
void format(T)(T writer) if (isOutputRange!(T, string))
{
//TODO: verify URI in debug mode
writer.put(Location);
}
static LocationHeader parse(string line)
{
LocationHeader loc;
loc.Location = line;
return loc;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.31,
* "Max-Forwards" header)
*
* Type:
* request-header
*/
struct MaxForwardsHeader
{
public:
///
ulong Forwards;
static string Key = "Max-Forwards";
void format(T)(T writer) if (isOutputRange!(T, string))
{
formattedWrite(writer, Forwards);
}
static MaxForwardsHeader parse(string line)
{
MaxForwardsHeader mf;
mf.Forwards = std.conv.parse!ulong(line);
return mf;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.32,
* "Pragma" header)
*
* Type:
* general-header
*/
struct PragmaHeader
{
public:
///
PragmaDirective[] Directives;
static string Key = "Pragma";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Directives)
{
if(entry.Type == PragmaDirective.NoCache)
{
writer.put("no-cache");
assert(entry.ExtensionKey == "");
assert(entry.ExtensionValue == "");
}
else
{
assert(entry.ExtensionKey != "");
assert(isToken(entry.ExtensionKey));
writer.put(entry.ExtensionKey);
if(entry.ExtensionValue != "")
{
writer.put("=");
if(isToken(entry.ExtensionValue))
writer.put(entry.ExtensionValue);
else
writer.put(quote(entry.ExtensionValue));
}
}
if(i != Directives.length - 1)
writer.put(", ");
}
}
static PragmaHeader parse(string line)
{
PragmaHeader prag;
string[] list = parseCommaList(line);
foreach(entry; list)
{
PragmaDirective dir;
const(char)* start;
mixin(initParser!("entry"));
#line 2694 "http.d"
{
cs = parsePragmaEntry_start;
}
#line 2699 "http.d"
{
if ( p == pe )
goto _test_eof;
switch ( cs )
{
case 1:
switch( (*p) ) {
case 33u: goto tr0;
case 124u: goto tr0;
case 126u: goto tr0;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto tr0;
} else if ( (*p) >= 35u )
goto tr0;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto tr0;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto tr0;
} else
goto tr0;
} else
goto tr0;
goto st0;
st0:
cs = 0;
goto _out;
tr0:
#line 3297 "http.d.rl"
{{
start = p;
}}
goto st8;
st8:
if ( ++p == pe )
goto _test_eof8;
case 8:
#line 2743 "http.d"
switch( (*p) ) {
case 33u: goto st8;
case 61u: goto tr12;
case 124u: goto st8;
case 126u: goto st8;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto st8;
} else if ( (*p) >= 35u )
goto st8;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto st8;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto st8;
} else
goto st8;
} else
goto st8;
goto st0;
tr12:
#line 3300 "http.d.rl"
{{
string key = entry[(start - entry.ptr)
.. (p - entry.ptr)];
if(key == "no-cache")
{
dir.Type = PragmaDirective.NoCache;
}
else
{
dir.Type = PragmaDirective.Extension;
dir.ExtensionKey = key;
}
}}
goto st2;
st2:
if ( ++p == pe )
goto _test_eof2;
case 2:
#line 2789 "http.d"
switch( (*p) ) {
case 34u: goto tr3;
case 124u: goto tr2;
case 126u: goto tr2;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto tr2;
} else if ( (*p) >= 33u )
goto tr2;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto tr2;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto tr2;
} else
goto tr2;
} else
goto tr2;
goto st0;
tr2:
#line 3297 "http.d.rl"
{{
start = p;
}}
goto st9;
st9:
if ( ++p == pe )
goto _test_eof9;
case 9:
#line 2824 "http.d"
switch( (*p) ) {
case 33u: goto st9;
case 124u: goto st9;
case 126u: goto st9;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto st9;
} else if ( (*p) >= 35u )
goto st9;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto st9;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto st9;
} else
goto st9;
} else
goto st9;
goto st0;
tr3:
#line 3297 "http.d.rl"
{{
start = p;
}}
goto st3;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
#line 2859 "http.d"
switch( (*p) ) {
case 13u: goto st4;
case 34u: goto st10;
case 92u: goto st6;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto st3;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
if ( (*p) == 10u )
goto st5;
goto st0;
st5:
if ( ++p == pe )
goto _test_eof5;
case 5:
switch( (*p) ) {
case 9u: goto st3;
case 32u: goto st3;
default: break;
}
goto st0;
st10:
if ( ++p == pe )
goto _test_eof10;
case 10:
goto st0;
st6:
if ( ++p == pe )
goto _test_eof6;
case 6:
switch( (*p) ) {
case 13u: goto st7;
case 34u: goto st11;
case 92u: goto st6;
default: break;
}
goto st3;
st7:
if ( ++p == pe )
goto _test_eof7;
case 7:
switch( (*p) ) {
case 10u: goto st5;
case 13u: goto st4;
case 34u: goto st10;
case 92u: goto st6;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 11u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto st3;
st11:
if ( ++p == pe )
goto _test_eof11;
case 11:
switch( (*p) ) {
case 13u: goto st4;
case 34u: goto st10;
case 92u: goto st6;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto st3;
default: break;
}
_test_eof8: cs = 8; goto _test_eof;
_test_eof2: cs = 2; goto _test_eof;
_test_eof9: cs = 9; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof4: cs = 4; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
_test_eof10: cs = 10; goto _test_eof;
_test_eof6: cs = 6; goto _test_eof;
_test_eof7: cs = 7; goto _test_eof;
_test_eof11: cs = 11; goto _test_eof;
_test_eof: {}
if ( p == eof )
{
switch ( cs ) {
case 8:
#line 3300 "http.d.rl"
{{
string key = entry[(start - entry.ptr)
.. (p - entry.ptr)];
if(key == "no-cache")
{
dir.Type = PragmaDirective.NoCache;
}
else
{
dir.Type = PragmaDirective.Extension;
dir.ExtensionKey = key;
}
}}
break;
case 9:
case 10:
case 11:
#line 3313 "http.d.rl"
{{
dir.ExtensionValue = prepareValue(entry[(start - entry.ptr)
.. (p - entry.ptr)]);
}}
break;
#line 2983 "http.d"
default: break;
}
}
_out: {}
}
#line 1719 "http.d.rl"
mixin(finishParser!"parsePragmaEntry");
prag.Directives ~= dir;
}
return prag;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.35,
* "Range" header)
*
* Type:
* request-header
*/
struct RangeHeader
{
public:
///
ByteRangeSpec[] Ranges;
static string Key = "Range";
void format(T)(T writer) if (isOutputRange!(T, string))
{
writer.put("bytes=");
foreach(i, entry; Ranges)
{
if(entry.Type == ByteRangeSpec.SuffixSpec)
{
writer.put("-");
formattedWrite(writer, "%s", entry.Suffix);
}
else
{
formattedWrite(writer, "%s", entry.First);
writer.put("-");
formattedWrite(writer, "%s", entry.Last);
}
if(i != Ranges.length - 1)
writer.put(",");
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.36,
* "Referer" header)
*
* Type:
* request-header
*/
struct RefererHeader
{
public:
///
string Location;
static string Key = "Referer";
void format(T)(T writer) if (isOutputRange!(T, string))
{
//TODO: in debug mode check if Location is a valid URI
writer.put(Location);
}
static RefererHeader parse(string line)
{
RefererHeader refa;
refa.Location = line;
return refa;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.37,
* "Retry-After" header)
*
* Type:
* response-header
*/
struct RetryAfterHeader
{
public:
///
SysTime Date;
///
ulong Delta;
///Use a time value in the Retry-After header instead of delta seconds
bool useTime = false;
static string Key = "Retry-After";
void format(T)(T writer) if (isOutputRange!(T, string))
{
if(useTime)
{
formatDate(writer, Date);
}
else
{
formattedWrite(writer, "%s", Delta);
}
}
static RetryAfterHeader parse(string line)
{
RetryAfterHeader ret;
const(char)* start;
mixin(initParser!());
#line 3098 "http.d"
{
cs = parseRetryAfter_start;
}
#line 3103 "http.d"
{
if ( p == pe )
goto _test_eof;
switch ( cs )
{
case 1:
switch( (*p) ) {
case 13u: goto st2;
case 127u: goto st0;
default: break;
}
if ( (*p) < 10u ) {
if ( (*p) <= 8u )
goto st0;
} else if ( (*p) > 31u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto st5;
} else
goto st0;
goto st4;
st0:
cs = 0;
goto _out;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
switch( (*p) ) {
case 13u: goto st2;
case 127u: goto st0;
default: break;
}
if ( (*p) > 8u ) {
if ( 10u <= (*p) && (*p) <= 31u )
goto st0;
} else
goto st0;
goto st4;
st2:
if ( ++p == pe )
goto _test_eof2;
case 2:
if ( (*p) == 10u )
goto st3;
goto st0;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
switch( (*p) ) {
case 9u: goto st4;
case 32u: goto st4;
default: break;
}
goto st0;
st5:
if ( ++p == pe )
goto _test_eof5;
case 5:
if ( 48u <= (*p) && (*p) <= 57u )
goto st5;
goto st0;
default: break;
}
_test_eof4: cs = 4; goto _test_eof;
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
_test_eof: {}
if ( p == eof )
{
switch ( cs ) {
case 5:
#line 3469 "http.d.rl"
{{
ret.useTime = false;
ret.Delta = std.conv.parse!ulong(line);
}}
break;
case 4:
#line 3474 "http.d.rl"
{{
ret.useTime = true;
ret.Date = parseDate(line);
}}
break;
#line 3191 "http.d"
default: break;
}
}
_out: {}
}
#line 1828 "http.d.rl"
mixin(finishParser!"parseRetryAfter");
return ret;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.39,
* "TE" header)
*
* Type:
* request-header
*/
struct TEHeader
{
public:
///
TCoding[] Codings;
static string Key = "TE";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Codings)
{
if(Codings.length == 1 && entr.Trailers)
{
assert(i == 0, "The 'trailers' coding must be the first coding!");
writer.put("trailers");
}
else
{
assert(isToken(entry.Extension));
writer.put(entry.Extension);
foreach(key, value; entry.Parameters)
{
writeParameter(writer, key, value);
}
if(entry.Q >= 0)
{
assert(entry.Q <= 1);
formattedWrite(writer, ";q=%.3f", entry.Q);
foreach(key, value; entry.AcceptParameters)
{
writeParameter(writer, key, value);
}
}
}
if(i != Codings.length - 1)
writer.put(", ");
}
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.40,
* "Trailer" header)
*
* Type:
* general-header
*/
struct TrailerHeader
{
public:
///
string[] Fields;
static string Key = "Trailer";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(entry; Fields)
{
assert(isToken(entry));
writer.put(entry);
if(i != Fields.length - 1)
writer.put(", ");
}
}
static TrailerHeader parse(string line)
{
TrailerHeader head;
head.Fields = parseCommaList(line);
return head;
}
}
/**
* Data type for the $(LINK2 http://tools.ietf.org/html/rfc2616#section-14.41,
* "Transfer-Encoding" header)
*
* Type:
* general-header
*/
struct TransferEncodingHeader
{
public:
///
TransferCoding[] Codings;
static string Key = "Transfer-Encoding";
void format(T)(T writer) if (isOutputRange!(T, string))
{
foreach(i, entry; Codings)
{
if(entry.Type == TransferCoding.Chunked)
{
writer.put("chunked");
assert(entry.Raw == "");
assert(entry.Parameters.length == 0);
}
else
{
assert(entry.Raw != "");
assert(isToken(entry.Raw));
writer.put(entry.Raw);
foreach(key, value; entry.Parameters)
{
writeParameter(writer, key, value);
}
}
if(i != Codings.length - 1)
writer.put(", ");
}
}
static TransferEncodingHeader parse(string line)
{
TransferEncodingHeader head;
string[] list = parseCommaList(line);
foreach(entry; list)
{
TransferCoding cod;
const(char)* start;
mixin(initParser!("entry"));
#line 3334 "http.d"
{
cs = parseTransferCoding_start;
}
#line 3339 "http.d"
{
if ( p == pe )
goto _test_eof;
switch ( cs )
{
case 1:
switch( (*p) ) {
case 33u: goto tr0;
case 124u: goto tr0;
case 126u: goto tr0;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto tr0;
} else if ( (*p) >= 35u )
goto tr0;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto tr0;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto tr0;
} else
goto tr0;
} else
goto tr0;
goto st0;
st0:
cs = 0;
goto _out;
tr0:
#line 3326 "http.d.rl"
{{
start = p;
}}
goto st4;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
#line 3383 "http.d"
switch( (*p) ) {
case 9u: goto tr4;
case 13u: goto tr5;
case 32u: goto tr4;
case 33u: goto st4;
case 59u: goto tr7;
case 124u: goto st4;
case 126u: goto st4;
default: break;
}
if ( (*p) < 45u ) {
if ( (*p) > 39u ) {
if ( 42u <= (*p) && (*p) <= 43u )
goto st4;
} else if ( (*p) >= 35u )
goto st4;
} else if ( (*p) > 46u ) {
if ( (*p) < 65u ) {
if ( 48u <= (*p) && (*p) <= 57u )
goto st4;
} else if ( (*p) > 90u ) {
if ( 94u <= (*p) && (*p) <= 122u )
goto st4;
} else
goto st4;
} else
goto st4;
goto st0;
tr4:
#line 3329 "http.d.rl"
{{
string key = entry[(start - entry.ptr)
.. (p - entry.ptr)];
if(key == "chunked")
{
cod.Type = TransferCoding.Chunked;
}
else
{
cod.Type = TransferCoding.Custom;
cod.Raw = key;
}
}}
goto st5;
st5:
if ( ++p == pe )
goto _test_eof5;
case 5:
#line 3432 "http.d"
switch( (*p) ) {
case 9u: goto st5;
case 13u: goto st2;
case 32u: goto st5;
case 59u: goto tr9;
default: break;
}
goto st0;
tr5:
#line 3329 "http.d.rl"
{{
string key = entry[(start - entry.ptr)
.. (p - entry.ptr)];
if(key == "chunked")
{
cod.Type = TransferCoding.Chunked;
}
else
{
cod.Type = TransferCoding.Custom;
cod.Raw = key;
}
}}
goto st2;
st2:
if ( ++p == pe )
goto _test_eof2;
case 2:
#line 3461 "http.d"
if ( (*p) == 10u )
goto st3;
goto st0;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
switch( (*p) ) {
case 9u: goto st5;
case 32u: goto st5;
default: break;
}
goto st0;
tr9:
#line 3326 "http.d.rl"
{{
start = p;
}}
goto st6;
tr7:
#line 3329 "http.d.rl"
{{
string key = entry[(start - entry.ptr)
.. (p - entry.ptr)];
if(key == "chunked")
{
cod.Type = TransferCoding.Chunked;
}
else
{
cod.Type = TransferCoding.Custom;
cod.Raw = key;
}
}}
#line 3326 "http.d.rl"
{{
start = p;
}}
goto st6;
st6:
if ( ++p == pe )
goto _test_eof6;
case 6:
#line 3505 "http.d"
goto st6;
default: break;
}
_test_eof4: cs = 4; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof6: cs = 6; goto _test_eof;
_test_eof: {}
if ( p == eof )
{
switch ( cs ) {
case 4:
#line 3329 "http.d.rl"
{{
string key = entry[(start - entry.ptr)
.. (p - entry.ptr)];
if(key == "chunked")
{
cod.Type = TransferCoding.Chunked;
}
else
{
cod.Type = TransferCoding.Custom;
cod.Raw = key;
}
}}