1 module HttpBenchmark;
2 
3 import hunt.http.codec.http.decode.HttpParser;
4 import hunt.http.codec.http.model;
5 // import hunt.http.codec.http.model.HttpComplianceSection;
6 
7 import hunt.lang.exception;
8 import hunt.lang.Charset;
9 
10 import hunt.container.BufferUtils;
11 import hunt.container.ByteBuffer;
12 import hunt.container.ArrayList;
13 import hunt.container.List;
14 
15 import hunt.logging;
16 
17 import std.conv;
18 import std.range;
19 import std.stdio;
20 
21 alias State = HttpParser.State;
22 
23 
24 class HttpBenchmark {
25 
26     private string _host;
27     private int _port;
28     private string _bad;
29     private string _content;
30     private string _methodOrVersion;
31     private string _uriOrStatus;
32     private string _versionOrReason;
33     private List!HttpField _fields;
34     private List!HttpField _trailers;
35     private string[] _hdr;
36     private string[] _val;
37     private int _headers;
38     private bool _early;
39     private bool _headerCompleted;
40     private bool _messageCompleted;
41     private List!HttpComplianceSection _complianceViolation;
42 
43     this() {
44         _fields = new ArrayList!HttpField();
45         _trailers = new ArrayList!HttpField();
46         _complianceViolation = new ArrayList!HttpComplianceSection();
47         HttpParser.RequestHandler handler = new Handler();
48         parser = new HttpParser(handler);
49     }
50     private HttpParser parser;
51 
52     void benchmark(int number = 10) {
53         import core.time;
54         import std.datetime;
55         import hunt.datetime;
56         MonoTime startTime = MonoTime.currTime;
57         foreach(j ; 0..number) {
58             testParseRequest();
59         }
60         Duration timeElapsed = MonoTime.currTime - startTime;
61         size_t t = timeElapsed.total!(TimeUnit.Microsecond)();
62         tracef("time consuming (%d), total: %d microseconds, avg: %d microseconds", number, t, t/number);
63     }
64 
65     void initialize() {
66         _bad = null;
67         _host = null;
68         _content = null;
69         _methodOrVersion = null;
70         _uriOrStatus = null;
71         _versionOrReason = null;
72         _hdr = null;
73         _val = null;
74         _headers = 0;
75         _headerCompleted = false;
76         _messageCompleted = false;
77         _complianceViolation.clear();
78     }
79 
80     void testParseRequest() {
81         initialize();
82         string str = `GET /plaintext HTTP/1.1
83 cache-control: no-cache
84 Postman-Token: f290cab4-ac2b-46c7-9db8-ca07f5758989
85 User-Agent: PostmanRuntime/7.4.0
86 Accept: */*
87 Host: 127.0.0.1:8080
88 accept-encoding: gzip, deflate
89 Connection: keep-alive
90 
91 `;
92         ByteBuffer buffer = BufferUtils.toBuffer(str);
93         // HttpParser.RequestHandler handler = new Handler();
94         // parser = new HttpParser(handler);        
95         parser.parseNext(buffer);
96         parser.reset();
97     }
98 
99 
100     private class Handler : HttpParser.RequestHandler, HttpParser.ResponseHandler, HttpParser.ComplianceHandler {
101         
102         bool content(ByteBuffer buffer) {
103             if (_content == null)
104                 _content = "";
105             string c = BufferUtils.toString(buffer);
106             _content = _content ~ c;
107             buffer.position(buffer.limit());
108             return false;
109         }
110 
111         
112         bool startRequest(string method, string uri, HttpVersion ver) {
113             version (HUNT_DEBUG) {
114                 tracef("server received the request line, %s, %s, %s", method, uri, ver);
115             }
116             _fields.clear();
117             _trailers.clear();
118             _headers = -1;
119             _hdr = new string[10];
120             _val = new string[10];
121             _methodOrVersion = method;
122             _uriOrStatus = uri;
123             _versionOrReason = ver == HttpVersion.Null ? null : ver.asString();
124             _messageCompleted = false;
125             _headerCompleted = false;
126             _early = false;
127             return false;
128         }
129 
130         
131         void parsedHeader(HttpField field) {
132             _fields.add(field);
133             _hdr[++_headers] = field.getName();
134             _val[_headers] = field.getValue();
135 
136             if (typeid(field) == typeid(HostPortHttpField)) {
137                 HostPortHttpField hpfield = cast(HostPortHttpField) field;
138                 _host = hpfield.getHost();
139                 _port = hpfield.getPort();
140             }
141         }
142 
143         
144         bool headerComplete() {
145             _content = null;
146             _headerCompleted = true;
147             return false;
148         }
149 
150         
151         void parsedTrailer(HttpField field) {
152             _trailers.add(field);
153         }
154 
155         
156         bool contentComplete() {
157             return false;
158         }
159 
160         
161         bool messageComplete() {
162             _messageCompleted = true;
163             return true;
164         }
165 
166         
167         void badMessage(BadMessageException failure) {
168             string reason = failure.getReason();
169             _bad = reason.empty ? failure.getCode().to!string : reason;
170         }
171 
172         void badMessage(int status, string reason) {
173             
174         }
175 
176         
177         bool startResponse(HttpVersion ver, int status, string reason) {
178             _fields.clear();
179             _trailers.clear();
180             _methodOrVersion = ver.asString();
181             _uriOrStatus = status.to!string;
182             _versionOrReason = reason;
183             _headers = -1;
184             _hdr = new string[10];
185             _val = new string[10];
186             _messageCompleted = false;
187             _headerCompleted = false;
188             return false;
189         }
190 
191         
192         void earlyEOF() {
193             _early = true;
194         }
195 
196         
197         int getHeaderCacheSize() {
198             return 512;
199         }
200 
201         
202         void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, string reason) {
203             _complianceViolation.add(violation);
204         }
205     }
206 }