mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Add an HTTP transport for loading isos.
Not exposed in UI yet, but you can use command line.
This commit is contained in:
parent
b620070fa6
commit
6dca6ad9bd
2 changed files with 159 additions and 1 deletions
158
Core/Loaders.cpp
158
Core/Loaders.cpp
|
@ -15,7 +15,11 @@
|
|||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "base/stringutil.h"
|
||||
#include "file/file_util.h"
|
||||
#include "net/http_client.h"
|
||||
#include "net/resolve.h"
|
||||
#include "net/url.h"
|
||||
#include <cstdio>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
|
@ -53,7 +57,41 @@ private:
|
|||
std::string filename_;
|
||||
};
|
||||
|
||||
class HTTPFileLoader : public FileLoader {
|
||||
public:
|
||||
HTTPFileLoader(const std::string &filename);
|
||||
virtual ~HTTPFileLoader();
|
||||
|
||||
virtual bool Exists() override;
|
||||
virtual bool IsDirectory() override;
|
||||
virtual s64 FileSize() override;
|
||||
virtual std::string Path() const override;
|
||||
|
||||
virtual void Seek(s64 absolutePos) override;
|
||||
virtual size_t Read(size_t bytes, size_t count, void *data) override {
|
||||
return ReadAt(filepos_, bytes, count, data);
|
||||
}
|
||||
virtual size_t Read(size_t bytes, void *data) override {
|
||||
return ReadAt(filepos_, bytes, data);
|
||||
}
|
||||
virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override {
|
||||
return ReadAt(absolutePos, bytes * count, data) / bytes;
|
||||
}
|
||||
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override;
|
||||
|
||||
private:
|
||||
// TODO: Caching, etc.
|
||||
s64 filesize_;
|
||||
s64 filepos_;
|
||||
Url url_;
|
||||
net::AutoInit netInit_;
|
||||
http::Client client_;
|
||||
std::string filename_;
|
||||
};
|
||||
|
||||
FileLoader *ConstructFileLoader(const std::string &filename) {
|
||||
if (filename.find("http://") == 0 || filename.find("https://") == 0)
|
||||
return new HTTPFileLoader(filename);
|
||||
return new LocalFileLoader(filename);
|
||||
}
|
||||
|
||||
|
@ -125,6 +163,126 @@ size_t LocalFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void
|
|||
return Read(bytes, count, data);
|
||||
}
|
||||
|
||||
HTTPFileLoader::HTTPFileLoader(const std::string &filename)
|
||||
: filesize_(0), url_(filename), filename_(filename) {
|
||||
if (!client_.Resolve(url_.Host().c_str(), 80)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Keepalive, etc.
|
||||
client_.Connect();
|
||||
int err = client_.SendRequest("HEAD", url_.Resource().c_str());
|
||||
if (err < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Buffer readbuf;
|
||||
std::vector<std::string> responseHeaders;
|
||||
int code = client_.ReadResponseHeaders(&readbuf, responseHeaders);
|
||||
if (code != 200) {
|
||||
// Leave size at 0, invalid.
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Expire cache via ETag, etc.
|
||||
for (std::string header : responseHeaders) {
|
||||
if (startsWith(header, "Content-Length:")) {
|
||||
size_t size_pos = header.find_first_of(' ');
|
||||
if (size_pos != header.npos) {
|
||||
size_pos = header.find_first_not_of(' ', size_pos);
|
||||
}
|
||||
if (size_pos != header.npos) {
|
||||
filesize_ = atoll(&header[size_pos]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client_.Disconnect();
|
||||
|
||||
// If we didn't end up with a filesize_ (e.g. chunked response), give up. File invalid.
|
||||
}
|
||||
|
||||
HTTPFileLoader::~HTTPFileLoader() {
|
||||
}
|
||||
|
||||
bool HTTPFileLoader::Exists() {
|
||||
// TODO
|
||||
return url_.Valid() && filesize_ > 0;
|
||||
}
|
||||
|
||||
bool HTTPFileLoader::IsDirectory() {
|
||||
// Only files.
|
||||
return false;
|
||||
}
|
||||
|
||||
s64 HTTPFileLoader::FileSize() {
|
||||
return filesize_;
|
||||
}
|
||||
|
||||
std::string HTTPFileLoader::Path() const {
|
||||
return filename_;
|
||||
}
|
||||
|
||||
void HTTPFileLoader::Seek(s64 absolutePos) {
|
||||
filepos_ = absolutePos;
|
||||
}
|
||||
|
||||
size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) {
|
||||
s64 absoluteEnd = absolutePos + bytes;
|
||||
|
||||
// TODO: Keepalive, etc.
|
||||
client_.Connect();
|
||||
|
||||
char requestHeaders[4096];
|
||||
// Note that the Range header is *inclusive*.
|
||||
snprintf(requestHeaders, sizeof(requestHeaders),
|
||||
"Range: bytes=%lld-%lld\r\n", absolutePos, absoluteEnd - 1);
|
||||
|
||||
int err = client_.SendRequest("GET", url_.Resource().c_str(), requestHeaders);
|
||||
if (err < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Buffer readbuf;
|
||||
std::vector<std::string> responseHeaders;
|
||||
int code = client_.ReadResponseHeaders(&readbuf, responseHeaders);
|
||||
if (code != 206) {
|
||||
ERROR_LOG(LOADER, "HTTP server does not support range requests.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Expire cache via ETag, etc.
|
||||
// We don't support multipart/byteranges responses.
|
||||
bool supportedResponse = false;
|
||||
for (std::string header : responseHeaders) {
|
||||
if (startsWith(header, "Content-Range:")) {
|
||||
// TODO: More correctness. Whitespace can be missing or different.
|
||||
s64 first = -1, last = -1, total = -1;
|
||||
if (sscanf(header.c_str(), "Content-Range: bytes %lld-%lld/%lld", &first, &last, &total) >= 2) {
|
||||
if (first == absolutePos && last == absoluteEnd - 1) {
|
||||
supportedResponse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Would be nice to read directly.
|
||||
Buffer output;
|
||||
client_.ReadResponseEntity(&readbuf, responseHeaders, &output);
|
||||
|
||||
if (!supportedResponse) {
|
||||
ERROR_LOG(LOADER, "HTTP server did not respond with the range we wanted.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
client_.Disconnect();
|
||||
|
||||
size_t readBytes = output.size();
|
||||
output.Take(readBytes, (char *)data);
|
||||
filepos_ = absolutePos + readBytes;
|
||||
return readBytes;
|
||||
}
|
||||
|
||||
// TODO : improve, look in the file more
|
||||
IdentifiedFileType Identify_File(FileLoader *fileLoader)
|
||||
{
|
||||
|
|
2
native
2
native
|
@ -1 +1 @@
|
|||
Subproject commit 92be7b0b1bb73b01b4322d787b9c54d03ed7c270
|
||||
Subproject commit 73d5ad3b5c937afceb95569dd55ce8603da17357
|
Loading…
Add table
Reference in a new issue