-
Notifications
You must be signed in to change notification settings - Fork 844
TS-4042: Add feature to buffer request body before making downstream requests #2335
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
|
TS_CONFIG_HTTP_REQUEST_BUFFER_ENABLED is added to ts_lua and InkAPITest. The build issue is gone. |
98d73a4 to
5fc5c68
Compare
|
@scw00 thanks for reminding me. Regression tests now should be okay. |
|
Did you take a look at plugins/experimental/buffer_upload ? There is a plugins handles this. In TSHttpTxnGetClientRequestBody you are doubling the memory foot print creating a copy of the buffer. This looks like a potential DOS. |
|
I'm pretty concerned about this concept in general, it seems like as implemented, it'd be near trivial to kill any server that accepts a POST with this buffering enabled. You will consume 2x the memory that the user POSTed ( (for some amount of time), right? Also, how is this different / better than the existing buffer_upload plugin? |
|
I did some investigation on the buffer_upload plugin and which is better between it and this PR. How does upload_buffer work? upload_buffer calls How does this PR work? At the beginning of HttpTransact::HandleRequest, ATS core injects a new state called The upload_buffer plugin is super cool. Its advantage is that it's a plugin so no ATS core changes are required. This PR tries to solve the issue that how to enable a plugin read the request body before opening connections to the server. The way to implement it is a bit "twisted" but I think upload_buffer is at least double the twistedness. @bryancall @zwoop What do you guys think? |
|
Currently the HttpTunnel can not decode the Chunked data into TransformVC. @zizhong Do you have any idea to handle the Chunked data in HttpTunnel ? Can we implement the decoding support depending on this PR ? |
|
@zizhong There is a timeout problem. client ----[high speed link]---> ATS -------[low speed link]------> OServer
|
|
@oknet Thanks for your comments. Let me look into them. |
|
@bryancall @zwoop @oknet Before jumping into fixing you guys' comments, I want to make sure that we're on the same page that this RB is more acceptable than the solution of using |
|
Do u have read the below code ? These code implement a feature:
It is very similar to this PR. |
|
@oknet Yep, you're right. They both have the post buffer functionality. Please feel free to share your idea about this with me. Thanks! |
|
ping on this one! @bryancall @zwoop @oknet Your opinions matter a lot to this project!
|
|
Slow-post attack is a type of Slowloris from #1237 |
| alloc_index = DEFAULT_REQUEST_BUFFER_SIZE_INDEX; | ||
| } | ||
| } else { | ||
| alloc_index = buffer_size_to_index(t_state.hdr_info.request_content_length); |
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 will block the iocore when a flood attack with a larger content-length.
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.
which is also true for the original SM?
proxy/http/HttpSM.cc
Outdated
| } | ||
| MIOBuffer *post_buffer = new_MIOBuffer(alloc_index); | ||
| IOBufferReader *buf_start = post_buffer->alloc_reader(); | ||
| int64_t post_bytes = chunked ? INT64_MAX : t_state.hdr_info.request_content_length; |
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.
A chunked request may include the content-length header.
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.
http://greenbytes.de/tech/webdav/rfc2616.html#rfc.section.4.4.p.5
Messages must not include both a Content-Length header field and a non-identity transfer-coding. If the message does include a non-identity transfer-coding, the Content-Length must be ignored.
In that case, the request buffer is probably better not to be enabled. This functionality is intended to solve the scenario as below.
|
|
@bryancall @zwoop @oknet @SolidWallOfCode @maskit @scw00 I added test about how ATS handles slow post attacks. This is the main reason we're trying to push this functionality out. It's a huge security flaw now that we don't have it as a protection. |
|
The So the next step may be:
|
|
Thanks @oknet for your valuable comments! I'll look into them asap. |
|
@oknet Are you saying that the postbuf in the HttpSM could be reused for buffering before connecting to the origin? |
|
@bryancall yes, because the postbuf is managed by HttpSM now. |
|
@zizhong I would prefer it if you can use the postbuf in the HttpSM. For new APIs we need to have docs in the PR and an email will need to be set to de dev@ mailing list with this information: |
|
@bryancall @oknet Thanks! Will apply the |
|
[approve ci] |
zwoop
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.
I'm still not 100% sold on this, but I guess someone can just choose not to use it. The memory usage for this seems potentially very high.
proxy/InkAPI.cc
Outdated
| } | ||
|
|
||
| tsapi char * | ||
| TSHttpTxnGetClientRequestBody(TSHttpTxn txnp, int *len) |
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 should be TSHttpTxnClientReqBodyGet() . 1) Get() at the end, and 2) bcall pointed out that we have a TSHttpTxnClientReqGet().
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.
Thanks, zwoop.
|
updated.
@zwoop @bryancall @scw00 @oknet @maskit please take a look again! |
|
[approve ci] |
proxy/InkAPI.cc
Outdated
| tsapi char * | ||
| TSHttpTxnGetClientRequestBody(TSHttpTxn txnp, int *len) | ||
| { | ||
| char *ret = NULL; |
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.
Use nullptr instead of NULL
proxy/InkAPI.cc
Outdated
| } | ||
|
|
||
| tsapi char * | ||
| TSHttpTxnGetClientRequestBody(TSHttpTxn txnp, int *len) |
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.
How do you plan to use the API? You are read the post body, but what are you going to be doing with it, since you can't modify 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.
There are two use cases for us currently.
- preventing slow post attack, which doesn't require this API;
- redirecting based on post body, which uses this API to get the body.
I can see modifying the body is useful. If you think the functionally is necessary for this PR, I can work on it and add it here.
proxy/InkAPI.cc
Outdated
| } | ||
|
|
||
| tsapi char * | ||
| TSHttpTxnClientReqBodyGet(TSHttpTxn txnp, int *len) |
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 think we it would be more flexible to return a TSIOBufferReader and do the copying of the bytes in the plugin instead of doing it here.
Using the external APIs in internal code means that either we should be exposing more of the underlying implementation or using the internal APIs directly.
The API could be redone to be something like:
TSIOBufferReader TSIOBufferReaderPostGet() {
sdk_assert(sdk_sanity_check_txn(txnp) == TS_SUCCESS);
HttpSM *sm = (HttpSM *)txnp;
return (TSIOBufferReader)sm->get_postbuf_clone_reader();
}
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.
Thanks! Sounds reasonable. Will change it.
|
@bryancall updated as you suggested |
|
@zizhong Thanks for the update. Looks good to me. Can you shoot an email to dev@ on the updated API? If no one objects, I will merge it. |
|
@bryancall Will do. Thanks! |
|
[approve ci] |
|
Please rename the API to TSHttpTxnPostBufferReaderGet as discussed on the mailing list. |
|
@bryancall Thanks! updated. |
This is bug introduced with PR apache#2335. The `if` is to avoid unnecessary works when buffering the post body, but since redirects also need to execute the logic flow and the request info may be changed during the process of redirects. We need to extract the request info every time redirects happen.
This is a bug introduced with PR apache#2335. The `if` is to avoid unnecessary works when buffering the post body, but since redirects also need to execute the logic flow and the request info may be changed during the process of redirects. We need to extract the request info every time redirects happen.
This is a bug introduced with PR #2335. The `if` is to avoid unnecessary works when buffering the post body, but since redirects also need to execute the logic flow and the request info may be changed during the process of redirects. We need to extract the request info every time redirects happen.
This is a rework on PR#351.
Why do we want this feature? (statements below copied from the old PR)
The main difference between the new PR and the old one is the way to achieve reading request body.
The old PR calls do_io_read() directly and duplicates a
chunked handler, which is kind of implementing read part ofHttpTunnelfrom scratch.The new PR reuses
HttpTunnel. This requires theHttpTunnelto supportno consumer modeand correctly resume from it.This PR includes ATS core changes, a C API and a C plugin.
I will add C++ API and C++ plugin example. I'll write some other plugins which make a better demonstration.
Locally I wrote several Python test cases and I'll try to convert it to autests.
And I'll try my best to keep each commits small and clear.
In summary, my current todo list:
@bryancall @zwoop @jpeach @SolidWallOfCode @maskit @scw00 @oknet @bgaff Please review this if you'd like to. Any ideas would be appreciated.