1 /* 2 * "$Id: http-support.c 148 2006-04-25 16:54:17Z njacobs $" 3 * 4 * HTTP support routines for the Common UNIX Printing System (CUPS) scheduler. 5 * 6 * Copyright 1997-2005 by Easy Software Products, all rights reserved. 7 * 8 * These coded instructions, statements, and computer programs are the 9 * property of Easy Software Products and are protected by Federal 10 * copyright law. Distribution and use rights are outlined in the file 11 * "LICENSE.txt" which should have been included with this file. If this 12 * file is missing or damaged please contact Easy Software Products 13 * at: 14 * 15 * Attn: CUPS Licensing Information 16 * Easy Software Products 17 * 44141 Airport View Drive, Suite 204 18 * Hollywood, Maryland 20636 USA 19 * 20 * Voice: (301) 373-9600 21 * EMail: cups-info@cups.org 22 * WWW: http://www.cups.org 23 * 24 * This file is subject to the Apple OS-Developed Software exception. 25 * 26 * Contents: 27 * 28 * httpSeparate() - Separate a Universal Resource Identifier into its 29 * components. 30 * httpSeparate2() - Separate a Universal Resource Identifier into its 31 * components. 32 * httpStatus() - Return a short string describing a HTTP status code. 33 * cups_hstrerror() - hstrerror() emulation function for Solaris and others... 34 * http_copy_decode() - Copy and decode a URI. 35 */ 36 37 #pragma ident "%Z%%M% %I% %E% SMI" 38 39 /* 40 * Include necessary headers... 41 */ 42 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <stdarg.h> 46 #include <ctype.h> 47 #include "string.h" 48 49 #include "http.h" 50 51 52 /* 53 * Local functions... 54 */ 55 56 static const char *http_copy_decode(char *dst, const char *src, 57 int dstsize, const char *term); 58 59 60 /* 61 * 'httpSeparate()' - Separate a Universal Resource Identifier into its 62 * components. 63 */ 64 65 void 66 httpSeparate(const char *uri, /* I - Universal Resource Identifier */ 67 char *method, /* O - Method [32] (http, https, etc.) */ 68 char *username, /* O - Username [1024] */ 69 char *host, /* O - Hostname [1024] */ 70 int *port, /* O - Port number to use */ 71 char *resource) /* O - Resource/filename [1024] */ 72 { 73 httpSeparate2(uri, method, 32, username, HTTP_MAX_URI, host, HTTP_MAX_URI, 74 port, resource, HTTP_MAX_URI); 75 } 76 77 78 /* 79 * 'httpSeparate2()' - Separate a Universal Resource Identifier into its 80 * components. 81 */ 82 83 void 84 httpSeparate2(const char *uri, /* I - Universal Resource Identifier */ 85 char *method, /* O - Method (http, https, etc.) */ 86 int methodlen, /* I - Size of method buffer */ 87 char *username, /* O - Username */ 88 int usernamelen, /* I - Size of username buffer */ 89 char *host, /* O - Hostname */ 90 int hostlen, /* I - Size of hostname buffer */ 91 int *port, /* O - Port number to use */ 92 char *resource, /* O - Resource/filename */ 93 int resourcelen) /* I - Size of resource buffer */ 94 { 95 char *ptr; /* Pointer into string... */ 96 const char *atsign, /* @ sign */ 97 *slash; /* Separator */ 98 99 100 /* 101 * Range check input... 102 */ 103 104 if (uri == NULL || method == NULL || username == NULL || host == NULL || 105 port == NULL || resource == NULL) 106 return; 107 108 /* 109 * Grab the method portion of the URI... 110 */ 111 112 if (strncmp(uri, "//", 2) == 0) 113 { 114 /* 115 * Workaround for HP IPP client bug... 116 */ 117 118 strlcpy(method, "ipp", methodlen); 119 } 120 else 121 { 122 /* 123 * Standard URI with method... 124 */ 125 126 uri = http_copy_decode(host, uri, hostlen, ":"); 127 128 if (*uri == ':') 129 uri ++; 130 131 /* 132 * If the method contains a period or slash, then it's probably 133 * hostname/filename... 134 */ 135 136 if (strchr(host, '.') != NULL || strchr(host, '/') != NULL || *uri == '\0') 137 { 138 if ((ptr = strchr(host, '/')) != NULL) 139 { 140 strlcpy(resource, ptr, resourcelen); 141 *ptr = '\0'; 142 } 143 else 144 resource[0] = '\0'; 145 146 if (isdigit(*uri & 255)) 147 { 148 /* 149 * OK, we have "hostname:port[/resource]"... 150 */ 151 152 *port = strtol(uri, (char **)&uri, 10); 153 154 if (*uri == '/') 155 strlcpy(resource, uri, resourcelen); 156 } 157 else 158 *port = 631; 159 160 strlcpy(method, "http", methodlen); 161 username[0] = '\0'; 162 return; 163 } 164 else 165 strlcpy(method, host, methodlen); 166 } 167 168 /* 169 * If the method starts with less than 2 slashes then it is a local resource... 170 */ 171 172 if (strncmp(uri, "//", 2) != 0) 173 { 174 strlcpy(resource, uri, resourcelen); 175 176 username[0] = '\0'; 177 host[0] = '\0'; 178 *port = 0; 179 return; 180 } 181 182 /* 183 * Grab the username, if any... 184 */ 185 186 uri += 2; 187 188 if ((slash = strchr(uri, '/')) == NULL) 189 slash = uri + strlen(uri); 190 191 if ((atsign = strchr(uri, '@')) != NULL && atsign < slash) 192 { 193 /* 194 * Got a username:password combo... 195 */ 196 197 uri = http_copy_decode(username, uri, usernamelen, "@") + 1; 198 } 199 else 200 username[0] = '\0'; 201 202 /* 203 * Grab the hostname... 204 */ 205 206 uri = http_copy_decode(host, uri, hostlen, ":/"); 207 208 if (*uri != ':') 209 { 210 if (strcasecmp(method, "http") == 0) 211 *port = 80; 212 else if (strcasecmp(method, "https") == 0) 213 *port = 443; 214 else if (strcasecmp(method, "ipp") == 0) 215 *port = 631; 216 else if (strcasecmp(method, "lpd") == 0) 217 *port = 515; 218 else if (strcasecmp(method, "socket") == 0) /* Not registered yet... */ 219 *port = 9100; 220 else 221 *port = 0; 222 } 223 else 224 { 225 /* 226 * Parse port number... 227 */ 228 229 *port = strtol(uri + 1, (char **)&uri, 10); 230 } 231 232 if (*uri == '\0') 233 { 234 /* 235 * Hostname but no port or path... 236 */ 237 238 resource[0] = '/'; 239 resource[1] = '\0'; 240 return; 241 } 242 243 /* 244 * The remaining portion is the resource string... 245 */ 246 247 http_copy_decode(resource, uri, resourcelen, ""); 248 } 249 250 251 /* 252 * 'httpStatus()' - Return a short string describing a HTTP status code. 253 */ 254 255 const char * /* O - String or NULL */ 256 httpStatus(http_status_t status) /* I - HTTP status code */ 257 { 258 switch (status) 259 { 260 case HTTP_CONTINUE : 261 return ("Continue"); 262 case HTTP_SWITCHING_PROTOCOLS : 263 return ("Switching Protocols"); 264 case HTTP_OK : 265 return ("OK"); 266 case HTTP_CREATED : 267 return ("Created"); 268 case HTTP_ACCEPTED : 269 return ("Accepted"); 270 case HTTP_NO_CONTENT : 271 return ("No Content"); 272 case HTTP_NOT_MODIFIED : 273 return ("Not Modified"); 274 case HTTP_BAD_REQUEST : 275 return ("Bad Request"); 276 case HTTP_UNAUTHORIZED : 277 return ("Unauthorized"); 278 case HTTP_FORBIDDEN : 279 return ("Forbidden"); 280 case HTTP_NOT_FOUND : 281 return ("Not Found"); 282 case HTTP_REQUEST_TOO_LARGE : 283 return ("Request Entity Too Large"); 284 case HTTP_URI_TOO_LONG : 285 return ("URI Too Long"); 286 case HTTP_UPGRADE_REQUIRED : 287 return ("Upgrade Required"); 288 case HTTP_NOT_IMPLEMENTED : 289 return ("Not Implemented"); 290 case HTTP_NOT_SUPPORTED : 291 return ("Not Supported"); 292 default : 293 return ("Unknown"); 294 } 295 } 296 297 298 #ifndef HAVE_HSTRERROR 299 /* 300 * 'cups_hstrerror()' - hstrerror() emulation function for Solaris and others... 301 */ 302 303 const char * /* O - Error string */ 304 cups_hstrerror(int error) /* I - Error number */ 305 { 306 static const char * const errors[] = /* Error strings */ 307 { 308 "OK", 309 "Host not found.", 310 "Try again.", 311 "Unrecoverable lookup error.", 312 "No data associated with name." 313 }; 314 315 316 if (error < 0 || error > 4) 317 return ("Unknown hostname lookup error."); 318 else 319 return (errors[error]); 320 } 321 #endif /* !HAVE_HSTRERROR */ 322 323 324 /* 325 * 'http_copy_decode()' - Copy and decode a URI. 326 */ 327 328 static const char * /* O - New source pointer */ 329 http_copy_decode(char *dst, /* O - Destination buffer */ 330 const char *src, /* I - Source pointer */ 331 int dstsize, /* I - Destination size */ 332 const char *term) /* I - Terminating characters */ 333 { 334 char *ptr, /* Pointer into buffer */ 335 *end; /* End of buffer */ 336 int quoted; /* Quoted character */ 337 338 339 /* 340 * Copy the src to the destination until we hit a terminating character 341 * or the end of the string. 342 */ 343 344 for (ptr = dst, end = dst + dstsize - 1; *src && !strchr(term, *src); src ++) 345 if (ptr < end) 346 { 347 if (*src == '%' && isxdigit(src[1] & 255) && isxdigit(src[2] & 255)) 348 { 349 /* 350 * Grab a hex-encoded character... 351 */ 352 353 src ++; 354 if (isalpha(*src)) 355 quoted = (tolower(*src) - 'a' + 10) << 4; 356 else 357 quoted = (*src - '0') << 4; 358 359 src ++; 360 if (isalpha(*src)) 361 quoted |= tolower(*src) - 'a' + 10; 362 else 363 quoted |= *src - '0'; 364 365 *ptr++ = quoted; 366 } 367 else 368 *ptr++ = *src; 369 } 370 371 *ptr = '\0'; 372 373 return (src); 374 } 375 376 377 /* 378 * End of "$Id: http-support.c 148 2006-04-25 16:54:17Z njacobs $" 379 */ 380