Project
Loading...
Searching...
No Matches
HTTPParser.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include "HTTPParser.h"
14#include <string_view>
15#include "Framework/SHA1.h"
16#include "Base64.h"
17#include <regex>
18#include <cassert>
19
20using namespace o2::framework::internal;
21namespace o2::framework
22{
23
24namespace
25{
27void memmask(char* dst, char const* src, size_t size, uint32_t mask)
28{
29 if (mask) {
30 char* m = (char*)&mask;
31 for (size_t len = 0; len < size; ++len) {
32 *dst++ = *src++ ^ m[len % 4];
33 }
34 } else {
35 memcpy(dst, src, size);
36 }
37}
38
39void memunmask(char* data, size_t size, uint32_t mask)
40{
41 char* m = (char*)&mask;
42 for (size_t len = 0; len < size; ++len) {
43 *data++ ^= m[len % 4];
44 }
45}
46} // namespace
47
48void encode_websocket_frames(std::vector<uv_buf_t>& outputs, char const* src, size_t size, WebSocketOpCode opcode, uint32_t mask)
49{
50 void* finalHeader;
51 size_t headerSize;
52 char* buffer = nullptr;
53 char* startPayload = nullptr;
54 int maskSize = mask ? 4 : 0;
55
56 if (size < 126) {
57 headerSize = sizeof(WebSocketFrameTiny<std::endian::native>);
58 // Allocate a new page if we do not fit in the current one
59 if (outputs.empty() || outputs.back().len > WebSocketConstants::MaxChunkSize || (size + maskSize + headerSize) > (WebSocketConstants::MaxChunkSize - outputs.back().len)) {
60 char* chunk = (char*)malloc(WebSocketConstants::MaxChunkSize);
61 outputs.push_back(uv_buf_init(chunk, 0));
62 }
63 auto& buf = outputs.back();
64 // Reposition the buffer to the end of the current page
65 buffer = buf.base + buf.len;
66 buf.len += headerSize + size + maskSize;
67 auto* header = (WebSocketFrameTiny<std::endian::native>*)buffer;
68 memset(buffer, 0, headerSize);
69 header->len = size;
70 } else if (size < 1 << 16) {
71 headerSize = sizeof(WebSocketFrameShort<std::endian::native>);
72 // Allocate a new page if we do not fit in the current one
73 if (outputs.empty() || outputs.back().len > WebSocketConstants::MaxChunkSize || (size + maskSize + headerSize) > (WebSocketConstants::MaxChunkSize - outputs.back().len)) {
74 char* chunk = (char*)malloc(WebSocketConstants::MaxChunkSize);
75 outputs.push_back(uv_buf_init(chunk, 0));
76 }
77 auto& buf = outputs.back();
78 // Reposition the buffer to the end of the current page
79 buffer = buf.base + buf.len;
80 buf.len += headerSize + size + maskSize;
81 auto* header = (WebSocketFrameShort<std::endian::native>*)buffer;
82 memset(buffer, 0, headerSize);
83 header->len = 126;
84 header->len16 = htons(size);
85 } else {
86 // For larger messages we do standalone allocation
87 // so that the message does not need to be sent in multiple chunks
88 headerSize = sizeof(WebSocketFrameHuge<std::endian::native>);
89 buffer = (char*)malloc(headerSize + maskSize + size);
90 auto* header = (WebSocketFrameHuge<std::endian::native>*)buffer;
91 memset(buffer, 0, headerSize);
92 header->len = 127;
93 header->len64 = (std::endian::native == std::endian::little) ? __builtin_bswap64(size) : size;
94 outputs.push_back(uv_buf_init(buffer, size + maskSize + headerSize));
95 }
96 size_t fullHeaderSize = maskSize + headerSize;
97 startPayload = buffer + fullHeaderSize;
98 auto* header = (WebSocketFrameTiny<std::endian::native>*)buffer;
99 header->fin = 1;
100 header->opcode = (unsigned char)opcode; // binary or text for now
101 // Mask is right before payload.
102 if (mask) {
103 *((uint32_t*)(startPayload - 4)) = mask;
104 }
105 header->mask = mask ? 1 : 0;
106 memmask(startPayload, src, size, mask);
107}
108
109void decode_websocket(char* start, size_t size, WebSocketHandler& handler)
110{
111 // Handle the case in whiche the header is cut
112 if (handler.pendingHeaderSize) {
113 assert(handler.pendingHeader);
114 size_t pendingFullSize = handler.pendingHeaderSize + size;
115 char* pendingFull = new char[handler.pendingHeaderSize + size];
116 memcpy(pendingFull, handler.pendingHeader, handler.pendingHeaderSize);
117 memcpy(pendingFull + handler.pendingHeaderSize, start, size);
118 // We do not need the intermediate buffer anymore.
119 handler.pendingHeaderSize = 0;
120 delete[] handler.pendingHeader;
121 handler.pendingHeader = nullptr;
122 decode_websocket(pendingFull, pendingFullSize, handler);
123 delete[] pendingFull;
124 return;
125 }
126
127 // Handle the case the previous message was cut in half
128 // by the I/O stack.
129 char* cur = start + handler.remainingSize;
130 if (handler.remainingSize) {
131 assert(handler.pendingBuffer);
132 auto newChunkSize = std::min(handler.remainingSize, size);
133 memcpy(handler.pendingBuffer + handler.pendingSize, start, newChunkSize);
134 handler.pendingSize += newChunkSize;
135 handler.remainingSize -= newChunkSize;
136 if (handler.remainingSize == 0) {
137 // One recursion should be enough.
138 decode_websocket(handler.pendingBuffer, handler.pendingSize, handler);
139 delete[] handler.pendingBuffer;
140 handler.pendingBuffer = nullptr;
141 }
142 }
143 handler.beginChunk();
144 // The + 2 is there because we need at least 2 bytes.
145 while (cur - start < size) {
146 auto* header = (WebSocketFrameTiny<std::endian::native>*)cur;
147 size_t payloadSize = 0;
148 size_t headerSize = 0;
149 if ((cur + 2 - start >= size) ||
150 ((cur + 2 + 2 - start >= size) && header->len >= 126) ||
151 ((cur + 2 + 8 - start >= size) && header->len == 127)) {
152 // We do not have enough bytes for a tiny header. We copy in the pending header
153 handler.pendingHeaderSize = size - (cur - start);
154 handler.pendingHeader = new char[handler.pendingHeaderSize];
155 memcpy(handler.pendingHeader, cur, handler.pendingHeaderSize);
156 break;
157 }
158
159 if (header->len < 126) {
160 payloadSize = header->len;
161 headerSize = 2 + (header->mask ? 4 : 0);
162 } else if (header->len == 126) {
163 auto* headerSmall = (WebSocketFrameShort<std::endian::native>*)cur;
164 payloadSize = ntohs(headerSmall->len16);
165 headerSize = 2 + 2 + (header->mask ? 4 : 0);
166 } else if (header->len == 127) {
167 auto* headerSmall = (WebSocketFrameHuge<std::endian::native>*)cur;
168 payloadSize = (std::endian::native == std::endian::little) ? __builtin_bswap64(headerSmall->len64) : headerSmall->len64;
169 headerSize = 2 + 8 + (header->mask ? 4 : 0);
170 }
171 size_t availableSize = size - (cur - start);
172 if (availableSize < payloadSize + headerSize) {
173 handler.remainingSize = payloadSize + headerSize - availableSize;
174 handler.pendingSize = availableSize;
175 handler.pendingBuffer = new char[payloadSize + headerSize];
176 memcpy(handler.pendingBuffer, cur, availableSize);
177 break;
178 }
179 if (header->mask) {
180 int32_t mask = *(int32_t*)(cur + headerSize - 4);
181 memunmask(cur + headerSize, payloadSize, mask);
182 }
183 handler.frame(cur + headerSize, payloadSize);
184 cur += headerSize + payloadSize;
185 }
186 handler.endChunk();
187}
188
189std::string encode_websocket_handshake_request(const char* endpoint, const char* protocol, int version, char const* nonce,
190 std::vector<std::pair<std::string, std::string>> headers)
191{
192 constexpr auto res =
193 "GET {} HTTP/1.1\r\n"
194 "Upgrade: websocket\r\n"
195 "Connection: Upgrade\r\n"
196 "Sec-WebSocket-Key: {}\r\n"
197 "Sec-WebSocket-Protocol: {}\r\n"
198 "Sec-WebSocket-Version: {}\r\n"
199 "{}\r\n";
200 std::string encodedHeaders;
201 for (auto [k, v] : headers) {
202 encodedHeaders += std::string(fmt::format("{}: {}\r\n", k, v));
203 }
204 return fmt::format(res, endpoint, nonce, protocol, version, encodedHeaders);
205}
206
207std::string HTTPParserHelpers::calculateAccept(const char* nonce)
208{
209 std::string reply = std::string(nonce) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
210 char sha[21];
211 SHA1(sha, reply.data(), reply.size());
212 char base[64];
213 base64_encode(base, 64, (unsigned char*)sha, 20);
214 return fmt::format("{}", base);
215}
216
217std::string encode_websocket_handshake_reply(char const* nonce, const char* protocol)
218{
219 constexpr auto res =
220 "HTTP/1.1 101 Switching Protocols\r\n"
221 "Upgrade: websocket\r\n"
222 "Connection: Upgrade\r\n"
223 "Access-Control-Allow-Origin: \"*\"\r\n"
224 "{}"
225 "Sec-WebSocket-Accept: {}\r\n\r\n";
226 return fmt::format(res, protocol && protocol[0] ? fmt::format("Sec-WebSocket-Protocol: {}\r\n", protocol) : "", HTTPParserHelpers::calculateAccept(nonce));
227}
228
229void parse_http_request(char* start, size_t size, HTTPParser* parser)
230{
232 // Too short, let's try again...
233 if (size < 2) {
234 parser->remaining += std::string_view(start, size);
235 }
236 char* cur = start;
237 char* next = cur;
238 std::string_view lastToken(cur, 0);
239 std::string_view lastKey;
240 std::string_view lastValue;
241 std::string lastError;
242 if (parser->states.empty()) {
243 parser->states.push_back(HTTPState::IN_START);
244 }
245 char const* delimiters = nullptr;
246 char const* skippable = nullptr;
247 char const* separator = nullptr;
248 char const* spaces = "\t \v";
249 char const* colon = ":";
250 char const* newline = "\r\n";
251 bool done = false;
252
253 while (!done) {
254 HTTPState state = parser->states.back();
255 parser->states.pop_back();
256 switch (state) {
258 parser->states.push_back(HTTPState::BEGIN_METHOD);
259 break;
261 parser->states.push_back(HTTPState::BEGIN_REPLY_VERSION);
262 break;
264 parser->states.push_back(HTTPState::END_REPLY_VERSION);
265 parser->states.push_back(HTTPState::IN_CAPTURE_DELIMITERS);
266 delimiters = spaces;
267 break;
269 parser->replyVersion(lastToken);
270 parser->states.push_back(HTTPState::BEGIN_REPLY_CODE);
271 parser->states.push_back(HTTPState::IN_SKIP_CHARS);
272 skippable = spaces;
273 break;
275 parser->states.push_back(HTTPState::END_REPLY_CODE);
276 parser->states.push_back(HTTPState::IN_CAPTURE_DELIMITERS);
277 delimiters = spaces;
278 break;
280 parser->replyCode(lastToken);
281 parser->states.push_back(HTTPState::BEGIN_REPLY_MESSAGE);
282 parser->states.push_back(HTTPState::IN_SKIP_CHARS);
283 skippable = spaces;
284 break;
286 parser->states.push_back(HTTPState::END_REPLY_MESSAGE);
287 parser->states.push_back(HTTPState::IN_CAPTURE_SEPARATOR);
288 separator = newline;
289 break;
291 parser->replyMessage(lastToken);
292 parser->states.push_back(HTTPState::BEGIN_HEADERS);
293 break;
295 parser->states.push_back(HTTPState::END_METHOD);
296 parser->states.push_back(HTTPState::IN_CAPTURE_DELIMITERS);
297 delimiters = spaces;
298 break;
300 parser->method(lastToken);
301 parser->states.push_back(HTTPState::BEGIN_TARGET);
302 parser->states.push_back(HTTPState::IN_SKIP_CHARS);
303 skippable = spaces;
304 break;
306 parser->states.push_back(HTTPState::END_TARGET);
307 parser->states.push_back(HTTPState::IN_CAPTURE_DELIMITERS);
308 delimiters = spaces;
309 break;
311 parser->target(lastToken);
312 parser->states.push_back(HTTPState::BEGIN_VERSION);
313 parser->states.push_back(HTTPState::IN_SKIP_CHARS);
314 skippable = spaces;
315 break;
317 parser->states.push_back(HTTPState::END_VERSION);
318 parser->states.push_back(HTTPState::IN_CAPTURE_SEPARATOR);
319 separator = newline;
320 break;
322 parser->version(lastToken);
323 parser->states.push_back(HTTPState::BEGIN_HEADERS);
324 break;
326 parser->states.push_back(HTTPState::BEGIN_HEADER);
327 break;
329 parser->states.push_back(HTTPState::BEGIN_HEADER_KEY);
330 break;
332 parser->states.push_back(HTTPState::END_HEADER_KEY);
333 parser->states.push_back(HTTPState::IN_CAPTURE_SEPARATOR);
334 separator = colon;
335 break;
337 lastKey = lastToken;
338 parser->states.push_back(HTTPState::BEGIN_HEADER_VALUE);
339 parser->states.push_back(HTTPState::IN_SKIP_CHARS);
340 skippable = spaces;
341 break;
343 parser->states.push_back(HTTPState::END_HEADER_VALUE);
344 parser->states.push_back(HTTPState::IN_CAPTURE_SEPARATOR);
345 separator = newline;
346 break;
348 lastValue = lastToken;
349 parser->states.push_back(HTTPState::END_HEADER);
350 break;
352 if (strncmp("\r\n", next, 2) == 0) {
353 parser->header(lastKey, lastValue);
354 parser->states.push_back(HTTPState::END_HEADERS);
355 next += 2;
356 cur = next;
357 } else {
358 parser->header(lastKey, lastValue);
359 parser->states.push_back(HTTPState::BEGIN_HEADER);
360 cur = next;
361 }
362 break;
364 parser->endHeaders();
365 parser->states.push_back(HTTPState::BEGIN_BODY);
366 break;
368 size_t bodySize = size - (cur - start);
369 parser->body(cur, bodySize);
370 next = cur + bodySize;
371 cur = next;
372 parser->states.push_back(HTTPState::BEGIN_BODY);
373 parser->states.push_back(HTTPState::IN_DONE);
374 } break;
376 while (true) {
377 if (next - start == size) {
378 parser->remaining += std::string_view(cur, next - cur);
379 }
380 if (strchr(skippable, *next)) {
381 next++;
382 continue;
383 }
384 cur = next;
385 break;
386 }
387 break;
389 if (memcmp(separator, cur, strlen(separator)) != 0) {
390 parser->states.push_back(HTTPState::IN_ERROR);
391 break;
392 }
393 next += strlen(separator);
394 cur = next;
395 break;
397 while (true) {
398 if (next - start == size) {
399 parser->remaining += std::string_view(cur, next - cur);
400 }
401 if (strchr(delimiters, *next) == nullptr) {
402 next++;
403 continue;
404 }
405 lastToken = std::string_view(cur, next - cur);
406 cur = next;
407 break;
408 }
409 break;
411 while (true) {
412 if (next + strlen(separator) - start == size) {
413 parser->remaining += std::string_view(cur, next - cur);
414 }
415 if (memcmp(separator, next, strlen(separator)) != 0) {
416 next++;
417 continue;
418 }
419 lastToken = std::string_view(cur, next - cur);
420 next += strlen(separator);
421 cur = next;
422 break;
423 }
424 break;
426 // The only case in which there can be a pending state when IN_DONE, is if
427 // we plan to resume processing.
428 if (parser->states.size() == 1 && parser->states.back() == HTTPState::BEGIN_BODY) {
429 done = true;
430 } else if (parser->states.empty()) {
431 done = true;
432 } else {
433 parser->states.push_back(HTTPState::IN_ERROR);
434 }
435 break;
437 parser->error = lastError;
438 parser->states.clear();
439 done = true;
440 break;
441 default:
442 parser->states.push_back(HTTPState::IN_ERROR);
443 break;
444 }
445 }
446}
447
448std::pair<std::string, unsigned short> parse_websocket_url(char const* url)
449{
450 std::string s = url;
451 if (s == "ws://") {
452 s = "ws://127.0.0.1:8080";
453 }
454 const std::regex urlMatcher("^ws://([0-9-_.]+)[:]([0-9]+)$");
455 std::smatch parts;
456 if (!std::regex_match(s, parts, urlMatcher)) {
457 throw runtime_error_f(
458 "Unable to parse driver client url: %s.\n"
459 "Format should be ws://[<driver ip>:<port>] e.g. ws://127.0.0.1:8080 or just ws://");
460 }
461 std::string ip = std::string{parts[1]};
462 auto portS = std::string(parts[2]);
463 unsigned short port = std::stoul(portS);
464 return {ip, port};
465}
466} // namespace o2::framework
std::string url
unsigned int uint32_t
std::vector< std::string > header
bool done
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder int32_t
SurfaceTrackState state
uint8_t endpoint
Definition RawData.h:0
uint32_t res
Definition RawData.h:0
uint32_t version
Definition RawData.h:8
const GLfloat * m
Definition glcorearb.h:4066
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLenum GLenum dst
Definition glcorearb.h:1767
GLuint start
Definition glcorearb.h:469
GLenum GLenum GLsizei len
Definition glcorearb.h:4232
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glcorearb.h:2514
GLint GLuint mask
Definition glcorearb.h:291
int base64_encode(char *dest, int size, unsigned char *src, int slen)
Definition Base64.cxx:52
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
@ IN_SEPARATOR
capture until a specific "separator"
@ IN_CAPTURE_SEPARATOR
capture until any or the "delimiters" characters
@ IN_CAPTURE_DELIMITERS
skip any "delimiters" char.
void encode_websocket_frames(std::vector< uv_buf_t > &outputs, char const *src, size_t size, WebSocketOpCode opcode, uint32_t mask)
std::pair< std::string, unsigned short > parse_websocket_url(char const *url)
void parse_http_request(char *start, size_t size, HTTPParser *parser)
std::string encode_websocket_handshake_request(const char *endpoint, const char *protocol, int version, char const *nonce, std::vector< std::pair< std::string, std::string > > headers)
void decode_websocket(char *start, size_t size, WebSocketHandler &handler)
RuntimeErrorRef runtime_error_f(const char *,...)
std::string encode_websocket_handshake_reply(char const *nonce, const char *protocol)
static std::string calculateAccept(const char *nonce)
Helper to calculate the reply to a nonce.
virtual void replyVersion(std::string_view const &s)
Definition HTTPParser.h:229
virtual void header(std::string_view const &k, std::string_view const &v)
Definition HTTPParser.h:223
virtual void method(std::string_view const &s)
Definition HTTPParser.h:220
virtual void replyCode(std::string_view const &s)
Definition HTTPParser.h:230
virtual void endHeaders()
Definition HTTPParser.h:224
virtual void body(char *data, size_t s)
Definition HTTPParser.h:228
virtual void target(std::string_view const &s)
Definition HTTPParser.h:221
std::vector< HTTPState > states
Definition HTTPParser.h:219
virtual void replyMessage(std::string_view const &s)
Definition HTTPParser.h:231
virtual void version(std::string_view const &s)
Definition HTTPParser.h:222
static constexpr size_t MaxChunkSize
Definition HTTPParser.h:126
An handler for a websocket message stream.
Definition HTTPParser.h:149
size_t pendingHeaderSize
Bytes from an incomplete header.
Definition HTTPParser.h:175
virtual void endChunk()
Invoked whenever we have no more input to process.
Definition HTTPParser.h:162
virtual void frame(char const *frame, size_t s)
Definition HTTPParser.h:158
char * pendingBuffer
A buffer large enough to contain the next frame to be processed.
Definition HTTPParser.h:173
size_t remainingSize
Bytes which are still to be received for the previous, half delivered frame.
Definition HTTPParser.h:169
size_t pendingSize
Bytes which are already there from the previous, half delivered frame.
Definition HTTPParser.h:171
virtual void beginChunk()
Invoked before processing the next round of input.
Definition HTTPParser.h:160
void * malloc(size_t n)