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.
25
* response-header-1.c:
26
* an example program which illustrates adding and manipulating
27
* an HTTP response MIME header:
29
* Authorized possession and use of this software pursuant only
30
* to the terms of a written license agreement.
32
* Usage: response-header-1.so
34
* add read_resp_header hook
35
* get http response header
37
* add mime extension header with count of zero
38
* add mime extension header with date response was received
39
* add "Cache-Control: public" header
41
* retrieve cached header
42
* get old value of mime header count
43
* increment mime header count
44
* store mime header with new count
56
static int init_buffer_status;
58
static char *mimehdr1_name;
59
static char *mimehdr2_name;
60
static char *mimehdr1_value;
62
static TSMBuffer hdr_bufp;
63
static TSMLoc hdr_loc;
65
static TSMLoc field_loc;
66
static TSMLoc value_loc;
69
modify_header(TSHttpTxn txnp, TSCont contp)
72
TSMBuffer cached_bufp;
75
TSHttpStatus resp_status;
77
TSMLoc cached_field_loc;
83
int num_refreshes = 0;
85
if (!init_buffer_status)
86
return; /* caller reenables */
88
if (!TSHttpTxnServerRespGet(txnp, &resp_bufp, &resp_loc)) {
89
TSError("couldn't retrieve server response header\n");
90
return; /* caller reenables */
93
/* TSqa06246/TSqa06144 */
94
resp_status = TSHttpHdrStatusGet(resp_bufp, resp_loc);
96
if (TS_HTTP_STATUS_OK == resp_status) {
98
TSDebug("resphdr", "Processing 200 OK");
99
new_field_loc = TSMimeHdrFieldCreate(resp_bufp, resp_loc);
100
TSDebug("resphdr", "Created new resp field with loc %d", new_field_loc);
102
/* copy name/values created at init
103
* ( "x-num-served-from-cache" ) : ( "0" )
105
TSMimeHdrFieldCopy(resp_bufp, resp_loc, new_field_loc, hdr_bufp, hdr_loc, field_loc);
107
/*********** Unclear why this is needed **************/
108
TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
111
/* Cache-Control: Public */
112
new_field_loc = TSMimeHdrFieldCreate(resp_bufp, resp_loc);
113
TSDebug("resphdr", "Created new resp field with loc %d", new_field_loc);
114
TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
115
TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc,
116
TS_MIME_FIELD_CACHE_CONTROL, TS_MIME_LEN_CACHE_CONTROL);
117
TSMimeHdrFieldValueStringInsert(resp_bufp, resp_loc, new_field_loc,
118
-1, TS_HTTP_VALUE_PUBLIC, TS_HTTP_LEN_PUBLIC);
121
* mimehdr2_name = TSstrdup( "x-date-200-recvd" ) : CurrentDateTime
123
new_field_loc = TSMimeHdrFieldCreate(resp_bufp, resp_loc);
124
TSDebug("resphdr", "Created new resp field with loc %d", new_field_loc);
125
TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
126
TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr2_name, strlen(mimehdr2_name));
127
recvd_time = time(NULL);
128
TSMimeHdrFieldValueDateInsert(resp_bufp, resp_loc, new_field_loc, recvd_time);
130
TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc);
131
TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
133
} else if (TS_HTTP_STATUS_NOT_MODIFIED == resp_status) {
135
TSDebug("resphdr", "Processing 304 Not Modified");
137
/* N.B.: Protect writes to data (hash on URL + mutex: (ies)) */
139
/* Get the cached HTTP header */
140
if (!TSHttpTxnCachedRespGet(txnp, &cached_bufp, &cached_loc)) {
141
TSError("STATUS 304, TSHttpTxnCachedRespGet():");
142
TSError("couldn't retrieve cached response header\n");
143
TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
144
return; /* Caller reenables */
147
/* Get the cached MIME field name for this HTTP header */
148
cached_field_loc = TSMimeHdrFieldFind(cached_bufp, cached_loc,
149
(const char *) mimehdr1_name, strlen(mimehdr1_name));
150
if (0 == cached_field_loc) {
151
TSError("Can't find header %s in cached document", mimehdr1_name);
152
TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
153
TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
154
return; /* Caller reenables */
157
/* Get the cached MIME value for this name in this HTTP header */
158
if (TSMimeHdrFieldValueStringGet(cached_bufp, cached_loc, cached_field_loc, 0, &chkptr, &chklength) == TS_ERROR ||
159
NULL == chkptr || !chklength) {
160
TSError("Could not find value for cached MIME field name %s", mimehdr1_name);
161
TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
162
TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
163
TSHandleMLocRelease(cached_bufp, cached_loc, cached_field_loc);
164
return; /* Caller reenables */
166
TSDebug("resphdr", "Header field value is %s, with length %d", chkptr, chklength);
169
/* TODO check these comments for correctness */
171
* Since TSMimeHdrFieldValueStringGet returned with valid values
172
* are we also guaranteed that TSMimeHdrFieldValueUintGet returns
173
* valid values? There is no erro code for TSMimeHdrFieldValueUintGet
174
* and 0 is a valid value.
176
/* Get the cached MIME value for this name in this HTTP header */
178
TSMimeHdrFieldValueUintGet(cached_bufp, cached_loc, cached_field_loc, 0, &num_refreshes);
180
"Cached header shows %d refreshes so far", num_refreshes );
185
/* txn origin server response for this transaction stored
186
* in resp_bufp, resp_loc
188
* Create a new MIME field/value. Cached value has been incremented.
189
* Insert new MIME field/value into the server response buffer,
190
* allow HTTP processing to continue. This will update
191
* (indirectly invalidates) the cached HTTP headers MIME field.
192
* It is apparently not necessary to update all of the MIME fields
193
* in the in-process response in order to have the cached response
196
new_field_loc = TSMimeHdrFieldCreate(resp_bufp, resp_loc);
198
/* mimehdr1_name : TSstrdup( "x-num-served-from-cache" ) ; */
200
TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
201
TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr1_name, strlen(mimehdr1_name));
203
TSMimeHdrFieldValueUintInsert(resp_bufp, resp_loc, new_field_loc, -1, num_refreshes);
205
TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc);
206
TSHandleMLocRelease(cached_bufp, cached_loc, cached_field_loc);
207
TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
208
TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
211
TSDebug("resphdr", "other response code %d", resp_status);
215
* Additional 200/304 processing can go here, if so desired.
218
/* Caller reneables */
223
modify_response_header_plugin(TSCont contp, TSEvent event, void *edata)
226
TSHttpTxn txnp = (TSHttpTxn) edata;
229
case TS_EVENT_HTTP_READ_RESPONSE_HDR:
230
TSDebug("resphdr", "Called back with TS_EVENT_HTTP_READ_RESPONSE_HDR");
231
modify_header(txnp, contp);
232
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
245
const char *ts_version = TSTrafficServerVersionGet();
249
int major_ts_version = 0;
250
int minor_ts_version = 0;
251
int patch_ts_version = 0;
253
if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
257
/* Need at least TS 2.0 */
258
if (major_ts_version >= 2) {
268
TSPluginInit(int argc, const char *argv[])
270
TSMLoc chk_field_loc;
272
TSPluginRegistrationInfo info;
274
info.plugin_name = "response-header-1";
275
info.vendor_name = "MyCompany";
276
info.support_email = "ts-api-support@MyCompany.com";
278
if (!TSPluginRegister(TS_SDK_VERSION_3_0, &info)) {
279
TSError("Plugin registration failed.\n");
282
if (!check_ts_version()) {
283
TSError("Plugin requires Traffic Server 3.0 or later\n");
287
init_buffer_status = 0;
289
TSError("usage: %s \n", argv[0]);
290
TSError("warning: too many args %d\n", argc);
291
TSError("warning: ignoring unused arguments beginning with %s\n", argv[1]);
295
* The following code sets up an "init buffer" containing an extension header
296
* and its initial value. This will be the same for all requests, so we try
297
* to be efficient and do all of the work here rather than on a per-transaction
302
hdr_bufp = TSMBufferCreate();
303
hdr_loc = TSMimeHdrCreate(hdr_bufp);
305
mimehdr1_name = TSstrdup("x-num-served-from-cache");
306
mimehdr1_value = TSstrdup("0");
308
/* Create name here and set DateTime value when o.s.
309
* response 200 is received
311
mimehdr2_name = TSstrdup("x-date-200-recvd");
313
TSDebug("resphdr", "Inserting header %s with value %s into init buffer", mimehdr1_name, mimehdr1_value);
315
field_loc = TSMimeHdrFieldCreate(hdr_bufp, hdr_loc);
316
TSMimeHdrFieldAppend(hdr_bufp, hdr_loc, field_loc);
317
TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, mimehdr1_name, strlen(mimehdr1_name));
318
TSMimeHdrFieldValueStringInsert(hdr_bufp, hdr_loc, field_loc, -1, mimehdr1_value, strlen(mimehdr1_value));
319
TSDebug("resphdr", "init buffer hdr, field and value locs are %d, %d and %d", hdr_loc, field_loc, value_loc);
320
init_buffer_status = 1;
323
TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(modify_response_header_plugin, NULL));
326
* The following code demonstrates how to extract the field_loc from the header.
327
* In this plugin, the init buffer and thus field_loc never changes. Code
328
* similar to this may be used to extract header fields from any buffer.
331
if (0 == (chk_field_loc = TSMimeHdrFieldGet(hdr_bufp, hdr_loc, 0))) {
332
TSError("couldn't retrieve header field from init buffer");
333
TSError("marking init buffer as corrupt; no more plugin processing");
334
init_buffer_status = 0;
335
/* bail out here and reenable transaction */
337
if (field_loc != chk_field_loc)
338
TSError("retrieved buffer field loc is %d when it should be %d", chk_field_loc, field_loc);