Fix whitespace inconsistencies.
[herrie-working.git] / herrie / src / vfs_http.c
blob856dbc8b4654d38b7e0e21a73998a4338fa0a167
1 /*
2 * Copyright (c) 2006-2011 Ed Schouten <ed@80386.nl>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 /**
27 * @file vfs_http.c
28 * @brief HTTP file access.
31 #include "stdinc.h"
33 #include <curl/curl.h>
34 #include <curl/easy.h>
35 #include <curl/multi.h>
37 #include "gui.h"
38 #include "vfs.h"
39 #include "vfs_modules.h"
41 /**
42 * @brief Datastructure with HTTP stream buffer.
44 struct httpstream {
45 /**
46 * @brief URL of current connection.
48 char *url;
49 /**
50 * @brief CURL 'easy' connection.
52 CURL *con;
53 /**
54 * @brief CURL 'multi' connection.
56 CURLM *conm;
58 /**
59 * @brief Pointer to current read position in the buffer.
61 char *bufptr;
62 /**
63 * @brief Pointer to where the buffer's contents end.
65 char *buflen;
66 /**
67 * @brief Temporary buffer to store fetched data.
69 char buf[CURL_MAX_WRITE_SIZE];
72 /**
73 * @brief Callback function that copies packet contents to httpstream
74 * structure.
76 static size_t
77 vfs_http_incoming(void *ptr, size_t size, size_t nmemb, void *cookie)
79 struct httpstream *hs = cookie;
80 size_t len;
82 /* We just assume the buffer is completely drained */
83 len = size * nmemb;
84 memcpy(hs->buf, ptr, size * nmemb);
85 hs->bufptr = hs->buf;
86 hs->buflen = hs->buf + len;
88 return (len);
91 /**
92 * @brief fread() routine for HTTP streams.
94 #ifdef __GLIBC__
95 static ssize_t
96 vfs_http_readfn(void *cookie, char *buf, size_t len)
97 #else /* !__GLIBC__ */
98 static int
99 vfs_http_readfn(void *cookie, char *buf, int len)
100 #endif /* __GLIBC__ */
102 struct httpstream *hs = cookie;
103 struct timeval timeout = { 5, 0 };
104 char *errmsg;
105 int handles, left = len, copylen, maxfd, sret;
106 fd_set rfds, wfds, efds;
107 CURLMcode cret;
109 while (left > 0) {
110 if (hs->bufptr == hs->buflen) {
111 FD_ZERO(&rfds);
112 FD_ZERO(&wfds);
113 FD_ZERO(&efds);
114 curl_multi_fdset(hs->conm, &rfds, &wfds, &efds,
115 &maxfd);
116 if (maxfd != -1) {
117 /* Wait for data to arrive */
118 sret = select(maxfd + 1, &rfds, &wfds,
119 &efds, &timeout);
120 if (sret <= 0)
121 goto bad;
123 /* Fetch data from socket */
124 cret = curl_multi_perform(hs->conm, &handles);
125 if (handles == 0)
126 goto bad;
127 if (cret == CURLM_CALL_MULTI_PERFORM ||
128 hs->bufptr == hs->buflen)
129 continue;
130 if (cret != CURLM_OK)
131 goto bad;
134 /* Perform a copyout of the buffer */
135 copylen = MIN(left, hs->buflen - hs->bufptr);
136 memcpy(buf, hs->bufptr, copylen);
137 left -= copylen;
138 hs->bufptr += copylen;
139 buf += copylen;
142 return (len);
144 bad: /* Bail out with an error message */
145 errmsg = g_strdup_printf(
146 _("Connection with \"%s\" lost."), hs->url);
147 gui_msgbar_warn(errmsg);
148 g_free(errmsg);
149 return (0);
153 * @brief fclose() routine for HTTP streams.
155 static int
156 vfs_http_closefn(void *cookie)
158 struct httpstream *hs = cookie;
160 curl_multi_cleanup(hs->conm);
161 curl_easy_cleanup(hs->con);
162 g_free(hs->url);
163 g_slice_free(struct httpstream, hs);
165 return (0);
169 * Public interface
173 vfs_http_match(struct vfsent *ve, int isdir)
175 return strncmp(ve->filename, "http://", 7);
178 FILE *
179 vfs_http_open(struct vfsent *ve)
181 struct httpstream *hs;
182 FILE *ret;
183 #ifdef __GLIBC__
184 cookie_io_functions_t iofn = {
185 vfs_http_readfn, NULL, NULL, vfs_http_closefn };
186 #endif /* __GLIBC__ */
188 /* Allocate the datastructure */
189 hs = g_slice_new(struct httpstream);
190 hs->bufptr = hs->buflen = NULL;
192 /* Curl connection */
193 hs->con = curl_easy_init();
194 hs->url = g_strdup(ve->filename);
195 curl_easy_setopt(hs->con, CURLOPT_URL, hs->url);
196 curl_easy_setopt(hs->con, CURLOPT_CONNECTTIMEOUT, 5);
197 curl_easy_setopt(hs->con, CURLOPT_USERAGENT, APP_NAME "/" APP_VERSION);
199 curl_easy_setopt(hs->con, CURLOPT_WRITEFUNCTION, vfs_http_incoming);
200 curl_easy_setopt(hs->con, CURLOPT_WRITEDATA, hs);
202 hs->conm = curl_multi_init();
203 curl_multi_add_handle(hs->conm, hs->con);
205 #ifdef __GLIBC__
206 /* glibc systems should have fopencookie() */
207 ret = fopencookie(hs, "rb", iofn);
208 #else /* !__GLIBC__ */
209 /* BSD's */
210 ret = funopen(hs, vfs_http_readfn, NULL, NULL, vfs_http_closefn);
211 #endif /* __GLIBC__ */
212 if (ret == NULL)
213 vfs_http_closefn(hs);
215 return (ret);