};
~~~
+Access the struct fields with `Curl_str()` for the pointer and `Curl_strlen()`
+for the length rather than using the struct fields directly.
+
+## `Curl_str_init`
+
+~~~c
+void Curl_str_init(struct Curl_str *out)
+~~~
+
+This initiates a string struct. The parser functions that store info in
+strings always init the string themselves, so this stand-alone use is often
+not necessary.
+
## `Curl_str_word`
~~~c
size_t srcport,
size_t dstport)
{
- enum alpnid dstalpnid = Curl_alpn2alpnid(dstalpn->str, dstalpn->len);
- enum alpnid srcalpnid = Curl_alpn2alpnid(srcalpn->str, srcalpn->len);
+ enum alpnid dstalpnid =
+ Curl_alpn2alpnid(Curl_str(dstalpn), Curl_strlen(dstalpn));
+ enum alpnid srcalpnid =
+ Curl_alpn2alpnid(Curl_str(srcalpn), Curl_strlen(srcalpn));
if(!srcalpnid || !dstalpnid)
return NULL;
- return altsvc_createid(srchost->str, srchost->len,
- dsthost->str, dsthost->len,
+ return altsvc_createid(Curl_str(srchost), Curl_strlen(srchost),
+ Curl_str(dsthost), Curl_strlen(dsthost),
srcalpnid, dstalpnid,
srcport, dstport);
}
/* The date parser works on a null terminated string. The maximum length
is upheld by Curl_str_quotedword(). */
- memcpy(dbuf, date.str, date.len);
- dbuf[date.len] = 0;
+ memcpy(dbuf, Curl_str(&date), Curl_strlen(&date));
+ dbuf[Curl_strlen(&date)] = 0;
expires = Curl_getdate_capped(dbuf);
as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn,
(size_t)srcport, (size_t)dstport);
Curl_str_trimblanks(&val);
/* Reject cookies with a TAB inside the value */
- if(memchr(val.str, '\t', val.len)) {
+ if(memchr(Curl_str(&val), '\t', Curl_strlen(&val))) {
infof(data, "cookie contains TAB, dropping");
return CERR_TAB;
}
}
}
else {
- val.str = NULL;
- val.len = 0;
+ Curl_str_init(&val);
}
/*
* combination of name + contents. Chrome and Firefox support 4095 or
* 4096 bytes combo
*/
- if(name.len >= (MAX_NAME-1) || val.len >= (MAX_NAME-1) ||
- ((name.len + val.len) > MAX_NAME)) {
+ if(Curl_strlen(&name) >= (MAX_NAME-1) ||
+ Curl_strlen(&val) >= (MAX_NAME-1) ||
+ ((Curl_strlen(&name) + Curl_strlen(&val)) > MAX_NAME)) {
infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
- name.len, val.len);
+ Curl_strlen(&name), Curl_strlen(&val));
return CERR_TOO_BIG;
}
* "the rest". Prefixes must start with '__' and end with a '-', so
* only test for names where that can possibly be true.
*/
- if(strncasecompare("__Secure-", name.str, 9))
+ if(strncasecompare("__Secure-", Curl_str(&name), 9))
co->prefix_secure = TRUE;
- else if(strncasecompare("__Host-", name.str, 7))
+ else if(strncasecompare("__Host-", Curl_str(&name), 7))
co->prefix_host = TRUE;
/*
/* Bad name/value pair. */
return CERR_NO_SEP;
- strstore(&co->name, name.str, name.len);
- strstore(&co->value, val.str, val.len);
+ strstore(&co->name, Curl_str(&name), Curl_strlen(&name));
+ strstore(&co->value, Curl_str(&val), Curl_strlen(&val));
done = TRUE;
if(!co->name || !co->value)
return CERR_NO_NAME_VALUE;
return CERR_INVALID_OCTET;
}
}
- else if(!val.len) {
+ else if(!Curl_strlen(&val)) {
/*
* this was a "<name>=" with no content, and we must allow
* 'secure' and 'httponly' specified this weirdly
if(done)
;
else if(Curl_str_casecompare(&name, "path")) {
- strstore(&co->path, val.str, val.len);
+ strstore(&co->path, Curl_str(&val), Curl_strlen(&val));
if(!co->path)
return CERR_OUT_OF_MEMORY;
free(co->spath); /* if this is set again */
if(!co->spath)
return CERR_OUT_OF_MEMORY;
}
- else if(Curl_str_casecompare(&name, "domain") && val.len) {
+ else if(Curl_str_casecompare(&name, "domain") && Curl_strlen(&val)) {
bool is_ip;
-
+ const char *v = Curl_str(&val);
/*
* Now, we make sure that our host is within the given domain, or
* the given domain is not valid and thus cannot be set.
*/
- if('.' == val.str[0])
+ if('.' == *v)
Curl_str_nudge(&val, 1);
#ifndef USE_LIBPSL
* TLD or otherwise "protected" suffix. To reduce risk, we require a
* dot OR the exact hostname being "localhost".
*/
- if(bad_domain(val.str, val.len))
+ if(bad_domain(Curl_str(&val), Curl_strlen(&val)))
domain = ":";
#endif
- is_ip = Curl_host_is_ipnum(domain ? domain : val.str);
+ is_ip = Curl_host_is_ipnum(domain ? domain : Curl_str(&val));
if(!domain
- || (is_ip && !strncmp(val.str, domain, val.len) &&
- (val.len == strlen(domain)))
- || (!is_ip && cookie_tailmatch(val.str, val.len, domain))) {
- strstore(&co->domain, val.str, val.len);
+ || (is_ip && !strncmp(Curl_str(&val), domain, Curl_strlen(&val)) &&
+ (Curl_strlen(&val) == strlen(domain)))
+ || (!is_ip && cookie_tailmatch(Curl_str(&val),
+ Curl_strlen(&val), domain))) {
+ strstore(&co->domain, Curl_str(&val), Curl_strlen(&val));
if(!co->domain)
return CERR_OUT_OF_MEMORY;
* not a domain to which the current host belongs. Mark as bad.
*/
infof(data, "skipped cookie with bad tailmatch domain: %s",
- val.str);
+ Curl_str(&val));
return CERR_NO_TAILMATCH;
}
}
else if(Curl_str_casecompare(&name, "version")) {
/* just ignore */
}
- else if(Curl_str_casecompare(&name, "max-age") && val.len) {
+ else if(Curl_str_casecompare(&name, "max-age") && Curl_strlen(&val)) {
/*
* Defined in RFC2109:
*
* cookie should be discarded immediately.
*/
int rc;
- const char *maxage = val.str;
+ const char *maxage = Curl_str(&val);
if(*maxage == '\"')
maxage++;
rc = Curl_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
}
cap_expires(now, co);
}
- else if(Curl_str_casecompare(&name, "expires") && val.len) {
- if(!co->expires && (val.len < MAX_DATE_LENGTH)) {
+ else if(Curl_str_casecompare(&name, "expires") && Curl_strlen(&val)) {
+ if(!co->expires && (Curl_strlen(&val) < MAX_DATE_LENGTH)) {
/*
* Let max-age have priority.
*
* will be treated as a session cookie
*/
char dbuf[MAX_DATE_LENGTH + 1];
- memcpy(dbuf, val.str, val.len);
- dbuf[val.len] = 0;
+ memcpy(dbuf, Curl_str(&val), Curl_strlen(&val));
+ dbuf[Curl_strlen(&val)] = 0;
co->expires = Curl_getdate_capped(dbuf);
/*
struct Curl_str out;
while(!Curl_str_until(&config, &out, 32, ',')) {
int lvl = CURL_LOG_LVL_INFO;
- const char *token = out.str;
+ const char *token = Curl_str(&out);
if(*token == '-') {
lvl = CURL_LOG_LVL_NONE;
if(!Curl_str_number(&host, &num, 0xffff)) {
/* Create an entry id, based upon the hostname and port */
- entry_len = create_hostcache_id(source.str, source.len, (int)num,
+ entry_len = create_hostcache_id(Curl_str(&source),
+ Curl_strlen(&source), (int)num,
entry_id, sizeof(entry_id));
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
}
#endif
- if(target.len >= sizeof(address))
+ if(Curl_strlen(&target) >= sizeof(address))
goto err;
- memcpy(address, target.str, target.len);
- address[target.len] = '\0';
+ memcpy(address, Curl_str(&target), Curl_strlen(&target));
+ address[Curl_strlen(&target)] = '\0';
ai = Curl_str2addr(address, (int)port);
if(!ai) {
}
/* Create an entry id, based upon the hostname and port */
- entry_len = create_hostcache_id(source.str, source.len, (int)port,
+ entry_len = create_hostcache_id(Curl_str(&source), Curl_strlen(&source),
+ (int)port,
entry_id, sizeof(entry_id));
if(data->share)
if(dns) {
infof(data, "RESOLVE %.*s:%" CURL_FORMAT_CURL_OFF_T
- " - old addresses discarded", (int)source.len, source.str, port);
+ " - old addresses discarded", (int)Curl_strlen(&source),
+ Curl_str(&source), port);
/* delete old entry, there are two reasons for this
1. old entry may have different addresses.
2. even if entry with correct addresses is already in the cache,
}
/* put this new host in the cache */
- dns = Curl_cache_addr(data, head, source.str, source.len, (int)port,
- permanent);
+ dns = Curl_cache_addr(data, head, Curl_str(&source),
+ Curl_strlen(&source), (int)port, permanent);
if(dns) {
/* release the returned reference; the cache itself will keep the
* entry alive: */
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
infof(data, "Added %.*s:%" CURL_FORMAT_CURL_OFF_T ":%s to DNS cache%s",
- (int)source.len, source.str, port, addresses,
+ (int)Curl_strlen(&source), Curl_str(&source), port, addresses,
permanent ? "" : " (non-permanent)");
#endif
/* Wildcard hostname */
- if((source.len == 1) && (source.str[0] == '*')) {
+ if(Curl_str_casecompare(&source, "*")) {
infof(data, "RESOLVE *:%" CURL_FORMAT_CURL_OFF_T " using wildcard",
port);
data->state.wildcard_resolve = TRUE;
struct stsentry *e;
char dbuf[MAX_HSTS_DATELEN + 1];
time_t expires;
+ const char *hp = Curl_str(&host);
/* The date parser works on a null terminated string. The maximum length
is upheld by Curl_str_quotedword(). */
- memcpy(dbuf, date.str, date.len);
- dbuf[date.len] = 0;
+ memcpy(dbuf, Curl_str(&date), Curl_strlen(&date));
+ dbuf[Curl_strlen(&date)] = 0;
expires = strcmp(dbuf, UNLIMITED) ? Curl_getdate_capped(dbuf) :
TIME_T_MAX;
- if(host.str[0] == '.') {
- host.str++;
- host.len--;
+ if(hp[0] == '.') {
+ Curl_str_nudge(&host, 1);
subdomain = TRUE;
}
/* only add it if not already present */
- e = Curl_hsts(h, host.str, host.len, subdomain);
+ e = Curl_hsts(h, Curl_str(&host), Curl_strlen(&host), subdomain);
if(!e)
- result = hsts_create(h, host.str, host.len, subdomain, expires);
- else if((strlen(e->host) == host.len) &&
- strncasecompare(host.str, e->host, host.len)) {
+ result = hsts_create(h, Curl_str(&host), Curl_strlen(&host),
+ subdomain, expires);
+ else if(Curl_str_casecompare(&host, e->host)) {
/* the same hostname, use the largest expire time */
if(expires > e->expires)
e->expires = expires;
/* nothing to do */
}
- if(!service.len) {
+ if(!Curl_strlen(&service)) {
const char *p = hostname;
if(Curl_str_until(&p, &service, MAX_SIGV4_LEN, '.') ||
Curl_str_single(&p, '.')) {
}
infof(data, "aws_sigv4: picked service %.*s from host",
- (int)service.len, service.str);
+ (int)Curl_strlen(&service), Curl_str(&service));
- if(!region.len) {
+ if(!Curl_strlen(®ion)) {
if(Curl_str_until(&p, ®ion, MAX_SIGV4_LEN, '.') ||
Curl_str_single(&p, '.')) {
failf(data, "aws-sigv4: region missing in parameters and hostname");
goto fail;
}
infof(data, "aws_sigv4: picked region %.*s from host",
- (int)region.len, region.str);
+ (int)Curl_strlen(®ion), Curl_str(®ion));
}
}
Curl_http_method(data, conn, &method, &httpreq);
- payload_hash = parse_content_sha_hdr(data, provider1.str, provider1.len,
- &payload_hash_len);
+ payload_hash =
+ parse_content_sha_hdr(data, Curl_str(&provider1), Curl_strlen(&provider1),
+ &payload_hash_len);
if(!payload_hash) {
/* AWS S3 requires a x-amz-content-sha256 header, and supports special
Curl_str_casecompare(&service, "s3");
if(sign_as_s3)
- result = calc_s3_payload_hash(data, httpreq,
- provider1.str, provider1.len,
- sha_hash, sha_hex, content_sha256_hdr);
+ result = calc_s3_payload_hash(data, httpreq, Curl_str(&provider1),
+ Curl_strlen(&provider1), sha_hash, sha_hex,
+ content_sha256_hdr);
else
result = calc_payload_hash(data, sha_hash, sha_hex);
if(result)
}
result = make_headers(data, hostname, timestamp,
- provider1.str, provider1.len,
+ Curl_str(&provider1), Curl_strlen(&provider1),
&date_header, content_sha256_hdr,
&canonical_headers, &signed_headers);
if(result)
DEBUGF(infof(data, "Canonical request: %s", canonical_request));
- request_type = aprintf("%.*s4_request", (int)provider0.len, provider0.str);
+ request_type = aprintf("%.*s4_request",
+ (int)Curl_strlen(&provider0), Curl_str(&provider0));
if(!request_type)
goto fail;
/* provider0 is lowercased *after* aprintf() so that the buffer can be
written to */
- Curl_strntolower(request_type, request_type, provider0.len);
+ Curl_strntolower(request_type, request_type, Curl_strlen(&provider0));
- credential_scope = aprintf("%s/%.*s/%.*s/%s",
- date, (int)region.len, region.str,
- (int)service.len, service.str,
+ credential_scope = aprintf("%s/%.*s/%.*s/%s", date,
+ (int)Curl_strlen(®ion), Curl_str(®ion),
+ (int)Curl_strlen(&service), Curl_str(&service),
request_type);
if(!credential_scope)
goto fail;
"%s\n" /* RequestDateTime */
"%s\n" /* CredentialScope */
"%s", /* HashedCanonicalRequest in hex */
- (int)provider0.len, provider0.str,
+ (int)Curl_strlen(&provider0), Curl_str(&provider0),
timestamp,
credential_scope,
sha_hex);
goto fail;
/* make provider0 part done uppercase */
- Curl_strntoupper(str_to_sign, provider0.str, provider0.len);
+ Curl_strntoupper(str_to_sign, Curl_str(&provider0), Curl_strlen(&provider0));
- secret = aprintf("%.*s4%s", (int)provider0.len, provider0.str,
- data->state.aptr.passwd ?
+ secret = aprintf("%.*s4%s", (int)Curl_strlen(&provider0),
+ Curl_str(&provider0), data->state.aptr.passwd ?
data->state.aptr.passwd : "");
if(!secret)
goto fail;
/* make provider0 part done uppercase */
- Curl_strntoupper(secret, provider0.str, provider0.len);
+ Curl_strntoupper(secret, Curl_str(&provider0), Curl_strlen(&provider0));
HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0);
- HMAC_SHA256(sign0, sizeof(sign0), region.str, region.len, sign1);
- HMAC_SHA256(sign1, sizeof(sign1), service.str, service.len, sign0);
+ HMAC_SHA256(sign0, sizeof(sign0),
+ Curl_str(®ion), Curl_strlen(®ion), sign1);
+ HMAC_SHA256(sign1, sizeof(sign1),
+ Curl_str(&service), Curl_strlen(&service), sign0);
HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
*/
"%s"
"%s", /* optional sha256 header includes \r\n */
- (int)provider0.len, provider0.str,
+ (int)Curl_strlen(&provider0), Curl_str(&provider0),
user,
credential_scope,
Curl_dyn_ptr(&signed_headers),
}
/* provider 0 uppercase */
Curl_strntoupper(&auth_headers[sizeof("Authorization: ") - 1],
- provider0.str, provider0.len);
+ Curl_str(&provider0), Curl_strlen(&provider0));
Curl_safefree(data->state.aptr.userpwd);
data->state.aptr.userpwd = auth_headers;
#include "strparse.h"
#include "strcase.h"
+void Curl_str_init(struct Curl_str *out)
+{
+ out->str = NULL;
+ out->len = 0;
+}
+
/* Get a word until the first DELIM or end of string. At least one byte long.
return non-zero on error */
int Curl_str_until(const char **linep, struct Curl_str *out,
size_t len = 0;
DEBUGASSERT(linep && *linep && out && max && delim);
- out->str = NULL;
- out->len = 0;
+ Curl_str_init(out);
while(*s && (*s != delim)) {
s++;
if(++len > max) {
size_t len = 0;
DEBUGASSERT(linep && *linep && out && max);
- out->str = NULL;
- out->len = 0;
+ Curl_str_init(out);
if(*s != '\"')
return STRE_BEGQUOTE;
s++;
*linep = &s[len];
return STRE_OK;
}
- out->str = NULL;
- out->len = 0;
+ Curl_str_init(out);
return STRE_SHORT;
}
#define STRE_OVERFLOW 7
#define STRE_NO_NUM 8
+/* public struct, but all accesses should be done using the provided
+ functions */
struct Curl_str {
const char *str;
size_t len;
};
+void Curl_str_init(struct Curl_str *out);
+
+#define Curl_str(x) ((x)->str)
+#define Curl_strlen(x) ((x)->len)
+
/* Get a word until the first space
return non-zero on error */
int Curl_str_word(const char **linep, struct Curl_str *out, const size_t max);