-
Notifications
You must be signed in to change notification settings - Fork 3.5k
HTTP server accept throttle callback #578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
1 similar comment
|
I notice this failure on one configuration - however, all the other HTTP tests seem to have failed too? Is there anything I can do? |
azat
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for delay, could you take a look at the comments?
http.c
Outdated
| case 3: | ||
| /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */ | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please clean this patch from this whitespace fixes (I know I know, it looks better now, but it pollutes the patch)
include/event2/http.h
Outdated
|
|
||
| /* Older versions of libevent did not have this callback, so make it | ||
| * possible for users to detect it */ | ||
| #define EVENT2_HTTP_HAS_THROTTLECB |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like it here, we should either move it into some *-config.h or just let user detect this by himself, using his build system (well it is simpler to just #ifdef but we don't have such defines for other functions). Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
plus I guess it should be defined as EVENT2_HTTP_HAS_THROTTLEREQCB to avoid different namings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this should be renamed with the other rename.
My suggestion here is that we should make presence of this callback easy to detect at runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this is not "at runtime", and there is nothing that we can do here
include/event2/http.h
Outdated
| const char *address, ev_uint16_t port); | ||
|
|
||
| /** | ||
| /** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well this is definitely a bad hunk (even though previous whitespace hunks were fine, at least they make sense)
listener.c
Outdated
| void *user_data; | ||
| LOCK(lev); | ||
| while (1) { | ||
| while (lev->enabled) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what this for? even though this makes sense, this should be a separate patch, otherwise it will became too tricky to track changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the intention was to immediately act, if a cb decides to disable the listener, to prevent it draining the queue.
If you would accept this as a separate PR I would add it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, just submit another PR, since this is totally different thing
| return; | ||
| end: | ||
| tt_fail(); | ||
| exit(17); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that tt_abort() is better instead, no? or does the semantic differs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tt_abort ends up doing goto end - I copied this more drastic exit from elsewhere in the file
| struct http_throttlereqcb_test_state* state = arg; | ||
| state->connections_noticed ++; | ||
| http_throttlereqcb_test_state_check(state); | ||
| if (1 == state->connections_noticed%7) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugh, why do people prefer 1 == some_var instead of some_var == 1, never mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fewer typos!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, don't see your point
http.c
Outdated
| } | ||
|
|
||
| void | ||
| evhttp_set_throttlereqcb(struct evhttp *http, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this could be renamed, since this is useful not only for throttling, but also for some kind of whitelist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@azat exactly - happy to rename it, what would you like me to call it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@azat called it newreqcb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, sounds more generic
http.c
Outdated
|
|
||
| TAILQ_INSERT_TAIL(&evcon->requests, req, next); | ||
| if (http->throttlereqcb) { | ||
| if (http->throttlereqcb(req, http->throttlereqcbarg)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whitespace issues, we use tabs, not spaces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(and please check all other places)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
plus I guess this can be rewritten with if (http->throttlereqcb && http->throttlereqcb(...)) { ... }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done! Hope the whitespace is better now!
| http_request_error_throttlereqcb(enum evhttp_request_error err, void *arg) | ||
| { | ||
| struct http_throttlereqcb_test_state* state = arg; | ||
| state->connections_error ++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what space for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(and in other places too)
| end: | ||
| evhttp_free(http); | ||
|
|
||
| for (n = 0; n < sizeof(evcons)/sizeof(evcons[0]); ++n) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is ARRAY_SIZE() in regress_dnc.c, could be moved into some header and re-used here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would that really be clearer? People unfamiliar with the project would have to understand which kind of size is being referred to by that macro
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pretty common macro I suppose, but I'm fine with that sizeof/sizeof
could give the link to this failures? |
|
the failures I am referring to are in this run https://travis-ci.org/libevent/libevent/jobs/309815275 Sorry for the whitespace changes. I'll try to go through and fix them. |
6e1a7e1 to
1e1f699
Compare
1 similar comment
yep, now it looks cleaner, thanks! |
grep |
| */ | ||
| EVENT2_EXPORT_SYMBOL | ||
| void evhttp_set_newreqcb(struct evhttp *http, | ||
| int (*cb)(struct evhttp_request*, void *), void *arg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about returning enum instead, but don't have a clear idea what we can add in future, plus all other callbacks returns int. At least let's make well-defined return code, let's say "If the callback returns -1, the connection will be terminated"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
1 similar comment
…oming connections. This is important, as otherwise clients can easily exhaust the file descriptors available on a libevent HTTP server, which can cause problems in other code which does not handle EMFILE well: for example, see bitcoin/bitcoin#11368
|
as far as I can tell, all the HTTP regression tests fail in that CI mode so the new one failing too is to be expected Would you like any more changes @azat ? |
Well most of the time tests passes.
Nope, I will take a look through this again today, thanks for fixing all notes! |
1 similar comment
|
Applied, thanks! (but one small comment, please take a look at the differences between upstream commit and your patch, since I had been fixed small coding style issues) |
This is a refined version of the logic previously in #578 The rationale is that the consumer of sockets may wish to temporarily delay accepting for some reason (e.g. being out of file-descriptors). The kernel will then queue them up. The kernel queue is bounded and programs like NodeJS will actually try to quickly accept and then close (as the current behaviour before this PR). However, it seems that libevent should allow the user to choose whether to accept and respond correctly if the listener is disabled.
Add callback to allow HTTP servers to decline (and thereby close) incoming connections.
This is important, as otherwise clients can easily exhaust the file
descriptors available on a libevent HTTP server, which can cause
problems in other code which does not handle EMFILE well: for example,
see bitcoin/bitcoin#11368