Browse code

get_body_part() function is introduced, that returns a specific part of the message body, for example application/sdp. The result can be the whole body, or a part of it in case of multipart/somehing Content-Type.

Miklos Tirpak authored on 22/05/2008 16:12:16
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,291 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ *
27
+ * History:
28
+ * --------
29
+ *  2008-05-22  Initial version, get_body_part() is introduced (Miklos)
30
+ */
31
+
32
+#include "../trim.h"
33
+#include "parser_f.h"
34
+#include "parse_content.h"
35
+#include "parse_param.h"
36
+#include "keys.h"
37
+#include "parse_body.h"
38
+
39
+/* returns the value of boundary parameter from the Contect-Type HF */
40
+static inline int get_boundary_param(struct sip_msg *msg, str *boundary)
41
+{
42
+	str	s;
43
+	char	*c;
44
+	param_t	*p, *list;
45
+
46
+#define is_boundary(c) \
47
+	(((c)[0] == 'b' || (c)[0] == 'B') && \
48
+	((c)[1] == 'o' || (c)[1] == 'O') && \
49
+	((c)[2] == 'u' || (c)[2] == 'U') && \
50
+	((c)[3] == 'n' || (c)[3] == 'N') && \
51
+	((c)[4] == 'd' || (c)[4] == 'D') && \
52
+	((c)[5] == 'a' || (c)[5] == 'A') && \
53
+	((c)[6] == 'r' || (c)[6] == 'R') && \
54
+	((c)[7] == 'y' || (c)[7] == 'Y'))
55
+
56
+#define boundary_param_len (sizeof("boundary")-1)
57
+
58
+	/* get the pointer to the beginning of the parameter list */
59
+	s.s = msg->content_type->body.s;
60
+	s.len = msg->content_type->body.len;
61
+	c = find_not_quoted(&s, ';');
62
+	if (!c)
63
+		return -1;
64
+	c++;
65
+	s.len = s.len - (c - s.s);
66
+	s.s = c;
67
+	trim_leading(&s);
68
+
69
+	if (s.len <= 0)
70
+		return -1;
71
+
72
+	/* parse the parameter list, and search for boundary */
73
+	if (parse_params(&s, CLASS_ANY, NULL, &list)<0)
74
+		return -1;
75
+
76
+	boundary->s = NULL;
77
+	for (p = list; p; p = p->next)
78
+		if ((p->name.len == boundary_param_len) &&
79
+			is_boundary(p->name.s)
80
+		) {
81
+			boundary->s = p->body.s;
82
+			boundary->len = p->body.len;
83
+			break;
84
+		}
85
+	free_params(list);
86
+	if (!boundary->s || !boundary->len)
87
+		return -1;
88
+
89
+	DBG("boundary is \"%.*s\"\n",
90
+		boundary->len, boundary->s);
91
+	return 0;
92
+}
93
+
94
+/* search the next boundary in the buffer */
95
+static inline char *search_boundary(char *buf, char *buf_end, str *boundary)
96
+{
97
+	char *c;
98
+
99
+	c = buf;
100
+	while (c + 2 /* -- */ + boundary->len < buf_end) {
101
+		if ((*c == '-') && (*(c+1) == '-') &&
102
+			(memcmp(c+2, boundary->s, boundary->len) == 0)
103
+		)
104
+			return c; /* boundary found */
105
+
106
+		/* go to the next line */
107
+		while ((c < buf_end) && (*c != '\n')) c++;
108
+		c++;
109
+	}
110
+	return NULL;
111
+}
112
+
113
+/* extract the body of a part from a multipart SIP msg body */
114
+inline static char *get_multipart_body(char *buf,
115
+					char *buf_end,
116
+					str *boundary,
117
+					int *len)
118
+{
119
+	char *beg, *end;
120
+
121
+	if (buf >= buf_end)
122
+		goto error;
123
+
124
+	beg = buf;
125
+	while ((*beg != '\r') && (*beg != '\n')) {
126
+		while ((beg < buf_end) && (*beg != '\n'))
127
+			beg++;
128
+		beg++;
129
+		if (beg >= buf_end)
130
+			goto error;
131
+	}
132
+	/* CRLF delimeter found, the body begins right after it */
133
+	while ((beg < buf_end) && (*beg != '\n'))
134
+		beg++;
135
+	beg++;
136
+	if (beg >= buf_end)
137
+		goto error;
138
+
139
+	if (!(end = search_boundary(beg, buf_end, boundary)))
140
+		goto error;
141
+
142
+	/* CRLF preceding the boundary belongs to the boundary
143
+	and not to the body */
144
+	if (*(end-1) == '\n') end--;
145
+	if (*(end-1) == '\r') end--;
146
+
147
+	if (end < beg)
148
+		goto error;
149
+
150
+	*len = end-beg;
151
+	return beg;
152
+error:
153
+	ERR("failed to extract the body from the multipart mime type\n");
154
+	return NULL;
155
+}
156
+
157
+
158
+/* macros from parse_hname2.c */
159
+#define READ(val) \
160
+(*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
161
+
162
+#define LOWER_DWORD(d) ((d) | 0x20202020)
163
+
164
+/* Returns the pointer within the msg body to the given type/subtype,
165
+ * and sets the length of the body part.
166
+ * The result can be the whole msg body, or a part of a multipart body.
167
+ */
168
+char *get_body_part(	struct sip_msg *msg,
169
+			unsigned short type, unsigned short subtype,
170
+			int *len)
171
+{
172
+	int	mime;
173
+	unsigned int	umime;
174
+	char	*c, *c2, *buf_end;
175
+	str	boundary;
176
+
177
+#define content_type_len \
178
+	(sizeof("Content-Type") - 1)
179
+
180
+	if ((mime = parse_content_type_hdr(msg)) <= 0)
181
+		return NULL;
182
+
183
+	if (mime == ((type<<16)|subtype)) {
184
+		/* content-type is type/subtype */
185
+		c = get_body(msg);
186
+		if (c)
187
+			*len = msg->buf+msg->len - c;
188
+		return c;
189
+
190
+	} else if ((mime>>16) == TYPE_MULTIPART) {
191
+		/* type is multipart/something, search for type/subtype part */
192
+
193
+		if (get_boundary_param(msg, &boundary)) {
194
+			ERR("failed to get boundary parameter\n");
195
+			return NULL;
196
+		}
197
+		if (!(c = get_body(msg)))
198
+			return NULL;
199
+		buf_end = msg->buf+msg->len;
200
+
201
+		/* check all the body parts delimated by the boundary value,
202
+		and search for the Content-Type HF with the given 
203
+		type/subtype */
204
+next_part:
205
+		while ((c = search_boundary(c, buf_end, &boundary))) {
206
+			/* skip boundary */
207
+			c += 2 + boundary.len;
208
+
209
+			if ((c+2 > buf_end) ||
210
+				((*c == '-') && (*(c+1) == '-'))
211
+			)
212
+				/* end boundary, no more body part
213
+				will follow */
214
+				return NULL;
215
+
216
+			/* go to the next line */
217
+			while ((c < buf_end) && (*c != '\n')) c++;
218
+			c++;
219
+			if (c >= buf_end)
220
+				return NULL;
221
+
222
+			/* try to find the content-type header */
223
+			while ((*c != '\r') && (*c != '\n')) {
224
+				if (c + content_type_len >= buf_end)
225
+					return NULL;
226
+
227
+				if ((LOWER_DWORD(READ(c)) == _cont_) &&
228
+					(LOWER_DWORD(READ(c+4)) == _ent__) &&
229
+					(LOWER_DWORD(READ(c+8)) == _type_)
230
+				) {
231
+					/* Content-Type HF found */
232
+					c += content_type_len;
233
+					while ((c < buf_end) &&
234
+						((*c == ' ') || (*c == '\t'))
235
+					)
236
+						c++;
237
+
238
+					if (c + 1 /* : */ >= buf_end)
239
+						return NULL;
240
+
241
+					if (*c != ':')
242
+						/* not realy a Content-Type HF */
243
+						goto next_hf;
244
+					c++;
245
+
246
+					/* search the end of the header body,
247
+					decode_mime_type() needs it */
248
+					c2 = c;
249
+					while (((c2 < buf_end) && (*c2 != '\n')) ||
250
+						((c2+1 < buf_end) && (*c2 == '\n') &&
251
+							((*(c2+1) == ' ') || (*(c2+1) == '\t')))
252
+					)
253
+						c2++;
254
+
255
+					if (c2 >= buf_end)
256
+						return NULL;
257
+					if (*(c2-1) == '\r') c2--;
258
+
259
+					if (!decode_mime_type(c, c2 , &umime)) {
260
+						ERR("failed to decode the mime type\n");
261
+						return NULL;
262
+					}
263
+
264
+					/* c2 points to the CRLF at the end of the line,
265
+					move the pointer to the beginning of the next line */
266
+					c = c2;
267
+					if ((c < buf_end) && (*c == '\r')) c++;
268
+					if ((c < buf_end) && (*c == '\n')) c++;
269
+
270
+					if (umime != ((type<<16)|subtype)) {
271
+						/* this is not the part we are looking for */
272
+						goto next_part;
273
+					}
274
+
275
+					/* the requested type/subtype is found! */
276
+					return get_multipart_body(c,
277
+							buf_end,
278
+							&boundary,
279
+							len);
280
+				}
281
+next_hf:
282
+				/* go to the next line */
283
+				while ((c < buf_end) && (*c != '\n')) c++;
284
+				c++;
285
+			}
286
+			/* CRLF delimeter reached,
287
+			no Content-Type HF was found */
288
+		}
289
+	}
290
+	return NULL;
291
+}
0 292
new file mode 100644
... ...
@@ -0,0 +1,40 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ *
27
+ */
28
+
29
+#ifndef PARSE_BODY_H
30
+#define PARSE_BODY_H
31
+
32
+/* Returns the pointer within the msg body to the given type/subtype,
33
+ * and sets the length.
34
+ * The result can be the whole msg body, or a part of a multipart body.
35
+ */
36
+char *get_body_part(	struct sip_msg *msg,
37
+			unsigned short type, unsigned short subtype,
38
+			int *len);
39
+
40
+#endif /* PARSE_BODY_H */
... ...
@@ -120,4 +120,9 @@ int parse_accept_hdr( struct sip_msg *msg );
120 120
  */
121 121
 char* parse_content_length( char* buffer, char* end, int* len);
122 122
 
123
+/*
124
+ * Sets the mime type from the body of a Content-Type header
125
+ */
126
+char* decode_mime_type(char *start, char *end, unsigned int *mime_type);
127
+
123 128
 #endif