barbieri pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=3cf20ea8e8b9ddcca73578a59442da1c8bf546c5
commit 3cf20ea8e8b9ddcca73578a59442da1c8bf546c5 Author: Gustavo Sverzut Barbieri <[email protected]> Date: Tue Nov 29 01:19:40 2016 -0200 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. --- src/lib/ecore_con/ecore_con_url_curl.c | 1 + src/lib/ecore_con/ecore_con_url_curl.h | 5 ++ src/lib/ecore_con/efl_net_dialer_http.c | 103 +++++++++++++++++++++++++++++++ src/lib/ecore_con/efl_net_dialer_http.eo | 23 +++++++ 4 files changed, 132 insertions(+) diff --git a/src/lib/ecore_con/ecore_con_url_curl.c b/src/lib/ecore_con/ecore_con_url_curl.c index c6ef501..507dd61 100644 --- a/src/lib/ecore_con/ecore_con_url_curl.c +++ b/src/lib/ecore_con/ecore_con_url_curl.c @@ -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(); diff --git a/src/lib/ecore_con/ecore_con_url_curl.h b/src/lib/ecore_con/ecore_con_url_curl.h index 9f82230..094c286 100644 --- a/src/lib/ecore_con/ecore_con_url_curl.h +++ b/src/lib/ecore_con/ecore_con_url_curl.h @@ -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 diff --git a/src/lib/ecore_con/efl_net_dialer_http.c b/src/lib/ecore_con/efl_net_dialer_http.c index 97b6e5b..cf6c4a9 100644 --- a/src/lib/ecore_con/efl_net_dialer_http.c +++ b/src/lib/ecore_con/efl_net_dialer_http.c @@ -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) { diff --git a/src/lib/ecore_con/efl_net_dialer_http.eo b/src/lib/ecore_con/efl_net_dialer_http.eo index f3c331a..5c41d78 100644 --- a/src/lib/ecore_con/efl_net_dialer_http.eo +++ b/src/lib/ecore_con/efl_net_dialer_http.eo @@ -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 { --
