You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.6 KiB
147 lines
3.6 KiB
#include "curl-common.h"
|
|
|
|
CURL* get_handle(SEXP ptr){
|
|
return get_ref(ptr)->handle;
|
|
}
|
|
|
|
reference* get_ref(SEXP ptr){
|
|
if(TYPEOF(ptr) != EXTPTRSXP || !Rf_inherits(ptr, "curl_handle"))
|
|
Rf_error("handle is not a curl_handle()");
|
|
if(!R_ExternalPtrAddr(ptr))
|
|
error("handle is dead");
|
|
reference *ref = (reference*) R_ExternalPtrAddr(ptr);
|
|
return ref;
|
|
}
|
|
|
|
void set_form(reference *ref, struct curl_httppost* newform){
|
|
if(ref->form)
|
|
curl_formfree(ref->form);
|
|
ref->form = newform;
|
|
if(newform){
|
|
assert(curl_easy_setopt(ref->handle, CURLOPT_HTTPPOST, ref->form));
|
|
} else {
|
|
//CURLOPT_HTTPPOST has bug for empty forms. We probably want this:
|
|
assert(curl_easy_setopt(ref->handle, CURLOPT_POSTFIELDS, ""));
|
|
}
|
|
}
|
|
|
|
void reset_resheaders(reference *ref){
|
|
if(ref->resheaders.buf)
|
|
free(ref->resheaders.buf);
|
|
ref->resheaders.buf = NULL;
|
|
ref->resheaders.size = 0;
|
|
}
|
|
|
|
void reset_errbuf(reference *ref){
|
|
memset(ref->errbuf, 0, CURL_ERROR_SIZE);
|
|
}
|
|
|
|
void assert(CURLcode res){
|
|
if(res != CURLE_OK)
|
|
error(curl_easy_strerror(res));
|
|
}
|
|
|
|
void assert_status(CURLcode res, reference *ref){
|
|
if(res == CURLE_OPERATION_TIMEDOUT)
|
|
Rf_error("%s: %s", curl_easy_strerror(res), ref->errbuf);
|
|
if(res != CURLE_OK)
|
|
Rf_error("%s", strlen(ref->errbuf) ? ref->errbuf : curl_easy_strerror(res));
|
|
}
|
|
|
|
void massert(CURLMcode res){
|
|
if(res != CURLM_OK)
|
|
error(curl_multi_strerror(res));
|
|
}
|
|
|
|
void stop_for_status(CURL *http_handle){
|
|
long status = 0;
|
|
assert(curl_easy_getinfo(http_handle, CURLINFO_RESPONSE_CODE, &status));
|
|
|
|
/* check http status code. Not sure what this does for ftp. */
|
|
if(status >= 300)
|
|
error("HTTP error %d.", status);
|
|
}
|
|
|
|
/* make sure to call curl_slist_free_all on this object */
|
|
struct curl_slist* vec_to_slist(SEXP vec){
|
|
if(!isString(vec))
|
|
error("vec is not a character vector");
|
|
struct curl_slist *slist = NULL;
|
|
for(int i = 0; i < length(vec); i++){
|
|
slist = curl_slist_append(slist, CHAR(STRING_ELT(vec, i)));
|
|
}
|
|
return slist;
|
|
}
|
|
|
|
SEXP slist_to_vec(struct curl_slist *slist){
|
|
/* linked list of strings */
|
|
struct curl_slist *cursor = slist;
|
|
|
|
/* count slist */
|
|
int n = 0;
|
|
while (cursor) {
|
|
n++;
|
|
cursor = cursor->next;
|
|
}
|
|
|
|
SEXP out = PROTECT(allocVector(STRSXP, n));
|
|
cursor = slist;
|
|
for(int i = 0; i < n; i++){
|
|
SET_STRING_ELT(out, i, mkChar(cursor->data));
|
|
cursor = cursor->next;
|
|
}
|
|
UNPROTECT(1);
|
|
return out;
|
|
}
|
|
|
|
size_t push_disk(void* contents, size_t sz, size_t nmemb, FILE *ctx) {
|
|
//if (pending_interrupt())
|
|
// return 0;
|
|
return fwrite(contents, sz, nmemb, ctx);
|
|
}
|
|
|
|
static size_t round_up(size_t v){
|
|
if(v == 0)
|
|
return 0;
|
|
v--;
|
|
v |= v >> 1;
|
|
v |= v >> 2;
|
|
v |= v >> 4;
|
|
v |= v >> 8;
|
|
v |= v >> 16;
|
|
if (sizeof(size_t) == 8)
|
|
v |= v >> 32;
|
|
return ++v;
|
|
}
|
|
|
|
size_t append_buffer(void *contents, size_t sz, size_t nmemb, void *ctx) {
|
|
//if (pending_interrupt())
|
|
// return 0;
|
|
|
|
/* avoids compiler warning on windows */
|
|
size_t realsize = sz * nmemb;
|
|
memory *mem = (memory*) ctx;
|
|
|
|
/* realloc can be slow, therefore increase buffer to nearest 2^n */
|
|
mem->buf = realloc(mem->buf, round_up(mem->size + realsize));
|
|
if (!mem->buf)
|
|
return 0;
|
|
|
|
/* append data and increment size */
|
|
memcpy(&(mem->buf[mem->size]), contents, realsize);
|
|
mem->size += realsize;
|
|
return realsize;
|
|
}
|
|
|
|
size_t data_callback(void * data, size_t sz, size_t nmemb, SEXP fun) {
|
|
size_t size = sz * nmemb;
|
|
SEXP buf = PROTECT(allocVector(RAWSXP, size));
|
|
memcpy(RAW(buf), data, size);
|
|
|
|
/* call the R function */
|
|
int err;
|
|
SEXP call = PROTECT(Rf_lang3(fun, buf, ScalarInteger(0)));
|
|
R_tryEval(call, R_GlobalEnv, &err);
|
|
UNPROTECT(2);
|
|
return err ? 0 : size;
|
|
}
|
|
|