~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to example/response-header-1/response-header-1.c

  • Committer: Bazaar Package Importer
  • Author(s): Arno Toell
  • Date: 2011-01-13 11:49:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110113114918-vu422h8dknrgkj15
Tags: upstream-2.1.5-unstable
ImportĀ upstreamĀ versionĀ 2.1.5-unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 
 
3
  A brief file description
 
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
 
 
24
/*
 
25
 * response-header-1.c:
 
26
 *              an example program which illustrates adding and manipulating
 
27
 *              an HTTP response MIME header:
 
28
 *
 
29
 *   Authorized possession and use of this software pursuant only
 
30
 *   to the terms of a written license agreement.
 
31
 *
 
32
 *      Usage:  response-header-1.so
 
33
 *
 
34
 *      add read_resp_header hook
 
35
 *      get http response header
 
36
 *      if 200, then
 
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
 
40
 *      else if 304, then
 
41
 *              retrieve cached header
 
42
 *              get old value of mime header count
 
43
 *              increment mime header count
 
44
 *              store mime header with new count
 
45
 *
 
46
 *
 
47
 *
 
48
 */
 
49
 
 
50
#include <time.h>
 
51
#include <stdio.h>
 
52
#include <string.h>
 
53
#include <ctype.h>
 
54
#include <ts/ts.h>
 
55
 
 
56
static int init_buffer_status;
 
57
 
 
58
static char *mimehdr1_name;
 
59
static char *mimehdr2_name;
 
60
static char *mimehdr1_value;
 
61
 
 
62
static TSMBuffer hdr_bufp;
 
63
static TSMLoc hdr_loc;
 
64
 
 
65
static TSMLoc field_loc;
 
66
static TSMLoc value_loc;
 
67
 
 
68
static void
 
69
modify_header(TSHttpTxn txnp, TSCont contp)
 
70
{
 
71
  TSMBuffer resp_bufp;
 
72
  TSMBuffer cached_bufp;
 
73
  TSMLoc resp_loc;
 
74
  TSMLoc cached_loc;
 
75
  TSHttpStatus resp_status;
 
76
  TSMLoc new_field_loc;
 
77
  TSMLoc cached_field_loc;
 
78
  time_t recvd_time;
 
79
 
 
80
  const char *chkptr;
 
81
  int chklength;
 
82
 
 
83
  int num_refreshes = 0;
 
84
 
 
85
  if (!init_buffer_status)
 
86
    return;                     /* caller reenables */
 
87
 
 
88
  if (!TSHttpTxnServerRespGet(txnp, &resp_bufp, &resp_loc)) {
 
89
    TSError("couldn't retrieve server response header\n");
 
90
    return;                     /* caller reenables */
 
91
  }
 
92
 
 
93
  /* TSqa06246/TSqa06144 */
 
94
  resp_status = TSHttpHdrStatusGet(resp_bufp, resp_loc);
 
95
 
 
96
  if (TS_HTTP_STATUS_OK == resp_status) {
 
97
 
 
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);
 
101
 
 
102
    /* copy name/values created at init
 
103
     * ( "x-num-served-from-cache" ) : ( "0"  )
 
104
     */
 
105
    TSMimeHdrFieldCopy(resp_bufp, resp_loc, new_field_loc, hdr_bufp, hdr_loc, field_loc);
 
106
 
 
107
        /*********** Unclear why this is needed **************/
 
108
    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
 
109
 
 
110
 
 
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);
 
119
 
 
120
    /*
 
121
     * mimehdr2_name  = TSstrdup( "x-date-200-recvd" ) : CurrentDateTime
 
122
     */
 
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);
 
129
 
 
130
    TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc);
 
131
    TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
 
132
 
 
133
  } else if (TS_HTTP_STATUS_NOT_MODIFIED == resp_status) {
 
134
 
 
135
    TSDebug("resphdr", "Processing 304 Not Modified");
 
136
 
 
137
    /* N.B.: Protect writes to data (hash on URL + mutex: (ies)) */
 
138
 
 
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 */
 
145
    }
 
146
 
 
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 */
 
155
    }
 
156
 
 
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 */
 
165
    }
 
166
    TSDebug("resphdr", "Header field value is %s, with length %d", chkptr, chklength);
 
167
 
 
168
 
 
169
    /* TODO check these comments for correctness */
 
170
    /*
 
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.
 
175
     */
 
176
    /* Get the cached MIME value for this name in this HTTP header */
 
177
    /*
 
178
       TSMimeHdrFieldValueUintGet(cached_bufp, cached_loc, cached_field_loc, 0, &num_refreshes);
 
179
       TSDebug("resphdr",
 
180
       "Cached header shows %d refreshes so far", num_refreshes );
 
181
 
 
182
       num_refreshes++ ;
 
183
     */
 
184
 
 
185
       /* txn origin server response for this transaction stored
 
186
       * in resp_bufp, resp_loc
 
187
       *
 
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
 
194
       * become invalid.
 
195
     */
 
196
    new_field_loc = TSMimeHdrFieldCreate(resp_bufp, resp_loc);
 
197
 
 
198
    /* mimehdr1_name : TSstrdup( "x-num-served-from-cache" ) ; */
 
199
 
 
200
    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
 
201
    TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr1_name, strlen(mimehdr1_name));
 
202
 
 
203
    TSMimeHdrFieldValueUintInsert(resp_bufp, resp_loc, new_field_loc, -1, num_refreshes);
 
204
 
 
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);
 
209
 
 
210
  } else {
 
211
    TSDebug("resphdr", "other response code %d", resp_status);
 
212
  }
 
213
 
 
214
  /*
 
215
   *  Additional 200/304 processing can go here, if so desired.
 
216
   */
 
217
 
 
218
  /* Caller reneables */
 
219
}
 
220
 
 
221
 
 
222
static int
 
223
modify_response_header_plugin(TSCont contp, TSEvent event, void *edata)
 
224
{
 
225
 
 
226
  TSHttpTxn txnp = (TSHttpTxn) edata;
 
227
 
 
228
  switch (event) {
 
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);
 
233
    /*  fall through  */
 
234
 
 
235
  default:
 
236
    break;
 
237
  }
 
238
  return 0;
 
239
}
 
240
 
 
241
int
 
242
check_ts_version()
 
243
{
 
244
 
 
245
  const char *ts_version = TSTrafficServerVersionGet();
 
246
  int result = 0;
 
247
 
 
248
  if (ts_version) {
 
249
    int major_ts_version = 0;
 
250
    int minor_ts_version = 0;
 
251
    int patch_ts_version = 0;
 
252
 
 
253
    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
 
254
      return 0;
 
255
    }
 
256
 
 
257
    /* Need at least TS 2.0 */
 
258
    if (major_ts_version >= 2) {
 
259
      result = 1;
 
260
    }
 
261
 
 
262
  }
 
263
 
 
264
  return result;
 
265
}
 
266
 
 
267
void
 
268
TSPluginInit(int argc, const char *argv[])
 
269
{
 
270
  TSMLoc chk_field_loc;
 
271
 
 
272
  TSPluginRegistrationInfo info;
 
273
 
 
274
  info.plugin_name = "response-header-1";
 
275
  info.vendor_name = "MyCompany";
 
276
  info.support_email = "ts-api-support@MyCompany.com";
 
277
 
 
278
  if (!TSPluginRegister(TS_SDK_VERSION_3_0, &info)) {
 
279
    TSError("Plugin registration failed.\n");
 
280
  }
 
281
 
 
282
  if (!check_ts_version()) {
 
283
    TSError("Plugin requires Traffic Server 3.0 or later\n");
 
284
    return;
 
285
  }
 
286
 
 
287
  init_buffer_status = 0;
 
288
  if (argc > 1) {
 
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]);
 
292
  }
 
293
 
 
294
  /*
 
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
 
298
   *  basis.
 
299
   */
 
300
 
 
301
 
 
302
  hdr_bufp = TSMBufferCreate();
 
303
  hdr_loc = TSMimeHdrCreate(hdr_bufp);
 
304
 
 
305
  mimehdr1_name = TSstrdup("x-num-served-from-cache");
 
306
  mimehdr1_value = TSstrdup("0");
 
307
 
 
308
  /* Create name here and set DateTime value when o.s.
 
309
   * response 200 is received
 
310
   */
 
311
  mimehdr2_name = TSstrdup("x-date-200-recvd");
 
312
 
 
313
  TSDebug("resphdr", "Inserting header %s with value %s into init buffer", mimehdr1_name, mimehdr1_value);
 
314
 
 
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;
 
321
 
 
322
 
 
323
  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(modify_response_header_plugin, NULL));
 
324
 
 
325
  /*
 
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.
 
329
   */
 
330
 
 
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 */
 
336
  } else {
 
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);
 
339
  }
 
340
}