Files
ppsspp/Common/Net/HTTPNaettRequest.h
T
Henrik Rydgård b120f0004f http: Make Cancel() actually stop an HTTPS transfer
Cancel() worked on the plain HTTP path - cancelled_ is threaded down as
progress->cancelled and checked while connecting and reading - but on the naett
path it only set a flag that nothing looked at. The transfer ran to completion
and cancelling just relabelled the result afterwards. Cancelling a store icon
that scrolled away, or a homebrew download the user gave up on, kept using the
bandwidth either way.

naett has one hook for this: a body writer that takes less than it was given
fails the request. So HTTPSRequest installs its own writer, which refuses
everything once cancelled. That works on all four backends and needs nothing
from naettClose, which is only really safe on Android.

The catch is lifetime. The writer runs on naett's transfer thread, and a request
that's still going when we're torn down would then be writing into a destroyed
HTTPSRequest - which is why the buffer it writes into is a separate refcounted
sink rather than a member. Join() on an unfinished request parks the sink where
it won't be freed and lets the request go, so a chunk that lands afterwards
writes somewhere that still exists.

That path is shutdown-only: RequestManager only cancels from its destructor, and
Update() waits for Done() before joining. Join now also notices a request that
finished while nobody was polling, and closes it properly instead of abandoning
it. What's left leaking at that point is a request still in flight as the
process exits, which is what already happened, just deliberate now and logged as
such rather than as an error.
2026-09-05 13:15:12 -06:00

52 lines
1.4 KiB
C++

#pragma once
#include <thread>
#include <string_view>
#include "Common/Net/HTTPRequest.h"
#ifndef HTTPS_NOT_AVAILABLE
#include "ext/naett-lib/naett.h"
namespace http {
// Really an asynchronous request.
class HTTPSRequest : public Request {
public:
HTTPSRequest(RequestMethod method, std::string_view url, std::string_view postData, std::string_view postMime, const Path &outfile, RequestFlags flags = RequestFlags::ProgressBar | RequestFlags::ProgressBarDelayed, std::string_view name = "");
~HTTPSRequest();
void Start() override;
void Join() override;
// Also acts as a Poll.
bool Done() override;
bool Failed() const override { return failed_; }
// Cancelling has to reach naett, or it only changes the code we report once the transfer ends
// on its own. See the .cpp.
void Cancel() override;
private:
static int WriteBodyThunk(const void *source, int bytes, void *userData);
std::string postData_;
std::string postMime_;
bool completed_ = false;
bool failed_ = false;
// Where the response body lands. Deliberately not a member of this object: naett writes into
// it from its own transfer thread, and that can outlive us if we're torn down before the
// request finishes. See NaettBodySink in the .cpp.
std::shared_ptr<struct NaettBodySink> sink_;
// Naett state
naettReq *req_ = nullptr;
naettRes *res_ = nullptr;
};
} // namespace http
#endif // HTTPS_NOT_AVAILABLE