Public Access
A streaming JSON scanner (a 33 KB list of releases costs a few hundred bytes), the release reader built on it, HTTP response heads and chunked bodies, URLs, and the decisions: which release is an update, whether to announce it, and which download URLs the device takes. Tested against the real answers of git.twis.la. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
63 lines
1.8 KiB
C++
63 lines
1.8 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
namespace roro::release {
|
|
|
|
// The status line and headers of an HTTP/1.1 response, read as bytes arrive.
|
|
struct HttpHead {
|
|
int status = 0;
|
|
long contentLength = -1; // -1: not given
|
|
bool chunked = false;
|
|
std::string location, contentType;
|
|
};
|
|
|
|
class HttpHeadParser {
|
|
public:
|
|
static constexpr size_t kMaxBytes = 4096;
|
|
|
|
// Takes bytes up to and including the blank line that ends the head; returns how many it used.
|
|
// What follows is the body.
|
|
size_t feed(const char* data, size_t len);
|
|
bool complete() const { return complete_; }
|
|
bool failed() const { return failed_; }
|
|
const HttpHead& head() const { return head_; }
|
|
|
|
private:
|
|
void line();
|
|
|
|
HttpHead head_;
|
|
std::string line_;
|
|
size_t total_ = 0;
|
|
bool first_ = true, complete_ = false, failed_ = false;
|
|
};
|
|
|
|
// Takes the chunks of "Transfer-Encoding: chunked" apart as they arrive.
|
|
class ChunkedDecoder {
|
|
public:
|
|
// `out` has room for `len` bytes (the body is never longer than what carried it).
|
|
size_t decode(const uint8_t* in, size_t len, uint8_t* out);
|
|
bool done() const { return state_ == State::Done; }
|
|
bool failed() const { return failed_; }
|
|
|
|
private:
|
|
enum class State : uint8_t { Size, Extension, SizeLf, Data, DataCr, DataLf, Trailer, Done };
|
|
State state_ = State::Size;
|
|
size_t remaining_ = 0;
|
|
bool anyDigit_ = false, failed_ = false;
|
|
size_t trailerLine_ = 0;
|
|
};
|
|
|
|
// "https://git.twis.la/twisla/x/releases/download/v1/a.ota" taken apart. Only http and https.
|
|
struct Url {
|
|
bool ok = false;
|
|
bool https = false;
|
|
std::string host, path; // path from the first "/", with its query; "/" if none
|
|
int port = 0;
|
|
};
|
|
Url parseUrl(const std::string& url);
|
|
|
|
} // namespace roro::release
|