[Kazehakase-devel 1949] Content-Encoding: x-gzip 対応

Back to archive index

Kazuhiro NISHIYAMA zn****@mbf*****
2005年 2月 24日 (木) 18:41:55 JST


西山和広です。

Content-Encoding: x-gzip 対応をしてみたのですが、強制的に
buffer modeにする方法がわからなかったので、リモートブックマークの
x-gzipは対処できたのですが、ドロップしてダウンロードでは
CRITICAL **: kz_io_decode_buffer: assertion `kz_io_is_buffer_mode(io)' failed
と出て、gzipされたままダウンロードされます。

これで、samidareのsites.lirs.gzが使えるようになります。

ただしgzipの入力に一時ファイルを使って出力はg_spawn_syncに
まかせてgchar**で受け取るようにしてしまったので、'\0'が入る
バイナリやUTF-8以外のUnicodeなどで問題がありそうです。

それに対処しようかと思ってContent-Typeも保存するようにして
みたのですが、textの時だけデコードするようにしても結局
Unicodeで問題がありそうなので、Content-Typeは使っていません。


以上のような状況なのですが、commitしてしまっても良いでしょうか?
g_spawn_async_with_pipesを使うか何かで'\0'対策をしておかないと
だめでしょうか?


-- 
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)
-------------- next part --------------
Index: src/net/kz-http.c
===================================================================
RCS file: /cvsroot/kazehakase/kazehakase/src/net/kz-http.c,v
retrieving revision 1.54
diff -u -p -r1.54 kz-http.c
--- src/net/kz-http.c	24 Feb 2005 03:33:55 -0000	1.54
+++ src/net/kz-http.c	24 Feb 2005 08:54:46 -0000
@@ -25,6 +25,7 @@
 #define __USE_XOPEN
 #include <time.h>
 #include <glib/gi18n.h>
+#include <unistd.h>
 
 #include "gobject-utils.h"
 #include "kz-http.h"
@@ -70,6 +71,8 @@ struct _KzHTTPPrivate 
 
 	gboolean redirection; /* for Redirection 3xx */
 	gchar    *location;   /* Redirect-URI */
+	gchar    *content_type;
+	gchar    *content_encoding;
 
 	gchar *post_data;
 };
@@ -208,6 +211,8 @@ kz_http_init (KzHTTP *http)
 	http->priv->chunked         = FALSE;
 	http->priv->redirection     = FALSE;
 	http->priv->location        = NULL;
+	http->priv->content_type    = NULL;
+	http->priv->content_encoding = NULL;
 
 	http->priv->chunk_size      = 0;
 
@@ -230,6 +235,10 @@ kz_http_dispose (GObject *object)
 		g_free(http->priv->path);
 	if (http->priv->location)
 		g_free(http->priv->location);
+	if (http->priv->content_type)
+		g_free(http->priv->content_type);
+	if (http->priv->content_encoding)
+		g_free(http->priv->content_encoding);
 	if (http->priv->post_data)
 		g_free(http->priv->post_data);
 
@@ -237,6 +246,8 @@ kz_http_dispose (GObject *object)
 	http->priv->hostname  = NULL;
 	http->priv->path      = NULL;
 	http->priv->location  = NULL;
+	http->priv->content_type = NULL;
+	http->priv->content_encoding = NULL;
 	http->priv->post_data = NULL;
 
 	if (G_OBJECT_CLASS (parent_class)->dispose)
@@ -411,6 +422,20 @@ kz_http_in_header(KzHTTP *http, GIOChann
 		if (g_str_has_prefix(value, "chunked"))
 			kz_http_set_chunked_mode(http);
 	}
+	else if (g_ascii_strncasecmp(buffer->str, "Content-Type:", 13) == 0)
+	{
+		const gchar *value = buffer->str + 13;
+		while (*value && g_ascii_isspace(*value))
+			++value;
+		http->priv->content_type = g_strchomp(g_strdup(value));
+	}
+	else if (g_ascii_strncasecmp(buffer->str, "Content-Encoding:", 17) == 0)
+	{
+		const gchar *value = buffer->str + 17;
+		while (*value && g_ascii_isspace(*value))
+			++value;
+		http->priv->content_encoding = g_strchomp(g_strdup(value));
+	}
 	else if (g_ascii_strncasecmp(buffer->str, "Location:", 9) == 0)
 	{
 		const gchar *value = buffer->str + 9;
@@ -549,11 +574,17 @@ kz_http_read_from_io (KzIO *io, GIOChann
 	else 		/* Entity-Body Section */
 		iostatus = kz_http_in_body(http, iochannel);
 	
-	if (iostatus == G_IO_STATUS_EOF && kz_http_is_redirection(http))
-	{
-		g_object_set(G_OBJECT(http),
-			     "uri", g_strchomp(http->priv->location), NULL);
-		iostatus = G_IO_STATUS_AGAIN;
+	if (iostatus == G_IO_STATUS_EOF) {
+		if (kz_http_is_redirection(http))
+		{
+			g_object_set(G_OBJECT(http),
+				     "uri", g_strchomp(http->priv->location),
+				     NULL);
+			iostatus = G_IO_STATUS_AGAIN;
+		}
+		else if (http->priv->content_encoding) {
+			return kz_io_decode_buffer(KZ_IO(http), http->priv->content_encoding);
+		}
 	}
 
 	return iostatus;
Index: src/net/kz-io.c
===================================================================
RCS file: /cvsroot/kazehakase/kazehakase/src/net/kz-io.c,v
retrieving revision 1.31
diff -u -p -r1.31 kz-io.c
--- src/net/kz-io.c	13 Feb 2005 22:55:15 -0000	1.31
+++ src/net/kz-io.c	24 Feb 2005 08:54:46 -0000
@@ -733,3 +733,83 @@ kz_io_stop (KzIO *io)
 	return;
 }
 
+
+#include <sys/wait.h>
+#include <unistd.h>
+
+static void
+kz_io_decode_child_setup(gpointer user_data)
+{
+	GString *string = user_data;
+	gchar *name_used = NULL;
+	GError *error = NULL;
+	gint fd = g_file_open_tmp("kz_io_decode.XXXXXX", &name_used, &error);
+	if (name_used) {
+		unlink(name_used);
+		g_free(name_used);
+		name_used = NULL;
+	}
+
+	if (error) {
+		g_warning("g_file_open_tmp: %s", error->message);
+		g_error_free(error);
+		return;
+	}
+
+	write(fd, string->str, string->len);
+	lseek(fd, 0, SEEK_SET);
+
+	dup2(fd, 0);
+	close(fd);
+}
+
+GIOStatus
+kz_io_decode_buffer(KzIO *io, const gchar *content_encoding)
+{
+	GIOStatus status = G_IO_STATUS_EOF;
+	GError *error = NULL;
+	gchar *standard_output = NULL;
+	gint exit_status = 0;
+	gboolean success;
+
+	g_return_val_if_fail(KZ_IS_IO(io), status);
+	g_return_val_if_fail(kz_io_is_buffer_mode(io), status);
+	g_return_val_if_fail(content_encoding, status);
+
+	if (strcmp(content_encoding, "x-gzip") == 0) {
+		gchar *argv[] = {
+			"gzip", "-dc", NULL,
+		};
+		GString *string = g_string_new_len(
+			kz_io_get_buffer(io),
+			kz_io_get_loaded_size(io));
+		success = g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
+				       kz_io_decode_child_setup, string,
+				       &standard_output, NULL, &exit_status,
+				       &error);
+		g_string_free(string, TRUE);
+	} else {
+		return status;
+	}
+	if (error) {
+		g_warning("g_spawn_sync failed: %s", error->message);
+		g_error_free(error);
+	} else if (!success) {
+		g_warning("g_spawn_sync failed");
+	} else if (exit_status != 0 || standard_output == NULL) {
+		g_warning("decode content failed: status=%d", exit_status);
+		g_warning("WIFEXITED=%d WEXITSTATUS=%d", WIFEXITED(exit_status), WEXITSTATUS(exit_status));
+		g_warning("WIFSIGNALED=%d WTERMSIG=%d", WIFSIGNALED(exit_status), WTERMSIG(exit_status));
+		g_warning("WIFSTOPPED=%d WSTOPSIG=%d", WIFSTOPPED(exit_status), WSTOPSIG(exit_status));
+	} else {
+		/* reset buffer */
+		gsize len = strlen(standard_output);
+		g_string_truncate(io->priv->buffer, 0);
+		io->priv->loaded_size = 0;
+		io->priv->file_size = len;
+		io_to_buffer(io, len, standard_output);
+	}
+	g_free(standard_output);
+
+	return status;
+}
Index: src/net/kz-io.h
===================================================================
RCS file: /cvsroot/kazehakase/kazehakase/src/net/kz-io.h,v
retrieving revision 1.14
diff -u -p -r1.14 kz-io.h
--- src/net/kz-io.h	25 Nov 2004 07:28:48 -0000	1.14
+++ src/net/kz-io.h	24 Feb 2005 08:54:46 -0000
@@ -96,6 +96,8 @@ const gchar *kz_io_get_buffer       (KzI
 void         kz_io_start            (KzIO *io);
 void         kz_io_stop             (KzIO *io);
 KzIOMode     kz_io_get_mode         (KzIO *io);
+GIOStatus    kz_io_decode_buffer    (KzIO *io,
+				     const gchar *content_encoding);
 
 
 G_END_DECLS


Kazehakase-devel メーリングリストの案内
Back to archive index