Improve str.h functions

Add strn_startswith() and strncase_startswith().

Make all str*_startswith() functions take const char * arguments, to make it
possible to do safe programming with consts.
This commit is contained in:
Andrew Bettison 2012-11-20 18:07:04 +10:30
parent 0e435683f7
commit c84b7e5db4
6 changed files with 58 additions and 22 deletions

View File

@ -593,7 +593,7 @@ int rhizome_direct_parse_http_request(rhizome_http_request *r)
char *content = NULL;
int contentlen = 0;
char *p;
if ((str_startswith(verb, "GET", &p) || str_startswith(verb, "POST", &p)) && isspace(*p)) {
if ((str_startswith(verb, "GET", (const char **)&p) || str_startswith(verb, "POST", (const char **)&p)) && isspace(*p)) {
*p++ = '\0';
path = p;
while (p < request_end && !isspace(*p))
@ -602,9 +602,9 @@ int rhizome_direct_parse_http_request(rhizome_http_request *r)
pathlen = p - path;
*p++ = '\0';
proto = p;
if ( str_startswith(p, "HTTP/1.", &p)
&& (str_startswith(p, "0", &p) || str_startswith(p, "1", &p))
&& (str_startswith(p, "\r\n", &headers) || str_startswith(p, "\n", &headers))
if ( str_startswith(p, "HTTP/1.", (const char **)&p)
&& (str_startswith(p, "0", (const char **)&p) || str_startswith(p, "1", (const char **)&p))
&& (str_startswith(p, "\r\n", (const char **)&headers) || str_startswith(p, "\n", (const char **)&headers))
) {
*p = '\0';
char *eoh = str_str(headers, "\r\n\r\n", request_end - p);

View File

@ -1140,7 +1140,7 @@ int unpack_http_response(char *response, struct http_response_parts *parts)
parts->content_length = -1;
parts->content_start = NULL;
char *p = NULL;
if (!str_startswith(response, "HTTP/1.0 ", &p)) {
if (!str_startswith(response, "HTTP/1.0 ", (const char **)&p)) {
if (debug&DEBUG_RHIZOME_RX)
DEBUGF("Malformed HTTP reply: missing HTTP/1.0 preamble");
return -1;
@ -1160,7 +1160,7 @@ int unpack_http_response(char *response, struct http_response_parts *parts)
*p++ = '\0';
// Iterate over header lines until the last blank line.
while (!(p[0] == '\n' || (p[0] == '\r' && p[1] == '\n'))) {
if (strcase_startswith(p, "Content-Length:", &p)) {
if (strcase_startswith(p, "Content-Length:", (const char **)&p)) {
while (*p == ' ')
++p;
parts->content_length = 0;

View File

@ -501,10 +501,10 @@ int rhizome_server_parse_http_request(rhizome_http_request *r)
// Parse the HTTP "GET" line.
char *path = NULL;
size_t pathlen = 0;
if (str_startswith(r->request, "POST ", &path)) {
if (str_startswith(r->request, "POST ", (const char **)&path)) {
return rhizome_direct_parse_http_request(r);
} else if (str_startswith(r->request, "GET ", &path)) {
char *p;
} else if (str_startswith(r->request, "GET ", (const char **)&path)) {
const char *p;
// This loop is guaranteed to terminate before the end of the buffer, because we know that the
// buffer contains at least "\n\n" and maybe "\r\n\r\n" at the end of the header block.
for (p = path; !isspace(*p); ++p)
@ -533,7 +533,7 @@ int rhizome_server_parse_http_request(rhizome_http_request *r)
} else if (strcmp(path, "/rhizome/bars") == 0) {
/* Return the list of known BARs */
rhizome_server_sql_query_http_response(r, "bar", "manifests", "from manifests", 32, 0);
} else if (str_startswith(path, "/rhizome/file/", &id)) {
} else if (str_startswith(path, "/rhizome/file/", (const char **)&id)) {
/* Stream the specified payload */
if (!rhizome_str_is_file_hash(id)) {
rhizome_server_simple_http_response(r, 400, "<html><h1>Invalid payload ID</h1></html>\r\n");
@ -553,10 +553,10 @@ int rhizome_server_parse_http_request(rhizome_http_request *r)
r->request_type |= RHIZOME_HTTP_REQUEST_BLOB;
}
}
} else if (str_startswith(path, "/rhizome/manifest/", &id)) {
} else if (str_startswith(path, "/rhizome/manifest/", (const char **)&id)) {
// TODO: Stream the specified manifest
rhizome_server_simple_http_response(r, 500, "<html><h1>Not implemented</h1></html>\r\n");
} else if (str_startswith(path, "/rhizome/manifestbyprefix/", &id)) {
} else if (str_startswith(path, "/rhizome/manifestbyprefix/", (const char **)&id)) {
/* Manifest by prefix */
char bid_low[RHIZOME_MANIFEST_ID_STRLEN+1];
char bid_high[RHIZOME_MANIFEST_ID_STRLEN+1];

28
str.c
View File

@ -85,7 +85,7 @@ char *str_toupper_inplace(char *str)
return str;
}
int str_startswith(char *str, const char *substring, char **afterp)
int str_startswith(const char *str, const char *substring, const char **afterp)
{
while (*substring && *substring == *str)
++substring, ++str;
@ -96,7 +96,18 @@ int str_startswith(char *str, const char *substring, char **afterp)
return 1;
}
int strcase_startswith(char *str, const char *substring, char **afterp)
int strn_startswith(const char *str, size_t len, const char *substring, const char **afterp)
{
while (len && *substring && *substring == *str)
--len, ++substring, ++str;
if (*substring)
return 0;
if (afterp)
*afterp = str;
return 1;
}
int strcase_startswith(const char *str, const char *substring, const char **afterp)
{
while (*substring && *str && toupper(*substring) == toupper(*str))
++substring, ++str;
@ -107,6 +118,17 @@ int strcase_startswith(char *str, const char *substring, char **afterp)
return 1;
}
int strncase_startswith(const char *str, size_t len, const char *substring, const char **afterp)
{
while (len && *substring && toupper(*substring) == toupper(*str))
--len, ++substring, ++str;
if (*substring)
return 0;
if (afterp)
*afterp = str;
return 1;
}
int parse_argv(char *cmdline, char delim, char **argv, int max_argv)
{
int argc=0;
@ -139,7 +161,7 @@ char *str_str(char *haystack, const char *needle, int haystack_len)
return NULL;
}
int str_to_ll_scaled(const char *str, int base, long long *result, char **afterp)
int str_to_ll_scaled(const char *str, int base, long long *result, const char **afterp)
{
if (!(isdigit(*str) || *str == '-' || *str == '+'))
return 0;

26
str.h
View File

@ -82,9 +82,9 @@ size_t str_fromprint(unsigned char *dst, const char *src);
#define alloca_toprint(dstlen,buf,len) toprint((char *)alloca((dstlen) == -1 ? toprint_len((const char *)(buf),(len), "``") + 1 : (dstlen)), (dstlen), (const char *)(buf), (len), "``")
#define alloca_str_toprint(str) toprint_str((char *)alloca(toprint_str_len(str, "``") + 1), -1, (str), "``")
/* Check if a given string starts with a given sub-string. If so, return 1 and, if afterp is not
* NULL, set *afterp to point to the character immediately following the substring. Otherwise
* return 0.
/* Check if a given nul-terminated string 'str' starts with a given nul-terminated sub-string. If
* so, return 1 and, if afterp is not NULL, set *afterp to point to the character in 'str'
* immediately following the substring. Otherwise return 0.
*
* This function is used to parse HTTP headers and responses, which are typically not
* nul-terminated, but are held in a buffer which has an associated length. To avoid this function
@ -95,11 +95,25 @@ size_t str_fromprint(unsigned char *dst, const char *src);
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int str_startswith(char *str, const char *substring, char **afterp);
int str_startswith(const char *str, const char *substring, const char **afterp);
/* Check if a given string 'str' of a given length 'len' starts with a given nul-terminated
* sub-string. If so, return 1 and, if afterp is not NULL, set *afterp to point to the character
* immediately following the substring. Otherwise return 0.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int strn_startswith(const char *str, size_t len, const char *substring, const char **afterp);
/* Case-insensitive form of str_startswith().
* @author Andrew Bettison <andrew@servalproject.com>
*/
int strcase_startswith(char *str, const char *substring, char **afterp);
int strcase_startswith(const char *str, const char *substring, const char **afterp);
/* Case-insensitive form of strn_startswith().
* @author Andrew Bettison <andrew@servalproject.com>
*/
int strncase_startswith(const char *str, size_t len, const char *substring, const char **afterp);
/* like strstr(3), but doesn't depend on null termination.
*
@ -122,7 +136,7 @@ char *str_str(char *haystack, const char *needle, int haystack_len);
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int str_to_ll_scaled(const char *str, int base, long long *result, char **afterp);
int str_to_ll_scaled(const char *str, int base, long long *result, const char **afterp);
int parse_argv(char *cmdline, char delim, char **argv, int max_argv);

View File

@ -53,7 +53,7 @@ int main(int argc, char **argv)
const char *label = "";
int i;
for (i = 1; i < argc; ++i) {
char *arg = argv[i];
const char *arg = argv[i];
if (str_startswith(arg, "--size=", &arg)) {
if (!str_to_ll_scaled(arg, 10, &size, NULL) || size < 0)
fatal("illegal --size= argument: %s", arg);