~ubuntu-branches/ubuntu/vivid/sflphone/vivid

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjsip/src/pjsip/sip_multipart.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2013-06-30 11:40:56 UTC
  • mfrom: (4.1.18 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130630114056-0np50jkyqo6vnmii
Tags: 1.2.3-2
* changeset_r92d62cfc54732bbbcfff2b1d36c096b120b981a5.diff 
  - fixes automatic endian detection 
* Update Vcs: fixes vcs-field-not-canonical

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: sip_multipart.c 3841 2011-10-24 09:28:13Z ming $ */
 
2
/*
 
3
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 */
 
19
#include <pjsip/sip_multipart.h>
 
20
#include <pjsip/sip_parser.h>
 
21
#include <pjlib-util/scanner.h>
 
22
#include <pj/assert.h>
 
23
#include <pj/ctype.h>
 
24
#include <pj/errno.h>
 
25
#include <pj/except.h>
 
26
#include <pj/guid.h>
 
27
#include <pj/log.h>
 
28
#include <pj/pool.h>
 
29
#include <pj/string.h>
 
30
 
 
31
#define THIS_FILE               "sip_multipart.c"
 
32
 
 
33
#define IS_SPACE(c)     ((c)==' ' || (c)=='\t')
 
34
 
 
35
#if 0
 
36
#   define TRACE_(x)    PJ_LOG(4,x)
 
37
#else
 
38
#   define TRACE_(x)
 
39
#endif
 
40
 
 
41
extern pj_bool_t pjsip_use_compact_form;
 
42
 
 
43
/* Type of "data" in multipart pjsip_msg_body */
 
44
struct multipart_data
 
45
{
 
46
    pj_str_t              boundary;
 
47
    pjsip_multipart_part  part_head;
 
48
};
 
49
 
 
50
 
 
51
static int multipart_print_body(struct pjsip_msg_body *msg_body,
 
52
                                char *buf, pj_size_t size)
 
53
{
 
54
    const struct multipart_data *m_data;
 
55
    pj_str_t clen_hdr =  { "Content-Length: ", 16};
 
56
    pjsip_multipart_part *part;
 
57
    char *p = buf, *end = buf+size;
 
58
 
 
59
#define SIZE_LEFT()     (end-p)
 
60
 
 
61
    m_data = (const struct multipart_data*)msg_body->data;
 
62
 
 
63
    PJ_ASSERT_RETURN(m_data && !pj_list_empty(&m_data->part_head), PJ_EINVAL);
 
64
 
 
65
    part = m_data->part_head.next;
 
66
    while (part != &m_data->part_head) {
 
67
        enum { CLEN_SPACE = 5 };
 
68
        char *clen_pos;
 
69
        const pjsip_hdr *hdr;
 
70
 
 
71
        clen_pos = NULL;
 
72
 
 
73
        /* Print delimiter */
 
74
        if (SIZE_LEFT() <= (m_data->boundary.slen+8) << 1)
 
75
            return -1;
 
76
        *p++ = 13; *p++ = 10; *p++ = '-'; *p++ = '-';
 
77
        pj_memcpy(p, m_data->boundary.ptr, m_data->boundary.slen);
 
78
        p += m_data->boundary.slen;
 
79
        *p++ = 13; *p++ = 10;
 
80
 
 
81
        /* Print optional headers */
 
82
        hdr = part->hdr.next;
 
83
        while (hdr != &part->hdr) {
 
84
            int printed = pjsip_hdr_print_on((pjsip_hdr*)hdr, p,
 
85
                                             SIZE_LEFT()-2);
 
86
            if (printed < 0)
 
87
                return -1;
 
88
            p += printed;
 
89
            *p++ = '\r';
 
90
            *p++ = '\n';
 
91
            hdr = hdr->next;
 
92
        }
 
93
 
 
94
        /* Automaticly adds Content-Type and Content-Length headers, only
 
95
         * if content_type is set in the message body.
 
96
         */
 
97
        if (part->body && part->body->content_type.type.slen) {
 
98
            pj_str_t ctype_hdr = { "Content-Type: ", 14};
 
99
            const pjsip_media_type *media = &part->body->content_type;
 
100
 
 
101
            if (pjsip_use_compact_form) {
 
102
                ctype_hdr.ptr = "c: ";
 
103
                ctype_hdr.slen = 3;
 
104
            }
 
105
 
 
106
            /* Add Content-Type header. */
 
107
            if ( (end-p) < 24 + media->type.slen + media->subtype.slen) {
 
108
                return -1;
 
109
            }
 
110
            pj_memcpy(p, ctype_hdr.ptr, ctype_hdr.slen);
 
111
            p += ctype_hdr.slen;
 
112
            p += pjsip_media_type_print(p, end-p, media);
 
113
            *p++ = '\r';
 
114
            *p++ = '\n';
 
115
 
 
116
            /* Add Content-Length header. */
 
117
            if ((end-p) < clen_hdr.slen + 12 + 2) {
 
118
                return -1;
 
119
            }
 
120
            pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen);
 
121
            p += clen_hdr.slen;
 
122
 
 
123
            /* Print blanks after "Content-Length:", this is where we'll put
 
124
             * the content length value after we know the length of the
 
125
             * body.
 
126
             */
 
127
            pj_memset(p, ' ', CLEN_SPACE);
 
128
            clen_pos = p;
 
129
            p += CLEN_SPACE;
 
130
            *p++ = '\r';
 
131
            *p++ = '\n';
 
132
        }
 
133
 
 
134
        /* Empty newline */
 
135
        *p++ = 13; *p++ = 10;
 
136
 
 
137
        /* Print the body */
 
138
        pj_assert(part->body != NULL);
 
139
        if (part->body) {
 
140
            int printed = part->body->print_body(part->body, p, SIZE_LEFT());
 
141
            if (printed < 0)
 
142
                return -1;
 
143
            p += printed;
 
144
 
 
145
            /* Now that we have the length of the body, print this to the
 
146
             * Content-Length header.
 
147
             */
 
148
            if (clen_pos) {
 
149
                char tmp[16];
 
150
                int len;
 
151
 
 
152
                len = pj_utoa(printed, tmp);
 
153
                if (len > CLEN_SPACE) len = CLEN_SPACE;
 
154
                pj_memcpy(clen_pos+CLEN_SPACE-len, tmp, len);
 
155
            }
 
156
        }
 
157
 
 
158
        part = part->next;
 
159
    }
 
160
 
 
161
    /* Print closing delimiter */
 
162
    if (SIZE_LEFT() < m_data->boundary.slen+8)
 
163
        return -1;
 
164
    *p++ = 13; *p++ = 10; *p++ = '-'; *p++ = '-';
 
165
    pj_memcpy(p, m_data->boundary.ptr, m_data->boundary.slen);
 
166
    p += m_data->boundary.slen;
 
167
    *p++ = '-'; *p++ = '-'; *p++ = 13; *p++ = 10;
 
168
 
 
169
#undef SIZE_LEFT
 
170
 
 
171
    return p - buf;
 
172
}
 
173
 
 
174
static void* multipart_clone_data(pj_pool_t *pool, const void *data,
 
175
                                  unsigned len)
 
176
{
 
177
    const struct multipart_data *src;
 
178
    struct multipart_data *dst;
 
179
    const pjsip_multipart_part *src_part;
 
180
 
 
181
    PJ_UNUSED_ARG(len);
 
182
 
 
183
    src = (const struct multipart_data*) data;
 
184
    dst = PJ_POOL_ALLOC_T(pool, struct multipart_data);
 
185
 
 
186
    pj_strdup(pool, &dst->boundary, &src->boundary);
 
187
 
 
188
    src_part = src->part_head.next;
 
189
    while (src_part != &src->part_head) {
 
190
        pjsip_multipart_part *dst_part;
 
191
        const pjsip_hdr *src_hdr;
 
192
 
 
193
        dst_part = pjsip_multipart_create_part(pool);
 
194
 
 
195
        src_hdr = src_part->hdr.next;
 
196
        while (src_hdr != &src_part->hdr) {
 
197
            pjsip_hdr *dst_hdr = (pjsip_hdr*)pjsip_hdr_clone(pool, src_hdr);
 
198
            pj_list_push_back(&dst_part->hdr, dst_hdr);
 
199
            src_hdr = src_hdr->next;
 
200
        }
 
201
 
 
202
        dst_part->body = pjsip_msg_body_clone(pool, src_part->body);
 
203
 
 
204
        pj_list_push_back(&dst->part_head, dst_part);
 
205
 
 
206
        src_part = src_part->next;
 
207
    }
 
208
 
 
209
    return (void*)dst;
 
210
}
 
211
 
 
212
/*
 
213
 * Create an empty multipart body.
 
214
 */
 
215
PJ_DEF(pjsip_msg_body*) pjsip_multipart_create( pj_pool_t *pool,
 
216
                                                const pjsip_media_type *ctype,
 
217
                                                const pj_str_t *boundary)
 
218
{
 
219
    pjsip_msg_body *body;
 
220
    pjsip_param *ctype_param;
 
221
    struct multipart_data *mp_data;
 
222
    pj_str_t STR_BOUNDARY = { "boundary", 8 };
 
223
 
 
224
    PJ_ASSERT_RETURN(pool, NULL);
 
225
 
 
226
    body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
 
227
 
 
228
    /* content-type */
 
229
    if (ctype && ctype->type.slen) {
 
230
        pjsip_media_type_cp(pool, &body->content_type, ctype);
 
231
    } else {
 
232
        pj_str_t STR_MULTIPART = {"multipart", 9};
 
233
        pj_str_t STR_MIXED = { "mixed", 5 };
 
234
 
 
235
        pjsip_media_type_init(&body->content_type,
 
236
                              &STR_MULTIPART, &STR_MIXED);
 
237
    }
 
238
 
 
239
    /* multipart data */
 
240
    mp_data = PJ_POOL_ZALLOC_T(pool, struct multipart_data);
 
241
    pj_list_init(&mp_data->part_head);
 
242
    if (boundary) {
 
243
        pj_strdup(pool, &mp_data->boundary, boundary);
 
244
    } else {
 
245
        pj_create_unique_string(pool, &mp_data->boundary);
 
246
    }
 
247
    body->data = mp_data;
 
248
 
 
249
    /* Add ";boundary" parameter to content_type parameter. */
 
250
    ctype_param = pjsip_param_find(&body->content_type.param, &STR_BOUNDARY);
 
251
    if (!ctype_param) {
 
252
        ctype_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
 
253
        ctype_param->name = STR_BOUNDARY;
 
254
        pj_list_push_back(&body->content_type.param, ctype_param);
 
255
    }
 
256
    ctype_param->value = mp_data->boundary;
 
257
 
 
258
    /* function pointers */
 
259
    body->print_body = &multipart_print_body;
 
260
    body->clone_data = &multipart_clone_data;
 
261
 
 
262
    return body;
 
263
}
 
264
 
 
265
/*
 
266
 * Create an empty multipart part.
 
267
 */
 
268
PJ_DEF(pjsip_multipart_part*) pjsip_multipart_create_part(pj_pool_t *pool)
 
269
{
 
270
    pjsip_multipart_part *mp;
 
271
 
 
272
    mp = PJ_POOL_ZALLOC_T(pool, pjsip_multipart_part);
 
273
    pj_list_init(&mp->hdr);
 
274
 
 
275
    return mp;
 
276
}
 
277
 
 
278
 
 
279
/*
 
280
 * Deep clone.
 
281
 */
 
282
PJ_DEF(pjsip_multipart_part*)
 
283
pjsip_multipart_clone_part(pj_pool_t *pool,
 
284
                           const pjsip_multipart_part *src)
 
285
{
 
286
    pjsip_multipart_part *dst;
 
287
    const pjsip_hdr *hdr;
 
288
 
 
289
    dst = pjsip_multipart_create_part(pool);
 
290
 
 
291
    hdr = src->hdr.next;
 
292
    while (hdr != &src->hdr) {
 
293
        pj_list_push_back(&dst->hdr, pjsip_hdr_clone(pool, hdr));
 
294
        hdr = hdr->next;
 
295
    }
 
296
 
 
297
    dst->body = pjsip_msg_body_clone(pool, src->body);
 
298
 
 
299
    return dst;
 
300
}
 
301
 
 
302
 
 
303
/*
 
304
 * Add a part into multipart bodies.
 
305
 */
 
306
PJ_DEF(pj_status_t) pjsip_multipart_add_part( pj_pool_t *pool,
 
307
                                              pjsip_msg_body *mp,
 
308
                                              pjsip_multipart_part *part)
 
309
{
 
310
    struct multipart_data *m_data;
 
311
 
 
312
    /* All params must be specified */
 
313
    PJ_ASSERT_RETURN(pool && mp && part, PJ_EINVAL);
 
314
 
 
315
    /* mp must really point to an actual multipart msg body */
 
316
    PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, PJ_EINVAL);
 
317
 
 
318
    /* The multipart part must contain a valid message body */
 
319
    PJ_ASSERT_RETURN(part->body && part->body->print_body, PJ_EINVAL);
 
320
 
 
321
    m_data = (struct multipart_data*)mp->data;
 
322
    pj_list_push_back(&m_data->part_head, part);
 
323
 
 
324
    PJ_UNUSED_ARG(pool);
 
325
 
 
326
    return PJ_SUCCESS;
 
327
}
 
328
 
 
329
/*
 
330
 * Get the first part of multipart bodies.
 
331
 */
 
332
PJ_DEF(pjsip_multipart_part*)
 
333
pjsip_multipart_get_first_part(const pjsip_msg_body *mp)
 
334
{
 
335
    struct multipart_data *m_data;
 
336
 
 
337
    /* Must specify mandatory params */
 
338
    PJ_ASSERT_RETURN(mp, NULL);
 
339
 
 
340
    /* mp must really point to an actual multipart msg body */
 
341
    PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL);
 
342
 
 
343
    m_data = (struct multipart_data*)mp->data;
 
344
    if (pj_list_empty(&m_data->part_head))
 
345
        return NULL;
 
346
 
 
347
    return m_data->part_head.next;
 
348
}
 
349
 
 
350
/*
 
351
 * Get the next part after the specified part.
 
352
 */
 
353
PJ_DEF(pjsip_multipart_part*)
 
354
pjsip_multipart_get_next_part(const pjsip_msg_body *mp,
 
355
                              pjsip_multipart_part *part)
 
356
{
 
357
    struct multipart_data *m_data;
 
358
 
 
359
    /* Must specify mandatory params */
 
360
    PJ_ASSERT_RETURN(mp && part, NULL);
 
361
 
 
362
    /* mp must really point to an actual multipart msg body */
 
363
    PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL);
 
364
 
 
365
    m_data = (struct multipart_data*)mp->data;
 
366
 
 
367
    /* the part parameter must be really member of the list */
 
368
    PJ_ASSERT_RETURN(pj_list_find_node(&m_data->part_head, part) != NULL,
 
369
                     NULL);
 
370
 
 
371
    if (part->next == &m_data->part_head)
 
372
        return NULL;
 
373
 
 
374
    return part->next;
 
375
}
 
376
 
 
377
/*
 
378
 * Find a body inside multipart bodies which has the specified content type.
 
379
 */
 
380
PJ_DEF(pjsip_multipart_part*)
 
381
pjsip_multipart_find_part( const pjsip_msg_body *mp,
 
382
                           const pjsip_media_type *content_type,
 
383
                           const pjsip_multipart_part *start)
 
384
{
 
385
    struct multipart_data *m_data;
 
386
    pjsip_multipart_part *part;
 
387
 
 
388
    /* Must specify mandatory params */
 
389
    PJ_ASSERT_RETURN(mp && content_type, NULL);
 
390
 
 
391
    /* mp must really point to an actual multipart msg body */
 
392
    PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL);
 
393
 
 
394
    m_data = (struct multipart_data*)mp->data;
 
395
 
 
396
    if (start)
 
397
        part = start->next;
 
398
    else
 
399
        part = m_data->part_head.next;
 
400
 
 
401
    while (part != &m_data->part_head) {
 
402
        if (pjsip_media_type_cmp(&part->body->content_type,
 
403
                                 content_type, 0)==0)
 
404
        {
 
405
            return part;
 
406
        }
 
407
        part = part->next;
 
408
    }
 
409
 
 
410
    return NULL;
 
411
}
 
412
 
 
413
/* Parse a multipart part. "pct" is parent content-type  */
 
414
static pjsip_multipart_part *parse_multipart_part(pj_pool_t *pool,
 
415
                                                  char *start,
 
416
                                                  pj_size_t len,
 
417
                                                  const pjsip_media_type *pct)
 
418
{
 
419
    pjsip_multipart_part *part = pjsip_multipart_create_part(pool);
 
420
    char *p = start, *end = start+len, *end_hdr = NULL, *start_body = NULL;
 
421
    pjsip_ctype_hdr *ctype_hdr = NULL;
 
422
 
 
423
    TRACE_((THIS_FILE, "Parsing part: begin--\n%.*s\n--end",
 
424
            (int)len, start));
 
425
 
 
426
    /* Find the end of header area, by looking at an empty line */
 
427
    for (;;) {
 
428
        while (p!=end && *p!='\n') ++p;
 
429
        if (p==end) {
 
430
            start_body = end;
 
431
            break;
 
432
        }
 
433
        if ((p==start) || (p==start+1 && *(p-1)=='\r')) {
 
434
            /* Empty header section */
 
435
            end_hdr = start;
 
436
            start_body = ++p;
 
437
            break;
 
438
        } else if (p==end-1) {
 
439
            /* Empty body section */
 
440
            end_hdr = end;
 
441
            start_body = ++p;
 
442
        } else if ((p>=start+1 && *(p-1)=='\n') ||
 
443
                   (p>=start+2 && *(p-1)=='\r' && *(p-2)=='\n'))
 
444
        {
 
445
            /* Found it */
 
446
            end_hdr = (*(p-1)=='\r') ? (p-1) : p;
 
447
            start_body = ++p;
 
448
            break;
 
449
        } else {
 
450
            ++p;
 
451
        }
 
452
    }
 
453
 
 
454
    /* Parse the headers */
 
455
    if (end_hdr-start > 0) {
 
456
        pjsip_hdr *hdr;
 
457
        pj_status_t status;
 
458
 
 
459
        status = pjsip_parse_headers(pool, start, end_hdr-start,
 
460
                                     &part->hdr, 0);
 
461
        if (status != PJ_SUCCESS) {
 
462
            PJ_PERROR(2,(THIS_FILE, status, "Warning: error parsing multipart"
 
463
                                            " header"));
 
464
        }
 
465
 
 
466
        /* Find Content-Type header */
 
467
        hdr = part->hdr.next;
 
468
        while (hdr != &part->hdr) {
 
469
            TRACE_((THIS_FILE, "Header parsed: %.*s", (int)hdr->name.slen,
 
470
                    hdr->name.ptr));
 
471
            if (hdr->type == PJSIP_H_CONTENT_TYPE) {
 
472
                ctype_hdr = (pjsip_ctype_hdr*)hdr;
 
473
            }
 
474
            hdr = hdr->next;
 
475
        }
 
476
    }
 
477
 
 
478
    /* Assign the body */
 
479
    part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body);
 
480
    if (ctype_hdr) {
 
481
        pjsip_media_type_cp(pool, &part->body->content_type, &ctype_hdr->media);
 
482
    } else if (pct && pj_stricmp2(&pct->subtype, "digest")==0) {
 
483
        part->body->content_type.type = pj_str("message");
 
484
        part->body->content_type.subtype = pj_str("rfc822");
 
485
    } else {
 
486
        part->body->content_type.type = pj_str("text");
 
487
        part->body->content_type.subtype = pj_str("plain");
 
488
    }
 
489
 
 
490
    if (start_body < end) {
 
491
        part->body->data = start_body;
 
492
        part->body->len = end - start_body;
 
493
    } else {
 
494
        part->body->data = (void*)"";
 
495
        part->body->len = 0;
 
496
    }
 
497
    TRACE_((THIS_FILE, "Body parsed: \"%.*s\"", (int)part->body->len,
 
498
            part->body->data));
 
499
    part->body->print_body = &pjsip_print_text_body;
 
500
    part->body->clone_data = &pjsip_clone_text_data;
 
501
 
 
502
    return part;
 
503
}
 
504
 
 
505
/* Public function to parse multipart message bodies into its parts */
 
506
PJ_DEF(pjsip_msg_body*) pjsip_multipart_parse(pj_pool_t *pool,
 
507
                                              char *buf, pj_size_t len,
 
508
                                              const pjsip_media_type *ctype,
 
509
                                              unsigned options)
 
510
{
 
511
    pj_str_t boundary, delim;
 
512
    char *curptr, *endptr;
 
513
    const pjsip_param *ctype_param;
 
514
    const pj_str_t STR_BOUNDARY = { "boundary", 8 };
 
515
    pjsip_msg_body *body = NULL;
 
516
 
 
517
    PJ_ASSERT_RETURN(pool && buf && len && ctype && !options, NULL);
 
518
 
 
519
    TRACE_((THIS_FILE, "Started parsing multipart body"));
 
520
 
 
521
    /* Get the boundary value in the ctype */
 
522
    boundary.ptr = NULL;
 
523
    boundary.slen = 0;
 
524
    ctype_param = pjsip_param_find(&ctype->param, &STR_BOUNDARY);
 
525
    if (ctype_param) {
 
526
        boundary = ctype_param->value;
 
527
        if (boundary.slen>2 && *boundary.ptr=='"') {
 
528
            /* Remove quote */
 
529
            boundary.ptr++;
 
530
            boundary.slen -= 2;
 
531
        }
 
532
        TRACE_((THIS_FILE, "Boundary is specified: '%.*s'", (int)boundary.slen,
 
533
                boundary.ptr));
 
534
    }
 
535
 
 
536
    if (!boundary.slen) {
 
537
        /* Boundary not found or not specified. Try to be clever, get
 
538
         * the boundary from the body.
 
539
         */
 
540
        char *p=buf, *end=buf+len;
 
541
 
 
542
        PJ_LOG(4,(THIS_FILE, "Warning: boundary parameter not found or "
 
543
                             "not specified when parsing multipart body"));
 
544
 
 
545
        /* Find the first "--". This "--" must be right after a CRLF, unless
 
546
         * it really appears at the start of the buffer.
 
547
         */
 
548
        for (;;) {
 
549
            while (p!=end && *p!='-') ++p;
 
550
            if (p!=end && *(p+1)=='-' &&
 
551
                ((p>buf && *(p-1)=='\n') || (p==buf)))
 
552
            {
 
553
                p+=2;
 
554
                break;
 
555
            } else {
 
556
                ++p;
 
557
            }
 
558
        }
 
559
 
 
560
        if (p==end) {
 
561
            /* Unable to determine boundary. Maybe this is not a multipart
 
562
             * message?
 
563
             */
 
564
            PJ_LOG(4,(THIS_FILE, "Error: multipart boundary not specified and"
 
565
                                 " unable to calculate from the body"));
 
566
            return NULL;
 
567
        }
 
568
 
 
569
        boundary.ptr = p;
 
570
        while (p!=end && !pj_isspace(*p)) ++p;
 
571
        boundary.slen = p - boundary.ptr;
 
572
 
 
573
        TRACE_((THIS_FILE, "Boundary is calculated: '%.*s'",
 
574
                (int)boundary.slen, boundary.ptr));
 
575
    }
 
576
 
 
577
    /* Build the delimiter:
 
578
     *   delimiter = "--" boundary
 
579
     */
 
580
    delim.slen = boundary.slen+2;
 
581
    delim.ptr = (char*)pj_pool_alloc(pool, (int)delim.slen);
 
582
    delim.ptr[0] = '-';
 
583
    delim.ptr[1] = '-';
 
584
    pj_memcpy(delim.ptr+2, boundary.ptr, boundary.slen);
 
585
 
 
586
    /* Start parsing the body, skip until the first delimiter. */
 
587
    curptr = buf;
 
588
    endptr = buf + len;
 
589
    {
 
590
        pj_str_t body;
 
591
 
 
592
        body.ptr = buf; body.slen = len;
 
593
        curptr = pj_strstr(&body, &delim);
 
594
        if (!curptr)
 
595
            return NULL;
 
596
    }
 
597
 
 
598
    body = pjsip_multipart_create(pool, ctype, &boundary);
 
599
 
 
600
    for (;;) {
 
601
        char *start_body, *end_body;
 
602
        pjsip_multipart_part *part;
 
603
 
 
604
        /* Eat the boundary */
 
605
        curptr += delim.slen;
 
606
        if (*curptr=='-' && curptr<endptr-1 && *(curptr+1)=='-') {
 
607
            /* Found the closing delimiter */
 
608
            curptr += 2;
 
609
            break;
 
610
        }
 
611
        /* Optional whitespace after delimiter */
 
612
        while (curptr!=endptr && IS_SPACE(*curptr)) ++curptr;
 
613
        /* Mandatory CRLF */
 
614
        if (*curptr=='\r') ++curptr;
 
615
        if (*curptr!='\n') {
 
616
            /* Expecting a newline here */
 
617
            return NULL;
 
618
        }
 
619
        ++curptr;
 
620
 
 
621
        /* We now in the start of the body */
 
622
        start_body = curptr;
 
623
 
 
624
        /* Find the next delimiter */
 
625
        {
 
626
            pj_str_t subbody;
 
627
 
 
628
            subbody.ptr = curptr; subbody.slen = endptr - curptr;
 
629
            curptr = pj_strstr(&subbody, &delim);
 
630
            if (!curptr) {
 
631
                /* We're really expecting end delimiter to be found. */
 
632
                return NULL;
 
633
            }
 
634
        }
 
635
 
 
636
        end_body = curptr;
 
637
 
 
638
        /* The newline preceeding the delimiter is conceptually part of
 
639
         * the delimiter, so trim it from the body.
 
640
         */
 
641
        if (*(end_body-1) == '\n')
 
642
            --end_body;
 
643
        if (*(end_body-1) == '\r')
 
644
            --end_body;
 
645
 
 
646
        /* Now that we have determined the part's boundary, parse it
 
647
         * to get the header and body part of the part.
 
648
         */
 
649
        part = parse_multipart_part(pool, start_body, end_body - start_body,
 
650
                                    ctype);
 
651
        if (part) {
 
652
            pjsip_multipart_add_part(pool, body, part);
 
653
        }
 
654
    }
 
655
 
 
656
    return body;
 
657
}