2 * Copyright (C) 2009-2010 Andy Spencer <andy753421@gmail.com>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @short_description: Hyper Text Transfer Protocol
22 * #GisHttp is a small wrapper around libsoup to provide data access using the
23 * Hyper Text Transfer Protocol. Each #GisHttp should be associated with a
24 * particular server or dataset, all the files downloaded for this dataset will
25 * be cached together in $HOME.cache/libgis/
30 #include <glib/gstdio.h>
31 #include <libsoup/soup.h>
37 * @prefix: The prefix in the cache to store the downloaded files.
38 * For example: * "/nexrad/level2/".
40 * Create a new #GisHttp for the given prefix
42 * Returns: the new #GisHttp
44 GisHttp *gis_http_new(const gchar *prefix)
46 g_debug("GisHttp: new - %s", prefix);
47 GisHttp *http = g_new0(GisHttp, 1);
48 http->soup = soup_session_sync_new();
49 http->prefix = g_strdup(prefix);
50 g_object_set(http->soup, "user-agent", PACKAGE_STRING, NULL);
56 * @http: the #GisHttp to free
58 * Frees resources used by @http and cancels any pending requests.
60 void gis_http_free(GisHttp *http)
62 g_debug("GisHttp: free - %s", http->prefix);
63 soup_session_abort(http->soup);
64 g_object_unref(http->soup);
69 /* For passing data to the chunck callback */
73 GisChunkCallback callback;
78 * Append data to the file and call the users callback if they supplied one.
80 static void _chunk_cb(SoupMessage *message, SoupBuffer *chunk, gpointer _info)
82 struct _CacheInfo *info = _info;
84 if (!SOUP_STATUS_IS_SUCCESSFUL(message->status_code)) {
85 g_warning("GisHttp: _chunk_cb - soup failed with %d",
86 message->status_code);
90 if (!fwrite(chunk->data, chunk->length, 1, info->fp))
91 g_error("GisHttp: _chunk_cb - Unable to write data");
94 goffset cur = ftell(info->fp);
95 goffset st=0, end=0, total=0;
96 soup_message_headers_get_content_range(message->response_headers,
98 info->callback(info->path, cur, total, info->user_data);
104 * @http: the #GisHttp connection to use
105 * @uri: the URI to fetch
106 * @local: the local name to give to the file
107 * @mode: the update type to use when fetching data
108 * @callback: callback to call when a chunk of data is received
109 * @user_data: user data to pass to the callback
111 * Fetch a file from the cache. Whether the file is actually loaded from the
112 * remote server depends on the value of @mode.
114 * Returns: The local path to the complete file
116 /* TODO: use .part extentions and continue even when using GIS_ONCE */
117 gchar *gis_http_fetch(GisHttp *http, const gchar *uri, const char *local,
118 GisCacheType mode, GisChunkCallback callback, gpointer user_data)
120 g_debug("GisHttp: fetch - %.20s... >> %s/%s mode=%d",
121 uri, http->prefix, local, mode);
123 gchar *path = g_build_filename(g_get_user_cache_dir(), PACKAGE,
124 http->prefix, local, NULL);
126 /* Unlink the file if we're refreshing it */
127 if (mode == GIS_REFRESH)
130 /* Do the cache if necessasairy */
131 if (!(mode == GIS_ONCE && g_file_test(path, G_FILE_TEST_EXISTS)) &&
133 g_debug("GisHttp: do_cache - Caching file %s", local);
135 /* Open the file for writting */
136 FILE *fp = fopen_p(path, "a");
139 struct _CacheInfo info = {
142 .callback = callback,
143 .user_data = user_data,
146 /* Download the file */
147 SoupMessage *message = soup_message_new("GET", uri);
149 g_error("message is null, cannot parse uri");
150 g_signal_connect(message, "got-chunk", G_CALLBACK(_chunk_cb), &info);
151 soup_message_headers_set_range(message->request_headers, ftell(fp), -1);
152 soup_session_send_message(http->soup, message);
155 if (message->status_code == 416) {
156 /* Range unsatisfiable, file already complete */
157 } else if (!SOUP_STATUS_IS_SUCCESSFUL(message->status_code))
158 g_warning("GisHttp: done_cb - error copying file, status=%d\n"
161 message->status_code, uri, path);
164 /* TODO: free everything.. */