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
);
48 quvi_write_callback_default(void *p
, size_t size
, size_t nmemb
,
51 struct mem_s
*m
= (struct mem_s
*)data
;
52 const size_t rsize
= size
* nmemb
;
53 void *tmp
= _realloc(m
->p
, m
->size
+ rsize
+ 1);
57 memcpy(&(m
->p
[m
->size
]), p
, rsize
);
65 extern char *lua_get_field_s(lua_State
*, const char *);
68 fetch_to_mem(_quvi_media_t video
, const char *url
, lua_State
* l
,
71 char *fetch_type
, *arbitrary_cookie
, *user_agent
;
72 QUVIstatusType fetch_type_n
;
73 long respcode
, conncode
;
79 return (QUVI_BADHANDLE
);
87 arbitrary_cookie
= NULL
;
88 fetch_type_n
= QUVISTATUSTYPE_PAGE
; /* default */
90 /* Additional settings from LUA table */
92 if (lua_istable(l
, 2))
94 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 (video
->quvi
->status_func
)
109 status_func(makelong(QUVISTATUS_FETCH
, fetch_type_n
),
110 (void *)url
) != QUVI_OK
)
112 return (QUVI_ABORTEDBYCALLBACK
);
116 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_URL
, url
);
117 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_ENCODING
, "");
119 memset(&mem
, 0, sizeof(mem
));
120 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_WRITEDATA
, &mem
);
122 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_WRITEFUNCTION
,
123 video
->quvi
->write_func
124 ? (curl_write_callback
) video
->quvi
->write_func
125 : (curl_write_callback
) quvi_write_callback_default
);
127 if (arbitrary_cookie
!= NULL
&& *arbitrary_cookie
!= '\0')
129 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_COOKIE
,
133 if (user_agent
!= NULL
&& *user_agent
!= '\0')
135 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_USERAGENT
, user_agent
);
138 curlcode
= curl_easy_perform(video
->quvi
->curl
);
143 curl_easy_getinfo(video
->quvi
->curl
, CURLINFO_RESPONSE_CODE
,
145 curl_easy_getinfo(video
->quvi
->curl
, CURLINFO_HTTP_CONNECTCODE
,
148 if (curlcode
== CURLE_OK
&& respcode
== 200)
150 if (video
->quvi
->status_func
)
152 if (video
->quvi
->status_func(makelong(QUVISTATUS_FETCH
,
153 QUVISTATUSTYPE_DONE
),
156 rc
= QUVI_ABORTEDBYCALLBACK
;
162 if (curlcode
== CURLE_OK
)
164 freprintf(&video
->quvi
->errmsg
,
165 "server response code %ld (conncode=%ld)", respcode
,
170 freprintf(&video
->quvi
->errmsg
,
171 "%s (curlcode=%d, conncode=%ld)",
172 curl_easy_strerror(curlcode
), curlcode
, conncode
);
181 if (rc
== QUVI_OK
&& !video
->charset
) /* charset */
182 run_lua_charset_func(video
, mem
.p
);
185 video
->quvi
->httpcode
= respcode
;
186 video
->quvi
->curlcode
= curlcode
;
191 QUVIcode
query_file_length(_quvi_t quvi
, llst_node_t lnk
)
193 static const char *scheme
= "http://";
194 long respcode
, conncode
;
195 _quvi_video_link_t qvl
;
202 return (QUVI_BADHANDLE
);
205 return (QUVI_BADHANDLE
);
207 qvl
= (_quvi_video_link_t
) lnk
->data
;
211 return (QUVI_BADHANDLE
);
213 qvl
->url
= from_html_entities(qvl
->url
);
215 /* We can currently check HTTP URLs only */
216 memset(&buf
, 0, sizeof(buf
));
217 if (strcmp(strncpy(buf
, qvl
->url
, strlen(scheme
)), scheme
) != 0)
218 return (QUVI_OK
); /* Skip video URL verification discreetly. */
220 if (quvi
->status_func
)
222 if (quvi
->status_func(makelong(QUVISTATUS_VERIFY
, 0), 0) != QUVI_OK
)
224 return (QUVI_ABORTEDBYCALLBACK
);
228 curl_easy_setopt(quvi
->curl
, CURLOPT_URL
, qvl
->url
);
229 curl_easy_setopt(quvi
->curl
, CURLOPT_NOBODY
, 1L); /* get -> head */
231 memset(&mem
, 0, sizeof(mem
));
232 curl_easy_setopt(quvi
->curl
, CURLOPT_WRITEDATA
, &mem
);
234 curl_easy_setopt(quvi
->curl
, CURLOPT_WRITEFUNCTION
, (quvi
->write_func
)
235 ? (curl_write_callback
) quvi
->write_func
236 : (curl_write_callback
) quvi_write_callback_default
);
238 curlcode
= curl_easy_perform(quvi
->curl
);
240 curl_easy_setopt(quvi
->curl
, CURLOPT_HTTPGET
, 1L); /* reset: head -> get */
246 curl_easy_getinfo(quvi
->curl
, CURLINFO_RESPONSE_CODE
, &respcode
);
247 curl_easy_getinfo(quvi
->curl
, CURLINFO_HTTP_CONNECTCODE
, &conncode
);
249 if (curlcode
== CURLE_OK
)
251 if (respcode
== 200 || respcode
== 206)
255 curl_easy_getinfo(quvi
->curl
, CURLINFO_CONTENT_TYPE
, &ct
);
257 _free(qvl
->content_type
);
258 asprintf(&qvl
->content_type
, "%s", ct
);
260 curl_easy_getinfo(quvi
->curl
,
261 CURLINFO_CONTENT_LENGTH_DOWNLOAD
, &qvl
->length
);
263 if (quvi
->status_func
)
265 if (quvi
->status_func(makelong
266 (QUVISTATUS_VERIFY
, QUVISTATUSTYPE_DONE
),
269 rc
= QUVI_ABORTEDBYCALLBACK
;
275 /* Content-Type -> suffix. */
276 rc
= run_lua_suffix_func(quvi
, qvl
);
281 freprintf(&quvi
->errmsg
,
282 "server response code %ld (conncode=%ld)", respcode
,
289 freprintf(&quvi
->errmsg
, "%s (curlcode=%d, conncode=%ld)",
290 curl_easy_strerror(curlcode
), curlcode
, conncode
);
294 quvi
->httpcode
= respcode
;
295 quvi
->curlcode
= curlcode
;
304 * Check if URL is a shortened URL (e.g. dai.ly, goo.gl, etc.) and
305 * replace the (shortened) video page URL with the redirect URL.
307 QUVIcode
is_shortened_url(_quvi_media_t video
)
309 long respcode
, conncode
;
314 assert(video
!= NULL
);
316 if (video
->quvi
->status_func
)
318 if (video
->quvi
->status_func(QUVISTATUS_SHORTENED
, 0) != QUVI_OK
)
319 return (QUVI_ABORTEDBYCALLBACK
);
322 memset(&mem
, 0, sizeof(mem
));
323 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_WRITEDATA
, &mem
);
325 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_WRITEFUNCTION
,
326 (video
->quvi
->write_func
)
327 ? (curl_write_callback
) video
->quvi
->write_func
328 : (curl_write_callback
) quvi_write_callback_default
);
330 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_URL
, video
->page_link
);
331 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_FOLLOWLOCATION
, 0L);
332 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_NOBODY
, 1L); /* get -> head */
334 curlcode
= curl_easy_perform(video
->quvi
->curl
);
336 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_FOLLOWLOCATION
, 1L); /* reset */
338 curl_easy_setopt(video
->quvi
->curl
, CURLOPT_HTTPGET
, 1L); /* reset: head -> get */
344 curl_easy_getinfo(video
->quvi
->curl
, CURLINFO_RESPONSE_CODE
,
346 curl_easy_getinfo(video
->quvi
->curl
, CURLINFO_HTTP_CONNECTCODE
,
349 if (curlcode
== CURLE_OK
)
351 if (respcode
>= 301 && respcode
<= 303)
357 curl_easy_getinfo(video
->quvi
->curl
, CURLINFO_REDIRECT_URL
, &url
);
358 freprintf(&video
->page_link
, "%s", url
);
362 /* respcode >= 301 && respcode <= 303 */
365 /* Most likely not a shortened URL redirect. Let it pass. */
369 if (video
->quvi
->status_func
)
372 makelong(QUVISTATUS_SHORTENED
, QUVISTATUSTYPE_DONE
);
374 rc
= video
->quvi
->status_func(param
, 0);
379 freprintf(&video
->quvi
->errmsg
, "%s (curlcode=%d, conncode=%ld)",
380 curl_easy_strerror(curlcode
), curlcode
, conncode
);
388 video
->quvi
->httpcode
= respcode
;
389 video
->quvi
->curlcode
= curlcode
;
394 /* vim: set ts=2 sw=2 tw=72 expandtab: */