static void test_kstr() { kstr str1, str2, str3; kstr_init(&str1); kstr_init_cstr(&str2, "bar"); kstr_init_kstr(&str3, &str2); assert(kstr_equal_cstr(&str2, "bar")); assert(kstr_equal_kstr(&str2, &str3)); kstr_assign_cstr(&str3, "foobar"); kstr_assign_kstr(&str1, &str3); kstr_sf(&str2, "%sbar", "foo"); assert(kstr_equal_kstr(&str3, &str2)); assert(kstr_equal_kstr(&str1, &str2)); kstr_sf(&str2, "%s buffer to grow", "I want my"); assert(kstr_equal_cstr(&str2, "I want my buffer to grow")); kstr_clear(&str2); assert(kstr_equal_cstr(&str2, "")); kstr_append_char(&str2, 'f'); kstr_append_char(&str2, 'o'); kstr_assign_cstr(&str1, "ob"); kstr_append_kstr(&str2, &str1); kstr_append_cstr(&str2, "ar"); assert(kstr_equal_cstr(&str2, "foobar")); kstr_free(&str1); kstr_free(&str2); kstr_free(&str3); }
/* This function normalizes a path. It simplifies the directory portion and * makes the path absolute if requested. */ void kpath_normalize(kstr *path, int absolute_flag, int format) { struct kpath_dir dir; kstr dir_path, filename, ext; kstr_init(&dir_path); kstr_init(&filename); kstr_init(&ext); kpath_dir_init(&dir); /* If requested, make the path absolute. */ if (absolute_flag) kpath_make_absolute(path, format); /* Split the path. */ kpath_split(path, &dir_path, &filename, &ext, format); /* Decompose, simplify and recompose the directory portion. */ kpath_decompose_dir(&dir_path, &dir, format); kpath_simplify_dir(&dir); kpath_recompose_dir(&dir_path, &dir, format); /* Recompose the path. */ kstr_assign_kstr(path, &dir_path); kstr_append_kstr(path, &filename); if (ext.slen) { kstr_append_char(path, '.'); kstr_append_kstr(path, &ext); } kpath_dir_clean(&dir); kstr_clean(&dir_path); kstr_clean(&filename); kstr_clean(&ext); }
/* This function recomposes a directory path from its subcomponents. If the * directory path has no absolute part and no other components, the directory * path will be empty. Otherwise, the directory path will end with a delimiter. */ void kpath_recompose_dir(kstr *path, struct kpath_dir *dir, int format) { int i; kstr_reset(path); if (dir->abs_part.slen) kstr_assign_kstr(path, &dir->abs_part); for (i = 0; i < dir->components.size; i++) { kstr_append_kstr(path, (kstr *) dir->components.data[i]); kstr_append_char(path, kpath_delim(format)); } }
/** Converts a DNS name to a domain DN. * * Example: AD.LOCAL => DC=AD,DC=LOCAL. * * This is very much AD specific. It won't work for Lotus Domino DNs. */ char *kdldap_DNS_to_dn(apr_pool_t *pool, const char *dns_dom) { kstr r; const char *s = dns_dom; char *dn; kstr_init_cstr(&r, "DC="); while (*s) { if (*s == '.') kstr_append_cstr(&r, ",DC="); else kstr_append_char(&r, *s); s++; } dn = apr_pstrdup(pool, r.data); kstr_clean(&r); return dn; }
/* Replace all occurences of the string 'from' with the string 'to' in the * string specified. */ void kstr_replace(kstr *self, char *from, char *to) { kstr tmp; int i = 0; int l = strlen(from); assert(l); kstr_init(&tmp); while (i < self->slen) { if (! strncmp(self->data + i, from, l)) { kstr_append_cstr(&tmp, to); i += l; } else { kstr_append_char(&tmp, self->data[i]); i++; } } kstr_assign_kstr(self, &tmp); kstr_clean(&tmp); }
/* This function asks the proxy to connect us to the end server. * This function sets the KMO error string. It returns 0, -1, -2 or -3. */ static int knp_handle_proxy(struct knp_query *query, k3p_proto *k3p, kstr *proxy_login, kstr *proxy_pwd) { int error = 0; int first_line = 1; struct kmo_data_transfer *transfer = &query->transfer; kstr msg; kstr str; kmod_log_msg(3, "knp_handle_proxy() called.\n"); kstr_init(&msg); kstr_init(&str); /* Try. */ do { /* Connect to the specified server and port. */ kstr_sf(&msg, "CONNECT %s:%d HTTP/1.0\r\n", query->server_addr.data, query->server_port); /* Using the following "user:pwd" credentials encoded in base 64. */ if (proxy_login->slen > 0 || proxy_pwd->slen > 0) { kbuffer in, out; kbuffer_init(&in, 100); kbuffer_init(&out, 100); kbuffer_write(&in, proxy_login->data, proxy_login->slen); kbuffer_write(&in, ":", 1); kbuffer_write(&in, proxy_pwd->data, proxy_pwd->slen); bin2b64(&in, &out); kstr_append_cstr(&msg, "Proxy-Authorization: basic "); kstr_append_buf(&msg, out.data, out.len); kstr_append_cstr(&msg, "\r\n"); kbuffer_clean(&in); kbuffer_clean(&out); } /* An empty line marks the end of the request. */ kstr_append_cstr(&msg, "\r\n"); /* Send the message to the proxy. */ transfer->read_flag = 0; transfer->buf = msg.data; transfer->min_len = transfer->max_len = msg.slen; error = knp_exec_transfer(transfer, k3p); if (error) break; if (transfer->status != KMO_COMM_TRANS_COMPLETED) { assert(transfer->status == KMO_COMM_TRANS_ERROR); kmo_seterror("proxy error: %s", kmo_data_transfer_err(transfer)); knp_query_handle_conn_error(query, transfer->err_msg ? KMO_SERROR_MISC : KMO_SERROR_TIMEOUT); error = -1; break; } /* Receive the reply from the server, char by char to avoid reading past * the HTTP reply data. */ kstr_clear(&msg); while (1) { char c; transfer->read_flag = 1; transfer->buf = &c; transfer->min_len = transfer->max_len = 1; error = knp_exec_transfer(transfer, k3p); if (error) break; if (transfer->status != KMO_COMM_TRANS_COMPLETED) { assert(transfer->status == KMO_COMM_TRANS_ERROR); kmo_seterror("proxy error: %s", kmo_data_transfer_err(transfer)); knp_query_handle_conn_error(query, transfer->err_msg ? KMO_SERROR_MISC : KMO_SERROR_TIMEOUT); error = -1; break; } kstr_append_char(&msg, c); /* We reached the end of a line. */ if (msg.slen >= 2 && msg.data[msg.slen - 2] == '\r' && msg.data[msg.slen - 1] == '\n') { /* This is the response line. Parse it. */ if (first_line) { int reply_code; /* Expecting "HTTP/x.x ddd <string>\r\n" */ if (msg.slen < 16 || msg.data[0] != 'H' || msg.data[1] != 'T' || msg.data[2] != 'T' || msg.data[3] != 'P' || ! is_digit(msg.data[9]) || ! is_digit(msg.data[10]) || ! is_digit(msg.data[11])) { kmo_seterror("invalid proxy HTTP reply"); error = -1; break; } /* Get the numeric code. */ reply_code = atoi(msg.data + 9); /* Not 200, it didn't work. */ if (reply_code != 200) { /* Get the reason. */ kstr_assign_buf(&str, msg.data + 13, msg.slen - 2 - 13); kmo_seterror("the proxy refuses to connect: %s (code %d)", str.data, reply_code); error = -1; break; } first_line = 0; } /* The server is sending us some unwanted line. Ignore it. */ else if (msg.slen != 2) { /* Void. */ } /* We reached the end of the reply. The next bytes received will be SSL bytes. */ else { break; } /* Clear the line buffer. */ kstr_clear(&msg); } /* It's too long. */ else if (msg.slen > 1000) { kmo_seterror("HTTP reply too long"); error = -1; break; } } if (error) break; } while (0); kstr_free(&msg); kstr_free(&str); return error; }
/* This function splits the path into 3 components, directory (with trailing * delimiter), file name (without extension), and extension (without '.'). * * The path '/etc/ld.so.conf' will yield directory '/etc/', file name 'ld', and extension 'so.conf'. * The path '/etc/' will yield directory '/etc/', file name '', and extension ''. * The path '/etc' will yield directory '/', file name 'etc', and extension ''. * The path 'foo.' will yield directory './', file name 'foo.' and extension '', i.e. the extension must not be empty. * The path '.foo' will yield directory './', file name '.foo' and extension '', i.e. the file name must not be empty. * The path '.' will yield directory './', file name '', and extension ''. * The path '..' will yield directory '../', file name '', and extension ''. * The path '' will yield directory '', file name '', and extension ''. * Rule of thumb: If the extension is not empty, then <dir><filename>.<extension> is the path. * If the extension is empty, then <dir><filename> is the path. * Arguments: * String containing the path. * Directory string pointer, can be NULL. * File name string pointer, can be NULL. * Extension string pointer, can be NULL. */ void kpath_split(kstr *path, kstr *dir, kstr *name, kstr *ext, int format) { int i; int last_delim_pos = -1; int filename_start_pos = 0; int first_dot_pos = -1; /* Locate the last path delimiter, if any. */ for (i = path->slen - 1; i >= 0; i--) { if (kpath_is_delim(path->data[i], format)) { last_delim_pos = i; break; } } /* Check if the next characters after the last delimiter, or the first * characters if there is no last delimiter, are exactly and no more than * '.' or '..'. In that case, consider the whole path to be a directory * path. */ if (last_delim_pos != -1) filename_start_pos = last_delim_pos + 1; if (! strcmp(path->data + filename_start_pos, ".")) filename_start_pos += 1; else if (! strcmp(path->data + filename_start_pos, "..")) filename_start_pos += 2; /* Locate the first dot in the file name, if any. */ for (i = filename_start_pos; i < path->slen; i++) { /* We found a dot. */ if (path->data[i] == '.') { /* If there's nothing before or after the dot, consider there is no dot. */ if (i != filename_start_pos && i != path->slen - 1) first_dot_pos = i; break; } } /* Get the directory portion. */ if (dir) { /* Empty path. */ if (! path->slen) kstr_reset(dir); /* Relative path with no directory specified. */ else if (! filename_start_pos) kstr_sf(dir, ".%c", kpath_delim(format)); /* Directory present. Extract the directory and add a delimiter if * required. */ else { kstr_mid(path, dir, 0, filename_start_pos); if (! kpath_is_delim(dir->data[dir->slen - 1], format)) kstr_append_char(dir, kpath_delim(format)); } } /* Get the file name. */ if (name) { int filename_size; /* No extension case. */ if (first_dot_pos == -1) filename_size = path->slen - filename_start_pos; /* Extension case. */ else filename_size = first_dot_pos - filename_start_pos; kstr_mid(path, name, filename_start_pos, filename_size); } /* Get the extension. */ if (ext) { /* No extension case. */ if (first_dot_pos == -1) kstr_reset(ext); /* Extension case. */ else kstr_mid(path, ext, first_dot_pos + 1, path->slen - first_dot_pos - 1); } }
/* This function adds a trailing delimiter to the string specified if one is not * already present and if the string is non-empty. */ void kpath_add_delim(kstr *path, int format) { if (path->slen && ! kpath_is_delim(path->data[path->slen - 1], format)) { kstr_append_char(path, kpath_delim(format)); } }
/* This function decomposes the directory path specified into an array of * subcomponents. If the path is absolute, the absolute part will be something * like 'C:\' on Windows and '/' on UNIX, otherwise it will be empty. The * remaining components will not contain delimiters. * * The path 'C:/toto/bar' will yield ('C:\', 'toto', 'bar') on Windows with alt * support. * The path '/toto/bar/' will yield ('/', 'toto', 'bar') on UNIX. * The path './../foo/' will yield ('.', '..', 'foo'). * The path '' will yield (). */ void kpath_decompose_dir(kstr *path, struct kpath_dir *dir, int format) { int scan_pos = 0; kstr cur_component; /* Get the platform format. */ int platform_format = kpath_get_platform_format(format); /* Determine if the path is absolute. */ int is_absolute = kpath_is_absolute(path, format); kstr_init(&cur_component); kpath_dir_reset(dir); /* If the path is absolute, obtain the absolute part. */ if (is_absolute) { if (platform_format == KPATH_FORMAT_UNIX) { kstr_append_char(&dir->abs_part, '/'); scan_pos = 1; } else { kstr_append_buf(&dir->abs_part, path->data, 2); kstr_append_char(&dir->abs_part, kpath_delim(format)); scan_pos = 3; } } /* Scan the rest of the path. */ while (scan_pos < path->slen) { /* We encountered a delimiter. */ if (kpath_is_delim(path->data[scan_pos], format)) { /* If the current component is empty, ignore it. Otherwise, add the * component in the component array. */ if (cur_component.slen) { kstr *s = kstr_new(); kstr_assign_kstr(s, &cur_component); karray_push(&dir->components, s); } /* Reset the current component. */ kstr_reset(&cur_component); } /* Append the current character. */ else kstr_append_char(&cur_component, path->data[scan_pos]); scan_pos++; } /* Add the last component, if any, in the component array. */ if (cur_component.slen) { kstr *s = kstr_new(); kstr_assign_kstr(s, &cur_component); karray_push(&dir->components, s); } kstr_clean(&cur_component); }