in cups/http-support.c [112:416]
static void DNSSD_API http_resolve_cb(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullName,
const char *hostTarget,
uint16_t port, uint16_t txtLen,
const unsigned char *txtRecord,
void *context);
#endif /* HAVE_DNSSD */
#ifdef HAVE_AVAHI
static void http_client_cb(AvahiClient *client,
AvahiClientState state, void *simple_poll);
static int http_poll_cb(struct pollfd *pollfds, unsigned int num_pollfds,
int timeout, void *context);
static void http_resolve_cb(AvahiServiceResolver *resolver,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiResolverEvent event,
const char *name, const char *type,
const char *domain, const char *host_name,
const AvahiAddress *address, uint16_t port,
AvahiStringList *txt,
AvahiLookupResultFlags flags, void *context);
#endif /* HAVE_AVAHI */
/*
* 'httpAssembleURI()' - Assemble a uniform resource identifier from its
* components.
*
* This function escapes reserved characters in the URI depending on the
* value of the "encoding" argument. You should use this function in
* place of traditional string functions whenever you need to create a
* URI string.
*
* @since CUPS 1.2/macOS 10.5@
*/
http_uri_status_t /* O - URI status */
httpAssembleURI(
http_uri_coding_t encoding, /* I - Encoding flags */
char *uri, /* I - URI buffer */
int urilen, /* I - Size of URI buffer */
const char *scheme, /* I - Scheme name */
const char *username, /* I - Username */
const char *host, /* I - Hostname or address */
int port, /* I - Port number */
const char *resource) /* I - Resource */
{
char *ptr, /* Pointer into URI buffer */
*end; /* End of URI buffer */
/*
* Range check input...
*/
if (!uri || urilen < 1 || !scheme || port < 0)
{
if (uri)
*uri = '\0';
return (HTTP_URI_STATUS_BAD_ARGUMENTS);
}
/*
* Assemble the URI starting with the scheme...
*/
end = uri + urilen - 1;
ptr = http_copy_encode(uri, scheme, end, NULL, NULL, 0);
if (!ptr)
goto assemble_overflow;
if (!strcmp(scheme, "geo") || !strcmp(scheme, "mailto") || !strcmp(scheme, "tel"))
{
/*
* geo:, mailto:, and tel: only have :, no //...
*/
if (ptr < end)
*ptr++ = ':';
else
goto assemble_overflow;
}
else
{
/*
* Schemes other than geo:, mailto:, and tel: typically have //...
*/
if ((ptr + 2) < end)
{
*ptr++ = ':';
*ptr++ = '/';
*ptr++ = '/';
}
else
goto assemble_overflow;
}
/*
* Next the username and hostname, if any...
*/
if (host)
{
const char *hostptr; /* Pointer into hostname */
int have_ipv6; /* Do we have an IPv6 address? */
if (username && *username)
{
/*
* Add username@ first...
*/
ptr = http_copy_encode(ptr, username, end, "/?#[]@", NULL,
encoding & HTTP_URI_CODING_USERNAME);
if (!ptr)
goto assemble_overflow;
if (ptr < end)
*ptr++ = '@';
else
goto assemble_overflow;
}
/*
* Then add the hostname. Since IPv6 is a particular pain to deal
* with, we have several special cases to deal with. If we get
* an IPv6 address with brackets around it, assume it is already in
* URI format. Since DNS-SD service names can sometimes look like
* raw IPv6 addresses, we specifically look for "._tcp" in the name,
* too...
*/
for (hostptr = host,
have_ipv6 = strchr(host, ':') && !strstr(host, "._tcp");
*hostptr && have_ipv6;
hostptr ++)
if (*hostptr != ':' && !isxdigit(*hostptr & 255))
{
have_ipv6 = *hostptr == '%';
break;
}
if (have_ipv6)
{
/*
* We have a raw IPv6 address...
*/
if (strchr(host, '%') && !(encoding & HTTP_URI_CODING_RFC6874))
{
/*
* We have a link-local address, add "[v1." prefix...
*/
if ((ptr + 4) < end)
{
*ptr++ = '[';
*ptr++ = 'v';
*ptr++ = '1';
*ptr++ = '.';
}
else
goto assemble_overflow;
}
else
{
/*
* We have a normal (or RFC 6874 link-local) address, add "[" prefix...
*/
if (ptr < end)
*ptr++ = '[';
else
goto assemble_overflow;
}
/*
* Copy the rest of the IPv6 address, and terminate with "]".
*/
while (ptr < end && *host)
{
if (*host == '%')
{
/*
* Convert/encode zone separator
*/
if (encoding & HTTP_URI_CODING_RFC6874)
{
if (ptr >= (end - 2))
goto assemble_overflow;
*ptr++ = '%';
*ptr++ = '2';
*ptr++ = '5';
}
else
*ptr++ = '+';
host ++;
}
else
*ptr++ = *host++;
}
if (*host)
goto assemble_overflow;
if (ptr < end)
*ptr++ = ']';
else
goto assemble_overflow;
}
else
{
/*
* Otherwise, just copy the host string (the extra chars are not in the
* "reg-name" ABNF rule; anything <= SP or >= DEL plus % gets automatically
* percent-encoded.
*/
ptr = http_copy_encode(ptr, host, end, "\"#/:<>?@[\\]^`{|}", NULL,
encoding & HTTP_URI_CODING_HOSTNAME);
if (!ptr)
goto assemble_overflow;
}
/*
* Finish things off with the port number...
*/
if (port > 0)
{
snprintf(ptr, (size_t)(end - ptr + 1), ":%d", port);
ptr += strlen(ptr);
if (ptr >= end)
goto assemble_overflow;
}
}
/*
* Last but not least, add the resource string...
*/
if (resource)
{
char *query; /* Pointer to query string */
/*
* Copy the resource string up to the query string if present...
*/
query = strchr(resource, '?');
ptr = http_copy_encode(ptr, resource, end, NULL, "?",
encoding & HTTP_URI_CODING_RESOURCE);
if (!ptr)
goto assemble_overflow;
if (query)
{
/*
* Copy query string without encoding...
*/
ptr = http_copy_encode(ptr, query, end, NULL, NULL,
encoding & HTTP_URI_CODING_QUERY);
if (!ptr)
goto assemble_overflow;
}
}
else if (ptr < end)
*ptr++ = '/';
else
goto assemble_overflow;
/*
* Nul-terminate the URI buffer and return with no errors...
*/
*ptr = '\0';
return (HTTP_URI_STATUS_OK);
/*
* Clear the URI string and return an overflow error; I don't usually
* like goto's, but in this case it makes sense...
*/
assemble_overflow:
*uri = '\0';
return (HTTP_URI_STATUS_OVERFLOW);
}