1.. Licensed to the Apache Software Foundation (ASF) under one 2 or more contributor license agreements. See the NOTICE file 3 distributed with this work for additional information 4 regarding copyright ownership. The ASF licenses this file 5 to you under the Apache License, Version 2.0 (the 6 "License"); you may not use this file except in compliance 7 with the License. You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11 Unless required by applicable law or agreed to in writing, 12 software distributed under the License is distributed on an 13 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 KIND, either express or implied. See the License for the 15 specific language governing permissions and limitations 16 under the License. 17 18.. include:: ../../../common.defs 19 20.. _developer-plugins-io-transformations: 21 22Transformations 23*************** 24 25Vconnection Implementer's View 26============================== 27 28A VConnection implementer writes only transformations. All other 29VConnections (net VConnections and cache VConnections) are implemented 30in iocore. As mentioned earlier, a given vconnection can have a maximum 31of one read operation and one write operation being performed on it. The 32vconnection user gets information about the operation being performed by 33examining the VIO returned by a call to :c:func:`TSVConnRead` or 34:c:func:`TSVConnWrite`. The implementer, in turn, gets a handle on the VIO 35operation by examining the VIO returned by :c:func:`TSVConnReadVIOGet` or 36:c:func:`TSVConnWriteVIOGet` (recall that every vconnection created through 37the Traffic Server API has an associated read VIO and write VIO, even if 38it only supports reading or writing). 39 40For example, the null transform plugin's transformation examines the 41input VIO by calling: 42 43.. code-block:: c 44 45 input_vio = TSVConnWriteVIOGet (contp); 46 47where ``contp`` is the transformation. 48 49A vconnection is a continuation. This means it has a handler function 50that is run when an event is sent to it, or more accurately, when an 51event that was sent to it is received. It is the handler function's job 52to examine the event, the current state of its read VIO and write VIO, 53and any other internal state the vconnection might have and potentially 54make some progress on the IO operations. 55 56It is common for the handler function for all vconnections to look 57similar. Their basic form looks something like the code fragment below: 58 59.. code-block:: c 60 61 int 62 vconnection_handler (TSCont contp, TSEvent event, void *edata) 63 { 64 if (TSVConnClosedGet (contp)) { 65 /* Destroy any vconnection specific data here. */ 66 TSContDestroy (contp); 67 return 0; 68 } else { 69 /* Handle the incoming event */ 70 } 71 } 72 73This code fragment basically shows that many vconnections simply want to 74destroy themselves when they are closed. However, the situation might 75also require the vconnection to do some cleanup processing - which is 76why :c:func:`TSVConnClose` does not simply just destroy the vconnection. 77 78Vconnections are state machines that are animated by the events they 79receive. An event is sent to the vconnection whenever an 80:c:func:`TSVConnRead`, :c:func:`TSVConnWrite`, :c:func:`TSVConnClose`, 81:c:func:`TSVConnShutdown`, or :c:func:`TSVIOReenable` call is performed. 82:c:func:`TSVIOReenable` indirectly references the vconnection through a 83back-pointer in the VIO structure to the vconnection. The vconnection 84itself only knows which call was performed by examining its state and 85the state of its VIOs. For example, when :c:func:`TSVConnClose` is called, the 86vconnection is sent an immediate event (``TS_EVENT_IMMEDIATE``). For 87every event the vconnection receives, it needs to check its closed flag 88to see if it has been closed. Similarly, when :c:func:`TSVIOReenable` is 89called, the vconnection is sent an immediate event. For every event the 90vconnection receives, it must check its VIOs to see if the buffers have 91been modified to a state in which it can continue processing one of its 92operations. 93 94Finally, a vconnection is likely the user of other vconnections. It also 95receives events as the user of these other vconnections. When it 96receives such an event, like ``TS_EVENT_VCONN_WRITE_READY``, it might 97just enable another vconnection that's writing into the buffer used by 98the vconnection reading from it. The above description is merely 99intended to give the overall idea for what a vconnection needs to do. 100 101Transformation VConnection 102-------------------------- 103 104A :ref:`transformation <transformations>` is 105a specific type of vconnection. It supports a subset of the vconnection 106functionality that enables one or more transformations to be chained 107together. A transformation sits as a bottleneck between an input data 108source and an output data sink, which enables it to view and modify all 109the data passing through it. Alternatively, some transformations simply 110scan the data and pass it on. A common transformation is one that 111compresses data in some manner. 112 113A transformation can modify either the data stream being sent *to* an 114HTTP client (e.g. the document) or the data stream being sent *from* an 115HTTP client (e.g. post data). To do this, the transformation should hook 116on to one of the following hooks: 117 118- ``TS_HTTP_REQUEST_TRANSFORM_HOOK`` 119 120- ``TS_HTTP_RESPONSE_TRANSFORM_HOOK`` 121 122Note that because a transformation is intimately associated with a given 123transaction, it is only possible to add the hook to the transaction 124hooks - not to the global or session hooks. Transformations reside in a 125chain, so their ordering is quite easily determined: transformations 126that add themselves to the chain are simply appended to it. 127 128Data is passed in to the transformation by initiating a vconnection 129write operation on the transformation. As a consequence of this design, 130a transformation must support the vconnection write operation. In other 131words, your transformation must expect an upstream vconnection to write 132data to it. The transformation has to read the data, consume it, and 133tell the upstream vconnection it is finished by sending it an 134``TS_EVENT_WRITE_COMPLETE`` event. Transformations cannot send the 135``TS_EVENT_VCONN_WRITE_COMPLETE`` event to the upstream vconnection 136unless they are finished consuming all incoming data. If 137``TS_EVENT_VCONN_WRITE_COMPLETE`` is sent prematurely, then certain 138internal Traffic Server data structures will not be deallocated, thereby 139causing a memory leak. 140 141Here's how to make sure that all incoming data is consumed: 142 143- After reading or copying data, make sure that you consume the data 144 and increase the value of ndone for the input VIO, as in the 145 following example taken from ``null_transform.c``: 146 147 .. code-block:: c 148 149 TSIOBufferCopy (TSVIOBufferGet (data->output_vio), 150 TSVIOReaderGet (input_vio), towrite, 0); 151 /* Tell the read buffer that we have read the data and are no longer interested in it. */ 152 TSIOBufferReaderConsume (TSVIOReaderGet (input_vio), towrite); 153 /* Modify the input VIO to reflect how much has been read.*/ 154 TSVIONDoneSet (input_vio, TSVIONDoneGet (input_vio) + towrite); 155 156- Before sending ``TS_EVENT_VCONN_WRITE_COMPLETE``, your transformation 157 should check the number of bytes remaining in the upstream 158 vconnection's write VIO (input VIO) using the function 159 ``TSVIONTodoGet`` (``input_vio``). This value should go to zero when 160 all of the upstream data is consumed 161 (``TSVIONTodoGet = nbytes - ndone``). Do not send 162 ``TS_EVENT_VCONN_WRITE_COMPLETE`` events if :c:func:`TSVIONTodoGet` is 163 greater than zero. 164- The transformation passes data out of itself by using the output 165 vconnection retrieved by :c:func:`TSTransformOutputVConnGet`. Immediately 166 before Traffic Server initiates the write operation (which inputs 167 data into the transformation), it sets the output vconnection either 168 to the next transformation in the chain of transformations or to a 169 special terminating transformation (if it's the last transformation 170 in the chain). Since the transformation is handed ownership of the 171 output vconnection, it must close it at some point in order for it to 172 be deallocated. 173- All of the transformations in a transformation chain share the 174 transaction's mutex. This small restriction (enforced by 175 :c:func:`TSTransformCreate`) removes many of the locking complications of 176 implementing general vconnections. For example, a transformation does 177 not have to grab its write VIO mutex before accessing its write VIO 178 because it knows it already holds the mutex. 179 180The transformation functions are: 181 182 - :c:func:`TSTransformCreate` 183 - :c:func:`TSTransformOutputVConnGet` 184