blob: f78a11d84444c60e6bc5b336036a35e449e9e10f [file] [log] [blame]
/** @file
A brief file description
@section license License
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.
*/
#pragma once
#include <sys/time.h>
#include <string_view>
#include <string>
#include "tscore/ink_assert.h"
#include "tscore/ink_apidefs.h"
#include "tscore/ink_string++.h"
#include "tscore/ParseRules.h"
#include "HdrHeap.h"
#include "HdrToken.h"
#include "tscpp/util/TextView.h"
/***********************************************************************
* *
* Defines *
* *
***********************************************************************/
enum ParseResult {
PARSE_RESULT_ERROR = -1,
PARSE_RESULT_DONE = 0,
PARSE_RESULT_CONT = 1,
PARSE_RESULT_OK = 3, // This is only used internally in mime_parser_parse and not returned to the user
};
enum {
UNDEFINED_COUNT = -1,
};
/// Parsing state.
enum MimeParseState {
MIME_PARSE_BEFORE, ///< Before a field.
MIME_PARSE_FOUND_CR, ///< Before a field, found a CR.
MIME_PARSE_INSIDE, ///< Inside a field.
MIME_PARSE_AFTER, ///< After a field.
};
/***********************************************************************
* *
* Assertions *
* *
***********************************************************************/
#ifdef ENABLE_MIME_SANITY_CHECK
#define MIME_HDR_SANITY_CHECK mime_hdr_sanity_check
#else
#define MIME_HDR_SANITY_CHECK (void)
#endif
#define MIME_FIELD_SLOT_READINESS_EMPTY 0
#define MIME_FIELD_SLOT_READINESS_DETACHED 1
#define MIME_FIELD_SLOT_READINESS_LIVE 2
#define MIME_FIELD_SLOT_READINESS_DELETED 3
#define MIME_FIELD_SLOT_FLAGS_DUP_HEAD (1 << 0)
#define MIME_FIELD_SLOT_FLAGS_COOKED (1 << 1)
#define MIME_FIELD_BLOCK_SLOTS 16
#define MIME_FIELD_SLOTNUM_BITS 4
#define MIME_FIELD_SLOTNUM_MASK ((1 << MIME_FIELD_SLOTNUM_BITS) - 1)
#define MIME_FIELD_SLOTNUM_MAX (MIME_FIELD_SLOTNUM_MASK - 1)
#define MIME_FIELD_SLOTNUM_UNKNOWN MIME_FIELD_SLOTNUM_MAX
/***********************************************************************
* *
* MIMEField & MIMEFieldBlockImpl *
* *
***********************************************************************/
struct MIMEHdrImpl;
struct MIMEField {
const char *m_ptr_name; // 4
const char *m_ptr_value; // 4
MIMEField *m_next_dup; // 4
int16_t m_wks_idx; // 2
uint16_t m_len_name; // 2
uint32_t m_len_value : 24; // 3
uint8_t m_n_v_raw_printable : 1; // 1/8
uint8_t m_n_v_raw_printable_pad : 3; // 3/8
uint8_t m_readiness : 2; // 2/8
uint8_t m_flags : 2; // 2/8
bool
is_dup_head() const
{
return (m_flags & MIME_FIELD_SLOT_FLAGS_DUP_HEAD);
}
bool
is_cooked()
{
return (m_flags & MIME_FIELD_SLOT_FLAGS_COOKED) ? true : false;
}
bool
is_live() const
{
return (m_readiness == MIME_FIELD_SLOT_READINESS_LIVE);
}
bool
is_detached() const
{
return (m_readiness == MIME_FIELD_SLOT_READINESS_DETACHED);
}
bool
supports_commas() const
{
if (m_wks_idx >= 0) {
return (hdrtoken_index_to_flags(m_wks_idx) & HTIF_COMMAS);
}
return true; // by default, assume supports commas
}
/// @return The name of @a this field.
std::string_view name_get() const;
const char *name_get(int *length) const;
/** Find the index of the value in the multi-value field.
If @a value is one of the values in this field return the
0 based index of it in the list of values. If the field is
not multivalued the index will always be zero if found.
Otherwise return -1 if the @a value is not found.
@note The most common use of this is to check for the presence of a specific
value in a comma enabled field.
@return The index of @a value.
*/
int value_get_index(const char *value, int length) const;
/// @return The value of @a this field.
std::string_view value_get() const;
const char *value_get(int *length) const;
int32_t value_get_int() const;
uint32_t value_get_uint() const;
int64_t value_get_int64() const;
time_t value_get_date() const;
int value_get_comma_list(StrList *list) const;
void name_set(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int length);
bool name_is_valid() const;
void value_set(HdrHeap *heap, MIMEHdrImpl *mh, const char *value, int length);
void value_set_int(HdrHeap *heap, MIMEHdrImpl *mh, int32_t value);
void value_set_uint(HdrHeap *heap, MIMEHdrImpl *mh, uint32_t value);
void value_set_int64(HdrHeap *heap, MIMEHdrImpl *mh, int64_t value);
void value_set_date(HdrHeap *heap, MIMEHdrImpl *mh, time_t value);
void value_clear(HdrHeap *heap, MIMEHdrImpl *mh);
// MIME standard separator ',' is used as the default value
// Other separators (e.g. ';' in Set-cookie/Cookie) are also possible
void value_append(HdrHeap *heap, MIMEHdrImpl *mh, const char *value, int length, bool prepend_comma = false,
const char separator = ',');
bool value_is_valid() const;
int has_dups() const;
};
struct MIMEFieldBlockImpl : public HdrHeapObjImpl {
// HdrHeapObjImpl is 4 bytes
uint32_t m_freetop;
MIMEFieldBlockImpl *m_next;
MIMEField m_field_slots[MIME_FIELD_BLOCK_SLOTS];
// mime_hdr_copy_onto assumes that m_field_slots is last --
// don't add any new fields after it.
// Marshaling Functions
int marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str);
void unmarshal(intptr_t offset);
void move_strings(HdrStrHeap *new_heap);
size_t strings_length();
bool contains(const MIMEField *field);
// Sanity Check Functions
void check_strings(HeapCheck *heaps, int num_heaps);
};
/***********************************************************************
* *
* MIMECooked *
* *
***********************************************************************/
enum MIMECookedMask {
MIME_COOKED_MASK_CC_MAX_AGE = (1 << 0),
MIME_COOKED_MASK_CC_NO_CACHE = (1 << 1),
MIME_COOKED_MASK_CC_NO_STORE = (1 << 2),
MIME_COOKED_MASK_CC_NO_TRANSFORM = (1 << 3),
MIME_COOKED_MASK_CC_MAX_STALE = (1 << 4),
MIME_COOKED_MASK_CC_MIN_FRESH = (1 << 5),
MIME_COOKED_MASK_CC_ONLY_IF_CACHED = (1 << 6),
MIME_COOKED_MASK_CC_PUBLIC = (1 << 7),
MIME_COOKED_MASK_CC_PRIVATE = (1 << 8),
MIME_COOKED_MASK_CC_MUST_REVALIDATE = (1 << 9),
MIME_COOKED_MASK_CC_PROXY_REVALIDATE = (1 << 10),
MIME_COOKED_MASK_CC_S_MAXAGE = (1 << 11),
MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE = (1 << 12),
MIME_COOKED_MASK_CC_EXTENSION = (1 << 13)
};
struct MIMECookedCacheControl {
uint32_t m_mask;
int32_t m_secs_max_age;
int32_t m_secs_s_maxage;
int32_t m_secs_max_stale;
int32_t m_secs_min_fresh;
};
struct MIMECookedPragma {
bool m_no_cache;
};
struct MIMECooked {
MIMECookedCacheControl m_cache_control;
MIMECookedPragma m_pragma;
};
/***********************************************************************
* *
* MIMEHdr *
* *
***********************************************************************/
struct MIMEHdrImpl : public HdrHeapObjImpl {
// HdrHeapObjImpl is 4 bytes, so this will result in 4 bytes padding
uint64_t m_presence_bits;
uint32_t m_slot_accelerators[4];
MIMECooked m_cooked_stuff;
MIMEFieldBlockImpl *m_fblock_list_tail;
MIMEFieldBlockImpl m_first_fblock; // 1 block inline
// mime_hdr_copy_onto assumes that m_first_fblock is last --
// don't add any new fields after it.
// Marshaling Functions
int marshal(MarshalXlate *ptr_xlate, int num_ptr, MarshalXlate *str_xlate, int num_str);
void unmarshal(intptr_t offset);
void move_strings(HdrStrHeap *new_heap);
size_t strings_length();
// Sanity Check Functions
void check_strings(HeapCheck *heaps, int num_heaps);
// Cooked values
void recompute_cooked_stuff(MIMEField *changing_field_or_null = nullptr);
void recompute_accelerators_and_presence_bits();
};
/***********************************************************************
* *
* Parser *
* *
***********************************************************************/
/** A pre-parser used to extract MIME "lines" from raw input for further parsing.
*
* This maintains an internal line buffer which is used to keeping content between calls
* when the parse has not yet completed.
*
*/
struct MIMEScanner {
using self_type = MIMEScanner; ///< Self reference type.
public:
/// Type of input scanning.
enum ScanType {
LINE = 0, ///< Scan a single line.
FIELD = 1, ///< Scan with line folding enabled.
};
void init(); ///< Pseudo-constructor required by proxy allocation.
void clear(); ///< Pseudo-destructor required by proxy allocation.
/// @return The size of the internal line buffer.
size_t get_buffered_line_size() const;
/** Scan @a input for MIME data delimited by CR/LF end of line markers.
*
* @param input [in,out] Text to scan.
* @param output [out] Parsed text from @a input, if any.
* @param output_shares_input [out] Whether @a output is in @a input.
* @param eof_p [in] The source for @a input is done, no more data will ever be available.
* @param scan_type [in] Whether to check for line folding.
* @return The result of scanning.
*
* @a input is updated to remove text that was scanned. @a output is updated to be a view of the
* scanned @a input. This is separate because @a output may be a view of @a input or a view of the
* internal line buffer. Which of these cases obtains is returned in @a output_shares_input. This
* is @c true if @a output is a view of @a input, and @c false if @a output is a view of the
* internal buffer, but is only set if the result is not @c PARSE_RESULT_CONT (that is, it is not
* set until scanning has completed). If @a scan_type is @c FIELD then folded lines are
* accumulated in to a single line stored in the internal buffer. Otherwise the scanning
* terminates at the first CR/LF.
*/
ParseResult get(ts::TextView &input, ts::TextView &output, bool &output_shares_input, bool eof_p, ScanType scan_type);
protected:
/** Append @a text to the internal buffer.
*
* @param text Text to append.
* @return @a this
*
* A copy of @a text is appended to the internal line buffer.
*/
self_type &append(ts::TextView text);
static constexpr MimeParseState INITIAL_PARSE_STATE = MIME_PARSE_BEFORE;
std::string m_line; ///< Internally buffered line data for field coalescence.
MimeParseState m_state{INITIAL_PARSE_STATE}; ///< Parsing machine state.
};
inline size_t
MIMEScanner::get_buffered_line_size() const
{
return m_line.size();
}
inline void
MIMEScanner::clear()
{
std::string empty; // GAH! @c swap isn't defined to take r-value reference!
std::swap(m_line, empty); // make sure the memory is released.
m_state = INITIAL_PARSE_STATE;
}
struct MIMEParser {
MIMEScanner m_scanner;
int32_t m_field;
int m_field_flags;
int m_value;
};
/***********************************************************************
* *
* SDK *
* *
***********************************************************************/
/********************************************/
/* SDK Handles to Fields are special structures */
/********************************************/
struct MIMEFieldSDKHandle : public HdrHeapObjImpl {
MIMEHdrImpl *mh;
MIMEField *field_ptr;
};
/***********************************************************************
* *
* Well-Known Field Name Tokens *
* *
***********************************************************************/
extern const char *MIME_FIELD_ACCEPT;
extern const char *MIME_FIELD_ACCEPT_CHARSET;
extern const char *MIME_FIELD_ACCEPT_ENCODING;
extern const char *MIME_FIELD_ACCEPT_LANGUAGE;
extern const char *MIME_FIELD_ACCEPT_RANGES;
extern const char *MIME_FIELD_AGE;
extern const char *MIME_FIELD_ALLOW;
extern const char *MIME_FIELD_APPROVED;
extern const char *MIME_FIELD_AUTHORIZATION;
extern const char *MIME_FIELD_BYTES;
extern const char *MIME_FIELD_CACHE_CONTROL;
extern const char *MIME_FIELD_CLIENT_IP;
extern const char *MIME_FIELD_CONNECTION;
extern const char *MIME_FIELD_CONTENT_BASE;
extern const char *MIME_FIELD_CONTENT_ENCODING;
extern const char *MIME_FIELD_CONTENT_LANGUAGE;
extern const char *MIME_FIELD_CONTENT_LENGTH;
extern const char *MIME_FIELD_CONTENT_LOCATION;
extern const char *MIME_FIELD_CONTENT_MD5;
extern const char *MIME_FIELD_CONTENT_RANGE;
extern const char *MIME_FIELD_CONTENT_TYPE;
extern const char *MIME_FIELD_CONTROL;
extern const char *MIME_FIELD_COOKIE;
extern const char *MIME_FIELD_DATE;
extern const char *MIME_FIELD_DISTRIBUTION;
extern const char *MIME_FIELD_ETAG;
extern const char *MIME_FIELD_EXPECT;
extern const char *MIME_FIELD_EXPIRES;
extern const char *MIME_FIELD_FOLLOWUP_TO;
extern const char *MIME_FIELD_FROM;
extern const char *MIME_FIELD_HOST;
extern const char *MIME_FIELD_IF_MATCH;
extern const char *MIME_FIELD_IF_MODIFIED_SINCE;
extern const char *MIME_FIELD_IF_NONE_MATCH;
extern const char *MIME_FIELD_IF_RANGE;
extern const char *MIME_FIELD_IF_UNMODIFIED_SINCE;
extern const char *MIME_FIELD_KEEP_ALIVE;
extern const char *MIME_FIELD_KEYWORDS;
extern const char *MIME_FIELD_LAST_MODIFIED;
extern const char *MIME_FIELD_LINES;
inkcoreapi extern const char *MIME_FIELD_LOCATION;
extern const char *MIME_FIELD_MAX_FORWARDS;
extern const char *MIME_FIELD_MESSAGE_ID;
extern const char *MIME_FIELD_NEWSGROUPS;
extern const char *MIME_FIELD_ORGANIZATION;
extern const char *MIME_FIELD_PATH;
extern const char *MIME_FIELD_PRAGMA;
extern const char *MIME_FIELD_PROXY_AUTHENTICATE;
extern const char *MIME_FIELD_PROXY_AUTHORIZATION;
extern const char *MIME_FIELD_PROXY_CONNECTION;
extern const char *MIME_FIELD_PUBLIC;
extern const char *MIME_FIELD_RANGE;
extern const char *MIME_FIELD_REFERENCES;
extern const char *MIME_FIELD_REFERER;
extern const char *MIME_FIELD_REPLY_TO;
extern const char *MIME_FIELD_RETRY_AFTER;
extern const char *MIME_FIELD_SENDER;
extern const char *MIME_FIELD_SERVER;
extern const char *MIME_FIELD_SET_COOKIE;
extern const char *MIME_FIELD_STRICT_TRANSPORT_SECURITY;
extern const char *MIME_FIELD_SUBJECT;
extern const char *MIME_FIELD_SUMMARY;
extern const char *MIME_FIELD_TE;
extern const char *MIME_FIELD_TRANSFER_ENCODING;
extern const char *MIME_FIELD_UPGRADE;
extern const char *MIME_FIELD_USER_AGENT;
extern const char *MIME_FIELD_VARY;
extern const char *MIME_FIELD_VIA;
extern const char *MIME_FIELD_WARNING;
extern const char *MIME_FIELD_WWW_AUTHENTICATE;
extern const char *MIME_FIELD_XREF;
extern const char *MIME_FIELD_ATS_INTERNAL;
extern const char *MIME_FIELD_X_ID;
extern const char *MIME_FIELD_X_FORWARDED_FOR;
extern const char *MIME_FIELD_FORWARDED;
extern const char *MIME_FIELD_SEC_WEBSOCKET_KEY;
extern const char *MIME_FIELD_SEC_WEBSOCKET_VERSION;
extern const char *MIME_FIELD_HTTP2_SETTINGS;
extern const char *MIME_FIELD_EARLY_DATA;
extern const char *MIME_VALUE_BYTES;
extern const char *MIME_VALUE_CHUNKED;
extern const char *MIME_VALUE_CLOSE;
extern const char *MIME_VALUE_COMPRESS;
extern const char *MIME_VALUE_DEFLATE;
extern const char *MIME_VALUE_GZIP;
extern const char *MIME_VALUE_IDENTITY;
extern const char *MIME_VALUE_KEEP_ALIVE;
extern const char *MIME_VALUE_MAX_AGE;
extern const char *MIME_VALUE_MAX_STALE;
extern const char *MIME_VALUE_MIN_FRESH;
extern const char *MIME_VALUE_MUST_REVALIDATE;
extern const char *MIME_VALUE_NONE;
extern const char *MIME_VALUE_NO_CACHE;
extern const char *MIME_VALUE_NO_STORE;
extern const char *MIME_VALUE_NO_TRANSFORM;
extern const char *MIME_VALUE_ONLY_IF_CACHED;
extern const char *MIME_VALUE_PRIVATE;
extern const char *MIME_VALUE_PROXY_REVALIDATE;
extern const char *MIME_VALUE_PUBLIC;
extern const char *MIME_VALUE_S_MAXAGE;
extern const char *MIME_VALUE_NEED_REVALIDATE_ONCE;
extern const char *MIME_VALUE_WEBSOCKET;
extern const char *MIME_VALUE_H2C;
extern int MIME_LEN_ACCEPT;
extern int MIME_LEN_ACCEPT_CHARSET;
extern int MIME_LEN_ACCEPT_ENCODING;
extern int MIME_LEN_ACCEPT_LANGUAGE;
extern int MIME_LEN_ACCEPT_RANGES;
extern int MIME_LEN_AGE;
extern int MIME_LEN_ALLOW;
extern int MIME_LEN_APPROVED;
extern int MIME_LEN_AUTHORIZATION;
extern int MIME_LEN_BYTES;
extern int MIME_LEN_CACHE_CONTROL;
extern int MIME_LEN_CLIENT_IP;
extern int MIME_LEN_CONNECTION;
extern int MIME_LEN_CONTENT_BASE;
extern int MIME_LEN_CONTENT_ENCODING;
extern int MIME_LEN_CONTENT_LANGUAGE;
extern int MIME_LEN_CONTENT_LENGTH;
extern int MIME_LEN_CONTENT_LOCATION;
extern int MIME_LEN_CONTENT_MD5;
extern int MIME_LEN_CONTENT_RANGE;
extern int MIME_LEN_CONTENT_TYPE;
extern int MIME_LEN_CONTROL;
extern int MIME_LEN_COOKIE;
extern int MIME_LEN_DATE;
extern int MIME_LEN_DISTRIBUTION;
extern int MIME_LEN_ETAG;
extern int MIME_LEN_EXPECT;
extern int MIME_LEN_EXPIRES;
extern int MIME_LEN_FOLLOWUP_TO;
extern int MIME_LEN_FROM;
extern int MIME_LEN_HOST;
extern int MIME_LEN_IF_MATCH;
extern int MIME_LEN_IF_MODIFIED_SINCE;
extern int MIME_LEN_IF_NONE_MATCH;
extern int MIME_LEN_IF_RANGE;
extern int MIME_LEN_IF_UNMODIFIED_SINCE;
extern int MIME_LEN_KEEP_ALIVE;
extern int MIME_LEN_KEYWORDS;
extern int MIME_LEN_LAST_MODIFIED;
extern int MIME_LEN_LINES;
inkcoreapi extern int MIME_LEN_LOCATION;
extern int MIME_LEN_MAX_FORWARDS;
extern int MIME_LEN_MESSAGE_ID;
extern int MIME_LEN_NEWSGROUPS;
extern int MIME_LEN_ORGANIZATION;
extern int MIME_LEN_PATH;
extern int MIME_LEN_PRAGMA;
extern int MIME_LEN_PROXY_AUTHENTICATE;
extern int MIME_LEN_PROXY_AUTHORIZATION;
extern int MIME_LEN_PROXY_CONNECTION;
extern int MIME_LEN_PUBLIC;
extern int MIME_LEN_RANGE;
extern int MIME_LEN_REFERENCES;
extern int MIME_LEN_REFERER;
extern int MIME_LEN_REPLY_TO;
extern int MIME_LEN_RETRY_AFTER;
extern int MIME_LEN_SENDER;
extern int MIME_LEN_SERVER;
extern int MIME_LEN_SET_COOKIE;
extern int MIME_LEN_STRICT_TRANSPORT_SECURITY;
extern int MIME_LEN_SUBJECT;
extern int MIME_LEN_SUMMARY;
extern int MIME_LEN_TE;
extern int MIME_LEN_TRANSFER_ENCODING;
extern int MIME_LEN_UPGRADE;
extern int MIME_LEN_USER_AGENT;
extern int MIME_LEN_VARY;
extern int MIME_LEN_VIA;
extern int MIME_LEN_WARNING;
extern int MIME_LEN_WWW_AUTHENTICATE;
extern int MIME_LEN_XREF;
extern int MIME_LEN_ATS_INTERNAL;
extern int MIME_LEN_X_ID;
extern int MIME_LEN_X_FORWARDED_FOR;
extern int MIME_LEN_FORWARDED;
extern int MIME_LEN_BYTES;
extern int MIME_LEN_CHUNKED;
extern int MIME_LEN_CLOSE;
extern int MIME_LEN_COMPRESS;
extern int MIME_LEN_DEFLATE;
extern int MIME_LEN_GZIP;
extern int MIME_LEN_IDENTITY;
extern int MIME_LEN_KEEP_ALIVE;
extern int MIME_LEN_MAX_AGE;
extern int MIME_LEN_MAX_STALE;
extern int MIME_LEN_MIN_FRESH;
extern int MIME_LEN_MUST_REVALIDATE;
extern int MIME_LEN_NONE;
extern int MIME_LEN_NO_CACHE;
extern int MIME_LEN_NO_STORE;
extern int MIME_LEN_NO_TRANSFORM;
extern int MIME_LEN_ONLY_IF_CACHED;
extern int MIME_LEN_PRIVATE;
extern int MIME_LEN_PROXY_REVALIDATE;
extern int MIME_LEN_PUBLIC;
extern int MIME_LEN_S_MAXAGE;
extern int MIME_LEN_NEED_REVALIDATE_ONCE;
extern int MIME_LEN_SEC_WEBSOCKET_KEY;
extern int MIME_LEN_SEC_WEBSOCKET_VERSION;
extern int MIME_LEN_HTTP2_SETTINGS;
extern int MIME_LEN_EARLY_DATA;
extern int MIME_WKSIDX_ACCEPT;
extern int MIME_WKSIDX_ACCEPT_CHARSET;
extern int MIME_WKSIDX_ACCEPT_ENCODING;
extern int MIME_WKSIDX_ACCEPT_LANGUAGE;
extern int MIME_WKSIDX_ACCEPT_RANGES;
extern int MIME_WKSIDX_AGE;
extern int MIME_WKSIDX_ALLOW;
extern int MIME_WKSIDX_APPROVED;
extern int MIME_WKSIDX_AUTHORIZATION;
extern int MIME_WKSIDX_BYTES;
extern int MIME_WKSIDX_CACHE_CONTROL;
extern int MIME_WKSIDX_CLIENT_IP;
extern int MIME_WKSIDX_CONNECTION;
extern int MIME_WKSIDX_CONTENT_BASE;
extern int MIME_WKSIDX_CONTENT_ENCODING;
extern int MIME_WKSIDX_CONTENT_LANGUAGE;
extern int MIME_WKSIDX_CONTENT_LENGTH;
extern int MIME_WKSIDX_CONTENT_LOCATION;
extern int MIME_WKSIDX_CONTENT_MD5;
extern int MIME_WKSIDX_CONTENT_RANGE;
extern int MIME_WKSIDX_CONTENT_TYPE;
extern int MIME_WKSIDX_CONTROL;
extern int MIME_WKSIDX_COOKIE;
extern int MIME_WKSIDX_DATE;
extern int MIME_WKSIDX_DISTRIBUTION;
extern int MIME_WKSIDX_ETAG;
extern int MIME_WKSIDX_EXPECT;
extern int MIME_WKSIDX_EXPIRES;
extern int MIME_WKSIDX_FOLLOWUP_TO;
extern int MIME_WKSIDX_FROM;
extern int MIME_WKSIDX_HOST;
extern int MIME_WKSIDX_IF_MATCH;
extern int MIME_WKSIDX_IF_MODIFIED_SINCE;
extern int MIME_WKSIDX_IF_NONE_MATCH;
extern int MIME_WKSIDX_IF_RANGE;
extern int MIME_WKSIDX_IF_UNMODIFIED_SINCE;
extern int MIME_WKSIDX_KEEP_ALIVE;
extern int MIME_WKSIDX_KEYWORDS;
extern int MIME_WKSIDX_LAST_MODIFIED;
extern int MIME_WKSIDX_LINES;
extern int MIME_WKSIDX_LOCATION;
extern int MIME_WKSIDX_MAX_FORWARDS;
extern int MIME_WKSIDX_MESSAGE_ID;
extern int MIME_WKSIDX_NEWSGROUPS;
extern int MIME_WKSIDX_ORGANIZATION;
extern int MIME_WKSIDX_PATH;
extern int MIME_WKSIDX_PRAGMA;
extern int MIME_WKSIDX_PROXY_AUTHENTICATE;
extern int MIME_WKSIDX_PROXY_AUTHORIZATION;
extern int MIME_WKSIDX_PROXY_CONNECTION;
extern int MIME_WKSIDX_PUBLIC;
extern int MIME_WKSIDX_RANGE;
extern int MIME_WKSIDX_REFERENCES;
extern int MIME_WKSIDX_REFERER;
extern int MIME_WKSIDX_REPLY_TO;
extern int MIME_WKSIDX_RETRY_AFTER;
extern int MIME_WKSIDX_SENDER;
extern int MIME_WKSIDX_SERVER;
extern int MIME_WKSIDX_SET_COOKIE;
extern int MIME_WKSIDX_STRICT_TRANSPORT_SECURITY;
extern int MIME_WKSIDX_SUBJECT;
extern int MIME_WKSIDX_SUMMARY;
extern int MIME_WKSIDX_TE;
extern int MIME_WKSIDX_TRANSFER_ENCODING;
extern int MIME_WKSIDX_UPGRADE;
extern int MIME_WKSIDX_USER_AGENT;
extern int MIME_WKSIDX_VARY;
extern int MIME_WKSIDX_VIA;
extern int MIME_WKSIDX_WARNING;
extern int MIME_WKSIDX_WWW_AUTHENTICATE;
extern int MIME_WKSIDX_XREF;
extern int MIME_WKSIDX_ATS_INTERNAL;
extern int MIME_WKSIDX_X_ID;
extern int MIME_WKSIDX_SEC_WEBSOCKET_KEY;
extern int MIME_WKSIDX_SEC_WEBSOCKET_VERSION;
extern int MIME_WKSIDX_HTTP2_SETTINGS;
extern int MIME_WKSIDX_EARLY_DATA;
/***********************************************************************
* *
* Internal C API *
* *
***********************************************************************/
uint64_t mime_field_presence_mask(const char *well_known_str);
uint64_t mime_field_presence_mask(int well_known_str_index);
int mime_field_presence_get(MIMEHdrImpl *h, const char *well_known_str);
int mime_field_presence_get(MIMEHdrImpl *h, int well_known_str_index);
void mime_hdr_presence_set(MIMEHdrImpl *h, const char *well_known_str);
void mime_hdr_presence_set(MIMEHdrImpl *h, int well_known_str_index);
void mime_hdr_presence_unset(MIMEHdrImpl *h, const char *well_known_str);
void mime_hdr_presence_unset(MIMEHdrImpl *h, int well_known_str_index);
void mime_hdr_sanity_check(MIMEHdrImpl *mh);
void mime_init();
void mime_init_cache_control_cooking_masks();
void mime_init_date_format_table();
MIMEHdrImpl *mime_hdr_create(HdrHeap *heap);
void _mime_hdr_field_block_init(MIMEFieldBlockImpl *fblock);
void mime_hdr_cooked_stuff_init(MIMEHdrImpl *mh, MIMEField *changing_field_or_null = nullptr);
void mime_hdr_init(MIMEHdrImpl *mh);
MIMEFieldBlockImpl *_mime_field_block_copy(MIMEFieldBlockImpl *s_fblock, HdrHeap *s_heap, HdrHeap *d_heap);
void _mime_field_block_destroy(HdrHeap *heap, MIMEFieldBlockImpl *fblock);
void mime_hdr_destroy_field_block_list(HdrHeap *heap, MIMEFieldBlockImpl *head);
void mime_hdr_destroy(HdrHeap *heap, MIMEHdrImpl *mh);
void mime_hdr_copy_onto(MIMEHdrImpl *s_mh, HdrHeap *s_heap, MIMEHdrImpl *d_mh, HdrHeap *d_heap, bool inherit_strs = true);
MIMEHdrImpl *mime_hdr_clone(MIMEHdrImpl *s_mh, HdrHeap *s_heap, HdrHeap *d_heap, bool inherit_strs = true);
void mime_hdr_field_block_list_adjust(int block_count, MIMEFieldBlockImpl *old_list, MIMEFieldBlockImpl *new_list);
int mime_hdr_length_get(MIMEHdrImpl *mh);
void mime_hdr_fields_clear(HdrHeap *heap, MIMEHdrImpl *mh);
MIMEField *_mime_hdr_field_list_search_by_wks(MIMEHdrImpl *mh, int wks_idx);
MIMEField *_mime_hdr_field_list_search_by_string(MIMEHdrImpl *mh, const char *field_name_str, int field_name_len);
MIMEField *_mime_hdr_field_list_search_by_slotnum(MIMEHdrImpl *mh, int slotnum);
inkcoreapi MIMEField *mime_hdr_field_find(MIMEHdrImpl *mh, const char *field_name_str, int field_name_len);
MIMEField *mime_hdr_field_get(MIMEHdrImpl *mh, int idx);
MIMEField *mime_hdr_field_get_slotnum(MIMEHdrImpl *mh, int slotnum);
int mime_hdr_fields_count(MIMEHdrImpl *mh);
void mime_field_init(MIMEField *field);
MIMEField *mime_field_create(HdrHeap *heap, MIMEHdrImpl *mh);
MIMEField *mime_field_create_named(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int length);
void mime_hdr_field_attach(MIMEHdrImpl *mh, MIMEField *field, int check_for_dups, MIMEField *prev_dup);
void mime_hdr_field_detach(MIMEHdrImpl *mh, MIMEField *field, bool detach_all_dups = false);
void mime_hdr_field_delete(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, bool delete_all_dups = false);
/**
* Returned slotnum is not a persistent value. A slotnum may refer a different field after making changes to a mime header.
*/
int mime_hdr_field_slotnum(MIMEHdrImpl *mh, MIMEField *field);
inkcoreapi MIMEField *mime_hdr_prepare_for_value_set(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int name_length);
void mime_field_destroy(MIMEHdrImpl *mh, MIMEField *field);
void mime_field_name_set(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int16_t name_wks_idx_or_neg1, const char *name,
int length, bool must_copy_string);
int32_t mime_field_value_get_int(const MIMEField *field);
uint32_t mime_field_value_get_uint(const MIMEField *field);
int64_t mime_field_value_get_int64(const MIMEField *field);
time_t mime_field_value_get_date(const MIMEField *field);
const char *mime_field_value_get_comma_val(const MIMEField *field, int *length, int idx);
int mime_field_value_get_comma_val_count(const MIMEField *field);
int mime_field_value_get_comma_list(const MIMEField *field, StrList *list);
void mime_field_value_set_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
int new_piece_len);
void mime_field_value_delete_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx);
void mime_field_value_extend_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
int new_piece_len);
void mime_field_value_insert_comma_val(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int idx, const char *new_piece_str,
int new_piece_len);
inkcoreapi void mime_field_value_set(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, const char *value, int length,
bool must_copy_string);
void mime_field_value_set_int(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int32_t value);
void mime_field_value_set_uint(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, uint32_t value);
void mime_field_value_set_int64(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int64_t value);
void mime_field_value_set_date(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, time_t value);
void mime_field_name_value_set(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, int16_t name_wks_idx_or_neg1, const char *name,
int name_length, const char *value, int value_length, int n_v_raw_printable, int n_v_raw_length,
bool must_copy_strings);
void mime_field_value_append(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, const char *value, int length, bool prepend_comma,
const char separator);
void mime_parser_init(MIMEParser *parser);
void mime_parser_clear(MIMEParser *parser);
ParseResult mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char **real_s, const char *real_e,
bool must_copy_strings, bool eof, bool remove_ws_from_field_name, size_t max_hdr_field_size = 131070);
void mime_hdr_describe(HdrHeapObjImpl *raw, bool recurse);
void mime_field_block_describe(HdrHeapObjImpl *raw, bool recurse);
int mime_hdr_print(HdrHeap *heap, MIMEHdrImpl *mh, char *buf_start, int buf_length, int *buf_index_inout,
int *buf_chars_to_skip_inout);
int mime_mem_print(const char *src_d, int src_l, char *buf_start, int buf_length, int *buf_index_inout,
int *buf_chars_to_skip_inout);
int mime_mem_print_lc(const char *src_d, int src_l, char *buf_start, int buf_length, int *buf_index_inout,
int *buf_chars_to_skip_inout);
int mime_field_print(MIMEField *field, char *buf_start, int buf_length, int *buf_index_inout, int *buf_chars_to_skip_inout);
const char *mime_str_u16_set(HdrHeap *heap, const char *s_str, int s_len, const char **d_str, uint16_t *d_len, bool must_copy);
int mime_field_length_get(MIMEField *field);
int mime_format_int(char *buf, int32_t val, size_t buf_len);
int mime_format_uint(char *buf, uint32_t val, size_t buf_len);
int mime_format_int64(char *buf, int64_t val, size_t buf_len);
void mime_days_since_epoch_to_mdy_slowcase(unsigned int days_since_jan_1_1970, int *m_return, int *d_return, int *y_return);
void mime_days_since_epoch_to_mdy(unsigned int days_since_jan_1_1970, int *m_return, int *d_return, int *y_return);
int mime_format_date(char *buffer, time_t value);
int32_t mime_parse_int(const char *buf, const char *end = nullptr);
uint32_t mime_parse_uint(const char *buf, const char *end = nullptr);
int64_t mime_parse_int64(const char *buf, const char *end = nullptr);
int mime_parse_rfc822_date_fastcase(const char *buf, int length, struct tm *tp);
time_t mime_parse_date(const char *buf, const char *end = nullptr);
bool mime_parse_day(const char *&buf, const char *end, int *day);
bool mime_parse_month(const char *&buf, const char *end, int *month);
bool mime_parse_mday(const char *&buf, const char *end, int *mday);
bool mime_parse_year(const char *&buf, const char *end, int *year);
bool mime_parse_time(const char *&buf, const char *end, int *hour, int *min, int *sec);
bool mime_parse_integer(const char *&buf, const char *end, int *integer);
/***********************************************************************
* *
* MIMEField Methods *
* *
***********************************************************************/
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline const char *
MIMEField::name_get(int *length) const
{
auto name{this->name_get()};
*length = int(name.size());
return name.data();
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEField::name_set(HdrHeap *heap, MIMEHdrImpl *mh, const char *name, int length)
{
const char *name_wks;
if (hdrtoken_is_wks(name)) {
int16_t name_wks_idx = hdrtoken_wks_to_index(name);
mime_field_name_set(heap, mh, this, name_wks_idx, name, length, true);
} else {
int field_name_wks_idx = hdrtoken_tokenize(name, length, &name_wks);
mime_field_name_set(heap, mh, this, field_name_wks_idx, (field_name_wks_idx == -1 ? name : name_wks), length, true);
}
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline bool
MIMEField::name_is_valid() const
{
const char *name;
int length;
for (name = name_get(&length); length > 0; length--) {
if (ParseRules::is_control(name[length - 1])) {
return false;
}
}
return true;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline const char *
MIMEField::value_get(int *length) const
{
auto value{this->value_get()};
*length = int(value.size());
return value.data();
}
inline int32_t
MIMEField::value_get_int() const
{
return mime_field_value_get_int(this);
}
inline uint32_t
MIMEField::value_get_uint() const
{
return mime_field_value_get_uint(this);
}
inline int64_t
MIMEField::value_get_int64() const
{
return mime_field_value_get_int64(this);
}
inline time_t
MIMEField::value_get_date() const
{
return mime_field_value_get_date(this);
}
inline int
MIMEField::value_get_comma_list(StrList *list) const
{
return mime_field_value_get_comma_list(this, list);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEField::value_set(HdrHeap *heap, MIMEHdrImpl *mh, const char *value, int length)
{
mime_field_value_set(heap, mh, this, value, length, true);
}
inline void
MIMEField::value_set_int(HdrHeap *heap, MIMEHdrImpl *mh, int32_t value)
{
mime_field_value_set_int(heap, mh, this, value);
}
inline void
MIMEField::value_set_uint(HdrHeap *heap, MIMEHdrImpl *mh, uint32_t value)
{
mime_field_value_set_uint(heap, mh, this, value);
}
inline void
MIMEField::value_set_int64(HdrHeap *heap, MIMEHdrImpl *mh, int64_t value)
{
mime_field_value_set_int64(heap, mh, this, value);
}
inline void
MIMEField::value_set_date(HdrHeap *heap, MIMEHdrImpl *mh, time_t value)
{
mime_field_value_set_date(heap, mh, this, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEField::value_clear(HdrHeap *heap, MIMEHdrImpl *mh)
{
value_set(heap, mh, "", 0);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEField::value_append(HdrHeap *heap, MIMEHdrImpl *mh, const char *value, int length, bool prepend_comma, const char separator)
{
mime_field_value_append(heap, mh, this, value, length, prepend_comma, separator);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline bool
MIMEField::value_is_valid() const
{
const char *value;
int length;
for (value = value_get(&length); length > 0; length--) {
if (ParseRules::is_control(value[length - 1])) {
return false;
}
}
return true;
}
inline int
MIMEField::has_dups() const
{
return (m_next_dup != nullptr);
}
/***********************************************************************
* *
* MIMEFieldIter *
* *
***********************************************************************/
struct MIMEFieldIter {
MIMEFieldIter() {}
uint32_t m_slot = 0;
MIMEFieldBlockImpl *m_block = nullptr;
};
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
/***********************************************************************
* *
* MIMEHdr Class *
* *
***********************************************************************/
class MIMEHdr : public HdrHeapSDKHandle
{
public:
/** Iterator over fields in the header.
* This iterator should be stable over field deletes, but not insertions.
*/
class iterator
{
using self_type = iterator; ///< Self reference types.
public:
iterator() = default;
// STL iterator compliance types.
using difference_type = void;
using value_type = MIMEField;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::forward_iterator_tag;
pointer operator->();
reference operator*();
self_type &operator++();
self_type operator++(int);
bool operator==(self_type const &that);
bool operator!=(self_type const &that);
protected:
MIMEFieldBlockImpl *_block = nullptr; ///< Current block.
unsigned _slot = 0; ///< Slot in @a _block
/// Internal method to move to a valid slot.
/// If the current location is valid, this is a no-op.
self_type &step();
friend class MIMEHdr;
};
MIMEHdrImpl *m_mime = nullptr;
MIMEHdr() = default; // Force the creation of the default constructor
int valid() const;
void create(HdrHeap *heap = nullptr);
void copy(const MIMEHdr *hdr);
int length_get();
void fields_clear();
int fields_count();
MIMEField *field_create(const char *name = nullptr, int length = -1);
MIMEField *field_find(const char *name, int length);
const MIMEField *field_find(const char *name, int length) const;
void field_attach(MIMEField *field);
void field_detach(MIMEField *field, bool detach_all_dups = true);
void field_delete(MIMEField *field, bool delete_all_dups = true);
void field_delete(const char *name, int name_length);
iterator begin();
iterator end();
/*
MIMEField *iter_get_first(MIMEFieldIter *iter);
MIMEField *iter_get(MIMEFieldIter *iter);
MIMEField *iter_get_next(MIMEFieldIter *iter);
*/
uint64_t presence(uint64_t mask);
int print(char *buf, int bufsize, int *bufindex, int *chars_to_skip);
int parse(MIMEParser *parser, const char **start, const char *end, bool must_copy_strs, bool eof, bool remove_ws_from_field_name,
size_t max_hdr_field_size = UINT16_MAX);
int value_get_index(const char *name, int name_length, const char *value, int value_length) const;
const char *value_get(const char *name, int name_length, int *value_length) const;
std::string_view value_get(std::string_view const &name) const; // Convenience overload.
int32_t value_get_int(const char *name, int name_length) const;
uint32_t value_get_uint(const char *name, int name_length) const;
int64_t value_get_int64(const char *name, int name_length) const;
time_t value_get_date(const char *name, int name_length) const;
int value_get_comma_list(const char *name, int name_length, StrList *list) const;
void value_set(const char *name, int name_length, const char *value, int value_length);
void value_set_int(const char *name, int name_length, int32_t value);
void value_set_uint(const char *name, int name_length, uint32_t value);
void value_set_int64(const char *name, int name_length, int64_t value);
void value_set_date(const char *name, int name_length, time_t value);
// MIME standard separator ',' is used as the default value
// Other separators (e.g. ';' in Set-cookie/Cookie) are also possible
void value_append(const char *name, int name_length, const char *value, int value_length, bool prepend_comma = false,
const char separator = ',');
void field_value_set(MIMEField *field, const char *value, int value_length, bool reuse_heaps = false);
void field_value_set_int(MIMEField *field, int32_t value);
void field_value_set_uint(MIMEField *field, uint32_t value);
void field_value_set_int64(MIMEField *field, int64_t value);
void field_value_set_date(MIMEField *field, time_t value);
// MIME standard separator ',' is used as the default value
// Other separators (e.g. ';' in Set-cookie/Cookie) are also possible
void field_value_append(MIMEField *field, const char *value, int value_length, bool prepend_comma = false,
const char separator = ',');
void value_append_or_set(const char *name, const int name_length, char *value, int value_length);
void field_combine_dups(MIMEField *field, bool prepend_comma = false, const char separator = ',');
time_t get_age();
int64_t get_content_length() const;
time_t get_date();
time_t get_expires();
time_t get_if_modified_since();
time_t get_if_unmodified_since();
time_t get_last_modified();
time_t get_if_range_date();
int32_t get_max_forwards();
int32_t get_warning(int idx = 0);
uint32_t get_cooked_cc_mask();
int32_t get_cooked_cc_max_age();
int32_t get_cooked_cc_s_maxage();
int32_t get_cooked_cc_max_stale();
int32_t get_cooked_cc_min_fresh();
bool get_cooked_pragma_no_cache();
/** Get the value of the host field.
This parses the host field for brackets and port value.
@return The mime HOST field if it has a value, @c NULL otherwise.
*/
MIMEField *get_host_port_values(const char **host_ptr, ///< [out] Pointer to host.
int *host_len, ///< [out] Length of host.
const char **port_ptr, ///< [out] Pointer to port.
int *port_len ///< [out] Length of port.
);
void set_cooked_cc_need_revalidate_once();
void unset_cooked_cc_need_revalidate_once();
void set_age(time_t value);
void set_content_length(int64_t value);
void set_date(time_t value);
void set_expires(time_t value);
void set_if_modified_since(time_t value);
void set_if_unmodified_since(time_t value);
void set_last_modified(time_t value);
void set_max_forwards(int32_t value);
void set_warning(int32_t value);
void set_server(const char *server_id_tag, int server_id_tag_size);
// No gratuitous copies & refcounts!
MIMEHdr(const MIMEHdr &m) = delete;
MIMEHdr &operator=(const MIMEHdr &m) = delete;
private:
// Interface to replace (overwrite) field value without
// changing the heap as long as the new value is not longer
// than the current value
bool field_value_replace(MIMEField *field, const char *value, int value_length);
};
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int
MIMEHdr::valid() const
{
return (m_mime && m_heap);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::create(HdrHeap *heap)
{
if (heap) {
m_heap = heap;
} else if (!m_heap) {
m_heap = new_HdrHeap();
}
m_mime = mime_hdr_create(m_heap);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::copy(const MIMEHdr *src_hdr)
{
if (valid()) {
mime_hdr_copy_onto(src_hdr->m_mime, src_hdr->m_heap, m_mime, m_heap, (m_heap != src_hdr->m_heap) ? true : false);
} else {
m_heap = new_HdrHeap();
m_mime = mime_hdr_clone(src_hdr->m_mime, src_hdr->m_heap, m_heap);
}
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int
MIMEHdr::length_get()
{
return mime_hdr_length_get(m_mime);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::fields_clear()
{
mime_hdr_fields_clear(m_heap, m_mime);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int
MIMEHdr::fields_count()
{
return mime_hdr_fields_count(m_mime);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline MIMEField *
MIMEHdr::field_create(const char *name, int length)
{
MIMEField *field = mime_field_create(m_heap, m_mime);
if (name) {
int field_name_wks_idx = hdrtoken_tokenize(name, length);
mime_field_name_set(m_heap, m_mime, field, field_name_wks_idx, name, length, true);
}
return field;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline MIMEField *
MIMEHdr::field_find(const char *name, int length)
{
// ink_assert(valid());
return mime_hdr_field_find(m_mime, name, length);
}
inline const MIMEField *
MIMEHdr::field_find(const char *name, int length) const
{
// ink_assert(valid());
MIMEField *retval = mime_hdr_field_find(const_cast<MIMEHdr *>(this)->m_mime, name, length);
return retval;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::field_attach(MIMEField *field)
{
mime_hdr_field_attach(m_mime, field, 1, nullptr);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::field_detach(MIMEField *field, bool detach_all_dups)
{
mime_hdr_field_detach(m_mime, field, detach_all_dups);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::field_delete(MIMEField *field, bool delete_all_dups)
{
mime_hdr_field_delete(m_heap, m_mime, field, delete_all_dups);
}
inline auto
MIMEHdr::begin() -> iterator
{
iterator spot;
spot._block = &m_mime->m_first_fblock;
spot._slot = 0;
return spot.step();
}
inline auto
MIMEHdr::end() -> iterator
{
return {}; // default constructed iterator.
}
inline auto
MIMEHdr::iterator::step() -> self_type &
{
while (_block) {
auto limit = _block->m_freetop;
while (_slot < limit) {
if (_block->m_field_slots[_slot].is_live()) {
return *this;
}
++_slot;
}
_block = _block->m_next;
_slot = 0;
}
return *this;
}
inline auto
MIMEHdr::iterator::operator*() -> reference
{
return _block->m_field_slots[_slot];
}
inline auto
MIMEHdr::iterator::operator->() -> pointer
{
return &(_block->m_field_slots[_slot]);
}
inline bool
MIMEHdr::iterator::operator==(const self_type &that)
{
return _block == that._block && _slot == that._slot;
}
inline bool
MIMEHdr::iterator::operator!=(const self_type &that)
{
return _block != that._block || _slot != that._slot;
}
inline auto
MIMEHdr::iterator::operator++() -> self_type &
{
if (_block) {
++_slot;
this->step();
}
return *this;
}
inline auto
MIMEHdr::iterator::operator++(int) -> self_type
{
self_type zret{*this};
this->step();
return zret;
}
inline void
MIMEHdr::field_delete(const char *name, int name_length)
{
MIMEField *field = field_find(name, name_length);
if (field)
field_delete(field);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline uint64_t
MIMEHdr::presence(uint64_t mask)
{
return (m_mime->m_presence_bits & mask);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int
MIMEHdr::print(char *buf, int bufsize, int *bufindex, int *chars_to_skip)
{
return mime_hdr_print(m_heap, m_mime, buf, bufsize, bufindex, chars_to_skip);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int
MIMEHdr::parse(MIMEParser *parser, const char **start, const char *end, bool must_copy_strs, bool eof,
bool remove_ws_from_field_name, size_t max_hdr_field_size)
{
if (!m_heap)
m_heap = new_HdrHeap();
if (!m_mime)
m_mime = mime_hdr_create(m_heap);
return mime_parser_parse(parser, m_heap, m_mime, start, end, must_copy_strs, eof, remove_ws_from_field_name, max_hdr_field_size);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int
MIMEHdr::value_get_index(const char *name, int name_length, const char *value, int value_length) const
{
const MIMEField *field = field_find(name, name_length);
if (field) {
return field->value_get_index(value, value_length);
}
return -1;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline const char *
MIMEHdr::value_get(const char *name, int name_length, int *value_length_return) const
{
const MIMEField *field = field_find(name, name_length);
if (field) {
return field->value_get(value_length_return);
}
return nullptr;
}
inline std::string_view
MIMEHdr::value_get(std::string_view const &name) const
{
MIMEField const *field = field_find(name.data(), name.size());
if (field) {
return field->value_get();
}
return {};
}
inline int32_t
MIMEHdr::value_get_int(const char *name, int name_length) const
{
const MIMEField *field = field_find(name, name_length);
if (field) {
return mime_field_value_get_int(field);
}
return 0;
}
inline uint32_t
MIMEHdr::value_get_uint(const char *name, int name_length) const
{
const MIMEField *field = field_find(name, name_length);
if (field) {
return mime_field_value_get_uint(field);
}
return 0;
}
inline int64_t
MIMEHdr::value_get_int64(const char *name, int name_length) const
{
const MIMEField *field = field_find(name, name_length);
if (field) {
return mime_field_value_get_int64(field);
}
return 0;
}
inline time_t
MIMEHdr::value_get_date(const char *name, int name_length) const
{
const MIMEField *field = field_find(name, name_length);
if (field) {
return mime_field_value_get_date(field);
}
return 0;
}
inline int
MIMEHdr::value_get_comma_list(const char *name, int name_length, StrList *list) const
{
const MIMEField *field = field_find(name, name_length);
if (field) {
return field->value_get_comma_list(list);
}
return 0;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline bool
MIMEHdr::field_value_replace(MIMEField *field, const char *value, int value_length)
{
if (field->m_len_value >= value_length) {
memcpy((char *)field->m_ptr_value, value, value_length);
field->m_len_value = value_length;
return true;
}
return false;
}
inline void
MIMEHdr::field_value_set(MIMEField *field, const char *value, int value_length, bool reuse_heaps)
{
if (!reuse_heaps || !field_value_replace(field, value, value_length)) {
field->value_set(m_heap, m_mime, value, value_length);
}
}
inline void
MIMEHdr::field_value_set_int(MIMEField *field, int32_t value)
{
field->value_set_int(m_heap, m_mime, value);
}
inline void
MIMEHdr::field_value_set_uint(MIMEField *field, uint32_t value)
{
field->value_set_uint(m_heap, m_mime, value);
}
inline void
MIMEHdr::field_value_set_int64(MIMEField *field, int64_t value)
{
field->value_set_int64(m_heap, m_mime, value);
}
inline void
MIMEHdr::field_value_set_date(MIMEField *field, time_t value)
{
field->value_set_date(m_heap, m_mime, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::field_value_append(MIMEField *field, const char *value_str, int value_len, bool prepend_comma, const char separator)
{
field->value_append(m_heap, m_mime, value_str, value_len, prepend_comma, separator);
}
inline void
MIMEHdr::field_combine_dups(MIMEField *field, bool prepend_comma, const char separator)
{
MIMEField *current = field->m_next_dup;
while (current) {
int value_len = 0;
const char *value_str = current->value_get(&value_len);
if (value_len > 0) {
HdrHeap::HeapGuard guard(m_heap, value_str); // reference count the source string so it doesn't get moved
field->value_append(m_heap, m_mime, value_str, value_len, prepend_comma, separator);
}
field_delete(current, false); // don't delete duplicates
current = field->m_next_dup;
}
}
inline void
MIMEHdr::value_append_or_set(const char *name, const int name_length, char *value, int value_length)
{
MIMEField *field = nullptr;
if ((field = field_find(name, name_length)) != nullptr) {
while (field->m_next_dup) {
field = field->m_next_dup;
}
field_value_append(field, value, value_length, true);
} else {
value_set(name, name_length, value, value_length);
}
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::value_set(const char *name, int name_length, const char *value, int value_length)
{
MIMEField *field;
field = mime_hdr_prepare_for_value_set(m_heap, m_mime, name, name_length);
field->value_set(m_heap, m_mime, value, value_length);
}
inline void
MIMEHdr::value_set_int(const char *name, int name_length, int32_t value)
{
MIMEField *field;
field = mime_hdr_prepare_for_value_set(m_heap, m_mime, name, name_length);
field->value_set_int(m_heap, m_mime, value);
}
inline void
MIMEHdr::value_set_uint(const char *name, int name_length, uint32_t value)
{
MIMEField *field;
field = mime_hdr_prepare_for_value_set(m_heap, m_mime, name, name_length);
field->value_set_uint(m_heap, m_mime, value);
}
inline void
MIMEHdr::value_set_int64(const char *name, int name_length, int64_t value)
{
MIMEField *field;
field = mime_hdr_prepare_for_value_set(m_heap, m_mime, name, name_length);
field->value_set_int64(m_heap, m_mime, value);
}
inline void
MIMEHdr::value_set_date(const char *name, int name_length, time_t value)
{
MIMEField *field;
field = mime_hdr_prepare_for_value_set(m_heap, m_mime, name, name_length);
field->value_set_date(m_heap, m_mime, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::value_append(const char *name, int name_length, const char *value, int value_length, bool prepend_comma,
const char separator)
{
MIMEField *field;
field = field_find(name, name_length);
if (field) {
while (field->m_next_dup)
field = field->m_next_dup;
field->value_append(m_heap, m_mime, value, value_length, prepend_comma, separator);
} else {
field = field_create(name, name_length);
field_attach(field);
field->value_set(m_heap, m_mime, value, value_length);
}
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline time_t
MIMEHdr::get_age()
{
int64_t age = value_get_int64(MIME_FIELD_AGE, MIME_LEN_AGE);
if (age < 0) // We should ignore negative Age: values
return 0;
if ((4 == sizeof(time_t)) && (age > INT_MAX)) // Overflow
return -1;
return age;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int64_t
MIMEHdr::get_content_length() const
{
return value_get_int64(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline time_t
MIMEHdr::get_date()
{
return value_get_date(MIME_FIELD_DATE, MIME_LEN_DATE);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline time_t
MIMEHdr::get_expires()
{
return value_get_date(MIME_FIELD_EXPIRES, MIME_LEN_EXPIRES);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline time_t
MIMEHdr::get_if_modified_since()
{
return value_get_date(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline time_t
MIMEHdr::get_if_unmodified_since()
{
return value_get_date(MIME_FIELD_IF_UNMODIFIED_SINCE, MIME_LEN_IF_UNMODIFIED_SINCE);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline time_t
MIMEHdr::get_last_modified()
{
return value_get_date(MIME_FIELD_LAST_MODIFIED, MIME_LEN_LAST_MODIFIED);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline time_t
MIMEHdr::get_if_range_date()
{
return value_get_date(MIME_FIELD_IF_RANGE, MIME_LEN_IF_RANGE);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int32_t
MIMEHdr::get_max_forwards()
{
return value_get_int(MIME_FIELD_MAX_FORWARDS, MIME_LEN_MAX_FORWARDS);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int32_t
MIMEHdr::get_warning(int idx)
{
(void)idx;
// FIXME: what do we do here?
ink_release_assert(!"unimplemented");
return 0;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline uint32_t
MIMEHdr::get_cooked_cc_mask()
{
return m_mime->m_cooked_stuff.m_cache_control.m_mask;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int32_t
MIMEHdr::get_cooked_cc_max_age()
{
return m_mime->m_cooked_stuff.m_cache_control.m_secs_max_age;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int32_t
MIMEHdr::get_cooked_cc_s_maxage()
{
return m_mime->m_cooked_stuff.m_cache_control.m_secs_s_maxage;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int32_t
MIMEHdr::get_cooked_cc_max_stale()
{
return m_mime->m_cooked_stuff.m_cache_control.m_secs_max_stale;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline int32_t
MIMEHdr::get_cooked_cc_min_fresh()
{
return m_mime->m_cooked_stuff.m_cache_control.m_secs_min_fresh;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline bool
MIMEHdr::get_cooked_pragma_no_cache()
{
return m_mime->m_cooked_stuff.m_pragma.m_no_cache;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_cooked_cc_need_revalidate_once()
{
m_mime->m_cooked_stuff.m_cache_control.m_mask |= MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::unset_cooked_cc_need_revalidate_once()
{
m_mime->m_cooked_stuff.m_cache_control.m_mask &= ~((uint32_t)MIME_COOKED_MASK_CC_NEED_REVALIDATE_ONCE);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_age(time_t value)
{
if (value < 0)
value_set_uint(MIME_FIELD_AGE, MIME_LEN_AGE, (uint32_t)INT_MAX + 1);
else {
if (sizeof(time_t) > 4) {
value_set_int64(MIME_FIELD_AGE, MIME_LEN_AGE, value);
} else {
value_set_uint(MIME_FIELD_AGE, MIME_LEN_AGE, value);
}
}
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_content_length(int64_t value)
{
value_set_int64(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_date(time_t value)
{
value_set_date(MIME_FIELD_DATE, MIME_LEN_DATE, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_expires(time_t value)
{
value_set_date(MIME_FIELD_EXPIRES, MIME_LEN_EXPIRES, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_if_modified_since(time_t value)
{
value_set_date(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_if_unmodified_since(time_t value)
{
value_set_date(MIME_FIELD_IF_UNMODIFIED_SINCE, MIME_LEN_IF_UNMODIFIED_SINCE, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_last_modified(time_t value)
{
value_set_date(MIME_FIELD_LAST_MODIFIED, MIME_LEN_LAST_MODIFIED, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_max_forwards(int32_t value)
{
value_set_int(MIME_FIELD_MAX_FORWARDS, MIME_LEN_MAX_FORWARDS, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_warning(int32_t value)
{
value_set_int(MIME_FIELD_WARNING, MIME_LEN_WARNING, value);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
inline void
MIMEHdr::set_server(const char *server_id_tag, int server_id_tag_size)
{
value_set(MIME_FIELD_SERVER, MIME_LEN_SERVER, server_id_tag, server_id_tag_size);
}