Browse code

core: parser - function to proper handling multipart bodies with same content type

- closes FS#170, based on a patch by Luis Martin

Daniel-Constantin Mierla authored on 25/02/2013 10:19:15
Showing 2 changed files
... ...
@@ -294,3 +294,302 @@ next_hf:
294 294
 	}
295 295
 	return NULL;
296 296
 }
297
+
298
+
299
+/**
300
+ * trim_leading_hts
301
+ *
302
+ * trim leading all spaces ' ' and horizontal tabs '\t' characters.
303
+ *   - buffer, pointer to the beginning of the buffer.
304
+ *   - end_buffer, pointer to the end of the buffer.
305
+ * returns
306
+ *   - pointer to the first non-match character if success.
307
+ *   - pointer to NULL if the end_buffer is reached.
308
+ */
309
+char *trim_leading_hts (char *buffer, char *end_buffer)
310
+{
311
+	char *cpy_buffer = buffer;
312
+	while ((cpy_buffer < end_buffer) &&
313
+			((*cpy_buffer == ' ') || (*cpy_buffer == '\t'))) {
314
+		cpy_buffer++;
315
+	}
316
+
317
+	return ((cpy_buffer < end_buffer) ? cpy_buffer : NULL);
318
+}
319
+
320
+
321
+/**
322
+ * trim_leading_e_r
323
+ *
324
+ * trim leading characters until get a '\r'.
325
+ *   - buffer, pointer to the beginning of the buffer.
326
+ *   - end_buffer, pointer to the end of the buffer.
327
+ *
328
+ * returns
329
+ *   - pointer to the first '\r' character if success.
330
+ *   - pointer to NULL if the end_buffer is reached.
331
+ */
332
+char *trim_leading_e_r (char *buffer, char *end_buffer)
333
+{
334
+	char *cpy_buffer = buffer;
335
+	while ((cpy_buffer < end_buffer) && (*cpy_buffer != '\r')) {
336
+		cpy_buffer++;
337
+	}
338
+	return ((cpy_buffer < end_buffer) ? cpy_buffer : NULL);
339
+}
340
+
341
+
342
+/**
343
+ * part_multipart_headers_cmp
344
+ * trim leading characters until get a '\r'.
345
+ * receives
346
+ *   - buffer, pointer to the beginning of the headers in a part of the multipart body.
347
+ *   - end_buffer, pointer to the end of the headers in the multipart body.
348
+ *   - content type/ content subtype.
349
+ *         if (type == 0 / subtype == 0): Content-Type: disabled in the search.
350
+ *   - content id.
351
+ *         if (id == NULL): Content-ID: disabled in the search.
352
+ *   - content length.
353
+ *         if (length == NULL) Content-Length: disabled in the search.
354
+ *
355
+ * returns
356
+ *   - true, if the part of the multipart body has :
357
+ *            -- Content-Type   that matches content_type / content_subtype. (if Content-Type enabled) &&
358
+ *            -- Content-ID     that matches content_id. (if Content-ID enabled) &&
359
+ *            -- Content-Length that matches content_length. (if Content-Length enabled)
360
+ *   - false, if any of them doesnt match.
361
+ */
362
+int part_multipart_headers_cmp (char *buffer,
363
+				char *end_buffer,
364
+				unsigned short content_type,
365
+				unsigned short content_subtype,
366
+				char *content_id,
367
+				char *content_length)
368
+{
369
+	int error = 0;
370
+	char *error_msg = NULL;
371
+
372
+	char *cpy_c = NULL;
373
+	char *cpy_d = NULL;
374
+
375
+	char *value_ini = NULL;
376
+	char *value_fin = NULL;
377
+	unsigned int umime;
378
+
379
+	int found = 0;
380
+	int found_content_type   = 0;
381
+	int found_content_id     = 0;
382
+	int found_content_length = 0;
383
+
384
+	if ((buffer == NULL) || (end_buffer == NULL)) {
385
+		error = -1;
386
+		error_msg = "buffer and/or end_buffer are NULL";
387
+	} else {
388
+		cpy_c = buffer;
389
+		cpy_d = end_buffer;
390
+
391
+		if ((content_type == 0) && (content_subtype == 0)) {
392
+			found_content_type   = 1;
393
+		}
394
+		if (content_id == NULL) {
395
+			found_content_id = 1;
396
+		}
397
+		if (content_length == NULL) {
398
+			found_content_length = 1;
399
+		}
400
+
401
+		found = found_content_type * found_content_id * found_content_length;
402
+		while ((!found) && (!error) && (cpy_c < cpy_d)) {
403
+			if ((cpy_c + 8) < cpy_d) {
404
+				if ( (LOWER_DWORD(READ(cpy_c)) == _cont_)
405
+						&& (LOWER_DWORD(READ(cpy_c + 4)) == _ent__) ) {
406
+					cpy_c += 8;
407
+					if ( (!found_content_type)
408
+							&& ((cpy_c + 5) < cpy_d)
409
+							&& ((*(cpy_c + 0) == 't') || (*(cpy_c + 0) == 'T'))
410
+							&& ((*(cpy_c + 1) == 'y') || (*(cpy_c + 1) == 'Y'))
411
+							&& ((*(cpy_c + 2) == 'p') || (*(cpy_c + 2) == 'P'))
412
+							&& ((*(cpy_c + 3) == 'e') || (*(cpy_c + 3) == 'E'))
413
+							&& (*(cpy_c + 4) == ':') ) {
414
+						cpy_c += 5;
415
+						/* value_ has the content of the header */
416
+						value_ini = trim_leading_hts(cpy_c, cpy_d);
417
+						value_fin = trim_leading_e_r(cpy_c, cpy_d);
418
+						if ((value_ini != NULL) && (value_fin != NULL)) {
419
+							cpy_c = value_fin;
420
+							if (decode_mime_type(value_ini, value_fin, &umime)) {
421
+								if (umime == ((content_type<<16)|content_subtype)) {
422
+									found_content_type = 1;
423
+								} else {
424
+									error = -2;
425
+									error_msg = "MIME types mismatch";
426
+								}
427
+							} else {
428
+								error = -3;
429
+								error_msg = "Failed to decode MIME type";
430
+							}
431
+						} else {
432
+							error = -4;
433
+							error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
434
+						}
435
+					} else if( (!found_content_id) && ((cpy_c + 3) < cpy_d)
436
+							&& ((*(cpy_c + 0) == 'i') || (*(cpy_c + 0) == 'I'))
437
+							&& ((*(cpy_c + 1) == 'd') || (*(cpy_c + 1) == 'D'))
438
+							&& (*(cpy_c + 2) == ':') ) {
439
+						cpy_c += 3;
440
+						/* value_ has the content of the header */
441
+						value_ini = trim_leading_hts(cpy_c, cpy_d);
442
+						value_fin = trim_leading_e_r(cpy_c, cpy_d);
443
+						if ((value_ini != NULL) && (value_fin != NULL)) {
444
+							cpy_c = value_fin;
445
+							if (strncmp(content_id, value_ini, value_fin-value_ini) == 0) {
446
+								found_content_id = 1;
447
+							} else {
448
+								error = -5;
449
+								error_msg = "Content-ID mismatch";
450
+							}
451
+						} else {
452
+							error = -6;
453
+							error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
454
+						}
455
+					} else if( (!found_content_length) && ((cpy_c + 7) < cpy_d)
456
+							&& ((*(cpy_c + 0) == 'l') || (*(cpy_c + 0) == 'L'))
457
+							&& ((*(cpy_c + 1) == 'e') || (*(cpy_c + 1) == 'E'))
458
+							&& ((*(cpy_c + 2) == 'n') || (*(cpy_c + 2) == 'N'))
459
+							&& ((*(cpy_c + 3) == 'g') || (*(cpy_c + 3) == 'G'))
460
+							&& ((*(cpy_c + 4) == 't') || (*(cpy_c + 4) == 'T'))
461
+							&& ((*(cpy_c + 5) == 'h') || (*(cpy_c + 5) == 'H'))
462
+							&& (*(cpy_c + 6) == ':') ) {
463
+						cpy_c += 7;
464
+						/* value_ has the content of the header */
465
+						value_ini = trim_leading_hts(cpy_c, cpy_d);
466
+						value_fin = trim_leading_e_r(cpy_c, cpy_d);
467
+						if ((value_ini != NULL) && (value_fin != NULL)) {
468
+							cpy_c = value_fin;
469
+							if (strncmp(content_length, value_ini, value_fin-value_ini) == 0) {
470
+								found_content_length = 1;
471
+							} else {
472
+								error = -7;
473
+								error_msg = "Content-Length mismatch";
474
+							}
475
+						} else {
476
+							error = -8;
477
+							error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
478
+						}
479
+					} else {
480
+						/* Next characters dont match "Type:" or "ID:" or "Length:" OR
481
+					     * header already parsed (maybe duplicates?) and founded OR
482
+					     * header initially set as disabled and it doesnt need to be treated.
483
+					     * This is NOT an error. */
484
+						;
485
+					}
486
+				} else {
487
+					/* First 8 characters dont match "Content-"
488
+					 * This is NOT an error. */
489
+					;
490
+				}
491
+			} else {
492
+				error = -9;
493
+				error_msg = "We reached the end of the buffer";
494
+			}
495
+			found = found_content_type * found_content_id * found_content_length;
496
+			if ((!found) && (!error)) {
497
+				value_fin = trim_leading_e_r(cpy_c, cpy_d);
498
+				if (value_fin != NULL) {
499
+					cpy_c = value_fin;
500
+					if ((cpy_c + 1) < cpy_d) {
501
+						if ((*cpy_c == '\r') && (*(cpy_c + 1) == '\n')) {
502
+							cpy_c++;
503
+							cpy_c++;
504
+						} else {
505
+							error = -10;
506
+							error_msg = "Each line must end with a \r\n";
507
+						}
508
+					} else {
509
+						error = -11;
510
+						error_msg = "We reached the end of the buffer";
511
+					}
512
+				} else {
513
+					error = -12;
514
+					error_msg = "Failed to perform trim_leading_e_r";
515
+				}
516
+			}
517
+		} /* End main while loop */
518
+	}
519
+
520
+	if (error < 0) {
521
+		LM_ERR("part_multipart_headers_cmp. error. \"%i\". \"%s\".\n", error, error_msg);
522
+		return 0;
523
+	} else {
524
+		return found;
525
+	}
526
+}
527
+
528
+/**
529
+ * get_body_part_by_filter
530
+ *
531
+ * Filters the multipart part from a given SIP message which matches the
532
+ * Content-Type && || Content-ID  && || Content-Length
533
+ * receives
534
+ *   - SIP message
535
+ *   - pointer to the beginning of the headers in a part of the multipart body.
536
+ *   - pointer to the end of the headers in the multipart body.
537
+ *   - content type/ content subtype.
538
+ *         if (type == 0 / subtype == 0): Content-Type: disabled in the search.
539
+ *   - content id.
540
+ *         if (id == NULL): Content-ID: disabled in the search.
541
+ *   - content length.
542
+ *         if (length == NULL) Content-Length: disabled in the search.
543
+ *   - len. Length of the multipart message returned.
544
+ *
545
+ * returns
546
+ *   - pointer to the multipart if success.
547
+ *   - NULL, if none of the multiparts match.
548
+ */
549
+char *get_body_part_by_filter(struct sip_msg *msg,
550
+		     unsigned short content_type,
551
+		     unsigned short content_subtype,
552
+		     char *content_id,
553
+		     char *content_length,
554
+		     int *len)
555
+{
556
+	int mime;
557
+	char*c, *d, *buf_end;
558
+	str boundary;
559
+
560
+	if ((mime = parse_content_type_hdr(msg)) <= 0)
561
+		return NULL;
562
+
563
+	if ((mime>>16) == TYPE_MULTIPART) {
564
+		/* type is multipart/something, search for type/subtype part */
565
+		if (get_boundary_param(msg, &boundary)) {
566
+			ERR("failed to get boundary parameter\n");
567
+			return NULL;
568
+		}
569
+		if (!(c = get_body(msg)))
570
+			return NULL;
571
+		buf_end = msg->buf+msg->len;
572
+
573
+		while ((c = search_boundary(c, buf_end, &boundary))) {
574
+			/* skip boundary */
575
+			c += 2 + boundary.len;
576
+
577
+			if ((c+2 > buf_end) || ((*c == '-') && (*(c+1) == '-')) )
578
+				/* end boundary, no more body part will follow */
579
+				return NULL;
580
+
581
+			/* go to the next line */
582
+			while ((c < buf_end) && (*c != '\n')) c++;
583
+			c++;
584
+			if (c >= buf_end)
585
+				return NULL;
586
+
587
+			d = get_multipart_body(c, buf_end, &boundary, len);
588
+			if (part_multipart_headers_cmp(c, d, content_type, content_subtype,
589
+						content_id, content_length)) {
590
+				return d;
591
+			}
592
+		}
593
+	}
594
+	return NULL;
595
+}
... ...
@@ -41,4 +41,15 @@ char *get_body_part(	struct sip_msg *msg,
41 41
 			unsigned short type, unsigned short subtype,
42 42
 			int *len);
43 43
 
44
+/*! \brief Returns the pointer within the msg body to the given part matching
45
+ * type/subtype, content id or content lenght. It sets the length.
46
+ * The result can be the whole msg body, or a part of a multipart body.
47
+ */
48
+char *get_body_part_by_filter(struct sip_msg *msg,
49
+		     unsigned short content_type,
50
+		     unsigned short content_subtype,
51
+		     char *content_id,
52
+		     char *content_length,
53
+		     int *len);
54
+
44 55
 #endif /* PARSE_BODY_H */