bodyhandler.c 38.5 KB
Newer Older
1 2
/*
	belle-sip - SIP (RFC3261) library.
3
	Copyright (C) 2010-2018  Belledonne Communications SARL
4

5 6 7 8
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 2 of the License, or
	(at your option) any later version.
9

10 11 12 13
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
14

15 16
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 18 19
*/

#include "belle_sip_internal.h"
20
#include "bctoolbox/vfs.h"
21

Ghislain MARY's avatar
Ghislain MARY committed
22 23 24
#ifdef HAVE_ZLIB
#include "zlib.h"
#endif
25 26 27 28 29 30 31 32 33 34

/*
 * Body handler base class implementation
 */

struct belle_sip_body_handler{
	belle_sip_object_t base;
	belle_sip_body_handler_progress_callback_t progress_cb;
	size_t expected_size; /* 0 if unknown*/
	size_t transfered_size;
35 36
	belle_sip_list_t *headers; /**> used when this body is part of a multipart message to store the header of this part */
	char *headerStringBuffer; /**> buffer populated with a string created from marshaling the headers */
37 38 39 40 41 42 43 44
	void *user_data;
};

static void belle_sip_body_handler_clone(belle_sip_body_handler_t *obj, const belle_sip_body_handler_t *orig){
	obj->progress_cb=orig->progress_cb;
	obj->user_data=orig->user_data;
	obj->expected_size=orig->expected_size;
	obj->transfered_size=orig->transfered_size;
45 46 47 48
	obj->headers=belle_sip_list_copy_with_data(orig->headers,(void *(*)(void*))belle_sip_object_clone_and_ref);
	if (orig->headerStringBuffer!=NULL) {
		obj->headerStringBuffer = strdup(orig->headerStringBuffer);
	}
49 50
}

51
static void belle_sip_body_handler_destroy(belle_sip_body_handler_t *obj){
52 53
	belle_sip_list_free_with_data(obj->headers,belle_sip_object_unref);
	belle_sip_free(obj->headerStringBuffer);
54 55
}

56 57 58
static belle_sip_error_code belle_sip_body_handler_marshal(belle_sip_body_handler_t *obj, char *buff, size_t buff_size, size_t *offset) {
	int ret;
	size_t len;
59
	if (*offset == 0) belle_sip_body_handler_begin_send_transfer(obj);
60 61 62 63 64
	do {
		len = buff_size - *offset;
		ret = belle_sip_body_handler_send_chunk(obj, NULL, (uint8_t*)buff + *offset, &len);
		*offset += len;
	} while ((ret == BELLE_SIP_CONTINUE) && (len > 0));
65
	if ((ret == BELLE_SIP_CONTINUE) || (ret == BELLE_SIP_BUFFER_OVERFLOW)) return BELLE_SIP_BUFFER_OVERFLOW;
66 67 68 69
	if (ret == BELLE_SIP_STOP) belle_sip_body_handler_end_transfer(obj);
	return BELLE_SIP_OK;
}

70 71 72 73 74
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_body_handler_t);

BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_body_handler_t)
	{
		BELLE_SIP_VPTR_INIT(belle_sip_body_handler_t,belle_sip_object_t,TRUE),
75
		(belle_sip_object_destroy_t) belle_sip_body_handler_destroy,
76
		(belle_sip_object_clone_t) belle_sip_body_handler_clone,
77
		(belle_sip_object_marshal_t) belle_sip_body_handler_marshal,
78 79
		(belle_sip_object_on_first_ref_t) NULL,
		(belle_sip_object_on_last_ref_t) NULL,
80
		BELLE_SIP_DEFAULT_BUFSIZE_HINT
81
	},
82 83
	NULL, /* begin_recv_transfer */
	NULL, /* begin_send_transfer */
84
	NULL, /* end_transfer */
85 86 87 88 89 90 91
	NULL, /*chunk_recv*/
	NULL /*chunk_send*/
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END

void belle_sip_body_handler_init(belle_sip_body_handler_t *obj, belle_sip_body_handler_progress_callback_t progress_cb, void *user_data){
	obj->user_data=user_data;
	obj->progress_cb=progress_cb;
92 93
	obj->headers = NULL; /* header is not used in most of the case, set it using a dedicated function if needed */
	obj->headerStringBuffer = NULL; /* header string buffer is set when adding a body handler to a multipart body handler */
94 95
}

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
void belle_sip_body_handler_add_header(belle_sip_body_handler_t *obj, belle_sip_header_t *header) {
	if (header != NULL) {
		obj->headers=belle_sip_list_append(obj->headers,belle_sip_object_ref(header));
	}
}

void belle_sip_body_handler_remove_header_from_ptr(belle_sip_body_handler_t *obj, belle_sip_header_t* header) {
	belle_sip_list_t* it = belle_sip_list_find(obj->headers, header);
	if (it) {
		belle_sip_object_unref(header);
		obj->headers = belle_sip_list_delete_link(obj->headers, it);
	}
}

const belle_sip_list_t* belle_sip_body_handler_get_headers(const belle_sip_body_handler_t *obj) {
	return obj->headers;
}

114 115 116 117
size_t belle_sip_body_handler_get_size(const belle_sip_body_handler_t *obj){
	return obj->expected_size;
}

118 119 120 121
void belle_sip_body_handler_set_size(belle_sip_body_handler_t *obj, size_t size){
	obj->expected_size=size;
}

122 123 124 125 126
size_t belle_sip_body_handler_get_transfered_size(const belle_sip_body_handler_t *obj){
	return obj->transfered_size;
}

static void update_progress(belle_sip_body_handler_t *obj, belle_sip_message_t *msg){
127
	belle_sip_debug("body handler [%p] : %llu bytes exchanged of %llu ", obj, (unsigned long long)obj->transfered_size, (unsigned long long)obj->expected_size);
128 129 130 131
	if (obj->progress_cb)
		obj->progress_cb(obj,msg,obj->user_data,obj->transfered_size,obj->expected_size);
}

132
void belle_sip_body_handler_begin_recv_transfer(belle_sip_body_handler_t *obj){
133
	BELLE_SIP_OBJECT_VPTR_TYPE(belle_sip_body_handler_t) *vptr = BELLE_SIP_OBJECT_VPTR(obj, belle_sip_body_handler_t);
134 135
	if (vptr->begin_recv_transfer != NULL) {
		vptr->begin_recv_transfer(obj);
136
	}
137 138 139
	obj->transfered_size=0;
}

140 141 142 143 144 145 146 147
void belle_sip_body_handler_begin_send_transfer(belle_sip_body_handler_t *obj) {
	BELLE_SIP_OBJECT_VPTR_TYPE(belle_sip_body_handler_t) *vptr = BELLE_SIP_OBJECT_VPTR(obj, belle_sip_body_handler_t);
	if (vptr->begin_send_transfer != NULL) {
		vptr->begin_send_transfer(obj);
	}
	obj->transfered_size = 0;
}

148
void belle_sip_body_handler_recv_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, uint8_t *buf, size_t size){
149
	BELLE_SIP_OBJECT_VPTR(obj,belle_sip_body_handler_t)->chunk_recv(obj,msg,(off_t)obj->transfered_size,buf,size);
150 151 152 153 154 155
	obj->transfered_size+=size;
	update_progress(obj,msg);
}

int belle_sip_body_handler_send_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, uint8_t *buf, size_t *size){
	int ret;
156
	size_t to_send = *size;
157
	if (obj->expected_size!=0){
158
		to_send=MIN(*size,obj->expected_size-obj->transfered_size);
159
	}
160 161 162
	if (to_send==0 && obj->transfered_size==obj->expected_size) {
		// An eWouldBlock error added a call to the function, nothing to send so return
		// In some case to_send=0 because not buffer is available but sendings not finished.
163 164 165 166
		belle_sip_message("body handler [%p] : Nothing to send",obj);
		*size=0;
		return BELLE_SIP_STOP;
	}
167
	ret=BELLE_SIP_OBJECT_VPTR(obj,belle_sip_body_handler_t)->chunk_send(obj,msg,(off_t)obj->transfered_size,buf,&to_send);
168 169
	obj->transfered_size+=to_send;
	*size=to_send;
170 171
	update_progress(obj,msg);
	if (obj->expected_size!=0){
172
		if (obj->transfered_size==obj->expected_size) {
173
			return BELLE_SIP_STOP;
174
		}
175 176 177 178 179 180 181 182 183
		if (ret==BELLE_SIP_STOP && obj->transfered_size<obj->expected_size){
			belle_sip_error("body handler [%p] transfered only [%i] bytes while [%i] were expected",obj,
					(int)obj->transfered_size,(int)obj->expected_size);
		}
	}
	return ret;
}

void belle_sip_body_handler_end_transfer(belle_sip_body_handler_t *obj){
184 185 186 187
	BELLE_SIP_OBJECT_VPTR_TYPE(belle_sip_body_handler_t) *vptr = BELLE_SIP_OBJECT_VPTR(obj, belle_sip_body_handler_t);
	if (vptr->end_transfer != NULL) {
		vptr->end_transfer(obj);
	}
188 189 190 191 192 193 194 195 196 197 198
	if (obj->expected_size==0)
		obj->expected_size=obj->transfered_size;
}

/*
 * memory body handler implementation.
**/

struct belle_sip_memory_body_handler{
	belle_sip_body_handler_t base;
	uint8_t *buffer;
Ghislain MARY's avatar
Ghislain MARY committed
199
	uint8_t encoding_applied;
200 201 202 203 204 205 206 207
};

static void belle_sip_memory_body_handler_destroy(belle_sip_memory_body_handler_t *obj){
	if (obj->buffer) belle_sip_free(obj->buffer);
}

static void belle_sip_memory_body_handler_clone(belle_sip_memory_body_handler_t *obj, const belle_sip_memory_body_handler_t *orig){
	if (orig->buffer) {
208 209 210
		obj->buffer=belle_sip_malloc(orig->base.expected_size+1);
		memcpy(obj->buffer,orig->buffer,orig->base.expected_size);
		obj->buffer[orig->base.expected_size]='\0';
211
	}
Ghislain MARY's avatar
Ghislain MARY committed
212
	obj->encoding_applied = orig->encoding_applied;
213 214
}

215
static void belle_sip_memory_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, off_t offset, uint8_t *buf, size_t size){
216 217 218 219 220 221
	belle_sip_memory_body_handler_t *obj=(belle_sip_memory_body_handler_t*)base;
	obj->buffer=belle_sip_realloc(obj->buffer,offset+size+1);
	memcpy(obj->buffer+offset,buf,size);
	obj->buffer[offset+size]='\0';
}

222
static int belle_sip_memory_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, off_t offset, uint8_t *buf, size_t *size){
223
	belle_sip_memory_body_handler_t *obj=(belle_sip_memory_body_handler_t*)base;
224
	size_t to_send=MIN(*size,obj->base.expected_size-offset);
225
	if (obj->buffer == NULL) return BELLE_SIP_STOP;
226 227
	memcpy(buf,obj->buffer+offset,to_send);
	*size=to_send;
228
	return (obj->base.expected_size-offset==*size) ? BELLE_SIP_STOP : BELLE_SIP_CONTINUE;
229 230 231 232 233 234 235 236 237
}

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_memory_body_handler_t);
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_memory_body_handler_t)
	{
		{
			BELLE_SIP_VPTR_INIT(belle_sip_memory_body_handler_t,belle_sip_body_handler_t,TRUE),
			(belle_sip_object_destroy_t) belle_sip_memory_body_handler_destroy,
			(belle_sip_object_clone_t)belle_sip_memory_body_handler_clone,
238 239
			NULL,
			BELLE_SIP_DEFAULT_BUFSIZE_HINT
240
		},
241 242
		NULL,
		NULL,
243
		NULL,
244 245 246 247 248
		belle_sip_memory_body_handler_recv_chunk,
		belle_sip_memory_body_handler_send_chunk
	}
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END

249
void *belle_sip_memory_body_handler_get_buffer(const belle_sip_memory_body_handler_t *obj){
250 251 252
	return obj->buffer;
}

253
void belle_sip_memory_body_handler_set_buffer(belle_sip_memory_body_handler_t *obj, void *buffer) {
254
	if (obj->buffer != NULL) belle_sip_free(obj->buffer);
255 256 257
	obj->buffer = (uint8_t *)buffer;
}

258
#define BELLE_SIP_MEMORY_BODY_HANDLER_MINIMUM_DEFLATE_INPUT_SIZE 256
259
#define BELLE_SIP_MEMORY_BODY_HANDLER_ZLIB_INITIAL_SIZE 2048
Ghislain MARY's avatar
Ghislain MARY committed
260

261 262 263 264 265
int belle_sip_memory_body_handler_apply_encoding(belle_sip_memory_body_handler_t *obj, const char *encoding) {
	if (obj->encoding_applied == TRUE)
		return 0;
	if (!obj->buffer || (belle_sip_body_handler_get_size(BELLE_SIP_BODY_HANDLER(obj)) < BELLE_SIP_MEMORY_BODY_HANDLER_MINIMUM_DEFLATE_INPUT_SIZE))
		return -1;
Ghislain MARY's avatar
Ghislain MARY committed
266 267 268 269 270 271

#ifdef HAVE_ZLIB
	if (strcmp(encoding, "deflate") == 0) {
		z_stream strm;
		size_t initial_size = belle_sip_body_handler_get_size(BELLE_SIP_BODY_HANDLER(obj));
		size_t final_size;
272
		unsigned int avail_out = BELLE_SIP_MEMORY_BODY_HANDLER_ZLIB_INITIAL_SIZE;
Ghislain MARY's avatar
Ghislain MARY committed
273 274 275 276 277 278 279 280 281
		unsigned int outbuf_size = avail_out;
		unsigned char *outbuf = belle_sip_malloc(outbuf_size);
		unsigned char *outbuf_ptr = outbuf;
		int ret;

		strm.zalloc = Z_NULL;
		strm.zfree = Z_NULL;
		strm.opaque = Z_NULL;
		ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
282 283 284 285
		if (ret != Z_OK) {
			belle_sip_free(outbuf);
			return -1;
		}
286
		strm.avail_in = (uInt)initial_size;
Ghislain MARY's avatar
Ghislain MARY committed
287 288
		strm.next_in = obj->buffer;
		do {
289
			if (avail_out < BELLE_SIP_MEMORY_BODY_HANDLER_ZLIB_INITIAL_SIZE) {
290
				unsigned int cursize = (unsigned int)(outbuf_ptr - outbuf);
291
				outbuf_size *= 2;
Ghislain MARY's avatar
Ghislain MARY committed
292 293 294 295 296 297 298
				outbuf = belle_sip_realloc(outbuf, outbuf_size);
				outbuf_ptr = outbuf + cursize;
			}
			strm.avail_out = avail_out;
			strm.next_out = outbuf_ptr;
			deflate(&strm, Z_FINISH);
			outbuf_ptr += avail_out - strm.avail_out;
299
			avail_out = outbuf_size - (unsigned int)(outbuf_ptr - outbuf);
Ghislain MARY's avatar
Ghislain MARY committed
300 301 302
		} while (strm.avail_out == 0);
		deflateEnd(&strm);
		final_size = outbuf_ptr - outbuf;
303 304 305 306 307
		if ((final_size + 27) >= initial_size) { // 27 is the size of the Content-Encoding header
			belle_sip_message("Body not compressed because its size would have increased");
			belle_sip_free(outbuf);
			return -1;
		}
Ghislain MARY's avatar
Ghislain MARY committed
308 309 310 311 312
		belle_sip_message("Body has been compressed: %u->%u:\n%s", (unsigned int)initial_size, (unsigned int)final_size, obj->buffer);
		belle_sip_free(obj->buffer);
		obj->buffer = outbuf;
		belle_sip_body_handler_set_size(BELLE_SIP_BODY_HANDLER(obj), final_size);
		obj->encoding_applied = TRUE;
313
		return 0;
Ghislain MARY's avatar
Ghislain MARY committed
314 315 316 317
	} else
#endif
	{
		belle_sip_warning("%s: unknown encoding '%s'", __FUNCTION__, encoding);
318
		return -1;
Ghislain MARY's avatar
Ghislain MARY committed
319 320 321
	}
}

322 323 324 325 326 327 328 329
int belle_sip_memory_body_handler_unapply_encoding(belle_sip_memory_body_handler_t *obj, const char *encoding) {
	if (obj->buffer == NULL) return -1;

#ifdef HAVE_ZLIB
	if (strcmp(encoding, "deflate") == 0) {
		z_stream strm;
		size_t initial_size = belle_sip_body_handler_get_size(BELLE_SIP_BODY_HANDLER(obj));
		size_t final_size;
330
		unsigned int avail_out = BELLE_SIP_MEMORY_BODY_HANDLER_ZLIB_INITIAL_SIZE;
331 332 333
		unsigned int outbuf_size = avail_out;
		unsigned char *outbuf = belle_sip_malloc(outbuf_size);
		unsigned char *outbuf_ptr = outbuf;
334
		bool_t outbuf_too_small = FALSE;
335 336 337 338 339 340 341 342 343
		int ret;

		strm.zalloc = Z_NULL;
		strm.zfree = Z_NULL;
		strm.opaque = Z_NULL;
		strm.avail_in = 0;
		strm.next_in = Z_NULL;
		ret = inflateInit(&strm);
		if (ret != Z_OK) return -1;
344
		strm.avail_in = (uInt)initial_size;
345 346
		strm.next_in = obj->buffer;
		do {
347
			if ((avail_out < BELLE_SIP_MEMORY_BODY_HANDLER_ZLIB_INITIAL_SIZE) || (outbuf_too_small == TRUE)) {
348
				unsigned int cursize = (unsigned int)(outbuf_ptr - outbuf);
349
				unsigned int increase = outbuf_size;
350
				outbuf_size *= 2;
351 352
				outbuf = belle_sip_realloc(outbuf, outbuf_size);
				outbuf_ptr = outbuf + cursize;
353
				avail_out += increase;
354
			}
355
			outbuf_too_small = FALSE;
356 357 358 359
			strm.avail_out = avail_out;
			strm.next_out = outbuf_ptr;
			ret = inflate(&strm, Z_NO_FLUSH);
			switch (ret) {
360
				case Z_OK:
361 362 363 364 365 366
					/* Error handling for truncated input buffer. Z_STREAM_END is not returned but there is no further input content */
					if (strm.avail_out > 0) {
						belle_sip_error("%s: truncated compressed body. Cannot uncompress it...", __FUNCTION__);
						return -1;
					}
					break;
367
				case Z_STREAM_END:
368 369 370 371 372 373
					// Everything is ok, continue
					break;
				case Z_BUF_ERROR:
					// Ask for more output space
					outbuf_too_small = TRUE;
					break;
374 375
				case Z_NEED_DICT:
				case Z_DATA_ERROR:
376
				case Z_STREAM_ERROR:
377
				case Z_MEM_ERROR:
378
				default:
379 380 381 382 383
					inflateEnd(&strm);
					belle_sip_free(outbuf);
					return -1;
			}
			outbuf_ptr += avail_out - strm.avail_out;
384
			avail_out = outbuf_size - (unsigned int)(outbuf_ptr - outbuf);
385 386 387
		} while (ret != Z_STREAM_END);
		inflateEnd(&strm);
		final_size = outbuf_ptr - outbuf;
388 389 390 391 392 393
		if (final_size == outbuf_size) {
			/* If not enough space get it to be able to put the final NULL character. */
			outbuf = belle_sip_realloc(outbuf, outbuf_size + 1);
			outbuf_ptr = outbuf + final_size;
		}
		*outbuf_ptr = '\0';
394 395 396 397 398 399 400 401 402 403 404 405 406
		belle_sip_message("Body has been uncompressed: %u->%u:\n%s", (unsigned int)initial_size, (unsigned int)final_size, outbuf);
		belle_sip_free(obj->buffer);
		obj->buffer = outbuf;
		belle_sip_body_handler_set_size(BELLE_SIP_BODY_HANDLER(obj), final_size);
		return 0;
	} else
#endif
	{
		belle_sip_warning("%s: unknown encoding '%s'", __FUNCTION__, encoding);
		return -1;
	}
}

407 408 409 410 411 412 413 414 415 416
belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new(belle_sip_body_handler_progress_callback_t cb, void *user_data){
	belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t);
	belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data);
	return obj;
}

belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new_from_buffer(void *buffer, size_t bufsize, belle_sip_body_handler_progress_callback_t cb, void *user_data){
	belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t);
	belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data);
	obj->buffer=(uint8_t*)buffer;
417
	obj->base.expected_size=bufsize;
418 419 420 421 422 423 424 425
	return obj;
}

belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new_copy_from_buffer(const void *buffer, size_t bufsize, belle_sip_body_handler_progress_callback_t cb, void *user_data){
	belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t);
	belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data);
	obj->buffer=(uint8_t*)belle_sip_malloc(bufsize+1);
	obj->buffer[bufsize]='\0';
426
	obj->base.expected_size=bufsize;
427 428 429 430 431 432 433 434 435 436
	memcpy(obj->buffer,buffer,bufsize);
	return obj;
}

/*
 * User body handler implementation
 */

struct belle_sip_user_body_handler{
	belle_sip_body_handler_t base;
437
	belle_sip_user_body_handler_start_callback_t start_cb;
438 439
	belle_sip_user_body_handler_recv_callback_t recv_cb;
	belle_sip_user_body_handler_send_callback_t send_cb;
440
	belle_sip_user_body_handler_stop_callback_t stop_cb;
441 442
};

443 444 445 446 447 448 449 450 451 452 453 454
static void belle_sip_user_body_handler_begin_transfer(belle_sip_body_handler_t *base) {
	belle_sip_user_body_handler_t *obj = (belle_sip_user_body_handler_t *)base;
	if (obj->start_cb)
		obj->start_cb((belle_sip_user_body_handler_t*)base, base->user_data);
}

static void belle_sip_user_body_handler_end_transfer(belle_sip_body_handler_t *base) {
	belle_sip_user_body_handler_t *obj = (belle_sip_user_body_handler_t *)base;
	if (obj->stop_cb)
		obj->stop_cb((belle_sip_user_body_handler_t*)base, base->user_data);
}

455
static void belle_sip_user_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, off_t offset, uint8_t *buf, size_t size){
456 457 458 459 460 461
	belle_sip_user_body_handler_t *obj=(belle_sip_user_body_handler_t*)base;
	if (obj->recv_cb)
		obj->recv_cb((belle_sip_user_body_handler_t*)base, msg, base->user_data, offset, buf, size);
	else belle_sip_warning("belle_sip_user_body_handler_t ignoring received chunk.");
}

462
static int belle_sip_user_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, off_t offset, uint8_t *buf, size_t *size){
463 464 465 466 467 468 469 470 471
	belle_sip_user_body_handler_t *obj=(belle_sip_user_body_handler_t*)base;
	if (obj->send_cb)
		return obj->send_cb((belle_sip_user_body_handler_t*)base, msg, base->user_data, offset, buf, size);
	else belle_sip_warning("belle_sip_user_body_handler_t ignoring send chunk.");
	*size=0;
	return BELLE_SIP_STOP;
}

static void belle_sip_user_body_handler_clone(belle_sip_user_body_handler_t *obj, const belle_sip_user_body_handler_t *orig){
472
	obj->start_cb=orig->start_cb;
473 474
	obj->recv_cb=orig->recv_cb;
	obj->send_cb=orig->send_cb;
475
	obj->stop_cb=orig->stop_cb;
476 477 478 479 480 481 482 483 484
}

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_user_body_handler_t);
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_user_body_handler_t)
	{
		{
			BELLE_SIP_VPTR_INIT(belle_sip_user_body_handler_t,belle_sip_body_handler_t,TRUE),
			(belle_sip_object_destroy_t) NULL,
			(belle_sip_object_clone_t)belle_sip_user_body_handler_clone,
485 486
			NULL,
			BELLE_SIP_DEFAULT_BUFSIZE_HINT
487
		},
488
		belle_sip_user_body_handler_begin_transfer,
489
		belle_sip_user_body_handler_begin_transfer,
490
		belle_sip_user_body_handler_end_transfer,
491 492 493 494 495 496 497 498
		belle_sip_user_body_handler_recv_chunk,
		belle_sip_user_body_handler_send_chunk
	}
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END

belle_sip_user_body_handler_t *belle_sip_user_body_handler_new(
	size_t total_size,
	belle_sip_body_handler_progress_callback_t progress_cb,
499
	belle_sip_user_body_handler_start_callback_t start_cb,
500 501
	belle_sip_user_body_handler_recv_callback_t recv_cb,
	belle_sip_user_body_handler_send_callback_t send_cb,
502
	belle_sip_user_body_handler_stop_callback_t stop_cb,
503 504 505 506
	void *data){
	belle_sip_user_body_handler_t * obj=belle_sip_object_new(belle_sip_user_body_handler_t);
	belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,progress_cb,data);
	obj->base.expected_size=total_size;
507
	obj->start_cb=start_cb;
508 509
	obj->recv_cb=recv_cb;
	obj->send_cb=send_cb;
510
	obj->stop_cb=stop_cb;
511 512 513 514
	return obj;
}


515 516 517 518 519 520 521
/**
 * File body handler implementation
**/

struct belle_sip_file_body_handler{
	belle_sip_body_handler_t base;
	char *filepath;
522
	bctbx_vfs_file_t *file;
523
	belle_sip_user_body_handler_t *user_bh;
524 525 526 527
};

static void belle_sip_file_body_handler_destroy(belle_sip_file_body_handler_t *obj) {
	if (obj->filepath) belle_sip_free(obj->filepath);
528 529 530 531 532 533 534 535
	if (obj->file) {
		ssize_t ret;
		ret = bctbx_file_close(obj->file);
		if (ret == BCTBX_VFS_ERROR) {
			bctbx_error("Can't close file %s", obj->filepath);
		}
		obj->file = NULL;
	}
536 537 538 539
	if (obj->user_bh) {
		belle_sip_object_unref(obj->user_bh);
		obj->user_bh = NULL;
	}
540 541 542 543
}

static void belle_sip_file_body_handler_clone(belle_sip_file_body_handler_t *obj, const belle_sip_file_body_handler_t *orig) {
	obj->filepath = belle_sip_strdup(orig->filepath);
544
	obj->file = orig->file;
545 546 547 548
	obj->user_bh = orig->user_bh;
	if (obj->user_bh) {
		belle_sip_object_ref(obj->user_bh);
	}
549 550
}

551
static void belle_sip_file_body_handler_begin_recv_transfer(belle_sip_body_handler_t *base) {
552
	belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base;
553
	bctbx_vfs_t *vfs = bctbx_vfs_get_default();
Erwan Croze's avatar
Erwan Croze committed
554

555
	if (obj->filepath == NULL) return;
556 557 558 559
	obj->file = bctbx_file_open(vfs, obj->filepath, "r+");
	if (!obj->file) {
		bctbx_error("Can't open file %s", obj->filepath);
	}
560

561 562 563
	if (obj->user_bh && obj->user_bh->start_cb) {
		obj->user_bh->start_cb((belle_sip_user_body_handler_t*)&(obj->user_bh->base), obj->user_bh->base.user_data);
	}
564 565
}

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
static void belle_sip_file_body_handler_begin_send_transfer(belle_sip_body_handler_t *base) {
	belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base;
	bctbx_vfs_t *vfs = bctbx_vfs_get_default();

	if (obj->filepath == NULL) return;
	obj->file = bctbx_file_open(vfs, obj->filepath, "r");
	if (!obj->file) {
		bctbx_error("Can't open file %s", obj->filepath);
	}

	if (obj->user_bh && obj->user_bh->start_cb) {
		obj->user_bh->start_cb((belle_sip_user_body_handler_t*)&(obj->user_bh->base), obj->user_bh->base.user_data);
	}
}

581 582
static void belle_sip_file_body_handler_end_transfer(belle_sip_body_handler_t *base) {
	belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base;
583

584 585 586
	if (obj->user_bh && obj->user_bh->stop_cb) {
		obj->user_bh->stop_cb((belle_sip_user_body_handler_t*)&(obj->user_bh->base), obj->user_bh->base.user_data);
	}
587

588 589 590 591 592 593 594 595 596 597
	if (obj->file) {
		ssize_t ret;
		ret = bctbx_file_close(obj->file);
		if (ret == BCTBX_VFS_ERROR) {
			bctbx_error("Can't close file %s", obj->filepath);
		}
		obj->file = NULL;
	}
}

598
static void belle_sip_file_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, off_t offset, uint8_t *buf, size_t size) {
599 600
	belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base;
	ssize_t ret;
Erwan Croze's avatar
Erwan Croze committed
601

602
	if (obj->file == NULL) return;
603

604 605 606
	if (obj->user_bh && obj->user_bh->recv_cb) {
		obj->user_bh->recv_cb((belle_sip_user_body_handler_t*)&(obj->user_bh->base), msg, obj->user_bh->base.user_data, offset, buf, size);
	}
607

608 609
	ret = bctbx_file_write(obj->file, buf, size, offset);
	if (ret == BCTBX_VFS_ERROR) {
610
		bctbx_error("File body handler recv write error at offset %lu", (unsigned long)offset);
611
	}
612 613
}

614
static int belle_sip_file_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, off_t offset, uint8_t *buf, size_t *size) {
615
	belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base;
616
	ssize_t size_t_ret;
617
	size_t to_send = MIN(*size, obj->base.expected_size - offset);
Erwan Croze's avatar
Erwan Croze committed
618

619 620 621
	if (obj->file == NULL) return BELLE_SIP_STOP;
	size_t_ret = bctbx_file_read(obj->file, buf, to_send, offset);
	if (size_t_ret == BCTBX_VFS_ERROR) {
622
		bctbx_error("File body handler send read error at offset %lu", (unsigned long)offset);
623 624
		return BELLE_SIP_STOP;
	}
625
	*size = (size_t)size_t_ret;
626

627 628 629 630
	if (obj->user_bh && obj->user_bh->send_cb) {
		int result = obj->user_bh->send_cb((belle_sip_user_body_handler_t*)&(obj->user_bh->base), msg, obj->user_bh->base.user_data, offset, buf, size);
		if (result == BELLE_SIP_STOP) return result;
	}
631

632
	return (((obj->base.expected_size - offset) == (size_t)size_t_ret) || (*size == 0)) ? BELLE_SIP_STOP : BELLE_SIP_CONTINUE;
633 634 635 636 637 638 639 640 641
}

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_file_body_handler_t);
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_file_body_handler_t)
	{
		{
			BELLE_SIP_VPTR_INIT(belle_sip_file_body_handler_t,belle_sip_body_handler_t,TRUE),
			(belle_sip_object_destroy_t) belle_sip_file_body_handler_destroy,
			(belle_sip_object_clone_t)belle_sip_file_body_handler_clone,
642 643
			NULL,
			BELLE_SIP_DEFAULT_BUFSIZE_HINT
644
		},
645 646
		belle_sip_file_body_handler_begin_recv_transfer,
		belle_sip_file_body_handler_begin_send_transfer,
647
		belle_sip_file_body_handler_end_transfer,
648 649 650 651 652 653 654 655 656 657
		belle_sip_file_body_handler_recv_chunk,
		belle_sip_file_body_handler_send_chunk
	}
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END

belle_sip_file_body_handler_t *belle_sip_file_body_handler_new(const char *filepath, belle_sip_body_handler_progress_callback_t progress_cb, void *data) {
	struct stat statbuf;
	belle_sip_file_body_handler_t *obj = belle_sip_object_new(belle_sip_file_body_handler_t);
	belle_sip_body_handler_init((belle_sip_body_handler_t*)obj, progress_cb, data);
	obj->filepath = belle_sip_strdup(filepath);
658
	obj->user_bh = NULL;
659 660 661 662 663 664
	if (stat(obj->filepath, &statbuf) == 0) {
		obj->base.expected_size = statbuf.st_size;
	}
	return obj;
}

665 666 667 668
size_t belle_sip_file_body_handler_get_file_size(belle_sip_file_body_handler_t *file_bh) {
	return file_bh->base.expected_size;
}

669 670 671 672 673 674
void belle_sip_file_body_handler_set_user_body_handler(belle_sip_file_body_handler_t *file_bh, belle_sip_user_body_handler_t *user_bh) {
	if (file_bh) {
		file_bh->user_bh = user_bh;
		belle_sip_object_ref(file_bh->user_bh);
	}
}
675

676 677 678 679 680 681 682 683
/*
 * Multipart body handler implementation
 * TODO
**/

struct belle_sip_multipart_body_handler{
	belle_sip_body_handler_t base;
	belle_sip_list_t *parts;
684
	belle_sip_list_t *transfer_current_part;
685 686
	char *boundary;
	uint8_t *buffer;
687
	unsigned int related;
688
};
689
GET_SET_BOOL(belle_sip_multipart_body_handler,related,is);
690 691 692

static void belle_sip_multipart_body_handler_destroy(belle_sip_multipart_body_handler_t *obj){
	belle_sip_list_free_with_data(obj->parts,belle_sip_object_unref);
693 694
	if (obj->buffer != NULL) belle_sip_free(obj->buffer);
	if (obj->boundary != NULL) belle_sip_free(obj->boundary);
695 696 697 698 699 700
}

static void belle_sip_multipart_body_handler_clone(belle_sip_multipart_body_handler_t *obj){
	obj->parts=belle_sip_list_copy_with_data(obj->parts,(void *(*)(void*))belle_sip_object_clone_and_ref);
}

701 702 703 704 705 706 707 708 709 710 711
static void belle_sip_multipart_body_handler_begin_recv_transfer(belle_sip_body_handler_t *obj) {
	const belle_sip_list_t *it;
	belle_sip_multipart_body_handler_t *obj_multipart = (belle_sip_multipart_body_handler_t *)obj;
	for (it = obj_multipart->parts; it != NULL; it = it->next) {
		belle_sip_body_handler_t *bh = BELLE_SIP_BODY_HANDLER(it->data);
		belle_sip_body_handler_begin_recv_transfer(bh);
	}
	obj_multipart->transfer_current_part = obj_multipart->parts;
}

static void belle_sip_multipart_body_handler_begin_send_transfer(belle_sip_body_handler_t *obj) {
jehan's avatar
jehan committed
712
	const belle_sip_list_t *it;
713
	belle_sip_multipart_body_handler_t *obj_multipart = (belle_sip_multipart_body_handler_t *)obj;
jehan's avatar
jehan committed
714
	for (it = obj_multipart->parts; it != NULL; it = it->next) {
715
		belle_sip_body_handler_t *bh = BELLE_SIP_BODY_HANDLER(it->data);
716
		belle_sip_body_handler_begin_send_transfer(bh);
717 718 719 720 721
	}
	obj_multipart->transfer_current_part = obj_multipart->parts;
}

static void belle_sip_multipart_body_handler_end_transfer(belle_sip_body_handler_t *obj) {
jehan's avatar
jehan committed
722
	const belle_sip_list_t *it;
723
	belle_sip_multipart_body_handler_t *obj_multipart = (belle_sip_multipart_body_handler_t *)obj;
jehan's avatar
jehan committed
724
	for (it = obj_multipart->parts; it != NULL; it = it->next) {
725 726 727 728 729 730
		belle_sip_body_handler_t *bh = BELLE_SIP_BODY_HANDLER(it->data);
		belle_sip_body_handler_end_transfer(bh);
	}
	obj_multipart->transfer_current_part = NULL;
}

731
static void belle_sip_multipart_body_handler_recv_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, off_t offset,
732
							uint8_t *buffer, size_t size){
733 734 735 736 737
	/* Store the whole buffer, the parts will be split when belle_sip_multipart_body_handler_progress_cb() is called with transfered size equal to expected size. */
	belle_sip_multipart_body_handler_t *obj_multipart = (belle_sip_multipart_body_handler_t *)obj;
	obj_multipart->buffer = belle_sip_realloc(obj_multipart->buffer,offset + size + 1);
	memcpy(obj_multipart->buffer + offset, buffer, size);
	obj_multipart->buffer[offset + size] = '\0';
738 739
}

740
static int belle_sip_multipart_body_handler_send_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, off_t offset,
741
														 uint8_t *buffer, size_t *size){
742
	belle_sip_multipart_body_handler_t *obj_multipart=(belle_sip_multipart_body_handler_t*)obj;
743

744
	if (obj_multipart->transfer_current_part->data) { /* we have a part, get its content from handler */
745
		int retval = BELLE_SIP_STOP;
746
		size_t offsetSize = 0; /* used to store size of data added by this function and not given by the body handler of current part */
747
		size_t boundary_len = strlen(obj_multipart->boundary);
748
		belle_sip_body_handler_t *current_part = (belle_sip_body_handler_t *)obj_multipart->transfer_current_part->data;
749
		*size -= strlen(obj_multipart->boundary) + 8; /* just in case it will be the end of the message, ask for less characters than possible in order to be able to add the multipart message termination. 8 is for "\r\n--" and "--\r\n" */
750

751
		if (current_part->transfered_size == 0) { /* Nothing transfered yet on this part, include a separator and the header if exists */
752
			size_t headersSize = 0;
753 754 755 756
			if (current_part != (belle_sip_body_handler_t *)obj_multipart->parts->data) {
				offsetSize += 2; /*delimiter := CRLF dash-boundary*/
			}
			offsetSize += boundary_len + 4;  /* 4 is for "--" and "\r\n" */
757

758 759 760
			if (current_part->headerStringBuffer != NULL) {
				headersSize = strlen(current_part->headerStringBuffer);
			}
761

762 763 764
			/* check if buffer is large enough to get the whole header + separtor and at least a byte of data */
			if (*size < headersSize+offsetSize+1) {
				return BELLE_SIP_BUFFER_OVERFLOW;
765
			}
766

767
			/* insert separator */
768 769 770 771 772
			if (current_part != (belle_sip_body_handler_t *)obj_multipart->parts->data) {
				snprintf((char*)buffer, *size, "\r\n--%s\r\n",obj_multipart->boundary); /*delimiter := CRLF dash-boundary*/
			} else {
				snprintf((char*)buffer, *size, "--%s\r\n",obj_multipart->boundary);
			}
773

774 775 776 777 778
			/* insert part header */
			if (headersSize!=0) {
				memcpy(buffer+offsetSize, current_part->headerStringBuffer, headersSize);
				offsetSize += headersSize;
			}
779

780
			*size -=offsetSize; /* decrease data length requested to the current part handler */
781
		}
782

783
		retval = belle_sip_body_handler_send_chunk(current_part, msg, buffer+offsetSize, size); /* add offsetSize to the buffer address in order to point at the begining of free space (after header if included) */
784
		*size +=offsetSize; /* restore total of data given including potential separator and header */
785 786


787 788 789
		if (retval == BELLE_SIP_CONTINUE) {
			return BELLE_SIP_CONTINUE; /* there is still data to be sent, continue */
		} else { /* this part has reach the end, pass to next one if there is one */
790 791
			if (obj_multipart->transfer_current_part->next!=NULL) { /* there is an other part to be sent */
				obj_multipart->transfer_current_part = belle_sip_list_next(obj_multipart->transfer_current_part);
792 793
				return BELLE_SIP_CONTINUE;
			} else { /* there is nothing else, close the message and return STOP */
794 795 796 797 798
				size_t boundary_len = strlen(obj_multipart->boundary);
				memcpy(buffer + *size, "\r\n--", 4);
				memcpy(buffer + *size + 4, obj_multipart->boundary, boundary_len);
				memcpy(buffer + *size + 4 + boundary_len, "--\r\n", 4);
				*size+=boundary_len + 8;
799 800 801 802
				return BELLE_SIP_STOP;
			}
		}
	}
803 804 805
	return BELLE_SIP_STOP;
}

806 807 808 809 810 811
/* FIXME: Temporary workaround for -Wcast-function-type. */
#if __GNUC__ >= 8
	_Pragma("GCC diagnostic push")
	_Pragma("GCC diagnostic ignored \"-Wcast-function-type\"")
#endif // if __GNUC__ >= 8

812 813 814 815 816 817 818
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_multipart_body_handler_t);
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_multipart_body_handler_t)
	{
		{
			BELLE_SIP_VPTR_INIT(belle_sip_multipart_body_handler_t,belle_sip_body_handler_t,TRUE),
			(belle_sip_object_destroy_t) belle_sip_multipart_body_handler_destroy,
			(belle_sip_object_clone_t)belle_sip_multipart_body_handler_clone,
819 820
			NULL,
			BELLE_SIP_DEFAULT_BUFSIZE_HINT
821
		},
822 823
		belle_sip_multipart_body_handler_begin_recv_transfer,
		belle_sip_multipart_body_handler_begin_send_transfer,
824
		belle_sip_multipart_body_handler_end_transfer,
825 826 827 828 829
		belle_sip_multipart_body_handler_recv_chunk,
		belle_sip_multipart_body_handler_send_chunk
	}
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END

830 831 832 833
#if __GNUC__ >= 8
	_Pragma("GCC diagnostic pop")
#endif // if __GNUC__ >= 8

834 835 836 837
static void belle_sip_multipart_body_handler_set_boundary(belle_sip_multipart_body_handler_t *obj, const char *boundary) {
	if (obj->boundary != NULL) {
		belle_sip_free(obj->boundary);
	}
838 839 840 841 842
	if (boundary != NULL) {
		obj->boundary = belle_sip_strdup(boundary);
	} else {
		obj->boundary = belle_sip_strdup(BELLESIP_MULTIPART_BOUNDARY);
	}
843 844
}

845 846 847 848
const char *belle_sip_multipart_body_handler_get_boundary(const belle_sip_multipart_body_handler_t *obj) {
	return obj->boundary;
}

849 850 851 852 853
belle_sip_multipart_body_handler_t *belle_sip_multipart_body_handler_new(belle_sip_body_handler_progress_callback_t progress_cb, void *data,
									 belle_sip_body_handler_t *first_part, const char *boundary){
	belle_sip_multipart_body_handler_t *obj=belle_sip_object_new(belle_sip_multipart_body_handler_t);
	belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,progress_cb,data);
	belle_sip_multipart_body_handler_set_boundary(obj, boundary);
854
	obj->base.expected_size = strlen(obj->boundary) + 8; /* body's length will be part length(including boundary) + multipart end. 8 is for "\r\n--" and "--\r\n" */
855 856 857 858
	if (first_part) belle_sip_multipart_body_handler_add_part(obj,first_part);
	return obj;
}

859
belle_sip_multipart_body_handler_t *belle_sip_multipart_body_handler_new_from_buffer(const void *buffer, size_t bufsize, const char *boundary) {
860 861 862 863 864
	belle_sip_multipart_body_handler_t *obj_multipart = belle_sip_object_new(belle_sip_multipart_body_handler_t);
	belle_sip_body_handler_t *obj = (belle_sip_body_handler_t *)obj_multipart;
	belle_sip_body_handler_init((belle_sip_body_handler_t *)obj, belle_sip_multipart_body_handler_progress_cb, NULL);
	belle_sip_multipart_body_handler_set_boundary(obj_multipart, boundary);
	obj_multipart->base.expected_size = bufsize;
865
	belle_sip_body_handler_begin_recv_transfer(obj);
866 867 868 869 870
	belle_sip_body_handler_recv_chunk(obj, NULL, (uint8_t *)buffer, bufsize);
	belle_sip_body_handler_end_transfer(obj);
	return obj_multipart;
}

871
#define DEFAULT_HEADER_STRING_SIZE 512
872
void belle_sip_multipart_body_handler_add_part(belle_sip_multipart_body_handler_t *obj, belle_sip_body_handler_t *part){
873 874 875 876
	if (obj->parts != NULL) {
		obj->base.expected_size += 2; /*delimiter := CRLF dash-boundary*/
		//add initial CRLF*/
	}
877
	obj->base.expected_size+=part->expected_size+strlen(obj->boundary) + 4; /* add the separator length to the body length as each part start with a separator. 4 is for "--" and "\r\n" */
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
	if (part->headers != NULL) { /* there is a declared header for this part, add its length to the expected total length */
		size_t headerStringBufferSize = DEFAULT_HEADER_STRING_SIZE;
		size_t offset = 0;
		belle_sip_list_t *headerList = part->headers;
		part->headerStringBuffer = (char *)belle_sip_malloc(DEFAULT_HEADER_STRING_SIZE);

		while (headerList != NULL) {
			size_t offsetBackup=offset; /* we must backup the offset as it will be messed up by the marshal function in case of failure */
			belle_sip_error_code returnCode = belle_sip_object_marshal(headerList->data, part->headerStringBuffer, headerStringBufferSize-5, &offset); /* -5 to leave room for carriage returns */
			if (returnCode == BELLE_SIP_BUFFER_OVERFLOW) { /* increase buffer size */
				offset=offsetBackup; /* restore the offset, no data were written to the buffer */
				headerStringBufferSize+=DEFAULT_HEADER_STRING_SIZE;
				part->headerStringBuffer = (char *)belle_sip_realloc(part->headerStringBuffer, headerStringBufferSize);
			} else if (returnCode == BELLE_SIP_OK) { /* add the carriage return chars */
				part->headerStringBuffer[offset++]='\r';
				part->headerStringBuffer[offset++]='\n';
				headerList = belle_sip_list_next(headerList);
			}
		}
		part->headerStringBuffer[offset++]='\r';
		part->headerStringBuffer[offset++]='\n';
		obj->base.expected_size += offset;
		part->headerStringBuffer[offset++]='\0'; /* null terminate the buffer in order to be able to get it length later using strlen */
901
	}
902 903
	obj->parts=belle_sip_list_append(obj->parts,belle_sip_object_ref(part));
}
904 905 906
const belle_sip_list_t* belle_sip_multipart_body_handler_get_parts(const belle_sip_multipart_body_handler_t *obj) {
	return obj->parts;
}
907

908 909 910 911 912 913 914 915 916 917 918 919
void belle_sip_multipart_body_handler_progress_cb(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, void *user_data, size_t transfered, size_t expected_total) {
	if (transfered == expected_total) {
		/* The full multipart body has been received, we can now parse it and split the different parts,
		 * creating a belle_sip_memory_body_handler for each part and adding them to the belle_sip_multipart_body_handler
		 * parts list. */
		belle_sip_multipart_body_handler_t *obj_multipart = (belle_sip_multipart_body_handler_t *)obj;
		belle_sip_memory_body_handler_t *memorypart;
		belle_sip_header_t *header;
		uint8_t *end_part_cursor;
		uint8_t *end_headers_cursor;
		uint8_t *end_header_cursor;
		uint8_t *cursor = obj_multipart->buffer;
920 921
		char *dash_boundary = belle_sip_strdup_printf("--%s", obj_multipart->boundary);
		if (strncmp((char *)cursor, dash_boundary, strlen(dash_boundary))) {
922
			belle_sip_warning("belle_sip_multipart_body_handler [%p]: body not starting by specified boundary '%s'", obj_multipart, obj_multipart->boundary);
923
			belle_sip_free(dash_boundary);
924 925
			return;
		}
926
		cursor += strlen(dash_boundary);
927
		do {
928
			bool_t delimiter_contains_crlf = FALSE;
929 930
			if (strncmp((char *)cursor, "\r\n", 2)) {
				belle_sip_warning("belle_sip_multipart_body_handler [%p]: no new-line after boundary", obj_multipart);
931
				belle_sip_free(dash_boundary);
932 933 934
				return;
			}
			cursor += 2;
935
			end_part_cursor = (uint8_t *)strstr((char *)cursor, dash_boundary);
936 937
			if (end_part_cursor == NULL) {
				belle_sip_warning("belle_sip_multipart_body_handler [%p]: cannot find next boundary", obj_multipart);
938
				belle_sip_free(dash_boundary);
939 940
				return;
			} else {
941 942 943 944
				if (*(end_part_cursor-1) == '\n' && *(end_part_cursor-2) == '\r') {
					end_part_cursor-=2; /* delimiter is well formed: delimiter := CRLF dash-boundary */
					delimiter_contains_crlf = TRUE;
				}
945 946 947
				*end_part_cursor = 0;
				end_headers_cursor = (uint8_t *)strstr((char *)cursor, "\r\n\r\n");
				if (end_headers_cursor == NULL) {
948
					memorypart = belle_sip_memory_body_handler_new_copy_from_buffer(cursor, strlen((char *)cursor), NULL, NULL);
949 950
				} else {
					uint8_t *begin_body_cursor = end_headers_cursor + 4;
951
					memorypart = belle_sip_memory_body_handler_new_copy_from_buffer(begin_body_cursor, strlen((char *)begin_body_cursor), NULL, NULL);
952 953 954 955 956 957 958 959 960 961 962
					do {
						end_header_cursor = (uint8_t *)strstr((char *)cursor, "\r\n");
						*end_header_cursor = 0;
						header = belle_sip_header_parse((char *)cursor);
						if (header != NULL) {
							belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(memorypart), header);
						}
						cursor = end_header_cursor + 2;
					} while (end_header_cursor != end_headers_cursor);
				}
				belle_sip_multipart_body_handler_add_part(obj_multipart, BELLE_SIP_BODY_HANDLER(memorypart));
963 964 965
				cursor = end_part_cursor + strlen(dash_boundary);
				if (delimiter_contains_crlf)
					cursor += 2;
966 967
			}
		} while (strcmp((char *)cursor, "--\r\n"));
968
		belle_sip_free(dash_boundary);
969 970
	}
}