mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-21 01:11:34 +00:00
http: Add actual serving of recent ISOs.
This commit is contained in:
parent
0edc4d1652
commit
bc614b6f85
@ -57,12 +57,85 @@ static void ExecuteServer() {
|
||||
net::Init();
|
||||
auto http = new http::Server(new threading::SameThreadExecutor());
|
||||
|
||||
std::map<std::string, std::string> paths;
|
||||
for (std::string filename : g_Config.recentIsos) {
|
||||
#ifdef _WIN32
|
||||
static const std::string sep = "\\/";
|
||||
#else
|
||||
static const std::string sep = "/";
|
||||
#endif
|
||||
size_t basepos = filename.find_last_of(sep);
|
||||
std::string basename = "/" + (basepos == filename.npos ? filename : filename.substr(basepos + 1));
|
||||
|
||||
// Let's not serve directories, since they won't work. Only single files.
|
||||
// Maybe can do PBPs and other files later. Would be neat to stream virtual disc filesystems.
|
||||
if (endsWithNoCase(basename, ".cso") || endsWithNoCase(basename, ".iso")) {
|
||||
paths[basename] = filename;
|
||||
}
|
||||
}
|
||||
|
||||
auto handler = [&](const http::Request &request) {
|
||||
std::string filename = paths[request.resource()];
|
||||
s64 sz = File::GetFileSize(filename);
|
||||
|
||||
std::string range;
|
||||
if (request.Method() == http::RequestHeader::HEAD) {
|
||||
request.WriteHttpResponseHeader(200, sz, "application/octet-stream", "Accept-Ranges: bytes\r\n");
|
||||
} else if (request.GetHeader("range", &range)) {
|
||||
s64 begin = 0, last = 0;
|
||||
if (sscanf(range.c_str(), "bytes=%lld-%lld", &begin, &last) != 2) {
|
||||
request.WriteHttpResponseHeader(400, -1, "text/plain");
|
||||
request.Out()->Push("Could not understand range request.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (begin < 0 || begin > last || last >= sz) {
|
||||
request.WriteHttpResponseHeader(416, -1, "text/plain");
|
||||
request.Out()->Push("Range goes outside of file.");
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *fp = File::OpenCFile(filename, "rb");
|
||||
if (!fp || fseek(fp, begin, SEEK_SET) != 0) {
|
||||
request.WriteHttpResponseHeader(500, -1, "text/plain");
|
||||
request.Out()->Push("File access failed.");
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
s64 len = last - begin + 1;
|
||||
char contentRange[1024];
|
||||
sprintf(contentRange, "Content-Range: bytes %lld-%lld/%lld\r\n", begin, last, sz);
|
||||
request.WriteHttpResponseHeader(206, len, "application/octet-stream", contentRange);
|
||||
|
||||
const size_t CHUNK_SIZE = 16 * 1024;
|
||||
char *buf = new char[CHUNK_SIZE];
|
||||
for (s64 pos = 0; pos < len; pos += CHUNK_SIZE) {
|
||||
s64 chunklen = std::min(len - pos, (s64)CHUNK_SIZE);
|
||||
fread(buf, chunklen, 1, fp);
|
||||
request.Out()->Push(buf, chunklen);
|
||||
}
|
||||
fclose(fp);
|
||||
delete [] buf;
|
||||
request.Out()->Flush();
|
||||
} else {
|
||||
request.WriteHttpResponseHeader(418, -1, "text/plain");
|
||||
request.Out()->Push("This server only supports range requests.");
|
||||
}
|
||||
};
|
||||
|
||||
for (auto pair : paths) {
|
||||
http->RegisterHandler(pair.first.c_str(), handler);
|
||||
}
|
||||
|
||||
http->Listen(0);
|
||||
// TODO: Report local IP and port.
|
||||
UpdateStatus(ServerStatus::RUNNING);
|
||||
|
||||
while (RetrieveStatus() == ServerStatus::RUNNING) {
|
||||
http->RunSlice(5.0);
|
||||
http->RunSlice(5.0);
|
||||
}
|
||||
|
||||
net::Shutdown();
|
||||
|
@ -60,48 +60,50 @@ private:
|
||||
|
||||
// Register handlers on this class to serve stuff.
|
||||
class Server {
|
||||
public:
|
||||
Server(threading::Executor *executor);
|
||||
public:
|
||||
Server(threading::Executor *executor);
|
||||
|
||||
typedef std::function<void(const Request &)> UrlHandlerFunc;
|
||||
typedef std::map<std::string, UrlHandlerFunc> UrlHandlerMap;
|
||||
typedef std::function<void(const Request &)> UrlHandlerFunc;
|
||||
typedef std::map<std::string, UrlHandlerFunc> UrlHandlerMap;
|
||||
|
||||
// Runs forever, serving request. If you want to do something else than serve pages,
|
||||
// better put this on a thread. Returns false if failed to start serving, never
|
||||
// returns if successful.
|
||||
bool Run(int port);
|
||||
// May run for (significantly) longer than timeout, but won't wait longer than that
|
||||
// for a new connection to handle.
|
||||
bool RunSlice(double timeout);
|
||||
bool Listen(int port);
|
||||
// Runs forever, serving request. If you want to do something else than serve pages,
|
||||
// better put this on a thread. Returns false if failed to start serving, never
|
||||
// returns if successful.
|
||||
bool Run(int port);
|
||||
// May run for (significantly) longer than timeout, but won't wait longer than that
|
||||
// for a new connection to handle.
|
||||
bool RunSlice(double timeout);
|
||||
bool Listen(int port);
|
||||
|
||||
void RegisterHandler(const char *url_path, UrlHandlerFunc handler);
|
||||
void SetFallbackHandler(UrlHandlerFunc handler);
|
||||
void RegisterHandler(const char *url_path, UrlHandlerFunc handler);
|
||||
void SetFallbackHandler(UrlHandlerFunc handler);
|
||||
|
||||
// If you want to customize things at a lower level than just a simple path handler,
|
||||
// then inherit and override this. Implementations should forward to HandleRequestDefault
|
||||
// if they don't recognize the url.
|
||||
virtual void HandleRequest(const Request &request);
|
||||
// If you want to customize things at a lower level than just a simple path handler,
|
||||
// then inherit and override this. Implementations should forward to HandleRequestDefault
|
||||
// if they don't recognize the url.
|
||||
virtual void HandleRequest(const Request &request);
|
||||
|
||||
private:
|
||||
void HandleConnection(int conn_fd);
|
||||
int Port() {
|
||||
return port_;
|
||||
}
|
||||
|
||||
void GetRequest(Request *request);
|
||||
private:
|
||||
void HandleConnection(int conn_fd);
|
||||
|
||||
// Things like default 404, etc.
|
||||
void HandleRequestDefault(const Request &request);
|
||||
// Things like default 404, etc.
|
||||
void HandleRequestDefault(const Request &request);
|
||||
|
||||
// Neat built-in handlers that are tied to the server.
|
||||
void HandleListing(const Request &request);
|
||||
void Handle404(const Request &request);
|
||||
// Neat built-in handlers that are tied to the server.
|
||||
void HandleListing(const Request &request);
|
||||
void Handle404(const Request &request);
|
||||
|
||||
int listener_;
|
||||
int port_;
|
||||
int listener_;
|
||||
int port_;
|
||||
|
||||
UrlHandlerMap handlers_;
|
||||
UrlHandlerFunc fallback_;
|
||||
UrlHandlerMap handlers_;
|
||||
UrlHandlerFunc fallback_;
|
||||
|
||||
threading::Executor *executor_;
|
||||
threading::Executor *executor_;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
Loading…
x
Reference in New Issue
Block a user