--- /dev/null
+/*
+ * http_utils.c
+ *
+ * Created on: 2009-12-18
+ * Author: marcin
+ */
+
+#include "http_utils.h"
+
+#define HTTP_CACHE_PATH "/tmp/jamendo-cache"
+#define MAX_CACHE_DAYS 2
+
+static GInputStream* http_cache_get(const gchar* uri);
+
+xmlDocPtr http_get_xml(const gchar* uri) {
+ GInputStream* stream = NULL;
+ GError *error = NULL;
+ gchar buf[1024];
+ gint ncount = 0;
+ xmlParserCtxtPtr ctxt = NULL;
+ xmlDocPtr doc = NULL;
+
+ g_debug("http_get_xml: uri=%s", uri);
+
+ /**
+ * I found out that, this line will also do parsing xml from HTTP, instead of this complicated function
+ *
+ xmlDocPtr doc = xmlReadFile(uri,NULL,0);
+ */
+
+ stream = http_cache_get(uri);
+
+ if (!stream) {
+ g_warning("http_get_xml: ERROR");
+ return NULL;
+ }
+
+ do {
+ ncount = g_input_stream_read(G_INPUT_STREAM(stream), buf, G_N_ELEMENTS(buf), NULL, &error);
+ if (error) {
+ g_error("http_get_xml: %s", error->message);
+ g_error_free(error);
+ error = NULL;
+ }
+ if (ncount) {
+ if (!ctxt) {
+ ctxt = xmlCreatePushParserCtxt(NULL, NULL, buf, ncount, uri);
+ } else {
+ xmlParseChunk(ctxt, buf, ncount, 0);
+ }
+ }
+ } while (ncount != 0);
+
+ if (ctxt) {
+ xmlParseChunk(ctxt, buf, 0, 1);
+ doc = ctxt->myDoc;
+ if (!ctxt->wellFormed) {
+ g_warning("http_get_xml: wellFormed=%d", ctxt->wellFormed);
+ }
+ xmlFreeParserCtxt(ctxt);
+ }
+
+ g_input_stream_close(stream, NULL, NULL);
+
+ return doc;
+}
+
+GdkPixbuf* http_get_image(const gchar* uri, gint width, gint height) {
+ GError *error = NULL;
+ GdkPixbuf* image = NULL;
+
+ GInputStream* stream = http_cache_get(uri);
+ if (stream) {
+ image = gdk_pixbuf_new_from_stream_at_scale(stream, width, height, TRUE, NULL, &error);
+ g_input_stream_close(stream, NULL, NULL);
+ }
+
+ return image;
+}
+
+//TODO: add parameter to support cache expiration
+static GInputStream* http_cache_get(const gchar* uri) {
+ gchar* tmp;
+ gchar* cache_path;
+ GFile* cache_file;
+ GFile* http_file;
+ GError* error = NULL;
+ GInputStream* input_stream;
+ GOutputStream* output_stream;
+
+ cache_file = g_file_new_for_path(HTTP_CACHE_PATH);
+ if (!g_file_query_exists(cache_file, NULL)) {
+ g_file_make_directory_with_parents(cache_file, NULL, NULL);
+ }
+ g_object_unref(cache_file);
+
+ /** check if uri is in our cache **/
+ tmp = g_uri_escape_string(uri, NULL, FALSE);
+ cache_path = g_strdup_printf("%s/%s", HTTP_CACHE_PATH, tmp);
+ g_free(tmp);
+
+ cache_file = g_file_new_for_path(cache_path);
+ g_free(cache_path);
+
+ if (g_file_query_exists(cache_file, NULL)) {
+ GFileInfo *info;
+ GTimeVal mod, cur;
+ GDate *modDate = g_date_new(), *curDate = g_date_new();
+
+ info = g_file_query_info(cache_file, G_FILE_ATTRIBUTE_TIME_MODIFIED, 0, NULL, NULL);
+ mod.tv_sec = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+ g_object_unref(info);
+ g_date_set_time_val(modDate, &mod);
+
+ g_get_current_time(&cur);
+ g_date_set_time_val(curDate, &cur);
+
+ gint days = g_date_days_between(modDate, curDate);
+
+ if (days <= MAX_CACHE_DAYS) {
+ g_debug("http_cache_get: cache age %d days - ok", days);
+ input_stream = G_INPUT_STREAM(g_file_read(cache_file, NULL, &error));
+
+ if (!error) {
+ g_object_unref(cache_file);
+ return input_stream;
+ }
+
+ g_warning("http_cache_get: cannot read cache file: %s", error->message);
+ g_error_free(error);
+ error = NULL;
+ }
+ else {
+ g_debug("http_cache_get: cache age %d days - to old", days);
+ }
+ }
+
+ /** not in cache, get it from http */
+ http_file = g_file_new_for_uri(uri);
+ input_stream = G_INPUT_STREAM(g_file_read(http_file, NULL, &error));
+ g_object_unref(http_file);
+ if (error) {
+ g_warning("http_cache_get: cannot read from HTTP: %s", error->message);
+ g_error_free(error);
+ g_object_unref(cache_file);
+ return NULL;
+ }
+
+ output_stream = G_OUTPUT_STREAM(g_file_replace(cache_file,NULL,0,G_FILE_CREATE_REPLACE_DESTINATION,NULL,&error));
+ if (error) {
+ g_warning("http_cache_get: cannot create cache file: %s", error->message);
+ g_error_free(error);
+ g_object_unref(cache_file);
+ return input_stream;
+ }
+
+ g_output_stream_splice(output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE
+ | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error);
+ if (error) {
+ g_warning("http_cache_get: cannot write HTTP file to cache: %s", error->message);
+ g_error_free(error);
+ g_object_unref(cache_file);
+ return NULL;
+ }
+
+ /** input and output streams are closed by g_output_stream_splice **/
+ input_stream = G_INPUT_STREAM(g_file_read(cache_file, NULL, &error));
+ g_object_unref(cache_file);
+ if (error) {
+ g_warning("http_cache_get: cannot reopen cache file %s", error->message);
+ g_error_free(error);
+ return NULL;
+ }
+ return input_stream;
+}