2 * "$Id: http-support.c 7952 2008-09-17 00:56:20Z mike $"
4 * HTTP support routines for the Common UNIX Printing System (CUPS) scheduler.
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * httpAssembleURI() - Assemble a uniform resource identifier from its
21 * httpAssembleURIf() - Assemble a uniform resource identifier from its
22 * components with a formatted resource.
23 * httpDecode64() - Base64-decode a string.
24 * httpDecode64_2() - Base64-decode a string.
25 * httpEncode64() - Base64-encode a string.
26 * httpEncode64_2() - Base64-encode a string.
27 * httpGetDateString() - Get a formatted date/time string from a time value.
28 * httpGetDateString2() - Get a formatted date/time string from a time value.
29 * httpGetDateTime() - Get a time value from a formatted date/time string.
30 * httpSeparate() - Separate a Universal Resource Identifier into its
32 * httpSeparate2() - Separate a Universal Resource Identifier into its
34 * httpSeparateURI() - Separate a Universal Resource Identifier into its
36 * httpStatus() - Return a short string describing a HTTP status code.
37 * _cups_hstrerror() - hstrerror() emulation function for Solaris and
39 * _httpEncodeURI() - Percent-encode a HTTP request URI.
40 * _httpResolveURI() - Resolve a DNS-SD URI.
41 * http_copy_decode() - Copy and decode a URI.
42 * http_copy_encode() - Copy and encode a URI.
43 * resolve_callback() - Build a device URI for the given service name.
47 * Include necessary headers...
56 #endif /* HAVE_DNSSD */
63 typedef struct _http_uribuf_s
/* URI buffer */
65 char *buffer
; /* Pointer to buffer */
66 size_t bufsize
; /* Size of buffer */
74 static const char * const http_days
[7] =
84 static const char * const http_months
[12] =
105 static const char *http_copy_decode(char *dst
, const char *src
,
106 int dstsize
, const char *term
,
108 static char *http_copy_encode(char *dst
, const char *src
,
109 char *dstend
, const char *reserved
,
110 const char *term
, int encode
);
112 static void resolve_callback(DNSServiceRef sdRef
,
113 DNSServiceFlags flags
,
114 uint32_t interfaceIndex
,
115 DNSServiceErrorType errorCode
,
116 const char *fullName
,
117 const char *hostTarget
,
118 uint16_t port
, uint16_t txtLen
,
119 const unsigned char *txtRecord
,
121 #endif /* HAVE_DNSSD */
125 * 'httpAssembleURI()' - Assemble a uniform resource identifier from its
128 * This function escapes reserved characters in the URI depending on the
129 * value of the "encoding" argument. You should use this function in
130 * place of traditional string functions whenever you need to create a
133 * @since CUPS 1.2/Mac OS X 10.5@
136 http_uri_status_t
/* O - URI status */
138 http_uri_coding_t encoding
, /* I - Encoding flags */
139 char *uri
, /* I - URI buffer */
140 int urilen
, /* I - Size of URI buffer */
141 const char *scheme
, /* I - Scheme name */
142 const char *username
, /* I - Username */
143 const char *host
, /* I - Hostname or address */
144 int port
, /* I - Port number */
145 const char *resource
) /* I - Resource */
147 char *ptr
, /* Pointer into URI buffer */
148 *end
; /* End of URI buffer */
152 * Range check input...
155 if (!uri
|| urilen
< 1 || !scheme
|| port
< 0)
160 return (HTTP_URI_BAD_ARGUMENTS
);
164 * Assemble the URI starting with the scheme...
167 end
= uri
+ urilen
- 1;
168 ptr
= http_copy_encode(uri
, scheme
, end
, NULL
, NULL
, 0);
171 goto assemble_overflow
;
173 if (!strcmp(scheme
, "mailto"))
176 * mailto: only has :, no //...
182 goto assemble_overflow
;
187 * Schemes other than mailto: all have //...
197 goto assemble_overflow
;
201 * Next the username and hostname, if any...
206 if (username
&& *username
)
209 * Add username@ first...
212 ptr
= http_copy_encode(ptr
, username
, end
, "/?@", NULL
,
213 encoding
& HTTP_URI_CODING_USERNAME
);
216 goto assemble_overflow
;
221 goto assemble_overflow
;
225 * Then add the hostname. Since IPv6 is a particular pain to deal
226 * with, we have several special cases to deal with. If we get
227 * an IPv6 address with brackets around it, assume it is already in
228 * URI format. Since DNS-SD service names can sometimes look like
229 * raw IPv6 addresses, we specifically look for "._tcp" in the name,
233 if (host
[0] != '[' && strchr(host
, ':') && !strstr(host
, "._tcp"))
236 * We have a raw IPv6 address...
239 if (strchr(host
, '%'))
242 * We have a link-local address, add "[v1." prefix...
253 goto assemble_overflow
;
258 * We have a normal address, add "[" prefix...
264 goto assemble_overflow
;
268 * Copy the rest of the IPv6 address, and terminate with "]".
271 while (ptr
< end
&& *host
)
275 *ptr
++ = '+'; /* Convert zone separator */
283 goto assemble_overflow
;
288 goto assemble_overflow
;
293 * Otherwise, just copy the host string...
296 ptr
= http_copy_encode(ptr
, host
, end
, ":/?#[]@\\", NULL
,
297 encoding
& HTTP_URI_CODING_HOSTNAME
);
300 goto assemble_overflow
;
304 * Finish things off with the port number...
309 snprintf(ptr
, end
- ptr
+ 1, ":%d", port
);
313 goto assemble_overflow
;
318 * Last but not least, add the resource string...
323 char *query
; /* Pointer to query string */
327 * Copy the resource string up to the query string if present...
330 query
= strchr(resource
, '?');
331 ptr
= http_copy_encode(ptr
, resource
, end
, NULL
, "?",
332 encoding
& HTTP_URI_CODING_RESOURCE
);
334 goto assemble_overflow
;
339 * Copy query string without encoding...
342 ptr
= http_copy_encode(ptr
, query
, end
, NULL
, NULL
,
343 encoding
& HTTP_URI_CODING_QUERY
);
345 goto assemble_overflow
;
351 goto assemble_overflow
;
354 * Nul-terminate the URI buffer and return with no errors...
359 return (HTTP_URI_OK
);
362 * Clear the URI string and return an overflow error; I don't usually
363 * like goto's, but in this case it makes sense...
369 return (HTTP_URI_OVERFLOW
);
374 * 'httpAssembleURIf()' - Assemble a uniform resource identifier from its
375 * components with a formatted resource.
377 * This function creates a formatted version of the resource string
378 * argument "resourcef" and escapes reserved characters in the URI
379 * depending on the value of the "encoding" argument. You should use
380 * this function in place of traditional string functions whenever
381 * you need to create a URI string.
383 * @since CUPS 1.2/Mac OS X 10.5@
386 http_uri_status_t
/* O - URI status */
388 http_uri_coding_t encoding
, /* I - Encoding flags */
389 char *uri
, /* I - URI buffer */
390 int urilen
, /* I - Size of URI buffer */
391 const char *scheme
, /* I - Scheme name */
392 const char *username
, /* I - Username */
393 const char *host
, /* I - Hostname or address */
394 int port
, /* I - Port number */
395 const char *resourcef
, /* I - Printf-style resource */
396 ...) /* I - Additional arguments as needed */
398 va_list ap
; /* Pointer to additional arguments */
399 char resource
[1024]; /* Formatted resource string */
400 int bytes
; /* Bytes in formatted string */
404 * Range check input...
407 if (!uri
|| urilen
< 1 || !scheme
|| port
< 0 || !resourcef
)
412 return (HTTP_URI_BAD_ARGUMENTS
);
416 * Format the resource string and assemble the URI...
419 va_start(ap
, resourcef
);
420 bytes
= vsnprintf(resource
, sizeof(resource
), resourcef
, ap
);
423 if (bytes
>= sizeof(resource
))
426 return (HTTP_URI_OVERFLOW
);
429 return (httpAssembleURI(encoding
, uri
, urilen
, scheme
, username
, host
,
435 * 'httpDecode64()' - Base64-decode a string.
437 * This function is deprecated. Use the httpDecode64_2() function instead
438 * which provides buffer length arguments.
443 char * /* O - Decoded string */
444 httpDecode64(char *out
, /* I - String to write to */
445 const char *in
) /* I - String to read from */
447 int outlen
; /* Output buffer length */
451 * Use the old maximum buffer size for binary compatibility...
456 return (httpDecode64_2(out
, &outlen
, in
));
461 * 'httpDecode64_2()' - Base64-decode a string.
463 * @since CUPS 1.1.21/Mac OS X 10.4@
466 char * /* O - Decoded string */
467 httpDecode64_2(char *out
, /* I - String to write to */
468 int *outlen
, /* IO - Size of output string */
469 const char *in
) /* I - String to read from */
471 int pos
, /* Bit position */
472 base64
; /* Value of this character */
473 char *outptr
, /* Output pointer */
474 *outend
; /* End of output buffer */
478 * Range check input...
481 if (!out
|| !outlen
|| *outlen
< 1 || !in
)
493 * Convert from base-64 to bytes...
496 for (outptr
= out
, outend
= out
+ *outlen
- 1, pos
= 0; *in
!= '\0'; in
++)
499 * Decode this character into a number from 0 to 63...
502 if (*in
>= 'A' && *in
<= 'Z')
504 else if (*in
>= 'a' && *in
<= 'z')
505 base64
= *in
- 'a' + 26;
506 else if (*in
>= '0' && *in
<= '9')
507 base64
= *in
- '0' + 52;
518 * Store the result in the appropriate chars...
525 *outptr
= base64
<< 2;
530 *outptr
++ |= (base64
>> 4) & 3;
532 *outptr
= (base64
<< 4) & 255;
537 *outptr
++ |= (base64
>> 2) & 15;
539 *outptr
= (base64
<< 6) & 255;
553 * Return the decoded string and size...
556 *outlen
= (int)(outptr
- out
);
563 * 'httpEncode64()' - Base64-encode a string.
565 * This function is deprecated. Use the httpEncode64_2() function instead
566 * which provides buffer length arguments.
571 char * /* O - Encoded string */
572 httpEncode64(char *out
, /* I - String to write to */
573 const char *in
) /* I - String to read from */
575 return (httpEncode64_2(out
, 512, in
, (int)strlen(in
)));
580 * 'httpEncode64_2()' - Base64-encode a string.
582 * @since CUPS 1.1.21/Mac OS X 10.4@
585 char * /* O - Encoded string */
586 httpEncode64_2(char *out
, /* I - String to write to */
587 int outlen
, /* I - Size of output string */
588 const char *in
, /* I - String to read from */
589 int inlen
) /* I - Size of input string */
591 char *outptr
, /* Output pointer */
592 *outend
; /* End of output buffer */
593 static const char base64
[] = /* Base64 characters... */
595 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
596 "abcdefghijklmnopqrstuvwxyz"
603 * Range check input...
606 if (!out
|| outlen
< 1 || !in
)
610 * Convert bytes to base-64...
613 for (outptr
= out
, outend
= out
+ outlen
- 1; inlen
> 0; in
++, inlen
--)
616 * Encode the up to 3 characters as 4 Base64 numbers...
620 *outptr
++ = base64
[(in
[0] & 255) >> 2];
625 *outptr
++ = base64
[(((in
[0] & 255) << 4) | ((in
[1] & 255) >> 4)) & 63];
627 *outptr
++ = base64
[((in
[0] & 255) << 4) & 63];
644 *outptr
++ = base64
[(((in
[0] & 255) << 2) | ((in
[1] & 255) >> 6)) & 63];
646 *outptr
++ = base64
[((in
[0] & 255) << 2) & 63];
659 *outptr
++ = base64
[in
[0] & 63];
665 * Return the encoded string...
673 * 'httpGetDateString()' - Get a formatted date/time string from a time value.
678 const char * /* O - Date/time string */
679 httpGetDateString(time_t t
) /* I - UNIX time */
681 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
684 return (httpGetDateString2(t
, cg
->http_date
, sizeof(cg
->http_date
)));
689 * 'httpGetDateString2()' - Get a formatted date/time string from a time value.
691 * @since CUPS 1.2/Mac OS X 10.5@
694 const char * /* O - Date/time string */
695 httpGetDateString2(time_t t
, /* I - UNIX time */
696 char *s
, /* I - String buffer */
697 int slen
) /* I - Size of string buffer */
699 struct tm
*tdate
; /* UNIX date/time data */
703 snprintf(s
, slen
, "%s, %02d %s %d %02d:%02d:%02d GMT",
704 http_days
[tdate
->tm_wday
], tdate
->tm_mday
,
705 http_months
[tdate
->tm_mon
], tdate
->tm_year
+ 1900,
706 tdate
->tm_hour
, tdate
->tm_min
, tdate
->tm_sec
);
713 * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
716 time_t /* O - UNIX time */
717 httpGetDateTime(const char *s
) /* I - Date/time string */
719 int i
; /* Looping var */
720 char mon
[16]; /* Abbreviated month name */
721 int day
, year
; /* Day of month and year */
722 int hour
, min
, sec
; /* Time */
723 int days
; /* Number of days since 1970 */
724 static const int normal_days
[] = /* Days to a month, normal years */
725 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
726 static const int leap_days
[] = /* Days to a month, leap years */
727 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
730 DEBUG_printf(("2httpGetDateTime(s=\"%s\")", s
));
733 * Extract the date and time from the formatted string...
736 if (sscanf(s
, "%*s%d%15s%d%d:%d:%d", &day
, mon
, &year
, &hour
, &min
, &sec
) < 6)
739 DEBUG_printf(("4httpGetDateTime: day=%d, mon=\"%s\", year=%d, hour=%d, "
740 "min=%d, sec=%d", day
, mon
, year
, hour
, min
, sec
));
743 * Convert the month name to a number from 0 to 11.
746 for (i
= 0; i
< 12; i
++)
747 if (!strcasecmp(mon
, http_months
[i
]))
753 DEBUG_printf(("4httpGetDateTime: i=%d", i
));
756 * Now convert the date and time to a UNIX time value in seconds since
757 * 1970. We can't use mktime() since the timezone may not be UTC but
758 * the date/time string *is* UTC.
761 if ((year
& 3) == 0 && ((year
% 100) != 0 || (year
% 400) == 0))
762 days
= leap_days
[i
] + day
- 1;
764 days
= normal_days
[i
] + day
- 1;
766 DEBUG_printf(("4httpGetDateTime: days=%d", days
));
768 days
+= (year
- 1970) * 365 + /* 365 days per year (normally) */
769 ((year
- 1) / 4 - 492) - /* + leap days */
770 ((year
- 1) / 100 - 19) + /* - 100 year days */
771 ((year
- 1) / 400 - 4); /* + 400 year days */
773 DEBUG_printf(("4httpGetDateTime: days=%d\n", days
));
775 return (days
* 86400 + hour
* 3600 + min
* 60 + sec
);
780 * 'httpSeparate()' - Separate a Universal Resource Identifier into its
783 * This function is deprecated; use the httpSeparateURI() function instead.
789 httpSeparate(const char *uri
, /* I - Universal Resource Identifier */
790 char *scheme
, /* O - Scheme [32] (http, https, etc.) */
791 char *username
, /* O - Username [1024] */
792 char *host
, /* O - Hostname [1024] */
793 int *port
, /* O - Port number to use */
794 char *resource
) /* O - Resource/filename [1024] */
796 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, 32, username
,
797 HTTP_MAX_URI
, host
, HTTP_MAX_URI
, port
, resource
,
803 * 'httpSeparate2()' - Separate a Universal Resource Identifier into its
806 * This function is deprecated; use the httpSeparateURI() function instead.
808 * @since CUPS 1.1.21/Mac OS X 10.4@
813 httpSeparate2(const char *uri
, /* I - Universal Resource Identifier */
814 char *scheme
, /* O - Scheme (http, https, etc.) */
815 int schemelen
, /* I - Size of scheme buffer */
816 char *username
, /* O - Username */
817 int usernamelen
, /* I - Size of username buffer */
818 char *host
, /* O - Hostname */
819 int hostlen
, /* I - Size of hostname buffer */
820 int *port
, /* O - Port number to use */
821 char *resource
, /* O - Resource/filename */
822 int resourcelen
) /* I - Size of resource buffer */
824 httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, schemelen
, username
,
825 usernamelen
, host
, hostlen
, port
, resource
, resourcelen
);
830 * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its
833 * @since CUPS 1.2/Mac OS X 10.5@
836 http_uri_status_t
/* O - Result of separation */
838 http_uri_coding_t decoding
, /* I - Decoding flags */
839 const char *uri
, /* I - Universal Resource Identifier */
840 char *scheme
, /* O - Scheme (http, https, etc.) */
841 int schemelen
, /* I - Size of scheme buffer */
842 char *username
, /* O - Username */
843 int usernamelen
, /* I - Size of username buffer */
844 char *host
, /* O - Hostname */
845 int hostlen
, /* I - Size of hostname buffer */
846 int *port
, /* O - Port number to use */
847 char *resource
, /* O - Resource/filename */
848 int resourcelen
) /* I - Size of resource buffer */
850 char *ptr
, /* Pointer into string... */
851 *end
; /* End of string */
852 const char *sep
; /* Separator character */
853 http_uri_status_t status
; /* Result of separation */
857 * Initialize everything to blank...
860 if (scheme
&& schemelen
> 0)
863 if (username
&& usernamelen
> 0)
866 if (host
&& hostlen
> 0)
872 if (resource
&& resourcelen
> 0)
876 * Range check input...
879 if (!uri
|| !port
|| !scheme
|| schemelen
<= 0 || !username
||
880 usernamelen
<= 0 || !host
|| hostlen
<= 0 || !resource
||
882 return (HTTP_URI_BAD_ARGUMENTS
);
885 return (HTTP_URI_BAD_URI
);
888 * Grab the scheme portion of the URI...
891 status
= HTTP_URI_OK
;
893 if (!strncmp(uri
, "//", 2))
896 * Workaround for HP IPP client bug...
899 strlcpy(scheme
, "ipp", schemelen
);
900 status
= HTTP_URI_MISSING_SCHEME
;
902 else if (*uri
== '/')
908 strlcpy(scheme
, "file", schemelen
);
909 status
= HTTP_URI_MISSING_SCHEME
;
914 * Standard URI with scheme...
917 for (ptr
= scheme
, end
= scheme
+ schemelen
- 1;
918 *uri
&& *uri
!= ':' && ptr
< end
;)
919 if (isalnum(*uri
& 255) || *uri
== '-' || *uri
== '+' || *uri
== '.')
929 return (HTTP_URI_BAD_SCHEME
);
936 * Set the default port number...
939 if (!strcmp(scheme
, "http"))
941 else if (!strcmp(scheme
, "https"))
943 else if (!strcmp(scheme
, "ipp"))
945 else if (!strcasecmp(scheme
, "lpd"))
947 else if (!strcmp(scheme
, "socket")) /* Not yet registered with IANA... */
949 else if (strcmp(scheme
, "file") && strcmp(scheme
, "mailto"))
950 status
= HTTP_URI_UNKNOWN_SCHEME
;
953 * Now see if we have a hostname...
956 if (!strncmp(uri
, "//", 2))
965 * Grab the username, if any...
968 if ((sep
= strpbrk(uri
, "@/")) != NULL
&& *sep
== '@')
971 * Get a username:password combo...
974 uri
= http_copy_decode(username
, uri
, usernamelen
, "@",
975 decoding
& HTTP_URI_CODING_USERNAME
);
980 return (HTTP_URI_BAD_USERNAME
);
987 * Then the hostname/IP address...
993 * Grab IPv6 address...
997 if (!strncmp(uri
, "v1.", 3))
998 uri
+= 3; /* Skip IPvN leader... */
1000 uri
= http_copy_decode(host
, uri
, hostlen
, "]",
1001 decoding
& HTTP_URI_CODING_HOSTNAME
);
1006 return (HTTP_URI_BAD_HOSTNAME
);
1016 return (HTTP_URI_BAD_HOSTNAME
);
1021 for (ptr
= host
; *ptr
; ptr
++)
1025 * Convert zone separator to % and stop here...
1031 else if (*ptr
!= ':' && *ptr
!= '.' && !isxdigit(*ptr
& 255))
1034 return (HTTP_URI_BAD_HOSTNAME
);
1040 * Validate the hostname or IPv4 address first...
1043 for (ptr
= (char *)uri
; *ptr
; ptr
++)
1044 if (strchr(":?/", *ptr
))
1046 else if (!strchr("abcdefghijklmnopqrstuvwxyz"
1047 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1051 "!$&'()*+,;=\\", *ptr
))
1054 return (HTTP_URI_BAD_HOSTNAME
);
1058 * Then copy the hostname or IPv4 address to the buffer...
1061 uri
= http_copy_decode(host
, uri
, hostlen
, ":?/",
1062 decoding
& HTTP_URI_CODING_HOSTNAME
);
1067 return (HTTP_URI_BAD_HOSTNAME
);
1072 * Validate hostname for file scheme - only empty and localhost are
1076 if (!strcmp(scheme
, "file") && strcmp(host
, "localhost") && host
[0])
1079 return (HTTP_URI_BAD_HOSTNAME
);
1083 * See if we have a port number...
1089 * Yes, collect the port number...
1092 if (!isdigit(uri
[1] & 255))
1095 return (HTTP_URI_BAD_PORT
);
1098 *port
= strtol(uri
+ 1, (char **)&uri
, 10);
1100 if (*uri
!= '/' && *uri
)
1103 return (HTTP_URI_BAD_PORT
);
1109 * The remaining portion is the resource string...
1112 if (*uri
== '?' || !*uri
)
1115 * Hostname but no path...
1118 status
= HTTP_URI_MISSING_RESOURCE
;
1122 * Copy any query string...
1126 uri
= http_copy_decode(resource
+ 1, uri
, resourcelen
- 1, NULL
,
1127 decoding
& HTTP_URI_CODING_QUERY
);
1133 uri
= http_copy_decode(resource
, uri
, resourcelen
, "?",
1134 decoding
& HTTP_URI_CODING_RESOURCE
);
1136 if (uri
&& *uri
== '?')
1139 * Concatenate any query string...
1142 char *resptr
= resource
+ strlen(resource
);
1144 uri
= http_copy_decode(resptr
, uri
, resourcelen
- (int)(resptr
- resource
),
1145 NULL
, decoding
& HTTP_URI_CODING_QUERY
);
1152 return (HTTP_URI_BAD_RESOURCE
);
1156 * Return the URI separation status...
1164 * 'httpStatus()' - Return a short string describing a HTTP status code.
1166 * The returned string is localized to the current POSIX locale and is based
1167 * on the status strings defined in RFC 2616.
1170 const char * /* O - Localized status string */
1171 httpStatus(http_status_t status
) /* I - HTTP status code */
1173 const char *s
; /* Status string */
1174 _cups_globals_t
*cg
= _cupsGlobals(); /* Global data */
1177 if (!cg
->lang_default
)
1178 cg
->lang_default
= cupsLangDefault();
1182 case HTTP_CONTINUE
:
1185 case HTTP_SWITCHING_PROTOCOLS
:
1186 s
= _("Switching Protocols");
1194 case HTTP_ACCEPTED
:
1197 case HTTP_NO_CONTENT
:
1198 s
= _("No Content");
1200 case HTTP_MOVED_PERMANENTLY
:
1201 s
= _("Moved Permanently");
1203 case HTTP_SEE_OTHER
:
1206 case HTTP_NOT_MODIFIED
:
1207 s
= _("Not Modified");
1209 case HTTP_BAD_REQUEST
:
1210 s
= _("Bad Request");
1212 case HTTP_UNAUTHORIZED
:
1213 case HTTP_AUTHORIZATION_CANCELED
:
1214 s
= _("Unauthorized");
1216 case HTTP_FORBIDDEN
:
1219 case HTTP_NOT_FOUND
:
1222 case HTTP_REQUEST_TOO_LARGE
:
1223 s
= _("Request Entity Too Large");
1225 case HTTP_URI_TOO_LONG
:
1226 s
= _("URI Too Long");
1228 case HTTP_UPGRADE_REQUIRED
:
1229 s
= _("Upgrade Required");
1231 case HTTP_NOT_IMPLEMENTED
:
1232 s
= _("Not Implemented");
1234 case HTTP_NOT_SUPPORTED
:
1235 s
= _("Not Supported");
1237 case HTTP_EXPECTATION_FAILED
:
1238 s
= _("Expectation Failed");
1240 case HTTP_SERVICE_UNAVAILABLE
:
1241 s
= _("Service Unavailable");
1243 case HTTP_SERVER_ERROR
:
1244 s
= _("Internal Server Error");
1252 return (_cupsLangString(cg
->lang_default
, s
));
1256 #ifndef HAVE_HSTRERROR
1258 * '_cups_hstrerror()' - hstrerror() emulation function for Solaris and others...
1261 const char * /* O - Error string */
1262 _cups_hstrerror(int error
) /* I - Error number */
1264 static const char * const errors
[] = /* Error strings */
1269 "Unrecoverable lookup error.",
1270 "No data associated with name."
1274 if (error
< 0 || error
> 4)
1275 return ("Unknown hostname lookup error.");
1277 return (errors
[error
]);
1279 #endif /* !HAVE_HSTRERROR */
1283 * '_httpEncodeURI()' - Percent-encode a HTTP request URI.
1286 char * /* O - Encoded URI */
1287 _httpEncodeURI(char *dst
, /* I - Destination buffer */
1288 const char *src
, /* I - Source URI */
1289 size_t dstsize
) /* I - Size of destination buffer */
1291 http_copy_encode(dst
, src
, dst
+ dstsize
- 1, NULL
, NULL
, 1);
1297 * '_httpResolveURI()' - Resolve a DNS-SD URI.
1300 const char * /* O - Resolved URI */
1302 const char *uri
, /* I - DNS-SD URI */
1303 char *resolved_uri
, /* I - Buffer for resolved URI */
1304 size_t resolved_size
, /* I - Size of URI buffer */
1305 int logit
) /* I - Log progress to stderr? */
1307 char scheme
[32], /* URI components... */
1313 http_uri_status_t status
; /* URI decode status */
1317 DEBUG_printf(("4_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
1318 "resolved_size=" CUPS_LLFMT
")", uri
, resolved_uri
,
1319 CUPS_LLCAST resolved_size
));
1322 * Get the device URI...
1326 if ((status
= httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
,
1327 sizeof(scheme
), userpass
, sizeof(userpass
),
1328 hostname
, sizeof(hostname
), &port
, resource
,
1329 sizeof(resource
))) < HTTP_URI_OK
)
1331 if (httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
,
1332 sizeof(scheme
), userpass
, sizeof(userpass
),
1333 hostname
, sizeof(hostname
), &port
, resource
,
1334 sizeof(resource
)) < HTTP_URI_OK
)
1338 _cupsLangPrintf(stderr
, _("Bad device URI \"%s\"!\n"), uri
);
1340 DEBUG_printf(("6_httpResolveURI: httpSeparateURI returned %d!", status
));
1341 DEBUG_puts("5_httpResolveURI: Returning NULL");
1346 * Resolve it as needed...
1349 if (strstr(hostname
, "._tcp"))
1352 DNSServiceRef ref
, /* DNS-SD master service reference */
1353 domainref
, /* DNS-SD service reference for domain */
1354 localref
; /* DNS-SD service reference for .local */
1355 int domainsent
= 0; /* Send the domain resolve? */
1356 char *regtype
, /* Pointer to type in hostname */
1357 *domain
; /* Pointer to domain in hostname */
1358 _http_uribuf_t uribuf
; /* URI buffer */
1359 struct pollfd polldata
; /* Polling data */
1363 fprintf(stderr
, "DEBUG: Resolving \"%s\"...\n", hostname
);
1366 * Separate the hostname into service name, registration type, and domain...
1369 for (regtype
= strstr(hostname
, "._tcp") - 2;
1372 if (regtype
[0] == '.' && regtype
[1] == '_')
1375 * Found ._servicetype in front of ._tcp...
1382 if (regtype
<= hostname
)
1384 DEBUG_puts("5_httpResolveURI: Bad hostname, returning NULL");
1388 for (domain
= strchr(regtype
, '.');
1390 domain
= strchr(domain
+ 1, '.'))
1391 if (domain
[1] != '_')
1397 uribuf
.buffer
= resolved_uri
;
1398 uribuf
.bufsize
= resolved_size
;
1400 resolved_uri
[0] = '\0';
1402 DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
1403 "domain=\"%s\"\n", hostname
, regtype
, domain
));
1406 fputs("STATE: +connecting-to-device\n", stderr
);
1407 fprintf(stderr
, "DEBUG: Resolving \"%s\", regtype=\"%s\", "
1408 "domain=\"local.\"...\n", hostname
, regtype
);
1409 _cupsLangPuts(stderr
, _("INFO: Looking for printer...\n"));
1414 if (DNSServiceCreateConnection(&ref
) == kDNSServiceErr_NoError
)
1417 if (DNSServiceResolve(&localref
, kDNSServiceFlagsShareConnection
, 0,
1418 hostname
, regtype
, "local.", resolve_callback
,
1419 &uribuf
) == kDNSServiceErr_NoError
)
1421 if (strcasecmp(domain
, "local."))
1424 * Wait 2 seconds for a response to the local resolve; if nothing comes
1425 * in, do an additional domain resolution...
1428 polldata
.fd
= DNSServiceRefSockFD(ref
);
1429 polldata
.events
= POLLIN
;
1431 if (poll(&polldata
, 1, 2000) != 1)
1434 * OK, send the domain name resolve...
1438 fprintf(stderr
, "DEBUG: Resolving \"%s\", regtype=\"%s\", "
1439 "domain=\"%s\"...\n", hostname
, regtype
, domain
);
1442 if (DNSServiceResolve(&domainref
, kDNSServiceFlagsShareConnection
, 0,
1443 hostname
, regtype
, domain
, resolve_callback
,
1444 &uribuf
) == kDNSServiceErr_NoError
)
1449 if (DNSServiceProcessResult(ref
) == kDNSServiceErr_NoError
)
1453 DNSServiceRefDeallocate(domainref
);
1455 DNSServiceRefDeallocate(localref
);
1458 DNSServiceRefDeallocate(ref
);
1464 fprintf(stderr
, "DEBUG: Resolved as \"%s\"...\n", uri
);
1466 fputs("DEBUG: Unable to resolve URI!\n", stderr
);
1468 fputs("STATE: -connecting-to-device\n", stderr
);
1473 * No DNS-SD support...
1477 #endif /* HAVE_DNSSD */
1480 _cupsLangPuts(stderr
, _("Unable to find printer!\n"));
1483 DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri
));
1490 * 'http_copy_decode()' - Copy and decode a URI.
1493 static const char * /* O - New source pointer or NULL on error */
1494 http_copy_decode(char *dst
, /* O - Destination buffer */
1495 const char *src
, /* I - Source pointer */
1496 int dstsize
, /* I - Destination size */
1497 const char *term
, /* I - Terminating characters */
1498 int decode
) /* I - Decode %-encoded values */
1500 char *ptr
, /* Pointer into buffer */
1501 *end
; /* End of buffer */
1502 int quoted
; /* Quoted character */
1506 * Copy the src to the destination until we hit a terminating character
1507 * or the end of the string.
1510 for (ptr
= dst
, end
= dst
+ dstsize
- 1;
1511 *src
&& (!term
|| !strchr(term
, *src
));
1515 if (*src
== '%' && decode
)
1517 if (isxdigit(src
[1] & 255) && isxdigit(src
[2] & 255))
1520 * Grab a hex-encoded character...
1525 quoted
= (tolower(*src
) - 'a' + 10) << 4;
1527 quoted
= (*src
- '0') << 4;
1531 quoted
|= tolower(*src
) - 'a' + 10;
1533 quoted
|= *src
- '0';
1540 * Bad hex-encoded character...
1558 * 'http_copy_encode()' - Copy and encode a URI.
1561 static char * /* O - End of current URI */
1562 http_copy_encode(char *dst
, /* O - Destination buffer */
1563 const char *src
, /* I - Source pointer */
1564 char *dstend
, /* I - End of destination buffer */
1565 const char *reserved
, /* I - Extra reserved characters */
1566 const char *term
, /* I - Terminating characters */
1567 int encode
) /* I - %-encode reserved chars? */
1569 static const char hex
[] = "0123456789ABCDEF";
1572 while (*src
&& dst
< dstend
)
1574 if (term
&& *src
== *term
)
1577 if (encode
&& (*src
== '%' || *src
<= ' ' || *src
& 128 ||
1578 (reserved
&& strchr(reserved
, *src
))))
1581 * Hex encode reserved characters...
1584 if ((dst
+ 2) >= dstend
)
1588 *dst
++ = hex
[(*src
>> 4) & 15];
1589 *dst
++ = hex
[*src
& 15];
1608 * 'resolve_callback()' - Build a device URI for the given service name.
1613 DNSServiceRef sdRef
, /* I - Service reference */
1614 DNSServiceFlags flags
, /* I - Results flags */
1615 uint32_t interfaceIndex
, /* I - Interface number */
1616 DNSServiceErrorType errorCode
, /* I - Error, if any */
1617 const char *fullName
, /* I - Full service name */
1618 const char *hostTarget
, /* I - Hostname */
1619 uint16_t port
, /* I - Port number */
1620 uint16_t txtLen
, /* I - Length of TXT record */
1621 const unsigned char *txtRecord
, /* I - TXT record data */
1622 void *context
) /* I - Pointer to URI buffer */
1624 const char *scheme
; /* URI scheme */
1625 char rp
[257]; /* Remote printer */
1626 const void *value
; /* Value from TXT record */
1627 uint8_t valueLen
; /* Length of value */
1628 _http_uribuf_t
*uribuf
; /* URI buffer */
1631 DEBUG_printf(("7resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
1632 "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
1633 "txtLen=%u, txtRecord=%p, context=%p)", sdRef
, flags
,
1634 interfaceIndex
, errorCode
, fullName
, hostTarget
, port
, txtLen
,
1635 txtRecord
, context
));
1638 * Figure out the scheme from the full name...
1641 if (strstr(fullName
, "._ipp") || strstr(fullName
, "._fax-ipp"))
1643 else if (strstr(fullName
, "._printer."))
1645 else if (strstr(fullName
, "._pdl-datastream."))
1648 scheme
= "riousbprint";
1651 * Extract the "remote printer" key from the TXT record...
1654 if ((value
= TXTRecordGetValuePtr(txtLen
, txtRecord
, "rp",
1655 &valueLen
)) != NULL
)
1658 * Convert to resource by concatenating with a leading "/"...
1662 memcpy(rp
+ 1, value
, valueLen
);
1663 rp
[valueLen
+ 1] = '\0';
1669 * Assemble the final device URI...
1672 uribuf
= (_http_uribuf_t
*)context
;
1674 httpAssembleURI(HTTP_URI_CODING_ALL
, uribuf
->buffer
, uribuf
->bufsize
, scheme
,
1675 NULL
, hostTarget
, ntohs(port
), rp
);
1677 DEBUG_printf(("8resolve_callback: Resolved URI is \"%s\"...",
1680 #endif /* HAVE_DNSSD */
1684 * End of "$Id: http-support.c 7952 2008-09-17 00:56:20Z mike $".