/* * librest - RESTful web services access * Copyright (c) 2010 Intel Corporation. * * Authors: Ross Burton * Rob Bradford * * RestParam is inspired by libsoup's SoupBuffer * Copyright (C) 2000-2030 Ximian, Inc * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include "rest-param.h" /** * SECTION:rest-param * @short_description: Name/value parameter data type with intelligent memory * management * @see_also: #RestParams, #RestProxyCall. */ /* Internal RestMemoryUse values */ enum { REST_MEMORY_OWNED = REST_MEMORY_COPY + 1 }; struct _RestParam { char *name; RestMemoryUse use; gconstpointer data; gsize length; const char *content_type; char *filename; volatile gint ref_count; gpointer owner; GDestroyNotify owner_dnotify; }; G_DEFINE_BOXED_TYPE (RestParam, rest_param, rest_param_ref, rest_param_unref) /** * rest_param_new_full: * @name: the parameter name * @use: the #RestMemoryUse describing how the memory can be used * @data: (array length=length) (element-type guint8): a pointer to * the start of the data * @length: the length of the data * @content_type: the content type of the data * @filename: (nullable): the original filename, or %NULL * * Create a new #RestParam called @name with @length bytes of @data as the * value. @content_type is the type of the data as a MIME type, for example * "text/plain" for simple string parameters. * * If the parameter is a file upload it can be passed as @filename. * * Returns: a new #RestParam. **/ RestParam * rest_param_new_full (const char *name, RestMemoryUse use, gconstpointer data, gsize length, const char *content_type, const char *filename) { RestParam *param; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (content_type != NULL, NULL); g_return_val_if_fail (data != NULL, NULL); param = g_slice_new0 (RestParam); if (use == REST_MEMORY_COPY) { data = g_memdup2 (data, length); use = REST_MEMORY_TAKE; } param->name = g_strdup (name); param->use = use; param->data = data; param->length = length; param->content_type = g_intern_string (content_type); param->filename = g_strdup (filename); param->ref_count = 1; if (use == REST_MEMORY_TAKE) { param->owner = (gpointer)data; param->owner_dnotify = g_free; } return param; } /** * rest_param_new_with_owner: * @name: the parameter name * @data: (array length=length) (element-type guint8): a pointer to * the start of the data * @length: the length of the data * @content_type: the content type of the data * @filename: (allow-none): the original filename, or %NULL * @owner: (transfer full): pointer to an object that owns @data * @owner_dnotify: (allow-none): a function to free/unref @owner when * the buffer is freed * * Create a new #RestParam called @name with @length bytes of @data as the * value. @content_type is the type of the data as a MIME type, for example * "text/plain" for simple string parameters. * * If the parameter is a file upload it can be passed as @filename. * * When the #RestParam is freed, it will call @owner_dnotify, passing @owner to * it. This allows you to do something like this: * * |[ * GMappedFile *map = g_mapped_file_new (filename, FALSE, &error); * RestParam *param = rest_param_new_with_owner ("media", * g_mapped_file_get_contents (map), * g_mapped_file_get_length (map), * "image/jpeg", * filename, * map, * (GDestroyNotify)g_mapped_file_unref); * ]| * * Returns: a new #RestParam. **/ RestParam * rest_param_new_with_owner (const char *name, gconstpointer data, gsize length, const char *content_type, const char *filename, gpointer owner, GDestroyNotify owner_dnotify) { RestParam *param; g_return_val_if_fail (name, NULL); g_return_val_if_fail (data, NULL); g_return_val_if_fail (content_type, NULL); param = g_slice_new0 (RestParam); param->name = g_strdup (name); param->use = REST_MEMORY_OWNED; param->data = data; param->length = length; param->content_type = g_intern_string (content_type); param->filename = g_strdup (filename); param->ref_count = 1; param->owner = owner; param->owner_dnotify = owner_dnotify; return param; } /** * rest_param_new_string: * @name: the parameter name * @use: the #RestMemoryUse describing how the memory can be used * @string: the parameter value * * A convience constructor to create a #RestParam from a given UTF-8 string. * The resulting #RestParam will have a content type of "text/plain". * * Returns: a new #RestParam. **/ RestParam * rest_param_new_string (const char *name, RestMemoryUse use, const char *string) { g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (string != NULL, NULL); if (string == NULL) { use = REST_MEMORY_STATIC; string = ""; } return rest_param_new_full (name, use, string, strlen (string) + 1, g_intern_static_string ("text/plain"), NULL); } /** * rest_param_get_name: * @param: a valid #RestParam * * Get the name of the parameter. * * Returns: the parameter name. **/ const char * rest_param_get_name (RestParam *param) { g_return_val_if_fail (param != NULL, NULL); return param->name; } /** * rest_param_get_content_type: * @param: a valid #RestParam * * Get the MIME type of the parameter. For example, basic strings have the MIME * type "text/plain". * * Returns: the MIME type **/ const char * rest_param_get_content_type (RestParam *param) { g_return_val_if_fail (param != NULL, NULL); return param->content_type; } /** * rest_param_get_file_name: * @param: a valid #RestParam * * Get the original file name of the parameter, if one is available. * * Returns: the filename if set, or %NULL. **/ const char * rest_param_get_file_name (RestParam *param) { g_return_val_if_fail (param != NULL, FALSE); return param->filename; } /** * rest_param_is_string: * @param: a valid #RestParam * * Determine if the parameter is a string value, i.e. the content type is "text/plain". * * Returns: %TRUE if the parameter is a string, %FALSE otherwise. */ gboolean rest_param_is_string (RestParam *param) { g_return_val_if_fail (param != NULL, FALSE); return param->content_type == g_intern_static_string ("text/plain"); } /** * rest_param_get_content: * @param: a valid #RestParam * * Get the content of @param. The content should be treated as read-only and * not modified in any way. * * Returns: (transfer none): the content. **/ gconstpointer rest_param_get_content (RestParam *param) { g_return_val_if_fail (param != NULL, NULL); return param->data; } /** * rest_param_get_content_length: * @param: a valid #RestParam * * Get the length of the content of @param. * * Returns: the length of the content **/ gsize rest_param_get_content_length (RestParam *param) { g_return_val_if_fail (param != NULL, 0); return param->length; } /** * rest_param_ref: * @param: a valid #RestParam * * Increase the reference count on @param. * * Returns: the #RestParam **/ RestParam * rest_param_ref (RestParam *param) { /* TODO: bring back REST_MEMORY_TEMPORARY? */ g_return_val_if_fail (param != NULL, NULL); g_return_val_if_fail (param->ref_count > 0, NULL); g_atomic_int_inc (¶m->ref_count); return param; } /** * rest_param_unref: * @param: a valid #RestParam * * Decrease the reference count on @param, destroying it if the reference count * reaches 0. **/ void rest_param_unref (RestParam *param) { g_return_if_fail (param); if (g_atomic_int_dec_and_test (¶m->ref_count)) { if (param->owner_dnotify) param->owner_dnotify (param->owner); g_free (param->name); g_free (param->filename); g_slice_free (RestParam, param); } }