Commit 8d151687 authored by Pekka Pessi's avatar Pekka Pessi

msg: added msg_as_string(). Updated msg_make() prototype.

darcs-hash:20061128201026-65a35-e279142515a6a8073889a5aae5d471d598bb2a7b.gz
parent a3abd1a1
......@@ -1308,7 +1308,7 @@ issize_t msg_extract_separator(msg_t *msg, msg_pub_t *mo,
if (hr->hr_class->hc_parse(msg_home(msg), h, b, l) < 0)
return -1;
h->sh_data = b, h->sh_len = l;
h->sh_data = b, h->sh_len = l;
append_parsed(msg, mo, hr, h, 0);
......@@ -1527,7 +1527,8 @@ extract_trailers(msg_t *msg, msg_pub_t *mo,
static inline size_t
msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags);
static size_t msg_header_prepare(msg_mclass_t const *, int flags,
msg_header_t *h, char *b, size_t bsiz);
msg_header_t *h, msg_header_t **return_next,
char *b, size_t bsiz);
/**Encode all message fragments.
*
......@@ -1596,7 +1597,7 @@ int msg_is_prepared(msg_t const *msg)
issize_t msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags)
{
msg_mclass_t const *mc = msg->m_class;
msg_header_t *h;
msg_header_t *h, *next;
ssize_t n = 0;
size_t bsiz = 0, used = 0;
char *b;
......@@ -1609,13 +1610,18 @@ issize_t msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags)
return -1;
for (h = headers; h;) {
if (h->sh_data) {
total += h->sh_len;
h = h->sh_succ;
continue;
}
n = msg_header_prepare(mc, flags, h, b, bsiz - used);
for (next = h->sh_succ; next; next = next->sh_succ)
if (next->sh_class != h->sh_class || next->sh_data)
break;
n = msg_header_prepare(mc, flags, h, &next, b, bsiz - used);
if (n == (ssize_t)-1) {
errno = EINVAL;
......@@ -1630,12 +1636,16 @@ issize_t msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags)
continue;
}
h->sh_data = b, h->sh_len = n;
for (h = h->sh_succ; h != next; h = h->sh_succ)
h->sh_data = b + n, h->sh_len = 0;
msg_buf_used(msg, n);
total += n;
used += n;
b += n;
h = h->sh_succ;
}
return total;
......@@ -1644,31 +1654,29 @@ issize_t msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags)
/** Encode a header or a list of headers */
static
size_t msg_header_prepare(msg_mclass_t const *mc, int flags,
msg_header_t *h, char *b, size_t bsiz)
msg_header_t *h, msg_header_t **return_next,
char *b, size_t bsiz)
{
msg_header_t *h0, *next;
msg_hclass_t *hc;
char const *s;
size_t n; ssize_t m;
int middle = 0, compact, one_line_list, comma_list;
int compact, one_line_list, comma_list;
assert(h); assert(h->sh_class);
hc = h->sh_class;
compact = MSG_IS_COMPACT(flags);
one_line_list = compact || hc->hc_kind == msg_kind_apndlist;
comma_list = one_line_list || MSG_IS_COMMA_LISTS(flags);
one_line_list = hc->hc_kind == msg_kind_apndlist;
comma_list = compact || one_line_list || MSG_IS_COMMA_LISTS(flags);
for (h0 = h, n = 0; h; h = next) {
for (h0 = h, n = 0; ; h = next) {
next = h->sh_succ;
if (!next || next->sh_class != hc || next->sh_data || !comma_list)
next = NULL;
if (!middle && hc->hc_name && hc->hc_name[0])
if (h == h0 && hc->hc_name && hc->hc_name[0])
n += msg_header_name_e(b + n, bsiz >= n ? bsiz - n : 0, h, flags);
if ((m = hc->hc_print(b + n, bsiz >= n ? bsiz - n : 0, h, flags)) < 0) {
if ((m = hc->hc_print(b + n, bsiz >= n ? bsiz - n : 0, h, flags)) == -1) {
if (bsiz >= n + 64)
m = 2 * (bsiz - n);
else
......@@ -1678,41 +1686,26 @@ size_t msg_header_prepare(msg_mclass_t const *mc, int flags,
n += m;
if (hc->hc_name) {
/* Encode continuation */
if (!next)
s = CRLF;
if (!comma_list || !next || next == *return_next)
s = CRLF, m = 2;
/* Else encode continuation */
else if (compact)
s = ",";
s = ",", m = 1;
else if (one_line_list)
s = ", ";
s = ", ", m = 2;
else
s = "," CRLF "\t";
s = "," CRLF "\t", m = 4;
m = strlen(s);
if (bsiz <= n + m) {
if (!next)
return n + m;
}
else {
strcpy(b + n, s);
}
if (bsiz > n + m)
memcpy(b + n, s, m);
n += m;
}
middle = 1;
if (!comma_list || !next || next == *return_next)
break;
}
if (bsiz > n) { /* XXX */
h0->sh_data = b, h0->sh_len = n;
for (h = h0; h; h = next) {
next = h->sh_succ;
if (!next || next->sh_class != hc || next->sh_data || !comma_list)
break;
else
next->sh_data = b, next->sh_len = 0;
}
}
*return_next = next;
return n;
}
......@@ -1780,6 +1773,97 @@ msg_header_name_e(char b[], size_t bsiz, msg_header_t const *h, int flags)
return n2;
}
/** Convert a message to a string.
*
* A message is encoded and the encoding result is returned as a string.
* Because the message may contain binary payload (or NUL in headers), the
* message length is returned separately in @a *return_len, too.
*
* Note that the message is serialized as a side effect.
*
* @param home memory home used to allocate the string
* @param msg message to encode
* @param pub message object to encode (may be NULL)
* @param flags flags used when encoding
* @param return_len return-value parameter for encoded message length
*
* @return Encoding result as a C string.
*
* @since New in @VERSION_1_12_4
*
* @sa msg_make(), msg_prepare(), msg_serialize().
*/
char *msg_as_string(su_home_t *home, msg_t *msg, msg_pub_t *pub, int flags,
size_t *return_len)
{
msg_mclass_t const *mc = msg->m_class;
msg_header_t *h, *next;
ssize_t n = 0;
size_t bsiz = 0, used = 0;
char *b, *b2;
if (pub == NULL)
pub = msg->m_object;
if (msg_serialize(msg, pub) < 0)
return NULL;
if (return_len == NULL)
return_len = &used;
b = su_alloc(home, bsiz = msg_min_size);
if (!b)
return NULL;
if (pub == msg->m_object)
h = msg->m_chain;
else
h = pub->msg_common->h_succ;
while (h) {
for (next = h->sh_succ; next; next = next->sh_succ)
if (next->sh_class != h->sh_class)
break;
n = msg_header_prepare(mc, flags, h, &next, b + used, bsiz - used);
if (n == -1) {
errno = EINVAL;
su_free(home, b);
return NULL;
}
if (bsiz > used + n) {
used += n;
h = next;
}
else {
/* Realloc */
if (h->sh_succ)
bsiz = (used + n + msg_min_size) / msg_min_size * msg_min_size;
else
bsiz = used + n + 1;
b2 = su_realloc(home, b, bsiz);
if (b2 == NULL || bsiz < msg_min_size) {
errno = ENOMEM;
su_free(home, b);
return NULL;
}
continue;
}
}
*return_len = used;
b[used] = '\0'; /* NUL terminate */
return su_realloc(home, b, used + 1);
}
/* ====================================================================== */
/* Handling header chain */
......
......@@ -1817,7 +1817,16 @@ issize_t msg_random_token(char token[], isize_t tlen,
/** Parse a message.
*
* Parse a message with parser @a mc.
* Parse a text message with parser @a mc. The @a data is copied and it is
* not modified or referenced by the parsed message.
*
* @par Example
* Parse a SIP message fragment (e.g., payload of NOTIFY sent in response to
* REFER):
* @code
* msg_t *m = msg_make(sip_default_mclass(), 0, pl->pl_data, pl->pl_len);
* sip_t *frag = sip_object(m);
* @endcode
*
* @param mc message class (parser table)
* @param flags message flags (see #msg_flg_user)
......@@ -1826,13 +1835,15 @@ issize_t msg_random_token(char token[], isize_t tlen,
*
* @retval A pointer to a freshly allocated and parsed message.
*
* Upon parsing error, the MSG_FLG_ERROR is set in
* @a msg_object(msg)->msg_flags.
* Upon parsing error, the header structure may be left incomplete. The
* #MSG_FLG_ERROR is set in @a msg_object(msg)->msg_flags.
*
* @since New in @VERSION_1_12_4
*
* @sa msg_as_string(), msg_extract()
*/
msg_t *msg_make(msg_mclass_t const *mc, int flags,
char const *data, ssize_t len)
void const *data, ssize_t len)
{
msg_t *msg;
msg_iovec_t iovec[2];
......@@ -1849,7 +1860,7 @@ msg_t *msg_make(msg_mclass_t const *mc, int flags,
if (msg_recv_iovec(msg, iovec, 2, len, 1) < 0) {
perror("msg_recv_iovec");
}
assert(iovec->mv_len == len);
assert((ssize_t)iovec->mv_len == len);
memcpy(iovec->mv_base, data, len);
msg_recv_commit(msg, len, 1);
......
......@@ -35,6 +35,7 @@
*/
#include <sofia-sip/msg_types.h>
#include <sofia-sip/su_alloc.h>
SOFIA_BEGIN_DECLS
......@@ -45,7 +46,10 @@ SOFIAPUBFUN msg_t *msg_copy(msg_t *);
SOFIAPUBFUN msg_t *msg_dup(msg_t const *);
SOFIAPUBFUN msg_t *msg_make(msg_mclass_t const *mc, int flags,
char const *data, ssize_t len);
void const *data, ssize_t len);
SOFIAPUBFUN char *msg_as_string(su_home_t *home,
msg_t *msg, msg_pub_t *pub, int flags,
size_t *return_len);
SOFIAPUBFUN void msg_set_parent(msg_t *kid, msg_t *dad);
......
......@@ -74,9 +74,9 @@ struct msg_href_s
* The message class object contains all the information needed to parse a
* message. It used when headers are added or removed from the message. When
* a message is sent, the message class is used to order message components
* and print the message.
* and print (encode) the message in text format.
*
* The message class contains references to headers and other components
* The message class contains reference objects to headers and other components
* within the message. Each reference contains a pointer to a @ref
* msg_hclass_s "header class" and a offset to the header objects within
* public message structure. The parser engine uses these references when it
......@@ -88,6 +88,10 @@ struct msg_href_s
* class with the msg_mclass_insert_header() and msg_mclass_insert()
* functions. The message class of an existing message object can be found
* out with the function msg_mclass().
*
* @sa sip_default_mclass(), http_default_mclass(), msg_create(),
* msg_mclass(), msg_mclass_clone(), msg_mclass_insert_header(),
* msg_mclass_insert_with_mask(), msg_mclass_insert().
*/
struct msg_mclass_s
{
......
......@@ -578,6 +578,7 @@ int test_msg_parsing(void)
msg_status_t *status;
msg_content_location_t *location;
msg_content_language_t *language;
msg_accept_language_t *se;
msg_separator_t *separator;
msg_payload_t *payload;
......@@ -681,6 +682,10 @@ int test_msg_parsing(void)
TEST_P((char *)en->aa_common->h_data + en->aa_common->h_len,
fi->aa_common->h_data);
TEST(fi->aa_common->h_len, 0);
TEST_P((char *)en->aa_common->h_data + en->aa_common->h_len,
se->aa_common->h_data);
TEST(se->aa_common->h_len, 0);
TEST_1(de = msg_accept_language_make(msg_home(msg), "de;q=0.3"));
......@@ -725,7 +730,6 @@ int test_msg_parsing(void)
/* Bug #2429 */
orig = read_msg("GET a-life HTTP/1.1" CRLF
"Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF
"Foo: bar" CRLF
"Content-Length: 6" CRLF
CRLF
......@@ -756,6 +760,10 @@ int test_msg_parsing(void)
TEST_1(language =
msg_content_language_make(home, "se-FI, fi-FI, sv-FI"));
TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)language), 0);
TEST_1(se = msg_accept_language_make(home, "se, fi, sv"));
TEST_1(se->aa_next); TEST_1(se->aa_next->aa_next);
TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)se), 0);
TEST(msg_serialize(msg, (msg_pub_t *)tst), 0);
TEST_1(msg_prepare(msg) > 0);
......@@ -783,6 +791,30 @@ int test_msg_parsing(void)
TEST_M(language->k_common->h_data, encoded, language->k_common->h_len);
}
{
char const encoded[] = "Accept-Language: se, fi, sv\r\n";
TEST_SIZE(se->aa_common->h_len, strlen(encoded));
TEST_M(se->aa_common->h_data, encoded, se->aa_common->h_len);
TEST_P((char *)se->aa_common->h_data + se->aa_common->h_len,
se->aa_next->aa_common->h_data);
TEST_P((char *)se->aa_common->h_data + se->aa_common->h_len,
se->aa_next->aa_next->aa_common->h_data);
}
{
size_t size = SIZE_MAX;
char *s = msg_as_string(msg_home(msg), msg, NULL, 0, &size);
TEST_S(s,
"GET a-wife HTTP/1.1" CRLF
"Foo: bar" CRLF
"Content-Length: 6" CRLF
"Content-Location: http://localhost:8080/wife\r\n"
"Content-Language: se-FI, fi-FI, sv-FI\r\n"
"Accept-Language: se, fi, sv\r\n"
CRLF
"test" CRLF);
}
msg_destroy(msg);
END();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment