1 module hunt.imf.ParserBase;
2 
3 import hunt.imf.EvBuffer;
4 import hunt.net.Connection;
5 import hunt.imf.MessageBuffer;
6 import hunt.util.Serialize;
7 import std.bitmanip;
8 import std.stdint;
9 import std.string;
10 import std.stdio;
11 import std.conv;
12 import std.typecons;
13 import std.uri;
14 
15 struct HttpContent {
16     size_t status = 0;
17     string path;
18     string method;
19     string[string] headField;
20     string[string] parameters;
21     string body;
22 
23     void reset()
24     {
25         status= 0;
26         path = "";
27     }
28 }
29 
30 enum Field {
31     CONTENTLENGTH = "Content-Length"
32 }
33 
34 class ParserBase {
35 
36     protected enum string CONTEXT = "REVBUFFER";
37 
38     private const ulong DATAHEADLEN = 20;
39 
40     protected const string HTTPHEADEOF = "\r\n\r\n";
41     protected const string LINEFEEDS = "\r\n";
42 
43     enum MAX_HTTP_REQUEST_BUFF = 4096;
44 
45     public void parserTcpStream (EvBuffer!ubyte src , ubyte [] incr , Connection connection)
46     {
47         src.mergeBuffer(incr);
48         ulong uBufLen = 0;
49 
50         while ( (uBufLen = src.getBufferLength()) >= DATAHEADLEN )
51         {
52             auto head = new ubyte [DATAHEADLEN];
53             if (!src.copyOutFromHead(head ,DATAHEADLEN)) { break;}
54 
55             ulong bodyLength = bigEndianToNative!int32_t(head[16 .. 20]);
56 
57             if (bodyLength > 2147483647 || bodyLength < 0)
58             {
59                 src.reset();
60                 break;
61             }
62 
63             if (uBufLen >=  bodyLength + DATAHEADLEN)
64             {
65                 MessageBuffer msg = new MessageBuffer();
66                 msg.messageId = bigEndianToNative!long(head[8 .. 16]);
67                 if (!src.drainBufferFromHead(DATAHEADLEN)) { break;}
68                 msg.message = new ubyte [bodyLength];
69                 if (bodyLength)
70                 {
71                     if (!src.removeBufferFromHead(msg.message,bodyLength))  {break;}
72                 }
73                 if (connection !is null)
74                 {
75                     ConnectionEventHandler handler = connection.getHandler();
76                     if(handler !is null) {
77                         handler.messageReceived(connection, msg);
78                     }
79                 }
80             } else
81             {
82                 break;
83             }
84         }
85     }
86 
87     public void parserHttpStream (EvBuffer!ubyte src , ubyte [] incr , Connection connection)
88     {
89         src.mergeBuffer(incr);
90         if (src.getBufferLength() > MAX_HTTP_REQUEST_BUFF)
91         {
92             src.reset();
93             return;
94         }
95 
96         ulong head_pos = 0 ;
97         string buffer = cast(string)src.getBuffer();
98         while ((head_pos = indexOf(buffer,HTTPHEADEOF)) != -1)
99         {
100             HttpContent content;
101             string head = cast(string)buffer[0 .. head_pos];
102             parserHttpHead(content,head);
103             auto content_length = content.headField.get(Field.CONTENTLENGTH,null);
104             if (content_length !is null && (head_pos + 4 + to!int(content_length)) > buffer.length)
105             {
106                 break;
107             }
108             else
109             {
110                 content.body = buffer[head_pos + 4 .. $];
111                 MessageBuffer msg = new MessageBuffer();
112                 msg.messageId = cast(int)hashOf!string(content.path);
113                 msg.message = cast(ubyte[])serialize!HttpContent(content);
114                 if (connection !is null)
115                 {
116                     ConnectionEventHandler handler = connection.getHandler();
117                     if(handler !is null) {
118                         handler.messageReceived(connection, msg);
119                     }
120                 }
121                 src.reset();
122                 break;
123             }
124         }
125     }
126 
127     private void parserHttpHead(ref HttpContent httpcontent , string headBuff)
128     {
129         auto fields = split(headBuff,"\r\n");
130         foreach(field;fields)
131         {
132             if (field.count("HTTP/"))
133             {
134                 auto child = split(field," ");
135                 if (child[0].count("HTTP/"))
136                 {
137                     httpcontent.status = to!int(child[1]);
138 
139                 } else
140                 {
141                     httpcontent.method= child[0];
142                     string url = decodeComponent(child[1]);
143                     long flag = indexOf(url ,"?");
144                     httpcontent.path = url[0 .. flag == -1 ? $:flag];
145                     if (flag != -1)
146                     {
147                         string[] items = url[flag + 1 .. $].split("&");
148                         foreach( item ; items)
149                         {
150                             if(item != string.init)
151                             {
152                                 auto v = item.split("=");
153                                 httpcontent.parameters[v[0]] = v[1];
154                             }
155                         }
156                     }
157                 }
158             } else
159             {
160                 long pos = 0;
161                 if ( (pos = indexOf(field ,":")) != -1)
162                 {
163                     httpcontent.headField[strip(field[0 .. pos])] = strip(field[pos+1 ..$]);
164                 }
165             }
166         }
167     }
168 }