/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* soup-request-data.c: data: URI request object
*
* Copyright (C) 2009, 2010 Red Hat, Inc.
* Copyright (C) 2010 Igalia, S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include "soup-request-data.h"
#include "soup.h"
#include "soup-misc-private.h"
/**
* SECTION:soup-request-data
* @short_description: SoupRequest support for "data" URIs
*
* #SoupRequestData implements #SoupRequest for "data" URIs.
*/
struct _SoupRequestDataPrivate {
gsize content_length;
char *content_type;
};
G_DEFINE_TYPE_WITH_PRIVATE (SoupRequestData, soup_request_data, SOUP_TYPE_REQUEST)
static void
soup_request_data_init (SoupRequestData *data)
{
data->priv = soup_request_data_get_instance_private (data);
}
static void
soup_request_data_finalize (GObject *object)
{
SoupRequestData *data = SOUP_REQUEST_DATA (object);
g_free (data->priv->content_type);
G_OBJECT_CLASS (soup_request_data_parent_class)->finalize (object);
}
static gboolean
soup_request_data_check_uri (SoupRequest *request,
SoupURI *uri,
GError **error)
{
return uri->host == NULL;
}
#define BASE64_INDICATOR ";base64"
#define BASE64_INDICATOR_LEN (sizeof (";base64") - 1)
static GInputStream *
soup_request_data_send (SoupRequest *request,
GCancellable *cancellable,
GError **error)
{
SoupRequestData *data = SOUP_REQUEST_DATA (request);
SoupURI *uri = soup_request_get_uri (request);
GInputStream *memstream;
const char *comma, *start, *end;
gboolean base64 = FALSE;
char *uristr;
uristr = soup_uri_to_string (uri, FALSE);
start = uristr + 5;
comma = strchr (start, ',');
if (comma && comma != start) {
/* Deal with MIME type / params */
if (comma >= start + BASE64_INDICATOR_LEN && !g_ascii_strncasecmp (comma - BASE64_INDICATOR_LEN, BASE64_INDICATOR, BASE64_INDICATOR_LEN)) {
end = comma - BASE64_INDICATOR_LEN;
base64 = TRUE;
} else
end = comma;
if (end != start)
data->priv->content_type = soup_uri_decoded_copy (start, end - start, NULL);
}
memstream = g_memory_input_stream_new ();
if (comma)
start = comma + 1;
if (*start) {
int decoded_length = 0;
guchar *buf = (guchar *) soup_uri_decoded_copy (start, strlen (start),
&decoded_length);
if (base64)
buf = g_base64_decode_inplace ((gchar*) buf, &data->priv->content_length);
else
data->priv->content_length = decoded_length;
g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (memstream),
buf, data->priv->content_length,
g_free);
}
g_free (uristr);
return memstream;
}
static goffset
soup_request_data_get_content_length (SoupRequest *request)
{
SoupRequestData *data = SOUP_REQUEST_DATA (request);
return data->priv->content_length;
}
static const char *
soup_request_data_get_content_type (SoupRequest *request)
{
SoupRequestData *data = SOUP_REQUEST_DATA (request);
if (data->priv->content_type)
return data->priv->content_type;
else
return "text/plain;charset=US-ASCII";
}
static const char *data_schemes[] = { "data", NULL };
static void
soup_request_data_class_init (SoupRequestDataClass *request_data_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (request_data_class);
SoupRequestClass *request_class =
SOUP_REQUEST_CLASS (request_data_class);
request_class->schemes = data_schemes;
object_class->finalize = soup_request_data_finalize;
request_class->check_uri = soup_request_data_check_uri;
request_class->send = soup_request_data_send;
request_class->get_content_length = soup_request_data_get_content_length;
request_class->get_content_type = soup_request_data_get_content_type;
}