Revert manifest to default one
[external/cups.git] / cups / testhttp.c
1 /*
2  * "$Id: testhttp.c 9993 2011-09-09 21:55:11Z mike $"
3  *
4  *   HTTP test program for CUPS.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1997-2006 by Easy Software Products.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Apple Inc. and are protected by Federal copyright
11  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  *   which should have been included with this file.  If this file is
13  *   file is missing or damaged, see the license at "http://www.cups.org/".
14  *
15  *   This file is subject to the Apple OS-Developed Software exception.
16  *
17  * Contents:
18  *
19  *   main() - Main entry.
20  */
21
22 /*
23  * Include necessary headers...
24  */
25
26 #include "string-private.h"
27 #include "http-private.h"
28
29
30 /*
31  * Types and structures...
32  */
33
34 typedef struct uri_test_s               /**** URI test cases ****/
35 {
36   http_uri_status_t     result;         /* Expected return value */
37   const char            *uri,           /* URI */
38                         *scheme,        /* Scheme string */
39                         *username,      /* Username:password string */
40                         *hostname,      /* Hostname string */
41                         *resource;      /* Resource string */
42   int                   port,           /* Port number */
43                         assemble_port;  /* Port number for httpAssembleURI() */
44 } uri_test_t;
45
46
47 /*
48  * Local globals...
49  */
50
51 static uri_test_t       uri_tests[] =   /* URI test data */
52                         {
53                           /* Start with valid URIs */
54                           { HTTP_URI_OK, "file:/filename",
55                             "file", "", "", "/filename", 0, 0 },
56                           { HTTP_URI_OK, "file:/filename%20with%20spaces",
57                             "file", "", "", "/filename with spaces", 0, 0 },
58                           { HTTP_URI_OK, "file:///filename",
59                             "file", "", "", "/filename", 0, 0 },
60                           { HTTP_URI_OK, "file:///filename%20with%20spaces",
61                             "file", "", "", "/filename with spaces", 0, 0 },
62                           { HTTP_URI_OK, "file://localhost/filename",
63                             "file", "", "localhost", "/filename", 0, 0 },
64                           { HTTP_URI_OK, "file://localhost/filename%20with%20spaces",
65                             "file", "", "localhost", "/filename with spaces", 0, 0 },
66                           { HTTP_URI_OK, "http://server/",
67                             "http", "", "server", "/", 80, 0 },
68                           { HTTP_URI_OK, "http://username@server/",
69                             "http", "username", "server", "/", 80, 0 },
70                           { HTTP_URI_OK, "http://username:passwor%64@server/",
71                             "http", "username:password", "server", "/", 80, 0 },
72                           { HTTP_URI_OK, "http://username:passwor%64@server:8080/",
73                             "http", "username:password", "server", "/", 8080, 8080 },
74                           { HTTP_URI_OK, "http://username:passwor%64@server:8080/directory/filename",
75                             "http", "username:password", "server", "/directory/filename", 8080, 8080 },
76                           { HTTP_URI_OK, "http://[2000::10:100]:631/ipp",
77                             "http", "", "2000::10:100", "/ipp", 631, 631 },
78                           { HTTP_URI_OK, "https://username:passwor%64@server/directory/filename",
79                             "https", "username:password", "server", "/directory/filename", 443, 0 },
80                           { HTTP_URI_OK, "ipp://username:passwor%64@[::1]/ipp",
81                             "ipp", "username:password", "::1", "/ipp", 631, 0 },
82                           { HTTP_URI_OK, "lpd://server/queue?reserve=yes",
83                             "lpd", "", "server", "/queue?reserve=yes", 515, 0 },
84                           { HTTP_URI_OK, "mailto:user@domain.com",
85                             "mailto", "", "", "user@domain.com", 0, 0 },
86                           { HTTP_URI_OK, "socket://server/",
87                             "socket", "", "server", "/", 9100, 0 },
88                           { HTTP_URI_OK, "socket://192.168.1.1:9101/",
89                             "socket", "", "192.168.1.1", "/", 9101, 9101 },
90                           { HTTP_URI_OK, "ipp://username:password@[v1.fe80::200:1234:5678:9abc+eth0]:999/ipp",
91                             "ipp", "username:password", "fe80::200:1234:5678:9abc%eth0", "/ipp", 999, 999 },
92                           { HTTP_URI_OK, "http://server/admin?DEVICE_URI=usb://HP/Photosmart%25202600%2520series?serial=MY53OK70V10400",
93                             "http", "", "server", "/admin?DEVICE_URI=usb://HP/Photosmart%25202600%2520series?serial=MY53OK70V10400", 80, 0 },
94                           { HTTP_URI_OK, "lpd://Acme%20Laser%20(01%3A23%3A45).local._tcp._printer/",
95                             "lpd", "", "Acme Laser (01:23:45).local._tcp._printer", "/", 515, 0 },
96                           { HTTP_URI_OK, "ipp://HP%20Officejet%204500%20G510n-z%20%40%20Will's%20MacBook%20Pro%2015%22._ipp._tcp.local./",
97                             "ipp", "", "HP Officejet 4500 G510n-z @ Will's MacBook Pro 15\"._ipp._tcp.local.", "/", 631, 0 },
98
99                           /* Missing scheme */
100                           { HTTP_URI_MISSING_SCHEME, "/path/to/file/index.html",
101                             "file", "", "", "/path/to/file/index.html", 0, 0 },
102                           { HTTP_URI_MISSING_SCHEME, "//server/ipp",
103                             "ipp", "", "server", "/ipp", 631, 0 },
104
105                           /* Unknown scheme */
106                           { HTTP_URI_UNKNOWN_SCHEME, "vendor://server/resource",
107                             "vendor", "", "server", "/resource", 0, 0 },
108
109                           /* Missing resource */
110                           { HTTP_URI_MISSING_RESOURCE, "socket://[::192.168.2.1]",
111                             "socket", "", "::192.168.2.1", "/", 9100, 0 },
112                           { HTTP_URI_MISSING_RESOURCE, "socket://192.168.1.1:9101",
113                             "socket", "", "192.168.1.1", "/", 9101 },
114
115                           /* Bad URI */
116                           { HTTP_URI_BAD_URI, "",
117                             "", "", "", "", 0, 0 },
118
119                           /* Bad scheme */
120                           { HTTP_URI_BAD_SCHEME, "bad_scheme://server/resource",
121                             "", "", "", "", 0, 0 },
122
123                           /* Bad username */
124                           { HTTP_URI_BAD_USERNAME, "http://username:passwor%6@server/resource",
125                             "http", "", "", "", 80, 0 },
126
127                           /* Bad hostname */
128                           { HTTP_URI_BAD_HOSTNAME, "http://[/::1]/index.html",
129                             "http", "", "", "", 80, 0 },
130                           { HTTP_URI_BAD_HOSTNAME, "http://[",
131                             "http", "", "", "", 80, 0 },
132                           { HTTP_URI_BAD_HOSTNAME, "http://serve%7/index.html",
133                             "http", "", "", "", 80, 0 },
134
135                           /* Bad port number */
136                           { HTTP_URI_BAD_PORT, "http://127.0.0.1:9999a/index.html",
137                             "http", "", "127.0.0.1", "", 0, 0 },
138
139                           /* Bad resource */
140                           { HTTP_URI_BAD_RESOURCE, "http://server/index.html%",
141                             "http", "", "server", "", 80, 0 }
142                         };
143 static const char * const base64_tests[][2] =
144                         {
145                           { "A", "QQ==" },
146                           /* 010000 01 */
147                           { "AB", "QUI=" },
148                           /* 010000 010100 0010 */
149                           { "ABC", "QUJD" },
150                           /* 010000 010100 001001 000011 */
151                           { "ABCD", "QUJDRA==" },
152                           /* 010000 010100 001001 000011 010001 00 */
153                           { "ABCDE", "QUJDREU=" },
154                           /* 010000 010100 001001 000011 010001 000100 0101 */
155                           { "ABCDEF", "QUJDREVG" },
156                           /* 010000 010100 001001 000011 010001 000100 010101 000110 */
157                         };
158
159
160 /*
161  * 'main()' - Main entry.
162  */
163
164 int                                     /* O - Exit status */
165 main(int  argc,                         /* I - Number of command-line arguments */
166      char *argv[])                      /* I - Command-line arguments */
167 {
168   int           i, j, k;                /* Looping vars */
169   http_t        *http;                  /* HTTP connection */
170   http_encryption_t encryption;         /* Encryption type */
171   http_status_t status;                 /* Status of GET command */
172   int           failures;               /* Number of test failures */
173   char          buffer[8192];           /* Input buffer */
174   long          bytes;                  /* Number of bytes read */
175   FILE          *out;                   /* Output file */
176   char          encode[256],            /* Base64-encoded string */
177                 decode[256];            /* Base64-decoded string */
178   int           decodelen;              /* Length of decoded string */
179   char          scheme[HTTP_MAX_URI],   /* Scheme from URI */
180                 hostname[HTTP_MAX_URI], /* Hostname from URI */
181                 username[HTTP_MAX_URI], /* Username:password from URI */
182                 resource[HTTP_MAX_URI]; /* Resource from URI */
183   int           port;                   /* Port number from URI */
184   http_uri_status_t uri_status;         /* Status of URI separation */
185   http_addrlist_t *addrlist,            /* Address list */
186                 *addr;                  /* Current address */
187   off_t         length, total;          /* Length and total bytes */
188   time_t        start, current;         /* Start and end time */
189   static const char * const uri_status_strings[] =
190                 {
191                   "HTTP_URI_OVERFLOW",
192                   "HTTP_URI_BAD_ARGUMENTS",
193                   "HTTP_URI_BAD_RESOURCE",
194                   "HTTP_URI_BAD_PORT",
195                   "HTTP_URI_BAD_HOSTNAME",
196                   "HTTP_URI_BAD_USERNAME",
197                   "HTTP_URI_BAD_SCHEME",
198                   "HTTP_URI_BAD_URI",
199                   "HTTP_URI_OK",
200                   "HTTP_URI_MISSING_SCHEME",
201                   "HTTP_URI_UNKNOWN_SCHEME",
202                   "HTTP_URI_MISSING_RESOURCE"
203                 };
204
205
206  /*
207   * Do API tests if we don't have a URL on the command-line...
208   */
209
210   if (argc == 1)
211   {
212     failures = 0;
213
214    /*
215     * httpGetDateString()/httpGetDateTime()
216     */
217
218     fputs("httpGetDateString()/httpGetDateTime(): ", stdout);
219
220     start = time(NULL);
221     strcpy(buffer, httpGetDateString(start));
222     current = httpGetDateTime(buffer);
223
224     i = (int)(current - start);
225     if (i < 0)
226       i = -i;
227
228     if (!i)
229       puts("PASS");
230     else
231     {
232       failures ++;
233       puts("FAIL");
234       printf("    Difference is %d seconds, %02d:%02d:%02d...\n", i, i / 3600,
235              (i / 60) % 60, i % 60);
236       printf("    httpGetDateString(%d) returned \"%s\"\n", (int)start, buffer);
237       printf("    httpGetDateTime(\"%s\") returned %d\n", buffer, (int)current);
238       printf("    httpGetDateString(%d) returned \"%s\"\n", (int)current,
239              httpGetDateString(current));
240     }
241
242    /*
243     * httpDecode64_2()/httpEncode64_2()
244     */
245
246     fputs("httpDecode64_2()/httpEncode64_2(): ", stdout);
247
248     for (i = 0, j = 0; i < (int)(sizeof(base64_tests) / sizeof(base64_tests[0])); i ++)
249     {
250       httpEncode64_2(encode, sizeof(encode), base64_tests[i][0],
251                      (int)strlen(base64_tests[i][0]));
252       decodelen = (int)sizeof(decode);
253       httpDecode64_2(decode, &decodelen, base64_tests[i][1]);
254
255       if (strcmp(decode, base64_tests[i][0]))
256       {
257         failures ++;
258
259         if (j)
260         {
261           puts("FAIL");
262           j = 1;
263         }
264
265         printf("    httpDecode64_2() returned \"%s\", expected \"%s\"...\n",
266                decode, base64_tests[i][0]);
267       }
268
269       if (strcmp(encode, base64_tests[i][1]))
270       {
271         failures ++;
272
273         if (j)
274         {
275           puts("FAIL");
276           j = 1;
277         }
278
279         printf("    httpEncode64_2() returned \"%s\", expected \"%s\"...\n",
280                encode, base64_tests[i][1]);
281       }
282     }
283
284     if (!j)
285       puts("PASS");
286
287    /*
288     * httpGetHostname()
289     */
290
291     fputs("httpGetHostname(): ", stdout);
292
293     if (httpGetHostname(NULL, hostname, sizeof(hostname)))
294       printf("PASS (%s)\n", hostname);
295     else
296     {
297       failures ++;
298       puts("FAIL");
299     }
300
301    /*
302     * httpAddrGetList()
303     */
304
305     printf("httpAddrGetList(%s): ", hostname);
306
307     addrlist = httpAddrGetList(hostname, AF_UNSPEC, NULL);
308     if (addrlist)
309     {
310       for (i = 0, addr = addrlist; addr; i ++, addr = addr->next)
311       {
312         char    numeric[1024];          /* Numeric IP address */
313
314
315         httpAddrString(&(addr->addr), numeric, sizeof(numeric));
316         if (!strcmp(numeric, "UNKNOWN"))
317           break;
318       }
319
320       if (addr)
321         printf("FAIL (bad address for %s)\n", hostname);
322       else
323         printf("PASS (%d address(es) for %s)\n", i, hostname);
324
325       httpAddrFreeList(addrlist);
326     }
327     else if (isdigit(hostname[0] & 255))
328     {
329       puts("FAIL (ignored because hostname is numeric)");
330     }
331     else
332     {
333       failures ++;
334       puts("FAIL");
335     }
336
337    /*
338     * Test httpSeparateURI()...
339     */
340
341     fputs("httpSeparateURI(): ", stdout);
342     for (i = 0, j = 0; i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); i ++)
343     {
344       uri_status = httpSeparateURI(HTTP_URI_CODING_MOST,
345                                    uri_tests[i].uri, scheme, sizeof(scheme),
346                                    username, sizeof(username),
347                                    hostname, sizeof(hostname), &port,
348                                    resource, sizeof(resource));
349       if (uri_status != uri_tests[i].result ||
350           strcmp(scheme, uri_tests[i].scheme) ||
351           strcmp(username, uri_tests[i].username) ||
352           strcmp(hostname, uri_tests[i].hostname) ||
353           port != uri_tests[i].port ||
354           strcmp(resource, uri_tests[i].resource))
355       {
356         failures ++;
357
358         if (!j)
359         {
360           puts("FAIL");
361           j = 1;
362         }
363
364         printf("    \"%s\":\n", uri_tests[i].uri);
365
366         if (uri_status != uri_tests[i].result)
367           printf("        Returned %s instead of %s\n",
368                  uri_status_strings[uri_status + 8],
369                  uri_status_strings[uri_tests[i].result + 8]);
370
371         if (strcmp(scheme, uri_tests[i].scheme))
372           printf("        Scheme \"%s\" instead of \"%s\"\n",
373                  scheme, uri_tests[i].scheme);
374
375         if (strcmp(username, uri_tests[i].username))
376           printf("        Username \"%s\" instead of \"%s\"\n",
377                  username, uri_tests[i].username);
378
379         if (strcmp(hostname, uri_tests[i].hostname))
380           printf("        Hostname \"%s\" instead of \"%s\"\n",
381                  hostname, uri_tests[i].hostname);
382
383         if (port != uri_tests[i].port)
384           printf("        Port %d instead of %d\n",
385                  port, uri_tests[i].port);
386
387         if (strcmp(resource, uri_tests[i].resource))
388           printf("        Resource \"%s\" instead of \"%s\"\n",
389                  resource, uri_tests[i].resource);
390       }
391     }
392
393     if (!j)
394       printf("PASS (%d URIs tested)\n",
395              (int)(sizeof(uri_tests) / sizeof(uri_tests[0])));
396
397    /*
398     * Test httpAssembleURI()...
399     */
400
401     fputs("httpAssembleURI(): ", stdout);
402     for (i = 0, j = 0, k = 0;
403          i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0]));
404          i ++)
405       if (uri_tests[i].result == HTTP_URI_OK &&
406           !strstr(uri_tests[i].uri, "%64") &&
407           strstr(uri_tests[i].uri, "//"))
408       {
409         k ++;
410         uri_status = httpAssembleURI(HTTP_URI_CODING_MOST,
411                                      buffer, sizeof(buffer),
412                                      uri_tests[i].scheme,
413                                      uri_tests[i].username,
414                                      uri_tests[i].hostname,
415                                      uri_tests[i].assemble_port,
416                                      uri_tests[i].resource);
417
418         if (uri_status != HTTP_URI_OK)
419         {
420           failures ++;
421
422           if (!j)
423           {
424             puts("FAIL");
425             j = 1;
426           }
427
428           printf("    \"%s\": %s\n", uri_tests[i].uri,
429                  uri_status_strings[uri_status + 8]);
430         }
431         else if (strcmp(buffer, uri_tests[i].uri))
432         {
433           failures ++;
434
435           if (!j)
436           {
437             puts("FAIL");
438             j = 1;
439           }
440
441           printf("    \"%s\": assembled = \"%s\"\n", uri_tests[i].uri,
442                  buffer);
443         }
444       }
445
446     if (!j)
447       printf("PASS (%d URIs tested)\n", k);
448
449    /*
450     * Show a summary and return...
451     */
452
453     if (failures)
454       printf("\n%d TESTS FAILED!\n", failures);
455     else
456       puts("\nALL TESTS PASSED!");
457
458     return (failures);
459   }
460   else if (strstr(argv[1], "._tcp"))
461   {
462    /*
463     * Test resolving an mDNS name.
464     */
465
466     char        resolved[1024];         /* Resolved URI */
467
468
469     printf("_httpResolveURI(%s, _HTTP_RESOLVE_DEFAULT): ", argv[1]);
470     fflush(stdout);
471
472     if (!_httpResolveURI(argv[1], resolved, sizeof(resolved),
473                          _HTTP_RESOLVE_DEFAULT, NULL, NULL))
474     {
475       puts("FAIL");
476       return (1);
477     }
478     else
479       printf("PASS (%s)\n", resolved);
480
481     printf("_httpResolveURI(%s, _HTTP_RESOLVE_FQDN): ", argv[1]);
482     fflush(stdout);
483
484     if (!_httpResolveURI(argv[1], resolved, sizeof(resolved),
485                          _HTTP_RESOLVE_FQDN, NULL, NULL))
486     {
487       puts("FAIL");
488       return (1);
489     }
490     else if (strstr(resolved, ".local:"))
491     {
492       printf("FAIL (%s)\n", resolved);
493       return (1);
494     }
495     else
496     {
497       printf("PASS (%s)\n", resolved);
498       return (0);
499     }
500   }
501   else if (!strcmp(argv[1], "-u") && argc == 3)
502   {
503    /*
504     * Test URI separation...
505     */
506
507     uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, argv[2], scheme,
508                                  sizeof(scheme), username, sizeof(username),
509                                  hostname, sizeof(hostname), &port,
510                                  resource, sizeof(resource));
511     printf("uri_status = %s\n", uri_status_strings[uri_status + 8]);
512     printf("scheme     = \"%s\"\n", scheme);
513     printf("username   = \"%s\"\n", username);
514     printf("hostname   = \"%s\"\n", hostname);
515     printf("port       = %d\n", port);
516     printf("resource   = \"%s\"\n", resource);
517
518     return (0);
519   }
520
521  /*
522   * Test HTTP GET requests...
523   */
524
525   http = NULL;
526   out = stdout;
527
528   for (i = 1; i < argc; i ++)
529   {
530     if (!strcmp(argv[i], "-o"))
531     {
532       i ++;
533       if (i >= argc)
534         break;
535
536       out = fopen(argv[i], "wb");
537       continue;
538     }
539
540     httpSeparateURI(HTTP_URI_CODING_MOST, argv[i], scheme, sizeof(scheme),
541                     username, sizeof(username),
542                     hostname, sizeof(hostname), &port,
543                     resource, sizeof(resource));
544
545     if (!_cups_strcasecmp(scheme, "https") || !_cups_strcasecmp(scheme, "ipps") ||
546         port == 443)
547       encryption = HTTP_ENCRYPT_ALWAYS;
548     else
549       encryption = HTTP_ENCRYPT_IF_REQUESTED;
550
551     http = httpConnectEncrypt(hostname, port, encryption);
552     if (http == NULL)
553     {
554       perror(hostname);
555       continue;
556     }
557     printf("Requesting file \"%s\"...\n", resource);
558     httpClearFields(http);
559     httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en");
560     httpGet(http, resource);
561     while ((status = httpUpdate(http)) == HTTP_CONTINUE);
562
563     if (status == HTTP_OK)
564       puts("GET OK:");
565     else
566       printf("GET failed with status %d...\n", status);
567
568     start  = time(NULL);
569     length = httpGetLength2(http);
570     total  = 0;
571
572     while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
573     {
574       total += bytes;
575       fwrite(buffer, bytes, 1, out);
576       if (out != stdout)
577       {
578         current = time(NULL);
579         if (current == start) current ++;
580         printf("\r" CUPS_LLFMT "/" CUPS_LLFMT " bytes ("
581                CUPS_LLFMT " bytes/sec)      ", CUPS_LLCAST total,
582                CUPS_LLCAST length, CUPS_LLCAST (total / (current - start)));
583         fflush(stdout);
584       }
585     }
586   }
587
588   puts("Closing connection to server...");
589   httpClose(http);
590
591   if (out != stdout)
592     fclose(out);
593
594   return (0);
595 }
596
597
598 /*
599  * End of "$Id: testhttp.c 9993 2011-09-09 21:55:11Z mike $".
600  */