1 module hio.http.http_parser; 2 3 import std.experimental.logger; 4 import std.bitmanip; 5 6 enum http_parser_type 7 { 8 HTTP_REQUEST, 9 HTTP_RESPONSE, 10 HTTP_BOTH 11 } 12 13 struct http_parser_settings 14 { 15 http_cb on_message_begin; 16 http_data_cb on_url; 17 http_data_cb on_status; 18 http_data_cb on_header_field; 19 http_data_cb on_header_value; 20 http_cb on_headers_complete; 21 http_data_cb on_body; 22 http_cb on_message_complete; 23 /* When on_chunk_header is called, the current chunk length is stored 24 * in parser->content_length. 25 */ 26 http_cb on_chunk_header; 27 http_cb on_chunk_complete; 28 } 29 30 struct http_parser 31 { 32 mixin(bitfields!( 33 uint, "type", 2, /* enum http_parser_type */ 34 uint, "flags", 8, /* F_* values from 'flags' enum; semi-public */ 35 uint, "state", 7, /* enum state from http_parser.c */ 36 uint, "header_state", 7, /* enum header_state from http_parser.c */ 37 uint, "index", 5, /* index into current matcher */ 38 uint, "extra_flags", 2, 39 uint, "lenient_http_headers", 1 40 )); 41 42 uint nread; 43 ulong content_length; 44 45 ushort http_major; 46 ushort http_minor; 47 mixin(bitfields!( 48 uint, "status_code", 16, 49 uint, "method", 8, 50 uint, "http_errno", 7, 51 uint, "upgrade", 1 52 )); 53 // uint status_code : 16; /* responses only */ 54 // uint method : 8; /* requests only */ 55 // uint http_errno : 7; 56 57 /* 1 = Upgrade header was present and the parser has exited because of that. 58 * 0 = No upgrade header present. 59 * Should be checked when http_parser_execute() returns in addition to 60 * error checking. 61 */ 62 //uint upgrade : 1; 63 64 /** PUBLIC **/ 65 void *data; /* A pointer to get hook to the "connection" or "socket" object */ 66 } 67 enum http_parser_url_fields { 68 UF_SCHEMA = 0 69 , UF_HOST = 1 70 , UF_PORT = 2 71 , UF_PATH = 3 72 , UF_QUERY = 4 73 , UF_FRAGMENT = 5 74 , UF_USERINFO = 6 75 , UF_MAX = 7 76 } 77 78 package struct _field_data { 79 ushort off; /* Offset into buffer in which field starts */ 80 ushort len; /* Length of run in buffer */ 81 } 82 package struct http_parser_url { 83 ushort field_set; /* Bitmask of (1 << UF_*) values */ 84 ushort port; /* Converted UF_PORT string */ 85 86 _field_data[http_parser_url_fields.UF_MAX] 87 field_data; 88 } 89 90 package extern(C) 91 { 92 alias http_data_cb = int function(http_parser*, const char *at, size_t length); 93 alias http_cb = int function(http_parser*); 94 /// 95 void http_parser_init(http_parser *parser, http_parser_type type) @trusted; 96 size_t http_parser_execute(http_parser *parser, 97 const http_parser_settings *settings, 98 const char *data, 99 size_t len); 100 /* Initialize all http_parser_url members to 0 */ 101 void http_parser_url_init(http_parser_url *u) @trusted; 102 103 /* Parse a URL; return nonzero on failure */ 104 int http_parser_parse_url(const char *buf, size_t buflen, 105 int is_connect, 106 http_parser_url *u) @trusted; 107 } 108 109 unittest 110 { 111 info("Test http_parser basics"); 112 http_parser parser; 113 http_parser_settings settings; 114 http_parser_init(&parser, http_parser_type.HTTP_REQUEST); 115 auto data0 = "GET / HTTP/1.0\nConnect"; 116 auto data1 = "ion: close\n\n"; 117 auto r = http_parser_execute(&parser, &settings, data0.ptr, data0.length); 118 assert(r == data0.length); 119 r = http_parser_execute(&parser, &settings, data1.ptr, data1.length); 120 assert(r == data1.length); 121 assert(parser.http_errno == 0); 122 assert(parser.http_major == 1); 123 assert(parser.http_minor == 0); 124 } 125 126 unittest 127 { 128 import std.stdio; 129 info("Test http_parser callbacks"); 130 static bool 131 message_begin, 132 message_complete, 133 headers_complete; 134 http_cb on_message_begin = (http_parser* parser) 135 { 136 message_begin = true; 137 return 0; 138 }; 139 http_cb on_message_complete = (http_parser* parser) 140 { 141 message_complete = true; 142 return 0; 143 }; 144 http_cb on_headers_complete = (http_parser* parser) 145 { 146 headers_complete = true; 147 writeln("headers complete"); 148 return 0; 149 }; 150 http_data_cb on_header_field = (http_parser* parser, const char* at, size_t length) 151 { 152 writefln("HeaderField: <%s>", at[0..length]); 153 return 0; 154 }; 155 http_data_cb on_header_value = (http_parser* parser, const char* at, size_t length) 156 { 157 writefln("HeaderValue: <%s>", at[0..length]); 158 return 0; 159 }; 160 http_parser parser; 161 http_parser_settings settings; 162 settings.on_message_begin = on_message_begin; 163 settings.on_message_complete = on_message_complete; 164 settings.on_headers_complete = on_headers_complete; 165 settings.on_header_field = on_header_field; 166 settings.on_header_value = on_header_value; 167 http_parser_init(&parser, http_parser_type.HTTP_REQUEST); 168 auto data0 = "GET / HTTP/1.0\nConnecti"; 169 auto data1 = "on: close\nX: Y\n Z\n\n"; 170 auto r = http_parser_execute(&parser, &settings, data0.ptr, data0.length); 171 r = http_parser_execute(&parser, &settings, data1.ptr, data1.length); 172 http_parser_execute(&parser, &settings, null, 0); 173 assert(message_begin); 174 assert(headers_complete); 175 assert(message_complete); 176 }