1 /** @file
2
3 A simple remap plugin for ATS
4
5 @section license License
6
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
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
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.
22
23 @section description
24 This is a very simple plugin: it will add headers that are specified on a remap line
25
26 Example usage:
27 map /foo http://127.0.0.1/ @plugin=remap_header_add.so @pparam=foo:"x" @pparam=@test:"c" @pparam=a:"b"
28
29 */
30 #include <cstdio>
31 #include <cstdlib>
32 #include <cstring>
33
34 #include "ts/ts.h"
35 #include "ts/remap.h"
36
37 struct remap_line {
38 int argc;
39 char **argv; // store the originals
40
41 int nvc; // the number of name value pairs, should be argc - 2.
42 char **name; // at load we will parse out the name and values.
43 char **val;
44 };
45
46 #define PLUGIN_NAME "headeradd_remap"
47 #define EXTERN extern "C"
48
49 EXTERN void
ParseArgIntoNv(const char * arg,char ** n,char ** v)50 ParseArgIntoNv(const char *arg, char **n, char **v)
51 {
52 const char *colon_pos = strchr(arg, ':');
53
54 if (colon_pos == nullptr) {
55 *n = nullptr;
56 *v = nullptr;
57 TSDebug(PLUGIN_NAME, "No name value pair since it was malformed");
58 return;
59 }
60
61 size_t name_len = colon_pos - arg;
62 *n = static_cast<char *>(TSmalloc(name_len + 1));
63 memcpy(*n, arg, colon_pos - arg);
64 (*n)[name_len] = '\0';
65
66 size_t val_len = strlen(colon_pos + 1); // skip past the ':'
67
68 // check to see if the value is quoted.
69 if (val_len > 1 && colon_pos[1] == '"' && colon_pos[val_len] == '"') {
70 colon_pos++; // advance past the first quote
71 val_len -= 2; // don't include the trailing quote
72 }
73
74 *v = static_cast<char *>(TSmalloc(val_len + 1));
75 memcpy(*v, colon_pos + 1, val_len);
76 (*v)[val_len] = '\0';
77
78 TSDebug(PLUGIN_NAME, "\t name_len=%zu, val_len=%zu, %s=%s", name_len, val_len, *n, *v);
79 }
80
81 TSReturnCode
TSRemapInit(TSRemapInterface *,char *,int)82 TSRemapInit(TSRemapInterface *, char *, int)
83 {
84 return TS_SUCCESS;
85 }
86
87 TSReturnCode
TSRemapNewInstance(int argc,char * argv[],void ** ih,char *,int)88 TSRemapNewInstance(int argc, char *argv[], void **ih, char *, int)
89 {
90 remap_line *rl = nullptr;
91
92 TSDebug(PLUGIN_NAME, "TSRemapNewInstance()");
93
94 if (!argv || !ih) {
95 TSError("[%s] Unable to load plugin because missing argv or ih", PLUGIN_NAME);
96 return TS_ERROR;
97 }
98
99 // print all arguments for this particular remapping
100
101 rl = static_cast<remap_line *>(TSmalloc(sizeof(remap_line)));
102 rl->argc = argc;
103 rl->argv = argv;
104 rl->nvc = argc - 2; // the first two are the remap from and to
105 if (rl->nvc) {
106 rl->name = static_cast<char **>(TSmalloc(sizeof(char *) * rl->nvc));
107 rl->val = static_cast<char **>(TSmalloc(sizeof(char *) * rl->nvc));
108 }
109
110 TSDebug(PLUGIN_NAME, "NewInstance:");
111 for (int i = 2; i < argc; i++) {
112 ParseArgIntoNv(argv[i], &rl->name[i - 2], &rl->val[i - 2]);
113 }
114
115 *ih = rl;
116
117 return TS_SUCCESS;
118 }
119
120 void
TSRemapDeleteInstance(void * ih)121 TSRemapDeleteInstance(void *ih)
122 {
123 TSDebug(PLUGIN_NAME, "deleting instance %p", ih);
124
125 if (ih) {
126 remap_line *rl = static_cast<remap_line *>(ih);
127 for (int i = 0; i < rl->nvc; ++i) {
128 TSfree(rl->name[i]);
129 TSfree(rl->val[i]);
130 }
131
132 TSfree(rl->name);
133 TSfree(rl->val);
134 TSfree(rl);
135 }
136 }
137
138 TSRemapStatus
TSRemapDoRemap(void * ih,TSHttpTxn txn,TSRemapRequestInfo * rri)139 TSRemapDoRemap(void *ih, TSHttpTxn txn, TSRemapRequestInfo *rri)
140 {
141 remap_line *rl = static_cast<remap_line *>(ih);
142
143 if (!rl || !rri) {
144 TSError("[%s] rl or rri is null", PLUGIN_NAME);
145 return TSREMAP_NO_REMAP;
146 }
147
148 TSDebug(PLUGIN_NAME, "TSRemapDoRemap:");
149
150 TSMBuffer req_bufp;
151 TSMLoc req_loc;
152 if (TSHttpTxnClientReqGet(txn, &req_bufp, &req_loc) != TS_SUCCESS) {
153 TSError("[%s] Error while retrieving client request header", PLUGIN_NAME);
154 return TSREMAP_NO_REMAP;
155 }
156
157 for (int i = 0; i < rl->nvc; ++i) {
158 TSDebug(PLUGIN_NAME, R"(Attaching header "%s" with value "%s".)", rl->name[i], rl->val[i]);
159
160 TSMLoc field_loc;
161 if (TSMimeHdrFieldCreate(req_bufp, req_loc, &field_loc) == TS_SUCCESS) {
162 TSMimeHdrFieldNameSet(req_bufp, req_loc, field_loc, rl->name[i], strlen(rl->name[i]));
163 TSMimeHdrFieldAppend(req_bufp, req_loc, field_loc);
164 TSMimeHdrFieldValueStringInsert(req_bufp, req_loc, field_loc, 0, rl->val[i], strlen(rl->val[i]));
165 } else {
166 TSError("[%s] Failure on TSMimeHdrFieldCreate", PLUGIN_NAME);
167 }
168 }
169
170 return TSREMAP_NO_REMAP;
171 }
172