3
A brief file description
5
@section license License
7
Licensed to the Apache Software Foundation (ASF) under one
8
or more contributor license agreements. See the NOTICE file
9
distributed with this work for additional information
10
regarding copyright ownership. The ASF licenses this file
11
to you under the Apache License, Version 2.0 (the
12
"License"); you may not use this file except in compliance
13
with the License. You may obtain a copy of the License at
15
http://www.apache.org/licenses/LICENSE-2.0
17
Unless required by applicable law or agreed to in writing, software
18
distributed under the License is distributed on an "AS IS" BASIS,
19
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
See the License for the specific language governing permissions and
21
limitations under the License.
26
* an example program which redirects clients based on the source IP
30
* (NT): Redirect.dll block_ip url_redirect
31
* (Solaris): redirect-1.so block_ip url_redirect
40
# include <netinet/in.h>
41
# include <arpa/inet.h>
49
static in_addr_t ip_deny;
51
static unsigned int ip_deny;
55
* uncoupled statistics variables:
57
static TSStat method_count_redirected_connect;
58
static TSStat method_count_redirected_delete;
59
static TSStat method_count_redirected_get;
60
static TSStat method_count_redirected_head;
61
static TSStat method_count_redirected_icp_query;
62
static TSStat method_count_redirected_options;
63
static TSStat method_count_redirected_post;
64
static TSStat method_count_redirected_purge;
65
static TSStat method_count_redirected_put;
66
static TSStat method_count_redirected_trace;
67
static TSStat method_count_redirected_unknown;
71
* coupled statistics variables:
72
* coupled stat category for the following stats
73
* is request_outcomes. The relationship among the stats is:
74
* requests_all = requests_redirects + requests_unchanged
76
static TSCoupledStat request_outcomes;
77
static TSStat requests_all;
78
static TSStat requests_redirects;
79
static TSStat requests_unchanged;
82
void update_redirected_method_stats(TSMBuffer bufp, TSMLoc hdr_loc);
84
static char *url_redirect;
85
static char *uri_redirect;
86
static char *block_ip;
88
#define PLUGIN_NAME "redirect-1-neg"
89
#define LOG_SET_FUNCTION_NAME(NAME) const char * FUNCTION_NAME = NAME
91
#define LOG_ERROR_NEG(API_NAME) { \
92
TSDebug(PLUGIN_NAME, "%s: %s %s %s File %s, line number %d",PLUGIN_NAME, API_NAME, "NEGAPIFAIL", \
93
FUNCTION_NAME, __FILE__, __LINE__); \
97
handle_client_lookup(TSHttpTxn txnp, TSCont contp)
100
TSMLoc hdr_loc, url_loc;
103
#if !defined (_WIN32)
106
unsigned int clientip;
111
struct in_addr tempstruct;
114
* Here we declare local coupled statistics variables:
116
TSCoupledStat local_request_outcomes;
117
TSStat local_requests_all;
118
TSStat local_requests_redirects;
119
TSStat local_requests_unchanged;
121
LOG_SET_FUNCTION_NAME("handle_client_lookup");
124
* Create local copy of the global coupled stat category:
126
local_request_outcomes = TSStatCoupledLocalCopyCreate("local_request_outcomes", request_outcomes);
130
* Create the local copies of the global coupled stats:
132
local_requests_all = TSStatCoupledLocalAdd(local_request_outcomes, "requests.all.local", TSSTAT_TYPE_FLOAT);
133
local_requests_redirects = TSStatCoupledLocalAdd(local_request_outcomes,
134
"requests.redirects.local", TSSTAT_TYPE_INT64);
135
local_requests_unchanged = TSStatCoupledLocalAdd(local_request_outcomes,
136
"requests.unchanged.local", TSSTAT_TYPE_INT64);
140
* Increment the count of total requests:
141
* (it is more natural to treat the number of requests as an
142
* integer, but we declare this a FLOAT in order to demonstrate
143
* how to increment coupled FLOAT stats)
145
TSStatFloatAddTo(local_requests_all, 1.0);
149
if (TSStatCoupledLocalCopyCreate(NULL, request_outcomes) != TS_ERROR_PTR) {
150
LOG_ERROR_NEG("TSStatCoupledLocalCopyCreate");
152
if (TSStatCoupledLocalCopyCreate("my_local_copy", NULL) != TS_ERROR_PTR) {
153
LOG_ERROR_NEG("TSStatCoupledLocalCopyCreate");
156
if (TSStatCoupledLocalAdd(NULL, "requests.negtest", TSSTAT_TYPE_INT64) != TS_ERROR_PTR) {
157
LOG_ERROR_NEG("TSStatCoupledLocalAdd");
159
if (TSStatCoupledLocalAdd(local_request_outcomes, NULL, TSSTAT_TYPE_INT64) != TS_ERROR_PTR) {
160
LOG_ERROR_NEG("TSStatCoupledLocalAdd");
163
if (TSStatFloatAddTo(NULL, 1.0) != TS_ERROR) {
164
LOG_ERROR_NEG("TSStatFloatAddTo");
167
if (TSHttpTxnClientIPGet(NULL) != 0) {
168
LOG_ERROR_NEG("TSHttpTxnClientIPGet");
172
#if !defined (_WIN32)
173
clientip = (in_addr_t) TSHttpTxnClientIPGet(txnp);
175
clientip = TSHttpTxnClientIPGet(txnp);
178
tempstruct.s_addr = clientip;
179
clientstring = inet_ntoa(tempstruct);
180
TSDebug("redirect", "clientip is %s and block_ip is %s", clientstring, block_ip);
182
if (!TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc)) {
183
TSError("couldn't retrieve client request header\n");
187
url_loc = TSHttpHdrUrlGet(bufp, hdr_loc);
189
TSError("couldn't retrieve request url\n");
190
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
194
host = TSUrlHostGet(bufp, url_loc, &host_length);
196
TSError("couldn't retrieve request hostname\n");
197
TSHandleMLocRelease(bufp, hdr_loc, url_loc);
198
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
203
* Check to see if the client is already headed to the redirect site.
205
if (strncmp(host, url_redirect, host_length) == 0) {
206
TSHandleMLocRelease(bufp, hdr_loc, url_loc);
207
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
211
if (ip_deny == clientip) {
213
TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
215
update_redirected_method_stats(bufp, hdr_loc);
217
TSHandleMLocRelease(bufp, hdr_loc, url_loc);
218
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
221
* Increment the local redirect stat and do global update:
223
TSStatIncrement(local_requests_redirects);
224
TSStatsCoupledUpdate(local_request_outcomes);
225
TSStatCoupledLocalCopyDestroy(local_request_outcomes);
227
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
233
* Increment the local number unchanged stat and do global update:
235
TSStatIncrement(local_requests_unchanged);
236
TSStatsCoupledUpdate(local_request_outcomes);
237
TSStatCoupledLocalCopyDestroy(local_request_outcomes);
241
if (TSStatsCoupledUpdate(NULL) != TS_ERROR) {
242
LOG_ERROR_NEG("TSStatsCoupledUpdate");
244
if (TSStatCoupledLocalCopyDestroy(NULL) != TS_ERROR) {
245
LOG_ERROR_NEG("TSStatCoupledLocalCopyDestroy");
249
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
255
handle_response(TSHttpTxn txnp)
258
TSMLoc hdr_loc, newfield_loc;
262
char *errormsg_body = "All requests from this IP address are redirected.\n";
265
if (!TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc)) {
266
TSError("couldn't retrieve client response header\n");
270
TSHttpHdrStatusSet(bufp, hdr_loc, TS_HTTP_STATUS_MOVED_PERMANENTLY);
271
TSHttpHdrReasonSet(bufp, hdr_loc,
272
TSHttpHdrReasonLookup(TS_HTTP_STATUS_MOVED_PERMANENTLY),
273
strlen(TSHttpHdrReasonLookup(TS_HTTP_STATUS_MOVED_PERMANENTLY)));
275
newfield_loc = TSMimeHdrFieldCreate(bufp, hdr_loc);
276
TSMimeHdrFieldNameSet(bufp, hdr_loc, newfield_loc, TS_MIME_FIELD_LOCATION, TS_MIME_LEN_LOCATION);
277
TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, newfield_loc, uri_redirect, strlen(uri_redirect), -1);
278
TSMimeHdrFieldAppend(bufp, hdr_loc, newfield_loc);
282
* Note that we can't directly use errormsg_body, as TSHttpTxnErrorBodySet()
283
* will try to free the passed buffer with TSfree().
285
tmp_body = TSstrdup(errormsg_body);
286
TSHttpTxnErrorBodySet(txnp, tmp_body, strlen(tmp_body), NULL);
287
TSHandleMLocRelease(bufp, hdr_loc, newfield_loc);
288
TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
292
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
298
redirect_plugin(TSCont contp, TSEvent event, void *edata)
301
TSHttpTxn txnp = (TSHttpTxn) edata;
304
case TS_EVENT_HTTP_READ_REQUEST_HDR:
306
handle_client_lookup(txnp, contp);
309
case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
311
handle_response(txnp);
324
* Global statistics functions:
330
LOG_SET_FUNCTION_NAME("init_stats");
333
method_count_redirected_connect = TSStatCreate("method.count.redirected.connect", TSSTAT_TYPE_INT64);
334
method_count_redirected_delete = TSStatCreate("method.count.redirected.delete", TSSTAT_TYPE_INT64);
335
method_count_redirected_get = TSStatCreate("method.count.redirected.get", TSSTAT_TYPE_INT64);
336
method_count_redirected_head = TSStatCreate("method.count.redirected.head", TSSTAT_TYPE_FLOAT);
337
method_count_redirected_icp_query = TSStatCreate("method.count.redirected.icp_query", TSSTAT_TYPE_FLOAT);
338
method_count_redirected_options = TSStatCreate("method.count.redirected.options", TSSTAT_TYPE_INT64);
339
method_count_redirected_post = TSStatCreate("method.count.redirected.post", TSSTAT_TYPE_INT64);
340
method_count_redirected_purge = TSStatCreate("method.count.redirected.purge", TSSTAT_TYPE_INT64);
341
method_count_redirected_put = TSStatCreate("method.count.redirected.put", TSSTAT_TYPE_INT64);
342
method_count_redirected_trace = TSStatCreate("method.count.redirected.trace", TSSTAT_TYPE_INT64);
343
method_count_redirected_unknown = TSStatCreate("method.count.redirected.unknown", TSSTAT_TYPE_INT64);
346
request_outcomes = TSStatCoupledGlobalCategoryCreate("request_outcomes");
347
requests_all = TSStatCoupledGlobalAdd(request_outcomes, "requests.all", TSSTAT_TYPE_FLOAT);
348
requests_redirects = TSStatCoupledGlobalAdd(request_outcomes, "requests.redirects", TSSTAT_TYPE_INT64);
349
requests_unchanged = TSStatCoupledGlobalAdd(request_outcomes, "requests.unchanged", TSSTAT_TYPE_INT64);
353
if (TSStatCoupledGlobalCategoryCreate(NULL) != TS_ERROR_PTR) {
354
LOG_ERROR_NEG("TSStatCoupledGlobalCategoryCreate");
357
if (TSStatCoupledGlobalAdd(NULL, "requests.mytest", TSSTAT_TYPE_INT64) != TS_ERROR_PTR) {
358
LOG_ERROR_NEG("TSStatCoupledGlobalAdd");
360
if (TSStatCoupledGlobalAdd(request_outcomes, NULL, TSSTAT_TYPE_INT64) != TS_ERROR_PTR) {
361
LOG_ERROR_NEG("TSStatCoupledGlobalAdd");
367
* This function is only called for redirected requests. It illustrates
368
* several different ways of updating INT64 stats. Some may consider
369
* the particular use of TSDecrementStat() shown below somewhat contrived.
372
update_redirected_method_stats(TSMBuffer bufp, TSMLoc hdr_loc)
374
const char *txn_method;
378
LOG_SET_FUNCTION_NAME("update_redirected_method_stats");
380
txn_method = TSHttpHdrMethodGet(bufp, hdr_loc, &length);
382
if (NULL != txn_method) {
383
if (0 == strncmp(txn_method, TS_HTTP_METHOD_CONNECT, length))
384
TSStatIncrement(method_count_redirected_connect);
385
else if (0 == strncmp(txn_method, TS_HTTP_METHOD_DELETE, length))
386
TSStatIncrement(method_count_redirected_delete);
387
else if (0 == strncmp(txn_method, TS_HTTP_METHOD_GET, length))
388
TSStatIncrement(method_count_redirected_get);
390
else if (0 == strncmp(txn_method, TS_HTTP_METHOD_HEAD, length))
391
TSStatFloatAddTo(method_count_redirected_head, 1);
392
else if (0 == strncmp(txn_method, TS_HTTP_METHOD_ICP_QUERY, length))
393
TSStatFloatAddTo(method_count_redirected_icp_query, 1);
395
else if (0 == strncmp(txn_method, TS_HTTP_METHOD_OPTIONS, length)) {
396
TSStatIntGet(method_count_redirected_options, tempint);
398
TSStatIntSet(method_count_redirected_options, tempint);
399
} else if (0 == strncmp(txn_method, TS_HTTP_METHOD_POST, length)) {
400
TSStatDecrement(method_count_redirected_post);
401
TSStatIncrement(method_count_redirected_post);
402
TSStatIncrement(method_count_redirected_post);
405
else if (0 == strncmp(txn_method, TS_HTTP_METHOD_PURGE, length))
406
TSStatIncrement(method_count_redirected_purge);
407
else if (0 == strncmp(txn_method, TS_HTTP_METHOD_PUT, length))
408
TSStatIncrement(method_count_redirected_put);
409
else if (0 == strncmp(txn_method, TS_HTTP_METHOD_TRACE, length))
410
TSStatIncrement(method_count_redirected_trace);
412
TSStatIncrement(method_count_redirected_unknown);
417
if (TSStatIntSet(NULL, 0) != TS_ERROR) {
418
LOG_ERROR_NEG("TSStatIntSet");
421
if (TSStatDecrement(NULL) != TS_ERROR) {
422
LOG_ERROR_NEG("TSStatDecrement");
432
const char *ts_version = TSTrafficServerVersionGet();
436
int major_ts_version = 0;
437
int minor_ts_version = 0;
438
int patch_ts_version = 0;
440
if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
444
/* Since this is an TS-SDK 2.0 plugin, we need at
445
least Traffic Server 2.0 to run */
446
if (major_ts_version >= 2) {
455
TSPluginInit(int argc, const char *argv[])
457
const char prefix[] = "http://";
459
TSPluginRegistrationInfo info;
461
info.plugin_name = "redirect-1";
462
info.vendor_name = "MyCompany";
463
info.support_email = "ts-api-support@MyCompany.com";
465
if (!TSPluginRegister(TS_SDK_VERSION_3_0, &info)) {
466
TSError("Plugin registration failed.\n");
469
if (!check_ts_version()) {
470
TSError("Plugin requires Traffic Server 3.0 or later\n");
475
block_ip = TSstrdup(argv[1]);
478
* The Location header must contain an absolute URI:
481
url_redirect = TSstrdup(argv[2]);
482
uri_len = strlen(prefix) + strlen(url_redirect) + 1;
483
uri_redirect = TSmalloc(uri_len);
484
strcpy(uri_redirect, prefix);
485
strcat(uri_redirect, url_redirect);
488
TSError("Incorrect syntax in plugin.conf: correct usage is" "redirect-1.so ip_deny url_redirect");
492
ip_deny = inet_addr(block_ip);
494
TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(redirect_plugin, NULL));
496
TSDebug("redirect_init", "block_ip is %s, url_redirect is %s, and uri_redirect is %s",
497
block_ip, url_redirect, uri_redirect);
498
TSDebug("redirect_init", "ip_deny is %ld\n", ip_deny);
500
TSDebug("redirect_init", "initializing stats...");
505
* Demonstrate another tracing function. This can be used to
506
* enable debug calculations and other work that should only
507
* be done in debug mode.
510
if (TSIsDebugTagSet("redirect_demo"))
511
TSDebug("redirect_init", "The redirect_demo tag is set");
513
TSDebug("redirect_init", "The redirect_demo tag is not set");