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 /* output_header.c: a plugin prints out the client request header
25  *                 fields to stdout
26  * A sample internal plugin to use the HdrPrint functions and the TSIOBuffers
27  * that the functions utilize.
28  *
29  * The plugin simply prints all the incoming request headers
30  *
31  *   Note: tested on Solaris only.
32  */
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include "ts/ts.h"
39 #include "tscore/ink_defs.h"
40 
41 #define PLUGIN_NAME "output_header"
42 
43 static void
handle_dns(TSHttpTxn txnp,TSCont contp ATS_UNUSED)44 handle_dns(TSHttpTxn txnp, TSCont contp ATS_UNUSED)
45 {
46   TSMBuffer bufp;
47   TSMLoc hdr_loc;
48 
49   TSIOBuffer output_buffer;
50   TSIOBufferReader reader;
51   int total_avail;
52 
53   TSIOBufferBlock block;
54   const char *block_start;
55   int64_t block_avail;
56 
57   char *output_string;
58   int64_t output_len;
59 
60   if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
61     TSDebug(PLUGIN_NAME, "couldn't retrieve client request header");
62     TSError("[%s] Couldn't retrieve client request header", PLUGIN_NAME);
63     goto done;
64   }
65 
66   output_buffer = TSIOBufferCreate();
67   reader        = TSIOBufferReaderAlloc(output_buffer);
68 
69   /* This will print  just MIMEFields and not
70      the http request line */
71   TSDebug(PLUGIN_NAME, "Printing the hdrs ... ");
72   TSMimeHdrPrint(bufp, hdr_loc, output_buffer);
73 
74   if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc) == TS_ERROR) {
75     TSDebug(PLUGIN_NAME, "non-fatal: error releasing MLoc");
76     TSError("[%s] non-fatal: Couldn't release MLoc", PLUGIN_NAME);
77   }
78 
79   /* Find out how the big the complete header is by
80      seeing the total bytes in the buffer.  We need to
81      look at the buffer rather than the first block to
82      see the size of the entire header */
83   total_avail = TSIOBufferReaderAvail(reader);
84 
85   /* Allocate the string with an extra byte for the string
86      terminator */
87   output_string = (char *)TSmalloc(total_avail + 1);
88   output_len    = 0;
89 
90   /* We need to loop over all the buffer blocks to make
91      sure we get the complete header since the header can
92      be in multiple blocks */
93   block = TSIOBufferReaderStart(reader);
94   while (block) {
95     block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);
96 
97     /* We'll get a block pointer back even if there is no data
98        left to read so check for this condition and break out of
99        the loop. A block with no data to read means we've exhausted
100        buffer of data since if there was more data on a later
101        block in the chain, this block would have been skipped over */
102     if (block_avail == 0) {
103       break;
104     }
105 
106     memcpy(output_string + output_len, block_start, block_avail);
107     output_len += block_avail;
108 
109     /* Consume the data so that we get to the next block */
110     TSIOBufferReaderConsume(reader, block_avail);
111 
112     /* Get the next block now that we've consumed the
113        data off the last block */
114     block = TSIOBufferReaderStart(reader);
115   }
116 
117   /* Terminate the string */
118   output_string[output_len] = '\0';
119   output_len++;
120 
121   /* Free up the TSIOBuffer that we used to print out the header */
122   TSIOBufferReaderFree(reader);
123   TSIOBufferDestroy(output_buffer);
124 
125   /* Although I'd never do this a production plugin, printf
126      the header so that we can see it's all there */
127   TSDebug(PLUGIN_NAME, "%s", output_string);
128 
129   TSfree(output_string);
130 
131 done:
132   TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
133 }
134 
135 static int
hdr_plugin(TSCont contp,TSEvent event,void * edata)136 hdr_plugin(TSCont contp, TSEvent event, void *edata)
137 {
138   TSHttpTxn txnp = (TSHttpTxn)edata;
139 
140   switch (event) {
141   case TS_EVENT_HTTP_OS_DNS:
142     handle_dns(txnp, contp);
143     return 0;
144   default:
145     break;
146   }
147 
148   return 0;
149 }
150 
151 void
TSPluginInit(int argc ATS_UNUSED,const char * argv[]ATS_UNUSED)152 TSPluginInit(int argc ATS_UNUSED, const char *argv[] ATS_UNUSED)
153 {
154   TSPluginRegistrationInfo info;
155 
156   info.plugin_name   = PLUGIN_NAME;
157   info.vendor_name   = "Apache Software Foundation";
158   info.support_email = "dev@trafficserver.apache.org";
159 
160   if (TSPluginRegister(&info) != TS_SUCCESS) {
161     TSError("[%s] Plugin registration failed", PLUGIN_NAME);
162 
163     goto error;
164   }
165 
166   TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, TSContCreate(hdr_plugin, NULL));
167 
168 error:
169   TSError("[%s] Plugin not initialized", PLUGIN_NAME);
170 }
171