efl_net_dialer_http: special headers and date parse/serialize.

CURL needs some special curl_easy_setopt() calls to enable automatic
gzip deflate (CURLOPT_ENCODING) and
If-Modified-Since/If-Unmodified-Since logic.

As If-Modified-Since/If-Unmodified-Since requires a timestamp string,
let's expose class methods to handle those.
This commit is contained in:
Gustavo Sverzut Barbieri 2016-11-29 01:19:40 -02:00
parent 5c7b984746
commit 3cf20ea8e8
4 changed files with 132 additions and 0 deletions

View File

@ -312,6 +312,7 @@ _c_init(void)
SYM(curl_slist_free_all);
SYM(curl_slist_append);
SYM(curl_version_info);
SYM(curl_getdate);
_c_init_errors();

View File

@ -446,6 +446,7 @@ struct _Ecore_Con_Curl
void (*curl_slist_free_all)(struct curl_slist *);
struct curl_slist *(*curl_slist_append)(struct curl_slist *list,
const char *string);
time_t (*curl_getdate)(const char *p, const time_t *unused);
curl_version_info_data *(*curl_version_info)(CURLversion);
};
@ -460,4 +461,8 @@ void _c_shutdown(void);
Eina_Error _curlcode_to_eina_error(const CURLcode code);
Eina_Error _curlmcode_to_eina_error(const CURLMcode code);
/* only for legacy support to implement behavior that we're not exposing anymore */
CURL *efl_net_dialer_http_curl_get(const Eo *o);
#endif

View File

@ -29,6 +29,7 @@
#define curl_easy_init(...) _c->curl_easy_init(__VA_ARGS__)
#define curl_easy_cleanup(...) _c->curl_easy_cleanup(__VA_ARGS__)
#define curl_easy_pause(...) _c->curl_easy_pause(__VA_ARGS__)
#define curl_getdate(s, unused) _c->curl_getdate(s, unused)
#ifdef curl_easy_setopt
#undef curl_easy_setopt
@ -1260,6 +1261,7 @@ _efl_net_dialer_http_libproxy_cancel(void *data, Ecore_Thread *thread EINA_UNUSE
EOLIAN static Eina_Error
_efl_net_dialer_http_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Http_Data *pd, const char *address)
{
struct curl_slist *sl_it;
CURLcode r;
EINA_SAFETY_ON_NULL_RETURN_VAL(address, EINVAL);
@ -1279,6 +1281,77 @@ _efl_net_dialer_http_efl_net_dialer_dial(Eo *o, Efl_Net_Dialer_Http_Data *pd, co
o, curl_easy_strerror(r));
return EINVAL;
}
for (sl_it = pd->request.headers; sl_it != NULL; sl_it = sl_it->next)
{
#define IS_HEADER(x) (strncasecmp(sl_it->data, x ":", strlen(x ":")) == 0)
if (IS_HEADER("Accept-Encoding"))
{
const char *value = strchr(sl_it->data, ':') + 1;
while (*value && isspace(*value))
value++;
r = curl_easy_setopt(pd->easy, CURLOPT_ENCODING, value);
if (r != CURLE_OK)
{
ERR("dialer=%p could not set HTTP Accept-Encoding '%s': %s",
o, value, curl_easy_strerror(r));
return EINVAL;
}
DBG("Using Accept-Encoding: %s", value);
}
else if (IS_HEADER("If-Modified-Since"))
{
const char *value = strchr(sl_it->data, ':') + 1;
long t;
r = curl_easy_setopt(pd->easy, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
if (r != CURLE_OK)
{
ERR("dialer=%p could not set HTTP If-Modified-Since condition: %s",
o, curl_easy_strerror(r));
return EINVAL;
}
while (*value && isspace(*value))
value++;
t = curl_getdate(value, NULL);
r = curl_easy_setopt(pd->easy, CURLOPT_TIMEVALUE, t);
if (r != CURLE_OK)
{
ERR("dialer=%p could not set HTTP If-Modified-Since value=%ld: %s",
o, t, curl_easy_strerror(r));
return EINVAL;
}
DBG("Using If-Modified-Since: %s [t=%ld]", value, t);
}
else if (IS_HEADER("If-Unmodified-Since"))
{
const char *value = strchr(sl_it->data, ':') + 1;
long t;
r = curl_easy_setopt(pd->easy, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFUNMODSINCE);
if (r != CURLE_OK)
{
ERR("dialer=%p could not set HTTP If-Unmodified-Since condition: %s",
o, curl_easy_strerror(r));
return EINVAL;
}
while (*value && isspace(*value))
value++;
t = curl_getdate(value, NULL);
r = curl_easy_setopt(pd->easy, CURLOPT_TIMEVALUE, t);
if (r != CURLE_OK)
{
ERR("dialer=%p could not set HTTP If-Unmodified-Since value=%ld: %s",
o, t, curl_easy_strerror(r));
return EINVAL;
}
DBG("Using If-Unmodified-Since: %s [t=%ld]", value, t);
}
#undef IS_HEADER
}
if ((!pd->proxy) && (ecore_con_libproxy_init()))
{
@ -2192,6 +2265,36 @@ _efl_net_dialer_http_cookie_jar_get(Eo *o EINA_UNUSED, Efl_Net_Dialer_Http_Data
return pd->cookie_jar;
}
EOLIAN static long
_efl_net_dialer_http_date_parse(Efl_Class *cls EINA_UNUSED, void *cd EINA_UNUSED, const char *str)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(str, 0);
return curl_getdate(str, NULL);
}
EOLIAN static char *
_efl_net_dialer_http_date_serialize(Efl_Class *cls EINA_UNUSED, void *cd EINA_UNUSED, long t)
{
static const char *const wkday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const char * const month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
char buf[128];
struct tm *tm, storage;
tm = gmtime_r(&t, &storage);
EINA_SAFETY_ON_NULL_RETURN_VAL(tm, NULL);
snprintf(buf, sizeof(buf),
"%s, %02d %s %4d %02d:%02d:%02d GMT",
wkday[tm->tm_wday],
tm->tm_mday,
month[tm->tm_mon],
tm->tm_year + 1900,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
return strdup(buf);
}
CURL *
efl_net_dialer_http_curl_get(const Eo *o)
{

View File

@ -334,6 +334,29 @@ class Efl.Net.Dialer.Http (Efl.Loop_User, Efl.Net.Dialer, Efl.Io.Sizer) {
path: string; [[Path to cookie jar]]
}
}
date_parse @class {
[[Parse the given string as time in seconds since 1/1/1970.
This method is useful to parse header values such as
"Last-Modified".
]]
params {
str: string; [[String in HTTP text format: Tue, 15 Nov 1994 12:45:26 GMT]]
}
return: long; [[Seconds since 1/1/1970]]
}
date_serialize @class {
[[Serialize the given GMT time in seconds since 1/1/1970.
The timezone must be GMT (ie: gmtime()).
]]
params {
epochtime: long; [[UNIX Epoch time - seconds since 1/1/1970]]
}
return: free(own(ptr(char)), free) @warn_unused; [[Newly allocated null-terminated string on success or NULL on errors]]
}
}
events {