Initial commit
[jamendo] / src / http_utils.c
diff --git a/src/http_utils.c b/src/http_utils.c
new file mode 100644 (file)
index 0000000..ae0e74e
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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;
+}