diff options
Diffstat (limited to 'src/output/HttpdClient.cxx')
-rw-r--r-- | src/output/HttpdClient.cxx | 71 |
1 files changed, 45 insertions, 26 deletions
diff --git a/src/output/HttpdClient.cxx b/src/output/HttpdClient.cxx index 8e13fda38..102ce1ec3 100644 --- a/src/output/HttpdClient.cxx +++ b/src/output/HttpdClient.cxx @@ -37,24 +37,26 @@ HttpdClient::~HttpdClient() if (current_page != nullptr) current_page->Unref(); - for (auto page : pages) - page->Unref(); + ClearQueue(); } if (metadata) metadata->Unref(); + + if (IsDefined()) + BufferedSocket::Close(); } void HttpdClient::Close() { - httpd->RemoveClient(*this); + httpd.RemoveClient(*this); } void HttpdClient::LockClose() { - const ScopeLock protect(httpd->mutex); + const ScopeLock protect(httpd.mutex); Close(); } @@ -67,7 +69,7 @@ HttpdClient::BeginResponse() current_page = nullptr; if (!head_method) - httpd->SendHeader(*this); + httpd.SendHeader(*this); } /** @@ -155,13 +157,13 @@ HttpdClient::SendResponse() "realTimeInfo.dlna.org: DLNA.ORG_TLAG=*\r\n" "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0\r\n" "\r\n", - httpd->content_type); + httpd.content_type); } else if (metadata_requested) { char *metadata_header = - icy_server_metadata_header(httpd->name, httpd->genre, - httpd->website, - httpd->content_type, + icy_server_metadata_header(httpd.name, httpd.genre, + httpd.website, + httpd.content_type, metaint); g_strlcpy(buffer, metadata_header, sizeof(buffer)); @@ -176,7 +178,7 @@ HttpdClient::SendResponse() "Pragma: no-cache\r\n" "Cache-Control: no-cache, no-store\r\n" "\r\n", - httpd->content_type); + httpd.content_type); } ssize_t nbytes = SocketMonitor::Write(buffer, strlen(buffer)); @@ -192,11 +194,12 @@ HttpdClient::SendResponse() return true; } -HttpdClient::HttpdClient(HttpdOutput *_httpd, int _fd, EventLoop &_loop, +HttpdClient::HttpdClient(HttpdOutput &_httpd, int _fd, EventLoop &_loop, bool _metadata_supported) :BufferedSocket(_fd, _loop), httpd(_httpd), state(REQUEST), + queue_size(0), head_method(false), dlna_streaming_requested(false), metadata_supported(_metadata_supported), @@ -207,16 +210,24 @@ HttpdClient::HttpdClient(HttpdOutput *_httpd, int _fd, EventLoop &_loop, { } -size_t -HttpdClient::GetQueueSize() const +void +HttpdClient::ClearQueue() { - if (state != RESPONSE) - return 0; + assert(state == RESPONSE); - size_t size = 0; - for (auto page : pages) - size += page->size; - return size; + while (!pages.empty()) { + Page *page = pages.front(); + pages.pop(); + +#ifndef NDEBUG + assert(queue_size >= page->size); + queue_size -= page->size; +#endif + + page->Unref(); + } + + assert(queue_size == 0); } void @@ -225,9 +236,7 @@ HttpdClient::CancelQueue() if (state != RESPONSE) return; - for (auto page : pages) - page->Unref(); - pages.clear(); + ClearQueue(); if (current_page == nullptr) CancelWrite(); @@ -262,7 +271,7 @@ HttpdClient::GetBytesTillMetaData() const inline bool HttpdClient::TryWrite() { - const ScopeLock protect(httpd->mutex); + const ScopeLock protect(httpd.mutex); assert(state == RESPONSE); @@ -270,14 +279,17 @@ HttpdClient::TryWrite() if (pages.empty()) { /* another thread has removed the event source while this thread was waiting for - httpd->mutex */ + httpd.mutex */ CancelWrite(); return true; } current_page = pages.front(); - pages.pop_front(); + pages.pop(); current_position = 0; + + assert(queue_size >= current_page->size); + queue_size -= current_page->size; } const ssize_t bytes_to_write = GetBytesTillMetaData(); @@ -378,8 +390,15 @@ HttpdClient::PushPage(Page *page) /* the client is still writing the HTTP request */ return; + if (queue_size > 256 * 1024) { + FormatDebug(httpd_output_domain, + "client is too slow, flushing its queue"); + ClearQueue(); + } + page->Ref(); - pages.push_back(page); + pages.push(page); + queue_size += page->size; ScheduleWrite(); } |