[libsoup] New accept-language-auto property for SoupSession
- From: Dan Winship <danw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [libsoup] New accept-language-auto property for SoupSession
- Date: Thu, 17 Dec 2009 10:50:26 +0000 (UTC)
commit b3c60a3706682226c9ae10079ba58b7284757711
Author: Mario Sanchez Prada <msanchez igalia com>
Date: Wed Dec 16 15:17:01 2009 +0100
New accept-language-auto property for SoupSession
Provide a new way for SoupSession to assume an 'Accept-Language'
string automatically from the return value of g_get_language_names(),
properly formatted according to RFC2616.
https://bugzilla.gnome.org/show_bug.cgi?id=597004
libsoup/soup-session.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++-
libsoup/soup-session.h | 21 ++++---
2 files changed, 152 insertions(+), 14 deletions(-)
---
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 48f336e..2dc6d1f 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -76,6 +76,7 @@ typedef struct {
char *user_agent;
char *accept_language;
+ gboolean accept_language_auto;
GSList *features;
GHashTable *features_cache;
@@ -143,6 +144,7 @@ enum {
PROP_TIMEOUT,
PROP_USER_AGENT,
PROP_ACCEPT_LANGUAGE,
+ PROP_ACCEPT_LANGUAGE_AUTO,
PROP_IDLE_TIMEOUT,
PROP_ADD_FEATURE,
PROP_ADD_FEATURE_BY_TYPE,
@@ -592,6 +594,27 @@ soup_session_class_init (SoupSessionClass *session_class)
G_PARAM_READWRITE));
/**
+ * SoupSession:accept-language-auto:
+ *
+ * If %TRUE, #SoupSession will automatically set the string
+ * for the "Accept-Language" header on every #SoupMessage
+ * sent, based on the return value of g_get_language_names().
+ *
+ **/
+ /**
+ * SOUP_SESSION_ACCEPT_LANGUAGE_AUTO:
+ *
+ * Alias for the #SoupSession:accept-language-auto property, qv.
+ **/
+ g_object_class_install_property (
+ object_class, PROP_ACCEPT_LANGUAGE_AUTO,
+ g_param_spec_boolean (SOUP_SESSION_ACCEPT_LANGUAGE_AUTO,
+ "Accept-Language automatic mode",
+ "Accept-Language automatic mode",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ /**
* SoupSession:add-feature:
*
* Add a feature object to the session. (Shortcut for calling
@@ -675,6 +698,103 @@ safe_str_equal (const char *a, const char *b)
return strcmp (a, b) == 0;
}
+/* Converts a language in POSIX format and to be RFC2616 compliant */
+/* Based on code from epiphany-webkit (ephy_langs_append_languages()) */
+static gchar *
+posix_lang_to_rfc2616 (const gchar *language)
+{
+ char *lang = NULL;
+
+ if (strstr (language, ".") == 0 &&
+ strstr (language, "@") == 0 &&
+ strcmp (language, "C") != 0)
+ {
+ /* change to lowercase and '_' to '-' */
+ lang = g_strdelimit (g_ascii_strdown
+ (language, -1), "_", '-');
+ }
+
+ return lang;
+}
+
+/* Adds a quality value to a string (any value between 0 and 1). */
+static gchar *
+add_quality_value (const gchar *str, float qvalue)
+{
+ char *qv_str = NULL;
+
+ g_return_val_if_fail (str != NULL, NULL);
+
+ if ((qvalue >= 0.0) && (qvalue <= 1.0)) {
+ int qv_int = (qvalue * 1000 + 0.5);
+ qv_str = g_strdup_printf ("%s;q=%d.%d",
+ str,
+ (int) (qv_int / 1000),
+ qv_int % 1000);
+ } else {
+ /* Just dup the string in this case */
+ qv_str = g_strdup (str);
+ }
+
+ return qv_str;
+}
+
+/* Returns a RFC2616 compliant languages list from system locales */
+static gchar *
+accept_languages_from_system (void)
+{
+ const char * const * lang_names;
+ GArray *langs_garray = NULL;
+ char *cur_lang = NULL;
+ char *prev_lang = NULL;
+ char **langs_array;
+ char *langs_str;
+ float delta;
+ int i, n_lang_names;
+
+ lang_names = g_get_language_names ();
+ g_return_val_if_fail (lang_names != NULL, NULL);
+
+ /* Calculate delta for setting the quality values */
+ n_lang_names = g_strv_length ((gchar **)lang_names);
+ delta = 0.999 / (n_lang_names - 1);
+
+ /* Build the array of languages */
+ langs_garray = g_array_new (TRUE, FALSE, sizeof (char*));
+ for (i = 0; lang_names[i] != NULL; i++) {
+ cur_lang = posix_lang_to_rfc2616 (lang_names[i]);
+
+ /* Apart from getting a valid RFC2616 compliant
+ * language, also get rid of extra variants
+ */
+ if ((cur_lang != NULL) &&
+ (!prev_lang ||
+ (!g_strcmp0 (prev_lang, cur_lang) ||
+ !g_strstr_len (prev_lang, -1, cur_lang)))) {
+
+ gchar *qv_lang = NULL;
+
+ /* Save reference for further comparison */
+ prev_lang = cur_lang;
+
+ /* Add the quality value and append it */
+ qv_lang = add_quality_value (cur_lang, 1 - i * delta);
+ g_array_append_val (langs_garray, qv_lang);
+ }
+ }
+
+ /* Fallback: add "en" if list is empty */
+ if (langs_garray->len == 0) {
+ char *default_lang = g_strdup ("en");
+ g_array_append_val (langs_garray, default_lang);
+ }
+
+ langs_array = (char **) g_array_free (langs_garray, FALSE);
+ langs_str = g_strjoinv (", ", langs_array);
+
+ return langs_str;
+}
+
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
@@ -756,6 +876,18 @@ set_property (GObject *object, guint prop_id,
case PROP_ACCEPT_LANGUAGE:
g_free (priv->accept_language);
priv->accept_language = g_strdup (g_value_get_string (value));
+ priv->accept_language_auto = FALSE;
+ break;
+ case PROP_ACCEPT_LANGUAGE_AUTO:
+ priv->accept_language_auto = g_value_get_boolean (value);
+ if (priv->accept_language) {
+ g_free (priv->accept_language);
+ priv->accept_language = NULL;
+ }
+
+ /* Get languages from system if needed */
+ if (priv->accept_language_auto)
+ priv->accept_language = accept_languages_from_system ();
break;
case PROP_IDLE_TIMEOUT:
priv->idle_timeout = g_value_get_uint (value);
@@ -823,6 +955,9 @@ get_property (GObject *object, guint prop_id,
case PROP_ACCEPT_LANGUAGE:
g_value_set_string (value, priv->accept_language);
break;
+ case PROP_ACCEPT_LANGUAGE_AUTO:
+ g_value_set_boolean (value, priv->accept_language_auto);
+ break;
case PROP_IDLE_TIMEOUT:
g_value_set_uint (value, priv->idle_timeout);
break;
@@ -1021,10 +1156,12 @@ soup_session_send_queue_item (SoupSession *session,
"User-Agent", priv->user_agent);
}
- if (priv->accept_language) {
- soup_message_headers_replace (item->msg->request_headers,
- "Accept-Language",
- priv->accept_language);
+ if (priv->accept_language &&
+ !soup_message_headers_get_list (item->msg->request_headers,
+ "Accept-Language")) {
+ soup_message_headers_append (item->msg->request_headers,
+ "Accept-Language",
+ priv->accept_language);
}
g_signal_emit (session, signals[REQUEST_STARTED], 0,
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index c7873e7..056799d 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -58,16 +58,17 @@ typedef struct {
GType soup_session_get_type (void);
-#define SOUP_SESSION_PROXY_URI "proxy-uri"
-#define SOUP_SESSION_MAX_CONNS "max-conns"
-#define SOUP_SESSION_MAX_CONNS_PER_HOST "max-conns-per-host"
-#define SOUP_SESSION_USE_NTLM "use-ntlm"
-#define SOUP_SESSION_SSL_CA_FILE "ssl-ca-file"
-#define SOUP_SESSION_ASYNC_CONTEXT "async-context"
-#define SOUP_SESSION_TIMEOUT "timeout"
-#define SOUP_SESSION_USER_AGENT "user-agent"
-#define SOUP_SESSION_ACCEPT_LANGUAGE "accept-language"
-#define SOUP_SESSION_IDLE_TIMEOUT "idle-timeout"
+#define SOUP_SESSION_PROXY_URI "proxy-uri"
+#define SOUP_SESSION_MAX_CONNS "max-conns"
+#define SOUP_SESSION_MAX_CONNS_PER_HOST "max-conns-per-host"
+#define SOUP_SESSION_USE_NTLM "use-ntlm"
+#define SOUP_SESSION_SSL_CA_FILE "ssl-ca-file"
+#define SOUP_SESSION_ASYNC_CONTEXT "async-context"
+#define SOUP_SESSION_TIMEOUT "timeout"
+#define SOUP_SESSION_USER_AGENT "user-agent"
+#define SOUP_SESSION_ACCEPT_LANGUAGE "accept-language"
+#define SOUP_SESSION_ACCEPT_LANGUAGE_AUTO "accept-language-auto"
+#define SOUP_SESSION_IDLE_TIMEOUT "idle-timeout"
#define SOUP_SESSION_ADD_FEATURE "add-feature"
#define SOUP_SESSION_ADD_FEATURE_BY_TYPE "add-feature-by-type"
#define SOUP_SESSION_REMOVE_FEATURE_BY_TYPE "remove-feature-by-type"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]