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