1355b4669Sjacobs /*
2355b4669Sjacobs * "$Id: http-support.c 148 2006-04-25 16:54:17Z njacobs $"
3355b4669Sjacobs *
4355b4669Sjacobs * HTTP support routines for the Common UNIX Printing System (CUPS) scheduler.
5355b4669Sjacobs *
6355b4669Sjacobs * Copyright 1997-2005 by Easy Software Products, all rights reserved.
7355b4669Sjacobs *
8355b4669Sjacobs * These coded instructions, statements, and computer programs are the
9355b4669Sjacobs * property of Easy Software Products and are protected by Federal
10355b4669Sjacobs * copyright law. Distribution and use rights are outlined in the file
11355b4669Sjacobs * "LICENSE.txt" which should have been included with this file. If this
12355b4669Sjacobs * file is missing or damaged please contact Easy Software Products
13355b4669Sjacobs * at:
14355b4669Sjacobs *
15355b4669Sjacobs * Attn: CUPS Licensing Information
16355b4669Sjacobs * Easy Software Products
17355b4669Sjacobs * 44141 Airport View Drive, Suite 204
18355b4669Sjacobs * Hollywood, Maryland 20636 USA
19355b4669Sjacobs *
20355b4669Sjacobs * Voice: (301) 373-9600
21355b4669Sjacobs * EMail: cups-info@cups.org
22355b4669Sjacobs * WWW: http://www.cups.org
23355b4669Sjacobs *
24355b4669Sjacobs * This file is subject to the Apple OS-Developed Software exception.
25355b4669Sjacobs *
26355b4669Sjacobs * Contents:
27355b4669Sjacobs *
28355b4669Sjacobs * httpSeparate() - Separate a Universal Resource Identifier into its
29355b4669Sjacobs * components.
30355b4669Sjacobs * httpSeparate2() - Separate a Universal Resource Identifier into its
31355b4669Sjacobs * components.
32355b4669Sjacobs * httpStatus() - Return a short string describing a HTTP status code.
33355b4669Sjacobs * cups_hstrerror() - hstrerror() emulation function for Solaris and others...
34355b4669Sjacobs * http_copy_decode() - Copy and decode a URI.
35355b4669Sjacobs */
36355b4669Sjacobs
37355b4669Sjacobs /*
38355b4669Sjacobs * Include necessary headers...
39355b4669Sjacobs */
40355b4669Sjacobs
41355b4669Sjacobs #include <stdio.h>
42355b4669Sjacobs #include <stdlib.h>
43355b4669Sjacobs #include <stdarg.h>
44355b4669Sjacobs #include <ctype.h>
45355b4669Sjacobs #include "string.h"
46355b4669Sjacobs
47355b4669Sjacobs #include "http.h"
48355b4669Sjacobs
49355b4669Sjacobs
50355b4669Sjacobs /*
51355b4669Sjacobs * Local functions...
52355b4669Sjacobs */
53355b4669Sjacobs
54355b4669Sjacobs static const char *http_copy_decode(char *dst, const char *src,
55355b4669Sjacobs int dstsize, const char *term);
56355b4669Sjacobs
57355b4669Sjacobs
58355b4669Sjacobs /*
59355b4669Sjacobs * 'httpSeparate()' - Separate a Universal Resource Identifier into its
60355b4669Sjacobs * components.
61355b4669Sjacobs */
62355b4669Sjacobs
63355b4669Sjacobs void
httpSeparate(const char * uri,char * method,char * username,char * host,int * port,char * resource)64355b4669Sjacobs httpSeparate(const char *uri, /* I - Universal Resource Identifier */
65355b4669Sjacobs char *method, /* O - Method [32] (http, https, etc.) */
66355b4669Sjacobs char *username, /* O - Username [1024] */
67355b4669Sjacobs char *host, /* O - Hostname [1024] */
68355b4669Sjacobs int *port, /* O - Port number to use */
69355b4669Sjacobs char *resource) /* O - Resource/filename [1024] */
70355b4669Sjacobs {
71355b4669Sjacobs httpSeparate2(uri, method, 32, username, HTTP_MAX_URI, host, HTTP_MAX_URI,
72355b4669Sjacobs port, resource, HTTP_MAX_URI);
73355b4669Sjacobs }
74355b4669Sjacobs
75355b4669Sjacobs
76355b4669Sjacobs /*
77355b4669Sjacobs * 'httpSeparate2()' - Separate a Universal Resource Identifier into its
78355b4669Sjacobs * components.
79355b4669Sjacobs */
80355b4669Sjacobs
81355b4669Sjacobs void
httpSeparate2(const char * uri,char * method,int methodlen,char * username,int usernamelen,char * host,int hostlen,int * port,char * resource,int resourcelen)82355b4669Sjacobs httpSeparate2(const char *uri, /* I - Universal Resource Identifier */
83355b4669Sjacobs char *method, /* O - Method (http, https, etc.) */
84355b4669Sjacobs int methodlen, /* I - Size of method buffer */
85355b4669Sjacobs char *username, /* O - Username */
86355b4669Sjacobs int usernamelen, /* I - Size of username buffer */
87355b4669Sjacobs char *host, /* O - Hostname */
88355b4669Sjacobs int hostlen, /* I - Size of hostname buffer */
89355b4669Sjacobs int *port, /* O - Port number to use */
90355b4669Sjacobs char *resource, /* O - Resource/filename */
91355b4669Sjacobs int resourcelen) /* I - Size of resource buffer */
92355b4669Sjacobs {
93355b4669Sjacobs char *ptr; /* Pointer into string... */
94355b4669Sjacobs const char *atsign, /* @ sign */
95355b4669Sjacobs *slash; /* Separator */
96355b4669Sjacobs
97355b4669Sjacobs
98355b4669Sjacobs /*
99355b4669Sjacobs * Range check input...
100355b4669Sjacobs */
101355b4669Sjacobs
102355b4669Sjacobs if (uri == NULL || method == NULL || username == NULL || host == NULL ||
103355b4669Sjacobs port == NULL || resource == NULL)
104355b4669Sjacobs return;
105355b4669Sjacobs
106355b4669Sjacobs /*
107355b4669Sjacobs * Grab the method portion of the URI...
108355b4669Sjacobs */
109355b4669Sjacobs
110355b4669Sjacobs if (strncmp(uri, "//", 2) == 0)
111355b4669Sjacobs {
112355b4669Sjacobs /*
113355b4669Sjacobs * Workaround for HP IPP client bug...
114355b4669Sjacobs */
115355b4669Sjacobs
116355b4669Sjacobs strlcpy(method, "ipp", methodlen);
117355b4669Sjacobs }
118355b4669Sjacobs else
119355b4669Sjacobs {
120355b4669Sjacobs /*
121355b4669Sjacobs * Standard URI with method...
122355b4669Sjacobs */
123355b4669Sjacobs
124355b4669Sjacobs uri = http_copy_decode(host, uri, hostlen, ":");
125355b4669Sjacobs
126355b4669Sjacobs if (*uri == ':')
127355b4669Sjacobs uri ++;
128355b4669Sjacobs
129355b4669Sjacobs /*
130355b4669Sjacobs * If the method contains a period or slash, then it's probably
131355b4669Sjacobs * hostname/filename...
132355b4669Sjacobs */
133355b4669Sjacobs
134355b4669Sjacobs if (strchr(host, '.') != NULL || strchr(host, '/') != NULL || *uri == '\0')
135355b4669Sjacobs {
136355b4669Sjacobs if ((ptr = strchr(host, '/')) != NULL)
137355b4669Sjacobs {
138355b4669Sjacobs strlcpy(resource, ptr, resourcelen);
139355b4669Sjacobs *ptr = '\0';
140355b4669Sjacobs }
141355b4669Sjacobs else
142355b4669Sjacobs resource[0] = '\0';
143355b4669Sjacobs
144355b4669Sjacobs if (isdigit(*uri & 255))
145355b4669Sjacobs {
146355b4669Sjacobs /*
147355b4669Sjacobs * OK, we have "hostname:port[/resource]"...
148355b4669Sjacobs */
149355b4669Sjacobs
150355b4669Sjacobs *port = strtol(uri, (char **)&uri, 10);
151355b4669Sjacobs
152355b4669Sjacobs if (*uri == '/')
153355b4669Sjacobs strlcpy(resource, uri, resourcelen);
154355b4669Sjacobs }
155355b4669Sjacobs else
156355b4669Sjacobs *port = 631;
157355b4669Sjacobs
158355b4669Sjacobs strlcpy(method, "http", methodlen);
159355b4669Sjacobs username[0] = '\0';
160355b4669Sjacobs return;
161355b4669Sjacobs }
162355b4669Sjacobs else
163355b4669Sjacobs strlcpy(method, host, methodlen);
164355b4669Sjacobs }
165355b4669Sjacobs
166355b4669Sjacobs /*
167355b4669Sjacobs * If the method starts with less than 2 slashes then it is a local resource...
168355b4669Sjacobs */
169355b4669Sjacobs
170355b4669Sjacobs if (strncmp(uri, "//", 2) != 0)
171355b4669Sjacobs {
172355b4669Sjacobs strlcpy(resource, uri, resourcelen);
173355b4669Sjacobs
174355b4669Sjacobs username[0] = '\0';
175355b4669Sjacobs host[0] = '\0';
176355b4669Sjacobs *port = 0;
177355b4669Sjacobs return;
178355b4669Sjacobs }
179355b4669Sjacobs
180355b4669Sjacobs /*
181355b4669Sjacobs * Grab the username, if any...
182355b4669Sjacobs */
183355b4669Sjacobs
184355b4669Sjacobs uri += 2;
185355b4669Sjacobs
186355b4669Sjacobs if ((slash = strchr(uri, '/')) == NULL)
187355b4669Sjacobs slash = uri + strlen(uri);
188355b4669Sjacobs
189355b4669Sjacobs if ((atsign = strchr(uri, '@')) != NULL && atsign < slash)
190355b4669Sjacobs {
191355b4669Sjacobs /*
192355b4669Sjacobs * Got a username:password combo...
193355b4669Sjacobs */
194355b4669Sjacobs
195355b4669Sjacobs uri = http_copy_decode(username, uri, usernamelen, "@") + 1;
196355b4669Sjacobs }
197355b4669Sjacobs else
198355b4669Sjacobs username[0] = '\0';
199355b4669Sjacobs
200355b4669Sjacobs /*
201355b4669Sjacobs * Grab the hostname...
202355b4669Sjacobs */
203355b4669Sjacobs
204355b4669Sjacobs uri = http_copy_decode(host, uri, hostlen, ":/");
205355b4669Sjacobs
206355b4669Sjacobs if (*uri != ':')
207355b4669Sjacobs {
208355b4669Sjacobs if (strcasecmp(method, "http") == 0)
209355b4669Sjacobs *port = 80;
210355b4669Sjacobs else if (strcasecmp(method, "https") == 0)
211355b4669Sjacobs *port = 443;
212355b4669Sjacobs else if (strcasecmp(method, "ipp") == 0)
213355b4669Sjacobs *port = 631;
214355b4669Sjacobs else if (strcasecmp(method, "lpd") == 0)
215355b4669Sjacobs *port = 515;
216355b4669Sjacobs else if (strcasecmp(method, "socket") == 0) /* Not registered yet... */
217355b4669Sjacobs *port = 9100;
218355b4669Sjacobs else
219355b4669Sjacobs *port = 0;
220355b4669Sjacobs }
221355b4669Sjacobs else
222355b4669Sjacobs {
223355b4669Sjacobs /*
224355b4669Sjacobs * Parse port number...
225355b4669Sjacobs */
226355b4669Sjacobs
227355b4669Sjacobs *port = strtol(uri + 1, (char **)&uri, 10);
228355b4669Sjacobs }
229355b4669Sjacobs
230355b4669Sjacobs if (*uri == '\0')
231355b4669Sjacobs {
232355b4669Sjacobs /*
233355b4669Sjacobs * Hostname but no port or path...
234355b4669Sjacobs */
235355b4669Sjacobs
236355b4669Sjacobs resource[0] = '/';
237355b4669Sjacobs resource[1] = '\0';
238355b4669Sjacobs return;
239355b4669Sjacobs }
240355b4669Sjacobs
241355b4669Sjacobs /*
242355b4669Sjacobs * The remaining portion is the resource string...
243355b4669Sjacobs */
244355b4669Sjacobs
245355b4669Sjacobs http_copy_decode(resource, uri, resourcelen, "");
246355b4669Sjacobs }
247355b4669Sjacobs
248355b4669Sjacobs
249355b4669Sjacobs /*
250355b4669Sjacobs * 'httpStatus()' - Return a short string describing a HTTP status code.
251355b4669Sjacobs */
252355b4669Sjacobs
253355b4669Sjacobs const char * /* O - String or NULL */
httpStatus(http_status_t status)254355b4669Sjacobs httpStatus(http_status_t status) /* I - HTTP status code */
255355b4669Sjacobs {
256355b4669Sjacobs switch (status)
257355b4669Sjacobs {
258355b4669Sjacobs case HTTP_CONTINUE :
259355b4669Sjacobs return ("Continue");
260355b4669Sjacobs case HTTP_SWITCHING_PROTOCOLS :
261355b4669Sjacobs return ("Switching Protocols");
262355b4669Sjacobs case HTTP_OK :
263355b4669Sjacobs return ("OK");
264355b4669Sjacobs case HTTP_CREATED :
265355b4669Sjacobs return ("Created");
266355b4669Sjacobs case HTTP_ACCEPTED :
267355b4669Sjacobs return ("Accepted");
268355b4669Sjacobs case HTTP_NO_CONTENT :
269355b4669Sjacobs return ("No Content");
270355b4669Sjacobs case HTTP_NOT_MODIFIED :
271355b4669Sjacobs return ("Not Modified");
272355b4669Sjacobs case HTTP_BAD_REQUEST :
273355b4669Sjacobs return ("Bad Request");
274355b4669Sjacobs case HTTP_UNAUTHORIZED :
275355b4669Sjacobs return ("Unauthorized");
276355b4669Sjacobs case HTTP_FORBIDDEN :
277355b4669Sjacobs return ("Forbidden");
278355b4669Sjacobs case HTTP_NOT_FOUND :
279355b4669Sjacobs return ("Not Found");
280355b4669Sjacobs case HTTP_REQUEST_TOO_LARGE :
281355b4669Sjacobs return ("Request Entity Too Large");
282355b4669Sjacobs case HTTP_URI_TOO_LONG :
283355b4669Sjacobs return ("URI Too Long");
284355b4669Sjacobs case HTTP_UPGRADE_REQUIRED :
285355b4669Sjacobs return ("Upgrade Required");
286355b4669Sjacobs case HTTP_NOT_IMPLEMENTED :
287355b4669Sjacobs return ("Not Implemented");
288355b4669Sjacobs case HTTP_NOT_SUPPORTED :
289355b4669Sjacobs return ("Not Supported");
290355b4669Sjacobs default :
291355b4669Sjacobs return ("Unknown");
292355b4669Sjacobs }
293355b4669Sjacobs }
294355b4669Sjacobs
295355b4669Sjacobs
296355b4669Sjacobs #ifndef HAVE_HSTRERROR
297355b4669Sjacobs /*
298355b4669Sjacobs * 'cups_hstrerror()' - hstrerror() emulation function for Solaris and others...
299355b4669Sjacobs */
300355b4669Sjacobs
301355b4669Sjacobs const char * /* O - Error string */
cups_hstrerror(int error)302355b4669Sjacobs cups_hstrerror(int error) /* I - Error number */
303355b4669Sjacobs {
304355b4669Sjacobs static const char * const errors[] = /* Error strings */
305355b4669Sjacobs {
306355b4669Sjacobs "OK",
307355b4669Sjacobs "Host not found.",
308355b4669Sjacobs "Try again.",
309355b4669Sjacobs "Unrecoverable lookup error.",
310355b4669Sjacobs "No data associated with name."
311355b4669Sjacobs };
312355b4669Sjacobs
313355b4669Sjacobs
314355b4669Sjacobs if (error < 0 || error > 4)
315355b4669Sjacobs return ("Unknown hostname lookup error.");
316355b4669Sjacobs else
317355b4669Sjacobs return (errors[error]);
318355b4669Sjacobs }
319355b4669Sjacobs #endif /* !HAVE_HSTRERROR */
320355b4669Sjacobs
321355b4669Sjacobs
322355b4669Sjacobs /*
323355b4669Sjacobs * 'http_copy_decode()' - Copy and decode a URI.
324355b4669Sjacobs */
325355b4669Sjacobs
326355b4669Sjacobs static const char * /* O - New source pointer */
http_copy_decode(char * dst,const char * src,int dstsize,const char * term)327*1da57d55SToomas Soome http_copy_decode(char *dst, /* O - Destination buffer */
328355b4669Sjacobs const char *src, /* I - Source pointer */
329355b4669Sjacobs int dstsize, /* I - Destination size */
330355b4669Sjacobs const char *term) /* I - Terminating characters */
331355b4669Sjacobs {
332355b4669Sjacobs char *ptr, /* Pointer into buffer */
333355b4669Sjacobs *end; /* End of buffer */
334355b4669Sjacobs int quoted; /* Quoted character */
335355b4669Sjacobs
336355b4669Sjacobs
337355b4669Sjacobs /*
338355b4669Sjacobs * Copy the src to the destination until we hit a terminating character
339355b4669Sjacobs * or the end of the string.
340355b4669Sjacobs */
341355b4669Sjacobs
342355b4669Sjacobs for (ptr = dst, end = dst + dstsize - 1; *src && !strchr(term, *src); src ++)
343355b4669Sjacobs if (ptr < end)
344355b4669Sjacobs {
345355b4669Sjacobs if (*src == '%' && isxdigit(src[1] & 255) && isxdigit(src[2] & 255))
346355b4669Sjacobs {
347355b4669Sjacobs /*
348355b4669Sjacobs * Grab a hex-encoded character...
349355b4669Sjacobs */
350355b4669Sjacobs
351355b4669Sjacobs src ++;
352355b4669Sjacobs if (isalpha(*src))
353355b4669Sjacobs quoted = (tolower(*src) - 'a' + 10) << 4;
354355b4669Sjacobs else
355355b4669Sjacobs quoted = (*src - '0') << 4;
356355b4669Sjacobs
357355b4669Sjacobs src ++;
358355b4669Sjacobs if (isalpha(*src))
359355b4669Sjacobs quoted |= tolower(*src) - 'a' + 10;
360355b4669Sjacobs else
361355b4669Sjacobs quoted |= *src - '0';
362355b4669Sjacobs
363355b4669Sjacobs *ptr++ = quoted;
364355b4669Sjacobs }
365355b4669Sjacobs else
366355b4669Sjacobs *ptr++ = *src;
367355b4669Sjacobs }
368355b4669Sjacobs
369355b4669Sjacobs *ptr = '\0';
370355b4669Sjacobs
371355b4669Sjacobs return (src);
372355b4669Sjacobs }
373355b4669Sjacobs
374355b4669Sjacobs
375355b4669Sjacobs /*
376355b4669Sjacobs * End of "$Id: http-support.c 148 2006-04-25 16:54:17Z njacobs $"
377355b4669Sjacobs */
378