summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/CuTest.c13
-rw-r--r--test/CuTest.h5
-rw-r--r--test/serf_get.c40
-rw-r--r--test/server/serfcacert.pem50
-rw-r--r--test/server/serfrootcacert.pem60
-rw-r--r--test/server/serfservercert.pem50
-rw-r--r--test/server/serfserverkey.pem18
-rw-r--r--test/server/test_server.c171
-rw-r--r--test/server/test_server.h94
-rw-r--r--test/server/test_sslserver.c252
-rw-r--r--test/test_buckets.c332
-rw-r--r--test/test_context.c850
-rw-r--r--test/test_serf.h22
-rw-r--r--test/test_ssl.c21
-rw-r--r--test/test_util.c129
15 files changed, 1698 insertions, 409 deletions
diff --git a/test/CuTest.c b/test/CuTest.c
index 315f59f..377d396 100644
--- a/test/CuTest.c
+++ b/test/CuTest.c
@@ -205,13 +205,14 @@ void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message,
CuFail_Line(tc, file, line, NULL, message);
}
-void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
- const char* expected, const char* actual)
+void CuAssertStrnEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ const char* expected, size_t explen,
+ const char* actual)
{
CuString string;
if ((expected == NULL && actual == NULL) ||
(expected != NULL && actual != NULL &&
- strcmp(expected, actual) == 0))
+ strncmp(expected, actual, explen) == 0))
{
return;
}
@@ -230,6 +231,12 @@ void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const cha
CuFailInternal(tc, file, line, &string);
}
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ const char* expected, const char* actual)
+{
+ CuAssertStrnEquals_LineMsg(tc, file, line, message, expected, strlen(expected), actual);
+}
+
void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
int expected, int actual)
{
diff --git a/test/CuTest.h b/test/CuTest.h
index 1895bec..930ae9c 100644
--- a/test/CuTest.h
+++ b/test/CuTest.h
@@ -90,6 +90,9 @@ void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message,
void CuAssertStrEquals_LineMsg(CuTest* tc,
const char* file, int line, const char* message,
const char* expected, const char* actual);
+void CuAssertStrnEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ const char* expected, size_t explen, const char* actual);
void CuAssertIntEquals_LineMsg(CuTest* tc,
const char* file, int line, const char* message,
int expected, int actual);
@@ -108,6 +111,8 @@ void CuAssertPtrEquals_LineMsg(CuTest* tc,
#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertStrnEquals(tc,ex,exlen,ac) CuAssertStrnEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(exlen),(ac))
+#define CuAssertStrnEquals_Msg(tc,ms,ex,exlen,ac) CuAssertStrnEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(exlen),ac))
#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl))
diff --git a/test/serf_get.c b/test/serf_get.c
index ac1bb8e..b63bb66 100644
--- a/test/serf_get.c
+++ b/test/serf_get.c
@@ -68,6 +68,18 @@ static apr_status_t ignore_all_cert_errors(void *data, int failures,
return APR_SUCCESS;
}
+static char *
+convert_organisation_to_str(apr_hash_t *org, apr_pool_t *pool)
+{
+ return apr_psprintf(pool, "%s, %s, %s, %s, %s (%s)",
+ (char*)apr_hash_get(org, "OU", APR_HASH_KEY_STRING),
+ (char*)apr_hash_get(org, "O", APR_HASH_KEY_STRING),
+ (char*)apr_hash_get(org, "L", APR_HASH_KEY_STRING),
+ (char*)apr_hash_get(org, "ST", APR_HASH_KEY_STRING),
+ (char*)apr_hash_get(org, "C", APR_HASH_KEY_STRING),
+ (char*)apr_hash_get(org, "E", APR_HASH_KEY_STRING));
+}
+
static apr_status_t print_certs(void *data, int failures, int error_depth,
const serf_ssl_certificate_t * const * certs,
apr_size_t certs_len)
@@ -86,8 +98,34 @@ static apr_status_t print_certs(void *data, int failures, int error_depth,
fprintf(stderr, "Chain provided with depth=%d\n", error_depth);
while ((current = *certs) != NULL)
- {
+ {
+ apr_hash_t *issuer, *subject, *serf_cert;
+ apr_array_header_t *san;
+
+ subject = serf_ssl_cert_subject(current, pool);
+ issuer = serf_ssl_cert_issuer(current, pool);
+ serf_cert = serf_ssl_cert_certificate(current, pool);
+
fprintf(stderr, "\n-----BEGIN CERTIFICATE-----\n");
+ fprintf(stderr, "Hostname: %s\n",
+ (const char *)apr_hash_get(subject, "CN", APR_HASH_KEY_STRING));
+ fprintf(stderr, "Sha1: %s\n",
+ (const char *)apr_hash_get(serf_cert, "sha1", APR_HASH_KEY_STRING));
+ fprintf(stderr, "Valid from: %s\n",
+ (const char *)apr_hash_get(serf_cert, "notBefore", APR_HASH_KEY_STRING));
+ fprintf(stderr, "Valid until: %s\n",
+ (const char *)apr_hash_get(serf_cert, "notAfter", APR_HASH_KEY_STRING));
+ fprintf(stderr, "Issuer: %s\n", convert_organisation_to_str(issuer, pool));
+
+ san = apr_hash_get(serf_cert, "subjectAltName", APR_HASH_KEY_STRING);
+ if (san) {
+ int i;
+ for (i = 0; i < san->nelts; i++) {
+ char *s = APR_ARRAY_IDX(san, i, char*);
+ fprintf(stderr, "SubjectAltName: %s\n", s);
+ }
+ }
+
fprintf(stderr, "%s\n", serf_ssl_cert_export(current, pool));
fprintf(stderr, "-----END CERTIFICATE-----\n");
++certs;
diff --git a/test/server/serfcacert.pem b/test/server/serfcacert.pem
new file mode 100644
index 0000000..f8324cd
--- /dev/null
+++ b/test/server/serfcacert.pem
@@ -0,0 +1,50 @@
+Certificate:
+ Data:
+ Version: 1 (0x0)
+ Serial Number: 1048578 (0x100002)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=BE, ST=Antwerp, L=Mechelen, O=In Serf we trust, Inc., OU=Test Suite Root CA, CN=Serf Root CA/emailAddress=serfrootca@example.com
+ Validity
+ Not Before: Apr 13 11:28:06 2013 GMT
+ Not After : Apr 13 11:28:06 2014 GMT
+ Subject: C=BE, ST=Antwerp, L=Mechelen, O=In Serf we trust, Inc., OU=Test Suite CA, CN=Serf CA/emailAddress=serfca@example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:ab:10:e4:6c:e6:31:23:9f:f3:5d:a9:22:12:81:
+ 9a:b5:8d:7b:4d:8e:b7:8c:1f:2e:14:81:03:bb:44:
+ 50:79:d0:42:8c:f4:0f:86:f1:00:76:03:87:ac:a0:
+ a2:3a:6f:ab:b5:17:81:ce:86:d4:35:70:4c:a1:cb:
+ 2c:67:17:9b:06:b3:4f:1e:18:ce:9b:5d:15:8e:10:
+ 24:a5:9c:73:43:fe:b4:68:a8:65:50:58:31:3b:df:
+ b7:f8:33:d0:5d:af:c6:b1:ec:ed:73:09:cd:3e:42:
+ 6a:95:13:d0:bd:b8:9d:5a:23:24:fc:34:4f:b0:72:
+ 4b:15:e5:b4:13:4b:bc:24:85
+ Exponent: 65537 (0x10001)
+ Signature Algorithm: sha1WithRSAEncryption
+ 46:db:5f:de:b5:66:f8:9b:04:da:3c:f5:1a:99:98:c8:1f:57:
+ f8:1e:7a:f9:b4:1e:7e:21:97:11:70:64:2c:58:90:00:28:09:
+ 12:10:81:fb:27:01:37:4b:22:9a:56:95:42:e2:eb:4b:b5:8b:
+ bd:9f:09:4b:34:15:2f:ce:1e:dd:71:8c:40:0c:8a:6a:fe:a6:
+ 12:f1:68:b7:f3:be:e4:69:fb:b6:3b:c8:c4:13:9c:ae:09:d1:
+ dc:51:b9:77:90:14:2b:65:83:30:12:76:ef:33:24:65:99:63:
+ 2e:62:d7:21:db:e5:d9:a6:2d:05:17:a1:5e:ef:6f:26:f6:2f:
+ 96:b4
+-----BEGIN CERTIFICATE-----
+MIICwTCCAioCAxAAAjANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UEBhMCQkUxEDAO
+BgNVBAgMB0FudHdlcnAxETAPBgNVBAcMCE1lY2hlbGVuMR8wHQYDVQQKDBZJbiBT
+ZXJmIHdlIHRydXN0LCBJbmMuMRswGQYDVQQLDBJUZXN0IFN1aXRlIFJvb3QgQ0Ex
+FTATBgNVBAMMDFNlcmYgUm9vdCBDQTElMCMGCSqGSIb3DQEJARYWc2VyZnJvb3Rj
+YUBleGFtcGxlLmNvbTAeFw0xMzA0MTMxMTI4MDZaFw0xNDA0MTMxMTI4MDZaMIGg
+MQswCQYDVQQGEwJCRTEQMA4GA1UECAwHQW50d2VycDERMA8GA1UEBwwITWVjaGVs
+ZW4xHzAdBgNVBAoMFkluIFNlcmYgd2UgdHJ1c3QsIEluYy4xFjAUBgNVBAsMDVRl
+c3QgU3VpdGUgQ0ExEDAOBgNVBAMMB1NlcmYgQ0ExITAfBgkqhkiG9w0BCQEWEnNl
+cmZjYUBleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxDk
+bOYxI5/zXakiEoGatY17TY63jB8uFIEDu0RQedBCjPQPhvEAdgOHrKCiOm+rtReB
+zobUNXBMocssZxebBrNPHhjOm10VjhAkpZxzQ/60aKhlUFgxO9+3+DPQXa/Gsezt
+cwnNPkJqlRPQvbidWiMk/DRPsHJLFeW0E0u8JIUCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQBG21/etWb4mwTaPPUamZjIH1f4Hnr5tB5+IZcRcGQsWJAAKAkSEIH7JwE3
+SyKaVpVC4utLtYu9nwlLNBUvzh7dcYxADIpq/qYS8Wi3877kafu2O8jEE5yuCdHc
+Ubl3kBQrZYMwEnbvMyRlmWMuYtch2+XZpi0FF6Fe728m9i+WtA==
+-----END CERTIFICATE-----
diff --git a/test/server/serfrootcacert.pem b/test/server/serfrootcacert.pem
new file mode 100644
index 0000000..440f39f
--- /dev/null
+++ b/test/server/serfrootcacert.pem
@@ -0,0 +1,60 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 14060582211199810902 (0xc321390661bdbd56)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=BE, ST=Antwerp, L=Mechelen, O=In Serf we trust, Inc., OU=Test Suite Root CA, CN=Serf Root CA/emailAddress=serfrootca@example.com
+ Validity
+ Not Before: Apr 13 11:19:14 2013 GMT
+ Not After : Apr 11 11:19:14 2023 GMT
+ Subject: C=BE, ST=Antwerp, L=Mechelen, O=In Serf we trust, Inc., OU=Test Suite Root CA, CN=Serf Root CA/emailAddress=serfrootca@example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:e1:dd:69:ea:ac:fd:f2:73:81:ec:ed:b6:b1:0e:
+ 70:23:8c:01:6d:ab:f3:43:ab:0f:fc:8a:6a:23:eb:
+ 6c:48:37:c9:c0:8f:29:61:00:7e:89:1f:00:d1:68:
+ dd:70:de:bd:34:32:0e:41:ac:f9:ea:c1:a6:0d:b5:
+ 65:be:5c:9e:f1:b4:27:54:c1:79:61:63:d4:2d:06:
+ 11:5f:cc:4c:d9:d3:ef:4e:da:9f:a4:26:16:cb:3f:
+ 86:f8:21:7d:c5:3a:32:34:c8:cb:85:ad:c4:3f:e4:
+ b3:ad:8e:a7:67:9e:0c:3b:5a:58:29:5f:ce:96:3b:
+ e3:f5:ca:42:eb:7b:44:d5:75
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ B2:3E:19:35:C1:C4:4F:23:79:ED:BF:E8:DC:5C:31:03:F0:2F:15:77
+ X509v3 Authority Key Identifier:
+ keyid:B2:3E:19:35:C1:C4:4F:23:79:ED:BF:E8:DC:5C:31:03:F0:2F:15:77
+
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ c3:ec:1f:3e:b1:87:d0:80:10:f9:bf:73:1b:38:d4:b1:b7:80:
+ 4d:ea:20:c1:79:7d:f5:58:42:11:13:28:ab:b1:b4:0a:88:9c:
+ 20:4d:9c:b5:5a:41:28:5e:f6:69:5e:55:bb:e2:1a:b9:c6:62:
+ 38:86:32:7b:93:28:ca:9e:af:d1:06:f9:93:c2:5d:92:c0:25:
+ 68:6a:e1:fe:85:2a:19:a7:6b:17:4d:23:9a:72:d6:d0:c1:80:
+ ff:74:10:8b:62:7a:11:c3:9a:87:2a:e4:7d:d1:8c:72:a6:bf:
+ c1:3b:d8:b8:33:c0:ff:b0:f7:d6:0e:a3:dd:36:fe:8a:41:a0:
+ 98:cc
+-----BEGIN CERTIFICATE-----
+MIIDLDCCApWgAwIBAgIJAMMhOQZhvb1WMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD
+VQQGEwJCRTEQMA4GA1UECAwHQW50d2VycDERMA8GA1UEBwwITWVjaGVsZW4xHzAd
+BgNVBAoMFkluIFNlcmYgd2UgdHJ1c3QsIEluYy4xGzAZBgNVBAsMElRlc3QgU3Vp
+dGUgUm9vdCBDQTEVMBMGA1UEAwwMU2VyZiBSb290IENBMSUwIwYJKoZIhvcNAQkB
+FhZzZXJmcm9vdGNhQGV4YW1wbGUuY29tMB4XDTEzMDQxMzExMTkxNFoXDTIzMDQx
+MTExMTkxNFowga4xCzAJBgNVBAYTAkJFMRAwDgYDVQQIDAdBbnR3ZXJwMREwDwYD
+VQQHDAhNZWNoZWxlbjEfMB0GA1UECgwWSW4gU2VyZiB3ZSB0cnVzdCwgSW5jLjEb
+MBkGA1UECwwSVGVzdCBTdWl0ZSBSb290IENBMRUwEwYDVQQDDAxTZXJmIFJvb3Qg
+Q0ExJTAjBgkqhkiG9w0BCQEWFnNlcmZyb290Y2FAZXhhbXBsZS5jb20wgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAOHdaeqs/fJzgezttrEOcCOMAW2r80OrD/yK
+aiPrbEg3ycCPKWEAfokfANFo3XDevTQyDkGs+erBpg21Zb5cnvG0J1TBeWFj1C0G
+EV/MTNnT707an6QmFss/hvghfcU6MjTIy4WtxD/ks62Op2eeDDtaWClfzpY74/XK
+Qut7RNV1AgMBAAGjUDBOMB0GA1UdDgQWBBSyPhk1wcRPI3ntv+jcXDED8C8VdzAf
+BgNVHSMEGDAWgBSyPhk1wcRPI3ntv+jcXDED8C8VdzAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4GBAMPsHz6xh9CAEPm/cxs41LG3gE3qIMF5ffVYQhETKKux
+tAqInCBNnLVaQShe9mleVbviGrnGYjiGMnuTKMqer9EG+ZPCXZLAJWhq4f6FKhmn
+axdNI5py1tDBgP90EItiehHDmocq5H3RjHKmv8E72LgzwP+w99YOo902/opBoJjM
+-----END CERTIFICATE-----
diff --git a/test/server/serfservercert.pem b/test/server/serfservercert.pem
new file mode 100644
index 0000000..086e0e5
--- /dev/null
+++ b/test/server/serfservercert.pem
@@ -0,0 +1,50 @@
+Certificate:
+ Data:
+ Version: 1 (0x0)
+ Serial Number: 1048579 (0x100003)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=BE, ST=Antwerp, L=Mechelen, O=In Serf we trust, Inc., OU=Test Suite CA, CN=Serf CA/emailAddress=serfca@example.com
+ Validity
+ Not Before: Apr 13 11:41:01 2013 GMT
+ Not After : Apr 13 11:41:01 2014 GMT
+ Subject: C=BE, ST=Antwerp, L=Mechelen, O=In Serf we trust, Inc., OU=Test Suite Server, CN=Serf Server/emailAddress=serfserver@example.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:aa:8d:56:e7:0d:99:03:9b:3f:b3:c0:2a:63:33:
+ 51:65:4b:e7:d2:6c:60:d2:52:d7:8a:6d:c9:8b:93:
+ 3d:4c:1a:eb:29:26:9c:19:dc:a5:a6:70:3f:0b:a7:
+ 69:4d:8b:35:00:b6:8f:f2:4f:b6:38:43:b9:a7:c8:
+ 2d:51:7f:f2:f7:00:28:48:b8:f7:9a:7d:a5:7d:5c:
+ 17:f7:d0:14:54:86:39:88:43:1d:5c:d8:d4:56:9f:
+ 88:a8:3c:47:7f:65:cf:94:56:b0:d8:b6:dd:25:66:
+ 34:ba:cb:43:cd:df:93:ce:27:1b:57:7f:8a:50:f5:
+ 5a:33:d3:55:52:ff:9e:f7:4f
+ Exponent: 65537 (0x10001)
+ Signature Algorithm: sha1WithRSAEncryption
+ 82:02:80:89:ec:c2:56:51:1f:d1:f6:2f:8c:d9:50:49:c2:7f:
+ 00:76:53:65:15:96:bb:0f:7e:b3:5b:06:c2:9c:44:77:34:e9:
+ 64:41:ca:cd:aa:41:4a:6f:b0:95:cb:41:11:1b:75:0e:5e:d6:
+ 34:80:8f:22:a9:e4:ce:cd:9a:b6:0c:96:7e:e6:2a:f0:ce:eb:
+ 86:7a:2b:df:b8:13:3a:c8:b5:9d:5b:71:9c:40:61:56:c6:f9:
+ 90:b8:4f:1d:14:88:b2:ad:40:08:f5:88:ab:10:5d:74:6d:a6:
+ 29:3d:1b:01:68:9f:29:48:24:d9:3d:52:47:ca:bf:22:af:fd:
+ 7b:df
+-----BEGIN CERTIFICATE-----
+MIICvzCCAigCAxAAAzANBgkqhkiG9w0BAQUFADCBoDELMAkGA1UEBhMCQkUxEDAO
+BgNVBAgMB0FudHdlcnAxETAPBgNVBAcMCE1lY2hlbGVuMR8wHQYDVQQKDBZJbiBT
+ZXJmIHdlIHRydXN0LCBJbmMuMRYwFAYDVQQLDA1UZXN0IFN1aXRlIENBMRAwDgYD
+VQQDDAdTZXJmIENBMSEwHwYJKoZIhvcNAQkBFhJzZXJmY2FAZXhhbXBsZS5jb20w
+HhcNMTMwNDEzMTE0MTAxWhcNMTQwNDEzMTE0MTAxWjCBrDELMAkGA1UEBhMCQkUx
+EDAOBgNVBAgMB0FudHdlcnAxETAPBgNVBAcMCE1lY2hlbGVuMR8wHQYDVQQKDBZJ
+biBTZXJmIHdlIHRydXN0LCBJbmMuMRowGAYDVQQLDBFUZXN0IFN1aXRlIFNlcnZl
+cjEUMBIGA1UEAwwLU2VyZiBTZXJ2ZXIxJTAjBgkqhkiG9w0BCQEWFnNlcmZzZXJ2
+ZXJAZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKqNVucN
+mQObP7PAKmMzUWVL59JsYNJS14ptyYuTPUwa6ykmnBncpaZwPwunaU2LNQC2j/JP
+tjhDuafILVF/8vcAKEi495p9pX1cF/fQFFSGOYhDHVzY1FafiKg8R39lz5RWsNi2
+3SVmNLrLQ83fk84nG1d/ilD1WjPTVVL/nvdPAgMBAAEwDQYJKoZIhvcNAQEFBQAD
+gYEAggKAiezCVlEf0fYvjNlQScJ/AHZTZRWWuw9+s1sGwpxEdzTpZEHKzapBSm+w
+lctBERt1Dl7WNICPIqnkzs2atgyWfuYq8M7rhnor37gTOsi1nVtxnEBhVsb5kLhP
+HRSIsq1ACPWIqxBddG2mKT0bAWifKUgk2T1SR8q/Iq/9e98=
+-----END CERTIFICATE-----
diff --git a/test/server/serfserverkey.pem b/test/server/serfserverkey.pem
new file mode 100644
index 0000000..ed461a2
--- /dev/null
+++ b/test/server/serfserverkey.pem
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,8412FEAB72C5064F
+
+7hX15avmcrhdzHcirFHRc3clpNSnln+QFAsqXZjVc0TGWSKkrpQco783LDfIzLF1
+SWQUseIsIfELrxuFRV32kEwI75pwP27X82M5sDhp2Bw3Dxv++ZeMNRoCX1a3+fkO
+2I9QC6KFbvqdMeQXDAcwJXrR9ASCHtVoQbrdoMpoBo6n4NwRrF9loaPHtHgSnF64
+dQjmT0s7QU99qW/PbODjzfzpY+rqrtyu3lXx+XVkFTWrDTU+DpFXfOyUF3iqSd5U
+pEW1pimvRPF5geG8xxhAeOEfb8XZJINsfs1OI/5zpPyeXmBnwVNdgEW368pZ2ePp
+1MUd6Te6OwXoZXkCYghWm4iQSv2zSulCUq6pa55Rgb5+Zl8d74+vJ9N4Gt+g+0w6
+PkhkhizZiExYFV1GYmmTRx9BjzXgmo9qMDDtr9xENYB5KWgvSm1KmmUxKFZJZcPu
+zkv7vvlwrCPsUlsEOySanA0h6IME+ktPaQkBBG1aa28uorZD4Nbl81XYVt7jNifC
+hz9IHFxRjf51xA9WHQxDorztg74I0ZcOK1hcpCo40ivrI2Oruq3Zo/15eJNnorW2
+4cru/LaU29CZs1EaYLoANh7RFhTaQb+MkeYluwU7O6mF2DBaWvO+8lu61dLhLtEM
+SkJ3O1rOH5JzUf/bLat9L9fwGNJzPYcA1/3S6r+5q3tVdgR2s47v6WBOhXFFuR7K
+f5DC83PjOYSeWcgCoFP/Z1kW15pnJua4ORqo1NSvqFTh/jaeZHLDaX08f0GkR8s4
+c26JsBsKf6QWqQmISaWYQK2YgeEeAxM/tEnAUH2AouTJnu+6XzsL4w==
+-----END RSA PRIVATE KEY-----
diff --git a/test/server/test_server.c b/test/server/test_server.c
index 1ad2c9e..6130d6e 100644
--- a/test/server/test_server.c
+++ b/test/server/test_server.c
@@ -23,44 +23,6 @@
#include "test_server.h"
-struct serv_ctx_t {
- /* Pool for resource allocation. */
- apr_pool_t *pool;
-
- apr_int32_t options;
-
- /* Array of actions which server will replay when client connected. */
- test_server_action_t *action_list;
- /* Size of action_list array. */
- apr_size_t action_count;
- /* Index of current action. */
- apr_size_t cur_action;
-
- /* Array of messages the server will receive from the client. */
- test_server_message_t *message_list;
- /* Size of message_list array. */
- apr_size_t message_count;
- /* Index of current message. */
- apr_size_t cur_message;
-
- /* Number of messages received that the server didn't respond to yet. */
- apr_size_t outstanding_responses;
-
- /* Position in message buffer (incoming messages being read). */
- apr_size_t message_buf_pos;
-
- /* Position in action buffer. (outgoing messages being sent). */
- apr_size_t action_buf_pos;
-
- /* Address for server binding. */
- apr_sockaddr_t *serv_addr;
- apr_socket_t *serv_sock;
-
- /* Accepted client socket. NULL if there is no client socket. */
- apr_socket_t *client_sock;
-
-};
-
/* Replay support functions */
static void next_message(serv_ctx_t *servctx)
{
@@ -73,6 +35,20 @@ static void next_action(serv_ctx_t *servctx)
servctx->action_buf_pos = 0;
}
+static apr_status_t
+socket_write(serv_ctx_t *serv_ctx, const char *data,
+ apr_size_t *len)
+{
+ return apr_socket_send(serv_ctx->client_sock, data, len);
+}
+
+static apr_status_t
+socket_read(serv_ctx_t *serv_ctx, char *data,
+ apr_size_t *len)
+{
+ return apr_socket_recv(serv_ctx->client_sock, data, len);
+}
+
/* Verify received requests and take the necessary actions
(return a response, kill the connection ...) */
static apr_status_t replay(serv_ctx_t *servctx,
@@ -94,7 +70,7 @@ static apr_status_t replay(serv_ctx_t *servctx,
char buf[128];
apr_size_t len = sizeof(buf);
- status = apr_socket_recv(servctx->client_sock, buf, &len);
+ status = servctx->read(servctx, buf, &len);
if (! APR_STATUS_IS_EAGAIN(status)) {
/* we're out of actions! */
printf("Received more requests than expected.\n");
@@ -110,7 +86,7 @@ static apr_status_t replay(serv_ctx_t *servctx,
char buf[128];
apr_size_t len = sizeof(buf);
- status = apr_socket_recv(servctx->client_sock, buf, &len);
+ status = servctx->read(servctx, buf, &len);
if (status == APR_EOF) {
apr_socket_close(servctx->client_sock);
@@ -135,7 +111,7 @@ static apr_status_t replay(serv_ctx_t *servctx,
if (len > sizeof(buf))
len = sizeof(buf);
- status = apr_socket_recv(servctx->client_sock, buf, &len);
+ status = servctx->read(servctx, buf, &len);
if (status != APR_SUCCESS)
return status;
@@ -176,8 +152,9 @@ static apr_status_t replay(serv_ctx_t *servctx,
msg_len = strlen(action->text);
len = msg_len - servctx->action_buf_pos;
- status = apr_socket_send(servctx->client_sock,
- action->text + servctx->action_buf_pos, &len);
+ status = servctx->send(servctx,
+ action->text + servctx->action_buf_pos,
+ &len);
if (status != APR_SUCCESS)
return status;
@@ -219,7 +196,13 @@ apr_status_t test_server_run(serv_ctx_t *servctx,
const apr_pollfd_t *desc;
/* create a new pollset */
+#ifdef BROKEN_WSAPOLL
+ status = apr_pollset_create_ex(&pollset, 32, pool, 0,
+ APR_POLLSET_SELECT);
+#else
status = apr_pollset_create(&pollset, 32, pool, 0);
+#endif
+
if (status != APR_SUCCESS)
return status;
@@ -261,6 +244,13 @@ apr_status_t test_server_run(serv_ctx_t *servctx,
}
if (desc->desc.s == servctx->client_sock) {
+ if (servctx->handshake) {
+ status = servctx->handshake(servctx);
+ }
+
+ if (status)
+ goto cleanup;
+
/* Replay data to socket. */
status = replay(servctx, desc->rtnevents, pool);
@@ -286,20 +276,20 @@ cleanup:
return status;
}
-/* Start a TCP server on port SERV_PORT in thread THREAD. srv_replay is a array
- of action to replay when connection started. replay_count is count of
- actions in srv_replay. */
-apr_status_t test_start_server(serv_ctx_t **servctx_p,
- apr_sockaddr_t *address,
- test_server_message_t *message_list,
- apr_size_t message_count,
- test_server_action_t *action_list,
- apr_size_t action_count,
- apr_int32_t options,
- apr_pool_t *pool)
+
+/* Setup the context needed to start a TCP server on adress.
+ message_list is a list of expected requests.
+ action_list is the list of responses to be returned in order.
+ */
+void test_setup_server(serv_ctx_t **servctx_p,
+ apr_sockaddr_t *address,
+ test_server_message_t *message_list,
+ apr_size_t message_count,
+ test_server_action_t *action_list,
+ apr_size_t action_count,
+ apr_int32_t options,
+ apr_pool_t *pool)
{
- apr_status_t status;
- apr_socket_t *serv_sock;
serv_ctx_t *servctx;
servctx = apr_pcalloc(pool, sizeof(*servctx));
@@ -313,12 +303,58 @@ apr_status_t test_start_server(serv_ctx_t **servctx_p,
servctx->action_list = action_list;
servctx->action_count = action_count;
+ /* Start replay from first action. */
+ servctx->cur_action = 0;
+ servctx->action_buf_pos = 0;
+ servctx->outstanding_responses = 0;
+
+ servctx->read = socket_read;
+ servctx->send = socket_write;
+
+ *servctx_p = servctx;
+}
+
+void test_setup_https_server(serv_ctx_t **servctx_p,
+ apr_sockaddr_t *address,
+ test_server_message_t *message_list,
+ apr_size_t message_count,
+ test_server_action_t *action_list,
+ apr_size_t action_count,
+ apr_int32_t options,
+ const char *keyfile,
+ const char *certfile,
+ apr_pool_t *pool)
+{
+ serv_ctx_t *servctx;
+
+ test_setup_server(servctx_p, address, message_list,
+ message_count, action_list, action_count,
+ options, pool);
+
+ servctx = *servctx_p;
+
+ servctx->handshake = ssl_handshake;
+ /* Override with SSL encrypt/decrypt functions */
+ servctx->read = ssl_socket_read;
+ servctx->send = ssl_socket_write;
+
+ init_ssl_context(servctx, keyfile, certfile);
+}
+
+apr_status_t test_start_server(serv_ctx_t *servctx)
+{
+ apr_status_t status;
+ apr_socket_t *serv_sock;
+
/* create server socket */
#if APR_VERSION_AT_LEAST(1, 0, 0)
- status = apr_socket_create(&serv_sock, address->family, SOCK_STREAM, 0,
- pool);
+ status = apr_socket_create(&serv_sock, servctx->serv_addr->family,
+ SOCK_STREAM, 0,
+ servctx->pool);
#else
- status = apr_socket_create(&serv_sock, address->family, SOCK_STREAM, pool);
+ status = apr_socket_create(&serv_sock, servctx->serv_addr->family,
+ SOCK_STREAM,
+ servctx->pool);
#endif
if (status != APR_SUCCESS)
@@ -332,28 +368,29 @@ apr_status_t test_start_server(serv_ctx_t **servctx_p,
if (status != APR_SUCCESS)
return status;
- /* Start replay from first action. */
- servctx->cur_action = 0;
- servctx->action_buf_pos = 0;
- servctx->outstanding_responses = 0;
-
/* listen for clients */
- apr_socket_listen(serv_sock, SOMAXCONN);
+ status = apr_socket_listen(serv_sock, SOMAXCONN);
if (status != APR_SUCCESS)
return status;
servctx->serv_sock = serv_sock;
servctx->client_sock = NULL;
+
return APR_SUCCESS;
}
apr_status_t test_server_destroy(serv_ctx_t *servctx, apr_pool_t *pool)
{
- apr_socket_close(servctx->serv_sock);
+ apr_status_t status;
+
+ status = apr_socket_close(servctx->serv_sock);
if (servctx->client_sock) {
apr_socket_close(servctx->client_sock);
}
- return APR_SUCCESS;
+ if (servctx->ssl_ctx)
+ cleanup_ssl_context(servctx);
+
+ return status;
}
diff --git a/test/server/test_server.h b/test/server/test_server.h
index 9e8b0e2..65a61e6 100644
--- a/test/server/test_server.h
+++ b/test/server/test_server.h
@@ -16,8 +16,6 @@
#ifndef TEST_SERVER_H
#define TEST_SERVER_H
-typedef struct serv_ctx_t serv_ctx_t;
-
#define TEST_SERVER_DUMP 1
/* Default port for our test server. */
@@ -26,6 +24,15 @@ typedef struct serv_ctx_t serv_ctx_t;
#define PROXY_PORT 23456
+typedef struct serv_ctx_t serv_ctx_t;
+
+typedef apr_status_t (*send_func_t)(serv_ctx_t *serv_ctx, const char *data,
+ apr_size_t *len);
+typedef apr_status_t (*receive_func_t)(serv_ctx_t *serv_ctx, char *data,
+ apr_size_t *len);
+
+typedef apr_status_t (*handshake_func_t)(serv_ctx_t *serv_ctx);
+
typedef struct
{
enum {
@@ -44,14 +51,70 @@ typedef struct
const char *text;
} test_server_message_t;
-apr_status_t test_start_server(serv_ctx_t **servctx_p,
- apr_sockaddr_t *address,
- test_server_message_t *message_list,
- apr_size_t message_count,
- test_server_action_t *action_list,
- apr_size_t action_count,
- apr_int32_t options,
- apr_pool_t *pool);
+struct serv_ctx_t {
+ /* Pool for resource allocation. */
+ apr_pool_t *pool;
+
+ apr_int32_t options;
+
+ /* Array of actions which server will replay when client connected. */
+ test_server_action_t *action_list;
+ /* Size of action_list array. */
+ apr_size_t action_count;
+ /* Index of current action. */
+ apr_size_t cur_action;
+
+ /* Array of messages the server will receive from the client. */
+ test_server_message_t *message_list;
+ /* Size of message_list array. */
+ apr_size_t message_count;
+ /* Index of current message. */
+ apr_size_t cur_message;
+
+ /* Number of messages received that the server didn't respond to yet. */
+ apr_size_t outstanding_responses;
+
+ /* Position in message buffer (incoming messages being read). */
+ apr_size_t message_buf_pos;
+
+ /* Position in action buffer. (outgoing messages being sent). */
+ apr_size_t action_buf_pos;
+
+ /* Address for server binding. */
+ apr_sockaddr_t *serv_addr;
+ apr_socket_t *serv_sock;
+
+ /* Accepted client socket. NULL if there is no client socket. */
+ apr_socket_t *client_sock;
+
+ send_func_t send;
+ receive_func_t read;
+
+ handshake_func_t handshake;
+ void *ssl_ctx;
+};
+
+void test_setup_server(serv_ctx_t **servctx_p,
+ apr_sockaddr_t *address,
+ test_server_message_t *message_list,
+ apr_size_t message_count,
+ test_server_action_t *action_list,
+ apr_size_t action_count,
+ apr_int32_t options,
+ apr_pool_t *pool);
+
+void test_setup_https_server(serv_ctx_t **servctx_p,
+ apr_sockaddr_t *address,
+ test_server_message_t *message_list,
+ apr_size_t message_count,
+ test_server_action_t *action_list,
+ apr_size_t action_count,
+ apr_int32_t options,
+ const char *keyfile,
+ const char *certfile,
+ apr_pool_t *pool);
+
+apr_status_t test_start_server(serv_ctx_t *serv_ctx);
apr_status_t test_server_run(serv_ctx_t *servctx,
apr_short_interval_time_t duration,
@@ -59,6 +122,16 @@ apr_status_t test_server_run(serv_ctx_t *servctx,
apr_status_t test_server_destroy(serv_ctx_t *servctx, apr_pool_t *pool);
+apr_status_t init_ssl_context(serv_ctx_t *serv_ctx,
+ const char *keyfile,
+ const char *certfile);
+apr_status_t ssl_handshake(serv_ctx_t *servctx);
+apr_status_t ssl_socket_write(serv_ctx_t *serv_ctx, const char *data,
+ apr_size_t *len);
+apr_status_t ssl_socket_read(serv_ctx_t *serv_ctx, char *data, apr_size_t *len);
+void cleanup_ssl_context(serv_ctx_t *serv_ctx);
+
+
#ifndef APR_VERSION_AT_LEAST /* Introduced in APR 1.3.0 */
#define APR_VERSION_AT_LEAST(major,minor,patch) \
(((major) < APR_MAJOR_VERSION) \
@@ -67,4 +140,5 @@ apr_status_t test_server_destroy(serv_ctx_t *servctx, apr_pool_t *pool);
(patch) <= APR_PATCH_VERSION))
#endif /* APR_VERSION_AT_LEAST */
+
#endif /* TEST_SERVER_H */
diff --git a/test/server/test_sslserver.c b/test/server/test_sslserver.c
new file mode 100644
index 0000000..74492ec
--- /dev/null
+++ b/test/server/test_sslserver.c
@@ -0,0 +1,252 @@
+/* Copyright 2013 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "serf.h"
+#include "test_server.h"
+
+#include "serf_private.h"
+
+//#ifdef SERF_HAVE_OPENSSL
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#define TEST_VERBOSE 0
+
+static int init_done = 0;
+
+typedef struct ssl_context_t {
+ int handshake_done;
+
+ SSL_CTX* ctx;
+ SSL* ssl;
+ BIO *bio;
+
+} ssl_context_t;
+
+int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata)
+{
+ strncpy(buf, "serftest", size);
+ buf[size - 1] = '\0';
+ return strlen(buf);
+}
+
+static int bio_apr_socket_create(BIO *bio)
+{
+ bio->shutdown = 1;
+ bio->init = 1;
+ bio->num = -1;
+ bio->ptr = NULL;
+
+ return 1;
+}
+
+static int bio_apr_socket_destroy(BIO *bio)
+{
+ /* Did we already free this? */
+ if (bio == NULL) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static long bio_apr_socket_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+ long ret = 1;
+
+ switch (cmd) {
+ default:
+ /* abort(); */
+ break;
+ case BIO_CTRL_FLUSH:
+ /* At this point we can't force a flush. */
+ break;
+ case BIO_CTRL_PUSH:
+ case BIO_CTRL_POP:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+/* Returns the amount read. */
+static int bio_apr_socket_read(BIO *bio, char *in, int inlen)
+{
+ apr_size_t len = inlen;
+ serv_ctx_t *serv_ctx = bio->ptr;
+ apr_status_t status;
+
+ BIO_clear_retry_flags(bio);
+
+ status = apr_socket_recv(serv_ctx->client_sock, in, &len);
+ if (status == APR_EAGAIN) {
+ BIO_set_retry_read(bio);
+ if (len == 0)
+ return -1;
+
+ }
+
+ if (SERF_BUCKET_READ_ERROR(status))
+ return -1;
+
+ serf__log(TEST_VERBOSE, __FILE__, "Read %d bytes from socket with status %d.\n",
+ len, status);
+
+ return len;
+}
+
+/* Returns the amount written. */
+static int bio_apr_socket_write(BIO *bio, const char *in, int inlen)
+{
+ apr_size_t len = inlen;
+ serv_ctx_t *serv_ctx = bio->ptr;
+
+ apr_status_t status = apr_socket_send(serv_ctx->client_sock, in, &len);
+
+ if (SERF_BUCKET_READ_ERROR(status))
+ return -1;
+
+ serf__log(TEST_VERBOSE, __FILE__, "Wrote %d of %d bytes to socket.\n",
+ len, inlen);
+
+ return len;
+}
+
+
+static BIO_METHOD bio_apr_socket_method = {
+ BIO_TYPE_SOCKET,
+ "APR sockets",
+ bio_apr_socket_write,
+ bio_apr_socket_read,
+ NULL, /* Is this called? */
+ NULL, /* Is this called? */
+ bio_apr_socket_ctrl,
+ bio_apr_socket_create,
+ bio_apr_socket_destroy,
+#ifdef OPENSSL_VERSION_NUMBER
+ NULL /* sslc does not have the callback_ctrl field */
+#endif
+};
+
+apr_status_t init_ssl_context(serv_ctx_t *serv_ctx,
+ const char *keyfile,
+ const char *certfile)
+{
+ ssl_context_t *ssl_ctx = apr_pcalloc(serv_ctx->pool, sizeof(*ssl_ctx));
+ serv_ctx->ssl_ctx = ssl_ctx;
+
+ /* Init OpenSSL globally */
+ if (!init_done)
+ {
+ CRYPTO_malloc_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ init_done = 1;
+ }
+
+ /* Init this connection */
+ if (!ssl_ctx->ctx) {
+ ssl_ctx->ctx = SSL_CTX_new(SSLv23_server_method());
+ SSL_CTX_set_cipher_list(ssl_ctx->ctx, "ALL");
+ SSL_CTX_set_default_passwd_cb(ssl_ctx->ctx, pem_passwd_cb);
+
+ ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
+ SSL_use_PrivateKey_file(ssl_ctx->ssl, keyfile, SSL_FILETYPE_PEM);
+ SSL_use_certificate_file(ssl_ctx->ssl, certfile, SSL_FILETYPE_PEM);
+
+
+ ssl_ctx->bio = BIO_new(&bio_apr_socket_method);
+ ssl_ctx->bio->ptr = serv_ctx;
+ SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
+ }
+
+ return APR_SUCCESS;
+}
+
+apr_status_t ssl_handshake(serv_ctx_t *serv_ctx)
+{
+ ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+ int result;
+
+ if (ssl_ctx->handshake_done)
+ return APR_SUCCESS;
+
+ /* SSL handshake */
+ result = SSL_accept(ssl_ctx->ssl);
+ if (result == 1) {
+ serf__log(TEST_VERBOSE, __FILE__, "Handshake successful.\n");
+ ssl_ctx->handshake_done = 1;
+ }
+ else {
+ int ssl_err;
+
+ ssl_err = SSL_get_error(ssl_ctx->ssl, result);
+ switch (ssl_err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ return APR_EAGAIN;
+ default:
+ serf__log(TEST_VERBOSE, __FILE__, "SSL Error %d: ", ssl_err);
+ ERR_print_errors_fp(stderr);
+ serf__log_nopref(TEST_VERBOSE, "\n");
+ return APR_EGENERAL;
+ }
+ }
+
+ return APR_EAGAIN;
+}
+
+apr_status_t
+ssl_socket_write(serv_ctx_t *serv_ctx, const char *data,
+ apr_size_t *len)
+{
+ ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+ int result = SSL_write(ssl_ctx->ssl, data, *len);
+ if (result > 0) {
+ *len = result;
+ return APR_SUCCESS;
+ }
+
+ return APR_EGENERAL;
+}
+
+apr_status_t
+ssl_socket_read(serv_ctx_t *serv_ctx, char *data,
+ apr_size_t *len)
+{
+ ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+ int result = SSL_read(ssl_ctx->ssl, data, *len);
+ if (result > 0) {
+ *len = result;
+ return APR_SUCCESS;
+ }
+
+ return APR_EGENERAL;
+}
+
+void cleanup_ssl_context(serv_ctx_t *serv_ctx)
+{
+ ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+ SSL_clear(ssl_ctx->ssl);
+ SSL_CTX_free(ssl_ctx->ctx);
+}
+//#endif /* SERF_HAVE_OPENSSL */ \ No newline at end of file
diff --git a/test/test_buckets.c b/test/test_buckets.c
index 7d4f7ac..4707d70 100644
--- a/test/test_buckets.c
+++ b/test/test_buckets.c
@@ -20,8 +20,44 @@
#include "serf.h"
#include "test_serf.h"
+/* test case has access to internal functions. */
+#include "serf_private.h"
+
#define CRLF "\r\n"
+static apr_status_t read_all(serf_bucket_t *bkt,
+ char *buf,
+ apr_size_t buf_len,
+ apr_size_t *read_len)
+{
+ const char *data;
+ apr_size_t data_len;
+ apr_status_t status;
+ apr_size_t read;
+
+ read = 0;
+
+ do
+ {
+ status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &data_len);
+
+ if (!SERF_BUCKET_READ_ERROR(status))
+ {
+ if (data_len > buf_len - read)
+ {
+ /* Buffer is not large enough to read all data */
+ data_len = buf_len - read;
+ status = APR_EGENERAL;
+ }
+ memcpy(buf + read, data, data_len);
+ read += data_len;
+ }
+ } while(status == APR_SUCCESS);
+
+ *read_len = read;
+ return status;
+}
+
static void test_simple_bucket_readline(CuTest *tc)
{
apr_status_t status;
@@ -201,7 +237,7 @@ static void test_bucket_header_set(CuTest *tc)
CuAssertStrEquals(tc, "bar,baz,test", serf_bucket_headers_get(hdrs, "Foo"));
- // headers are case insensitive.
+ /* headers are case insensitive. */
CuAssertStrEquals(tc, "bar,baz,test", serf_bucket_headers_get(hdrs, "fOo"));
test_teardown(test_pool);
}
@@ -384,6 +420,44 @@ static void test_iovec_buckets(CuTest *tc)
test_teardown(test_pool);
}
+/* Construct a header bucket with some headers, and then read from it. */
+static void test_header_buckets(CuTest *tc)
+{
+ apr_status_t status;
+ apr_pool_t *test_pool = test_setup();
+ serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+ NULL);
+ const char *cur;
+
+ serf_bucket_t *hdrs = serf_bucket_headers_create(alloc);
+ CuAssertTrue(tc, hdrs != NULL);
+
+ serf_bucket_headers_set(hdrs, "Content-Type", "text/plain");
+ serf_bucket_headers_set(hdrs, "Content-Length", "100");
+
+ /* Note: order not guaranteed, assume here that it's fifo. */
+ cur = "Content-Type: text/plain" CRLF
+ "Content-Length: 100" CRLF
+ CRLF
+ CRLF;
+ while (1) {
+ const char *data;
+ apr_size_t len;
+
+ status = serf_bucket_read(hdrs, SERF_READ_ALL_AVAIL, &data, &len);
+ CuAssert(tc, "Unexpected error when waiting for response headers",
+ !SERF_BUCKET_READ_ERROR(status));
+ if (SERF_BUCKET_READ_ERROR(status) ||
+ APR_STATUS_IS_EOF(status))
+ break;
+
+ /* Check that the bytes read match with expected at current position. */
+ CuAssertStrnEquals(tc, cur, len, data);
+ cur += len;
+ }
+ CuAssertIntEquals(tc, APR_EOF, status);
+}
+
static void test_aggregate_buckets(CuTest *tc)
{
apr_status_t status;
@@ -409,6 +483,255 @@ static void test_aggregate_buckets(CuTest *tc)
test_teardown(test_pool);
}
+/* Test for issue: the server aborts the connection in the middle of
+ streaming the body of the response, where the length was set with the
+ Content-Length header. Test that we get a decent error code from the
+ response bucket instead of APR_EOF. */
+static void test_response_body_too_small_cl(CuTest *tc)
+{
+ serf_bucket_t *bkt, *tmp;
+ apr_pool_t *test_pool = test_setup();
+ serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+ NULL);
+
+ /* Make a response of 60 bytes, but set the Content-Length to 100. */
+#define BODY "12345678901234567890"\
+ "12345678901234567890"\
+ "12345678901234567890"
+
+ tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+ "Content-Type: text/plain" CRLF
+ "Content-Length: 100" CRLF
+ CRLF
+ BODY,
+ alloc);
+
+ bkt = serf_bucket_response_create(tmp, alloc);
+
+ {
+ const char *data;
+ apr_size_t len;
+ apr_status_t status;
+
+ status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
+
+ CuAssert(tc, "Read more data than expected.",
+ strlen(BODY) >= len);
+ CuAssert(tc, "Read data is not equal to expected.",
+ strncmp(BODY, data, len) == 0);
+ CuAssert(tc, "Error expected due to response body too short!",
+ SERF_BUCKET_READ_ERROR(status));
+ CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+ }
+}
+#undef BODY
+
+/* Test for issue: the server aborts the connection in the middle of
+ streaming the body of the response, using chunked encoding. Test that we get
+ a decent error code from the response bucket instead of APR_EOF. */
+static void test_response_body_too_small_chunked(CuTest *tc)
+{
+ serf_bucket_t *bkt, *tmp;
+ apr_pool_t *test_pool = test_setup();
+ serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+ NULL);
+
+ /* Make a response of 60 bytes, but set the chunk size to 60 and don't end
+ with chunk of length 0. */
+#define BODY "12345678901234567890"\
+"12345678901234567890"\
+"12345678901234567890"
+
+ tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+ "Content-Type: text/plain" CRLF
+ "Transfer-Encoding: chunked" CRLF
+ CRLF
+ "64" CRLF BODY,
+ alloc);
+
+ bkt = serf_bucket_response_create(tmp, alloc);
+
+ {
+ const char *data;
+ apr_size_t len;
+ apr_status_t status;
+
+ status = serf_bucket_read(bkt, SERF_READ_ALL_AVAIL, &data, &len);
+
+ CuAssert(tc, "Read more data than expected.",
+ strlen(BODY) >= len);
+ CuAssert(tc, "Read data is not equal to expected.",
+ strncmp(BODY, data, len) == 0);
+ CuAssert(tc, "Error expected due to response body too short!",
+ SERF_BUCKET_READ_ERROR(status));
+ CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+ }
+}
+#undef BODY
+
+/* Test for issue: the server aborts the connection in the middle of
+ streaming trailing CRLF after body chunk. Test that we get
+ a decent error code from the response bucket instead of APR_EOF. */
+static void test_response_body_chunked_no_crlf(CuTest *tc)
+{
+ serf_bucket_t *bkt, *tmp;
+ apr_pool_t *test_pool = test_setup();
+ serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+ NULL);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+ "Content-Type: text/plain" CRLF
+ "Transfer-Encoding: chunked" CRLF
+ CRLF
+ "2" CRLF
+ "AB",
+ alloc);
+
+ bkt = serf_bucket_response_create(tmp, alloc);
+
+ {
+ char buf[1024];
+ apr_size_t len;
+ apr_status_t status;
+
+ status = read_all(bkt, buf, sizeof(buf), &len);
+
+ CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+ }
+ test_teardown(test_pool);
+}
+
+/* Test for issue: the server aborts the connection in the middle of
+ streaming trailing CRLF after body chunk. Test that we get
+ a decent error code from the response bucket instead of APR_EOF. */
+static void test_response_body_chunked_incomplete_crlf(CuTest *tc)
+{
+ serf_bucket_t *bkt, *tmp;
+ apr_pool_t *test_pool = test_setup();
+ serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+ NULL);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+ "Content-Type: text/plain" CRLF
+ "Transfer-Encoding: chunked" CRLF
+ CRLF
+ "2" CRLF
+ "AB"
+ "\r",
+ alloc);
+
+ bkt = serf_bucket_response_create(tmp, alloc);
+
+ {
+ char buf[1024];
+ apr_size_t len;
+ apr_status_t status;
+
+ status = read_all(bkt, buf, sizeof(buf), &len);
+
+ CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+ }
+ test_teardown(test_pool);
+}
+
+static void test_response_body_chunked_gzip_small(CuTest *tc)
+{
+ serf_bucket_t *bkt, *tmp;
+ apr_pool_t *test_pool = test_setup();
+ serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+ NULL);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF
+ "Content-Type: text/plain" CRLF
+ "Transfer-Encoding: chunked" CRLF
+ "Content-Encoding: gzip" CRLF
+ CRLF
+ "2" CRLF
+ "A",
+ alloc);
+
+ bkt = serf_bucket_response_create(tmp, alloc);
+
+ {
+ char buf[1024];
+ apr_size_t len;
+ apr_status_t status;
+
+ status = read_all(bkt, buf, sizeof(buf), &len);
+
+ CuAssertIntEquals(tc, SERF_ERROR_TRUNCATED_HTTP_RESPONSE, status);
+ }
+ test_teardown(test_pool);
+}
+
+static void test_response_bucket_peek_at_headers(CuTest *tc)
+{
+ apr_pool_t *test_pool = test_setup();
+ serf_bucket_t *resp_bkt1, *tmp, *hdrs;
+ serf_status_line sl;
+ serf_bucket_alloc_t *alloc = serf_bucket_allocator_create(test_pool, NULL,
+ NULL);
+ const char *hdr_val, *cur;
+ apr_status_t status;
+
+#define EXP_RESPONSE "HTTP/1.1 200 OK" CRLF\
+ "Content-Type: text/plain" CRLF\
+ "Content-Length: 100" CRLF\
+ CRLF\
+ "12345678901234567890"\
+ "12345678901234567890"\
+ "12345678901234567890"
+
+ tmp = SERF_BUCKET_SIMPLE_STRING(EXP_RESPONSE,
+ alloc);
+
+ resp_bkt1 = serf_bucket_response_create(tmp, alloc);
+
+ status = serf_bucket_response_status(resp_bkt1, &sl);
+ CuAssertIntEquals(tc, 200, sl.code);
+ CuAssertStrEquals(tc, "OK", sl.reason);
+ CuAssertIntEquals(tc, SERF_HTTP_11, sl.version);
+
+ /* Ensure that the status line & headers are read in the response_bucket. */
+ status = serf_bucket_response_wait_for_headers(resp_bkt1);
+ CuAssert(tc, "Unexpected error when waiting for response headers",
+ !SERF_BUCKET_READ_ERROR(status));
+
+ hdrs = serf_bucket_response_get_headers(resp_bkt1);
+ CuAssertPtrNotNull(tc, hdrs);
+
+ hdr_val = serf_bucket_headers_get(hdrs, "Content-Type");
+ CuAssertStrEquals(tc, "text/plain", hdr_val);
+ hdr_val = serf_bucket_headers_get(hdrs, "Content-Length");
+ CuAssertStrEquals(tc, "100", hdr_val);
+
+ /* Create a new bucket for the response which still has the original
+ status line & headers. */
+
+ status = serf_response_full_become_aggregate(resp_bkt1);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+ cur = EXP_RESPONSE;
+
+ while (1) {
+ const char *data;
+ apr_size_t len;
+ apr_status_t status;
+
+ status = serf_bucket_read(resp_bkt1, SERF_READ_ALL_AVAIL, &data, &len);
+ CuAssert(tc, "Unexpected error when waiting for response headers",
+ !SERF_BUCKET_READ_ERROR(status));
+ if (SERF_BUCKET_READ_ERROR(status) ||
+ APR_STATUS_IS_EOF(status))
+ break;
+
+ /* Check that the bytes read match with expected at current position. */
+ CuAssertStrnEquals(tc, cur, len, data);
+ cur += len;
+ }
+
+}
+#undef EXP_RESPONSE
+
CuSuite *test_buckets(void)
{
CuSuite *suite = CuSuiteNew();
@@ -417,9 +740,16 @@ CuSuite *test_buckets(void)
SUITE_ADD_TEST(suite, test_response_bucket_read);
SUITE_ADD_TEST(suite, test_response_bucket_headers);
SUITE_ADD_TEST(suite, test_response_bucket_chunked_read);
+ SUITE_ADD_TEST(suite, test_response_body_too_small_cl);
+ SUITE_ADD_TEST(suite, test_response_body_too_small_chunked);
+ SUITE_ADD_TEST(suite, test_response_body_chunked_no_crlf);
+ SUITE_ADD_TEST(suite, test_response_body_chunked_incomplete_crlf);
+ SUITE_ADD_TEST(suite, test_response_body_chunked_gzip_small);
+ SUITE_ADD_TEST(suite, test_response_bucket_peek_at_headers);
SUITE_ADD_TEST(suite, test_bucket_header_set);
SUITE_ADD_TEST(suite, test_iovec_buckets);
SUITE_ADD_TEST(suite, test_aggregate_buckets);
+ SUITE_ADD_TEST(suite, test_header_buckets);
return suite;
}
diff --git a/test/test_context.c b/test/test_context.c
index d2a24d0..14d4fa9 100644
--- a/test/test_context.c
+++ b/test/test_context.c
@@ -43,6 +43,61 @@ typedef struct {
test_baton_t *tb;
} handler_baton_t;
+/* Helper function, runs the client and server context loops and validates
+ that no errors were encountered, and all messages were sent and received. */
+static apr_status_t
+test_helper_run_requests_no_check(CuTest *tc, test_baton_t *tb,
+ int num_requests,
+ handler_baton_t handler_ctx[],
+ apr_pool_t *pool)
+{
+ apr_pool_t *iter_pool;
+ int i, done = 0;
+ apr_status_t status;
+
+ apr_pool_create(&iter_pool, pool);
+
+ while (!done)
+ {
+ apr_pool_clear(iter_pool);
+
+ status = test_server_run(tb->serv_ctx, 0, iter_pool);
+ if (!APR_STATUS_IS_TIMEUP(status) &&
+ SERF_BUCKET_READ_ERROR(status))
+ return status;
+
+ status = serf_context_run(tb->context, 0, iter_pool);
+ if (!APR_STATUS_IS_TIMEUP(status) &&
+ SERF_BUCKET_READ_ERROR(status))
+ return status;
+
+ done = 1;
+ for (i = 0; i < num_requests; i++)
+ done &= handler_ctx[i].done;
+ }
+ apr_pool_destroy(iter_pool);
+
+ return APR_SUCCESS;
+}
+
+static void
+test_helper_run_requests_expect_ok(CuTest *tc, test_baton_t *tb,
+ int num_requests,
+ handler_baton_t handler_ctx[],
+ apr_pool_t *pool)
+{
+ apr_status_t status;
+
+ status = test_helper_run_requests_no_check(tc, tb, num_requests,
+ handler_ctx, pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+ /* Check that all requests were received */
+ CuAssertIntEquals(tc, num_requests, tb->sent_requests->nelts);
+ CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
+ CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
+}
+
static serf_bucket_t* accept_response(serf_request_t *request,
serf_bucket_t *stream,
void *acceptor_baton,
@@ -133,15 +188,67 @@ static apr_status_t handle_response(serf_request_t *request,
return APR_SUCCESS;
}
+static void setup_handler(test_baton_t *tb, handler_baton_t *handler_ctx,
+ const char *method, const char *path,
+ int req_id,
+ serf_response_handler_t handler)
+{
+ handler_ctx->method = method;
+ handler_ctx->path = path;
+ handler_ctx->done = FALSE;
+
+ handler_ctx->acceptor = accept_response;
+ handler_ctx->acceptor_baton = NULL;
+ handler_ctx->handler = handler ? handler : handle_response;
+ handler_ctx->req_id = req_id;
+ handler_ctx->accepted_requests = tb->accepted_requests;
+ handler_ctx->sent_requests = tb->sent_requests;
+ handler_ctx->handled_requests = tb->handled_requests;
+ handler_ctx->tb = tb;
+}
+
+static void create_new_prio_request(test_baton_t *tb,
+ handler_baton_t *handler_ctx,
+ const char *method, const char *path,
+ int req_id)
+{
+ setup_handler(tb, handler_ctx, method, path, req_id, NULL);
+ serf_connection_priority_request_create(tb->connection,
+ setup_request,
+ handler_ctx);
+}
+
+static void create_new_request(test_baton_t *tb,
+ handler_baton_t *handler_ctx,
+ const char *method, const char *path,
+ int req_id)
+{
+ setup_handler(tb, handler_ctx, method, path, req_id, NULL);
+ serf_connection_request_create(tb->connection,
+ setup_request,
+ handler_ctx);
+}
+
+static void
+create_new_request_with_resp_hdlr(test_baton_t *tb,
+ handler_baton_t *handler_ctx,
+ const char *method, const char *path,
+ int req_id,
+ serf_response_handler_t handler)
+{
+ setup_handler(tb, handler_ctx, method, path, req_id, handler);
+ serf_connection_request_create(tb->connection,
+ setup_request,
+ handler_ctx);
+}
+
/* Validate that requests are sent and completed in the order of creation. */
static void test_serf_connection_request_create(CuTest *tc)
{
test_baton_t *tb;
- serf_request_t *request1, *request2;
- handler_baton_t handler_ctx, handler2_ctx;
+ handler_baton_t handler_ctx[2];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
apr_status_t status;
- apr_pool_t *iter_pool;
- apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
int i;
test_server_message_t message_list[] = {
{CHUNKED_REQUEST(1, "1")},
@@ -152,74 +259,31 @@ static void test_serf_connection_request_create(CuTest *tc)
{SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
{SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
};
- apr_pool_t *test_pool = test_setup();
- accepted_requests = apr_array_make(test_pool, 2, sizeof(int));
- sent_requests = apr_array_make(test_pool, 2, sizeof(int));
- handled_requests = apr_array_make(test_pool, 2, sizeof(int));
+ apr_pool_t *test_pool = test_setup();
/* Set up a test context with a server */
status = test_server_setup(&tb,
- message_list, 2,
- action_list, 2, 0, NULL,
+ message_list, num_requests,
+ action_list, num_requests, 0, NULL,
test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
- handler_ctx.method = "GET";
- handler_ctx.path = "/";
- handler_ctx.done = FALSE;
-
- handler_ctx.acceptor = accept_response;
- handler_ctx.acceptor_baton = NULL;
- handler_ctx.handler = handle_response;
- handler_ctx.req_id = 1;
- handler_ctx.accepted_requests = accepted_requests;
- handler_ctx.sent_requests = sent_requests;
- handler_ctx.handled_requests = handled_requests;
-
- request1 = serf_connection_request_create(tb->connection,
- setup_request,
- &handler_ctx);
+ create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+ create_new_request(tb, &handler_ctx[1], "GET", "/", 2);
- handler2_ctx = handler_ctx;
- handler2_ctx.req_id = 2;
-
- request2 = serf_connection_request_create(tb->connection,
- setup_request,
- &handler2_ctx);
-
- apr_pool_create(&iter_pool, test_pool);
-
- while (!handler_ctx.done || !handler2_ctx.done)
- {
- apr_pool_clear(iter_pool);
-
- status = test_server_run(tb->serv_ctx, 0, iter_pool);
- if (APR_STATUS_IS_TIMEUP(status))
- status = APR_SUCCESS;
- CuAssertIntEquals(tc, APR_SUCCESS, status);
-
- status = serf_context_run(tb->context, 0, iter_pool);
- if (APR_STATUS_IS_TIMEUP(status))
- status = APR_SUCCESS;
- CuAssertIntEquals(tc, APR_SUCCESS, status);
- }
- apr_pool_destroy(iter_pool);
-
- /* Check that all requests were received */
- CuAssertIntEquals(tc, 2, sent_requests->nelts);
- CuAssertIntEquals(tc, 2, accepted_requests->nelts);
- CuAssertIntEquals(tc, 2, handled_requests->nelts);
+ test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+ test_pool);
/* Check that the requests were sent in the order we created them */
- for (i = 0; i < sent_requests->nelts; i++) {
- int req_nr = APR_ARRAY_IDX(sent_requests, i, int);
+ for (i = 0; i < tb->sent_requests->nelts; i++) {
+ int req_nr = APR_ARRAY_IDX(tb->sent_requests, i, int);
CuAssertIntEquals(tc, i + 1, req_nr);
}
/* Check that the requests were received in the order we created them */
- for (i = 0; i < handled_requests->nelts; i++) {
- int req_nr = APR_ARRAY_IDX(handled_requests, i, int);
+ for (i = 0; i < tb->handled_requests->nelts; i++) {
+ int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
CuAssertIntEquals(tc, i + 1, req_nr);
}
@@ -232,11 +296,9 @@ static void test_serf_connection_request_create(CuTest *tc)
static void test_serf_connection_priority_request_create(CuTest *tc)
{
test_baton_t *tb;
- serf_request_t *request1, *request2, *request3;
- handler_baton_t handler_ctx, handler2_ctx, handler3_ctx;
+ handler_baton_t handler_ctx[3];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
apr_status_t status;
- apr_pool_t *iter_pool;
- apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
int i;
test_server_message_t message_list[] = {
@@ -253,81 +315,29 @@ static void test_serf_connection_priority_request_create(CuTest *tc)
apr_pool_t *test_pool = test_setup();
- accepted_requests = apr_array_make(test_pool, 3, sizeof(int));
- sent_requests = apr_array_make(test_pool, 3, sizeof(int));
- handled_requests = apr_array_make(test_pool, 3, sizeof(int));
-
/* Set up a test context with a server */
status = test_server_setup(&tb,
- message_list, 3,
- action_list, 3, 0, NULL,
+ message_list, num_requests,
+ action_list, num_requests, 0, NULL,
test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
- handler_ctx.method = "GET";
- handler_ctx.path = "/";
- handler_ctx.done = FALSE;
-
- handler_ctx.acceptor = accept_response;
- handler_ctx.acceptor_baton = NULL;
- handler_ctx.handler = handle_response;
- handler_ctx.req_id = 2;
- handler_ctx.accepted_requests = accepted_requests;
- handler_ctx.sent_requests = sent_requests;
- handler_ctx.handled_requests = handled_requests;
-
- request1 = serf_connection_request_create(tb->connection,
- setup_request,
- &handler_ctx);
-
- handler2_ctx = handler_ctx;
- handler2_ctx.req_id = 3;
+ create_new_request(tb, &handler_ctx[0], "GET", "/", 2);
+ create_new_request(tb, &handler_ctx[1], "GET", "/", 3);
+ create_new_prio_request(tb, &handler_ctx[2], "GET", "/", 1);
- request2 = serf_connection_request_create(tb->connection,
- setup_request,
- &handler2_ctx);
- handler3_ctx = handler_ctx;
- handler3_ctx.req_id = 1;
-
- request3 = serf_connection_priority_request_create(tb->connection,
- setup_request,
- &handler3_ctx);
-
- apr_pool_create(&iter_pool, test_pool);
-
- while (!handler_ctx.done || !handler2_ctx.done || !handler3_ctx.done)
- {
- apr_pool_clear(iter_pool);
-
- status = test_server_run(tb->serv_ctx, 0, iter_pool);
- if (APR_STATUS_IS_TIMEUP(status))
- status = APR_SUCCESS;
- CuAssertIntEquals(tc, APR_SUCCESS, status);
-
- status = serf_context_run(tb->context, 0, iter_pool);
- if (APR_STATUS_IS_TIMEUP(status))
- status = APR_SUCCESS;
- CuAssertIntEquals(tc, APR_SUCCESS, status);
-
- /* Debugging purposes only! */
- serf_debug__closed_conn(tb->bkt_alloc);
- }
- apr_pool_destroy(iter_pool);
-
- /* Check that all requests were received */
- CuAssertIntEquals(tc, 3, sent_requests->nelts);
- CuAssertIntEquals(tc, 3, accepted_requests->nelts);
- CuAssertIntEquals(tc, 3, handled_requests->nelts);
+ test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+ test_pool);
/* Check that the requests were sent in the order we created them */
- for (i = 0; i < sent_requests->nelts; i++) {
- int req_nr = APR_ARRAY_IDX(sent_requests, i, int);
+ for (i = 0; i < tb->sent_requests->nelts; i++) {
+ int req_nr = APR_ARRAY_IDX(tb->sent_requests, i, int);
CuAssertIntEquals(tc, i + 1, req_nr);
}
/* Check that the requests were received in the order we created them */
- for (i = 0; i < handled_requests->nelts; i++) {
- int req_nr = APR_ARRAY_IDX(handled_requests, i, int);
+ for (i = 0; i < tb->handled_requests->nelts; i++) {
+ int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
CuAssertIntEquals(tc, i + 1, req_nr);
}
@@ -337,13 +347,12 @@ static void test_serf_connection_priority_request_create(CuTest *tc)
/* Test that serf correctly handles the 'Connection:close' header when the
server is planning to close the connection. */
-#define NUM_REQUESTS 10
static void test_serf_closed_connection(CuTest *tc)
{
test_baton_t *tb;
- apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
apr_status_t status;
- handler_baton_t handler_ctx[NUM_REQUESTS];
+ handler_baton_t handler_ctx[10];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
int done = FALSE, i;
test_server_message_t message_list[] = {
@@ -390,37 +399,18 @@ static void test_serf_closed_connection(CuTest *tc)
apr_pool_t *test_pool = test_setup();
- accepted_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
- sent_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
- handled_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
-
/* Set up a test context with a server. */
status = test_server_setup(&tb,
- message_list, 10,
+ message_list, num_requests,
action_list, 12,
0,
NULL,
test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
- for (i = 0 ; i < NUM_REQUESTS ; i++) {
- /* Send some requests on the connections */
- handler_ctx[i].method = "GET";
- handler_ctx[i].path = "/";
- handler_ctx[i].done = FALSE;
-
- handler_ctx[i].acceptor = accept_response;
- handler_ctx[i].acceptor_baton = NULL;
- handler_ctx[i].handler = handle_response;
- handler_ctx[i].req_id = i+1;
- handler_ctx[i].accepted_requests = accepted_requests;
- handler_ctx[i].sent_requests = sent_requests;
- handler_ctx[i].handled_requests = handled_requests;
- handler_ctx[i].tb = tb;
-
- serf_connection_request_create(tb->connection,
- setup_request,
- &handler_ctx[i]);
+ /* Send some requests on the connections */
+ for (i = 0 ; i < num_requests ; i++) {
+ create_new_request(tb, &handler_ctx[i], "GET", "/", i+1);
}
while (1) {
@@ -438,7 +428,7 @@ static void test_serf_closed_connection(CuTest *tc)
serf_debug__closed_conn(tb->bkt_alloc);
done = TRUE;
- for (i = 0 ; i < NUM_REQUESTS ; i++)
+ for (i = 0 ; i < num_requests ; i++)
if (handler_ctx[i].done == FALSE) {
done = FALSE;
break;
@@ -447,29 +437,26 @@ static void test_serf_closed_connection(CuTest *tc)
break;
}
- /* Check that all requests were received */
- CuAssertTrue(tc, sent_requests->nelts >= NUM_REQUESTS);
- CuAssertIntEquals(tc, NUM_REQUESTS, accepted_requests->nelts);
- CuAssertIntEquals(tc, NUM_REQUESTS, handled_requests->nelts);
+ /* Check that all requests were received */
+ CuAssertTrue(tc, tb->sent_requests->nelts >= num_requests);
+ CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
+ CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
/* Cleanup */
test_server_teardown(tb, test_pool);
test_teardown(test_pool);
}
-#undef NUM_REQUESTS
/* Test if serf is sending the request to the proxy, not to the server
directly. */
static void test_serf_setup_proxy(CuTest *tc)
{
test_baton_t *tb;
- serf_request_t *request;
- handler_baton_t handler_ctx;
- apr_status_t status;
- apr_pool_t *iter_pool;
- apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
int i;
- int numrequests = 1;
+ handler_baton_t handler_ctx[1];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+ apr_pool_t *iter_pool;
+ apr_status_t status;
test_server_message_t message_list[] = {
{"GET http://localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\
@@ -488,10 +475,6 @@ static void test_serf_setup_proxy(CuTest *tc)
apr_pool_t *test_pool = test_setup();
- accepted_requests = apr_array_make(test_pool, numrequests, sizeof(int));
- sent_requests = apr_array_make(test_pool, numrequests, sizeof(int));
- handled_requests = apr_array_make(test_pool, numrequests, sizeof(int));
-
/* Set up a test context with a server, no messages expected. */
status = test_server_proxy_setup(&tb,
/* server messages and actions */
@@ -504,25 +487,11 @@ static void test_serf_setup_proxy(CuTest *tc)
NULL, test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
- handler_ctx.method = "GET";
- handler_ctx.path = "/";
- handler_ctx.done = FALSE;
-
- handler_ctx.acceptor = accept_response;
- handler_ctx.acceptor_baton = NULL;
- handler_ctx.handler = handle_response;
- handler_ctx.req_id = 1;
- handler_ctx.accepted_requests = accepted_requests;
- handler_ctx.sent_requests = sent_requests;
- handler_ctx.handled_requests = handled_requests;
-
- request = serf_connection_request_create(tb->connection,
- setup_request,
- &handler_ctx);
+ create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
apr_pool_create(&iter_pool, test_pool);
- while (!handler_ctx.done)
+ while (!handler_ctx[0].done)
{
apr_pool_clear(iter_pool);
@@ -547,19 +516,20 @@ static void test_serf_setup_proxy(CuTest *tc)
apr_pool_destroy(iter_pool);
/* Check that all requests were received */
- CuAssertIntEquals(tc, numrequests, sent_requests->nelts);
- CuAssertIntEquals(tc, numrequests, accepted_requests->nelts);
- CuAssertIntEquals(tc, numrequests, handled_requests->nelts);
+ CuAssertIntEquals(tc, num_requests, tb->sent_requests->nelts);
+ CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts);
+ CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts);
+
/* Check that the requests were sent in the order we created them */
- for (i = 0; i < sent_requests->nelts; i++) {
- int req_nr = APR_ARRAY_IDX(sent_requests, i, int);
+ for (i = 0; i < tb->sent_requests->nelts; i++) {
+ int req_nr = APR_ARRAY_IDX(tb->sent_requests, i, int);
CuAssertIntEquals(tc, i + 1, req_nr);
}
/* Check that the requests were received in the order we created them */
- for (i = 0; i < handled_requests->nelts; i++) {
- int req_nr = APR_ARRAY_IDX(handled_requests, i, int);
+ for (i = 0; i < tb->handled_requests->nelts; i++) {
+ int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int);
CuAssertIntEquals(tc, i + 1, req_nr);
}
@@ -617,7 +587,6 @@ handle_response_keepalive_limit(serf_request_t *request,
static void test_keepalive_limit_one_by_one(CuTest *tc)
{
test_baton_t *tb;
- apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
apr_status_t status;
handler_baton_t handler_ctx[SEND_REQUESTS];
int done = FALSE, i;
@@ -644,35 +613,17 @@ static void test_keepalive_limit_one_by_one(CuTest *tc)
apr_pool_t *test_pool = test_setup();
- accepted_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
- sent_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
- handled_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
-
/* Set up a test context with a server. */
status = test_server_setup(&tb,
- message_list, 7,
- action_list, 7, 0, NULL,
+ message_list, RCVD_REQUESTS,
+ action_list, RCVD_REQUESTS, 0, NULL,
test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
for (i = 0 ; i < SEND_REQUESTS ; i++) {
- /* Send some requests on the connections */
- handler_ctx[i].method = "GET";
- handler_ctx[i].path = "/";
- handler_ctx[i].done = FALSE;
-
- handler_ctx[i].acceptor = accept_response;
- handler_ctx[i].acceptor_baton = NULL;
- handler_ctx[i].handler = handle_response_keepalive_limit;
- handler_ctx[i].req_id = i+1;
- handler_ctx[i].accepted_requests = accepted_requests;
- handler_ctx[i].sent_requests = sent_requests;
- handler_ctx[i].handled_requests = handled_requests;
- handler_ctx[i].tb = tb;
-
- serf_connection_request_create(tb->connection,
- setup_request,
- &handler_ctx[i]);
+ create_new_request_with_resp_hdlr(tb, &handler_ctx[i], "GET", "/", i+1,
+ handle_response_keepalive_limit);
+ /* TODO: don't think this needs to be done in the loop. */
serf_connection_set_max_outstanding_requests(tb->connection, 1);
}
@@ -701,9 +652,9 @@ static void test_keepalive_limit_one_by_one(CuTest *tc)
}
/* Check that all requests were received */
- CuAssertIntEquals(tc, RCVD_REQUESTS, sent_requests->nelts);
- CuAssertIntEquals(tc, RCVD_REQUESTS, accepted_requests->nelts);
- CuAssertIntEquals(tc, RCVD_REQUESTS, handled_requests->nelts);
+ CuAssertIntEquals(tc, RCVD_REQUESTS, tb->sent_requests->nelts);
+ CuAssertIntEquals(tc, RCVD_REQUESTS, tb->accepted_requests->nelts);
+ CuAssertIntEquals(tc, RCVD_REQUESTS, tb->handled_requests->nelts);
/* Cleanup */
test_server_teardown(tb, test_pool);
@@ -771,8 +722,7 @@ handle_response_keepalive_limit_burst(serf_request_t *request,
static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc)
{
test_baton_t *tb;
- apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
- apr_status_t status;
+ apr_status_t status;
handler_baton_t handler_ctx[SEND_REQUESTS];
int done = FALSE, i;
@@ -798,35 +748,16 @@ static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc)
apr_pool_t *test_pool = test_setup();
- accepted_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
- sent_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
- handled_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int));
-
/* Set up a test context with a server. */
status = test_server_setup(&tb,
- message_list, 7,
- action_list, 7, 0, NULL,
+ message_list, RCVD_REQUESTS,
+ action_list, RCVD_REQUESTS, 0, NULL,
test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
for (i = 0 ; i < SEND_REQUESTS ; i++) {
- /* Send some requests on the connections */
- handler_ctx[i].method = "GET";
- handler_ctx[i].path = "/";
- handler_ctx[i].done = FALSE;
-
- handler_ctx[i].acceptor = accept_response;
- handler_ctx[i].acceptor_baton = NULL;
- handler_ctx[i].handler = handle_response_keepalive_limit_burst;
- handler_ctx[i].req_id = i+1;
- handler_ctx[i].accepted_requests = accepted_requests;
- handler_ctx[i].sent_requests = sent_requests;
- handler_ctx[i].handled_requests = handled_requests;
- handler_ctx[i].tb = tb;
-
- serf_connection_request_create(tb->connection,
- setup_request,
- &handler_ctx[i]);
+ create_new_request_with_resp_hdlr(tb, &handler_ctx[i], "GET", "/", i+1,
+ handle_response_keepalive_limit_burst);
serf_connection_set_max_outstanding_requests(tb->connection, 1);
}
@@ -855,9 +786,9 @@ static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc)
}
/* Check that all requests were received */
- CuAssertIntEquals(tc, RCVD_REQUESTS, sent_requests->nelts);
- CuAssertIntEquals(tc, RCVD_REQUESTS, accepted_requests->nelts);
- CuAssertIntEquals(tc, RCVD_REQUESTS, handled_requests->nelts);
+ CuAssertIntEquals(tc, RCVD_REQUESTS, tb->sent_requests->nelts);
+ CuAssertIntEquals(tc, RCVD_REQUESTS, tb->accepted_requests->nelts);
+ CuAssertIntEquals(tc, RCVD_REQUESTS, tb->handled_requests->nelts);
/* Cleanup */
test_server_teardown(tb, test_pool);
@@ -866,7 +797,6 @@ static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc)
#undef SEND_REQUESTS
#undef RCVD_REQUESTS
-#define NUM_REQUESTS 5
typedef struct {
apr_off_t read;
apr_off_t written;
@@ -896,10 +826,10 @@ static apr_status_t progress_conn_setup(apr_socket_t *skt,
static void test_serf_progress_callback(CuTest *tc)
{
test_baton_t *tb;
- apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
apr_status_t status;
- handler_baton_t handler_ctx[NUM_REQUESTS];
- int done = FALSE, i;
+ handler_baton_t handler_ctx[5];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+ int i;
progress_baton_t *pb;
test_server_message_t message_list[] = {
@@ -919,15 +849,11 @@ static void test_serf_progress_callback(CuTest *tc)
};
apr_pool_t *test_pool = test_setup();
-
- accepted_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
- sent_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
- handled_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int));
-
+
/* Set up a test context with a server. */
status = test_server_setup(&tb,
- message_list, 5,
- action_list, 5, 0,
+ message_list, num_requests,
+ action_list, num_requests, 0,
progress_conn_setup, test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
@@ -936,64 +862,384 @@ static void test_serf_progress_callback(CuTest *tc)
tb->user_baton = pb;
serf_context_set_progress_cb(tb->context, progress_cb, tb);
- for (i = 0 ; i < NUM_REQUESTS ; i++) {
- /* Send some requests on the connections */
- handler_ctx[i].method = "GET";
- handler_ctx[i].path = "/";
- handler_ctx[i].done = FALSE;
-
- handler_ctx[i].acceptor = accept_response;
- handler_ctx[i].acceptor_baton = NULL;
- handler_ctx[i].handler = handle_response;
- handler_ctx[i].req_id = i+1;
- handler_ctx[i].accepted_requests = accepted_requests;
- handler_ctx[i].sent_requests = sent_requests;
- handler_ctx[i].handled_requests = handled_requests;
- handler_ctx[i].tb = tb;
-
- serf_connection_request_create(tb->connection,
+ /* Send some requests on the connections */
+ for (i = 0 ; i < num_requests ; i++) {
+ create_new_request(tb, &handler_ctx[i], "GET", "/", i+1);
+ }
+
+ test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+ test_pool);
+
+ /* Check that progress was reported. */
+ CuAssertTrue(tc, pb->written > 0);
+ CuAssertTrue(tc, pb->read > 0);
+
+ /* Cleanup */
+ test_server_teardown(tb, test_pool);
+ test_teardown(test_pool);
+}
+
+
+/*****************************************************************************
+ * Issue #91: test that serf correctly handle an incoming 4xx reponse while
+ * the outgoing request wasn't written completely yet.
+ *****************************************************************************/
+
+#define REQUEST_PART1 "PROPFIND / HTTP/1.1" CRLF\
+"Host: lgo-ubuntu.local" CRLF\
+"User-Agent: SVN/1.8.0-dev (x86_64-apple-darwin11.4.2) serf/2.0.0" CRLF\
+"Content-Type: text/xml" CRLF\
+"Transfer-Encoding: chunked" CRLF \
+CRLF\
+"12d" CRLF\
+"<?xml version=""1.0"" encoding=""utf-8""?><propfind xmlns=""DAV:""><prop>"
+
+#define REQUEST_PART2 \
+"<resourcetype xmlns=""DAV:""/><getcontentlength xmlns=""DAV:""/>"\
+"<deadprop-count xmlns=""http://subversion.tigris.org/xmlns/dav/""/>"\
+"<version-name xmlns=""DAV:""/><creationdate xmlns=""DAV:""/>"\
+"<creator-displayname xmlns=""DAV:""/></prop></propfind>" CRLF\
+"0" CRLF \
+CRLF
+
+#define RESPONSE_408 "HTTP/1.1 408 Request Time-out" CRLF\
+"Date: Wed, 14 Nov 2012 19:50:35 GMT" CRLF\
+"Server: Apache/2.2.17 (Ubuntu)" CRLF\
+"Vary: Accept-Encoding" CRLF\
+"Content-Length: 305" CRLF\
+"Connection: close" CRLF\
+"Content-Type: text/html; charset=iso-8859-1" CRLF \
+CRLF\
+"<!DOCTYPE HTML PUBLIC ""-//IETF//DTD HTML 2.0//EN""><html><head>"\
+"<title>408 Request Time-out</title></head><body><h1>Request Time-out</h1>"\
+"<p>Server timeout waiting for the HTTP request from the client.</p><hr>"\
+"<address>Apache/2.2.17 (Ubuntu) Server at lgo-ubuntu.local Port 80</address>"\
+"</body></html>"
+
+
+static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket)
+{
+ serf_bucket_t *body_bkt;
+ handler_baton_t *ctx = baton;
+
+ if (ctx->done) {
+ body_bkt = serf_bucket_simple_create(REQUEST_PART1, strlen(REQUEST_PART2),
+ NULL, NULL,
+ ctx->tb->bkt_alloc);
+ serf_bucket_aggregate_append(aggregate_bucket, body_bkt);
+ }
+
+ return APR_EAGAIN;
+}
+
+static apr_status_t setup_request_timeout(
+ serf_request_t *request,
+ void *setup_baton,
+ serf_bucket_t **req_bkt,
+ serf_response_acceptor_t *acceptor,
+ void **acceptor_baton,
+ serf_response_handler_t *handler,
+ void **handler_baton,
+ apr_pool_t *pool)
+{
+ handler_baton_t *ctx = setup_baton;
+ serf_bucket_t *body_bkt;
+
+ *req_bkt = serf__bucket_stream_create(serf_request_get_alloc(request),
+ detect_eof,
+ ctx);
+
+ /* create a simple body text */
+ body_bkt = serf_bucket_simple_create(REQUEST_PART1, strlen(REQUEST_PART1),
+ NULL, NULL,
+ serf_request_get_alloc(request));
+ serf_bucket_aggregate_append(*req_bkt, body_bkt);
+
+ APR_ARRAY_PUSH(ctx->sent_requests, int) = ctx->req_id;
+
+ *acceptor = ctx->acceptor;
+ *acceptor_baton = ctx;
+ *handler = ctx->handler;
+ *handler_baton = ctx;
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t handle_response_timeout(
+ serf_request_t *request,
+ serf_bucket_t *response,
+ void *handler_baton,
+ apr_pool_t *pool)
+{
+ handler_baton_t *ctx = handler_baton;
+ serf_status_line sl;
+ apr_status_t status;
+
+ if (! response) {
+ serf_connection_request_create(ctx->tb->connection,
setup_request,
- &handler_ctx[i]);
+ ctx);
+ return APR_SUCCESS;
}
- while (1) {
- status = test_server_run(tb->serv_ctx, 0, test_pool);
- if (APR_STATUS_IS_TIMEUP(status))
- status = APR_SUCCESS;
- CuAssertIntEquals(tc, APR_SUCCESS, status);
+ if (serf_request_is_written(request) != APR_EBUSY) {
+ return APR_EGENERAL;
+ }
- status = serf_context_run(tb->context, 0, test_pool);
- if (APR_STATUS_IS_TIMEUP(status))
- status = APR_SUCCESS;
- CuAssertIntEquals(tc, APR_SUCCESS, status);
- /* Debugging purposes only! */
- serf_debug__closed_conn(tb->bkt_alloc);
+ status = serf_bucket_response_status(response, &sl);
+ if (SERF_BUCKET_READ_ERROR(status)) {
+ return status;
+ }
+ if (!sl.version && (APR_STATUS_IS_EOF(status) ||
+ APR_STATUS_IS_EAGAIN(status))) {
+ return status;
+ }
+ if (sl.code == 408) {
+ APR_ARRAY_PUSH(ctx->handled_requests, int) = ctx->req_id;
+ ctx->done = TRUE;
+ }
- done = TRUE;
- for (i = 0 ; i < NUM_REQUESTS ; i++)
- if (handler_ctx[i].done == FALSE) {
- done = FALSE;
- break;
- }
- if (done)
- break;
+ /* discard the rest of the body */
+ while (1) {
+ const char *data;
+ apr_size_t len;
+
+ status = serf_bucket_read(response, 2048, &data, &len);
+ if (SERF_BUCKET_READ_ERROR(status) ||
+ APR_STATUS_IS_EAGAIN(status) ||
+ APR_STATUS_IS_EOF(status))
+ return status;
}
- /* Check that all requests were received */
- CuAssertTrue(tc, sent_requests->nelts >= NUM_REQUESTS);
- CuAssertIntEquals(tc, NUM_REQUESTS, accepted_requests->nelts);
- CuAssertIntEquals(tc, NUM_REQUESTS, handled_requests->nelts);
+ return APR_SUCCESS;
+}
- /* Check that progress was reported. */
- CuAssertTrue(tc, pb->written > 0);
- CuAssertTrue(tc, pb->read > 0);
+static void test_serf_request_timeout(CuTest *tc)
+{
+ test_baton_t *tb;
+ apr_status_t status;
+ handler_baton_t handler_ctx[1];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+
+ test_server_message_t message_list[] = {
+ {REQUEST_PART1},
+ {REQUEST_PART2},
+ };
+
+ test_server_action_t action_list[] = {
+ {SERVER_RESPOND, RESPONSE_408},
+ };
+
+ apr_pool_t *test_pool = test_setup();
+
+ /* Set up a test context with a server. */
+ status = test_server_setup(&tb,
+ message_list, 2,
+ action_list, 1, 0,
+ NULL, test_pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+ /* Send some requests on the connection */
+ handler_ctx[0].method = "PROPFIND";
+ handler_ctx[0].path = "/";
+ handler_ctx[0].done = FALSE;
+
+ handler_ctx[0].acceptor = accept_response;
+ handler_ctx[0].acceptor_baton = NULL;
+ handler_ctx[0].handler = handle_response_timeout;
+ handler_ctx[0].req_id = 1;
+ handler_ctx[0].accepted_requests = tb->accepted_requests;
+ handler_ctx[0].sent_requests = tb->sent_requests;
+ handler_ctx[0].handled_requests = tb->handled_requests;
+ handler_ctx[0].tb = tb;
+
+ serf_connection_request_create(tb->connection,
+ setup_request_timeout,
+ &handler_ctx[0]);
+
+ test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+ test_pool);
/* Cleanup */
test_server_teardown(tb, test_pool);
test_teardown(test_pool);
}
-#undef NUM_REQUESTS
+
+static apr_status_t
+ssl_server_cert_cb_expect_failures(void *baton, int failures,
+ const serf_ssl_certificate_t *cert)
+{
+ /* We expect an error from the certificate validation function. */
+ if (failures)
+ return APR_SUCCESS;
+ else
+ return APR_EGENERAL;
+}
+
+static apr_status_t
+ssl_server_cert_cb_expect_allok(void *baton, int failures,
+ const serf_ssl_certificate_t *cert)
+{
+ /* No error expected, certificate is valid. */
+ if (failures)
+ return APR_EGENERAL;
+ else
+ return APR_SUCCESS;
+}
+
+/* Validate that we can connect successfully to an https server. */
+static void test_serf_ssl_handshake(CuTest *tc)
+{
+ test_baton_t *tb;
+ handler_baton_t handler_ctx[1];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+ apr_status_t status;
+ test_server_message_t message_list[] = {
+ {CHUNKED_REQUEST(1, "1")},
+ };
+
+ test_server_action_t action_list[] = {
+ {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+ };
+
+
+ /* Set up a test context with a server */
+ apr_pool_t *test_pool = test_setup();
+ status = test_https_server_setup(&tb,
+ message_list, num_requests,
+ action_list, num_requests, 0,
+ NULL, /* default conn setup */
+ "test/server/serfserverkey.pem",
+ "test/server/serfservercert.pem",
+ ssl_server_cert_cb_expect_failures,
+ test_pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+ create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+ test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+ test_pool);
+
+ test_server_teardown(tb, test_pool);
+ test_teardown(test_pool);
+}
+
+static apr_status_t
+https_set_root_ca_conn_setup(apr_socket_t *skt,
+ serf_bucket_t **input_bkt,
+ serf_bucket_t **output_bkt,
+ void *setup_baton,
+ apr_pool_t *pool)
+{
+ serf_ssl_certificate_t *cacert, *rootcacert;
+ test_baton_t *tb = setup_baton;
+ apr_status_t status;
+
+ status = default_https_conn_setup(skt, input_bkt, output_bkt,
+ setup_baton, pool);
+ if (status)
+ return status;
+
+ status = serf_ssl_load_cert_file(&cacert, "test/server/serfcacert.pem",
+ pool);
+ if (status)
+ return status;
+ status = serf_ssl_trust_cert(tb->ssl_context, cacert);
+ if (status)
+ return status;
+
+ status = serf_ssl_load_cert_file(&rootcacert,
+ "test/server/serfrootcacert.pem",
+ pool);
+ if (status)
+ return status;
+ status = serf_ssl_trust_cert(tb->ssl_context, rootcacert);
+ if (status)
+ return status;
+
+ return status;
+}
+
+/* Validate that server certificate validation is ok when we
+ explicitly trust our self-signed root ca. */
+static void test_serf_ssl_trust_rootca(CuTest *tc)
+{
+ test_baton_t *tb;
+ handler_baton_t handler_ctx[1];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+ apr_status_t status;
+ test_server_message_t message_list[] = {
+ {CHUNKED_REQUEST(1, "1")},
+ };
+
+ test_server_action_t action_list[] = {
+ {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+ };
+
+ /* Set up a test context with a server */
+ apr_pool_t *test_pool = test_setup();
+ status = test_https_server_setup(&tb,
+ message_list, num_requests,
+ action_list, num_requests, 0,
+ https_set_root_ca_conn_setup,
+ "test/server/serfserverkey.pem",
+ "test/server/serfservercert.pem",
+ ssl_server_cert_cb_expect_allok,
+ test_pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+ create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+ test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx,
+ test_pool);
+
+ test_server_teardown(tb, test_pool);
+ test_teardown(test_pool);
+}
+
+/* Validate that when the application rejects the cert, the context loop
+ bails out with an error. */
+static void test_serf_ssl_application_rejects_cert(CuTest *tc)
+{
+ test_baton_t *tb;
+ handler_baton_t handler_ctx[1];
+ const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
+ apr_status_t status;
+ test_server_message_t message_list[] = {
+ {CHUNKED_REQUEST(1, "1")},
+ };
+
+ test_server_action_t action_list[] = {
+ {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE},
+ };
+
+ /* Set up a test context with a server */
+ apr_pool_t *test_pool = test_setup();
+
+ /* The certificate is valid, but we tell serf to reject it by using the
+ ssl_server_cert_cb_expect_failures callback. */
+ status = test_https_server_setup(&tb,
+ message_list, num_requests,
+ action_list, num_requests, 0,
+ https_set_root_ca_conn_setup,
+ "test/server/serfserverkey.pem",
+ "test/server/serfservercert.pem",
+ ssl_server_cert_cb_expect_failures,
+ test_pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+ create_new_request(tb, &handler_ctx[0], "GET", "/", 1);
+
+ status = test_helper_run_requests_no_check(tc, tb, num_requests,
+ handler_ctx, test_pool);
+ /* We expect an error from the certificate validation function. */
+ CuAssert(tc, "Application told serf the certificate should be rejected,"
+ " expected error!", status != APR_SUCCESS);
+
+ test_server_teardown(tb, test_pool);
+ test_teardown(test_pool);
+}
CuSuite *test_context(void)
{
@@ -1006,6 +1252,10 @@ CuSuite *test_context(void)
SUITE_ADD_TEST(suite, test_keepalive_limit_one_by_one);
SUITE_ADD_TEST(suite, test_keepalive_limit_one_by_one_and_burst);
SUITE_ADD_TEST(suite, test_serf_progress_callback);
+ SUITE_ADD_TEST(suite, test_serf_request_timeout);
+ SUITE_ADD_TEST(suite, test_serf_ssl_handshake);
+ SUITE_ADD_TEST(suite, test_serf_ssl_trust_rootca);
+ SUITE_ADD_TEST(suite, test_serf_ssl_application_rejects_cert);
return suite;
}
diff --git a/test/test_serf.h b/test/test_serf.h
index 454dfcc..6c0f5e7 100644
--- a/test/test_serf.h
+++ b/test/test_serf.h
@@ -93,8 +93,30 @@ typedef struct {
/* An extra baton which can be freely used by tests. */
void *user_baton;
+ apr_array_header_t *accepted_requests, *handled_requests, *sent_requests;
+
+ serf_ssl_context_t *ssl_context;
+ serf_ssl_need_server_cert_t server_cert_cb;
} test_baton_t;
+apr_status_t default_https_conn_setup(apr_socket_t *skt,
+ serf_bucket_t **input_bkt,
+ serf_bucket_t **output_bkt,
+ void *setup_baton,
+ apr_pool_t *pool);
+
+apr_status_t test_https_server_setup(test_baton_t **tb_p,
+ test_server_message_t *message_list,
+ apr_size_t message_count,
+ test_server_action_t *action_list,
+ apr_size_t action_count,
+ apr_int32_t options,
+ serf_connection_setup_t conn_setup,
+ const char *keyfile,
+ const char *certfile,
+ serf_ssl_need_server_cert_t server_cert_cb,
+ apr_pool_t *pool);
+
apr_status_t test_server_setup(test_baton_t **tb_p,
test_server_message_t *message_list,
apr_size_t message_count,
diff --git a/test/test_ssl.c b/test/test_ssl.c
index 81b939d..43e9f9a 100644
--- a/test/test_ssl.c
+++ b/test/test_ssl.c
@@ -55,14 +55,28 @@ static void test_ssl_init(CuTest *tc)
test_teardown(test_pool);
}
+
+static const char * get_ca_file(apr_pool_t *pool, const char * file)
+{
+ char *srcdir = "";
+
+ if (apr_env_get(&srcdir, "srcdir", pool) == APR_SUCCESS) {
+ return apr_pstrcat(pool, srcdir, "/", file, NULL);
+ }
+ else {
+ return file;
+ }
+}
+
+
/* Test that loading a custom CA certificate file works. */
static void test_ssl_load_cert_file(CuTest *tc)
{
serf_ssl_certificate_t *cert = NULL;
apr_pool_t *test_pool = test_setup();
- apr_status_t status = serf_ssl_load_cert_file(&cert, "test/serftestca.pem",
- test_pool);
+ apr_status_t status = serf_ssl_load_cert_file(
+ &cert, get_ca_file(test_pool, "test/serftestca.pem"), test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
CuAssertPtrNotNull(tc, cert);
@@ -78,7 +92,8 @@ static void test_ssl_cert_subject(CuTest *tc)
apr_pool_t *test_pool = test_setup();
- status = serf_ssl_load_cert_file(&cert, "test/serftestca.pem", test_pool);
+ status = serf_ssl_load_cert_file(
+ &cert, get_ca_file(test_pool, "test/serftestca.pem"), test_pool);
CuAssertIntEquals(tc, APR_SUCCESS, status);
CuAssertPtrNotNull(tc, cert);
diff --git a/test/test_util.c b/test/test_util.c
index 9496195..e99fb79 100644
--- a/test/test_util.c
+++ b/test/test_util.c
@@ -27,7 +27,8 @@
/* Server setup function(s)
*/
-#define SERV_URL "http://localhost:" SERV_PORT_STR
+#define HTTP_SERV_URL "http://localhost:" SERV_PORT_STR
+#define HTTPS_SERV_URL "https://localhost:" SERV_PORT_STR
static apr_status_t default_server_address(apr_sockaddr_t **address,
apr_pool_t *pool)
@@ -57,22 +58,51 @@ static void default_closed_connection(serf_connection_t *conn,
}
/* Default implementation of a serf_connection_setup_t callback. */
-static apr_status_t default_conn_setup(apr_socket_t *skt,
- serf_bucket_t **input_bkt,
- serf_bucket_t **output_bkt,
- void *setup_baton,
- apr_pool_t *pool)
+static apr_status_t default_http_conn_setup(apr_socket_t *skt,
+ serf_bucket_t **input_bkt,
+ serf_bucket_t **output_bkt,
+ void *setup_baton,
+ apr_pool_t *pool)
{
- test_baton_t *ctx = setup_baton;
+ test_baton_t *tb = setup_baton;
- *input_bkt = serf_bucket_socket_create(skt, ctx->bkt_alloc);
+ *input_bkt = serf_bucket_socket_create(skt, tb->bkt_alloc);
return APR_SUCCESS;
}
+/* This function makes serf use SSL on the connection. */
+apr_status_t default_https_conn_setup(apr_socket_t *skt,
+ serf_bucket_t **input_bkt,
+ serf_bucket_t **output_bkt,
+ void *setup_baton,
+ apr_pool_t *pool)
+{
+ test_baton_t *tb = setup_baton;
+
+ *input_bkt = serf_bucket_socket_create(skt, tb->bkt_alloc);
+ *input_bkt = serf_bucket_ssl_decrypt_create(*input_bkt, NULL,
+ tb->bkt_alloc);
+ tb->ssl_context = serf_bucket_ssl_encrypt_context_get(*input_bkt);
+
+ if (output_bkt) {
+ *output_bkt = serf_bucket_ssl_encrypt_create(*output_bkt,
+ tb->ssl_context,
+ tb->bkt_alloc);
+ }
+
+ if (tb->server_cert_cb)
+ serf_ssl_server_cert_callback_set(tb->ssl_context,
+ tb->server_cert_cb,
+ tb);
+
+ return APR_SUCCESS;
+}
static apr_status_t setup(test_baton_t **tb_p,
serf_connection_setup_t conn_setup,
+ const char *serv_url,
int use_proxy,
+ apr_size_t message_count,
apr_pool_t *pool)
{
apr_status_t status;
@@ -86,6 +116,11 @@ static apr_status_t setup(test_baton_t **tb_p,
tb->context = serf_context_create(pool);
tb->bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL);
+ tb->accepted_requests = apr_array_make(pool, message_count, sizeof(int));
+ tb->sent_requests = apr_array_make(pool, message_count, sizeof(int));
+ tb->handled_requests = apr_array_make(pool, message_count, sizeof(int));
+
+
status = default_server_address(&tb->serv_addr, pool);
if (status != APR_SUCCESS)
return status;
@@ -99,14 +134,13 @@ static apr_status_t setup(test_baton_t **tb_p,
serf_config_proxy(tb->context, tb->proxy_addr);
}
- status = apr_uri_parse(pool, SERV_URL, &url);
+ status = apr_uri_parse(pool, serv_url, &url);
if (status != APR_SUCCESS)
return status;
status = serf_connection_create2(&tb->connection, tb->context,
url,
- conn_setup ? conn_setup :
- default_conn_setup,
+ conn_setup,
tb,
default_closed_connection,
tb,
@@ -116,6 +150,43 @@ static apr_status_t setup(test_baton_t **tb_p,
}
+apr_status_t test_https_server_setup(test_baton_t **tb_p,
+ test_server_message_t *message_list,
+ apr_size_t message_count,
+ test_server_action_t *action_list,
+ apr_size_t action_count,
+ apr_int32_t options,
+ serf_connection_setup_t conn_setup,
+ const char *keyfile,
+ const char *certfile,
+ serf_ssl_need_server_cert_t server_cert_cb,
+ apr_pool_t *pool)
+{
+ apr_status_t status;
+ test_baton_t *tb;
+
+ status = setup(tb_p,
+ conn_setup ? conn_setup : default_https_conn_setup,
+ HTTPS_SERV_URL,
+ FALSE,
+ message_count,
+ pool);
+ if (status != APR_SUCCESS)
+ return status;
+
+ tb = *tb_p;
+ tb->server_cert_cb = server_cert_cb;
+
+ /* Prepare a server. */
+ test_setup_https_server(&tb->serv_ctx, tb->serv_addr,
+ message_list, message_count,
+ action_list, action_count, options,
+ keyfile, certfile,
+ pool);
+ status = test_start_server(tb->serv_ctx);
+
+ return status;
+}
apr_status_t test_server_setup(test_baton_t **tb_p,
test_server_message_t *message_list,
@@ -130,8 +201,10 @@ apr_status_t test_server_setup(test_baton_t **tb_p,
test_baton_t *tb;
status = setup(tb_p,
- conn_setup,
+ conn_setup ? conn_setup : default_http_conn_setup,
+ HTTP_SERV_URL,
FALSE,
+ message_count,
pool);
if (status != APR_SUCCESS)
return status;
@@ -139,9 +212,11 @@ apr_status_t test_server_setup(test_baton_t **tb_p,
tb = *tb_p;
/* Prepare a server. */
- status = test_start_server(&tb->serv_ctx, tb->serv_addr,
- message_list, message_count,
- action_list, action_count, options, pool);
+ test_setup_server(&tb->serv_ctx, tb->serv_addr,
+ message_list, message_count,
+ action_list, action_count, options,
+ pool);
+ status = test_start_server(tb->serv_ctx);
return status;
}
@@ -164,8 +239,10 @@ test_server_proxy_setup(test_baton_t **tb_p,
test_baton_t *tb;
status = setup(tb_p,
- conn_setup,
+ conn_setup ? conn_setup : default_http_conn_setup,
+ HTTP_SERV_URL,
TRUE,
+ serv_message_count,
pool);
if (status != APR_SUCCESS)
return status;
@@ -173,18 +250,22 @@ test_server_proxy_setup(test_baton_t **tb_p,
tb = *tb_p;
/* Prepare the server. */
- status = test_start_server(&tb->serv_ctx, tb->serv_addr,
- serv_message_list, serv_message_count,
- serv_action_list, serv_action_count,
- options, pool);
+ test_setup_server(&tb->serv_ctx, tb->serv_addr,
+ serv_message_list, serv_message_count,
+ serv_action_list, serv_action_count,
+ options,
+ pool);
+ status = test_start_server(tb->serv_ctx);
if (status != APR_SUCCESS)
return status;
/* Prepare the proxy. */
- status = test_start_server(&tb->proxy_ctx, tb->proxy_addr,
- proxy_message_list, proxy_message_count,
- proxy_action_list, proxy_action_count,
- options, pool);
+ test_setup_server(&tb->proxy_ctx, tb->proxy_addr,
+ proxy_message_list, proxy_message_count,
+ proxy_action_list, proxy_action_count,
+ options,
+ pool);
+ status = test_start_server(tb->proxy_ctx);
return status;
}