• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-message-body.c: SoupMessage request/response bodies
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include <string.h>
13 
14 #include "soup-message-body.h"
15 #include "soup.h"
16 
17 /**
18  * SECTION:soup-message-body
19  * @short_description: HTTP message body
20  * @see_also: #SoupMessage
21  *
22  * #SoupMessageBody represents the request or response body of a
23  * #SoupMessage.
24  *
25  * In addition to #SoupMessageBody, libsoup also defines a "smaller"
26  * data buffer type, #SoupBuffer, which is primarily used as a
27  * component of #SoupMessageBody. In particular, when using chunked
28  * encoding to transmit or receive a message, each chunk is
29  * represented as a #SoupBuffer.
30  **/
31 
32 /**
33  * SoupMemoryUse:
34  * @SOUP_MEMORY_STATIC: The memory is statically allocated and
35  * constant; libsoup can use the passed-in buffer directly and not
36  * need to worry about it being modified or freed.
37  * @SOUP_MEMORY_TAKE: The caller has allocated the memory for the
38  * #SoupBuffer's use; libsoup will assume ownership of it and free it
39  * (with g_free()) when it is done with it.
40  * @SOUP_MEMORY_COPY: The passed-in data belongs to the caller; the
41  * #SoupBuffer will copy it into new memory, leaving the caller free
42  * to reuse the original memory.
43  * @SOUP_MEMORY_TEMPORARY: The passed-in data belongs to the caller,
44  * but will remain valid for the lifetime of the #SoupBuffer. The
45  * difference between this and @SOUP_MEMORY_STATIC is that if you copy
46  * a @SOUP_MEMORY_TEMPORARY buffer, it will make a copy of the memory
47  * as well, rather than reusing the original memory.
48  *
49  * Describes how #SoupBuffer should use the data passed in by the
50  * caller.
51  *
52  * See also soup_buffer_new_with_owner(), which allows to you create a
53  * buffer containing data which is owned by another object.
54  **/
55 
56 /* Internal SoupMemoryUse values */
57 enum {
58 	SOUP_MEMORY_SUBBUFFER = SOUP_MEMORY_TEMPORARY + 1,
59 	SOUP_MEMORY_OWNED
60 };
61 
62 /**
63  * SoupBuffer:
64  * @data: (type gpointer): the data
65  * @length: length of @data
66  *
67  * A data buffer, generally used to represent a chunk of a
68  * #SoupMessageBody.
69  *
70  * @data is a #char because that's generally convenient; in some
71  * situations you may need to cast it to #guchar or another type.
72  **/
73 
74 typedef struct {
75 	SoupBuffer     buffer;
76 	SoupMemoryUse  use;
77 	guint          refcount;
78 
79 	gpointer       owner;
80 	GDestroyNotify owner_dnotify;
81 } SoupBufferPrivate;
82 
83 /**
84  * soup_buffer_new:
85  * @use: how @data is to be used by the buffer
86  * @data: (array length=length) (element-type guint8): data
87  * @length: length of @data
88  *
89  * Creates a new #SoupBuffer containing @length bytes from @data.
90  *
91  * Return value: the new #SoupBuffer.
92  **/
93 SoupBuffer *
soup_buffer_new(SoupMemoryUse use,gconstpointer data,gsize length)94 soup_buffer_new (SoupMemoryUse use, gconstpointer data, gsize length)
95 {
96 	SoupBufferPrivate *priv = g_slice_new0 (SoupBufferPrivate);
97 
98 	if (use == SOUP_MEMORY_COPY) {
99 		data = g_memdup (data, length);
100 		use = SOUP_MEMORY_TAKE;
101 	}
102 
103 	priv->buffer.data = data;
104 	priv->buffer.length = length;
105 	priv->use = use;
106 	priv->refcount = 1;
107 
108 	if (use == SOUP_MEMORY_TAKE) {
109 		priv->owner = (gpointer)data;
110 		priv->owner_dnotify = g_free;
111 	}
112 
113 	return (SoupBuffer *)priv;
114 }
115 
116 /**
117  * soup_buffer_new_take: (rename-to soup_buffer_new)
118  * @data: (array length=length) (transfer full): data
119  * @length: length of @data
120  *
121  * Creates a new #SoupBuffer containing @length bytes from @data.
122  *
123  * This function is exactly equivalent to soup_buffer_new() with
124  * %SOUP_MEMORY_TAKE as first argument; it exists mainly for
125  * convenience and simplifying language bindings.
126  *
127  * Return value: the new #SoupBuffer.
128  *
129  * Since: 2.32
130  **/
131 SoupBuffer *
soup_buffer_new_take(guchar * data,gsize length)132 soup_buffer_new_take (guchar *data, gsize length)
133 {
134 	return soup_buffer_new (SOUP_MEMORY_TAKE, data, length);
135 }
136 
137 /**
138  * soup_buffer_new_subbuffer:
139  * @parent: the parent #SoupBuffer
140  * @offset: offset within @parent to start at
141  * @length: number of bytes to copy from @parent
142  *
143  * Creates a new #SoupBuffer containing @length bytes "copied" from
144  * @parent starting at @offset. (Normally this will not actually copy
145  * any data, but will instead simply reference the same data as
146  * @parent does.)
147  *
148  * Return value: the new #SoupBuffer.
149  **/
150 SoupBuffer *
soup_buffer_new_subbuffer(SoupBuffer * parent,gsize offset,gsize length)151 soup_buffer_new_subbuffer (SoupBuffer *parent, gsize offset, gsize length)
152 {
153 	SoupBufferPrivate *priv;
154 
155 	/* Normally this is just a ref, but if @parent is TEMPORARY,
156 	 * it will do an actual copy.
157 	 */
158 	parent = soup_buffer_copy (parent);
159 
160 	priv = g_slice_new0 (SoupBufferPrivate);
161 	priv->buffer.data = parent->data + offset;
162 	priv->buffer.length = length;
163 	priv->use = SOUP_MEMORY_SUBBUFFER;
164 	priv->owner = parent;
165 	priv->owner_dnotify = (GDestroyNotify)soup_buffer_free;
166 	priv->refcount = 1;
167 
168 	return (SoupBuffer *)priv;
169 }
170 
171 /**
172  * soup_buffer_new_with_owner:
173  * @data: (array length=length) (element-type guint8): data
174  * @length: length of @data
175  * @owner: pointer to an object that owns @data
176  * @owner_dnotify: (allow-none): a function to free/unref @owner when
177  * the buffer is freed
178  *
179  * Creates a new #SoupBuffer containing @length bytes from @data. When
180  * the #SoupBuffer is freed, it will call @owner_dnotify, passing
181  * @owner to it. You must ensure that @data will remain valid until
182  * @owner_dnotify is called.
183  *
184  * For example, you could use this to create a buffer containing data
185  * returned from libxml without needing to do an extra copy:
186  *
187  * <informalexample><programlisting>
188  *	xmlDocDumpMemory (doc, &xmlbody, &len);
189  *	return soup_buffer_new_with_owner (xmlbody, len, xmlbody,
190  *	                                   (GDestroyNotify)xmlFree);
191  * </programlisting></informalexample>
192  *
193  * In this example, @data and @owner are the same, but in other cases
194  * they would be different (eg, @owner would be a object, and @data
195  * would be a pointer to one of the object's fields).
196  *
197  * Return value: the new #SoupBuffer.
198  **/
199 SoupBuffer *
soup_buffer_new_with_owner(gconstpointer data,gsize length,gpointer owner,GDestroyNotify owner_dnotify)200 soup_buffer_new_with_owner (gconstpointer  data, gsize length,
201 			    gpointer owner, GDestroyNotify owner_dnotify)
202 {
203 	SoupBufferPrivate *priv = g_slice_new0 (SoupBufferPrivate);
204 
205 	priv->buffer.data = data;
206 	priv->buffer.length = length;
207 	priv->use = SOUP_MEMORY_OWNED;
208 	priv->owner = owner;
209 	priv->owner_dnotify = owner_dnotify;
210 	priv->refcount = 1;
211 
212 	return (SoupBuffer *)priv;
213 }
214 
215 /**
216  * soup_buffer_get_owner:
217  * @buffer: a #SoupBuffer created with soup_buffer_new_with_owner()
218  *
219  * Gets the "owner" object for a buffer created with
220  * soup_buffer_new_with_owner().
221  *
222  * Return value: (transfer none): the owner pointer
223  **/
224 gpointer
soup_buffer_get_owner(SoupBuffer * buffer)225 soup_buffer_get_owner (SoupBuffer *buffer)
226 {
227 	SoupBufferPrivate *priv = (SoupBufferPrivate *)buffer;
228 
229 	g_return_val_if_fail ((int)priv->use == (int)SOUP_MEMORY_OWNED, NULL);
230 	return priv->owner;
231 }
232 
233 /**
234  * soup_buffer_get_data:
235  * @buffer: a #SoupBuffer
236  * @data: (out) (array length=length) (transfer none): the pointer
237  * to the buffer data is stored here
238  * @length: (out): the length of the buffer data is stored here
239  *
240  * This function exists for use by language bindings, because it's not
241  * currently possible to get the right effect by annotating the fields
242  * of #SoupBuffer.
243  *
244  * Since: 2.32
245  */
246 void
soup_buffer_get_data(SoupBuffer * buffer,const guint8 ** data,gsize * length)247 soup_buffer_get_data (SoupBuffer     *buffer,
248 		      const guint8  **data,
249 		      gsize          *length)
250 {
251 	*data = (const guint8 *)buffer->data;
252 	*length = buffer->length;
253 }
254 
255 /**
256  * soup_buffer_copy:
257  * @buffer: a #SoupBuffer
258  *
259  * Makes a copy of @buffer. In reality, #SoupBuffer is a refcounted
260  * type, and calling soup_buffer_copy() will normally just increment
261  * the refcount on @buffer and return it. However, if @buffer was
262  * created with #SOUP_MEMORY_TEMPORARY memory, then soup_buffer_copy()
263  * will actually return a copy of it, so that the data in the copy
264  * will remain valid after the temporary buffer is freed.
265  *
266  * Return value: the new (or newly-reffed) buffer
267  **/
268 SoupBuffer *
soup_buffer_copy(SoupBuffer * buffer)269 soup_buffer_copy (SoupBuffer *buffer)
270 {
271 	SoupBufferPrivate *priv = (SoupBufferPrivate *)buffer;
272 
273 	/* For non-TEMPORARY buffers, this is just a ref */
274 	if (priv->use != SOUP_MEMORY_TEMPORARY) {
275 		g_atomic_int_inc (&priv->refcount);
276 		return buffer;
277 	}
278 
279 	/* For TEMPORARY buffers, we need to do a real copy the first
280 	 * time, and then after that, we just keep returning the copy.
281 	 * We store the copy in priv->owner, which is technically
282 	 * backwards, but it saves us from having to keep an extra
283 	 * pointer in SoupBufferPrivate.
284 	 */
285 
286 	if (!priv->owner) {
287 		priv->owner = soup_buffer_new (SOUP_MEMORY_COPY,
288 					       buffer->data,
289 					       buffer->length);
290 		priv->owner_dnotify = (GDestroyNotify)soup_buffer_free;
291 	}
292 	return soup_buffer_copy (priv->owner);
293 }
294 
295 /**
296  * soup_buffer_free:
297  * @buffer: a #SoupBuffer
298  *
299  * Frees @buffer. (In reality, as described in the documentation for
300  * soup_buffer_copy(), this is actually an "unref" operation, and may
301  * or may not actually free @buffer.)
302  **/
303 void
soup_buffer_free(SoupBuffer * buffer)304 soup_buffer_free (SoupBuffer *buffer)
305 {
306 	SoupBufferPrivate *priv = (SoupBufferPrivate *)buffer;
307 
308 	if (!g_atomic_int_dec_and_test (&priv->refcount))
309 		return;
310 
311 	if (priv->owner_dnotify)
312 		priv->owner_dnotify (priv->owner);
313 	g_slice_free (SoupBufferPrivate, priv);
314 }
315 
316 /**
317  * soup_buffer_get_as_bytes:
318  * @buffer: a #SoupBuffer
319  *
320  * Creates a #GBytes pointing to the same memory as @buffer. The
321  * #GBytes will hold a reference on @buffer to ensure that it is not
322  * freed while the #GBytes is still valid.
323  *
324  * Returns: (transfer full): a new #GBytes which has the same content
325  * as the #SoupBuffer.
326  *
327  * Since: 2.40
328  */
329 GBytes *
soup_buffer_get_as_bytes(SoupBuffer * buffer)330 soup_buffer_get_as_bytes (SoupBuffer *buffer)
331 {
332 	SoupBuffer *copy;
333 
334 	copy = soup_buffer_copy (buffer);
335 	return g_bytes_new_with_free_func (copy->data, copy->length,
336 					   (GDestroyNotify)soup_buffer_free,
337 					   copy);
338 }
339 
340 G_DEFINE_BOXED_TYPE (SoupBuffer, soup_buffer, soup_buffer_copy, soup_buffer_free)
341 
342 
343 /**
344  * SoupMessageBody:
345  * @data: the data
346  * @length: length of @data
347  *
348  * A #SoupMessage request or response body.
349  *
350  * Note that while @length always reflects the full length of the
351  * message body, @data is normally %NULL, and will only be filled in
352  * after soup_message_body_flatten() is called. For client-side
353  * messages, this automatically happens for the response body after it
354  * has been fully read, unless you set the
355  * %SOUP_MESSAGE_OVERWRITE_CHUNKS flags. Likewise, for server-side
356  * messages, the request body is automatically filled in after being
357  * read.
358  *
359  * As an added bonus, when @data is filled in, it is always terminated
360  * with a '\0' byte (which is not reflected in @length).
361  **/
362 
363 typedef struct {
364 	SoupMessageBody body;
365 	GSList *chunks, *last;
366 	SoupBuffer *flattened;
367 	gboolean accumulate;
368 	goffset base_offset;
369 	int ref_count;
370 } SoupMessageBodyPrivate;
371 
372 /**
373  * soup_message_body_new:
374  *
375  * Creates a new #SoupMessageBody. #SoupMessage uses this internally; you
376  * will not normally need to call it yourself.
377  *
378  * Return value: a new #SoupMessageBody.
379  **/
380 SoupMessageBody *
soup_message_body_new(void)381 soup_message_body_new (void)
382 {
383 	SoupMessageBodyPrivate *priv;
384 
385 	priv = g_slice_new0 (SoupMessageBodyPrivate);
386 	priv->accumulate = TRUE;
387 	priv->ref_count = 1;
388 
389 	return (SoupMessageBody *)priv;
390 }
391 
392 /**
393  * soup_message_body_set_accumulate:
394  * @body: a #SoupMessageBody
395  * @accumulate: whether or not to accumulate body chunks in @body
396  *
397  * Sets or clears the accumulate flag on @body. (The default value is
398  * %TRUE.) If set to %FALSE, @body's %data field will not be filled in
399  * after the body is fully sent/received, and the chunks that make up
400  * @body may be discarded when they are no longer needed.
401  *
402  * In particular, if you set this flag to %FALSE on an "incoming"
403  * message body (that is, the #SoupMessage:response_body of a
404  * client-side message, or #SoupMessage:request_body of a server-side
405  * message), this will cause each chunk of the body to be discarded
406  * after its corresponding #SoupMessage::got_chunk signal is emitted.
407  * (This is equivalent to setting the deprecated
408  * %SOUP_MESSAGE_OVERWRITE_CHUNKS flag on the message.)
409  *
410  * If you set this flag to %FALSE on the #SoupMessage:response_body of
411  * a server-side message, it will cause each chunk of the body to be
412  * discarded after its corresponding #SoupMessage::wrote_chunk signal
413  * is emitted.
414  *
415  * If you set the flag to %FALSE on the #SoupMessage:request_body of a
416  * client-side message, it will block the accumulation of chunks into
417  * @body's %data field, but it will not normally cause the chunks to
418  * be discarded after being written like in the server-side
419  * #SoupMessage:response_body case, because the request body needs to
420  * be kept around in case the request needs to be sent a second time
421  * due to redirection or authentication. However, if you set the
422  * %SOUP_MESSAGE_CAN_REBUILD flag on the message, then the chunks will
423  * be discarded, and you will be responsible for recreating the
424  * request body after the #SoupMessage::restarted signal is emitted.
425  *
426  * Since: 2.24
427  **/
428 void
soup_message_body_set_accumulate(SoupMessageBody * body,gboolean accumulate)429 soup_message_body_set_accumulate (SoupMessageBody *body,
430 				  gboolean         accumulate)
431 {
432 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
433 
434 	priv->accumulate = accumulate;
435 }
436 
437 /**
438  * soup_message_body_get_accumulate:
439  * @body: a #SoupMessageBody
440  *
441  * Gets the accumulate flag on @body; see
442  * soup_message_body_set_accumulate() for details.
443  *
444  * Return value: the accumulate flag for @body.
445  *
446  * Since: 2.24
447  **/
448 gboolean
soup_message_body_get_accumulate(SoupMessageBody * body)449 soup_message_body_get_accumulate (SoupMessageBody *body)
450 {
451 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
452 
453 	return priv->accumulate;
454 }
455 
456 static void
append_buffer(SoupMessageBody * body,SoupBuffer * buffer)457 append_buffer (SoupMessageBody *body, SoupBuffer *buffer)
458 {
459 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
460 
461 	if (priv->last) {
462 		priv->last = g_slist_append (priv->last, buffer);
463 		priv->last = priv->last->next;
464 	} else
465 		priv->chunks = priv->last = g_slist_append (NULL, buffer);
466 
467 	if (priv->flattened) {
468 		soup_buffer_free (priv->flattened);
469 		priv->flattened = NULL;
470 		body->data = NULL;
471 	}
472 	body->length += buffer->length;
473 }
474 
475 /**
476  * soup_message_body_append:
477  * @body: a #SoupMessageBody
478  * @use: how to use @data
479  * @data: (array length=length) (element-type guint8): data to append
480  * @length: length of @data
481  *
482  * Appends @length bytes from @data to @body according to @use.
483  **/
484 void
soup_message_body_append(SoupMessageBody * body,SoupMemoryUse use,gconstpointer data,gsize length)485 soup_message_body_append (SoupMessageBody *body, SoupMemoryUse use,
486 			  gconstpointer data, gsize length)
487 {
488 	if (length > 0)
489 		append_buffer (body, soup_buffer_new (use, data, length));
490 	else if (use == SOUP_MEMORY_TAKE)
491 		g_free ((gpointer)data);
492 }
493 
494 /**
495  * soup_message_body_append_take: (rename-to soup_message_body_append)
496  * @body: a #SoupMessageBody
497  * @data: (array length=length) (transfer full): data to append
498  * @length: length of @data
499  *
500  * Appends @length bytes from @data to @body.
501  *
502  * This function is exactly equivalent to soup_message_body_append()
503  * with %SOUP_MEMORY_TAKE as second argument; it exists mainly for
504  * convenience and simplifying language bindings.
505  *
506  * Since: 2.32
507  **/
508 void
soup_message_body_append_take(SoupMessageBody * body,guchar * data,gsize length)509 soup_message_body_append_take (SoupMessageBody *body,
510 			       guchar *data, gsize length)
511 {
512 	soup_message_body_append(body, SOUP_MEMORY_TAKE, data, length);
513 }
514 
515 /**
516  * soup_message_body_append_buffer:
517  * @body: a #SoupMessageBody
518  * @buffer: a #SoupBuffer
519  *
520  * Appends the data from @buffer to @body. (#SoupMessageBody uses
521  * #SoupBuffers internally, so this is normally a constant-time
522  * operation that doesn't actually require copying the data in
523  * @buffer.)
524  **/
525 void
soup_message_body_append_buffer(SoupMessageBody * body,SoupBuffer * buffer)526 soup_message_body_append_buffer (SoupMessageBody *body, SoupBuffer *buffer)
527 {
528 	g_return_if_fail (buffer->length > 0);
529 	append_buffer (body, soup_buffer_copy (buffer));
530 }
531 
532 /**
533  * soup_message_body_truncate:
534  * @body: a #SoupMessageBody
535  *
536  * Deletes all of the data in @body.
537  **/
538 void
soup_message_body_truncate(SoupMessageBody * body)539 soup_message_body_truncate (SoupMessageBody *body)
540 {
541 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
542 
543 	g_slist_free_full (priv->chunks, (GDestroyNotify)soup_buffer_free);
544 	priv->chunks = priv->last = NULL;
545 	priv->base_offset = 0;
546 
547 	if (priv->flattened) {
548 		soup_buffer_free (priv->flattened);
549 		priv->flattened = NULL;
550 		body->data = NULL;
551 	}
552 	body->length = 0;
553 }
554 
555 /**
556  * soup_message_body_complete:
557  * @body: a #SoupMessageBody
558  *
559  * Tags @body as being complete; Call this when using chunked encoding
560  * after you have appended the last chunk.
561  **/
562 void
soup_message_body_complete(SoupMessageBody * body)563 soup_message_body_complete (SoupMessageBody *body)
564 {
565 	append_buffer (body, soup_buffer_new (SOUP_MEMORY_STATIC, NULL, 0));
566 }
567 
568 /**
569  * soup_message_body_flatten:
570  * @body: a #SoupMessageBody
571  *
572  * Fills in @body's data field with a buffer containing all of the
573  * data in @body (plus an additional '\0' byte not counted by @body's
574  * length field).
575  *
576  * Return value: a #SoupBuffer containing the same data as @body.
577  * (You must free this buffer if you do not want it.)
578  **/
579 SoupBuffer *
soup_message_body_flatten(SoupMessageBody * body)580 soup_message_body_flatten (SoupMessageBody *body)
581 {
582 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
583 	char *buf, *ptr;
584 	GSList *iter;
585 	SoupBuffer *chunk;
586 
587 	g_return_val_if_fail (priv->accumulate == TRUE, NULL);
588 
589 	if (!priv->flattened) {
590 #if GLIB_SIZEOF_SIZE_T < 8
591 		g_return_val_if_fail (body->length < G_MAXSIZE, NULL);
592 #endif
593 
594 		buf = ptr = g_malloc (body->length + 1);
595 		for (iter = priv->chunks; iter; iter = iter->next) {
596 			chunk = iter->data;
597 			memcpy (ptr, chunk->data, chunk->length);
598 			ptr += chunk->length;
599 		}
600 		*ptr = '\0';
601 
602 		priv->flattened = soup_buffer_new (SOUP_MEMORY_TAKE,
603 						   buf, body->length);
604 		body->data = priv->flattened->data;
605 	}
606 
607 	return soup_buffer_copy (priv->flattened);
608 }
609 
610 /**
611  * soup_message_body_get_chunk:
612  * @body: a #SoupMessageBody
613  * @offset: an offset
614  *
615  * Gets a #SoupBuffer containing data from @body starting at @offset.
616  * The size of the returned chunk is unspecified. You can iterate
617  * through the entire body by first calling
618  * soup_message_body_get_chunk() with an offset of 0, and then on each
619  * successive call, increment the offset by the length of the
620  * previously-returned chunk.
621  *
622  * If @offset is greater than or equal to the total length of @body,
623  * then the return value depends on whether or not
624  * soup_message_body_complete() has been called or not; if it has,
625  * then soup_message_body_get_chunk() will return a 0-length chunk
626  * (indicating the end of @body). If it has not, then
627  * soup_message_body_get_chunk() will return %NULL (indicating that
628  * @body may still potentially have more data, but that data is not
629  * currently available).
630  *
631  * Return value: (nullable): a #SoupBuffer, or %NULL.
632  **/
633 SoupBuffer *
soup_message_body_get_chunk(SoupMessageBody * body,goffset offset)634 soup_message_body_get_chunk (SoupMessageBody *body, goffset offset)
635 {
636 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
637 	GSList *iter;
638 	SoupBuffer *chunk = NULL;
639 
640 	offset -= priv->base_offset;
641 	for (iter = priv->chunks; iter; iter = iter->next) {
642 		chunk = iter->data;
643 
644 		if (offset < chunk->length || offset == 0)
645 			break;
646 
647 		offset -= chunk->length;
648 	}
649 
650 	if (!iter)
651 		return NULL;
652 
653 	if (offset == 0)
654 		return soup_buffer_copy (chunk);
655 	else {
656 		return soup_buffer_new_subbuffer (chunk, offset,
657 						  chunk->length - offset);
658 	}
659 }
660 
661 /**
662  * soup_message_body_got_chunk:
663  * @body: a #SoupMessageBody
664  * @chunk: a #SoupBuffer received from the network
665  *
666  * Handles the #SoupMessageBody part of receiving a chunk of data from
667  * the network. Normally this means appending @chunk to @body, exactly
668  * as with soup_message_body_append_buffer(), but if you have set
669  * @body's accumulate flag to %FALSE, then that will not happen.
670  *
671  * This is a low-level method which you should not normally need to
672  * use.
673  *
674  * Since: 2.24
675  **/
676 void
soup_message_body_got_chunk(SoupMessageBody * body,SoupBuffer * chunk)677 soup_message_body_got_chunk (SoupMessageBody *body, SoupBuffer *chunk)
678 {
679 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
680 
681 	if (!priv->accumulate)
682 		return;
683 
684 	soup_message_body_append_buffer (body, chunk);
685 }
686 
687 /**
688  * soup_message_body_wrote_chunk:
689  * @body: a #SoupMessageBody
690  * @chunk: a #SoupBuffer returned from soup_message_body_get_chunk()
691  *
692  * Handles the #SoupMessageBody part of writing a chunk of data to the
693  * network. Normally this is a no-op, but if you have set @body's
694  * accumulate flag to %FALSE, then this will cause @chunk to be
695  * discarded to free up memory.
696  *
697  * This is a low-level method which you should not need to use, and
698  * there are further restrictions on its proper use which are not
699  * documented here.
700  *
701  * Since: 2.24
702  **/
703 void
soup_message_body_wrote_chunk(SoupMessageBody * body,SoupBuffer * chunk)704 soup_message_body_wrote_chunk (SoupMessageBody *body, SoupBuffer *chunk)
705 {
706 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
707 	SoupBuffer *chunk2;
708 
709 	if (priv->accumulate)
710 		return;
711 
712 	chunk2 = priv->chunks->data;
713 	g_return_if_fail (chunk->length == chunk2->length);
714 	g_return_if_fail (chunk == chunk2 || ((SoupBufferPrivate *)chunk2)->use == SOUP_MEMORY_TEMPORARY);
715 
716 	priv->chunks = g_slist_remove (priv->chunks, chunk2);
717 	if (!priv->chunks)
718 		priv->last = NULL;
719 
720 	priv->base_offset += chunk2->length;
721 	soup_buffer_free (chunk2);
722 }
723 
724 static SoupMessageBody *
soup_message_body_copy(SoupMessageBody * body)725 soup_message_body_copy (SoupMessageBody *body)
726 {
727 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
728 
729 	g_atomic_int_inc (&priv->ref_count);
730 	return body;
731 }
732 
733 /**
734  * soup_message_body_free:
735  * @body: a #SoupMessageBody
736  *
737  * Frees @body. You will not normally need to use this, as
738  * #SoupMessage frees its associated message bodies automatically.
739  **/
740 void
soup_message_body_free(SoupMessageBody * body)741 soup_message_body_free (SoupMessageBody *body)
742 {
743 	SoupMessageBodyPrivate *priv = (SoupMessageBodyPrivate *)body;
744 
745 	if (!g_atomic_int_dec_and_test (&priv->ref_count))
746 		return;
747 
748 	soup_message_body_truncate (body);
749 	g_slice_free (SoupMessageBodyPrivate, priv);
750 }
751 
752 G_DEFINE_BOXED_TYPE (SoupMessageBody, soup_message_body, soup_message_body_copy, soup_message_body_free)
753