2 * Copyright (C) 2009,2010 Toni Gundogdu <legatvs@gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 #include <curl/curl.h>
28 #include "quvi/quvi.h"
32 #include "curl_wrap.h"
34 static void *_realloc(void *p
, const size_t size
)
37 return realloc(p
, size
);
47 quvi_write_callback_default(void *p
, size_t size
, size_t nmemb
, void *data
)
49 struct mem_s
*m
= (struct mem_s
*)data
;
50 const size_t rsize
= size
* nmemb
;
51 void *tmp
= _realloc(m
->p
, m
->size
+ rsize
+ 1);
54 memcpy(&(m
->p
[m
->size
]), p
, rsize
);
62 extern char *lua_get_field_s(lua_State
*, const char *);
65 fetch_to_mem(_quvi_video_t video
, const char *url
, lua_State
* l
, char **dst
)
67 char *fetch_type
, *arbitrary_cookie
, *user_agent
;
68 QUVIstatusType fetch_type_n
;
69 long respcode
, conncode
;
76 return (QUVI_BADHANDLE
);
81 return (QUVI_BADHANDLE
);
89 arbitrary_cookie
= NULL
;
90 fetch_type_n
= QUVISTATUSTYPE_PAGE
; /* default */
92 /* Additional settings from LUA table */
94 if (lua_istable(l
, 2)) {
95 fetch_type
= lua_get_field_s(l
, "fetch_type");
97 if (strcmp(fetch_type
, "config") == 0)
98 fetch_type_n
= QUVISTATUSTYPE_CONFIG
;
99 else if (strcmp(fetch_type
, "playlist") == 0)
100 fetch_type_n
= QUVISTATUSTYPE_PLAYLIST
;
102 arbitrary_cookie
= lua_get_field_s(l
, "arbitrary_cookie");
103 user_agent
= lua_get_field_s(l
, "user_agent");
106 if (quvi
->status_func
) {
107 if (quvi
->status_func(makelong(QUVISTATUS_FETCH
, fetch_type_n
),
108 (void *)url
) != QUVI_OK
) {
109 return (QUVI_ABORTEDBYCALLBACK
);
113 csetopt(CURLOPT_URL
, url
);
114 csetopt(CURLOPT_ENCODING
, "");
116 memset(&mem
, 0, sizeof(mem
));
118 csetopt(CURLOPT_WRITEDATA
, &mem
);
120 if (quvi
->write_func
)
121 csetopt(CURLOPT_WRITEFUNCTION
, (curl_write_callback
) quvi
->write_func
);
123 csetopt(CURLOPT_WRITEFUNCTION
, quvi_write_callback_default
);
125 if (arbitrary_cookie
!= NULL
&& *arbitrary_cookie
!= '\0')
126 csetopt(CURLOPT_COOKIE
, arbitrary_cookie
);
128 if (user_agent
!= NULL
&& *user_agent
!= '\0')
129 csetopt(CURLOPT_USERAGENT
, user_agent
);
131 curlcode
= curl_easy_perform(quvi
->curl
);
136 curl_easy_getinfo(quvi
->curl
, CURLINFO_RESPONSE_CODE
, &respcode
);
138 curl_easy_getinfo(quvi
->curl
, CURLINFO_HTTP_CONNECTCODE
, &conncode
);
140 if (curlcode
== CURLE_OK
&& respcode
== 200) {
142 if (quvi
->status_func
) {
144 if (quvi
->status_func(makelong(QUVISTATUS_FETCH
, QUVISTATUSTYPE_DONE
),
146 rc
= QUVI_ABORTEDBYCALLBACK
;
155 if (curlcode
== CURLE_OK
) {
156 seterr("server response code %ld (conncode=%ld)", respcode
, conncode
);
160 seterr("%s (curlcode=%d, conncode=%ld)",
161 curl_easy_strerror(curlcode
), curlcode
, conncode
);
169 if (rc
== QUVI_OK
&& !video
->charset
) /* charset */
170 run_lua_charset_func(video
, mem
.p
);
173 video
->quvi
->httpcode
= respcode
;
174 video
->quvi
->curlcode
= curlcode
;
179 QUVIcode
query_file_length(_quvi_t quvi
, llst_node_t lnk
)
181 long respcode
, conncode
;
182 _quvi_video_link_t qvl
;
188 return (QUVI_BADHANDLE
);
191 return (QUVI_BADHANDLE
);
193 qvl
= (_quvi_video_link_t
) lnk
->data
;
197 return (QUVI_BADHANDLE
);
199 if (quvi
->status_func
) {
200 if (quvi
->status_func(makelong(QUVISTATUS_VERIFY
, 0), 0) != QUVI_OK
) {
201 return (QUVI_ABORTEDBYCALLBACK
);
205 memset(&mem
, 0, sizeof(mem
));
207 csetopt(CURLOPT_WRITEDATA
, &mem
);
209 if (quvi
->write_func
)
210 csetopt(CURLOPT_WRITEFUNCTION
, (curl_write_callback
) quvi
->write_func
);
212 csetopt(CURLOPT_WRITEFUNCTION
, quvi_write_callback_default
);
214 qvl
->url
= from_html_entities(qvl
->url
);
216 csetopt(CURLOPT_URL
, qvl
->url
);
217 csetopt(CURLOPT_NOBODY
, 1L); /* get -> head */
219 curlcode
= curl_easy_perform(quvi
->curl
);
221 csetopt(CURLOPT_HTTPGET
, 1L); /* reset: head -> get */
227 curl_easy_getinfo(quvi
->curl
, CURLINFO_RESPONSE_CODE
, &respcode
);
229 curl_easy_getinfo(quvi
->curl
, CURLINFO_HTTP_CONNECTCODE
, &conncode
);
231 if (curlcode
== CURLE_OK
) {
233 if (respcode
== 200 || respcode
== 206) {
237 curl_easy_getinfo(quvi
->curl
, CURLINFO_CONTENT_TYPE
, &ct
);
239 _free(qvl
->content_type
);
240 asprintf(&qvl
->content_type
, "%s", ct
);
242 curl_easy_getinfo(quvi
->curl
,
243 CURLINFO_CONTENT_LENGTH_DOWNLOAD
, &qvl
->length
);
245 if (quvi
->status_func
) {
246 if (quvi
->status_func(makelong(QUVISTATUS_VERIFY
, QUVISTATUSTYPE_DONE
),
248 rc
= QUVI_ABORTEDBYCALLBACK
;
253 /* Content-Type -> suffix. */
254 rc
= run_lua_suffix_func(quvi
, qvl
);
257 seterr("server response code %ld (conncode=%ld)", respcode
, conncode
);
261 seterr("%s (curlcode=%d, conncode=%ld)",
262 curl_easy_strerror(curlcode
), curlcode
, conncode
);
266 quvi
->httpcode
= respcode
;
267 quvi
->curlcode
= curlcode
;
276 * Check if URL is a shortened URL (e.g. dai.ly, goo.gl, etc.) and
277 * replace the (shortened) video page URL with the redirect URL.
279 QUVIcode
is_shortened_url(_quvi_video_t video
)
281 long respcode
, conncode
;
287 assert(video
!= NULL
);
289 assert(quvi
!= NULL
);
291 if (quvi
->status_func
) {
293 const QUVIcode r
= quvi
->status_func(makelong(QUVISTATUS_SHORTENED
, 0), 0);
296 return (QUVI_ABORTEDBYCALLBACK
);
300 memset(&mem
, 0, sizeof(mem
));
302 csetopt(CURLOPT_WRITEDATA
, &mem
);
304 if (quvi
->write_func
)
305 csetopt(CURLOPT_WRITEFUNCTION
, (curl_write_callback
) quvi
->write_func
);
307 csetopt(CURLOPT_WRITEFUNCTION
, quvi_write_callback_default
);
309 csetopt(CURLOPT_URL
, video
->page_link
);
310 csetopt(CURLOPT_FOLLOWLOCATION
, 0L);
311 csetopt(CURLOPT_NOBODY
, 1L); /* get -> head */
313 curlcode
= curl_easy_perform(quvi
->curl
);
315 csetopt(CURLOPT_FOLLOWLOCATION
, 1L); /* reset */
316 csetopt(CURLOPT_HTTPGET
, 1L); /* reset: head -> get */
322 curl_easy_getinfo(quvi
->curl
, CURLINFO_RESPONSE_CODE
, &respcode
);
323 curl_easy_getinfo(quvi
->curl
, CURLINFO_HTTP_CONNECTCODE
, &conncode
);
325 if (curlcode
== CURLE_OK
) {
327 if (respcode
>= 301 && respcode
<= 303) {
333 curl_easy_getinfo(quvi
->curl
, CURLINFO_REDIRECT_URL
, &url
);
334 setvid(video
->page_link
, "%s", url
);
339 /* respcode >= 301 && respcode <= 303 */
341 /* Most likely not a shortened URL redirect. Let it pass. */
345 if (quvi
->status_func
) {
347 rc
= quvi
->status_func(makelong
348 (QUVISTATUS_SHORTENED
, QUVISTATUSTYPE_DONE
), 0);
354 seterr("%s (curlcode=%d, conncode=%ld)",
355 curl_easy_strerror(curlcode
), curlcode
, conncode
);
363 quvi
->httpcode
= respcode
;
364 quvi
->curlcode
= curlcode
;