Skip to content

Commit

Permalink
Add ADA parser as fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
jeroen authored Oct 22, 2024
1 parent 2d9b60b commit 6e53f18
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 23 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
bugs
^\.github$
^configure.log$
^src/ada
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ tools/option_table.txt
inst/doc
windows
configure.log
src/ada*
9 changes: 8 additions & 1 deletion R/parser.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,12 @@
#' @useDynLib curl R_parse_url
parse_url <- function(url){
stopifnot(is.character(url))
.Call(R_parse_url, url)
result <- .Call(R_parse_url, url)
if(length(result$scheme))
result$scheme <- sub("\\:$", "", result$scheme)
if(length( result$query))
result$query <- sub("^\\?", "", result$query)
if(length(result$fragment))
result$fragment <- sub("^\\#", "", result$fragment)
result
}
1 change: 1 addition & 0 deletions cleanup
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
#!/bin/sh
rm -f src/Makevars configure.log
rm -f src/ada*
7 changes: 5 additions & 2 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ if [ $? -ne 0 ]; then
exit 1
fi

# On MacOS the runtime version can be different from SDK version
if [ `uname` = "Darwin" ] && ${R_HOME}/bin/Rscript tools/testversion.R; then
# On curl < 7.62 (RHEL-8) enable the fallback
if [ "$TEST_ADA_PARSER" ] || ! ${R_HOME}/bin/Rscript tools/testversion.R "7.62"; then
tar xf tools/ada.tar.gz -C src
PKG_CFLAGS="$PKG_CFLAGS -DUSE_ADA_PARSER"
elif [ `uname` = "Darwin" ] && ${R_HOME}/bin/Rscript tools/testversion.R "7.80"; then
PKG_CFLAGS="$PKG_CFLAGS -DENABLE_ALL_FEATURES"
fi

Expand Down
66 changes: 47 additions & 19 deletions src/urlparser.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,51 @@
#include "curl-common.h"

#ifdef HAS_CURL_PARSER
static SEXP make_url_names(void){
SEXP names = PROTECT(Rf_allocVector(STRSXP, 9));
SET_STRING_ELT(names, 0, Rf_mkChar("url"));
SET_STRING_ELT(names, 1, Rf_mkChar("scheme"));
SET_STRING_ELT(names, 2, Rf_mkChar("host"));
SET_STRING_ELT(names, 3, Rf_mkChar("port"));
SET_STRING_ELT(names, 4, Rf_mkChar("path"));
SET_STRING_ELT(names, 5, Rf_mkChar("query"));
SET_STRING_ELT(names, 6, Rf_mkChar("fragment"));
SET_STRING_ELT(names, 7, Rf_mkChar("user"));
SET_STRING_ELT(names, 8, Rf_mkChar("password"));
UNPROTECT(1);
return names;
}

#ifdef USE_ADA_PARSER
#include "ada_c.h"
static SEXP get_ada_field(ada_string val){
if(val.length == 0)
return R_NilValue;
return Rf_ScalarString(Rf_mkCharLenCE(val.data, val.length, CE_UTF8));
}

SEXP R_parse_url(SEXP url) {
ada_url *result = ada_parse(CHAR(STRING_ELT(url, 0)), Rf_length(STRING_ELT(url, 0)));
if(!ada_is_valid(result)){
ada_free(result);
Rf_error("ADA failed to parse URL");
}
SEXP out = PROTECT(Rf_allocVector(VECSXP, 9));
SET_VECTOR_ELT(out, 0, get_ada_field(ada_get_href(result)));
SET_VECTOR_ELT(out, 1, get_ada_field(ada_get_protocol(result)));
SET_VECTOR_ELT(out, 2, get_ada_field(ada_get_hostname(result)));
SET_VECTOR_ELT(out, 3, get_ada_field(ada_get_port(result)));
SET_VECTOR_ELT(out, 4, get_ada_field(ada_get_pathname(result)));
SET_VECTOR_ELT(out, 5, get_ada_field(ada_get_search(result)));
SET_VECTOR_ELT(out, 6, get_ada_field(ada_get_hash(result)));
SET_VECTOR_ELT(out, 7, get_ada_field(ada_get_username(result)));
SET_VECTOR_ELT(out, 8, get_ada_field(ada_get_password(result)));

Rf_setAttrib(out, R_NamesSymbol, make_url_names());
UNPROTECT(1);
return out;
}

#elif defined(HAS_CURL_PARSER)
static void fail_if(CURLUcode err){
if(err != CURLUE_OK)
#ifdef HAS_CURL_PARSER_STRERROR
Expand All @@ -24,26 +69,10 @@ static SEXP get_field(CURLU *h, CURLUPart part, CURLUcode field_missing){
return field;
}

static SEXP make_url_names(void){
SEXP names = PROTECT(Rf_allocVector(STRSXP, 10));
SET_STRING_ELT(names, 0, Rf_mkChar("url"));
SET_STRING_ELT(names, 1, Rf_mkChar("scheme"));
SET_STRING_ELT(names, 2, Rf_mkChar("host"));
SET_STRING_ELT(names, 3, Rf_mkChar("port"));
SET_STRING_ELT(names, 4, Rf_mkChar("path"));
SET_STRING_ELT(names, 5, Rf_mkChar("query"));
SET_STRING_ELT(names, 6, Rf_mkChar("fragment"));
SET_STRING_ELT(names, 7, Rf_mkChar("user"));
SET_STRING_ELT(names, 8, Rf_mkChar("password"));
SET_STRING_ELT(names, 9, Rf_mkChar("options"));
UNPROTECT(1);
return names;
}

SEXP R_parse_url(SEXP url) {
CURLU *h = curl_url();
fail_if(curl_url_set(h, CURLUPART_URL, CHAR(STRING_ELT(url, 0)), 0));
SEXP out = PROTECT(Rf_allocVector(VECSXP, 10));
SEXP out = PROTECT(Rf_allocVector(VECSXP, 9));
SET_VECTOR_ELT(out, 0, get_field(h, CURLUPART_URL, CURLUE_OK));
SET_VECTOR_ELT(out, 1, get_field(h, CURLUPART_SCHEME, CURLUE_NO_SCHEME));
SET_VECTOR_ELT(out, 2, get_field(h, CURLUPART_HOST, CURLUE_NO_HOST));
Expand All @@ -53,7 +82,6 @@ SEXP R_parse_url(SEXP url) {
SET_VECTOR_ELT(out, 6, get_field(h, CURLUPART_FRAGMENT, CURLUE_NO_FRAGMENT));
SET_VECTOR_ELT(out, 7, get_field(h, CURLUPART_USER, CURLUE_NO_USER));
SET_VECTOR_ELT(out, 8, get_field(h, CURLUPART_PASSWORD, CURLUE_NO_PASSWORD));
SET_VECTOR_ELT(out, 9, get_field(h, CURLUPART_OPTIONS, CURLUE_NO_OPTIONS));
curl_url_cleanup(h);
Rf_setAttrib(out, R_NamesSymbol, make_url_names());
UNPROTECT(1);
Expand Down
Binary file added tools/ada.tar.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion tools/testversion.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
ver <- libcurlVersion()
cat("Curl runtime version", ver, "\n")
q('no', status = (numeric_version(ver) < "7.80"))
q('no', status = (numeric_version(ver) < commandArgs(TRUE)))

0 comments on commit 6e53f18

Please sign in to comment.