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