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