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