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