char *mget_cookie_create_request_header(mget_cookie_db_t *cookie_db, const mget_iri_t *iri) { int it, init = 0; time_t now = time(NULL); mget_buffer_t buf; if (!cookie_db || !iri) return NULL; debug_printf("cookie_create_request_header for host=%s path=%s\n",iri->host,iri->path); mget_thread_mutex_lock(&cookie_db->mutex); for (it = 0; it < mget_vector_size(cookie_db->cookies); it++) { mget_cookie_t *cookie = mget_vector_get(cookie_db->cookies, it); if (((!cookie->host_only && _domain_match(cookie->domain, iri->host)) || (cookie->host_only && !strcmp(cookie->domain, iri->host))) && (!cookie->expires || cookie->expires >= now) && (!cookie->secure_only || (cookie->secure_only && iri->scheme == MGET_IRI_SCHEME_HTTPS)) && _path_match(cookie->path, iri->path)) { if (!init) { mget_buffer_init(&buf, NULL, 128); init = 1; } if (buf.length) mget_buffer_printf_append2(&buf, "; %s=%s", cookie->name, cookie->value); else mget_buffer_printf_append2(&buf, "%s=%s", cookie->name, cookie->value); } } mget_thread_mutex_unlock(&cookie_db->mutex); return init ? buf.data : NULL; }
mget_buffer_t *mget_buffer_alloc(size_t size) { return mget_buffer_init(NULL, NULL, size); }
static void test_buffer(void) { char sbuf[16]; mget_buffer_t buf, *bufp; // testing buffer on stack, using initial stack memory // without resizing mget_buffer_init(&buf, sbuf, sizeof(sbuf)); mget_buffer_deinit(&buf); // testing buffer on stack, using initial stack memory // with resizing mget_buffer_init(&buf, sbuf, sizeof(sbuf)); _test_buffer(&buf, "Test 1"); mget_buffer_deinit(&buf); // testing buffer on stack, using initial heap memory // without resizing mget_buffer_init(&buf, NULL, 16); mget_buffer_deinit(&buf); // testing buffer on stack, using initial heap memory // with resizing mget_buffer_init(&buf, NULL, 16); _test_buffer(&buf, "Test 2"); mget_buffer_deinit(&buf); // testing buffer on heap, using initial stack memory // without resizing bufp = mget_buffer_init(NULL, sbuf, sizeof(sbuf)); mget_buffer_deinit(bufp); bufp = mget_buffer_init(NULL, sbuf, sizeof(sbuf)); mget_buffer_free(&bufp); // testing buffer on heap, using initial stack memory // with resizing bufp = mget_buffer_init(NULL, sbuf, sizeof(sbuf)); _test_buffer(bufp, "Test 3"); mget_buffer_deinit(bufp); bufp = mget_buffer_init(NULL, sbuf, sizeof(sbuf)); _test_buffer(bufp, "Test 4"); mget_buffer_free(&bufp); // testing buffer on heap, using initial heap memory // without resizing bufp = mget_buffer_alloc(16); mget_buffer_free(&bufp); // testing buffer on heap, using initial heap memory // with resizing bufp = mget_buffer_alloc(16); _test_buffer(bufp, "Test 5"); mget_buffer_free(&bufp); // check that appending works mget_buffer_init(&buf, sbuf, sizeof(sbuf)); mget_buffer_strcpy(&buf, "A"); mget_buffer_strcat(&buf, "B"); mget_buffer_memcat(&buf, "C", 1); mget_buffer_memset_append(&buf, 'D', 1); mget_buffer_printf_append2(&buf, "%s", "E"); if (!strcmp(buf.data, "ABCDE")) ok++; else { failed++; info_printf("test_buffer.append: got %s (expected %s)\n", buf.data, "ABCDE"); } mget_buffer_deinit(&buf); // test mget_buffer_trim() mget_buffer_init(&buf, sbuf, sizeof(sbuf)); for (int mid_ws = 0; mid_ws <= 2; mid_ws++) { char expected[16]; snprintf(expected, sizeof(expected), "x%.*sy", mid_ws, " "); for (int lead_ws = 0; lead_ws <= 2; lead_ws++) { for (int trail_ws = 0; trail_ws <= 2; trail_ws++) { mget_buffer_printf2(&buf, "%.*sx%.*sy%.*s", lead_ws, " ", mid_ws, " ", trail_ws, " "); mget_buffer_trim(&buf); if (!strcmp(buf.data, expected)) ok++; else { failed++; info_printf("test_buffer_trim: got '%s' (expected '%s') (%d, %d, %d)\n", buf.data, expected, lead_ws, mid_ws, trail_ws); } } } } mget_buffer_deinit(&buf); }
static void test_iri_relative_to_absolute(void) { static const struct iri_test_data { const char *base, *relative, *result; } test_data[] = { #define H1 "http://x.tld" { H1, "", H1"/" }, { H1, ".", H1"/" }, { H1, "./", H1"/" }, { H1, "..", H1"/" }, { H1, "../", H1"/" }, { H1, "foo", H1"/foo" }, { H1, "foo/bar", H1"/foo/bar" }, { H1, "foo///bar", H1"/foo/bar" }, { H1, "foo/.", H1"/foo/" }, { H1, "foo/./", H1"/foo/" }, { H1, "foo./", H1"/foo./" }, { H1, "foo/../bar", H1"/bar" }, { H1, "foo/../bar/", H1"/bar/" }, { H1, "foo/bar/..", H1"/foo/" }, { H1, "foo/bar/../x", H1"/foo/x" }, { H1, "foo/bar/../x/", H1"/foo/x/" }, { H1, "foo/..", H1"/" }, { H1, "foo/../..", H1"/" }, { H1, "foo/../../..", H1"/" }, { H1, "foo/../../bar/../../baz", H1"/baz" }, { H1, "a/b/../../c", H1"/c" }, { H1, "./a/../b", H1"/b" }, { H1, "/", H1"/" }, { H1, "/.", H1"/" }, { H1, "/./", H1"/" }, { H1, "/..", H1"/" }, { H1, "/../", H1"/" }, { H1, "/foo", H1"/foo" }, { H1, "/foo/bar", H1"/foo/bar" }, { H1, "/foo///bar", H1"/foo/bar" }, { H1, "/foo/.", H1"/foo/" }, { H1, "/foo/./", H1"/foo/" }, { H1, "/foo./", H1"/foo./" }, { H1, "/foo/../bar", H1"/bar" }, { H1, "/foo/../bar/", H1"/bar/" }, { H1, "/foo/bar/..", H1"/foo/" }, { H1, "/foo/bar/../x", H1"/foo/x" }, { H1, "/foo/bar/../x/", H1"/foo/x/" }, { H1, "/foo/..", H1"/" }, { H1, "/foo/../..", H1"/" }, { H1, "/foo/../../..", H1"/" }, { H1, "/foo/../../bar/../../baz", H1"/baz" }, { H1, "/a/b/../../c", H1"/c" }, { H1, "/./a/../b", H1"/b" }, { H1, ".x", H1"/.x" }, { H1, "..x", H1"/..x" }, { H1, "foo/.x", H1"/foo/.x" }, { H1, "foo/bar/.x", H1"/foo/bar/.x" }, { H1, "foo/..x", H1"/foo/..x" }, { H1, "foo/bar/..x", H1"/foo/bar/..x" }, { H1, "/x.php?y=ftp://example.com/&z=1_2", H1"/x.php?y=ftp://example.com/&z=1_2" }, { H1, "//x.y.com/", "http://x.y.com/" }, { H1, "http://x.y.com/", "http://x.y.com/" }, // { H1, "site;sub:.html", H1"/site;sub:.html" }, #undef H1 #define H1 "http://x.tld/" { H1, "", H1"" }, { H1, ".", H1"" }, { H1, "./", H1"" }, { H1, "..", H1"" }, { H1, "../", H1"" }, { H1, "foo", H1"foo" }, { H1, "foo/bar", H1"foo/bar" }, { H1, "foo///bar", H1"foo/bar" }, { H1, "foo/.", H1"foo/" }, { H1, "foo/./", H1"foo/" }, { H1, "foo./", H1"foo./" }, { H1, "foo/../bar", H1"bar" }, { H1, "foo/../bar/", H1"bar/" }, { H1, "foo/bar/..", H1"foo/" }, { H1, "foo/bar/../x", H1"foo/x" }, { H1, "foo/bar/../x/", H1"foo/x/" }, { H1, "foo/..", H1"" }, { H1, "foo/../..", H1"" }, { H1, "foo/../../..", H1"" }, { H1, "foo/../../bar/../../baz", H1"baz" }, { H1, "a/b/../../c", H1"c" }, { H1, "./a/../b", H1"b" }, { H1, "/", H1"" }, { H1, "/.", H1"" }, { H1, "/./", H1"" }, { H1, "/..", H1"" }, { H1, "/../", H1"" }, { H1, "/foo", H1"foo" }, { H1, "/foo/bar", H1"foo/bar" }, { H1, "/foo///bar", H1"foo/bar" }, { H1, "/foo/.", H1"foo/" }, { H1, "/foo/./", H1"foo/" }, { H1, "/foo./", H1"foo./" }, { H1, "/foo/../bar", H1"bar" }, { H1, "/foo/../bar/", H1"bar/" }, { H1, "/foo/bar/..", H1"foo/" }, { H1, "/foo/bar/../x", H1"foo/x" }, { H1, "/foo/bar/../x/", H1"foo/x/" }, { H1, "/foo/..", H1"" }, { H1, "/foo/../..", H1"" }, { H1, "/foo/../../..", H1"" }, { H1, "/foo/../../bar/../../baz", H1"baz" }, { H1, "/a/b/../../c", H1"c" }, { H1, "/./a/../b", H1"b" }, { H1, ".x", H1".x" }, { H1, "..x", H1"..x" }, { H1, "foo/.x", H1"foo/.x" }, { H1, "foo/bar/.x", H1"foo/bar/.x" }, { H1, "foo/..x", H1"foo/..x" }, { H1, "foo/bar/..x", H1"foo/bar/..x" }, { H1, "/x.php?y=ftp://example.com/&z=1_2", H1"x.php?y=ftp://example.com/&z=1_2" }, { H1, "//x.y.com/", "http://x.y.com/" }, { H1, "http://x.y.com/", "http://x.y.com/" }, #undef H1 #define H1 "http://x.tld/file" #define R1 "http://x.tld/" { H1, "", R1"" }, { H1, ".", R1"" }, { H1, "./", R1"" }, { H1, "..", R1"" }, { H1, "../", R1"" }, { H1, "foo", R1"foo" }, { H1, "foo/bar", R1"foo/bar" }, { H1, "foo///bar", R1"foo/bar" }, { H1, "foo/.", R1"foo/" }, { H1, "foo/./", R1"foo/" }, { H1, "foo./", R1"foo./" }, { H1, "foo/../bar", R1"bar" }, { H1, "foo/../bar/", R1"bar/" }, { H1, "foo/bar/..", R1"foo/" }, { H1, "foo/bar/../x", R1"foo/x" }, { H1, "foo/bar/../x/", R1"foo/x/" }, { H1, "foo/..", R1"" }, { H1, "foo/../..", R1"" }, { H1, "foo/../../..", R1"" }, { H1, "foo/../../bar/../../baz", R1"baz" }, { H1, "a/b/../../c", R1"c" }, { H1, "./a/../b", R1"b" }, { H1, "/", R1"" }, { H1, "/.", R1"" }, { H1, "/./", R1"" }, { H1, "/..", R1"" }, { H1, "/../", R1"" }, { H1, "/foo", R1"foo" }, { H1, "/foo/bar", R1"foo/bar" }, { H1, "/foo///bar", R1"foo/bar" }, { H1, "/foo/.", R1"foo/" }, { H1, "/foo/./", R1"foo/" }, { H1, "/foo./", R1"foo./" }, { H1, "/foo/../bar", R1"bar" }, { H1, "/foo/../bar/", R1"bar/" }, { H1, "/foo/bar/..", R1"foo/" }, { H1, "/foo/bar/../x", R1"foo/x" }, { H1, "/foo/bar/../x/", R1"foo/x/" }, { H1, "/foo/..", R1"" }, { H1, "/foo/../..", R1"" }, { H1, "/foo/../../..", R1"" }, { H1, "/foo/../../bar/../../baz", R1"baz" }, { H1, "/a/b/../../c", R1"c" }, { H1, "/./a/../b", R1"b" }, { H1, ".x", R1".x" }, { H1, "..x", R1"..x" }, { H1, "foo/.x", R1"foo/.x" }, { H1, "foo/bar/.x", R1"foo/bar/.x" }, { H1, "foo/..x", R1"foo/..x" }, { H1, "foo/bar/..x", R1"foo/bar/..x" }, { H1, "/x.php?y=ftp://example.com/&z=1_2", R1"x.php?y=ftp://example.com/&z=1_2" }, { H1, "//x.y.com/", "http://x.y.com/" }, { H1, "http://x.y.com/", "http://x.y.com/" }, #undef H1 #undef R1 #define H1 "http://x.tld/dir/" #define R1 "http://x.tld/" { H1, "", H1"" }, { H1, ".", H1"" }, { H1, "./", H1"" }, { H1, "..", R1"" }, { H1, "../", R1"" }, { H1, "foo", H1"foo" }, { H1, "foo/bar", H1"foo/bar" }, { H1, "foo///bar", H1"foo/bar" }, { H1, "foo/.", H1"foo/" }, { H1, "foo/./", H1"foo/" }, { H1, "foo./", H1"foo./" }, { H1, "foo/../bar", H1"bar" }, { H1, "foo/../bar/", H1"bar/" }, { H1, "foo/bar/..", H1"foo/" }, { H1, "foo/bar/../x", H1"foo/x" }, { H1, "foo/bar/../x/", H1"foo/x/" }, { H1, "foo/..", H1"" }, { H1, "foo/../..", R1"" }, { H1, "foo/../../..", R1"" }, { H1, "foo/../../bar/../../baz", R1"baz" }, { H1, "a/b/../../c", H1"c" }, { H1, "./a/../b", H1"b" }, { H1, "/", R1"" }, { H1, "/.", R1"" }, { H1, "/./", R1"" }, { H1, "/..", R1"" }, { H1, "/../", R1"" }, { H1, "/foo", R1"foo" }, { H1, "/foo/bar", R1"foo/bar" }, { H1, "/foo///bar", R1"foo/bar" }, { H1, "/foo/.", R1"foo/" }, { H1, "/foo/./", R1"foo/" }, { H1, "/foo./", R1"foo./" }, { H1, "/foo/../bar", R1"bar" }, { H1, "/foo/../bar/", R1"bar/" }, { H1, "/foo/bar/..", R1"foo/" }, { H1, "/foo/bar/../x", R1"foo/x" }, { H1, "/foo/bar/../x/", R1"foo/x/" }, { H1, "/foo/..", R1"" }, { H1, "/foo/../..", R1"" }, { H1, "/foo/../../..", R1"" }, { H1, "/foo/../../bar/../../baz", R1"baz" }, { H1, "/a/b/../../c", R1"c" }, { H1, "/./a/../b", R1"b" }, { H1, ".x", H1".x" }, { H1, "..x", H1"..x" }, { H1, "foo/.x", H1"foo/.x" }, { H1, "foo/bar/.x", H1"foo/bar/.x" }, { H1, "foo/..x", H1"foo/..x" }, { H1, "foo/bar/..x", H1"foo/bar/..x" }, { H1, "/x.php?y=ftp://example.com/&z=1_2", R1"x.php?y=ftp://example.com/&z=1_2" }, { H1, "//x.y.com/", "http://x.y.com/" }, { H1, "http://x.y.com/", "http://x.y.com/" } #undef H1 #undef R1 }; unsigned it; char uri_buf_static[32]; // use a size that forces allocation in some cases mget_buffer_t *uri_buf = mget_buffer_init(NULL, uri_buf_static, sizeof(uri_buf_static)); mget_iri_t *base; for (it = 0; it < countof(test_data); it++) { const struct iri_test_data *t = &test_data[it]; base = mget_iri_parse(t->base, "utf-8"); mget_iri_relative_to_abs(base, t->relative, strlen(t->relative), uri_buf); if (!strcmp(uri_buf->data, t->result)) ok++; else { failed++; info_printf("Failed [%u]: %s+%s -> %s (expected %s)\n", it, t->base, t->relative, uri_buf->data, t->result); } mget_iri_free(&base); } mget_buffer_free(&uri_buf); }
static void test_buffer_printf(void) { char buf_static[32]; mget_buffer_t buf; // testing buffer_printf() by comparing it with C standard function sprintf() static const char *zero_padded[] = { "", "0" }; static const char *left_adjust[] = { "", "-" }; static const long long number[] = { 0, 1LL, -1LL, 10LL, -10LL, 18446744073709551615ULL }; static const char *modifier[] = { "", "h", "hh", "l", "ll", "z" }; // %L... won't work on OpenBSD5.0 static const char *conversion[] = { "d", "i", "u", "o", "x", "X" }; char fmt[32], result[64], string[32]; size_t z, a, it, n, c, m; int width, precision; mget_buffer_init(&buf, buf_static, sizeof(buf_static)); mget_buffer_printf2(&buf, "%s://%s", "http", "host"); if (strcmp("http://host", buf.data)) { failed++; info_printf("%s: Failed with format ('%%s://%%s','http','host'): '%s' != 'http://host'\n", __func__, buf.data); return; } else ok++; for (z = 0; z < countof(zero_padded); z++) { for (a = 0; a < countof(left_adjust); a++) { for (width = -1; width < 12; width++) { for (precision = -1; precision < 12; precision++) { // testing %s stuff // Solaris' sprintf uses spaces instead of 0s for e.g. %03s padding if (width == -1) { if (precision == -1) { sprintf(fmt,"abc%%%s%ssxyz", left_adjust[a], zero_padded[z]); } else { sprintf(fmt,"abc%%%s%s.%dsxyz", left_adjust[a], zero_padded[z], precision); } } else { if (precision == -1) { sprintf(fmt,"abc%%%s%s%dsxyz", left_adjust[a], zero_padded[z], width); } else { sprintf(fmt,"abc%%%s%s%d.%dsxyz", left_adjust[a], zero_padded[z], width, precision); } } for (it = 0; it < sizeof(string); it++) { memset(string, 'a', it); string[it] = 0; #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif sprintf(result, fmt, string); mget_buffer_printf2(&buf, fmt, string); #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #pragma GCC diagnostic pop #endif if (strcmp(result, buf.data)) { failed++; info_printf("%s: Failed with format ('%s','%s'): '%s' != '%s'\n", __func__, fmt, string, buf.data, result); return; } else { // info_printf("%s: format ('%s','%s'): '%s' == '%s'\n", __func__, fmt, string, buf.data, result); ok++; } } if (width == -1) { if (precision == -1) { sprintf(fmt,"%%%s%ss", left_adjust[a], zero_padded[z]); } else { sprintf(fmt,"%%%s%s.*s", left_adjust[a], zero_padded[z]); } } else { if (precision == -1) { sprintf(fmt,"%%%s%s*s", left_adjust[a], zero_padded[z]); } else { sprintf(fmt,"%%%s%s*.*s", left_adjust[a], zero_padded[z]); } } for (it = 0; it < sizeof(string); it++) { memset(string, 'a', it); string[it] = 0; #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif if (width == -1) { if (precision == -1) { sprintf(result, fmt, string); mget_buffer_printf2(&buf, fmt, string); } else { sprintf(result, fmt, precision, string); mget_buffer_printf2(&buf, fmt, precision, string); } } else { if (precision == -1) { sprintf(result, fmt, width, string); mget_buffer_printf2(&buf, fmt, width, string); } else { sprintf(result, fmt, width, precision, string); mget_buffer_printf2(&buf, fmt, width, precision, string); } } #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #pragma GCC diagnostic pop #endif if (strcmp(result, buf.data)) { failed++; info_printf("%s: Failed with format ('%s','%s'): '%s' != '%s'\n", __func__, fmt, string, buf.data, result); return; } else { // info_printf("%s: format ('%s','%s'): '%s' == '%s'\n", __func__, fmt, string, buf.data, result); ok++; } } // testing integer stuff for (m = 0; m < countof(modifier); m++) { for (c = 0; c < countof(conversion); c++) { if (width == -1) { if (precision == -1) { sprintf(fmt,"%%%s%s%s%s", left_adjust[a], zero_padded[z], modifier[m], conversion[c]); } else { sprintf(fmt,"%%%s%s.%d%s%s", left_adjust[a], zero_padded[z], precision, modifier[m], conversion[c]); } } else { if (precision == -1) { sprintf(fmt,"%%%s%s%d%s%s", left_adjust[a], zero_padded[z], width, modifier[m], conversion[c]); } else { sprintf(fmt,"%%%s%s%d.%d%s%s", left_adjust[a], zero_padded[z], width, precision, modifier[m], conversion[c]); } } for (n = 0; n < countof(number); n++) { #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif sprintf(result, fmt, number[n]); mget_buffer_printf2(&buf, fmt, number[n]); #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #pragma GCC diagnostic pop #endif if (strcmp(result, buf.data)) { failed++; info_printf("%s: Failed with format ('%s','%lld'): '%s' != '%s'\n", __func__, fmt, number[n], buf.data, result); // return; } else { // info_printf("%s: format ('%s','%lld'): '%s' == '%s'\n", __func__, fmt, number[n], buf.data, result); ok++; } } } } } } } } mget_buffer_deinit(&buf); }