Public Access
When the connection breaks during a release download (issue #54), the device waits up to a minute for Wi-Fi, asks for the rest of the file with a Range request and carries on: the slot and the hash so far are kept. It gives up after three tries in a row that bring nothing. Nothing is kept across a restart. Carrying on asks for 64 KB free, not 80: between two connections of an install 78 KB is free, and the first attempt on the device was refused for that. update damage cut now breaks every connection after n bytes. Tried on the device: v0.23.0 installed over four connections, and a download that brought nothing given up with nothing switched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
63 lines
2.8 KiB
C++
63 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <NetworkClientSecure.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "http_head.h"
|
|
#include "platform/counted_client.h"
|
|
|
|
namespace roro {
|
|
|
|
// One HTTPS GET, read as a stream: the connection checks the server's chain and name against the
|
|
// roots in ca_roots.h, the head is parsed, and the body comes out whole whether the server sent it
|
|
// with a length or in chunks. Used by the Update Service to read Gitea's answers and to download a
|
|
// release. Redirects aren't followed: the device only goes where it was told to (Q163).
|
|
class HttpsGet {
|
|
public:
|
|
// A TLS connection to Gitea peaks at about 52 KB of heap (measured: the same with or without
|
|
// checking the certificate); with Q86's 20 KB to spare, it starts with at least this much free.
|
|
static constexpr size_t kNeedFree = 80 * 1024;
|
|
|
|
// Carrying on a download (issue #54) happens in the middle of an install, whose own buffers
|
|
// (about 8 KB, measured: 78 KB free between two connections) are already taken out of what is
|
|
// free, and with the screen taken over nothing else will ask for memory: the peak and 12 KB.
|
|
static constexpr size_t kNeedFreeToCarryOn = 64 * 1024;
|
|
|
|
explicit HttpsGet(net::User user) : tls_(user) {}
|
|
~HttpsGet() { close(); }
|
|
|
|
// Connects and reads the head. "" when a 200 is on its way, or why not, in words for the screen.
|
|
std::string open(const std::string& host, const std::string& path, const char* accept);
|
|
// The same, for the rest of a file from byte `from` (issue #54): asks for that range, with
|
|
// `ifRange` (an ETag, or "") so that a file that changed comes whole. The answer, a 206 or
|
|
// not, is for the caller to judge with head(): "" here only says a head was read.
|
|
std::string openFrom(const std::string& host, const std::string& path, const char* accept, long from, const std::string& ifRange);
|
|
long contentLength() const { return head_.contentLength; } // -1: not known
|
|
const release::HttpHead& head() const { return head_; }
|
|
|
|
// Body bytes into `buf`: how many, 0 at the end, -1 when the connection broke or stalled
|
|
// before the end.
|
|
int read(uint8_t* buf, size_t len);
|
|
void close();
|
|
|
|
private:
|
|
static constexpr size_t kRaw = 1024;
|
|
static constexpr uint32_t kStallMs = 10000;
|
|
|
|
int readRaw(uint8_t* into, size_t len); // from the connection, waiting up to kStallMs
|
|
std::string request(const std::string& host, const std::string& path, const char* accept, const std::string& more, size_t needFree);
|
|
|
|
Counted<NetworkClientSecure> tls_;
|
|
release::HttpHead head_;
|
|
release::ChunkedDecoder chunks_;
|
|
std::unique_ptr<uint8_t[]> raw_;
|
|
std::string early_; // body bytes that arrived with the head
|
|
size_t earlyAt_ = 0;
|
|
long left_ = -1; // body bytes still to come, if the server said how many
|
|
bool done_ = false;
|
|
};
|
|
|
|
} // namespace roro
|