Browse Source

travis

master
boB Rudis 5 years ago
parent
commit
92bdb640da
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 23
      .Rbuildignore
  2. 7
      .gitignore
  3. 41
      .travis.yml
  4. 0
      NEWS
  5. 1
      src/curlparse-main.cpp
  6. 82
      tmp/callbacks.c
  7. 9
      tmp/callbacks.h
  8. 67
      tmp/curl-common.h
  9. 779
      tmp/curl-symbols.h
  10. 81
      tmp/curl.R
  11. 289
      tmp/curl.c
  12. 39
      tmp/download.R
  13. 51
      tmp/download.c
  14. 126
      tmp/echo.R
  15. 63
      tmp/email.R
  16. 26
      tmp/escape.R
  17. 33
      tmp/escape.c
  18. 117
      tmp/fetch.R
  19. 91
      tmp/fetch.c
  20. 48
      tmp/form.R
  21. 46
      tmp/form.c
  22. 17
      tmp/getdate.c
  23. 209
      tmp/handle.R
  24. 484
      tmp/handle.c
  25. 177
      tmp/ieproxy.c
  26. 96
      tmp/init.c
  27. 69
      tmp/interrupt.c
  28. 202
      tmp/multi.R
  29. 316
      tmp/multi.c
  30. 37
      tmp/nslookup.R
  31. 100
      tmp/nslookup.c
  32. 27
      tmp/onload.R
  33. 37
      tmp/options.R
  34. 51
      tmp/parse_headers.R
  35. 48
      tmp/proxy.R
  36. 56
      tmp/reflist.c
  37. 16
      tmp/split.c
  38. 39
      tmp/ssl.c
  39. BIN
      tmp/sysdata.rda
  40. 39
      tmp/typechecking.c
  41. 49
      tmp/upload.R
  42. 51
      tmp/utilities.R
  43. 147
      tmp/utils.c
  44. 64
      tmp/version.c
  45. 70
      tmp/winidn.c
  46. 48
      tmp/writer.R
  47. 43
      tmp/writer.c

23
.Rbuildignore

@ -1,3 +1,24 @@
^\.DS_Store$
^\.travis.yml$
^\.git$
^\.gitignore$
^\.Rhistory$
^.*\.Rproj$
^\.Rproj\.user$
^windows$
^README.md$
^src/option_table.h$
^src/Makevars$
^tools/option_table.txt$
^src/*.def$
^appveyor\.yml$
^revdep$
^docker$
^httpbin.md$
^examples$
^release.R$
bugs
^tmp$
^.*\.Rproj$
^\.Rproj\.user$
^\.travis\.yml$
@ -11,4 +32,4 @@
^tmp$
^notes$
^\.gitlab-ci\.yml$
^README_cache$
^README_cache$

7
.gitignore

@ -2,7 +2,12 @@
.Rproj.user
.Rhistory
.RData
.Rproj
src/*.o
src/*.so
src/*.dll
src/*.a
src/*.def
src/Makevars
tools/option_table.txt
inst/doc
windows

41
.travis.yml

@ -1,6 +1,41 @@
language: R
sudo: false
language: r
cache: packages
latex: false
fortran: false
matrix:
include:
- dist: precise
r: 3.5.3
- dist: trusty
- dist: xenial
env: R_CODECOV=true
r_packages: covr
- dist: bionic
- os: osx
osx_image: xcode10.2
- os: osx
osx_image: xcode9.4
- os: osx
brew_packages: curl
env: PKG_CONFIG_PATH="/usr/local/opt/curl/lib/pkgconfig"
- os: osx
brew_packages: curl-openssl
env:
- PKG_CONFIG_PATH="/usr/local/opt/curl-openssl/lib/pkgconfig"
- HTTPBIN_TEST_SERVER="https://nghttp2.org/httpbin"
- os: osx
before_install: brew install curl --HEAD
env: PKG_CONFIG_PATH="/usr/local/opt/curl/lib/pkgconfig"
- os: osx
osx_image: xcode7.3
disable_homebrew: true
before_install: sed -i.bak 's/-isysroot /-I/g' $(R RHOME)/etc/Makeconf
addons:
apt:
packages:
- libcurl4-openssl-dev
after_success:
- Rscript -e 'covr::codecov()'
- if [[ "${R_CODECOV}" ]]; then R -e 'covr::codecov()'; fi

0
NEWS

1
src/curlparse-main.cpp

@ -1,6 +1,7 @@
#include <Rcpp.h>
#include <curl/curl.h>
#include <curl/urlapi.h>
using namespace Rcpp;

82
tmp/callbacks.c

@ -1,82 +0,0 @@
#include "curl-common.h"
int R_curl_callback_progress(SEXP fun,
double dltotal, double dlnow,
double ultotal, double ulnow) {
SEXP down = PROTECT(allocVector(REALSXP, 2));
REAL(down)[0] = dltotal;
REAL(down)[1] = dlnow;
SEXP up = PROTECT(allocVector(REALSXP, 2));
REAL(up)[0] = ultotal;
REAL(up)[1] = ulnow;
SEXP call = PROTECT(Rf_lang3(fun, down, up));
int ok;
SEXP res = PROTECT(R_tryEval(call, R_GlobalEnv, &ok));
if (ok != 0) {
UNPROTECT(4);
return CURL_READFUNC_ABORT;
}
if (TYPEOF(res) != LGLSXP || length(res) != 1) {
UNPROTECT(4);
Rf_warning("progress callback must return boolean");
return 0;
}
int out = asLogical(res);
UNPROTECT(4);
return !out;
}
size_t R_curl_callback_read(char *buffer, size_t size, size_t nitems, SEXP fun) {
SEXP nbytes = PROTECT(ScalarInteger(size * nitems));
SEXP call = PROTECT(Rf_lang2(fun, nbytes));
int ok;
SEXP res = PROTECT(R_tryEval(call, R_GlobalEnv, &ok));
if (ok != 0) {
UNPROTECT(3);
return CURL_READFUNC_ABORT;
}
if (TYPEOF(res) != RAWSXP) {
UNPROTECT(3);
Rf_warning("read callback must raw vector");
return CURL_READFUNC_ABORT;
}
size_t bytes_read = length(res);
memcpy(buffer, RAW(res), bytes_read);
UNPROTECT(3);
return bytes_read;
}
int R_curl_callback_debug(CURL *handle, curl_infotype type_, char *data,
size_t size, SEXP fun) {
/* wrap type and msg into R types */
SEXP type = PROTECT(ScalarInteger(type_));
SEXP msg = PROTECT(allocVector(RAWSXP, size));
memcpy(RAW(msg), data, size);
/* call the R function */
SEXP call = PROTECT(Rf_lang3(fun, type, msg));
R_tryEval(call, R_GlobalEnv, NULL);
UNPROTECT(3);
// Debug function must always return 0
return 0;
}
int R_curl_callback_xferinfo(SEXP fun,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow) {
return R_curl_callback_progress(fun, dltotal, dlnow, ultotal, ulnow);
}

9
tmp/callbacks.h

@ -1,9 +0,0 @@
int R_curl_callback_progress(SEXP fun, double dltotal, double dlnow,
double ultotal, double ulnow);
size_t R_curl_callback_read(char *buffer, size_t size, size_t nitems, SEXP fun);
int R_curl_callback_debug(CURL *handle, curl_infotype type_, char *data,
size_t size, SEXP fun);
int R_curl_callback_xferinfo(SEXP fun,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow);

67
tmp/curl-common.h

@ -1,67 +0,0 @@
#include <Rinternals.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <string.h>
#include <stdlib.h>
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 28)
#define HAS_MULTI_WAIT 1
#endif
typedef struct {
unsigned char *buf;
size_t size;
} memory;
typedef struct {
SEXP multiptr;
SEXP handles;
CURLM *m;
} multiref;
typedef struct {
multiref *mref;
struct refnode *node;
memory content;
SEXP complete;
SEXP error;
SEXP data;
} async;
typedef struct {
SEXP handleptr;
CURL *handle;
struct curl_httppost *form;
struct curl_slist *headers;
struct curl_slist *custom;
char errbuf[CURL_ERROR_SIZE];
memory resheaders;
async async;
int refCount;
int locked;
} reference;
CURL* get_handle(SEXP ptr);
reference* get_ref(SEXP ptr);
void assert_status(CURLcode res, reference *ref);
void assert(CURLcode res);
void massert(CURLMcode res);
void stop_for_status(CURL *http_handle);
SEXP slist_to_vec(struct curl_slist *slist);
struct curl_slist* vec_to_slist(SEXP vec);
struct curl_httppost* make_form(SEXP form);
void set_form(reference *ref, struct curl_httppost* newform);
void reset_resheaders(reference *ref);
void reset_errbuf(reference *ref);
void clean_handle(reference *ref);
size_t push_disk(void* contents, size_t sz, size_t nmemb, FILE *ctx);
size_t append_buffer(void *contents, size_t sz, size_t nmemb, void *ctx);
size_t data_callback(void * data, size_t sz, size_t nmemb, SEXP fun);
CURLcode curl_perform_with_interrupt(CURL *handle);
int pending_interrupt();
SEXP make_handle_response(reference *ref);
/* reflist.c */
SEXP reflist_init();
SEXP reflist_add(SEXP x, SEXP target);
SEXP reflist_remove(SEXP x, SEXP target);

779
tmp/curl-symbols.h

@ -1,779 +0,0 @@
#include <curl/curl.h>
#define LIBCURL_HAS(x) \
(defined(x ## _FIRST) && (x ## _FIRST <= LIBCURL_VERSION_NUM) && \
(!defined(x ## _LAST) || ( x ## _LAST >= LIBCURL_VERSION_NUM)))
#define CURLAUTH_ANY_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLAUTH_ANYSAFE_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLAUTH_BASIC_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLAUTH_DIGEST_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLAUTH_DIGEST_IE_FIRST 0x071303 /* Added in 7.19.3 */
#define CURLAUTH_GSSNEGOTIATE_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLAUTH_NEGOTIATE_FIRST 0x072600 /* Added in 7.38.0 */
#define CURLAUTH_NONE_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLAUTH_NTLM_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLAUTH_NTLM_WB_FIRST 0x071600 /* Added in 7.22.0 */
#define CURLAUTH_ONLY_FIRST 0x071503 /* Added in 7.21.3 */
#define CURLCLOSEPOLICY_CALLBACK_FIRST 0x070700 /* Added in 7.7 */
#define CURLCLOSEPOLICY_LEAST_RECENTLY_USED_FIRST 0x070700 /* Added in 7.7 */
#define CURLCLOSEPOLICY_LEAST_TRAFFIC_FIRST 0x070700 /* Added in 7.7 */
#define CURLCLOSEPOLICY_NONE_FIRST 0x070700 /* Added in 7.7 */
#define CURLCLOSEPOLICY_OLDEST_FIRST 0x070700 /* Added in 7.7 */
#define CURLCLOSEPOLICY_SLOWEST_FIRST 0x070700 /* Added in 7.7 */
#define CURLE_ABORTED_BY_CALLBACK_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_AGAIN_FIRST 0x071202 /* Added in 7.18.2 */
#define CURLE_ALREADY_COMPLETE_FIRST 0x070702 /* Added in 7.7.2 */
#define CURLE_BAD_CALLING_ORDER_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_BAD_CONTENT_ENCODING_FIRST 0x070a00 /* Added in 7.10 */
#define CURLE_BAD_DOWNLOAD_RESUME_FIRST 0x070a00 /* Added in 7.10 */
#define CURLE_BAD_FUNCTION_ARGUMENT_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_BAD_PASSWORD_ENTERED_FIRST 0x070402 /* Added in 7.4.2 */
#define CURLE_CHUNK_FAILED_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLE_CONV_FAILED_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLE_CONV_REQD_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLE_COULDNT_CONNECT_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_COULDNT_RESOLVE_HOST_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_COULDNT_RESOLVE_PROXY_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FAILED_INIT_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FILESIZE_EXCEEDED_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURLE_FILE_COULDNT_READ_FILE_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_ACCEPT_FAILED_FIRST 0x071800 /* Added in 7.24.0 */
#define CURLE_FTP_ACCEPT_TIMEOUT_FIRST 0x071800 /* Added in 7.24.0 */
#define CURLE_FTP_ACCESS_DENIED_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_BAD_DOWNLOAD_RESUME_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_BAD_FILE_LIST_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLE_FTP_CANT_GET_HOST_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_CANT_RECONNECT_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_COULDNT_GET_SIZE_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_COULDNT_RETR_FILE_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_COULDNT_SET_ASCII_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_COULDNT_SET_BINARY_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_COULDNT_SET_TYPE_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLE_FTP_COULDNT_STOR_FILE_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_COULDNT_USE_REST_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_PARTIAL_FILE_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_PORT_FAILED_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_PRET_FAILED_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLE_FTP_QUOTE_ERROR_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_SSL_FAILED_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLE_FTP_USER_PASSWORD_INCORRECT_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_WEIRD_227_FORMAT_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_WEIRD_PASS_REPLY_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_WEIRD_PASV_REPLY_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_WEIRD_SERVER_REPLY_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_WEIRD_USER_REPLY_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FTP_WRITE_ERROR_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_FUNCTION_NOT_FOUND_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_GOT_NOTHING_FIRST 0x070901 /* Added in 7.9.1 */
#define CURLE_HTTP2_FIRST 0x072600 /* Added in 7.38.0 */
#define CURLE_HTTP_NOT_FOUND_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_HTTP_PORT_FAILED_FIRST 0x070300 /* Added in 7.3 */
#define CURLE_HTTP_POST_ERROR_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_HTTP_RANGE_ERROR_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_HTTP_RETURNED_ERROR_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLE_INTERFACE_FAILED_FIRST 0x070c00 /* Added in 7.12.0 */
#define CURLE_LDAP_CANNOT_BIND_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_LDAP_INVALID_URL_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURLE_LDAP_SEARCH_FAILED_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_LIBRARY_NOT_FOUND_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_LOGIN_DENIED_FIRST 0x070d01 /* Added in 7.13.1 */
#define CURLE_MALFORMAT_USER_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_NOT_BUILT_IN_FIRST 0x071505 /* Added in 7.21.5 */
#define CURLE_NO_CONNECTION_AVAILABLE_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURLE_OK_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_OPERATION_TIMEDOUT_FIRST 0x070a02 /* Added in 7.10.2 */
#define CURLE_OPERATION_TIMEOUTED_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_OUT_OF_MEMORY_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_PARTIAL_FILE_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_PEER_FAILED_VERIFICATION_FIRST 0x071101 /* Added in 7.17.1 */
#define CURLE_QUOTE_ERROR_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLE_RANGE_ERROR_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLE_READ_ERROR_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_RECV_ERROR_FIRST 0x070a00 /* Added in 7.10 */
#define CURLE_REMOTE_ACCESS_DENIED_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLE_REMOTE_DISK_FULL_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLE_REMOTE_FILE_EXISTS_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLE_REMOTE_FILE_NOT_FOUND_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLE_RTSP_CSEQ_ERROR_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLE_RTSP_SESSION_ERROR_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLE_SEND_ERROR_FIRST 0x070a00 /* Added in 7.10 */
#define CURLE_SEND_FAIL_REWIND_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLE_SHARE_IN_USE_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLE_SSH_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLE_SSL_CACERT_FIRST 0x070a00 /* Added in 7.10 */
#define CURLE_SSL_CACERT_BADFILE_FIRST 0x071000 /* Added in 7.16.0 */
#define CURLE_SSL_CERTPROBLEM_FIRST 0x070a00 /* Added in 7.10 */
#define CURLE_SSL_CIPHER_FIRST 0x070a00 /* Added in 7.10 */
#define CURLE_SSL_CONNECT_ERROR_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_SSL_CRL_BADFILE_FIRST 0x071300 /* Added in 7.19.0 */
#define CURLE_SSL_ENGINE_INITFAILED_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLE_SSL_ENGINE_NOTFOUND_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLE_SSL_ENGINE_SETFAILED_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLE_SSL_INVALIDCERTSTATUS_FIRST 0x072900 /* Added in 7.41.0 */
#define CURLE_SSL_ISSUER_ERROR_FIRST 0x071300 /* Added in 7.19.0 */
#define CURLE_SSL_PEER_CERTIFICATE_FIRST 0x070800 /* Added in 7.8 */
#define CURLE_SSL_PINNEDPUBKEYNOTMATCH_FIRST 0x072700 /* Added in 7.39.0 */
#define CURLE_SSL_SHUTDOWN_FAILED_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLE_TELNET_OPTION_SYNTAX_FIRST 0x070700 /* Added in 7.7 */
#define CURLE_TFTP_DISKFULL_FIRST 0x070f00 /* Added in 7.15.0 */
#define CURLE_TFTP_EXISTS_FIRST 0x070f00 /* Added in 7.15.0 */
#define CURLE_TFTP_ILLEGAL_FIRST 0x070f00 /* Added in 7.15.0 */
#define CURLE_TFTP_NOSUCHUSER_FIRST 0x070f00 /* Added in 7.15.0 */
#define CURLE_TFTP_NOTFOUND_FIRST 0x070f00 /* Added in 7.15.0 */
#define CURLE_TFTP_PERM_FIRST 0x070f00 /* Added in 7.15.0 */
#define CURLE_TFTP_UNKNOWNID_FIRST 0x070f00 /* Added in 7.15.0 */
#define CURLE_TOO_MANY_REDIRECTS_FIRST 0x070500 /* Added in 7.5 */
#define CURLE_UNKNOWN_OPTION_FIRST 0x071505 /* Added in 7.21.5 */
#define CURLE_UNKNOWN_TELNET_OPTION_FIRST 0x070700 /* Added in 7.7 */
#define CURLE_UNSUPPORTED_PROTOCOL_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_UPLOAD_FAILED_FIRST 0x071003 /* Added in 7.16.3 */
#define CURLE_URL_MALFORMAT_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_URL_MALFORMAT_USER_FIRST 0x070100 /* Added in 7.1 */
#define CURLE_USE_SSL_FAILED_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLE_WRITE_ERROR_FIRST 0x070100 /* Added in 7.1 */
#define CURLFILETYPE_DEVICE_BLOCK_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFILETYPE_DEVICE_CHAR_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFILETYPE_DIRECTORY_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFILETYPE_DOOR_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFILETYPE_FILE_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFILETYPE_NAMEDPIPE_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFILETYPE_SOCKET_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFILETYPE_SYMLINK_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFILETYPE_UNKNOWN_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFINFOFLAG_KNOWN_FILENAME_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFINFOFLAG_KNOWN_FILETYPE_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFINFOFLAG_KNOWN_GID_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFINFOFLAG_KNOWN_HLINKCOUNT_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFINFOFLAG_KNOWN_PERM_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFINFOFLAG_KNOWN_SIZE_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFINFOFLAG_KNOWN_TIME_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFINFOFLAG_KNOWN_UID_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLFORM_ARRAY_FIRST 0x070901 /* Added in 7.9.1 */
#define CURLFORM_ARRAY_END_FIRST 0x070901 /* Added in 7.9.1 */
#define CURLFORM_ARRAY_END_LAST 0x070906 /* Last featured in 7.9.6 */
#define CURLFORM_ARRAY_START_FIRST 0x070901 /* Added in 7.9.1 */
#define CURLFORM_ARRAY_START_LAST 0x070906 /* Last featured in 7.9.6 */
#define CURLFORM_BUFFER_FIRST 0x070908 /* Added in 7.9.8 */
#define CURLFORM_BUFFERLENGTH_FIRST 0x070908 /* Added in 7.9.8 */
#define CURLFORM_BUFFERPTR_FIRST 0x070908 /* Added in 7.9.8 */
#define CURLFORM_CONTENTHEADER_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLFORM_CONTENTSLENGTH_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_CONTENTTYPE_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_COPYCONTENTS_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_COPYNAME_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_END_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_FILE_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_FILECONTENT_FIRST 0x070901 /* Added in 7.9.1 */
#define CURLFORM_FILENAME_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLFORM_NAMELENGTH_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_NOTHING_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_PTRCONTENTS_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_PTRNAME_FIRST 0x070900 /* Added in 7.9 */
#define CURLFORM_STREAM_FIRST 0x071202 /* Added in 7.18.2 */
#define CURLFTPAUTH_DEFAULT_FIRST 0x070c02 /* Added in 7.12.2 */
#define CURLFTPAUTH_SSL_FIRST 0x070c02 /* Added in 7.12.2 */
#define CURLFTPAUTH_TLS_FIRST 0x070c02 /* Added in 7.12.2 */
#define CURLFTPMETHOD_DEFAULT_FIRST 0x070f03 /* Added in 7.15.3 */
#define CURLFTPMETHOD_MULTICWD_FIRST 0x070f03 /* Added in 7.15.3 */
#define CURLFTPMETHOD_NOCWD_FIRST 0x070f03 /* Added in 7.15.3 */
#define CURLFTPMETHOD_SINGLECWD_FIRST 0x070f03 /* Added in 7.15.3 */
#define CURLFTPSSL_ALL_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLFTPSSL_CCC_ACTIVE_FIRST 0x071002 /* Added in 7.16.2 */
#define CURLFTPSSL_CCC_NONE_FIRST 0x071002 /* Added in 7.16.2 */
#define CURLFTPSSL_CCC_PASSIVE_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLFTPSSL_CONTROL_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLFTPSSL_NONE_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLFTPSSL_TRY_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLFTP_CREATE_DIR_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLFTP_CREATE_DIR_NONE_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLFTP_CREATE_DIR_RETRY_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLGSSAPI_DELEGATION_FLAG_FIRST 0x071600 /* Added in 7.22.0 */
#define CURLGSSAPI_DELEGATION_NONE_FIRST 0x071600 /* Added in 7.22.0 */
#define CURLGSSAPI_DELEGATION_POLICY_FLAG_FIRST 0x071600 /* Added in 7.22.0 */
#define CURLHEADER_SEPARATE_FIRST 0x072500 /* Added in 7.37.0 */
#define CURLHEADER_UNIFIED_FIRST 0x072500 /* Added in 7.37.0 */
#define CURLINFO_APPCONNECT_TIME_FIRST 0x071300 /* Added in 7.19.0 */
#define CURLINFO_CERTINFO_FIRST 0x071301 /* Added in 7.19.1 */
#define CURLINFO_CONDITION_UNMET_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLINFO_CONNECT_TIME_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_CONTENT_LENGTH_DOWNLOAD_FIRST 0x070601 /* Added in 7.6.1 */
#define CURLINFO_CONTENT_LENGTH_UPLOAD_FIRST 0x070601 /* Added in 7.6.1 */
#define CURLINFO_CONTENT_TYPE_FIRST 0x070904 /* Added in 7.9.4 */
#define CURLINFO_COOKIELIST_FIRST 0x070e01 /* Added in 7.14.1 */
#define CURLINFO_DATA_IN_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLINFO_DATA_OUT_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLINFO_DOUBLE_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_EFFECTIVE_URL_FIRST 0x070400 /* Added in 7.4 */
#define CURLINFO_END_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLINFO_FILETIME_FIRST 0x070500 /* Added in 7.5 */
#define CURLINFO_FTP_ENTRY_PATH_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLINFO_HEADER_IN_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLINFO_HEADER_OUT_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLINFO_HEADER_SIZE_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_HTTPAUTH_AVAIL_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURLINFO_HTTP_CODE_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_HTTP_CONNECTCODE_FIRST 0x070a07 /* Added in 7.10.7 */
#define CURLINFO_LASTONE_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_LASTSOCKET_FIRST 0x070f02 /* Added in 7.15.2 */
#define CURLINFO_LOCAL_IP_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLINFO_LOCAL_PORT_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLINFO_LONG_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_MASK_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_NAMELOOKUP_TIME_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_NONE_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_NUM_CONNECTS_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLINFO_OS_ERRNO_FIRST 0x070c02 /* Added in 7.12.2 */
#define CURLINFO_PRETRANSFER_TIME_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_PRIMARY_IP_FIRST 0x071300 /* Added in 7.19.0 */
#define CURLINFO_PRIMARY_PORT_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLINFO_PRIVATE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLINFO_PROXYAUTH_AVAIL_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURLINFO_REDIRECT_COUNT_FIRST 0x070907 /* Added in 7.9.7 */
#define CURLINFO_REDIRECT_TIME_FIRST 0x070907 /* Added in 7.9.7 */
#define CURLINFO_REDIRECT_URL_FIRST 0x071202 /* Added in 7.18.2 */
#define CURLINFO_REQUEST_SIZE_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_RESPONSE_CODE_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURLINFO_RTSP_CLIENT_CSEQ_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLINFO_RTSP_CSEQ_RECV_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLINFO_RTSP_SERVER_CSEQ_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLINFO_RTSP_SESSION_ID_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLINFO_SIZE_DOWNLOAD_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_SIZE_UPLOAD_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_SLIST_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLINFO_SPEED_DOWNLOAD_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_SPEED_UPLOAD_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_SSL_DATA_IN_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLINFO_SSL_DATA_OUT_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLINFO_SSL_ENGINES_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLINFO_SSL_VERIFYRESULT_FIRST 0x070500 /* Added in 7.5 */
#define CURLINFO_STARTTRANSFER_TIME_FIRST 0x070902 /* Added in 7.9.2 */
#define CURLINFO_STRING_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_TEXT_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLINFO_TLS_SESSION_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLINFO_TOTAL_TIME_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLINFO_TYPEMASK_FIRST 0x070401 /* Added in 7.4.1 */
#define CURLIOCMD_NOP_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLIOCMD_RESTARTREAD_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLIOE_FAILRESTART_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLIOE_OK_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLIOE_UNKNOWNCMD_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLKHMATCH_MISMATCH_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHMATCH_MISSING_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHMATCH_OK_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHSTAT_DEFER_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHSTAT_FINE_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHSTAT_FINE_ADD_TO_FILE_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHSTAT_REJECT_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHTYPE_DSS_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHTYPE_RSA_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHTYPE_RSA1_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLKHTYPE_UNKNOWN_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURLMOPT_MAXCONNECTS_FIRST 0x071003 /* Added in 7.16.3 */
#define CURLMOPT_MAX_HOST_CONNECTIONS_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURLMOPT_MAX_PIPELINE_LENGTH_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURLMOPT_MAX_TOTAL_CONNECTIONS_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURLMOPT_PIPELINING_FIRST 0x071000 /* Added in 7.16.0 */
#define CURLMOPT_PIPELINING_SERVER_BL_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURLMOPT_PIPELINING_SITE_BL_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURLMOPT_SOCKETDATA_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLMOPT_SOCKETFUNCTION_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLMOPT_TIMERDATA_FIRST 0x071000 /* Added in 7.16.0 */
#define CURLMOPT_TIMERFUNCTION_FIRST 0x071000 /* Added in 7.16.0 */
#define CURLMSG_DONE_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLMSG_NONE_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLM_ADDED_ALREADY_FIRST 0x072001 /* Added in 7.32.1 */
#define CURLM_BAD_EASY_HANDLE_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLM_BAD_HANDLE_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLM_BAD_SOCKET_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLM_CALL_MULTI_PERFORM_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLM_CALL_MULTI_SOCKET_FIRST 0x070f05 /* Added in 7.15.5 */
#define CURLM_INTERNAL_ERROR_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLM_OK_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLM_OUT_OF_MEMORY_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLM_UNKNOWN_OPTION_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLOPTTYPE_FUNCTIONPOINT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPTTYPE_LONG_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPTTYPE_OBJECTPOINT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPTTYPE_OFF_T_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLOPT_ACCEPTTIMEOUT_MS_FIRST 0x071800 /* Added in 7.24.0 */
#define CURLOPT_ACCEPT_ENCODING_FIRST 0x071506 /* Added in 7.21.6 */
#define CURLOPT_ADDRESS_SCOPE_FIRST 0x071300 /* Added in 7.19.0 */
#define CURLOPT_APPEND_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLOPT_AUTOREFERER_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_BUFFERSIZE_FIRST 0x070a00 /* Added in 7.10 */
#define CURLOPT_CAINFO_FIRST 0x070402 /* Added in 7.4.2 */
#define CURLOPT_CAPATH_FIRST 0x070908 /* Added in 7.9.8 */
#define CURLOPT_CERTINFO_FIRST 0x071301 /* Added in 7.19.1 */
#define CURLOPT_CHUNK_BGN_FUNCTION_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLOPT_CHUNK_DATA_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLOPT_CHUNK_END_FUNCTION_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLOPT_CLOSEFUNCTION_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_CLOSEFUNCTION_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_CLOSEPOLICY_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_CLOSESOCKETDATA_FIRST 0x071507 /* Added in 7.21.7 */
#define CURLOPT_CLOSESOCKETFUNCTION_FIRST 0x071507 /* Added in 7.21.7 */
#define CURLOPT_CONNECTTIMEOUT_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_CONNECTTIMEOUT_MS_FIRST 0x071002 /* Added in 7.16.2 */
#define CURLOPT_CONNECT_ONLY_FIRST 0x070f02 /* Added in 7.15.2 */
#define CURLOPT_CONV_FROM_NETWORK_FUNCTION_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLOPT_CONV_FROM_UTF8_FUNCTION_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLOPT_CONV_TO_NETWORK_FUNCTION_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURLOPT_COOKIE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_COOKIEFILE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_COOKIEJAR_FIRST 0x070900 /* Added in 7.9 */
#define CURLOPT_COOKIELIST_FIRST 0x070e01 /* Added in 7.14.1 */
#define CURLOPT_COOKIESESSION_FIRST 0x070907 /* Added in 7.9.7 */
#define CURLOPT_COPYPOSTFIELDS_FIRST 0x071101 /* Added in 7.17.1 */
#define CURLOPT_CRLF_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_CRLFILE_FIRST 0x071300 /* Added in 7.19.0 */
#define CURLOPT_CUSTOMREQUEST_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_DEBUGDATA_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLOPT_DEBUGFUNCTION_FIRST 0x070906 /* Added in 7.9.6 */
#define CURLOPT_DIRLISTONLY_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLOPT_DNS_CACHE_TIMEOUT_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLOPT_DNS_INTERFACE_FIRST 0x072100 /* Added in 7.33.0 */
#define CURLOPT_DNS_LOCAL_IP4_FIRST 0x072100 /* Added in 7.33.0 */
#define CURLOPT_DNS_LOCAL_IP6_FIRST 0x072100 /* Added in 7.33.0 */
#define CURLOPT_DNS_SERVERS_FIRST 0x071800 /* Added in 7.24.0 */
#define CURLOPT_DNS_USE_GLOBAL_CACHE_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLOPT_EGDSOCKET_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_ENCODING_FIRST 0x070a00 /* Added in 7.10 */
#define CURLOPT_ERRORBUFFER_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_EXPECT_100_TIMEOUT_MS_FIRST 0x072400 /* Added in 7.36.0 */
#define CURLOPT_FAILONERROR_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_FILE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_FILETIME_FIRST 0x070500 /* Added in 7.5 */
#define CURLOPT_FNMATCH_DATA_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLOPT_FNMATCH_FUNCTION_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLOPT_FOLLOWLOCATION_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_FORBID_REUSE_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_FRESH_CONNECT_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_FTPAPPEND_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_FTPASCII_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_FTPASCII_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_FTPLISTONLY_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_FTPPORT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_FTPSSLAUTH_FIRST 0x070c02 /* Added in 7.12.2 */
#define CURLOPT_FTP_ACCOUNT_FIRST 0x070d00 /* Added in 7.13.0 */
#define CURLOPT_FTP_ALTERNATIVE_TO_USER_FIRST 0x070f05 /* Added in 7.15.5 */
#define CURLOPT_FTP_CREATE_MISSING_DIRS_FIRST 0x070a07 /* Added in 7.10.7 */
#define CURLOPT_FTP_FILEMETHOD_FIRST 0x070f01 /* Added in 7.15.1 */
#define CURLOPT_FTP_RESPONSE_TIMEOUT_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURLOPT_FTP_SKIP_PASV_IP_FIRST 0x070f00 /* Added in 7.15.0 */
#define CURLOPT_FTP_SSL_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLOPT_FTP_SSL_CCC_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLOPT_FTP_USE_EPRT_FIRST 0x070a05 /* Added in 7.10.5 */
#define CURLOPT_FTP_USE_EPSV_FIRST 0x070902 /* Added in 7.9.2 */
#define CURLOPT_FTP_USE_PRET_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_GSSAPI_DELEGATION_FIRST 0x071600 /* Added in 7.22.0 */
#define CURLOPT_HEADER_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_HEADERDATA_FIRST 0x070a00 /* Added in 7.10 */
#define CURLOPT_HEADERFUNCTION_FIRST 0x070702 /* Added in 7.7.2 */
#define CURLOPT_HEADEROPT_FIRST 0x072500 /* Added in 7.37.0 */
#define CURLOPT_HTTP200ALIASES_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLOPT_HTTPAUTH_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLOPT_HTTPGET_FIRST 0x070801 /* Added in 7.8.1 */
#define CURLOPT_HTTPHEADER_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_HTTPPOST_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_HTTPPROXYTUNNEL_FIRST 0x070300 /* Added in 7.3 */
#define CURLOPT_HTTPREQUEST_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_HTTPREQUEST_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_HTTP_CONTENT_DECODING_FIRST 0x071002 /* Added in 7.16.2 */
#define CURLOPT_HTTP_TRANSFER_DECODING_FIRST 0x071002 /* Added in 7.16.2 */
#define CURLOPT_HTTP_VERSION_FIRST 0x070901 /* Added in 7.9.1 */
#define CURLOPT_IGNORE_CONTENT_LENGTH_FIRST 0x070e01 /* Added in 7.14.1 */
#define CURLOPT_INFILE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_INFILESIZE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_INFILESIZE_LARGE_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLOPT_INTERFACE_FIRST 0x070300 /* Added in 7.3 */
#define CURLOPT_INTERLEAVEDATA_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_INTERLEAVEFUNCTION_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_IOCTLDATA_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLOPT_IOCTLFUNCTION_FIRST 0x070c03 /* Added in 7.12.3 */
#define CURLOPT_IPRESOLVE_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURLOPT_ISSUERCERT_FIRST 0x071300 /* Added in 7.19.0 */
#define CURLOPT_KEYPASSWD_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLOPT_KRB4LEVEL_FIRST 0x070300 /* Added in 7.3 */
#define CURLOPT_KRBLEVEL_FIRST 0x071004 /* Added in 7.16.4 */
#define CURLOPT_LOCALPORT_FIRST 0x070f02 /* Added in 7.15.2 */
#define CURLOPT_LOCALPORTRANGE_FIRST 0x070f02 /* Added in 7.15.2 */
#define CURLOPT_LOGIN_OPTIONS_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLOPT_LOW_SPEED_LIMIT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_LOW_SPEED_TIME_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_MAIL_AUTH_FIRST 0x071900 /* Added in 7.25.0 */
#define CURLOPT_MAIL_FROM_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_MAIL_RCPT_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_MAXCONNECTS_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_MAXFILESIZE_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURLOPT_MAXFILESIZE_LARGE_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLOPT_MAXREDIRS_FIRST 0x070500 /* Added in 7.5 */
#define CURLOPT_MAX_RECV_SPEED_LARGE_FIRST 0x070f05 /* Added in 7.15.5 */
#define CURLOPT_MAX_SEND_SPEED_LARGE_FIRST 0x070f05 /* Added in 7.15.5 */
#define CURLOPT_MUTE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_MUTE_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_NETRC_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_NETRC_FILE_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLOPT_NEW_DIRECTORY_PERMS_FIRST 0x071004 /* Added in 7.16.4 */
#define CURLOPT_NEW_FILE_PERMS_FIRST 0x071004 /* Added in 7.16.4 */
#define CURLOPT_NOBODY_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_NOPROGRESS_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_NOPROXY_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLOPT_NOSIGNAL_FIRST 0x070a00 /* Added in 7.10 */
#define CURLOPT_NOTHING_FIRST 0x070101 /* Added in 7.1.1 */
#define CURLOPT_NOTHING_LAST 0x070b00 /* Last featured in 7.11.0 */
#define CURLOPT_OPENSOCKETDATA_FIRST 0x071101 /* Added in 7.17.1 */
#define CURLOPT_OPENSOCKETFUNCTION_FIRST 0x071101 /* Added in 7.17.1 */
#define CURLOPT_PASSWDDATA_FIRST 0x070402 /* Added in 7.4.2 */
#define CURLOPT_PASSWDDATA_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_PASSWDFUNCTION_FIRST 0x070402 /* Added in 7.4.2 */
#define CURLOPT_PASSWDFUNCTION_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_PASSWORD_FIRST 0x071301 /* Added in 7.19.1 */
#define CURLOPT_PASV_HOST_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLOPT_PASV_HOST_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_PINNEDPUBLICKEY_FIRST 0x072700 /* Added in 7.39.0 */
#define CURLOPT_PORT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_POST_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_POST301_FIRST 0x071101 /* Added in 7.17.1 */
#define CURLOPT_POSTFIELDS_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_POSTFIELDSIZE_FIRST 0x070200 /* Added in 7.2 */
#define CURLOPT_POSTFIELDSIZE_LARGE_FIRST 0x070b01 /* Added in 7.11.1 */
#define CURLOPT_POSTQUOTE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_POSTREDIR_FIRST 0x071301 /* Added in 7.19.1 */
#define CURLOPT_PREQUOTE_FIRST 0x070905 /* Added in 7.9.5 */
#define CURLOPT_PRIVATE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLOPT_PROGRESSDATA_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_PROGRESSFUNCTION_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_PROTOCOLS_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLOPT_PROXY_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_PROXYAUTH_FIRST 0x070a07 /* Added in 7.10.7 */
#define CURLOPT_PROXYHEADER_FIRST 0x072500 /* Added in 7.37.0 */
#define CURLOPT_PROXYPASSWORD_FIRST 0x071301 /* Added in 7.19.1 */
#define CURLOPT_PROXYPORT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_PROXYTYPE_FIRST 0x070a00 /* Added in 7.10 */
#define CURLOPT_PROXYUSERNAME_FIRST 0x071301 /* Added in 7.19.1 */
#define CURLOPT_PROXYUSERPWD_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_PROXY_TRANSFER_MODE_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLOPT_PUT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_QUOTE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_RANDOM_FILE_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_RANGE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_READDATA_FIRST 0x070907 /* Added in 7.9.7 */
#define CURLOPT_READFUNCTION_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_REDIR_PROTOCOLS_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLOPT_REFERER_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_RESOLVE_FIRST 0x071503 /* Added in 7.21.3 */
#define CURLOPT_RESUME_FROM_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_RESUME_FROM_LARGE_FIRST 0x070b00 /* Added in 7.11.0 */
#define CURLOPT_RTSPHEADER_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_RTSP_CLIENT_CSEQ_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_RTSP_REQUEST_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_RTSP_SERVER_CSEQ_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_RTSP_SESSION_ID_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_RTSP_STREAM_URI_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_RTSP_TRANSPORT_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_SASL_IR_FIRST 0x071f00 /* Added in 7.31.0 */
#define CURLOPT_SEEKDATA_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLOPT_SEEKFUNCTION_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLOPT_SERVER_RESPONSE_TIMEOUT_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLOPT_SHARE_FIRST 0x070a00 /* Added in 7.10 */
#define CURLOPT_SOCKOPTDATA_FIRST 0x071000 /* Added in 7.16.0 */
#define CURLOPT_SOCKOPTFUNCTION_FIRST 0x071000 /* Added in 7.16.0 */
#define CURLOPT_SOCKS5_GSSAPI_NEC_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLOPT_SOCKS5_GSSAPI_SERVICE_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLOPT_SOURCE_HOST_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLOPT_SOURCE_HOST_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_SOURCE_PATH_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLOPT_SOURCE_PATH_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_SOURCE_PORT_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLOPT_SOURCE_PORT_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_SOURCE_POSTQUOTE_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLOPT_SOURCE_POSTQUOTE_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_SOURCE_PREQUOTE_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLOPT_SOURCE_PREQUOTE_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_SOURCE_QUOTE_FIRST 0x070d00 /* Added in 7.13.0 */
#define CURLOPT_SOURCE_QUOTE_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_SOURCE_URL_FIRST 0x070d00 /* Added in 7.13.0 */
#define CURLOPT_SOURCE_URL_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_SOURCE_USERPWD_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURLOPT_SOURCE_USERPWD_LAST 0x070f05 /* Last featured in 7.15.5 */
#define CURLOPT_SSH_AUTH_TYPES_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLOPT_SSH_HOST_PUBLIC_KEY_MD5_FIRST 0x071101 /* Added in 7.17.1 */
#define CURLOPT_SSH_KEYDATA_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLOPT_SSH_KEYFUNCTION_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLOPT_SSH_KNOWNHOSTS_FIRST 0x071306 /* Added in 7.19.6 */
#define CURLOPT_SSH_PRIVATE_KEYFILE_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLOPT_SSH_PUBLIC_KEYFILE_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLOPT_SSLCERT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_SSLCERTPASSWD_FIRST 0x070101 /* Added in 7.1.1 */
#define CURLOPT_SSLCERTTYPE_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLOPT_SSLENGINE_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLOPT_SSLENGINE_DEFAULT_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLOPT_SSLKEY_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLOPT_SSLKEYPASSWD_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLOPT_SSLKEYTYPE_FIRST 0x070903 /* Added in 7.9.3 */
#define CURLOPT_SSLVERSION_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_SSL_CIPHER_LIST_FIRST 0x070900 /* Added in 7.9 */
#define CURLOPT_SSL_CTX_DATA_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLOPT_SSL_CTX_FUNCTION_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURLOPT_SSL_ENABLE_ALPN_FIRST 0x072400 /* Added in 7.36.0 */
#define CURLOPT_SSL_ENABLE_NPN_FIRST 0x072400 /* Added in 7.36.0 */
#define CURLOPT_SSL_OPTIONS_FIRST 0x071900 /* Added in 7.25.0 */
#define CURLOPT_SSL_SESSIONID_CACHE_FIRST 0x071000 /* Added in 7.16.0 */
#define CURLOPT_SSL_VERIFYHOST_FIRST 0x070801 /* Added in 7.8.1 */
#define CURLOPT_SSL_VERIFYPEER_FIRST 0x070402 /* Added in 7.4.2 */
#define CURLOPT_SSL_VERIFYSTATUS_FIRST 0x072900 /* Added in 7.41.0 */
#define CURLOPT_STDERR_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_TCP_KEEPALIVE_FIRST 0x071900 /* Added in 7.25.0 */
#define CURLOPT_TCP_KEEPIDLE_FIRST 0x071900 /* Added in 7.25.0 */
#define CURLOPT_TCP_KEEPINTVL_FIRST 0x071900 /* Added in 7.25.0 */
#define CURLOPT_TCP_NODELAY_FIRST 0x070b02 /* Added in 7.11.2 */
#define CURLOPT_TELNETOPTIONS_FIRST 0x070700 /* Added in 7.7 */
#define CURLOPT_TFTP_BLKSIZE_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLOPT_TIMECONDITION_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_TIMEOUT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_TIMEOUT_MS_FIRST 0x071002 /* Added in 7.16.2 */
#define CURLOPT_TIMEVALUE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_TLSAUTH_PASSWORD_FIRST 0x071504 /* Added in 7.21.4 */
#define CURLOPT_TLSAUTH_TYPE_FIRST 0x071504 /* Added in 7.21.4 */
#define CURLOPT_TLSAUTH_USERNAME_FIRST 0x071504 /* Added in 7.21.4 */
#define CURLOPT_TRANSFERTEXT_FIRST 0x070101 /* Added in 7.1.1 */
#define CURLOPT_TRANSFER_ENCODING_FIRST 0x071506 /* Added in 7.21.6 */
#define CURLOPT_UNIX_SOCKET_PATH_FIRST 0x072800 /* Added in 7.40.0 */
#define CURLOPT_UNRESTRICTED_AUTH_FIRST 0x070a04 /* Added in 7.10.4 */
#define CURLOPT_UPLOAD_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_URL_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_USERAGENT_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_USERNAME_FIRST 0x071301 /* Added in 7.19.1 */
#define CURLOPT_USERPWD_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_USE_SSL_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLOPT_VERBOSE_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_WILDCARDMATCH_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLOPT_WRITEDATA_FIRST 0x070907 /* Added in 7.9.7 */
#define CURLOPT_WRITEFUNCTION_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_WRITEHEADER_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_WRITEINFO_FIRST 0x070100 /* Added in 7.1 */
#define CURLOPT_XFERINFODATA_FIRST 0x072000 /* Added in 7.32.0 */
#define CURLOPT_XFERINFOFUNCTION_FIRST 0x072000 /* Added in 7.32.0 */
#define CURLOPT_XOAUTH2_BEARER_FIRST 0x072100 /* Added in 7.33.0 */
#define CURLPAUSE_ALL_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLPAUSE_CONT_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLPAUSE_RECV_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLPAUSE_RECV_CONT_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLPAUSE_SEND_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLPAUSE_SEND_CONT_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLPROTO_ALL_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_DICT_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_FILE_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_FTP_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_FTPS_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_GOPHER_FIRST 0x071502 /* Added in 7.21.2 */
#define CURLPROTO_HTTP_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_HTTPS_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_IMAP_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLPROTO_IMAPS_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLPROTO_LDAP_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_LDAPS_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_POP3_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLPROTO_POP3S_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLPROTO_RTMP_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLPROTO_RTMPE_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLPROTO_RTMPS_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLPROTO_RTMPT_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLPROTO_RTMPTE_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLPROTO_RTMPTS_FIRST 0x071500 /* Added in 7.21.0 */
#define CURLPROTO_RTSP_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLPROTO_SCP_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_SFTP_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_SMB_FIRST 0x072800 /* Added in 7.40.0 */
#define CURLPROTO_SMBS_FIRST 0x072800 /* Added in 7.40.0 */
#define CURLPROTO_SMTP_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLPROTO_SMTPS_FIRST 0x071400 /* Added in 7.20.0 */
#define CURLPROTO_TELNET_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROTO_TFTP_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROXY_HTTP_FIRST 0x070a00 /* Added in 7.10 */
#define CURLPROXY_HTTP_1_0_FIRST 0x071304 /* Added in 7.19.4 */
#define CURLPROXY_SOCKS4_FIRST 0x070a00 /* Added in 7.10 */
#define CURLPROXY_SOCKS4A_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLPROXY_SOCKS5_FIRST 0x070a00 /* Added in 7.10 */
#define CURLPROXY_SOCKS5_HOSTNAME_FIRST 0x071200 /* Added in 7.18.0 */
#define CURLSHE_BAD_OPTION_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHE_INVALID_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHE_IN_USE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHE_NOMEM_FIRST 0x070c00 /* Added in 7.12.0 */
#define CURLSHE_NOT_BUILT_IN_FIRST 0x071700 /* Added in 7.23.0 */
#define CURLSHE_OK_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHOPT_LOCKFUNC_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHOPT_NONE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHOPT_SHARE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHOPT_UNLOCKFUNC_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHOPT_UNSHARE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSHOPT_USERDATA_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURLSOCKTYPE_ACCEPT_FIRST 0x071c00 /* Added in 7.28.0 */
#define CURLSOCKTYPE_IPCXN_FIRST 0x071000 /* Added in 7.16.0 */
#define CURLSSH_AUTH_AGENT_FIRST 0x071c00 /* Added in 7.28.0 */
#define CURLSSH_AUTH_ANY_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLSSH_AUTH_DEFAULT_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLSSH_AUTH_HOST_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLSSH_AUTH_KEYBOARD_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLSSH_AUTH_NONE_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLSSH_AUTH_PASSWORD_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLSSH_AUTH_PUBLICKEY_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLSSLBACKEND_AXTLS_FIRST 0x072600 /* Added in 7.38.0 */
#define CURLSSLBACKEND_CYASSL_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_DARWINSSL_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_GNUTLS_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_GSKIT_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_NONE_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_NSS_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_OPENSSL_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_POLARSSL_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_QSOSSL_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLBACKEND_QSOSSL_LAST 0x072601 /* Last featured in 7.38.1 */
#define CURLSSLBACKEND_SCHANNEL_FIRST 0x072200 /* Added in 7.34.0 */
#define CURLSSLOPT_ALLOW_BEAST_FIRST 0x071900 /* Added in 7.25.0 */
#define CURLUSESSL_ALL_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLUSESSL_CONTROL_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLUSESSL_NONE_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLUSESSL_TRY_FIRST 0x071100 /* Added in 7.17.0 */
#define CURLVERSION_FIRST_FIRST 0x070a00 /* Added in 7.10 */
#define CURLVERSION_FOURTH_FIRST 0x071001 /* Added in 7.16.1 */
#define CURLVERSION_NOW_FIRST 0x070a00 /* Added in 7.10 */
#define CURLVERSION_SECOND_FIRST 0x070b01 /* Added in 7.11.1 */
#define CURLVERSION_THIRD_FIRST 0x070c00 /* Added in 7.12.0 */
#define CURL_CHUNK_BGN_FUNC_FAIL_FIRST 0x071500 /* Added in 7.21.0 */
#define CURL_CHUNK_BGN_FUNC_OK_FIRST 0x071500 /* Added in 7.21.0 */
#define CURL_CHUNK_BGN_FUNC_SKIP_FIRST 0x071500 /* Added in 7.21.0 */
#define CURL_CHUNK_END_FUNC_FAIL_FIRST 0x071500 /* Added in 7.21.0 */
#define CURL_CHUNK_END_FUNC_OK_FIRST 0x071500 /* Added in 7.21.0 */
#define CURL_CSELECT_ERR_FIRST 0x071003 /* Added in 7.16.3 */
#define CURL_CSELECT_IN_FIRST 0x071003 /* Added in 7.16.3 */
#define CURL_CSELECT_OUT_FIRST 0x071003 /* Added in 7.16.3 */
#define CURL_EASY_NONE_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_EASY_NONE_LAST 0x070f04 /* Last featured in 7.15.4 */
#define CURL_EASY_TIMEOUT_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_EASY_TIMEOUT_LAST 0x070f04 /* Last featured in 7.15.4 */
#define CURL_ERROR_SIZE_FIRST 0x070100 /* Added in 7.1 */
#define CURL_FNMATCHFUNC_FAIL_FIRST 0x071500 /* Added in 7.21.0 */
#define CURL_FNMATCHFUNC_MATCH_FIRST 0x071500 /* Added in 7.21.0 */
#define CURL_FNMATCHFUNC_NOMATCH_FIRST 0x071500 /* Added in 7.21.0 */
#define CURL_FORMADD_DISABLED_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURL_FORMADD_ILLEGAL_ARRAY_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_FORMADD_INCOMPLETE_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_FORMADD_MEMORY_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_FORMADD_NULL_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_FORMADD_OK_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_FORMADD_OPTION_TWICE_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_FORMADD_UNKNOWN_OPTION_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_GLOBAL_ACK_EINTR_FIRST 0x071e00 /* Added in 7.30.0 */
#define CURL_GLOBAL_ALL_FIRST 0x070800 /* Added in 7.8 */
#define CURL_GLOBAL_DEFAULT_FIRST 0x070800 /* Added in 7.8 */
#define CURL_GLOBAL_NOTHING_FIRST 0x070800 /* Added in 7.8 */
#define CURL_GLOBAL_SSL_FIRST 0x070800 /* Added in 7.8 */
#define CURL_GLOBAL_WIN32_FIRST 0x070801 /* Added in 7.8.1 */
#define CURL_HTTP_VERSION_1_0_FIRST 0x070901 /* Added in 7.9.1 */
#define CURL_HTTP_VERSION_1_1_FIRST 0x070901 /* Added in 7.9.1 */
#define CURL_HTTP_VERSION_2_0_FIRST 0x072100 /* Added in 7.33.0 */
#define CURL_HTTP_VERSION_NONE_FIRST 0x070901 /* Added in 7.9.1 */
#define CURL_IPRESOLVE_V4_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURL_IPRESOLVE_V6_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURL_IPRESOLVE_WHATEVER_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURL_LOCK_ACCESS_NONE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURL_LOCK_ACCESS_SHARED_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURL_LOCK_ACCESS_SINGLE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURL_LOCK_DATA_CONNECT_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURL_LOCK_DATA_COOKIE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURL_LOCK_DATA_DNS_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURL_LOCK_DATA_NONE_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURL_LOCK_DATA_SHARE_FIRST 0x070a04 /* Added in 7.10.4 */
#define CURL_LOCK_DATA_SSL_SESSION_FIRST 0x070a03 /* Added in 7.10.3 */
#define CURL_LOCK_TYPE_CONNECT_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_LOCK_TYPE_CONNECT_LAST 0x070a02 /* Last featured in 7.10.2 */
#define CURL_LOCK_TYPE_COOKIE_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_LOCK_TYPE_COOKIE_LAST 0x070a02 /* Last featured in 7.10.2 */
#define CURL_LOCK_TYPE_DNS_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_LOCK_TYPE_DNS_LAST 0x070a02 /* Last featured in 7.10.2 */
#define CURL_LOCK_TYPE_NONE_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_LOCK_TYPE_NONE_LAST 0x070a02 /* Last featured in 7.10.2 */
#define CURL_LOCK_TYPE_SSL_SESSION_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_LOCK_TYPE_SSL_SESSION_LAST 0x070a02 /* Last featured in 7.10.2 */
#define CURL_MAX_HTTP_HEADER_FIRST 0x071307 /* Added in 7.19.7 */
#define CURL_MAX_WRITE_SIZE_FIRST 0x070907 /* Added in 7.9.7 */
#define CURL_NETRC_IGNORED_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_NETRC_OPTIONAL_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_NETRC_REQUIRED_FIRST 0x070908 /* Added in 7.9.8 */
#define CURL_POLL_IN_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_POLL_INOUT_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_POLL_NONE_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_POLL_OUT_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_POLL_REMOVE_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_PROGRESS_BAR_FIRST 0x070101 /* Added in 7.1.1 */
#define CURL_PROGRESS_BAR_LAST 0x070401 /* Last featured in 7.4.1 */
#define CURL_PROGRESS_STATS_FIRST 0x070101 /* Added in 7.1.1 */
#define CURL_PROGRESS_STATS_LAST 0x070401 /* Last featured in 7.4.1 */
#define CURL_READFUNC_ABORT_FIRST 0x070c01 /* Added in 7.12.1 */
#define CURL_READFUNC_PAUSE_FIRST 0x071200 /* Added in 7.18.0 */
#define CURL_REDIR_GET_ALL_FIRST 0x071301 /* Added in 7.19.1 */
#define CURL_REDIR_POST_301_FIRST 0x071301 /* Added in 7.19.1 */
#define CURL_REDIR_POST_302_FIRST 0x071301 /* Added in 7.19.1 */
#define CURL_REDIR_POST_303_FIRST 0x071901 /* Added in 7.25.1 */
#define CURL_REDIR_POST_ALL_FIRST 0x071301 /* Added in 7.19.1 */
#define CURL_RTSPREQ_ANNOUNCE_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_DESCRIBE_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_GET_PARAMETER_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_NONE_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_OPTIONS_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_PAUSE_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_PLAY_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_RECEIVE_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_RECORD_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_SETUP_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_SET_PARAMETER_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_RTSPREQ_TEARDOWN_FIRST 0x071400 /* Added in 7.20.0 */
#define CURL_SEEKFUNC_CANTSEEK_FIRST 0x071305 /* Added in 7.19.5 */
#define CURL_SEEKFUNC_FAIL_FIRST 0x071305 /* Added in 7.19.5 */
#define CURL_SEEKFUNC_OK_FIRST 0x071305 /* Added in 7.19.5 */
#define CURL_SOCKET_BAD_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_SOCKET_TIMEOUT_FIRST 0x070e00 /* Added in 7.14.0 */
#define CURL_SOCKOPT_ALREADY_CONNECTED_FIRST 0x071505 /* Added in 7.21.5 */
#define CURL_SOCKOPT_ERROR_FIRST 0x071505 /* Added in 7.21.5 */
#define CURL_SOCKOPT_OK_FIRST 0x071505 /* Added in 7.21.5 */
#define CURL_SSLVERSION_DEFAULT_FIRST 0x070902 /* Added in 7.9.2 */
#define CURL_SSLVERSION_SSLv2_FIRST 0x070902 /* Added in 7.9.2 */
#define CURL_SSLVERSION_SSLv3_FIRST 0x070902 /* Added in 7.9.2 */
#define CURL_SSLVERSION_TLSv1_FIRST 0x070902 /* Added in 7.9.2 */
#define CURL_SSLVERSION_TLSv1_0_FIRST 0x072200 /* Added in 7.34.0 */
#define CURL_SSLVERSION_TLSv1_1_FIRST 0x072200 /* Added in 7.34.0 */
#define CURL_SSLVERSION_TLSv1_2_FIRST 0x072200 /* Added in 7.34.0 */
#define CURL_TIMECOND_IFMODSINCE_FIRST 0x070907 /* Added in 7.9.7 */
#define CURL_TIMECOND_IFUNMODSINCE_FIRST 0x070907 /* Added in 7.9.7 */
#define CURL_TIMECOND_LASTMOD_FIRST 0x070907 /* Added in 7.9.7 */
#define CURL_TIMECOND_NONE_FIRST 0x070907 /* Added in 7.9.7 */
#define CURL_TLSAUTH_NONE_FIRST 0x071504 /* Added in 7.21.4 */
#define CURL_TLSAUTH_SRP_FIRST 0x071504 /* Added in 7.21.4 */
#define CURL_VERSION_ASYNCHDNS_FIRST 0x070a07 /* Added in 7.10.7 */
#define CURL_VERSION_CONV_FIRST 0x070f04 /* Added in 7.15.4 */
#define CURL_VERSION_CURLDEBUG_FIRST 0x071306 /* Added in 7.19.6 */
#define CURL_VERSION_DEBUG_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURL_VERSION_GSSAPI_FIRST 0x072600 /* Added in 7.38.0 */
#define CURL_VERSION_GSSNEGOTIATE_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURL_VERSION_HTTP2_FIRST 0x072100 /* Added in 7.33.0 */
#define CURL_VERSION_IDN_FIRST 0x070c00 /* Added in 7.12.0 */
#define CURL_VERSION_IPV6_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_VERSION_KERBEROS4_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_VERSION_KERBEROS5_FIRST 0x072800 /* Added in 7.40.0 */
#define CURL_VERSION_LARGEFILE_FIRST 0x070b01 /* Added in 7.11.1 */
#define CURL_VERSION_LIBZ_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_VERSION_NTLM_FIRST 0x070a06 /* Added in 7.10.6 */
#define CURL_VERSION_NTLM_WB_FIRST 0x071600 /* Added in 7.22.0 */
#define CURL_VERSION_SPNEGO_FIRST 0x070a08 /* Added in 7.10.8 */
#define CURL_VERSION_SSL_FIRST 0x070a00 /* Added in 7.10 */
#define CURL_VERSION_SSPI_FIRST 0x070d02 /* Added in 7.13.2 */
#define CURL_VERSION_TLSAUTH_SRP_FIRST 0x071504 /* Added in 7.21.4 */
#define CURL_VERSION_UNIX_SOCKETS_FIRST 0x072800 /* Added in 7.40.0 */
#define CURL_WAIT_POLLIN_FIRST 0x071c00 /* Added in 7.28.0 */
#define CURL_WAIT_POLLOUT_FIRST 0x071c00 /* Added in 7.28.0 */
#define CURL_WAIT_POLLPRI_FIRST 0x071c00 /* Added in 7.28.0 */
#define CURL_WRITEFUNC_PAUSE_FIRST 0x071200 /* Added in 7.18.0 */

81
tmp/curl.R

@ -1,81 +0,0 @@
#' Curl connection interface
#'
#' Drop-in replacement for base \code{\link{url}} that supports https, ftps,
#' gzip, deflate, etc. Default behavior is identical to \code{\link{url}}, but
#' request can be fully configured by passing a custom \code{\link{handle}}.
#'
#' As of version 2.3 curl connections support \code{open(con, blocking = FALSE)}.
#' In this case \code{readBin} and \code{readLines} will return immediately with data
#' that is available without waiting. For such non-blocking connections the caller
#' needs to call \code{\link{isIncomplete}} to check if the download has completed
#' yet.
#'
#' @useDynLib curl R_curl_connection
#' @export
#' @param url character string. See examples.
#' @param open character string. How to open the connection if it should be opened
#' initially. Currently only "r" and "rb" are supported.
#' @param handle a curl handle object
#' @examples \dontrun{
#' con <- curl("https://httpbin.org/get")
#' readLines(con)
#'
#' # Auto-opened connections can be recycled
#' open(con, "rb")
#' bin <- readBin(con, raw(), 999)
#' close(con)
#' rawToChar(bin)
#'
#' # HTTP error
#' curl("https://httpbin.org/status/418", "r")
#'
#' # Follow redirects
#' readLines(curl("https://httpbin.org/redirect/3"))
#'
#' # Error after redirect
#' curl("https://httpbin.org/redirect-to?url=http://httpbin.org/status/418", "r")
#'
#' # Auto decompress Accept-Encoding: gzip / deflate (rfc2616 #14.3)
#' readLines(curl("http://httpbin.org/gzip"))
#' readLines(curl("http://httpbin.org/deflate"))
#'
#' # Binary support
#' buf <- readBin(curl("http://httpbin.org/bytes/98765", "rb"), raw(), 1e5)
#' length(buf)
#'
#' # Read file from disk
#' test <- paste0("file://", system.file("DESCRIPTION"))
#' readLines(curl(test))
#'
#' # Other protocols
#' read.csv(curl("ftp://cran.r-project.org/pub/R/CRAN_mirrors.csv"))
#' readLines(curl("ftps://test.rebex.net:990/readme.txt"))
#' readLines(curl("gopher://quux.org/1"))
#'
#' # Streaming data
#' con <- curl("http://jeroen.github.io/data/diamonds.json", "r")
#' while(length(x <- readLines(con, n = 5))){
#' print(x)
#' }
#'
#' # Stream large dataset over https with gzip
#' library(jsonlite)
#' con <- gzcon(curl("https://jeroen.github.io/data/nycflights13.json.gz"))
#' nycflights <- stream_in(con)
#' }
#'
curl <- function(url = "http://httpbin.org/get", open = "", handle = new_handle()){
curl_connection(url, open, handle)
}
# 'stream' currently only used for non-blocking connections to prevent
# busy looping in curl_fetch_stream()
curl_connection <- function(url, mode, handle, partial = FALSE){
con <- .Call(R_curl_connection, url, handle, partial)
if(!identical(mode, "")){
withCallingHandlers(open(con, open = mode), error = function(err) {
close(con)
})
}
return(con)
}

289
tmp/curl.c

@ -1,289 +0,0 @@
/* *
* Streaming interface to libcurl for R. (c) 2015 Jeroen Ooms.
* Source: https://github.com/jeroen/curl
* Comments and contributions are welcome!
* Helpful libcurl examples:
* - http://curl.haxx.se/libcurl/c/getinmemory.html
* - http://curl.haxx.se/libcurl/c/multi-single.html
* Sparse documentation about Rconnection API:
* - https://github.com/wch/r-source/blob/trunk/src/include/R_ext/Connections.h
* - http://biostatmatt.com/R/R-conn-ints/C-Structures.html
*
* Notes: the close() function in R actually calls con->destroy. The con->close
* function is only used when a connection is recycled after auto-open.
*/
#include "curl-common.h"
#include <Rconfig.h>
/* Define BSWAP_32 on Big Endian systems */
#ifdef WORDS_BIGENDIAN
#if (defined(__sun) && defined(__SVR4))
#include <sys/byteorder.h>
#elif (defined(__APPLE__) && defined(__ppc__) || defined(__ppc64__))
#include <libkern/OSByteOrder.h>
#define BSWAP_32 OSSwapInt32
#elif (defined(__OpenBSD__))
#define BSWAP_32(x) swap32(x)
#elif (defined(__GLIBC__))
#include <byteswap.h>
#define BSWAP_32(x) bswap_32(x)
#elif (defined(_AIX))
#define BSWAP_32(x) __builtin_bswap32(x)
#endif
#endif
/* the RConnection API is experimental and subject to change */
#include <R_ext/Connections.h>
#if ! defined(R_CONNECTIONS_VERSION) || R_CONNECTIONS_VERSION != 1
#error "Unsupported connections API version"
#endif
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define R_EOF -1
typedef struct {
char *url;
char *buf;
char *cur;
int has_data;
int has_more;
int used;
int partial;
size_t size;
size_t limit;
CURLM *manager;
CURL *handle;
reference *ref;
} request;
/* callback function to store received data */
static size_t push(void *contents, size_t sz, size_t nmemb, void *ctx) {
/* avoids compiler warning on windows */
request* req = (request*) ctx;
req->has_data = 1;
/* move existing data to front of buffer (if any) */
memmove(req->buf, req->cur, req->size);
/* allocate more space if required */
size_t realsize = sz * nmemb;
size_t newsize = req->size + realsize;
while(newsize > req->limit) {
size_t newlimit = 2 * req->limit;
//Rprintf("Resizing buffer to %d.\n", newlimit);
void *newbuf = realloc(req->buf, newlimit);
if(!newbuf)
error("Failure in realloc. Out of memory?");
req->buf = newbuf;
req->limit = newlimit;
}
/* append new data */
memcpy(req->buf + req->size, contents, realsize);
req->size = newsize;
req->cur = req->buf;
return realsize;
}
static size_t pop(void *target, size_t max, request *req){
size_t copy_size = min(req->size, max);
memcpy(target, req->cur, copy_size);
req->cur += copy_size;
req->size -= copy_size;
//Rprintf("Requested %d bytes, popped %d bytes, new size %d bytes.\n", max, copy_size, req->size);
return copy_size;
}
void check_manager(CURLM *manager, reference *ref) {
for(int msg = 1; msg > 0;){
CURLMsg *out = curl_multi_info_read(manager, &msg);
if(out)
assert_status(out->data.result, ref);
}
}
//NOTE: renamed because the name 'fetch' caused crash/conflict on Solaris.
void fetchdata(request *req) {
R_CheckUserInterrupt();
long timeout = 10*1000;
massert(curl_multi_timeout(req->manager, &timeout));
/* massert(curl_multi_perform(req->manager, &(req->has_more))); */
/* On libcurl < 7.20 we need to check for CURLM_CALL_MULTI_PERFORM, see docs */
CURLMcode res = CURLM_CALL_MULTI_PERFORM;
while(res == CURLM_CALL_MULTI_PERFORM){
res = curl_multi_perform(req->manager, &(req->has_more));
}
massert(res);
/* End */
check_manager(req->manager, req->ref);
}
/* Support for readBin() */
static size_t rcurl_read(void *target, size_t sz, size_t ni, Rconnection con) {
request *req = (request*) con->private;
size_t req_size = sz * ni;
/* append data to the target buffer */
size_t total_size = pop(target, req_size, req);
while((req_size > total_size) && req->has_more) {
/* wait for activity, timeout or "nothing" */
#ifdef HAS_MULTI_WAIT
int numfds;
if(con->blocking)
massert(curl_multi_wait(req->manager, NULL, 0, 1000, &numfds));
#endif
fetchdata(req);
total_size += pop((char*)target + total_size, (req_size-total_size), req);
//return less than requested data for non-blocking connections, or curl_fetch_stream()
if(!con->blocking || req->partial)
break;
}
con->incomplete = req->has_more || req->size;
return total_size;
}
/* naive implementation of readLines */
static int rcurl_fgetc(Rconnection con) {
int x = 0;
#ifdef WORDS_BIGENDIAN
return rcurl_read(&x, 1, 1, con) ? BSWAP_32(x) : R_EOF;
#else
return rcurl_read(&x, 1, 1, con) ? x : R_EOF;
#endif
}
void cleanup(Rconnection con) {
//Rprintf("Destroying connection.\n");
request *req = (request*) con->private;
reference *ref = req->ref;
/* free thee handle connection */
curl_multi_remove_handle(req->manager, req->handle);
ref->locked = 0;
/* delayed finalizer cleanup */
(ref->refCount)--;
clean_handle(ref);
/* clean up connection */
curl_multi_cleanup(req->manager);
free(req->buf);
free(req->url);
free(req);
}
/* reset to pre-opened state */
void reset(Rconnection con) {
//Rprintf("Resetting connection object.\n");
request *req = (request*) con->private;
curl_multi_remove_handle(req->manager, req->handle);
req->ref->locked = 0;
con->isopen = FALSE;
con->text = TRUE;
con->incomplete = FALSE;
strcpy(con->mode, "r");
}
static Rboolean rcurl_open(Rconnection con) {
request *req = (request*) con->private;
//same message as base::url()
if (con->mode[0] != 'r' || strchr(con->mode, 'w'))
Rf_error("can only open URLs for reading");
if(req->ref->locked)
Rf_error("Handle is already in use elsewhere.");
/* init a multi stack with callback */
CURL *handle = req->handle;
assert(curl_easy_setopt(handle, CURLOPT_URL, req->url));
assert(curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, push));
assert(curl_easy_setopt(handle, CURLOPT_WRITEDATA, req));
/* add the handle to the pool and lock it */
massert(curl_multi_add_handle(req->manager, handle));
req->ref->locked = 1;
/* reset the state */
req->handle = handle;
req->cur = req->buf;
req->size = 0;
req->used = 1;
req->has_data = 0;
req->has_more = 1;
/* fully non-blocking has 's' in open mode */
int block_open = strchr(con->mode, 's') == NULL;
int force_open = strchr(con->mode, 'f') != NULL;
/* Wait for first data to arrive. Monitoring a change in status code does not
suffice in case of http redirects */
while(block_open && req->has_more && !req->has_data) {
#ifdef HAS_MULTI_WAIT
int numfds;
massert(curl_multi_wait(req->manager, NULL, 0, 1000, &numfds));
#endif
fetchdata(req);
}
/* check http status code */
/* Stream connections should be checked via handle_data() */
/* Non-blocking open connections get checked during read */
if(block_open && !force_open)
stop_for_status(handle);
/* set mode in case open() changed it */
con->text = strchr(con->mode, 'b') ? FALSE : TRUE;
con->isopen = TRUE;
con->incomplete = TRUE;
return TRUE;
}
SEXP R_curl_connection(SEXP url, SEXP ptr, SEXP partial) {
if(!isString(url))
error("Argument 'url' must be string.");
/* create the R connection object, mimicking base::url() */
Rconnection con;
/* R wants description in native encoding, but we use UTF-8 URL below */
SEXP rc = PROTECT(R_new_custom_connection(translateChar(STRING_ELT(url, 0)), "r", "curl", &con));
/* setup curl. These are the parts that are recycable. */
request *req = malloc(sizeof(request));
req->handle = get_handle(ptr);
req->ref = get_ref(ptr);
req->limit = CURL_MAX_WRITE_SIZE;
req->buf = malloc(req->limit);
req->manager = curl_multi_init();
req->partial = asLogical(partial); //only for curl_fetch_stream()
req->used = 0;
/* allocate url string */
req->url = malloc(strlen(translateCharUTF8(asChar(url))) + 1);
strcpy(req->url, translateCharUTF8(asChar(url)));
/* set connection properties */
con->incomplete = FALSE;
con->private = req;
con->canseek = FALSE;
con->canwrite = FALSE;
con->isopen = FALSE;
con->blocking = TRUE;
con->text = TRUE;
con->UTF8out = TRUE;
con->open = rcurl_open;
con->close = reset;
con->destroy = cleanup;
con->read = rcurl_read;
con->fgetc = rcurl_fgetc;
con->fgetc_internal = rcurl_fgetc;
/* protect the handle */
(req->ref->refCount)++;
UNPROTECT(1);
return rc;
}

39
tmp/download.R

@ -1,39 +0,0 @@
#' Download file to disk
#'
#' Libcurl implementation of \code{C_download} (the "internal" download method)
#' with added support for https, ftps, gzip, etc. Default behavior is identical
#' to \code{\link{download.file}}, but request can be fully configured by passing
#' a custom \code{\link{handle}}.
#'
#' The main difference between \code{curl_download} and \code{curl_fetch_disk}
#' is that \code{curl_download} checks the http status code before starting the
#' download, and raises an error when status is non-successful. The behavior of
#' \code{curl_fetch_disk} on the other hand is to proceed as normal and write
#' the error page to disk in case of a non success response.
#'
#' @useDynLib curl R_download_curl
#' @param url A character string naming the URL of a resource to be downloaded.
#' @param destfile A character string with the name where the downloaded file
#' is saved. Tilde-expansion is performed.
#' @param quiet If \code{TRUE}, suppress status messages (if any), and the
#' progress bar.
#' @param mode A character string specifying the mode with which to write the file.
#' Useful values are \code{"w"}, \code{"wb"} (binary), \code{"a"} (append)
#' and \code{"ab"}.
#' @param handle a curl handle object
#' @return Path of downloaded file (invisibly).
#' @export
#' @examples \dontrun{download large file
#' url <- "http://www2.census.gov/acs2011_5yr/pums/csv_pus.zip"
#' tmp <- tempfile()
#' curl_download(url, tmp)
#' }
curl_download <- function(url, destfile, quiet = TRUE, mode = "wb", handle = new_handle()){
destfile <- enc2native(normalizePath(destfile, mustWork = FALSE))
nonblocking <- isTRUE(getOption("curl_interrupt", TRUE))
tmp <- enc2native(paste0(destfile, ".curltmp"))
on.exit(unlink(tmp))
.Call(R_download_curl, url, tmp, quiet, mode, handle, nonblocking)
file.rename(tmp, destfile)
invisible(destfile)
}

51
tmp/download.c

@ -1,51 +0,0 @@
/* *
* Reimplementation of C_download (the "internal" method for download.file).
*/
#include "curl-common.h"
SEXP R_download_curl(SEXP url, SEXP destfile, SEXP quiet, SEXP mode, SEXP ptr, SEXP nonblocking) {
if(!isString(url))
error("Argument 'url' must be string.");
if(!isString(destfile))
error("Argument 'destfile' must be string.");
if(!isLogical(quiet))
error("Argument 'quiet' must be TRUE/FALSE.");
if(!isString(mode))
error("Argument 'mode' must be string.");
/* get the handle */
CURL *handle = get_handle(ptr);
reset_errbuf(get_ref(ptr));
/* open file */
FILE *dest = fopen(CHAR(asChar(destfile)), CHAR(asChar(mode)));
if(!dest)
error("Failed to open file %s.", CHAR(asChar(destfile)));
/* set options */
curl_easy_setopt(handle, CURLOPT_URL, translateCharUTF8(asChar(url)));
curl_easy_setopt(handle, CURLOPT_NOPROGRESS, asLogical(quiet));
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, push_disk);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, dest);
/* perform blocking request */
CURLcode status = asLogical(nonblocking) ?
curl_perform_with_interrupt(handle) : curl_easy_perform(handle);
/* cleanup */
curl_easy_setopt(handle, CURLOPT_URL, NULL);
curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 1);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
fclose(dest);
/* raise for curl errors */
assert_status(status, get_ref(ptr));
/* check for success */
stop_for_status(handle);
return ScalarInteger(0);
}

126
tmp/echo.R

@ -1,126 +0,0 @@
#' Echo Service
#'
#' This function is only for testing purposes. It starts a local httpuv server to
#' echo the request body and content type in the response.
#'
#' @export
#' @param handle a curl handle object
#' @param port the port number on which to run httpuv server
#' @param progress show progress meter during http transfer
#' @param file path or connection to write body. Default returns body as raw vector.
#' @examples h <- new_handle(url = 'https://httpbin.org/post')
#' handle_setform(h, foo = "blabla", bar = charToRaw("test"),
#' myfile = form_file(system.file("DESCRIPTION"), "text/description"))
#'
#' # Echo the POST request data
#' formdata <- curl_echo(h)
#'
#' # Show the multipart body
#' cat(rawToChar(formdata$body))
#'
#' # Parse multipart
#' webutils::parse_http(formdata$body, formdata$content_type)
curl_echo <- function(handle, port = 9359, progress = interactive(), file = NULL){
progress <- isTRUE(progress)
if(!(is.null(file) || inherits(file, "connection") || is.character(file)))
stop("Argument 'file' must be a file path or connection object")
output <- NULL
echo_handler <- function(req){
if(progress){
cat("\nRequest Complete!\n", file = stderr())
progress <<- FALSE
}
body <- if(tolower(req[["REQUEST_METHOD"]]) %in% c("post", "put")){
if(!length(file)){
req[["rook.input"]]$read()
} else {
write_to_file(req[["rook.input"]]$read, file)
}
}
output <<- list(
method = req[["REQUEST_METHOD"]],
path = req[["PATH_INFO"]],
query = req[["QUERY_STRING"]],
content_type = req[["CONTENT_TYPE"]],
body = body,
headers = req[["HEADERS"]]
)
# Dummy response
list(
status = 200,
body = "",
headers = c("Content-Type" = "text/plain")
)
}
# Start httpuv
server_id <- httpuv::startServer("0.0.0.0", port, list(call = echo_handler))
on.exit(httpuv::stopServer(server_id), add = TRUE)
# Workaround bug in httpuv on windows that keeps protecting handler until next startServer()
on.exit(rm(handle), add = TRUE)
# httpuv 1.3.4 supports non-blocking service()
waittime <- ifelse(utils::packageVersion('httpuv') > "1.3.3", NA, 1)
# Post data from curl
xfer <- function(down, up){
if(progress){
if(up[1] == 0 && down[1] == 0){
cat("\rConnecting...", file = stderr())
} else {
cat(sprintf("\rUpload: %s (%d%%) ", format_size(up[2]),
as.integer(100 * up[2] / up[1])), file = stderr())
}
}
# Need very low wait to prevent gridlocking!
httpuv::service(waittime)
TRUE
}
handle_setopt(handle, connecttimeout = 2, xferinfofunction = xfer, noprogress = FALSE)
if(progress) cat("\n", file = stderr())
input_url <- handle_data(handle)$url
if(length(input_url) && nchar(input_url)){
target_url <- replace_host(input_url, paste0("http://127.0.0.1:", port))
host <- sub("https?://([^/]+).*", "\\1", input_url)
#hostname <- gsub(":[0-9]+$", "", host)
#handle_setopt(handle, port = port, resolve = paste0(hostname, ":", port, ':127.0.0.1'))
handle_setopt(handle, httpheader = c(paste0("Host:", host), handle_getheaders(handle)))
} else {
target_url <- paste0("http://localhost:", port)
}
curl_fetch_memory(target_url, handle = handle)
output$url <- input_url
if(progress) cat("\n", file = stderr())
return(output)
}
replace_host <- function(url, new_host = 'http://localhost'){
sub("[a-zA-Z]+://[^/]+", new_host, url)
}
write_to_file <- function(readfun, filename){
con <- if(inherits(filename, "connection")){
filename
} else {
base::file(filename)
}
if(!isOpen(con)){
open(con, "wb")
on.exit(close(con))
}
while(length(buf <- readfun(1e6))){
writeBin(buf, con)
}
return(filename)
}
format_size <- function(x){
if(x < 1024)
return(sprintf("%d b", x))
if(x < 1048576)
return(sprintf("%.2f Kb", x / 1024))
return(sprintf("%.2f Mb", x / 1048576))
}

63
tmp/email.R

@ -1,63 +0,0 @@
#' Send email
#'
#' Use the curl SMTP client to send an email. The \code{message} argument must be
#' properly formatted RFC2822 email message with From/To/Subject headers and CRLF
#' line breaks.
#'
#' @export
#' @param mail_rcpt one or more recipient email addresses. Do not include names,
#' these go into the \code{message} headers.
#' @param mail_from email address of the sender.
#' @param message either a string or connection with (properly formatted) email
#' message, including sender/recipient/subject headers. See example.
#' @param smtp_server address of the SMTP server without the \code{smtp://} part
#' @param verbose print output
#' @param ... other options passed to \code{\link{handle_setopt}}. In most cases
#' you will need to set a \code{username} and \code{password} to authenticate
#' with the SMTP server.
#' @examples \donttest{# Message in RFC2822 format
#' message <- 'From: "Testbot" <jeroen@ocpu.io>
#' To: "Jeroen Ooms" <jeroenooms@gmail.com>
#' Subject: Hello there!
#'
#' Hi Jeroen,
#' I am sending this email using curl.'
#'
#'
#' # Actually send the email
#' recipients <- c('test@opencpu.org', 'jeroenooms@gmail.com')
#' sender <- 'test@ocpu.io'
#' username <- 'mail@ocpu.io'
#' password <- askpass::askpass(paste("SMTP server password for", username))
#' send_mail(sender, recipients, smtp_server = 'smtp.mailgun.org',
#' message = message, username = username, password = password)}
send_mail <- function(mail_from, mail_rcpt, message, smtp_server = 'localhost',
verbose = TRUE, ...){
if(is.character(message))
message <- charToRaw(paste(message, collapse = '\r\n'))
con <- if(is.raw(message)){
rawConnection(message)
} else if(inherits(message, "connection")){
if(!isOpen(message))
open(message, 'rb')
message
} else {
stop("Body must be a string, raw vector, or connection object")
}
on.exit(close(con))
total_bytes <- 0
h <- new_handle(upload = TRUE, readfunction = function(nbytes, ...) {
buf <- readBin(con, raw(), nbytes)
total_bytes <<- total_bytes + length(buf)
if(verbose){
if(length(buf)){
cat(sprintf("\rUploaded %d bytes...", total_bytes), file = stderr())
} else {
cat(sprintf("\rUploaded %d bytes... all done!\n", total_bytes), file = stderr())
}
}
return(buf)
}, mail_from = mail_from, mail_rcpt = mail_rcpt, verbose = verbose, ...)
url <- paste0('smtp://', smtp_server)
curl_fetch_memory(url, handle = h)
}

26
tmp/escape.R

@ -1,26 +0,0 @@
#' URL encoding
#'
#' Escape all special characters (i.e. everything except for a-z, A-Z, 0-9, '-',
#' '.', '_' or '~') for use in URLs.
#'
#' @useDynLib curl R_curl_escape
#' @export
#' @param url A character vector (typically containing urls or parameters) to be
#' encoded/decoded
#' @examples # Escape strings
#' out <- curl_escape("foo = bar + 5")
#' curl_unescape(out)
#'
#' # All non-ascii characters are encoded
#' mu <- "\u00b5"
#' curl_escape(mu)
#' curl_unescape(curl_escape(mu))
curl_escape <- function(url){
.Call(R_curl_escape, enc2utf8(as.character(url)), FALSE);
}
#' @rdname curl_escape
#' @export
curl_unescape <- function(url){
.Call(R_curl_escape, enc2utf8(as.character(url)), TRUE);
}

33
tmp/escape.c

@ -1,33 +0,0 @@
#include <curl/curl.h>
#include <Rinternals.h>
SEXP R_curl_escape(SEXP url, SEXP unescape_) {
if (TYPEOF(url) != STRSXP)
error("`url` must be a character vector.");
/* init curl */
CURL *curl = curl_easy_init();
if (!curl)
return(R_NilValue);
int unescape = asLogical(unescape_);
int n = Rf_length(url);
SEXP output = PROTECT(allocVector(STRSXP, n));
for (int i = 0; i < n; ++i) {
const char *in = CHAR(STRING_ELT(url, i));
char *out;
if (unescape) {
out = curl_easy_unescape(curl, in, 0, NULL);
} else {
out = curl_easy_escape(curl, in, 0);
}
SET_STRING_ELT(output, i, mkCharCE(out, CE_UTF8));
curl_free(out);
}
curl_easy_cleanup(curl);
UNPROTECT(1);
return output;
}

117
tmp/fetch.R

@ -1,117 +0,0 @@
#' Fetch the contents of a URL
#'
#' Low-level bindings to write data from a URL into memory, disk or a callback
#' function. These are mainly intended for \code{httr}, most users will be better
#' off using the \code{\link{curl}} or \code{\link{curl_download}} function, or the
#' http specific wrappers in the \code{httr} package.
#'
#' The curl_fetch functions automatically raise an error upon protocol problems
#' (network, disk, ssl) but do not implement application logic. For example for
#' you need to check the status code of http requests yourself in the response,
#' and deal with it accordingly.
#'
#' Both \code{curl_fetch_memory} and \code{curl_fetch_disk} have a blocking and
#' non-blocking C implementation. The latter is slightly slower but allows for
#' interrupting the download prematurely (using e.g. CTRL+C or ESC). Interrupting
#' is enabled when R runs in interactive mode or when
#' \code{getOption("curl_interrupt") == TRUE}.
#'
#' The \code{curl_fetch_multi} function is the asynchronous equivalent of
#' \code{curl_fetch_memory}. It wraps \code{multi_add} to schedule requests which
#' are executed concurrently when calling \code{multi_run}. For each successful
#' request the \code{done} callback is triggered with response data. For failed
#' requests (when \code{curl_fetch_memory} would raise an error), the \code{fail}
#' function is triggered with the error message.
#'
#' @param url A character string naming the URL of a resource to be downloaded.
#' @param handle a curl handle object
#' @export
#' @rdname curl_fetch
#' @useDynLib curl R_curl_fetch_memory
#' @examples
#' # Load in memory
#' res <- curl_fetch_memory("http://httpbin.org/cookies/set?foo=123&bar=ftw")
#' res$content
#'
#' # Save to disk
#' res <- curl_fetch_disk("http://httpbin.org/stream/10", tempfile())
#' res$content
#' readLines(res$content)
#'
#' # Stream with callback
#' res <- curl_fetch_stream("http://www.httpbin.org/drip?duration=5&numbytes=15&code=200", function(x){
#' cat(rawToChar(x))
#' })
#'
#' # Async API
#' data <- list()
#' success <- function(res){
#' cat("Request done! Status:", res$status, "\n")
#' data <<- c(data, list(res))
#' }
#' failure <- function(msg){
#' cat("Oh noes! Request failed!", msg, "\n")
#' }
#' curl_fetch_multi("http://httpbin.org/get", success, failure)
#' curl_fetch_multi("http://httpbin.org/status/418", success, failure)
#' curl_fetch_multi("https://urldoesnotexist.xyz", success, failure)
#' multi_run()
#' str(data)
curl_fetch_memory <- function(url, handle = new_handle()){
nonblocking <- isTRUE(getOption("curl_interrupt", TRUE))
output <- .Call(R_curl_fetch_memory, enc2utf8(url), handle, nonblocking)
res <- handle_data(handle)
res$content <- output
res
}
#' @export
#' @param path Path to save results
#' @rdname curl_fetch
#' @useDynLib curl R_curl_fetch_disk
curl_fetch_disk <- function(url, path, handle = new_handle()){
nonblocking <- isTRUE(getOption("curl_interrupt", TRUE))
path <- enc2native(normalizePath(path, mustWork = FALSE))
output <- .Call(R_curl_fetch_disk, enc2utf8(url), handle, path, "wb", nonblocking)
res <- handle_data(handle)
res$content <- output
res
}
#' @export
#' @param fun Callback function. Should have one argument, which will be
#' a raw vector.
#' @rdname curl_fetch
#' @useDynLib curl R_curl_connection
curl_fetch_stream <- function(url, fun, handle = new_handle()){
# Blocking = TRUE and partial = TRUE to prevent busy-waiting
con <- curl_connection(url, mode = "", handle = handle, partial = TRUE)
# 'f' means: do not error for status code
open(con, "rbf")
on.exit(close(con))
while(isIncomplete(con)){
buf <- readBin(con, raw(), 32768L)
if(length(buf))
fun(buf)
}
handle_data(handle)
}
#' @export
#' @rdname curl_fetch
#' @inheritParams multi
#' @useDynLib curl R_curl_connection
curl_fetch_multi <- function(url, done = NULL, fail = NULL, pool = NULL,
data = NULL, handle = new_handle()){
handle_setopt(handle, url = enc2utf8(url))
multi_add(handle = handle, done = done, fail = fail, data = data, pool = pool)
invisible(handle)
}
#' @export
#' @rdname curl_fetch
curl_fetch_echo <- function(url, handle = new_handle()){
handle_setopt(handle, url = enc2utf8(url))
curl_echo(handle)
}

91
tmp/fetch.c

@ -1,91 +0,0 @@
/* *
* Blocking easy interfaces to libcurl for R.
* Example: http://curl.haxx.se/libcurl/c/getinmemory.html
*/
#include "curl-common.h"
SEXP R_curl_fetch_memory(SEXP url, SEXP ptr, SEXP nonblocking){
if (!isString(url) || length(url) != 1)
error("Argument 'url' must be string.");
/* get the handle */
CURL *handle = get_handle(ptr);
/* update the url */
curl_easy_setopt(handle, CURLOPT_URL, CHAR(STRING_ELT(url, 0)));
/* reset the response header buffer */
reset_resheaders(get_ref(ptr));
reset_errbuf(get_ref(ptr));
/* buffer body */
memory body = {NULL, 0};
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, append_buffer);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &body);
/* perform blocking request */
CURLcode status = asLogical(nonblocking) ?
curl_perform_with_interrupt(handle) : curl_easy_perform(handle);
/* Reset for reuse */
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
/* check for errors */
if (status != CURLE_OK) {
free(body.buf);
assert_status(status, get_ref(ptr));
}
/* create output */
SEXP out = PROTECT(allocVector(RAWSXP, body.size));
/* copy only if there is actual content */
if(body.size)
memcpy(RAW(out), body.buf, body.size);
/* cleanup and return */
UNPROTECT(1);
free(body.buf);
return out;
}
SEXP R_curl_fetch_disk(SEXP url, SEXP ptr, SEXP path, SEXP mode, SEXP nonblocking){
if (!isString(url) || length(url) != 1)
error("Argument 'url' must be string.");
if (!isString(path) || length(path) != 1)
error("`path` must be string.");
/* get the handle */
CURL *handle = get_handle(ptr);
/* update the url */
curl_easy_setopt(handle, CURLOPT_URL, CHAR(STRING_ELT(url, 0)));
/* reset the response header buffer */
reset_resheaders(get_ref(ptr));
reset_errbuf(get_ref(ptr));
/* open file */
FILE *dest = fopen(CHAR(asChar(path)), CHAR(asChar(mode)));
if(!dest)
error("Failed to open file %s.", CHAR(asChar(path)));
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, push_disk);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, dest);
/* perform blocking request */
CURLcode status = asLogical(nonblocking) ?
curl_perform_with_interrupt(handle): curl_easy_perform(handle);
/* cleanup */
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
fclose(dest);
/* check for errors */
assert_status(status, get_ref(ptr));
/* return the file path */
return path;
}

48
tmp/form.R

@ -1,48 +0,0 @@
#' POST files or data
#'
#' Build multipart form data elements. The \code{form_file} function uploads a
#' file. The \code{form_data} function allows for posting a string or raw vector
#' with a custom content-type.
#'
#' @param path a string with a path to an existing file on disk
#' @param type MIME content-type of the file.
#' @export
#' @name multipart
#' @rdname multipart
form_file <- function(path, type = NULL){
path <- enc2native(normalizePath(path[1], mustWork = TRUE))
if(!is.null(type)){
stopifnot(is.character(type))
}
structure(list(path = path, type = type), class = "form_file")
}
#' @export
#' @name multipart
#' @rdname multipart
#' @param value a character or raw vector to post
form_data <- function(value, type = NULL){
if(is.character(value))
value <- charToRaw(paste(enc2utf8(value), collapse = "\n"))
if(!is.raw(value))
stop("Argument 'value' must be string or raw vector")
structure(list(value = value, type = type), class = "form_data")
}
#' @export
print.form_file <- function(x, ...){
txt <- paste("Form file:", basename(x$path))
if(!is.null(x$type)){
txt <- sprintf("%s (type: %s)", txt, x$type)
}
cat(txt, "\n")
}
#' @export
print.form_data <- function(x, ...){
txt <- paste(sprintf("Form data of length %d", length(x$value)))
if(!is.null(x$type)){
txt <- sprintf("%s (type: %s)", txt, x$type)
}
cat(txt, "\n")
}

46
tmp/form.c

@ -1,46 +0,0 @@
#include "curl-common.h"
struct curl_httppost* make_form(SEXP form){
struct curl_httppost* post = NULL;
struct curl_httppost* last = NULL;
SEXP ln = PROTECT(getAttrib(form, R_NamesSymbol));
for(int i = 0; i < length(form); i++){
const char *name = translateCharUTF8(STRING_ELT(ln, i));
SEXP val = VECTOR_ELT(form, i);
if(TYPEOF(val) == RAWSXP){
long datalen = Rf_length(val);
if(datalen > 0){
unsigned char * data = RAW(val);
curl_formadd(&post, &last, CURLFORM_COPYNAME, name, CURLFORM_COPYCONTENTS, data, CURLFORM_CONTENTSLENGTH, datalen, CURLFORM_END);
} else {
//Note if 'CURLFORM_CONTENTLEN == 0' then libcurl assumes strlen() !
curl_formadd(&post, &last, CURLFORM_COPYNAME, name, CURLFORM_COPYCONTENTS, "", CURLFORM_END);
}
} else if(isVector(val) && Rf_length(val)){
if(isString(VECTOR_ELT(val, 0))){
//assume a form_file upload
const char * path = CHAR(asChar(VECTOR_ELT(val, 0)));
if(isString(VECTOR_ELT(val, 1))){
const char *content_type = CHAR(asChar(VECTOR_ELT(val, 1)));
curl_formadd(&post, &last, CURLFORM_COPYNAME, name, CURLFORM_FILE, path, CURLFORM_CONTENTTYPE, content_type, CURLFORM_END);
} else {
curl_formadd(&post, &last, CURLFORM_COPYNAME, name, CURLFORM_FILE, path, CURLFORM_END);
}
} else {
//assume a form_value upload
unsigned char * data = RAW(VECTOR_ELT(val, 0));
long datalen = Rf_length(VECTOR_ELT(val, 0));
if(isString(VECTOR_ELT(val, 1))){
const char * content_type = CHAR(asChar(VECTOR_ELT(val, 1)));
curl_formadd(&post, &last, CURLFORM_COPYNAME, name, CURLFORM_COPYCONTENTS, data, CURLFORM_CONTENTSLENGTH, datalen, CURLFORM_CONTENTTYPE, content_type, CURLFORM_END);
} else {
curl_formadd(&post, &last, CURLFORM_COPYNAME, name, CURLFORM_COPYCONTENTS, data, CURLFORM_CONTENTSLENGTH, datalen, CURLFORM_END);
}
}
} else {
error("form value %s not supported", name);
}
}
UNPROTECT(1);
return post;
}

17
tmp/getdate.c

@ -1,17 +0,0 @@
#include <curl/curl.h>
#include <Rinternals.h>
SEXP R_curl_getdate(SEXP datestring) {
if(!isString(datestring))
error("Argument 'datestring' must be string.");
int len = length(datestring);
SEXP out = PROTECT(allocVector(INTSXP, len));
for(int i = 0; i < len; i++){
time_t date = curl_getdate(CHAR(STRING_ELT(datestring, i)), NULL);
INTEGER(out)[i] = date < 0 ? NA_INTEGER : (int) date;
}
UNPROTECT(1);
return out;
}

209
tmp/handle.R

@ -1,209 +0,0 @@
#' Create and configure a curl handle
#'
#' Handles are the work horses of libcurl. A handle is used to configure a
#' request with custom options, headers and payload. Once the handle has been
#' set up, it can be passed to any of the download functions such as \code{\link{curl}}
#' ,\code{\link{curl_download}} or \code{\link{curl_fetch_memory}}. The handle will maintain
#' state in between requests, including keep-alive connections, cookies and
#' settings.
#'
#' Use \code{new_handle()} to create a new clean curl handle that can be
#' configured with custom options and headers. Note that \code{handle_setopt}
#' appends or overrides options in the handle, whereas \code{handle_setheaders}
#' replaces the entire set of headers with the new ones. The \code{handle_reset}
#' function resets only options/headers/forms in the handle. It does not affect
#' active connections, cookies or response data from previous requests. The safest
#' way to perform multiple independent requests is by using a separate handle for
#' each request. There is very little performance overhead in creating handles.
#'
#' @family handles
#' @param ... named options / headers to be set in the handle.
#' To send a file, see \code{\link{form_file}}. To list all allowed options,
#' see \code{\link{curl_options}}
#' @return A handle object (external pointer to the underlying curl handle).
#' All functions modify the handle in place but also return the handle
#' so you can create a pipeline of operations.
#' @export
#' @name handle
#' @useDynLib curl R_new_handle
#' @rdname handle
#' @examples
#' h <- new_handle()
#' handle_setopt(h, customrequest = "PUT")
#' handle_setform(h, a = "1", b = "2")
#' r <- curl_fetch_memory("http://httpbin.org/put", h)
#' cat(rawToChar(r$content))
#'
#' # Or use the list form
#' h <- new_handle()
#' handle_setopt(h, .list = list(customrequest = "PUT"))
#' handle_setform(h, .list = list(a = "1", b = "2"))
#' r <- curl_fetch_memory("http://httpbin.org/put", h)
#' cat(rawToChar(r$content))
new_handle <- function(...){
h <- .Call(R_new_handle)
handle_setopt(h, ...)
h
}
#' @export
#' @useDynLib curl R_handle_setopt
#' @param handle Handle to modify
#' @param .list A named list of options. This is useful if you've created
#' a list of options elsewhere, avoiding the use of \code{do.call()}.
#' @rdname handle
handle_setopt <- function(handle, ..., .list = list()){
stopifnot(inherits(handle, "curl_handle"))
values <- c(list(...), .list)
opt_names <- fix_options(tolower(names(values)))
keys <- as.integer(curl_options()[opt_names])
na_keys <- is.na(keys)
if(any(na_keys)){
bad_opts <- opt_names[na_keys]
stop("Unknown option", ifelse(length(bad_opts) > 1, "s: ", ": "),
paste(bad_opts, collapse=", "))
}
stopifnot(length(keys) == length(values))
.Call(R_handle_setopt, handle, keys, values)
invisible(handle)
}
#' @export
#' @useDynLib curl R_handle_setheaders
#' @rdname handle
handle_setheaders <- function(handle, ..., .list = list()){
stopifnot(inherits(handle, "curl_handle"))
opts <- c(list(...), .list)
if(!all(vapply(opts, is.character, logical(1)))){
stop("All headers must be strings.")
}
opts$Expect = ""
names <- names(opts)
values <- as.character(unlist(opts))
vec <- paste0(names, ": ", values)
.Call(R_handle_setheaders, handle, vec)
invisible(handle)
}
#' @useDynLib curl R_handle_getheaders
#' @rdname handle
handle_getheaders <- function(handle){
stopifnot(inherits(handle, "curl_handle"))
.Call(R_handle_getheaders, handle)
}
#' @useDynLib curl R_handle_getcustom
#' @rdname handle
handle_getcustom <- function(handle){
stopifnot(inherits(handle, "curl_handle"))
.Call(R_handle_getcustom, handle)
}
#' @export
#' @useDynLib curl R_handle_setform
#' @rdname handle
handle_setform <- function(handle, ..., .list = list()){
stopifnot(inherits(handle, "curl_handle"))
form <- c(list(...), .list)
for(i in seq_along(form)){
val <- form[[i]];
if(is.character(val)){
form[[i]] <- charToRaw(enc2utf8(val))
} else if(!is.raw(val) && !inherits(val, "form_file") && !inherits(val, "form_data")){
stop("Unsupported value type for form field '", names(form[i]), "'.")
}
}
.Call(R_handle_setform, handle, form)
invisible(handle)
}
#' @export
#' @rdname handle
#' @useDynLib curl R_handle_reset
handle_reset <- function(handle){
stopifnot(inherits(handle, "curl_handle"))
.Call(R_handle_reset, handle)
invisible(handle)
}
#' Extract cookies from a handle
#'
#' The \code{handle_cookies} function returns a data frame with 7 columns as specified in the
#' \href{http://www.cookiecentral.com/faq/#3.5}{netscape cookie file format}.
#'
#' @useDynLib curl R_get_handle_cookies
#' @export
#' @param handle a curl handle object
#' @family handles
#' @examples
#' h <- new_handle()
#' handle_cookies(h)
#'
#' # Server sets cookies
#' req <- curl_fetch_memory("http://httpbin.org/cookies/set?foo=123&bar=ftw", handle = h)
#' handle_cookies(h)
#'
#' # Server deletes cookies
#' req <- curl_fetch_memory("http://httpbin.org/cookies/delete?foo", handle = h)
#' handle_cookies(h)
#'
#' # Cookies will survive a reset!
#' handle_reset(h)
#' handle_cookies(h)
handle_cookies <- function(handle){
stopifnot(inherits(handle, "curl_handle"))
cookies <- .Call(R_get_handle_cookies, handle)
df <- if(length(cookies)){
values <- lapply(strsplit(cookies, split="\t"), `[`, 1:7)
as.data.frame(do.call(rbind, values), stringsAsFactors = FALSE)
} else {
as.data.frame(matrix(ncol=7, nrow=0))
}
names(df) <- c("domain", "flag", "path", "secure", "expiration", "name", "value")
df$flag <- as.logical(df$flag)
df$secure <- as.logical(df$secure)
expires <- as.numeric(df$expiration)
expires[expires==0] <- Inf
class(expires) = c("POSIXct", "POSIXt");
df$expiration <- expires
df
}
#' @export
#' @rdname handle
#' @useDynLib curl R_get_handle_response
handle_data <- function(handle){
stopifnot(inherits(handle, "curl_handle"))
out <- .Call(R_get_handle_response, handle)
out$content = NULL
out
}
#' @export
print.curl_handle <- function(x, ...){
stopifnot(inherits(x, "curl_handle"))
url <- handle_data(x)$url
if(!nchar(url)) url <- "empty"
cat(sprintf("<curl handle> (%s)\n", url))
}
# Only for testing memory leaks
#' @useDynLib curl R_total_handles
total_handles <- function(){
.Call(R_total_handles)
}
## Some hacks for backward compatibilty
fix_options <- function(opt_names){
# Recent libcurl should use xferinfo instead of progress
has_xferinfo <- length(curl_options("xferinfofunction"))
if(has_xferinfo){
opt_names[opt_names == "progressfunction"] <- "xferinfofunction"
return(opt_names)
} else {
opt_names[opt_names == "xferinfofunction"] <- "progressfunction"
return(opt_names)
}
}

484
tmp/handle.c

@ -1,484 +0,0 @@
#include "curl-common.h"
#include "callbacks.h"
/* These are defined in typechecking.c */
extern int r_curl_is_slist_option(CURLoption x);
extern int r_curl_is_long_option(CURLoption x);
extern int r_curl_is_off_t_option(CURLoption x);
extern int r_curl_is_string_option(CURLoption x);
extern int r_curl_is_postfields_option(CURLoption x);
#define make_string(x) x ? Rf_mkString(x) : ScalarString(NA_STRING)
#ifndef MAX_PATH
#define MAX_PATH 1024
#endif
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 47)
#define HAS_HTTP_VERSION_2TLS 1
#endif
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 32)
#define HAS_XFERINFOFUNCTION 1
#endif
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 36)
#define HAS_CURLOPT_EXPECT_100_TIMEOUT_MS 1
#endif
char CA_BUNDLE[MAX_PATH];
extern int windows_openssl;
SEXP R_set_bundle(SEXP path){
strcpy(CA_BUNDLE, CHAR(asChar(path)));
return mkString(CA_BUNDLE);
}
SEXP R_get_bundle(){
return mkString(CA_BUNDLE);
}
int total_handles = 0;
void clean_handle(reference *ref){
if(ref->refCount == 0){
if(ref->headers)
curl_slist_free_all(ref->headers);
if(ref->custom)
curl_slist_free_all(ref->custom);
if(ref->form)
curl_formfree(ref->form);
if(ref->handle)
curl_easy_cleanup(ref->handle);
if(ref->resheaders.buf)
free(ref->resheaders.buf);
free(ref);
total_handles--;
}
}
void fin_handle(SEXP ptr){
reference *ref = (reference*) R_ExternalPtrAddr(ptr);
//this kind of strange but the multi finalizer needs the ptr value
//if it is still pending
ref->refCount--;
if(ref->refCount == 0)
R_ClearExternalPtr(ptr);
//free stuff
clean_handle(ref);
}
/* the default readfunc os fread which can cause R to freeze */
size_t dummy_read(char *buffer, size_t size, size_t nitems, void *instream){
return 0;
}
#ifdef HAS_XFERINFOFUNCTION
#define xftype curl_off_t
#else
#define xftype double
#endif
static int xferinfo_callback(void *clientp, xftype dltotal, xftype dlnow, xftype ultotal, xftype ulnow){
static xftype dlprev = 0;
static xftype ulprev = 0;
if(dlnow && dlnow != dlprev){
dlprev = dlnow;
if(dltotal){
int pct_dn = (100 * dlnow)/dltotal;
REprintf("\r [%d%%] Downloaded %.0lf bytes...", (double) dlnow, pct_dn);
if(dlnow == dltotal)
REprintf("\n");
} else {
REprintf("\r Downloaded %.0lf bytes...", (double) dlnow);
}
} else if(ulnow && ulnow != ulprev){
ulprev = ulnow;
int pct_up = (100 * ulnow)/ultotal;
REprintf("\r [%d%%] Uploaded %.0lf bytes...", (double) ulnow, pct_up);
if(ulnow == ultotal)
REprintf("\n");
}
return 0;
}
/* Set default headers here, these are only allocated once */
static struct curl_slist * default_headers(){
static struct curl_slist * headers = NULL;
if(headers == NULL){
headers = curl_slist_append(headers, "Expect:");
}
return headers;
}
static void set_headers(reference *ref, struct curl_slist *newheaders){
if(ref->headers)
curl_slist_free_all(ref->headers);
ref->headers = newheaders;
assert(curl_easy_setopt(ref->handle, CURLOPT_HTTPHEADER,
newheaders ? newheaders : default_headers()));
}
/* These are defaulst that we always want to set */
static void set_handle_defaults(reference *ref){
/* the actual curl handle */
CURL *handle = ref->handle;
assert(curl_easy_setopt(handle, CURLOPT_PRIVATE, ref));
/* set the response header collector */
reset_resheaders(ref);
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, append_buffer);
curl_easy_setopt(handle, CURLOPT_HEADERDATA, &(ref->resheaders));
#ifdef _WIN32
if(windows_openssl == 1){
if( CA_BUNDLE != NULL && strlen(CA_BUNDLE)){
/* on windows a cert bundle is included with R version 3.2.0 */
curl_easy_setopt(handle, CURLOPT_CAINFO, CA_BUNDLE);
} else {
/* disable cert validation for older versions of R */
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);
}
}
#endif
/* needed to support compressed responses */
assert(curl_easy_setopt(handle, CURLOPT_ENCODING, ""));
/* follow redirect */
assert(curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L));
assert(curl_easy_setopt(handle, CURLOPT_MAXREDIRS, 10L));
/* a sensible timeout (10s) */
assert(curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, 10L));
/* needed to start the cookie engine */
assert(curl_easy_setopt(handle, CURLOPT_COOKIEFILE, ""));
assert(curl_easy_setopt(handle, CURLOPT_FILETIME, 1L));
/* set the default user agent */
SEXP agent = GetOption1(install("HTTPUserAgent"));
if(isString(agent) && Rf_length(agent)){
assert(curl_easy_setopt(handle, CURLOPT_USERAGENT, CHAR(STRING_ELT(agent, 0))));
} else {
assert(curl_easy_setopt(handle, CURLOPT_USERAGENT, "r/curl/jeroen"));
}
/* allow all authentication methods */
assert(curl_easy_setopt(handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY));
assert(curl_easy_setopt(handle, CURLOPT_UNRESTRICTED_AUTH, 1L));
assert(curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY));
/* enables HTTP2 on HTTPS (match behavior of curl cmd util) */
#if defined(CURL_VERSION_HTTP2) && defined(HAS_HTTP_VERSION_2TLS)
if(curl_version_info(CURLVERSION_NOW)->features & CURL_VERSION_HTTP2)
assert(curl_easy_setopt(handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS));
#endif
/* set an error buffer */
assert(curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, ref->errbuf));
/* dummy readfunction because default can freeze R */
assert(curl_easy_setopt(handle, CURLOPT_READFUNCTION, dummy_read));
/* seems to be needed for native WinSSL */
#ifdef _WIN32
curl_easy_setopt(handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
#endif
/* set default progress printer (disabled by default) */
#ifdef HAS_XFERINFOFUNCTION
assert(curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, xferinfo_callback));
#else
assert(curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, xferinfo_callback));
#endif
/* Disable the 'Expect: 100' header (deprecated in recent libcurl) */
set_headers(ref, NULL);
#ifdef HAS_CURLOPT_EXPECT_100_TIMEOUT_MS
assert(curl_easy_setopt(handle, CURLOPT_EXPECT_100_TIMEOUT_MS, 0L));
#endif
}
SEXP R_new_handle(){
reference *ref = calloc(1, sizeof(reference));
ref->refCount = 1;
ref->handle = curl_easy_init();
total_handles++;
set_handle_defaults(ref);
SEXP prot = PROTECT(allocVector(VECSXP, 5)); //for protecting callback functions
SEXP ptr = PROTECT(R_MakeExternalPtr(ref, R_NilValue, prot));
R_RegisterCFinalizerEx(ptr, fin_handle, TRUE);
setAttrib(ptr, R_ClassSymbol, mkString("curl_handle"));
UNPROTECT(2);
ref->handleptr = ptr;
return ptr;
}
SEXP R_handle_reset(SEXP ptr){
//reset all fields
reference *ref = get_ref(ptr);
set_form(ref, NULL);
reset_errbuf(ref);
curl_easy_reset(ref->handle);
//clear custom vector field
if(ref->custom){
curl_slist_free_all(ref->custom);
ref->custom = NULL;
}
//restore default settings
set_handle_defaults(ref);
return ScalarLogical(1);
}
SEXP R_handle_setheaders(SEXP ptr, SEXP vec){
if(!isString(vec))
error("header vector must be a string.");
set_headers(get_ref(ptr), vec_to_slist(vec));
return ScalarLogical(1);
}
SEXP R_handle_getheaders(SEXP ptr){
reference *ref = get_ref(ptr);
return slist_to_vec(ref->headers);
}
SEXP R_handle_getcustom(SEXP ptr){
reference *ref = get_ref(ptr);
return slist_to_vec(ref->custom);
}
SEXP R_handle_setopt(SEXP ptr, SEXP keys, SEXP values){
reference *ref = get_ref(ptr);
CURL *handle = get_handle(ptr);
SEXP prot = R_ExternalPtrProtected(ptr);
SEXP optnames = PROTECT(getAttrib(values, R_NamesSymbol));
if(!isInteger(keys))
error("keys` must be an integer");
if(!isVector(values))
error("`values` must be a list");
for(int i = 0; i < length(keys); i++){
int key = INTEGER(keys)[i];
const char* optname = CHAR(STRING_ELT(optnames, i));
SEXP val = VECTOR_ELT(values, i);
if(val == R_NilValue){
assert(curl_easy_setopt(handle, key, NULL));
#ifdef HAS_XFERINFOFUNCTION
} else if (key == CURLOPT_XFERINFOFUNCTION) {
if (TYPEOF(val) != CLOSXP)
error("Value for option %s (%d) must be a function.", optname, key);
assert(curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION,
(curl_progress_callback) R_curl_callback_xferinfo));
assert(curl_easy_setopt(handle, CURLOPT_XFERINFODATA, val));
assert(curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0));
SET_VECTOR_ELT(prot, 1, val); //protect gc
#endif
} else if (key == CURLOPT_PROGRESSFUNCTION) {
if (TYPEOF(val) != CLOSXP)
error("Value for option %s (%d) must be a function.", optname, key);
assert(curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION,
(curl_progress_callback) R_curl_callback_progress));
assert(curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, val));
assert(curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0));
SET_VECTOR_ELT(prot, 2, val); //protect gc
} else if (key == CURLOPT_READFUNCTION) {
if (TYPEOF(val) != CLOSXP)
error("Value for option %s (%d) must be a function.", optname, key);
assert(curl_easy_setopt(handle, CURLOPT_READFUNCTION,
(curl_read_callback) R_curl_callback_read));
assert(curl_easy_setopt(handle, CURLOPT_READDATA, val));
SET_VECTOR_ELT(prot, 3, val); //protect gc
} else if (key == CURLOPT_DEBUGFUNCTION) {
if (TYPEOF(val) != CLOSXP)
error("Value for option %s (%d) must be a function.", optname, key);
assert(curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION,
(curl_debug_callback) R_curl_callback_debug));
assert(curl_easy_setopt(handle, CURLOPT_DEBUGDATA, val));
SET_VECTOR_ELT(prot, 4, val); //protect gc
} else if (key == CURLOPT_URL) {
/* always use utf-8 for urls */
const char * url_utf8 = translateCharUTF8(STRING_ELT(val, 0));
assert(curl_easy_setopt(handle, CURLOPT_URL, url_utf8));
} else if(key == CURLOPT_HTTPHEADER){
R_handle_setheaders(ptr, val);
} else if (r_curl_is_slist_option(key)) {
if(!isString(val))
error("Value for option %s (%d) must be a string vector", optname, key);
ref->custom = vec_to_slist(val);
assert(curl_easy_setopt(handle, key, ref->custom));
} else if(r_curl_is_long_option(key)){
if(!isNumeric(val) || length(val) != 1) {
error("Value for option %s (%d) must be a number.", optname, key);
}
assert(curl_easy_setopt(handle, key, (long) asInteger(val)));
} else if(r_curl_is_off_t_option(key)){
if(!isNumeric(val) || length(val) != 1) {
error("Value for option %s (%d) must be a number.", optname, key);
}
assert(curl_easy_setopt(handle, key, (curl_off_t) asReal(val)));
} else if(r_curl_is_string_option(key) || r_curl_is_postfields_option(key)){
switch (TYPEOF(val)) {
case RAWSXP:
if(key == CURLOPT_POSTFIELDS || key == CURLOPT_COPYPOSTFIELDS)
assert(curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t) Rf_length(val)));
assert(curl_easy_setopt(handle, key, RAW(val)));
break;
case STRSXP:
if (length(val) != 1)
error("Value for option %s (%d) must be length-1 string", optname, key);
assert(curl_easy_setopt(handle, key, CHAR(STRING_ELT(val, 0))));
break;
default:
error("Value for option %s (%d) must be a string or raw vector.", optname, key);
}
} else {
error("Option %s (%d) has unknown or unsupported type.", optname, key);
}
}
UNPROTECT(1);
return ScalarLogical(1);
}
SEXP R_handle_setform(SEXP ptr, SEXP form){
if(!isVector(form))
error("Form must be a list.");
set_form(get_ref(ptr), make_form(form));
return ScalarLogical(1);
}
SEXP make_timevec(CURL *handle){
double time_redirect, time_lookup, time_connect, time_pre, time_start, time_total;
assert(curl_easy_getinfo(handle, CURLINFO_REDIRECT_TIME, &time_redirect));
assert(curl_easy_getinfo(handle, CURLINFO_NAMELOOKUP_TIME, &time_lookup));
assert(curl_easy_getinfo(handle, CURLINFO_CONNECT_TIME, &time_connect));
assert(curl_easy_getinfo(handle, CURLINFO_PRETRANSFER_TIME, &time_pre));
assert(curl_easy_getinfo(handle, CURLINFO_STARTTRANSFER_TIME, &time_start));
assert(curl_easy_getinfo(handle, CURLINFO_TOTAL_TIME, &time_total));
SEXP result = PROTECT(allocVector(REALSXP, 6));
REAL(result)[0] = time_redirect;
REAL(result)[1] = time_lookup;
REAL(result)[2] = time_connect;
REAL(result)[3] = time_pre;
REAL(result)[4] = time_start;
REAL(result)[5] = time_total;
SEXP names = PROTECT(allocVector(STRSXP, 6));
SET_STRING_ELT(names, 0, mkChar("redirect"));
SET_STRING_ELT(names, 1, mkChar("namelookup"));
SET_STRING_ELT(names, 2, mkChar("connect"));
SET_STRING_ELT(names, 3, mkChar("pretransfer"));
SET_STRING_ELT(names, 4, mkChar("starttransfer"));
SET_STRING_ELT(names, 5, mkChar("total"));
setAttrib(result, R_NamesSymbol, names);
UNPROTECT(2);
return result;
}
/* Extract current cookies (state) from handle */
SEXP make_cookievec(CURL *handle){
/* linked list of strings */
struct curl_slist *cookies;
assert(curl_easy_getinfo(handle, CURLINFO_COOKIELIST, &cookies));
SEXP out = slist_to_vec(cookies);
curl_slist_free_all(cookies);
return out;
}
SEXP make_status(CURL *handle){
long res_status;
assert(curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &res_status));
return ScalarInteger(res_status);
}
SEXP make_ctype(CURL *handle){
char * ct;
assert(curl_easy_getinfo(handle, CURLINFO_CONTENT_TYPE, &ct));
return make_string(ct);
}
SEXP make_url(CURL *handle){
char *res_url;
assert(curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &res_url));
return ScalarString(mkCharCE(res_url, CE_UTF8));
}
SEXP make_filetime(CURL *handle){
long filetime;
assert(curl_easy_getinfo(handle, CURLINFO_FILETIME, &filetime));
if(filetime < 0){
filetime = NA_INTEGER;
}
SEXP classes = PROTECT(allocVector(STRSXP, 2));
SET_STRING_ELT(classes, 0, mkChar("POSIXct"));
SET_STRING_ELT(classes, 1, mkChar("POSIXt"));
SEXP out = PROTECT(ScalarInteger(filetime));
setAttrib(out, R_ClassSymbol, classes);
UNPROTECT(2);
return out;
}
SEXP make_rawvec(unsigned char *ptr, size_t size){
SEXP out = PROTECT(allocVector(RAWSXP, size));
if(size > 0)
memcpy(RAW(out), ptr, size);
UNPROTECT(1);
return out;
}
SEXP make_namesvec(){
SEXP names = PROTECT(allocVector(STRSXP, 7));
SET_STRING_ELT(names, 0, mkChar("url"));
SET_STRING_ELT(names, 1, mkChar("status_code"));
SET_STRING_ELT(names, 2, mkChar("type"));
SET_STRING_ELT(names, 3, mkChar("headers"));
SET_STRING_ELT(names, 4, mkChar("modified"));
SET_STRING_ELT(names, 5, mkChar("times"));
SET_STRING_ELT(names, 6, mkChar("content"));
UNPROTECT(1);
return names;
}
SEXP R_get_handle_cookies(SEXP ptr){
return make_cookievec(get_handle(ptr));
}
SEXP make_handle_response(reference *ref){
CURL *handle = ref->handle;
SEXP res = PROTECT(allocVector(VECSXP, 7));
SET_VECTOR_ELT(res, 0, make_url(handle));
SET_VECTOR_ELT(res, 1, make_status(handle));
SET_VECTOR_ELT(res, 2, make_ctype(handle));
SET_VECTOR_ELT(res, 3, make_rawvec(ref->resheaders.buf, ref->resheaders.size));
SET_VECTOR_ELT(res, 4, make_filetime(handle));
SET_VECTOR_ELT(res, 5, make_timevec(handle));
SET_VECTOR_ELT(res, 6, R_NilValue);
setAttrib(res, R_NamesSymbol, make_namesvec());
UNPROTECT(1);
return res;
}
SEXP R_get_handle_response(SEXP ptr){
/* get the handle */
reference *ref = get_ref(ptr);
return make_handle_response(ref);
}
SEXP R_total_handles(){
return(ScalarInteger(total_handles));
}

177
tmp/ieproxy.c

@ -1,177 +0,0 @@
#include <Rinternals.h>
#ifdef _WIN32
#include <Windows.h>
#include <Winhttp.h>
#include <stdlib.h>
#define WINHTTP_AUTO_DETECT_TYPE_DHCP 0x00000001
#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 0x00000002
#define WINHTTP_AUTOPROXY_AUTO_DETECT 0x00000001
#define WINHTTP_AUTOPROXY_CONFIG_URL 0x00000002
#define WINHTTP_AUTOPROXY_RUN_INPROCESS 0x00010000
#define WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY 0x00020000
SEXP proxy_namesvec(){
SEXP names = PROTECT(allocVector(STRSXP, 4));
SET_STRING_ELT(names, 0, mkChar("AutoDetect"));
SET_STRING_ELT(names, 1, mkChar("AutoConfigUrl"));
SET_STRING_ELT(names, 2, mkChar("Proxy"));
SET_STRING_ELT(names, 3, mkChar("ProxyBypass"));
UNPROTECT(1);
return names;
}
SEXP auto_namesvec(){
SEXP names = PROTECT(allocVector(STRSXP, 3));
SET_STRING_ELT(names, 0, mkChar("HasProxy"));
SET_STRING_ELT(names, 1, mkChar("Proxy"));
SET_STRING_ELT(names, 2, mkChar("ProxyBypass"));
UNPROTECT(1);
return names;
}
SEXP R_proxy_info(){
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG MyProxyConfig;
if(!WinHttpGetIEProxyConfigForCurrentUser(&MyProxyConfig)){
return R_NilValue;
}
char buffer[500];
SEXP vec = PROTECT(allocVector(VECSXP, 4));
SET_VECTOR_ELT(vec, 0, ScalarLogical(MyProxyConfig.fAutoDetect));
if(MyProxyConfig.lpszAutoConfigUrl != NULL) {
wcstombs(buffer, MyProxyConfig.lpszAutoConfigUrl, 500);
SET_VECTOR_ELT(vec, 1, mkString(buffer));
}
if(MyProxyConfig.lpszProxy != NULL) {
wcstombs(buffer, MyProxyConfig.lpszProxy, 500);
SET_VECTOR_ELT(vec, 2, mkString(buffer));
}
if(MyProxyConfig.lpszProxyBypass != NULL) {
wcstombs(buffer, MyProxyConfig.lpszProxyBypass, 500);
SET_VECTOR_ELT(vec, 3, mkString(buffer));
}
setAttrib(vec, R_NamesSymbol, proxy_namesvec());
UNPROTECT(1);
return vec;
}
SEXP R_get_proxy_for_url(SEXP target_url, SEXP auto_detect, SEXP autoproxy_url){
// Convert char to windows strings
wchar_t *longurl = (wchar_t *) calloc(10000, sizeof(int));
mbstowcs(longurl, CHAR(STRING_ELT(target_url, 0)), LENGTH(STRING_ELT(target_url, 0)));
// Some settings
WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
WINHTTP_PROXY_INFO ProxyInfo;
// Clear memory
ZeroMemory( &AutoProxyOptions, sizeof(AutoProxyOptions) );
ZeroMemory( &ProxyInfo, sizeof(ProxyInfo) );
// Create the WinHTTP session.
HINTERNET hHttpSession = WinHttpOpen( L"WinHTTP AutoProxy Sample/1.0",
WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
// Exit if WinHttpOpen failed.
if( !hHttpSession )
error("Call to WinHttpOpen failed.");
// Auto-detection doesn't work very well
if(asLogical(auto_detect)){
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
}
// Use manual URL instead
if(isString(autoproxy_url) && LENGTH(autoproxy_url)){
wchar_t *autourl = (wchar_t *) calloc(10000, sizeof(int));
mbstowcs(autourl, CHAR(STRING_ELT(autoproxy_url, 0)), LENGTH(STRING_ELT(autoproxy_url, 0)));
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
AutoProxyOptions.lpszAutoConfigUrl = autourl;
}
// Use DHCP and DNS-based auto-detection.
AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
// This downloads and runs the JavaScript to map the url to a proxy
if(!WinHttpGetProxyForUrl( hHttpSession, longurl, &AutoProxyOptions, &ProxyInfo)){
DWORD err = GetLastError();
switch(err){
case ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR:
error("ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR");
case ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT:
error("ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT");
case ERROR_WINHTTP_INCORRECT_HANDLE_TYPE:
error("ERROR_WINHTTP_INCORRECT_HANDLE_TYPE");
case ERROR_WINHTTP_INTERNAL_ERROR:
error("ERROR_WINHTTP_INTERNAL_ERROR");
case ERROR_WINHTTP_INVALID_URL:
error("ERROR_WINHTTP_INVALID_URL");
case ERROR_WINHTTP_LOGIN_FAILURE:
error("ERROR_WINHTTP_LOGIN_FAILURE");
case ERROR_WINHTTP_OPERATION_CANCELLED:
error("ERROR_WINHTTP_OPERATION_CANCELLED");
case ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT:
error("ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT");
case ERROR_WINHTTP_UNRECOGNIZED_SCHEME:
error("ERROR_WINHTTP_UNRECOGNIZED_SCHEME");
case ERROR_NOT_ENOUGH_MEMORY:
error("ERROR_NOT_ENOUGH_MEMORY");
}
}
//store output data
char buffer[500];
SEXP vec = PROTECT(allocVector(VECSXP, 3));
SET_VECTOR_ELT(vec, 0, ScalarLogical(
ProxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_NAMED_PROXY ||
ProxyInfo.dwAccessType == WINHTTP_ACCESS_TYPE_DEFAULT_PROXY));
if(ProxyInfo.lpszProxy != NULL) {
wcstombs(buffer, ProxyInfo.lpszProxy, 500);
SET_VECTOR_ELT(vec, 1, mkString(buffer));
GlobalFree((void*) ProxyInfo.lpszProxy);
}
if(ProxyInfo.lpszProxyBypass != NULL) {
wcstombs(buffer, ProxyInfo.lpszProxyBypass, 500);
SET_VECTOR_ELT(vec, 2, mkString(buffer));
GlobalFree((void*) ProxyInfo.lpszProxyBypass );
}
//clean up
WinHttpCloseHandle( hHttpSession );
//return
setAttrib(vec, R_NamesSymbol, auto_namesvec());
UNPROTECT(1);
return vec;
}
SEXP R_windows_build(){
DWORD dwBuild = 0;
DWORD dwVersion = GetVersion();
if (dwVersion < 0x80000000)
dwBuild = (DWORD)(HIWORD(dwVersion));
return ScalarInteger(dwBuild);
}
#else //_WIN32
SEXP R_proxy_info(){
return R_NilValue;
}
SEXP R_get_proxy_for_url(SEXP target_url, SEXP auto_detect, SEXP autoproxy_url){
return R_NilValue;
}
SEXP R_windows_build(){
return R_NilValue;
}
#endif //_WIN32

96
tmp/init.c

@ -1,96 +0,0 @@
#include <R.h>
#include <Rinternals.h>
#include <stdlib.h> // for NULL
#include <R_ext/Rdynload.h>
#include <R_ext/Visibility.h>
#include <curl/curl.h>
/* .Call calls */
extern SEXP R_curl_connection(SEXP, SEXP, SEXP);
extern SEXP R_curl_escape(SEXP, SEXP);
extern SEXP R_curl_fetch_disk(SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP R_curl_fetch_memory(SEXP, SEXP, SEXP);
extern SEXP R_curl_getdate(SEXP);
extern SEXP R_curl_version();
extern SEXP R_download_curl(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP R_get_bundle();
extern SEXP R_get_handle_cookies(SEXP);
extern SEXP R_get_handle_response(SEXP);
extern SEXP R_get_proxy_for_url(SEXP, SEXP, SEXP);
extern SEXP R_handle_getcustom(SEXP);
extern SEXP R_handle_getheaders(SEXP);
extern SEXP R_handle_reset(SEXP);
extern SEXP R_handle_setform(SEXP, SEXP);
extern SEXP R_handle_setheaders(SEXP, SEXP);
extern SEXP R_handle_setopt(SEXP, SEXP, SEXP);
extern SEXP R_multi_add(SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP R_multi_cancel(SEXP);
extern SEXP R_multi_fdset(SEXP);
extern SEXP R_multi_list(SEXP);
extern SEXP R_multi_new();
extern SEXP R_multi_run(SEXP, SEXP, SEXP);
extern SEXP R_multi_setopt(SEXP, SEXP, SEXP, SEXP);
extern SEXP R_new_file_writer(SEXP);
extern SEXP R_new_handle();
extern SEXP R_nslookup(SEXP, SEXP);
extern SEXP R_proxy_info();
extern SEXP R_set_bundle(SEXP);
extern SEXP R_split_string(SEXP, SEXP);
extern SEXP R_total_handles();
extern SEXP R_total_writers();
extern SEXP R_windows_build();
extern SEXP R_write_file_writer(SEXP, SEXP, SEXP);
static const R_CallMethodDef CallEntries[] = {
{"R_curl_connection", (DL_FUNC) &R_curl_connection, 3},
{"R_curl_escape", (DL_FUNC) &R_curl_escape, 2},
{"R_curl_fetch_disk", (DL_FUNC) &R_curl_fetch_disk, 5},
{"R_curl_fetch_memory", (DL_FUNC) &R_curl_fetch_memory, 3},
{"R_curl_getdate", (DL_FUNC) &R_curl_getdate, 1},
{"R_curl_version", (DL_FUNC) &R_curl_version, 0},
{"R_download_curl", (DL_FUNC) &R_download_curl, 6},
{"R_get_bundle", (DL_FUNC) &R_get_bundle, 0},
{"R_get_handle_cookies", (DL_FUNC) &R_get_handle_cookies, 1},
{"R_get_handle_response", (DL_FUNC) &R_get_handle_response, 1},
{"R_get_proxy_for_url", (DL_FUNC) &R_get_proxy_for_url, 3},
{"R_handle_getcustom", (DL_FUNC) &R_handle_getcustom, 1},
{"R_handle_getheaders", (DL_FUNC) &R_handle_getheaders, 1},
{"R_handle_reset", (DL_FUNC) &R_handle_reset, 1},
{"R_handle_setform", (DL_FUNC) &R_handle_setform, 2},
{"R_handle_setheaders", (DL_FUNC) &R_handle_setheaders, 2},
{"R_handle_setopt", (DL_FUNC) &R_handle_setopt, 3},
{"R_multi_add", (DL_FUNC) &R_multi_add, 5},
{"R_multi_cancel", (DL_FUNC) &R_multi_cancel, 1},
{"R_multi_fdset", (DL_FUNC) &R_multi_fdset, 1},
{"R_multi_list", (DL_FUNC) &R_multi_list, 1},
{"R_multi_new", (DL_FUNC) &R_multi_new, 0},
{"R_multi_run", (DL_FUNC) &R_multi_run, 3},
{"R_multi_setopt", (DL_FUNC) &R_multi_setopt, 4},
{"R_new_file_writer", (DL_FUNC) &R_new_file_writer, 1},
{"R_new_handle", (DL_FUNC) &R_new_handle, 0},
{"R_nslookup", (DL_FUNC) &R_nslookup, 2},
{"R_proxy_info", (DL_FUNC) &R_proxy_info, 0},
{"R_set_bundle", (DL_FUNC) &R_set_bundle, 1},
{"R_split_string", (DL_FUNC) &R_split_string, 2},
{"R_total_handles", (DL_FUNC) &R_total_handles, 0},
{"R_total_writers", (DL_FUNC) &R_total_writers, 0},
{"R_windows_build", (DL_FUNC) &R_windows_build, 0},
{"R_write_file_writer", (DL_FUNC) &R_write_file_writer, 3},
{NULL, NULL, 0}
};
void select_ssl_backend();
CURLM *multi_handle = NULL;
attribute_visible void R_init_curl(DllInfo *info) {
select_ssl_backend();
curl_global_init(CURL_GLOBAL_DEFAULT);
multi_handle = curl_multi_init();
R_registerRoutines(info, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(info, FALSE);
}
attribute_visible void R_unload_curl(DllInfo *info) {
curl_multi_cleanup(multi_handle);
//curl_global_cleanup();
}

69
tmp/interrupt.c

@ -1,69 +0,0 @@
/* Non-blocking drop-in replacement for curl_easy_perform with support for
* R interruptions. Based on: https://curl.haxx.se/libcurl/c/multi-single.html
*/
#include <Rinternals.h>
#include "curl-common.h"
/* Check for interrupt without long jumping */
void check_interrupt_fn(void *dummy) {
R_CheckUserInterrupt();
}
int pending_interrupt() {
return !(R_ToplevelExec(check_interrupt_fn, NULL));
}
/* created in init.c */
CURLM * multi_handle;
/* Don't call Rf_error() until we remove the handle from the multi handle! */
CURLcode curl_perform_with_interrupt(CURL *handle){
/* start settings */
CURLcode status = CURLE_FAILED_INIT;
int still_running = 1;
if(CURLM_OK != curl_multi_add_handle(multi_handle, handle)){
return CURLE_FAILED_INIT;
}
/* non blocking downloading */
while(still_running) {
if(pending_interrupt()){
status = CURLE_ABORTED_BY_CALLBACK;
break;
}
#ifdef HAS_MULTI_WAIT
/* wait for activity, timeout or "nothing" */
int numfds;
if(curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds) != CURLM_OK)
break;
#endif
/* Required by old versions of libcurl */
CURLMcode res = CURLM_CALL_MULTI_PERFORM;
while(res == CURLM_CALL_MULTI_PERFORM)
res = curl_multi_perform(multi_handle, &(still_running));
/* check for multi errors */
if(res != CURLM_OK)
break;
}
/* set status if handle has completed. This might be overkill */
if(!still_running){
int msgq = 0;
do {
CURLMsg *m = curl_multi_info_read(multi_handle, &msgq);
if(m && (m->msg == CURLMSG_DONE)){
status = m->data.result;
break;
}
} while (msgq > 0);
}
/* cleanup first */
curl_multi_remove_handle(multi_handle, handle);
return status;
}

202
tmp/multi.R

@ -1,202 +0,0 @@
#' Async Multi Download
#'
#' AJAX style concurrent requests, possibly using HTTP/2 multiplexing.
#' Results are only available via callback functions. Advanced use only!
#'
#' Requests are created in the usual way using a curl \link{handle} and added
#' to the scheduler with \link{multi_add}. This function returns immediately
#' and does not perform the request yet. The user needs to call \link{multi_run}
#' which performs all scheduled requests concurrently. It returns when all
#' requests have completed, or case of a \code{timeout} or \code{SIGINT} (e.g.
#' if the user presses \code{ESC} or \code{CTRL+C} in the console). In case of
#' the latter, simply call \link{multi_run} again to resume pending requests.
#'
#' When the request succeeded, the \code{done} callback gets triggered with
#' the response data. The structure if this data is identical to \link{curl_fetch_memory}.
#' When the request fails, the \code{fail} callback is triggered with an error
#' message. Note that failure here means something went wrong in performing the
#' request such as a connection failure, it does not check the http status code.
#' Just like \link{curl_fetch_memory}, the user has to implement application logic.
#'
#' Raising an error within a callback function stops execution of that function
#' but does not affect other requests.
#'
#' A single handle cannot be used for multiple simultaneous requests. However
#' it is possible to add new requests to a pool while it is running, so you
#' can re-use a handle within the callback of a request from that same handle.
#' It is up to the user to make sure the same handle is not used in concurrent
#' requests.
#'
#' The \link{multi_cancel} function can be used to cancel a pending request.
#' It has no effect if the request was already completed or canceled.
#'
#' The \link{multi_fdset} function returns the file descriptors curl is
#' polling currently, and also a timeout parameter, the number of
#' milliseconds an application should wait (at most) before proceeding. It
#' is equivalent to the \code{curl_multi_fdset} and
#' \code{curl_multi_timeout} calls. It is handy for applications that is
#' expecting input (or writing output) through both curl, and other file
#' descriptors.
#'
#' @name multi
#' @rdname multi
#' @useDynLib curl R_multi_add
#' @param handle a curl \link{handle} with preconfigured \code{url} option.
#' @param done callback function for completed request. Single argument with
#' response data in same structure as \link{curl_fetch_memory}.
#' @param fail callback function called on failed request. Argument contains
#' error message.
#' @param data (advanced) callback function, file path, or connection object for writing
#' incoming data. This callback should only be used for \emph{streaming} applications,
#' where small pieces of incoming data get written before the request has completed. The
#' signature for the callback function is \code{write(data, final = FALSE)}. If set
#' to \code{NULL} the entire response gets buffered internally and returned by in
#' the \code{done} callback (which is usually what you want).
#' @param pool a multi handle created by \link{new_pool}. Default uses a global pool.
#' @export
#' @examples
#' results <- list()
#' success <- function(x){
#' results <<- append(results, list(x))
#' }
#' failure <- function(str){
#' cat(paste("Failed request:", str), file = stderr())
#' }
#' # This handle will take longest (3sec)
#' h1 <- new_handle(url = "https://eu.httpbin.org/delay/3")
#' multi_add(h1, done = success, fail = failure)
#'
#' # This handle writes data to a file
#' con <- file("output.txt")
#' h2 <- new_handle(url = "https://eu.httpbin.org/post", postfields = "bla bla")
#' multi_add(h2, done = success, fail = failure, data = con)
#'
#' # This handle raises an error
#' h3 <- new_handle(url = "https://urldoesnotexist.xyz")
#' multi_add(h3, done = success, fail = failure)
#'
#' # Actually perform the requests
#' multi_run(timeout = 2)
#' multi_run()
#'
#' # Check the file
#' readLines("output.txt")
#' unlink("output.txt")
multi_add <- function(handle, done = NULL, fail = NULL, data = NULL, pool = NULL){
if(is.null(pool))
pool <- multi_default()
if(inherits(data, "connection")){
con <- data
if(isOpen(con) && identical(summary(con)$text, "text")){
data <- function(x, finalize = FALSE){
cat(rawToChar(x), file = con)
flush(con)
}
} else {
was_open <- isOpen(con)
data <- function(x, finalize = FALSE){
if(!isOpen(con))
open(con, 'wb')
writeBin(x, con = con)
if(isTRUE(finalize && !was_open)){
close(con)
} else {
flush(con)
}
}
}
} else if(is_string(data)){
data <- file_writer(path = data)
}
stopifnot(inherits(handle, "curl_handle"))
stopifnot(inherits(pool, "curl_multi"))
stopifnot(is.null(done) || is.function(done))
stopifnot(is.null(fail) || is.function(fail))
stopifnot(is.null(data) || is.function(data))
.Call(R_multi_add, handle, done, fail, data, pool)
}
#' @param timeout max time in seconds to wait for results. Use \code{0} to poll for results without
#' waiting at all.
#' @param poll If \code{TRUE} then return immediately after any of the requests has completed.
#' May also be an integer in which case it returns after n requests have completed.
#' @export
#' @useDynLib curl R_multi_run
#' @rdname multi
multi_run <- function(timeout = Inf, poll = FALSE, pool = NULL){
if(is.null(pool))
pool <- multi_default()
stopifnot(is.numeric(timeout))
stopifnot(inherits(pool, "curl_multi"))
.Call(R_multi_run, pool, timeout, as.integer(poll))
}
#' @param total_con max total concurrent connections.
#' @param host_con max concurrent connections per host.
#' @param multiplex enable HTTP/2 multiplexing if supported by host and client.
#' @export
#' @useDynLib curl R_multi_setopt
#' @rdname multi
multi_set <- function(total_con = 50, host_con = 6, multiplex = TRUE, pool = NULL){
if(is.null(pool))
pool <- multi_default()
stopifnot(inherits(pool, "curl_multi"))
stopifnot(is.numeric(total_con))
stopifnot(is.numeric(host_con))
stopifnot(is.logical(multiplex))
.Call(R_multi_setopt, pool, total_con, host_con, multiplex)
}
#' @export
#' @useDynLib curl R_multi_list
#' @rdname multi
multi_list <- function(pool = NULL){
if(is.null(pool))
pool <- multi_default()
stopifnot(inherits(pool, "curl_multi"))
as.list(.Call(R_multi_list, pool))
}
#' @export
#' @useDynLib curl R_multi_cancel
#' @rdname multi
multi_cancel <- function(handle){
stopifnot(inherits(handle, "curl_handle"))
.Call(R_multi_cancel, handle)
}
#' @export
#' @useDynLib curl R_multi_new
#' @rdname multi
new_pool <- function(total_con = 100, host_con = 6, multiplex = TRUE){
pool <- .Call(R_multi_new)
multi_set(pool = pool, total_con = total_con, host_con = host_con, multiplex = multiplex)
}
multi_default <- local({
global_multi_handle <- NULL
function(){
if(is.null(global_multi_handle)){
global_multi_handle <<- new_pool()
}
stopifnot(inherits(global_multi_handle, "curl_multi"))
return(global_multi_handle)
}
})
#' @export
print.curl_multi <- function(x, ...){
len <- length(multi_list(x))
cat(sprintf("<curl multi-pool> (%d pending requests)\n", len))
}
#' @export
#' @useDynLib curl R_multi_fdset
#' @rdname multi
multi_fdset <- function(pool = NULL){
if(is.null(pool))
pool <- multi_default()
stopifnot(inherits(pool, "curl_multi"))
.Call(R_multi_fdset, pool)
}

316
tmp/multi.c

@ -1,316 +0,0 @@
#include "curl-common.h"
#include <time.h>
/* Notes:
* - First check for unhandled messages in curl_multi_info_read() before curl_multi_perform()
* - Use eval() to callback instead of R_tryEval() to propagate interrupt or error back to C
*/
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 30)
#define HAS_CURLMOPT_MAX_TOTAL_CONNECTIONS 1
#endif
multiref *get_multiref(SEXP ptr){
if(TYPEOF(ptr) != EXTPTRSXP || !Rf_inherits(ptr, "curl_multi"))
Rf_error("pool ptr is not a curl_multi handle");
multiref *mref = (multiref*) R_ExternalPtrAddr(ptr);
if(!mref)
Rf_error("multiref pointer is dead");
return mref;
}
void multi_release(reference *ref){
/* Release the easy-handle */
CURL *handle = ref->handle;
CURLM *multi = ref->async.mref->m;
massert(curl_multi_remove_handle(multi, handle));
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL);
/* Remove the curl handle from the handles list */
ref->async.mref->handles = reflist_remove(ref->async.mref->handles, ref->handleptr);
R_SetExternalPtrProtected(ref->async.mref->multiptr, ref->async.mref->handles);
SET_VECTOR_ELT(R_ExternalPtrProtected(ref->handleptr), 0, R_NilValue);
/* Reset multi state struct */
if(ref->async.content.buf){
free(ref->async.content.buf);
ref->async.content.buf = NULL;
ref->async.content.size = 0;
}
ref->async.mref = NULL;
ref->async.content.buf = NULL;
ref->async.content.size = 0;
ref->async.complete = NULL;
ref->async.error = NULL;
ref->async.data = NULL;
ref->async.node = NULL;
/* Unlock handle (and cleanup if needed) */
ref->locked = 0;
ref->refCount--;
clean_handle(ref);
}
SEXP R_multi_cancel(SEXP handle_ptr){
reference *ref = get_ref(handle_ptr);
if(ref->async.mref)
multi_release(ref);
return handle_ptr;
}
SEXP R_multi_add(SEXP handle_ptr, SEXP cb_complete, SEXP cb_error, SEXP cb_data, SEXP pool_ptr){
multiref *mref = get_multiref(pool_ptr);
CURLM *multi = mref->m;
reference *ref = get_ref(handle_ptr);
if(ref->locked)
Rf_error("Handle is locked. Probably in use in a connection or async request.");
/* placeholder body */
if(Rf_isFunction(cb_data)){
curl_easy_setopt(ref->handle, CURLOPT_WRITEFUNCTION, (curl_write_callback) data_callback);
curl_easy_setopt(ref->handle, CURLOPT_WRITEDATA, cb_data);
} else {
curl_easy_setopt(ref->handle, CURLOPT_WRITEFUNCTION, append_buffer);
curl_easy_setopt(ref->handle, CURLOPT_WRITEDATA, &(ref->async.content));
}
/* add to scheduler */
massert(curl_multi_add_handle(multi, ref->handle));
/* create node in ref */
ref->async.mref = mref;
mref->handles = reflist_add(mref->handles, handle_ptr);
R_SetExternalPtrProtected(pool_ptr, mref->handles);
/* set multi callbacks */
ref->async.complete = cb_complete;
ref->async.error = cb_error;
ref->async.data = cb_data;
SET_VECTOR_ELT(R_ExternalPtrProtected(handle_ptr), 0,
Rf_list3(cb_error, cb_complete, cb_data));
/* lock and protect handle */
ref->refCount++;
ref->locked = 1;
return handle_ptr;
}
SEXP R_multi_run(SEXP pool_ptr, SEXP timeout, SEXP max){
multiref *mref = get_multiref(pool_ptr);
CURLM *multi = mref->m;
int total_pending = -1;
int total_success = 0;
int total_fail = 0;
int result_max = asInteger(max);
double time_max = asReal(timeout);
time_t time_start = time(NULL);
double seconds_elapsed = 0;
while(1) {
/* check for completed requests */
int dirty = 0;
int msgq = 1;
while (msgq > 0) {
CURLMsg *m = curl_multi_info_read(multi, &msgq);
if(m && (m->msg == CURLMSG_DONE)){
dirty = 1;
reference *ref = NULL;
CURL *handle = m->easy_handle;
CURLcode status = m->data.result;
assert(curl_easy_getinfo(handle, CURLINFO_PRIVATE, (char**) &ref));
// prepare for callback
SEXP cb_complete = PROTECT(ref->async.complete);
SEXP cb_error = PROTECT(ref->async.error);
SEXP cb_data = PROTECT(ref->async.data);
SEXP buf = PROTECT(allocVector(RAWSXP, ref->async.content.size));
if(ref->async.content.buf && ref->async.content.size)
memcpy(RAW(buf), ref->async.content.buf, ref->async.content.size);
//release handle for use by callbacks
multi_release(ref);
// Trigger a final 'data' with second argument to TRUE
// This also ensures that a file is consistently created, even for empty responses
if(Rf_isFunction(cb_data)){
SEXP buf = PROTECT(Rf_allocVector(RAWSXP, 0));
SEXP call = PROTECT(Rf_lang3(cb_data, buf, ScalarInteger(1)));
eval(call, R_GlobalEnv);
UNPROTECT(2);
}
// callbacks must be trycatch! we should continue the loop
if(status == CURLE_OK){
total_success++;
if(Rf_isFunction(cb_complete)){
int arglen = Rf_length(FORMALS(cb_complete));
SEXP out = PROTECT(make_handle_response(ref));
SET_VECTOR_ELT(out, 6, buf);
SEXP call = PROTECT(LCONS(cb_complete, arglen ? LCONS(out, R_NilValue) : R_NilValue));
//R_tryEval(call, R_GlobalEnv, &cbfail);
eval(call, R_GlobalEnv); //OK to error here
UNPROTECT(2);
}
} else {
total_fail++;
if(Rf_isFunction(cb_error)){
int arglen = Rf_length(FORMALS(cb_error));
SEXP buf = PROTECT(mkString(strlen(ref->errbuf) ? ref->errbuf : curl_easy_strerror(status)));
SEXP call = PROTECT(LCONS(cb_error, arglen ? LCONS(buf, R_NilValue) : R_NilValue));
//R_tryEval(call, R_GlobalEnv, &cbfail);
eval(call, R_GlobalEnv); //OK to error here
UNPROTECT(2);
}
}
UNPROTECT(4);
}
R_CheckUserInterrupt();
}
/* check for user interruptions */
//if(pending_interrupt()) break;
R_CheckUserInterrupt();
/* check for timeout or max result*/
if(result_max > 0 && total_success + total_fail >= result_max)
break;
if(time_max == 0 && total_pending != -1)
break;
if(time_max > 0){
seconds_elapsed = (double) (time(NULL) - time_start);
if(seconds_elapsed > time_max)
break;
}
/* check if we are done */
if(total_pending == 0 && !dirty)
break;
#ifdef HAS_MULTI_WAIT
/* wait for activity, timeout or "nothing" */
int numfds;
double waitforit = fmin(time_max - seconds_elapsed, 1); //at most 1 sec to support interrupts
if(time_max > 0)
massert(curl_multi_wait(multi, NULL, 0, (int) waitforit * 1000, &numfds));
#endif
/* poll libcurl for new data - updates total_pending */
CURLMcode res = CURLM_CALL_MULTI_PERFORM;
while(res == CURLM_CALL_MULTI_PERFORM)
res = curl_multi_perform(multi, &(total_pending));
if(res != CURLM_OK)
break;
}
SEXP res = PROTECT(allocVector(VECSXP, 3));
SET_VECTOR_ELT(res, 0, ScalarInteger(total_success));
SET_VECTOR_ELT(res, 1, ScalarInteger(total_fail));
SET_VECTOR_ELT(res, 2, ScalarInteger(total_pending));
SEXP names = PROTECT(allocVector(STRSXP, 3));
SET_STRING_ELT(names, 0, mkChar("success"));
SET_STRING_ELT(names, 1, mkChar("error"));
SET_STRING_ELT(names, 2, mkChar("pending"));
setAttrib(res, R_NamesSymbol, names);
UNPROTECT(2);
return res;
}
void fin_multi(SEXP ptr){
multiref *mref = get_multiref(ptr);
SEXP handles = mref->handles;
while(handles != R_NilValue){
multi_release(get_ref(CAR(handles)));
handles = CDR(handles);
}
curl_multi_cleanup(mref->m);
free(mref);
R_ClearExternalPtr(ptr);
}
SEXP R_multi_new(){
multiref *ref = calloc(1, sizeof(multiref));
ref->m = curl_multi_init();
ref->handles = reflist_init();
SEXP ptr = PROTECT(R_MakeExternalPtr(ref, R_NilValue, ref->handles));
ref->multiptr = ptr;
R_RegisterCFinalizerEx(ptr, fin_multi, 1);
setAttrib(ptr, R_ClassSymbol, mkString("curl_multi"));
UNPROTECT(1);
return ptr;
}
SEXP R_multi_setopt(SEXP pool_ptr, SEXP total_con, SEXP host_con, SEXP multiplex){
multiref *mref = get_multiref(pool_ptr);
CURLM *multi = mref->m;
// NOTE: CURLPIPE_HTTP1 is unsafe for non idempotent requests
#ifdef CURLPIPE_MULTIPLEX
massert(curl_multi_setopt(multi, CURLMOPT_PIPELINING,
asLogical(multiplex) ? CURLPIPE_MULTIPLEX : CURLPIPE_NOTHING));
#endif
#ifdef HAS_CURLMOPT_MAX_TOTAL_CONNECTIONS
massert(curl_multi_setopt(multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, (long) asInteger(total_con)));
massert(curl_multi_setopt(multi, CURLMOPT_MAX_HOST_CONNECTIONS, (long) asInteger(host_con)));
#endif
return pool_ptr;
}
SEXP R_multi_list(SEXP pool_ptr){
return get_multiref(pool_ptr)->handles;
}
SEXP R_multi_fdset(SEXP pool_ptr){
multiref *mref = get_multiref(pool_ptr);
CURLM *multi = mref->m;
fd_set read_fd_set, write_fd_set, exc_fd_set;
int max_fd, i, num_read = 0, num_write = 0, num_exc = 0;
int *pread, *pwrite, *pexc;
long timeout;
SEXP result, names;
FD_ZERO(&read_fd_set);
FD_ZERO(&write_fd_set);
FD_ZERO(&exc_fd_set);
massert(curl_multi_fdset(multi, &read_fd_set, &write_fd_set,
&exc_fd_set, &max_fd));
massert(curl_multi_timeout(multi, &timeout));
for (i = 0; i <= max_fd; i++){
if (FD_ISSET(i, &read_fd_set)) num_read++;
if (FD_ISSET(i, &write_fd_set)) num_write++;
if (FD_ISSET(i, &exc_fd_set)) num_exc++;
}
result = PROTECT(allocVector(VECSXP, 4));
SET_VECTOR_ELT(result, 0, allocVector(INTSXP, num_read));
SET_VECTOR_ELT(result, 1, allocVector(INTSXP, num_write));
SET_VECTOR_ELT(result, 2, allocVector(INTSXP, num_exc));
SET_VECTOR_ELT(result, 3, ScalarReal((double) timeout));
names = PROTECT(allocVector(STRSXP, 4));
SET_STRING_ELT(names, 0, mkChar("reads"));
SET_STRING_ELT(names, 1, mkChar("writes"));
SET_STRING_ELT(names, 2, mkChar("exceptions"));
SET_STRING_ELT(names, 3, mkChar("timeout"));
setAttrib(result, R_NamesSymbol, names);
pread = INTEGER(VECTOR_ELT(result, 0));
pwrite = INTEGER(VECTOR_ELT(result, 1));
pexc = INTEGER(VECTOR_ELT(result, 2));
for (i = 0; i <= max_fd; i++){
if (FD_ISSET(i, &read_fd_set)) *(pread++) = i;
if (FD_ISSET(i, &write_fd_set)) *(pwrite++) = i;
if (FD_ISSET(i, &exc_fd_set)) *(pexc++) = i;
}
UNPROTECT(2);
return result;
}

37
tmp/nslookup.R

@ -1,37 +0,0 @@
#' Lookup a hostname
#'
#' The \code{nslookup} function is similar to \code{nsl} but works on all platforms
#' and can resolve ipv6 addresses if supported by the OS. Default behavior raises an
#' error if lookup fails. The \code{has_internet} function tests the internet
#' connection by resolving a random address.
#'
#' @export
#' @param host a string with a hostname
#' @param error raise an error for failed DNS lookup. Otherwise returns \code{NULL}.
#' @param ipv4_only always return ipv4 address. Set to `FALSE` to allow for ipv6 as well.
#' @param multiple returns multiple ip addresses if possible
#' @rdname nslookup
#' @useDynLib curl R_nslookup
#' @examples # Should always work if we are online
#' nslookup("www.r-project.org")
#'
#' # If your OS supports IPv6
#' nslookup("ipv6.test-ipv6.com", ipv4_only = FALSE, error = FALSE)
nslookup <- function(host, ipv4_only = FALSE, multiple = FALSE, error = TRUE){
stopifnot(is.character(host))
host <- enc2utf8(host)
if(grepl("://", host, fixed = TRUE))
stop("This looks like a URL, not a hostname")
out <- .Call(R_nslookup, host[1], as.logical(ipv4_only))
if(isTRUE(error) && is.null(out))
stop("Unable to resolve host: ", host)
if(isTRUE(multiple))
return(unique(out))
utils::head(out, 1)
}
#' @export
#' @rdname nslookup
has_internet <- function(){
!is.null(nslookup("google.com", error = FALSE))
}

100
tmp/nslookup.c

@ -1,100 +0,0 @@
//libcurl internal punycode converter
#ifdef _WIN32
int jeroen_win32_idn_to_ascii(const char *in, char **out);
#endif
//getaddrinfo is an extension (not C99)
#if !defined(_WIN32) && !defined(__sun) && !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200112L
#endif
#include <Rinternals.h>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
SEXP R_nslookup(SEXP hostname, SEXP ipv4_only) {
/* Because gethostbyname() is deprecated */
struct addrinfo hints = {0};
if(asLogical(ipv4_only))
hints.ai_family = AF_INET; //only allow ipv4
struct addrinfo *addr;
const char * hoststr = CHAR(STRING_ELT(hostname, 0));
#ifdef _WIN32
if(Rf_getCharCE(STRING_ELT(hostname, 0)) == CE_UTF8){
char * punycode;
if(jeroen_win32_idn_to_ascii(hoststr, &punycode))
hoststr = punycode;
}
#endif
if(getaddrinfo(hoststr, NULL, &hints, &addr))
return R_NilValue;
// count number of hits
int len = 0;
struct addrinfo * cur = addr;
while(cur != NULL){
len++;
cur = cur->ai_next;
}
//allocate output
SEXP out = PROTECT(allocVector(STRSXP, len));
//extract the values
cur = addr;
for(size_t i = 0; i < len; i++) {
struct sockaddr *sa = cur->ai_addr;
/* IPv4 vs v6 */
char ip[INET6_ADDRSTRLEN];
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sa_in = (struct sockaddr_in*) sa;
inet_ntop(AF_INET, &(sa_in->sin_addr), ip, INET_ADDRSTRLEN);
} else {
struct sockaddr_in6 *sa_in = (struct sockaddr_in6*) sa;
inet_ntop(AF_INET6, &(sa_in->sin6_addr), ip, INET6_ADDRSTRLEN);
}
SET_STRING_ELT(out, i, mkChar(ip));
cur = cur->ai_next;
}
UNPROTECT(1);
freeaddrinfo(addr);
return out;
}
/* Fallback implementation for inet_ntop in Win32 */
#if defined(_WIN32) && !defined(_WIN64)
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
struct sockaddr_storage ss;
unsigned long s = size;
ZeroMemory(&ss, sizeof(ss));
ss.ss_family = af;
switch(af) {
case AF_INET:
((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
break;
case AF_INET6:
((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
break;
default:
return NULL;
}
/* cannot direclty use &size because of strict aliasing rules */
return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)?
dst : NULL;
}
#endif

27
tmp/onload.R

@ -1,27 +0,0 @@
.onLoad <- function(libname, pkgname){
if (!grepl("mingw", R.Version()$platform))
return()
# Enable SSL on Windows if CA bundle is available (R >= 3.2.0)
bundle <- Sys.getenv("CURL_CA_BUNDLE",
file.path(R.home("etc"), "curl-ca-bundle.crt"))
if (bundle != "" && file.exists(bundle)) {
set_bundle(bundle)
}
}
.onAttach <- function(libname, pkgname){
if (grepl("mingw", R.Version()$platform) && !file.exists(get_bundle())){
warning("No CA bundle found. SSL validation disabled.", call. = FALSE)
}
}
#' @useDynLib curl R_set_bundle
set_bundle <- function(path){
.Call(R_set_bundle, path)
}
#' @useDynLib curl R_get_bundle
get_bundle <- function(){
.Call(R_get_bundle)
}

37
tmp/options.R

@ -1,37 +0,0 @@
#' List curl version and options.
#'
#' \code{curl_version()} shows the versions of libcurl, libssl and zlib and
#' supported protocols. \code{curl_options()} lists all options available in
#' the current version of libcurl. The dataset \code{curl_symbols} lists all
#' symbols (including options) provides more information about the symbols,
#' including when support was added/removed from libcurl.
#'
#' @export
#' @param filter string: only return options with string in name
#' @examples # Available options
#' curl_options()
#'
#' # List proxy options
#' curl_options("proxy")
#'
#' # Symbol table
#' curl_symbols("proxy")
curl_options <- function(filter = ""){
m <- grep(filter, names(option_table), ignore.case = TRUE)
option_table[m]
}
option_table <- (function(){
env <- new.env()
if(file.exists("tools/option_table.txt")){
source("tools/option_table.txt", env)
} else if(file.exists("../tools/option_table.txt")){
source("../tools/option_table.txt", env)
} else {
stop("Failed to find 'tools/option_table.txt' from:", getwd())
}
option_table <- unlist(as.list(env))
names(option_table) <- sub("^curlopt_", "", tolower(names(option_table)))
option_table[order(names(option_table))]
})()

51
tmp/parse_headers.R

@ -1,51 +0,0 @@
#' Parse response headers
#'
#' Parse response header data as returned by curl_fetch, either as a set of strings
#' or into a named list.
#'
#' The parse_headers_list function parses the headers into a normalized (lowercase
#' field names, trimmed whitespace) named list.
#'
#' If a request has followed redirects, the data can contain multiple sets of headers.
#' When multiple = TRUE, the function returns a list with the response headers
#' for each request. By default it only returns the headers of the final request.
#'
#' @param txt raw or character vector with the header data
#' @param multiple parse multiple sets of headers separated by a blank line. See details.
#' @export
#' @rdname parse_headers
#' @examples req <- curl_fetch_memory("https://httpbin.org/redirect/3")
#' parse_headers(req$headers)
#' parse_headers(req$headers, multiple = TRUE)
#'
#' # Parse into named list
#' parse_headers_list(req$headers)
parse_headers <- function(txt, multiple = FALSE){
if(is.raw(txt)){
txt <- rawToChar(txt)
}
stopifnot(is.character(txt))
if(length(txt) > 1){
txt <- paste(txt, collapse = "\n")
}
# Allow for either "\r\n" line breaks or just "\r" or "\n" (i.e. windows servers)
sets <- strsplit(txt, "\\r\\n\\r\\n|\\n\\n|\\r\\r")[[1]]
headers <- strsplit(sets, "\\r\\n|\\n|\\r")
if(multiple){
headers
} else {
headers[[length(headers)]]
}
}
#' @export
#' @rdname parse_headers
parse_headers_list <- function(txt){
headers <- grep(":", parse_headers(txt), fixed = TRUE, value = TRUE)
out <- lapply(headers, split_string, ":")
names <- tolower(vapply(out, `[[`, character(1), 1)) #names are case insensitive
values <- lapply(lapply(out, `[[`, 2), trimws)
names(values) <- names
values
}

48
tmp/proxy.R

@ -1,48 +0,0 @@
#' Internet Explorer proxy settings
#'
#' Lookup and mimic the system proxy settings on Windows as set by Internet
#' Explorer. This can be used to configure curl to use the same proxy server.
#'
#' The \code{ie_proxy_info} function looks
#' up your current proxy settings as configured in IE under "Internet Options"
#' > "Tab: Connections" > "LAN Settings". The \code{ie_get_proxy_for_url}
#' determines if and which proxy should be used to connect to a particular
#' URL. If your settings have an "automatic configuration script" this
#' involves downloading and executing a PAC file, which can take a while.
#'
#' @useDynLib curl R_proxy_info
#' @export
#' @rdname ie_proxy
#' @name ie_proxy
ie_proxy_info <- function(){
.Call(R_proxy_info)
}
#' @useDynLib curl R_get_proxy_for_url
#' @param target_url url with host for which to lookup the proxy server
#' @export
#' @rdname ie_proxy
ie_get_proxy_for_url <- function(target_url = "http://www.google.com"){
stopifnot(is.character(target_url))
info <- ie_proxy_info()
if(length(info$Proxy)){
if(isTRUE(grepl("<local>", info$ProxyBypass, fixed = TRUE)) &&
isTRUE(grepl("(://)[^./]+/", paste0(target_url, "/")))){
return(NULL)
} else {
return(info$Proxy)
}
}
if(isTRUE(info$AutoDetect) || length(info$AutoConfigUrl)){
out <- .Call(R_get_proxy_for_url, target_url, info$AutoDetect, info$AutoConfigUrl)
if(isTRUE(out$HasProxy)){
return(out$Proxy)
}
}
return(NULL);
}
#' @useDynLib curl R_windows_build
get_windows_build <- function(){
.Call(R_windows_build)
}

56
tmp/reflist.c

@ -1,56 +0,0 @@
#include <Rinternals.h>
SEXP reflist_init(){
return R_NilValue;
}
//note: you MUST use the return value for this object
SEXP reflist_add(SEXP x, SEXP target){
if(!Rf_isPairList(x))
Rf_error("Not a LISTSXP");
return(CONS(target, x));
}
SEXP reflist_has(SEXP x, SEXP target){
if(!Rf_isPairList(x))
Rf_error("Not a LISTSXP");
while(x != R_NilValue){
if(CAR(x) == target)
return(ScalarLogical(1));
x = CDR(x);
}
return(ScalarLogical(0));
}
SEXP reflist_remove(SEXP x, SEXP target){
if(!Rf_isPairList(x))
Rf_error("Not a LISTSXP");
//drop head
if(x != R_NilValue && CAR(x) == target)
return(CDR(x));
SEXP prev = x;
SEXP current = CDR(x);
//check inner nodes
while(current != R_NilValue){
if(CAR(current) == target){
SETCDR(prev, CDR(current));
return(x);
}
prev = current;
current = CDR(current);
}
Rf_error("Object not found in reflist!");
}
SEXP reflist_length(SEXP x) {
if(!Rf_isPairList(x))
Rf_error("Not a LISTSXP");
int i = 0;
while(x != R_NilValue){
i++;
x = CDR(x);
}
return ScalarInteger(i);
}

16
tmp/split.c

@ -1,16 +0,0 @@
#include <Rinternals.h>
#include <string.h>
SEXP R_split_string(SEXP string, SEXP split){
const char * str = CHAR(STRING_ELT(string, 0));
cetype_t enc = Rf_getCharCE(STRING_ELT(string, 0));
const char * cut = CHAR(STRING_ELT(split, 0));
char * out = strstr(str, cut);
if(!out)
return string;
SEXP res = PROTECT(allocVector(STRSXP, 2));
SET_STRING_ELT(res, 0, mkCharLenCE(str, out - str, enc));
SET_STRING_ELT(res, 1, mkCharCE(out + strlen(cut), enc));
UNPROTECT(1);
return res;
}

39
tmp/ssl.c

@ -1,39 +0,0 @@
#include <curl/curl.h>
#include <Rinternals.h>
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 56)
#define HAS_MULTI_SSL 1
#endif
int windows_openssl = 0;
/* Fall back on OpenSSL on Legacy Windows (Vista/2008) which do not support TLS 1.2 natively */
void select_ssl_backend(){
#if defined(_WIN32) && defined(HAS_MULTI_SSL)
DWORD dwBuild = 0;
DWORD dwVersion = GetVersion();
if (dwVersion < 0x80000000)
dwBuild = (DWORD)(HIWORD(dwVersion));
/* TLS 1.2 requires at least Windows 7 or 2008-R2 */
curl_sslbackend backend = dwBuild < 7600 ? CURLSSLBACKEND_OPENSSL : CURLSSLBACKEND_SCHANNEL;
/* Try to set the backend */
switch(curl_global_sslset(backend, NULL, NULL)){
case CURLSSLSET_OK :
if(backend == CURLSSLBACKEND_OPENSSL)
windows_openssl = 1;
break;
case CURLSSLSET_TOO_LATE:
Rf_warning("Failed to set libcurl SSL: already initiated");
break;
case CURLSSLSET_UNKNOWN_BACKEND:
Rf_warning("Failed to set libcurl SSL: unsupported backend");
break;
default:
Rf_warning("Failed to set libcurl SSL: unknown error");
break;
}
#endif
}

BIN
tmp/sysdata.rda

Binary file not shown.

39
tmp/typechecking.c

@ -1,39 +0,0 @@
/* Hack to get the GCC macros on all systems */
#include <curl/curl.h>
#ifndef __CURL_TYPECHECK_GCC_H
#undef curl_easy_setopt
#undef curl_easy_getinfo
#undef curl_share_setopt
#undef curl_multi_setopt
/* Remove the GNU extensions from typecheck-gcc.h */
#ifndef __warning__
#define __warning__(x)
#endif
#ifndef __unused__
#define __unused__
#endif
/* Add the file */
#include <curl/typecheck-gcc.h>
#endif
int r_curl_is_slist_option(CURLoption x){
return _curl_is_slist_option(x);
}
int r_curl_is_long_option(CURLoption x){
return _curl_is_long_option(x);
}
int r_curl_is_off_t_option(CURLoption x){
return _curl_is_off_t_option(x);
}
int r_curl_is_string_option(CURLoption x){
return _curl_is_string_option(x);
}
int r_curl_is_postfields_option(CURLoption x){
return _curl_is_postfields_option(x);
}

49
tmp/upload.R

@ -1,49 +0,0 @@
#' Upload a File
#'
#' Upload a file to an \code{http://}, \code{ftp://}, or \code{sftp://} (ssh)
#' server. Uploading to HTTP means performing an \code{HTTP PUT} on that URL.
#' Be aware that sftp is only available for libcurl clients built with libssh2.
#'
#' @export
#' @param file connection object or path to an existing file on disk
#' @param url where to upload, should start with e.g. \code{ftp://}
#' @param verbose emit some progress output
#' @param reuse try to keep alive and recycle connections when possible
#' @param ... other arguments passed to \code{\link{handle_setopt}}, for
#' example a \code{username} and \code{password}.
#' @examples \donttest{# Upload package to winbuilder:
#' curl_upload('mypkg_1.3.tar.gz', 'ftp://win-builder.r-project.org/R-devel/')
#' }
curl_upload <- function(file, url, verbose = TRUE, reuse = TRUE, ...) {
infilesize <- NA
con <- if(is.character(file)){
file <- normalizePath(file, mustWork = TRUE)
infilesize <- file.info(file)$size
base::file(file, open = 'rb')
} else if(inherits(file, 'connection')){
file
} else {
stop("Parameter 'file' must be a ")
}
on.exit(close(con))
total_bytes <- 0
h <- new_handle(upload = TRUE, filetime = FALSE, readfunction = function(n) {
buf <- readBin(con, raw(), n = n)
total_bytes <<- total_bytes + length(buf)
if(verbose){
if(length(buf) == 0 || identical(total_bytes, infilesize)){
cat(sprintf("\rUploaded %d bytes... all done!\n", total_bytes), file = stderr())
} else {
cat(sprintf("\rUploaded %d bytes...", total_bytes), file = stderr())
}
}
return(buf)
}, forbid_reuse = !isTRUE(reuse), verbose = verbose, ...)
if(!is.na(infilesize)){
handle_setopt(h, infilesize_large = infilesize)
}
if(grepl('/$', url) && is.character(file)){
url <- paste0(url, basename(file))
}
curl_fetch_memory(url, handle = h)
}

51
tmp/utilities.R

@ -1,51 +0,0 @@
#' @rdname curl_options
#' @export
curl_symbols <- function(filter = ""){
m <- grep(filter, curl_symbol_data$name, ignore.case = TRUE)
curl_symbol_data[m,]
}
#' @useDynLib curl R_curl_version
#' @export
#' @rdname curl_options
#' @examples
#' # Curl/ssl version info
#' curl_version()
curl_version <- function(){
.Call(R_curl_version);
}
#' Parse date/time
#'
#' Can be used to parse dates appearing in http response headers such
#' as \code{Expires} or \code{Last-Modified}. Automatically recognizes
#' most common formats. If the format is known, \code{\link{strptime}}
#' might be easier.
#'
#' @param datestring a string consisting of a timestamp
#' @useDynLib curl R_curl_getdate
#' @export
#' @examples
#' # Parse dates in many formats
#' parse_date("Sunday, 06-Nov-94 08:49:37 GMT")
#' parse_date("06 Nov 1994 08:49:37")
#' parse_date("20040911 +0200")
parse_date <- function(datestring){
out <- .Call(R_curl_getdate, datestring);
class(out) <- c("POSIXct", "POSIXt")
out
}
#' @useDynLib curl R_split_string
split_string <- function(x, split = ":"){
.Call(R_split_string, x, split)
}
trimws <- function(x) {
sub("\\s+$", "", sub("^\\s+", "", x))
}
is_string <- function(x){
is.character(x) && length(x)
}

147
tmp/utils.c

@ -1,147 +0,0 @@
#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;
}

64
tmp/version.c

@ -1,64 +0,0 @@
#include <curl/curl.h>
#include <Rinternals.h>
#define make_string(x) x ? Rf_mkString(x) : ScalarString(NA_STRING)
SEXP R_curl_version() {
/* retrieve info from curl */
const curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
/* put stuff in a list */
SEXP list = PROTECT(allocVector(VECSXP, 10));
SET_VECTOR_ELT(list, 0, make_string(data->version));
SET_VECTOR_ELT(list, 1, make_string(data->ssl_version));
SET_VECTOR_ELT(list, 2, make_string(data->libz_version));
SET_VECTOR_ELT(list, 3, make_string(data->libssh_version));
SET_VECTOR_ELT(list, 4, make_string(data->libidn));
SET_VECTOR_ELT(list, 5, make_string(data->host));
/* create vector of protocols */
int len = 0;
const char *const * temp = data->protocols;
while(*temp++) len++;
SEXP protocols = PROTECT(allocVector(STRSXP, len));
for (int i = 0; i < len; i++){
SET_STRING_ELT(protocols, i, mkChar(*(data->protocols + i)));
}
SET_VECTOR_ELT(list, 6, protocols);
/* add list names */
SEXP names = PROTECT(allocVector(STRSXP, 10));
SET_STRING_ELT(names, 0, mkChar("version"));
SET_STRING_ELT(names, 1, mkChar("ssl_version"));
SET_STRING_ELT(names, 2, mkChar("libz_version"));
SET_STRING_ELT(names, 3, mkChar("libssh_version"));
SET_STRING_ELT(names, 4, mkChar("libidn_version"));
SET_STRING_ELT(names, 5, mkChar("host"));
SET_STRING_ELT(names, 6, mkChar("protocols"));
SET_STRING_ELT(names, 7, mkChar("ipv6"));
SET_STRING_ELT(names, 8, mkChar("http2"));
SET_STRING_ELT(names, 9, mkChar("idn"));
setAttrib(list, R_NamesSymbol, names);
#ifdef CURL_VERSION_IPV6
SET_VECTOR_ELT(list, 7, ScalarLogical(data->features & CURL_VERSION_IPV6));
#else
SET_VECTOR_ELT(list, 7, ScalarLogical(0));
#endif
#ifdef CURL_VERSION_HTTP2
SET_VECTOR_ELT(list, 8, ScalarLogical(data->features & CURL_VERSION_HTTP2));
#else
SET_VECTOR_ELT(list, 8, ScalarLogical(0));
#endif
#ifdef CURL_VERSION_IDN
SET_VECTOR_ELT(list, 9, ScalarLogical(data->features & CURL_VERSION_IDN));
#else
SET_VECTOR_ELT(list, 9, ScalarLogical(0));
#endif
/* return */
UNPROTECT(3);
return list;
}

70
tmp/winidn.c

@ -1,70 +0,0 @@
/* IdnToAscii() requires at least vista to build */
#define _WIN32_WINNT 0x0600
#define WINVER 0x0600
#define IDN_MAX_LENGTH 255
#ifdef _WIN32
#include <Windows.h>
wchar_t * jeroen_convert_UTF8_to_wchar(const char *str_utf8){
wchar_t *str_w = NULL;
if(str_utf8) {
int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
str_utf8, -1, NULL, 0);
if(str_w_len > 0) {
str_w = malloc(str_w_len * sizeof(wchar_t));
if(str_w) {
if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
str_w_len) == 0) {
free(str_w);
return NULL;
}
}
}
}
return str_w;
}
char *jeroen_convert_wchar_to_UTF8(const wchar_t *str_w){
char *str_utf8 = NULL;
if(str_w) {
int str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL,
0, NULL, NULL);
if(str_utf8_len > 0) {
str_utf8 = malloc(str_utf8_len * sizeof(wchar_t));
if(str_utf8) {
if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len,
NULL, FALSE) == 0) {
free(str_utf8);
return NULL;
}
}
}
}
return str_utf8;
}
int jeroen_win32_idn_to_ascii(const char *in, char **out){
int success = FALSE;
wchar_t *in_w = jeroen_convert_UTF8_to_wchar(in);
if(in_w) {
wchar_t punycode[IDN_MAX_LENGTH];
int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
free(in_w);
if(chars) {
*out = jeroen_convert_wchar_to_UTF8(punycode);
if(*out)
success = TRUE;
}
}
return success;
}
#else
void placeholder_to_avoid_stupid_warning(){}
#endif

48
tmp/writer.R

@ -1,48 +0,0 @@
#' File Writer
#'
#' Generates a closure that writes binary (raw) data to a file.
#'
#' The writer function automatically opens the file on the first write and closes when
#' it goes out of scope, or explicitly by setting \code{close = TRUE}. This can be used
#' for the \code{data} callback in \code{multi_add()} or \code{curl_fetch_multi()}.
#'
#' @export
#' @param path file name or path on disk
#' @return Function with signature \code{writer(data = raw(), close = FALSE)}
#' @examples
#' # Doesn't open yet
#' tmp <- tempfile()
#' writer <- file_writer(tmp)
#'
#' # Now it opens
#' writer(charToRaw("Hello!\n"))
#' writer(charToRaw("How are you?\n"))
#'
#' # Close it!
#' writer(charToRaw("All done!\n"), close = TRUE)
#'
#' # Check it worked
#' readLines(tmp)
file_writer <- function(path){
path <- enc2native(normalizePath(path, mustWork = FALSE))
fp <- new_file_writer(path)
structure(function(data = raw(), close = FALSE){
stopifnot(is.raw(data))
write_file_writer(fp, data, as.logical(close))
}, class = "file_writer")
}
#' @useDynLib curl R_new_file_writer
new_file_writer <- function(path){
.Call(R_new_file_writer, path)
}
#' @useDynLib curl R_write_file_writer
write_file_writer <- function(fp, data, close){
.Call(R_write_file_writer, fp, data, close)
}
#' @useDynLib curl R_total_writers
total_writers <- function(){
.Call(R_total_writers)
}

43
tmp/writer.c

@ -1,43 +0,0 @@
#include <Rinternals.h>
static int total_open_writers = 0;
void fin_file_writer(SEXP ptr){
FILE *fp = R_ExternalPtrAddr(ptr);
if(fp != NULL){
fclose(fp);
R_ClearExternalPtr(ptr);
total_open_writers--;
}
}
SEXP R_write_file_writer(SEXP ptr, SEXP buf, SEXP close){
FILE *fp = R_ExternalPtrAddr(ptr);
if(fp == NULL){
SEXP path = R_ExternalPtrTag(ptr);
fp = fopen(CHAR(STRING_ELT(path, 0)), "wb");
if(!fp)
Rf_error("Failed to open file: %s", CHAR(STRING_ELT(path, 0)));
R_SetExternalPtrAddr(ptr, fp);
total_open_writers++;
}
size_t len = fwrite(RAW(buf), 1, Rf_xlength(buf), fp);
if(Rf_asLogical(close)){
fin_file_writer(ptr);
} else if(Rf_length(buf)) {
fflush(fp);
}
return ScalarInteger(len);
}
SEXP R_new_file_writer(SEXP path){
SEXP ptr = PROTECT(R_MakeExternalPtr(NULL, path, R_NilValue));
R_RegisterCFinalizerEx(ptr, fin_file_writer, TRUE);
setAttrib(ptr, R_ClassSymbol, mkString("file_writer"));
UNPROTECT(1);
return ptr;
}
SEXP R_total_writers(){
return(ScalarInteger(total_open_writers));
}
Loading…
Cancel
Save