Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 1 | /* |
| 2 | * HTTP test program for CUPS. |
| 3 | * |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 4 | * Copyright © 2007-2018 by Apple Inc. |
| 5 | * Copyright © 1997-2006 by Easy Software Products. |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 6 | * |
| 7 | * These coded instructions, statements, and computer programs are the |
| 8 | * property of Apple Inc. and are protected by Federal copyright |
| 9 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" |
| 10 | * which should have been included with this file. If this file is |
Philip P. Moltmann | 2447373 | 2017-05-11 09:37:47 -0700 | [diff] [blame] | 11 | * missing or damaged, see the license at "http://www.cups.org/". |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 12 | * |
| 13 | * This file is subject to the Apple OS-Developed Software exception. |
| 14 | */ |
| 15 | |
| 16 | /* |
| 17 | * Include necessary headers... |
| 18 | */ |
| 19 | |
| 20 | #include "cups-private.h" |
| 21 | |
| 22 | |
| 23 | /* |
| 24 | * Types and structures... |
| 25 | */ |
| 26 | |
| 27 | typedef struct uri_test_s /**** URI test cases ****/ |
| 28 | { |
| 29 | http_uri_status_t result; /* Expected return value */ |
| 30 | const char *uri, /* URI */ |
| 31 | *scheme, /* Scheme string */ |
| 32 | *username, /* Username:password string */ |
| 33 | *hostname, /* Hostname string */ |
| 34 | *resource; /* Resource string */ |
| 35 | int port, /* Port number */ |
| 36 | assemble_port; /* Port number for httpAssembleURI() */ |
| 37 | http_uri_coding_t assemble_coding;/* Coding for httpAssembleURI() */ |
| 38 | } uri_test_t; |
| 39 | |
| 40 | |
| 41 | /* |
| 42 | * Local globals... |
| 43 | */ |
| 44 | |
| 45 | static uri_test_t uri_tests[] = /* URI test data */ |
| 46 | { |
| 47 | /* Start with valid URIs */ |
| 48 | { HTTP_URI_STATUS_OK, "file:/filename", |
| 49 | "file", "", "", "/filename", 0, 0, |
| 50 | HTTP_URI_CODING_MOST }, |
| 51 | { HTTP_URI_STATUS_OK, "file:/filename%20with%20spaces", |
| 52 | "file", "", "", "/filename with spaces", 0, 0, |
| 53 | HTTP_URI_CODING_MOST }, |
| 54 | { HTTP_URI_STATUS_OK, "file:///filename", |
| 55 | "file", "", "", "/filename", 0, 0, |
| 56 | HTTP_URI_CODING_MOST }, |
| 57 | { HTTP_URI_STATUS_OK, "file:///filename%20with%20spaces", |
| 58 | "file", "", "", "/filename with spaces", 0, 0, |
| 59 | HTTP_URI_CODING_MOST }, |
| 60 | { HTTP_URI_STATUS_OK, "file://localhost/filename", |
| 61 | "file", "", "localhost", "/filename", 0, 0, |
| 62 | HTTP_URI_CODING_MOST }, |
| 63 | { HTTP_URI_STATUS_OK, "file://localhost/filename%20with%20spaces", |
| 64 | "file", "", "localhost", "/filename with spaces", 0, 0, |
| 65 | HTTP_URI_CODING_MOST }, |
| 66 | { HTTP_URI_STATUS_OK, "http://server/", |
| 67 | "http", "", "server", "/", 80, 0, |
| 68 | HTTP_URI_CODING_MOST }, |
| 69 | { HTTP_URI_STATUS_OK, "http://username@server/", |
| 70 | "http", "username", "server", "/", 80, 0, |
| 71 | HTTP_URI_CODING_MOST }, |
| 72 | { HTTP_URI_STATUS_OK, "http://username:passwor%64@server/", |
| 73 | "http", "username:password", "server", "/", 80, 0, |
| 74 | HTTP_URI_CODING_MOST }, |
| 75 | { HTTP_URI_STATUS_OK, "http://username:passwor%64@server:8080/", |
| 76 | "http", "username:password", "server", "/", 8080, 8080, |
| 77 | HTTP_URI_CODING_MOST }, |
| 78 | { HTTP_URI_STATUS_OK, "http://username:passwor%64@server:8080/directory/filename", |
| 79 | "http", "username:password", "server", "/directory/filename", 8080, 8080, |
| 80 | HTTP_URI_CODING_MOST }, |
| 81 | { HTTP_URI_STATUS_OK, "http://[2000::10:100]:631/ipp", |
| 82 | "http", "", "2000::10:100", "/ipp", 631, 631, |
| 83 | HTTP_URI_CODING_MOST }, |
| 84 | { HTTP_URI_STATUS_OK, "https://username:passwor%64@server/directory/filename", |
| 85 | "https", "username:password", "server", "/directory/filename", 443, 0, |
| 86 | HTTP_URI_CODING_MOST }, |
| 87 | { HTTP_URI_STATUS_OK, "ipp://username:passwor%64@[::1]/ipp", |
| 88 | "ipp", "username:password", "::1", "/ipp", 631, 0, |
| 89 | HTTP_URI_CODING_MOST }, |
| 90 | { HTTP_URI_STATUS_OK, "lpd://server/queue?reserve=yes", |
| 91 | "lpd", "", "server", "/queue?reserve=yes", 515, 0, |
| 92 | HTTP_URI_CODING_MOST }, |
| 93 | { HTTP_URI_STATUS_OK, "mailto:user@domain.com", |
| 94 | "mailto", "", "", "user@domain.com", 0, 0, |
| 95 | HTTP_URI_CODING_MOST }, |
| 96 | { HTTP_URI_STATUS_OK, "socket://server/", |
| 97 | "socket", "", "server", "/", 9100, 0, |
| 98 | HTTP_URI_CODING_MOST }, |
| 99 | { HTTP_URI_STATUS_OK, "socket://192.168.1.1:9101/", |
| 100 | "socket", "", "192.168.1.1", "/", 9101, 9101, |
| 101 | HTTP_URI_CODING_MOST }, |
| 102 | { HTTP_URI_STATUS_OK, "tel:8005551212", |
| 103 | "tel", "", "", "8005551212", 0, 0, |
| 104 | HTTP_URI_CODING_MOST }, |
| 105 | { HTTP_URI_STATUS_OK, "ipp://username:password@[v1.fe80::200:1234:5678:9abc+eth0]:999/ipp", |
| 106 | "ipp", "username:password", "fe80::200:1234:5678:9abc%eth0", "/ipp", 999, 999, |
| 107 | HTTP_URI_CODING_MOST }, |
| 108 | { HTTP_URI_STATUS_OK, "ipp://username:password@[fe80::200:1234:5678:9abc%25eth0]:999/ipp", |
| 109 | "ipp", "username:password", "fe80::200:1234:5678:9abc%eth0", "/ipp", 999, 999, |
| 110 | (http_uri_coding_t)(HTTP_URI_CODING_MOST | HTTP_URI_CODING_RFC6874) }, |
| 111 | { HTTP_URI_STATUS_OK, "http://server/admin?DEVICE_URI=usb://HP/Photosmart%25202600%2520series?serial=MY53OK70V10400", |
| 112 | "http", "", "server", "/admin?DEVICE_URI=usb://HP/Photosmart%25202600%2520series?serial=MY53OK70V10400", 80, 0, |
| 113 | HTTP_URI_CODING_MOST }, |
| 114 | { HTTP_URI_STATUS_OK, "lpd://Acme%20Laser%20(01%3A23%3A45).local._tcp._printer/", |
| 115 | "lpd", "", "Acme Laser (01:23:45).local._tcp._printer", "/", 515, 0, |
| 116 | HTTP_URI_CODING_MOST }, |
| 117 | { HTTP_URI_STATUS_OK, "ipp://HP%20Officejet%204500%20G510n-z%20%40%20Will's%20MacBook%20Pro%2015%22._ipp._tcp.local./", |
| 118 | "ipp", "", "HP Officejet 4500 G510n-z @ Will's MacBook Pro 15\"._ipp._tcp.local.", "/", 631, 0, |
| 119 | HTTP_URI_CODING_MOST }, |
| 120 | { HTTP_URI_STATUS_OK, "ipp://%22%23%2F%3A%3C%3E%3F%40%5B%5C%5D%5E%60%7B%7C%7D/", |
| 121 | "ipp", "", "\"#/:<>?@[\\]^`{|}", "/", 631, 0, |
| 122 | HTTP_URI_CODING_MOST }, |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 123 | { HTTP_URI_STATUS_UNKNOWN_SCHEME, "smb://server/Some%20Printer", |
| 124 | "smb", "", "server", "/Some Printer", 0, 0, |
| 125 | HTTP_URI_CODING_ALL }, |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 126 | |
| 127 | /* Missing scheme */ |
| 128 | { HTTP_URI_STATUS_MISSING_SCHEME, "/path/to/file/index.html", |
| 129 | "file", "", "", "/path/to/file/index.html", 0, 0, |
| 130 | HTTP_URI_CODING_MOST }, |
| 131 | { HTTP_URI_STATUS_MISSING_SCHEME, "//server/ipp", |
| 132 | "ipp", "", "server", "/ipp", 631, 0, |
| 133 | HTTP_URI_CODING_MOST }, |
| 134 | |
| 135 | /* Unknown scheme */ |
| 136 | { HTTP_URI_STATUS_UNKNOWN_SCHEME, "vendor://server/resource", |
| 137 | "vendor", "", "server", "/resource", 0, 0, |
| 138 | HTTP_URI_CODING_MOST }, |
| 139 | |
| 140 | /* Missing resource */ |
| 141 | { HTTP_URI_STATUS_MISSING_RESOURCE, "socket://[::192.168.2.1]", |
| 142 | "socket", "", "::192.168.2.1", "/", 9100, 0, |
| 143 | HTTP_URI_CODING_MOST }, |
| 144 | { HTTP_URI_STATUS_MISSING_RESOURCE, "socket://192.168.1.1:9101", |
| 145 | "socket", "", "192.168.1.1", "/", 9101, 0, |
| 146 | HTTP_URI_CODING_MOST }, |
| 147 | |
| 148 | /* Bad URI */ |
| 149 | { HTTP_URI_STATUS_BAD_URI, "", |
| 150 | "", "", "", "", 0, 0, |
| 151 | HTTP_URI_CODING_MOST }, |
| 152 | |
| 153 | /* Bad scheme */ |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 154 | { HTTP_URI_STATUS_BAD_SCHEME, "://server/ipp", |
| 155 | "", "", "", "", 0, 0, |
| 156 | HTTP_URI_CODING_MOST }, |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 157 | { HTTP_URI_STATUS_BAD_SCHEME, "bad_scheme://server/resource", |
| 158 | "", "", "", "", 0, 0, |
| 159 | HTTP_URI_CODING_MOST }, |
| 160 | |
| 161 | /* Bad username */ |
| 162 | { HTTP_URI_STATUS_BAD_USERNAME, "http://username:passwor%6@server/resource", |
| 163 | "http", "", "", "", 80, 0, |
| 164 | HTTP_URI_CODING_MOST }, |
| 165 | |
| 166 | /* Bad hostname */ |
| 167 | { HTTP_URI_STATUS_BAD_HOSTNAME, "http://[/::1]/index.html", |
| 168 | "http", "", "", "", 80, 0, |
| 169 | HTTP_URI_CODING_MOST }, |
| 170 | { HTTP_URI_STATUS_BAD_HOSTNAME, "http://[", |
| 171 | "http", "", "", "", 80, 0, |
| 172 | HTTP_URI_CODING_MOST }, |
| 173 | { HTTP_URI_STATUS_BAD_HOSTNAME, "http://serve%7/index.html", |
| 174 | "http", "", "", "", 80, 0, |
| 175 | HTTP_URI_CODING_MOST }, |
| 176 | { HTTP_URI_STATUS_BAD_HOSTNAME, "http://server with spaces/index.html", |
| 177 | "http", "", "", "", 80, 0, |
| 178 | HTTP_URI_CODING_MOST }, |
| 179 | { HTTP_URI_STATUS_BAD_HOSTNAME, "ipp://\"#/:<>?@[\\]^`{|}/", |
| 180 | "ipp", "", "", "", 631, 0, |
| 181 | HTTP_URI_CODING_MOST }, |
| 182 | |
| 183 | /* Bad port number */ |
| 184 | { HTTP_URI_STATUS_BAD_PORT, "http://127.0.0.1:9999a/index.html", |
| 185 | "http", "", "127.0.0.1", "", 0, 0, |
| 186 | HTTP_URI_CODING_MOST }, |
| 187 | |
| 188 | /* Bad resource */ |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 189 | { HTTP_URI_STATUS_BAD_RESOURCE, "mailto:\r\nbla", |
| 190 | "mailto", "", "", "", 0, 0, |
| 191 | HTTP_URI_CODING_MOST }, |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 192 | { HTTP_URI_STATUS_BAD_RESOURCE, "http://server/index.html%", |
| 193 | "http", "", "server", "", 80, 0, |
| 194 | HTTP_URI_CODING_MOST }, |
| 195 | { HTTP_URI_STATUS_BAD_RESOURCE, "http://server/index with spaces.html", |
| 196 | "http", "", "server", "", 80, 0, |
| 197 | HTTP_URI_CODING_MOST } |
| 198 | }; |
| 199 | static const char * const base64_tests[][2] = |
| 200 | { |
| 201 | { "A", "QQ==" }, |
| 202 | /* 010000 01 */ |
| 203 | { "AB", "QUI=" }, |
| 204 | /* 010000 010100 0010 */ |
| 205 | { "ABC", "QUJD" }, |
| 206 | /* 010000 010100 001001 000011 */ |
| 207 | { "ABCD", "QUJDRA==" }, |
| 208 | /* 010000 010100 001001 000011 010001 00 */ |
| 209 | { "ABCDE", "QUJDREU=" }, |
| 210 | /* 010000 010100 001001 000011 010001 000100 0101 */ |
| 211 | { "ABCDEF", "QUJDREVG" }, |
| 212 | /* 010000 010100 001001 000011 010001 000100 010101 000110 */ |
| 213 | }; |
| 214 | |
| 215 | |
| 216 | /* |
| 217 | * 'main()' - Main entry. |
| 218 | */ |
| 219 | |
| 220 | int /* O - Exit status */ |
| 221 | main(int argc, /* I - Number of command-line arguments */ |
| 222 | char *argv[]) /* I - Command-line arguments */ |
| 223 | { |
| 224 | int i, j, k; /* Looping vars */ |
| 225 | http_t *http; /* HTTP connection */ |
| 226 | http_encryption_t encryption; /* Encryption type */ |
| 227 | http_status_t status; /* Status of GET command */ |
| 228 | int failures; /* Number of test failures */ |
| 229 | char buffer[8192]; /* Input buffer */ |
| 230 | long bytes; /* Number of bytes read */ |
| 231 | FILE *out; /* Output file */ |
| 232 | char encode[256], /* Base64-encoded string */ |
| 233 | decode[256]; /* Base64-decoded string */ |
| 234 | int decodelen; /* Length of decoded string */ |
| 235 | char scheme[HTTP_MAX_URI], /* Scheme from URI */ |
| 236 | hostname[HTTP_MAX_URI], /* Hostname from URI */ |
| 237 | username[HTTP_MAX_URI], /* Username:password from URI */ |
| 238 | resource[HTTP_MAX_URI]; /* Resource from URI */ |
| 239 | int port; /* Port number from URI */ |
| 240 | http_uri_status_t uri_status; /* Status of URI separation */ |
| 241 | http_addrlist_t *addrlist, /* Address list */ |
| 242 | *addr; /* Current address */ |
| 243 | off_t length, total; /* Length and total bytes */ |
| 244 | time_t start, current; /* Start and end time */ |
| 245 | const char *encoding; /* Negotiated Content-Encoding */ |
| 246 | static const char * const uri_status_strings[] = |
| 247 | { |
| 248 | "HTTP_URI_STATUS_OVERFLOW", |
| 249 | "HTTP_URI_STATUS_BAD_ARGUMENTS", |
| 250 | "HTTP_URI_STATUS_BAD_RESOURCE", |
| 251 | "HTTP_URI_STATUS_BAD_PORT", |
| 252 | "HTTP_URI_STATUS_BAD_HOSTNAME", |
| 253 | "HTTP_URI_STATUS_BAD_USERNAME", |
| 254 | "HTTP_URI_STATUS_BAD_SCHEME", |
| 255 | "HTTP_URI_STATUS_BAD_URI", |
| 256 | "HTTP_URI_STATUS_OK", |
| 257 | "HTTP_URI_STATUS_MISSING_SCHEME", |
| 258 | "HTTP_URI_STATUS_UNKNOWN_SCHEME", |
| 259 | "HTTP_URI_STATUS_MISSING_RESOURCE" |
| 260 | }; |
| 261 | |
| 262 | |
| 263 | /* |
| 264 | * Do API tests if we don't have a URL on the command-line... |
| 265 | */ |
| 266 | |
| 267 | if (argc == 1) |
| 268 | { |
| 269 | failures = 0; |
| 270 | |
| 271 | /* |
| 272 | * httpGetDateString()/httpGetDateTime() |
| 273 | */ |
| 274 | |
| 275 | fputs("httpGetDateString()/httpGetDateTime(): ", stdout); |
| 276 | |
| 277 | start = time(NULL); |
| 278 | strlcpy(buffer, httpGetDateString(start), sizeof(buffer)); |
| 279 | current = httpGetDateTime(buffer); |
| 280 | |
| 281 | i = (int)(current - start); |
| 282 | if (i < 0) |
| 283 | i = -i; |
| 284 | |
| 285 | if (!i) |
| 286 | puts("PASS"); |
| 287 | else |
| 288 | { |
| 289 | failures ++; |
| 290 | puts("FAIL"); |
| 291 | printf(" Difference is %d seconds, %02d:%02d:%02d...\n", i, i / 3600, |
| 292 | (i / 60) % 60, i % 60); |
| 293 | printf(" httpGetDateString(%d) returned \"%s\"\n", (int)start, buffer); |
| 294 | printf(" httpGetDateTime(\"%s\") returned %d\n", buffer, (int)current); |
| 295 | printf(" httpGetDateString(%d) returned \"%s\"\n", (int)current, |
| 296 | httpGetDateString(current)); |
| 297 | } |
| 298 | |
| 299 | /* |
| 300 | * httpDecode64_2()/httpEncode64_2() |
| 301 | */ |
| 302 | |
| 303 | fputs("httpDecode64_2()/httpEncode64_2(): ", stdout); |
| 304 | |
| 305 | for (i = 0, j = 0; i < (int)(sizeof(base64_tests) / sizeof(base64_tests[0])); i ++) |
| 306 | { |
| 307 | httpEncode64_2(encode, sizeof(encode), base64_tests[i][0], |
| 308 | (int)strlen(base64_tests[i][0])); |
| 309 | decodelen = (int)sizeof(decode); |
| 310 | httpDecode64_2(decode, &decodelen, base64_tests[i][1]); |
| 311 | |
| 312 | if (strcmp(decode, base64_tests[i][0])) |
| 313 | { |
| 314 | failures ++; |
| 315 | |
| 316 | if (j) |
| 317 | { |
| 318 | puts("FAIL"); |
| 319 | j = 1; |
| 320 | } |
| 321 | |
| 322 | printf(" httpDecode64_2() returned \"%s\", expected \"%s\"...\n", |
| 323 | decode, base64_tests[i][0]); |
| 324 | } |
| 325 | |
| 326 | if (strcmp(encode, base64_tests[i][1])) |
| 327 | { |
| 328 | failures ++; |
| 329 | |
| 330 | if (j) |
| 331 | { |
| 332 | puts("FAIL"); |
| 333 | j = 1; |
| 334 | } |
| 335 | |
| 336 | printf(" httpEncode64_2() returned \"%s\", expected \"%s\"...\n", |
| 337 | encode, base64_tests[i][1]); |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | if (!j) |
| 342 | puts("PASS"); |
| 343 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 344 | #if 0 |
| 345 | /* |
| 346 | * _httpDigest() |
| 347 | */ |
| 348 | |
| 349 | fputs("_httpDigest(MD5): ", stdout); |
| 350 | if (!_httpDigest(buffer, sizeof(buffer), "MD5", "Mufasa", "http-auth@example.org", "Circle of Life", "7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", 1, "f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", "auth", "GET", "/dir/index.html")) |
| 351 | { |
| 352 | failures ++; |
| 353 | puts("FAIL (unable to calculate hash)"); |
| 354 | } |
| 355 | else if (strcmp(buffer, "8ca523f5e9506fed4657c9700eebdbec")) |
| 356 | { |
| 357 | failures ++; |
| 358 | printf("FAIL (got \"%s\", expected \"8ca523f5e9506fed4657c9700eebdbec\")\n", buffer); |
| 359 | } |
| 360 | else |
| 361 | puts("PASS"); |
| 362 | |
| 363 | fputs("_httpDigest(SHA-256): ", stdout); |
| 364 | if (!_httpDigest(buffer, sizeof(buffer), "SHA-256", "Mufasa", "http-auth@example.org", "Circle of Life", "7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", 1, "f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", "auth", "GET", "/dir/index.html")) |
| 365 | { |
| 366 | failures ++; |
| 367 | puts("FAIL (unable to calculate hash)"); |
| 368 | } |
| 369 | else if (strcmp(buffer, "753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1")) |
| 370 | { |
| 371 | failures ++; |
| 372 | printf("FAIL (got \"%s\", expected \"753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1\")\n", buffer); |
| 373 | } |
| 374 | else |
| 375 | puts("PASS"); |
| 376 | #endif /* 0 */ |
| 377 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 378 | /* |
| 379 | * httpGetHostname() |
| 380 | */ |
| 381 | |
| 382 | fputs("httpGetHostname(): ", stdout); |
| 383 | |
| 384 | if (httpGetHostname(NULL, hostname, sizeof(hostname))) |
| 385 | printf("PASS (%s)\n", hostname); |
| 386 | else |
| 387 | { |
| 388 | failures ++; |
| 389 | puts("FAIL"); |
| 390 | } |
| 391 | |
| 392 | /* |
| 393 | * httpAddrGetList() |
| 394 | */ |
| 395 | |
| 396 | printf("httpAddrGetList(%s): ", hostname); |
| 397 | |
| 398 | addrlist = httpAddrGetList(hostname, AF_UNSPEC, NULL); |
| 399 | if (addrlist) |
| 400 | { |
| 401 | for (i = 0, addr = addrlist; addr; i ++, addr = addr->next) |
| 402 | { |
| 403 | char numeric[1024]; /* Numeric IP address */ |
| 404 | |
| 405 | |
| 406 | httpAddrString(&(addr->addr), numeric, sizeof(numeric)); |
| 407 | if (!strcmp(numeric, "UNKNOWN")) |
| 408 | break; |
| 409 | } |
| 410 | |
| 411 | if (addr) |
| 412 | printf("FAIL (bad address for %s)\n", hostname); |
| 413 | else |
| 414 | printf("PASS (%d address(es) for %s)\n", i, hostname); |
| 415 | |
| 416 | httpAddrFreeList(addrlist); |
| 417 | } |
| 418 | else if (isdigit(hostname[0] & 255)) |
| 419 | { |
| 420 | puts("FAIL (ignored because hostname is numeric)"); |
| 421 | } |
| 422 | else |
| 423 | { |
| 424 | failures ++; |
| 425 | puts("FAIL"); |
| 426 | } |
| 427 | |
| 428 | /* |
| 429 | * Test httpSeparateURI()... |
| 430 | */ |
| 431 | |
| 432 | fputs("httpSeparateURI(): ", stdout); |
| 433 | for (i = 0, j = 0; i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); i ++) |
| 434 | { |
| 435 | uri_status = httpSeparateURI(HTTP_URI_CODING_MOST, |
| 436 | uri_tests[i].uri, scheme, sizeof(scheme), |
| 437 | username, sizeof(username), |
| 438 | hostname, sizeof(hostname), &port, |
| 439 | resource, sizeof(resource)); |
| 440 | if (uri_status != uri_tests[i].result || |
| 441 | strcmp(scheme, uri_tests[i].scheme) || |
| 442 | strcmp(username, uri_tests[i].username) || |
| 443 | strcmp(hostname, uri_tests[i].hostname) || |
| 444 | port != uri_tests[i].port || |
| 445 | strcmp(resource, uri_tests[i].resource)) |
| 446 | { |
| 447 | failures ++; |
| 448 | |
| 449 | if (!j) |
| 450 | { |
| 451 | puts("FAIL"); |
| 452 | j = 1; |
| 453 | } |
| 454 | |
| 455 | printf(" \"%s\":\n", uri_tests[i].uri); |
| 456 | |
| 457 | if (uri_status != uri_tests[i].result) |
| 458 | printf(" Returned %s instead of %s\n", |
| 459 | uri_status_strings[uri_status + 8], |
| 460 | uri_status_strings[uri_tests[i].result + 8]); |
| 461 | |
| 462 | if (strcmp(scheme, uri_tests[i].scheme)) |
| 463 | printf(" Scheme \"%s\" instead of \"%s\"\n", |
| 464 | scheme, uri_tests[i].scheme); |
| 465 | |
| 466 | if (strcmp(username, uri_tests[i].username)) |
| 467 | printf(" Username \"%s\" instead of \"%s\"\n", |
| 468 | username, uri_tests[i].username); |
| 469 | |
| 470 | if (strcmp(hostname, uri_tests[i].hostname)) |
| 471 | printf(" Hostname \"%s\" instead of \"%s\"\n", |
| 472 | hostname, uri_tests[i].hostname); |
| 473 | |
| 474 | if (port != uri_tests[i].port) |
| 475 | printf(" Port %d instead of %d\n", |
| 476 | port, uri_tests[i].port); |
| 477 | |
| 478 | if (strcmp(resource, uri_tests[i].resource)) |
| 479 | printf(" Resource \"%s\" instead of \"%s\"\n", |
| 480 | resource, uri_tests[i].resource); |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | if (!j) |
| 485 | printf("PASS (%d URIs tested)\n", |
| 486 | (int)(sizeof(uri_tests) / sizeof(uri_tests[0]))); |
| 487 | |
| 488 | /* |
| 489 | * Test httpAssembleURI()... |
| 490 | */ |
| 491 | |
| 492 | fputs("httpAssembleURI(): ", stdout); |
| 493 | for (i = 0, j = 0, k = 0; |
| 494 | i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); |
| 495 | i ++) |
| 496 | if (uri_tests[i].result == HTTP_URI_STATUS_OK && |
| 497 | !strstr(uri_tests[i].uri, "%64") && |
| 498 | strstr(uri_tests[i].uri, "//")) |
| 499 | { |
| 500 | k ++; |
| 501 | uri_status = httpAssembleURI(uri_tests[i].assemble_coding, |
| 502 | buffer, sizeof(buffer), |
| 503 | uri_tests[i].scheme, |
| 504 | uri_tests[i].username, |
| 505 | uri_tests[i].hostname, |
| 506 | uri_tests[i].assemble_port, |
| 507 | uri_tests[i].resource); |
| 508 | |
| 509 | if (uri_status != HTTP_URI_STATUS_OK) |
| 510 | { |
| 511 | failures ++; |
| 512 | |
| 513 | if (!j) |
| 514 | { |
| 515 | puts("FAIL"); |
| 516 | j = 1; |
| 517 | } |
| 518 | |
| 519 | printf(" \"%s\": %s\n", uri_tests[i].uri, |
| 520 | uri_status_strings[uri_status + 8]); |
| 521 | } |
| 522 | else if (strcmp(buffer, uri_tests[i].uri)) |
| 523 | { |
| 524 | failures ++; |
| 525 | |
| 526 | if (!j) |
| 527 | { |
| 528 | puts("FAIL"); |
| 529 | j = 1; |
| 530 | } |
| 531 | |
| 532 | printf(" \"%s\": assembled = \"%s\"\n", uri_tests[i].uri, |
| 533 | buffer); |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | if (!j) |
| 538 | printf("PASS (%d URIs tested)\n", k); |
| 539 | |
| 540 | /* |
| 541 | * httpAssembleUUID |
| 542 | */ |
| 543 | |
| 544 | fputs("httpAssembleUUID: ", stdout); |
| 545 | httpAssembleUUID("hostname.example.com", 631, "printer", 12345, buffer, |
| 546 | sizeof(buffer)); |
| 547 | if (strncmp(buffer, "urn:uuid:", 9)) |
| 548 | { |
| 549 | printf("FAIL (%s)\n", buffer); |
| 550 | failures ++; |
| 551 | } |
| 552 | else |
| 553 | printf("PASS (%s)\n", buffer); |
| 554 | |
| 555 | /* |
| 556 | * Show a summary and return... |
| 557 | */ |
| 558 | |
| 559 | if (failures) |
| 560 | printf("\n%d TESTS FAILED!\n", failures); |
| 561 | else |
| 562 | puts("\nALL TESTS PASSED!"); |
| 563 | |
| 564 | return (failures); |
| 565 | } |
| 566 | else if (strstr(argv[1], "._tcp")) |
| 567 | { |
| 568 | /* |
| 569 | * Test resolving an mDNS name. |
| 570 | */ |
| 571 | |
| 572 | char resolved[1024]; /* Resolved URI */ |
| 573 | |
| 574 | |
| 575 | printf("_httpResolveURI(%s, _HTTP_RESOLVE_DEFAULT): ", argv[1]); |
| 576 | fflush(stdout); |
| 577 | |
| 578 | if (!_httpResolveURI(argv[1], resolved, sizeof(resolved), |
| 579 | _HTTP_RESOLVE_DEFAULT, NULL, NULL)) |
| 580 | { |
| 581 | puts("FAIL"); |
| 582 | return (1); |
| 583 | } |
| 584 | else |
| 585 | printf("PASS (%s)\n", resolved); |
| 586 | |
| 587 | printf("_httpResolveURI(%s, _HTTP_RESOLVE_FQDN): ", argv[1]); |
| 588 | fflush(stdout); |
| 589 | |
| 590 | if (!_httpResolveURI(argv[1], resolved, sizeof(resolved), |
| 591 | _HTTP_RESOLVE_FQDN, NULL, NULL)) |
| 592 | { |
| 593 | puts("FAIL"); |
| 594 | return (1); |
| 595 | } |
| 596 | else if (strstr(resolved, ".local:")) |
| 597 | { |
| 598 | printf("FAIL (%s)\n", resolved); |
| 599 | return (1); |
| 600 | } |
| 601 | else |
| 602 | { |
| 603 | printf("PASS (%s)\n", resolved); |
| 604 | return (0); |
| 605 | } |
| 606 | } |
| 607 | else if (!strcmp(argv[1], "-u") && argc == 3) |
| 608 | { |
| 609 | /* |
| 610 | * Test URI separation... |
| 611 | */ |
| 612 | |
| 613 | uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, argv[2], scheme, |
| 614 | sizeof(scheme), username, sizeof(username), |
| 615 | hostname, sizeof(hostname), &port, |
| 616 | resource, sizeof(resource)); |
| 617 | printf("uri_status = %s\n", uri_status_strings[uri_status + 8]); |
| 618 | printf("scheme = \"%s\"\n", scheme); |
| 619 | printf("username = \"%s\"\n", username); |
| 620 | printf("hostname = \"%s\"\n", hostname); |
| 621 | printf("port = %d\n", port); |
| 622 | printf("resource = \"%s\"\n", resource); |
| 623 | |
| 624 | return (0); |
| 625 | } |
| 626 | |
| 627 | /* |
| 628 | * Test HTTP GET requests... |
| 629 | */ |
| 630 | |
| 631 | http = NULL; |
| 632 | out = stdout; |
| 633 | |
| 634 | for (i = 1; i < argc; i ++) |
| 635 | { |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 636 | int new_auth; |
| 637 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 638 | if (!strcmp(argv[i], "-o")) |
| 639 | { |
| 640 | i ++; |
| 641 | if (i >= argc) |
| 642 | break; |
| 643 | |
| 644 | out = fopen(argv[i], "wb"); |
| 645 | continue; |
| 646 | } |
| 647 | |
| 648 | httpSeparateURI(HTTP_URI_CODING_MOST, argv[i], scheme, sizeof(scheme), |
| 649 | username, sizeof(username), |
| 650 | hostname, sizeof(hostname), &port, |
| 651 | resource, sizeof(resource)); |
| 652 | |
| 653 | if (!_cups_strcasecmp(scheme, "https") || !_cups_strcasecmp(scheme, "ipps") || |
| 654 | port == 443) |
| 655 | encryption = HTTP_ENCRYPTION_ALWAYS; |
| 656 | else |
| 657 | encryption = HTTP_ENCRYPTION_IF_REQUESTED; |
| 658 | |
| 659 | http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL); |
| 660 | if (http == NULL) |
| 661 | { |
| 662 | perror(hostname); |
| 663 | continue; |
| 664 | } |
| 665 | |
| 666 | if (httpIsEncrypted(http)) |
| 667 | { |
| 668 | cups_array_t *creds; |
| 669 | char info[1024]; |
| 670 | static const char *trusts[] = { "OK", "Invalid", "Changed", "Expired", "Renewed", "Unknown" }; |
| 671 | if (!httpCopyCredentials(http, &creds)) |
| 672 | { |
| 673 | cups_array_t *lcreds; |
| 674 | http_trust_t trust = httpCredentialsGetTrust(creds, hostname); |
| 675 | |
| 676 | httpCredentialsString(creds, info, sizeof(info)); |
| 677 | |
| 678 | printf("Count: %d\n", cupsArrayCount(creds)); |
| 679 | printf("Trust: %s\n", trusts[trust]); |
| 680 | printf("Expiration: %s\n", httpGetDateString(httpCredentialsGetExpiration(creds))); |
| 681 | printf("IsValidName: %d\n", httpCredentialsAreValidForName(creds, hostname)); |
| 682 | printf("String: \"%s\"\n", info); |
| 683 | |
| 684 | printf("LoadCredentials: %d\n", httpLoadCredentials(NULL, &lcreds, hostname)); |
| 685 | httpCredentialsString(lcreds, info, sizeof(info)); |
| 686 | printf(" Count: %d\n", cupsArrayCount(lcreds)); |
| 687 | printf(" String: \"%s\"\n", info); |
| 688 | |
| 689 | if (lcreds && cupsArrayCount(creds) == cupsArrayCount(lcreds)) |
| 690 | { |
| 691 | http_credential_t *cred, *lcred; |
| 692 | |
| 693 | for (i = 1, cred = (http_credential_t *)cupsArrayFirst(creds), lcred = (http_credential_t *)cupsArrayFirst(lcreds); |
| 694 | cred && lcred; |
| 695 | i ++, cred = (http_credential_t *)cupsArrayNext(creds), lcred = (http_credential_t *)cupsArrayNext(lcreds)) |
| 696 | { |
| 697 | if (cred->datalen != lcred->datalen) |
| 698 | printf(" Credential #%d: Different lengths (saved=%d, current=%d)\n", i, (int)cred->datalen, (int)lcred->datalen); |
| 699 | else if (memcmp(cred->data, lcred->data, cred->datalen)) |
| 700 | printf(" Credential #%d: Different data\n", i); |
| 701 | else |
| 702 | printf(" Credential #%d: Matches\n", i); |
| 703 | } |
| 704 | } |
| 705 | |
| 706 | if (trust != HTTP_TRUST_OK) |
| 707 | { |
| 708 | printf("SaveCredentials: %d\n", httpSaveCredentials(NULL, creds, hostname)); |
| 709 | trust = httpCredentialsGetTrust(creds, hostname); |
| 710 | printf("New Trust: %s\n", trusts[trust]); |
| 711 | } |
| 712 | |
| 713 | httpFreeCredentials(creds); |
| 714 | } |
| 715 | else |
| 716 | puts("No credentials!"); |
| 717 | } |
| 718 | |
| 719 | printf("Checking file \"%s\"...\n", resource); |
| 720 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 721 | new_auth = 0; |
| 722 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 723 | do |
| 724 | { |
| 725 | if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) |
| 726 | { |
| 727 | httpClearFields(http); |
| 728 | if (httpReconnect2(http, 30000, NULL)) |
| 729 | { |
| 730 | status = HTTP_STATUS_ERROR; |
| 731 | break; |
| 732 | } |
| 733 | } |
| 734 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 735 | if (http->authstring && !strncmp(http->authstring, "Digest ", 7) && !new_auth) |
| 736 | _httpSetDigestAuthString(http, http->nextnonce, "HEAD", resource); |
| 737 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 738 | httpClearFields(http); |
| 739 | httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); |
| 740 | httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 741 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 742 | if (httpHead(http, resource)) |
| 743 | { |
| 744 | if (httpReconnect2(http, 30000, NULL)) |
| 745 | { |
| 746 | status = HTTP_STATUS_ERROR; |
| 747 | break; |
| 748 | } |
| 749 | else |
| 750 | { |
| 751 | status = HTTP_STATUS_UNAUTHORIZED; |
| 752 | continue; |
| 753 | } |
| 754 | } |
| 755 | |
| 756 | while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); |
| 757 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 758 | new_auth = 0; |
| 759 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 760 | if (status == HTTP_STATUS_UNAUTHORIZED) |
| 761 | { |
| 762 | /* |
| 763 | * Flush any error message... |
| 764 | */ |
| 765 | |
| 766 | httpFlush(http); |
| 767 | |
| 768 | /* |
| 769 | * See if we can do authentication... |
| 770 | */ |
| 771 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 772 | new_auth = 1; |
| 773 | |
| 774 | if (cupsDoAuthentication(http, "HEAD", resource)) |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 775 | { |
| 776 | status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; |
| 777 | break; |
| 778 | } |
| 779 | |
| 780 | if (httpReconnect2(http, 30000, NULL)) |
| 781 | { |
| 782 | status = HTTP_STATUS_ERROR; |
| 783 | break; |
| 784 | } |
| 785 | |
| 786 | continue; |
| 787 | } |
| 788 | #ifdef HAVE_SSL |
| 789 | else if (status == HTTP_STATUS_UPGRADE_REQUIRED) |
| 790 | { |
| 791 | /* Flush any error message... */ |
| 792 | httpFlush(http); |
| 793 | |
| 794 | /* Reconnect... */ |
| 795 | if (httpReconnect2(http, 30000, NULL)) |
| 796 | { |
| 797 | status = HTTP_STATUS_ERROR; |
| 798 | break; |
| 799 | } |
| 800 | |
| 801 | /* Upgrade with encryption... */ |
| 802 | httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); |
| 803 | |
| 804 | /* Try again, this time with encryption enabled... */ |
| 805 | continue; |
| 806 | } |
| 807 | #endif /* HAVE_SSL */ |
| 808 | } |
| 809 | while (status == HTTP_STATUS_UNAUTHORIZED || |
| 810 | status == HTTP_STATUS_UPGRADE_REQUIRED); |
| 811 | |
| 812 | if (status == HTTP_STATUS_OK) |
| 813 | puts("HEAD OK:"); |
| 814 | else |
| 815 | printf("HEAD failed with status %d...\n", status); |
| 816 | |
| 817 | encoding = httpGetContentEncoding(http); |
| 818 | |
| 819 | printf("Requesting file \"%s\" (Accept-Encoding: %s)...\n", resource, |
| 820 | encoding ? encoding : "identity"); |
| 821 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 822 | new_auth = 0; |
| 823 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 824 | do |
| 825 | { |
| 826 | if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) |
| 827 | { |
| 828 | httpClearFields(http); |
| 829 | if (httpReconnect2(http, 30000, NULL)) |
| 830 | { |
| 831 | status = HTTP_STATUS_ERROR; |
| 832 | break; |
| 833 | } |
| 834 | } |
| 835 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 836 | if (http->authstring && !strncmp(http->authstring, "Digest ", 7) && !new_auth) |
| 837 | _httpSetDigestAuthString(http, http->nextnonce, "GET", resource); |
| 838 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 839 | httpClearFields(http); |
| 840 | httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); |
| 841 | httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); |
| 842 | httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, encoding); |
| 843 | |
| 844 | if (httpGet(http, resource)) |
| 845 | { |
| 846 | if (httpReconnect2(http, 30000, NULL)) |
| 847 | { |
| 848 | status = HTTP_STATUS_ERROR; |
| 849 | break; |
| 850 | } |
| 851 | else |
| 852 | { |
| 853 | status = HTTP_STATUS_UNAUTHORIZED; |
| 854 | continue; |
| 855 | } |
| 856 | } |
| 857 | |
| 858 | while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); |
| 859 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 860 | new_auth = 0; |
| 861 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 862 | if (status == HTTP_STATUS_UNAUTHORIZED) |
| 863 | { |
| 864 | /* |
| 865 | * Flush any error message... |
| 866 | */ |
| 867 | |
| 868 | httpFlush(http); |
| 869 | |
| 870 | /* |
| 871 | * See if we can do authentication... |
| 872 | */ |
| 873 | |
Bryan Ferris | 5fb2ccd | 2019-06-21 10:49:26 -0700 | [diff] [blame] | 874 | new_auth = 1; |
| 875 | |
Philip P. Moltmann | 25aee82 | 2016-12-15 12:16:46 -0800 | [diff] [blame] | 876 | if (cupsDoAuthentication(http, "GET", resource)) |
| 877 | { |
| 878 | status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; |
| 879 | break; |
| 880 | } |
| 881 | |
| 882 | if (httpReconnect2(http, 30000, NULL)) |
| 883 | { |
| 884 | status = HTTP_STATUS_ERROR; |
| 885 | break; |
| 886 | } |
| 887 | |
| 888 | continue; |
| 889 | } |
| 890 | #ifdef HAVE_SSL |
| 891 | else if (status == HTTP_STATUS_UPGRADE_REQUIRED) |
| 892 | { |
| 893 | /* Flush any error message... */ |
| 894 | httpFlush(http); |
| 895 | |
| 896 | /* Reconnect... */ |
| 897 | if (httpReconnect2(http, 30000, NULL)) |
| 898 | { |
| 899 | status = HTTP_STATUS_ERROR; |
| 900 | break; |
| 901 | } |
| 902 | |
| 903 | /* Upgrade with encryption... */ |
| 904 | httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); |
| 905 | |
| 906 | /* Try again, this time with encryption enabled... */ |
| 907 | continue; |
| 908 | } |
| 909 | #endif /* HAVE_SSL */ |
| 910 | } |
| 911 | while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED); |
| 912 | |
| 913 | if (status == HTTP_STATUS_OK) |
| 914 | puts("GET OK:"); |
| 915 | else |
| 916 | printf("GET failed with status %d...\n", status); |
| 917 | |
| 918 | start = time(NULL); |
| 919 | length = httpGetLength2(http); |
| 920 | total = 0; |
| 921 | |
| 922 | while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) |
| 923 | { |
| 924 | total += bytes; |
| 925 | fwrite(buffer, (size_t)bytes, 1, out); |
| 926 | if (out != stdout) |
| 927 | { |
| 928 | current = time(NULL); |
| 929 | if (current == start) |
| 930 | current ++; |
| 931 | |
| 932 | printf("\r" CUPS_LLFMT "/" CUPS_LLFMT " bytes (" |
| 933 | CUPS_LLFMT " bytes/sec) ", CUPS_LLCAST total, |
| 934 | CUPS_LLCAST length, CUPS_LLCAST (total / (current - start))); |
| 935 | fflush(stdout); |
| 936 | } |
| 937 | } |
| 938 | } |
| 939 | |
| 940 | if (out != stdout) |
| 941 | putchar('\n'); |
| 942 | |
| 943 | puts("Closing connection to server..."); |
| 944 | httpClose(http); |
| 945 | |
| 946 | if (out != stdout) |
| 947 | fclose(out); |
| 948 | |
| 949 | return (0); |
| 950 | } |