| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| /** |
| * @file headers.cc |
| * @brief HTTP headers manipulation. |
| */ |
| |
| #include <cstdlib> |
| #include <cstring> |
| |
| #include "configs.h" |
| #include "headers.h" |
| |
| /** |
| * @brief Remove a header (fully) from an TSMLoc / TSMBuffer. |
| * |
| * @param bufp request's buffer |
| * @param hdrLoc request's header location |
| * @param header header name |
| * @param headerlen header name length |
| * @return the number of fields (header values) we removed. |
| */ |
| int |
| removeHeader(TSMBuffer bufp, TSMLoc hdrLoc, const char *header, int headerlen) |
| { |
| TSMLoc fieldLoc = TSMimeHdrFieldFind(bufp, hdrLoc, header, headerlen); |
| int cnt = 0; |
| |
| while (fieldLoc) { |
| TSMLoc tmp = TSMimeHdrFieldNextDup(bufp, hdrLoc, fieldLoc); |
| |
| ++cnt; |
| TSMimeHdrFieldDestroy(bufp, hdrLoc, fieldLoc); |
| TSHandleMLocRelease(bufp, hdrLoc, fieldLoc); |
| fieldLoc = tmp; |
| } |
| |
| return cnt; |
| } |
| |
| /** |
| * @brief Checks if the header exists. |
| * |
| * @param bufp request's buffer |
| * @param hdrLoc request's header location |
| * @return true - exists, false - does not exist |
| */ |
| bool |
| headerExist(TSMBuffer bufp, TSMLoc hdrLoc, const char *header, int headerlen) |
| { |
| TSMLoc fieldLoc = TSMimeHdrFieldFind(bufp, hdrLoc, header, headerlen); |
| if (TS_NULL_MLOC != fieldLoc) { |
| TSHandleMLocRelease(bufp, hdrLoc, fieldLoc); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @brief Get the header value |
| * |
| * @param bufp request's buffer |
| * @param hdrLoc request's header location |
| * @param header header name |
| * @param headerlen header name length |
| * @param value buffer for the value |
| * @param valuelen lenght of the buffer for the value |
| * @return pointer to the string with the value. |
| */ |
| char * |
| getHeader(TSMBuffer bufp, TSMLoc hdrLoc, const char *header, int headerlen, char *value, int *valuelen) |
| { |
| TSMLoc fieldLoc = TSMimeHdrFieldFind(bufp, hdrLoc, header, headerlen); |
| char *dst = value; |
| while (fieldLoc) { |
| TSMLoc next = TSMimeHdrFieldNextDup(bufp, hdrLoc, fieldLoc); |
| |
| int count = TSMimeHdrFieldValuesCount(bufp, hdrLoc, fieldLoc); |
| for (int i = 0; i < count; ++i) { |
| const char *v = nullptr; |
| int vlen = 0; |
| v = TSMimeHdrFieldValueStringGet(bufp, hdrLoc, fieldLoc, i, &vlen); |
| if (v == nullptr || vlen == 0) { |
| continue; |
| } |
| /* append the field content to the output buffer if enough space, plus space for ", " */ |
| bool first = (dst == value); |
| int neededSpace = ((dst - value) + vlen + (dst == value ? 0 : 2)); |
| if (neededSpace < *valuelen) { |
| if (!first) { |
| memcpy(dst, ", ", 2); |
| dst += 2; |
| } |
| memcpy(dst, v, vlen); |
| dst += vlen; |
| } |
| } |
| TSHandleMLocRelease(bufp, hdrLoc, fieldLoc); |
| fieldLoc = next; |
| } |
| |
| *valuelen = dst - value; |
| return value; |
| } |
| |
| /** |
| * @brief Set a header to a specific value. |
| * |
| * This will avoid going to through a remove / add sequence in case of an existing header but clean. |
| * |
| * @param bufp request's buffer |
| * @param hdrLoc request's header location |
| * @param header header name |
| * @param headerlen header name len |
| * @param value the new value |
| * @param valuelen lenght of the value |
| * @return true - OK, false - failed |
| */ |
| bool |
| setHeader(TSMBuffer bufp, TSMLoc hdrLoc, const char *header, int headerlen, const char *value, int valuelen) |
| { |
| if (!bufp || !hdrLoc || !header || headerlen <= 0 || !value || valuelen <= 0) { |
| return false; |
| } |
| |
| bool ret = false; |
| TSMLoc fieldLoc = TSMimeHdrFieldFind(bufp, hdrLoc, header, headerlen); |
| |
| if (!fieldLoc) { |
| // No existing header, so create one |
| if (TS_SUCCESS == TSMimeHdrFieldCreateNamed(bufp, hdrLoc, header, headerlen, &fieldLoc)) { |
| if (TS_SUCCESS == TSMimeHdrFieldValueStringSet(bufp, hdrLoc, fieldLoc, -1, value, valuelen)) { |
| TSMimeHdrFieldAppend(bufp, hdrLoc, fieldLoc); |
| ret = true; |
| } |
| TSHandleMLocRelease(bufp, hdrLoc, fieldLoc); |
| } |
| } else { |
| TSMLoc tmp = nullptr; |
| bool first = true; |
| |
| while (fieldLoc) { |
| if (first) { |
| first = false; |
| if (TS_SUCCESS == TSMimeHdrFieldValueStringSet(bufp, hdrLoc, fieldLoc, -1, value, valuelen)) { |
| ret = true; |
| } |
| } else { |
| TSMimeHdrFieldDestroy(bufp, hdrLoc, fieldLoc); |
| } |
| tmp = TSMimeHdrFieldNextDup(bufp, hdrLoc, fieldLoc); |
| TSHandleMLocRelease(bufp, hdrLoc, fieldLoc); |
| fieldLoc = tmp; |
| } |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * @brief Dump a header on stderr |
| * |
| * Useful together with TSDebug(). |
| * |
| * @param bufp request's buffer |
| * @param hdrLoc request's header location |
| */ |
| void |
| dumpHeaders(TSMBuffer bufp, TSMLoc hdrLoc) |
| { |
| TSIOBuffer output_buffer; |
| TSIOBufferReader reader; |
| TSIOBufferBlock block; |
| const char *block_start; |
| int64_t block_avail; |
| |
| output_buffer = TSIOBufferCreate(); |
| reader = TSIOBufferReaderAlloc(output_buffer); |
| |
| /* This will print just MIMEFields and not the http request line */ |
| TSMimeHdrPrint(bufp, hdrLoc, output_buffer); |
| |
| /* We need to loop over all the buffer blocks, there can be more than 1 */ |
| block = TSIOBufferReaderStart(reader); |
| do { |
| block_start = TSIOBufferBlockReadStart(block, reader, &block_avail); |
| if (block_avail > 0) { |
| PrefetchDebug("Headers are:\n%.*s", static_cast<int>(block_avail), block_start); |
| } |
| TSIOBufferReaderConsume(reader, block_avail); |
| block = TSIOBufferReaderStart(reader); |
| } while (block && block_avail != 0); |
| |
| /* Free up the TSIOBuffer that we used to print out the header */ |
| TSIOBufferReaderFree(reader); |
| TSIOBufferDestroy(output_buffer); |
| } |