0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-11 14:38:57 +02:00

ircd::resource: Allow each resource method to specify its timing.

This commit is contained in:
Jason Volk 2018-04-15 16:42:13 -07:00
parent 49d83de384
commit 19d7e05605
8 changed files with 52 additions and 5 deletions

View file

@ -87,8 +87,10 @@ struct ircd::client::conf
/// (or idle mode) after which it is disconnected.
seconds async_timeout {35s};
/// Time limit for how long a connected client can be in "request mode." This
/// should never be hit unless there's an error in the handling code.
/// Time limit for how long a connected client can be sending its request.
/// This is meaningful before the resource being sought is known (while
/// receiving headers), after which its own specific timeout specified by
/// its options takes over.
seconds request_timeout {15s};
};

View file

@ -187,9 +187,13 @@ struct ircd::resource::method
{
flag flags {(flag)0};
/// Timeout specific to this resource.
seconds timeout {30s};
/// The maximum size of the Content-Length for this method. Anything
/// larger will be summarily rejected with a 413.
size_t payload_max {128_KiB};
};
string_view name;

View file

@ -691,7 +691,7 @@ bool
ircd::client::handle_request(parse::capstan &pc)
try
{
const socket::scope_timeout timeout
net::scope_timeout timeout
{
*sock, conf->request_timeout
};
@ -705,6 +705,11 @@ try
pc.parsed += content_consumed;
assert(pc.parsed <= pc.read);
// The resource being sought will have its own specific timeout, or none
// at all. This timeout is now canceled to not conflict. Note that the
// time spent so far is still being accumulated by client.timer.
timeout.cancel();
log::debug
{
"socket(%p) local[%s] remote[%s] HTTP %s `%s' content-length:%zu have:%zu",

View file

@ -256,6 +256,33 @@ ircd::resource::operator()(client &client,
http::PAYLOAD_TOO_LARGE
};
// This timer will keep the request from hanging forever for whatever
// reason. The resource method may want to do its own timing and can
// disable this in its options structure.
const net::scope_timeout timeout
{
*client.sock, method.opts.timeout, [&client, &head]
(const bool &timed_out)
{
if(!timed_out)
return;
log::derror
{
"socket(%p) local[%s] remote[%s] Timed out in %s `%s'",
client.sock.get(),
string(local(client)),
string(remote(client)),
head.method,
head.path
};
//TODO: If we know that no response has been sent yet
//TODO: we can respond with http::REQUEST_TIMEOUT instead.
client.close(net::dc::RST, net::close_ignore);
}
};
// Content that hasn't yet arrived is remaining
const size_t content_remain
{

View file

@ -57,7 +57,8 @@ get_initialsync
{
initialsync_resource, "GET", initialsync,
{
get_initialsync.REQUIRES_AUTH
get_initialsync.REQUIRES_AUTH,
-1s // No timer for this method.
}
};

View file

@ -60,7 +60,8 @@ get_sync
{
sync_resource, "GET", sync,
{
get_sync.REQUIRES_AUTH
get_sync.REQUIRES_AUTH,
-1s, // TODO: this is only -1 b/c initialsyncs
}
};

View file

@ -151,6 +151,11 @@ method_put
send_resource, "PUT", handle_put,
{
method_put.VERIFY_ORIGIN,
// Coarse timeout
30s,
// Payload maximum
4_MiB // larger = HTTP 413 //TODO: conf
}
};

View file

@ -135,6 +135,8 @@ method_post_opts
resource::method::REQUIRES_AUTH |
resource::method::CONTENT_DISCRETION,
-1s, // TODO: no coarse timer
8_MiB //TODO: conf; (this is the payload max option)
};