Comments (10)
Wow, this is a lot to take in tonight. I may see where things could go wrong. I'm very tired tonight and will look into this tomorrow.
But oddly enough, I wrote a detailed example of proper request pausing usage here: https://github.com/criticalstack/libevhtp/blob/develop/examples/example_pause.c
Until tomorrow!
from libevhtp.
Yeah, sorry I provided so much. Its an issue I'v been stuck with for some time now and struggling with. I'll work on it some more and maybe this will be closed before you get a chance to look at it! =]
from libevhtp.
It actually maybe more of a work around than a fix, but I found [1] which instead of calling request_pause, only disabled EV_READ. Its probably an issue on the seafile side, so closing. Thanks for your help.
[1] https://sml.zincube.net/~niol/repositories.git/seafile-server/plain/debian/patches/recent-libevhtp
from libevhtp.
More information about the issue if interested in reading more.
from libevhtp.
Reopening as I remember seeing this issue, and I'm not 100% sure it's a seafile issue.
from libevhtp.
Ah, that patch above in (zincube) will only work correctly if the callback where the request is paused is the final one. Otherwise, the API wouldn't know to short-circuit and return back to the function that called the parser. So that person should watch out for that.
But I think he's on the right track, here is how pausing works at the moment:
- when
request_pause
is called, it sets theEVHTP_CONN_FLAG_PAUSED
on the connection
(evhtp_connection_t *)c->flags &= EVHP_CONN_FLAG_PAUSED)
-
The above actually happens from
evhtp_connection_pause
, but after it returns, it disables both EV_READ and EV_WRITE. -
It then sets the requests
status
toEVHTP_CONN_FLAG_PAUSED
-
This tells any further processing from htparser to stop, and as nested as it may be, all functions check for the paused status and return back until it finally gets back to the read callback.
-
when
evhtp_request_resume
is called, it executes anevent_active(conn->resume_ev, EV_WRITE, 1)
which will callhtp__connection_resumecb_
. This event is initialized as follows:
connection->resume_ev = event_new(evbase, -1, EV_READ | EV_PERSIST,
htp__connection_resumecb_, connection);
When event_active
gets around to calling htp__connection_resumecb_
it unsets the EVHTP_CONN_FLAG_PAUSED
flag, and does some checks here and there,
but I think the culprit may be here:
if (evbuffer_get_length(bufferevent_get_output(c->bev)))
{
HTP_FLAG_ON(c, EVHTP_CONN_FLAG_WAITING);
bufferevent_enable(c->bev, EV_WRITE);
} else {
bufferevent_enable(c->bev, EV_READ | EV_WRITE);
htp__connection_readcb_(c->bev, c);
}
If there is pending data on the output buffer, it will only set the bufferevent to EV_WRITE
. The assumption was that libevent would automatically start transferring pending data to the socket once the EV_WRITE
flag was set on the bufferevent. This is a dumb assumption. It does not. So if there is pending data, it just stays there until the bufferevent is written to again.
-
The flag
EVHTP_CONN_FLAG_WAITING
is set on the connection, which only gets checked and unset inhtp__connection_writecb_
(the write callback). But with the assumption above, and no data is written to the socket AFTERhtp__connection_resumecb_
. -
When (and if, in some cases apparently)
htp__connection_writecb_
is called by libevent, it checks for theEVHTP_CONN_FLAG_WAITING
flag in the connection, if enabled, it enablesEV_READ
again on the connection's bufferevent, then immediately callshtp__connection_readcb_
. But this doesn't take into account pending data on the write end of the bufferevent (unless, as I said, something writes to it afterwards).
It should be noted that even if htp__connection_writecb_
is called before htp__connection_resumecb_
(don't ask me how this could happen), it will return do to:
/* run user-hook for on_write callback before further analysis */
htp__hook_connection_write_(conn);
/* connection is in a paused state, no further processing yet */
if ((conn->flags & EVHTP_CONN_FLAG_PAUSED))
{
return;
}
/* checks for EVHTP_CONN_FLAG_WAITING, then enables read again */
I think some of the patches above were on the write (get it, "write", not "right"?) track. I do not think the EV_WRITE
flag should be unset on the connection's bufferevent when paused. We should let libevent do its dirty work of sending all pending data.
We might want to rearrange some of the code there, I'm thinking something like:
/* run user-hook for on_write callback before further analysis */
htp__hook_connection_write_(conn);
/* connection is in a paused state, no further processing yet */
if ((conn->flags & EVHTP_CONN_FLAG_PAUSED))
{
return;
}
if (conn->flags & EVHTP_CONN_FLAG_WAITING)
to
/* connection is in a paused state, no further processing yet */
if ((conn->flags & EVHTP_CONN_FLAG_PAUSED))
{
return;
}
/* run user-hook for on_write callback before further analysis */
htp__hook_connection_write_(conn);
if (conn->flags & EVHTP_CONN_FLAG_WAITING)
and
void
evhtp_connection_pause(evhtp_connection_t * c)
{
evhtp_assert(c != NULL);
HTP_FLAG_ON(c, EVHTP_CONN_FLAG_PAUSED);
bufferevent_disable(c->bev, EV_READ | EV_WRITE);
return;
}
should be
void
evhtp_connection_pause(evhtp_connection_t * c)
{
evhtp_assert(c != NULL);
HTP_FLAG_ON(c, EVHTP_CONN_FLAG_PAUSED);
bufferevent_disable(c->bev, EV_READ);
return;
}
Thoughts?
from libevhtp.
Pretty sure adding "Thoughts?" would upset the compiler quite a bit. =] Seriously though the suggested changes look good to me. This is more or less the patch i'v been using up until a few days ago. Rearranging the htp__hook_connection_write_(conn); would make more sense as well. After digesting all the information provided.
This is probably what should have occurred in 1.2.9 --> 1.2.10, but its hard to say because of how much the code has changed and how long ago I read that very detailed bug report on why it was done in the first place.(memory a bit spotty on the issue that user was having) Pretty sure it was lost with the project transfer, would have been nice to take another look at it. =/
I didn't expect the rearranging to break anything, but I'v had bad experiences with these assumptions so ran a quick test. Everything looks to be in order.
Thank you for digging into this issue.
from libevhtp.
Merged your pull request. Thanks for that. Hopefully, that fixes things. I tested, and nothing went wrong.
Cheers!
from libevhtp.
That's great news! When do you think you'll be tagging a new release?
from libevhtp.
https://github.com/criticalstack/libevhtp/releases/tag/1.2.16
And that's a wrap!
from libevhtp.
Related Issues (20)
- Q: how to peek at incoming http requests in pipelined mode
- Q: Is it safe to operate the same request between different threads? HOT 1
- use evbuffer_add_reference send json data have a problem HOT 2
- how to build libevhtp on windows
- Log.c is not cross-platform file.
- Empty pkgconfig libdir
- Inconsistency between EVHTP_BUILD_SHARED and BUILD_SHARED_LIBS CMake options HOT 2
- How to use multithreading HOT 5
- multiple nc request in keepalive fails to increase keepalive count HOT 1
- Does libevhtp support https? If support, what is the tps of http and https with keepalive or non-keepalive?
- Migrating from ev_http: How to get the socket for evhtp_accept_socket()? HOT 1
- Add example server with "1 thread per client connection"
- evhtp.c##htp__create_reply_() missed "buf = request->rc_scratch" after "request->rc_scratch = evbuffer_new()"?
- log-format $status is request status, not response status, why ?
- crash while invoking evhtp_connection_new() HOT 1
- Major slowdown using ssl and add_buffer(req->buffer_out,...) HOT 1
- Invalid content length value results in empty response
- info: libevhtp relies on onigposix.h, which is disabled in onig>=6.9.5_rev1 HOT 1
- Seperate http request thread and worker thread
- Is libevhtp support Server-send Events?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from libevhtp.