|
Packit Service |
ca3877 |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
Packit Service |
ca3877 |
/*
|
|
Packit Service |
ca3877 |
* soup-filter-input-stream.c
|
|
Packit Service |
ca3877 |
*
|
|
Packit Service |
ca3877 |
* Copyright 2012 Red Hat, Inc.
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
ca3877 |
#include <config.h>
|
|
Packit Service |
ca3877 |
#endif
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#include <string.h>
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
#include "soup-filter-input-stream.h"
|
|
Packit Service |
ca3877 |
#include "soup.h"
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* This is essentially a subset of GDataInputStream, except that we
|
|
Packit Service |
ca3877 |
* can do the equivalent of "fill_nonblocking()" on it. (We could use
|
|
Packit Service |
ca3877 |
* an actual GDataInputStream, and implement the nonblocking semantics
|
|
Packit Service |
ca3877 |
* via fill_async(), but that would be more work...)
|
|
Packit Service |
ca3877 |
*/
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
struct _SoupFilterInputStreamPrivate {
|
|
Packit Service |
ca3877 |
GByteArray *buf;
|
|
Packit Service |
ca3877 |
gboolean need_more;
|
|
Packit Service |
ca3877 |
gboolean in_read_until;
|
|
Packit Service |
ca3877 |
};
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void soup_filter_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface, gpointer interface_data);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
G_DEFINE_TYPE_WITH_CODE (SoupFilterInputStream, soup_filter_input_stream, G_TYPE_FILTER_INPUT_STREAM,
|
|
Packit Service |
ca3877 |
G_ADD_PRIVATE (SoupFilterInputStream)
|
|
Packit Service |
ca3877 |
G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_pollable_init))
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_init (SoupFilterInputStream *stream)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
stream->priv = soup_filter_input_stream_get_instance_private (stream);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_finalize (GObject *object)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (object);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_clear_pointer (&fstream->priv->buf, g_byte_array_unref);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
G_OBJECT_CLASS (soup_filter_input_stream_parent_class)->finalize (object);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static gssize
|
|
Packit Service |
ca3877 |
read_from_buf (SoupFilterInputStream *fstream, gpointer buffer, gsize count)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
GByteArray *buf = fstream->priv->buf;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (buf->len < count)
|
|
Packit Service |
ca3877 |
count = buf->len;
|
|
Packit Service |
ca3877 |
memcpy (buffer, buf->data, count);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (count == buf->len) {
|
|
Packit Service |
ca3877 |
g_byte_array_free (buf, TRUE);
|
|
Packit Service |
ca3877 |
fstream->priv->buf = NULL;
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
memmove (buf->data, buf->data + count,
|
|
Packit Service |
ca3877 |
buf->len - count);
|
|
Packit Service |
ca3877 |
g_byte_array_set_size (buf, buf->len - count);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return count;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static gssize
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_read_fn (GInputStream *stream,
|
|
Packit Service |
ca3877 |
void *buffer,
|
|
Packit Service |
ca3877 |
gsize count,
|
|
Packit Service |
ca3877 |
GCancellable *cancellable,
|
|
Packit Service |
ca3877 |
GError **error)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!fstream->priv->in_read_until)
|
|
Packit Service |
ca3877 |
fstream->priv->need_more = FALSE;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (fstream->priv->buf && !fstream->priv->in_read_until) {
|
|
Packit Service |
ca3877 |
return read_from_buf (fstream, buffer, count);
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
return g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream,
|
|
Packit Service |
ca3877 |
buffer, count,
|
|
Packit Service |
ca3877 |
TRUE, cancellable, error);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static gboolean
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_is_readable (GPollableInputStream *stream)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (fstream->priv->buf && !fstream->priv->need_more)
|
|
Packit Service |
ca3877 |
return TRUE;
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
return g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (G_FILTER_INPUT_STREAM (fstream)->base_stream));
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static gssize
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_read_nonblocking (GPollableInputStream *stream,
|
|
Packit Service |
ca3877 |
void *buffer,
|
|
Packit Service |
ca3877 |
gsize count,
|
|
Packit Service |
ca3877 |
GError **error)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!fstream->priv->in_read_until)
|
|
Packit Service |
ca3877 |
fstream->priv->need_more = FALSE;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (fstream->priv->buf && !fstream->priv->in_read_until) {
|
|
Packit Service |
ca3877 |
return read_from_buf (fstream, buffer, count);
|
|
Packit Service |
ca3877 |
} else {
|
|
Packit Service |
ca3877 |
return g_pollable_stream_read (G_FILTER_INPUT_STREAM (fstream)->base_stream,
|
|
Packit Service |
ca3877 |
buffer, count,
|
|
Packit Service |
ca3877 |
FALSE, NULL, error);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static GSource *
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_create_source (GPollableInputStream *stream,
|
|
Packit Service |
ca3877 |
GCancellable *cancellable)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
SoupFilterInputStream *fstream = SOUP_FILTER_INPUT_STREAM (stream);
|
|
Packit Service |
ca3877 |
GSource *base_source, *pollable_source;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (fstream->priv->buf && !fstream->priv->need_more)
|
|
Packit Service |
ca3877 |
base_source = g_timeout_source_new (0);
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
base_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (G_FILTER_INPUT_STREAM (fstream)->base_stream), cancellable);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_source_set_dummy_callback (base_source);
|
|
Packit Service |
ca3877 |
pollable_source = g_pollable_source_new (G_OBJECT (stream));
|
|
Packit Service |
ca3877 |
g_source_add_child_source (pollable_source, base_source);
|
|
Packit Service |
ca3877 |
g_source_unref (base_source);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return pollable_source;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_class_init (SoupFilterInputStreamClass *stream_class)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
GObjectClass *object_class = G_OBJECT_CLASS (stream_class);
|
|
Packit Service |
ca3877 |
GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (stream_class);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
object_class->finalize = soup_filter_input_stream_finalize;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
input_stream_class->read_fn = soup_filter_input_stream_read_fn;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
static void
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_pollable_init (GPollableInputStreamInterface *pollable_interface,
|
|
Packit Service |
ca3877 |
gpointer interface_data)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
pollable_interface->is_readable = soup_filter_input_stream_is_readable;
|
|
Packit Service |
ca3877 |
pollable_interface->read_nonblocking = soup_filter_input_stream_read_nonblocking;
|
|
Packit Service |
ca3877 |
pollable_interface->create_source = soup_filter_input_stream_create_source;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
GInputStream *
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_new (GInputStream *base_stream)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
return g_object_new (SOUP_TYPE_FILTER_INPUT_STREAM,
|
|
Packit Service |
ca3877 |
"base-stream", base_stream,
|
|
Packit Service |
ca3877 |
"close-base-stream", FALSE,
|
|
Packit Service |
ca3877 |
NULL);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
gssize
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_read_line (SoupFilterInputStream *fstream,
|
|
Packit Service |
ca3877 |
void *buffer,
|
|
Packit Service |
ca3877 |
gsize length,
|
|
Packit Service |
ca3877 |
gboolean blocking,
|
|
Packit Service |
ca3877 |
gboolean *got_line,
|
|
Packit Service |
ca3877 |
GCancellable *cancellable,
|
|
Packit Service |
ca3877 |
GError **error)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
return soup_filter_input_stream_read_until (fstream, buffer, length,
|
|
Packit Service |
ca3877 |
"\n", 1, blocking,
|
|
Packit Service |
ca3877 |
TRUE, got_line,
|
|
Packit Service |
ca3877 |
cancellable, error);
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
gssize
|
|
Packit Service |
ca3877 |
soup_filter_input_stream_read_until (SoupFilterInputStream *fstream,
|
|
Packit Service |
ca3877 |
void *buffer,
|
|
Packit Service |
ca3877 |
gsize length,
|
|
Packit Service |
ca3877 |
const void *boundary,
|
|
Packit Service |
ca3877 |
gsize boundary_length,
|
|
Packit Service |
ca3877 |
gboolean blocking,
|
|
Packit Service |
ca3877 |
gboolean include_boundary,
|
|
Packit Service |
ca3877 |
gboolean *got_boundary,
|
|
Packit Service |
ca3877 |
GCancellable *cancellable,
|
|
Packit Service |
ca3877 |
GError **error)
|
|
Packit Service |
ca3877 |
{
|
|
Packit Service |
ca3877 |
gssize nread, read_length;
|
|
Packit Service |
ca3877 |
guint8 *p, *buf, *end;
|
|
Packit Service |
ca3877 |
gboolean eof = FALSE;
|
|
Packit Service |
ca3877 |
GError *my_error = NULL;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (SOUP_IS_FILTER_INPUT_STREAM (fstream), -1);
|
|
Packit Service |
ca3877 |
g_return_val_if_fail (!include_boundary || (boundary_length < length), -1);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
*got_boundary = FALSE;
|
|
Packit Service |
ca3877 |
fstream->priv->need_more = FALSE;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!fstream->priv->buf || fstream->priv->buf->len < boundary_length) {
|
|
Packit Service |
ca3877 |
guint prev_len;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
fill_buffer:
|
|
Packit Service |
ca3877 |
if (!fstream->priv->buf)
|
|
Packit Service |
ca3877 |
fstream->priv->buf = g_byte_array_new ();
|
|
Packit Service |
ca3877 |
prev_len = fstream->priv->buf->len;
|
|
Packit Service |
ca3877 |
g_byte_array_set_size (fstream->priv->buf, length);
|
|
Packit Service |
ca3877 |
buf = fstream->priv->buf->data;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
fstream->priv->in_read_until = TRUE;
|
|
Packit Service |
ca3877 |
nread = g_pollable_stream_read (G_INPUT_STREAM (fstream),
|
|
Packit Service |
ca3877 |
buf + prev_len, length - prev_len,
|
|
Packit Service |
ca3877 |
blocking,
|
|
Packit Service |
ca3877 |
cancellable, &my_error);
|
|
Packit Service |
ca3877 |
fstream->priv->in_read_until = FALSE;
|
|
Packit Service |
ca3877 |
if (nread <= 0) {
|
|
Packit Service |
ca3877 |
if (prev_len)
|
|
Packit Service |
ca3877 |
fstream->priv->buf->len = prev_len;
|
|
Packit Service |
ca3877 |
else {
|
|
Packit Service |
ca3877 |
g_byte_array_free (fstream->priv->buf, TRUE);
|
|
Packit Service |
ca3877 |
fstream->priv->buf = NULL;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (nread == 0 && prev_len)
|
|
Packit Service |
ca3877 |
eof = TRUE;
|
|
Packit Service |
ca3877 |
else {
|
|
Packit Service |
ca3877 |
if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
|
|
Packit Service |
ca3877 |
fstream->priv->need_more = TRUE;
|
|
Packit Service |
ca3877 |
if (my_error)
|
|
Packit Service |
ca3877 |
g_propagate_error (error, my_error);
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
return nread;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (my_error)
|
|
Packit Service |
ca3877 |
g_propagate_error (error, my_error);
|
|
Packit Service |
ca3877 |
} else
|
|
Packit Service |
ca3877 |
fstream->priv->buf->len = prev_len + nread;
|
|
Packit Service |
ca3877 |
} else
|
|
Packit Service |
ca3877 |
buf = fstream->priv->buf->data;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
/* Scan for the boundary within the range we can possibly return. */
|
|
Packit Service |
ca3877 |
if (include_boundary)
|
|
Packit Service |
ca3877 |
end = buf + MIN (fstream->priv->buf->len, length) - boundary_length;
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
end = buf + MIN (fstream->priv->buf->len - boundary_length, length);
|
|
Packit Service |
ca3877 |
for (p = buf; p <= end; p++) {
|
|
Packit Service |
ca3877 |
if (*p == *(guint8*)boundary &&
|
|
Packit Service |
ca3877 |
!memcmp (p, boundary, boundary_length)) {
|
|
Packit Service |
ca3877 |
if (include_boundary)
|
|
Packit Service |
ca3877 |
p += boundary_length;
|
|
Packit Service |
ca3877 |
*got_boundary = TRUE;
|
|
Packit Service |
ca3877 |
break;
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
}
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (!*got_boundary && fstream->priv->buf->len < length && !eof)
|
|
Packit Service |
ca3877 |
goto fill_buffer;
|
|
Packit Service |
ca3877 |
|
|
Packit Service |
ca3877 |
if (eof && !*got_boundary)
|
|
Packit Service |
ca3877 |
read_length = MIN (fstream->priv->buf->len, length);
|
|
Packit Service |
ca3877 |
else
|
|
Packit Service |
ca3877 |
read_length = p - buf;
|
|
Packit Service |
ca3877 |
return read_from_buf (fstream, buffer, read_length);
|
|
Packit Service |
ca3877 |
}
|