void TSPluginInit(int argc, const char *argv[]) { TSMLoc field_loc; const char *p; int i, retval; TSPluginRegistrationInfo info; info.plugin_name = "add-header"; info.vendor_name = "MyCompany"; info.support_email = "*****@*****.**"; if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { TSError("[PluginInit] Plugin registration failed.\n"); goto error; } if (!check_ts_version()) { TSError("[PluginInit] Plugin requires Traffic Server 3.0 or later\n"); goto error; } if (argc < 2) { TSError("[PluginInit] Usage: %s \"name1: value1\" \"name2: value2\" ...>\n", argv[0]); goto error; } hdr_bufp = TSMBufferCreate(); if (TSMimeHdrCreate(hdr_bufp, &hdr_loc) != TS_SUCCESS) { TSError("[PluginInit] Can not create mime header"); goto error; } for (i = 1; i < argc; i++) { if (TSMimeHdrFieldCreate(hdr_bufp, hdr_loc, &field_loc) != TS_SUCCESS) { TSError("[PluginInit] Error while creating field"); goto error; } retval = TSMimeHdrFieldAppend(hdr_bufp, hdr_loc, field_loc); if (retval != TS_SUCCESS) { TSError("[PluginInit] Error while adding field"); goto error; } p = strchr(argv[i], ':'); if (p) { retval = TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, argv[i], p - argv[i]); if (retval == TS_ERROR) { TSError("[PluginInit] Error while naming field"); goto error; } p += 1; while (isspace(*p)) { p += 1; } retval = TSMimeHdrFieldValueStringInsert(hdr_bufp, hdr_loc, field_loc, -1, p, strlen(p)); if (retval == TS_ERROR) { TSError("[PluginInit] Error while inserting field value"); goto error; } } else { retval = TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, argv[i], strlen(argv[i])); if (retval == TS_ERROR) { TSError("[PluginInit] Error while inserting field value"); goto error; } } } /* Create a continuation with a mutex as there is a shared global structure containing the headers to add */ TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(add_header_plugin, TSMutexCreate())); goto done; error: TSError("[PluginInit] Plugin not initialized"); done: return; }
static void add_header(TSHttpTxn txnp, TSCont contp) { TSMBuffer req_bufp; TSMLoc req_loc; TSMLoc field_loc; TSMLoc next_field_loc; TSMLoc new_field_loc; int retval; if (TSHttpTxnClientReqGet(txnp, &req_bufp, &req_loc) != TS_SUCCESS) { TSError("[add_header] Error while retrieving client request header\n"); goto done; } field_loc = TSMimeHdrFieldGet(hdr_bufp, hdr_loc, 0); if (field_loc == TS_NULL_MLOC) { TSError("[add_header] Error while getting field"); goto error; } /* Loop on our header containing fields to add */ while (field_loc) { /* First create a new field in the client request header */ if (TSMimeHdrFieldCreate(req_bufp, req_loc, &new_field_loc) != TS_SUCCESS) { TSError("[add_header] Error while creating new field"); TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc); break; } /* Then copy our new field at this new location */ retval = TSMimeHdrFieldCopy(req_bufp, req_loc, new_field_loc, hdr_bufp, hdr_loc, field_loc); if (retval == TS_ERROR) { TSError("[add_header] Error while copying new field"); TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc); break; } /* Add this field to the Http client request header */ retval = TSMimeHdrFieldAppend(req_bufp, req_loc, new_field_loc); if (retval != TS_SUCCESS) { TSError("[add_header] Error while appending new field"); TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc); break; } /* We can now release this handle */ TSHandleMLocRelease(req_bufp, req_loc, new_field_loc); next_field_loc = TSMimeHdrFieldNext(hdr_bufp, hdr_loc, field_loc); TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc); field_loc = next_field_loc; } error: TSHandleMLocRelease(req_bufp, TS_NULL_MLOC, req_loc); done: TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); }
/** * Handler function to generate an error response */ static void error_response(TSHttpTxn txnp, tsib_txn_ctx *txndata) { const char *reason; TSMBuffer bufp; TSMLoc hdr_loc; TSMLoc field_loc; hdr_list *hdrs; TSReturnCode rv; /* make caller responsible for sanity checking */ assert((txndata != NULL) && (txndata->tx != NULL)); reason = TSHttpHdrReasonLookup(txndata->status); if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: couldn't retrieve client response header."); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); return; } rv = TSHttpHdrStatusSet(bufp, hdr_loc, txndata->status); if (rv != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: TSHttpHdrStatusSet"); } if (reason == NULL) { reason = "Other"; } rv = TSHttpHdrReasonSet(bufp, hdr_loc, reason, strlen(reason)); if (rv != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: TSHttpHdrReasonSet"); } while (hdrs = txndata->err_hdrs, hdrs != 0) { txndata->err_hdrs = hdrs->next; rv = TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc); if (rv != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: TSMimeHdrFieldCreate"); continue; } rv = TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, hdrs->hdr, strlen(hdrs->hdr)); if (rv != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: TSMimeHdrFieldNameSet"); goto errordoc_free1; } rv = TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, -1, hdrs->value, strlen(hdrs->value)); if (rv != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: TSMimeHdrFieldValueStringInsert"); goto errordoc_free1; } rv = TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc); if (rv != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: TSMimeHdrFieldAppend"); goto errordoc_free1; } errordoc_free1: rv = TSHandleMLocRelease(bufp, hdr_loc, field_loc); if (rv != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: TSHandleMLocRelease 1"); continue; } } if (txndata->err_body) { /* this will free the body, so copy it first! */ TSHttpTxnErrorBodySet(txnp, txndata->err_body, txndata->err_body_len, NULL); } rv = TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); if (rv != TS_SUCCESS) { ib_log_error_tx(txndata->tx, "ErrorDoc: TSHandleMLocRelease 2"); } ib_log_debug_tx(txndata->tx, "Sent error page %d \"%s\".", txndata->status, reason); }
/** * Handler function to generate an internal error response * when ironbee is unavailable to fill the fields or log errors. * * This may come from a TXN_START event, in which case we're * returning an HTTP/0.9 response and most of this is superfluous. */ static void internal_error_response(TSHttpTxn txnp) { TSReturnCode rv; const char *reason = "Server Unavailable"; TSMBuffer bufp; TSMLoc hdr_loc; TSMLoc field_loc; char *body; char clen[8]; int i; const struct { const char *name; const char *val; } headers[2] = { { "Content-Type", "text/plain" }, { "Content-Length", clen } }; if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: couldn't retrieve client response header."); return; } rv = TSHttpHdrStatusSet(bufp, hdr_loc, 503); if (rv != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: TSHttpHdrStatusSet"); } rv = TSHttpHdrReasonSet(bufp, hdr_loc, reason, strlen(reason)); if (rv != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: TSHttpHdrReasonSet"); } /* this will free the body, so copy it first! */ body = TSstrdup("Server unavailable or disabled.\n"); snprintf(clen, sizeof(clen), "%zd", strlen(body)); for (i = 0; i < 2; ++i) { rv = TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc); if (rv != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: TSMimeHdrFieldCreate"); continue; } rv = TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, headers[i].name, strlen(headers[i].name)); if (rv != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: TSMimeHdrFieldNameSet"); goto freehdr; } rv = TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, -1, headers[i].val, strlen(headers[i].val)); if (rv != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: TSMimeHdrFieldValueStringInsert"); goto freehdr; } rv = TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc); if (rv != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: TSMimeHdrFieldAppend"); goto freehdr; } freehdr: rv = TSHandleMLocRelease(bufp, hdr_loc, field_loc); if (rv != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: TSHandleMLocRelease 3"); continue; } } TSHttpTxnErrorBodySet(txnp, body, strlen(body), NULL); rv = TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); if (rv != TS_SUCCESS) { TSError("[ironbee] ErrorDoc: TSHandleMLocRelease 4"); } }
static int ts_lua_server_request_header_set(lua_State *L) { const char *key; const char *val; size_t val_len; size_t key_len; int remove; int first; TSMLoc field_loc, tmp; ts_lua_http_ctx *http_ctx; GET_HTTP_CONTEXT(http_ctx, L); remove = 0; val = NULL; /* we skip the first argument that is the table */ key = luaL_checklstring(L, 2, &key_len); if (lua_isnil(L, 3)) { remove = 1; } else { val = luaL_checklstring(L, 3, &val_len); } if (!http_ctx->server_request_hdrp) { if (TSHttpTxnServerReqGet(http_ctx->txnp, &http_ctx->server_request_bufp, &http_ctx->server_request_hdrp) != TS_SUCCESS) { return 0; } } field_loc = TSMimeHdrFieldFind(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, key, key_len); if (remove) { while (field_loc != TS_NULL_MLOC) { tmp = TSMimeHdrFieldNextDup(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc); TSMimeHdrFieldDestroy(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc); TSHandleMLocRelease(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc); field_loc = tmp; } } else if (field_loc != TS_NULL_MLOC) { first = 1; while (field_loc != TS_NULL_MLOC) { tmp = TSMimeHdrFieldNextDup(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc); if (first) { first = 0; TSMimeHdrFieldValueStringSet(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc, -1, val, val_len); } else { TSMimeHdrFieldDestroy(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc); } TSHandleMLocRelease(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc); field_loc = tmp; } } else if (TSMimeHdrFieldCreateNamed(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, key, key_len, &field_loc) != TS_SUCCESS) { TSError("[ts_lua][%s] TSMimeHdrFieldCreateNamed error", __FUNCTION__); return 0; } else { TSMimeHdrFieldValueStringSet(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc, -1, val, val_len); TSMimeHdrFieldAppend(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc); } if (field_loc != TS_NULL_MLOC) { TSHandleMLocRelease(http_ctx->server_request_bufp, http_ctx->server_request_hdrp, field_loc); } return 0; }
static void modify_header(TSHttpTxn txnp) { TSMBuffer resp_bufp; TSMBuffer cached_bufp; TSMLoc resp_loc; TSMLoc cached_loc; TSHttpStatus resp_status; TSMLoc new_field_loc; TSMLoc cached_field_loc; time_t recvd_time; const char *chkptr; int chklength; int num_refreshes = 0; if (!init_buffer_status) return; /* caller reenables */ if (TSHttpTxnServerRespGet(txnp, &resp_bufp, &resp_loc) != TS_SUCCESS) { TSError("couldn't retrieve server response header\n"); return; /* caller reenables */ } /* TSqa06246/TSqa06144 */ resp_status = TSHttpHdrStatusGet(resp_bufp, resp_loc); if (TS_HTTP_STATUS_OK == resp_status) { TSDebug("resphdr", "Processing 200 OK"); TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */ TSDebug("resphdr", "Created new resp field with loc %p", new_field_loc); /* copy name/values created at init * ( "x-num-served-from-cache" ) : ( "0" ) */ TSMimeHdrFieldCopy(resp_bufp, resp_loc, new_field_loc, hdr_bufp, hdr_loc, field_loc); /*********** Unclear why this is needed **************/ TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc); /* Cache-Control: Public */ TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */ TSDebug("resphdr", "Created new resp field with loc %p", new_field_loc); TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc); TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, TS_MIME_FIELD_CACHE_CONTROL, TS_MIME_LEN_CACHE_CONTROL); TSMimeHdrFieldValueStringInsert(resp_bufp, resp_loc, new_field_loc, -1, TS_HTTP_VALUE_PUBLIC, TS_HTTP_LEN_PUBLIC); /* * mimehdr2_name = TSstrdup( "x-date-200-recvd" ) : CurrentDateTime */ TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */ TSDebug("resphdr", "Created new resp field with loc %p", new_field_loc); TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc); TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr2_name, strlen(mimehdr2_name)); recvd_time = time(NULL); TSMimeHdrFieldValueDateInsert(resp_bufp, resp_loc, new_field_loc, recvd_time); TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc); TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc); } else if (TS_HTTP_STATUS_NOT_MODIFIED == resp_status) { TSDebug("resphdr", "Processing 304 Not Modified"); /* N.B.: Protect writes to data (hash on URL + mutex: (ies)) */ /* Get the cached HTTP header */ if (TSHttpTxnCachedRespGet(txnp, &cached_bufp, &cached_loc) != TS_SUCCESS) { TSError("STATUS 304, TSHttpTxnCachedRespGet():"); TSError("couldn't retrieve cached response header\n"); TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc); return; /* Caller reenables */ } /* Get the cached MIME field name for this HTTP header */ cached_field_loc = TSMimeHdrFieldFind(cached_bufp, cached_loc, (const char *)mimehdr1_name, strlen(mimehdr1_name)); if (TS_NULL_MLOC == cached_field_loc) { TSError("Can't find header %s in cached document", mimehdr1_name); TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc); TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc); return; /* Caller reenables */ } /* Get the cached MIME value for this name in this HTTP header */ chkptr = TSMimeHdrFieldValueStringGet(cached_bufp, cached_loc, cached_field_loc, -1, &chklength); if (NULL == chkptr || !chklength) { TSError("Could not find value for cached MIME field name %s", mimehdr1_name); TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc); TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc); TSHandleMLocRelease(cached_bufp, cached_loc, cached_field_loc); return; /* Caller reenables */ } TSDebug("resphdr", "Header field value is %s, with length %d", chkptr, chklength); /* Get the cached MIME value for this name in this HTTP header */ /* TSMimeHdrFieldValueUintGet(cached_bufp, cached_loc, cached_field_loc, 0, &num_refreshes); TSDebug("resphdr", "Cached header shows %d refreshes so far", num_refreshes ); num_refreshes++ ; */ /* txn origin server response for this transaction stored * in resp_bufp, resp_loc * * Create a new MIME field/value. Cached value has been incremented. * Insert new MIME field/value into the server response buffer, * allow HTTP processing to continue. This will update * (indirectly invalidates) the cached HTTP headers MIME field. * It is apparently not necessary to update all of the MIME fields * in the in-process response in order to have the cached response * become invalid. */ TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probaby should check for errrors */ /* mimehdr1_name : TSstrdup( "x-num-served-from-cache" ) ; */ TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc); TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr1_name, strlen(mimehdr1_name)); TSMimeHdrFieldValueUintInsert(resp_bufp, resp_loc, new_field_loc, -1, num_refreshes); TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc); TSHandleMLocRelease(cached_bufp, cached_loc, cached_field_loc); TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc); TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc); } else { TSDebug("resphdr", "other response code %d", resp_status); } /* * Additional 200/304 processing can go here, if so desired. */ /* Caller reneables */ }
void TSPluginInit(int argc, const char *argv[]) { TSMLoc chk_field_loc; TSPluginRegistrationInfo info; info.plugin_name = "response-header-1"; info.vendor_name = "MyCompany"; info.support_email = "*****@*****.**"; if (TSPluginRegister(&info) != TS_SUCCESS) { TSError("Plugin registration failed.\n"); } init_buffer_status = 0; if (argc > 1) { TSError("usage: %s \n", argv[0]); TSError("warning: too many args %d\n", argc); TSError("warning: ignoring unused arguments beginning with %s\n", argv[1]); } /* * The following code sets up an "init buffer" containing an extension header * and its initial value. This will be the same for all requests, so we try * to be efficient and do all of the work here rather than on a per-transaction * basis. */ hdr_bufp = TSMBufferCreate(); TSMimeHdrCreate(hdr_bufp, &hdr_loc); mimehdr1_name = TSstrdup("x-num-served-from-cache"); mimehdr1_value = TSstrdup("0"); /* Create name here and set DateTime value when o.s. * response 200 is received */ mimehdr2_name = TSstrdup("x-date-200-recvd"); TSDebug("resphdr", "Inserting header %s with value %s into init buffer", mimehdr1_name, mimehdr1_value); TSMimeHdrFieldCreate(hdr_bufp, hdr_loc, &field_loc); /* Probably should check for errors */ TSMimeHdrFieldAppend(hdr_bufp, hdr_loc, field_loc); TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, mimehdr1_name, strlen(mimehdr1_name)); TSMimeHdrFieldValueStringInsert(hdr_bufp, hdr_loc, field_loc, -1, mimehdr1_value, strlen(mimehdr1_value)); TSDebug("resphdr", "init buffer hdr, field and value locs are %p, %p and %p", hdr_loc, field_loc, value_loc); init_buffer_status = 1; TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(modify_response_header_plugin, NULL)); /* * The following code demonstrates how to extract the field_loc from the header. * In this plugin, the init buffer and thus field_loc never changes. Code * similar to this may be used to extract header fields from any buffer. */ if (TS_NULL_MLOC == (chk_field_loc = TSMimeHdrFieldGet(hdr_bufp, hdr_loc, 0))) { TSError("couldn't retrieve header field from init buffer"); TSError("marking init buffer as corrupt; no more plugin processing"); init_buffer_status = 0; /* bail out here and reenable transaction */ } else { if (field_loc != chk_field_loc) TSError("retrieved buffer field loc is %p when it should be %p", chk_field_loc, field_loc); } }