Commit 415a5486 authored by Pekka Pessi's avatar Pekka Pessi
Browse files

Added hc_update member to msg_hclass_t.

The hc_update is used to update shortcuts to well-known parameters.
Updated manipulation functions for header parameters to use hc_update.
Added updating functions for SIP headers.

darcs-hash:20051222130613-65a35-cc639bb9b1e29eaea3fc2c180bfba0520e55a20e.gz
parent 66dc420c
......@@ -66,21 +66,23 @@
#define HTTP_HCLASS_TEST(x) ((x) && (x)->hc_tag == HTTP_PROTOCOL_TAG)
#define HTTP_HDR_TEST(x) ((x)->sh_class && HTTP_HCLASS_TEST((x)->sh_class))
#define http_no_update NULL
/** Define a header class for a HTTP header. */
#define HTTP_HEADER_CLASS(c, l, params, kind, dup) \
MSG_HEADER_CLASS(http_, c, l, "", params, kind, http_ ## dup)
MSG_HEADER_CLASS(http_, c, l, "", params, kind, http_ ## dup, http_no)
/** This is used by headers with no extra data in copy */
#define HTTP_HEADER_CLASS_G(c, l, kind) \
MSG_HEADER_CLASS(http_, c, l, "", g_common, kind, msg_generic)
MSG_HEADER_CLASS(http_, c, l, "", g_common, kind, msg_generic, http_no)
/** Define a header class for a msg_list_t kind of header */
#define HTTP_HEADER_CLASS_LIST(c, l, kind) \
MSG_HEADER_CLASS(http_, c, l, "", k_items, kind, msg_list)
MSG_HEADER_CLASS(http_, c, l, "", k_items, kind, msg_list, http_no)
/** Define a authorization header class */
#define HTTP_HEADER_CLASS_AUTH(c, l, kind) \
MSG_HEADER_CLASS(http_, c, l, "", au_params, kind, msg_auth)
MSG_HEADER_CLASS(http_, c, l, "", au_params, kind, msg_auth, http_no)
/* ---------------------------------------------------------------------------
......
......@@ -52,6 +52,8 @@
#include <msg_parser.h>
#include <msg_header.h>
#define msg_generic_update NULL
/* ====================================================================== */
/**@ingroup msg_headers
......@@ -75,7 +77,8 @@ char *msg_error_dup_one(msg_header_t *dst, msg_header_t const *src,
char *b, int xtra);
msg_hclass_t msg_error_class[] =
MSG_HEADER_CLASS(msg_, error, "", "", er_common, append, msg_error);
MSG_HEADER_CLASS(msg_, error, "", "", er_common, append,
msg_error, msg_generic);
int msg_error_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -121,7 +124,8 @@ char *msg_error_dup_one(msg_header_t *dst, msg_header_t const *src,
*/
msg_hclass_t msg_unknown_class[] =
MSG_HEADER_CLASS(msg_, unknown, "", "", un_common, append, msg_unknown);
MSG_HEADER_CLASS(msg_, unknown, "", "", un_common, append,
msg_unknown, msg_generic);
int msg_unknown_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -200,7 +204,8 @@ char *msg_unknown_dup_one(msg_header_t *dst, msg_header_t const *src,
*/
msg_hclass_t msg_payload_class[1] =
MSG_HEADER_CLASS(msg_, payload, NULL, "", pl_common, append, msg_payload);
MSG_HEADER_CLASS(msg_, payload, NULL, "", pl_common, append,
msg_payload, msg_generic);
/** Create a MIME payload */
msg_payload_t *msg_payload_create(su_home_t *home, void const *data, int len)
......@@ -304,7 +309,8 @@ int msg_payload_length(msg_payload_t const *pl)
*/
msg_hclass_t msg_separator_class[] =
MSG_HEADER_CLASS(msg_, separator, NULL, "", sep_common, single, msg_default);
MSG_HEADER_CLASS(msg_, separator, NULL, "", sep_common, single,
msg_default, msg_generic);
/** Calculate length of line ending (0, 1 or 2) */
#define CRLF_TEST(s) ((s[0]) == '\r' ? ((s[1]) == '\n') + 1 : (s[0])=='\n')
......
......@@ -236,6 +236,9 @@ msg_header_t *msg_header_dup_one(su_home_t *home,
return NULL;
}
if (hc->hc_update)
msg_header_update_params(h->sh_common, 1);
assert(end == (char *)h + size + xtra);
return h;
......@@ -280,6 +283,9 @@ msg_header_t *msg_header_dup_as(su_home_t *home, msg_hclass_t *hc,
if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
break; /* error */
if (hc->hc_update)
msg_header_update_params(h->sh_common, 1);
assert(end == (char *)h + size + xtra);
*prev = h;
......
......@@ -101,12 +101,15 @@ union msg_mime_u
/** Define a header class for headers without any extra data to copy */
#define MSG_HEADER_CLASS_G(c, l, s, kind) \
MSG_HEADER_CLASS(msg_, c, l, s, g_common, kind, msg_generic)
MSG_HEADER_CLASS(msg_, c, l, s, g_common, kind, msg_generic, msg_generic)
#define msg_generic_update NULL
/** Define a header class for a msg_list_t kind of header */
#define MSG_HEADER_CLASS_LIST(c, l, s, kind) \
MSG_HEADER_CLASS(msg_, c, l, s, k_items, kind, msg_list)
MSG_HEADER_CLASS(msg_, c, l, s, k_items, kind, msg_list, msg_list)
#define msg_list_update NULL
/* ====================================================================== */
......@@ -479,8 +482,8 @@ msg_multipart_t *msg_multipart_parse(su_home_t *home,
assert(mp);
if (!mp)
break; /* error */
mp->mp_close_delim =
msg_header_alloc(msg_home(msg), msg_payload_class, 0)->sh_payload;
mp->mp_close_delim = (msg_payload_t *)
msg_header_alloc(msg_home(msg), msg_payload_class, 0);
if (!mp->mp_close_delim)
break; /* error */
/* Include also transport-padding and epilogue in the close-delimiter */
......@@ -934,6 +937,8 @@ char *msg_multipart_dup_one(msg_header_t *dst, msg_header_t const *src,
memset(dst, 0, sizeof dst->sh_common);
dst->sh_class = h->sh_class;
b = h->sh_class->hc_dup_one(dst, h, b + h->sh_class->hc_size, end - b);
if (h->sh_class->hc_update)
msg_header_update_params(h->sh_common, 0);
assert(b <= end);
}
}
......@@ -1083,11 +1088,9 @@ int msg_mediatype_d(char **ss, char const **type)
* @endcode
*/
static inline
void msg_accept_update(msg_accept_t *ac);
msg_hclass_t msg_accept_class[] =
MSG_HEADER_CLASS(msg_, accept, "Accept", "", ac_params, apndlist, msg_accept);
MSG_HEADER_CLASS(msg_, accept, "Accept", "", ac_params, apndlist,
msg_accept, msg_accept);
int msg_accept_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -1121,7 +1124,7 @@ int msg_accept_d(su_home_t *home, msg_header_t *h, char *s, int slen)
return -1;
if (ac->ac_params)
msg_accept_update(ac);
msg_header_update_params(ac->ac_common, 0);
h = NULL;
}
......@@ -1177,8 +1180,6 @@ char *msg_accept_dup_one(msg_header_t *dst, msg_header_t const *src,
MSG_STRING_DUP(b, ac->ac_type, o->ac_type);
if ((ac->ac_subtype = strchr(ac->ac_type, '/')))
ac->ac_subtype++;
if (ac->ac_params) msg_accept_update((msg_accept_t *)dst);
}
assert(b <= end);
......@@ -1186,10 +1187,22 @@ char *msg_accept_dup_one(msg_header_t *dst, msg_header_t const *src,
return b;
}
static inline
void msg_accept_update(msg_accept_t *ac)
/** Update parameter(s) for Accept header. */
int msg_accept_update(msg_common_t *h,
char const *name, int namelen,
char const *value)
{
ac->ac_q = msg_header_find_param(ac->ac_common, "q=");
msg_accept_t *ac = (msg_accept_t *)h;
if (name == NULL) {
ac->ac_q = NULL;
}
else if (namelen == 1 && strncasecmp(name, "q", 1) == 0) {
/* XXX - check for invalid value? */
ac->ac_q = value;
}
return 0;
}
/* ====================================================================== */
......@@ -1217,26 +1230,19 @@ int msg_accept_any_d(su_home_t *home,
aa = aa->aa_next = (msg_accept_any_t *)h;
}
/* "Accept-*:" 1#(token [; "q" = qvalue ]) */
/* "Accept-*:" 1#(token *(SEMI accept-param)) */
if (msg_token_d(&s, &aa->aa_value) == -1)
return -1;
if (*s == ';') {
*s++ = '\0';
skip_lws(&s);
if (*s++ != 'q')
return -1;
skip_lws(&s);
if (*s++ != '=')
return -1;
skip_lws(&s);
if (msg_token_d(&s, &aa->aa_q) == -1)
return -1;
}
if (*s == ';' && msg_params_d(home, &s, &aa->aa_params) == -1)
return -1;
if (*s != '\0' && *s != ',')
return -1;
if (aa->aa_params)
msg_header_update_params(aa->aa_common, 0);
h = NULL;
}
......@@ -1254,10 +1260,7 @@ int msg_accept_any_e(char b[], int bsiz, msg_header_t const *h, int f)
msg_accept_any_t const *aa = (msg_accept_any_t *)h;
MSG_STRING_E(b, end, aa->aa_value);
if (aa->aa_q) {
MSG_STRING_E(b, end, ";q=");
MSG_STRING_E(b, end, aa->aa_q);
}
MSG_PARAMS_E(b, end, aa->aa_params, flags);
MSG_TERM_E(b, end);
return b - b0;
......@@ -1270,8 +1273,8 @@ int msg_accept_any_dup_xtra(msg_header_t const *h, int offset)
int rv = offset;
msg_accept_any_t const *aa = (msg_accept_any_t *)h;
MSG_PARAMS_SIZE(rv, aa->aa_params);
rv += MSG_STRING_SIZE(aa->aa_value);
rv += MSG_STRING_SIZE(aa->aa_q);
return rv;
}
......@@ -1285,14 +1288,31 @@ char *msg_accept_any_dup_one(msg_header_t *dst, msg_header_t const *src,
msg_accept_any_t const *o = (msg_accept_any_t *)src;
char *end = b + xtra;
b = msg_params_dup(&aa->aa_params, o->aa_params, b, xtra);
MSG_STRING_DUP(b, aa->aa_value, o->aa_value);
MSG_STRING_DUP(b, aa->aa_q, o->aa_q);
assert(b <= end);
return b;
}
/** Update parameter(s) for Accept-* header. */
int msg_accept_any_update(msg_common_t *h,
char const *name, int namelen,
char const *value)
{
msg_accept_any_t *aa = (msg_accept_any_t *)h;
if (name == NULL) {
aa->aa_q = NULL;
}
else if (namelen == 1 && strncasecmp(name, "q", 1) == 0) {
aa->aa_q = value;
}
return 0;
}
/* ====================================================================== */
/**@ingroup msg_mime
......@@ -1321,6 +1341,7 @@ char *msg_accept_any_dup_one(msg_header_t *dst, msg_header_t const *src,
* msg_common_t aa_common[1]; // Common fragment info
* msg_accept_any_t *aa_next; // Pointer to next Accept-Charset
* char const *aa_value; // Charset
* msg_param_t const *aa_params; // Parameter list
* char const *aa_q; // Q-value
* } msg_accept_charset_t;
* @endcode
......@@ -1328,7 +1349,7 @@ char *msg_accept_any_dup_one(msg_header_t *dst, msg_header_t const *src,
msg_hclass_t msg_accept_charset_class[1] =
MSG_HEADER_CLASS(msg_, accept_charset, "Accept-Charset", "",
aa_params, apndlist, msg_accept_any);
aa_params, apndlist, msg_accept_any, msg_accept_any);
int msg_accept_charset_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -1371,6 +1392,7 @@ int msg_accept_charset_e(char b[], int bsiz, msg_header_t const *h, int f)
* msg_common_t aa_common[1]; // Common fragment info
* msg_accept_any_t *aa_next; // Pointer to next Accept-Encoding
* char const *aa_value; // Content-coding
* msg_param_t const *aa_params; // Parameter list
* char const *aa_q; // Q-value
* } msg_accept_encoding_t;
* @endcode
......@@ -1378,7 +1400,7 @@ int msg_accept_charset_e(char b[], int bsiz, msg_header_t const *h, int f)
msg_hclass_t msg_accept_encoding_class[1] =
MSG_HEADER_CLASS(msg_, accept_encoding, "Accept-Encoding", "",
aa_params, apndlist, msg_accept_any);
aa_params, apndlist, msg_accept_any, msg_accept_any);
int msg_accept_encoding_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -1421,6 +1443,7 @@ int msg_accept_encoding_e(char b[], int bsiz, msg_header_t const *h, int f)
* msg_common_t aa_common[1]; // Common fragment info
* msg_accept_any_t *aa_next; // Pointer to next Accept-Encoding
* char const *aa_value; // Language-range
* msg_param_t const *aa_params; // Parameter list
* char const *aa_q; // Q-value
* } msg_accept_language_t;
* @endcode
......@@ -1428,7 +1451,7 @@ int msg_accept_encoding_e(char b[], int bsiz, msg_header_t const *h, int f)
msg_hclass_t msg_accept_language_class[1] =
MSG_HEADER_CLASS(msg_, accept_language, "Accept-Language", "",
aa_params, apndlist, msg_accept_any);
aa_params, apndlist, msg_accept_any, msg_accept_any);
int msg_accept_language_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -1503,9 +1526,8 @@ int msg_accept_language_e(char b[], int bsiz, msg_header_t const *h, int f)
msg_hclass_t msg_content_disposition_class[] =
MSG_HEADER_CLASS(msg_, content_disposition, "Content-Disposition", "",
cd_params, single, msg_content_disposition);
static void msg_content_disposition_update(msg_content_disposition_t *cd);
cd_params, single, msg_content_disposition,
msg_content_disposition);
int msg_content_disposition_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -1516,7 +1538,7 @@ int msg_content_disposition_d(su_home_t *home, msg_header_t *h, char *s, int sle
return -1;
if (cd->cd_params)
msg_content_disposition_update(cd);
msg_header_update_params(cd->cd_common, 0);
return 0;
}
......@@ -1559,30 +1581,29 @@ char *msg_content_disposition_dup_one(msg_header_t *dst,
b = msg_params_dup(&cd->cd_params, o->cd_params, b, xtra);
MSG_STRING_DUP(b, cd->cd_type, o->cd_type);
if (cd->cd_params)
msg_content_disposition_update((msg_content_disposition_t *)dst);
assert(b <= end);
return b;
}
static void msg_content_disposition_update(msg_content_disposition_t *cd)
/** Update Content-Disposition parameters */
int msg_content_disposition_update(msg_common_t *h,
char const *name, int namelen,
char const *value)
{
int i;
msg_param_t h;
msg_content_disposition_t *cd = (msg_content_disposition_t *)h;
cd->cd_handling = NULL, cd->cd_required = 0, cd->cd_optional = 0;
if (name == NULL) {
cd->cd_handling = NULL, cd->cd_required = 0, cd->cd_optional = 0;
}
else if (namelen == strlen("handling") &&
strncasecmp(name, "handling", namelen) == 0) {
cd->cd_handling = value;
cd->cd_required = strcasecmp(value, "required") == 0;
cd->cd_optional = strcasecmp(value, "optional") == 0;
}
if (cd->cd_params)
for (i = 0; (h = cd->cd_params[i]); i++) {
if (strncasecmp(h, "handling=", strlen("handling=")) == 0) {
h += strlen("handling=");
cd->cd_handling = h;
cd->cd_required = strcasecmp(h, "required") == 0;
cd->cd_optional = strcasecmp(h, "optional") == 0;
}
}
return 0;
}
/* ====================================================================== */
......@@ -1618,7 +1639,7 @@ static void msg_content_disposition_update(msg_content_disposition_t *cd)
*/
msg_hclass_t msg_content_encoding_class[] =
MSG_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list);
MSG_HEADER_CLASS_LIST(content_encoding, "Content-Encoding", "e", list);
int msg_content_encoding_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -1723,7 +1744,7 @@ int msg_content_language_e(char b[], int bsiz, msg_header_t const *h, int f)
msg_hclass_t msg_content_length_class[] =
MSG_HEADER_CLASS(msg_, content_length, "Content-Length", "l",
l_common, single_critical, msg_default);
l_common, single_critical, msg_default, msg_generic);
/**@ingroup msg_content_length
*Create a @b Content-Length header object.
......@@ -1864,9 +1885,11 @@ MSG_HEADER_CLASS_G(content_id, "Content-ID", "", single);
* whitespace around the slash.
*/
#define msg_content_type_update NULL
msg_hclass_t msg_content_type_class[] =
MSG_HEADER_CLASS(msg_, content_type, "Content-Type", "c", c_params,
single, msg_content_type);
single, msg_content_type, msg_content_type);
int msg_content_type_d(su_home_t *home, msg_header_t *h, char *s, int slen)
{
......@@ -2210,5 +2233,8 @@ char *msg_warning_dup_one(msg_header_t *dst,
return b;
}
#define msg_warning_update NULL
msg_hclass_t msg_warning_class[] =
MSG_HEADER_CLASS(msg_, warning, "Warning", "", w_common, append, msg_warning);
MSG_HEADER_CLASS(msg_, warning, "Warning", "", w_common, append,
msg_warning, msg_warning);
......@@ -81,7 +81,7 @@ struct msg_accept_s
char const *ac_type; /**< Pointer to type/subtype */
char const *ac_subtype; /**< Points after first slash in type */
msg_param_t const *ac_params; /**< List of parameters */
msg_param_t ac_q; /**< Value of q parameter */
char const *ac_q; /**< Value of q parameter */
};
/**@ingroup msg_accept_encoding
......@@ -106,7 +106,7 @@ struct msg_content_disposition_s
msg_error_t *cd_next; /**< Link to next (dummy) */
char const *cd_type; /**< Disposition type */
msg_param_t const *cd_params; /**< List of parameters */
msg_param_t cd_handling; /**< Value of @b handling parameter */
char const *cd_handling; /**< Value of @b handling parameter */
unsigned cd_required:1; /**< True if handling=required */
unsigned cd_optional:1; /**< True if handling=optional */
unsigned :0; /* pad */
......
......@@ -310,4 +310,9 @@ su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt,
/** @} */
/* Internal prototypes */
MSG_DLL msg_update_f msg_accept_update;
MSG_DLL msg_update_f msg_accept_any_update;
MSG_DLL msg_update_f msg_content_disposition_update;
#endif /** !defined(MSG_MIME_PROTOS_H) */
......@@ -60,8 +60,11 @@
#define msg_status_class NULL
#define mp_status mp_common
#define MSG_MULTIPART_HCLASS \
MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, msg_multipart)
#define msg_multipart_update NULL
#define MSG_MULTIPART_HCLASS \
MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, \
msg_multipart, msg_multipart)
......@@ -2332,6 +2332,9 @@ int msg_header_add_dup(msg_t *msg,
if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
return -1; /* error */
if (hc->hc_update)
msg_header_update_params(h->sh_common, 0);
assert(end == (char *)h + size + xtra);
if (msg_header_add(msg, pub, hh, h) < 0)
......
......@@ -62,28 +62,30 @@
#if HAVE_STRUCT_KEYWORDS
/** Define a header class */
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup) \
{{ \
hc_hash: pr##c##_hash, \
hc_parse: pr##c##_d, \
hc_print: pr##c##_e, \
hc_dxtra: dup##_dup_xtra, \
hc_dup_one: dup##_dup_one, \
hc_name: l, \
hc_len: sizeof(l) - 1, \
hc_short: s, \
hc_size: MSG_ALIGN(sizeof(pr##c##_t), sizeof(void*)), \
hc_params: offsetof(pr##c##_t, params), \
hc_kind: msg_kind_##kind, \
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
{{ \
hc_hash: pr##c##_hash, \
hc_parse: pr##c##_d, \
hc_print: pr##c##_e, \
hc_dxtra: dup##_dup_xtra, \
hc_dup_one: dup##_dup_one, \
hc_update: upd##_update, \
hc_name: l, \
hc_len: sizeof(l) - 1, \
hc_short: s, \
hc_size: MSG_ALIGN(sizeof(pr##c##_t), sizeof(void*)), \
hc_params: offsetof(pr##c##_t, params), \
hc_kind: msg_kind_##kind, \
}}
#else
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup) \
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
{{ \
pr##c##_hash, \
pr##c##_d, \
pr##c##_e, \
dup##_dup_xtra, \
dup##_dup_one, \
upd##_update, \
l, \
sizeof(l) - 1, \
s, \
......@@ -231,6 +233,8 @@ int msg_any_list_d(su_home_t *home, char **ss,
/* Parameter lists */
int msg_header_update_params(msg_common_t *h, int clear);
/** Match a parameter with any value. @HI */
#define MSG_PARAM_MATCH(v, s, name) \
(strncasecmp(s, name "=", sizeof(name)) == 0 ? (v = s + sizeof(name)) : NULL)
......
......@@ -786,41 +786,161 @@ char const *msg_header_find_param(msg_common_t const *h, char const *name)
return NULL;
}
/** Add a parameter to a header.
*
* A header parameter @a param is a string of format name "=" value or just
* name. The caller of msg_header_add_param() should have allocated it from
* memory home associated with header @a h.
*
* @retval 0 if parameter was added
* @retval -1 upon an error
*/
int msg_header_add_param(su_home_t *home, msg_common_t *h, char const *param)
{
if (h && h->h_class->hc_params) {
int retval;
msg_param_t **params = (msg_param_t **)
((char *)h + h->h_class->hc_params);
return msg_params_add(home, params, param);
msg_fragment_clear(h);
retval = msg_params_add(home, params, param);
if (retval < 0)
return -1;
if (h->h_class->hc_update) {
size_t namelen;
char const *name, *value;
name = param;
namelen = strcspn(name, "=");
value = param + namelen + (name[namelen] == '=');
h->h_class->hc_update(h, name, namelen, value);
}
return retval;
}
return -1;
}
/** Replace or add a parameter to a header.
*
* The shortcuts to parameter values are updated accordingly.
*
* @note This function does not duplicate @p param.
*
* @param home memory home
* @param h pointer to a header
* @param param parameter to be replaced or added
*
* @retval 0 if parameter was added
* @retval 1 if parameter was replaced
* @retval -1 upon an error
*/
int msg_header_replace_param(su_home_t *home,
msg_common_t *h,
char const *param)
{
if (h && h->h_class->hc_params) {
int retval;
msg_param_t **params = (msg_param_t **)
((char *)h + h->h_class->hc_params);
return msg_params_replace(home, params, param);
msg_fragment_clear(h);
retval = msg_params_replace(home, params, param);
if (retval < 0)