Skip to content

Commit

Permalink
feat(http): Add DELETE method support (#1442)
Browse files Browse the repository at this point in the history
When we try to remove an old segment from a live stream we uploaded via HTTP, we need to send DELETE requests.
  • Loading branch information
joeyparrish authored Oct 25, 2024
1 parent 2c9d100 commit ddeacb2
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 13 deletions.
8 changes: 0 additions & 8 deletions docs/source/tutorials/http_upload.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,6 @@ Backlog
Please note the HTTP upload feature still lacks some features
probably important for production. Contributions are welcome!

HTTP DELETE
===========
Nothing has be done to support this yet:

Packager supports removing old segments automatically.
See ``preserved_segments_outside_live_window`` option in
DASH_ options or HLS_ options for details.

Software tests
==============
We should do some minimal QA, check whether the test
Expand Down
12 changes: 10 additions & 2 deletions packager/file/file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ File* CreateHttpsFile(const char* file_name, const char* mode) {
return new HttpFile(method, std::string("https://") + file_name);
}

bool DeleteHttpsFile(const char* file_name) {
return HttpFile::Delete(std::string("https://") + file_name);
}

File* CreateHttpFile(const char* file_name, const char* mode) {
HttpMethod method = HttpMethod::kGet;
if (strcmp(mode, "r") != 0) {
Expand All @@ -119,6 +123,10 @@ File* CreateHttpFile(const char* file_name, const char* mode) {
return new HttpFile(method, std::string("http://") + file_name);
}

bool DeleteHttpFile(const char* file_name) {
return HttpFile::Delete(std::string("http://") + file_name);
}

File* CreateMemoryFile(const char* file_name, const char* mode) {
return new MemoryFile(file_name, mode);
}
Expand All @@ -138,8 +146,8 @@ static const FileTypeInfo kFileTypeInfo[] = {
{kUdpFilePrefix, &CreateUdpFile, nullptr, nullptr},
{kMemoryFilePrefix, &CreateMemoryFile, &DeleteMemoryFile, nullptr},
{kCallbackFilePrefix, &CreateCallbackFile, nullptr, nullptr},
{kHttpFilePrefix, &CreateHttpFile, nullptr, nullptr},
{kHttpsFilePrefix, &CreateHttpsFile, nullptr, nullptr},
{kHttpFilePrefix, &CreateHttpFile, &DeleteHttpFile, nullptr},
{kHttpsFilePrefix, &CreateHttpsFile, &DeleteHttpsFile, nullptr},
};

std::string_view GetFileTypePrefix(std::string_view file_name) {
Expand Down
20 changes: 17 additions & 3 deletions packager/file/http_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <absl/strings/str_format.h>
#include <curl/curl.h>

#include <packager/file/file_closer.h>
#include <packager/file/thread_pool.h>
#include <packager/macros/compiler.h>
#include <packager/macros/logging.h>
Expand Down Expand Up @@ -174,6 +175,7 @@ HttpFile::HttpFile(HttpMethod method,
upload_content_type_(upload_content_type),
timeout_in_seconds_(timeout_in_seconds),
method_(method),
isUpload_(method == HttpMethod::kPut || method == HttpMethod::kPost),
download_cache_(absl::GetFlag(FLAGS_io_cache_size)),
upload_cache_(absl::GetFlag(FLAGS_io_cache_size)),
curl_(curl_easy_init()),
Expand Down Expand Up @@ -201,8 +203,7 @@ HttpFile::HttpFile(HttpMethod method,
!AppendHeader("Content-Type: " + upload_content_type_, &temp_headers)) {
return;
}
if (method != HttpMethod::kGet &&
!AppendHeader("Transfer-Encoding: chunked", &temp_headers)) {
if (isUpload_ && !AppendHeader("Transfer-Encoding: chunked", &temp_headers)) {
return;
}
for (const auto& item : headers) {
Expand All @@ -215,6 +216,16 @@ HttpFile::HttpFile(HttpMethod method,

HttpFile::~HttpFile() {}

// static
bool HttpFile::Delete(const std::string& url) {
std::unique_ptr<HttpFile, FileCloser> file(
new HttpFile(HttpMethod::kDelete, url));
if (!file->Open()) {
return false;
}
return file.release()->Close();
}

bool HttpFile::Open() {
VLOG(2) << "Opening " << url_;

Expand Down Expand Up @@ -313,6 +324,9 @@ void HttpFile::SetupRequest() {
case HttpMethod::kPut:
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
break;
case HttpMethod::kDelete:
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
break;
}

curl_easy_setopt(curl, CURLOPT_URL, url_.c_str());
Expand All @@ -322,7 +336,7 @@ void HttpFile::SetupRequest() {
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &download_cache_);
if (method_ != HttpMethod::kGet) {
if (isUpload_) {
curl_easy_setopt(curl, CURLOPT_READFUNCTION, &CurlReadCallback);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_cache_);
}
Expand Down
4 changes: 4 additions & 0 deletions packager/file/http_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum class HttpMethod {
kGet,
kPost,
kPut,
kDelete,
};

/// HttpFile reads or writes network requests.
Expand All @@ -47,6 +48,8 @@ class HttpFile : public File {
HttpFile(const HttpFile&) = delete;
HttpFile& operator=(const HttpFile&) = delete;

static bool Delete(const std::string& url);

Status CloseWithStatus();

/// @name File implementation overrides.
Expand Down Expand Up @@ -78,6 +81,7 @@ class HttpFile : public File {
const std::string upload_content_type_;
const int32_t timeout_in_seconds_;
const HttpMethod method_;
const bool isUpload_;
IoCache download_cache_;
IoCache upload_cache_;
std::unique_ptr<CURL, CurlDelete> curl_;
Expand Down
12 changes: 12 additions & 0 deletions packager/file/http_file_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,18 @@ TEST_F(HttpFileTest, MultipleChunks) {
ASSERT_JSON_STRING(json, "headers.Transfer-Encoding", "chunked");
}

TEST_F(HttpFileTest, BasicDelete) {
FilePtr file(new HttpFile(HttpMethod::kDelete, server_.ReflectUrl(),
kNoContentType, kNoHeaders, kDefaultTestTimeout));
ASSERT_TRUE(file);
ASSERT_TRUE(file->Open());

auto json = HandleResponse(file);
ASSERT_TRUE(json.is_object());
ASSERT_TRUE(file.release()->Close());
ASSERT_JSON_STRING(json, "method", "DELETE");
}

TEST_F(HttpFileTest, Error404) {
FilePtr file(new HttpFile(HttpMethod::kGet, server_.StatusCodeUrl(404),
kNoContentType, kNoHeaders, kDefaultTestTimeout));
Expand Down

0 comments on commit ddeacb2

Please sign in to comment.