mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-20 00:51:42 +00:00
This makes code easier to read and more consistent between C++ and Java. Also update clang-format settings to always add a line break (even if no braces are used).
194 lines
5.7 KiB
C++
194 lines
5.7 KiB
C++
// Copyright (c) FIRST and other WPILib contributors.
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
// the WPILib BSD license file in the root directory of this project.
|
|
|
|
#include "wpi/HttpParser.h"
|
|
|
|
using namespace wpi;
|
|
|
|
uint32_t HttpParser::GetParserVersion() {
|
|
return static_cast<uint32_t>(http_parser_version());
|
|
}
|
|
|
|
HttpParser::HttpParser(Type type) {
|
|
http_parser_init(&m_parser,
|
|
static_cast<http_parser_type>(static_cast<int>(type)));
|
|
m_parser.data = this;
|
|
|
|
http_parser_settings_init(&m_settings);
|
|
|
|
// Unlike the underlying http_parser library, we don't perform callbacks
|
|
// (other than body) with partial data; instead we buffer and call the user
|
|
// callback only when the data is complete.
|
|
|
|
// on_message_begin: initialize our state, call user callback
|
|
m_settings.on_message_begin = [](http_parser* p) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
self.m_urlBuf.clear();
|
|
self.m_state = kStart;
|
|
self.messageBegin();
|
|
return self.m_aborted;
|
|
};
|
|
|
|
// on_url: collect into buffer
|
|
m_settings.on_url = [](http_parser* p, const char* at, size_t length) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
// append to buffer
|
|
if ((self.m_urlBuf.size() + length) > self.m_maxLength) {
|
|
return 1;
|
|
}
|
|
self.m_urlBuf += StringRef{at, length};
|
|
self.m_state = kUrl;
|
|
return 0;
|
|
};
|
|
|
|
// on_status: collect into buffer, call user URL callback
|
|
m_settings.on_status = [](http_parser* p, const char* at,
|
|
size_t length) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
// use valueBuf for the status
|
|
if ((self.m_valueBuf.size() + length) > self.m_maxLength) {
|
|
return 1;
|
|
}
|
|
self.m_valueBuf += StringRef{at, length};
|
|
self.m_state = kStatus;
|
|
return 0;
|
|
};
|
|
|
|
// on_header_field: collect into buffer, call user header/status callback
|
|
m_settings.on_header_field = [](http_parser* p, const char* at,
|
|
size_t length) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
|
|
// once we're in header, we know the URL is complete
|
|
if (self.m_state == kUrl) {
|
|
self.url(self.m_urlBuf);
|
|
if (self.m_aborted) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// once we're in header, we know the status is complete
|
|
if (self.m_state == kStatus) {
|
|
self.status(self.m_valueBuf);
|
|
if (self.m_aborted) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// if we previously were in value state, that means we finished a header
|
|
if (self.m_state == kValue) {
|
|
self.header(self.m_fieldBuf, self.m_valueBuf);
|
|
if (self.m_aborted) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// clear field and value when we enter this state
|
|
if (self.m_state != kField) {
|
|
self.m_state = kField;
|
|
self.m_fieldBuf.clear();
|
|
self.m_valueBuf.clear();
|
|
}
|
|
|
|
// append data to field buffer
|
|
if ((self.m_fieldBuf.size() + length) > self.m_maxLength) {
|
|
return 1;
|
|
}
|
|
self.m_fieldBuf += StringRef{at, length};
|
|
return 0;
|
|
};
|
|
|
|
// on_header_field: collect into buffer
|
|
m_settings.on_header_value = [](http_parser* p, const char* at,
|
|
size_t length) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
|
|
// if we weren't previously in value state, clear the buffer
|
|
if (self.m_state != kValue) {
|
|
self.m_state = kValue;
|
|
self.m_valueBuf.clear();
|
|
}
|
|
|
|
// append data to value buffer
|
|
if ((self.m_valueBuf.size() + length) > self.m_maxLength) {
|
|
return 1;
|
|
}
|
|
self.m_valueBuf += StringRef{at, length};
|
|
return 0;
|
|
};
|
|
|
|
// on_headers_complete: call user status/header/complete callback
|
|
m_settings.on_headers_complete = [](http_parser* p) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
|
|
// if we previously were in url state, that means we finished the url
|
|
if (self.m_state == kUrl) {
|
|
self.url(self.m_urlBuf);
|
|
if (self.m_aborted) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// if we previously were in status state, that means we finished the status
|
|
if (self.m_state == kStatus) {
|
|
self.status(self.m_valueBuf);
|
|
if (self.m_aborted) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// if we previously were in value state, that means we finished a header
|
|
if (self.m_state == kValue) {
|
|
self.header(self.m_fieldBuf, self.m_valueBuf);
|
|
if (self.m_aborted) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
self.headersComplete(self.ShouldKeepAlive());
|
|
return self.m_aborted;
|
|
};
|
|
|
|
// on_body: call user callback
|
|
m_settings.on_body = [](http_parser* p, const char* at,
|
|
size_t length) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
self.body(StringRef{at, length}, self.IsBodyFinal());
|
|
return self.m_aborted;
|
|
};
|
|
|
|
// on_message_complete: call user callback
|
|
m_settings.on_message_complete = [](http_parser* p) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
self.messageComplete(self.ShouldKeepAlive());
|
|
return self.m_aborted;
|
|
};
|
|
|
|
// on_chunk_header: call user callback
|
|
m_settings.on_chunk_header = [](http_parser* p) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
self.chunkHeader(p->content_length);
|
|
return self.m_aborted;
|
|
};
|
|
|
|
// on_chunk_complete: call user callback
|
|
m_settings.on_chunk_complete = [](http_parser* p) -> int {
|
|
auto& self = *static_cast<HttpParser*>(p->data);
|
|
self.chunkComplete();
|
|
return self.m_aborted;
|
|
};
|
|
}
|
|
|
|
void HttpParser::Reset(Type type) {
|
|
http_parser_init(&m_parser,
|
|
static_cast<http_parser_type>(static_cast<int>(type)));
|
|
m_parser.data = this;
|
|
m_maxLength = 1024;
|
|
m_state = kStart;
|
|
m_urlBuf.clear();
|
|
m_fieldBuf.clear();
|
|
m_valueBuf.clear();
|
|
m_aborted = false;
|
|
}
|