Merge pull request #14755 from unknownbrackets/http-accept

Specify Accept headers for HTTP requests
This commit is contained in:
Henrik Rydgård 2021-08-23 00:21:17 +02:00 committed by GitHub
commit fef7b8918d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 70 additions and 40 deletions

View file

@ -38,10 +38,11 @@ bool LoadRemoteFileList(const Path &url, bool *cancel, std::vector<File::FileInf
}
// Start by requesting the list of files from the server.
http::RequestParams req(baseURL.Resource(), "text/plain, text/html; q=0.9, */*; q=0.8");
if (http.Resolve(baseURL.Host().c_str(), baseURL.Port())) {
if (http.Connect(2, 20.0, cancel)) {
http::RequestProgress progress(cancel);
code = http.GET(baseURL.Resource().c_str(), &result, responseHeaders, &progress);
code = http.GET(req, &result, responseHeaders, &progress);
http.Disconnect();
}
}

View file

@ -243,11 +243,10 @@ void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength, float *prog
}
}
int Client::GET(const char *resource, Buffer *output, std::vector<std::string> &responseHeaders, RequestProgress *progress) {
int Client::GET(const RequestParams &req, Buffer *output, std::vector<std::string> &responseHeaders, RequestProgress *progress) {
const char *otherHeaders =
"Accept: */*\r\n"
"Accept-Encoding: gzip\r\n";
int err = SendRequest("GET", resource, otherHeaders, progress);
int err = SendRequest("GET", req, otherHeaders, progress);
if (err < 0) {
return err;
}
@ -265,20 +264,20 @@ int Client::GET(const char *resource, Buffer *output, std::vector<std::string> &
return code;
}
int Client::GET(const char *resource, Buffer *output, RequestProgress *progress) {
int Client::GET(const RequestParams &req, Buffer *output, RequestProgress *progress) {
std::vector<std::string> responseHeaders;
int code = GET(resource, output, responseHeaders, progress);
int code = GET(req, output, responseHeaders, progress);
return code;
}
int Client::POST(const char *resource, const std::string &data, const std::string &mime, Buffer *output, RequestProgress *progress) {
int Client::POST(const RequestParams &req, const std::string &data, const std::string &mime, Buffer *output, RequestProgress *progress) {
char otherHeaders[2048];
if (mime.empty()) {
snprintf(otherHeaders, sizeof(otherHeaders), "Content-Length: %lld\r\n", (long long)data.size());
} else {
snprintf(otherHeaders, sizeof(otherHeaders), "Content-Length: %lld\r\nContent-Type: %s\r\n", (long long)data.size(), mime.c_str());
}
int err = SendRequestWithData("POST", resource, data, otherHeaders, progress);
int err = SendRequestWithData("POST", req, data, otherHeaders, progress);
if (err < 0) {
return err;
}
@ -297,15 +296,15 @@ int Client::POST(const char *resource, const std::string &data, const std::strin
return code;
}
int Client::POST(const char *resource, const std::string &data, Buffer *output, RequestProgress *progress) {
return POST(resource, data, "", output, progress);
int Client::POST(const RequestParams &req, const std::string &data, Buffer *output, RequestProgress *progress) {
return POST(req, data, "", output, progress);
}
int Client::SendRequest(const char *method, const char *resource, const char *otherHeaders, RequestProgress *progress) {
return SendRequestWithData(method, resource, "", otherHeaders, progress);
int Client::SendRequest(const char *method, const RequestParams &req, const char *otherHeaders, RequestProgress *progress) {
return SendRequestWithData(method, req, "", otherHeaders, progress);
}
int Client::SendRequestWithData(const char *method, const char *resource, const std::string &data, const char *otherHeaders, RequestProgress *progress) {
int Client::SendRequestWithData(const char *method, const RequestParams &req, const std::string &data, const char *otherHeaders, RequestProgress *progress) {
progress->progress = 0.01f;
net::Buffer buffer;
@ -313,14 +312,16 @@ int Client::SendRequestWithData(const char *method, const char *resource, const
"%s %s HTTP/%s\r\n"
"Host: %s\r\n"
"User-Agent: %s\r\n"
"Accept: %s\r\n"
"Connection: close\r\n"
"%s"
"\r\n";
buffer.Printf(tpl,
method, resource, httpVersion_,
method, req.resource.c_str(), httpVersion_,
host_.c_str(),
userAgent_.c_str(),
req.acceptMime,
otherHeaders ? otherHeaders : "");
buffer.Append(data);
bool flushed = buffer.FlushSocket(sock(), dataTimeout_, progress->cancelled);
@ -508,7 +509,8 @@ int Download::PerformGET(const std::string &url) {
return -1;
}
return client.GET(fileUrl.Resource().c_str(), &buffer_, responseHeaders_, &progress_);
RequestParams req(fileUrl.Resource(), acceptMime_);
return client.GET(req, &buffer_, responseHeaders_, &progress_);
}
std::string Download::RedirectLocation(const std::string &baseUrl) {
@ -569,8 +571,10 @@ void Download::Do() {
completed_ = true;
}
std::shared_ptr<Download> Downloader::StartDownload(const std::string &url, const Path &outfile) {
std::shared_ptr<Download> Downloader::StartDownload(const std::string &url, const Path &outfile, const char *acceptMime) {
std::shared_ptr<Download> dl(new Download(url, outfile));
if (acceptMime)
dl->SetAccept(acceptMime);
downloads_.push_back(dl);
dl->Start();
return dl;
@ -579,8 +583,11 @@ std::shared_ptr<Download> Downloader::StartDownload(const std::string &url, cons
std::shared_ptr<Download> Downloader::StartDownloadWithCallback(
const std::string &url,
const Path &outfile,
std::function<void(Download &)> callback) {
std::function<void(Download &)> callback,
const char *acceptMime) {
std::shared_ptr<Download> dl(new Download(url, outfile));
if (acceptMime)
dl->SetAccept(acceptMime);
dl->SetCallback(callback);
downloads_.push_back(dl);
dl->Start();

View file

@ -53,23 +53,32 @@ struct RequestProgress {
bool *cancelled = nullptr;
};
struct RequestParams {
RequestParams() {}
explicit RequestParams(const char *r) : resource(r) {}
RequestParams(const std::string &r, const char *a) : resource(r), acceptMime(a) {}
std::string resource;
const char *acceptMime = "*/*";
};
class Client : public net::Connection {
public:
Client();
~Client();
// Return value is the HTTP return code. 200 means OK. < 0 means some local error.
int GET(const char *resource, Buffer *output, RequestProgress *progress);
int GET(const char *resource, Buffer *output, std::vector<std::string> &responseHeaders, RequestProgress *progress);
int GET(const RequestParams &req, Buffer *output, RequestProgress *progress);
int GET(const RequestParams &req, Buffer *output, std::vector<std::string> &responseHeaders, RequestProgress *progress);
// Return value is the HTTP return code.
int POST(const char *resource, const std::string &data, const std::string &mime, Buffer *output, RequestProgress *progress);
int POST(const char *resource, const std::string &data, Buffer *output, RequestProgress *progress);
int POST(const RequestParams &req, const std::string &data, const std::string &mime, Buffer *output, RequestProgress *progress);
int POST(const RequestParams &req, const std::string &data, Buffer *output, RequestProgress *progress);
// HEAD, PUT, DELETE aren't implemented yet, but can be done with SendRequest.
int SendRequest(const char *method, const char *resource, const char *otherHeaders, RequestProgress *progress);
int SendRequestWithData(const char *method, const char *resource, const std::string &data, const char *otherHeaders, RequestProgress *progress);
int SendRequest(const char *method, const RequestParams &req, const char *otherHeaders, RequestProgress *progress);
int SendRequestWithData(const char *method, const RequestParams &req, const std::string &data, const char *otherHeaders, RequestProgress *progress);
int ReadResponseHeaders(net::Buffer *readbuf, std::vector<std::string> &responseHeaders, RequestProgress *progress);
// If your response contains a response, you must read it.
int ReadResponseEntity(net::Buffer *readbuf, const std::vector<std::string> &responseHeaders, Buffer *output, RequestProgress *progress);
@ -111,6 +120,10 @@ public:
std::string url() const { return url_; }
const Path &outfile() const { return outfile_; }
void SetAccept(const char *mime) {
acceptMime_ = mime;
}
// If not downloading to a file, access this to get the result.
Buffer &buffer() { return buffer_; }
const Buffer &buffer() const { return buffer_; }
@ -151,6 +164,7 @@ private:
std::string url_;
Path outfile_;
std::thread thread_;
const char *acceptMime_ = "*/*";
int resultCode_ = 0;
bool completed_ = false;
bool failed_ = false;
@ -168,12 +182,13 @@ public:
CancelAll();
}
std::shared_ptr<Download> StartDownload(const std::string &url, const Path &outfile);
std::shared_ptr<Download> StartDownload(const std::string &url, const Path &outfile, const char *acceptMime = nullptr);
std::shared_ptr<Download> StartDownloadWithCallback(
const std::string &url,
const Path &outfile,
std::function<void(Download &)> callback);
std::function<void(Download &)> callback,
const char *acceptMime = nullptr);
// Drops finished downloads from the list.
void Update();

View file

@ -1393,8 +1393,9 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
// splash screen quickly), but then we'll just show the notification next time instead, we store the
// upgrade number in the ini.
if (iRunCount % 10 == 0 && bCheckForNewVersion) {
std::shared_ptr<http::Download> dl = g_DownloadManager.StartDownloadWithCallback(
"http://www.ppsspp.org/version.json", Path(), &DownloadCompletedCallback);
const char *versionUrl = "http://www.ppsspp.org/version.json";
const char *acceptMime = "application/json, text/*; q=0.9, */*; q=0.8";
auto dl = g_DownloadManager.StartDownloadWithCallback(versionUrl, Path(), &DownloadCompletedCallback, acceptMime);
dl->SetHidden(true);
}

View file

@ -137,7 +137,8 @@ int HTTPFileLoader::SendHEAD(const Url &url, std::vector<std::string> &responseH
return -400;
}
int err = client_.SendRequest("HEAD", url.Resource().c_str(), nullptr, &progress_);
http::RequestParams req(url.Resource(), "*/*");
int err = client_.SendRequest("HEAD", req, nullptr, &progress_);
if (err < 0) {
ERROR_LOG(LOADER, "HTTP request failed, failed to send request: %s port %d", url.Host().c_str(), url.Port());
latestError_ = "Could not connect (could not request data)";
@ -196,7 +197,8 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f
snprintf(requestHeaders, sizeof(requestHeaders),
"Range: bytes=%lld-%lld\r\n", absolutePos, absoluteEnd - 1);
int err = client_.SendRequest("GET", url_.Resource().c_str(), requestHeaders, &progress_);
http::RequestParams req(url_.Resource(), "*/*");
int err = client_.SendRequest("GET", req, requestHeaders, &progress_);
if (err < 0) {
latestError_ = "Invalid response reading data";
Disconnect();

View file

@ -282,7 +282,7 @@ namespace Reporting
if (http.Resolve(serverHost, ServerPort())) {
http.Connect();
int result = http.POST(uri, data, mimeType, output, &progress);
int result = http.POST(http::RequestParams(uri), data, mimeType, output, &progress);
http.Disconnect();
return result >= 200 && result < 300;

View file

@ -100,7 +100,8 @@ bool GameManager::DownloadAndInstall(std::string storeFileUrl) {
}
Path filename = GetTempFilename();
curDownload_ = g_DownloadManager.StartDownload(storeFileUrl, filename);
const char *acceptMime = "application/zip, application/x-cso, application/x-iso9660-image, application/octet-stream; q=0.9, */*; q=0.8";
curDownload_ = g_DownloadManager.StartDownload(storeFileUrl, filename, acceptMime);
return true;
}

View file

@ -74,7 +74,7 @@ static bool RegisterServer(int port) {
std::string ip = fd_util::GetLocalIP(http.sock());
snprintf(resource4, sizeof(resource4) - 1, "/match/update?local=%s&port=%d", ip.c_str(), port);
if (http.GET(resource4, &theVoid, &progress) > 0)
if (http.GET(http::RequestParams(resource4), &theVoid, &progress) > 0)
success = true;
theVoid.Skip(theVoid.size());
http.Disconnect();
@ -87,7 +87,7 @@ static bool RegisterServer(int port) {
// We register both IPv4 and IPv6 in case the other client is using a different one.
if (resource4[0] != 0 && http.Connect(timeout)) {
if (http.GET(resource4, &theVoid, &progress) > 0)
if (http.GET(http::RequestParams(resource4), &theVoid, &progress) > 0)
success = true;
theVoid.Skip(theVoid.size());
http.Disconnect();
@ -99,7 +99,7 @@ static bool RegisterServer(int port) {
std::string ip = fd_util::GetLocalIP(http.sock());
snprintf(resource6, sizeof(resource6) - 1, "/match/update?local=%s&port=%d", ip.c_str(), port);
if (http.GET(resource6, &theVoid, &progress) > 0)
if (http.GET(http::RequestParams(resource6), &theVoid, &progress) > 0)
success = true;
theVoid.Skip(theVoid.size());
http.Disconnect();

View file

@ -1206,7 +1206,8 @@ void FrameDumpTestScreen::update() {
UIScreen::update();
if (!listing_) {
listing_ = g_DownloadManager.StartDownload(framedumpsBaseUrl, Path());
const char *acceptMime = "text/html, */*; q=0.8";
listing_ = g_DownloadManager.StartDownload(framedumpsBaseUrl, Path(), acceptMime);
}
if (listing_ && listing_->Done() && files_.empty()) {

View file

@ -137,7 +137,7 @@ bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort
SetStatus("Loading game list from [URL]...", host, port);
http::RequestProgress progress(&scanCancelled);
code = http.GET(subdir.c_str(), &result, &progress);
code = http.GET(http::RequestParams(subdir.c_str()), &result, &progress);
http.Disconnect();
if (code != 200) {
@ -191,7 +191,7 @@ bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort
if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) {
if (http.Connect(2, 20.0, &scanCancelled)) {
http::RequestProgress progress(&scanCancelled);
code = http.GET("/match/list", &result, &progress);
code = http.GET(http::RequestParams("/match/list"), &result, &progress);
http.Disconnect();
}
}

View file

@ -134,7 +134,9 @@ void HttpImageFileView::DownloadCompletedCallback(http::Download &download) {
void HttpImageFileView::Draw(UIContext &dc) {
using namespace Draw;
if (!texture_ && !textureFailed_ && !path_.empty() && !download_) {
download_ = downloader_->StartDownloadWithCallback(path_, Path(), std::bind(&HttpImageFileView::DownloadCompletedCallback, this, std::placeholders::_1));
auto cb = std::bind(&HttpImageFileView::DownloadCompletedCallback, this, std::placeholders::_1);
const char *acceptMime = "image/png, image/jpeg, image/*; q=0.9, */*; q=0.8";
download_ = downloader_->StartDownloadWithCallback(path_, Path(), cb, acceptMime);
download_->SetHidden(true);
}
@ -366,8 +368,8 @@ StoreScreen::StoreScreen() {
loading_ = true;
std::string indexPath = storeBaseUrl + "index.json";
listing_ = g_DownloadManager.StartDownload(indexPath, Path());
const char *acceptMime = "application/json, */*; q=0.8";
listing_ = g_DownloadManager.StartDownload(indexPath, Path(), acceptMime);
}
StoreScreen::~StoreScreen() {