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
httpSeparate(const char * uri,char * method,char * username,char * host,int * port,char * resource)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
httpSeparate2(const char * uri,char * method,int methodlen,char * username,int usernamelen,char * host,int hostlen,int * port,char * resource,int resourcelen)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 */
httpStatus(http_status_t status)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 */
cups_hstrerror(int error)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 */
http_copy_decode(char * dst,const char * src,int dstsize,const char * term)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