2 * Copyright (c) 2006-2011 Ed Schouten <ed@80386.nl>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
28 * @brief HTTP file access.
33 #include <curl/curl.h>
34 #include <curl/easy.h>
35 #include <curl/multi.h>
39 #include "vfs_modules.h"
42 * @brief Datastructure with HTTP stream buffer.
46 * @brief URL of current connection.
50 * @brief CURL 'easy' connection.
54 * @brief CURL 'multi' connection.
59 * @brief Pointer to current read position in the buffer.
63 * @brief Pointer to where the buffer's contents end.
67 * @brief Temporary buffer to store fetched data.
69 char buf
[CURL_MAX_WRITE_SIZE
];
73 * @brief Callback function that copies packet contents to httpstream
77 vfs_http_incoming(void *ptr
, size_t size
, size_t nmemb
, void *cookie
)
79 struct httpstream
*hs
= cookie
;
82 /* We just assume the buffer is completely drained */
84 memcpy(hs
->buf
, ptr
, size
* nmemb
);
86 hs
->buflen
= hs
->buf
+ len
;
92 * @brief fread() routine for HTTP streams.
96 vfs_http_readfn(void *cookie
, char *buf
, size_t len
)
97 #else /* !__GLIBC__ */
99 vfs_http_readfn(void *cookie
, char *buf
, int len
)
100 #endif /* __GLIBC__ */
102 struct httpstream
*hs
= cookie
;
103 struct timeval timeout
= { 5, 0 };
105 int handles
, left
= len
, copylen
, maxfd
, sret
;
106 fd_set rfds
, wfds
, efds
;
110 if (hs
->bufptr
== hs
->buflen
) {
114 curl_multi_fdset(hs
->conm
, &rfds
, &wfds
, &efds
,
117 /* Wait for data to arrive */
118 sret
= select(maxfd
+ 1, &rfds
, &wfds
,
123 /* Fetch data from socket */
124 cret
= curl_multi_perform(hs
->conm
, &handles
);
127 if (cret
== CURLM_CALL_MULTI_PERFORM
||
128 hs
->bufptr
== hs
->buflen
)
130 if (cret
!= CURLM_OK
)
134 /* Perform a copyout of the buffer */
135 copylen
= MIN(left
, hs
->buflen
- hs
->bufptr
);
136 memcpy(buf
, hs
->bufptr
, copylen
);
138 hs
->bufptr
+= copylen
;
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
);
153 * @brief fclose() routine for HTTP streams.
156 vfs_http_closefn(void *cookie
)
158 struct httpstream
*hs
= cookie
;
160 curl_multi_cleanup(hs
->conm
);
161 curl_easy_cleanup(hs
->con
);
163 g_slice_free(struct httpstream
, hs
);
173 vfs_http_match(struct vfsent
*ve
, int isdir
)
175 return strncmp(ve
->filename
, "http://", 7);
179 vfs_http_open(struct vfsent
*ve
)
181 struct httpstream
*hs
;
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
);
206 /* glibc systems should have fopencookie() */
207 ret
= fopencookie(hs
, "rb", iofn
);
208 #else /* !__GLIBC__ */
210 ret
= funopen(hs
, vfs_http_readfn
, NULL
, NULL
, vfs_http_closefn
);
211 #endif /* __GLIBC__ */
213 vfs_http_closefn(hs
);