mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-12-27 08:49:16 +08:00
748d26c114
I see that there is no way to set CURLOPT_CONNECTTIMEOUT, but there is support for CURLOPT_TIMEOUT. So, accept the line 'HTTP.CONNECTTIMEOUT' in .rc file to allow user to set CURLOPT_CONNECTTIMEOUT.
397 lines
11 KiB
C
397 lines
11 KiB
C
/*
|
|
Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
|
|
See COPYRIGHT for license information.
|
|
*/
|
|
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_STDARG_H
|
|
#include <stdarg.h>
|
|
#endif
|
|
#include "netcdf.h"
|
|
#include "ncbytes.h"
|
|
#include "ncuri.h"
|
|
#include "ncauth.h"
|
|
#include "nclog.h"
|
|
#include "ncwinpath.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#undef MEMCHECK
|
|
#define MEMCHECK(x) if((x)==NULL) {goto nomem;} else {}
|
|
|
|
/* Define the curl flag defaults in envv style */
|
|
static const char* AUTHDEFAULTS[] = {
|
|
"HTTP.TIMEOUT","1800", /*seconds */ /* Long but not infinite */
|
|
"HTTP.CONNECTTIMEOUT","50", /*seconds */ /* Long but not infinite */
|
|
NULL
|
|
};
|
|
|
|
/* Forward */
|
|
static int setauthfield(NCauth* auth, const char* flag, const char* value);
|
|
static void setdefaults(NCauth*);
|
|
|
|
/**************************************************/
|
|
/* External Entry Points */
|
|
|
|
int
|
|
NC_parseproxy(NCauth* auth, const char* surl)
|
|
{
|
|
int ret = NC_NOERR;
|
|
NCURI* uri = NULL;
|
|
if(surl == NULL || strlen(surl) == 0)
|
|
return (NC_NOERR); /* nothing there*/
|
|
if(ncuriparse(surl,&uri))
|
|
return (NC_EURL);
|
|
auth->proxy.user = uri->user;
|
|
auth->proxy.pwd = uri->password;
|
|
auth->proxy.host = strdup(uri->host);
|
|
if(uri->port != NULL)
|
|
auth->proxy.port = atoi(uri->port);
|
|
else
|
|
auth->proxy.port = 80;
|
|
return (ret);
|
|
}
|
|
|
|
char*
|
|
NC_combinehostport(NCURI* uri)
|
|
{
|
|
size_t len;
|
|
char* host = NULL;
|
|
char* port = NULL;
|
|
char* hp = NULL;
|
|
if(uri == NULL) return NULL;
|
|
host = uri->host;
|
|
port = uri->port;
|
|
if(uri == NULL || host == NULL) return NULL;
|
|
if(port != NULL && strlen(port) == 0) port = NULL;
|
|
len = strlen(host);
|
|
if(port != NULL) len += (1+strlen(port));
|
|
hp = (char*)malloc(len+1);
|
|
if(hp == NULL) return NULL;
|
|
strncpy(hp,host,len);
|
|
if(port != NULL) {
|
|
strncat(hp,":",len);
|
|
strncat(hp,port,len);
|
|
}
|
|
return hp;
|
|
}
|
|
|
|
int
|
|
NC_authsetup(NCauth* auth, NCURI* uri)
|
|
{
|
|
int ret = NC_NOERR;
|
|
char* uri_hostport = NULL;
|
|
|
|
if(uri != NULL)
|
|
uri_hostport = NC_combinehostport(uri);
|
|
else
|
|
return NC_EDAP; /* Generic EDAP error. */
|
|
setdefaults(auth);
|
|
|
|
/* Note, we still must do this function even if
|
|
ncrc_getglobalstate()->rc.ignore is set in order
|
|
to getinfo e.g. host+port from url
|
|
*/
|
|
|
|
setauthfield(auth,"HTTP.DEFLATE",
|
|
NC_rclookup("HTTP.DEFLATE",uri_hostport));
|
|
setauthfield(auth,"HTTP.VERBOSE",
|
|
NC_rclookup("HTTP.VERBOSE",uri_hostport));
|
|
setauthfield(auth,"HTTP.TIMEOUT",
|
|
NC_rclookup("HTTP.TIMEOUT",uri_hostport));
|
|
setauthfield(auth,"HTTP.CONNECTTIMEOUT",
|
|
NC_rclookup("HTTP.CONNECTTIMEOUT",uri_hostport));
|
|
setauthfield(auth,"HTTP.USERAGENT",
|
|
NC_rclookup("HTTP.USERAGENT",uri_hostport));
|
|
setauthfield(auth,"HTTP.COOKIEFILE",
|
|
NC_rclookup("HTTP.COOKIEFILE",uri_hostport));
|
|
setauthfield(auth,"HTTP.COOKIE_FILE",
|
|
NC_rclookup("HTTP.COOKIE_FILE",uri_hostport));
|
|
setauthfield(auth,"HTTP.COOKIEJAR",
|
|
NC_rclookup("HTTP.COOKIEJAR",uri_hostport));
|
|
setauthfield(auth,"HTTP.COOKIE_JAR",
|
|
NC_rclookup("HTTP.COOKIE_JAR",uri_hostport));
|
|
setauthfield(auth,"HTTP.PROXY.SERVER",
|
|
NC_rclookup("HTTP.PROXY.SERVER",uri_hostport));
|
|
setauthfield(auth,"HTTP.PROXY_SERVER",
|
|
NC_rclookup("HTTP.PROXY_SERVER",uri_hostport));
|
|
setauthfield(auth,"HTTP.SSL.VALIDATE",
|
|
NC_rclookup("HTTP.SSL.VALIDATE",uri_hostport));
|
|
setauthfield(auth,"HTTP.SSL.CERTIFICATE",
|
|
NC_rclookup("HTTP.SSL.CERTIFICATE",uri_hostport));
|
|
setauthfield(auth,"HTTP.SSL.KEY",
|
|
NC_rclookup("HTTP.SSL.KEY",uri_hostport));
|
|
setauthfield(auth,"HTTP.SSL.KEYPASSWORD",
|
|
NC_rclookup("HTTP.SSL.KEYPASSWORD",uri_hostport));
|
|
setauthfield(auth,"HTTP.SSL.CAINFO",
|
|
NC_rclookup("HTTP.SSL.CAINFO",uri_hostport));
|
|
setauthfield(auth,"HTTP.SSL.CAPATH",
|
|
NC_rclookup("HTTP.SSL.CAPATH",uri_hostport));
|
|
setauthfield(auth,"HTTP.SSL.VERIFYPEER",
|
|
NC_rclookup("HTTP.SSL.VERIFYPEER",uri_hostport));
|
|
setauthfield(auth,"HTTP.NETRC",
|
|
NC_rclookup("HTTP.NETRC",uri_hostport));
|
|
|
|
{ /* Handle various cases for user + password */
|
|
/* First, see if the user+pwd was in the original url */
|
|
char* user = NULL;
|
|
char* pwd = NULL;
|
|
if(uri->user != NULL && uri->password != NULL) {
|
|
user = uri->user;
|
|
pwd = uri->password;
|
|
} else {
|
|
user = NC_rclookup("HTTP.CREDENTIALS.USER",uri_hostport);
|
|
pwd = NC_rclookup("HTTP.CREDENTIALS.PASSWORD",uri_hostport);
|
|
}
|
|
if(user != NULL && pwd != NULL) {
|
|
user = strdup(user); /* so we can consistently reclaim */
|
|
pwd = strdup(pwd);
|
|
} else {
|
|
/* Could not get user and pwd, so try USERPASSWORD */
|
|
const char* userpwd = NC_rclookup("HTTP.CREDENTIALS.USERPASSWORD",uri_hostport);
|
|
if(userpwd != NULL) {
|
|
ret = NC_parsecredentials(userpwd,&user,&pwd);
|
|
if(ret) {nullfree(uri_hostport); return ret;}
|
|
}
|
|
}
|
|
setauthfield(auth,"HTTP.CREDENTIALS.USERNAME",user);
|
|
setauthfield(auth,"HTTP.CREDENTIALS.PASSWORD",pwd);
|
|
nullfree(user);
|
|
nullfree(pwd);
|
|
nullfree(uri_hostport);
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
void
|
|
NC_authclear(NCauth* auth)
|
|
{
|
|
if(auth->curlflags.cookiejarcreated) {
|
|
#ifdef _MSC_VER
|
|
DeleteFile(auth->curlflags.cookiejar);
|
|
#else
|
|
remove(auth->curlflags.cookiejar);
|
|
#endif
|
|
}
|
|
nullfree(auth->curlflags.useragent);
|
|
nullfree(auth->curlflags.cookiejar);
|
|
nullfree(auth->curlflags.netrc);
|
|
nullfree(auth->ssl.certificate);
|
|
nullfree(auth->ssl.key);
|
|
nullfree(auth->ssl.keypasswd);
|
|
nullfree(auth->ssl.cainfo);
|
|
nullfree(auth->ssl.capath);
|
|
nullfree(auth->proxy.host);
|
|
nullfree(auth->proxy.user);
|
|
nullfree(auth->proxy.pwd);
|
|
nullfree(auth->creds.user);
|
|
nullfree(auth->creds.pwd);
|
|
}
|
|
|
|
/**************************************************/
|
|
|
|
static int
|
|
setauthfield(NCauth* auth, const char* flag, const char* value)
|
|
{
|
|
int ret = NC_NOERR;
|
|
if(value == NULL) goto done;
|
|
if(strcmp(flag,"HTTP.DEFLATE")==0) {
|
|
if(atoi(value)) auth->curlflags.compress = 1;
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.DEFLATE: %ld", infoflags.compress);
|
|
#endif
|
|
}
|
|
if(strcmp(flag,"HTTP.VERBOSE")==0) {
|
|
if(atoi(value)) auth->curlflags.verbose = 1;
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.VERBOSE: %ld", auth->curlflags.verbose);
|
|
#endif
|
|
}
|
|
if(strcmp(flag,"HTTP.TIMEOUT")==0) {
|
|
if(atoi(value)) auth->curlflags.timeout = atoi(value);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.TIMEOUT: %ld", auth->curlflags.timeout);
|
|
#endif
|
|
}
|
|
if(strcmp(flag,"HTTP.CONNECTTIMEOUT")==0) {
|
|
if(atoi(value)) auth->curlflags.connecttimeout = atoi(value);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.CONNECTTIMEOUT: %ld", auth->curlflags.connecttimeout);
|
|
#endif
|
|
}
|
|
if(strcmp(flag,"HTTP.USERAGENT")==0) {
|
|
if(atoi(value)) auth->curlflags.useragent = strdup(value);
|
|
MEMCHECK(auth->curlflags.useragent);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.USERAGENT: %s", auth->curlflags.useragent);
|
|
#endif
|
|
}
|
|
if(
|
|
strcmp(flag,"HTTP.COOKIEFILE")==0
|
|
|| strcmp(flag,"HTTP.COOKIE_FILE")==0
|
|
|| strcmp(flag,"HTTP.COOKIEJAR")==0
|
|
|| strcmp(flag,"HTTP.COOKIE_JAR")==0
|
|
) {
|
|
nullfree(auth->curlflags.cookiejar);
|
|
auth->curlflags.cookiejar = strdup(value);
|
|
MEMCHECK(auth->curlflags.cookiejar);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.COOKIEJAR: %s", auth->curlflags.cookiejar);
|
|
#endif
|
|
}
|
|
if(strcmp(flag,"HTTP.PROXY.SERVER")==0 || strcmp(flag,"HTTP.PROXY_SERVER")==0) {
|
|
ret = NC_parseproxy(auth,value);
|
|
if(ret != NC_NOERR) goto done;
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.PROXY.SERVER: %s", value);
|
|
#endif
|
|
}
|
|
if(strcmp(flag,"HTTP.SSL.VALIDATE")==0) {
|
|
if(atoi(value)) {
|
|
auth->ssl.verifypeer = 1;
|
|
auth->ssl.verifyhost = 1;
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.SSL.VALIDATE: %ld", 1);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if(strcmp(flag,"HTTP.SSL.CERTIFICATE")==0) {
|
|
nullfree(auth->ssl.certificate);
|
|
auth->ssl.certificate = strdup(value);
|
|
MEMCHECK(auth->ssl.certificate);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.SSL.CERTIFICATE: %s", auth->ssl.certificate);
|
|
#endif
|
|
}
|
|
|
|
if(strcmp(flag,"HTTP.SSL.KEY")==0) {
|
|
nullfree(auth->ssl.key);
|
|
auth->ssl.key = strdup(value);
|
|
MEMCHECK(auth->ssl.key);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.SSL.KEY: %s", auth->ssl.key);
|
|
#endif
|
|
}
|
|
|
|
if(strcmp(flag,"HTTP.SSL.KEYPASSWORD")==0) {
|
|
nullfree(auth->ssl.keypasswd) ;
|
|
auth->ssl.keypasswd = strdup(value);
|
|
MEMCHECK(auth->ssl.keypasswd);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.SSL.KEYPASSWORD: %s", auth->ssl.keypasswd);
|
|
#endif
|
|
}
|
|
|
|
if(strcmp(flag,"HTTP.SSL.CAINFO")==0) {
|
|
nullfree(auth->ssl.cainfo) ;
|
|
auth->ssl.cainfo = strdup(value);
|
|
MEMCHECK(auth->ssl.cainfo);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.SSL.CAINFO: %s", auth->ssl.cainfo);
|
|
#endif
|
|
}
|
|
|
|
if(strcmp(flag,"HTTP.SSL.CAPATH")==0) {
|
|
nullfree(auth->ssl.capath) ;
|
|
auth->ssl.capath = strdup(value);
|
|
MEMCHECK(auth->ssl.capath);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.SSL.CAPATH: %s", auth->ssl.capath);
|
|
#endif
|
|
}
|
|
|
|
if(strcmp(flag,"HTTP.SSL.VERIFYPEER")==0) {
|
|
const char* s = value;
|
|
int tf = 0;
|
|
if(s == NULL || strcmp(s,"0")==0 || strcasecmp(s,"false")==0)
|
|
tf = 0;
|
|
else if(strcmp(s,"1")==0 || strcasecmp(s,"true")==0)
|
|
tf = 1;
|
|
else
|
|
tf = 1; /* default if not null */
|
|
auth->ssl.verifypeer = tf;
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.SSL.VERIFYPEER: %d", auth->ssl.verifypeer);
|
|
#endif
|
|
}
|
|
|
|
if(strcmp(flag,"HTTP.NETRC")==0) {
|
|
nullfree(auth->curlflags.netrc);
|
|
auth->curlflags.netrc = strdup(value);
|
|
MEMCHECK(auth->curlflags.netrc);
|
|
#ifdef D4DEBUG
|
|
nclog(NCLOGNOTE,"HTTP.NETRC: %s", auth->curlflags.netrc);
|
|
#endif
|
|
}
|
|
|
|
if(strcmp(flag,"HTTP.CREDENTIALS.USERNAME")==0) {
|
|
nullfree(auth->creds.user);
|
|
auth->creds.user = strdup(value);
|
|
MEMCHECK(auth->creds.user);
|
|
}
|
|
if(strcmp(flag,"HTTP.CREDENTIALS.PASSWORD")==0) {
|
|
nullfree(auth->creds.pwd);
|
|
auth->creds.pwd = strdup(value);
|
|
MEMCHECK(auth->creds.pwd);
|
|
}
|
|
|
|
done:
|
|
return (ret);
|
|
|
|
nomem:
|
|
return (NC_ENOMEM);
|
|
}
|
|
|
|
/*
|
|
Given form user:pwd, parse into user and pwd
|
|
and do %xx unescaping
|
|
*/
|
|
int
|
|
NC_parsecredentials(const char* userpwd, char** userp, char** pwdp)
|
|
{
|
|
char* user = NULL;
|
|
char* pwd = NULL;
|
|
|
|
if(userpwd == NULL)
|
|
return NC_EINVAL;
|
|
user = strdup(userpwd);
|
|
if(user == NULL)
|
|
return NC_ENOMEM;
|
|
pwd = strchr(user,':');
|
|
if(pwd == NULL) {
|
|
free(user);
|
|
return NC_EINVAL;
|
|
}
|
|
*pwd = '\0';
|
|
pwd++;
|
|
if(userp)
|
|
*userp = ncuridecode(user);
|
|
if(pwdp)
|
|
*pwdp = ncuridecode(pwd);
|
|
free(user);
|
|
return NC_NOERR;
|
|
}
|
|
|
|
static void
|
|
setdefaults(NCauth* auth)
|
|
{
|
|
int ret = NC_NOERR;
|
|
const char** p;
|
|
for(p=AUTHDEFAULTS;*p;p+=2) {
|
|
ret = setauthfield(auth,p[0],p[1]);
|
|
if(ret) {
|
|
nclog(NCLOGERR, "RC file defaulting failed for: %s=%s",p[0],p[1]);
|
|
}
|
|
}
|
|
}
|