Downloads
This commit is contained in:
@@ -167,6 +167,10 @@ MimeTypes::MimeTypes()
|
||||
AddMimeType("MPG", "video/mp2p");
|
||||
AddMimeType("MPEG", "video/mp2p");
|
||||
|
||||
// custom.
|
||||
AddMimeType("NAM", "application/x-nam+json");
|
||||
|
||||
|
||||
}
|
||||
|
||||
const MimeTypes&MimeTypes::instance()
|
||||
|
||||
@@ -2879,3 +2879,8 @@ void PiPedalModel::OnAlsaDriverTerminatedAbnormally() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool PiPedalModel::IsInUploadsDirectory(const std::string &path)
|
||||
{
|
||||
return !storage.IsInUploadsDirectory(path);
|
||||
}
|
||||
@@ -456,6 +456,8 @@ namespace pipedal
|
||||
std::string RenameFilePropertyFile(const std::string &oldRelativePath, const std::string &newRelativePath, const UiFileProperty &uiFileProperty);
|
||||
FilePropertyDirectoryTree::ptr GetFilePropertydirectoryTree(const UiFileProperty &uiFileProperty,const std::string&selectedPath);
|
||||
|
||||
bool IsInUploadsDirectory(const std::string &path);
|
||||
|
||||
std::string UploadUserFile(const std::string &directory, int64_t instanceId, const std::string &patchProperty, const std::string &filename, std::istream &inputStream, size_t streamLength);
|
||||
uint64_t CreateNewPreset();
|
||||
|
||||
|
||||
+88
-14
@@ -153,7 +153,7 @@ namespace pipedal
|
||||
}
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
RingBufferStatus readWait_until(size_t size,const std::chrono::time_point<Clock, Duration> &time_point)
|
||||
RingBufferStatus readWait_until(size_t size, const std::chrono::time_point<Clock, Duration> &time_point)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
@@ -161,7 +161,7 @@ namespace pipedal
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
size_t available = readSpace_();
|
||||
if (available >= size)
|
||||
if (available >= size)
|
||||
{
|
||||
return RingBufferStatus::Ready;
|
||||
}
|
||||
@@ -215,12 +215,69 @@ namespace pipedal
|
||||
return (size_t)size;
|
||||
}
|
||||
|
||||
|
||||
size_t readSpace()
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
return readSpace_();
|
||||
}
|
||||
|
||||
bool write_packet(size_t bytes, void *data)
|
||||
{
|
||||
if (MULTI_WRITER)
|
||||
{
|
||||
std::lock_guard writeLock{writeMutex};
|
||||
if (writeSpace() < bytes + sizeof(bytes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
size_t index = this->writePosition;
|
||||
for (size_t i = 0; i < sizeof(bytes); ++i)
|
||||
{
|
||||
buffer[(index++() & ringBufferMask] = ((uint8_t*)(&bytes))[i];
|
||||
|
||||
}
|
||||
for (size_t i = 0; i < bytes; ++i)
|
||||
{
|
||||
buffer[(index++) & ringBufferMask] = data[i];
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
this->writePosition = (index) & ringBufferMask;
|
||||
}
|
||||
if (SEMAPHORE_READER)
|
||||
{
|
||||
cvRead.notify_all();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (writeSpace() < bytes + sizeof(bytes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
size_t index = this->writePosition;
|
||||
for (size_t i = 0; i < sizeof(bytes); ++i)
|
||||
{
|
||||
buffer[(index++() & ringBufferMask] = ((uint8_t*)(&bytes))[i];
|
||||
|
||||
}
|
||||
for (size_t i = 0; i < bytes; ++i)
|
||||
{
|
||||
buffer[(index++) & ringBufferMask] = data[i];
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
this->writePosition = (index) & ringBufferMask;
|
||||
}
|
||||
if (SEMAPHORE_READER)
|
||||
{
|
||||
cvRead.notify_all();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool write(size_t bytes, uint8_t *data)
|
||||
{
|
||||
if (MULTI_WRITER)
|
||||
@@ -273,7 +330,7 @@ namespace pipedal
|
||||
if (MULTI_WRITER)
|
||||
{
|
||||
std::lock_guard guard(writeMutex);
|
||||
if (writeSpace() <= sizeof(bytes) + bytes +bytes2)
|
||||
if (writeSpace() <= sizeof(bytes) + bytes + bytes2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -340,6 +397,23 @@ namespace pipedal
|
||||
}
|
||||
}
|
||||
|
||||
size_t read_packet(size_t maxSize, void*data) {
|
||||
size_t packet_size;
|
||||
if (!read(sizeof(packet_size), (uint8_t*)&packet_size))
|
||||
{
|
||||
throw std::runtime_error("RingBuffer::read_packet: failed to read packet size.");
|
||||
}
|
||||
if (packet_size > maxSize)
|
||||
{
|
||||
throw std::runtime_error("RingBuffer::read_packet: packet size too large.");
|
||||
}
|
||||
if (!read(packet_size, (uint8_t*)data))
|
||||
{
|
||||
throw std::runtime_error("RingBuffer::read_packet: failed to read packet data.");
|
||||
}
|
||||
return packet_size;
|
||||
}
|
||||
|
||||
bool read(size_t bytes, uint8_t *data)
|
||||
{
|
||||
if (readSpace() < bytes)
|
||||
@@ -366,18 +440,20 @@ namespace pipedal
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
bool isReadReady() {
|
||||
bool isReadReady()
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
if (isReadReady_()) return true;
|
||||
if (isReadReady_())
|
||||
return true;
|
||||
return !this->is_open;
|
||||
}
|
||||
bool isReadReady(size_t size) {
|
||||
bool isReadReady(size_t size)
|
||||
{
|
||||
size_t available = readSpace();
|
||||
return available >= size;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
size_t readSpace_()
|
||||
{
|
||||
int64_t size = writePosition - readPosition;
|
||||
@@ -389,7 +465,7 @@ namespace pipedal
|
||||
uint32_t peekSize()
|
||||
{
|
||||
volatile uint32_t result;
|
||||
uint8_t *p = (uint8_t*)&result;
|
||||
uint8_t *p = (uint8_t *)&result;
|
||||
size_t ix = this->readPosition;
|
||||
for (size_t i = 0; i < sizeof(result); ++i)
|
||||
{
|
||||
@@ -400,14 +476,12 @@ namespace pipedal
|
||||
bool isReadReady_()
|
||||
{
|
||||
size_t available = readSpace_();
|
||||
if (available < sizeof(uint32_t)) return false;
|
||||
if (available < sizeof(uint32_t))
|
||||
return false;
|
||||
// peak to get the size!
|
||||
uint32_t packetSize = peekSize();
|
||||
return packetSize+sizeof(uint32_t) <= available;
|
||||
return packetSize + sizeof(uint32_t) <= available;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -327,6 +327,7 @@ namespace pipedal
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write(RingBufferCommand command, const T &value, size_t dataLength, uint8_t *variableData)
|
||||
{
|
||||
|
||||
+46
-1
@@ -34,6 +34,7 @@
|
||||
#include "PresetBundle.hpp"
|
||||
#include "json.hpp"
|
||||
#include "HotspotManager.hpp"
|
||||
#include "MimeTypes.hpp"
|
||||
|
||||
#define OLD_PRESET_EXTENSION ".piPreset"
|
||||
#define PRESET_EXTENSION ".piPreset"
|
||||
@@ -51,6 +52,22 @@ using namespace pipedal;
|
||||
using namespace boost::system;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
|
||||
|
||||
static bool HasDotDot(const std::filesystem::path &path) {
|
||||
for (auto &part : path)
|
||||
{
|
||||
if (part == "..") {
|
||||
return true;
|
||||
}
|
||||
if (part == ".")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class UserUploadResponse
|
||||
{
|
||||
public:
|
||||
@@ -63,6 +80,13 @@ JSON_MAP_REFERENCE(UserUploadResponse, errorMessage)
|
||||
JSON_MAP_REFERENCE(UserUploadResponse, path)
|
||||
JSON_MAP_END()
|
||||
|
||||
static std::string GetMimeType(const std::filesystem::path&path) {
|
||||
std::string extension = path.extension();
|
||||
const MimeTypes&mimeTypes = MimeTypes::instance();
|
||||
auto result = mimeTypes.MimeTypeFromExtension(extension);
|
||||
return result;
|
||||
|
||||
}
|
||||
static bool IsZipFile(const std::filesystem::path &path)
|
||||
{
|
||||
std::ifstream f(path);
|
||||
@@ -119,6 +143,10 @@ public:
|
||||
return false;
|
||||
}
|
||||
std::string segment = request_uri.segment(1);
|
||||
if (segment == "downloadMediaFile")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (segment == "uploadPluginPresets")
|
||||
{
|
||||
return true;
|
||||
@@ -154,7 +182,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GetContentDispositionHeader(const std::string &name, const std::string &extension)
|
||||
static std::string GetContentDispositionHeader(const std::string &name, const std::string &extension)
|
||||
{
|
||||
std::string fileName = name.substr(0, 64) + extension;
|
||||
std::stringstream s;
|
||||
@@ -423,6 +451,23 @@ public:
|
||||
{
|
||||
std::string segment = request_uri.segment(1);
|
||||
|
||||
if (segment == "downloadMediaFile") {
|
||||
fs::path path = request_uri.query("path");
|
||||
|
||||
if (!fs::exists(path) || !this->model->IsInUploadsDirectory(path) || HasDotDot(path))
|
||||
{
|
||||
throw PiPedalException("File not found.");
|
||||
}
|
||||
auto mimeType = GetMimeType(path);
|
||||
if (mimeType.empty()) {
|
||||
throw PiPedalException("Can't download files of this type.");
|
||||
}
|
||||
res.set(HttpField::content_type, mimeType);
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
std::string disposition = GetContentDispositionHeader(path.stem().string(), path.extension().string());
|
||||
res.set(HttpField::content_disposition, disposition);
|
||||
res.setBodyFile(path,false);
|
||||
}
|
||||
if (segment == "uploadPluginPresets")
|
||||
{
|
||||
PluginPresets presets;
|
||||
|
||||
Reference in New Issue
Block a user