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