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