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