Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions example/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ example_Plugins = \
blacklist_0.la \
blacklist_1.la \
bnull_transform.la \
request_buffer.la \
cache_scan.la \
file_1.la \
hello.la \
Expand Down Expand Up @@ -98,6 +99,7 @@ basic_auth_la_SOURCES = basic_auth/basic_auth.c
blacklist_0_la_SOURCES = blacklist_0/blacklist_0.c
blacklist_1_la_SOURCES = blacklist_1/blacklist_1.c
bnull_transform_la_SOURCES = bnull_transform/bnull_transform.c
request_buffer_la_SOURCES = request_buffer/request_buffer.c
cache_scan_la_SOURCES = cache_scan/cache_scan.cc
file_1_la_SOURCES = file_1/file_1.c
hello_la_SOURCES = hello/hello.c
Expand Down
148 changes: 148 additions & 0 deletions example/request_buffer/request_buffer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/** @file

A brief file description

@section license License

Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ts/ts.h"
#include "ts/ink_assert.h"
#include "ts/ink_defs.h"

#define PLUGIN_NAME "request_buffer"

#define TS_NULL_MUTEX NULL

static char *
request_body_get(TSHttpTxn txnp, int *len)
{
char *ret = NULL;
TSIOBufferReader post_buffer_reader = TSHttpTxnPostBufferReaderGet(txnp);
int64_t read_avail = TSIOBufferReaderAvail(post_buffer_reader);
if (read_avail == 0) {
TSIOBufferReaderFree(post_buffer_reader);
return NULL;
}

ret = (char *)TSmalloc(sizeof(char) * read_avail);

int64_t consumed = 0;
int64_t data_len = 0;
const char *char_data = NULL;
TSIOBufferBlock block = TSIOBufferReaderStart(post_buffer_reader);
while (block != NULL) {
char_data = TSIOBufferBlockReadStart(block, post_buffer_reader, &data_len);
memcpy(ret + consumed, char_data, data_len);
consumed += data_len;
block = TSIOBufferBlockNext(block);
}
TSIOBufferReaderFree(post_buffer_reader);

*len = (int)consumed;
return ret;
}

static int
request_buffer_plugin(TSCont contp, TSEvent event, void *edata)
{
TSDebug(PLUGIN_NAME, "request_buffer_plugin starting, event[%d]", event);
TSHttpTxn txnp = (TSHttpTxn)(edata);
if (event == TS_EVENT_HTTP_REQUEST_BUFFER_COMPLETE) {
int len = 0;
char *body = request_body_get(txnp, &len);
TSDebug(PLUGIN_NAME, "request_buffer_plugin gets the request body with length[%d]", len);
TSfree(body);
TSContDestroy(contp);
} else {
ink_assert(0);
}
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
return 0;
}

bool
is_post_request(TSHttpTxn txnp)
{
TSMLoc req_loc;
TSMBuffer req_bufp;
if (TSHttpTxnClientReqGet(txnp, &req_bufp, &req_loc) == TS_ERROR) {
TSError("Error while retrieving client request header\n");
return false;
}
int method_len = 0;
const char *method = TSHttpHdrMethodGet(req_bufp, req_loc, &method_len);
if (method_len != (int)strlen(TS_HTTP_METHOD_POST) || strncasecmp(method, TS_HTTP_METHOD_POST, method_len) != 0) {
TSHandleMLocRelease(req_bufp, TS_NULL_MLOC, req_loc);
return false;
}
TSHandleMLocRelease(req_bufp, TS_NULL_MLOC, req_loc);
return true;
}

static int
global_plugin(TSCont contp ATS_UNUSED, TSEvent event, void *edata)
{
TSDebug(PLUGIN_NAME, "transform_plugin starting");
TSHttpTxn txnp = (TSHttpTxn)edata;

switch (event) {
case TS_EVENT_HTTP_READ_REQUEST_HDR:
if (is_post_request(txnp)) {
TSHttpTxnConfigIntSet(txnp, TS_CONFIG_HTTP_REQUEST_BUFFER_ENABLED, 1);
TSHttpTxnHookAdd(txnp, TS_HTTP_REQUEST_BUFFER_READ_COMPLETE_HOOK, TSContCreate(request_buffer_plugin, TSMutexCreate()));
}
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
return 0;
default:
break;
}

return 0;
}

void
TSPluginInit(int argc ATS_UNUSED, const char *argv[] ATS_UNUSED)
{
TSPluginRegistrationInfo info;

info.plugin_name = PLUGIN_NAME;
info.vendor_name = "Apache Software Foundation";
info.support_email = "dev@trafficserver.apache.org";

if (TSPluginRegister(&info) != TS_SUCCESS) {
TSDebug(PLUGIN_NAME, "[%s] Plugin registration failed", PLUGIN_NAME);

goto Lerror;
}

/* This is call we could use if we need to protect global data */
/* TSReleaseAssert ((mutex = TSMutexCreate()) != TS_NULL_MUTEX); */

TSMutex mutex = TS_NULL_MUTEX;
TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(global_plugin, mutex));
TSDebug(PLUGIN_NAME, "[%s] Plugin registration succeeded", PLUGIN_NAME);
return;

Lerror:
TSDebug(PLUGIN_NAME, "[%s] Plugin disabled", PLUGIN_NAME);
}
3 changes: 3 additions & 0 deletions lib/ts/apidefs.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ typedef enum {
TS_SSL_SERVER_VERIFY_HOOK,
TS_SSL_SESSION_HOOK,
TS_SSL_LAST_HOOK = TS_SSL_SESSION_HOOK,
TS_HTTP_REQUEST_BUFFER_READ_COMPLETE_HOOK = 23,
TS_HTTP_LAST_HOOK
} TSHttpHookID;

Expand Down Expand Up @@ -451,6 +452,7 @@ typedef enum {
TS_EVENT_LIFECYCLE_CLIENT_SSL_CTX_INITIALIZED = 60022,
TS_EVENT_VCONN_PRE_ACCEPT = 60023,
TS_EVENT_LIFECYCLE_MSG = 60024,
TS_EVENT_HTTP_REQUEST_BUFFER_COMPLETE = 60025,
TS_EVENT_MGMT_UPDATE = 60100,
TS_EVENT_INTERNAL_60200 = 60200,
TS_EVENT_INTERNAL_60201 = 60201,
Expand Down Expand Up @@ -764,6 +766,7 @@ typedef enum {
TS_CONFIG_HTTP_NORMALIZE_AE,
TS_CONFIG_HTTP_INSERT_FORWARDED,
TS_CONFIG_HTTP_ALLOW_MULTI_RANGE,
TS_CONFIG_HTTP_REQUEST_BUFFER_ENABLED,
TS_CONFIG_LAST_ENTRY
} TSOverridableConfigKey;

Expand Down
2 changes: 2 additions & 0 deletions plugins/experimental/ts_lua/ts_lua_http_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ typedef enum {
TS_LUA_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS = TS_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS,
TS_LUA_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT = TS_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT,
TS_LUA_CONFIG_HTTP_ALLOW_MULTI_RANGE = TS_CONFIG_HTTP_ALLOW_MULTI_RANGE,
TS_LUA_CONFIG_HTTP_REQUEST_BUFFER_ENABLED = TS_CONFIG_HTTP_REQUEST_BUFFER_ENABLED,
TS_LUA_CONFIG_LAST_ENTRY = TS_CONFIG_LAST_ENTRY,
} TSLuaOverridableConfigKey;

Expand Down Expand Up @@ -258,6 +259,7 @@ ts_lua_var_item ts_lua_http_config_vars[] = {
TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_PER_PARENT_CONNECT_ATTEMPTS),
TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_PARENT_CONNECT_ATTEMPT_TIMEOUT),
TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_ALLOW_MULTI_RANGE),
TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_REQUEST_BUFFER_ENABLED),
TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_LAST_ENTRY),
};

Expand Down
13 changes: 13 additions & 0 deletions proxy/InkAPI.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8114,6 +8114,9 @@ _conf_to_memberp(TSOverridableConfigKey conf, OverridableHttpConfigParams *overr
case TS_CONFIG_HTTP_POST_CHECK_CONTENT_LENGTH_ENABLED:
ret = _memberp_to_generic(&overridableHttpConfig->post_check_content_length_enabled, typep);
break;
case TS_CONFIG_HTTP_REQUEST_BUFFER_ENABLED:
ret = _memberp_to_generic(&overridableHttpConfig->request_buffer_enabled, typep);
break;
case TS_CONFIG_HTTP_GLOBAL_USER_AGENT_HEADER:
ret = _memberp_to_generic(&overridableHttpConfig->global_user_agent_header, typep);
break;
Expand Down Expand Up @@ -8594,6 +8597,8 @@ TSHttpTxnConfigFind(const char *name, int length, TSOverridableConfigKey *conf,
case 'd':
if (!strncmp(name, "proxy.config.http.forward_connect_method", length)) {
cnf = TS_CONFIG_HTTP_FORWARD_CONNECT_METHOD;
} else if (!strncmp(name, "proxy.config.http.request_buffer_enabled", length)) {
cnf = TS_CONFIG_HTTP_REQUEST_BUFFER_ENABLED;
}
break;
case 'e':
Expand Down Expand Up @@ -9629,3 +9634,11 @@ TSRemapToUrlGet(TSHttpTxn txnp, TSMLoc *urlLocp)
{
return remapUrlGet(txnp, urlLocp, &UrlMappingContainer::getToURL);
}

tsapi TSIOBufferReader
TSHttpTxnPostBufferReaderGet(TSHttpTxn txnp)
{
sdk_assert(sdk_sanity_check_txn(txnp) == TS_SUCCESS);
HttpSM *sm = (HttpSM *)txnp;
return (TSIOBufferReader)sm->get_postbuf_clone_reader();
}
6 changes: 4 additions & 2 deletions proxy/InkAPITest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5545,7 +5545,8 @@ typedef enum {
ORIG_TS_SSL_SERVERNAME_HOOK,
ORIG_TS_SSL_SERVER_VERIFY_HOOK,
ORIG_TS_SSL_SESSION_HOOK,
ORIG_TS_SSL_LAST_HOOK = ORIG_TS_SSL_SESSION_HOOK,
ORIG_TS_SSL_LAST_HOOK = ORIG_TS_SSL_SESSION_HOOK,
ORIG_TS_HTTP_REQUEST_BUFFER_READ_COMPLETE_HOOK = 23,
ORIG_TS_HTTP_LAST_HOOK
} ORIG_TSHttpHookID;

Expand Down Expand Up @@ -7603,7 +7604,8 @@ const char *SDK_Overridable_Configs[TS_CONFIG_LAST_ENTRY] = {"proxy.config.url_r
"proxy.config.http.parent_proxy.connect_attempts_timeout",
"proxy.config.http.normalize_ae",
"proxy.config.http.insert_forwarded",
"proxy.config.http.allow_multi_range"};
"proxy.config.http.allow_multi_range",
"proxy.config.http.request_buffer_enabled"};

REGRESSION_TEST(SDK_API_OVERRIDABLE_CONFIGS)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
{
Expand Down
5 changes: 5 additions & 0 deletions proxy/api/ts/ts.h
Original file line number Diff line number Diff line change
Expand Up @@ -2460,6 +2460,11 @@ tsapi TSReturnCode TSRemapFromUrlGet(TSHttpTxn txnp, TSMLoc *urlLocp);
//
tsapi TSReturnCode TSRemapToUrlGet(TSHttpTxn txnp, TSMLoc *urlLocp);

/*
* Get a TSIOBufferReader to read the buffered body. The return value needs to be freed.
*/
tsapi TSIOBufferReader TSHttpTxnPostBufferReaderGet(TSHttpTxn txnp);

#ifdef __cplusplus
}
#endif /* __cplusplus */
Expand Down
3 changes: 3 additions & 0 deletions proxy/http/HttpConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,7 @@ HttpConfig::startup()
HttpEstablishStaticConfigLongLong(c.oride.flow_high_water_mark, "proxy.config.http.flow_control.high_water");
HttpEstablishStaticConfigLongLong(c.oride.flow_low_water_mark, "proxy.config.http.flow_control.low_water");
HttpEstablishStaticConfigByte(c.oride.post_check_content_length_enabled, "proxy.config.http.post.check.content_length.enabled");
HttpEstablishStaticConfigByte(c.oride.request_buffer_enabled, "proxy.config.http.request_buffer_enabled");
HttpEstablishStaticConfigByte(c.strict_uri_parsing, "proxy.config.http.strict_uri_parsing");

// [amc] This is a bit of a mess, need to figure out to make this cleaner.
Expand Down Expand Up @@ -1247,6 +1248,8 @@ HttpConfig::reconfigure()

params->oride.post_check_content_length_enabled = INT_TO_BOOL(m_master.oride.post_check_content_length_enabled);

params->oride.request_buffer_enabled = INT_TO_BOOL(m_master.oride.request_buffer_enabled);

params->oride.flow_control_enabled = INT_TO_BOOL(m_master.oride.flow_control_enabled);
params->oride.flow_high_water_mark = m_master.oride.flow_high_water_mark;
params->oride.flow_low_water_mark = m_master.oride.flow_low_water_mark;
Expand Down
6 changes: 6 additions & 0 deletions proxy/http/HttpConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ struct OverridableHttpConfigParams {
parent_failures_update_hostdb(0),
cache_open_write_fail_action(0),
post_check_content_length_enabled(1),
request_buffer_enabled(0),
ssl_client_verify_server(0),
redirect_use_orig_cache_key(0),
number_of_redirections(0),
Expand Down Expand Up @@ -624,6 +625,11 @@ struct OverridableHttpConfigParams {
////////////////////////
MgmtByte post_check_content_length_enabled;

////////////////////////////////////////////////
// Buffer post body before connecting servers //
////////////////////////////////////////////////
MgmtByte request_buffer_enabled;

/////////////////////////////
// server verification mode//
/////////////////////////////
Expand Down
6 changes: 6 additions & 0 deletions proxy/http/HttpDebugNames.cc
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,10 @@ HttpDebugNames::get_action_name(HttpTransact::StateMachineAction_t e)
return ("SM_ACTION_DRAIN_REQUEST_BODY");
#endif /* PROXY_DRAIN */

case HttpTransact::SM_ACTION_WAIT_FOR_FULL_BODY:
return ("SM_ACTION_WAIT_FOR_FULL_BODY");
case HttpTransact::SM_ACTION_REQUEST_BUFFER_READ_COMPLETE:
return ("SM_ACTION_REQUEST_BUFFER_READ_COMPLETE");
case HttpTransact::SM_ACTION_API_SM_START:
return ("SM_ACTION_API_SM_START");
case HttpTransact::SM_ACTION_REDIRECT_READ:
Expand Down Expand Up @@ -438,6 +442,8 @@ HttpDebugNames::get_api_hook_name(TSHttpHookID t)
return "TS_HTTP_SEND_RESPONSE_HDR_HOOK";
case TS_HTTP_REQUEST_TRANSFORM_HOOK:
return "TS_HTTP_REQUEST_TRANSFORM_HOOK";
case TS_HTTP_REQUEST_BUFFER_READ_COMPLETE_HOOK:
return "TS_HTTP_REQUEST_BUFFER_READ_COMPLETE_HOOK";
case TS_HTTP_RESPONSE_TRANSFORM_HOOK:
return "TS_HTTP_RESPONSE_TRANSFORM_HOOK";
case TS_HTTP_SELECT_ALT_HOOK:
Expand Down
Loading