/* * "$Id: http-support.c 148 2006-04-25 16:54:17Z njacobs $" * * HTTP support routines for the Common UNIX Printing System (CUPS) scheduler. * * Copyright 1997-2005 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal * copyright law. Distribution and use rights are outlined in the file * "LICENSE.txt" which should have been included with this file. If this * file is missing or damaged please contact Easy Software Products * at: * * Attn: CUPS Licensing Information * Easy Software Products * 44141 Airport View Drive, Suite 204 * Hollywood, Maryland 20636 USA * * Voice: (301) 373-9600 * EMail: cups-info@cups.org * WWW: http://www.cups.org * * This file is subject to the Apple OS-Developed Software exception. * * Contents: * * httpSeparate() - Separate a Universal Resource Identifier into its * components. * httpSeparate2() - Separate a Universal Resource Identifier into its * components. * httpStatus() - Return a short string describing a HTTP status code. * cups_hstrerror() - hstrerror() emulation function for Solaris and others... * http_copy_decode() - Copy and decode a URI. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Include necessary headers... */ #include #include #include #include #include "string.h" #include "http.h" /* * Local functions... */ static const char *http_copy_decode(char *dst, const char *src, int dstsize, const char *term); /* * 'httpSeparate()' - Separate a Universal Resource Identifier into its * components. */ void httpSeparate(const char *uri, /* I - Universal Resource Identifier */ char *method, /* O - Method [32] (http, https, etc.) */ char *username, /* O - Username [1024] */ char *host, /* O - Hostname [1024] */ int *port, /* O - Port number to use */ char *resource) /* O - Resource/filename [1024] */ { httpSeparate2(uri, method, 32, username, HTTP_MAX_URI, host, HTTP_MAX_URI, port, resource, HTTP_MAX_URI); } /* * 'httpSeparate2()' - Separate a Universal Resource Identifier into its * components. */ void httpSeparate2(const char *uri, /* I - Universal Resource Identifier */ char *method, /* O - Method (http, https, etc.) */ int methodlen, /* I - Size of method buffer */ char *username, /* O - Username */ int usernamelen, /* I - Size of username buffer */ char *host, /* O - Hostname */ int hostlen, /* I - Size of hostname buffer */ int *port, /* O - Port number to use */ char *resource, /* O - Resource/filename */ int resourcelen) /* I - Size of resource buffer */ { char *ptr; /* Pointer into string... */ const char *atsign, /* @ sign */ *slash; /* Separator */ /* * Range check input... */ if (uri == NULL || method == NULL || username == NULL || host == NULL || port == NULL || resource == NULL) return; /* * Grab the method portion of the URI... */ if (strncmp(uri, "//", 2) == 0) { /* * Workaround for HP IPP client bug... */ strlcpy(method, "ipp", methodlen); } else { /* * Standard URI with method... */ uri = http_copy_decode(host, uri, hostlen, ":"); if (*uri == ':') uri ++; /* * If the method contains a period or slash, then it's probably * hostname/filename... */ if (strchr(host, '.') != NULL || strchr(host, '/') != NULL || *uri == '\0') { if ((ptr = strchr(host, '/')) != NULL) { strlcpy(resource, ptr, resourcelen); *ptr = '\0'; } else resource[0] = '\0'; if (isdigit(*uri & 255)) { /* * OK, we have "hostname:port[/resource]"... */ *port = strtol(uri, (char **)&uri, 10); if (*uri == '/') strlcpy(resource, uri, resourcelen); } else *port = 631; strlcpy(method, "http", methodlen); username[0] = '\0'; return; } else strlcpy(method, host, methodlen); } /* * If the method starts with less than 2 slashes then it is a local resource... */ if (strncmp(uri, "//", 2) != 0) { strlcpy(resource, uri, resourcelen); username[0] = '\0'; host[0] = '\0'; *port = 0; return; } /* * Grab the username, if any... */ uri += 2; if ((slash = strchr(uri, '/')) == NULL) slash = uri + strlen(uri); if ((atsign = strchr(uri, '@')) != NULL && atsign < slash) { /* * Got a username:password combo... */ uri = http_copy_decode(username, uri, usernamelen, "@") + 1; } else username[0] = '\0'; /* * Grab the hostname... */ uri = http_copy_decode(host, uri, hostlen, ":/"); if (*uri != ':') { if (strcasecmp(method, "http") == 0) *port = 80; else if (strcasecmp(method, "https") == 0) *port = 443; else if (strcasecmp(method, "ipp") == 0) *port = 631; else if (strcasecmp(method, "lpd") == 0) *port = 515; else if (strcasecmp(method, "socket") == 0) /* Not registered yet... */ *port = 9100; else *port = 0; } else { /* * Parse port number... */ *port = strtol(uri + 1, (char **)&uri, 10); } if (*uri == '\0') { /* * Hostname but no port or path... */ resource[0] = '/'; resource[1] = '\0'; return; } /* * The remaining portion is the resource string... */ http_copy_decode(resource, uri, resourcelen, ""); } /* * 'httpStatus()' - Return a short string describing a HTTP status code. */ const char * /* O - String or NULL */ httpStatus(http_status_t status) /* I - HTTP status code */ { switch (status) { case HTTP_CONTINUE : return ("Continue"); case HTTP_SWITCHING_PROTOCOLS : return ("Switching Protocols"); case HTTP_OK : return ("OK"); case HTTP_CREATED : return ("Created"); case HTTP_ACCEPTED : return ("Accepted"); case HTTP_NO_CONTENT : return ("No Content"); case HTTP_NOT_MODIFIED : return ("Not Modified"); case HTTP_BAD_REQUEST : return ("Bad Request"); case HTTP_UNAUTHORIZED : return ("Unauthorized"); case HTTP_FORBIDDEN : return ("Forbidden"); case HTTP_NOT_FOUND : return ("Not Found"); case HTTP_REQUEST_TOO_LARGE : return ("Request Entity Too Large"); case HTTP_URI_TOO_LONG : return ("URI Too Long"); case HTTP_UPGRADE_REQUIRED : return ("Upgrade Required"); case HTTP_NOT_IMPLEMENTED : return ("Not Implemented"); case HTTP_NOT_SUPPORTED : return ("Not Supported"); default : return ("Unknown"); } } #ifndef HAVE_HSTRERROR /* * 'cups_hstrerror()' - hstrerror() emulation function for Solaris and others... */ const char * /* O - Error string */ cups_hstrerror(int error) /* I - Error number */ { static const char * const errors[] = /* Error strings */ { "OK", "Host not found.", "Try again.", "Unrecoverable lookup error.", "No data associated with name." }; if (error < 0 || error > 4) return ("Unknown hostname lookup error."); else return (errors[error]); } #endif /* !HAVE_HSTRERROR */ /* * 'http_copy_decode()' - Copy and decode a URI. */ static const char * /* O - New source pointer */ http_copy_decode(char *dst, /* O - Destination buffer */ const char *src, /* I - Source pointer */ int dstsize, /* I - Destination size */ const char *term) /* I - Terminating characters */ { char *ptr, /* Pointer into buffer */ *end; /* End of buffer */ int quoted; /* Quoted character */ /* * Copy the src to the destination until we hit a terminating character * or the end of the string. */ for (ptr = dst, end = dst + dstsize - 1; *src && !strchr(term, *src); src ++) if (ptr < end) { if (*src == '%' && isxdigit(src[1] & 255) && isxdigit(src[2] & 255)) { /* * Grab a hex-encoded character... */ src ++; if (isalpha(*src)) quoted = (tolower(*src) - 'a' + 10) << 4; else quoted = (*src - '0') << 4; src ++; if (isalpha(*src)) quoted |= tolower(*src) - 'a' + 10; else quoted |= *src - '0'; *ptr++ = quoted; } else *ptr++ = *src; } *ptr = '\0'; return (src); } /* * End of "$Id: http-support.c 148 2006-04-25 16:54:17Z njacobs $" */