00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00031 #include "stdinc.h"
00032
00033 #include <curl/curl.h>
00034 #include <curl/easy.h>
00035 #include <curl/multi.h>
00036
00037 #include "gui.h"
00038 #include "vfs.h"
00039 #include "vfs_modules.h"
00040
00044 struct httpstream {
00048 char *url;
00052 CURL *con;
00056 CURLM *conm;
00057
00061 char *bufptr;
00065 char *buflen;
00069 char buf[CURL_MAX_WRITE_SIZE];
00070 };
00071
00076 static size_t
00077 vfs_http_incoming(void *ptr, size_t size, size_t nmemb, void *cookie)
00078 {
00079 struct httpstream *hs = cookie;
00080 size_t len;
00081
00082
00083 len = size * nmemb;
00084 memcpy(hs->buf, ptr, size * nmemb);
00085 hs->bufptr = hs->buf;
00086 hs->buflen = hs->buf + len;
00087
00088 return (len);
00089 }
00090
00094 #ifdef __GLIBC__
00095 static ssize_t
00096 vfs_http_readfn(void *cookie, char *buf, size_t len)
00097 #else
00098 static int
00099 vfs_http_readfn(void *cookie, char *buf, int len)
00100 #endif
00101 {
00102 struct httpstream *hs = cookie;
00103 struct timeval timeout = { 5, 0 };
00104 char *errmsg;
00105 int handles, left = len, copylen, maxfd, sret;
00106 fd_set rfds, wfds, efds;
00107 CURLMcode cret;
00108
00109 while (left > 0) {
00110 if (hs->bufptr == hs->buflen) {
00111 FD_ZERO(&rfds);
00112 FD_ZERO(&wfds);
00113 FD_ZERO(&efds);
00114 curl_multi_fdset(hs->conm, &rfds, &wfds, &efds,
00115 &maxfd);
00116 if (maxfd != -1) {
00117
00118 sret = select(maxfd + 1, &rfds, &wfds,
00119 &efds, &timeout);
00120 if (sret <= 0)
00121 goto bad;
00122 }
00123
00124 cret = curl_multi_perform(hs->conm, &handles);
00125 if (handles == 0)
00126 goto bad;
00127 if (cret == CURLM_CALL_MULTI_PERFORM ||
00128 hs->bufptr == hs->buflen)
00129 continue;
00130 if (cret != CURLM_OK)
00131 goto bad;
00132 }
00133
00134
00135 copylen = MIN(left, hs->buflen - hs->bufptr);
00136 memcpy(buf, hs->bufptr, copylen);
00137 left -= copylen;
00138 hs->bufptr += copylen;
00139 buf += copylen;
00140 }
00141
00142 return (len);
00143
00144 bad:
00145 errmsg = g_strdup_printf(
00146 _("Connection with \"%s\" lost."), hs->url);
00147 gui_msgbar_warn(errmsg);
00148 g_free(errmsg);
00149 return (0);
00150 }
00151
00155 static int
00156 vfs_http_closefn(void *cookie)
00157 {
00158 struct httpstream *hs = cookie;
00159
00160 curl_multi_cleanup(hs->conm);
00161 curl_easy_cleanup(hs->con);
00162 g_free(hs->url);
00163 g_slice_free(struct httpstream, hs);
00164
00165 return (0);
00166 }
00167
00168
00169
00170
00171
00172 int
00173 vfs_http_match(struct vfsent *ve, int isdir)
00174 {
00175 return strncmp(ve->filename, "http://", 7);
00176 }
00177
00178 FILE *
00179 vfs_http_open(struct vfsent *ve)
00180 {
00181 struct httpstream *hs;
00182 FILE *ret;
00183 #ifdef __GLIBC__
00184 cookie_io_functions_t iofn = {
00185 vfs_http_readfn, NULL, NULL, vfs_http_closefn };
00186 #endif
00187
00188
00189 hs = g_slice_new(struct httpstream);
00190 hs->bufptr = hs->buflen = NULL;
00191
00192
00193 hs->con = curl_easy_init();
00194 hs->url = g_strdup(ve->filename);
00195 curl_easy_setopt(hs->con, CURLOPT_URL, hs->url);
00196 curl_easy_setopt(hs->con, CURLOPT_CONNECTTIMEOUT, 5);
00197 curl_easy_setopt(hs->con, CURLOPT_USERAGENT, APP_NAME "/" APP_VERSION);
00198
00199 curl_easy_setopt(hs->con, CURLOPT_WRITEFUNCTION, vfs_http_incoming);
00200 curl_easy_setopt(hs->con, CURLOPT_WRITEDATA, hs);
00201
00202 hs->conm = curl_multi_init();
00203 curl_multi_add_handle(hs->conm, hs->con);
00204
00205 #ifdef __GLIBC__
00206
00207 ret = fopencookie(hs, "rb", iofn);
00208 #else
00209
00210 ret = funopen(hs, vfs_http_readfn, NULL, NULL, vfs_http_closefn);
00211 #endif
00212 if (ret == NULL)
00213 vfs_http_closefn(hs);
00214
00215 return (ret);
00216 }