Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

Commit

Permalink
Fix HTTP connection shutdown issue (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
ringgaard authored May 14, 2018
1 parent 4e4bfe9 commit c445d4f
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 12 deletions.
52 changes: 40 additions & 12 deletions sling/http/http-server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,15 @@ void HTTPServer::Worker() {
// Get new events.
int rc = epoll_wait(pollfd_, events, max_events, 2000);
if (stop_) break;
if (rc == 0 || errno == EAGAIN) continue;
if (errno == EAGAIN) continue;
if (rc < 0) {
LOG(ERROR) << Error("epoll_wait");
break;
}
if (rc == 0) {
ShutdownIdleConnections();
continue;
}

// Process events.
for (int i = 0; i < rc; ++i) {
Expand Down Expand Up @@ -364,14 +368,20 @@ void HTTPServer::Worker() {
conn->state_ = HTTP_STATE_TERMINATE;
}

// Update expected events.
ev->events = 0;
if (conn->AwaitsInput()) ev->events |= EPOLLIN;
if (conn->HasOutput()) ev->events |= EPOLLOUT;
rc = epoll_ctl(pollfd_, EPOLL_CTL_MOD, conn->sock_, ev);
if (rc < 0) LOG(ERROR) << Error("epoll_ctl");
VLOG(5) << "Done processing in state " << conn->state_
<< ", events " << ev->events;
if (conn->state_ == HTTP_STATE_TERMINATE) {
conn->Shutdown();
VLOG(5) << "Shutdown HTTP connection";
} else {
// Update expected events.
ev->events = 0;
if (conn->AwaitsInput()) ev->events |= EPOLLIN;
if (conn->HasOutput()) ev->events |= EPOLLOUT;
rc = epoll_ctl(pollfd_, EPOLL_CTL_MOD, conn->sock_, ev);
if (rc < 0) LOG(ERROR) << Error("epoll_ctl");
conn->last_ = time(0);
VLOG(5) << "Done processing in state " << conn->state_
<< ", events " << ev->events;
}
}
}
}
Expand Down Expand Up @@ -437,6 +447,20 @@ void HTTPServer::RemoveConnection(HTTPConnection *conn) {
conn->next_ = conn->prev_ = nullptr;
}

void HTTPServer::ShutdownIdleConnections() {
if (options_.max_idle <= 0) return;
MutexLock lock(&mu_);
time_t expire = time(0) - options_.max_idle;
HTTPConnection *conn = connections_;
while (conn != nullptr) {
if (conn->last_ < expire) {
conn->Shutdown();
VLOG(5) << "Shut down idle connection";
}
conn = conn->next_;
}
}

HTTPConnection::HTTPConnection(HTTPServer *server, int sock)
: server_(server), sock_(sock) {
next_ = prev_ = nullptr;
Expand All @@ -446,6 +470,7 @@ HTTPConnection::HTTPConnection(HTTPServer *server, int sock)
state_ = HTTP_STATE_IDLE;
header_state_ = HDR_STATE_FIRSTWORD;
keep_ = false;
last_ = time(0);
}

HTTPConnection::~HTTPConnection() {
Expand Down Expand Up @@ -514,10 +539,9 @@ Status HTTPConnection::Process(int events) {
// Fall through

case HTTP_STATE_READ_BODY:
// Check if any input data is ready.
if ((events & EPOLLIN) == 0) return Status::OK;
while (request_body_.size() < request_->content_length()) {
// Check if any input data is ready.
if ((events & EPOLLIN) == 0) return Status::OK;

// Receive more data.
Status st = Recv(&request_body_, &done);
if (!st.ok()) return st;
Expand Down Expand Up @@ -656,6 +680,10 @@ Status HTTPConnection::Send(HTTPBuffer *buffer, bool *done) {
return Status::OK;
}

void HTTPConnection::Shutdown() {
shutdown(sock_, SHUT_RDWR);
}

void HTTPConnection::Dispatch() {
// Allocate response object.
delete response_;
Expand Down
13 changes: 13 additions & 0 deletions sling/http/http-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <netinet/in.h>
#include <string.h>
#include <time.h>
#include <string>

#include "sling/base/status.h"
Expand Down Expand Up @@ -122,6 +123,9 @@ struct HTTPServerOptions {
// Number of events per worker poll.
int max_events = 1;

// Maximum idle time (in seconds) before connection is shut down.
int max_idle = 600;

// Initial buffer size.
int initial_bufsiz = 1 << 10;

Expand Down Expand Up @@ -192,6 +196,9 @@ class HTTPServer {
// Remove connection from server.
void RemoveConnection(HTTPConnection *conn);

// Shut down idle connections.
void ShutdownIdleConnections();

// Server configuration.
HTTPServerOptions options_;

Expand Down Expand Up @@ -277,12 +284,18 @@ class HTTPConnection {
// be sent without blocking has been sent.
Status Send(HTTPBuffer *buffer, bool *done);

// Shut down connection.
void Shutdown();

// HTTP server for connection.
HTTPServer *server_;

// Socket for connection.
int sock_;

// Last time event was received on connection.
time_t last_;

// HTTP connection list.
HTTPConnection *next_;
HTTPConnection *prev_;
Expand Down

0 comments on commit c445d4f

Please sign in to comment.