summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Rühsen <tim.ruehsen@gmx.de>2015-08-28 15:43:22 +0200
committerTim Rühsen <tim.ruehsen@gmx.de>2015-08-28 15:43:22 +0200
commit57cea296730bafb7d90eaa95fc03e12e44e9d0ab (patch)
tree5b3edf7b5462f782f9a90bfc57d590b904f49ab3
parenta9ba54e76ae6533ca7dbd9200ca597f533745d69 (diff)
downloadwget-tim/wget2.tar.gz
Merge test suite from Mget as tests2/tim/wget2
-rw-r--r--Makefile.am2
-rw-r--r--include/libwget.h8
-rw-r--r--libwget/cookie.c20
-rw-r--r--libwget/css.c3
-rw-r--r--libwget/encoding.c38
-rw-r--r--libwget/http.c2
-rw-r--r--libwget/iri.c73
-rw-r--r--libwget/net.c51
-rw-r--r--libwget/ssl_gnutls.c59
-rw-r--r--tests2/Makefile.am33
-rw-r--r--tests2/buffer_printf2_perf.c81
-rw-r--r--tests2/certs/README77
-rw-r--r--tests2/certs/x509-ca-cert.pem22
-rw-r--r--tests2/certs/x509-ca-key.pem165
-rw-r--r--tests2/certs/x509-client-cert.pem21
-rw-r--r--tests2/certs/x509-client-key.pem165
-rw-r--r--tests2/certs/x509-server-cert.pem23
-rw-r--r--tests2/certs/x509-server-crl.pem13
-rw-r--r--tests2/certs/x509-server-key.pem165
-rw-r--r--tests2/files/contact.html785
-rw-r--r--tests2/files/main.css1744
-rw-r--r--tests2/files/x.css13
-rw-r--r--tests2/libtest.c850
-rw-r--r--tests2/libtest.h132
-rw-r--r--tests2/stringmap_perf.c128
-rw-r--r--tests2/test--accept.c270
-rw-r--r--tests2/test--follow-tags.c215
-rw-r--r--tests2/test--page-requisites.c105
-rw-r--r--tests2/test--post-file.c47
-rw-r--r--tests2/test--spider-r.c103
-rw-r--r--tests2/test-E-k.c90
-rw-r--r--tests2/test-auth-basic.c70
-rw-r--r--tests2/test-directory-clash.c107
-rw-r--r--tests2/test-ftp.c122
-rw-r--r--tests2/test-ftps.c103
-rw-r--r--tests2/test-i-http.c94
-rw-r--r--tests2/test-i-https.c155
-rw-r--r--tests2/test-idn-cmd.c89
-rw-r--r--tests2/test-idn-meta.c101
-rw-r--r--tests2/test-idn-robots.c110
-rw-r--r--tests2/test-iri-disabled.c147
-rw-r--r--tests2/test-iri-forced-remote.c127
-rw-r--r--tests2/test-iri-list.c110
-rw-r--r--tests2/test-iri-percent.c92
-rw-r--r--tests2/test-iri.c152
-rw-r--r--tests2/test-k.c92
-rw-r--r--tests2/test-meta-robots.c101
-rw-r--r--tests2/test-np.c110
-rw-r--r--tests2/test-parse-html.c210
-rw-r--r--tests2/test-parse-rss.c99
-rw-r--r--tests2/test-restrict-ascii.c89
-rw-r--r--tests2/test-wget-1.c553
-rw-r--r--tests2/test.c1499
53 files changed, 9717 insertions, 118 deletions
diff --git a/Makefile.am b/Makefile.am
index b5936437..c9b982b0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,7 +41,7 @@ distuninstallcheck_listfiles = find . -type f | \
ACLOCAL_AMFLAGS = -I m4
# subdirectories in the distribution
-SUBDIRS = lib src doc po include libwget src2 examples tests util testenv
+SUBDIRS = lib src doc po include libwget src2 examples tests tests2 util testenv
EXTRA_DIST = MAILING-LIST \
msdos/config.h msdos/Makefile.DJ \
diff --git a/include/libwget.h b/include/libwget.h
index 36ff1738..0b3e48b8 100644
--- a/include/libwget.h
+++ b/include/libwget.h
@@ -1224,8 +1224,6 @@ void
wget_ssl_set_config_string(int key, const char *value);
void
wget_ssl_set_config_int(int key, int value);
-//void *
-// wget_ssl_open(int sockfd, const char *hostname, int connect_timeout) G_GNUC_WGET_NONNULL((2));
int
wget_ssl_open(wget_tcp_t *tcp);
void
@@ -1237,8 +1235,8 @@ void
wget_ssl_server_init(void);
void
wget_ssl_server_deinit(void);
-void *
- wget_ssl_server_open(int sockfd, int connect_timeout);
+int
+ wget_ssl_server_open(wget_tcp_t *tcp);
void
wget_ssl_server_close(void **session);
@@ -1419,7 +1417,7 @@ const char *
const char *
wget_http_parse_connection(const char *s, char *keep_alive) G_GNUC_WGET_NONNULL_ALL;
const char *
- wget_http_parse_setcookie(const char *s, wget_cookie_t *cookie) G_GNUC_WGET_NONNULL_ALL;
+ wget_http_parse_setcookie(const char *s, wget_cookie_t *cookie) G_GNUC_WGET_NONNULL((1));
const char *
wget_http_parse_etag(const char *s, const char **etag) G_GNUC_WGET_NONNULL((1));
diff --git a/libwget/cookie.c b/libwget/cookie.c
index 632d6ec2..bbc295ac 100644
--- a/libwget/cookie.c
+++ b/libwget/cookie.c
@@ -57,20 +57,20 @@ struct wget_cookie_db_st {
int wget_cookie_db_load_psl(wget_cookie_db_t *cookie_db, const char *fname)
{
#ifdef HAVE_LIBPSL
- if (fname) {
- psl_ctx_t *psl = psl_load_file(fname);
+ if (fname) {
+ psl_ctx_t *psl = psl_load_file(fname);
- if (psl)
- psl_free(cookie_db->psl);
- cookie_db->psl = psl;
- } else {
+ if (psl)
psl_free(cookie_db->psl);
- cookie_db->psl = NULL;
- }
+ cookie_db->psl = psl;
+ } else {
+ psl_free(cookie_db->psl);
+ cookie_db->psl = psl_builtin();
+ }
- return 0;
+ return 0;
#else
- return -1;
+ return -1;
#endif
}
diff --git a/libwget/css.c b/libwget/css.c
index 1f2b1d95..75168180 100644
--- a/libwget/css.c
+++ b/libwget/css.c
@@ -157,9 +157,6 @@ void wget_css_parse_file(
{
int fd;
- if (!fname)
- return;
-
if (strcmp(fname,"-")) {
if ((fd = open(fname, O_RDONLY)) != -1) {
struct stat st;
diff --git a/libwget/encoding.c b/libwget/encoding.c
index 77cfab54..12e1d22b 100644
--- a/libwget/encoding.c
+++ b/libwget/encoding.c
@@ -106,7 +106,7 @@ char *wget_charset_transcode(const char *src, const char *src_encoding, const ch
ret = strndup(dst, dst_len - dst_len_tmp);
debug_printf("converted '%s' (%s) -> '%s' (%s)\n", src, src_encoding, ret, dst_encoding);
} else
- error_printf(_("Failed to convert '%s' string into '%s' (%d)\n"), src_encoding, dst_encoding, errno);
+ error_printf(_("Failed to convert '%s' string into '%s' (%d): '%s'\n"), src_encoding, dst_encoding, errno, src);
xfree(dst);
iconv_close(cd);
@@ -127,6 +127,11 @@ int wget_str_needs_encoding(const char *s)
return !!*s;
}
+char *wget_str_to_utf8(const char *src, const char *encoding)
+{
+ return wget_charset_transcode(src, encoding, "utf-8");
+}
+
int wget_str_is_valid_utf8(const char *utf8)
{
const unsigned char *s = (const unsigned char *) utf8;
@@ -153,11 +158,6 @@ int wget_str_is_valid_utf8(const char *utf8)
return 1;
}
-char *wget_str_to_utf8(const char *src, const char *encoding)
-{
- return wget_charset_transcode(src, encoding, "utf-8");
-}
-
char *wget_utf8_to_str(const char *src, const char *encoding)
{
return wget_charset_transcode(src, "utf-8", encoding);
@@ -210,13 +210,27 @@ const char *wget_str_to_ascii(const char *src)
char *asc = NULL;
int rc;
- // idna_to_ascii_8z() automatically converts UTF-8 to lowercase
+/*
+ * Work around a libidn <= 1.30 vulnerability.
+ *
+ * The function checks for a valid UTF-8 character sequence before
+ * passing it to idna_to_ascii_8z().
+ *
+ * [1] http://lists.gnu.org/archive/html/help-libidn/2015-05/msg00002.html
+ * [2] https://lists.gnu.org/archive/html/bug-wget/2015-06/msg00002.html
+ * [3] http://curl.haxx.se/mail/lib-2015-06/0143.html
+ */
+ if (wget_is_valid_utf8(src)) {
+ // idna_to_ascii_8z() automatically converts UTF-8 to lowercase
- if ((rc = idna_to_ascii_8z(src, &asc, IDNA_USE_STD3_ASCII_RULES)) == IDNA_SUCCESS) {
- // debug_printf("toASCII '%s' -> '%s'\n", src, asc);
- src = asc;
- } else
- error_printf(_("toASCII failed (%d): %s\n"), rc, idna_strerror(rc));
+ if ((rc = idna_to_ascii_8z(src, &asc, IDNA_USE_STD3_ASCII_RULES)) == IDNA_SUCCESS) {
+ // debug_printf("toASCII '%s' -> '%s'\n", src, asc);
+ src = asc;
+ } else
+ error_printf(_("toASCII failed (%d): %s\n"), rc, idna_strerror(rc));
+ }
+ else
+ error_printf(_("Invalid UTF-8 sequence not converted: '%s'\n"), src);
}
#else
if (wget_str_needs_encoding(src)) {
diff --git a/libwget/http.c b/libwget/http.c
index ba11eac1..3ad56547 100644
--- a/libwget/http.c
+++ b/libwget/http.c
@@ -1514,7 +1514,7 @@ int wget_http_open(wget_http_connection_t **_conn, const wget_iri_t *iri)
void wget_http_close(wget_http_connection_t **conn)
{
- if (conn && *conn) {
+ if (*conn) {
wget_tcp_deinit(&(*conn)->tcp);
// if (!wget_tcp_get_dns_caching())
// freeaddrinfo((*conn)->addrinfo);
diff --git a/libwget/iri.c b/libwget/iri.c
index cc6e2560..d4799d62 100644
--- a/libwget/iri.c
+++ b/libwget/iri.c
@@ -698,10 +698,14 @@ char *wget_iri_get_path(const wget_iri_t *iri, wget_buffer_t *buf, const char *e
if (iri->path) {
if (wget_strcasecmp_ascii(encoding, "utf-8")) {
- char *fname = wget_utf8_to_str(iri->path, encoding);
- if (fname) {
+ char *fname;
+
+ if ((fname = wget_utf8_to_str(iri->path, encoding))) {
wget_buffer_strcat(buf, fname);
xfree(fname);
+ } else {
+ // conversion failed, keep original string
+ wget_buffer_strcat(buf, iri->path);
}
} else {
wget_buffer_strcat(buf, iri->path);
@@ -725,38 +729,37 @@ char *wget_iri_get_query_as_filename(const wget_iri_t *iri, wget_buffer_t *buf,
if (wget_strcasecmp_ascii(encoding, "utf-8")) {
if ((query = wget_utf8_to_str(iri->query, encoding)))
allocated = 1;
- } else {
+ else
+ query = iri->query;
+ } else
query = iri->query;
- }
- if (query) {
- int slashes = 0;
- const char *src = query;
+ int slashes = 0;
+ const char *src = query;
- // count slashes in query string
- while ((src = strchr(src, '/'))) {
- slashes++;
- src++;
- }
+ // count slashes in query string
+ while ((src = strchr(src, '/'))) {
+ slashes++;
+ src++;
+ }
- if (slashes) {
- // escape slashes to use query as part of a filename
- const char *begin;
-
- for (src = begin = query; *src; src++) {
- if (*src == '/') {
- if (begin != src)
- wget_buffer_memcat(buf, begin, src - begin);
- begin = src + 1;
- wget_buffer_memcat(buf, "%2F", 3);
- }
- }
+ if (slashes) {
+ // escape slashes to use query as part of a filename
+ const char *begin;
- if (begin != src)
- wget_buffer_memcat(buf, begin, src - begin);
- } else {
- wget_buffer_strcat(buf, query);
+ for (src = begin = query; *src; src++) {
+ if (*src == '/') {
+ if (begin != src)
+ wget_buffer_memcat(buf, begin, src - begin);
+ begin = src + 1;
+ wget_buffer_memcat(buf, "%2F", 3);
+ }
}
+
+ if (begin != src)
+ wget_buffer_memcat(buf, begin, src - begin);
+ } else {
+ wget_buffer_strcat(buf, query);
}
if (allocated)
@@ -769,15 +772,19 @@ char *wget_iri_get_query_as_filename(const wget_iri_t *iri, wget_buffer_t *buf,
char *wget_iri_get_filename(const wget_iri_t *iri, wget_buffer_t *buf, const char *encoding)
{
if (iri->path) {
- char *fname;
+ char *fname, *p;
if (wget_strcasecmp_ascii(encoding, "utf-8")) {
- if ((fname = strrchr(iri->path, '/')))
- fname = wget_utf8_to_str(fname + 1, encoding);
- else
- fname = wget_utf8_to_str(iri->path, encoding);
+ if ((p = strrchr(iri->path, '/'))) {
+ if (!(fname = wget_utf8_to_str(p + 1, encoding)))
+ wget_buffer_strcat(buf, p + 1); // conversion failed, keep original string
+ } else {
+ if (!(fname = wget_utf8_to_str(iri->path, encoding)))
+ wget_buffer_strcat(buf, iri->path); // conversion failed, keep original string
+ }
if (fname) {
+ // conversion succeeded
wget_buffer_strcat(buf, fname);
xfree(fname);
}
diff --git a/libwget/net.c b/libwget/net.c
index eb208e34..ce9a08fc 100644
--- a/libwget/net.c
+++ b/libwget/net.c
@@ -180,10 +180,11 @@ struct addrinfo *wget_tcp_resolve(wget_tcp_t *tcp, const char *host, const char
if (!tcp)
tcp = &_global_tcp;
- if (!port)
- port = "0";
+// if (!port)
+// port = "0";
- if (tcp->caching) {
+ // if port is NULL,
+ if (tcp->caching && port) {
if ((addrinfo = _wget_dns_cache_get(host, port)))
return addrinfo;
@@ -198,7 +199,7 @@ struct addrinfo *wget_tcp_resolve(wget_tcp_t *tcp, const char *host, const char
addrinfo = NULL;
#if defined(AI_NUMERICSERV)
- ai_flags |= (isdigit(*port) ? AI_NUMERICSERV : 0);
+ ai_flags |= (port && isdigit(*port) ? AI_NUMERICSERV : 0);
#endif
#if defined(AI_ADDRCONFIG)
ai_flags |= AI_ADDRCONFIG;
@@ -249,7 +250,7 @@ struct addrinfo *wget_tcp_resolve(wget_tcp_t *tcp, const char *host, const char
if (rc) {
error_printf(_("Failed to resolve %s:%s (%s)\n"), host, port, gai_strerror(rc));
- if (tcp->caching)
+ if (tcp->caching && port)
wget_thread_mutex_unlock(&mutex);
return NULL;
@@ -302,7 +303,7 @@ struct addrinfo *wget_tcp_resolve(wget_tcp_t *tcp, const char *host, const char
}
}
- if (tcp->caching) {
+ if (tcp->caching && port) {
// In case of a race condition the already exisiting addrinfo is returned.
// The addrinfo argument given to _wget_dns_cache_add() will be freed in this case.
addrinfo = _wget_dns_cache_add(host, port, addrinfo);
@@ -609,7 +610,7 @@ int wget_tcp_connect(wget_tcp_t *tcp, const char *host, const char *port)
break; /* stop here - the server cert couldn't be validated */
}
- // do not free tcp->addrinfo when calling mget_tcp_close()
+ // do not free tcp->addrinfo when calling wget_tcp_close()
struct addrinfo *ai_tmp = tcp->addrinfo;
tcp->addrinfo = NULL;
wget_tcp_close(tcp);
@@ -735,29 +736,18 @@ wget_tcp_t *wget_tcp_accept(wget_tcp_t *parent_tcp)
int wget_tcp_tls_start(wget_tcp_t *tcp)
{
- int ret;
-
- // TODO: unify wget_ssl_open and wget_ssl_server_open
- if (tcp->passive) {
- if ((tcp->ssl_session = wget_ssl_server_open(tcp->sockfd, tcp->connect_timeout))) {
- return 0;
- }
- ret = WGET_E_UNKNOWN;
- } else {
+ if (tcp->passive)
+ return wget_ssl_server_open(tcp);
+ else
return wget_ssl_open(tcp);
- }
-
- return ret;
}
-void mget_tcp_tls_stop(wget_tcp_t *tcp)
+void wget_tcp_tls_stop(wget_tcp_t *tcp)
{
- if (tcp->ssl_session) {
- if (tcp->passive)
- wget_ssl_server_close(&tcp->ssl_session);
- else
- wget_ssl_close(&tcp->ssl_session);
- }
+ if (tcp->passive)
+ wget_ssl_server_close(&tcp->ssl_session);
+ else
+ wget_ssl_close(&tcp->ssl_session);
}
ssize_t wget_tcp_read(wget_tcp_t *tcp, char *buf, size_t count)
@@ -788,7 +778,7 @@ ssize_t wget_tcp_write(wget_tcp_t *tcp, const char *buf, size_t count)
ssize_t nwritten = 0, n;
int rc;
- if (tcp->ssl)
+ if (tcp->ssl_session)
return wget_ssl_write_timeout(tcp->ssl_session, buf, count, tcp->timeout);
while (count) {
@@ -885,12 +875,7 @@ ssize_t wget_tcp_printf(wget_tcp_t *tcp, const char *fmt, ...)
void wget_tcp_close(wget_tcp_t *tcp)
{
if (tcp) {
- if (tcp->ssl && tcp->ssl_session) {
- if (tcp->passive)
- wget_ssl_server_close(&tcp->ssl_session);
- else
- wget_ssl_close(&tcp->ssl_session);
- }
+ wget_tcp_tls_stop(tcp);
if (tcp->sockfd != -1) {
close(tcp->sockfd);
tcp->sockfd = -1;
diff --git a/libwget/ssl_gnutls.c b/libwget/ssl_gnutls.c
index ead5174b..15f32fd2 100644
--- a/libwget/ssl_gnutls.c
+++ b/libwget/ssl_gnutls.c
@@ -1278,13 +1278,21 @@ void wget_ssl_server_deinit(void)
wget_thread_mutex_unlock(&_mutex);
}
-void *wget_ssl_server_open(int sockfd, int connect_timeout)
+int wget_ssl_server_open(wget_tcp_t *tcp)
{
gnutls_session_t session;
+ int ret = WGET_E_UNKNOWN;
+ int rc, sockfd, connect_timeout;
+
+ if (!tcp)
+ return WGET_E_INVALID;
if (!_init)
wget_ssl_server_init();
+ sockfd= tcp->sockfd;
+ connect_timeout = tcp->connect_timeout;
+
#ifdef GNUTLS_NONBLOCK
gnutls_init(&session, GNUTLS_SERVER | GNUTLS_NONBLOCK);
#else
@@ -1305,41 +1313,52 @@ void *wget_ssl_server_open(int sockfd, int connect_timeout)
// Wait for socket being ready before we call gnutls_handshake().
// I had problems on a KVM Win7 + CygWin (gnutls 3.2.4-1).
- int ret = wget_ready_2_write(sockfd, connect_timeout);
+ rc = wget_ready_2_write(sockfd, connect_timeout);
// Perform the TLS handshake
- while (ret > 0) {
- ret = gnutls_handshake(session);
- if (ret == 0 || gnutls_error_is_fatal(ret)) {
- if (ret == 0)
- ret = 1;
+ while (rc > 0) {
+ rc = gnutls_handshake(session);
+ if (rc == 0 || gnutls_error_is_fatal(rc)) {
+ if (rc == 0) {
+ ret = WGET_E_SUCCESS;
+ } else {
+ error_printf("GnuTLS: (%d) %s\n", rc, gnutls_strerror(rc));
+
+ if (rc == GNUTLS_E_CERTIFICATE_ERROR)
+ ret = WGET_E_CERTIFICATE;
+ else
+ ret = WGET_E_HANDSHAKE;
+ }
break;
}
if (gnutls_record_get_direction(session)) {
// wait for writeability
- ret = wget_ready_2_write(sockfd, connect_timeout);
+ rc = wget_ready_2_write(sockfd, connect_timeout);
} else {
// wait for readability
- ret = wget_ready_2_read(sockfd, connect_timeout);
+ rc = wget_ready_2_read(sockfd, connect_timeout);
}
}
- if (ret <= 0) {
- if (ret)
- debug_printf("Server handshake failed (%d)\n", ret);
- else
- debug_printf("Server handshake timed out\n");
+ if (_config.print_info)
+ _print_info(session);
- error_printf("GnuTLS Server: %s\n", gnutls_strerror(ret));
+ if (ret == WGET_E_UNKNOWN) {
+ if (rc == 0) {
+ debug_printf("Server handshake timed out\n");
+ ret = WGET_E_TIMEOUT;
+ }
+ }
+ if (ret == WGET_E_SUCCESS) {
+ debug_printf("Server handshake completed\n");
+ tcp->ssl_session = session;
+ } else {
gnutls_deinit(session);
- return NULL;
}
- debug_printf("Server handshake completed\n");
-
- return session;
+ return ret;
}
void wget_ssl_server_close(void **session)
@@ -1399,7 +1418,7 @@ ssize_t wget_ssl_read_timeout(void *session, char *buf, size_t count, int timeou
ssize_t wget_ssl_write_timeout(void *session, const char *buf, size_t count, int timeout) { return 0; }
void wget_ssl_server_init(void) { }
void wget_ssl_server_deinit(void) { }
-void *wget_ssl_server_open(int sockfd, int connect_timeout) { return NULL; }
+int wget_ssl_server_open(wget_tcp_t *tcp) { return WGET_E_UNKNOWN; }
void wget_ssl_server_close(void **session) { }
#endif // !HAVE_LIBGNUTLS
diff --git a/tests2/Makefile.am b/tests2/Makefile.am
new file mode 100644
index 00000000..31a67073
--- /dev/null
+++ b/tests2/Makefile.am
@@ -0,0 +1,33 @@
+#DEFS = @DEFS@ -DDATADIR=\"$(datadir)/@PACKAGE@\" -DSRCDIR=\"$(srcdir)\"
+DEFS = @DEFS@ -DDATADIR=\"$(top_srcdir)/data\" -DSRCDIR=\"$(srcdir)\"
+AM_CPPFLAGS = -Wno-missing-field-initializers -I$(top_srcdir)/include
+AM_LDFLAGS = -static
+LDADD = libtest.la ../libwget/libwget-@LIBWGET_API_VERSION@.la @LTLIBICONV@ @LTLIBINTL@ $(LIBIDN2) $(LIBUNISTRING) $(LIBPTHREAD)
+
+# test-iri-disabled removed since Mget always uses IRIs
+WGET_TESTS = test test-wget-1 test-restrict-ascii test-i-http test-i-https test-np test--spider-r \
+ test-meta-robots test-idn-robots test-idn-meta test-idn-cmd \
+ test-iri test-iri-percent test-iri-list test-iri-forced-remote \
+ test-auth-basic test-parse-html test-parse-rss test--page-requisites test--accept \
+ test-k test--follow-tags test-directory-clash test-ftp test-ftps
+
+#test--post-file test-E-k
+
+check_PROGRAMS = buffer_printf2_perf stringmap_perf $(WGET_TESTS)
+
+test_SOURCES = test.c
+test_LDADD = ../libwget/libwget-@LIBWGET_API_VERSION@.la ../src2/wget2-log.o ../src2/wget2-options.o @LTLIBICONV@ @LTLIBINTL@ $(LIBIDN2) $(LIBUNISTRING) $(LIBPTHREAD)
+test_parse_html_LDADD = ../libwget/libwget-@LIBWGET_API_VERSION@.la ../src2/wget2-log.o ../src2/wget2-options.o @LTLIBICONV@ @LTLIBINTL@ $(LIBIDN2) $(LIBUNISTRING) $(LIBPTHREAD)
+
+noinst_LTLIBRARIES = libtest.la
+libtest_la_SOURCES = libtest.c
+libtest_la_CPPFLAGS = -I$(srcdir) -I$(top_srcdir)/include
+#libtest_LDADD = libtest.o
+
+EXTRA_DIST = files libtest.h certs
+
+clean-local:
+ rm -rf $(srcdir)/.test_*
+
+AM_TESTS_ENVIRONMENT = export VALGRIND_TESTS"=@VALGRIND_TESTS@";
+TESTS = $(WGET_TESTS)
diff --git a/tests2/buffer_printf2_perf.c b/tests2/buffer_printf2_perf.c
new file mode 100644
index 00000000..d7edf576
--- /dev/null
+++ b/tests2/buffer_printf2_perf.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright(c) 2012 Tim Ruehsen
+ *
+ * This file is part of MGet.
+ *
+ * Wget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Wget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Wget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * testing performance of buffer printf routines
+ *
+ * Changelog
+ * 06.07.2012 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include <libwget.h>
+
+int main(void)
+{
+ int it;
+ wget_buffer_t buf;
+ char sbuf[128];
+
+ wget_buffer_init(&buf, sbuf, sizeof(sbuf));
+
+ for (it = 0; it < 10000000; it++) {
+ // buffer: 0.239s libc: 0.018s (gcc replaces sprintf(%s) by strcpy())
+// snprintf(sbuf,sizeof(sbuf),"%s", "teststring sabbeldi heidewitzka\n");
+// buffer_printf2(&buf,"%s", "teststring sabbeldi heidewitzka\n");
+
+ // buffer: 0.306s libc: 1.040s
+// sprintf(sbuf,"%s\n", "teststring sabbeldi heidewitzka\n");
+// buffer_printf2(&buf,"%s\n", "teststring sabbeldi heidewitzka\n");
+
+ // function call and loop overhead: buffer: 0.072s libc: 0.390s
+// buffer_printf2(&buf, "", "teststring sabbeldi heidewitzka\n");
+// sprintf(sbuf, "", "teststring sabbeldi heidewitzka\n");
+
+ // buffer: 0.392s libc: 0.838s
+// sprintf(sbuf,"%.*s\n", 17, "teststring sabbeldi heidewitzka\n");
+// buffer_printf2(&buf,"%.*s\n", 17, "teststring sabbeldi heidewitzka\n");
+
+ // buffer: 0.407s libc: 0.960s
+// sprintf(sbuf,"%d\n", it);
+// buffer_printf2(&buf,"%d\n", it);
+
+ // buffer: 0.643s libc/sprintf: 1.251s libc/snprintf: 1.253s
+// snprintf(sbuf,sizeof(sbuf),"%10.*d\n", 8, it);
+// sprintf(sbuf,"%10.*d\n", 8, it);
+// buffer_printf2(&buf,"%10.*d\n", 8, it);
+
+ // buffer: 0.456s libc: 0.867s
+// sprintf(sbuf,"%X\n", it);
+ wget_buffer_printf2(&buf, "%X\n", it);
+
+ // buffer: 0.955s libc: 1.648s
+// sprintf(sbuf,"teststring %s sabbeldi %d\n", "[foobar foobar foobar]", it);
+// buffer_printf2(&buf,"teststring %s sabbeldi %d\n", "[foobar foobar foobar]", it);
+ }
+
+ wget_buffer_deinit(&buf);
+
+ return 0;
+}
diff --git a/tests2/certs/README b/tests2/certs/README
new file mode 100644
index 00000000..ae9de6e8
--- /dev/null
+++ b/tests2/certs/README
@@ -0,0 +1,77 @@
+To create the server RSA private key:
+$ certtool --generate-privkey --outfile x509-server-key.pem --rsa
+
+
+To create a self signed CA certificate:
+$ certtool --generate-privkey --outfile x509-ca-key.pem
+$ certtool --generate-self-signed --load-privkey x509-ca-key.pem --outfile x509-ca-cert.pem
+Common name: Mget
+UID:
+Organizational unit name: Mget
+Organization name: rockdaboot
+Locality name:
+State or province name:
+Country name (2 chars):
+Enter the subject's domain component (DC):
+This field should not be used in new certificates.
+E-mail:
+Enter the certificate's serial number in decimal (default: 6080487640893163573):
+
+Activation/Expiration time.
+The certificate will expire in (days): -1
+
+Extensions.
+Does the certificate belong to an authority? (y/N): y
+Path length constraint (decimal, -1 for no constraint):
+Is this a TLS web client certificate? (y/N):
+Will the certificate be used for IPsec IKE operations? (y/N):
+Is this a TLS web server certificate? (y/N):
+Enter a dnsName of the subject of the certificate:
+Enter a URI of the subject of the certificate:
+Enter the IP address of the subject of the certificate:
+Enter the e-mail of the subject of the certificate:
+Will the certificate be used to sign other certificates? (y/N): y
+Will the certificate be used to sign CRLs? (y/N): y
+Will the certificate be used to sign code? (y/N):
+Will the certificate be used to sign OCSP requests? (y/N): y
+Will the certificate be used for time stamping? (y/N):
+Enter the URI of the CRL distribution point:
+
+
+To generate a server certificate using the private key only:
+$ certtool --generate-certificate --load-privkey x509-server-key.pem --outfile x509-server-cert.pem --load-ca-certificate x509-ca-cert.pem --load-ca-privkey x509-ca-key.pem
+Common name: 127.0.0.1
+UID:
+Organizational unit name: Mget
+Organization name: rockdaboot
+Locality name:
+State or province name:
+Country name (2 chars):
+Enter the subject's domain component (DC):
+This field should not be used in new certificates.
+E-mail:
+Enter the certificate's serial number in decimal (default: 6080488276853553635):
+
+Activation/Expiration time.
+The certificate will expire in (days): -1
+
+Extensions.
+Does the certificate belong to an authority? (y/N):
+Is this a TLS web client certificate? (y/N):
+Will the certificate be used for IPsec IKE operations? (y/N):
+Is this a TLS web server certificate? (y/N): y
+Enter a dnsName of the subject of the certificate: 127.0.0.1
+Enter a dnsName of the subject of the certificate: localhost
+Enter a dnsName of the subject of the certificate:
+Enter a URI of the subject of the certificate:
+Enter the IP address of the subject of the certificate:
+Will the certificate be used for signing (DHE and RSA-EXPORT ciphersuites)? (Y/n):
+Will the certificate be used for encryption (RSA ciphersuites)? (Y/n):
+
+
+To create a CRL for the server certificate:
+$ certtool --generate-crl --load-ca-privkey x509-ca-key.pem --load-ca-certificate x509-ca-cert.pem --load-certificate x509-server-cert.pem --outfile x509-server-crl.pem
+Generating a signed CRL...
+Update times.
+The certificate will expire in (days): -1
+CRL Number (default: 6080006793650397145):
diff --git a/tests2/certs/x509-ca-cert.pem b/tests2/certs/x509-ca-cert.pem
new file mode 100644
index 00000000..95fd8f82
--- /dev/null
+++ b/tests2/certs/x509-ca-cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAlygAwIBAgIIVOoKhxVSl5wwDQYJKoZIhvcNAQELBQAwMzENMAsGA1UE
+AxMETWdldDENMAsGA1UECxMETWdldDETMBEGA1UEChMKcm9ja2RhYm9vdDAiGA8y
+MDE1MDIyMjE2NTc0NloYDzk5OTkxMjMxMjM1OTU5WjAzMQ0wCwYDVQQDEwRNZ2V0
+MQ0wCwYDVQQLEwRNZ2V0MRMwEQYDVQQKEwpyb2NrZGFib290MIIBUjANBgkqhkiG
+9w0BAQEFAAOCAT8AMIIBOgKCATEAwrMa15OMLS3aW2g/U2ASSHYZ5+lGema1vBjg
+d7TVN6hi+m3UU3S5P+7U9K83uWEQjK8Fuf+uS3bN4ltmAEkOoWm9JrGIh809CprJ
+fz0csR1i+z6vylNadMxTFFBpPgnzBxOuD6SpXcxHCJ5blsyToPkdDzZFq3bdnn9n
+IzfOn9hGDt7//nbEV+ypjKeTwAtOjnxlqyRnk74/KryoLtuEZ1UZEFZ4wpFDf95S
+Ejb8TuarWy87/iPlHHXAgWfnUYByrIK0tCu028/3o51PXU++jikuBP/GF94S4YQF
+m0FWwrbQfCmPgwS+Eg/S+xFzlfvbKmY/aRlEyww49n7HSJFBAxO0tKbZvx2ic6AX
++trMzcwUP1gkcfRc4TqxnMFN3W0Bm+aidLzPTHOQOhhcrI4QkwIDAQABo1gwVjAP
+BgNVHRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMJMA8GA1UdDwEB/wQF
+AwMHBgAwHQYDVR0OBBYEFHEGnMpPofvpa59JwTdIcZ1ARc3DMA0GCSqGSIb3DQEB
+CwUAA4IBMQCtrLovjm5ZdFbdbjbb2OOqEImSk+9moWsH78fNXjgiAXYOpsAiYYUj
+/s3ho1NWOdXroj7G5gD7kFfFgEKD94eD3YbyEmnJPo0w1cD7Y6FmdKk9I0SdsHtZ
+CEboHYnjV5Prgm0XxREzXuZzvrT57u+l319z6Aiomdg3yntxLcGF/PqHcGsdpRC0
+kHPJjxEADYDkRK7U4Osmpl7G6KOmLRh7ZdPZd+WXNQ/tfcgTrFdxuf3ufQe0sNR2
++o6oXhfuOJn8Xhv4JmVtkKZb+tr2/4UGEUiryICLHZkeIDPYANUOtxtZ5Yw+nHfH
+3Lr2jJlwUkPw2HXJt88nkGPm3ZLwEvIfe53OHqJw2IDlLoZ0LY+CykeuShxek0+X
+JiC0QAsEq2yoDsMr3gTa1ICC459s6RQO
+-----END CERTIFICATE-----
diff --git a/tests2/certs/x509-ca-key.pem b/tests2/certs/x509-ca-key.pem
new file mode 100644
index 00000000..d46c979b
--- /dev/null
+++ b/tests2/certs/x509-ca-key.pem
@@ -0,0 +1,165 @@
+Public Key Info:
+ Public Key Algorithm: RSA
+ Key Security Level: Normal (2432 bits)
+
+modulus:
+ 00:c2:b3:1a:d7:93:8c:2d:2d:da:5b:68:3f:53:60:
+ 12:48:76:19:e7:e9:46:7a:66:b5:bc:18:e0:77:b4:
+ d5:37:a8:62:fa:6d:d4:53:74:b9:3f:ee:d4:f4:af:
+ 37:b9:61:10:8c:af:05:b9:ff:ae:4b:76:cd:e2:5b:
+ 66:00:49:0e:a1:69:bd:26:b1:88:87:cd:3d:0a:9a:
+ c9:7f:3d:1c:b1:1d:62:fb:3e:af:ca:53:5a:74:cc:
+ 53:14:50:69:3e:09:f3:07:13:ae:0f:a4:a9:5d:cc:
+ 47:08:9e:5b:96:cc:93:a0:f9:1d:0f:36:45:ab:76:
+ dd:9e:7f:67:23:37:ce:9f:d8:46:0e:de:ff:fe:76:
+ c4:57:ec:a9:8c:a7:93:c0:0b:4e:8e:7c:65:ab:24:
+ 67:93:be:3f:2a:bc:a8:2e:db:84:67:55:19:10:56:
+ 78:c2:91:43:7f:de:52:12:36:fc:4e:e6:ab:5b:2f:
+ 3b:fe:23:e5:1c:75:c0:81:67:e7:51:80:72:ac:82:
+ b4:b4:2b:b4:db:cf:f7:a3:9d:4f:5d:4f:be:8e:29:
+ 2e:04:ff:c6:17:de:12:e1:84:05:9b:41:56:c2:b6:
+ d0:7c:29:8f:83:04:be:12:0f:d2:fb:11:73:95:fb:
+ db:2a:66:3f:69:19:44:cb:0c:38:f6:7e:c7:48:91:
+ 41:03:13:b4:b4:a6:d9:bf:1d:a2:73:a0:17:fa:da:
+ cc:cd:cc:14:3f:58:24:71:f4:5c:e1:3a:b1:9c:c1:
+ 4d:dd:6d:01:9b:e6:a2:74:bc:cf:4c:73:90:3a:18:
+ 5c:ac:8e:10:93:
+
+public exponent:
+ 01:00:01:
+
+private exponent:
+ 3b:da:79:8e:fa:21:e6:a5:a8:f1:de:bb:50:f3:40:
+ cb:9b:da:dc:eb:5e:aa:34:36:fc:2b:1d:9e:4f:2e:
+ 18:dd:20:08:62:89:1a:5a:d0:b4:31:c4:af:af:c9:
+ ce:a8:63:41:0c:71:13:3b:e1:a5:fb:50:d1:9c:4d:
+ 60:1b:15:6f:53:a5:3d:66:e8:54:ef:28:2b:c1:67:
+ de:40:b8:38:4e:93:66:2f:60:35:2f:a8:a8:2d:44:
+ 01:03:b3:46:ca:22:36:f3:ba:d7:be:43:fe:bc:d4:
+ bd:76:89:2b:73:9a:92:aa:e2:5f:11:cd:1b:28:00:
+ 7b:40:29:41:af:5f:4a:ce:5e:c3:25:94:c6:f2:55:
+ eb:bd:aa:65:be:02:72:d0:47:07:10:80:e4:ba:dd:
+ 48:92:73:6e:a3:fa:ab:35:a7:55:bc:b7:37:c2:0d:
+ f0:37:ab:8f:27:24:67:27:ab:d9:66:9c:6f:c8:f6:
+ 30:d7:72:db:e6:b1:3a:a1:df:a2:2f:42:fd:1c:fd:
+ c8:14:0e:cc:23:e8:f6:ba:38:42:97:78:80:6f:7c:
+ c9:a0:99:1f:c6:83:95:a8:1e:3a:a2:f5:27:fb:6a:
+ 82:f2:23:fe:00:18:75:b2:24:2e:1e:50:ad:07:c5:
+ b3:92:88:19:41:6a:a1:a8:09:6a:53:ab:f1:8f:3d:
+ c8:c9:f3:d5:4d:de:0c:c3:21:6d:25:fb:a8:de:57:
+ 04:a2:9d:0f:d7:b5:8e:ca:2e:9a:4a:5a:c3:c3:95:
+ 28:b7:30:b0:05:7b:ca:d8:b0:04:d2:85:7b:15:fb:
+ 61:66:4d:01:
+
+prime1:
+ 00:df:3d:5b:db:0f:a9:c4:c8:b5:3e:8c:65:8f:e8:
+ d6:40:1c:d0:83:e5:2a:99:0e:3a:67:07:f0:37:86:
+ 51:c7:07:a7:68:51:ba:32:bd:3a:a9:89:a5:1d:fe:
+ 65:e7:45:10:e8:27:81:58:cc:a4:4b:38:af:60:26:
+ 58:9e:ed:78:f3:ed:7b:8a:08:9d:9c:7c:6c:b7:74:
+ be:36:36:02:73:ba:5e:d5:15:f6:73:e7:89:33:c5:
+ 7e:63:d1:6d:26:5c:87:7d:b7:0a:c8:56:83:c5:45:
+ 9d:69:b6:01:fd:5e:7c:ee:8d:bc:6a:23:77:ed:43:
+ 07:47:a3:46:fe:55:75:e8:de:f9:e9:d9:20:b5:35:
+ 6c:1f:72:03:38:2a:11:8f:e4:a9:ad:09:e9:75:9f:
+ 9e:ae:13:
+
+prime2:
+ 00:df:45:8e:87:45:6f:e6:fe:10:27:b6:f7:a2:9e:
+ 1d:b8:92:9b:18:84:bf:9a:04:66:4e:6f:42:58:cd:
+ e6:60:29:f4:9d:78:a3:79:23:0e:dd:93:8c:4b:0d:
+ d4:dc:ab:48:af:36:21:b1:a8:da:94:00:f6:dc:19:
+ 84:8b:19:2b:60:a4:ec:f2:ed:d8:5f:ad:5e:f1:6a:
+ fa:e2:29:71:29:93:29:d2:0a:88:67:be:80:d9:be:
+ fe:19:38:e3:20:90:c4:5a:3d:b2:d0:5c:33:89:07:
+ e3:55:48:a6:ac:63:a9:8e:8c:bc:0f:f3:71:42:2f:
+ 0b:60:27:28:0a:84:d8:0a:de:4b:3c:b6:da:4f:89:
+ e5:a5:e7:fd:5d:4d:24:00:11:b8:4c:33:5a:9e:bb:
+ 7d:63:81:
+
+coefficient:
+ 35:cc:a8:18:c0:03:10:e4:6d:f5:fb:93:20:ec:c9:
+ e6:f6:2e:a1:0f:a0:a7:d1:d3:ff:db:ab:ee:20:91:
+ 27:9a:39:eb:ac:7a:a8:98:7a:fb:1a:71:69:59:0f:
+ 8d:4c:52:e7:38:71:55:c0:de:83:b8:9f:c5:eb:66:
+ c3:27:35:6c:ab:63:62:9c:eb:e5:49:7d:01:82:60:
+ 87:7e:58:c7:39:39:69:e0:6d:a0:56:98:13:b1:79:
+ 9e:64:6d:5f:6f:91:70:8a:cd:d8:49:73:ce:83:01:
+ ba:61:fb:85:4c:d7:54:1e:3e:b0:87:38:0f:4e:d3:
+ f9:63:2b:e0:1f:bb:ea:a6:b2:4e:b4:e1:38:a1:f2:
+ c8:7d:23:49:8f:86:0a:f8:df:bd:93:92:87:ce:a6:
+ 1d:b8:
+
+exp1:
+ 5e:95:49:b0:d3:bf:13:30:12:92:90:bb:8b:30:94:
+ 6e:0f:87:4d:0a:b0:74:ae:b1:91:eb:ac:1c:6a:5d:
+ 85:9d:39:91:9a:66:f0:8e:7a:27:50:b9:53:ae:f0:
+ 8f:ff:14:3d:b8:57:36:3f:66:30:b4:b0:a1:65:3d:
+ d1:00:3e:69:e3:29:9f:7f:2d:00:1b:3b:98:b2:ee:
+ d0:5b:2b:c8:ca:a2:d9:57:77:d6:fd:b7:84:e6:dd:
+ 38:ff:87:66:64:77:c7:8c:e1:15:a6:8a:27:ef:e9:
+ d4:db:17:96:b9:0c:e7:a9:c7:b5:94:97:80:40:10:
+ fa:8a:34:4f:17:f8:60:14:f0:ff:e2:4d:d8:58:ed:
+ 19:99:9d:c1:93:19:63:c4:f7:1a:e8:83:30:a1:d3:
+ 82:5f:
+
+exp2:
+ 00:a2:70:97:c6:e1:05:0e:39:30:05:c4:ff:9c:07:
+ 8f:b6:16:ab:d2:85:da:64:b2:e8:c0:0e:00:66:5d:
+ bf:4b:9d:9a:c3:ea:de:7c:a6:be:0d:05:69:5f:bd:
+ bb:6d:a5:0c:a7:b5:29:84:79:46:35:c2:11:d8:86:
+ 94:41:23:59:c4:e1:99:27:11:56:88:1d:b9:e2:c9:
+ 23:a8:e1:df:dc:10:9e:af:9b:4c:2c:b6:94:46:57:
+ c7:c5:0f:f7:67:5d:0c:0e:5f:af:36:1a:ae:bf:f6:
+ c6:35:e9:3a:a2:57:8c:28:13:4a:4c:0c:a1:0d:36:
+ ee:fe:d0:de:37:f0:f8:c1:c7:83:53:b3:f1:57:47:
+ 0b:96:ce:17:2f:07:8d:b6:a3:2d:c3:fa:e4:e6:71:
+ a0:43:81:
+
+
+Public Key ID: 71:06:9C:CA:4F:A1:FB:E9:6B:9F:49:C1:37:48:71:9D:40:45:CD:C3
+Public key's random art:
++--[ RSA 2432]----+
+| .....+=++ |
+| +. o oEo|
+| . o..+ .|
+| + .* . |
+| +S + o |
+| . . o . |
+| . .. |
+| +. o |
+| ooo+ |
++-----------------+
+
+-----BEGIN RSA PRIVATE KEY-----
+MIIFewIBAAKCATEAwrMa15OMLS3aW2g/U2ASSHYZ5+lGema1vBjgd7TVN6hi+m3U
+U3S5P+7U9K83uWEQjK8Fuf+uS3bN4ltmAEkOoWm9JrGIh809CprJfz0csR1i+z6v
+ylNadMxTFFBpPgnzBxOuD6SpXcxHCJ5blsyToPkdDzZFq3bdnn9nIzfOn9hGDt7/
+/nbEV+ypjKeTwAtOjnxlqyRnk74/KryoLtuEZ1UZEFZ4wpFDf95SEjb8TuarWy87
+/iPlHHXAgWfnUYByrIK0tCu028/3o51PXU++jikuBP/GF94S4YQFm0FWwrbQfCmP
+gwS+Eg/S+xFzlfvbKmY/aRlEyww49n7HSJFBAxO0tKbZvx2ic6AX+trMzcwUP1gk
+cfRc4TqxnMFN3W0Bm+aidLzPTHOQOhhcrI4QkwIDAQABAoIBMDvaeY76IealqPHe
+u1DzQMub2tzrXqo0NvwrHZ5PLhjdIAhiiRpa0LQxxK+vyc6oY0EMcRM74aX7UNGc
+TWAbFW9TpT1m6FTvKCvBZ95AuDhOk2YvYDUvqKgtRAEDs0bKIjbzute+Q/681L12
+iStzmpKq4l8RzRsoAHtAKUGvX0rOXsMllMbyVeu9qmW+AnLQRwcQgOS63UiSc26j
++qs1p1W8tzfCDfA3q48nJGcnq9lmnG/I9jDXctvmsTqh36IvQv0c/cgUDswj6Pa6
+OEKXeIBvfMmgmR/Gg5WoHjqi9Sf7aoLyI/4AGHWyJC4eUK0HxbOSiBlBaqGoCWpT
+q/GPPcjJ89VN3gzDIW0l+6jeVwSinQ/XtY7KLppKWsPDlSi3MLAFe8rYsATShXsV
++2FmTQECgZkA3z1b2w+pxMi1Poxlj+jWQBzQg+UqmQ46ZwfwN4ZRxwenaFG6Mr06
+qYmlHf5l50UQ6CeBWMykSzivYCZYnu148+17igidnHxst3S+NjYCc7pe1RX2c+eJ
+M8V+Y9FtJlyHfbcKyFaDxUWdabYB/V587o28aiN37UMHR6NG/lV16N756dkgtTVs
+H3IDOCoRj+SprQnpdZ+erhMCgZkA30WOh0Vv5v4QJ7b3op4duJKbGIS/mgRmTm9C
+WM3mYCn0nXijeSMO3ZOMSw3U3KtIrzYhsajalAD23BmEixkrYKTs8u3YX61e8Wr6
+4ilxKZMp0gqIZ76A2b7+GTjjIJDEWj2y0FwziQfjVUimrGOpjoy8D/NxQi8LYCco
+CoTYCt5LPLbaT4nlpef9XU0kABG4TDNanrt9Y4ECgZhelUmw078TMBKSkLuLMJRu
+D4dNCrB0rrGR66wcal2FnTmRmmbwjnonULlTrvCP/xQ9uFc2P2YwtLChZT3RAD5p
+4ymffy0AGzuYsu7QWyvIyqLZV3fW/beE5t04/4dmZHfHjOEVpoon7+nU2xeWuQzn
+qce1lJeAQBD6ijRPF/hgFPD/4k3YWO0ZmZ3BkxljxPca6IMwodOCXwKBmQCicJfG
+4QUOOTAFxP+cB4+2FqvShdpksujADgBmXb9LnZrD6t58pr4NBWlfvbttpQyntSmE
+eUY1whHYhpRBI1nE4ZknEVaIHbniySOo4d/cEJ6vm0wstpRGV8fFD/dnXQwOX682
+Gq6/9sY16TqiV4woE0pMDKENNu7+0N438PjBx4NTs/FXRwuWzhcvB422oy3D+uTm
+caBDgQKBmDXMqBjAAxDkbfX7kyDsyeb2LqEPoKfR0//bq+4gkSeaOeuseqiYevsa
+cWlZD41MUuc4cVXA3oO4n8XrZsMnNWyrY2Kc6+VJfQGCYId+WMc5OWngbaBWmBOx
+eZ5kbV9vkXCKzdhJc86DAbph+4VM11QePrCHOA9O0/ljK+Afu+qmsk604Tih8sh9
+I0mPhgr4372TkofOph24
+-----END RSA PRIVATE KEY-----
diff --git a/tests2/certs/x509-client-cert.pem b/tests2/certs/x509-client-cert.pem
new file mode 100644
index 00000000..930e4ff9
--- /dev/null
+++ b/tests2/certs/x509-client-cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDijCCAkKgAwIBAgIEUvoTYjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDEwxN
+Z2V0IHRlc3QgQ0EwIhgPMjAxNDAyMTExMjExMTRaGA8yMDE1MDIxMTEyMTExNFow
+GzEZMBcGA1UEAxMQTWdldCB0ZXN0IGNsaWVudDCCAVIwDQYJKoZIhvcNAQEBBQAD
+ggE/ADCCAToCggExAMnbJAFsp0B4xYqoHvCJCM76R2VAdYsqlSxA1pNSNw9GWpJG
+fuKftjJJRr2n9x3AY56Z3sS+1DiFMfDljvwrtFzDp/bQNMqSsVL1Oic6maN0ZvIm
+zFRQ9iPLRDnpp6u1yTjU1q5Tyvyc9Kk4WDrovYg0uk17XPnmnLNNLTicoveF2jyR
+ZK6D/gfX8NRcc1/MDEgXJvn5ME/zbGd7zJyJTuz9/EVF5D8dMTI6nvEheRoBH3JN
+VoDnoMgxn2t/IqDRZIBgSchNBUMn7c4IcWNJfIRE0aknRLxjUFNMUUEAnoZ44Gez
+v/kca74AtBFzEaXEj5bCQNlYXQ5ortVoCKCYAgXsxIhX3UiQmcynGSTMx+sVR0Of
+BzSspZNAh9mkWcDfnBRVN/AiL6GTZfmNBUZuMOcCAwEAAaN2MHQwDAYDVR0TAQH/
+BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAjAPBgNVHQ8BAf8EBQMDB6AAMB0GA1Ud
+DgQWBBRB0d9XNqMFDCjvq3o40vRsUFCneTAfBgNVHSMEGDAWgBRxBpzKT6H76Wuf
+ScE3SHGdQEXNwzANBgkqhkiG9w0BAQsFAAOCATEAekKrNi/Phbrd4HDEgEdO/Jw7
+HDF5Wq4M1M1P0ZYsdkXjs1I0Gu8zLmrftt675ngfE9l9ZUvWpRSbi4r+3RGEwiTG
+PqD82PSs2AyFG1RAzWyuzQb9JfdxhaVj6VEv26r3MujRgWK7eKsDqatMtQqoDyoq
+KpYpKdRmVI6TMbifS769tvONzsoeIZJWXORqwtYW1MeVkkm5IcwWwjbtlSXnDPFD
+ZSFm9nlwachTMUdq+ATr0KBBcD/EYt9QaH0FPRC2Bns/vYnOr+um5fYhLmNyNl/5
+iSU5tMv0GI/He0PpDx7GDBx3WqWatjxMUqx7jG0BJPsxrF5tjyN14Lk0264YcSb2
+mMWAtnRWtX0EpnRUVQYmHfMwgiGmRGi4+E7+G6IHT+qlW5D1zOfIF2jvMrWMLQ==
+-----END CERTIFICATE-----
diff --git a/tests2/certs/x509-client-key.pem b/tests2/certs/x509-client-key.pem
new file mode 100644
index 00000000..1125fe11
--- /dev/null
+++ b/tests2/certs/x509-client-key.pem
@@ -0,0 +1,165 @@
+Public Key Info:
+ Public Key Algorithm: RSA
+ Key Security Level: Normal (2432 bits)
+
+modulus:
+ 00:c9:db:24:01:6c:a7:40:78:c5:8a:a8:1e:f0:89:
+ 08:ce:fa:47:65:40:75:8b:2a:95:2c:40:d6:93:52:
+ 37:0f:46:5a:92:46:7e:e2:9f:b6:32:49:46:bd:a7:
+ f7:1d:c0:63:9e:99:de:c4:be:d4:38:85:31:f0:e5:
+ 8e:fc:2b:b4:5c:c3:a7:f6:d0:34:ca:92:b1:52:f5:
+ 3a:27:3a:99:a3:74:66:f2:26:cc:54:50:f6:23:cb:
+ 44:39:e9:a7:ab:b5:c9:38:d4:d6:ae:53:ca:fc:9c:
+ f4:a9:38:58:3a:e8:bd:88:34:ba:4d:7b:5c:f9:e6:
+ 9c:b3:4d:2d:38:9c:a2:f7:85:da:3c:91:64:ae:83:
+ fe:07:d7:f0:d4:5c:73:5f:cc:0c:48:17:26:f9:f9:
+ 30:4f:f3:6c:67:7b:cc:9c:89:4e:ec:fd:fc:45:45:
+ e4:3f:1d:31:32:3a:9e:f1:21:79:1a:01:1f:72:4d:
+ 56:80:e7:a0:c8:31:9f:6b:7f:22:a0:d1:64:80:60:
+ 49:c8:4d:05:43:27:ed:ce:08:71:63:49:7c:84:44:
+ d1:a9:27:44:bc:63:50:53:4c:51:41:00:9e:86:78:
+ e0:67:b3:bf:f9:1c:6b:be:00:b4:11:73:11:a5:c4:
+ 8f:96:c2:40:d9:58:5d:0e:68:ae:d5:68:08:a0:98:
+ 02:05:ec:c4:88:57:dd:48:90:99:cc:a7:19:24:cc:
+ c7:eb:15:47:43:9f:07:34:ac:a5:93:40:87:d9:a4:
+ 59:c0:df:9c:14:55:37:f0:22:2f:a1:93:65:f9:8d:
+ 05:46:6e:30:e7:
+
+public exponent:
+ 01:00:01:
+
+private exponent:
+ 4c:60:ed:28:d4:d2:1c:65:16:6a:36:df:2e:28:cb:
+ fa:75:5d:5a:84:9f:75:7f:31:5e:c3:51:ee:00:a7:
+ f0:d1:b0:27:b5:21:01:e3:68:ef:72:26:a0:50:d4:
+ 02:9f:ef:91:ed:ab:0b:4b:21:c6:19:30:22:74:da:
+ 3b:b4:d5:d4:5b:fc:4c:39:d0:1f:ee:8d:c6:54:20:
+ 23:03:db:6a:ab:fa:e0:19:aa:2b:25:4f:5d:8f:e6:
+ 4a:fb:8c:84:3e:8e:db:40:3d:d3:4c:c5:7b:fc:6f:
+ df:30:00:c2:99:9a:4d:d5:95:c1:07:b2:d0:a4:60:
+ 1a:c0:53:22:1e:b2:d3:72:04:77:f2:93:e4:2c:f1:
+ 8c:4a:3b:48:3f:8b:30:6e:67:1f:48:13:69:76:ce:
+ bf:11:31:92:c3:66:2e:b4:8c:05:9b:c7:92:92:87:
+ 74:d9:90:a1:63:b8:5f:41:a2:7b:69:5e:f0:d4:ca:
+ f8:f0:0d:39:17:27:1f:be:7a:44:0f:99:d7:db:0e:
+ 91:fc:8c:bc:4f:42:aa:d0:ef:2d:3d:95:96:cd:7c:
+ 08:b2:b3:77:80:fd:c8:cc:78:62:a3:28:8e:95:de:
+ 65:63:83:fb:c9:0e:12:d9:d1:a4:6c:de:2b:b8:1e:
+ 11:33:a3:98:22:55:17:85:17:f4:a5:64:ab:53:24:
+ 9d:44:e2:c1:ec:b7:1d:1e:bb:a8:38:62:e3:87:49:
+ 75:42:3a:08:da:25:94:4b:6e:ec:a6:12:c8:e0:fa:
+ 57:25:5d:f9:cc:6c:4c:d0:6b:b8:d0:31:c9:6b:86:
+ 28:81:e0:21:
+
+prime1:
+ 00:fe:2d:10:cc:db:19:c0:8c:63:74:98:e3:bc:ee:
+ 73:7b:c1:18:48:eb:31:f0:29:6c:91:56:50:0a:36:
+ 54:43:ca:aa:fb:48:f7:5a:2c:fe:8a:11:d7:56:9e:
+ e9:76:03:8d:b5:a0:15:c0:b6:c3:69:23:ab:52:35:
+ e5:bd:7a:d3:3a:d1:4d:fd:8f:a6:01:db:d0:d2:19:
+ 5f:60:e5:f6:1c:de:26:54:f1:4a:b2:26:08:b8:93:
+ 95:1f:52:0e:d7:66:13:27:12:e3:01:d6:c0:90:da:
+ 63:a2:2b:d2:4a:91:85:90:6f:fb:ff:e8:b9:fc:88:
+ 6e:ff:50:95:73:dd:6f:e5:03:ad:fa:cd:82:4e:aa:
+ 02:00:f7:5d:e0:fa:0e:f4:2f:05:9f:06:3e:fc:bb:
+ d5:bf:af:
+
+prime2:
+ 00:cb:4d:f5:e1:67:58:9c:2a:f7:19:20:6a:e3:0a:
+ dd:b9:35:df:c5:eb:3d:40:95:1d:ca:7a:83:6b:fc:
+ aa:22:91:94:98:a0:16:7e:68:48:8f:d1:db:88:62:
+ db:ac:e3:6f:5e:00:f1:29:8f:2d:3e:96:4f:c2:67:
+ ef:15:78:25:f7:78:04:b7:18:87:e6:16:e1:fb:12:
+ 1f:d4:e9:d8:63:70:8c:0d:96:ba:27:75:19:00:25:
+ dd:b1:c5:00:56:4b:96:2e:52:0a:dd:c6:c4:62:bb:
+ d2:24:20:f0:c2:bd:c1:41:e7:5f:8f:9f:db:93:1d:
+ fb:40:02:85:49:70:f3:eb:12:61:65:8f:92:b8:9a:
+ 9d:b6:8a:6e:78:8a:74:d8:49:e6:ad:1a:c4:9c:c9:
+ 07:f8:49:
+
+coefficient:
+ 53:f4:68:8c:8c:57:d8:ab:13:6c:2c:22:27:44:12:
+ 28:ae:b3:71:b6:d9:7f:c3:21:b1:f5:6f:fa:b3:70:
+ a6:64:54:4a:fe:cb:ed:22:af:76:2e:eb:05:b4:a8:
+ ed:50:93:ed:34:c7:90:9f:9f:0a:8c:69:5d:63:20:
+ 1f:52:f2:0d:18:59:df:b4:bb:67:c5:e2:b2:10:31:
+ be:4b:c6:07:a4:90:e9:50:8e:b3:0b:95:0a:e1:82:
+ ef:0f:3d:48:8f:e4:e5:12:a7:5c:12:89:0c:9b:34:
+ 6b:da:83:a4:b1:61:5d:58:9a:ac:44:f7:b2:b4:bf:
+ 7a:c6:ad:41:86:70:40:3a:71:20:30:35:a1:2d:8b:
+ 29:eb:1d:cf:c6:b5:c5:8a:55:29:7f:d4:98:91:76:
+ 4b:a1:
+
+exp1:
+ 79:8d:39:a4:8d:ff:01:ba:e1:71:08:10:98:f0:7b:
+ 9f:aa:17:20:00:01:f0:b5:0e:ab:6e:58:76:99:c6:
+ b0:68:c2:5d:cb:66:26:e4:af:91:7d:b8:ba:3e:e2:
+ ac:c2:44:49:a0:55:e6:c4:40:2d:0e:96:c6:88:e9:
+ e6:34:4f:c1:a8:08:a1:02:ca:43:c7:48:54:c1:37:
+ 80:92:58:a1:33:87:a7:45:81:10:32:ea:26:c2:c5:
+ 24:a6:4c:5c:ab:fe:ea:c7:b8:71:cf:ae:65:57:5b:
+ 20:59:ce:86:44:93:58:20:85:a5:bb:38:fe:50:8c:
+ ac:62:70:26:69:b6:32:12:11:68:88:51:11:a7:71:
+ af:de:9c:31:93:c4:04:f8:5b:ba:d1:f4:db:4e:44:
+ 89:17:
+
+exp2:
+ 48:1e:4f:aa:b5:ce:69:17:94:b0:05:1f:e5:8a:65:
+ 3c:de:2f:93:35:ef:74:89:71:17:f2:7d:cc:40:c4:
+ d9:9e:6a:e7:f9:62:01:55:5c:e8:27:b9:88:98:08:
+ f5:3b:78:b6:0f:ff:7c:8e:9d:ae:26:04:05:22:79:
+ 5d:54:51:a3:87:9f:a4:93:bf:21:8f:dc:7a:03:e3:
+ e6:d3:4d:3f:79:1d:35:74:d2:74:4c:c5:a1:97:cd:
+ 1c:d2:95:5c:07:54:2e:fa:4b:80:80:92:09:b4:36:
+ c7:3a:28:2d:ec:c2:31:6e:b2:27:70:bd:a3:62:6f:
+ 4e:35:96:b2:86:af:00:24:75:08:61:f5:da:26:7e:
+ eb:d2:0f:7e:13:1f:7f:da:37:4a:10:c4:ce:19:42:
+ 0a:81:
+
+
+Public Key ID: 41:D1:DF:57:36:A3:05:0C:28:EF:AB:7A:38:D2:F4:6C:50:50:A7:79
+Public key's random art:
++--[ RSA 2432]----+
+| ..o+..o.. |
+| . o+.. . +o|
+| .o+E . .o.+|
+| ..o ... .|
+| . S . |
+| o . |
+| o = . |
+| . + = . |
+| ..=.. |
++-----------------+
+
+-----BEGIN RSA PRIVATE KEY-----
+MIIFegIBAAKCATEAydskAWynQHjFiqge8IkIzvpHZUB1iyqVLEDWk1I3D0ZakkZ+
+4p+2MklGvaf3HcBjnpnexL7UOIUx8OWO/Cu0XMOn9tA0ypKxUvU6JzqZo3Rm8ibM
+VFD2I8tEOemnq7XJONTWrlPK/Jz0qThYOui9iDS6TXtc+eacs00tOJyi94XaPJFk
+roP+B9fw1FxzX8wMSBcm+fkwT/NsZ3vMnIlO7P38RUXkPx0xMjqe8SF5GgEfck1W
+gOegyDGfa38ioNFkgGBJyE0FQyftzghxY0l8hETRqSdEvGNQU0xRQQCehnjgZ7O/
++RxrvgC0EXMRpcSPlsJA2VhdDmiu1WgIoJgCBezEiFfdSJCZzKcZJMzH6xVHQ58H
+NKylk0CH2aRZwN+cFFU38CIvoZNl+Y0FRm4w5wIDAQABAoIBMExg7SjU0hxlFmo2
+3y4oy/p1XVqEn3V/MV7DUe4Ap/DRsCe1IQHjaO9yJqBQ1AKf75HtqwtLIcYZMCJ0
+2ju01dRb/Ew50B/ujcZUICMD22qr+uAZqislT12P5kr7jIQ+jttAPdNMxXv8b98w
+AMKZmk3VlcEHstCkYBrAUyIestNyBHfyk+Qs8YxKO0g/izBuZx9IE2l2zr8RMZLD
+Zi60jAWbx5KSh3TZkKFjuF9BontpXvDUyvjwDTkXJx++ekQPmdfbDpH8jLxPQqrQ
+7y09lZbNfAiys3eA/cjMeGKjKI6V3mVjg/vJDhLZ0aRs3iu4HhEzo5giVReFF/Sl
+ZKtTJJ1E4sHstx0eu6g4YuOHSXVCOgjaJZRLbuymEsjg+lclXfnMbEzQa7jQMclr
+hiiB4CECgZkA/i0QzNsZwIxjdJjjvO5ze8EYSOsx8ClskVZQCjZUQ8qq+0j3Wiz+
+ihHXVp7pdgONtaAVwLbDaSOrUjXlvXrTOtFN/Y+mAdvQ0hlfYOX2HN4mVPFKsiYI
+uJOVH1IO12YTJxLjAdbAkNpjoivSSpGFkG/7/+i5/Ihu/1CVc91v5QOt+s2CTqoC
+APdd4PoO9C8FnwY+/LvVv68CgZkAy0314WdYnCr3GSBq4wrduTXfxes9QJUdynqD
+a/yqIpGUmKAWfmhIj9HbiGLbrONvXgDxKY8tPpZPwmfvFXgl93gEtxiH5hbh+xIf
+1OnYY3CMDZa6J3UZACXdscUAVkuWLlIK3cbEYrvSJCDwwr3BQedfj5/bkx37QAKF
+SXDz6xJhZY+SuJqdtopueIp02EnmrRrEnMkH+EkCgZh5jTmkjf8BuuFxCBCY8Huf
+qhcgAAHwtQ6rblh2mcawaMJdy2Ym5K+Rfbi6PuKswkRJoFXmxEAtDpbGiOnmNE/B
+qAihAspDx0hUwTeAklihM4enRYEQMuomwsUkpkxcq/7qx7hxz65lV1sgWc6GRJNY
+IIWluzj+UIysYnAmabYyEhFoiFERp3Gv3pwxk8QE+Fu60fTbTkSJFwKBmEgeT6q1
+zmkXlLAFH+WKZTzeL5M173SJcRfyfcxAxNmeauf5YgFVXOgnuYiYCPU7eLYP/3yO
+na4mBAUieV1UUaOHn6STvyGP3HoD4+bTTT95HTV00nRMxaGXzRzSlVwHVC76S4CA
+kgm0Nsc6KC3swjFusidwvaNib041lrKGrwAkdQhh9domfuvSD34TH3/aN0oQxM4Z
+QgqBAoGYU/RojIxX2KsTbCwiJ0QSKK6zcbbZf8MhsfVv+rNwpmRUSv7L7SKvdi7r
+BbSo7VCT7TTHkJ+fCoxpXWMgH1LyDRhZ37S7Z8XishAxvkvGB6SQ6VCOswuVCuGC
+7w89SI/k5RKnXBKJDJs0a9qDpLFhXViarET3srS/esatQYZwQDpxIDA1oS2LKesd
+z8a1xYpVKX/UmJF2S6E=
+-----END RSA PRIVATE KEY-----
diff --git a/tests2/certs/x509-server-cert.pem b/tests2/certs/x509-server-cert.pem
new file mode 100644
index 00000000..e597402e
--- /dev/null
+++ b/tests2/certs/x509-server-cert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID6jCCAqKgAwIBAgIIVOoLCjBx2XwwDQYJKoZIhvcNAQELBQAwMzENMAsGA1UE
+AxMETWdldDENMAsGA1UECxMETWdldDETMBEGA1UEChMKcm9ja2RhYm9vdDAiGA8y
+MDE1MDIyMjE2NTk1N1oYDzk5OTkxMjMxMjM1OTU5WjA4MRIwEAYDVQQDEwkxMjcu
+MC4wLjExDTALBgNVBAsTBE1nZXQxEzARBgNVBAoTCnJvY2tkYWJvb3QwggFSMA0G
+CSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQDRsecbE8++eK1mxuxPOQdcGXWAsxuF
+pCuLuLI3BPViQ63Kqy9Yy7Yt9oeuPJq4HI5W0w8EieBWbaONajs0w0cWIjvc31/E
+IvTLBBHqYc6NoK0miScC3TQhRnvTSrJbl4CQ5H90Ri7ske6oAVMSDuUQF8+DQf+p
+czLJ8tohsNjj2ASEtwiEAFXvMTI0bHYpbqvUgNR/hLFcXvXKattJVyjbKecZLGOJ
+QqR27DspHT9az1s31wdaWbsaqiZky9PANx9mFxZpZGQJEoD23UTRSsZI3NYf/b0I
+nTzkyJNubP+tkdyA6yhBAkb4i87FWkiHSwpVJk2vsZm5sKA1SzJiji7l9dUwMXmA
+xTajnAI6N6F66MArfPdab9SRFkRNAHVwt1aYp3vjgOzKpRRnu0LDyqrXAgMBAAGj
+gZgwgZUwDAYDVR0TAQH/BAIwADAfBgNVHREEGDAWggkxMjcuMC4wLjGCCWxvY2Fs
+aG9zdDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHQ8BAf8EBQMDB6AAMB0GA1Ud
+DgQWBBShB4xj2jWSG4m1m7gPRKAWKujGPjAfBgNVHSMEGDAWgBRxBpzKT6H76Wuf
+ScE3SHGdQEXNwzANBgkqhkiG9w0BAQsFAAOCATEAKUVQOzo8UV9zSaPL/LqrWwaP
+C0JP/ncxqtRLVBc6a67Oe8I20nRK1S3TiSJZAKC2BSeyYKsYUV5/NdL7KhvF5Pjz
+vuHC5PB7SCFSZrD4axorFsr3oHBlXmBIEbvkotOokz0yWiScquvcSrYeQRRGVpMp
++an2b2UOekcxc1xwozre1j7BDw3V6xc5UdeDxqqdG0KptRSSBRdsF9tPKO50+URn
+JUg8Smosuq32EH6dJuTLDocl5mynz+lGLy/828RLZgIFSSacl/ts8T95D3DjL1+b
+iHDfQfqcjwkb5m1VusG1k55HWTnwuFlj2bvve1txXECUngMz9MMfOK/+Ly6ACrt0
+jDH07vJ9VtgWFREDGvj/e1tsk8sWMnK2LlggKWayx/COOMgWuv9SdEyZTlumZQ==
+-----END CERTIFICATE-----
diff --git a/tests2/certs/x509-server-crl.pem b/tests2/certs/x509-server-crl.pem
new file mode 100644
index 00000000..29b9edc1
--- /dev/null
+++ b/tests2/certs/x509-server-crl.pem
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIICBzCBwAIBATANBgkqhkiG9w0BAQsFADAzMQ0wCwYDVQQDEwRNZ2V0MQ0wCwYD
+VQQLEwRNZ2V0MRMwEQYDVQQKEwpyb2NrZGFib290GA8yMDE1MDIyMjE3MDM1MVoY
+Dzk5OTkxMjMxMjM1OTU5WjAdMBsCCFTqCwowcdl8GA8yMDE1MDIyMjE3MDM1MVqg
+NjA0MB8GA1UdIwQYMBaAFHEGnMpPofvpa59JwTdIcZ1ARc3DMBEGA1UdFAQKAghU
+6gv5MFwyuDANBgkqhkiG9w0BAQsFAAOCATEASyaCHchc7sIQDN41351nGfhsCnOS
+rno2X1ivJQ1M987KwODfl+s1Ecrkxp20VijBmt9FJ1gqqLSypB/cUKz7QC3WzRPo
+buKdio66a2e+LN8+7kXSfwt4wUlpR3BXTOmlZVDnLBA8PCtjnPHwuY82Y4Cpg38R
+yfSRmLtenSCVZk/SraVQ6c6kvKbgCM9kR/7/gMrZyW6SFLgXVFDAe6ZNSSALfgjC
+zg3He+3a0+upvwghS3YZZrxYBzbzr6s+RisTVF9bhg18LiHtEV5IlZJJPK1Lfdur
+5snpuXK7fDD1mTd0bHlneE8cnMg7c7UHNudXgDdoJH+aFay/hVQkFoVGlNtmjJjS
++yUOXhHvQDe2LWLVu2bYWjny99cQDYV7MR8NuBQpY2etPIHlldShhnj6BQ==
+-----END X509 CRL-----
diff --git a/tests2/certs/x509-server-key.pem b/tests2/certs/x509-server-key.pem
new file mode 100644
index 00000000..611d1f5f
--- /dev/null
+++ b/tests2/certs/x509-server-key.pem
@@ -0,0 +1,165 @@
+Public Key Info:
+ Public Key Algorithm: RSA
+ Key Security Level: Normal (2432 bits)
+
+modulus:
+ 00:d1:b1:e7:1b:13:cf:be:78:ad:66:c6:ec:4f:39:
+ 07:5c:19:75:80:b3:1b:85:a4:2b:8b:b8:b2:37:04:
+ f5:62:43:ad:ca:ab:2f:58:cb:b6:2d:f6:87:ae:3c:
+ 9a:b8:1c:8e:56:d3:0f:04:89:e0:56:6d:a3:8d:6a:
+ 3b:34:c3:47:16:22:3b:dc:df:5f:c4:22:f4:cb:04:
+ 11:ea:61:ce:8d:a0:ad:26:89:27:02:dd:34:21:46:
+ 7b:d3:4a:b2:5b:97:80:90:e4:7f:74:46:2e:ec:91:
+ ee:a8:01:53:12:0e:e5:10:17:cf:83:41:ff:a9:73:
+ 32:c9:f2:da:21:b0:d8:e3:d8:04:84:b7:08:84:00:
+ 55:ef:31:32:34:6c:76:29:6e:ab:d4:80:d4:7f:84:
+ b1:5c:5e:f5:ca:6a:db:49:57:28:db:29:e7:19:2c:
+ 63:89:42:a4:76:ec:3b:29:1d:3f:5a:cf:5b:37:d7:
+ 07:5a:59:bb:1a:aa:26:64:cb:d3:c0:37:1f:66:17:
+ 16:69:64:64:09:12:80:f6:dd:44:d1:4a:c6:48:dc:
+ d6:1f:fd:bd:08:9d:3c:e4:c8:93:6e:6c:ff:ad:91:
+ dc:80:eb:28:41:02:46:f8:8b:ce:c5:5a:48:87:4b:
+ 0a:55:26:4d:af:b1:99:b9:b0:a0:35:4b:32:62:8e:
+ 2e:e5:f5:d5:30:31:79:80:c5:36:a3:9c:02:3a:37:
+ a1:7a:e8:c0:2b:7c:f7:5a:6f:d4:91:16:44:4d:00:
+ 75:70:b7:56:98:a7:7b:e3:80:ec:ca:a5:14:67:bb:
+ 42:c3:ca:aa:d7:
+
+public exponent:
+ 01:00:01:
+
+private exponent:
+ 72:42:5b:c9:17:4c:75:5e:d0:2d:56:6a:e0:e8:14:
+ 28:8c:fe:c7:b7:d0:61:4b:89:26:c2:e6:e8:af:dc:
+ fd:44:1f:68:75:4a:81:39:ce:f4:d0:86:31:dc:77:
+ f9:a6:25:b1:0d:a3:fb:37:1d:74:3a:9d:89:aa:be:
+ c4:0b:3b:aa:c5:d0:94:93:6a:5d:37:26:e7:90:3a:
+ 2a:da:4c:70:43:82:d5:a2:9a:0d:27:77:06:42:9f:
+ aa:0b:e3:8f:a0:c7:bf:2b:a2:7f:3a:d6:ca:b4:e1:
+ b3:cd:b4:f3:fc:05:b8:75:20:ef:46:81:06:55:ec:
+ f0:b9:51:3e:56:5c:78:19:f6:ac:52:07:63:d5:c2:
+ fd:68:73:10:b9:a0:d1:06:aa:be:49:cc:80:07:4f:
+ 95:22:74:6f:a4:bc:6d:46:65:89:49:5e:22:4a:d0:
+ eb:7c:a6:63:e8:e2:f7:27:7a:a0:05:be:29:32:28:
+ c1:3b:27:80:3d:f6:b9:09:cb:1d:d3:68:16:a1:16:
+ 1c:cc:ba:af:fe:f1:90:b3:71:48:4f:76:17:81:b0:
+ b4:b4:72:b8:b4:5d:11:f3:a3:fa:e2:45:8c:cc:b9:
+ ed:3e:2c:3b:85:fc:ef:1e:6f:e1:3b:c9:c0:da:ed:
+ 6c:cb:d7:90:b4:28:bf:a8:3e:cd:d4:2e:b7:73:25:
+ 58:ef:0d:9c:b9:15:27:c0:53:42:81:82:2b:6b:89:
+ 94:3b:63:f5:8c:37:74:33:c0:1a:bd:b2:d0:30:d5:
+ f8:75:b5:f6:78:86:ea:3e:70:a0:0f:c5:36:b4:cf:
+ 29:2f:91:a1:
+
+prime1:
+ 00:ef:34:77:5b:e2:46:2c:80:ce:e6:20:46:9d:33:
+ d0:81:7d:33:02:bb:c9:12:a0:c2:2f:ba:30:32:95:
+ a3:db:a7:27:af:35:ee:59:70:0a:09:22:1a:f4:96:
+ 37:7d:fa:54:fb:46:4e:f7:1b:b9:50:4d:e5:05:16:
+ 71:9b:75:3b:fc:ae:a7:9c:05:3d:62:45:0a:d3:01:
+ a7:22:3c:49:ad:fe:1c:be:84:84:7b:f3:45:a4:54:
+ 98:f7:1d:bc:67:29:1d:4e:01:6b:7d:a1:82:26:32:
+ 12:c2:a7:fb:1c:0a:c6:1e:10:5f:f6:a7:e2:19:7b:
+ 05:39:26:6e:77:4d:e3:e9:62:53:ed:ad:7e:6a:16:
+ b6:a0:f0:5b:2c:8c:46:2e:98:ab:2c:e5:71:67:00:
+ c2:c7:69:
+
+prime2:
+ 00:e0:6b:03:ff:f8:07:75:ae:56:e0:f1:b8:cd:8e:
+ cc:c0:7c:54:bc:43:19:dd:62:a9:10:07:01:37:6a:
+ 91:e1:43:18:51:05:f1:0c:33:c4:f3:e5:d5:c2:52:
+ 79:56:33:b8:4e:72:f0:80:b2:2a:32:9d:63:25:af:
+ 32:77:98:00:d1:22:86:25:f2:86:74:91:19:eb:fd:
+ 85:e1:63:43:2e:c5:54:d8:d3:74:7f:0c:ae:b5:e8:
+ 83:53:ed:97:97:28:d5:be:94:b7:d4:36:b4:0d:51:
+ a0:b2:fc:b3:8c:70:8d:46:a2:e2:c6:11:ed:75:fe:
+ 37:f9:a8:4d:fe:a9:94:37:d0:72:6f:fc:bf:aa:ad:
+ 68:56:f0:ed:f1:86:04:a0:4c:27:6e:89:c5:cb:6e:
+ 63:d8:3f:
+
+coefficient:
+ 00:eb:8e:c0:fe:3e:81:67:64:61:a1:97:01:94:99:
+ 35:86:d5:8e:c4:60:00:90:f9:6c:ff:f3:b1:55:60:
+ b8:2f:60:e8:6d:0b:ee:15:7a:7d:f3:6e:42:7c:39:
+ 91:a6:57:59:39:86:3e:da:73:db:e0:54:ac:5d:81:
+ 31:23:9b:d3:fc:a0:9a:8b:9a:7f:67:63:d8:eb:f4:
+ 37:a4:13:46:d8:4c:44:1f:c7:28:e4:c5:ba:2c:78:
+ a1:5c:6a:cc:65:84:a9:1e:a1:6d:c4:62:57:3c:a8:
+ e5:42:ed:a4:ec:b0:11:91:5f:12:55:67:f4:9d:19:
+ 6f:36:2f:e4:3b:08:6b:e1:68:b6:d1:26:b2:7e:a8:
+ 60:04:8f:7b:0b:ca:2c:98:d5:c9:10:94:ab:d5:99:
+ eb:d2:31:
+
+exp1:
+ 1b:62:a7:53:96:a9:30:09:23:26:c7:85:2e:14:33:
+ 87:cf:9c:9a:70:83:49:a5:ab:f5:a8:dc:41:be:4d:
+ ff:24:b8:ef:5f:3e:45:71:05:45:1c:69:77:9d:07:
+ 07:5e:34:82:7b:ff:28:5d:3d:2f:0b:6b:ef:d4:2c:
+ f7:7e:49:7a:d9:48:09:1d:b4:74:5e:b1:29:8d:23:
+ e4:50:80:a2:f1:d7:ba:9c:13:4a:d9:84:1c:97:2e:
+ d8:03:c8:81:0a:fc:f6:e4:44:b9:22:57:73:26:02:
+ 6d:d4:ab:73:ff:6b:c5:1f:5c:cd:31:55:3a:53:92:
+ 3a:83:c2:db:d7:c8:02:fd:25:dc:ad:23:2e:e4:20:
+ ce:76:16:0a:18:99:24:56:88:2a:60:ae:45:fb:99:
+ 51:19:
+
+exp2:
+ 6d:f6:e2:39:dd:de:41:e2:d0:7d:5e:d4:90:1c:e5:
+ e5:77:c6:c9:8d:13:b2:70:32:a9:40:d5:6e:c3:10:
+ 82:51:af:2b:9c:7e:b5:dc:f4:28:12:b9:c0:83:4b:
+ 23:5b:2a:77:7e:48:ac:b7:20:88:36:a8:ab:81:82:
+ 78:29:8a:54:ef:d6:cd:e7:5d:cc:e6:80:ce:2b:27:
+ 1b:fe:d8:9f:a5:5f:e2:f3:12:45:63:00:84:f0:4e:
+ d1:a4:3d:40:7b:68:e8:fe:d4:68:ee:f9:21:01:9b:
+ 7d:b8:e7:7d:ec:74:bd:64:f9:3b:d6:f3:05:7b:31:
+ 10:6b:50:f4:75:41:c4:6b:a6:77:8b:60:9b:90:66:
+ ed:1b:17:6c:de:9f:8b:b0:65:2d:fb:e2:68:c1:49:
+ b9:5f:
+
+
+Public Key ID: A1:07:8C:63:DA:35:92:1B:89:B5:9B:B8:0F:44:A0:16:2A:E8:C6:3E
+Public key's random art:
++--[ RSA 2432]----+
+|.. . |
+|+..o * |
+|=.o X = . |
+|=. = O + . |
+| ++ = . S |
+|o. . . |
+| Eo |
+| .o |
+| . |
++-----------------+
+
+-----BEGIN RSA PRIVATE KEY-----
+MIIFewIBAAKCATEA0bHnGxPPvnitZsbsTzkHXBl1gLMbhaQri7iyNwT1YkOtyqsv
+WMu2LfaHrjyauByOVtMPBIngVm2jjWo7NMNHFiI73N9fxCL0ywQR6mHOjaCtJokn
+At00IUZ700qyW5eAkOR/dEYu7JHuqAFTEg7lEBfPg0H/qXMyyfLaIbDY49gEhLcI
+hABV7zEyNGx2KW6r1IDUf4SxXF71ymrbSVco2ynnGSxjiUKkduw7KR0/Ws9bN9cH
+Wlm7GqomZMvTwDcfZhcWaWRkCRKA9t1E0UrGSNzWH/29CJ085MiTbmz/rZHcgOso
+QQJG+IvOxVpIh0sKVSZNr7GZubCgNUsyYo4u5fXVMDF5gMU2o5wCOjeheujAK3z3
+Wm/UkRZETQB1cLdWmKd744DsyqUUZ7tCw8qq1wIDAQABAoIBMHJCW8kXTHVe0C1W
+auDoFCiM/se30GFLiSbC5uiv3P1EH2h1SoE5zvTQhjHcd/mmJbENo/s3HXQ6nYmq
+vsQLO6rF0JSTal03JueQOiraTHBDgtWimg0ndwZCn6oL44+gx78ron861sq04bPN
+tPP8Bbh1IO9GgQZV7PC5UT5WXHgZ9qxSB2PVwv1ocxC5oNEGqr5JzIAHT5UidG+k
+vG1GZYlJXiJK0Ot8pmPo4vcneqAFvikyKME7J4A99rkJyx3TaBahFhzMuq/+8ZCz
+cUhPdheBsLS0cri0XRHzo/riRYzMue0+LDuF/O8eb+E7ycDa7WzL15C0KL+oPs3U
+LrdzJVjvDZy5FSfAU0KBgitriZQ7Y/WMN3QzwBq9stAw1fh1tfZ4huo+cKAPxTa0
+zykvkaECgZkA7zR3W+JGLIDO5iBGnTPQgX0zArvJEqDCL7owMpWj26cnrzXuWXAK
+CSIa9JY3ffpU+0ZO9xu5UE3lBRZxm3U7/K6nnAU9YkUK0wGnIjxJrf4cvoSEe/NF
+pFSY9x28ZykdTgFrfaGCJjISwqf7HArGHhBf9qfiGXsFOSZud03j6WJT7a1+aha2
+oPBbLIxGLpirLOVxZwDCx2kCgZkA4GsD//gHda5W4PG4zY7MwHxUvEMZ3WKpEAcB
+N2qR4UMYUQXxDDPE8+XVwlJ5VjO4TnLwgLIqMp1jJa8yd5gA0SKGJfKGdJEZ6/2F
+4WNDLsVU2NN0fwyuteiDU+2XlyjVvpS31Da0DVGgsvyzjHCNRqLixhHtdf43+ahN
+/qmUN9Byb/y/qq1oVvDt8YYEoEwnbonFy25j2D8CgZgbYqdTlqkwCSMmx4UuFDOH
+z5yacINJpav1qNxBvk3/JLjvXz5FcQVFHGl3nQcHXjSCe/8oXT0vC2vv1Cz3fkl6
+2UgJHbR0XrEpjSPkUICi8de6nBNK2YQcly7YA8iBCvz25ES5IldzJgJt1Ktz/2vF
+H1zNMVU6U5I6g8Lb18gC/SXcrSMu5CDOdhYKGJkkVogqYK5F+5lRGQKBmG324jnd
+3kHi0H1e1JAc5eV3xsmNE7JwMqlA1W7DEIJRryucfrXc9CgSucCDSyNbKnd+SKy3
+IIg2qKuBgngpilTv1s3nXczmgM4rJxv+2J+lX+LzEkVjAITwTtGkPUB7aOj+1Gju
++SEBm324533sdL1k+TvW8wV7MRBrUPR1QcRrpneLYJuQZu0bF2zen4uwZS374mjB
+SblfAoGZAOuOwP4+gWdkYaGXAZSZNYbVjsRgAJD5bP/zsVVguC9g6G0L7hV6ffNu
+Qnw5kaZXWTmGPtpz2+BUrF2BMSOb0/ygmouaf2dj2Ov0N6QTRthMRB/HKOTFuix4
+oVxqzGWEqR6hbcRiVzyo5ULtpOywEZFfElVn9J0ZbzYv5DsIa+FottEmsn6oYASP
+ewvKLJjVyRCUq9WZ69Ix
+-----END RSA PRIVATE KEY-----
diff --git a/tests2/files/contact.html b/tests2/files/contact.html
new file mode 100644
index 00000000..4aadf4f2
--- /dev/null
+++ b/tests2/files/contact.html
@@ -0,0 +1,785 @@
+<!doctype html>
+<!--[if lt IE 7 ]> <html class="no-js ie6" lang="en"> <![endif]-->
+<!--[if IE 7 ]> <html class="no-js ie7" lang="en"> <![endif]-->
+<!--[if IE 8 ]> <html class="no-js ie8" lang="en"> <![endif]-->
+<!--[if (gte IE 9)|!(IE)]><!--> <html class="no-js"> <!--<![endif]-->
+<head>
+ <title>Linux Security Contacts</title>
+ <meta name="description" content="SUSE Linux Enterprise security contact information and encryption keys" />
+ <meta name="keywords" content="suse, security, contact, encryption keys" />
+
+ <meta charset="utf-8">
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+<link rel="shortcut icon" href="/common/img/favicon.gif">
+<link rel="apple-touch-icon" href="/common/img/apple-touch-iphone.png">
+<link rel="apple-touch-icon" sizes="72x72" href="/common/img/apple-touch-ipad.png">
+<link rel="apple-touch-icon" sizes="114x114" href="/common/img/apple-touch-iphone4.png">
+<link rel="stylesheet" href="/common/inc/css/main.css?v=11">
+
+<!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if necessary -->
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
+<script>window.jQuery || document.write("<script src='/common/inc/js/jquery-1.5.1.min.js'><\/script>")</script>
+
+<!-- JS that is necessary for page load. All other JS is included in ftr_js.html -->
+<script src="/common/inc/js/core.js?v=1"></script>
+<script src="/common/inc/js/modernizr-1.7.min.js"></script>
+
+<!-- Typekit -->
+<script type="text/javascript" src="http://use.typekit.com/oar0gpe.js"></script>
+<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
+
+<script type="text/javascript">
+ document.write('<script type="text/javascript" src="http://www.suse.com/common/util/geophone.php?co='+user_country_code+'"><\/script>');
+</script>
+
+<!-- Foresee Survey -->
+
+ <script type="text/javascript" src="/common/inc/foresee/foresee-trigger.js"></script>
+
+
+</head>
+<body>
+<div id="container">
+ <header>
+ <div class="wrap">
+ <!-- <p class="portal"><a href="#"><strong>SuSE</strong> Customer Portal</a></p> -->
+ <div>
+ <div id="search">
+ <form action="/SearchUI/query" method="get">
+ <label for="q">Search</label>
+ <input type="text" name="term" value="" id="q">
+ <input type="submit" name="submit" value="" id="q_submit">
+ </form>
+ </div>
+ </div>
+ <div id="logo"><a href="/">SUSE</a></div>
+ <ul id="nav">
+ <li id="nav_solutions"><a href="/solutions/">Solutions</a>
+ <div class="nav_sub">
+ <div class="nav_sub_contents">
+ <div class="col col_two">
+ <p class="nav_subheading"><a href="/solutions/platform.html">Platform Solutions</a></p>
+ <ul>
+ <li><a href="/solutions/platform.html#server">Server</a></li>
+ <li><a href="/solutions/platform.html#desktop">Desktop</a></li>
+ <li><a href="/solutions/platform.html#cloud">Cloud Computing</a></li>
+ <li><a href="/solutions/platform.html#virtualization">Virtualization</a></li>
+ </ul>
+</div>
+<div class="col col_two">
+ <p class="nav_subheading"><a href="/solutions/industry.html">Industry Solutions</a></p>
+ <ul>
+ <li><a href="/solutions/industry.html#retail">Retail</a></li>
+ <li><a href="/solutions/industry.html#healthcare"><span>Healthcare</span></a></li>
+ <li><a href="/solutions/industry.html#manufacturing">Manufacturing</a></li>
+ <li><a href="/solutions/industry.html#government">Government</a></li>
+ <li><a href="/solutions/industry.html#banking">Banking &amp; Finance</a></li>
+ </ul>
+</div>
+<div class="clr"></div>
+
+ </div>
+ </div>
+ </li>
+ <li id="nav_products"><a href="/products/">Products &amp; Services</a>
+ <div class="nav_sub">
+ <div class="nav_sub_contents">
+ <div class="col col_four">
+ <p class="nav_subheading">Server</p>
+ <ul>
+ <li><a href="/products/server/">SUSE Linux Enterprise Server</a></li>
+ <li><a href="/products/systemz/">SUSE Linux Enterprise Server for System z</a></li>
+ <li><a href="/products/expandedsupport/">SUSE Linux Enterprise Server with Expanded Support</a></li>
+ <li><a href="/products/sles-for-sap/">SUSE Linux Enterprise Server for SAP Applications</a></li>
+ <li><a href="/products/linuxpointofservice/">SUSE Linux Enterprise Point of Service</a></li>
+ </ul>
+</div>
+<div class="col col_four">
+ <p class="nav_subheading">OEM and Desktop</p>
+ <ul>
+ <li><a href="/partners/alliance-partners/vmware/">SUSE Linux Enterprise Server for VMware</a></li>
+ <li><a href="http://aws.amazon.com/suse/">SUSE Linux Enterprise Server for Amazon EC2</a></li>
+ <li><a href="/products/desktop/">SUSE Linux Enterprise Desktop</a></li>
+ <li><a href="http://www.novell.com/products/libreoffice/">LibreOffice</a></li>
+ </ul>
+</div>
+<div class="col col_four">
+ <p class="nav_subheading">Extensions</p>
+ <ul>
+ <li><a href="/products/highavailability/">SUSE Linux Enterprise High Availability Extension</a></li>
+ <li><a href="/products/realtime/">SUSE Linux Enterprise Real Time Extension</a></li>
+ <li><a href="/products/vmdriverpack/">SUSE Linux Enterprise Virtual Machine Driver Pack</a></li>
+ <li><a href="http://www.novell.com/products/sle-management-pack/">SUSE Linux Enterprise Management Pack for System Center Operations Manager R2 2007</a></li>
+ </ul>
+</div>
+<div class="col col_four">
+ <p class="nav_subheading">Management and Services</p>
+ <ul>
+ <li><a href="/products/suse-manager/">SUSE Manager</a></li>
+ <li><a href="/products/susestudio/">SUSE Studio</a></li>
+ <li><a href="/support/">Support</a></li>
+ <li><a href="/training/">Training and Certification</a></li>
+ <li><a href="http://www.novell.com/consulting/">Consulting</a></li>
+ </ul>
+</div>
+<div class="clr"></div>
+
+ </div>
+ </div>
+ </li>
+ <li id="nav_support"><a href="/support/">Support</a>
+ <div class="nav_sub">
+ <div class="nav_sub_contents">
+ <div class="col col_five">
+ <p class="nav_subheading"><a href="/support/">Self Support</a></p>
+ <ul>
+ <li><a href="/support/kb/">Knowledgebase</a></li>
+ <li><a href="http://support.novell.com/advisor/index.html">Novell Support Advisor</a></li>
+ <li><a href="http://forums.suse.com">Discussion Forums</a></li>
+ <li><a href="/documentation/">Documentation</a></li>
+ <li><a href="/releasenotes/">Release Notes</a></li>
+ <li><a href="/support/">Support by Product</a></li>
+ <li><a href="https://secure-www.novell.com/center/regadmin/jsps/activate_app.jsp">Activate My Product</a></li>
+ <li><a href="http://support.novell.com/subscriptions/index.html">Technical Subscriptions</a></li>
+ <li><a href="/security/">Get Security Reports</a></li>
+ </ul>
+</div>
+<div class="col col_five">
+ <p class="nav_subheading"><a href="/support/programs.html">Support Programs</a></p>
+ <ul>
+ <li><a href="http://support.novell.com/partner_services.html">Support from Partner</a></li>
+ <li><a href="http://support.novell.com/contact/index.html">Open Service Request</a></li>
+ <li><a href="/support/programs.html">SUSE Support Programs</a></li>
+ <li><a href="http://support.novell.com/lifecycle/index.html">Product Support Lifecycle</a></li>
+ <li><a href="http://support.novell.com/chat/general">Chat with Us (Non-technical Questions)</a></li>
+ </ul>
+</div>
+<div class="col col_five">
+ <p class="nav_subheading">Participate</p>
+ <ul>
+ <li><a href="http://support.novell.com/additional/bugreport.html">Report a Bug</a></li>
+ <li><a href="http://www.novell.com/communities/node/1394/how-submit-content">Submit Tips, Tricks &amp; Tools</a></li>
+ <li><a href="http://support.novell.com/enhancement/index.html">Request Product Enhancement</a></li>
+ <li><a href="http://support.novell.com/security-alerts/index.html">Report Software Vulnerability</a></li>
+ <li><a href="http://www.novell.com/beta/index.jsp">Beta Test</a></li>
+ </ul>
+</div>
+<div class="col col_five">
+ <p class="nav_subheading"><a href="/download-linux/">Download</a></p>
+ <ul>
+ <li><a href="http://support.novell.com/patches.html">Patches</a></li>
+ <li><a href="http://download.novell.com/">Products</a></li>
+ <li><a href="http://drivers.suse.com/">Drivers</a></li>
+ <li><a href="http://beta.novell.com/">Beta</a></li>
+ <li><a href="http://www.novell.com/communities/coolsolutions/tools">Cool Tools</a></li>
+ </ul>
+</div>
+<div class="col col_five">
+ <p class="nav_subheading"><a href="https://secure-www.novell.com/center/regadmin/jsps/home_app.jsp">Customer Center</a></p>
+ <ul>
+ <li><a href="https://secure-www.novell.com/center/regadmin/jsps/profile_app.jsp">My Profile</a></li>
+ <li><a href="https://secure-www.novell.com/center/regadmin/jsps/sub_app.jsp?topic=list&amp;clearFilter=true&amp;clearGroupId=true">My Products</a></li>
+ <li><a href="https://secure-www.novell.com/center/eservice/">My Support</a></li>
+ <li><a href="https://secure-www.novell.com/center/trnsrv">My Training</a></li>
+ <li><a href="http://support.novell.com/contact/index.html">Open Service Request</a></li>
+ </ul>
+</div>
+<div class="clr"></div>
+
+ </div>
+ </div>
+ </li>
+ <li id="nav_partners"><a href="/partners/">Partners</a>
+ <div class="nav_sub">
+ <div class="nav_sub_contents">
+ <div class="col col_four">
+ <p class="nav_subheading"><a href="/partners">Partner with SUSE</a></p>
+ <ul>
+ <li><a href="/partners/solution/">Solution Provider &amp; System Integrator</a></li>
+ <li><a href="/partners/ihv/">Hardware Vendor</a></li>
+ <li><a href="/partners/isv/">Software Vendor</a></li>
+ <li><a href="https://www.partnernetprogram.com/program/commercial-training/suse.html">Commercial Training Partner</a></li>
+ <li><a href="https://www.partnernetprogram.com/program/academic-training/suse.html">Academic Training Partner</a></li>
+ <li><a href="https://www.partnernetprogram.com/program/cloud-service-provider/suse.html">Cloud Service Provider</a></li>
+ </ul>
+</div>
+<div class="col col_four">
+ <p class="nav_subheading"><a href="http://www.novell.com/site/partners/protected/index.page">PartnerNet</a></p>
+ <ul>
+ <li><a href="http://www.novell.com/site/partners/protected/index.page">PartnerNet Login</a></li>
+ <li><a href="http://www.novell.com/communities/partners/">PartnerNet Community</a></li>
+ <li><a href="http://www.novell.com/site/partners/protected/enablement/datacenter/enterpriselinuxservers/index.page">Enablement Central</a></li>
+ </ul>
+</div>
+<div class="col col_four">
+ <p class="nav_subheading"><a href="http://www.novell.com/partnerlocator/">Find a Partner</a></p>
+ <ul>
+ <li><a href="http://www.novell.com/partnerlocator/">Partner Locator</a></li>
+ <li><a href="/partner/isv/isvcatalog">SUSE Linux Enterprise ISV Catalog</a></li>
+ <li><a href="/partners/alliance-partners/">Alliance Partners</a></li>
+ </ul>
+</div>
+<div class="col col_four">
+ <p class="nav_subheading"><a href="/partners/isv/#suse_phone">Developers</a></p>
+ <ul>
+ <li><a href="http://developer.novell.com/devnet/yes/">YES Certified Program</a></li>
+ <li><a href="http://www.novell.com/communities/developers/">Developer Community</a></li>
+ </ul>
+</div>
+<div class="clr"></div>
+
+ </div>
+ </div>
+ </li>
+ <li id="nav_community"><a href="/communities/">Community</a>
+ <div class="nav_sub">
+ <div class="nav_sub_contents">
+ <div class="col col_one">
+ <p class="nav_subheading"><a href="/communities/">Community</a></p>
+ <ul>
+ <li><a href="/communities/#communities_user">User Communities</a></li>
+ <li><a href="/communities/#communities_social">Social Networks</a></li>
+ <li><a href="/communities/#communities_opensource">Open Source</a></li>
+ </ul>
+</div>
+<div class="clr"></div>
+
+ </div>
+ </div>
+ </li>
+ <li id="nav_dl" class="highlight"><a href="/download-linux/">Free Downloads</a></li>
+ <li id="nav_shop" class="highlight"><a href="http://shop.novell.com/store/novell/DisplayCategoryProductListPage/categoryID.1581900">Shop</a></li>
+ </ul>
+ <div class="clr"></div>
+ </div>
+</header>
+
+ <div id="main" role="main">
+ <div class="longtail tier4">
+ <div id="content">
+ <div class="wrap">
+ <div class="share">
+ <div class="post-share-links">
+ <ul>
+ <li><a title="share on Facebook" onclick="return sharePost('facebook',window.location.href,document.title);" href="#" class="post-share-link-facebook">Facebook</a></li>
+ <li><a title="share on Twitter" onclick="return sharePost('twitter',window.location.href,document.title);" href="#" class="post-share-link-twitter">Twitter</a></li>
+ <li><a title="share in email" onclick="emailFriendPost(window.location.href); return false" href="#" class="post-share-link-email">E-mail</a></li>
+ </ul>
+</div>
+<p class="social">
+ <a onclick="return false;" href="#" class="share_btn social_btns">
+
+ Share
+
+ <img alt="" src="/common/img/social/share_icon.png"></a>
+</p>
+ </div>
+ <h1>SUSE Security Contacts</h1>
+ <div class="content_left">
+ <p class="subtitle">To contact the SUSE Security Team, write email to
+ <ul>
+ <li><a href="mailto:security@suse.de">security@suse.com</a></li>
+ <li><a href="mailto:security@suse.de">security@suse.de</a></li>
+ </ul>
+ <p>We encourage people who wish to contact SUSE Security to use mail encryption. Our key is:</p>
+
+ <p>3D25D3D9 1999-03-06 SUSE Security Team &lt;security suse.de&gt;<br />
+ Key fingerprint = 73 5F 2E 99 DF DB 94 C4 8F 5A A3 AE AF 22 F2 D5</p>
+ <p>The key is listed below in ASCII encoded form.</p>
+<pre>
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.6 (GNU/Linux)
+Comment: For more information see http://www.suse.de/security
+
+mQENAzbhLQQAAAEIAKAkXHe0lWRBXLpn38hMHy03F0I4Sszmoc8aaKJrhfhyMlOA
+BqvklPLE2f9UrI4Xc860gH79ZREwAgPt0pi6+SleNFLNcNFAuuHMLQOOsaMFatbz
+JR9i4m/lf6q929YROu5zB48rBAlcfTm+IBbijaEdnqpwGib45wE/Cfy6FAttBHQh
+1Kp+r/jPbf1mYAvljUfHKuvbg8t2EIQz/5yGp+n5trn9pElfQO2cRBq8LFpf1l+U
+P7EKjFmlOq+Gs/fF98/dP3DfniSd78LQPq5vp8RL8nr/o2i7jkAQ33m4f1wOBWd+
+cZovrKXYlXiR+Bf7m2hpZo+/sAzhd7LmAD0l09kABRG0JVN1U0UgU2VjdXJpdHkg
+VGVhbSA8c2VjdXJpdHlAc3VzZS5kZT6JARUDBRA24S1H5Fiyh7HKPEUBAVcOB/9b
+yHYji1/+4Xc2GhvXK0FSJN0MGgeXgW47yxDL7gmR4mNgjlIOUHZj0PEpVjWepOJ7
+tQS3L9oP6cpj1Fj/XxuLbkp5VCQ61hpt54coQAvYrnT9rtWEGN+xmwejT1WmYmDJ
+xG+EGBXKr+XP69oIUl1E2JO3rXeklulgjqRKos4cdXKgyjWZ7CP9V9daRXDtje63
+Om8gwSdU/nCvhdRIWp/Vwbf7Ia8iZr9OJ5YuQl0DBG4qmGDDrvImgPAFkYFzwlqo
+choXFQ9y0YVCV41DnR+GYhwl2qBd81T8aXhihEGPIgaw3g8gd8B5o6mPVgl+nJqI
+BkEYGBusiag2pS6qwznZiQEVAwUQNuEtBHey5gA9JdPZAQFtOAf+KVh939b0J94u
+v/kpg4xs1LthlhquhbHcKNoVTNspugiC3qMPyvSX4XcBr2PC0cVkS4Z9PY9iCfT+
+x9WM96g39dAF+le2CCx7XISk9XXJ4ApEy5g4AuK7NYgAJd39PPbERgWnxjxir9g0
+Ix30dS30bW39D+3NPU5Ho9TD/B7UDFvYT5AWHl3MGwo3a1RhTs6sfgL7yQ3U+mvq
+MkTExZb5mfN1FeaYKMopoI4VpzNVeGxQWIz67VjJHVyUlF20ekOz4kWVgsxkc8G2
+saqZd6yv2EwqYTi8BDAduweP33KrQc4KDDommQNDOXxaKOeCoESIdM4p7Esdjq1o
+L0oixF12CohGBBARAgAGBQI7HmHDAAoJEJ5A4xAACqukTlQAoI4QzP9yjPohY7OU
+F7J3eKBTzp25AJ42BmtSd3pvm5ldmognWF3Trhp+GYkAlQMFEDe3O8IWkDf+zvyS
+FQEBAfkD/3GG5UgJj18UhYmh1gfjIlDcPAeqMwSytEHDENmHC+vlZQ/p0mT9tPiW
+tp34io54mwr+bLPN8l6B5GJNkbGvH6M+mO7R8Lj4nHL6pyAv3PQr83WyLHcaX7It
+Klj371/4yzKV6qpz43SGRK4MacLo2rNZ/dNej7lwPCtzCcFYwqkiiEYEEBECAAYF
+AjoaQqQACgkQx1KqMrDf94ArewCfWnTUDG5gNYkmHG4bYL8fQcizyA4An2eVo/n+
+3J2KRWSOhpAMsnMxtPbBmQGiBDnu9IERBACT8Y35+2vv4MGVKiLEMOl9GdST6MCk
+YS3yEKeueNWc+z/0Kvff4JctBsgs47tjmiI9sl0eHjm3gTR8rItXMN6sJEUHWzDP
++Y0PFPboMvKx0FXl/A0dM+HFrruCgBlWt6FA+okRySQiliuI5phwqkXefl9AhkwR
+8xocQSVCFxcwvwCglVcOQliHu8jwRQHxlRE0tkwQQI0D+wfQwKdvhDplxHJ5nf7U
+8c/yE/vdvpN6lF0tmFrKXBUX+K7u4ifrZlQvj/81M4INjtXreqDiJtr99Rs6xa0S
+cZqITuZC4CWxJa9GynBED3+D2t1V/f8l0smsuYoFOF7Ib49IkTdbtwAThlZp8bEh
+ELBeGaPdNCcmfZ66rKUdG5sRA/9ovnc1krSQF2+sqB9/o7w5/q2qiyzwOSTnkjtB
+UVKn4zLUOf6aeBAoV6NMCC3Kj9aZHfA+ND0ehPaVGJgjaVNFhPi4x0e7BULdvgOo
+AqajLfvkURHAeSsxXIoEmyW/xC1sBbDkDUIBSx5oej73XCZgnj/inphRqGpsb+1n
+KFvF+rQoU3VTRSBQYWNrYWdlIFNpZ25pbmcgS2V5IDxidWlsZEBzdXNlLmRlPohc
+BBMRAgAcBQI57vSBBQkDwmcABAsKAwQDFQMCAxYCAQIXgAAKCRCoTtronIAKyl8s
+AJ98BgD40zw0GHJHIf6dNfnwI2PAsgCgjH1+PnYEl7TFjtZsqhezX7vZvYCIRgQQ
+EQIABgUCOnBeUgAKCRCeQOMQAAqrpNzOAKCL512FZvv4VZx94TpbA9lxyoAejACe
+OO1HIbActAevk5MUBhNeLZa/qM2JARUDBRA6cGBvd7LmAD0l09kBATWnB/9An5vf
+iUUE1VQnt+T/EYklES3tXXaJJp9pHMa4fzFa8jPVtv5UBHGee3XoUNDVwM2OgSEI
+SZxbzdXGnqIlcT08TzBUD9i579uifklLsnr35SJDZ6ram51/CWOnnaVhUzneOA9g
+TPSr+/fT3WeVnwJiQCQ30kNLWVXWATMnsnT486eAOlT6UNBPYQLpUprF5Yryk23p
+QUPAgJENDEqeU6iIO9Ot1ZPtB0lniw+/xCi13D360o1tZDYOp0hHHJN3D3EN8C1y
+PqZd5CvvznYvB6bWBIpWcRgdn2DUVMmpU661jwqGlRz1F84JG/xe4jGuzgpJt9IX
+SzyohEJB6XG5+D0BiF0EExECAB0FAjxqqTQFCQoAgrMFCwcKAwQDFQMCAxYCAQIX
+gAAKCRCoTtronIAKyp1fAJ9dR7saz2KPNwD3U+fy/0BDKXrYGACfbJ8fQcJqCBQx
+eHvt9yMPDVq0B0W5Ag0EOe70khAIAISR0E3ozF/la+oNaRwxHLrCet30NgnxRROY
+hPaJB/Tu1FQokn2/Qld/HZnh3TwhBIw1FqrhWBJ7491iAjLR9uPbdWJrn+A7t8kS
+kPaF3Z/6kyc5a8fas44ht5h+6HMBzoFCMAq2aBHQRFRNp9Mz1ZvoXXcI1lk1l8Oq
+cUM/ovXbDfPcXsUVeTPTtGzcAi2jVl9hl3iwJKkyv/RLmcusdsi8YunbvWGFAF5G
+aagYQo7YlF6UaBQnYJTM523AMgpPQtsKm9o/w9WdgXkgWhgkhZEeqUS3m5xNey1n
+Lu9iMvq9M/iXnGz4sg6Q2Y+GqZ+yAvNWjRRou3zSE7Bzg28MI4sAAwYH/2D71Xc5
+HPDgu87WnBFgmp8MpSr8QnSs0wwPg3xEullGEocolSb2c0ctuSyeVnCttJMzkukL
+9TqyF4s/6XRstWirSWawJxRLKH6Zjo/FaKsshYKf8gBkAaddvpl3pO0gmUYbqmpQ
+3xDEYlhCeieXS5MkockQ1sj2xYdB1xO0ExzfiCiscUKjUFy+mdzUsUutafuZ+gbH
+og1CN/ccZCkxcBa5IFCHORrNjq9pYWlrxsEn6ApsG7JJbM2besW1PkdEoxak74z1
+senh36m5jQvVjA3U4xq1wwylxadmmJaJHzeiLfb7G1ZRjZTsB7fyYxqDzMVul6o9
+BSwO/1XsIAnV1uuITAQYEQIADAUCOe70kgUJA8JnAAAKCRCoTtronIAKyksiAJsF
+B3/77SkH3JlYOGrEe1Ol0JdGwACeKTttgeVPFB+iGJdiwQlxasOfuXyITAQYEQIA
+DAUCPGqpWQUJCgCCxwAKCRCoTtronIAKyofBAKCSZM2UFyta/fe9WgITK9I5hbxx
+tQCfX+0ar2CZmSknn3coSPihn1+OBNw=
+=r69E
+-----END PGP PUBLIC KEY BLOCK-----
+</pre>
+ <br /><br />
+
+
+ </div>
+ <div class="content_right">
+ <div id="rac_preview" class="rac_button_embedded">
+ <p class="button button_chat"><a href="#"><span>Chat Now</span></a></p>
+</div>
+
+<div id="requestcall">
+
+ <script type="text/javascript" src="http://www.novell.com/company/sales_call_request_translated_javascript.js"></script>
+ <script type="text/javascript" src="http://www.novell.com/inc/util/secure/userInfo.php"></script>
+ <script type="text/javascript" src="http://www.novell.com/inc/util/pagequery.js"></script>
+
+
+ <p class="title">Request a Call</p>
+
+
+ <p class="phonecall">Call <script type="text/javascript">document.write(n_phone);</script> or complete the form below.</p>
+ <div id="form_wrap">
+ <div id="form_content">
+ <p id="required_note"><span class="req">*</span> Required Fields</p>
+ <form id="salescallrequest" method="post" action="http://www.novell.com/surveyutil/route_survey_data.jsp" onsubmit="return formCheck(this);">
+ <fieldset>
+ <input type="hidden" name="survey-id" value="400">
+ <input type="hidden" name="charset" value="">
+ <input type="hidden" name="email_to" value="crc@novell.com">
+ <input type="hidden" name="email_cc" value="">
+ <input type="hidden" name="email_bcc" value="jwhitloc@novell.com">
+ <input type="hidden" name="email_from" value="sales_call_request@suse.com">
+ <input type="hidden" name="email_subject" value="SUSE.com Web Lead - Call Immediately">
+ <input type="hidden" name="fromUrl" id="fromUrl" value="">
+ <input type="hidden" name="send_html" value="true">
+ <input type="hidden" name="email_template" value="/company/sales_call_request_template_new.txt">
+ <input type="hidden" name="thankyou_page" value="http://www.suse.com/company/thankyou.html">
+ <input type="hidden" name="request_from" value="Request a call">
+ <input type="hidden" name="novell_magic_field" value="">
+ <input type="hidden" name="question_6241" value="">
+ <input type="hidden" name="question_6242" value="">
+ <input type="hidden" name="question_7040" value="">
+ <input type="hidden" name="question_6425" value="">
+ <input type="hidden" name="question_6243" value="">
+ <input type="hidden" name="question_7478" value="">
+ <input type="hidden" name="question_7519" value="">
+ <input type="hidden" name="question_7648" value="">
+ <input type="hidden" name="question_7649" value="">
+
+ <div id="requestcall_fname" class="half"><label for="question_6173">First Name <span class="req">*</span></label> <input type="text" id="question_6173" name="question_6173"></div>
+ <div id="requestcall_lname" class="half last"><label for="question_6174">Last Name <span class="req">*</span></label> <input type="text" id="question_6174" name="question_6174"></div>
+
+ <div id="requestcall_company" class="half"><label for="question_6175">Company <span class="req">*</span></label> <input type="text" id="question_6175" name="question_6175"></div>
+ <div id="requestcall_phone" class="half last"><label for="question_6177">Phone <span class="req">*</span></label> <input type="text" id="question_6177" name="question_6177" onchange="setPhoneChanged();" onfocus="clearPrefill(this)"></div>
+ <div id="requestcall_address" style="display:none;"><label for="question_6179">Street Address <span class="req">*</span></label> <input type="text" id="question_6179" name="question_6179"></div>
+ <div id="requestcall_state" style="display:none;"><label for="question_6182">State/Province <span class="req">*</span></label> <input type="text" id="question_6182" name="question_6182"></div>
+
+ <div id="requestcall_postal" style="display:none;"><label for="question_6183">Postal Code <span class="req">*</span></label> <input type="text" id="question_6183" name="question_6183"></div>
+ <div id="requestcall_city" class="half"><label for="question_6181">City <span class="req">*</span></label> <input type="text" id="question_6181" name="question_6181"></div>
+ <div id="requestcall_country" class="half last"><label for="question_6178">Country <span class="req">*</span></label>
+ <select name="question_6178" id="question_6178" onchange="setPhonePrefill(this.value);">
+ <option value="">&nbsp;</option>
+
+ <option value=""></option>
+<option value="United States">United States</option>
+<option value="Germany">Germany</option>
+<option value="India">India</option>
+<option value="">-----</option>
+<option value="Afghanistan">Afghanistan</option>
+<option value="Albania">Albania</option>
+<option value="Algeria">Algeria</option>
+<option value="American Samoa">American Samoa</option>
+<option value="Andorra">Andorra</option>
+<option value="Angola">Angola</option>
+<option value="Anguilla">Anguilla</option>
+<option value="Antarctica">Antarctica</option>
+<option value="Antigua and Barbuda">Antigua and Barbuda</option>
+<option value="Argentina">Argentina</option>
+<option value="Armenia">Armenia</option>
+<option value="Aruba">Aruba</option>
+<option value="Australia">Australia</option>
+<option value="Austria">Austria</option>
+<option value="Azerbaijan">Azerbaijan</option>
+<option value="Bahamas">Bahamas</option>
+<option value="Bahrain">Bahrain</option>
+<option value="Bangladesh">Bangladesh</option>
+<option value="Barbados">Barbados</option>
+<option value="Belarus">Belarus</option>
+<option value="Belgium">Belgium</option>
+<option value="Belize">Belize</option>
+<option value="Benin">Benin</option>
+<option value="Bermuda">Bermuda</option>
+<option value="Bhutan">Bhutan</option>
+<option value="Bolivia">Bolivia</option>
+<option value="Bosnia and Herzegovina">Bosnia and Herzegovina</option>
+<option value="Botswana">Botswana</option>
+<option value="Bouvet Island">Bouvet Island</option>
+<option value="Brazil">Brazil</option>
+<option value="British Indian Ocean Territory">British Indian Ocean Territory</option>
+<option value="Brunei Darussalam">Brunei Darussalam</option>
+<option value="Bulgaria">Bulgaria</option>
+<option value="Burkina Faso">Burkina Faso</option>
+<option value="Burundi">Burundi</option>
+<option value="Cambodia">Cambodia</option>
+<option value="Cameroon">Cameroon</option>
+<option value="Canada">Canada</option>
+<option value="Cape Verde">Cape Verde</option>
+<option value="Cayman Islands">Cayman Islands</option>
+<option value="Central African Republic">Central African Republic</option>
+<option value="Chad">Chad</option>
+<option value="Chile">Chile</option>
+<option value="China">China</option>
+<option value="Christmas Island">Christmas Island</option>
+<option value="Cocos (Keeling) Islands">Cocos (Keeling) Islands</option>
+<option value="Colombia">Colombia</option>
+<option value="Comoros">Comoros</option>
+<option value="Congo">Congo</option>
+<option value="Cook Islands">Cook Islands</option>
+<option value="Costa Rica">Costa Rica</option>
+<option value="Cote d&#39;Ivoire">Cote d&#39;Ivoire</option>
+<option value="Croatia">Croatia</option>
+<option value="Cyprus">Cyprus</option>
+<option value="Czech Republic">Czech Republic</option>
+<option value="Denmark">Denmark</option>
+<option value="Djibouti">Djibouti</option>
+<option value="Dominica">Dominica</option>
+<option value="Dominican Republic">Dominican Republic</option>
+<option value="Ecuador">Ecuador</option>
+<option value="Egypt">Egypt</option>
+<option value="El Salvador">El Salvador</option>
+<option value="Equatorial Guinea">Equatorial Guinea</option>
+<option value="Eritrea">Eritrea</option>
+<option value="Estonia">Estonia</option>
+<option value="Ethiopia">Ethiopia</option>
+<option value="Falkland Islands (Malvinas)">Falkland Islands (Malvinas)</option>
+<option value="Faroe Islands">Faroe Islands</option>
+<option value="Fiji Islands">Fiji Islands</option>
+<option value="Finland">Finland</option>
+<option value="France">France</option>
+<option value="French Guiana">French Guiana</option>
+<option value="French Polynesia">French Polynesia</option>
+<option value="French Southern Territories">French Southern Territories</option>
+<option value="Gabon">Gabon</option>
+<option value="Gambia">Gambia</option>
+<option value="Georgia">Georgia</option>
+<option value="Ghana">Ghana</option>
+<option value="Gibraltar">Gibraltar</option>
+<option value="Greece">Greece</option>
+<option value="Greenland">Greenland</option>
+<option value="Grenada">Grenada</option>
+<option value="Guadeloupe">Guadeloupe</option>
+<option value="Guam">Guam</option>
+<option value="Guatemala">Guatemala</option>
+<option value="Guinea">Guinea</option>
+<option value="Guinea-Bissau">Guinea-Bissau</option>
+<option value="Guyana">Guyana</option>
+<option value="Haiti">Haiti</option>
+<option value="Heard Island and McDonald Islands">Heard Island and McDonald Islands</option>
+<option value="Honduras">Honduras</option>
+<option value="Hong Kong">Hong Kong</option>
+<option value="Hungary">Hungary</option>
+<option value="Iceland">Iceland</option>
+<option value="Indonesia">Indonesia</option>
+<option value="Iraq">Iraq</option>
+<option value="Ireland">Ireland</option>
+<option value="Israel">Israel</option>
+<option value="Italy">Italy</option>
+<option value="Jamaica">Jamaica</option>
+<option value="Japan">Japan</option>
+<option value="Jordan">Jordan</option>
+<option value="Kazakhstan">Kazakhstan</option>
+<option value="Kenya">Kenya</option>
+<option value="Kiribati">Kiribati</option>
+<option value="Korea">Korea, Republic of</option>
+<option value="Kuwait">Kuwait</option>
+<option value="Kyrgyzstan">Kyrgyzstan</option>
+<option value="Lao People&#39;s Democratic Republic">Lao People&#39;s Democratic Republic</option>
+<option value="Latvia">Latvia</option>
+<option value="Lebanon">Lebanon</option>
+<option value="Lesotho">Lesotho</option>
+<option value="Liberia">Liberia</option>
+<option value="Libyan Arab Jamahiriya">Libyan Arab Jamahiriya</option>
+<option value="Liechtenstein">Liechtenstein</option>
+<option value="Lithuania">Lithuania</option>
+<option value="Luxembourg">Luxembourg</option>
+<option value="Macao">Macao</option>
+<option value="Macedonia">Macedonia</option>
+<option value="Madagascar">Madagascar</option>
+<option value="Malawi">Malawi</option>
+<option value="Malaysia">Malaysia</option>
+<option value="Maldives">Maldives</option>
+<option value="Mali">Mali</option>
+<option value="Malta">Malta</option>
+<option value="Marshall Islands">Marshall Islands</option>
+<option value="Martinique">Martinique</option>
+<option value="Mauritania">Mauritania</option>
+<option value="Mauritius">Mauritius</option>
+<option value="Mayotte">Mayotte</option>
+<option value="Mexico">Mexico</option>
+<option value="Micronesia">Micronesia, Federated States of</option>
+<option value="Moldova, Republic of">Moldova, Republic of</option>
+<option value="Monaco">Monaco</option>
+<option value="Mongolia">Mongolia</option>
+<option value="Montserrat">Montserrat</option>
+<option value="Morocco">Morocco</option>
+<option value="Mozambique">Mozambique</option>
+<option value="Myanmar">Myanmar</option>
+<option value="Namibia">Namibia</option>
+<option value="Nauru">Nauru</option>
+<option value="Nepal">Nepal</option>
+<option value="Netherlands">Netherlands</option>
+<option value="Netherlands Antilles">Netherlands Antilles</option>
+<option value="New Caledonia">New Caledonia</option>
+<option value="New Zealand">New Zealand</option>
+<option value="Nicaragua">Nicaragua</option>
+<option value="Niger">Niger</option>
+<option value="Nigeria">Nigeria</option>
+<option value="Niue">Niue</option>
+<option value="Norfolk Island">Norfolk Island</option>
+<option value="Northern Mariana Islands">Northern Mariana Islands</option>
+<option value="Norway">Norway</option>
+<option value="Oman">Oman</option>
+<option value="Pakistan">Pakistan</option>
+<option value="Palau">Palau</option>
+<option value="Palestinian Territory">Palestinian Territory, Occupied</option>
+<option value="Panama">Panama</option>
+<option value="Papua New Guinea">Papua New Guinea</option>
+<option value="Paraguay">Paraguay</option>
+<option value="Peru">Peru</option>
+<option value="Philippines">Philippines</option>
+<option value="Pitcairn">Pitcairn</option>
+<option value="Poland">Poland</option>
+<option value="Portugal">Portugal</option>
+<option value="Puerto Rico">Puerto Rico</option>
+<option value="Qatar">Qatar</option>
+<option value="Reunion">Reunion</option>
+<option value="Romania">Romania</option>
+<option value="Russia">Russia</option>
+<option value="Rwanda">Rwanda</option>
+<option value="Saint Helena">Saint Helena</option>
+<option value="Saint Kitts and Nevis">Saint Kitts and Nevis</option>
+<option value="Saint Lucia">Saint Lucia</option>
+<option value="Saint Pierre and Miquelon">Saint Pierre and Miquelon</option>
+<option value="Saint Vincent and the Grenadines">Saint Vincent and the Grenadines</option>
+<option value="Samoa">Samoa</option>
+<option value="San Marino">San Marino</option>
+<option value="Sao Tome and Principe">Sao Tome and Principe</option>
+<option value="Saudi Arabia">Saudi Arabia</option>
+<option value="Senegal">Senegal</option>
+<option value="Serbia and Montenegro">Serbia and Montenegro</option>
+<option value="Seychelles">Seychelles</option>
+<option value="Sierra Leone">Sierra Leone</option>
+<option value="Singapore">Singapore</option>
+<option value="Slovakia">Slovakia</option>
+<option value="Slovenia">Slovenia</option>
+<option value="Solomon Islands">Solomon Islands</option>
+<option value="Somalia">Somalia</option>
+<option value="South Africa">South Africa</option>
+<option value="South Georgia and the South Sandwich Islands">South Georgia and the South Sandwich Islands</option>
+<option value="Spain">Spain</option>
+<option value="Sri Lanka">Sri Lanka</option>
+<option value="Suriname">Suriname</option>
+<option value="Svalbard and Jan Mayen">Svalbard and Jan Mayen</option>
+<option value="Swaziland">Swaziland</option>
+<option value="Sweden">Sweden</option>
+<option value="Switzerland">Switzerland</option>
+<option value="Taiwan">Taiwan, Republic of China</option>
+<option value="Tajikistan">Tajikistan</option>
+<option value="Tanzania">Tanzania</option>
+<option value="Thailand">Thailand</option>
+<option value="Timor-Leste">Timor-Leste</option>
+<option value="Togo">Togo</option>
+<option value="Tokelau">Tokelau</option>
+<option value="Tonga">Tonga</option>
+<option value="Trinidad and Tobago">Trinidad and Tobago</option>
+<option value="Tunisia">Tunisia</option>
+<option value="Turkey">Turkey</option>
+<option value="Turkmenistan">Turkmenistan</option>
+<option value="Turks and Caicos Islands">Turks and Caicos Islands</option>
+<option value="Tuvalu">Tuvalu</option>
+<option value="Uganda">Uganda</option>
+<option value="Ukraine">Ukraine</option>
+<option value="United Arab Emirates">United Arab Emirates</option>
+<option value="United Kingdom">United Kingdom</option>
+<option value="United States Minor Outlying Islands">United States Minor Outlying Islands</option>
+<option value="Uruguay">Uruguay</option>
+<option value="Uzbekistan">Uzbekistan</option>
+<option value="Vanuatu">Vanuatu</option>
+<option value="Vatican City State">Vatican City State</option>
+<option value="Venezuela">Venezuela</option>
+<option value="Vietnam">Vietnam</option>
+<option value="Virgin Islands-British">Virgin Islands, British</option>
+<option value="Virgin Islands-U.S.">Virgin Islands, U.S.</option>
+<option value="Wallis and Futuna">Wallis and Futuna</option>
+<option value="Western Sahara">Western Sahara</option>
+<option value="Yemen">Yemen</option>
+<option value="Zambia">Zambia</option>
+<option value="Zimbabwe">Zimbabwe</option>
+
+ </select>
+ </div>
+ <div id="requestcall_email"><label for="question_6176">Email Address <span class="req">*</span></label> <input type="text" id="question_6176" name="question_6176"></div>
+ <div id="requestcall_comments"><label for="question_6184">Comments</label> <textarea name="question_6184" id="question_6184" class="expanding" rows="2" cols="15"></textarea></div>
+
+ <p id="disclaimer">Read our <a href="/company/policies/privacy/">Privacy Policy</a>.</p>
+
+ <p class="form_submit_hide"><input type="submit" value="Submit"></p>
+ </fieldset>
+ </form>
+ </div>
+ <div class="form_submit">
+ <p><a href="#">Request a Call&nbsp;&#8250;</a></p>
+ </div>
+ </div>
+</div>
+ </div>
+ <div class="clr"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <footer>
+
+ <div class="footer_global">
+ <div class="wrap">
+ <p>&copy; 2012 SUSE</p>
+ <ul>
+ <li><a href="/company/careers/" target="_top">Careers</a></li>
+ <li><a href="/company/legal/" target="_top">Legal</a></li>
+ <li><a href="#" class="feedback">Feedback</a></li>
+ <li><a href="/company/" target="_top">About</a></li>
+ <li><a href="/ContactsOffices/contacts_offices.jsp" target="_top">Contact Us</a></li>
+ </ul>
+ <p id="suse_phone"><a href="#" class="rac"><script type="text/javascript">if(typeof n_phone != "undefined"){ document.write(n_phone); }</script></a></p>
+ <div class="clr"></div>
+ </div>
+ </div>
+
+
+
+
+
+
+
+ </footer>
+</div> <!--! end of #container -->
+<!-- Non-page-dependent JS at the bottom for fast page loading -->
+
+<!--[if lt IE 7 ]>
+ <script src="/common/inc/js/dd_belatedpng.js"></script>
+ <script>DD_belatedPNG.fix("img, .png_bg"); // Fix any <img> or .png_bg bg-images. Also, please read goo.gl/mZiyb </script>
+<![endif]-->
+
+<script type="text/javascript">
+ var ga_code = (window.location.href.indexOf("wwwstage") > -1 || window.location.href.indexOf("wwwtest") > -1) ? "UA-23738999-2" : "UA-23738999-1"; //-2 is stage, -1 is prod
+ var gaevent_code = (window.location.href.indexOf("wwwstage") > -1 || window.location.href.indexOf("wwwtest") > -1) ? "UA-23741840-2" : "UA-23741840-1"; //-2 is stage, -1 is prod
+ var trackPageViewOnLoad = (typeof trackPageViewOnLoad != "undefined" && trackPageViewOnLoad === false) ? false : true;
+ var _gaq=[
+ ["_setAccount",ga_code],
+ ["_setDomainName",".suse.com"],
+ ["event._setAccount",gaevent_code],
+ ["event._setDomainName",".suse.com"],
+ ];
+ if(trackPageViewOnLoad) {
+ if(typeof is404Page != "undefined" && is404Page === true) {
+ _gaq.push(["_trackPageview", "/404.html?page=" + document.location.pathname + document.location.search + "&from=" + document.referrer]);
+ }
+ else {
+ _gaq.push(["_trackPageview"]);
+ }
+ _gaq.push(["event._trackPageview"]);
+ }
+ (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.async=1;
+ g.src=("https:"==location.protocol?"//ssl":"//www")+".google-analytics.com/ga.js";
+ s.parentNode.insertBefore(g,s)}(document,"script"));
+</script>
+<script>
+ //begin suse_gaevent checking
+ var params = document.params;
+ if(!params) {
+ document.params = (location.search.substring(1)).split("&");
+ params = document.params;
+ }
+ if(typeof params != "undefined" && params != "") {
+ for(var i = 0; i < params.length; i++) {
+ var param = params[i].split("=");
+ if(param[0] == "suse_gaevent") {
+ _gaq.push(['event._trackEvent', 'Ad Tracking', 'clicks', param[1]]); //log the click
+ }
+ }
+ }
+ //end suse_gaevent checking
+</script>
+<script src="/common/inc/js/plugins.js?v=1"></script>
+<script src="/common/inc/js/main.js?v=11"></script>
+<script src="/common/inc/js/blindformsubmit.js?v=1"></script>
+<script src="/common/inc/js/plugins/scroll/jScrollPane.js?v=1"></script>
+<script src="/common/inc/js/plugins/scroll/jquery.mousewheel.js?v=1"></script>
+<script src="/common/inc/js/rac.js"></script>
+
+<script type="text/javascript" src="http://www.novell.com/common/inc/elqNow/elqCfg.js"></script>
+<script type="text/javascript" src="http://www.novell.com/common/inc/elqNow/elqImg.js"></script>
+<script type="text/javascript" src="http://www.novell.com/common/inc/elqNow/elqCPers.js"></script>
+
+<!--[if !IE]>-->
+<script>
+ // dom fixup for gecko pre 1.9b5; see http://blog.whatwg.org/supporting-new-elements-in-firefox-2
+ function fixForFF(){
+ var n = document.getElementsByTagName('header')[0];
+ if (n.childNodes.length <= 1) { // the element was closed early
+ n.appendChild(n.nextSibling);
+ var f = document.getElementsByTagName('footer')[0];
+ f.appendChild(f.nextSibling);
+
+ if($("#product").hasClass("product_index") || $("#newsticker").length){ //product or home pages have two child divs
+ f.appendChild(f.nextSibling);
+ f.appendChild(f.nextSibling);
+ }
+ }
+ }
+ if($("header").length){
+ fixForFF();
+ }
+ //subdomains which pull in the header/footer via JS won't render in time, so they'll call the funtion directly.
+</script>
+<!--<![endif]-->
+</body>
+</html> \ No newline at end of file
diff --git a/tests2/files/main.css b/tests2/files/main.css
new file mode 100644
index 00000000..0e62d7da
--- /dev/null
+++ b/tests2/files/main.css
@@ -0,0 +1,1744 @@
+/**
+ * html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline)
+ * v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark
+ * html5doctor.com/html-5-reset-stylesheet/
+ */
+
+body{ font-family: Helvetica, Arial, sans-serif; }
+
+html, body, div, span, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
+small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+/* font: inherit;*/
+/* font-family:Omnes_Regular;*/
+/* font-family: Helvetica, Arial, sans-serif;*/
+ vertical-align: baseline;
+}
+
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+
+blockquote, q { quotes: none; }
+blockquote:before, blockquote:after,
+q:before, q:after { content: ""; content: none; }
+ins { background-color: #ff9; color: #000; text-decoration: none; }
+mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
+del { text-decoration: line-through; }
+abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
+table { border-collapse: collapse; border-spacing: 0; }
+hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
+input, select { vertical-align: middle; }
+a{ outline:none; }
+
+/**
+ * Font normalization inspired by YUI Library's fonts.css: developer.yahoo.com/yui/
+ */
+
+body { font:13px/1.231 Helvetica, Arial, sans-serif; *font-size:small; } /* Hack retained to preserve specificity */
+select, input, textarea, button { font:99% sans-serif; }
+
+/* Normalize monospace sizing:
+ en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */
+pre, code, kbd, samp { font-family: monospace, sans-serif; }
+
+/**
+ * Minimal base styles.
+ */
+
+/* Always force a scrollbar in non-IE */
+html { overflow-y: scroll; }
+
+/* Accessible focus treatment: people.opera.com/patrickl/experiments/keyboard/test */
+a:hover, a:active { outline: none; }
+
+ul, ol { margin-left: 1.2em; }
+ol { list-style-type: decimal; }
+
+/* Remove margins for navigation lists */
+nav ul, nav li { margin: 0; list-style:none; list-style-image: none; }
+
+small { font-size: 85%; }
+strong, th { font-weight: bold; /*font-family:Omnes_Medium;*/ }
+
+td { vertical-align: top; }
+
+/* Set sub, sup without affecting line-height: gist.github.com/413930 */
+sub, sup { font-size: 75%; line-height: 0; position: relative; }
+sub.article_promoted_text{ line-height:14px; position:static; }
+sup { top: -0.5em; }
+sub { bottom: -0.25em; }
+
+pre {
+ /* www.pathf.com/blogs/2008/05/formatting-quoted-code-in-blog-posts-css21-white-space-pre-wrap/ */
+ white-space: pre; white-space: pre-wrap; word-wrap: break-word;
+ padding: 15px;
+}
+
+h1{ font-size:30px; line-height:30px; font-weight:400; color:#439539; }
+
+textarea { overflow: auto; } /* www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars/ */
+
+.ie6 legend, .ie7 legend { margin-left: -7px; }
+
+/* Align checkboxes, radios, text inputs with their label by: Thierry Koblentz tjkdesign.com/ez-css/css/base.css */
+input[type="radio"] { vertical-align: text-bottom; }
+input[type="checkbox"] { vertical-align: bottom; }
+.ie7 input[type="checkbox"] { vertical-align: baseline; }
+.ie6 input { vertical-align: text-bottom; }
+
+/* Hand cursor on clickable input elements */
+label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; }
+
+/* Webkit browsers add a 2px margin outside the chrome of form elements */
+button, input, select, textarea { margin: 0; }
+
+/* Colors for form validity */
+input:valid, textarea:valid { }
+input:invalid, textarea:invalid {
+ border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red;
+}
+.no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; }
+
+/* These selection declarations have to be separate
+ No text-shadow: twitter.com/miketaylr/status/12228805301
+ Also: hot pink! */
+::-moz-selection{ background: #439339; color:#fff; text-shadow: none; }
+::selection { background:#439339; color:#fff; text-shadow: none; }
+
+/* j.mp/webkit-tap-highlight-color */
+a:link { -webkit-tap-highlight-color: #FF5E99; }
+
+/* Make buttons play nice in IE:
+ www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ */
+button { width: auto; overflow: visible; }
+
+/* Bicubic resizing for non-native sized IMG:
+ code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ */
+.ie7 img { -ms-interpolation-mode: bicubic; }
+
+/**
+ * You might tweak these..
+ */
+
+body, select, input, textarea {
+ /* #444 looks better than black: twitter.com/H_FJ/statuses/11800719859 */
+ color: #444;
+ /* Set your base font here, to apply evenly */
+ /* font-family: Georgia, serif; */
+}
+
+/**
+ * Primary styles
+ */
+
+/* Basic formatting, structure
+----------------------------------- */
+body{ font-family:Arial, Helvetica, sans-serif; }
+.wrap{ width:978px; margin:0 auto; padding:0 20px; }
+
+/* The Magnificent Clearfix: Updated to prevent margin-collapsing on child elements. j.mp/bestclearfix */
+.clr:before, .clr:after { content: "\0020"; display: block; height: 0; overflow: hidden; }
+.clr:after { clear: both; }
+/* Fix clearfix: blueprintcss.lighthouseapp.com/projects/15318/tickets/5-extra-margin-padding-bottom-of-page */
+.clr { zoom: 1; }
+.ie6 .clr, .ie7 .clr{ clear:both; height:1px; } /* This shouldn't be necessary but IE isn't playing nice with the .clr method used */
+
+#content > .wrap{ padding-bottom:90px; }
+.content_left{ float:left; width:705px; margin-right:50px; }
+.content_right{ float:left; width:222px; }
+
+.longtail .content_left, .how_to_buy .content_left, .services_support .content_left, .technical_information .content_left{ width:723px; margin-right:32px; }
+#product .col_small, #partner .col_small, #solution .col_small, #solution .col_small{ width:222px; margin-right:30px; float:left; position:relative; }
+#product .col_large, #partner .col_large, #solution .col_large, #solution .col_large{ width:471px; float:left; position:relative; }
+.content_left .col_half{ float:left; width:345px; }
+.content_left .even{ margin-right:32px; }
+
+#content > .wrap > .col_half{ float:left; width:473px; overflow:hidden; }
+#content > .wrap > .even{ margin-right:32px; }
+
+/* Header
+----------------------------------- */
+header{ /*border-top:3px solid #333;*/ height:100px; }
+header .wrap{ position:relative; z-index:1000; }
+/*header .wrap p.portal{ position:absolute; top:0; right:0; background:#333 url(/common/img/portal_curve.png) top left no-repeat; margin:0; padding:0; font-size:11px; text-transform:uppercase; font-weight:300; }
+header .wrap p.portal a{ color:#fff; text-decoration:none; padding:3px 25px 1px 48px; height:19px; display:block; }
+header .wrap p.portal a strong{ color:#79C043; }
+*/
+header ul#meta{ margin:0; padding:0; list-style-type:none; position:absolute; top:12px; right:160px; }
+header ul#meta li{ float:left; padding:4px 15px; border-left:1px solid #f6f6f6; }
+header ul#meta li:first-child{ border-left:none; }
+header ul#meta li a{ color:#666; text-decoration:none; font-size:11px; }
+header ul#meta li a:hover{ text-decoration:underline; }
+header ul#meta li strong { font-size:11px; font-weight:normal; }
+header ul#meta li#meta_countrylang a{ font-style:italic; }
+
+header #search{ width:138px; height:25px; background:url(/common/img/search.png) top left no-repeat; position:absolute; top:12px; right:20px; }
+header #search form{ margin:0; padding:0; position:relative; display:block; }
+header #search form label{ position:absolute; top:3px; left:3px; width:105px; height:19px; z-index:101; font:11px Helvetica, Arial, sans-serif; color:#666; padding:5px 0 0 5px; }
+header #search form input#q{ margin:3px; border:none; border-color:transparent; width:105px; height:15px; padding:2px; /*position:relative;*/ z-index:100; }
+header #search form input#q_submit{ display:block; text-indent:-9999px; width:23px; height:23px; position:absolute; top:0; right:0; background:none; border:none; }
+header #search.focus{ box-shadow: 0 0 10px #439539; -webkit-box-shadow: 0 0 10px #439539; -moz-box-shadow: 0 0 10px #439539; }
+header #search.focus input:focus{ outline-width:0; outline:none; }
+
+header #logo{ width:107px; height:50px; background:url(/common/img/logo.png) bottom left no-repeat; float:left; padding-top:32px; }
+header #logo a{ display:block; text-indent:-9999px; width:107px; height:50px; }
+
+header ul#nav{ margin:0; padding:0; list-style-type:none; float:right; padding-top:55px; }
+header ul#nav li{ float:left; font-size:11px; text-transform:uppercase; width:139px; text-align:center; font-weight:300; font-family:Helvetica, Arial, sans-serif; letter-spacing:0.5px; padding:15px 0; position:relative; z-index:999; }
+header ul#nav li.active{ background:#4B9037; }
+header ul#nav li.active_nosub{ background:#eee; padding-bottom:14px; }
+header ul#nav li div.nav_sub{ display:none; /*background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, rgba(255,255,255,0)), color-stop(1, rgba(255,255,255,.8))); background-image: -moz-linear-gradient(top, rgba(255,255,255,0), rgba(255,255,255,.8));*/ }
+header ul#nav li.active div.nav_sub{ display:block; }
+.ie6 ul#nav li.active div.nav_sub, .ie7 ul#nav li.active div.nav_sub{ background:url(/common/img/transparent_pixel.png) top left no-repeat; } /*http://www.webtechwise.com/fix-ie7-submenu-hover-problem/*/
+
+header ul#nav li#nav_solutions{ width:125px; }
+header ul#nav li#nav_products{ width:185px; }
+header ul#nav li#nav_support{ width:105px; }
+header ul#nav li#nav_partners{ width:115px; }
+header ul#nav li#nav_community{ width:115px; }
+header ul#nav li#nav_dl{ width:155px; }
+header ul#nav li#nav_shop{ width:65px; padding-right:0; }
+header ul#nav li a{ background:url(/common/img/bullets/nav.png) bottom right no-repeat; padding:5px 7px 3px; color:#666; text-decoration:none; line-height:16px; }
+header ul#nav li.active a{ color:#fff; }
+/*header ul#nav li a:hover{ background:#eee; color:#439539; }*/
+header ul#nav li.highlight.last-child{ text-align:right;}
+header ul#nav li.highlight a{ color:#439539; }
+
+header ul#nav .nav_sub{ width:954px; padding:0 12px 12px 12px; z-index:998; position:absolute; top:46px; }
+.ie7 header ul#nav .nav_sub{ top:44px; }
+header ul#nav li#nav_solutions .nav_sub{ left:-125px; }
+header ul#nav li#nav_products .nav_sub{ left:-238px; }
+header ul#nav li#nav_support .nav_sub{ left:-423px; }
+header ul#nav li#nav_partners .nav_sub{ left:-528px; }
+header ul#nav li#nav_community .nav_sub{ left:-77px; }
+header ul#nav .nav_sub_contents{ padding:32px; background:#4B9037; text-align:left; text-transform:none; letter-spacing:0; z-index:997; }
+.ie6 header ul#nav .nav_sub_contents, .ie7 header ul#nav .nav_sub_contents{ padding-bottom:0; }
+header ul#nav .nav_subheading{ color:#88d847; font-size:15px; font-weight:300; padding-bottom:12px; text-transform:none; }
+header ul#nav .nav_subheading a{ color:#88d847 !important; background:none; padding:0; text-transform:none; }
+header ul#nav .nav_subheading a:hover{ text-decoration:underline; }
+header ul#nav .col_two{ width:185px; float:left; margin-right:32px; }
+header ul#nav .col_three{ width:274px; float:left; margin-right:32px; }
+header ul#nav .col_four{ width:198px; float:left; margin-right:32px; }
+header ul#nav .col_five{ width:152px; float:left; margin-right:32px; }
+header ul#nav .last{ margin-right:0; }
+header ul#nav .col ul, header ul#nav .col ul li{ margin:0; padding:0; list-style-type:none; }
+header ul#nav .col ul li{ font-size:11px; line-height:13px; padding:3px 0; border-bottom:1px solid #7ac142; text-align:left; text-transform:none; width:100%; }
+header ul#nav .col ul li:first-child{ border-top:1px solid #7ac142; }
+header ul#nav .col ul li a{ text-decoration:none; color:#fff; background:none; padding:0; line-height:13px; }
+header ul#nav .col ul li a:hover{ color:#DFFFBF; }
+
+header ul#nav #nav_community .nav_sub{ width:254px; left:590px; }
+header ul#nav #nav_solutions .nav_sub{ width:486px; }
+
+header #lang_select{ background:#202020; width:275px; overflow:hidden; position:absolute; top:15px; right:9999px; z-index:1000; padding-bottom:30px; height:200px; }
+header #lang_select_top{ position:relative; height:25px; width:100%; }
+header #lang_select_close{ position:absolute; top:12px; right:12px; margin:0; padding:0; width:16px; height:16px; }
+header #lang_select_close a{ display:block; width:16px; height:16px; background:url(/common/img/hdr/lang_select_close.png) top left no-repeat; text-indent:-9999px; }
+header #lang_select_close a:hover{ background-position:0 -16px; }
+header #lang_select_content{ padding:0px 10px 0px 15px; }
+header #lang_select_heading{ font-weight:bold; position:absolute; top:12px; left:60px; font-size:13px; color:#fff; margin:0; }
+header #lang_select #countries_hdr, header #lang_select #countries{ display:none; }
+header #lang_select .scroll-pane{ height:395px; }
+header #lang_select hr{ background:#474747; color:#474747; height:1px; border:none; font-size:1px; line-height:1px; width:100%; overflow:hidden; margin:8px 0; }
+header #lang_select hr.dark{ background:#292929; color:#292929; }
+header #lang_select p{ margin:0; padding:0; }
+header #lang_select p strong{ color:#76AD2D; }
+header #lang_select p.section{ font-size:11px; color:#999; padding-bottom:7px; }
+header #lang_select p#lang_selection{ font-weight:bold; color:#fff; }
+header #lang_select p#lang_selection span{ color:#999; font-weight:normal; font-size:11px; }
+header #lang_select p#lang_selection a{ color:#999; text-decoration:none; }
+header #lang_select ul, header #lang_select ul li{ margin:0; padding:0; list-style-type:none; }
+header #lang_select ul li{ font-size:13px; margin:0; padding:0; }
+header #lang_select ul li a{ color:#ccc; text-decoration:none; display:block; padding:1px 0 1px 15px; margin:0; min-height:12px; height:auto !important; height:12px; }
+header #lang_select ul li a:hover, header #lang_select ul li.active a{ color:#76AD2D; text-decoration:none !important; background:#2d2d2d; cursor:pointer; }
+header #lang_select ul li.active a{ background:#444; }
+header #lang_select ul li.current a{ background:url(/common/img/hdr/arrow_lang.png) 0px 3px no-repeat; }
+header #lang_select .jScrollPaneTrack{ background:#292929; }
+header #lang_select .jScrollPaneDrag{ background:url(/common/img/hdr/scrollbar_handle.png) top left no-repeat; }
+header #lang_select .jScrollArrowUp{ background:url(/common/img/hdr/scrollarrow_up.png) top left no-repeat; width:14px; height:16px; }
+header #lang_select .jScrollArrowDown{ background:url(/common/img/hdr/scrollarrow_down.png) top left no-repeat; width:14px; height:16px; }
+
+header.light { height:41px; background:transparent url(/common/img/hdr/bg-lighthdr.png) repeat-x top left; min-width:1018px; }
+header.light ul#meta { right:12px; top:8px; }
+header.light ul#meta li a { color:#fff; }
+header.light ul#meta li#hdr_login { border-left: 1px solid #F6F6F6; }
+header.light ul#meta li#meta_countrylang { display:none; }
+header.light #logo { position:relative; top:8px;background:transparent url(/common/img/hdr/logo-lighthdr.png) no-repeat top left; width:53px; height:32px; padding:0px; }
+header.light #logo a { width:53px; height:32px; }
+header.light #lang_select { display:none; }
+.nologin footer .footer_global { background-color:#202020; padding:9px 0; }
+.nologin footer .footer_global a, .nologin footer .footer_global p { color: #666666 !important; }
+.nologin header.light { height:60px; }
+.nologin header.light #logo { top:18px; }
+
+#search_autocomplete{ position: absolute; top: 37px; background:#fff; right:20px; width: 136px; border-radius: 0px 0px 5px 5px; display:none; border-bottom:1px solid #f5f5f5; border-left:1px solid #f5f5f5; border-right:1px solid #f5f5f5; z-index:1000; box-shadow:0px 6px 9px #439539; }
+#search_autocomplete ul, #search_autocomplete ul li{ margin:0; padding:0; list-style-type:none; }
+#search_autocomplete ul{ padding:5px 0; }
+#search_autocomplete ul li{ /*padding-bottom:4px;*/ }
+#search_autocomplete ul li a{ text-decoration:none; color:#333; padding:5px 10px; display:block; }
+#search_autocomplete ul li.active a{ background:#ceebcb; }
+
+
+/* Home page
+----------------------------------- */
+#banners{ background:url(/common/img/gray_dotted_home.png) top center repeat-y; }
+#banners .wrap{ position:relative; min-height:272px; height:auto !important; height:272px; clear:both; }
+#banners .banner{ display:none; min-height:272px; height:auto !important; height:272px; }
+#banners .banner h1{ font-size:40px; line-height:37px; font-weight:200; }
+#banners .banner h1 a{ text-decoration:none; color:#439539; }
+#banners .banner h1 strong{ display:block; color:#333; font-weight:200; margin-bottom:10px; }
+#banners .banner h1 span{ display:block; padding:4px 0 4px 20px; font-size:12px; line-height:12px; font-family:Helvetica, Arial, sans-serif; background:url(/common/img/arrow.png) 0px 3px no-repeat; }
+#banners .banner h1 a:hover span{ text-decoration:underline; }
+#banners #banner_nav{ position:absolute; top:15px; right:20px; }
+#banners #banner_nav a{ width:10px; height:10px; background:#ddd; /*-moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px;*/ display:block; float:left; margin-left:5px; }
+#banners #banner_nav a:hover{ background:#439539; }
+#banners #banner_nav a.active{ background:#333; }
+
+#newsticker{ background:#7ac142; padding:8px 0; }
+#newsticker p{ padding:0; color:#F1FFD6; line-height:100%; float:left; padding-right:10px; font-weight:bold; text-transform:uppercase; font-size:12px; }
+#newsticker p a { color:#FFFFFF; text-decoration:none; }
+#newsticker p a:hover { text-decoration:underline; }
+#newsticker ul, #newsticker ul li{ margin:0; padding:0; list-style-type:none; }
+#newsticker ul li{ display:none; float:left; line-height:100%; font-size:12px; }
+#newsticker ul li a{ color:#F1FFD6; text-decoration:none; }
+#newsticker ul li a:hover{ text-decoration:underline; }
+
+#hotoffers{ background:url(/common/img/gray_dotted_bg.png) top left repeat-x; padding:25px 0; }
+#hotoffers .wrap{ overflow:hidden; }
+#hotoffers #hotoffers_wrap{ width:1100px; }
+.offer{ width:235px; height:175px; float:left; margin-right:13px; position:relative; }
+.offer a{ width:235px; height:175px; display:block; text-decoration:none; color:#fff; font-size:16px; background:url(http://dummyimage.com/235x175) top left no-repeat; position:relative; }
+.en-us .offer a{ font-size:18px; }
+.offer a span{ font-weight:300; padding:16px; position:absolute; bottom:0px; left:0px; width:203px; line-height:16px; /*min-height:51px; height:auto !important; height:51px;*/ }
+.en-us .offer a span{ font-weight:100; }
+.offer_green a span{ background:#79BB46; opacity:0.9; -moz-opacity:0.9; filter:alpha(opacity=90); -moz-border-radius-bottomright: 2px; border-bottom-right-radius: 2px; -moz-border-radius-bottomleft: 2px; border-bottom-left-radius: 2px; }
+
+#trial_content{ padding:55px 0; }
+#trial_content .trial_content_sub{ position:relative; padding-right:690px; /*background:url(/home/img/businesses.png) 353px 27px no-repeat;*/ }
+#trial_content .trial_content_sub p{ padding-bottom:20px; }
+#trial_content h2{ font-size:25px; line-height:24px; color:#439539; font-weight:100; padding-bottom:18px; }
+
+#trial_content .trial_content_sub ul, .trial_content_sub ul li{ margin:0; padding:0; list-style-type:none; }
+#trial_content .trial_content_sub ul{ position:absolute; top:15px; right:0; }
+#trial_content .trial_content_sub ul li{ float:left; border:none !important; margin-left:25px; }
+#trial_content .trial_content_sub ul li a{ display:block; text-indent:-9999px; height:76px; background-position:top left; background-repeat:no-repeat; padding:0; }
+#trial_content .trial_content_sub ul li#success_lse a{ width:158px; background-image:url(/home/img/success_lse.png); }
+#trial_content .trial_content_sub ul li#success_od a{ width:134px; background-image:url(/home/img/success_od.png); }
+#trial_content .trial_content_sub ul li#success_sony a{ width:114px; background-image:url(/home/img/success_sony.png); }
+#trial_content .trial_content_sub ul li#success_wal a{ width:135px; background-image:url(/home/img/success_wal.png); }
+
+
+#home_alliance{ border-top:1px solid #666; border-bottom:1px solid #666; padding:5px 0; margin-bottom:15px; }
+#home_alliance p{ padding:0; font-size:12px; color:#666; float:left; width:165px; padding-top:11px; }
+#home_alliance ul{ float:right; }
+#home_alliance li{ border:none; width:auto; float:left; padding-left:25px; }
+
+#home_alliance li#home_alliance_amd a{ background-image:url(/common/img/alliance_partners/home/amd_alliance_sprite_s1.png); width:66px; }
+#home_alliance li#home_alliance_fujitsu a{ background-image:url(/common/img/alliance_partners/home/fujitsu_alliance_sprite_s1.png); width:50px; }
+#home_alliance li#home_alliance_hp a{ background-image:url(/common/img/alliance_partners/home/hp_alliance_sprite_s1.png); width:30px; }
+#home_alliance li#home_alliance_ibm a{ background-image:url(/common/img/alliance_partners/home/ibm_alliance_sprite_s1.png); width:47px; }
+#home_alliance li#home_alliance_dell a{ background-image:url(/common/img/alliance_partners/home/dell_alliance_sprite_s1.png); width:35px; }
+#home_alliance li#home_alliance_intel a{ background-image:url(/common/img/alliance_partners/home/intel_alliance_sprite_s1.png); width:39px; }
+#home_alliance li#home_alliance_ms a{ background-image:url(/common/img/alliance_partners/home/microsoft_alliance_sprite_s1.png); width:77px; }
+#home_alliance li#home_alliance_oracle a{ background-image:url(/common/img/alliance_partners/home/oracle_alliance_sprite_s1.png); width:66px; }
+#home_alliance li#home_alliance_sap a{ background-image:url(/common/img/alliance_partners/home/sap_alliance_sprite_s1.png); width:47px; }
+#home_alliance li#home_alliance_vmware a{ background-image:url(/common/img/alliance_partners/home/vmware_alliance_sprite_s1.png); width:72px; }
+
+#home_alliance li a{ padding:0; background-position:top right; background-repeat:no-repeat; display:block; text-indent:-9999px; height:34px; }
+#home_alliance li a:hover{ background-position:bottom right; }
+
+
+
+
+/* Feature banner section (e.g. on product page)
+----------------------------------- */
+.feature{ background:url(/common/img/green_dotted_bg.png) top left repeat; padding-top:43px; }
+.feature h2{ color:#fff; font-size:28px; font-weight:300; }
+.feature h2 a{ color:#fff; text-decoration:none; }
+.feature h2 a:hover{ text-decoration:underline; }
+.feature h2 span{ font-size:8px; }
+.feature .links{ height:41px; position:relative; z-index:1; }
+.feature_main .links{ border-bottom:1px solid #A6D838; }
+.feature #product_nav, .feature #product_nav li, .feature #meta_nav, .feature #meta_nav li{ margin:0; padding:0; list-style-type:none; }
+.feature #product_nav{ position:absolute; left:0; bottom:11px; width:850px; }
+.feature #meta_nav{ position:absolute; right:0; bottom:11px; }
+.feature #product_nav li{ float:left; margin-right:20px; font:12px Helvetica, Arial, sans-serif; margin-top:4px; }
+.feature #product_nav li a{ color:#fff; text-decoration:none; }
+.feature #product_nav li.active a, .feature #product_nav li.active a:hover{ color:#A5D838; }
+.feature #product_nav li a:hover{ color:#E3EDD7; }
+
+.feature #meta_nav li{ padding-right:10px; margin-right:10px; border-right:1px solid #333; float:left; font-size:12px; }
+.feature #meta_nav li.last-child{ border:none !important; margin:0; padding:0; }
+.feature #meta_nav li a{ text-decoration:none; color:#333; }
+.feature #meta_nav li a:hover{ text-decoration:underline; }
+
+.feature .headline{ padding:80px 0 0 166px; background-position:0 80px; background-repeat:no-repeat; font-size:42px; line-height:40px; width:500px; color:#fff; float:left; font-weight:300; min-height:210px; height:auto !important; height:210px; }
+.feature .headline strong{ font-weight:500; }
+
+.feature #cta_links, .feature #cta_links li{ margin:0; padding:0; list-style-type:none; }
+.feature #cta_links{ float:right; padding-top:88px; width:222px; }
+.feature #cta_links li{ border-bottom:1px solid #fff; }
+.feature #cta_links li a{ display:block; padding:4px 2px; text-decoration:none; color:#fff; font:12px Helvetica, Arial, sans-serif; }
+.feature #cta_links li a:hover{ background:#fff; color:#439539; }
+.feature #cta_links #cta{ position:relative; border:none; background:url(/common/img/gray_dotted_dark_bg.png) top left repeat; /*-moz-box-shadow:2px 2px #6f8a3a; -webkit-box-shadow:2px 2px #6f8a3a; box-shadow:2px 2px #6f8a3a;*/ margin-bottom:2px; }
+.feature #cta_links #cta a{ display:block; background:url(/common/img/gray_dotted_dark.png) top left no-repeat; padding:5px 5px 11px 9px; color:#79BF43; font-size:23px; line-height:23px; font-weight:400; letter-spacing:0.3px; }
+.feature #cta_links #cta a:hover{ /*text-shadow:0px 0px 10px #99c24e;*/ }
+.feature #cta_links #cta span { position:absolute; top:-4px; right:8px; display:none; width: 9px; height: 9px; background:#78AB36; /*Should be 79BF43 when the bg images are color corrected*/ -webkit-transform: rotate(-45deg); -moz-transform: rotate(-45deg); -ms-transform: rotate(-45deg); -o-transform: rotate(-45deg); transform: rotate(-45deg); -webkit-transform-origin: 0 100%; -moz-transform-origin: 0 100%; -ms-transform-origin: 0 100%; -o-transform-origin: 0 100%; transform-origin: 0 100%; }
+.ie6 .feature #cta_links #cta span, .ie7 .feature #cta_links #cta span{ display:none; } /* To do: create the triangle as an image, so no CSS3. IE gets jacked up */
+
+.headline_links, .headline_links li{ margin:0; padding:0; list-style-type:none; }
+.headline_links li{ float:left; font-size:12px; padding-left:13px; background:url(/common/img/bullets/list_icon.png) 0px 5px no-repeat; margin-right:35px; line-height:12px; }
+.headline_links li a{ text-decoration:none; color:#fff; }
+.headline_links li a:hover{ text-decoration:underline; }
+
+.subnav, .subnav li{ margin:0; padding:0; list-style-type:none; }
+.subnav li{ float:left; margin-right:32px; padding-top:15px; font-family:Helvetica, Arial, sans-serif; font-size:12px; }
+.subnav li a{ color:#6A972C; text-decoration:none; }
+.subnav li a:hover{ text-decoration:underline; }
+.subnav li.active a{ color:#333; }
+
+/* Content styles
+----------------------------------- */
+#content p{ padding-bottom:20px; font-size:13px; line-height:110%; }
+#content img + p, #content ul + p, #content ol + p{ padding-top:20px; }
+#content p, #content li{ color:#5F5F5F; }
+#content p a, #content li a{ color:#439239; text-decoration:underline; }
+#content p a:hover, #content li a:hover{ color:#333; }
+/*#content strong{ color:#439239; }*/
+#content{ margin-top:15px; padding-top:54px; background:url(/common/img/gray_dotted_bg.png) top left repeat-x; }
+#content.content_short{ margin-top:0; }
+h3{ font-size:28px; color:#439239; line-height:32px; font-weight:300; }
+h4{ font-size:15px; color:#333; padding:18px 0; border-top:1px solid #333; font-weight:400; }
+a.external{ background:url(/common/img/bullets/external.png) top right no-repeat; padding-right:19px; }
+
+#content .callout{ padding:36px 0; background-repeat:no-repeat; border-bottom:1px solid #eee; }
+#content h3 + .callout, #content p + .callout{ border-top:1px solid #eee; margin-top:36px; }
+.longtail_four #content .callout{ border:none; }
+#content .callout_left{ padding-right:313px; background-position:center right; }
+#content .callout_right{ padding-left:313px; background-position:center left; }
+#content .callout p{ font-size:21px; line-height:21px; color:#333; padding:36px 0; font-weight:300; }
+#content .callout_left p, #content .callout_right p{ padding:0; }
+#content .callout_left p + ul, #content .callout_right p + ul{ padding-top:36px; }
+#content .callout p strong{ font-weight:400; }
+#content .callout p a{ text-decoration:none; color:#439539; }
+#content .callout p a:hover{ text-decoration:underline; }
+#content .callout ul, #content .callout ul li, #content ul.callout_links, #content ul.callout_links li, #trial_content ul, #trial_content ul li{ margin:0; padding:0; list-style-type:none; }
+/*.callout ul{ padding-bottom:36px; }*/
+#content .callout ul li, #content ul.callout_links li, #trial_content ul li{ border-bottom:1px solid #f0f0f0; }
+#content .callout ul li:first-child, #content ul.callout_links li:first-child, #trial_content ul li:first-child{ border-top:1px solid #f0f0f0; }
+#content .callout ul li a, #content ul.callout_links li a, #trial_content ul li a{ display:block; background:url(/common/img/bullets/list_icon.png) 0px 11px no-repeat; padding:6px 15px 4px 15px; color:#439539; text-decoration:none; }
+#content .callout ul li a:hover, #content ul.callout_links li a:hover, #trial_content ul li a:hover{ color:#999; }
+#content ul.callout_links li.external a{ background-image:url(/common/img/bullets/external.png); padding-left:19px; background-position:0px 8px; }
+
+.product_index #content .col_half{ width:335px; }
+#content p.intro_text{ font-size:15px; line-height:16px; }
+#content .col_half .callout{ margin-top:20px; padding-bottom:0; border:none; background:url(http://dummyimage.com/335x240) top left no-repeat; padding-top:260px; }
+#content .col_half .callout p{ padding-top:0; }
+#content .callout_full{ padding-top:150px; background:url(http://dummyimage.com/705x130) top left no-repeat; margin-top:20px; }
+#content .callout_full p{ padding:0; }
+
+#highlight_wrap{ border-top:1px solid #439539; padding-top:50px; }
+.col_highlight_one{ width:280px; float:left; margin-right:32px; }
+.col_highlight_two{ width:390px; float:left; }
+
+#content .col_highlight_one p{ font-size:18px; font-weight:400; color:#333; }
+#content .col_highlight_one p a{ text-decoration:none; }
+#content .col_highlight_one p a:hover{ text-decoration:underline; }
+#content .col_highlight_one p strong{ font-weight:400; }
+
+#content .col_highlight_two ul, .col_highlight_two ul li{ margin:0; padding:0; list-style:none; }
+#content .col_highlight_two li{ padding:28px 0; border-bottom:1px solid #f0f0f0; }
+#content .col_highlight_two li:first-child{ padding-top:0; }
+#content .col_highlight_two li.last-child{ border-bottom:none; }
+#content .col_highlight_two li strong{ color:#333; display:block; }
+#content .col_highlight_two li a{ text-decoration:none; }
+#content .col_highlight_two li a:hover{ text-decoration:underline; }
+
+#content .sublinks, .sublinks li{ margin:0; padding:0; list-style-type:none; }
+#content .sublinks{ padding:45px 0; }
+#content .sublinks li{ padding:30px 0; border-bottom:1px solid #f0f0f0; color:#333; font-size:15px; line-height:16px; font-weight:300; }
+#content .sublinks li.last-child{ border:none; }
+#content .sublinks li strong{ display:block; font-size:19px; font-weight:400; }
+#content .sublinks li a{ color:#439539; text-decoration:none; }
+#content .sublinks li a:hover{ text-decoration:underline; }
+
+#content .trio_list{ border-top:1px solid #f0f0f0; }
+.longtail #content .trio_list, .longtail #content .resource_library{ border:none !important; }
+#content p.title{ font-size:28px; color:#439539; line-height:27px; padding:50px 0; font-weight:300; }
+#content .trio_list ul, .trio_list ul li{ margin:0; padding:0; list-style-type:none; }
+#content .trio_list ul li{ float:left; width:216px; margin-right:28px; }
+.longtail #content .trio_list ul li{ margin-right:37px !important; }
+#content .trio_list ul li.last-child, #content .trio_list ul li.third{ margin-right:0 !important; }
+#content .trio_list ul li.third + li{ clear:left; }
+#content .trio_list ul li img{ background:#f8f8f8; }
+#content .trio_list ul li strong{ font-weight:bold; display:block; padding-top:10px; }
+#content .trio_list ul li p{ color:#646464; font-size:13px; line-height:16px; padding:30px 0; }
+#content .trio_list p.more, #content #success p.more{ border-top:1px solid #f0f0f0; border-bottom:1px solid #f0f0f0; font-size:13px; padding:0; }
+#content .trio_list p.more a, #content #success p.more a{ padding:4px 3px; text-decoration:none; display:block; color:#439539; }
+#content .trio_list p.more a:hover, #content #success p.more a:hover{ /*background:url(/common/img/green_dotted_bg.png) top left repeat;*/ color:#999; }
+#content .trio_list p.external a span, #content #success p.more a span{ background:url(/common/img/bullets/external.png) center right no-repeat; padding-right:20px; }
+.tier4_wide #content .trio_list ul li{ margin-bottom:32px; }
+
+#content .anchors, .content_left .anchors li, .content_left .anchor_content, .content_left .anchor_content li{ margin:0; padding:0; list-style-type:none; }
+#content .anchors{ padding-top:43px; }
+#content .content_left h3 + p{ padding-top:20px; }
+#content .content_left h3 + h3{ padding-top:80px; }
+#content .content_left p + .anchors{ padding-top:0; }
+.technical_information #content .anchors, .faq #content .anchors, .resource_library #content .anchors, .news_and_commentary #content .anchors{ padding-top:0; }
+#content .anchors li{ font-size:13px; /*font-family:Omnes_Light;*/ margin-bottom:4px; width:325px; line-height:16px; background:url(/common/img/bullets/subnav.png) 0px 3px no-repeat; padding-left:15px; }
+#content .content_left .nowrap li{ width:auto; }
+#content .anchors li.column_two, .content_left .anchor_content li.column_two{ margin-left:350px !important; }
+#content .anchors li a{ text-decoration:none; color:#333; }
+#content .anchors li a:hover{ color:#999; }
+#content .content_left .anchor_content li{ font-size:13px; width:320px; line-height:16px; color:#606060; margin-top:32px; }
+#content .content_left .anchor_content strong{ display:block; margin-bottom:10px; font-weight:500; font-size:15px; color:#333; }
+#content .content_left .anchor_content li a{ text-decoration:none; }
+#content .content_left .anchor_content li a:hover{ text-decoration:underline; }
+#content .content_left .anchor_content li ul, #content .content_left .anchor_content li ol{ padding:15px 0; }
+#content .content_left .anchor_content li li{ margin:0 0 0 1em; list-style-type:disc; width:auto; }
+
+#content .anchor_active{ padding-top:55px !important; }
+#content .anchor_active span{ padding:10px 10px 8px 10px; background:#f6c747; }
+
+#content .content_left .anchor_title{ margin-top:39px; padding:45px 0 30px 0; background-position:top left; background-repeat:no-repeat; font-size:18px; color:#333; font-weight:500; border-bottom:1px solid #f0f0f0; background-image:url(http://dummyimage.com/62x36.jpg); }
+#content .content_left ul + .anchor_title{ margin-top:59px; }
+#content .content_left .anchor_title + p{ padding:20px 0; }
+#content .active_hash > span{ background-color:#ffd324; background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.55, rgb(243,184,36)), color-stop(0.78, rgb(255,211,35))); background-image: -moz-linear-gradient(center bottom,rgb(243,184,36) 55%,rgb(255,211,35) 78%); padding:10px; display:block; }
+
+blockquote{ font-weight:500; font-style:italic; font-size:25px; padding:40px 0; }
+blockquote span{ font-weight:400; font-style:italic; font-size:80px; color:#7BBD46; display:block; float:left; margin:-12px 60px 0 60px; }
+blockquote span sup{ font-size:30px; top:-1em; }
+
+blockquote.quote{ font-style:italic; font-size:16px; line-height:17px; font-weight:400; padding:36px 0; border-top:4px solid #439539; border-bottom:4px solid #439539; margin-top:36px; }
+blockquote.quote strong{ display:block; margin-top:20px; font-style:normal; font-family:Helvetica, Arial, sans-serif; color:#333; font-size:12px; font-weight:bold; }
+blockquote.quote span{ font-style:normal; font-family:Helvetica, Arial, sans-serif; font-weight:normal; font-size:12px; color:#333; margin:0; float:none; }
+
+/* Products/services
+----------------------------------- */
+.products_services h3, .downloads_index h1, .training_index h1{ padding-bottom:20px; border-bottom:1px solid #439539; margin-bottom:100px; }
+.products_services h4{ font-size:28px; margin:0; padding:0 0 20px 0; font-weight:400; border:0; }
+.products_services h5, .downloads_index h3, .training_index h2{ padding:10px; margin:18px 0; text-transform:uppercase; color:#fff; font-size:14px; background:#bababa; line-height:100%; font-weight:normal; }
+.products_services .even h5, .downloads_index h3, .training_index .even h2{ background:#8AC33C; }
+.products_services #content p.title{ padding:10px 0; }
+
+.products_services #content .product_list, .products_services .product_list li{ margin:0; padding:0; list-style-type:none; }
+.products_services #content .product_list{ width:520px; }
+.products_services #content .product_list li{ width:222px; margin:50px 32px 0 0; float:left; padding-top:85px; background:url(http://dummyimage.com/72x72) top left no-repeat; }
+.products_services #content .product_list li.even, .downloads_index #content .product_list li.fourth{ clear:left; }
+.products_services #content .product_list li p.title{ font-weight:400; color:#439539; font-size:16px; padding-bottom:10px; line-height:17px; }
+.products_services #content .product_list li p.links{ color:#E1E4E0; border-top:1px solid #f0f0f0; border-bottom:1px solid #f0f0f0; padding:4px 0; font-size:12px; }
+.products_services #content .product_list li a{ text-decoration:none; }
+
+.products_services #content .callout_links{ padding-bottom:18px; }
+.products_services .product_break + h5{ margin-top:50px; }
+
+.products_services #content .anchors{ padding-top:0; }
+
+/* Alternate product index design
+----------------------------------- */
+.product_index_alt .headline{ font-size:18px; line-height:18px; background-position:0 40px; padding-top:40px; min-height:170px; height:auto !important; height:170px; }
+.product_index_alt .headline strong{ font-size:36px; line-height:36px; display:block; font-weight:400; }
+.product_index_alt .feature #cta_links{ padding-top:48px; }
+.product_index_alt #content h3, .product_index_alt #content .trio_list .title{ border-top:1px solid #439539; font-size:15px; line-height:17px; font-weight:400; padding:15px 0; }
+
+.product_index_alt #content .highlight{ padding:47px 110px 47px 167px; background:url(http://dummyimage.com/70x70) 47px 51px no-repeat; border-bottom:1px solid #F0F0F0; }
+.product_index_alt #content .highlights .highlight.last-child{ border:none; }
+.product_index_alt #content .highlight h4{ color:#333; font-weight:500; margin:0; padding:0; border:none; font-size:17px; line-height:21px; }
+.product_index_alt #content .highlight p{ color:#656565; font-weight:400; margin:0; padding:0; font-size:17px; line-height:21px; }
+.product_index_alt #content .highlight p a{ text-decoration:none; }
+.product_index_alt #content .highlight p a:hover{ text-decoration:underline; }
+.product_index_alt #content .highlight ul, .product_index_alt .highlight ul li{ list-style-type:none; }
+.product_index_alt #content .highlight ul{ padding-top:20px; margin:0; }
+.product_index_alt #content .highlight ul li{ float:left; font-size:12px; padding-left:13px; background:url(/common/img/bullets/list_icon.png) 0px 5px no-repeat; margin-right:20px; }
+.product_index_alt #content .highlight ul li a{ text-decoration:none; color:#439539; }
+.product_index_alt #content .highlight ul li a:hover{ text-decoration:underline; }
+
+.product_index_alt #content .trio_list{ border:none; }
+.product_index_alt #content .trio_list .title{ margin:20px 0 50px 0; }
+
+.product_index_alt #content{ padding-top:27px; }
+.product_index_alt .feature #cta_links #cta a{ padding:0 22px 3px 8px; font-size:21px; }
+
+/* Longtail page content
+----------------------------------- */
+.tier4 h1{ font-size:28px; color:#439239; line-height:32px; font-weight:300; }
+.tier4 #content .content_left h1{ border-bottom:0; border-top:1px solid #439539; padding:15px 0 30px 0; }
+
+.longtail #content h3,
+.comparison #content h3,
+.technical_information #content h3,
+.how_to_buy #content h3,
+.faq #content h3,
+.services_support #content h3,
+.resource_library #content h3,
+.news_and_commentary #content h3,
+.tier4 h1,
+.app h1{ border-bottom:1px solid #439239; padding-bottom:7px; /*padding-right:200px;*/ margin-bottom:60px; }
+.longtail #content .content_right hr{ height:1px; font-size:1px; line-height:1px; border:none; background:#000; margin:22px 0; }
+
+#content .subtitle{ font-weight:500; color:#333; font-size:15px; }
+#content p + p.subtitle{ padding-top:12px; }
+#content p.subtitle + blockquote{ margin-top:0; }
+.longtail #content .col_small li{ color:#333; font-size:13px; margin-bottom:5px; }
+.longtail #content .col_small li ul, .longtail #content .col_small li ol, .content_left li ul, .content_left li ol{ padding:15px 0; }
+/*.longtail #content .col_small li ul a, .longtail #content .col_small li ol a{ font-weight:bold; }*/
+.longtail #content h4, .services_support #content h4{ font-size:21px; padding:0; border:none; padding-bottom:20px; }
+.longtail_two #content h4, .longtail_three #content h4, .longtail_four #content h4{ font-size:18px; padding-bottom:60px; }
+.longtail #content h4 a, .services_support #content h4 a{ color:#439539; }
+
+.longtail_four h3, #solution.longtail_four h3, #solution.solution_industry h3, #solution.solution_platform h3{ padding:90px 350px 90px 0; background-position:right center; background-repeat:no-repeat; }
+.longtail_four #content h4{ padding-bottom:36px; }
+.longtail_four #content hr + h4{ padding-top:20px; }
+.longtail_four #content{ margin-top:0 !important; }
+.longtail_four .share{ float:none; margin-bottom:36px; }
+
+.tier4 .content_left{ width:640px; margin-right:115px; }
+.tier4_wide .content_left{ width:723px; margin-right:32px; }
+
+.tier4 .content_short .content_right h2{ font-size:15px; color:#333; padding:18px 0; border-top:1px solid #333; font-weight:400; }
+.tier4 #content .content_right .callout_links{ padding-bottom:32px; }
+
+#solution.longtail .content_left h4{ border:none; padding:0 0 60px 0; margin:0; }
+#solution.longtail .content_left .col_half{ padding-top:0; }
+
+.greenbox{ width:84px; background:#98C109; position:absolute; right:0; }
+#content .greenbox p{ text-align:center; padding:15px 10px; }
+#content .greenbox p.number{ font-weight:300; font-size:43px; color:#fff; padding-bottom:5px; position:relative; }
+#content .greenbox p.number sup{ font-size:22px; }
+#content .greenbox p.text{ font-weight:500; font-size:11px; border-top:1px dotted #cfdb89; color:#333; }
+#content .greenbox p span{ position:absolute; top:28px; right:-15px; display:block; width:17px; height:17px; background:#98C109; -webkit-transform: rotate(-45deg); -moz-transform: rotate(-45deg); -ms-transform: rotate(-45deg); -o-transform: rotate(-45deg); transform: rotate(-45deg); -webkit-transform-origin: 0 100%; -moz-transform-origin: 0 100%; -ms-transform-origin: 0 100%; -o-transform-origin: 0 100%; transform-origin: 0 100%; z-index:-1; }
+
+#content .col_small blockquote{ font-weight:400; font-style:italic; font-size:23px; color:#333; padding-right:32px; border-right:5px solid #eee; text-align:right; position:absolute; right:0; }
+
+/* Comparison page
+----------------------------------- */
+.comparison #content h4{ font-size:18px; padding:0; border:none; padding-bottom:40px; }
+
+.table_comparison{ width:100%; border-collapse:collapse; border-spacing:0; margin-bottom:20px; }
+.table_comparison thead th{ background:#efefef; height:125px; vertical-align:middle; width:165px; line-height:1px; border-right:1px solid #fff; }
+.table_comparison thead th.null{ width:auto; border:none; }
+.table_comparison thead th:first-child{ background:#f3f3f3; }
+.table_comparison thead th.last-child{ border:none; }
+.table_comparison tbody td{ vertical-align:middle; text-align:left; padding:30px 0; color:#333; font-weight:500; font-size:15px; border-right:1px solid #e9e9e9; border-bottom:1px solid #e9e9e9; }
+.table_comparison tbody td a{ color:#439539; text-decoration:underline; }
+.table_comparison tbody td a:hover{ color:#999; }
+.table_comparison tbody td span{ display:block; text-align:center; }
+.table_comparison tbody td span.no{ display:none; }
+.table_comparison tbody td span.na{ color:#999; }
+.table_comparison tbody td span.yes, .table_comparison tbody td span.half{ background:url(/common/img/comparison.png) bottom center no-repeat; text-indent:-9999px; height:14px; }
+.table_comparison tbody td span.half{ background-position:top center; }
+
+.version_comparison thead th{ width:335px; }
+.version_comparison tbody td{ vertical-align:top; padding-left:20px; font-size:13px; }
+.version_comparison tbody td.title{ padding-left:0; font-size:15px; }
+.version_comparison tbody td li{ color:#333 !important; }
+.version_comparison tbody td span{ color:#439239; font-weight:500; font-style:italic; padding-right:5px; display:inline; }
+
+/* Technical information
+----------------------------------- */
+.technical_information #content .content_left .col_half, .resource_library #content .content_left .col_half{ width:318px; }
+.technical_information #content .content_left .anchor_title{ padding-top:0; background:none; }
+#content .table_header{ background:#95ba4d; font-size:15px; color:#fff; padding:13px 15px 15px 15px; margin:15px 0; font-weight:500; }
+#content .table_header strong{ color:#fff; }
+#content .table_header span{ display:block; font-size:12px; color:#333; }
+.table_text thead th{ height:auto; line-height:100%; padding:5px 0; width:auto; }
+.table_text thead th.null{ width:150px; }
+.table_text thead th:first-child{ border-right:1px solid #fff; }
+.table_text tbody td{ padding:15px; font-size:13px; vertical-align:top; }
+.table_text tbody td.title{ padding:15px 5px 15px 0; color:#439539; }
+.table_text tbody td p{ padding:0 20px; font-size:15px; }
+
+/* FAQ
+----------------------------------- */
+.faq #content .anchor_title{ padding:0; background:none; border:none; font-size:15px; }
+.faq .contact{ margin-top:20px; }
+.faq .contact p{ clear:both; padding-top:10px; }
+.faq .contact label{ width:150px; float:left; text-align:right; margin-right:15px; display:block; padding-top:4px; }
+.faq .contact input, .faq .contact textarea{ float:left; width:300px; margin:0; padding:4px; border:1px solid #eee; }
+.faq .contact p#submit{ background:url(/common/img/green_dotted_bg.png) top left repeat; float:right; padding:0; margin:10px 230px 0 0; }
+.faq .contact p#submit input{ width:auto; padding:4px 12px 3px 12px; background:url(/common/img/green_dotted_bg.png) top left repeat; border:none; color:#fff; cursor:pointer; }
+
+/* Services and support
+----------------------------------- */
+.services_support #content .anchor_title{ padding-top:0; background:none; padding-bottom:12px; margin-bottom:32px; }
+.services_support #content .content_left .anchor_title:first-child{ margin-top:0; }
+
+/* Resource library
+----------------------------------- */
+.resource_library #content .anchor_title{ padding-bottom:15px; margin-bottom:25px; }
+.resource_library #content p#Downloads{ background-image:url(/common/img/resources_download.png); }
+.resource_library #content p#AV{ background-image:url(/common/img/resources_av.png); }
+.resource_library #content p#Flyers{ background-image:url(/common/img/resources_flyer.png); }
+.resource_library #content p#WhitePapers{ background-image:url(/common/img/resources_whitepaper.png); }
+.resource_library #content p#Demos{ background-image:url(/common/img/resources_demo.png); }
+.resource_library #content p#Data_Sheets { background-image:url(/common/img/resources_datasheet.png); }
+.resource_library #content p#FAQ { background-image:url(/common/img/resources_faq.png); }
+
+/* News/commentary
+----------------------------------- */
+.news_and_commentary #content .anchor_title{ padding-top:0; background:none; padding-bottom:15px; margin-bottom:25px; }
+
+/* How to buy page
+----------------------------------- */
+#cpu_form{ margin-top:32px; }
+#cpu_form label, #cpu_form select{ float:left; }
+#cpu_form label{ font-size:28px; display:block; margin-right:15px; }
+#cpu_form select{ margin-top:5px; }
+
+.support_comparison thead th{ width:200px; padding:15px 0; text-align:left; }
+.support_comparison thead th img{ float:left; margin-left:27px; }
+.support_comparison thead th span{ float:left; display:block; padding:10px 0 0 15px; font-size:15px; color:#666; font-weight:normal; line-height:16px; }
+/*.support_comparison .buy{ display:none; }*/
+.support_comparison .buy td{ background:#666; border-right:1px solid #999; border-bottom:1px solid #999; padding:10px 15px !important; color:#fff !important; text-align:left; }
+.support_comparison .buy td div{ position:relative; }
+.support_comparison .buy td span{ display:inline; text-align:left; }
+.support_comparison .buy a{ background:#95ba4d; font-size:11px; color:#fff; text-decoration:none; padding:2px 8px 3px 8px; /*position:absolute; top:0; right:0;*/ border-radius:3px; -moz-border-radius:3px; font-weight:500; float:right; }
+.support_comparison .buy a:hover{ box-shadow: 0 0 5px #333; -webkit-box-shadow: 0 0 5px #333; -moz-box-shadow: 0 0 5px #333; color:#fff; background:#95BA4D; }
+.support_comparison .buy a:active{ background:#76AD2D; }
+
+/* Promo
+----------------------------------- */
+#content .content_right .promo{ margin-top:20px; }
+#content .content_right .promo p{ padding:0; font-size:15px; }
+#content .content_right .promo p a{ display:block; padding:15px 100px 15px 15px; text-decoration:none; color:#fff; background:#333 url(/common/img/support_standard.png) 150px 10px no-repeat; }
+#content .content_right .promo p a:hover{ background-color:#444; }
+#content .content_right .promo p a strong{ display:block; color:#439539; }
+
+#promo_container{ border-top:1px solid #333; padding:0 0 30px 0; border:none; position:relative; }
+#promo_wrapper{ border-top:1px solid #439539; border-bottom:1px solid #439539; }
+#promo_container .promo_single{ padding-bottom:0; display:none; }
+#promo_container .promo_single a{ text-decoration:none; color:#439539; }
+#promo_container .promo_single strong{ display:block; font-family:"omnes-pro-1"; color:#439539; font-size:19px; line-height:20px; font-weight:400; padding:32px 15px 7px 15px; }
+#promo_container .promo_single span{ padding:0 15px; text-decoration:none; color:#646464; font-size:11px; margin-bottom:25px; display:block; }
+#promo_container .promo_single img{ display:block; }
+#promo_container #promo_nav{ position:absolute; bottom:10px; right:0; }
+#promo_container #promo_nav a{ width:10px; height:10px; background:#ddd; /*-moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px;*/ display:block; float:left; margin-left:5px; }
+#promo_container #promo_nav a:hover{ background:#439539; }
+#promo_container #promo_nav a.active{ background:#333; }
+
+
+/*.promo_sidebar{ border-top:1px solid #333; padding-top:18px; }*/
+.promo_sidebar a{ border-top:3px solid #7ac142; border-bottom:3px solid #7ac142; display:block; text-decoration:none !important; padding:32px 18px 130px 18px; background:url(/common/img/promo/geeko_zpromo.png) bottom right no-repeat; }
+.promo_sidebar a strong{ display:block; color:#439539; font-size:18px; margin-bottom:12px; font-weight:400; }
+.promo_sidebar a span{ display:block; color:#666; font-size:12px; }
+.promo_sidebar a:hover{ background-color:#fafafa; }
+
+/* Solution
+----------------------------------- */
+#solution .feature li a, .sap .feature #product_nav li a{ color:#ccc; }
+.event #product_nav li a{ color:#fff; }
+#solution .feature li.active a, .sap .feature #product_nav li.active a, #solution .feature #product_nav li a:hover, .sap .feature #product_nav li a:hover{ color:#7ac142; }
+#solution .feature_main .links{ border-bottom:1px solid #7ac142; }
+#solution .feature{ background-image:url(/common/img/black_dotted_bg.png); background-color:#323232; }
+#solution .feature .headline{ float:none; width:auto; padding:50px 0 30px 0; font-size:29px; line-height:31px; color:#7ac142; min-height:0; }
+#solution .feature p{ color:#fff; padding-bottom:60px; width:650px; }
+
+#solution_selection{ padding-top:20px; }
+#solution_selection ul, #solution_selection ul li, .solution_list, .solution_list li{ margin:0; padding:0; list-style-type:none; }
+#solution_selection ul li, #content .solution_list li{ background:url(/common/img/solution_separator.png) center right no-repeat; float:left; padding:20px 25px 0 25px; text-align:center; }
+#solution_selection ul li a, #content .solution_list li a{ display:block; padding-top:85px; background:url(http://dummyimage.com/85x75) top center no-repeat; min-width:85px; width:auto !important; width:85px; text-decoration:none; color:#439539; }
+#solution_selection ul li a:hover, #content .solution_list li a:hover{ color:#999; }
+#solution_selection ul li a span, #content .solution_list li a span{ padding-left:13px; background:url(/common/img/bullets/subnav.png) 0px 4px no-repeat; }
+#solution_selection .solution_sub li{ background:none; padding:0 25px 0 0; }
+#solution_selection .solution_sub li a{ background:none; padding-top:0; min-width:0; }
+
+#solution_selection p{ padding:50px 0 0 20px; float:left; }
+#solution_selection p a{ text-decoration:none; color:#439539; }
+#solution_selection p a:hover{ color:#999; }
+
+.solution_index #content hr{ border-color:#439539; }
+.solution_index #content .solution_list li{ width:182px; text-align:left; }
+.solution_index #content .solution_list li:first-child{ padding-left:0; }
+.solution_index #content .solution_list li.last-child{ background:none; }
+.solution_index #content .solution_list li a{ background-position:top left; }
+
+#solution .content_left .col_half{ padding-top:60px; width:336px; }
+#solution h3{ padding-bottom:15px; }
+#solution .col_half a{ text-decoration:none; }
+#solution .col_half .callout_links{ padding-bottom:25px; }
+
+#solution.solution_index hr{ background:#439539; margin:3em 0; }
+#solution.solution_industry h3, #solution.solution_platform h3{ padding:0 0 20px 0; border-top:none; border-bottom:1px solid #439539; margin-bottom:30px; display:none; }
+#solution.solution_industry .content_left h4, #solution.solution_platform .content_left h4{ font-size:28px; font-weight:300; color:#439539; border-top:1px solid #439539; padding-top:50px; }
+#solution .content_left h5{ border-top:none; padding-top:0; font-weight:500; border-bottom:1px solid #f0f0f0; padding-bottom:10px; margin-bottom:20px; font-size:18px; }
+#solution .content_left h6{ font-size:16px; font-weight:500; padding:10px 0 15px 0; }
+
+#content .box{ background:#729D3A; padding:20px; }
+#content .box { background:#729D3A; padding:20px; }
+#content .box .col_half{ padding-top:0; width:315px; }
+#content .box p{ color:#fff; font-size:11px; }
+#content .box p.box_title{ font-size:16px; font-weight:400; padding-bottom:10px; }
+#content .box p.box_link{ border-top:1px solid #fff; text-align:right; font-size:13px; padding:5px 0 0 0; }
+#content .box p.box_link a{ color:#333; background:url(/common/img/bullets/list_icon.png) 0px -10px no-repeat; padding-left:13px; }
+#content .box p.box_link a:hover{ text-decoration:underline; }
+
+.anchor_top{ display:block; float:right; padding-left:13px; background:url(/common/img/bullets/subnav.png) 0px -31px no-repeat; text-decoration:none; color:#439539; margin-top:30px; }
+.anchor_top:hover{ text-decoration:underline; }
+#product .anchor_top{ margin-top:40px; }
+
+.solution_industry h3{ padding:45px 0 20px 0; border-top:1px solid #439539; }
+.solution_industry .col_half{ padding:0 0 30px 0 !important; }
+
+.solution_industry #content .company{ border-top:1px solid #333; padding:20px 0; }
+.solution_industry #content .company > p{ float:left; width:110px; margin-right:15px; }
+.solution_industry #content .company .company_info{ float:left; width:210px; }
+.solution_industry #content .company .company_info p{ font-weight:bold; padding-bottom:5px; border-bottom:1px solid #f0f0f0; color:#333; margin-bottom:15px; }
+.solution_industry #content .company .company_info p.desc{ font-weight:normal; padding-bottom:10px; border:none; color:#333; }
+.solution_industry #content .company ul.company_products, .solution_industry #content .company ul.company_products li{ margin:0; padding:0; list-style-type:none; }
+.solution_industry #content .company ul.company_products{ padding-bottom:10px; }
+.solution_industry #content .company ul.company_products li{ padding:5px 0; color:#666; }
+
+#solution blockquote.quote{ border:none; padding:0; margin:18px 0; }
+
+/* Partners
+----------------------------------- */
+#partner .feature{ /* background:#618c2a url(/common/img/partners/partner_greendotted_bg.png) top left repeat-x; */ padding-top:0; }
+#partner .feature_sub{ background-position:top center; background-repeat:no-repeat; padding-top:43px; }
+#partner .feature_cloud{ background-image:url(/common/img/partners/linecloud_bg.png); }
+/*#partner .feature_appliance{ background-image:url(/common/img/partners/linecloud_bg.png); }*/
+#partner .feature .headline{ padding:69px 0 0 0; width:650px; min-height:199px; height:auto !important; height:199px; }
+#partner .feature #cta_links #cta span{ background:#618c2a; }
+#partner .feature #cta_links{ padding-top:77px; }
+
+#partner_main #content{ margin-top:0; }
+#partner_main h1{ font-size:28px; color:#439239; line-height:32px; font-weight:300; border-bottom:1px solid #439239; padding-bottom:7px; /*padding-right:200px;*/ margin-bottom:60px; }
+#partner_main .content_left h2{ font-size:28px; font-weight:400; margin:0; padding:0 0 20px 0; border:none; }
+#partner_main .content_left h3{ font-size:16px; font-weight:500; margin:0; padding:20px 0 10px 0; color:#333; line-height:17px; }
+#partner_main .content_left p a{ text-decoration:none; }
+#partner_main .content_left p a:hover{ text-decoration:underline; }
+#partner_main .content_right ul.callout_links{ padding-bottom:20px; }
+
+#content .suse_button a{ display:inline-block; padding:5px 15px; color:#fff; text-decoration:none; background:url(/common/img/green_dotted_bg.png) top left repeat; }
+#content .suse_button a:hover{ text-decoration:underline; color:#fff; }
+.indent{ padding-left:55px; }
+
+.appliance_pavilion #content h3{ margin-bottom:30px; padding-bottom:10px; border-bottom:1px solid #439539; }
+.appliance_pavilion #content .content_left h4{ padding:0; border:none; font-weight:500; margin-bottom:30px; }
+.appliance_pavilion #content .anchors{ padding-top:0; }
+
+.appliance_pavilion .pavilion_partner{ padding-top:45px; border-top:1px solid #e0e0e0; margin-top:45px; }
+.appliance_pavilion .pavilion_one{ width:133px; float:left; margin-right:32px; }
+.appliance_pavilion .pavilion_two{ width:300px; float:left; margin-right:32px; }
+.webcasts .pavilion_two{ width:540px; margin-right:0; }
+.appliance_pavilion .pavilion_three{ width:208px; float:left; }
+
+.appliance_pavilion .pavilion_two blockquote{ padding:22px 0; border-top:2px solid #e0e0e0; border-bottom:2px solid #e0e0e0; font-style:italic; font-size:12px; font-family:Helvetica, Arial, sans-serif; }
+.appliance_pavilion .pavilion_two blockquote strong{ font-style:normal; display:block; padding-top:15px; }
+.appliance_pavilion .pavilion_two blockquote span{ font-style:normal; color:#333; font-size:12px; font-family:Helvetica, Arial, sans-serif; float:none; margin:0; }
+.appliance_pavilion #content .content_right h4{ border-top:1px solid #333; font-weight:400; padding:18px 0; font-size:15px; }
+.appliance_pavilion #content .content_right .callout_links{ padding-bottom:25px; }
+
+.appliance_pavilion #content .content_right .promo { position:relative; width:222px; height:95px; margin:0; }
+.appliance_pavilion #content .content_right .promo a{ background:none; padding:0; }
+.appliance_pavilion #content .content_right .promo a:hover{ background:none; }
+.appliance_pavilion #content .content_right .promo a strong{ display:inline !important; }
+.appliance_pavilion #content .content_right p.promo_1 a { font-size:13px; position:absolute; left:8px; top:4px; }
+.appliance_pavilion #content .content_right p.promo_2 a { font-size:11px; position:absolute; left:8px; top:10px; line-height:13px; }
+.appliance_pavilion #content .content_right p.promo_3 a { font-size:14px; position:absolute; left:8px; top:14px; }
+.appliance_pavilion #content .content_right .largetxt { font-size:13px !important; line-height:15px !important; color:#CEE4A4 !important; }
+.appliance_pavilion #content .content_right p.promo_2 span.readnow { font-size:12px; color:#47555E; position:absolute; top:55px; }
+.appliance_pavilion #content .content_right p.promo_3 span.try { color:#CCDFA6; font-size:13px; font-weight:normal; position:absolute; top:39px; }
+
+.alliance_partners_index .feature p a, .alliance_partners .feature p a{ color:#7AC142; text-decoration:none; }
+.alliance_partners_index .feature p a:hover, .alliance_partners .feature p a:hover{ text-decoration:underline; }
+.alliance_partners_index .trio_list li{ margin-bottom:32px; }
+#solution.alliance_partners_index blockquote.quote{ padding:22px 0; border-top:2px solid #e0e0e0; border-bottom:2px solid #e0e0e0; font-size:18px; font-style:normal; color:#439539; line-height:20px; }
+#solution.alliance_partners_index blockquote.quote strong{ font-style:normal; display:block; padding-top:15px; text-align:right; }
+#solution.alliance_partners_index blockquote.quote span{ font-style:normal; color:#333; font-size:12px; font-family:Helvetica, Arial, sans-serif; float:none; margin:0; text-align:right; }
+.alliance_partners h3{ font-size:19px; line-height:21px; color:#5F5F5F; padding:32px 0 !important; border-top:3px solid #7ac142; font-weight:400; }
+.alliance_wrap{ padding:32px 0; border-top:2px solid #ddd; }
+.alliance_one{ float:left; width:140px; margin-right:32px; }
+.alliance_one h4{ color:#333; font-size:19px; line-height:21px; font-weight:500; padding:0; border:none; }
+.alliance_two{ float:left; width:220px; margin-right:32px; }
+.alliance_three{ float:left; width:280px; }
+.alliance_wrap .col_half{ padding-top:15px !important; }
+
+.alliance_two_small, .alliance_three_small, .alliance_four_small{ float:left; width:160px; margin-right:25px; }
+.alliance_four_small{ margin-right:0; }
+
+#solution .feature_alliance .headline{ width:600px; }
+#solution .feature_alliance #alliance_banner_img{ float:right; margin-top:55px; }
+
+
+/* Press
+----------------------------------- */
+.press h3{ margin-bottom:25px; }
+.content_left_one{ width:120px; float:left; margin-right:10px; }
+.content_left_one h4{ font-size:20px; font-weight:400; }
+.content_left_two{ width:565px; float:left;}
+.press .content_left hr{ margin:3em 0; }
+
+/* SAP customization
+----------------------------------- */
+.sap .feature{ background-image:url(/common/img/black_dotted_bg.png); background-color:#323232; }
+.sap .feature_main .links{ border-bottom:1px solid #9ECD38; }
+.sap .feature #meta_nav li{ border-right:1px solid #fff; }
+.sap .feature #meta_nav li a{ color:#fff; }
+.sap .feature #cta_links #cta{ box-shadow:2px 2px #0a3f73; -moz-box-shadow:2px 2px #0a3f73; -webkit-box-shadow:2px 2px #0a3f73; }
+.sap .feature #cta_links #cta a{ color:#2380bf; }
+.sap .feature #cta_links #cta span{ background:#004486; }
+.sap .feature .headline{ font-size:35px; line-height:33px; padding-left:196px; }
+.sap .feature .headline p{ padding-bottom:15px; color:#9ECD38; }
+
+.sap_sles #content .sublinks{ padding-bottom:0; }
+.sap_sles #content h3{ font-size:18px; color:#333; font-weight:400; border-top:1px solid #439539; padding:50px 0; }
+.sap_sles #content h4{ margin-top:20px; }
+.sap_sles #content .content_left h4{ border-top:1px solid #439539; color:#439539; }
+.sap_sles #content .sublinks{ padding:0 0 30px 0; margin-left:1em; }
+.sap_sles #content .sublinks li{ border:none; font-size:13px; list-style-type:disc; padding:0; color:#666; font-family:Helvetica, Arial, sans-serif; margin-bottom:8px; }
+.sap_sles #content .sublinks li strong{ display:inline; font-size:15px; color:#333; font-weight:500; }
+.sap_sles #content .sublinks li strong:after{ content:" \2014 "; }
+.sap_sles #content #industry_experts li{ font-size:11px; border-top:none !important; }
+
+/* Event page
+----------------------------------- */
+.event .feature{ /*padding-bottom:15px;*/ padding-top:26px; }
+.event .feature .links{ height:auto; padding-top:15px; }
+.event h2{ padding-bottom:15px; }
+.event h2 span{ font-family:Arial; font-size:12px; color:#999; }
+.event .links{ border:none !important; }
+.event #content{ margin-top:0; padding-top:32px; }
+.event #product_nav{ position:static; top:auto; left:auto; bottom:auto; }
+.event #product_nav li{ margin-top:0; padding-bottom:10px; }
+
+.event .col_left{ float:left; width:720px; margin-right:32px; padding-top:50px; }
+.event .col_left_mini{ float:left; width:145px; margin-right:20px; }
+.event .col_left_large{ float:left; width:500px; }
+.event .col_right{ float:left; width:222px; padding-top:50px; }
+.event .col_right h3{ color:#666; }
+.event .col_right h4{ color:#666; padding-top:15px; border-top:1px solid #000; }
+
+.event hr{ border:none; }
+.event p.cta{ float:right; }
+.event p.cta a{ color:#fff !important; display:inline-block; background:url(/common/img/green_dotted_bg.png) top left repeat; display:block; text-decoration:none !important; padding:4px 12px 5px 12px; }
+
+.event #content #accordion{ padding-bottom:25px; }
+.event #content .accordion_header{ background:#f4f4f4; padding:10px 15px; color:#999; font-size:11px; border-top:1px solid #fff; border-bottom:1px solid #e7e7e7; cursor:pointer; }
+.event #content .accordion_header strong{ color:#211f1f; }
+.event #content .accordion_body{ background:#fdfdfd; padding:15px; color:#505253;}
+.event #content .accordion_body p{ margin:0; padding:0 0 10px 0; font-size:11px; }
+
+#solutions_follow{ padding-bottom:15px; }
+#content #solutions_follow h3{ color:#000; border-top:1px solid #000; padding:15px 0; font-size:13px; }
+#content #solutions_follow ul, #content #solutions_follow ul li{ margin:0; padding:0; list-style-type:none; }
+#content #solutions_follow ul li{ width:24px; height:24px; margin:0 10px 10px 0; float:left; }
+#content #solutions_follow li a{ width:24px; height:24px; display:block; text-indent:-9999px; background-position:top left; background-repeat:no-repeat; }
+#content #solutions_follow li a:hover{ background-position:bottom left; }
+#solutions_follow li#sf_cool a{ background-image:url(http://www.novell.com/common/img/follow/cool.jpg); }
+#solutions_follow li#sf_email a{ background-image:url(http://www.novell.com/common/img/follow/email.jpg); }
+#solutions_follow li#sf_fb a{ background-image:url(http://www.novell.com/common/img/follow/fb.jpg); }
+#solutions_follow li#sf_forum a{ background-image:url(http://www.novell.com/common/img/follow/forum.jpg); }
+#solutions_follow li#sf_google a{ background-image:url(http://www.novell.com/common/img/follow/google.jpg); }
+#solutions_follow li#sf_quote a{ background-image:url(http://www.novell.com/common/img/follow/quote.jpg); }
+#solutions_follow li#sf_rss a{ background-image:url(http://www.novell.com/common/img/follow/rss.jpg); }
+#solutions_follow li#sf_twitter a{ background-image:url(http://www.novell.com/common/img/follow/twitter.jpg); }
+#solutions_follow li#sf_url a{ background-image:url(http://www.novell.com/common/img/follow/url.jpg); }
+
+.event #content #events_related p{ font-size:11px; }
+.event #content #events_related a{ font-weight:bold; color:#333; display:block; text-decoration:none; }
+.event #content #events_related a:hover{ text-decoration:underline; }
+
+.event .feature{ background:url(/common/img/green_dotted_bg.png) top left repeat !important; padding-top:75px; }
+
+.event .meta{ position:relative; float:right; width:400px; }
+#solution.event .meta p{ position:absolute; right:80px; bottom:15px; width:auto; text-align:right; padding:0; }
+.event .meta ul, .event .meta ul li{ margin:0; padding:0; list-style-type:none; }
+.event .meta ul{ position:absolute; bottom:15px; right:0; }
+.event .meta ul li{ float:left; margin-right:10px; width:24px; height:24px; }
+.event .meta ul li a{ display:block; width:24px; height:24px; text-indent:-9999px; background-repeat:no-repeat; background-position:top left; }
+.event .meta ul li.event_follow_rss a{ background-image:url(/common/img/icons/event_rss.jpg); }
+.event .meta ul li.event_follow_calendar a{ background-image:url(/common/img/icons/event_calendar.jpg); }
+
+.eventb .banner_left{ width:295px; height:160px; background:#333; float:left; padding:30px; }
+.eventb .banner_left h3{ color:#999; font-size:23px; line-height:25px; }
+.eventb .banner_left h3 strong{ color:#7ac142; font-weight:normal; }
+.eventb .banner_right{ width:623px; height:220px; float:left; }
+.eventb h4{ color:#439539; font-size:25px; border:none; padding-bottom:15px; font-weight:300 }
+.eventb .col_left{ border-top:1px solid #439539; padding-top:15px; }
+.eventb .col_right{ border-top:1px solid #000; padding-top:15px; }
+.eventb #content .col_left p.title{ font-size:19px; margin:0; padding:0 0 10px 0; color:#333; }
+.eventb #content .col_left p.title strong{ color:#439539; font-weight:normal; }
+.eventb #content .col_left hr{ background:#e4e5e6; }
+.eventb #content .col_left p.register_now{ padding-bottom:0; }
+.eventb #content .col_left p.register_now a{ text-decoration:none; }
+.eventb #content .col_left p.register_now a:hover{ text-decoration:underline; }
+.eventb .col_right{ border:none; padding-top:0; }
+.eventb .col_right h4{ font-size:16px; font-weight:300; }
+.eventb #content .col_right #events_ondemand a{ display:block; text-decoration:none; }
+
+/* Support
+----------------------------------- */
+#support .feature h1 { color:#fff; font-size: 28px; font-weight: 300; }
+#support .feature .wrap { position:relative; }
+#support .feature li a{ color:#ccc; }
+#support .feature li.active a, #support .feature #product_nav li a:hover{ color:#7ac142; }
+#support .feature_main .links{ border-bottom:1px solid #7ac142; }
+#support .feature{ background-image:url(/common/img/black_dotted_bg.png); background-color:#323232; }
+#support .feature .headline{ float:none; width:auto; padding:50px 0 30px 0; font-size:29px; line-height:31px; color:#7ac142; min-height:0; }
+#support .feature p{ color:#fff; padding-bottom:60px; width:650px; }
+#support #content { margin-top:15px; }
+
+/* Downloads
+----------------------------------- */
+#downloads h1{ font-size:28px; color:#439239; line-height:32px; font-weight:300; border-bottom:1px solid #439239; padding-bottom:7px; /*padding-right:200px;*/ margin-bottom:60px; }
+#downloads .dl_heading, #training .training_heading{ margin-top:50px; font-size:18px; color:#333; font-weight:400; }
+#training .training_heading{ font-size:28px; margin:0; padding:0 0 20px 0; font-weight:400; border:0; }
+#downloads .product_list, #downloads .product_list li, #training .product_list, #training .product_list li{ margin:0; padding:0; list-style-type:none; }
+#downloads .product_list, #training .product_list{ width:520px; }
+#downloads .product_list li, #training .product_list li{ width:139px; float:left; margin:0 27px 32px 0; }
+#downloads .product_list li a, #training .product_list li a{ text-decoration:none; display:block; font-size:16px; color:#439539; padding-top:85px; background:url(http://dummyimage.com/72x72) top left no-repeat; }
+
+/* Training
+----------------------------------- */
+.training_index h1{ font-size:28px; color:#439239; line-height:32px; font-weight:300; margin-bottom:70px; }
+.training_index #content h3{ font-size:15px; font-weight:400; color:#333; border-top:1px solid #333; padding:18px 0; margin-top:50px; }
+
+/* Company
+----------------------------------- */
+#company .links{ border:none; }
+#company .feature_company{ background:url(/common/img/gray_dotted_nofade.png) top left repeat; margin-top:15px; }
+#company h3{ color:#439539; font-size:24px; line-height:26px; }
+#company .feature_company h3{ width:700px; padding-bottom:43px; }
+#company #content{ background:none; }
+
+#company .feature_company ul, #company .feature_company ul li{ margin:0; padding:0; list-style-type:none; }
+#company .feature_company ul li{ float:left; }
+#company .feature_company ul li a{ display:block; padding:8px 12px; color:#439539; text-decoration:none; }
+/*#company .feature_company ul li:first-child a{ padding-left:0; }*/
+#company .feature_company ul li a:hover{ text-decoration:underline; }
+#company .feature_company ul li.active{ background:#fff; }
+#company .feature_company ul li.active a{ color:#333; }
+#company .feature_company ul li.active a:hover{ text-decoration:none; }
+
+#company table tr td{ vertical-align:middle; }
+#company table tr td:first-child{ padding-right:32px; }
+
+#company .section_title{ margin-top:50px; padding:32px 0 50px 0; border-top:1px solid #e0e0e0; font-size:27px; color:#439539; }
+#company .content_left > .section_title:first-child{ margin-top:0; }
+#company .bio_image{ float:right; margin:0 0 20px 20px; }
+#company .suse_exec{ clear:both; padding-top:65px; }
+#company .content_right ul.callout_links{ padding-bottom:20px; }
+
+#company.press h1{ margin-bottom:20px; }
+#company.press h1 + p{ margin-bottom:20px; }
+#company.press h4{ border:none; padding-top:0; }
+#company.press .flyspec { font-size:11px; }
+
+.package_index .table_text tbody td.sub{ padding-left:25px; }
+.package_index .table_text tbody td.title{ color:#333 }
+
+#content.contacts_offices .content_left select{ float:right; font-size:12px; margin-top:8px; }
+#content.contacts_offices h3{ margin-bottom:40px; }
+#content.contacts_offices .col_one_left{ width:182px; float:left; margin-right:20px; }
+#content.contacts_offices .third{ float:left; width:165px; margin-right:40px; padding-top:20px; }
+#content.contacts_offices .third td{ font-size:12px; color:#4b4b4b; }
+#content.contacts_offices .last{ margin-right:0px; }
+#content.contacts_offices .content_left h4{ font-family:"omnes-pro-1", Helvetica, Arial, sans-serif; font-size:18px; line-height:19px; font-weight:300; color:#333; text-transform:none; border:none; padding:0; }
+#content.contacts_offices .col_one_right{ width:500px; float:left; }
+#content.contacts_offices .col_one_right p{ padding:0 0 15px 0; }
+#content.contacts_offices .col_one_right p:last-child{ padding-bottom:0; }
+#content.contacts_offices table tr td:first-child{ padding:0; }
+#content.contacts_offices hr{ margin:2em 0; }
+
+
+/* Documentation
+----------------------------------- */
+#documentation .prodlist a{ color:#439539; }
+
+/* Downloads
+----------------------------------- */
+#downloads #content{ margin-top:0; }
+#downloads h2{ font-size:28px; color:#333; line-height:30px; padding-bottom:32px; font-weight:400; width:600px; }
+#downloads #content p a{ text-decoration:none; }
+#downloads #content p a:hover{ text-decoration:underline; }
+
+/* Community
+----------------------------------- */
+#community h1{ padding-bottom:8px; border-bottom:1px solid #439539; margin-bottom:35px; font-size:28px; font-weight:300; line-height:32px; color:#439539; }
+#community h2{ clear:both; padding:9px 10px 8px 10px; margin:0 0 36px 0; text-transform:uppercase; color:#fff; font-size:14px; background:#8AC33C; line-height:100%; border:none; font-weight:400; }
+#community h3{ font-size:14px; line-height:110%; font-weight:500; color:#000; padding:23px 40px 10px 0; background:-repeat:no-repeat; background:url(/common/img/social/icon_generic.png) top left no-repeat; }
+#community h3 a{ color:#333; text-decoration:none; }
+#community p.desc{ margin-bottom:34px; font-weight:400; color:#333; font-size:16px; width:700px; }
+#community #content p{ padding-bottom:0; }
+#community #content hr{ margin:36px 0; }
+#community #content .callout_links{ padding-top:20px; }
+
+#community .contentfilter { border-top:1px solid #F0F0F0; border-bottom:1px solid #F0F0F0; }
+#community .contentfilter ul { height:30px; line-height:30px; list-style-type:none; text-align:left; margin:0; padding:1px 0 0 0; }
+#community .contentfilter li { float:left; font-size:12px; text-indent:4px; padding-right:32px; }
+#community .contentfilter li a { color:#439539; text-decoration:none; background:url(/common/img/bullets/subnav.png) 0px 4px no-repeat; padding-left:15px; }
+#community .contentfilter li.selected { background:#00AEEF url(/common/img/filter_selected_bg.png) no-repeat top right; }
+
+#community #communities { margin:0; padding:32px 0 0 0; width:978px; overflow:hidden; }
+#community .communitycategory { overflow:hidden; width:1020px; border-top:2px solid #fff; padding:0 0 30px 0; clear:both; background-color:#fff; }
+#community .divider { clear:both; padding-top:34px; border-top:1px solid #fff; }
+
+#community .communityfeed { position:relative; width:338px; float:left; padding-bottom:20px; }
+#community .communityfeed p { margin:0; padding:0 40px 0 0; font-size:11px; }
+#community .communityfeed ul { list-style-type:none; margin:16px 40px 0 0; padding:16px 0 0 0; border-top:1px solid #F0F0F0; }
+#community .communityfeed ul li { margin:0; padding:0 0 16px 0; font-size:11px; line-height:120%; background-image:none; }
+#community .communityfeed ul li strong { font-weight:normal; display:block; }
+#community .communityfeed ul li a { text-decoration:none; }
+#community .communityfeed ul li a:hover { text-decoration:underline; color:#439539; }
+#community p.feedaction { clear:left; padding:6px 0 0 0; margin:0 40px 0 0; border-top:1px solid #F0F0F0; }
+#community p.feedaction a strong { font-weight:normal; color:#439539; }
+#community p.feedaction a { text-decoration:none; color:#333; }
+#community p.feedrss { clear:left; margin:0; padding:0; position:relative; left:274px; top:-14px; }
+
+#community #content .callout_links { padding-top:0px; }
+#community .communityfeed ul.callout_links { border-top:none; padding-top:0px; padding-bottom:0px; }
+#community .communityfeed ul.callout_links li { padding-bottom:0px; border:none; }
+
+/* Landing page
+----------------------------------- */
+#landing_page #landing_page_banner{ padding:63px 0; background:url(http://dummyimage.com/250x150) center right no-repeat; border-bottom:1px solid #439539; margin-bottom:50px; }
+#landing_page #content #landing_page_banner h1{ border:none; margin:0; padding:0 275px 0 0; }
+#landing_page #content #landing_page_banner h1 strong{ color:#333; font-weight:300; }
+#landing_page #content h2{ font-weight:500; margin-top:32px; border-top:1px solid #e0e0e0; padding:18px 0; font-size:15px; }
+#landing_page #content table td{ padding-right:12px; }
+
+/* Share/print
+----------------------------------- */
+.share{ margin-bottom:10px; }
+#content .post p.social{padding:10px 0 0 0; height: 20px; }
+#content a.social_btns{display:block; float:left; padding: 0 6px; font-size: 10px; line-height: 18px; border: 1px solid #e6e6e6; background: #eaeaea url(/common/img/social/social_btn_bg.gif) repeat-x left top; margin-right: 7px; text-decoration:none; color:#888; }
+#content a.social_btns img{padding-left: 5px; border-left: 1px solid #e6e6e6; margin: 4px 0 0 0; }
+#content a.social_btns:hover{text-decoration:none !important;}
+#content a.share_btn{height: 18px; }
+#content a.share_btn img{padding-left: 5px; border-left: 0 none; margin: 3px 0 -3px 0; }
+
+#content .post-share-links{display: none; position: relative; height: 0;}
+#content .post-share-links ul{position:absolute; top: -88px; left: 0; z-index: 30001; display: block; height:94px; width:99px; background: transparent url(/common/img/social/share_popup_black_bg.png) no-repeat left top; margin: 0; padding: 8px;}
+#content .post-share-links ul li{line-height: 19px; height: 19px; margin: 0 0 10px 0; background: 0; padding: 0; list-style-type:none; }
+#content .post-share-links ul li a{font-weight: bold; font-size: 11px; font-family: arial, helvetica, sans-serif; background: transparent no-repeat left top; padding: 5px 0 5px 30px; color: #cccccc; text-decoration:none; }
+#content .post-share-links ul li a:hover{text-decoration: underline; }
+#content .post-share-links ul li a.post-share-link-facebook{background-image: url(/common/img/social/social_popup_facebook_icon-1.png);}
+#content .post-share-links ul li a.post-share-link-twitter{background-image: url(/common/img/social/social_popup_twitter_icon-1.png);}
+#content .post-share-links ul li a.post-share-link-email{background-image: url(/common/img/social/social_popup_email_icon-1.png);}
+
+
+/* RAC/lead gen form
+----------------------------------- */
+.content_right img + #requestcall{ padding-top:15px; }
+
+#content #requestcall #racError, #overlay #requestcall #racError{ padding-bottom:10px; }
+#content #requestcall #racError p, #content #requestcall #racError ul, #overlay #requestcall #racError p, #overlay #requestcall #racError ul{ padding:5px; }
+#content #requestcall #racError p, #content #requestcall #racError li, #overlay #requestcall #racError p, #overlay #requestcall #racError li{ color:#C00 !important; margin:0; font-size:11px; }
+#content #requestcall #racError strong, #overlay #requestcall #racError strong{ color:#C00 !important;}
+#content #requestcall #racError p, #overlay #requestcall #racError p{ margin:0; padding:8px 0 2px 0; }
+#content #requestcall #racError #racErrorMsgs p, #overlay #requestcall #racError #racErrorMsgs p{ padding-left:18px; background:transparent url(http://www.novell.com/common/img/icons/missing_field.png) no-repeat 0px 8px; }
+#form_content div.form-error input, #form_content div.form-error textarea, #form_content div.form-error select,.form_content div.form-error input, .form_content div.form-error textarea, .form_content div.form-error select{ border:2px solid #ED1D25; }
+#form_content div.form-error select{ height:22px; }
+#content #requestcall .title{ font-size:15px; color:#439539; font-weight:400; border-top:1px solid #439539; padding:15px 0; line-height:17px; }
+#requestcall .phonecall{ font:11px Arial, Helvetica, sans-serif; color:#999; line-height:12px; }
+#requestcall #required_note{ padding-bottom:5px; text-align:right; font-size:11px; }
+#requestcall #required_note, #requestcall .req{ color:#CC0000; }
+#form_content label, .form_content label{ /*margin-right:12px;*/ text-align:right; font-size:11px; color:#595959; padding:0; }
+#form_content input, .form_content input{ width:210px; padding:3px 5px; font-size:11px; color:#2c3333; }
+#form_content select, .form_content select{ width:221px; font-size:11px; padding:0; color:#333; }
+#form_content textarea, .form_content textarea{ border:none; padding:5px; width:210px; font:11px Arial; color:#2C3333; line-height:12px; height:13px; }
+#form_content input, #form_content textarea, .form_content input, .form_content textarea{ border:1px solid #e4e4e4; background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.47, rgb(253,253,253)), color-stop(0.82, rgb(238,238,238))); background-image: -moz-linear-gradient(center bottom, rgb(253,253,253) 47%, rgb(238,238,238) 82%); }
+#form_content input:focus, #form_content textarea:focus, .form_content input:focus, .form_content textarea:focus{ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.47, rgb(234,242,246)), color-stop(0.83, rgb(200,207,209))); background-image: -moz-linear-gradient(center bottom, rgb(234,242,246) 47%, rgb(200,207,209) 83%); border:1px solid #b0b0b0; }
+.content_right #form_content{ width:222px; overflow:hidden; }
+.content_right #form_content fieldset{ width:240px; }
+#form_content fieldset div. .form_content fieldset div{ clear:both; padding:0 0 5px 0; }
+#form_content #disclaimer{ font-size:11px; line-height:11px; padding:16px 0; color:#999; clear:both; }
+#form_content #disclaimer a{ color:#999; text-decoration:underline; }
+#form_content #disclaimer a:hover{ color:#000; }
+#form_content div span.instructions. .form_content div span.instructions{ font-size:11px; color:#C5312C; display:none; }
+.form_submit{ height:50px; display:none; }
+.form_submit p{ font-size:12px; float:right; }
+.form_submit p div{ width:1px !important; height:auto; }
+.secure .form_submit p{ padding-left:30px; background:url(http://novell.com/common/img/forms/form_secure.png) 0px 2px no-repeat; }
+.form_submit p a{ color:#fff !important; text-decoration:none !important; background:url(/common/img/green_dotted_bg.png) top left repeat; display:block; padding:4px 12px 5px 12px; }
+.form_submit p a:hover{ text-decoration:none !important; color:#fff; background-position:bottom right; }
+#form_content .form_submit_hide, .form_content .form_submit_hide, #form_content .form_submit_hide input, .form_content .form_submit_hide input{ margin:0; padding:0; border:none; height: 1px; width: 1px; position: absolute; z-index: -100; }
+
+#form_content input.validation-failed, .form_content input.validation-failed{ border:2px solid #ED1D25; }
+#form_content div.input_advice, .form_content div.input_advice{ font-size:11px; font-weight:bold; padding-top:5px; color:#ED1D25; }
+
+#form_content div.half, #form_content div.extra-fields{ float:left; width:104px; clear:none; margin-right:12px; }
+#form_content div.half input, #form_content div.extra-fields input{ width:93px; }
+#form_content div.half select{ width:105px; height:20px; }
+#form_content div.last{ margin-right:0 !important; }
+
+.content_left #form_content div#requestcall_email{ float:left; clear:none; margin-right:12px; }
+.content_left #requestcall #form_wrap{ padding:20px; background:#eee; margin-bottom:20px; }
+/*.content_left #requestcall form{ padding:20px; background:#eee; }*/
+.content_left #requestcall form fieldset{ width:550px; }
+.content_left #requestcall form fieldset > div{ width:235px !important; padding-top:10px; }
+.content_left #requestcall #form_content label{ text-align:left; display:block; }
+.content_left #requestcall #form_content input{ width:222px; background:#fff; }
+.content_left #requestcall #form_content select{ width:233px; background:#fff; margin-bottom:4px; }
+.content_left #requestcall #form_content textarea{ width:470px; background:#fff; height:23px; }
+.content_left #requestcall #form_content #disclaimer{ width:480px; }
+.content_left #requestcall .form_submit{ height:24px; }
+#content .content_left #requestcall .title{ color:#333; border:none; padding-top:30px; font-size:20px; font-weight:400; }
+.content_left #form_content div.last{ margin-right:12px !important; }
+
+/* MST3k overrides
+-------------------------------------------------- */
+#mst3k_address1, #mst3k_postalCode, #mst3k_state{ display:none; }
+#mst3k_address1, #mst3k_postalCode{ clear:left; }
+#MST_form .half, #MST_form .full{ margin-top:6px; }
+#MST_form .full{ clear:both; }
+
+/* Landing Pages
+----------------------------------- */
+.landing_page .feature{ padding:0; }
+.landing_page .feature_main .wrap{ background:url(/home/img/banners/zenterprise.png) right bottom no-repeat; padding:80px 0; }
+.landing_page .feature_main h1{ margin:0; padding:0; border:none; font-size:28px; line-height:28px; color:#fff; width:500px; }
+.landing_page_gray .feature_main{ background-image:url(/common/img/gray_dotted_nofade.png); }
+.landing_page_gray .feature_main h1{ color:#439539; }
+.landing_page_gray #content{ background:none; }
+
+.landing_page #content .content_left h1{ border-top:0; padding:0; margin-bottom:40px; }
+.landing_page #content .content_left blockquote{ font-style:normal; margin-bottom:20px; }
+.landing_page #content .content_left ol, .landing_page #content .content_left ul{ color:#439539 !important; }
+.landing_page #content .content_left ol li, .landing_page #content .content_left ul li{ color:inherit; margin-bottom:3px; }
+.landing_page #content .content_left ol li p, .landing_page #content .content_left ul li p{ color:#5F5F5F; margin:0; padding:0; }
+.landing_page #content .content_left p.small{ font-size:11px; color:#999; }
+.landing_page #content .content_left .trio_list ul li{ width:190px; margin-right:35px !important; }
+.landing_page #content .content_left .trio_list ul li.third{ margin-right:0px !important; }
+.landing_page #content .content_left .trio_list p.title{ font-size:17px; line-height:17px; padding:32px 0; margin:15px 0; border-top:1px solid #439593; border-bottom:1px solid #eee; }
+
+.landing_page #content h4{ border-top:1px solid #333; padding:18px 0; font-size:15px; }
+.landing_page #content .content_right blockquote{ font-style:normal; border-top:1px solid #333; border-bottom:1px solid #333; margin:0; }
+.landing_page #content .content_right blockquote strong, .landing_page #content .content_right blockquote span{ width:100%; text-align:right; }
+.landing_page #content .content_right #customers li{ float:none; margin-bottom:15px; clear:left; }
+.landing_page #content .content_right #customers li img{ width:60px; float:left; margin-right:20px; }
+.landing_page #content .content_right #customers p{ border:none; padding:0 0 0 80px; }
+
+#content #follow ul, #content #follow ul li{ margin:0; padding:0; list-style-type:none; }
+#content #follow ul li{ width:24px; height:24px; margin:0 10px 10px 0; float:left; }
+#content #follow li a{ width:24px; height:24px; display:block; text-indent:-9999px; background-position:top left; background-repeat:no-repeat; }
+#content #follow li a:hover{ background-position:bottom left; }
+#follow li#sf_cool a{ background-image:url(http://www.novell.com/common/img/follow/cool.jpg); }
+#follow li#sf_email a{ background-image:url(http://www.novell.com/common/img/follow/email.jpg); }
+#follow li#sf_fb a{ background-image:url(http://www.novell.com/common/img/follow/fb.jpg); }
+#follow li#sf_forum a{ background-image:url(http://www.novell.com/common/img/follow/forum.jpg); }
+#follow li#sf_quote a{ background-image:url(http://www.novell.com/common/img/follow/quote.jpg); }
+#follow li#sf_rss a{ background-image:url(http://www.novell.com/common/img/follow/rss.jpg); }
+#follow li#sf_twitter a{ background-image:url(http://www.novell.com/common/img/follow/twitter.jpg); }
+#follow li#sf_url a{ background-image:url(http://www.novell.com/common/img/follow/url.jpg); }
+
+.landing_noleak #form_wrap #form_content div{ clear:both; padding-top:5px; }
+.landing_noleak #form_wrap #form_content label{ float:left; width:100px; padding-top:3px; }
+.landing_noleak #form_wrap #form_content input, .landing_noleak #form_wrap #form_content select{ float:left; width:150px; }
+.landing_noleak #form_wrap #form_content select{ width:160px; padding:2px 0; }
+.landing_noleak #form_wrap #form_content div.questions{ clear:both; padding-top:15px; }
+.landing_noleak #form_wrap #form_content div.questions p{ padding-bottom:5px; }
+.landing_noleak #form_wrap #form_content div.questions label{ float:none; width:auto; padding:0; display:block; text-align:left; }
+.landing_noleak #form_wrap #form_content div.questions input{ float:none; width:249px; }
+.landing_noleak #form_wrap #form_content div.questions select{ float:none; width:275px; }
+
+.landing_noleak .content_left{ width:608px; margin-right:45px; }
+.landing_noleak #content .content_left .trio_list ul li{ margin-right:19px !important; }
+.landing_noleak .content_right{ width:325px; }
+.landing_noleak .content_right h2.title{ background:#333; padding:32px 22px; color:#7ac142; border-bottom:1px solid #000; margin:0; font-size:23px; line-height:22px; font-weight:100; }
+.landing_noleak #form_wrap{ background:#333; border-top:1px solid #3e3e3e; padding:22px; }
+.landing_noleak #form_content{ width:281px; }
+.landing_noleak #form_content fieldset{ width:281px; }
+.landing_noleak #form_content fieldset input{ width:269px; }
+.landing_noleak #form_content fieldset div{ padding-bottom:10px; }
+.landing_noleak #form_wrap #form_content #eloqua_form label, .landing_noleak #form_wrap #form_content #eloqua_form input, .landing_noleak #form_wrap #form_content #eloqua_form select, .landing_noleak #form_wrap #form_content #MST_form label, .landing_noleak #form_wrap #form_content #MST_form input, .landing_noleak #form_wrap #form_content #MST_form select{ float:none; }
+.landing_noleak #form_wrap #form_content #eloqua_form input, .landing_noleak #form_wrap #form_content #MST_form input{ width:269px; }
+.landing_noleak #form_wrap #form_content fieldset div.half, .landing_page #form_wrap #form_content fieldset div.extra-fields{ width:134px; clear:none; }
+.landing_noleak #form_wrap #form_content fieldset div.half label, .landing_page #form_wrap #form_content fieldset div.extra-fields label{ float:none; width:auto; padding:0; }
+.landing_noleak #form_wrap #form_content #eloqua_form fieldset div.half input, .landing_page #form_wrap #form_content #eloqua_form fieldset div.extra-fields input, .landing_noleak #form_wrap #form_content #MST_form fieldset div.half input, .landing_page #form_wrap #form_content #MST_form fieldset div.extra-fields input{ width:126px; }
+.landing_noleak .form_submit{ height:26px; }
+.landing_noleak #MST_form .input_advice{ padding-bottom:0px; }
+.landing_noleak #content .form_asset_desc p{ text-transform:uppercase; font-size:11px; color:#fff; padding:15px 0 30px 0; }
+.landing_noleak #content .form_asset_desc p strong{ display:block; font-weight:bold; }
+.landing_noleak #content label{ color:#999; }
+.landing_noleak #content #required_note{ text-align:right; font-size:11px; color:#999; margin:0; padding-bottom:5px; }
+.landing_noleak #content .req{ color:#fff; }
+
+
+#rac_preview{ padding:15px 0; border-top:1px solid #439539; /*border-bottom:1px solid #439539;*/ }
+#rac_preview p{ margin:0; padding:0; color:#439539; }
+#rac_preview .button a{ background:#439539 url(/common/img/button_bg.png) bottom left no-repeat; padding:0 10px 0 0; margin-top:12px; display:block; text-decoration:none; }
+#rac_preview .button a:hover{ text-decoration:none; background-position:top left; }
+#rac_preview .button_rac a{ padding-right:12px; }
+#rac_preview .button a span{ font-size:15px; color:#fff; padding:10px; display:block; }
+#rac_preview .button_rac a span{ background:url(/common/img/phone.png) center right no-repeat; }
+#rac_preview .button_chat{ display:none; } /* disable by default. EMEA countries will have it enabled via JS */
+#rac_preview .button_chat a span{ background:url(/common/img/chat_bubble.png) center right no-repeat; }
+.ie6 .career #meta_wrap{ height:164; }
+.ie6 .career .feature .wrap{ padding:80px 0 0 0; }
+.ie6 .career #content{ clear:both; }
+.ie6 #rac_preview p.button{ height:30px; }
+#rac_preview.rac_button_embedded{ padding:0 0 15px 0; border-top:0; }
+#rac_preview.rac_button_embedded a{ margin-top:0; }
+
+
+.landing_ty_asset .content_left, .landing_ty_asset .content_right{ width:43% }
+.landing_ty_asset .asset{ background:#333; padding:22px; border-bottom:1px solid #000; border-top:1px solid #3e3e3e; }
+.landing_ty_asset #content .asset p{ color:#fff; text-transform:uppercase; font-size:11px; padding:0; }
+.landing_ty_asset #content .asset p strong{ display:block; }
+.landing_ty_asset #content .asset p.download{ padding-top:15px; }
+.landing_ty_asset #content .asset p.download a{ background:url(/common/img/green_dotted_bg.png) top left repeat; text-transform:none; padding:4px 12px 5px; text-decoration:none !important; color:#fff; display:inline-block; }
+
+
+/* Sidebar content
+----------------------------------- */
+.module{ padding-bottom:36px; }
+
+#content .rac_sublinks, #content .rac_sublinks li{ margin:0; padding:0; list-style-type:none; }
+#content .rac_sublinks li{ font-size:14px; padding:6px 0 3px 0; border-top:1px solid #439539; }
+#content .rac_sublinks li.last-child{ border-bottom:1px solid #439539; }
+#content .rac_sublinks li a{ color:#439539; text-decoration:none; display:block; }
+#content .rac_sublinks li a:hover{ text-decoration:underline; }
+
+#industry_experts p{ font-size:13px; line-height:16px; }
+#industry_experts p a{ color:#646464; text-decoration:none; }
+#industry_experts p strong{ font-weight:500; color:#439539; display:block; }
+#industry_experts p.last-child{ padding-bottom:0; }
+#industry_experts p a:hover{ text-decoration:underline; }
+
+#news_events ul, #news_events ul li, #follow_social ul, #follow_social ul li, #alliance_partners ul, #alliance_partners ul li{ margin:0; padding:0; list-style-type:none; }
+#news_events ul li{ font-size:13px; padding:10px 0; color:#646464; line-height:16px; }
+#news_events ul li a{ color:#666; text-decoration:none; }
+#news_events ul li a:hover{ text-decoration:underline; }
+#news_events ul li span{ display:block; color:#999; }
+
+#follow_social ul li{ width:24px; height:24px; float:left; margin-right:10px; }
+#follow_social ul li a{ display:block; background:url(http://dummyimage.com/24x48.jpg) top left no-repeat; text-indent:-9999px; width:24px; height:24px; }
+#follow_social ul li a:hover{ background-position:bottom left; }
+#follow_social ul li.follow_fb a{ background-image:url(/common/img/social/facebook_24x24.png); }
+#follow_social ul li.follow_cs a{ background-image:url(/common/img/social/cool_24x24.png); }
+#follow_social ul li.follow_forum a{ background-image:url(/common/img/social/forums_24x24.png); }
+#follow_social ul li.follow_blog a{ background-image:url(/common/img/social/blog_24x24.png); }
+#follow_social ul li.follow_newsletter a{ background-image:url(/common/img/social/newsletter_24x24.png); }
+#follow_social ul li.follow_rss a{ background-image:url(/common/img/social/rss_24x24.png); }
+#follow_social ul li.follow_site a{ background-image:url(/common/img/social/rss_site.png); }
+#follow_social ul li.follow_twitter a{ background-image:url(/common/img/social/rss_twitter.png); }
+
+#alliance_partners ul li{ width:74px; float:left; margin-bottom:10px; text-align:center; }
+#alliance_partners ul li a{ display:block; width:80px; height:44px; background-repeat:no-repeat; background-position:top center; text-indent:-9999px; }
+#alliance_partners ul li a:hover{ box-shadow: 0 0 10px #439539; -webkit-box-shadow: 0 0 10px #439539; -moz-box-shadow: 0 0 10px #439539; }
+
+#alliance_partners ul li#amd a{ background-image:url(/common/img/alliance_partners/amd.png); }
+#alliance_partners ul li#broadcom a{ background-image:url(/common/img/alliance_partners/broadcom.png); }
+#alliance_partners ul li#brocade a{ background-image:url(/common/img/alliance_partners/brocade.png); }
+#alliance_partners ul li#emulex a{ background-image:url(/common/img/alliance_partners/emulex.png); }
+#alliance_partners ul li#fujitsu a{ background-image:url(/common/img/alliance_partners/fujitsu.png); }
+#alliance_partners ul li#hp a{ background-image:url(/common/img/alliance_partners/hp.png); }
+#alliance_partners ul li#ibm a{ background-image:url(/common/img/alliance_partners/ibm.png); }
+#alliance_partners ul li#intel a{ background-image:url(/common/img/alliance_partners/intel.png); }
+#alliance_partners ul li#lsi a{ background-image:url(/common/img/alliance_partners/lsi.png); }
+#alliance_partners ul li#microsoft a{ background-image:url(/common/img/alliance_partners/microsoft.png); }
+#alliance_partners ul li#nvidia a{ background-image:url(/common/img/alliance_partners/nvidia.png); }
+#alliance_partners ul li#oracle a{ background-image:url(/common/img/alliance_partners/oracle.png); }
+#alliance_partners ul li#qlogic a{ background-image:url(/common/img/alliance_partners/qlogic.png); }
+#alliance_partners ul li#sap a{ background-image:url(/common/img/alliance_partners/sap.png); }
+#alliance_partners ul li#symantec a{ background-image:url(/common/img/alliance_partners/symantec.png); }
+#alliance_partners ul li#vmware a{ background-image:url(/common/img/alliance_partners/vmware.png); }
+#alliance_partners ul li#dell a{ background-image:url(/common/img/alliance_partners/dell.png); }
+
+#content .link_arrow{ margin:0; padding:15px 0 36px 0; }
+#content .link_arrow a{ display:block; padding-left:21px; background:url(/common/img/link_arrow.png) top left no-repeat; color:#439239; text-decoration:none; }
+#content .link_arrow a:hover{ text-decoration:underline; }
+#content .content_left .link_arrow{ padding-top:0; }
+
+/* Careers
+----------------------------------- */
+.career img.infographic{ width:966px; box-shadow: 0px 0px 15px #bbb; -moz-box-shadow: 0px 0px 15px #bbb; -webkit-box-shadow: 0px 0px 15px #bbb; border:6px solid white; margin-top:15px; }
+.career .career_content{ width:700px; padding-top:10px; }
+.career .suse_button{ float:right; padding-top:10px; }
+
+.career h3{ margin-bottom:60px; }
+
+.career_right p{ padding-top:10px !important; font-size:12px; }
+.career_right h4{ clear:both; color:#439539; border-color:#439539; margin:8px 0; }
+.career_right img{ display:block; padding:10px; background:#fff; box-shadow:0px 0px 5px #ccc; margin-bottom:5px; }
+#content .jobs_title{ color:#666; font-family:"omnes-pro-1"; font-size:16px; text-align:center; }
+.career_right .quotes{ margin-top:7px; }
+.career_right blockquote{ margin:0; padding:15px 0 0 0; font-style:italic; font-size:12px; display:none; font-weight:normal; font-family:Arial, Helvetica, sans-serif; }
+.career .content_left .suse_button{ float:none; }
+
+.career .career_num{ width:70px; height:93px; display:block; float:left; margin-right:5px; background-repeat:no-repeat; background-position:top left; text-indent:-9999px; }
+.career .num_last{ margin-right:0; }
+.career .num_0{ background:url(/company/careers/numbers/0.png); }
+.career .num_1{ background:url(/company/careers/numbers/1.png); }
+.career .num_2{ background:url(/company/careers/numbers/2.png); }
+.career .num_3{ background:url(/company/careers/numbers/3.png); }
+.career .num_4{ background:url(/company/careers/numbers/4.png); }
+.career .num_5{ background:url(/company/careers/numbers/5.png); }
+.career .num_6{ background:url(/company/careers/numbers/6.png); }
+.career .num_7{ background:url(/company/careers/numbers/7.png); }
+.career .num_8{ background:url(/company/careers/numbers/8.png); }
+.career .num_9{ background:url(/company/careers/numbers/9.png); }
+
+
+/* ISV Catalog
+----------------------------------- */
+br.clear{ clear:both; }
+#app_tier4 h1{ position:static; font-size:30px; color:#439539; font-weight:400; padding-top:30px; }
+#app_tier4 #desc1{ font-size:20px; float:none; }
+#app_tier4 #desc2{ color:#439539; font-size:19px; font-weight:normal; }
+#app_tier4 #contentcontainer{ padding:0 !important; background:none; }
+#app_tier4 #info_box #info_line1, #app_tier4 #info_box #info_line2, #app_tier4 #info_box #info_line3{ height:auto; }
+#app_tier4 #contenthead{ height:auto; border:none; }
+#app_tier4 #subcontenthead p{ font-weight:bold; font-size:18px; color:#439539; padding:0; }
+#app_tier4 #subcontenthead p.sub{ font-weight:normal; font-size:15px; color:#333; }
+
+/* Footer
+----------------------------------- */
+footer{ /*background:#E4E7E9;*/ padding:36px 0 62px 0; }
+footer .col{ padding:0 16px; float:left; width:130px; }
+footer h5{ font-size:15px; color:#439539; margin:26px 0 20px; font-weight:300; }
+footer ul{ margin:0; padding:0; list-style-type:none; }
+footer ul li{ border-bottom:1px solid #C6C6C6; font-size:11px; font-family:Helvetica, Arial, sans-serif; }
+footer ul li:first-child{ border-top:1px solid #C6C6C6; }
+footer ul li a{ color:#666; text-decoration:none; display:block; padding:2px 0; }
+footer ul li a:hover{ color:#439339; }
+
+footer.product, footer.home{ background:#202020; padding-bottom:0; }
+footer.product .wrap .col, footer.home .wrap .col{ border-top:1px solid #76ad2d; padding:17px 0 0 0; margin-right:32px; }
+footer.product .wrap .col h5, footer.home .wrap .col h5{ margin:0 0 15px 0; color:#999; }
+footer.product .wrap .col h5 a, footer.home .wrap .col h5 a{ color:#999; text-decoration:none; }
+footer.product .wrap .col h5 a:hover, footer.home .wrap .col h5 a:hover{ color:#666; }
+footer.product .wrap .col ul, footer.home .wrap .col ul{ padding-bottom:32px; }
+footer.product .wrap .col ul li, footer.home .wrap .col ul li{ border-bottom:1px solid #2f2f2f; /*font-family:Omnes_Regular;*/ }
+footer.product .wrap .col ul li:first-child, footer.home .wrap .col ul li:first-child{ border-top:1px solid #2f2f2f; }
+footer.product .wrap .col ul li a, footer.home .wrap .col ul li a{ color:#76ad2d; padding:8px 2px 5px; }
+footer.product .wrap .col ul li a:hover, footer.home .wrap .col ul li a:hover{ color:#5E9632; }
+footer.product .subtitle{ font-size:11px; color:#fff; }
+
+footer.product .wrap .col:first-child, footer.home .wrap .col1{ width:222px; }
+footer.product .wrap .col:first-child ul{ padding-top:22px; }
+footer.product .wrap .col:first-child li{ border-bottom:1px solid #76ad2d; padding:2px 0; font-weight:500; }
+footer.product .wrap .col:first-child li#footer_rac{ background:#76ad2d; }
+footer.product .wrap .col:first-child li:first-child{ border-top:1px solid #76ad2d; }
+footer.product .wrap .col:first-child li a{ color:#e3e4e5; font-size:13px; padding:2px 5px 2px 5px; }
+footer.product .wrap .col:first-child li a:hover{ color:#fff; text-decoration:none; }
+footer.product .wrap .col:first-child li#footer_rac a{ color:#202020; }
+footer.product .wrap .col:first-child li#footer_rac a:hover{ color:#000; }
+
+footer.product .wrap .second-child{ width:304px; }
+footer.product .wrap .third-child{ width:388px; margin-right:0; }
+
+footer.home .wrap .col{ float:left; margin-right:30px; }
+footer.home .col1, footer.home .col5{ width:222px; }
+footer.home .col2, footer.home .col3, footer.home .col4{ width:138px; }
+footer.home .wrap .col1{ padding-top:0; border-top:none; }
+footer.home .wrap .col5{ margin:0; }
+footer.home p{ color:#999; padding-bottom:20px; }
+footer.home .footer_title{ font-weight:100; color:#76AD2D; font-size:25px; padding-bottom:15px; }
+
+footer.home .footer_global{ padding:0; background:none; }
+footer.home .footer_global p, footer.home .footer_global a{ color:#666 !important; }
+
+footer .footer_global{ background:#f2f2f2; padding:32px 0 28px; min-width:1018px; }
+footer .footer_global p, footer .footer_global ul li{ float:left; color:#333; padding-right:32px; font-size:12px; }
+footer .footer_global p{ font-weight:500; padding-top:2px; }
+footer .footer_global p#suse_phone{ float:right; padding:0; }
+footer .footer_global p#suse_phone a{ color:#333; text-decoration:none; }
+footer .footer_global p#suse_phone a:hover{ text-decoration:underline; }
+footer .footer_global li{ font-weight:400; border:none !important; }
+footer .footer_global li a:hover{ text-decoration:underline; color:#76ad2d; }
+
+/* Typekit font events to eliminate FOUT on Firefox: http://blog.typekit.com/2010/10/29/font-events-controlling-the-fout/
+----------------------------------- */
+.wf-loading h1,
+.wf-loading h1 strong,
+.wf-loading h2,
+.wf-loading h3,
+.wf-loading h4,
+.wf-loading h5,
+/*.wf-loading header ul#nav li,*/
+/*.wf-loading .feature #product_nav li,*/
+.wf-loading .feature .headline,
+.wf-loading .feature .headline strong,
+.wf-loading .feature #cta_links #cta a,
+.wf-loading #content .callout p,
+.wf-loading #content .highlight p,
+.wf-loading #content .callout p strong,
+.wf-loading #content .sublinks li,
+.wf-loading #content .sublinks li strong,
+.wf-loading #content p.title,
+.wf-loading #content .content_left .anchor_content strong,
+.wf-loading #content .content_left .anchor_title,
+.wf-loading #content .content_left .anchor_title span,
+.wf-loading blockquote,
+.wf-loading blockquote span,
+.wf-loading #content .product_list li p.title,
+.wf-loading #content .product_list li a,
+.wf-loading #content .subtitle,
+.wf-loading #content .greenbox p.number,
+.wf-loading #content .greenbox p.text,
+.wf-loading #content .col_small blockquote,
+.wf-loading .table_comparison tbody td,
+.wf-loading .version_comparison tbody td span,
+.wf-loading #content .table_header,
+.wf-loading .support_comparison thead th span,
+.wf-loading .support_comparison .buy a,
+.wf-loading #content .box p.box_title,
+.wf-loading #community p.desc,
+.wf-loading #content #requestcall .title,
+.wf-loading footer.product .wrap .col:first-child li,
+.wf-loading .col_highlight_one p,
+.wf-loading header ul#nav .nav_subheading,
+.wf-loading #company .section_title,
+.wf-loading .offer a span,
+.wf-loading footer.home .footer_title,
+.wf-loading #training .training_heading,
+.wf-loading .promo_sidebar a strong{ visibility:hidden; }
+
+/* Typekit font customizations
+----------------------------------- */
+/* .tk-omnes-pro is the default class which enables this on any element to which the class is applied */
+h1,
+h1 strong,
+h2,
+h3,
+h4,
+h5,
+/*header ul#nav li,*/
+/*.feature #product_nav li,*/
+.feature .headline,
+.feature .headline strong,
+.feature #cta_links #cta a,
+#content .callout p,
+#content .highlight p,
+#content .sublinks li,
+#content .sublinks li strong,
+#content p.title,
+#content .content_left .anchor_content strong,
+#content .content_left .anchor_title,
+#content .content_left .anchor_title span,
+blockquote,
+blockquote span,
+#content .product_list li p.title,
+#content .product_list li a,
+#content .subtitle,
+#content .greenbox p.number,
+#content .greenbox p.text,
+#content .col_small blockquote,
+.table_comparison tbody td,
+.version_comparison tbody td span,
+#content .table_header,
+.support_comparison thead th span,
+.support_comparison .buy a,
+#content .box p.box_title,
+#community p.desc,
+#content #requestcall .title,
+footer.product .wrap .col:first-child li,
+.col_highlight_one p,
+.col_highlight_one p strong,
+header ul#nav .nav_subheading,
+#company .section_title,
+.offer a span,
+footer.home .footer_title,
+#training .training_heading,
+.promo_sidebar a strong{ font-family: "omnes-pro-1", "omnes-pro-2", Helvetica, Arial, sans-serif; }
+
+/* Japanese/Chinese overrides
+----------------------------------- */
+.ja-jp .feature .headline, .zh-cn .feature .headline{ font-size:31px; line-height:38px; }
+.ja-jp .feature #cta_links #cta a, .zh-cn .feature #cta_links #cta a{ line-height:32px; }
+.ja-jp #content .callout p, .zh-cn #content .callout p{ line-height:26px; }
+.ja-jp #trial_content h2, .ja-jp #content p, .ja-jp footer p, .ja-jp #form_content #disclaimer, .ja-jp #content .sublinks li, .zh-cn #content p, .zh-cn #form_content #disclaimer, .zh-cn #content .sublinks li{ line-height:130%; }
+.ja-jp #content .content_left .anchor_content li, .zh-cn #content .content_left .anchor_content li{ line-height:18px; }
+/* Need to specifically override elements that were targeted for Omnes font customization */
+html body.ja-jp,
+html body.ja-jp #container,
+.ja-jp h1,
+.ja-jp h1 strong,
+.ja-jp h2,
+.ja-jp h3,
+.ja-jp h4,
+.ja-jp h5,
+.ja-jp .feature .headline,
+.ja-jp .feature .headline strong,
+.ja-jp .feature #cta_links #cta a,
+.ja-jp #content .callout p,
+.ja-jp #content .highlight p,
+.ja-jp #content .sublinks li,
+.ja-jp #content .sublinks li strong,
+.ja-jp #content p.title,
+.ja-jp #content .content_left .anchor_content strong,
+.ja-jp #content .content_left .anchor_title,
+.ja-jp #content .content_left .anchor_title span,
+.ja-jp blockquote,
+.ja-jp blockquote span,
+.ja-jp #content .product_list li p.title,
+.ja-jp #content .product_list li a,
+.ja-jp #content .subtitle,
+.ja-jp #content .greenbox p.number,
+.ja-jp #content .greenbox p.text,
+.ja-jp #content .col_small blockquote,
+.ja-jp .table_comparison tbody td,
+.ja-jp .version_comparison tbody td span,
+.ja-jp #content .table_header,
+.ja-jp .support_comparison thead th span,
+.ja-jp .support_comparison .buy a,
+.ja-jp #content .box p.box_title,
+.ja-jp #community p.desc,
+.ja-jp #content #requestcall .title,
+.ja-jp footer.product .wrap .col:first-child li,
+.ja-jp .col_highlight_one p,
+.ja-jp .col_highlight_one p strong,
+.ja-jp header ul#nav .nav_subheading,
+.ja-jp #company .section_title,
+.ja-jp .offer a span,
+.ja-jp footer.home .footer_title,
+.ja-jp #training .training_heading,
+.ja-jp .promo_sidebar a strong,
+.ja-jp header ul#nav li,
+.ja-jp footer ul li{ font-family:"メイリオ","Meiryo","ヒラギノ角ゴ Pro W3","Hiragino Kaku Gothic Pro","MS Pゴシック","arial","sans-serif" !important }
+
+
+.hu-hu header ul#nav li#nav_solutions{ width:115px; }
+.hu-hu header ul#nav li#nav_products{ width:210px; }
+.hu-hu header ul#nav li#nav_support{ width:140px; }
+.hu-hu header ul#nav li#nav_partners{ width:100px; }
+.hu-hu header ul#nav li#nav_community{ width:100px; }
+.hu-hu header ul#nav li#nav_dl{ width:135px; }
+
+/**
+ * Media queries for responsive design.
+ *
+ * These follow after primary styles so they will successfully override.
+ */
+
+@media all and (orientation:portrait) {
+ /* Style adjustments for portrait mode goes here */
+
+}
+
+@media all and (orientation:landscape) {
+ /* Style adjustments for landscape mode goes here */
+
+}
+
+/* Grade-A Mobile Browsers (Opera Mobile, Mobile Safari, Android Chrome)
+ consider this: www.cloudfour.com/css-media-query-for-mobile-is-fools-gold/ */
+@media screen and (max-device-width: 480px) {
+
+
+ /* Uncomment if you don't want iOS and WinMobile to mobile-optimize the text for you: j.mp/textsizeadjust */
+ /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
+}
+
+/**
+ * Print styles.
+ *
+ * Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/
+ */
+@media print {
+ * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important;
+ -ms-filter: none !important; } /* Black prints faster: sanbeiji.com/archives/953 */
+ a, a:visited { color: #444 !important; text-decoration: underline; }
+ a[href]:after { content: " (" attr(href) ")"; }
+ abbr[title]:after { content: " (" attr(title) ")"; }
+ .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */
+ pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
+ thead { display: table-header-group; } /* css-discuss.incutio.com/wiki/Printing_Tables */
+ tr, img { page-break-inside: avoid; }
+ @page { margin: 0.5cm; }
+ p, h2, h3 { orphans: 3; widows: 3; }
+ h2, h3{ page-break-after: avoid; }
+}
+
+/**
+ * Prettyphoto
+ */
+
+div.pp_default .pp_top,div.pp_default .pp_top .pp_middle,div.pp_default .pp_top .pp_left,div.pp_default .pp_top .pp_right,div.pp_default .pp_bottom,div.pp_default .pp_bottom .pp_left,div.pp_default .pp_bottom .pp_middle,div.pp_default .pp_bottom .pp_right{height:13px}div.pp_default .pp_top .pp_left{background:url(/common/img/prettyPhoto/default/sprite.png) -78px -93px no-repeat}div.pp_default .pp_top .pp_middle{background:url(/common/img/prettyPhoto/default/sprite_x.png) top left repeat-x}div.pp_default .pp_top .pp_right{background:url(/common/img/prettyPhoto/default/sprite.png) -112px -93px no-repeat}div.pp_default .pp_content .ppt{color:#f8f8f8}div.pp_default .pp_content_container .pp_left{background:url(/common/img/prettyPhoto/default/sprite_y.png) -7px 0 repeat-y;padding-left:13px}div.pp_default .pp_content_container .pp_right{background:url(/common/img/prettyPhoto/default/sprite_y.png) top right repeat-y;padding-right:13px}div.pp_default .pp_next:hover{background:url(/common/img/prettyPhoto/default/sprite_next.png) center right no-repeat;cursor:pointer}div.pp_default .pp_previous:hover{background:url(/common/img/prettyPhoto/default/sprite_prev.png) center left no-repeat;cursor:pointer}div.pp_default .pp_expand{background:url(/common/img/prettyPhoto/default/sprite.png) 0 -29px no-repeat;cursor:pointer;width:28px;height:28px}div.pp_default .pp_expand:hover{background:url(/common/img/prettyPhoto/default/sprite.png) 0 -56px no-repeat;cursor:pointer}div.pp_default .pp_contract{background:url(/common/img/prettyPhoto/default/sprite.png) 0 -84px no-repeat;cursor:pointer;width:28px;height:28px}div.pp_default .pp_contract:hover{background:url(/common/img/prettyPhoto/default/sprite.png) 0 -113px no-repeat;cursor:pointer}div.pp_default .pp_close{width:30px;height:30px;background:url(/common/img/prettyPhoto/default/sprite.png) 2px 1px no-repeat;cursor:pointer}div.pp_default .pp_gallery ul li a{background:url(/common/img/prettyPhoto/default/default_thumb.png) center center #f8f8f8;border:1px solid #aaa}div.pp_default .pp_gallery a.pp_arrow_previous,div.pp_default .pp_gallery a.pp_arrow_next{position:static;left:auto}div.pp_default .pp_nav .pp_play,div.pp_default .pp_nav .pp_pause{background:url(/common/img/prettyPhoto/default/sprite.png) -51px 1px no-repeat;height:30px;width:30px}div.pp_default .pp_nav .pp_pause{background-position:-51px -29px}div.pp_default a.pp_arrow_previous,div.pp_default a.pp_arrow_next{background:url(/common/img/prettyPhoto/default/sprite.png) -31px -3px no-repeat;height:20px;width:20px;margin:4px 0 0}div.pp_default a.pp_arrow_next{left:52px;background-position:-82px -3px}div.pp_default .pp_content_container .pp_details{margin-top:5px}div.pp_default .pp_nav{clear:none;height:30px;width:105px;position:relative}div.pp_default .pp_nav .currentTextHolder{font-family:Georgia;font-style:italic;font-color:#999;font-size:11px;left:75px;line-height:25px;position:absolute;top:2px;margin:0;padding:0 0 0 10px}div.pp_default .pp_close:hover,div.pp_default .pp_nav .pp_play:hover,div.pp_default .pp_nav .pp_pause:hover,div.pp_default .pp_arrow_next:hover,div.pp_default .pp_arrow_previous:hover{opacity:0.7}div.pp_default .pp_description{font-size:11px;font-weight:700;line-height:14px;margin:5px 50px 5px 0}div.pp_default .pp_bottom .pp_left{background:url(/common/img/prettyPhoto/default/sprite.png) -78px -127px no-repeat}div.pp_default .pp_bottom .pp_middle{background:url(/common/img/prettyPhoto/default/sprite_x.png) bottom left repeat-x}div.pp_default .pp_bottom .pp_right{background:url(/common/img/prettyPhoto/default/sprite.png) -112px -127px no-repeat}div.pp_default .pp_loaderIcon{background:url(/common/img/prettyPhoto/default/loader.gif) center center no-repeat}div.light_rounded .pp_top .pp_left{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -88px -53px no-repeat}div.light_rounded .pp_top .pp_right{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -110px -53px no-repeat}div.light_rounded .pp_next:hover{background:url(/common/img/prettyPhoto/light_rounded/btnNext.png) center right no-repeat;cursor:pointer}div.light_rounded .pp_previous:hover{background:url(/common/img/prettyPhoto/light_rounded/btnPrevious.png) center left no-repeat;cursor:pointer}div.light_rounded .pp_expand{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -31px -26px no-repeat;cursor:pointer}div.light_rounded .pp_expand:hover{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -31px -47px no-repeat;cursor:pointer}div.light_rounded .pp_contract{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) 0 -26px no-repeat;cursor:pointer}div.light_rounded .pp_contract:hover{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) 0 -47px no-repeat;cursor:pointer}div.light_rounded .pp_close{width:75px;height:22px;background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -1px -1px no-repeat;cursor:pointer}div.light_rounded .pp_nav .pp_play{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -1px -100px no-repeat;height:15px;width:14px}div.light_rounded .pp_nav .pp_pause{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -24px -100px no-repeat;height:15px;width:14px}div.light_rounded .pp_arrow_previous{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) 0 -71px no-repeat}div.light_rounded .pp_arrow_next{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -22px -71px no-repeat}div.light_rounded .pp_bottom .pp_left{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -88px -80px no-repeat}div.light_rounded .pp_bottom .pp_right{background:url(/common/img/prettyPhoto/light_rounded/sprite.png) -110px -80px no-repeat}div.dark_rounded .pp_top .pp_left{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -88px -53px no-repeat}div.dark_rounded .pp_top .pp_right{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -110px -53px no-repeat}div.dark_rounded .pp_content_container .pp_left{background:url(/common/img/prettyPhoto/dark_rounded/contentPattern.png) top left repeat-y}div.dark_rounded .pp_content_container .pp_right{background:url(/common/img/prettyPhoto/dark_rounded/contentPattern.png) top right repeat-y}div.dark_rounded .pp_next:hover{background:url(/common/img/prettyPhoto/dark_rounded/btnNext.png) center right no-repeat;cursor:pointer}div.dark_rounded .pp_previous:hover{background:url(/common/img/prettyPhoto/dark_rounded/btnPrevious.png) center left no-repeat;cursor:pointer}div.dark_rounded .pp_expand{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -31px -26px no-repeat;cursor:pointer}div.dark_rounded .pp_expand:hover{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -31px -47px no-repeat;cursor:pointer}div.dark_rounded .pp_contract{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) 0 -26px no-repeat;cursor:pointer}div.dark_rounded .pp_contract:hover{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) 0 -47px no-repeat;cursor:pointer}div.dark_rounded .pp_close{width:75px;height:22px;background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -1px -1px no-repeat;cursor:pointer}div.dark_rounded .pp_description{margin-right:85px;color:#fff}div.dark_rounded .pp_nav .pp_play{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -1px -100px no-repeat;height:15px;width:14px}div.dark_rounded .pp_nav .pp_pause{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -24px -100px no-repeat;height:15px;width:14px}div.dark_rounded .pp_arrow_previous{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) 0 -71px no-repeat}div.dark_rounded .pp_arrow_next{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -22px -71px no-repeat}div.dark_rounded .pp_bottom .pp_left{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -88px -80px no-repeat}div.dark_rounded .pp_bottom .pp_right{background:url(/common/img/prettyPhoto/dark_rounded/sprite.png) -110px -80px no-repeat}div.dark_rounded .pp_loaderIcon, div.pp_suse .pp_loaderIcon{background:url(/common/img/prettyPhoto/dark_rounded/loader.gif) center center no-repeat}div.dark_square .pp_left,div.dark_square .pp_middle,div.dark_square .pp_right,div.dark_square .pp_content{background:#000}div.dark_square .pp_description{color:#fff;margin:0 85px 0 0}div.dark_square .pp_loaderIcon{background:url(/common/img/prettyPhoto/dark_square/loader.gif) center center no-repeat}div.dark_square .pp_expand{background:url(/common/img/prettyPhoto/dark_square/sprite.png) -31px -26px no-repeat;cursor:pointer}div.dark_square .pp_expand:hover{background:url(/common/img/prettyPhoto/dark_square/sprite.png) -31px -47px no-repeat;cursor:pointer}div.dark_square .pp_contract{background:url(/common/img/prettyPhoto/dark_square/sprite.png) 0 -26px no-repeat;cursor:pointer}div.dark_square .pp_contract:hover{background:url(/common/img/prettyPhoto/dark_square/sprite.png) 0 -47px no-repeat;cursor:pointer}div.dark_square .pp_close{width:75px;height:22px;background:url(/common/img/prettyPhoto/dark_square/sprite.png) -1px -1px no-repeat;cursor:pointer}div.dark_square .pp_nav{clear:none}div.dark_square .pp_nav .pp_play{background:url(/common/img/prettyPhoto/dark_square/sprite.png) -1px -100px no-repeat;height:15px;width:14px}div.dark_square .pp_nav .pp_pause{background:url(/common/img/prettyPhoto/dark_square/sprite.png) -24px -100px no-repeat;height:15px;width:14px}div.dark_square .pp_arrow_previous{background:url(/common/img/prettyPhoto/dark_square/sprite.png) 0 -71px no-repeat}div.dark_square .pp_arrow_next{background:url(/common/img/prettyPhoto/dark_square/sprite.png) -22px -71px no-repeat}div.dark_square .pp_next:hover{background:url(/common/img/prettyPhoto/dark_square/btnNext.png) center right no-repeat;cursor:pointer}div.dark_square .pp_previous:hover{background:url(/common/img/prettyPhoto/dark_square/btnPrevious.png) center left no-repeat;cursor:pointer}div.light_square .pp_expand{background:url(/common/img/prettyPhoto/light_square/sprite.png) -31px -26px no-repeat;cursor:pointer}div.light_square .pp_expand:hover{background:url(/common/img/prettyPhoto/light_square/sprite.png) -31px -47px no-repeat;cursor:pointer}div.light_square .pp_contract{background:url(/common/img/prettyPhoto/light_square/sprite.png) 0 -26px no-repeat;cursor:pointer}div.light_square .pp_contract:hover{background:url(/common/img/prettyPhoto/light_square/sprite.png) 0 -47px no-repeat;cursor:pointer}div.light_square .pp_close{width:75px;height:22px;background:url(/common/img/prettyPhoto/light_square/sprite.png) -1px -1px no-repeat;cursor:pointer}div.light_square .pp_nav .pp_play{background:url(/common/img/prettyPhoto/light_square/sprite.png) -1px -100px no-repeat;height:15px;width:14px}div.light_square .pp_nav .pp_pause{background:url(/common/img/prettyPhoto/light_square/sprite.png) -24px -100px no-repeat;height:15px;width:14px}div.light_square .pp_arrow_previous{background:url(/common/img/prettyPhoto/light_square/sprite.png) 0 -71px no-repeat}div.light_square .pp_arrow_next{background:url(/common/img/prettyPhoto/light_square/sprite.png) -22px -71px no-repeat}div.light_square .pp_next:hover{background:url(/common/img/prettyPhoto/light_square/btnNext.png) center right no-repeat;cursor:pointer}div.light_square .pp_previous:hover{background:url(/common/img/prettyPhoto/light_square/btnPrevious.png) center left no-repeat;cursor:pointer}div.facebook .pp_top .pp_left{background:url(/common/img/prettyPhoto/facebook/sprite.png) -88px -53px no-repeat}div.facebook .pp_top .pp_middle{background:url(/common/img/prettyPhoto/facebook/contentPatternTop.png) top left repeat-x}div.facebook .pp_top .pp_right{background:url(/common/img/prettyPhoto/facebook/sprite.png) -110px -53px no-repeat}div.facebook .pp_content_container .pp_left{background:url(/common/img/prettyPhoto/facebook/contentPatternLeft.png) top left repeat-y}div.facebook .pp_content_container .pp_right{background:url(/common/img/prettyPhoto/facebook/contentPatternRight.png) top right repeat-y}div.facebook .pp_expand{background:url(/common/img/prettyPhoto/facebook/sprite.png) -31px -26px no-repeat;cursor:pointer}div.facebook .pp_expand:hover{background:url(/common/img/prettyPhoto/facebook/sprite.png) -31px -47px no-repeat;cursor:pointer}div.facebook .pp_contract{background:url(/common/img/prettyPhoto/facebook/sprite.png) 0 -26px no-repeat;cursor:pointer}div.facebook .pp_contract:hover{background:url(/common/img/prettyPhoto/facebook/sprite.png) 0 -47px no-repeat;cursor:pointer}div.facebook .pp_close{width:22px;height:22px;background:url(/common/img/prettyPhoto/facebook/sprite.png) -1px -1px no-repeat;cursor:pointer}div.facebook .pp_description{margin:0 37px 0 0}div.facebook .pp_loaderIcon{background:url(/common/img/prettyPhoto/facebook/loader.gif) center center no-repeat}div.facebook .pp_arrow_previous{background:url(/common/img/prettyPhoto/facebook/sprite.png) 0 -71px no-repeat;height:22px;margin-top:0;width:22px}div.facebook .pp_arrow_previous.disabled{background-position:0 -96px;cursor:default}div.facebook .pp_arrow_next{background:url(/common/img/prettyPhoto/facebook/sprite.png) -32px -71px no-repeat;height:22px;margin-top:0;width:22px}div.facebook .pp_arrow_next.disabled{background-position:-32px -96px;cursor:default}div.facebook .pp_nav{margin-top:0}div.facebook .pp_nav p{font-size:15px;padding:0 3px 0 4px}div.facebook .pp_nav .pp_play{background:url(/common/img/prettyPhoto/facebook/sprite.png) -1px -123px no-repeat;height:22px;width:22px}div.facebook .pp_nav .pp_pause{background:url(/common/img/prettyPhoto/facebook/sprite.png) -32px -123px no-repeat;height:22px;width:22px}div.facebook .pp_next:hover{background:url(/common/img/prettyPhoto/facebook/btnNext.png) center right no-repeat;cursor:pointer}div.facebook .pp_previous:hover{background:url(/common/img/prettyPhoto/facebook/btnPrevious.png) center left no-repeat;cursor:pointer}div.facebook .pp_bottom .pp_left{background:url(/common/img/prettyPhoto/facebook/sprite.png) -88px -80px no-repeat}div.facebook .pp_bottom .pp_middle{background:url(/common/img/prettyPhoto/facebook/contentPatternBottom.png) top left repeat-x}div.facebook .pp_bottom .pp_right{background:url(/common/img/prettyPhoto/facebook/sprite.png) -110px -80px no-repeat}div.pp_pic_holder a:focus{outline:none}div.pp_overlay{background:#000;display:none;left:0;position:absolute;top:0;width:100%;z-index:9500}div.pp_pic_holder{display:none;position:absolute;width:100px;z-index:10000}.pp_content{height:40px;min-width:40px}* html .pp_content{width:40px}.pp_content_container{position:relative;text-align:left;width:100%}.pp_content_container .pp_left{padding-left:20px}.pp_content_container .pp_right{padding-right:20px}.pp_content_container .pp_details{float:left;margin:10px 0 2px}.pp_description{display:none;margin:0}.pp_social{float:left;margin:7px 0 0}.pp_social .facebook{float:left;position:relative;top:-1px;margin-left:5px;width:55px;overflow:hidden}.pp_social .twitter{float:left}.pp_nav{clear:right;float:left;margin:3px 10px 0 0}.pp_nav p{float:left;margin:2px 4px}.pp_nav .pp_play,.pp_nav .pp_pause{float:left;margin-right:4px;text-indent:-10000px}a.pp_arrow_previous,a.pp_arrow_next{display:block;float:left;height:15px;margin-top:3px;overflow:hidden;text-indent:-10000px;width:14px}.pp_hoverContainer{position:absolute;top:0;width:100%;z-index:2000}.pp_gallery{display:none;left:50%;margin-top:-50px;position:absolute;z-index:10000}.pp_gallery div{float:left;overflow:hidden;position:relative}.pp_gallery ul{float:left;height:35px;position:relative;white-space:nowrap;margin:0 0 0 5px;padding:0}.pp_gallery ul a{border:1px rgba(0,0,0,0.5) solid;display:block;float:left;height:33px;overflow:hidden}.pp_gallery ul a img{border:0}.pp_gallery li{display:block;float:left;margin:0 5px 0 0;padding:0}.pp_gallery li.default a{background:url(/common/img/prettyPhoto/facebook/default_thumbnail.gif) 0 0 no-repeat;display:block;height:33px;width:50px}.pp_gallery .pp_arrow_previous,.pp_gallery .pp_arrow_next{margin-top:7px!important}a.pp_next{background:url(/common/img/prettyPhoto/light_rounded/btnNext.png) 10000px 10000px no-repeat;display:block;float:right;height:100%;text-indent:-10000px;width:49%}a.pp_previous{background:url(/common/img/prettyPhoto/light_rounded/btnNext.png) 10000px 10000px no-repeat;display:block;float:left;height:100%;text-indent:-10000px;width:49%}a.pp_expand,a.pp_contract{cursor:pointer;display:none;height:20px;position:absolute;right:30px;text-indent:-10000px;top:10px;width:20px;z-index:20000}a.pp_close{position:absolute;right:0;top:0;display:block;line-height:22px;text-indent:-10000px}.pp_loaderIcon{display:block;height:24px;left:50%;position:absolute;top:50%;width:24px;margin:-12px 0 0 -12px}#pp_full_res{line-height:1!important}#pp_full_res .pp_inline{text-align:left}#pp_full_res .pp_inline p{margin:0 0 15px}div.ppt{color:#fff;display:none;font-size:17px;z-index:9999;margin:0 0 5px 15px}div.pp_default .pp_content,div.light_rounded .pp_content{background-color:#fff}div.pp_default #pp_full_res .pp_inline,div.light_rounded .pp_content .ppt,div.light_rounded #pp_full_res .pp_inline,div.light_square .pp_content .ppt,div.light_square #pp_full_res .pp_inline,div.facebook .pp_content .ppt,div.facebook #pp_full_res .pp_inline{color:#000}div.pp_default .pp_gallery ul li a:hover,div.pp_default .pp_gallery ul li.selected a,.pp_gallery ul a:hover,.pp_gallery li.selected a{border-color:#fff}div.pp_default .pp_details,div.light_rounded .pp_details,div.dark_rounded .pp_details,div.dark_square .pp_details,div.light_square .pp_details,div.facebook .pp_details{position:relative}div.light_rounded .pp_top .pp_middle,div.light_rounded .pp_content_container .pp_left,div.light_rounded .pp_content_container .pp_right,div.light_rounded .pp_bottom .pp_middle,div.light_square .pp_left,div.light_square .pp_middle,div.light_square .pp_right,div.light_square .pp_content,div.facebook .pp_content{background:#fff}div.light_rounded .pp_description,div.light_square .pp_description{margin-right:85px}div.light_rounded .pp_gallery a.pp_arrow_previous,div.light_rounded .pp_gallery a.pp_arrow_next,div.dark_rounded .pp_gallery a.pp_arrow_previous,div.dark_rounded .pp_gallery a.pp_arrow_next,div.dark_square .pp_gallery a.pp_arrow_previous,div.dark_square .pp_gallery a.pp_arrow_next,div.light_square .pp_gallery a.pp_arrow_previous,div.light_square .pp_gallery a.pp_arrow_next{margin-top:12px!important}div.light_rounded .pp_arrow_previous.disabled,div.dark_rounded .pp_arrow_previous.disabled,div.dark_square .pp_arrow_previous.disabled,div.light_square .pp_arrow_previous.disabled{background-position:0 -87px;cursor:default}div.light_rounded .pp_arrow_next.disabled,div.dark_rounded .pp_arrow_next.disabled,div.dark_square .pp_arrow_next.disabled,div.light_square .pp_arrow_next.disabled{background-position:-22px -87px;cursor:default}div.light_rounded .pp_loaderIcon,div.light_square .pp_loaderIcon{background:url(/common/img/prettyPhoto/light_rounded/loader.gif) center center no-repeat}div.dark_rounded .pp_top .pp_middle,div.dark_rounded .pp_content,div.dark_rounded .pp_bottom .pp_middle{background:url(/common/img/prettyPhoto/dark_rounded/contentPattern.png) top left repeat}div.dark_rounded .currentTextHolder,div.dark_square .currentTextHolder{color:#c4c4c4}div.dark_rounded #pp_full_res .pp_inline,div.dark_square #pp_full_res .pp_inline{color:#fff}.pp_top,.pp_bottom{height:20px;position:relative}* html .pp_top,* html .pp_bottom{padding:0 20px}.pp_top .pp_left,.pp_bottom .pp_left{height:20px;left:0;position:absolute;width:20px}.pp_top .pp_middle,.pp_bottom .pp_middle{height:20px;left:20px;position:absolute;right:20px}* html .pp_top .pp_middle,* html .pp_bottom .pp_middle{left:0;position:static}.pp_top .pp_right,.pp_bottom .pp_right{height:20px;left:auto;position:absolute;right:0;top:0;width:20px}.pp_fade,.pp_gallery li.default a img{display:none}
+
+.pp_suse .pp_content{ background:none !important; }
+.pp_suse div.ppt{ height:0; margin:0; display:none !important; }
+.pp_suse div.ppt_custom{ display:none; background:#fff; width:300px !important; padding:40px 0 0 28px; font-size:21px; margin:0; z-index:9999; color:#439539; position:relative; font-family:"omnes-pro-1", Arial, sans-serif; }
+.pp_suse a.pp_close{ top:19px; right:28px; background-image:url(/common/img/x.gif); width:10px; height:10px; background-position:0px 0px; }
+#suse_overlay_iframe{ overflow:hidden; }
+.pp_margin{ top:150px !important; }
+
+
+/**
+ * qtip
+ */
+
+.ui-tooltip,.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:14px;line-height:12px;z-index:15000;}.ui-tooltip-fluid{display:block;visibility:hidden;position:static!important;float:left!important;}.ui-tooltip-content{position:relative;padding:12px 12px 9px 12px;overflow:hidden;border-width:1px;border-style:solid;text-align:left;word-wrap:break-word;overflow:hidden;}.ui-tooltip-titlebar{position:relative;min-height:14px;padding:5px 35px 5px 10px;overflow:hidden;border-width:1px 1px 0;border-style:solid;font-weight:bold;}.ui-tooltip-titlebar+.ui-tooltip-content{border-top-width:0!important;}/*!Default close button class */ .ui-tooltip-titlebar .ui-state-default{position:absolute;right:4px;top:50%;margin-top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;}* html .ui-tooltip-titlebar .ui-state-default{top:16px;}.ui-tooltip-titlebar .ui-icon,.ui-tooltip-icon .ui-icon{display:block;text-indent:-1000em;}.ui-tooltip-icon,.ui-tooltip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}.ui-tooltip-icon .ui-icon{width:18px;height:14px;text-align:center;text-indent:0;font:normal bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em;}/*!Default tooltip style */ .ui-tooltip-default .ui-tooltip-titlebar,.ui-tooltip-default .ui-tooltip-content{border-color:#F1D031;background-color:#FFFFA3;color:#333;}.ui-tooltip-default .ui-tooltip-titlebar{background-color:#FFEF93;}.ui-tooltip-default .ui-tooltip-icon{border-color:#CCC;background:#F1F1F1;color:#777;}.ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover{border-color:#AAA;color:#111;}.ui-tooltip .ui-tooltip-tip{margin:0 auto;overflow:hidden;background:transparent!important;border:0 dashed transparent!important;z-index:10;}.ui-tooltip .ui-tooltip-tip,.ui-tooltip .ui-tooltip-tip *{position:absolute;line-height:.1px!important;font-size:.1px!important;color:#123456;background:transparent;border:0 dashed transparent;}.ui-tooltip .ui-tooltip-tip canvas{top:0;left:0;}/*!Light tooltip style */ .ui-tooltip-light .ui-tooltip-titlebar,.ui-tooltip-light .ui-tooltip-content{border-color:#E2E2E2;color:#454545;}.ui-tooltip-light .ui-tooltip-content{background-color:white;}.ui-tooltip-light .ui-tooltip-titlebar{background-color:#f1f1f1;}/*!Dark tooltip style */ .ui-tooltip-dark .ui-tooltip-titlebar,.ui-tooltip-dark .ui-tooltip-content{border-color:#303030;color:#f3f3f3;}.ui-tooltip-dark .ui-tooltip-content{background-color:#505050;}.ui-tooltip-dark .ui-tooltip-titlebar{background-color:#404040;}.ui-tooltip-dark .ui-tooltip-icon{border-color:#444;}.ui-tooltip-dark .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}/*!Cream tooltip style */ .ui-tooltip-cream .ui-tooltip-titlebar,.ui-tooltip-cream .ui-tooltip-content{border-color:#F9E98E;color:#A27D35;}.ui-tooltip-cream .ui-tooltip-content{background-color:#FBF7AA;}.ui-tooltip-cream .ui-tooltip-titlebar{background-color:#F0DE7D;}.ui-tooltip-cream .ui-state-default .ui-tooltip-icon{background-position:-82px 0;}/*!Red tooltip style */ .ui-tooltip-red .ui-tooltip-titlebar,.ui-tooltip-red .ui-tooltip-content{border-color:#D95252;color:#912323;}.ui-tooltip-red .ui-tooltip-content{background-color:#F78B83;}.ui-tooltip-red .ui-tooltip-titlebar{background-color:#F06D65;}.ui-tooltip-red .ui-state-default .ui-tooltip-icon{background-position:-102px 0;}.ui-tooltip-red .ui-tooltip-icon{border-color:#D95252;}.ui-tooltip-red .ui-tooltip-titlebar .ui-state-hover{border-color:#D95252;}/*!Green tooltip style */ .ui-tooltip-green .ui-tooltip-titlebar,.ui-tooltip-green .ui-tooltip-content{border-color:#D7FB60;color:#3F6219;}.ui-tooltip-green .ui-tooltip-content{background-color:#D7FB60;}.ui-tooltip-green .ui-tooltip-titlebar{background-color:#B0DE78;}.ui-tooltip-green .ui-state-default .ui-tooltip-icon{background-position:-42px 0;}/*!Blue tooltip style */ .ui-tooltip-blue .ui-tooltip-titlebar,.ui-tooltip-blue .ui-tooltip-content{border-color:#ADD9ED;color:#5E99BD;}.ui-tooltip-blue .ui-tooltip-content{background-color:#E5F6FE;}.ui-tooltip-blue .ui-tooltip-titlebar{background-color:#D0E9F5;}.ui-tooltip-blue .ui-state-default .ui-tooltip-icon{background-position:-2px 0;}/*!Add shadows to your tooltips in:FF3+,Chrome 2+,Opera 10.6+,IE6+,Safari 2+*/ .ui-tooltip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);}.ui-tooltip-shadow .ui-tooltip-titlebar,.ui-tooltip-shadow .ui-tooltip-content{filter:progid:DXImageTransform.Microsoft.Shadow(Color='gray',Direction=135,Strength=3);-ms-filter:"progid:DXImageTransform.Microsoft.Shadow(Color='gray',Direction=135,Strength=3)";_margin-bottom:-3px;.margin-bottom:-3px;}/*!Add rounded corners to your tooltips in:FF3+,Chrome 2+,Opera 10.6+,IE9+,Safari 2+*/ .ui-tooltip-rounded,.ui-tooltip-rounded .ui-tooltip-content,.ui-tooltip-tipsy,.ui-tooltip-tipsy .ui-tooltip-content,.ui-tooltip-youtube,.ui-tooltip-youtube .ui-tooltip-content{-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;}.ui-tooltip-rounded .ui-tooltip-titlebar,.ui-tooltip-tipsy .ui-tooltip-titlebar,.ui-tooltip-youtube .ui-tooltip-titlebar{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.ui-tooltip-rounded .ui-tooltip-titlebar+.ui-tooltip-content,.ui-tooltip-tipsy .ui-tooltip-titlebar+.ui-tooltip-content,.ui-tooltip-youtube .ui-tooltip-titlebar+.ui-tooltip-content{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;}/*!Youtube tooltip style */ .ui-tooltip-youtube{-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;}.ui-tooltip-youtube .ui-tooltip-titlebar,.ui-tooltip-youtube .ui-tooltip-content{_margin-bottom:0;.margin-bottom:0;background:transparent;background:rgba(0,0,0,0.85);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)";color:white;border-color:#CCC;}.ui-tooltip-youtube .ui-tooltip-icon{border-color:#222;}.ui-tooltip-youtube .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}.ui-tooltip-jtools{background:#232323;background:rgba(0,0,0,0.7);background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333;}.ui-tooltip-jtools .ui-tooltip-titlebar{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)";}.ui-tooltip-jtools .ui-tooltip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)";}.ui-tooltip-jtools .ui-tooltip-titlebar,.ui-tooltip-jtools .ui-tooltip-content{background:transparent;color:white;border:0 dashed transparent;}.ui-tooltip-jtools .ui-tooltip-icon{border-color:#555;}.ui-tooltip-jtools .ui-tooltip-titlebar .ui-state-hover{border-color:#333;}.ui-tooltip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,0.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,0.4);box-shadow:4px 4px 5px rgba(0,0,0,0.4);}.ui-tooltip-cluetip .ui-tooltip-titlebar{background-color:#87876A;color:white;border:0 dashed transparent;}.ui-tooltip-cluetip .ui-tooltip-content{background-color:#D9D9C2;color:#111;border:0 dashed transparent;}.ui-tooltip-cluetip .ui-tooltip-icon{border-color:#808064;}.ui-tooltip-cluetip .ui-tooltip-titlebar .ui-state-hover{border-color:#696952;color:#696952;}.ui-tooltip-tipsy{border:0;}.ui-tooltip-tipsy .ui-tooltip-titlebar,.ui-tooltip-tipsy .ui-tooltip-content{_margin-bottom:0;.margin-bottom:0;background:transparent;background:rgba(0,0,0,.87);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)";color:white;border:0 transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:bold;line-height:16px;text-shadow:0 1px black;}.ui-tooltip-tipsy .ui-tooltip-titlebar{padding:6px 35px 0 10;}.ui-tooltip-tipsy .ui-tooltip-content{padding:6px 10;}.ui-tooltip-tipsy .ui-tooltip-icon{border-color:#222;text-shadow:none;}.ui-tooltip-tipsy .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}.ui-tooltip-tipped .ui-tooltip-titlebar,.ui-tooltip-tipped .ui-tooltip-content{border:3px solid #959FA9;filter:none;-ms-filter:none;}.ui-tooltip-tipped .ui-tooltip-titlebar{background:#3A79B8;background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)";color:white;font-weight:normal;font-family:serif;border-bottom-width:0;-moz-border-radius:3px 3px 0 0;-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}.ui-tooltip-tipped .ui-tooltip-content{background-color:#F9F9F9;color:#454545;-moz-border-radius:0 0 3px 3px;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.ui-tooltip-tipped .ui-tooltip-icon{border:2px solid #285589;background:#285589;}.ui-tooltip-tipped .ui-tooltip-icon .ui-icon{background-color:#FBFBFB;color:#555;}.ui-tooltip:not(.ie9haxors) div.ui-tooltip-content,.ui-tooltip:not(.ie9haxors) div.ui-tooltip-titlebar{filter:none;-ms-filter:none;}
+
+/**
+ * jScrollPayne
+ */
+
+.jScrollPaneContainer {
+ position: relative;
+ overflow: hidden;
+ z-index: 1;
+}
+
+.jScrollPaneTrack {
+ position: absolute;
+ cursor: pointer;
+ right: 0;
+ top: 0;
+ height: 100%;
+ background: #aaa;
+}
+.jScrollPaneDrag {
+ position: absolute;
+ background: #666;
+ cursor: pointer;
+ overflow: hidden;
+}
+.jScrollPaneDragTop {
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+}
+.jScrollPaneDragBottom {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ overflow: hidden;
+}
+a.jScrollArrowUp {
+ display: block;
+ position: absolute;
+ z-index: 1;
+ top: 0;
+ right: 0;
+ text-indent: -2000px;
+ overflow: hidden;
+ /*background-color: #666;*/
+ height: 9px;
+}
+a.jScrollArrowUp:hover {
+ /*background-color: #f60;*/
+}
+
+a.jScrollArrowDown {
+ display: block;
+ position: absolute;
+ z-index: 1;
+ bottom: 0;
+ right: 0;
+ text-indent: -2000px;
+ overflow: hidden;
+ /*background-color: #666;*/
+ height: 9px;
+}
+a.jScrollArrowDown:hover {
+ /*background-color: #f60;*/
+}
+a.jScrollActiveArrowButton, a.jScrollActiveArrowButton:hover {
+ /*background-color: #f00;*/
+} \ No newline at end of file
diff --git a/tests2/files/x.css b/tests2/files/x.css
new file mode 100644
index 00000000..b744f4ce
--- /dev/null
+++ b/tests2/files/x.css
@@ -0,0 +1,13 @@
+@IMPORT "http://example.com"
+
+@media print {
+ * {
+ background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important
+;
+ -ms-filter: none !important;
+ } /* Black prints faster: sanbeiji.com/archives/953 */
+header #search{ width:138px; height:25px; background:url(/common/img/search.png) top left no-repeat; position:absolute; top:12px; right:20px; }
+ background:url( '/common/img/search.png' );
+ background:url( '//example.com/common/img/search.png' );
+ background:url("/common/img/search.png");
+}
diff --git a/tests2/libtest.c b/tests2/libtest.c
new file mode 100644
index 00000000..a775732c
--- /dev/null
+++ b/tests2/libtest.c
@@ -0,0 +1,850 @@
+/*
+ * Copyright(c) 2013-2014 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Test suite function library
+ *
+ * Changelog
+ * 16.01.2013 Tim Ruehsen created
+ *
+ * To create the X.509 stuff, I followed the instructions at
+ * gnutls.org/manual/html_node/gnutls_002dserv-Invocation.html
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <utime.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <libwget.h>
+
+#include "libtest.h"
+
+static wget_thread_t
+ http_server_tid,
+ https_server_tid,
+ ftp_server_tid,
+ ftps_server_tid;
+static int
+ http_server_port,
+ https_server_port,
+ ftp_server_port,
+ ftps_server_port,
+ ftps_implicit,
+ terminate,
+ keep_tmpfiles;
+/*static const char
+ *response_code = "200 Dontcare",
+ *response_body = "";
+static WGET_VECTOR
+ *response_headers; */
+static wget_vector_t
+ *request_urls;
+static wget_test_url_t
+ *urls;
+static size_t
+ nurls;
+static wget_test_ftp_io_t
+ *ios;
+static size_t
+ nios;
+static int
+ ios_ordered;
+static char
+ tmpdir[128];
+static const char
+ *server_hello;
+
+static void sigterm_handler(int sig G_GNUC_WGET_UNUSED)
+{
+ terminate = 1;
+}
+
+static void *_http_server_thread(void *ctx)
+{
+ wget_tcp_t *tcp=NULL, *parent_tcp = ctx;
+ wget_test_url_t *url = NULL;
+ char buf[4096], method[32], request_url[256], tag[64], value[256], *p;
+ ssize_t nbytes, from_bytes, to_bytes;
+ size_t body_len, request_url_length;
+ unsigned it;
+ int byterange, authorized;
+ time_t modified;
+
+#if defined(_WIN32) || defined(_WIN64)
+ signal(SIGTERM, sigterm_handler);
+#else
+ sigaction(SIGTERM, &(struct sigaction) { .sa_handler = sigterm_handler }, NULL);
+#endif
+
+ while (!terminate) {
+ wget_tcp_deinit(&tcp);
+
+ if ((tcp = wget_tcp_accept(parent_tcp))) {
+ authorized = 0;
+
+ // as a quick hack, just assume that request comes in one packet
+ if ((nbytes = wget_tcp_read(tcp, buf, sizeof(buf)-1)) > 0) {
+ buf[nbytes]=0;
+ if (sscanf(buf, "%31s %255s", method, request_url) !=2) {
+ wget_tcp_printf(tcp, "HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
+ continue;
+ }
+
+ byterange = from_bytes = to_bytes = 0;
+ modified = 0;
+
+ for (p = strstr(buf, "\r\n"); sscanf(p, "\r\n%63[^:]: %255[^\r]", tag, value) == 2; p = strstr(p + 2, "\r\n")) {
+ if (!wget_strcasecmp_ascii(tag, "Range")) {
+ if ((byterange = sscanf(value, "bytes=%zd-%zd", &from_bytes, &to_bytes)) < 1)
+ byterange = 0;
+ }
+ else if (url && !wget_strcasecmp_ascii(tag, "Authorization")) {
+ const char *auth_scheme, *s;
+
+ s=wget_http_parse_token(value, &auth_scheme);
+ while (isblank(*s)) s++;
+
+ if (!wget_strcasecmp_ascii(auth_scheme, "basic")) {
+ const char *encoded = wget_base64_encode_printf_alloc("%s:%s", url->auth_username, url->auth_password);
+
+ wget_error_printf("Auth check '%s' <-> '%s'\n", encoded, s);
+ if (!strcmp(encoded, s))
+ authorized = 1;
+
+ wget_xfree(encoded);
+ }
+
+ wget_xfree(auth_scheme);
+ }
+ else if (!wget_strcasecmp_ascii(tag, "If-Modified-Since")) {
+ modified = wget_http_parse_full_date(value);
+ wget_info_printf("modified = %ld\n", modified);
+ }
+ }
+
+ url = NULL;
+ request_url_length = strlen(request_url);
+
+ if (request_url[request_url_length - 1] == '/') {
+ // access a directory
+ for (it = 0; it < nurls; it++) {
+ if (!strcmp(request_url, urls[it].name) ||
+ (!strncmp(request_url, urls[it].name, request_url_length) &&
+ !strcmp(urls[it].name + request_url_length, "index.html")))
+ {
+ url = &urls[it];
+ break;
+ }
+ }
+ } else {
+ // access a file
+ for (it = 0; it < nurls; it++) {
+ // printf("%s %s\n", request_url, urls[it].name);
+ if (!strcmp(request_url, urls[it].name)) {
+ url = &urls[it];
+ break;
+ }
+ }
+ }
+
+ if (!url) {
+ wget_tcp_printf(tcp, "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n");
+ continue;
+ }
+
+ if (url->auth_method && !authorized) {
+ if (!wget_strcasecmp_ascii(url->auth_method, "basic"))
+ wget_tcp_printf(tcp,
+ "HTTP/1.1 401 Unauthorized\r\n" \
+ "WWW-Authenticate: %s realm=\"Protected Page\"\r\n" \
+ "Connection: close\r\n\r\n",
+ url->auth_method);
+ else
+ wget_error_printf(_("Unknown authentication scheme '%s'\n"), url->auth_method);
+
+ continue;
+ }
+
+ if (modified && url->modified<=modified) {
+ wget_tcp_printf(tcp,"HTTP/1.1 304 Not Modified\r\n\r\n");
+ continue;
+ }
+
+ if (byterange == 1) {
+ to_bytes = strlen(url->body) - 1;
+ }
+ if (byterange) {
+ if (from_bytes > to_bytes || from_bytes >= (int)strlen(url->body)) {
+ wget_tcp_printf(tcp, "HTTP/1.1 416 Range Not Satisfiable\r\nConnection: close\r\n\r\n");
+ continue;
+ }
+
+ // create response
+ body_len = to_bytes - from_bytes + 1;
+ nbytes = snprintf(buf, sizeof(buf),
+ "HTTP/1.1 206 Partial Content\r\n"\
+ "Content-Length: %zu\r\n"\
+ "Accept-Ranges: bytes\r\n"\
+ "Content-Range: %zd-%zd/%zu\r\n",
+ body_len, from_bytes, to_bytes, body_len);
+ for (it = 0; it < countof(url->headers) && url->headers[it]; it++) {
+ nbytes += snprintf(buf + nbytes, sizeof(buf) - nbytes, "%s\r\n", url->headers[it]);
+ }
+ nbytes += snprintf(buf + nbytes, sizeof(buf) - nbytes, "\r\n");
+ if (!strcmp(method, "GET") || !strcmp(method, "POST"))
+ nbytes += snprintf(buf + nbytes, sizeof(buf) - nbytes, "%.*s", (int)body_len, url->body + from_bytes);
+ } else {
+ // create response
+ body_len = strlen(url->body ? url->body : "");
+ nbytes = snprintf(buf, sizeof(buf),
+ "HTTP/1.1 %s\r\n"\
+ "Content-Length: %zu\r\n",
+ url->code ? url->code : "200 OK\r\n", body_len);
+ for (it = 0; it < countof(url->headers) && url->headers[it]; it++) {
+ nbytes += snprintf(buf + nbytes, sizeof(buf) - nbytes, "%s\r\n", url->headers[it]);
+ }
+ nbytes += snprintf(buf + nbytes, sizeof(buf) - nbytes, "\r\n");
+ if (!strcmp(method, "GET") || !strcmp(method, "POST"))
+ nbytes += snprintf(buf + nbytes, sizeof(buf) - nbytes, "%s", url->body ? url->body : "");
+ }
+
+ // send response
+ wget_tcp_write(tcp, buf, nbytes);
+ }
+ } else if (!terminate)
+ wget_error_printf(_("Failed to get connection (%d)\n"), errno);
+ }
+
+ wget_tcp_deinit(&parent_tcp);
+
+ return NULL;
+}
+
+static void *_ftp_server_thread(void *ctx)
+{
+ wget_tcp_t *tcp = NULL, *parent_tcp = ctx, *pasv_parent_tcp = NULL, *pasv_tcp = NULL;
+ char buf[4096];
+ ssize_t nbytes;
+ int pasv_port, found;
+ unsigned io_pos;
+
+#if defined(_WIN32) || defined(_WIN64)
+ signal(SIGTERM, sigterm_handler);
+#else
+ sigaction(SIGTERM, &(struct sigaction) { .sa_handler = sigterm_handler }, NULL);
+#endif
+
+ while (!terminate) {
+ wget_tcp_deinit(&tcp);
+ wget_tcp_deinit(&pasv_tcp);
+ wget_tcp_deinit(&pasv_parent_tcp);
+
+ if ((tcp = wget_tcp_accept(parent_tcp))) {
+ io_pos = 0;
+
+ if (server_hello)
+ wget_tcp_printf(tcp, "%s\r\n", server_hello);
+
+ // as a quick hack, just assume that each line comes in one packet
+ while ((nbytes = wget_tcp_read(tcp, buf, sizeof(buf)-1)) > 0) {
+ buf[nbytes] = 0;
+
+ while (--nbytes >= 0 && (buf[nbytes] == '\r' || buf[nbytes] == '\n'))
+ buf[nbytes] = 0;
+
+ wget_debug_printf("### Got: '%s'\n", buf);
+
+ found = 0;
+ if (ios_ordered) {
+ if (!strcmp(buf, ios[io_pos].in))
+ found = 1;
+ } else {
+ for (io_pos = 0; io_pos < nios; io_pos++) {
+ if (!strcmp(buf, ios[io_pos].in)) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ wget_error_printf(_("Unexpected input: '%s'\n"), buf);
+ wget_tcp_printf(tcp, "500 Unknown command\r\n");
+ continue;
+ }
+
+ if (!strncmp(buf, "AUTH", 4)) {
+ // assume TLS auth type
+ wget_tcp_printf(tcp, "%s\r\n", ios[io_pos].out);
+ if (atoi(ios[io_pos].out)/100 == 2)
+ wget_tcp_tls_start(tcp);
+ io_pos++;
+ continue;
+ }
+
+ if (!strncmp(buf, "PASV", 4) || !strncmp(buf, "EPSV", 4)) {
+ // init FTP PASV/EPSV socket
+ // we ignore EPSV address type here, we listen on IPv4 and IPv6 anyways
+ pasv_parent_tcp=wget_tcp_init();
+ wget_tcp_set_timeout(pasv_parent_tcp, -1); // INFINITE timeout
+ if (!strncmp(buf, "EPSV", 4)) {
+ switch (atoi(buf+4)) {
+ case 1: wget_tcp_set_family(pasv_parent_tcp, WGET_NET_FAMILY_IPV4); break;
+ case 2: wget_tcp_set_family(pasv_parent_tcp, WGET_NET_FAMILY_IPV6); break;
+ default: wget_tcp_set_family(pasv_parent_tcp, WGET_NET_FAMILY_ANY); break;
+ }
+ }
+ if (wget_tcp_listen(pasv_parent_tcp, "localhost", NULL, 5) != 0) {
+ wget_tcp_printf(tcp, "500 failed to open port\r\n");
+ break;
+ }
+ pasv_port = wget_tcp_get_local_port(pasv_parent_tcp);
+
+ const char *src = ios[io_pos].out;
+ char *response = wget_malloc(strlen(src) + 32 + 1);
+ char *dst = response;
+
+ while (*src) {
+ if (*src == '{') {
+ if (!strncmp(src, "{{pasvdata}}", 12)) {
+ if (!strncmp(buf, "EPSV", 4))
+ dst += sprintf(dst, "(|||%d|)", pasv_port);
+ else
+ dst += sprintf(dst, "(127,0,0,1,%d,%d)", pasv_port / 256, pasv_port % 256);
+ src += 12;
+ continue;
+ }
+ }
+ *dst++ = *src++;
+ }
+ *dst = 0;
+
+ wget_tcp_printf(tcp, "%s\r\n", response);
+ wget_xfree(response);
+
+ if (!(pasv_tcp = wget_tcp_accept(pasv_parent_tcp))) {
+ wget_error_printf(_("Failed to get PASV connection\n"));
+ break;
+ }
+ } else {
+ wget_tcp_printf(tcp, "%s\r\n", ios[io_pos].out);
+ }
+
+ if (ios[io_pos].send_url && pasv_tcp) {
+ // send data
+ wget_tcp_printf(pasv_tcp, "%s", ios[io_pos].send_url->body);
+ wget_tcp_deinit(&pasv_tcp);
+ wget_tcp_printf(tcp, "226 Transfer complete\r\n");
+ }
+
+ io_pos++;
+ }
+ } else if (!terminate)
+ wget_error_printf(_("Failed to get connection (%d)\n"), errno);
+ }
+
+ wget_tcp_deinit(&parent_tcp);
+
+ return NULL;
+}
+
+// To reduce the verbosity of 'valgrind --trace-children=yes' output,
+// we avoid system("rm -rf ...") calls.
+static void _remove_directory(const char *dirname);
+static void _empty_directory(const char *dirname)
+{
+ DIR *dir;
+ struct dirent *dp;
+ size_t dirlen = strlen(dirname);
+
+ if ((dir = opendir(dirname))) {
+ while ((dp = readdir(dir))) {
+ if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1] == '.' && dp->d_name[2] == 0)))
+ continue;
+
+ char fname[dirlen + 1 + strlen(dp->d_name) + 1];
+ snprintf(fname, sizeof(fname), "%s/%s", dirname, dp->d_name);
+
+ if (unlink(fname) == -1) {
+ if (errno == EISDIR)
+ _remove_directory(fname);
+ else
+ wget_error_printf(_("Failed to unlink %s (%d)\n"), fname, errno);
+ }
+ }
+
+ closedir(dir);
+ } else
+ wget_error_printf(_("Failed to opendir %s\n"), dirname);
+}
+
+static void _remove_directory(const char *dirname)
+{
+ _empty_directory(dirname);
+ if (rmdir(dirname) == -1)
+ wget_error_printf(_("Failed to rmdir %s\n"), dirname);
+}
+
+void wget_test_stop_server(void)
+{
+ size_t it;
+
+// wget_vector_free(&response_headers);
+ wget_vector_free(&request_urls);
+
+ for (it = 0; it < nurls; it++) {
+ if (urls[it].body_alloc) {
+ wget_xfree(urls[it].body);
+ urls[it].body_alloc = 0;
+ }
+ }
+
+ if (chdir("..") != 0)
+ wget_error_printf(_("Failed to chdir ..\n"));
+
+ if (!keep_tmpfiles)
+ _remove_directory(tmpdir);
+
+ // free resources - needed for valgrind testing
+ pthread_kill(http_server_tid, SIGTERM);
+ pthread_kill(https_server_tid, SIGTERM);
+ pthread_kill(ftp_server_tid, SIGTERM);
+ if (ftps_implicit)
+ pthread_kill(ftps_server_tid, SIGTERM);
+
+ wget_thread_join(http_server_tid);
+ wget_thread_join(https_server_tid);
+ wget_thread_join(ftp_server_tid);
+ if (ftps_implicit)
+ wget_thread_join(ftps_server_tid);
+
+ wget_global_deinit();
+}
+
+void wget_test_start_server(int first_key, ...)
+{
+ static wget_tcp_t *http_parent_tcp, *https_parent_tcp, *ftp_parent_tcp, *ftps_parent_tcp;
+ int rc, key;
+ size_t it;
+ va_list args;
+
+ wget_global_init(
+ WGET_DEBUG_STREAM, stderr,
+ WGET_ERROR_STREAM, stderr,
+// WGET_INFO_STREAM, stdout,
+ NULL);
+
+ va_start(args, first_key);
+ for (key = first_key; key; key = va_arg(args, int)) {
+ switch (key) {
+/* case WGET_TEST_RESPONSE_BODY:
+ response_body = va_arg(args, const char *);
+ break;
+ case WGET_TEST_RESPONSE_HEADER:
+ if (!response_headers)
+ response_headers = wget_vector_create(4,4,NULL);
+ wget_vector_add_str(response_headers, va_arg(args, const char *));
+ break;
+ case WGET_TEST_RESPONSE_CODE:
+ response_code = va_arg(args, const char *);
+ break;
+*/ case WGET_TEST_EXPECTED_REQUEST_HEADER:
+ break;
+ case WGET_TEST_RESPONSE_URLS:
+ urls = va_arg(args, wget_test_url_t *);
+ nurls = va_arg(args, size_t);
+ break;
+ case WGET_TEST_FTP_SERVER_HELLO:
+ server_hello = va_arg(args, const char *);
+ case WGET_TEST_FTP_IO_ORDERED:
+ ios_ordered = 1;
+ ios = va_arg(args, wget_test_ftp_io_t *);
+ nios = va_arg(args, size_t);
+ case WGET_TEST_FTP_IO_UNORDERED:
+ ios_ordered = 0;
+ ios = va_arg(args, wget_test_ftp_io_t *);
+ nios = va_arg(args, size_t);
+ break;
+ case WGET_TEST_FTPS_IMPLICIT:
+ ftps_implicit = va_arg(args, int);
+ break;
+ default:
+ wget_error_printf(_("Unknown option %d\n"), key);
+ }
+ }
+ va_end(args);
+
+ atexit(wget_test_stop_server);
+
+ snprintf(tmpdir, sizeof(tmpdir), ".test_%d", (int) getpid());
+
+#if defined(_WIN32) || defined(_WIN64)
+ if (mkdir(tmpdir) != 0)
+#else
+ if (mkdir(tmpdir, 0755) != 0)
+#endif
+ wget_error_printf_exit(_("Failed to create tmpdir (%d)\n"), errno);
+
+ if (chdir(tmpdir) != 0)
+ wget_error_printf_exit(_("Failed to change to tmpdir (%d)\n"), errno);
+
+ // init server SSL layer (default cert and key file types are PEM)
+ // SRCDIR is the (relative) path to the tests dir. Since we chdir()'ed into a subdirectory, we need "../"
+ wget_ssl_set_config_string(WGET_SSL_CA_FILE, "../" SRCDIR "/certs/x509-ca-cert.pem");
+ wget_ssl_set_config_string(WGET_SSL_CERT_FILE, "../" SRCDIR "/certs/x509-server-cert.pem");
+ wget_ssl_set_config_string(WGET_SSL_KEY_FILE, "../" SRCDIR "/certs/x509-server-key.pem");
+
+ // init HTTP server socket
+ http_parent_tcp=wget_tcp_init();
+ wget_tcp_set_timeout(http_parent_tcp, -1); // INFINITE timeout
+ if (wget_tcp_listen(http_parent_tcp, "localhost", NULL, 5) != 0)
+ exit(1);
+ http_server_port = wget_tcp_get_local_port(http_parent_tcp);
+
+ // init HTTPS server socket
+ https_parent_tcp=wget_tcp_init();
+ wget_tcp_set_ssl(https_parent_tcp, 1); // switch SSL on
+ wget_tcp_set_timeout(https_parent_tcp, -1); // INFINITE timeout
+ if (wget_tcp_listen(https_parent_tcp, "localhost", NULL, 5) != 0)
+ exit(1);
+ https_server_port = wget_tcp_get_local_port(https_parent_tcp);
+
+ // init FTP server socket
+ ftp_parent_tcp=wget_tcp_init();
+ wget_tcp_set_timeout(ftp_parent_tcp, -1); // INFINITE timeout
+ if (wget_tcp_listen(ftp_parent_tcp, "localhost", NULL, 5) != 0)
+ exit(1);
+ ftp_server_port = wget_tcp_get_local_port(ftp_parent_tcp);
+
+ // init FTPS server socket
+ ftps_parent_tcp=wget_tcp_init();
+ wget_tcp_set_ssl(ftps_parent_tcp, 1); // switch SSL on
+ wget_tcp_set_timeout(ftps_parent_tcp, -1); // INFINITE timeout
+ if (wget_tcp_listen(ftps_parent_tcp, "localhost", NULL, 5) != 0)
+ exit(1);
+ ftps_server_port = wget_tcp_get_local_port(ftps_parent_tcp);
+
+ // now replace {{port}} in the body by the actual server port
+ for (it = 0; it < nurls; it++) {
+ if (urls[it].body && (strstr(urls[it].body, "{{port}}") || strstr(urls[it].body, "{{sslport}}")
+ || strstr(urls[it].body, "{{ftpport}}") || strstr(urls[it].body, "{{ftpsport}}")))
+ {
+ const char *src = urls[it].body;
+ char *dst = wget_malloc(strlen(src) + 1);
+
+ urls[it].body = dst;
+ urls[it].body_alloc = 1;
+
+ while (*src) {
+ if (*src == '{') {
+ if (!strncmp(src, "{{port}}", 8)) {
+ dst += sprintf(dst, "%d", http_server_port);
+ src += 8;
+ continue;
+ }
+ else if (!strncmp(src, "{{sslport}}", 11)) {
+ dst += sprintf(dst, "%d", https_server_port);
+ src += 11;
+ continue;
+ }
+ else if (!strncmp(src, "{{ftpport}}", 11)) {
+ dst += sprintf(dst, "%d", ftp_server_port);
+ src += 11;
+ continue;
+ }
+ else if (!strncmp(src, "{{ftpsport}}", 12)) {
+ dst += sprintf(dst, "%d", ftps_server_port);
+ src += 12;
+ continue;
+ }
+ }
+ *dst++ = *src++;
+ }
+ *dst = 0;
+ }
+ }
+
+ // start thread for HTTP
+ if ((rc = wget_thread_start(&http_server_tid, _http_server_thread, http_parent_tcp, 0)) != 0)
+ wget_error_printf_exit(_("Failed to start HTTP server, error %d\n"), rc);
+
+ // start thread for HTTPS
+ if ((rc = wget_thread_start(&https_server_tid, _http_server_thread, https_parent_tcp, 0)) != 0)
+ wget_error_printf_exit(_("Failed to start HTTPS server, error %d\n"), rc);
+
+ // start thread for FTP
+ if ((rc = wget_thread_start(&ftp_server_tid, _ftp_server_thread, ftp_parent_tcp, 0)) != 0)
+ wget_error_printf_exit(_("Failed to start FTP server, error %d\n"), rc);
+
+ // start thread for FTPS
+ if (ftps_implicit) {
+ if ((rc = wget_thread_start(&ftps_server_tid, _ftp_server_thread, ftps_parent_tcp, 0)) != 0)
+ wget_error_printf_exit(_("Failed to start FTP server, error %d\n"), rc);
+ }
+}
+
+static void _scan_for_unexpected(const char *dirname, const wget_test_file_t *expected_files)
+{
+ DIR *dir;
+ struct dirent *dp;
+ struct stat st;
+ size_t it, dirlen = strlen(dirname);
+
+ wget_info_printf("Entering %s\n", dirname);
+
+ if ((dir = opendir(dirname))) {
+ while ((dp = readdir(dir))) {
+ char fname[dirlen + 1 + strlen(dp->d_name) + 1];
+
+ if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+ continue;
+
+ if (*dirname == '.' && dirname[1] == 0)
+ sprintf(fname, "%s", dp->d_name);
+ else
+ sprintf(fname, "%s/%s", dirname, dp->d_name);
+
+ wget_info_printf(" - %s/%s\n", dirname, dp->d_name);
+ if (stat(fname, &st) == 0 && S_ISDIR(st.st_mode)) {
+ _scan_for_unexpected(fname, expected_files);
+ continue;
+ }
+
+ if (expected_files) {
+ wget_info_printf("search %s\n", fname);
+
+ for (it = 0; expected_files[it].name && strcmp(expected_files[it].name, fname); it++);
+
+ if (!expected_files[it].name)
+ wget_error_printf_exit(_("Unexpected file %s/%s found\n"), tmpdir, fname);
+ } else
+ wget_error_printf_exit(_("Unexpected file %s/%s found\n"), tmpdir, fname);
+ }
+
+ closedir(dir);
+ } else
+ wget_error_printf_exit(_("Failed to diropen %s\n"), dirname);
+}
+
+void wget_test(int first_key, ...)
+{
+ const char
+ *request_url,
+ *options="",
+ *executable="../../src2/wget2";
+ const wget_test_file_t
+ *expected_files = NULL,
+ *existing_files = NULL;
+ wget_buffer_t
+ *cmd = wget_buffer_alloc(1024);
+ unsigned
+ it;
+ int
+ key,
+ fd,
+ rc,
+ expected_error_code = 0;
+ va_list args;
+
+ keep_tmpfiles = 0;
+ server_hello = "220 FTP server ready";
+
+ if (!request_urls)
+ request_urls = wget_vector_create(8,8,NULL);
+
+ va_start (args, first_key);
+ for (key = first_key; key; key = va_arg(args, int)) {
+ switch (key) {
+ case WGET_TEST_REQUEST_URL:
+ if ((request_url = va_arg(args, const char *)))
+ wget_vector_add_str(request_urls, request_url);
+ break;
+ case WGET_TEST_REQUEST_URLS:
+ while ((request_url = va_arg(args, const char *)))
+ wget_vector_add_str(request_urls, request_url);
+ break;
+ case WGET_TEST_EXPECTED_ERROR_CODE:
+ expected_error_code = va_arg(args, int);
+ break;
+ case WGET_TEST_EXPECTED_FILES:
+ expected_files = va_arg(args, const wget_test_file_t *);
+ break;
+ case WGET_TEST_EXISTING_FILES:
+ existing_files = va_arg(args, const wget_test_file_t *);
+ break;
+ case WGET_TEST_OPTIONS:
+ options = va_arg(args, const char *);
+ break;
+ case WGET_TEST_KEEP_TMPFILES:
+ keep_tmpfiles = va_arg(args, int);
+ break;
+ case WGET_TEST_EXECUTABLE:
+ executable = va_arg(args, const char *);
+ break;
+ case WGET_TEST_FTP_SERVER_HELLO:
+ server_hello = va_arg(args, const char *);
+ break;
+ default:
+ wget_error_printf_exit(_("Unknown option %d [%s]\n"), key, options);
+ }
+ }
+
+ // clean directory
+ wget_buffer_printf2(cmd, "../%s", tmpdir);
+ _empty_directory(cmd->data);
+
+ // create files
+ if (existing_files) {
+ for (it = 0; existing_files[it].name; it++) {
+ if ((fd = open(existing_files[it].name, O_CREAT|O_WRONLY|O_TRUNC, 0644)) != -1) {
+ ssize_t nbytes = write(fd, existing_files[it].content, strlen(existing_files[it].content));
+ close(fd);
+
+ if (nbytes != (ssize_t)strlen(existing_files[it].content))
+ wget_error_printf_exit(_("Failed to write %zu bytes to file %s/%s [%s]\n"),
+ strlen(existing_files[it].content), tmpdir, existing_files[it].name, options);
+
+ if (existing_files[it].timestamp) {
+ // take the old utime() instead of utimes()
+ if (utime(existing_files[it].name, &(struct utimbuf){ 0, existing_files[it].timestamp }))
+ wget_error_printf_exit(_("Failed to set mtime of %s/%s [%s]\n"),
+ tmpdir, existing_files[it].name, options);
+ }
+
+ } else {
+ wget_error_printf_exit(_("Failed to write open file %s/%s [%s] (%d,%s)\n"),
+ tmpdir, *existing_files[it].name == '/' ? existing_files[it].name + 1 : existing_files[it].name , options,
+ errno, strerror(errno));
+ }
+ }
+ }
+
+ const char *valgrind = getenv("VALGRIND_TESTS");
+ if (!valgrind || !*valgrind || !strcmp(valgrind, "0")) {
+ wget_buffer_printf2(cmd, "%s %s", executable, options);
+ } else if (!strcmp(valgrind, "1")) {
+ wget_buffer_printf2(cmd, "valgrind --error-exitcode=301 --leak-check=yes --show-reachable=yes --track-origins=yes %s %s", executable, options);
+ } else
+ wget_buffer_printf2(cmd, "%s %s %s", valgrind, executable, options);
+
+ for (it = 0; it < (size_t)wget_vector_size(request_urls); it++) {
+ wget_buffer_printf_append2(cmd, " 'http://localhost:%d/%s'",
+ http_server_port, (char *)wget_vector_get(request_urls, it));
+ }
+// for (it = 0; it < (size_t)wget_vector_size(ftp_files); it++) {
+// wget_buffer_printf_append2(cmd, " 'ftp://localhost:%d/%s'",
+// ftp_server_port, (char *)wget_vector_get(ftp_files, it));
+// }
+ wget_buffer_strcat(cmd, " 2>&1");
+
+ wget_error_printf("\n Testing '%s'\n", cmd->data);
+ rc = system(cmd->data);
+
+#if defined(_WIN32) || defined(_WIN64)
+ if (rc) {
+ wget_error_printf_exit(_("Failed to execute command (%d)\n"), errno);
+ }/* else {
+ if ((fp = fopen("exit_code", "r"))) {
+ if (fscanf(fp, "%d", &rc) != 1)
+ wget_error_printf_exit(_("Failed to fetch exit code\n"));
+ else if (rc != expected_error_code) {
+ wget_error_printf_exit(_("Unexpected error code %d, expected %d [%s]\n"),
+ rc, expected_error_code, options);
+ fclose(fp);
+ } else
+ wget_error_printf_exit(_("Failed to execute command (%d)\n"), errno);
+ }
+ unlink("exit_code"); */
+#else
+ if (!WIFEXITED(rc)) {
+ wget_error_printf_exit(_("Unexpected error code %d, expected %d [%s]\n"), rc, expected_error_code, options);
+ }
+ else if (WEXITSTATUS(rc) != expected_error_code) {
+ wget_error_printf_exit(_("Unexpected error code %d, expected %d [%s]\n"),
+ WEXITSTATUS(rc), expected_error_code, options);
+ }
+#endif
+
+ if (expected_files) {
+ for (it = 0; expected_files[it].name; it++) {
+ struct stat st;
+
+ if (stat(expected_files[it].name, &st) != 0)
+ wget_error_printf_exit(_("Missing expected file %s/%s [%s]\n"), tmpdir, expected_files[it].name, options);
+
+ if (expected_files[it].content) {
+ char content[st.st_size];
+
+ if ((fd = open(expected_files[it].name, O_RDONLY)) != -1) {
+ ssize_t nbytes = read(fd, content, st.st_size);
+ close(fd);
+
+ if (nbytes != st.st_size)
+ wget_error_printf_exit(_("Failed to read %lld bytes from file %s/%s [%s]\n"),
+ (long long)st.st_size, tmpdir, expected_files[it].name, options);
+
+ if (strlen(expected_files[it].content) != (size_t)nbytes || memcmp(expected_files[it].content, content, nbytes) != 0)
+ wget_error_printf_exit(_("Unexpected content in %s [%s]\n"), expected_files[it].name, options);
+ }
+ }
+
+ if (expected_files[it].timestamp && st.st_mtime != expected_files[it].timestamp)
+ wget_error_printf_exit(_("Unexpected timestamp %s/%s [%s]\n"), tmpdir, expected_files[it].name, options);
+ }
+ }
+
+ // look if there are unexpected files in our working dir
+ _scan_for_unexpected(".", expected_files);
+
+ wget_vector_clear(request_urls);
+ wget_buffer_free(&cmd);
+
+ // system("ls -la");
+}
+
+int wget_test_get_http_server_port(void)
+{
+ return http_server_port;
+}
+
+int wget_test_get_https_server_port(void)
+{
+ return https_server_port;
+}
+
+int wget_test_get_ftp_server_port(void)
+{
+ return ftp_server_port;
+}
+
+int wget_test_get_ftps_server_port(void)
+{
+ return ftps_server_port;
+}
diff --git a/tests2/libtest.h b/tests2/libtest.h
new file mode 100644
index 00000000..4da7c1d4
--- /dev/null
+++ b/tests2/libtest.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright(c) 2013-2014 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Test suite function library header
+ *
+ * Changelog
+ * 10.03.2013 Tim Ruehsen created
+ *
+ * Test suite function library
+ *
+ * To create the X.509 stuff, I followed the instructions at
+ * gnutls.org/manual/html_node/gnutls_002dserv-Invocation.html
+ *
+ */
+
+#ifndef _LIBWGET_LIBTEST_H
+#define _LIBWGET_LIBTEST_H
+
+#include <libwget.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// defines for wget_test_start_http_server()
+#define WGET_TEST_EXPECTED_REQUEST_HEADER 1001
+#define WGET_TEST_RESPONSE_URLS 1002
+#define WGET_TEST_FTP_IO_UNORDERED 1003
+#define WGET_TEST_FTP_IO_ORDERED 1004
+#define WGET_TEST_FTP_SERVER_HELLO 1005
+#define WGET_TEST_FTPS_IMPLICIT 1006
+
+// defines for wget_test()
+#define WGET_TEST_REQUEST_URL 2001
+#define WGET_TEST_OPTIONS 2002
+#define WGET_TEST_EXPECTED_ERROR_CODE 2003
+#define WGET_TEST_EXPECTED_FILES 2004
+#define WGET_TEST_EXISTING_FILES 2005
+#define WGET_TEST_KEEP_TMPFILES 2006
+#define WGET_TEST_REQUEST_URLS 2007
+#define WGET_TEST_EXECUTABLE 2008
+
+#define countof(a) (sizeof(a)/sizeof(*(a)))
+
+G_GNUC_WGET_UNUSED static const char *WGET_TEST_SOME_HTML_BODY = "\
+<html>\n\
+<head>\n\
+ <title>The Title</title>\n\
+</head>\n\
+<body>\n\
+ <p>\n\
+ Some text\n\
+ </p>\n\
+</body>\n\
+</html>\n";
+
+typedef struct {
+ const char *
+ name;
+ const char *
+ content;
+ time_t
+ timestamp;
+} wget_test_file_t;
+
+typedef struct {
+ const char *
+ name;
+ const char *
+ code;
+ const char *
+ body;
+ const char *
+ headers[10];
+ const char *
+ request_headers[10];
+ time_t
+ modified;
+ char
+ body_alloc; // if body has been allocated internally (and need to be freed on exit)
+
+ // auth fields
+ const char *
+ auth_method;
+ const char *
+ auth_username;
+ const char *
+ auth_password;
+} wget_test_url_t;
+
+typedef struct {
+ const char *
+ in;
+ const char *
+ out;
+ wget_test_url_t *
+ send_url;
+} wget_test_ftp_io_t;
+
+void wget_test_stop_server(void);
+void wget_test_start_server(int first_key, ...);
+void wget_test(int first_key, ...);
+int wget_test_get_http_server_port(void) G_GNUC_WGET_PURE;
+int wget_test_get_https_server_port(void) G_GNUC_WGET_PURE;
+int wget_test_get_ftp_server_port(void) G_GNUC_WGET_PURE;
+int wget_test_get_ftps_server_port(void) G_GNUC_WGET_PURE;
+
+#if defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBWGET_LIBTEST_H */
diff --git a/tests2/stringmap_perf.c b/tests2/stringmap_perf.c
new file mode 100644
index 00000000..dda18c0e
--- /dev/null
+++ b/tests2/stringmap_perf.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright(c) 2012 Tim Ruehsen
+ *
+ * This file is part of MGet.
+ *
+ * Wget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Wget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Wget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * testing performance of hashmap/stringmap routines
+ *
+ * Changelog
+ * 06.07.2012 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef HAVE_MMAP
+# include <sys/mman.h>
+#endif
+#include <errno.h>
+
+#include <libwget.h>
+
+static int G_GNUC_WGET_NONNULL_ALL _print_word(G_GNUC_WGET_UNUSED void *ctx, const char *word)
+{
+ printf("%s\n", word);
+ return 0;
+}
+
+int main(int argc, const char *const *argv)
+{
+ int fd, it, unique = 0, duple = 0;
+ char *buf, *word, *end;
+ size_t length;
+ struct stat st;
+ wget_stringmap_t *map = wget_stringmap_create(1024);
+
+ for (it = 1; it < argc; it++) {
+ if ((fd = open(argv[it], O_RDONLY)) == -1) {
+ fprintf(stderr, "Failed to read open %s\n", argv[it]);
+ continue;
+ }
+
+ if (fstat(fd, &st)) {
+ fprintf(stderr, "Failed to stat %s\n", argv[it]);
+ close(fd);
+ continue;
+ }
+
+ length = st.st_size;
+
+#ifdef HAVE_MMAP
+ if (!(buf = mmap(NULL, length + 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0))) {
+ fprintf(stderr, "Failed to mmap %s (%d)\n", argv[it], errno);
+ close(fd);
+ continue;
+ }
+#else
+ if (!(buf = xmalloc(length + 1)) || read(fd, buf, length) != (signed)length) {
+ fprintf(stderr, "Failed to read %s (%d)\n", argv[it], errno);
+ close(fd);
+ continue;
+ }
+#endif
+
+ buf[length] = 0;
+
+ for (word = buf; *word; word = end) {
+ while (*word && !isalnum(*word)) word++;
+ for (end = word; *end && isalnum(*end);) end++;
+ if (word != end) {
+ char c = *end;
+ *end = 0;
+
+/* if (stringmap_get(map, word)) {
+ duple++;
+ } else {
+ stringmap_put_ident_noalloc(map, strndup(word, end - word));
+ unique++;
+ }
+*/
+ if (wget_stringmap_put(map, word, NULL, 0))
+ duple++;
+ else
+ unique++;
+
+ *end = c;
+ }
+ }
+
+#ifdef HAVE_MMAP
+ munmap(buf, length);
+#else
+ free(buf);
+#endif
+ close(fd);
+ }
+
+ printf("read %u words, %u uniques, %u doubles\n", unique + duple, unique, duple);
+
+ // const void *keys = stringmap_get_keys(map);
+ wget_stringmap_browse(map, (int(*)(void *, const char *, void *))_print_word, NULL);
+
+ wget_stringmap_free(&map);
+
+ return 0;
+}
diff --git a/tests2/test--accept.c b/tests2/test--accept.c
new file mode 100644
index 00000000..999e15d6
--- /dev/null
+++ b/tests2/test--accept.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 08.07.2013 Tim Ruehsen created
+ * 02.07.2014 Tim Ruehsen added uppercase combinations of <a href...> (issue #21)
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <A hreF=\"http://localhost:{{port}}/secondpage.html\">second page</a>." \
+ " <a href=\"picture_a.jpeg\">Picture a</a>." \
+ " <a href=\"picture_A.jpeg\">Picture A</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/secondpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Second Page</title></head><body><p>A link to a" \
+ " <a href=\"picture_b.jpeg\">Picture b</a>." \
+ " <a href=\"picture_B.JpeG\">Picture B</a>." \
+ " <a href=\"picture_c.png\">Picture C</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/picture_a.jpeg",
+ .code = "200 Dontcare",
+ .body = "don't care",
+ .headers = { "Content-Type: image/jpeg" }
+ },
+ { .name = "/picture_A.jpeg",
+ .code = "200 Dontcare",
+ .body = "don't care",
+ .headers = { "Content-Type: image/jpeg" }
+ },
+ { .name = "/picture_b.jpeg",
+ .code = "200 Dontcare",
+ .body = "don't care",
+ .headers = { "Content-Type: image/jpeg" }
+ },
+ { .name = "/picture_B.JpeG",
+ .code = "200 Dontcare",
+ .body = "don't care",
+ .headers = { "Content-Type: image/jpeg" }
+ },
+ { .name = "/picture_c.png",
+ .code = "200 Dontcare",
+ .body = "don't care",
+ .headers = { "Content-Type: image/png" }
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // --accept using just suffixes
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --accept '.jpeg'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { NULL } },
+ 0);
+
+ // --reject using just suffixes
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --reject '.jpeg'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[5].name + 1, urls[5].body },
+ { urls[6].name + 1, urls[6].body },
+ { NULL } },
+ 0);
+
+ // --accept using just suffixes and ignore case
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --accept '.jpeg' --ignore-case",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { urls[5].name + 1, urls[5].body },
+ { NULL } },
+ 0);
+
+ // --reject using just suffixes and ignore case
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --reject '.jpeg' --ignore-case",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[6].name + 1, urls[6].body },
+ { NULL } },
+ 0);
+
+ // --accept using wildcards
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --accept '*.jpeg'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { NULL } },
+ 0);
+
+ // --reject using wildcards
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --reject '*.jpeg'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[5].name + 1, urls[5].body },
+ { urls[6].name + 1, urls[6].body },
+ { NULL } },
+ 0);
+
+ // --accept using wildcards and ignore case
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --accept '*.jpeg' --ignore-case",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { urls[5].name + 1, urls[5].body },
+ { NULL } },
+ 0);
+
+ // --reject using wildcards and ignore case
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --reject '*.jpeg' --ignore-case",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[6].name + 1, urls[6].body },
+ { NULL } },
+ 0);
+
+ // --accept using wildcards
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --accept '*picture*'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { urls[5].name + 1, urls[5].body },
+ { urls[6].name + 1, urls[6].body },
+ { NULL } },
+ 0);
+
+ // --reject using wildcards
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --reject '*picture*'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { NULL } },
+ 0);
+
+ // --accept using wildcards
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --accept '*picture_[ab]*'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[2].name + 1, urls[2].body },
+ { urls[4].name + 1, urls[4].body },
+ { NULL } },
+ 0);
+
+ // --reject using wildcards
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --reject '*picture_[ab]*'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[5].name + 1, urls[5].body },
+ { urls[6].name + 1, urls[6].body },
+ { NULL } },
+ 0);
+
+ // --accept using wildcards
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --accept '*picture_a*' --accept '*picture_c*'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[2].name + 1, urls[2].body },
+ { urls[6].name + 1, urls[6].body },
+ { NULL } },
+ 0);
+
+ // --reject using wildcards
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --reject '*picture_a*' --reject '*picture_c*'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { urls[5].name + 1, urls[5].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test--follow-tags.c b/tests2/test--follow-tags.c
new file mode 100644
index 00000000..99dcf1be
--- /dev/null
+++ b/tests2/test--follow-tags.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 09.09.2014 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <a href=\"secondpage.html\">second page</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/secondpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Second Page</title></head><body><p>A link to a" \
+ " <a href=\"2a.jpeg\">Picture 2a</a>." \
+ " <img src=\"2b.jpeg\" data-500px=\"2c.jpeg\" data-highres=\"2d.jpeg\">" \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/2a.jpeg",
+ .code = "200 Dontcare",
+ .body = "pic 2a",
+ .headers = { "Content-Type: image/jpeg" }
+ },
+ { .name = "/2b.jpeg",
+ .code = "200 Dontcare",
+ .body = "pic 2b",
+ .headers = { "Content-Type: image/jpeg" }
+ },
+ { .name = "/2c.jpeg",
+ .code = "200 Dontcare",
+ .body = "pic 2c",
+ .headers = { "Content-Type: image/jpeg" }
+ },
+ { .name = "/2d.jpeg",
+ .code = "200 Dontcare",
+ .body = "pic 2c",
+ .headers = { "Content-Type: image/jpeg" }
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // without additional tags
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH ",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { NULL } },
+ 0);
+
+ // --follow-tags single entry
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --follow-tags 'img/data-500px'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { NULL } },
+ 0);
+
+ // --follow-tags single entry without attribute
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --follow-tags 'img'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { urls[5].name + 1, urls[5].body },
+ { NULL } },
+ 0);
+
+ // --follow-tags two entries
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --follow-tags 'img/data-500px,img/data-highres'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { urls[5].name + 1, urls[5].body },
+ { NULL } },
+ 0);
+
+ // --follow-tags two entries
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --follow-tags 'img/data-highres,img/data-500px'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { urls[4].name + 1, urls[4].body },
+ { urls[5].name + 1, urls[5].body },
+ { NULL } },
+ 0);
+
+ // --ignore-tags single entry
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --ignore-tags 'img/src'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+
+ // --ignore-tags single entry without attribute
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --ignore-tags 'img'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+
+ // --ignore-tags two entries
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --ignore-tags 'img/src,a/href'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { NULL } },
+ 0);
+
+ // --ignore-tags two entries
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --ignore-tags 'a/href,img/src'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { NULL } },
+ 0);
+
+ // --ignore-tags and --follow-tags combined
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH --ignore-tags 'img/src' --follow-tags='img/data-500px'",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { urls[4].name + 1, urls[4].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test--page-requisites.c b/tests2/test--page-requisites.c
new file mode 100644
index 00000000..a6e0d876
--- /dev/null
+++ b/tests2/test--page-requisites.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 27.05.2014 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <a href=\"http://localhost:{{port}}/secondpage.html\">second page</a>." \
+ " Hey, a picture <img src=\"picture.png\"/>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/secondpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Second Page</title></head><body><p>A link to a" \
+ " <a href=\"http://localhost:{{port}}/thirdpage.html\">third page</a>." \
+ " Also, a <a href=\"http://localhost:{{port}}/nonexistent\">broken link</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ "Content-Disposition: attachment; filename=\"filename.html\"",
+ }
+ },
+ { .name = "/thirdpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Third Page</title></head><body><p>A link to a" \
+ " <a href=\"http://localhost:{{port}}/dummy.txt\">text file</a>." \
+ " Also, a <a href=\"http://localhost:{{port}}/againnonexistent\">broken link</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/picture.png",
+ .code = "200 Dontcare",
+ .body = "PNG data",
+ .headers = {
+ "Content-Type: image/png",
+ }
+ },
+ { .name = "/dummy.txt",
+ .code = "200 Dontcare",
+ .body = "What ever",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test--page-requisites
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--page-requisites",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "localhost/index.html", urls[0].body },
+ { "localhost/picture.png", urls[3].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test--post-file.c b/tests2/test--post-file.c
new file mode 100644
index 00000000..0004ddf1
--- /dev/null
+++ b/tests2/test--post-file.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 15.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ // functions won't come back if an error occurs
+ wget_test_start_server(0);
+
+ // test-i
+ wget_test(
+ WGET_TEST_OPTIONS, "-d --post-file=nofile",
+ WGET_TEST_REQUEST_URL, "",
+ WGET_TEST_EXPECTED_ERROR_CODE, 3, // fails with older Wget (<= 1.14)
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test--spider-r.c b/tests2/test--spider-r.c
new file mode 100644
index 00000000..3a17a656
--- /dev/null
+++ b/tests2/test--spider-r.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 15.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <a href=\"http://localhost:{{port}}/secondpage.html\">second page</a>." \
+ " Also, a <a href=\"http://localhost:{{port}}/nonexistent\">broken link</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/secondpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Second Page</title></head><body><p>A link to a" \
+ " <a href=\"http://localhost:{{port}}/thirdpage.html\">third page</a>." \
+ " Also, a <a href=\"http://localhost:{{port}}/nonexistent\">broken link</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ "Content-Disposition: attachment; filename=\"filename.html\"",
+ }
+ },
+ { .name = "/thirdpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Third Page</title></head><body><p>A link to a" \
+ " <a href=\"http://localhost:{{port}}/dummy.txt\">text file</a>." \
+ " Also, a <a href=\"http://localhost:{{port}}/againnonexistent\">broken link</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/dummy.txt",
+ .code = "200 Dontcare",
+ .body = "What ever",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test--spider-r-HTTP-Content-Disposition
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--spider -r",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 8,
+ 0);
+
+ // test--spider-r
+ urls[1].headers[1] = NULL;
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--spider -r",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 8,
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-E-k.c b/tests2/test-E-k.c
new file mode 100644
index 00000000..2a45cf83
--- /dev/null
+++ b/tests2/test-E-k.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 15.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.php",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <a href=\"http://localhost:{{port}}/subpage.php\">second page</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/subpage.php",
+ .code = "200 Dontcare",
+ .body = "<html><head><title>Sub Page</title></head><body>Some Text</body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ };
+
+ const char *mainpagemangled =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <a href=\"subpage.php.html\">second page</a>." \
+ "</p></body></html>";
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-E-k
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nd -E -k",
+ WGET_TEST_REQUEST_URL, "index.php",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "index.php.html", mainpagemangled },
+ { "subpage.php.html", urls[1].body },
+ { NULL } },
+ 0);
+
+ // test-E-k-K
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nd -E -k -K",
+ WGET_TEST_REQUEST_URL, "index.php",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "index.php.html", mainpagemangled },
+ { "index.php.orig", urls[0].body },
+ { "subpage.php.html", urls[1].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-auth-basic.c b/tests2/test-auth-basic.c
new file mode 100644
index 00000000..bc8fc35b
--- /dev/null
+++ b/tests2/test-auth-basic.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 08.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include <string.h> // strlen()
+#include "libtest.h"
+
+#define username "my_username"
+#define password "my_password"
+
+int main(void)
+{
+ wget_test_url_t urls[] = {
+ { .name = "/needs-auth.txt",
+ .auth_method = "Basic",
+ .auth_username = username,
+ .auth_password = password,
+ .code = "200 Dontcare",
+ .body = "You are authenticated.",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ }
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-auth-basic
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "-d --user=" username " --password=" password,
+ WGET_TEST_REQUEST_URL, urls[0].name + 1,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-directory-clash.c b/tests2/test-directory-clash.c
new file mode 100644
index 00000000..24db3fcb
--- /dev/null
+++ b/tests2/test-directory-clash.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright(c) 2014 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing file/directory ambiguity
+ *
+ * Changelog
+ * 19.09.2014 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>Moin" \
+ " <a href=\"http://localhost:{{port}}/subdir\">File with same name as directory</a>." \
+ " <a href=\"subdir/\">Directory again</a>." \
+ " <a href=\"subdir/index.html\">File in directory</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/index2.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>Moin" \
+ " <a href=\"subdir/\">Directory</a>." \
+ " <a href=\"subdir/index.html\">File in directory</a>." \
+ " <a href=\"http://localhost:{{port}}/subdir\">File with same name as directory</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/subdir",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Subdir Page 1</title></head><body><p>Hello 1</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/subdir/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Second Page</title></head><body><p>Hello 2</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[3].name + 1, urls[3].body },
+ { "subdir.1", urls[2].body, 0 }, // filename / directory clash appends .x to the file
+ { NULL } },
+ 0);
+
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -nH",
+ WGET_TEST_REQUEST_URL, "index2.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[1].name + 1, urls[1].body },
+ { urls[3].name + 1, urls[3].body },
+ { "subdir.1", urls[2].body, 0 }, // filename / directory clash appends .x to the file
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-ftp.c b/tests2/test-ftp.c
new file mode 100644
index 00000000..5f87218c
--- /dev/null
+++ b/tests2/test-ftp.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 08.07.2015 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "info.txt",
+ .body = "Dummy file content"
+ },
+ { .name = ".listing",
+ .body =
+"drwxr-xr-x 9 ftp ftp 4096 Aug 14 2013 .\r\n"
+"drwxr-xr-x 9 ftp ftp 4096 Aug 14 2013 ..\r\n"
+"lrw-r--r-- 1 ftp ftp 16 Jan 12 2013 dir2 -> dir1\r\n"
+"drwxr-xr-x 8 ftp ftp 4096 Jul 8 15:37 dir1\r\n"
+"-rw-r--r-- 1 ftp ftp 245 Jul 1 2013 info.txt\r\n"
+ },
+ };
+ wget_test_ftp_io_t io[]={
+ { .in = "USER anonymous",
+ .out = "331 Anonymous login ok"
+ },
+ { .in = "PASS -wget@",
+ .out = "230- Hello\r\n and good night\r\n\r\n230 Access granted"
+ },
+ { .in = "SYST",
+ .out = "215 UNIX Type: L8"
+ },
+ { .in = "PWD",
+ .out = "257 \"/\" is the current directory"
+ },
+ { .in = "TYPE I",
+ .out = "200 Type set to I"
+ },
+ { .in = "PASV",
+ .out = "227 Entering Passive Mode {{pasvdata}}."
+ },
+ { .in = "EPSV 2",
+ .out = "229 Entering Passive Mode {{pasvdata}}."
+ },
+ { .in = "LIST -a",
+ .out = "150 Opening BINARY mode data connection for file list",
+ .send_url = &urls[1]
+ },
+ { .in = "RETR info.txt",
+ .out = "150 Opening BINARY mode data connection",
+ .send_url = &urls[0]
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ WGET_TEST_FTP_IO_UNORDERED, &io, countof(io),
+ 0);
+
+ char options[128];
+
+ // without -O/dev/null Wget generates HTML output from the listing
+ snprintf(options, sizeof(options),
+ "-d --tries=1 --no-remove-listing -O/dev/null ftp://localhost:%d",
+ wget_test_get_ftp_server_port());
+
+ // test downloading the top directory content
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_EXECUTABLE, "wget",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[1].name, urls[1].body },
+ { NULL } },
+ 0);
+
+ // without -O/dev/null Wget generates HTML output from the listing
+ snprintf(options, sizeof(options),
+ "-d ftp://localhost:%d/info.txt",
+ wget_test_get_ftp_server_port());
+
+ // test downloading a file
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_EXECUTABLE, "wget",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name, urls[0].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-ftps.c b/tests2/test-ftps.c
new file mode 100644
index 00000000..124b347a
--- /dev/null
+++ b/tests2/test-ftps.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 08.07.2015 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "info.txt",
+ .body = "Dummy file content"
+ },
+ { .name = ".listing",
+ .body =
+"drwxr-xr-x 9 ftp ftp 4096 Aug 14 2013 .\r\n"
+"drwxr-xr-x 9 ftp ftp 4096 Aug 14 2013 ..\r\n"
+"lrw-r--r-- 1 ftp ftp 16 Jan 12 2013 dir2 -> dir1\r\n"
+"drwxr-xr-x 8 ftp ftp 4096 Jul 8 15:37 dir1\r\n"
+"-rw-r--r-- 1 ftp ftp 245 Jul 1 2013 info.txt\r\n"
+ },
+ };
+ wget_test_ftp_io_t io[]={
+ { .in = "USER anonymous",
+ .out = "331 Anonymous login ok"
+ },
+ { .in = "PASS -wget@",
+ .out = "230- Hello\r\n and good night\r\n\r\n230 Access granted"
+ },
+ { .in = "SYST",
+ .out = "215 UNIX Type: L8"
+ },
+ { .in = "PWD",
+ .out = "257 \"/\" is the current directory"
+ },
+ { .in = "TYPE I",
+ .out = "200 Type set to I"
+ },
+ { .in = "PASV",
+ .out = "227 Entering Passive Mode {{pasvdata}}."
+ },
+ { .in = "EPSV 2",
+ .out = "229 Entering Passive Mode {{pasvdata}}."
+ },
+ { .in = "LIST -a",
+ .out = "150 Opening BINARY mode data connection for file list",
+ .send_url = &urls[1]
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ WGET_TEST_FTP_IO_UNORDERED, &io, countof(io),
+ WGET_TEST_FTPS_IMPLICIT, 1, // use TLS connections right away, no AUTH
+ 0);
+
+ char options[128];
+
+ // without -O/dev/null Wget generates HTML output from the listing
+ snprintf(options, sizeof(options),
+ "-d --tries=1 --no-remove-listing -O/dev/null ftp://localhost:%d",
+ wget_test_get_ftp_server_port());
+
+ // test-ftp
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_EXECUTABLE, "wget",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[1].name, urls[1].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-i-http.c b/tests2/test-i-http.c
new file mode 100644
index 00000000..d648a826
--- /dev/null
+++ b/tests2/test-i-http.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 08.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/urls.txt",
+ .code = "200 Dontcare",
+ .body = "http://localhost:{{port}}/page1.html\nhttp://localhost:{{port}}/page2.html\n",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ { .name = "/page1.html",
+ .code = "200 Dontcare",
+ .body = "<html>hello1</html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/page2.html",
+ .code = "200 Dontcare",
+ .body = "<html>hello2</html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ }
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-i
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "-i urls.txt",
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "urls.txt", urls[0].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+/*
+ // test-i-http (expands to -i http://localhost:{{port}}/urls.txt)
+ wget_test(
+ WGET_TEST_OPTIONS, "-i",
+ WGET_TEST_REQUEST_URL, "urls.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+*/
+ exit(0);
+}
diff --git a/tests2/test-i-https.c b/tests2/test-i-https.c
new file mode 100644
index 00000000..3f2474ce
--- /dev/null
+++ b/tests2/test-i-https.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 08.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/urls.txt",
+ .code = "200 Dontcare",
+ .body = "https://localhost:{{sslport}}/page1.html\nhttps://localhost:{{sslport}}/page2.html\n",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ { .name = "/page1.html",
+ .code = "200 Dontcare",
+ .body = "<html>hello1</html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/page2.html",
+ .code = "200 Dontcare",
+ .body = "<html>hello2</html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ }
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-i-https with loading CA Certificate
+ wget_test(
+ // WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--ca-certificate=../" SRCDIR "/certs/x509-ca-cert.pem --no-ocsp -i urls.txt",
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "urls.txt", urls[0].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+
+ // test-i-https with loading CA Certificate and CRL
+ wget_test(
+ // WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "-d --ca-certificate=../" SRCDIR "/certs/x509-ca-cert.pem --crl-file=../" SRCDIR "/certs/x509-server-crl.pem --no-ocsp -i urls.txt",
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 5,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "urls.txt", urls[0].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { NULL } },
+ 0);
+
+ // test-i-https ignoring unknown certificate
+ wget_test(
+ // WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--no-check-certificate -i urls.txt",
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "urls.txt", urls[0].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+
+ // test-i-https ignoring unknown certificate (with CRL)
+ wget_test(
+ // WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--no-check-certificate --crl-file=../" SRCDIR "/certs/x509-server-crl.pem -i urls.txt",
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "urls.txt", urls[0].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+
+ // test-i-https failing due to unknown certificate
+ wget_test(
+ // WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--tries=1 -i urls.txt",
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 5,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "urls.txt", urls[0].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { NULL } },
+ 0);
+
+/*
+ // test-i-http (expands to -i https://localhost:{{sslport}}/urls.txt)
+ wget_test(
+ WGET_TEST_OPTIONS, "-i",
+ WGET_TEST_REQUEST_URL, "urls.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+*/
+ exit(0);
+}
diff --git a/tests2/test-idn-cmd.c b/tests2/test-idn-cmd.c
new file mode 100644
index 00000000..4074e7da
--- /dev/null
+++ b/tests2/test-idn-cmd.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 17.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+// Kon'nichiwa <dot> Japan
+#define euc_jp_hostname "\272\243\306\374\244\317.\306\374\313\334"
+#define utf8_hostname "\344\273\212\346\227\245\343\201\257.\346\227\245\346\234\254"
+#define punycoded_hostname "xn--v9ju72g90p.xn--wgv71a"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "http://" punycoded_hostname "/index.html",
+ .code = "200 Dontcare",
+ .body = "What ever",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ };
+
+ char options[256];
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-idn-cmd
+ snprintf(options, sizeof(options),
+ "--iri -rH -e http_proxy=localhost:%d --local-encoding=EUC-JP " euc_jp_hostname,
+ wget_test_get_http_server_port());
+
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { punycoded_hostname "/index.html", urls[0].body },
+ { NULL } },
+ 0);
+
+ // test-idn-cmd
+ snprintf(options, sizeof(options),
+ "--iri -rH -e http_proxy=localhost:%d --local-encoding=UTF-8 " utf8_hostname,
+ wget_test_get_http_server_port());
+
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { punycoded_hostname "/index.html", urls[0].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-idn-meta.c b/tests2/test-idn-meta.c
new file mode 100644
index 00000000..d9010824
--- /dev/null
+++ b/tests2/test-idn-meta.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 17.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+// Kon'nichiwa <dot> Japan
+#define euc_jp_hostname "\272\243\306\374\244\317.\306\374\313\334"
+#define punycoded_hostname "xn--v9ju72g90p.xn--wgv71a"
+
+// The charset in the document's META tag is stated wrong by purpose (UTF-8).
+// The charset in the response header has priority and is correct (EUC-JP)
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "http://start-here.com/start.html",
+ .code = "200 Dontcare",
+ .body =
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" \
+ "<a href=\"http://" euc_jp_hostname "/\">The link</a>",
+ .headers = {
+ "Content-Type: text/html; charset=EUC-JP",
+ }
+ },
+ { .name = "http://" punycoded_hostname "/index.html",
+ .code = "200 Dontcare",
+ .body = "What ever",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ };
+
+ char options[256];
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-idn-meta
+ snprintf(options, sizeof(options),
+ "--iri -rH -e http_proxy=localhost:%d http://start-here.com/start.html",
+ wget_test_get_http_server_port());
+
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "start-here.com/start.html", urls[0].body },
+ { punycoded_hostname "/index.html", urls[1].body },
+ { NULL } },
+ 0);
+
+ // test-idn-headers
+ urls[0].body = "<a href=\"http://" euc_jp_hostname "/\">The link</a>";
+ urls[0].headers[0] = "Content-Type: text/html; charset=EUC-JP";
+
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "start-here.com/start.html", urls[0].body },
+ { punycoded_hostname "/index.html", urls[1].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-idn-robots.c b/tests2/test-idn-robots.c
new file mode 100644
index 00000000..9f46680e
--- /dev/null
+++ b/tests2/test-idn-robots.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 15.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+// Kon'nichiwa <dot> Japan
+#define euc_jp_hostname "\272\243\306\374\244\317.\306\374\313\334"
+#define utf8_hostname "\344\273\212\346\227\245\343\201\257.\346\227\245\346\234\254"
+#define punycoded_hostname "xn--v9ju72g90p.xn--wgv71a"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "http://" punycoded_hostname "/index.html",
+ .code = "200 Dontcare",
+ .body = "<a href=\"http://" euc_jp_hostname "/foo.txt\">The link</a>",
+ .headers = {
+ "Content-Type: text/html; charset=EUC-JP",
+ }
+ },
+ { .name = "http://" punycoded_hostname "/foo.txt",
+ .code = "200 Dontcare",
+ .body = "What ever",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ { .name = "http://" punycoded_hostname "/robots.txt",
+ .code = "200 Dontcare",
+ .body = "",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ };
+
+ char options[256];
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-idn-robots
+ snprintf(options, sizeof(options),
+ "--iri -e robots=on -rH -e http_proxy=localhost:%d --local-encoding=EUC-JP http://" euc_jp_hostname "/",
+ wget_test_get_http_server_port());
+
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { punycoded_hostname "/index.html", urls[0].body },
+ { punycoded_hostname "/foo.txt", urls[1].body },
+ { punycoded_hostname "/robots.txt", urls[2].body },
+ { NULL } },
+ 0);
+
+ // test-idn-robots-utf8
+ snprintf(options, sizeof(options),
+ "--iri -e robots=on -rH -e http_proxy=localhost:%d --local-encoding=UTF-8 http://" utf8_hostname "/",
+ wget_test_get_http_server_port());
+
+ urls[0].body = "<a href=\"http://" utf8_hostname "/foo.txt\">The link</a>",
+ urls[0].headers[0] = "Content-Type: text/html; charset=UTF-8";
+
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, options,
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { punycoded_hostname "/index.html", urls[0].body },
+ { punycoded_hostname "/foo.txt", urls[1].body },
+ { punycoded_hostname "/robots.txt", urls[2].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-iri-disabled.c b/tests2/test-iri-disabled.c
new file mode 100644
index 00000000..e00dde06
--- /dev/null
+++ b/tests2/test-iri-disabled.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 17.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+#define ccedilla_l15 "\xE7"
+#define ccedilla_u8 "\xC3\xA7"
+#define eacute_l15 "\xE9"
+#define eacute_u8 "\xC3\xA9"
+#define eurosign_l15 "\xA4"
+#define eurosign_u8 "\xE2\x82\xAC"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>" \
+ "Link to page 1 <a href=\"http://localhost:{{port}}/p1_fran" ccedilla_l15 "ais.html\">La seule page en fran&ccedil;ais</a>." \
+ "Link to page 3 <a href=\"http://localhost:{{port}}/p3_" eurosign_l15 eurosign_l15 eurosign_l15 ".html\">My tailor is rich</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-15",
+ }
+ },
+ { .name = "/robots.txt",
+ .code = "200 Dontcare",
+ .body = "",
+ .headers = {
+ "Content-type: text/plain",
+ }
+ },
+ { .name = "/p1_fran%C3%A7ais.html", // UTF-8 encoded
+ .code = "200 Dontcare1",
+ .body =
+ "<html><head><title>La seule page en fran" ccedilla_l15 "ais</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/></head><body>" \
+ "<p>Link to page 2 <a href=\"http://localhost:{{port}}/p2_" eacute_l15 eacute_l15 "n.html\">Die enkele nerderlangstalige pagina</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=UTF-8",
+ }
+ },
+ { .name = "/p1_fran%E7ais.html",
+ .code = "200 Dontcare2",
+ .body =
+ "<html><head><title>La seule page en fran" ccedilla_l15 "ais</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/></head><body>" \
+ "<p>Link to page 2 <a href=\"http://localhost:{{port}}/p2_" eacute_l15 eacute_l15 "n.html\">Die enkele nerderlangstalige pagina</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=UTF-8",
+ }
+ },
+ { .name = "/p2_%C3%A9%C3%A9n.html", // UTF-8 encoded
+ .code = "200 Dontcare1",
+ .body =
+ "<html><head><title>Die enkele nederlandstalige pagina</title></head>" \
+ "<body><p>&Eacute;&eacute;n is niet veel maar toch meer dan nul.<br/>" \
+ "Nerdelands is een mooie taal... dit zin stuckje spreekt vanzelf, of niet :)<br/>" \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=UTF-8",
+ },
+ },
+ { .name = "/p2_%E9%E9n.html",
+ .code = "200 Dontcare2",
+ .body =
+ "<html><head><title>Die enkele nederlandstalige pagina</title></head>" \
+ "<body><p>&Eacute;&eacute;n is niet veel maar toch meer dan nul.<br/>" \
+ "Nerdelands is een mooie taal... dit zin stuckje spreekt vanzelf, of niet :)<br/>" \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-1",
+ },
+ },
+ { .name = "/p3_%E2%82%AC%E2%82%AC%E2%82%AC.html", // UTF-8 encoded
+ .code = "200 Dontcare1",
+ .body =
+ "<html><head><title>Euro page</title>" \
+ "</head><body><p>My tailor isn't rich anymore.</p></body></html>",
+ .headers = {
+ "Content-type: text/plain",
+ },
+ },
+ { .name = "/p3_%A4%A4%A4.html",
+ .code = "200 Dontcare2",
+ .body =
+ "<html><head><title>Euro page</title>" \
+ "</head><body><p>My tailor isn't rich anymore.</p></body></html>",
+ .headers = {
+ "Content-type: text/plain",
+ },
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-iri-disabled
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--no-iri -e robots=on -nH -r",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body }, // index.html
+ { urls[1].name + 1, urls[1].body }, // robots.txt
+ { "p1_fran" ccedilla_u8 "ais.html", urls[3].body },
+ { "p2_" eacute_u8 eacute_u8 "n.html", urls[4].body },
+ { "p3_" eurosign_u8 eurosign_u8 eurosign_u8 ".html", urls[6].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-iri-forced-remote.c b/tests2/test-iri-forced-remote.c
new file mode 100644
index 00000000..f7c7da9f
--- /dev/null
+++ b/tests2/test-iri-forced-remote.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 27.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+#define ccedilla_l15 "\xE7"
+#define ccedilla_u8 "\xC3\xA7"
+#define eurosign_l15 "\xA4"
+#define eurosign_u8 "\xE2\x82\xAC"
+#define eacute_l15 "\xE9"
+#define eacute_u8 "\xC3\xA9"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>" \
+ "Link to page 1 <a href=\"http://localhost:{{port}}/p1_fran" ccedilla_l15 "ais.html\">La seule page en fran&ccedil;ais</a>." \
+ "Link to page 1 <a href=\"http://localhost:{{port}}/p3_" eurosign_l15 eurosign_l15 eurosign_l15 ".html\">My tailor is rich</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-15",
+ }
+ },
+ { .name = "/robots.txt",
+ .code = "200 Dontcare",
+ .body = "",
+ .headers = {
+ "Content-type: text/plain",
+ }
+ },
+ { .name = "/p1_fran%C3%A7ais.html", // UTF-8 encoded
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>La seule page en fran" ccedilla_l15 "ais</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/></head><body>" \
+ "<p>Link to page 2 <a href=\"http://localhost:{{port}}/p2_" eacute_l15 eacute_l15 "n.html\">Die enkele nerderlangstalige pagina</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-15", // overrides META tag in document
+ }
+ },
+ { .name = "/p2_%C3%A9%C3%A9n.html", // UTF-8 encoded
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Die enkele nederlandstalige pagina</title>" \
+ "</head><body><p>&Eacute;&eacute;n is niet veel maar toch meer dan nul.<br/>" \
+ "Nerdelands is een mooie taal... dit zin stuckje spreekt vanzelf, of niet :)<br/>" \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=UTF-8",
+ },
+ },
+ { .name = "/p2_%E9%E9n.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Die enkele nederlandstalige pagina</title>" \
+ "</head><body><p>&Eacute;&eacute;n is niet veel maar toch meer dan nul.<br/>" \
+ "Nerdelands is een mooie taal... dit zin stuckje spreekt vanzelf, of niet :)<br/>" \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-1",
+ },
+ },
+ { .name = "/p3_%E2%82%AC%E2%82%AC%E2%82%AC.html", // UTF-8 encoded
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Euro page</title>" \
+ "</head><body><p>My tailor isn't rich anymore.</p></body></html>",
+ .headers = {
+ "Content-type: text/plain",
+ },
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-iri-disabled
+ wget_test(
+ // WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "-e robots=on --trust-server-names --local-encoding=UTF-8 --remote-encoding=iso-8859-1 -nH -r",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { "p1_fran" ccedilla_u8 "ais.html", urls[2].body },
+ { "p2_" eacute_u8 eacute_u8 "n.html", urls[3].body },
+ { "p3_" eurosign_u8 eurosign_u8 eurosign_u8 ".html", urls[5].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-iri-list.c b/tests2/test-iri-list.c
new file mode 100644
index 00000000..192d0be8
--- /dev/null
+++ b/tests2/test-iri-list.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 24.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+#define ccedilla_l1 "\xE7"
+#define ccedilla_u8 "\xC3\xA7"
+#define eacute_l1 "\xE9"
+#define eacute_u8 "\xC3\xA9"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>Mainpage</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-15",
+ }
+ },
+ { .name = "/robots.txt",
+ .code = "200 Dontcare",
+ .body = "",
+ .headers = {
+ "Content-type: text/plain",
+ }
+ },
+ { .name = "/p1_fran%C3%A7ais.html", // UTF-8 encoded
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>404</title><p>nop</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=UTF-8",
+ }
+ },
+ { .name = "/p2_%C3%A9%C3%A9n.html", // UTF-8 encoded
+ .code = "200 Dontcare1",
+ .body =
+ "<html><head><title>Die enkele nederlandstalige pagina</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/></head>" \
+ "<body><p>Dutch page</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-1",
+ },
+ },
+ { .name = "/urls.txt",
+ .code = "200 Dontcare",
+ .body =
+ "http://localhost:{{port}}/\r\n" \
+ "http://localhost:{{port}}/p1_fran" ccedilla_l1 "ais.html\r\n" \
+ "http://localhost:{{port}}/p2_" eacute_l1 eacute_l1 "n.html",
+ .headers = {
+ "Content-type: text/plain; charset=ISO-8859-1",
+ },
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-iri-disabled
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--local-encoding=UTF-8 --input-encoding=ISO-8859-1 --iri --trust-server-names -i urls.txt",
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "urls.txt", urls[4].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body }, // index.html
+ { "p1_fran" ccedilla_u8 "ais.html", urls[2].body },
+ { "p2_" eacute_u8 eacute_u8 "n.html", urls[3].body },
+ { "urls.txt", urls[4].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-iri-percent.c b/tests2/test-iri-percent.c
new file mode 100644
index 00000000..072b2935
--- /dev/null
+++ b/tests2/test-iri-percent.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 23.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+// #define ccedilla_l15 "\xE7"
+#define ccedilla_l15_pct "%E7"
+#define ccedilla_u8 "\xC3\xA7"
+#define ccedilla_u8_pct "%C3%A7"
+#define eacute_l15 "\xE9"
+#define eacute_u8 "\xC3\xA9"
+#define eacute_u8_pct "%C3%A9"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>" \
+ "Link to page 1 <a href=\"http://localhost:{{port}}/hello_" ccedilla_l15_pct eacute_l15 ".html\">La seule page en fran&ccedil;ais</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-15",
+ }
+ },
+ { .name = "/hello_" ccedilla_u8_pct eacute_u8_pct ".html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>La seule page en fran" ccedilla_u8 "ais</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-15\"/></head><body>" \
+ "<p></p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=UTF-8",
+ }
+ },
+ { .name = "/robots.txt",
+ .code = "200 Dontcare",
+ .body = "",
+ .headers = {
+ "Content-Type: text/plain",
+ }
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-iri-disabled
+ wget_test(
+ // WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--iri -e robots=off --restrict-file-names=nocontrol -nH -r",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { "hello_" ccedilla_u8 eacute_u8 ".html", urls[1].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-iri.c b/tests2/test-iri.c
new file mode 100644
index 00000000..97fd8d3b
--- /dev/null
+++ b/tests2/test-iri.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 17.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+#define ccedilla_l15 "\xE7"
+#define ccedilla_u8 "\xC3\xA7"
+#define eacute_l15 "\xE9"
+#define eacute_u8 "\xC3\xA9"
+#define eurosign_l15 "\xA4"
+#define eurosign_u8 "\xE2\x82\xAC"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "Link to page 1 <a href=\"http://localhost:{{port}}/p1_fran" ccedilla_l15 "ais.html\">La seule page en fran&ccedil;ais</a>." \
+ "Link to page 3 <a href=\"http://localhost:{{port}}/p3_" eurosign_l15 eurosign_l15 eurosign_l15 ".html\">My tailor is rich</a>.",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-15",
+ }
+ },
+ { .name = "/robots.txt",
+ .code = "200 Dontcare",
+ .body = "",
+ .headers = {
+ "Content-type: text/plain",
+ }
+ },
+ { .name = "/p1_fran%E7ais.html",
+ .code = "404 Not found",
+ .body =
+ "<html><head><title>404</title></head><body><p>What ever</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=UTF-8",
+ }
+ },
+ { .name = "/p1_fran%C3%A7ais.html", // UTF-8 encoded
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>La seule page en fran" ccedilla_l15 "ais</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/></head><body>" \
+ "<p>Link to page 2 <a href=\"http://localhost:{{port}}/p2_" eacute_l15 eacute_l15 "n.html\">Die enkele nerderlangstalige pagina</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=ISO-8859-15", // server response overrides META charset attribute
+ }
+ },
+ { .name = "/p2_%C3%A9%C3%A9n.html", // UTF-8 encoded
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Die enkele nederlandstalige pagina</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-15\"/>" \
+ "</head><body><p>&Eacute;&eacute;n is niet veel maar toch meer dan nul.<br/>" \
+ "Nerdelands is een mooie taal... dit zin stuckje spreekt vanzelf, of niet :)<br/>" \
+ "<a href=\"http://localhost:{{port}}/p4_m" eacute_u8 eacute_u8 "r.html\">M&eacute&eacute;r</a>" \
+ "</p></body></html>",
+ .headers = {
+ "Content-type: text/html; charset=UTF-8", // server response overrides META charset attribute
+ },
+ },
+ { .name = "/p3_%E2%82%AC%E2%82%AC%E2%82%AC.html", // UTF-8 encoded
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Euro page</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>" \
+ "</head><body><p>My tailor isn't rich anymore.</p></body></html>",
+ .headers = {
+ "Content-type: text/plain; charset=ISO-8859-15",
+ },
+ },
+ { .name = "/p3_%A4%A4%A4.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Euro page</title>" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>" \
+ "</head><body><p>My tailor isn't rich anymore.</p></body></html>",
+ .headers = {
+ "Content-type: text/plain; charset=ISO-8859-15",
+ },
+ },
+ { .name = "/p4_m%C3%A9%C3%A9r.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Bekende supermarkt</title></head>" \
+ "<body><p>Ik ben toch niet gek !</p></body></html>",
+ .headers = {
+ "Content-type: text/plain; charset=UTF-8",
+ },
+ },
+ };
+
+ char request_header[256];
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-iri
+ snprintf(request_header, sizeof(request_header),
+ "Referer: http://localhost:%d/p2_%%C3%%A9%%C3%%A9n.html",
+ wget_test_get_http_server_port());
+ urls[4].request_headers[0] = urls[7].request_headers[0] = request_header;
+
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--iri -e robots=on --trust-server-names --restrict-file-names=nocontrol -nH -r",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { "p1_fran" ccedilla_u8 "ais.html", urls[3].body },
+ { "p2_" eacute_u8 eacute_u8 "n.html", urls[4].body },
+ { "p3_" eurosign_u8 eurosign_u8 eurosign_u8 ".html", urls[5].body },
+ { "p4_m" eacute_u8 eacute_u8 "r.html", urls[7].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-k.c b/tests2/test-k.c
new file mode 100644
index 00000000..7de5c8a5
--- /dev/null
+++ b/tests2/test-k.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 15.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <a href=\"second.html\">second page</a>." \
+ " <a href=\"htTp://localhost:{{port}}/second.html\">second page</a>." \
+ " <a href=\"subdir/third.html\">third page</a>." \
+ " <a href=\"htTp://localhost:{{port}}/subdir/third.html\">third page</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/second.html",
+ .code = "200 Dontcare",
+ .body = "<html><head><title>Site</title></head><body>Some Text</body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/subdir/third.html",
+ .code = "200 Dontcare",
+ .body = "<html><head><title>Site</title></head><body>Some Text</body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ };
+
+ const char *converted =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <a href=\"second.html\">second page</a>." \
+ " <a href=\"second.html\">second page</a>." \
+ " <a href=\"subdir/third.html\">third page</a>." \
+ " <a href=\"subdir/third.html\">third page</a>." \
+ "</p></body></html>";
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-k
+ wget_test(
+ WGET_TEST_OPTIONS, "-k -r -nH",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, converted },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-meta-robots.c b/tests2/test-meta-robots.c
new file mode 100644
index 00000000..60c30a30
--- /dev/null
+++ b/tests2/test-meta-robots.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 15.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/start.html",
+ .code = "200 Dontcare",
+ .body =
+ "<meta name= \"roBoTS\" content=\"noFolLow , foo, bar \">" \
+ "<a href=\"/bombshell.html\">Don't follow me!</a>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/mid.html",
+ .code = "200 Dontcare",
+ .body =
+ "<meta name=\"rObOts\" content=\" foo , NOfOllow , bar \">" \
+ "<a href=\"/bombshell.html\">Don't follow me!</a>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/end.html",
+ .code = "200 Dontcare",
+ .body =
+ "<meta name=\"RoBotS\" content=\"foo,BAr, nofOLLOw \">" \
+ "<a href=\"/bombshell.html\">Don't follow me!</a>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/solo.html",
+ .code = "200 Dontcare",
+ .body =
+ "<meta name=\"robots\" content=\"nofollow\">" \
+ "<a href=\"/bombshell.html\">Don't follow me!</a>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/bombshell.html",
+ .code = "200 Dontcare",
+ .body = "What ever",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-meta-robots
+ wget_test(
+ WGET_TEST_OPTIONS, "-r -e robots=on -nd",
+ WGET_TEST_REQUEST_URLS, "start.html", "mid.html", "end.html", "solo.html", NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-np.c b/tests2/test-np.c
new file mode 100644
index 00000000..ac65270f
--- /dev/null
+++ b/tests2/test-np.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright(c) 2014 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 02.07.2014 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/firstlevel/index.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Main Page</title></head><body><p>A link to a" \
+ " <A hreF=\"http://localhost:{{port}}/firstlevel/secondpage.html\">second page</a>." \
+ " <a href=\"file://path/file_to_be_ignored.txt\">Unsupported file scheme</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/firstlevel/secondpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Second Page</title></head><body><p>A link to a" \
+ " <a hRef=\"http://localhost:{{port}}/firstlevel/lowerlevel/thirdpage.html\">third page</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/firstlevel/lowerlevel/thirdpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Third Page</title></head><body><p>A link to a" \
+ " <A href=\"http://localhost:{{port}}/higherlevelpage.html\">higher level page</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/firstlevel/fourthpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Fourth Page</title></head><body><p>" \
+ "This page is only linked by the higher level page. Therefore, it should not be downloaded." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/higherlevelpage.html",
+ .code = "200 Dontcare",
+ .body =
+ "<html><head><title>Higher Level Page</title></head><body><p>" \
+ "This page is on a higher level in the URL path hierarchy. Therefore, it" \
+ "should not be downloaded. Wget should not visit the following link to a" \
+ " <a Href=\"http://localhost:{{port}}/firstlevel/fourthpage.html\">fourth page</a>." \
+ "</p></body></html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-i
+ wget_test(
+ WGET_TEST_OPTIONS, "-np -nH -r",
+ WGET_TEST_REQUEST_URL, "firstlevel/",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-parse-html.c b/tests2/test-parse-html.c
new file mode 100644
index 00000000..9241a533
--- /dev/null
+++ b/tests2/test-parse-html.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright(c) 2012 Tim Ruehsen
+ *
+ * This file is part of MGet.
+ *
+ * Wget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Wget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Wget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * test routines
+ *
+ * Changelog
+ * 16.08.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+#include <libwget.h>
+#include "../libwget/private.h"
+#include "../src2/options.h"
+
+static int
+ ok,
+ failed;
+
+static const char *test_data[] ={
+ "<!doctype html>\n"\
+ "<!--[if lt IE 7 ]> <html class=\"no-js ie6\" lang=\"en\"> <![endif]-->\n"\
+ "<!--[if (gte IE 9)|!(IE)]><!--> <html class=\"no-js\"> <!--<![endif]-->\n"\
+ "<head>\n"\
+ " <meta charset=\"utf-8\">\n"\
+ " <script>window.jQuery || document.write(\"<script src='/common/inc/js/jquery-1.5.1.min.js'><\\/script>\")</script>\n"\
+ " <script src=\"/common/inc/js/core.js?v=1\"></script>\n"\
+ "</head>\n"\
+ "<body>\n"\
+ " <ul>\n"\
+ " <li><a href=\"/solutions/platform.html#server\">Server</a></li>\n"\
+ " <li><a href=\"/solutions/platform.html#desktop\">Desktop</a></li>\n"\
+ " </ul>\n"\
+ "</body>\n"\
+ "</html>\n"
+};
+
+static void html_dump(void *user_ctx, int flags, const char *dir G_GNUC_WGET_UNUSED, const char *attr, const char *val, size_t len, size_t pos)
+{
+// info_printf("\n%02X %s %s '%.*s' %zd %zd\n", flags, dir, attr, (int) len, val, len, pos);
+ if ((flags & XML_FLG_ATTRIBUTE) && val) {
+ int found = 0;
+
+ // info_printf("%02X %s %s '%.*s' %zd %zd\n", flags, dir, attr, (int) len, val, len, pos);
+
+ // very simplified
+ // see http://stackoverflow.com/questions/2725156/complete-list-of-html-tag-attributes-which-have-a-url-value
+ switch (tolower(*attr)) {
+ case 'h':
+ found = !wget_strcasecmp_ascii(attr, "href");
+ break;
+ case 's':
+ found = !wget_strcasecmp_ascii(attr, "src");
+ break;
+ }
+
+ if (found) {
+ // check if len and pos matches
+ const char *doc = (const char *)user_ctx;
+
+ if (memcmp(doc + pos, val, len)) {
+ failed++;
+ error_printf_exit("Not found: '%.*s' expected at pos %zd with length %zd\n", (int) len, val, pos, len);
+ } else
+ ok++;
+ }
+ }
+ return;
+/*
+ if (flags & XML_FLG_BEGIN) {
+ const char *p = *dir == '/' ? strrchr(dir, '/') : dir;
+ if (p) {
+ if (*dir == '/') p++;
+ if (flags == (XML_FLG_BEGIN | XML_FLG_END)) {
+ info_printf("<%s/>", p);
+ return;
+ }
+ info_printf("<%s", p);
+ }
+ }
+ if (flags & XML_FLG_ATTRIBUTE) {
+ if (val)
+ info_printf(" %s=\"%.*s\"", attr, (int) len, val);
+ else
+ info_printf(" %s", attr); // HTML bareword attribute
+ }
+ if (flags & XML_FLG_CLOSE) {
+ info_printf(">");
+ }
+ if (flags & XML_FLG_CONTENT) {
+ info_printf("%.*s", (int) len, val);
+ }
+ if (flags & XML_FLG_END) {
+ const char *p = *dir == '/' ? strrchr(dir, '/') : dir;
+ if (p) {
+ if (*dir == '/') p++;
+ info_printf("</%s>", p);
+ }
+ }
+
+ if (flags == XML_FLG_COMMENT)
+ info_printf("<!--%.*s-->", (int) len, val);
+ else if (flags == XML_FLG_PROCESSING)
+ info_printf("<?%.*s?>", (int) len, val);
+ else if (flags == XML_FLG_SPECIAL)
+ info_printf("<!%.*s>", (int) len, val);
+*/
+}
+
+static void test_parse_buffer(void)
+{
+ unsigned it;
+
+ for (it = 0; it < countof(test_data); it++) {
+ wget_html_parse_buffer(test_data[it], html_dump, (void *)test_data[it], 0);
+ }
+}
+
+static void test_parse_files(void)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ const char *ext;
+ char fname[128];
+ int xml = 0, html = 0, css = 0, type;
+
+ // test the XML / HTML parser, you should start the test with valgrind
+ // to detect memory faults
+ if ((dirp = opendir(SRCDIR "/files")) != NULL) {
+ while ((dp = readdir(dirp)) != NULL) {
+ if (*dp->d_name == '.') continue;
+ if ((ext = strrchr(dp->d_name, '.'))) {
+ if (!wget_strcasecmp_ascii(ext, ".xml"))
+ type = 1;
+ else if (!wget_strcasecmp_ascii(ext, ".html"))
+ type = 2;
+ else
+ continue;
+
+ snprintf(fname, sizeof(fname), SRCDIR "/files/%s", dp->d_name);
+ info_printf("parsing %s\n", fname);
+
+ char *data;
+
+ if ((data = wget_read_file(fname, NULL))) {
+ if (type == 1) {
+ wget_xml_parse_buffer(data, html_dump, data, 0);
+ xml++;
+ } else {
+ wget_html_parse_buffer(data, html_dump, data, 0);
+ html++;
+ }
+
+ xfree(data);
+ }
+ }
+ }
+ closedir(dirp);
+ }
+
+ info_printf("%d XML, %d HTML and %d CSS files parsed\n", xml, html, css);
+}
+
+int main(int argc, const char * const *argv)
+{
+ init(argc, argv); // allows us to test with options (e.g. with --debug)
+
+ test_parse_buffer();
+ test_parse_files();
+
+ deinit(); // free resources allocated by init()
+
+ if (failed) {
+ info_printf("Summary: %d out of %d tests failed\n", failed, ok + failed);
+ return 1;
+ }
+
+ info_printf("Summary: All %d tests passed\n", ok + failed);
+ return 0;
+}
diff --git a/tests2/test-parse-rss.c b/tests2/test-parse-rss.c
new file mode 100644
index 00000000..0c0a7ef6
--- /dev/null
+++ b/tests2/test-parse-rss.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 25.12.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include <string.h> // strlen()
+#include "libtest.h"
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/main.rss",
+ .body =
+"<?xml version=\"1.0\" encoding=\"utf-8\"?>"\
+"<channel>"\
+"<title>Da title</title>"\
+"<link>http://localhost:{{port}}/page1.html</link>"\
+"<description>Nice article</description>"\
+"<item>"\
+"<title>Item title</title>"\
+"<link>http://localhost:{{port}}/page2.html</link>"\
+"<pubDate>Sun, 01 Sep 2013 18:41:05 -0700</pubDate>"\
+"<guid isPermaLink=\"true\">http://localhost:{{port}}/page3.html</guid>"\
+"<description>item description</description>"\
+"</item></channel></rss>",
+ },
+ { .name = "/page1.html",
+ .code = "200 Dontcare",
+ .body = "<html>hello1</html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/page2.html",
+ .code = "200 Dontcare",
+ .body = "<html>hello2</html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/page3.html",
+ .code = "200 Dontcare",
+ .body = "<html>hello3</html>",
+ .headers = {
+ "Content-Type: text/html",
+ }
+ }
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test--parse-rss
+ wget_test(
+ // WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--force-rss -i main.rss",
+ WGET_TEST_REQUEST_URL, NULL,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "main.rss", urls[0].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { urls[1].name + 1, urls[1].body },
+ { urls[2].name + 1, urls[2].body },
+ { urls[3].name + 1, urls[3].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test-restrict-ascii.c b/tests2/test-restrict-ascii.c
new file mode 100644
index 00000000..3939d5b5
--- /dev/null
+++ b/tests2/test-restrict-ascii.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 08.07.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include <string.h> // strlen()
+#include "libtest.h"
+
+static const char *mainpage = "\
+<html>\n\
+<head>\n\
+ <title>Main Page</title>\n\
+</head>\n\
+<body>\n\
+ <p>\n\
+ Don't care.\n\
+ </p>\n\
+</body>\n\
+</html>\n";
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+// { .name = "/%CE%B3%CE%BD%CF%89%CF%83%CE%B9%CF%82.html", // "gnosis" in UTF-8 greek
+ { .name = "/%CE%B3%CE%BD%E1%BF%B6%CF%83%CE%B9%CF%82.html", // "gnosis" in UTF-8 greek
+ .code = "200 Dontcare",
+ .body = mainpage,
+ .headers = {
+ "Content-Type: text/html",
+ }
+ }
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-restrict-ascii
+ wget_test(
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--restrict-file-names=ascii",
+ WGET_TEST_REQUEST_URL, urls[0].name + 1,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { NULL } },
+ 0);
+
+ // test-restrict-ascii
+/*
+ wget_test(
+ WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_OPTIONS, "--local-encoding=utf-8",
+ WGET_TEST_REQUEST_URL, urls[0].name + 1,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { urls[0].name + 1, urls[0].body },
+ { NULL } },
+ 0);
+*/
+ exit(0);
+}
diff --git a/tests2/test-wget-1.c b/tests2/test-wget-1.c
new file mode 100644
index 00000000..ee1c3b27
--- /dev/null
+++ b/tests2/test-wget-1.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright(c) 2013 Tim Ruehsen
+ *
+ * This file is part of libwget.
+ *
+ * Libwget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Libwget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libwget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Testing Wget
+ *
+ * Changelog
+ * 10.03.2013 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // exit()
+#include <string.h> // strlen()
+#include "libtest.h"
+
+static const char *mainpage = "\
+<html>\n\
+<head>\n\
+ <title>Main Page</title>\n\
+</head>\n\
+<body>\n\
+ <p>\n\
+ Some text and a link to a <a href=\"http://localhost:{{port}}/secondpage.html\">second page</a>.\n\
+ Also, a <a href=\"http://localhost:{{port}}/nonexistent\">broken link</a>.\n\
+ </p>\n\
+</body>\n\
+</html>\n";
+
+static const char *secondpage = "\
+<html>\n\
+<head>\n\
+ <title>Main Page</title>\n\
+</head>\n\
+<body>\n\
+ <p>\n\
+ Some text and a link to a <a href=\"http://localhost:{{port}}/thirdpage.html\">third page</a>.\n\
+ Also, a <a href=\"http://localhost:{{port}}/nonexistent\">broken link</a>.\n\
+ </p>\n\
+</body>\n\
+</html>\n";
+
+static const char *thirdpage = "\
+<html>\n\
+<head>\n\
+ <title>Main Page</title>\n\
+</head>\n\
+<body>\n\
+ <p>\n\
+ Some text and a link to a <a href=\"http://localhost:{{port}}/dummy.txt\">dummy text</a>.\n\
+ Also, a <a href=\"http://localhost:{{port}}/againnonexistent\">broken link</a>.\n\
+ </p>\n\
+</body>\n\
+</html>\n";
+
+static const char *dummypage = "\
+<html>\n\
+<head>\n\
+ <title>Main Page</title>\n\
+</head>\n\
+<body>\n\
+ <p>\n\
+ Don't care.\n\
+ </p>\n\
+</body>\n\
+</html>\n";
+
+int main(void)
+{
+ wget_test_url_t urls[]={
+ { .name = "/index.html",
+ .code = "200 Dontcare",
+ .body = mainpage,
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/secondpage.html",
+ .code = "200 Dontcare",
+ .body = secondpage,
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/thirdpage.html",
+ .code = "200 Dontcare",
+ .body = thirdpage,
+ .headers = {
+ "Content-Type: text/html",
+ }
+ },
+ { .name = "/dummy.txt",
+ .code = "200 Dontcare",
+ .body = "Don't care.",
+ .headers = {
+ "Content-Type: text/plain",
+ },
+ },
+ { .name = "/dummy.html",
+ .code = "200 Dontcare",
+ .body = dummypage,
+ .headers = {
+ "Content-Type: text/plain",
+ "Content-Disposition: attachment; filename=\"filename.html\"",
+ }
+ },
+ { .name = "/dummy2.html",
+ .code = "200 Dontcare",
+ .body = dummypage,
+ .headers = {
+ "Content-Type: text/plain",
+ "Content-Disposition: attachment; filename*=UTF-8''%66ile_fran%c3%A7ais.html",
+ }
+ }
+ };
+
+ // functions won't come back if an error occurs
+ wget_test_start_server(
+ WGET_TEST_RESPONSE_URLS, &urls, countof(urls),
+ 0);
+
+ // test-noop
+ wget_test(
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "index.html", urls[0].body },
+ { NULL } },
+ 0);
+
+ // test-nonexistent-quiet
+ wget_test(
+ WGET_TEST_OPTIONS, "--quiet",
+ WGET_TEST_REQUEST_URL, "nonexistent",
+ WGET_TEST_EXPECTED_ERROR_CODE, 8,
+ 0);
+
+ // test-stdouterr
+ wget_test(
+ WGET_TEST_OPTIONS, "-c -O /dev/full",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 3,
+ 0);
+
+ // test--spider
+ wget_test(
+ WGET_TEST_OPTIONS, "--spider",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ 0);
+
+ // test--spider-fail
+ wget_test(
+ WGET_TEST_OPTIONS, "--spider",
+ WGET_TEST_REQUEST_URL, "nonexistent",
+ WGET_TEST_EXPECTED_ERROR_CODE, 8,
+ 0);
+
+ // test--spider-r--no-content-disposition-trivial
+ wget_test(
+ WGET_TEST_OPTIONS, "--spider -r --no-content-disposition",
+ WGET_TEST_REQUEST_URL, "",
+ WGET_TEST_EXPECTED_ERROR_CODE, 8,
+ 0);
+
+ // test--no-content-disposition-trivial
+ wget_test(
+ WGET_TEST_OPTIONS, "--no-content-disposition",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "index.html", urls[0].body },
+ { NULL } },
+ 0);
+
+ urls[1].headers[1] = "Content-Disposition: attachment; filename=\"filename.html\"";
+
+ // test--no-content-disposition
+ wget_test(
+ WGET_TEST_OPTIONS, "--no-content-disposition",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "index.html", urls[0].body },
+ { NULL } },
+ 0);
+
+ // test--spider-r--no-content-disposition
+ wget_test(
+ WGET_TEST_OPTIONS, "--spider -r --no-content-disposition",
+ WGET_TEST_REQUEST_URL, "",
+ WGET_TEST_EXPECTED_ERROR_CODE, 8,
+ 0);
+
+ urls[1].headers[1] = NULL;
+
+ // test--HTTP-content-disposition
+ wget_test(
+ WGET_TEST_OPTIONS, "-e contentdisposition=on",
+ WGET_TEST_REQUEST_URL, "dummy.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "filename.html", dummypage },
+ { NULL } },
+ 0);
+
+ // test--HTTP-content-disposition-1
+ wget_test(
+ WGET_TEST_OPTIONS, "-e contentdisposition=on",
+ WGET_TEST_REQUEST_URL, "dummy.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "filename.html", "dontcare" },
+ { "filename.html.1", "dontcare" },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "filename.html", "dontcare" },
+ { "filename.html.1", "dontcare" },
+ { "filename.html.2", dummypage },
+ { NULL } },
+ 0);
+
+ // test--HTTP-content-disposition-2
+ wget_test(
+ WGET_TEST_OPTIONS, "--no-content-disposition",
+ WGET_TEST_REQUEST_URL, "dummy.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "filename.html", "dontcare" },
+ { "filename.html.1", "dontcare" },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "filename.html", "dontcare" },
+ { "filename.html.1", "dontcare" },
+ { "dummy.html", dummypage },
+ { NULL } },
+ 0);
+
+ // test--HTTP-content-disposition-RFC6266
+#define ccedilla_u8 "\xC3\xA7"
+ wget_test(
+ WGET_TEST_OPTIONS, "-e contentdisposition=on --local-encoding=utf-8",
+ WGET_TEST_REQUEST_URL, "dummy2.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "filename.html", "dontcare" },
+ { "filename.html.1", "dontcare" },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "filename.html", "dontcare" },
+ { "filename.html.1", "dontcare" },
+ { "file_fran" ccedilla_u8 "ais.html", dummypage },
+ { NULL } },
+ 0);
+
+ urls[3].headers[1] = "Last-Modified: Sat, 09 Oct 2004 08:30:00 GMT";
+
+ // test-N--no-content-disposition-trivial
+ wget_test(
+ WGET_TEST_OPTIONS, "-N --no-content-disposition",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body, 1097310600 },
+ { NULL } },
+ 0);
+
+ urls[3].headers[2] = "Content-Disposition: attachment; filename=\"filename.txt\"";
+
+ // test-N--no-content-disposition
+ wget_test(
+ WGET_TEST_OPTIONS, "-N --no-content-disposition",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body, 1097310600 },
+ { NULL } },
+ 0);
+
+ // test-N-HTTP--content-disposition
+ wget_test(
+ WGET_TEST_OPTIONS, "-N --content-disposition",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "filename.txt", urls[3].body, 1097310600 },
+ { NULL } },
+ 0);
+
+ urls[3].headers[2] = NULL;
+
+ {
+ // server sends same length content with slightly different content
+ char modified[strlen(urls[3].body) + 1];
+
+ strcpy(modified,urls[3].body);
+ modified[3] = 'x';
+
+ urls[3].modified = 1097310600;
+
+ // test-N-current
+ wget_test(
+ WGET_TEST_OPTIONS, "-N",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", modified, 1097310600 },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", modified, 1097310600 },
+ { NULL } },
+ 0);
+
+ // test-N-old
+ wget_test(
+ WGET_TEST_OPTIONS, "-N",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", modified, 1097310000 }, // earlier timestamp
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body, 1097310600 },
+ { NULL } },
+ 0);
+
+/*
+ // test-N-smaller
+ // This test just works with a HEAD request. But Wget uses If-Modified-Since.
+ const char *old_body = urls[3].body;
+ modified[strlen(modified)-2] = 0;
+ urls[3].body = modified;
+ wget_test(
+ WGET_TEST_OPTIONS, "-N",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", old_body, 1097310600 },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", modified, 1097310600 },
+ { NULL } },
+ 0);
+ urls[3].body = old_body; // restore body
+*/
+ }
+
+ // test-N
+ wget_test(
+ WGET_TEST_OPTIONS, "-N",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body, 0},
+ { NULL } },
+ 0);
+
+ urls[3].headers[1] = NULL;
+
+/*
+ // test-N-no-info
+ // This test just works with a HEAD request. But Wget uses If-Modified-Since.
+ wget_test(
+ WGET_TEST_OPTIONS, "-N",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", "anycontent", 1097310600 },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body, 0},
+ { NULL } },
+ 0);
+*/
+
+ urls[1].headers[1] = "Content-Disposition: attachment; filename=\"filename.html\"";
+
+ // test-O--no-content-disposition
+ wget_test(
+ WGET_TEST_OPTIONS, "-O out --no-content-disposition",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "out", urls[3].body },
+ { NULL } },
+ 0);
+
+ // test-O-HTTP-content-disposition
+ wget_test(
+ WGET_TEST_OPTIONS, "-O out",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "out", urls[3].body },
+ { NULL } },
+ 0);
+
+
+ urls[3].headers[1] = NULL;
+
+ // test-O-nc
+ wget_test(
+ WGET_TEST_OPTIONS, "-nc -O out",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "out", urls[3].body },
+ { NULL } },
+ 0);
+
+ // test-O-nonexisting
+ wget_test(
+ WGET_TEST_OPTIONS, "-O out",
+ WGET_TEST_REQUEST_URL, "nonexistent",
+ WGET_TEST_EXPECTED_ERROR_CODE, 8,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ // { "out", "" }, // Wget would create an empty file here, but Wget not
+ { NULL } },
+ 0);
+
+ // test-O
+ wget_test(
+ WGET_TEST_OPTIONS, "-O out",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "out", urls[3].body },
+ { NULL } },
+ 0);
+
+ // test-restrict-lowercase
+ urls[3].name="/DuMmy.Txt";
+ wget_test(
+ WGET_TEST_OPTIONS, "--restrict-file-names=lowercase",
+ WGET_TEST_REQUEST_URL, "DuMmy.Txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body },
+ { NULL } },
+ 0);
+
+ // test-restrict-uppercase
+ wget_test(
+ WGET_TEST_OPTIONS, "--restrict-file-names=uppercase",
+ WGET_TEST_REQUEST_URL, "DuMmy.Txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "DUMMY.TXT", urls[3].body },
+ { NULL } },
+ 0);
+ urls[3].name="/dummy.txt";
+
+ // test-c-full
+ wget_test(
+ WGET_TEST_OPTIONS, "-c",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body },
+ { NULL } },
+ 0);
+
+ {
+ // server sends same length content with slightly different content
+ char *partial = strndup(urls[3].body, strlen(urls[3].body)-2);
+
+ // test-c-partial
+ wget_test(
+ WGET_TEST_OPTIONS, "-c",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", partial },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body },
+ { NULL } },
+ 0);
+
+ wget_xfree(partial);
+ }
+
+/*
+ * this test needs a broken server ... I don't have one right now.
+ {
+ // server sends same length content with slightly different content
+ char *partial = strndup(urls[3].body, strlen(urls[3].body)-2);
+ const char *old_body = urls[3].body;
+ urls[3].body = "";
+
+ // test-c-shorter
+ wget_test(
+ WGET_TEST_OPTIONS, "-d -c",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+// WGET_TEST_KEEP_TMPFILES, 1,
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXISTING_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", partial },
+ { NULL } },
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body },
+ { NULL } },
+ 0);
+
+ urls[3].body = old_body;
+ wget_xfree(partial);
+ }
+*/
+ // test-c
+ wget_test(
+ WGET_TEST_OPTIONS, "-c",
+ WGET_TEST_REQUEST_URL, "dummy.txt",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ // no existing file
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "dummy.txt", urls[3].body },
+ { NULL } },
+ 0);
+
+ // test--https-only
+ wget_test(
+ WGET_TEST_OPTIONS, "--https-only -r -nH",
+ WGET_TEST_REQUEST_URL, "index.html",
+ WGET_TEST_EXPECTED_ERROR_CODE, 0,
+ WGET_TEST_EXPECTED_FILES, &(wget_test_file_t []) {
+ { "index.html", urls[0].body },
+ { NULL } },
+ 0);
+
+ exit(0);
+}
diff --git a/tests2/test.c b/tests2/test.c
new file mode 100644
index 00000000..57f6c91b
--- /dev/null
+++ b/tests2/test.c
@@ -0,0 +1,1499 @@
+/*
+ * Copyright(c) 2012 Tim Ruehsen
+ *
+ * This file is part of MGet.
+ *
+ * Wget is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Wget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Wget. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * test routines
+ *
+ * Changelog
+ * 06.07.2012 Tim Ruehsen created
+ *
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <time.h>
+
+#include <libwget.h>
+#include "../libwget/private.h"
+
+#include "../src2/options.h"
+#include "../src2/log.h"
+
+static int
+ ok,
+ failed;
+
+static void _test_buffer(wget_buffer_t *buf, const char *name)
+{
+ char test[256];
+ int it;
+
+ for (it = 0; it < (int)sizeof(test)-1; it++) {
+ test[it] = 'a' + it % 26;
+ test[it + 1] = 0;
+
+ wget_buffer_strcpy(buf, test);
+ wget_buffer_strcat(buf, test);
+
+ if (!strncmp(buf->data, test, it + 1) && !strncmp(buf->data + it + 1, test, it + 1)) {
+ ok++;
+ } else {
+ failed++;
+ info_printf("test_buffer.1 '%s': [%d] got %s (expected %s%s)\n", name, it, buf->data, test, test);
+ }
+
+ wget_buffer_memcpy(buf, test, it + 1);
+ wget_buffer_memcat(buf, test, it + 1);
+
+ if (!strncmp(buf->data, test, it + 1) && !strncmp(buf->data + it + 1, test, it + 1)) {
+ ok++;
+ } else {
+ failed++;
+ info_printf("test_buffer.2 '%s': [%d] got %s (expected %s%s)\n", name, it, buf->data, test, test);
+ }
+
+ wget_buffer_printf(buf, "%s%s", test, test);
+
+ if (!strncmp(buf->data, test, it + 1) && !strncmp(buf->data + it + 1, test, it + 1)) {
+ ok++;
+ } else {
+ failed++;
+ info_printf("test_buffer.3 '%s': [%d] got %s (expected %s%s)\n", name, it, buf->data, test, test);
+ }
+
+ wget_buffer_printf(buf, "%s", test);
+ wget_buffer_printf_append(buf, "%s", test);
+
+ if (!strncmp(buf->data, test, it + 1) && !strncmp(buf->data + it + 1, test, it + 1)) {
+ ok++;
+ } else {
+ failed++;
+ info_printf("test_buffer.4 '%s': [%d] got %s (expected %s%s)\n", name, it, buf->data, test, test);
+ }
+ }
+}
+
+static void test_buffer(void)
+{
+ char sbuf[16];
+ wget_buffer_t buf, *bufp;
+
+ // testing buffer on stack, using initial stack memory
+ // without resizing
+
+ wget_buffer_init(&buf, sbuf, sizeof(sbuf));
+ wget_buffer_deinit(&buf);
+
+ // testing buffer on stack, using initial stack memory
+ // with resizing
+
+ wget_buffer_init(&buf, sbuf, sizeof(sbuf));
+ _test_buffer(&buf, "Test 1");
+ wget_buffer_deinit(&buf);
+
+ // testing buffer on stack, using initial heap memory
+ // without resizing
+
+ wget_buffer_init(&buf, NULL, 16);
+ wget_buffer_deinit(&buf);
+
+ // testing buffer on stack, using initial heap memory
+ // with resizing
+
+ wget_buffer_init(&buf, NULL, 16);
+ _test_buffer(&buf, "Test 2");
+ wget_buffer_deinit(&buf);
+
+ // testing buffer on heap, using initial stack memory
+ // without resizing
+
+ bufp = wget_buffer_init(NULL, sbuf, sizeof(sbuf));
+ wget_buffer_deinit(bufp);
+
+ bufp = wget_buffer_init(NULL, sbuf, sizeof(sbuf));
+ wget_buffer_free(&bufp);
+
+ // testing buffer on heap, using initial stack memory
+ // with resizing
+
+ bufp = wget_buffer_init(NULL, sbuf, sizeof(sbuf));
+ _test_buffer(bufp, "Test 3");
+ wget_buffer_deinit(bufp);
+
+ bufp = wget_buffer_init(NULL, sbuf, sizeof(sbuf));
+ _test_buffer(bufp, "Test 4");
+ wget_buffer_free(&bufp);
+
+ // testing buffer on heap, using initial heap memory
+ // without resizing
+
+ bufp = wget_buffer_alloc(16);
+ wget_buffer_free(&bufp);
+
+ // testing buffer on heap, using initial heap memory
+ // with resizing
+
+ bufp = wget_buffer_alloc(16);
+ _test_buffer(bufp, "Test 5");
+ wget_buffer_free(&bufp);
+
+ // check that appending works
+
+ wget_buffer_init(&buf, sbuf, sizeof(sbuf));
+ wget_buffer_strcpy(&buf, "A");
+ wget_buffer_strcat(&buf, "B");
+ wget_buffer_memcat(&buf, "C", 1);
+ wget_buffer_memset_append(&buf, 'D', 1);
+ wget_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");
+ }
+ wget_buffer_deinit(&buf);
+
+ // test wget_buffer_trim()
+
+ wget_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++) {
+ wget_buffer_printf2(&buf, "%.*sx%.*sy%.*s", lead_ws, " ", mid_ws, " ", trail_ws, " ");
+ wget_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);
+ }
+ }
+ }
+ }
+ wget_buffer_deinit(&buf);
+}
+
+static void test_buffer_printf(void)
+{
+ char buf_static[32];
+ wget_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;
+
+ wget_buffer_init(&buf, buf_static, sizeof(buf_static));
+
+ wget_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);
+ wget_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);
+ wget_buffer_printf2(&buf, fmt, string);
+ } else {
+ sprintf(result, fmt, precision, string);
+ wget_buffer_printf2(&buf, fmt, precision, string);
+ }
+ } else {
+ if (precision == -1) {
+ sprintf(result, fmt, width, string);
+ wget_buffer_printf2(&buf, fmt, width, string);
+ } else {
+ sprintf(result, fmt, width, precision, string);
+ wget_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]);
+ wget_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++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ wget_buffer_deinit(&buf);
+}
+
+static void test_iri_parse(void)
+{
+ const struct iri_test_data {
+ const char
+ *uri,
+ *display,
+ *scheme,
+ *userinfo,
+ *password,
+ *host,
+ *port,
+ *path,
+ *query,
+ *fragment;
+ } test_data[] = {
+ { "1.2.3.4", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "1.2.3.4", NULL, NULL, NULL, NULL},
+ { "1.2.3.4:987", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "1.2.3.4", "987", NULL, NULL, NULL},
+ { "//example.com/thepath", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, "thepath", NULL, NULL},
+ // { "///thepath", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, NULL, NULL, "thepath", NULL, NULL},
+ { "example.com", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, NULL, NULL, NULL},
+ { "example.com:555", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", "555", NULL, NULL, NULL},
+ { "http://example.com", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, NULL, NULL, NULL},
+ { "http://example.com:", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, NULL, NULL, NULL},
+ { "http://example.com:/", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, "", NULL, NULL},
+ { "http://example.com:80/", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, "", NULL, NULL},
+ { "https://example.com", NULL, WGET_IRI_SCHEME_HTTPS, NULL, NULL, "example.com", NULL, NULL, NULL, NULL},
+ { "https://example.com:443", NULL, WGET_IRI_SCHEME_HTTPS, NULL, NULL, "example.com", NULL, NULL, NULL, NULL},
+ { "https://example.com:444", NULL, WGET_IRI_SCHEME_HTTPS, NULL, NULL, "example.com", "444", NULL, NULL, NULL},
+ { "http://example.com:80", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, NULL, NULL, NULL},
+ { "http://example.com:81", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", "81", NULL, NULL, NULL},
+ { "http://example.com/index.html", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, "index.html", NULL, NULL},
+ { "http://example.com/index.html?query#frag", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, "index.html", "query", "frag"},
+ { "http://example.com/index.html?#", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "example.com", NULL, "index.html", "", ""},
+ { "碼標準萬國碼.com", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "xn--9cs565brid46mda086o.com", NULL, NULL, NULL, NULL},
+ // { "ftp://cnn.example.com&story=breaking_news@10.0.0.1/top_story.htm", NULL,"ftp",NULL,NULL,"cnn.example.com",NULL,NULL,"story=breaking_news@10.0.0.1/top_story.htm",NULL }
+ { "ftp://cnn.example.com?story=breaking_news@10.0.0.1/top_story.htm", NULL, "ftp", NULL, NULL, "cnn.example.com", NULL, NULL, "story=breaking_news@10.0.0.1/top_story.htm", NULL},
+// { "site;sub:.html", NULL, WGET_IRI_SCHEME_HTTP, NULL, NULL, "site", NULL, ";sub:.html", NULL, NULL},
+ };
+ unsigned it;
+
+ for (it = 0; it < countof(test_data); it++) {
+ const struct iri_test_data *t = &test_data[it];
+ wget_iri_t *iri = wget_iri_parse(t->uri, "utf-8");
+
+ if (wget_strcmp(iri->display, t->display)
+ || wget_strcmp(iri->scheme, t->scheme)
+ || wget_strcmp(iri->userinfo, t->userinfo)
+ || wget_strcmp(iri->password, t->password)
+ || wget_strcmp(iri->host, t->host)
+ || wget_strcmp(iri->port, t->port)
+ || wget_strcmp(iri->path, t->path)
+ || wget_strcmp(iri->query, t->query)
+ || wget_strcmp(iri->fragment, t->fragment))
+ {
+ failed++;
+ printf("IRI test #%u failed:\n", it + 1);
+ printf(" [%s]\n", iri->uri);
+ printf(" display %s (expected %s)\n", iri->display, t->display);
+ printf(" scheme %s (expected %s)\n", iri->scheme, t->scheme);
+ printf(" user %s (expected %s)\n", iri->userinfo, t->userinfo);
+ printf(" host %s (expected %s)\n", iri->host, t->host);
+ printf(" port %s (expected %s)\n", iri->port, t->port);
+ printf(" path %s (expected %s)\n", iri->path, t->path);
+ printf(" query %s (expected %s)\n", iri->query, t->query);
+ printf(" fragment %s (expected %s)\n", iri->fragment, t->fragment);
+ printf("\n");
+ } else {
+ ok++;
+ }
+
+ wget_iri_free(&iri);
+ }
+}
+
+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
+ wget_buffer_t *uri_buf = wget_buffer_init(NULL, uri_buf_static, sizeof(uri_buf_static));
+ wget_iri_t *base;
+
+ for (it = 0; it < countof(test_data); it++) {
+ const struct iri_test_data *t = &test_data[it];
+
+ base = wget_iri_parse(t->base, "utf-8");
+ wget_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);
+ }
+
+ wget_iri_free(&base);
+ }
+
+ wget_buffer_free(&uri_buf);
+}
+
+static void test_iri_compare(void)
+{
+ static const struct iri_test_data {
+ const char
+ *url1,
+ *url2;
+ int
+ result;
+ } test_data[] = {
+ { "http://abc.com", "http://abc.com/", -1}, // different, some web servers redirect ... to .../ due to normalization issues
+ { "http://abc.com", "http://abc.com:", 0},
+ { "http://abc.com", "http://abc.com:/", -1},
+ { "http://abc.com", "http://abc.com:80/", -1},
+ { "http://abc.com", "http://abc.com:80//", -1},
+ // { "http://äöü.com", "http://ÄÖÜ.com:80//", 0},
+ { "http://abc.com:80/~smith/home.html", "http://abc.com/~smith/home.html", 0},
+ { "http://abc.com:80/~smith/home.html", "http://ABC.com/~smith/home.html", 0},
+ { "http://abc.com:80/~smith/home.html", "http://ABC.com/%7Esmith/home.html", 0},
+ { "http://abc.com:80/~smith/home.html", "http://ABC.com/%7esmith/home.html", 0},
+ { "http://ABC.com/%7esmith/home.html", "http://ABC.com/%7Esmith/home.html", 0},
+ { "http://ABC.com/%7esmith/home.html", "http://ACB.com/%7Esmith/home.html", -1}
+ };
+ unsigned it;
+ int n;
+
+ for (it = 0; it < countof(test_data); it++) {
+ const struct iri_test_data *t = &test_data[it];
+ wget_iri_t *iri1 = wget_iri_parse(t->url1, "utf-8");
+ wget_iri_t *iri2 = wget_iri_parse(t->url2, "utf-8");
+
+ n = wget_iri_compare(iri1, iri2);
+ if (n < -1) n = -1;
+ else if (n > 1) n = 1;
+
+ if (n == t->result)
+ ok++;
+ else {
+ failed++;
+ info_printf("Failed [%u]: compare(%s,%s) -> %d (expected %d)\n", it, t->url1, t->url2, n, t->result);
+ printf(" display %s / %s\n", iri1->display, iri2->display);
+ printf(" scheme %s / %s\n", iri1->scheme, iri2->scheme);
+ printf(" user %s / %s\n", iri1->userinfo, iri2->userinfo);
+ printf(" host %s / %s\n", iri1->host, iri2->host);
+ printf(" port %s / %s\n", iri1->port, iri2->port);
+ printf(" path %s / %s\n", iri1->path, iri2->path);
+ printf(" query %s / %s\n", iri1->query, iri2->query);
+ printf(" fragment %s / %s\n", iri1->fragment, iri2->fragment);
+ printf("\n");
+ }
+
+ wget_iri_free(&iri2);
+ wget_iri_free(&iri1);
+ }
+}
+
+/*
+static void _css_dump_charset(G_GNUC_WGET_UNUSED void *user_ctx, const char *encoding, size_t len)
+{
+ debug_printf(_("URI content encoding = '%.*s'\n"), (int)len, encoding);
+}
+
+static void _css_dump_uri(G_GNUC_WGET_UNUSED void *user_ctx, const char *url, size_t len, G_GNUC_WGET_UNUSED size_t pos)
+{
+ debug_printf("*** %zu '%.*s'\n", len, (int)len, url);
+}
+*/
+
+static void test_parser(void)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ const char *ext;
+ char fname[128];
+ int xml = 0, html = 0, css = 0;
+
+ // test the XML / HTML parser, you should start the test with valgrind
+ // to detect memory faults
+ if ((dirp = opendir(SRCDIR "/files")) != NULL) {
+ while ((dp = readdir(dirp)) != NULL) {
+ if (*dp->d_name == '.') continue;
+ if ((ext = strrchr(dp->d_name, '.'))) {
+ snprintf(fname, sizeof(fname), SRCDIR "/files/%s", dp->d_name);
+ if (!wget_strcasecmp_ascii(ext, ".xml")) {
+ info_printf("parsing %s\n", fname);
+ wget_xml_parse_file(fname, NULL, NULL, 0);
+ xml++;
+ }
+/* else if (!wget_strcasecmp_ascii(ext, ".html")) {
+ info_printf("parsing %s\n", fname);
+ wget_html_parse_file(fname, NULL, NULL, 0);
+ html++;
+ }
+ else if (!wget_strcasecmp_ascii(ext, ".css")) {
+ info_printf("parsing %s\n", fname);
+ wget_css_parse_file(fname, _css_dump_uri, _css_dump_charset, NULL);
+ css++;
+ } */
+ }
+ }
+ closedir(dirp);
+ }
+
+ info_printf("%d XML, %d HTML and %d CSS files parsed\n", xml, html, css);
+}
+
+static void test_cookies(void)
+{
+ static const struct test_data {
+ const char
+ *uri,
+ *set_cookie,
+ *name, *value, *domain, *path, *expires;
+ unsigned int
+ domain_dot : 1, // for compatibility with Netscape cookie format
+ normalized : 1,
+ persistent : 1,
+ host_only : 1,
+ secure_only : 1, // cookie should be used over secure connections only (TLS/HTTPS)
+ http_only : 1; // just use the cookie via HTTP/HTTPS protocol
+ int
+ result,
+ psl_result;
+ } test_data[] = {
+ { // allowed cookie
+ "www.example.com",
+ "ID=65=abcd; expires=Tuesday, 07-May-2013 07:48:53 GMT; path=/; domain=.example.com; HttpOnly",
+ "ID", "65=abcd", "example.com", "/", "Tue, 07 May 2013 07:48:53 GMT",
+ 1, 1, 1, 0, 0, 1,
+ 0, 0
+ },
+ { // allowed cookie ANSI C's asctime format
+ "www.example.com",
+ "ID=65=abcd; expires=Tue May 07 07:48:53 2013; path=/; domain=.example.com",
+ "ID", "65=abcd", "example.com", "/", "Tue, 07 May 2013 07:48:53 GMT",
+ 1, 1, 1, 0, 0, 0,
+ 0, 0
+ },
+ { // allowed cookie without path
+ "www.example.com",
+ "ID=65=abcd; expires=Tue, 07-May-2013 07:48:53 GMT; domain=.example.com",
+ "ID", "65=abcd", "example.com", "/", "Tue, 07 May 2013 07:48:53 GMT",
+ 1, 1, 1, 0, 0, 0,
+ 0, 0
+ },
+ { // allowed cookie without domain
+ "www.example.com",
+ "ID=65=abcd; expires=Tue, 07-May-2013 07:48:53 GMT; path=/",
+ "ID", "65=abcd", "www.example.com", "/", "Tue, 07 May 2013 07:48:53 GMT",
+ 0, 1, 1, 1, 0, 0,
+ 0, 0
+ },
+ { // allowed cookie without domain, path and expires
+ "www.example.com",
+ "ID=65=abcd",
+ "ID", "65=abcd", "www.example.com", "/", "Tue, 07 May 2013 07:48:53 GMT",
+ 0, 1, 0, 1, 0, 0,
+ 0, 0
+ },
+ { // illegal cookie
+ "www.example.com",
+ "ID=65=abcd; expires=Tue, 07-May-2013 07:48:53 GMT; path=/; domain=.example.org",
+ "ID", "65=abcd", "example.org", "/", "Tue, 07 May 2013 07:48:53 GMT",
+ 1, 0, 1, 0, 0, 0,
+ -1, 0
+ },
+#ifdef WITH_LIBPSL
+ { // supercookie, accepted by normalization (rule 'com') but not by wget_cookie_check_psl())
+ "www.example.com",
+ "ID=65=abcd; expires=Mon, 29-Feb-2016 07:48:54 GMT; path=/; domain=.com; HttpOnly; Secure",
+ "ID", "65=abcd", "com", "/", "Mon, 29 Feb 2016 07:48:54 GMT",
+ 1, 0, 1, 0, 1, 1,
+ 0, -1
+ },
+ { // supercookie, accepted by normalization (rule '*.ar') but not by wget_cookie_check_psl())
+ "www.sa.gov.au",
+ "ID=65=abcd; expires=Tue, 29-Feb-2000 07:48:55 GMT; path=/; domain=.sa.gov.au",
+ "ID", "65=abcd", "sa.gov.au", "/", "Tue, 29 Feb 2000 07:48:55 GMT",
+ 1, 0, 1, 0, 0, 0,
+ 0, -1
+ },
+#endif
+ { // exception rule '!educ.ar', accepted by normalization
+ "www.educ.ar",
+ "ID=65=abcd; path=/; domain=.educ.ar",
+ "ID", "65=abcd", "educ.ar", "/", NULL,
+ 1, 1, 0, 0, 0, 0,
+ 0, 0
+ },
+ };
+ wget_cookie_t cookie;
+ wget_cookie_db_t *cookies;
+ wget_iri_t *iri;
+ unsigned it;
+ int result, result_psl;
+
+ cookies = wget_cookie_db_init(NULL);
+ wget_cookie_db_load_psl(cookies, NULL);
+
+ for (it = 0; it < countof(test_data); it++) {
+ const struct test_data *t = &test_data[it];
+ char thedate[32], *header;
+
+ iri = wget_iri_parse(t->uri, "utf-8");
+ wget_http_parse_setcookie(t->set_cookie, &cookie);
+ if ((result = wget_cookie_normalize(iri, &cookie)) != t->result) {
+ failed++;
+ info_printf("Failed [%u]: normalize_cookie(%s) -> %d (expected %d)\n", it, t->set_cookie, result, t->result);
+ wget_cookie_deinit(&cookie);
+ goto next;
+ } else {
+ if ((result_psl = wget_cookie_check_psl(cookies, &cookie)) != t->psl_result) {
+ failed++;
+ info_printf("Failed [%u]: PSL check(%s) -> %d (expected %d)\n", it, t->set_cookie, result_psl, t->psl_result);
+ }
+ wget_cookie_deinit(&cookie);
+ goto next;
+ }
+
+ if (cookie.expires) {
+ wget_http_print_date(cookie.expires, thedate, sizeof(thedate));
+ if (strcmp(thedate, t->expires)) {
+ failed++;
+ info_printf("Failed [%u]: expires mismatch: '%s' != '%s' (time_t %lld)\n", it, thedate, t->expires, (long long)cookie.expires);
+ wget_cookie_deinit(&cookie);
+ goto next;
+ }
+ }
+
+ if (strcmp(cookie.name, t->name) ||
+ strcmp(cookie.value, t->value) ||
+ strcmp(cookie.domain, t->domain) ||
+ strcmp(cookie.path, t->path) ||
+ cookie.domain_dot != t->domain_dot ||
+ cookie.normalized != t->normalized ||
+ cookie.persistent != t->persistent ||
+ cookie.host_only != t->host_only ||
+ cookie.secure_only != t->secure_only ||
+ cookie.http_only != t->http_only)
+ {
+ failed++;
+
+ info_printf("Failed [%u]: cookie (%s) differs:\n", it, t->set_cookie);
+ if (strcmp(cookie.name, t->name))
+ info_printf(" name %s (expected %s)\n", cookie.name, t->name);
+ if (strcmp(cookie.value, t->value))
+ info_printf(" value %s (expected %s)\n", cookie.value, t->value);
+ if (strcmp(cookie.domain, t->domain))
+ info_printf(" domain %s (expected %s)\n", cookie.domain, t->domain);
+ if (strcmp(cookie.path, t->path))
+ info_printf(" path %s (expected %s)\n", cookie.path, t->path);
+ if (cookie.domain_dot != t->domain_dot)
+ info_printf(" domain_dot %d (expected %d)\n", cookie.domain_dot, t->domain_dot);
+ if (cookie.normalized != t->normalized)
+ info_printf(" normalized %d (expected %d)\n", cookie.normalized, t->normalized);
+ if (cookie.persistent != t->persistent)
+ info_printf(" persistent %d (expected %d)\n", cookie.persistent, t->persistent);
+ if (cookie.host_only != t->host_only)
+ info_printf(" host_only %d (expected %d)\n", cookie.host_only, t->host_only);
+ if (cookie.secure_only != t->secure_only)
+ info_printf(" secure_only %d (expected %d)\n", cookie.secure_only, t->secure_only);
+ if (cookie.http_only != t->http_only)
+ info_printf(" http_only %d (expected %d)\n", cookie.http_only, t->http_only);
+
+ wget_cookie_deinit(&cookie);
+ goto next;
+ }
+
+ wget_cookie_store_cookie(cookies, &cookie);
+
+ info_printf("%s\n", header = wget_cookie_create_request_header(cookies, iri));
+ xfree(header);
+
+ ok++;
+
+next:
+ wget_iri_free(&iri);
+ }
+
+ wget_cookie_db_free(&cookies);
+}
+
+static void test_hsts(void)
+{
+ static const struct hsts_db_data {
+ const char *
+ host;
+ int
+ port;
+ const char *
+ hsts_params;
+ } hsts_db_data[] = {
+ { "www.example.com", 443, "max-age=14400; includeSubDomains" },
+ { "www.example2.com", 443, "max-age=14400" },
+ { "www.example2.com", 443, "max-age=0" }, // this removes the previous entry
+ };
+ static const struct hsts_data {
+ const char *
+ host;
+ int
+ port;
+ int
+ result;
+ } hsts_data[] = {
+ { "www.example.com", 443, 1 }, // exact match
+ { "ftp.example.com", 443, 0 },
+ { "example.com", 443, 0 },
+ { "sub.www.example.com", 443, 1 }, // subdomain
+ { "sub1.sub2.www.example.com", 443, 1 }, // subdomain
+ { "www.example2.com", 443, 0 }, // entry should have been removed due to maxage=0
+ { "www.example.com", 80, 0 }, // wrong port
+ };
+ wget_hsts_db_t *hsts_db = wget_hsts_db_init(NULL);
+ time_t maxage;
+ char include_subdomains;
+ int n;
+
+ // fill HSTS database with values
+ for (unsigned it = 0; it < countof(hsts_db_data); it++) {
+ const struct hsts_db_data *t = &hsts_db_data[it];
+ wget_http_parse_strict_transport_security(t->hsts_params, &maxage, &include_subdomains);
+ wget_hsts_db_add(hsts_db, wget_hsts_new(t->host, t->port, maxage, include_subdomains));
+ }
+
+ // check HSTS database with values
+ for (unsigned it = 0; it < countof(hsts_data); it++) {
+ const struct hsts_data *t = &hsts_data[it];
+
+ n = wget_hsts_host_match(hsts_db, t->host, t->port);
+
+ if (n == t->result)
+ ok++;
+ else {
+ failed++;
+ info_printf("Failed [%u]: wget_hsts_host_match(%s,%d) -> %d (expected %d)\n", it, t->host, t->port, n, t->result);
+ }
+ }
+
+ wget_hsts_db_free(&hsts_db);
+}
+
+static void test_parse_challenge(void)
+{
+ static const struct test_data {
+ const char *
+ input;
+ const char *
+ scheme[3];
+ } test_data[] = {
+ { // simplebasic
+ "Basic realm=\"foo\"",
+ { "Basic", NULL }
+ },
+ { // simplebasicucase
+ "BASIC REALM=\"foo\"",
+ { "Basic", NULL }
+ },
+ { // simplebasicucase
+ "Basic , realm=\"foo\"",
+ { "Basic", NULL }
+ },
+ { //
+ "Basic realm=\"test realm\"",
+ { "Basic", NULL }
+ },
+ { //
+ "Basic realm=\"test-äöÜ\"",
+ { "Basic", NULL }
+ },
+ { //
+ "Basic realm=\"basic\", Newauth realm=\"newauth\"",
+ { "Basic", "Newauth", NULL }
+ },
+ };
+
+ wget_vector_t *challenges;
+ wget_http_challenge_t *challenge;
+
+ // Testcases found here http://greenbytes.de/tech/tc/httpauth/
+ challenges = wget_vector_create(2, 2, NULL);
+ wget_vector_set_destructor(challenges, (void(*)(void *))wget_http_free_challenge);
+
+ for (unsigned it = 0; it < countof(test_data); it++) {
+ const struct test_data *t = &test_data[it];
+
+ wget_http_parse_challenges(t->input, challenges);
+ for (unsigned nchal = 0; nchal < countof(test_data[0].scheme) && t->scheme[nchal]; nchal++) {
+ challenge = wget_vector_get(challenges, nchal);
+
+ if (!t->scheme[nchal]) {
+ if (challenge) {
+ failed++;
+ info_printf("Failed [%u]: wget_http_parse_challenges(%s) found %d challenges (expected %d)\n", it, t->input, wget_vector_size(challenges), nchal);
+ }
+ break;
+ }
+
+ if (!challenge) {
+ failed++;
+ info_printf("Failed [%u]: wget_http_parse_challenges(%s) did not find enough challenges\n", it, t->input);
+ break;
+ }
+
+ if (!wget_strcasecmp_ascii(challenge->auth_scheme, t->scheme[nchal])) {
+ ok++;
+ } else {
+ failed++;
+ info_printf("Failed [%u]: wget_http_parse_challenges(%s) -> '%s' (expected '%s')\n", it, t->input, challenge->auth_scheme, t->scheme[nchal]);
+ }
+ }
+
+ wget_vector_clear(challenges);
+ }
+
+ wget_http_free_challenges(&challenges);
+}
+
+static void test_utils(void)
+{
+ int it;
+ unsigned char src[1];
+ char dst1[3], dst2[3];
+
+ for (int ndst = 1; ndst <= 3; ndst++) {
+ for (it = 0; it <= 255; it++) {
+ src[0] = (unsigned char) it;
+ wget_memtohex(src, 1, dst1, ndst);
+ snprintf(dst2, ndst, "%02x", src[0]);
+ if (strcmp(dst1, dst2)) {
+ info_printf("buffer_to_hex failed: '%s' instead of '%s' (ndst=%d)\n", dst1, dst2, ndst);
+ failed++;
+ break;
+ }
+ }
+
+ if (it >= 256)
+ ok++;
+ else
+ failed++;
+ }
+}
+
+static void test_strcasecmp_ascii(void)
+{
+ static const struct test_data {
+ const char *
+ s1;
+ const char *
+ s2;
+ int
+ result;
+ } test_data[] = {
+ { NULL, NULL, 0 },
+ { NULL, "x", -1 },
+ { "x", NULL, 1 },
+ { "Abc", "abc", 0 },
+ { "abc", "abc", 0 },
+ { "abc", "ab", 'c' },
+ { "ab", "abc", -'c' },
+ { "abc", "", 'a' },
+ { "", "abc", -'a' },
+ };
+ static const struct test_data2 {
+ const char *
+ s1;
+ const char *
+ s2;
+ size_t
+ n;
+ int
+ result;
+ } test_data2[] = {
+ { NULL, NULL, 1, 0 },
+ { NULL, "x", 1, -1 },
+ { "x", NULL, 1, 1 },
+ { "Abc", "abc", 2, 0 },
+ { "abc", "abc", 3, 0 },
+ { "abc", "ab", 2, 0 },
+ { "abc", "ab", 3, 'c' },
+ { "ab", "abc", 2, 0 },
+ { "ab", "abc", 3, -'c' },
+ { "abc", "", 1, 'a' },
+ { "", "abc", 1, -'a' },
+ { "", "abc", 0, 0 },
+ };
+
+ for (unsigned it = 0; it < countof(test_data); it++) {
+ const struct test_data *t = &test_data[it];
+
+ int n = wget_strcasecmp_ascii(t->s1, t->s2);
+
+ if (n == t->result)
+ ok++;
+ else {
+ failed++;
+ info_printf("Failed [%u]: wget_strcasecmp_ascii(%s,%s) -> %d (expected %d)\n", it, t->s1, t->s2, n, t->result);
+ }
+ }
+
+ for (unsigned it = 0; it < countof(test_data2); it++) {
+ const struct test_data2 *t = &test_data2[it];
+
+ int n = wget_strncasecmp_ascii(t->s1, t->s2, t->n);
+
+ if (n == t->result)
+ ok++;
+ else {
+ failed++;
+ info_printf("Failed [%u]: wget_strncasecmp_ascii(%s,%s,%zd) -> %d (expected %d)\n", it, t->s1, t->s2, t->n, n, t->result);
+ }
+ }
+
+ for (unsigned it = 0; it < 26; it++) {
+ char s1[8], s2[8];
+
+ s1[0] = 'a' + it; s1[1] = 0;
+ s2[0] = 'A' + it; s2[1] = 0;
+
+ if (wget_strcasecmp_ascii(s1, s2) == 0)
+ ok++;
+ else {
+ failed++;
+ info_printf("Failed: wget_strcasecmp_ascii(%s,%s) != 0\n", s1, s2);
+ }
+
+ if (wget_strncasecmp_ascii(s1, s2, 1) == 0)
+ ok++;
+ else {
+ failed++;
+ info_printf("Failed: wget_strncasecmp_ascii(%s,%s) != 0\n", s1, s2);
+ }
+ }
+}
+
+struct ENTRY {
+ const char
+ *txt;
+};
+
+static int compare_txt(struct ENTRY *a1, struct ENTRY *a2)
+{
+ return wget_strcasecmp_ascii(a1->txt, a2->txt);
+}
+
+static void test_vector(void)
+{
+ struct ENTRY
+ *tmp,
+ txt_sorted[5] = { {""}, {"four"}, {"one"}, {"three"}, {"two"} },
+ *txt[countof(txt_sorted)];
+ wget_vector_t
+ *v = wget_vector_create(2, -2, (int(*)(const void *, const void *))compare_txt);
+ unsigned
+ it;
+ int
+ n;
+
+ // copy
+ for (it = 0; it < countof(txt); it++)
+ txt[it] = &txt_sorted[it];
+
+ // shuffle txt
+ for (it = 0; it < countof(txt); it++) {
+ n = rand() % countof(txt);
+ tmp = txt[n];
+ txt[n] = txt[it];
+ txt[it] = tmp;
+ }
+
+ for (it = 0; it < countof(txt); it++) {
+ wget_vector_insert_sorted(v, txt[it], sizeof(struct ENTRY));
+ }
+
+ for (it = 0; it < countof(txt); it++) {
+ struct ENTRY *e = wget_vector_get(v, it);
+ if (!strcmp(e->txt,txt_sorted[it].txt))
+ ok++;
+ else
+ failed++;
+ }
+
+ wget_vector_free(&v);
+}
+
+// this hash function generates collisions and reduces the map to a simple list.
+// O(1) insertion, but O(n) search and removal
+static unsigned int hash_txt(G_GNUC_WGET_UNUSED const char *key)
+{
+ return 0;
+}
+
+static void test_stringmap(void)
+{
+ wget_stringmap_t *m;
+ char key[128], value[128], *val;
+ int run, it;
+ size_t valuesize;
+
+ // the initial size of 16 forces the internal reshashing function to be called twice
+
+ m = wget_stringmap_create(16);
+
+ for (run = 0; run < 2; run++) {
+ if (run) {
+ wget_stringmap_clear(m);
+ wget_stringmap_sethashfunc(m, hash_txt);
+ }
+
+ for (it = 0; it < 26; it++) {
+ sprintf(key, "http://www.example.com/subdir/%d.html", it);
+ valuesize = sprintf(value, "%d.html", it);
+ if (wget_stringmap_put(m, key, value, valuesize + 1)) {
+ failed++;
+ info_printf("stringmap_put(%s) returns unexpected old value\n", key);
+ } else ok++;
+ }
+
+ if ((it = wget_stringmap_size(m)) != 26) {
+ failed++;
+ info_printf("stringmap_size() returned %d (expected %d)\n", it, 26);
+ } else ok++;
+
+ // now, look up every single entry
+ for (it = 0; it < 26; it++) {
+ sprintf(key, "http://www.example.com/subdir/%d.html", it);
+ sprintf(value, "%d.html", it);
+ if (!(val = wget_stringmap_get(m, key))) {
+ failed++;
+ info_printf("stringmap_get(%s) didn't find entry\n", key);
+ } else if (strcmp(val, value)) {
+ failed++;
+ info_printf("stringmap_get(%s) found '%s' (expected '%s')\n", key, val, value);
+ } else ok++;
+ }
+
+ wget_stringmap_clear(m);
+
+ if ((it = wget_stringmap_size(m)) != 0) {
+ failed++;
+ info_printf("stringmap_size() returned %d (expected 0)\n", it);
+ } else ok++;
+
+ for (it = 0; it < 26; it++) {
+ sprintf(key, "http://www.example.com/subdir/%d.html", it);
+ valuesize = sprintf(value, "%d.html", it);
+ if (wget_stringmap_put(m, key, value, valuesize + 1)) {
+ failed++;
+ info_printf("stringmap_put(%s) returns unexpected old value\n", key);
+ } else ok++;
+ }
+
+ if ((it = wget_stringmap_size(m)) != 26) {
+ failed++;
+ info_printf("stringmap_size() returned %d (expected %d)\n", it, 26);
+ } else ok++;
+
+ // now, remove every single entry
+ for (it = 0; it < 26; it++) {
+ sprintf(key, "http://www.example.com/subdir/%d.html", it);
+ sprintf(value, "%d.html", it);
+ wget_stringmap_remove(m, key);
+ }
+
+ if ((it = wget_stringmap_size(m)) != 0) {
+ failed++;
+ info_printf("stringmap_size() returned %d (expected 0)\n", it);
+ } else ok++;
+
+ for (it = 0; it < 26; it++) {
+ sprintf(key, "http://www.example.com/subdir/%d.html", it);
+ valuesize = sprintf(value, "%d.html", it);
+ if (wget_stringmap_put(m, key, value, valuesize + 1)) {
+ failed++;
+ info_printf("stringmap_put(%s) returns unexpected old value\n", key);
+ } else ok++;
+ }
+
+ if ((it = wget_stringmap_size(m)) != 26) {
+ failed++;
+ info_printf("stringmap_size() returned %d (expected %d)\n", it, 26);
+ } else ok++;
+ }
+
+ // testing alloc/free in stringmap/hashmap
+ wget_stringmap_clear(m);
+ wget_stringmap_put(m, "thekey", NULL, 0) ? failed++ : ok++;
+ wget_stringmap_put(m, "thekey", NULL, 0) ? ok++ : failed++;
+ wget_stringmap_put(m, "thekey", "thevalue", 9) ? ok++ : failed++;
+ wget_stringmap_put(m, "thekey", "thevalue", 9) ? ok++ : failed++;
+ wget_stringmap_put(m, "thekey", NULL, 0) ? ok++ : failed++;
+
+ // testing key/value identity alloc/free in stringmap/hashmap
+ wget_stringmap_clear(m);
+ wget_stringmap_put(m, "thekey", NULL, 0) ? failed++ : ok++;
+ wget_stringmap_put(m, "thekey", NULL, 0) ? ok++ : failed++;
+ wget_stringmap_put(m, "thekey", "thevalue", 9) ? ok++ : failed++;
+ wget_stringmap_put(m, "thekey", NULL, 0) ? ok++ : failed++;
+
+ wget_stringmap_free(&m);
+
+ wget_http_challenge_t challenge;
+ wget_http_parse_challenge("Basic realm=\"test realm\"", &challenge);
+ wget_http_free_challenge(&challenge);
+
+ wget_vector_t *challenges;
+ challenges = wget_vector_create(2, 2, NULL);
+ wget_vector_set_destructor(challenges, (void(*)(void *))wget_http_free_challenge);
+ wget_http_parse_challenge("Basic realm=\"test realm\"", &challenge);
+ wget_vector_add(challenges, &challenge, sizeof(challenge));
+ wget_http_free_challenges(&challenges);
+
+ char *response_text = strdup(
+"HTTP/1.1 401 Authorization Required\r\n"\
+"Date: Sun, 23 Dec 2012 21:03:45 GMT\r\n"\
+"Server: Apache/2.2.22 (Debian)\r\n"\
+"WWW-Authenticate: Digest realm=\"therealm\", nonce=\"Ip6MaovRBAA=c4af733c51270698260f5d357724c2cbce20fa3d\", algorithm=MD5, domain=\"/prot_digest_md5\", qop=\"auth\"\r\n"\
+"Vary: Accept-Encoding\r\n"\
+"Content-Length: 476\r\n"\
+"Keep-Alive: timeout=5, max=99\r\n"\
+"Connection: Keep-Alive\r\n"\
+"Content-Type: text/html; charset=iso-8859-1\r\n\r\n");
+
+ wget_iri_t *iri = wget_iri_parse("http://localhost/prot_digest_md5/", NULL);
+ wget_http_request_t *req = wget_http_create_request(iri, "GET");
+ wget_http_response_t *resp = wget_http_parse_response_header(response_text);
+ wget_http_add_credentials(req, wget_vector_get(resp->challenges, 0), "tim", "123");
+// for (it=0;it<vec_size(req->lines);it++) {
+// info_printf("%s\n", (char *)vec_get(req->lines, it));
+// }
+ wget_http_free_response(&resp);
+ wget_http_free_request(&req);
+ wget_iri_free(&iri);
+ xfree(response_text);
+
+// Authorization: Digest username="tim", realm="therealm", nonce="Ip6MaovRBAA=c4af733c51270698260f5d357724c2cbce20fa3d", uri="/prot_digest_md5/", response="a99e2012d507a73dd46eb044d3f4641c", qop=auth, nc=00000001, cnonce="3d20faa1"
+
+}
+
+int main(int argc, const char * const *argv)
+{
+ // if VALGRIND testing is enabled, we have to call ourselves with valgrind checking
+ const char *valgrind = getenv("VALGRIND_TESTS");
+
+ if (!valgrind || !*valgrind || !strcmp(valgrind, "0")) {
+ // fallthrough
+ }
+ else if (!strcmp(valgrind, "1")) {
+ char cmd[strlen(argv[0]) + 256];
+
+ snprintf(cmd, sizeof(cmd), "VALGRIND_TESTS=\"\" valgrind --error-exitcode=301 --leak-check=yes --show-reachable=yes --track-origins=yes %s", argv[0]);
+ return system(cmd) != 0;
+ } else {
+ char cmd[strlen(valgrind) + strlen(argv[0]) + 32];
+
+ snprintf(cmd, sizeof(cmd), "VALGRIND_TESTS="" %s %s", valgrind, argv[0]);
+ return system(cmd) != 0;
+ }
+
+ init(argc, argv); // allows us to test with options (e.g. with --debug)
+
+ srand((unsigned int) time(NULL));
+
+ // testing basic library functionality
+ test_buffer();
+ test_buffer_printf();
+ test_utils();
+ test_strcasecmp_ascii();
+ test_vector();
+ test_stringmap();
+
+ if (failed) {
+ info_printf("ERROR: %d out of %d basic tests failed\n", failed, ok + failed);
+ info_printf("This may completely break Wget functionality !!!\n");
+ return 1;
+ }
+
+ test_iri_parse();
+ test_iri_relative_to_absolute();
+ test_iri_compare();
+ test_parser();
+
+ test_cookies();
+ test_hsts();
+ test_parse_challenge();
+
+ selftest_options() ? failed++ : ok++;
+
+ deinit(); // free resources allocated by init()
+
+ if (failed) {
+ info_printf("Summary: %d out of %d tests failed\n", failed, ok + failed);
+ return 1;
+ }
+
+ info_printf("Summary: All %d tests passed\n", ok + failed);
+ return 0;
+}