The null-transform.c plugin performs a null transformation on response content. The plugin is called each time Traffic Server reads an HTTP response header. -- The TSPluginInit function has a global hook set up for the READ RESPONSE HDR event. This plugin follows the default behavior for transforms: transformed content is cached. Therefore the transformation of the response need happen only once, when the content is received from the origin server. To make sure this happens, the plugin checks for a "200 OK" server response header before transforming. -- This check is done in the subroutine called "transformable". If the response is transformable, the plugin creates a transformation, and adds it to the response transform hook. -- This is done in "transform_add" using TSTransformCreate and TSHttpTxnHookAdd. -- The handler function for the transformation is null_transform. When it is time to transform the response data, the null_transform function is called. The transformation acts as a one-way data pipe: response data comes in from an upstream vconnection (which could be an HTTP state machine or itself another transformation) and goes out to the downstream vconnection, whatever that might be. The transformation has to: (a) Write transformed data to the downstream vconnection. (b) Copy data from the upstream vconnection's output buffer to the downstream vconnection's input buffer. (c) Clean up when the transformation is complete (either if it stopped because of an error or it finished transforming). Here is how this is implemented: the null_transform function (the transformation's handler function) first checks to make sure the transformation has not been closed (null_transform destroys itself if it finds out the transformation has been closed). Then null_transform has a switch statement that handles the following events: -- TS_EVENT_ERROR: if there is an error, null_transform lets the downstream vconnection know that the write operation is terminated (the downstream vconnection should not expect any more data). -- TS_EVENT_VCONN_WRITE_COMPLETE: the downstream vconnection has read all the data written to it. null_transform shuts down the write portion of the downstream vconnection, meaning that the transformation does not want any more WRITE events from the downstream vconnection. -- TS_EVENT_VCONN_WRITE_READY: null_transform calls handle_transform to transform data. -- All other events: call handle_transform. In the handle_transform function, the transformation vconnection takes the role of the "vconnection user" (see the SDK Programmer's Guide). handle_transform needs to initiate the transformation by a call to TSVConnWrite on the output vconnection. To do this, handle_transform has to: -- get the output vconnection using TSTransformOutputVConnGet -- get the input vio using TSVConnWriteVIOGet (the input vio contains the total number of bytes to be written, and keeps track of the number of bytes that the upstream vconnection has written to the input buffer. When the transformation has consumed data from the input buffer, it has to modify the input vio.) After calling TSVConnWrite, the transformation can expect to receive WRITE_READY and WRITE_COMPLETE events from the downstream vconnection. If there is data to read, handle_transform copies it over using TSIOBufferCopy. When done with the buffer, it calls TSIOBufferReaderConsume. If there is more data to read (than one buffer's worth), two things happen: -- handle_transform wakes up the downstream vconnection using TSVIOReenable -- handle_transform wakes up the upstream vconnection, asking it for more data, by using TSContCall and sending it a WRITE_READY event If there is no more data to read, handle_transform informs the downstream vconnection using TSVIONBytesSet and TSVIOReenable. Then handle_transform sends the upstream vconnection the WRITE_COMPLETE event using TSContCall. This is how the transformation receives the WRITE_COMPLETE event: when the downstream vconnection learns through the downstream (output) vio that there is no more data left to read (nbytes=ndone), the downstream vconnection sends WRITE_COMPLETE upstream.