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