1355b4669Sjacobs /*
2355b4669Sjacobs  * "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
3355b4669Sjacobs  *
4355b4669Sjacobs  *   HTTP routines for the Common UNIX Printing System (CUPS).
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  *   httpInitialize()     - Initialize the HTTP interface library and set the
29355b4669Sjacobs  *                          default HTTP proxy (if any).
30355b4669Sjacobs  *   httpCheck()          - Check to see if there is a pending response from
31355b4669Sjacobs  *                          the server.
32355b4669Sjacobs  *   httpClearCookie()    - Clear the cookie value(s).
33355b4669Sjacobs  *   httpClose()          - Close an HTTP connection...
34355b4669Sjacobs  *   httpConnect()        - Connect to a HTTP server.
35355b4669Sjacobs  *   httpConnectEncrypt() - Connect to a HTTP server using encryption.
36355b4669Sjacobs  *   httpEncryption()     - Set the required encryption on the link.
37355b4669Sjacobs  *   httpReconnect()      - Reconnect to a HTTP server...
38355b4669Sjacobs  *   httpGetSubField()    - Get a sub-field value.
39355b4669Sjacobs  *   httpSetField()       - Set the value of an HTTP header.
40355b4669Sjacobs  *   httpDelete()         - Send a DELETE request to the server.
41355b4669Sjacobs  *   httpGet()            - Send a GET request to the server.
42355b4669Sjacobs  *   httpHead()           - Send a HEAD request to the server.
43355b4669Sjacobs  *   httpOptions()        - Send an OPTIONS request to the server.
44355b4669Sjacobs  *   httpPost()           - Send a POST request to the server.
45355b4669Sjacobs  *   httpPut()            - Send a PUT request to the server.
46355b4669Sjacobs  *   httpTrace()          - Send an TRACE request to the server.
47355b4669Sjacobs  *   httpFlush()          - Flush data from a HTTP connection.
48355b4669Sjacobs  *   httpRead()           - Read data from a HTTP connection.
49355b4669Sjacobs  *   httpSetCookie()      - Set the cookie value(s)...
50355b4669Sjacobs  *   httpWait()           - Wait for data available on a connection.
51355b4669Sjacobs  *   httpWrite()          - Write data to a HTTP connection.
52355b4669Sjacobs  *   httpGets()           - Get a line of text from a HTTP connection.
53355b4669Sjacobs  *   httpPrintf()         - Print a formatted string to a HTTP connection.
54355b4669Sjacobs  *   httpGetDateString()  - Get a formatted date/time string from a time value.
55355b4669Sjacobs  *   httpGetDateTime()    - Get a time value from a formatted date/time string.
56355b4669Sjacobs  *   httpUpdate()         - Update the current HTTP state for incoming data.
57355b4669Sjacobs  *   httpDecode64()       - Base64-decode a string.
58355b4669Sjacobs  *   httpDecode64_2()     - Base64-decode a string.
59355b4669Sjacobs  *   httpEncode64()       - Base64-encode a string.
60355b4669Sjacobs  *   httpEncode64_2()     - Base64-encode a string.
61355b4669Sjacobs  *   httpGetLength()      - Get the amount of data remaining from the
62355b4669Sjacobs  *                          content-length or transfer-encoding fields.
63355b4669Sjacobs  *   http_field()         - Return the field index for a field name.
64355b4669Sjacobs  *   http_send()          - Send a request with all fields and the trailing
65355b4669Sjacobs  *                          blank line.
66355b4669Sjacobs  *   http_wait()          - Wait for data available on a connection.
67355b4669Sjacobs  *   http_upgrade()       - Force upgrade to TLS encryption.
68355b4669Sjacobs  *   http_setup_ssl()     - Set up SSL/TLS on a connection.
69355b4669Sjacobs  *   http_shutdown_ssl()  - Shut down SSL/TLS on a connection.
70355b4669Sjacobs  *   http_read_ssl()      - Read from a SSL/TLS connection.
71355b4669Sjacobs  *   http_write_ssl()     - Write to a SSL/TLS connection.
72355b4669Sjacobs  *   CDSAReadFunc()       - Read function for CDSA decryption code.
73355b4669Sjacobs  *   CDSAWriteFunc()      - Write function for CDSA encryption code.
74355b4669Sjacobs  */
75355b4669Sjacobs 
76355b4669Sjacobs /*
77355b4669Sjacobs  * Include necessary headers...
78355b4669Sjacobs  */
79355b4669Sjacobs 
80355b4669Sjacobs #include "http-private.h"
81355b4669Sjacobs 
82355b4669Sjacobs #include <stdio.h>
83355b4669Sjacobs #include <stdlib.h>
84355b4669Sjacobs #include <stdarg.h>
85355b4669Sjacobs #include <ctype.h>
86355b4669Sjacobs #include "string.h"
87355b4669Sjacobs #include <fcntl.h>
88355b4669Sjacobs #include <errno.h>
89355b4669Sjacobs 
90355b4669Sjacobs #include "http.h"
91355b4669Sjacobs #include "debug.h"
92355b4669Sjacobs 
93355b4669Sjacobs #ifndef WIN32
94355b4669Sjacobs #  include <signal.h>
95355b4669Sjacobs #  include <sys/time.h>
96355b4669Sjacobs #  include <sys/resource.h>
97355b4669Sjacobs #endif /* !WIN32 */
98355b4669Sjacobs 
99355b4669Sjacobs 
100355b4669Sjacobs /*
101355b4669Sjacobs  * Some operating systems have done away with the Fxxxx constants for
102355b4669Sjacobs  * the fcntl() call; this works around that "feature"...
103355b4669Sjacobs  */
104355b4669Sjacobs 
105355b4669Sjacobs #ifndef FNONBLK
106355b4669Sjacobs #  define FNONBLK O_NONBLOCK
107355b4669Sjacobs #endif /* !FNONBLK */
108355b4669Sjacobs 
109355b4669Sjacobs 
110355b4669Sjacobs /*
111355b4669Sjacobs  * Local functions...
112355b4669Sjacobs  */
113355b4669Sjacobs 
114355b4669Sjacobs static http_field_t	http_field(const char *name);
115355b4669Sjacobs static int		http_send(http_t *http, http_state_t request,
116355b4669Sjacobs 			          const char *uri);
117355b4669Sjacobs static int		http_wait(http_t *http, int msec);
118355b4669Sjacobs #ifdef HAVE_SSL
119355b4669Sjacobs static int		http_upgrade(http_t *http);
120355b4669Sjacobs static int		http_setup_ssl(http_t *http);
121355b4669Sjacobs static void		http_shutdown_ssl(http_t *http);
122355b4669Sjacobs static int		http_read_ssl(http_t *http, char *buf, int len);
123355b4669Sjacobs static int		http_write_ssl(http_t *http, const char *buf, int len);
124355b4669Sjacobs #  ifdef HAVE_CDSASSL
125355b4669Sjacobs static OSStatus		CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength);
126355b4669Sjacobs static OSStatus		CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);
127355b4669Sjacobs #  endif /* HAVE_CDSASSL */
128355b4669Sjacobs #endif /* HAVE_SSL */
129355b4669Sjacobs 
130355b4669Sjacobs 
131355b4669Sjacobs /*
132355b4669Sjacobs  * Local globals...
133355b4669Sjacobs  */
134355b4669Sjacobs 
135355b4669Sjacobs static const char * const http_fields[] =
136355b4669Sjacobs 			{
137355b4669Sjacobs 			  "Accept-Language",
138355b4669Sjacobs 			  "Accept-Ranges",
139355b4669Sjacobs 			  "Authorization",
140355b4669Sjacobs 			  "Connection",
141355b4669Sjacobs 			  "Content-Encoding",
142355b4669Sjacobs 			  "Content-Language",
143355b4669Sjacobs 			  "Content-Length",
144355b4669Sjacobs 			  "Content-Location",
145355b4669Sjacobs 			  "Content-MD5",
146355b4669Sjacobs 			  "Content-Range",
147355b4669Sjacobs 			  "Content-Type",
148355b4669Sjacobs 			  "Content-Version",
149355b4669Sjacobs 			  "Date",
150355b4669Sjacobs 			  "Host",
151355b4669Sjacobs 			  "If-Modified-Since",
152355b4669Sjacobs 			  "If-Unmodified-since",
153355b4669Sjacobs 			  "Keep-Alive",
154355b4669Sjacobs 			  "Last-Modified",
155355b4669Sjacobs 			  "Link",
156355b4669Sjacobs 			  "Location",
157355b4669Sjacobs 			  "Range",
158355b4669Sjacobs 			  "Referer",
159355b4669Sjacobs 			  "Retry-After",
160355b4669Sjacobs 			  "Transfer-Encoding",
161355b4669Sjacobs 			  "Upgrade",
162355b4669Sjacobs 			  "User-Agent",
163355b4669Sjacobs 			  "WWW-Authenticate"
164355b4669Sjacobs 			};
165355b4669Sjacobs static const char * const days[7] =
166355b4669Sjacobs 			{
167355b4669Sjacobs 			  "Sun",
168355b4669Sjacobs 			  "Mon",
169355b4669Sjacobs 			  "Tue",
170355b4669Sjacobs 			  "Wed",
171355b4669Sjacobs 			  "Thu",
172355b4669Sjacobs 			  "Fri",
173355b4669Sjacobs 			  "Sat"
174355b4669Sjacobs 			};
175355b4669Sjacobs static const char * const months[12] =
176355b4669Sjacobs 			{
177355b4669Sjacobs 			  "Jan",
178355b4669Sjacobs 			  "Feb",
179355b4669Sjacobs 			  "Mar",
180355b4669Sjacobs 			  "Apr",
181355b4669Sjacobs 			  "May",
182355b4669Sjacobs 			  "Jun",
183355b4669Sjacobs 		          "Jul",
184355b4669Sjacobs 			  "Aug",
185355b4669Sjacobs 			  "Sep",
186355b4669Sjacobs 			  "Oct",
187355b4669Sjacobs 			  "Nov",
188355b4669Sjacobs 			  "Dec"
189355b4669Sjacobs 			};
190355b4669Sjacobs 
191355b4669Sjacobs void
httpDumpData(FILE * fp,const char * tag,const char * buffer,int bytes)1920a44ef6dSjacobs httpDumpData(FILE *fp, const char *tag, const char *buffer, int bytes)
193355b4669Sjacobs {
194355b4669Sjacobs         int i, j, ch;
195355b4669Sjacobs 
196355b4669Sjacobs 	fprintf(fp, "%s %d(0x%x) bytes...\n", tag, bytes, bytes);
197355b4669Sjacobs         for (i = 0; i < bytes; i += 16) {
198355b4669Sjacobs                 fprintf(fp, "%s   ", (tag ? tag : ""));
199355b4669Sjacobs 
200355b4669Sjacobs                 for (j = 0; j < 16 && (i + j) < bytes; j ++)
201355b4669Sjacobs                         fprintf(fp, " %02X", buffer[i + j] & 255);
202355b4669Sjacobs 
203355b4669Sjacobs                 while (j < 16) {
204355b4669Sjacobs                         fprintf(fp, "   ");
205355b4669Sjacobs                         j++;
206355b4669Sjacobs                 }
207355b4669Sjacobs 
208355b4669Sjacobs                 fprintf(fp, "    ");
209355b4669Sjacobs                 for (j = 0; j < 16 && (i + j) < bytes; j ++) {
210355b4669Sjacobs                         ch = buffer[i + j] & 255;
211355b4669Sjacobs                         if (ch < ' ' || ch == 127)
212355b4669Sjacobs                                 ch = '.';
213355b4669Sjacobs                         putc(ch, fp);
214355b4669Sjacobs                 }
215355b4669Sjacobs                 putc('\n', fp);
216355b4669Sjacobs         }
217355b4669Sjacobs }
218355b4669Sjacobs 
219355b4669Sjacobs 
220355b4669Sjacobs /*
221355b4669Sjacobs  * 'httpInitialize()' - Initialize the HTTP interface library and set the
222355b4669Sjacobs  *                      default HTTP proxy (if any).
223355b4669Sjacobs  */
224355b4669Sjacobs 
225355b4669Sjacobs void
httpInitialize(void)226355b4669Sjacobs httpInitialize(void)
227355b4669Sjacobs {
228355b4669Sjacobs #ifdef HAVE_LIBSSL
229355b4669Sjacobs #  ifndef WIN32
230355b4669Sjacobs   struct timeval	curtime;	/* Current time in microseconds */
231355b4669Sjacobs #  endif /* !WIN32 */
232355b4669Sjacobs   int			i;		/* Looping var */
233355b4669Sjacobs   unsigned char		data[1024];	/* Seed data */
234355b4669Sjacobs #endif /* HAVE_LIBSSL */
235355b4669Sjacobs 
236355b4669Sjacobs #ifdef WIN32
237355b4669Sjacobs   WSADATA	winsockdata;		/* WinSock data */
238355b4669Sjacobs   static int	initialized = 0;	/* Has WinSock been initialized? */
239355b4669Sjacobs 
240355b4669Sjacobs 
241355b4669Sjacobs   if (!initialized)
242355b4669Sjacobs     WSAStartup(MAKEWORD(1,1), &winsockdata);
243355b4669Sjacobs #elif defined(HAVE_SIGSET)
244355b4669Sjacobs   sigset(SIGPIPE, SIG_IGN);
245355b4669Sjacobs #elif defined(HAVE_SIGACTION)
246355b4669Sjacobs   struct sigaction	action;		/* POSIX sigaction data */
247355b4669Sjacobs 
248355b4669Sjacobs 
249355b4669Sjacobs  /*
250355b4669Sjacobs   * Ignore SIGPIPE signals...
251355b4669Sjacobs   */
252355b4669Sjacobs 
253355b4669Sjacobs   memset(&action, 0, sizeof(action));
254355b4669Sjacobs   action.sa_handler = SIG_IGN;
255355b4669Sjacobs   sigaction(SIGPIPE, &action, NULL);
256355b4669Sjacobs #else
257355b4669Sjacobs   signal(SIGPIPE, SIG_IGN);
258355b4669Sjacobs #endif /* WIN32 */
259355b4669Sjacobs 
260355b4669Sjacobs #ifdef HAVE_GNUTLS
261355b4669Sjacobs   gnutls_global_init();
262355b4669Sjacobs #endif /* HAVE_GNUTLS */
263355b4669Sjacobs 
264355b4669Sjacobs #ifdef HAVE_LIBSSL
265355b4669Sjacobs   SSL_load_error_strings();
266355b4669Sjacobs   SSL_library_init();
267355b4669Sjacobs 
268355b4669Sjacobs  /*
269355b4669Sjacobs   * Using the current time is a dubious random seed, but on some systems
270355b4669Sjacobs   * it is the best we can do (on others, this seed isn't even used...)
271355b4669Sjacobs   */
272355b4669Sjacobs 
273355b4669Sjacobs #ifdef WIN32
274355b4669Sjacobs #else
275355b4669Sjacobs   gettimeofday(&curtime, NULL);
276355b4669Sjacobs   srand(curtime.tv_sec + curtime.tv_usec);
277355b4669Sjacobs #endif /* WIN32 */
278355b4669Sjacobs 
279355b4669Sjacobs   for (i = 0; i < sizeof(data); i ++)
280355b4669Sjacobs     data[i] = rand(); /* Yes, this is a poor source of random data... */
281355b4669Sjacobs 
282355b4669Sjacobs   RAND_seed(&data, sizeof(data));
283355b4669Sjacobs #endif /* HAVE_LIBSSL */
284355b4669Sjacobs }
285355b4669Sjacobs 
286355b4669Sjacobs 
287355b4669Sjacobs /*
288355b4669Sjacobs  * 'httpCheck()' - Check to see if there is a pending response from the server.
289355b4669Sjacobs  */
290355b4669Sjacobs 
291355b4669Sjacobs int				/* O - 0 = no data, 1 = data available */
httpCheck(http_t * http)292355b4669Sjacobs httpCheck(http_t *http)		/* I - HTTP connection */
293355b4669Sjacobs {
294355b4669Sjacobs   return (httpWait(http, 0));
295355b4669Sjacobs }
296355b4669Sjacobs 
297355b4669Sjacobs 
298355b4669Sjacobs /*
299355b4669Sjacobs  * 'httpClearCookie()' - Clear the cookie value(s).
300355b4669Sjacobs  */
301355b4669Sjacobs 
302355b4669Sjacobs void
httpClearCookie(http_t * http)303355b4669Sjacobs httpClearCookie(http_t *http)			/* I - Connection */
304355b4669Sjacobs {
305355b4669Sjacobs   if (!http)
306355b4669Sjacobs     return;
307355b4669Sjacobs 
308355b4669Sjacobs   if (http->cookie)
309355b4669Sjacobs   {
310355b4669Sjacobs     free(http->cookie);
311355b4669Sjacobs     http->cookie = NULL;
312355b4669Sjacobs   }
313355b4669Sjacobs }
314355b4669Sjacobs 
315355b4669Sjacobs 
316355b4669Sjacobs /*
317355b4669Sjacobs  * 'httpClose()' - Close an HTTP connection...
318355b4669Sjacobs  */
319355b4669Sjacobs 
320355b4669Sjacobs void
httpClose(http_t * http)321355b4669Sjacobs httpClose(http_t *http)		/* I - Connection to close */
322355b4669Sjacobs {
323355b4669Sjacobs   DEBUG_printf(("httpClose(http=%p)\n", http));
324355b4669Sjacobs 
325355b4669Sjacobs   if (!http)
326355b4669Sjacobs     return;
327355b4669Sjacobs 
328355b4669Sjacobs   if (http->input_set)
329355b4669Sjacobs     free(http->input_set);
330355b4669Sjacobs 
331355b4669Sjacobs   if (http->cookie)
332355b4669Sjacobs     free(http->cookie);
333355b4669Sjacobs 
334355b4669Sjacobs #ifdef HAVE_SSL
335355b4669Sjacobs   if (http->tls)
336355b4669Sjacobs     http_shutdown_ssl(http);
337355b4669Sjacobs #endif /* HAVE_SSL */
338355b4669Sjacobs 
339355b4669Sjacobs #ifdef WIN32
340355b4669Sjacobs   closesocket(http->fd);
341355b4669Sjacobs #else
342355b4669Sjacobs   close(http->fd);
343355b4669Sjacobs #endif /* WIN32 */
344355b4669Sjacobs 
345355b4669Sjacobs   free(http);
346355b4669Sjacobs }
347355b4669Sjacobs 
348355b4669Sjacobs 
349355b4669Sjacobs /*
350355b4669Sjacobs  * 'httpConnect()' - Connect to a HTTP server.
351355b4669Sjacobs  */
352355b4669Sjacobs 
353355b4669Sjacobs http_t *				/* O - New HTTP connection */
httpConnect(const char * host,int port)354355b4669Sjacobs httpConnect(const char *host,		/* I - Host to connect to */
355355b4669Sjacobs             int        port)		/* I - Port number */
356355b4669Sjacobs {
357355b4669Sjacobs   http_encryption_t	encrypt;	/* Type of encryption to use */
358355b4669Sjacobs 
359355b4669Sjacobs 
360355b4669Sjacobs  /*
361355b4669Sjacobs   * Set the default encryption status...
362355b4669Sjacobs   */
363355b4669Sjacobs 
364355b4669Sjacobs   if (port == 443)
365355b4669Sjacobs     encrypt = HTTP_ENCRYPT_ALWAYS;
366355b4669Sjacobs   else
367355b4669Sjacobs     encrypt = HTTP_ENCRYPT_IF_REQUESTED;
368355b4669Sjacobs 
369355b4669Sjacobs   return (httpConnectEncrypt(host, port, encrypt));
370355b4669Sjacobs }
371355b4669Sjacobs 
372355b4669Sjacobs 
373355b4669Sjacobs /*
374355b4669Sjacobs  * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
375355b4669Sjacobs  */
376355b4669Sjacobs 
377355b4669Sjacobs http_t *				/* O - New HTTP connection */
httpConnectEncrypt(const char * host,int port,http_encryption_t encrypt)378355b4669Sjacobs httpConnectEncrypt(const char *host,	/* I - Host to connect to */
379355b4669Sjacobs                    int        port,	/* I - Port number */
380355b4669Sjacobs 		   http_encryption_t encrypt)
381355b4669Sjacobs 					/* I - Type of encryption to use */
382355b4669Sjacobs {
383355b4669Sjacobs   int			i;		/* Looping var */
384355b4669Sjacobs   http_t		*http;		/* New HTTP connection */
385355b4669Sjacobs   struct hostent	*hostaddr;	/* Host address data */
386355b4669Sjacobs 
387355b4669Sjacobs 
388355b4669Sjacobs   DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encrypt=%d)\n",
389355b4669Sjacobs                 host ? host : "(null)", port, encrypt));
390355b4669Sjacobs 
391355b4669Sjacobs   if (!host)
392355b4669Sjacobs     return (NULL);
393355b4669Sjacobs 
394355b4669Sjacobs   httpInitialize();
395355b4669Sjacobs 
396355b4669Sjacobs  /*
397355b4669Sjacobs   * Lookup the host...
398355b4669Sjacobs   */
399355b4669Sjacobs 
400355b4669Sjacobs   if ((hostaddr = httpGetHostByName(host)) == NULL)
401355b4669Sjacobs   {
402355b4669Sjacobs    /*
403355b4669Sjacobs     * This hack to make users that don't have a localhost entry in
404355b4669Sjacobs     * their hosts file or DNS happy...
405355b4669Sjacobs     */
406355b4669Sjacobs 
407355b4669Sjacobs     if (strcasecmp(host, "localhost") != 0)
408355b4669Sjacobs       return (NULL);
409355b4669Sjacobs     else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL)
410355b4669Sjacobs       return (NULL);
411355b4669Sjacobs   }
412355b4669Sjacobs 
413355b4669Sjacobs  /*
414355b4669Sjacobs   * Verify that it is an IPv4, IPv6, or domain address...
415355b4669Sjacobs   */
416355b4669Sjacobs 
417355b4669Sjacobs   if ((hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4)
418355b4669Sjacobs #ifdef AF_INET6
419355b4669Sjacobs       && (hostaddr->h_addrtype != AF_INET6 || hostaddr->h_length != 16)
420355b4669Sjacobs #endif /* AF_INET6 */
421355b4669Sjacobs #ifdef AF_LOCAL
422355b4669Sjacobs       && (hostaddr->h_addrtype != AF_LOCAL)
423355b4669Sjacobs #endif /* AF_LOCAL */
424355b4669Sjacobs       )
425355b4669Sjacobs     return (NULL);
426355b4669Sjacobs 
427355b4669Sjacobs  /*
428355b4669Sjacobs   * Allocate memory for the structure...
429355b4669Sjacobs   */
430355b4669Sjacobs 
431355b4669Sjacobs   http = calloc(sizeof(http_t), 1);
432355b4669Sjacobs   if (http == NULL)
433355b4669Sjacobs     return (NULL);
434355b4669Sjacobs 
435355b4669Sjacobs   http->version  = HTTP_1_1;
436355b4669Sjacobs   http->blocking = 1;
437355b4669Sjacobs   http->activity = time(NULL);
438355b4669Sjacobs   http->fd       = -1;
439355b4669Sjacobs 
440355b4669Sjacobs  /*
441355b4669Sjacobs   * Set the encryption status...
442355b4669Sjacobs   */
443355b4669Sjacobs 
444355b4669Sjacobs   if (port == 443)			/* Always use encryption for https */
445355b4669Sjacobs     http->encryption = HTTP_ENCRYPT_ALWAYS;
446355b4669Sjacobs   else
447355b4669Sjacobs     http->encryption = encrypt;
448355b4669Sjacobs 
449355b4669Sjacobs  /*
450355b4669Sjacobs   * Loop through the addresses we have until one of them connects...
451355b4669Sjacobs   */
452355b4669Sjacobs 
453355b4669Sjacobs   strlcpy(http->hostname, host, sizeof(http->hostname));
454355b4669Sjacobs 
455355b4669Sjacobs   for (i = 0; hostaddr->h_addr_list[i]; i ++)
456355b4669Sjacobs   {
457355b4669Sjacobs    /*
458355b4669Sjacobs     * Load the address...
459355b4669Sjacobs     */
460355b4669Sjacobs 
461355b4669Sjacobs     httpAddrLoad(hostaddr, port, i, &(http->hostaddr));
462355b4669Sjacobs 
463355b4669Sjacobs    /*
464355b4669Sjacobs     * Connect to the remote system...
465355b4669Sjacobs     */
466355b4669Sjacobs 
467355b4669Sjacobs     if (!httpReconnect(http))
468355b4669Sjacobs       return (http);
469355b4669Sjacobs   }
470355b4669Sjacobs 
471355b4669Sjacobs  /*
472355b4669Sjacobs   * Could not connect to any known address - bail out!
473355b4669Sjacobs   */
474355b4669Sjacobs 
475355b4669Sjacobs   free(http);
476355b4669Sjacobs   return (NULL);
477355b4669Sjacobs }
478355b4669Sjacobs 
479355b4669Sjacobs 
480355b4669Sjacobs /*
481355b4669Sjacobs  * 'httpEncryption()' - Set the required encryption on the link.
482355b4669Sjacobs  */
483355b4669Sjacobs 
484355b4669Sjacobs int					/* O - -1 on error, 0 on success */
httpEncryption(http_t * http,http_encryption_t e)485355b4669Sjacobs httpEncryption(http_t            *http,	/* I - HTTP data */
486355b4669Sjacobs                http_encryption_t e)	/* I - New encryption preference */
487355b4669Sjacobs {
488355b4669Sjacobs   DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e));
489355b4669Sjacobs 
490355b4669Sjacobs #ifdef HAVE_SSL
491355b4669Sjacobs   if (!http)
492355b4669Sjacobs     return (0);
493355b4669Sjacobs 
494355b4669Sjacobs   http->encryption = e;
495355b4669Sjacobs 
496355b4669Sjacobs   if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) ||
497355b4669Sjacobs       (http->encryption == HTTP_ENCRYPT_NEVER && http->tls))
498355b4669Sjacobs     return (httpReconnect(http));
499355b4669Sjacobs   else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
500355b4669Sjacobs     return (http_upgrade(http));
501355b4669Sjacobs   else
502355b4669Sjacobs     return (0);
503355b4669Sjacobs #else
504355b4669Sjacobs   if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED)
505355b4669Sjacobs     return (-1);
506355b4669Sjacobs   else
507355b4669Sjacobs     return (0);
508355b4669Sjacobs #endif /* HAVE_SSL */
509355b4669Sjacobs }
510355b4669Sjacobs 
511355b4669Sjacobs 
512355b4669Sjacobs /*
513355b4669Sjacobs  * 'httpReconnect()' - Reconnect to a HTTP server...
514355b4669Sjacobs  */
515355b4669Sjacobs 
516355b4669Sjacobs int					/* O - 0 on success, non-zero on failure */
httpReconnect(http_t * http)517355b4669Sjacobs httpReconnect(http_t *http)		/* I - HTTP data */
518355b4669Sjacobs {
519355b4669Sjacobs   int		val;			/* Socket option value */
520355b4669Sjacobs   int		status;			/* Connect status */
521355b4669Sjacobs 
522355b4669Sjacobs 
523355b4669Sjacobs   DEBUG_printf(("httpReconnect(http=%p)\n", http));
524355b4669Sjacobs 
525355b4669Sjacobs   if (!http)
526355b4669Sjacobs     return (-1);
527355b4669Sjacobs 
528355b4669Sjacobs #ifdef HAVE_SSL
529355b4669Sjacobs   if (http->tls)
530355b4669Sjacobs     http_shutdown_ssl(http);
531355b4669Sjacobs #endif /* HAVE_SSL */
532355b4669Sjacobs 
533355b4669Sjacobs  /*
534355b4669Sjacobs   * Close any previously open socket...
535355b4669Sjacobs   */
536355b4669Sjacobs 
537355b4669Sjacobs   if (http->fd >= 0)
538355b4669Sjacobs #ifdef WIN32
539355b4669Sjacobs     closesocket(http->fd);
540355b4669Sjacobs #else
541355b4669Sjacobs     close(http->fd);
542355b4669Sjacobs #endif /* WIN32 */
543355b4669Sjacobs 
544355b4669Sjacobs  /*
545355b4669Sjacobs   * Create the socket and set options to allow reuse.
546355b4669Sjacobs   */
547355b4669Sjacobs 
548355b4669Sjacobs   if ((http->fd = socket(http->hostaddr.addr.sa_family, SOCK_STREAM, 0)) < 0)
549355b4669Sjacobs   {
550355b4669Sjacobs #ifdef WIN32
551355b4669Sjacobs     http->error  = WSAGetLastError();
552355b4669Sjacobs #else
553355b4669Sjacobs     http->error  = errno;
554355b4669Sjacobs #endif /* WIN32 */
555355b4669Sjacobs     http->status = HTTP_ERROR;
556355b4669Sjacobs     return (-1);
557355b4669Sjacobs   }
558355b4669Sjacobs 
559355b4669Sjacobs #ifdef FD_CLOEXEC
560355b4669Sjacobs   fcntl(http->fd, F_SETFD, FD_CLOEXEC);	/* Close this socket when starting *
561355b4669Sjacobs 					 * other processes...              */
562355b4669Sjacobs #endif /* FD_CLOEXEC */
563355b4669Sjacobs 
564355b4669Sjacobs   val = 1;
565355b4669Sjacobs   setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
566355b4669Sjacobs 
567355b4669Sjacobs #ifdef SO_REUSEPORT
568355b4669Sjacobs   val = 1;
569355b4669Sjacobs   setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
570355b4669Sjacobs #endif /* SO_REUSEPORT */
571355b4669Sjacobs 
572355b4669Sjacobs  /*
573355b4669Sjacobs   * Using TCP_NODELAY improves responsiveness, especially on systems
574355b4669Sjacobs   * with a slow loopback interface...  Since we write large buffers
575355b4669Sjacobs   * when sending print files and requests, there shouldn't be any
576355b4669Sjacobs   * performance penalty for this...
577355b4669Sjacobs   */
578355b4669Sjacobs 
579355b4669Sjacobs   val = 1;
580355b4669Sjacobs #ifdef WIN32
581*1da57d55SToomas Soome   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
582355b4669Sjacobs #else
583*1da57d55SToomas Soome   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
584355b4669Sjacobs #endif /* WIN32 */
585355b4669Sjacobs 
586355b4669Sjacobs  /*
587355b4669Sjacobs   * Connect to the server...
588355b4669Sjacobs   */
589355b4669Sjacobs 
590355b4669Sjacobs #ifdef AF_INET6
591355b4669Sjacobs   if (http->hostaddr.addr.sa_family == AF_INET6)
592355b4669Sjacobs     status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
593355b4669Sjacobs                      sizeof(http->hostaddr.ipv6));
594355b4669Sjacobs   else
595355b4669Sjacobs #endif /* AF_INET6 */
596355b4669Sjacobs #ifdef AF_LOCAL
597355b4669Sjacobs   if (http->hostaddr.addr.sa_family == AF_LOCAL)
598355b4669Sjacobs     status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
599355b4669Sjacobs                      SUN_LEN(&(http->hostaddr.un)));
600355b4669Sjacobs   else
601355b4669Sjacobs #endif /* AF_LOCAL */
602355b4669Sjacobs   status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
603355b4669Sjacobs                    sizeof(http->hostaddr.ipv4));
604355b4669Sjacobs 
605355b4669Sjacobs   if (status < 0)
606355b4669Sjacobs   {
607355b4669Sjacobs #ifdef WIN32
608355b4669Sjacobs     http->error  = WSAGetLastError();
609355b4669Sjacobs #else
610355b4669Sjacobs     http->error  = errno;
611355b4669Sjacobs #endif /* WIN32 */
612355b4669Sjacobs     http->status = HTTP_ERROR;
613355b4669Sjacobs 
614355b4669Sjacobs #ifdef WIN32
615355b4669Sjacobs     closesocket(http->fd);
616355b4669Sjacobs #else
617355b4669Sjacobs     close(http->fd);
618355b4669Sjacobs #endif
619355b4669Sjacobs 
620355b4669Sjacobs     http->fd = -1;
621355b4669Sjacobs 
622355b4669Sjacobs     return (-1);
623355b4669Sjacobs   }
624355b4669Sjacobs 
625355b4669Sjacobs   http->error  = 0;
626355b4669Sjacobs   http->status = HTTP_CONTINUE;
627355b4669Sjacobs 
628355b4669Sjacobs #ifdef HAVE_SSL
629355b4669Sjacobs   if (http->encryption == HTTP_ENCRYPT_ALWAYS)
630355b4669Sjacobs   {
631355b4669Sjacobs    /*
632355b4669Sjacobs     * Always do encryption via SSL.
633355b4669Sjacobs     */
634355b4669Sjacobs 
635355b4669Sjacobs     if (http_setup_ssl(http) != 0)
636355b4669Sjacobs     {
637355b4669Sjacobs #ifdef WIN32
638355b4669Sjacobs       closesocket(http->fd);
639355b4669Sjacobs #else
640355b4669Sjacobs       close(http->fd);
641355b4669Sjacobs #endif /* WIN32 */
642355b4669Sjacobs 
643355b4669Sjacobs       return (-1);
644355b4669Sjacobs     }
645355b4669Sjacobs   }
646355b4669Sjacobs   else if (http->encryption == HTTP_ENCRYPT_REQUIRED)
647355b4669Sjacobs     return (http_upgrade(http));
648355b4669Sjacobs #endif /* HAVE_SSL */
649355b4669Sjacobs 
650355b4669Sjacobs   return (0);
651355b4669Sjacobs }
652355b4669Sjacobs 
653355b4669Sjacobs 
654355b4669Sjacobs /*
655355b4669Sjacobs  * 'httpGetSubField()' - Get a sub-field value.
656355b4669Sjacobs  */
657355b4669Sjacobs 
658355b4669Sjacobs char *					/* O - Value or NULL */
httpGetSubField(http_t * http,http_field_t field,const char * name,char * value)659355b4669Sjacobs httpGetSubField(http_t       *http,	/* I - HTTP data */
660355b4669Sjacobs                 http_field_t field,	/* I - Field index */
661355b4669Sjacobs                 const char   *name,	/* I - Name of sub-field */
662355b4669Sjacobs 		char         *value)	/* O - Value string */
663355b4669Sjacobs {
664355b4669Sjacobs   const char	*fptr;			/* Pointer into field */
665355b4669Sjacobs   char		temp[HTTP_MAX_VALUE],	/* Temporary buffer for name */
666355b4669Sjacobs 		*ptr;			/* Pointer into string buffer */
667355b4669Sjacobs 
668355b4669Sjacobs 
669355b4669Sjacobs   DEBUG_printf(("httpGetSubField(http=%p, field=%d, name=\"%s\", value=%p)\n",
670355b4669Sjacobs                 http, field, name, value));
671355b4669Sjacobs 
672355b4669Sjacobs   if (http == NULL ||
673355b4669Sjacobs       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
674355b4669Sjacobs       field > HTTP_FIELD_WWW_AUTHENTICATE ||
675355b4669Sjacobs       name == NULL || value == NULL)
676355b4669Sjacobs     return (NULL);
677355b4669Sjacobs 
678355b4669Sjacobs   for (fptr = http->fields[field]; *fptr;)
679355b4669Sjacobs   {
680355b4669Sjacobs    /*
681355b4669Sjacobs     * Skip leading whitespace...
682355b4669Sjacobs     */
683355b4669Sjacobs 
684355b4669Sjacobs     while (isspace(*fptr & 255))
685355b4669Sjacobs       fptr ++;
686355b4669Sjacobs 
687355b4669Sjacobs     if (*fptr == ',')
688355b4669Sjacobs     {
689355b4669Sjacobs       fptr ++;
690355b4669Sjacobs       continue;
691355b4669Sjacobs     }
692355b4669Sjacobs 
693355b4669Sjacobs    /*
694355b4669Sjacobs     * Get the sub-field name...
695355b4669Sjacobs     */
696355b4669Sjacobs 
697355b4669Sjacobs     for (ptr = temp;
698355b4669Sjacobs          *fptr && *fptr != '=' && !isspace(*fptr & 255) && ptr < (temp + sizeof(temp) - 1);
699355b4669Sjacobs          *ptr++ = *fptr++);
700355b4669Sjacobs 
701355b4669Sjacobs     *ptr = '\0';
702355b4669Sjacobs 
703355b4669Sjacobs     DEBUG_printf(("httpGetSubField: name=\"%s\"\n", temp));
704355b4669Sjacobs 
705355b4669Sjacobs    /*
706355b4669Sjacobs     * Skip trailing chars up to the '='...
707355b4669Sjacobs     */
708355b4669Sjacobs 
709355b4669Sjacobs     while (isspace(*fptr & 255))
710355b4669Sjacobs       fptr ++;
711355b4669Sjacobs 
712355b4669Sjacobs     if (!*fptr)
713355b4669Sjacobs       break;
714355b4669Sjacobs 
715355b4669Sjacobs     if (*fptr != '=')
716355b4669Sjacobs       continue;
717355b4669Sjacobs 
718355b4669Sjacobs    /*
719355b4669Sjacobs     * Skip = and leading whitespace...
720355b4669Sjacobs     */
721355b4669Sjacobs 
722355b4669Sjacobs     fptr ++;
723355b4669Sjacobs 
724355b4669Sjacobs     while (isspace(*fptr & 255))
725355b4669Sjacobs       fptr ++;
726355b4669Sjacobs 
727355b4669Sjacobs     if (*fptr == '\"')
728355b4669Sjacobs     {
729355b4669Sjacobs      /*
730355b4669Sjacobs       * Read quoted string...
731355b4669Sjacobs       */
732355b4669Sjacobs 
733355b4669Sjacobs       for (ptr = value, fptr ++;
734355b4669Sjacobs            *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1);
735355b4669Sjacobs 	   *ptr++ = *fptr++);
736355b4669Sjacobs 
737355b4669Sjacobs       *ptr = '\0';
738355b4669Sjacobs 
739355b4669Sjacobs       while (*fptr && *fptr != '\"')
740355b4669Sjacobs         fptr ++;
741355b4669Sjacobs 
742355b4669Sjacobs       if (*fptr)
743355b4669Sjacobs         fptr ++;
744355b4669Sjacobs     }
745355b4669Sjacobs     else
746355b4669Sjacobs     {
747355b4669Sjacobs      /*
748355b4669Sjacobs       * Read unquoted string...
749355b4669Sjacobs       */
750355b4669Sjacobs 
751355b4669Sjacobs       for (ptr = value;
752355b4669Sjacobs            *fptr && !isspace(*fptr & 255) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1);
753355b4669Sjacobs 	   *ptr++ = *fptr++);
754355b4669Sjacobs 
755355b4669Sjacobs       *ptr = '\0';
756355b4669Sjacobs 
757355b4669Sjacobs       while (*fptr && !isspace(*fptr & 255) && *fptr != ',')
758355b4669Sjacobs         fptr ++;
759355b4669Sjacobs     }
760355b4669Sjacobs 
761355b4669Sjacobs     DEBUG_printf(("httpGetSubField: value=\"%s\"\n", value));
762355b4669Sjacobs 
763355b4669Sjacobs    /*
764355b4669Sjacobs     * See if this is the one...
765355b4669Sjacobs     */
766355b4669Sjacobs 
767355b4669Sjacobs     if (strcmp(name, temp) == 0)
768355b4669Sjacobs       return (value);
769355b4669Sjacobs   }
770355b4669Sjacobs 
771355b4669Sjacobs   value[0] = '\0';
772355b4669Sjacobs 
773355b4669Sjacobs   return (NULL);
774355b4669Sjacobs }
775355b4669Sjacobs 
776355b4669Sjacobs 
777355b4669Sjacobs /*
778355b4669Sjacobs  * 'httpSetField()' - Set the value of an HTTP header.
779355b4669Sjacobs  */
780355b4669Sjacobs 
781355b4669Sjacobs void
httpSetField(http_t * http,http_field_t field,const char * value)782355b4669Sjacobs httpSetField(http_t       *http,	/* I - HTTP data */
783355b4669Sjacobs              http_field_t field,	/* I - Field index */
784355b4669Sjacobs 	     const char   *value)	/* I - Value */
785355b4669Sjacobs {
786355b4669Sjacobs   if (http == NULL ||
787355b4669Sjacobs       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
788355b4669Sjacobs       field > HTTP_FIELD_WWW_AUTHENTICATE ||
789355b4669Sjacobs       value == NULL)
790355b4669Sjacobs     return;
791355b4669Sjacobs 
792355b4669Sjacobs   strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
793355b4669Sjacobs }
794355b4669Sjacobs 
795355b4669Sjacobs 
796355b4669Sjacobs /*
797355b4669Sjacobs  * 'httpDelete()' - Send a DELETE request to the server.
798355b4669Sjacobs  */
799355b4669Sjacobs 
800355b4669Sjacobs int					/* O - Status of call (0 = success) */
httpDelete(http_t * http,const char * uri)801355b4669Sjacobs httpDelete(http_t     *http,		/* I - HTTP data */
802355b4669Sjacobs            const char *uri)		/* I - URI to delete */
803355b4669Sjacobs {
804355b4669Sjacobs   return (http_send(http, HTTP_DELETE, uri));
805355b4669Sjacobs }
806355b4669Sjacobs 
807355b4669Sjacobs 
808355b4669Sjacobs /*
809355b4669Sjacobs  * 'httpGet()' - Send a GET request to the server.
810355b4669Sjacobs  */
811355b4669Sjacobs 
812355b4669Sjacobs int					/* O - Status of call (0 = success) */
httpGet(http_t * http,const char * uri)813355b4669Sjacobs httpGet(http_t     *http,		/* I - HTTP data */
814355b4669Sjacobs         const char *uri)		/* I - URI to get */
815355b4669Sjacobs {
816355b4669Sjacobs   return (http_send(http, HTTP_GET, uri));
817355b4669Sjacobs }
818355b4669Sjacobs 
819355b4669Sjacobs 
820355b4669Sjacobs /*
821355b4669Sjacobs  * 'httpHead()' - Send a HEAD request to the server.
822355b4669Sjacobs  */
823355b4669Sjacobs 
824355b4669Sjacobs int					/* O - Status of call (0 = success) */
httpHead(http_t * http,const char * uri)825355b4669Sjacobs httpHead(http_t     *http,		/* I - HTTP data */
826355b4669Sjacobs          const char *uri)		/* I - URI for head */
827355b4669Sjacobs {
828355b4669Sjacobs   return (http_send(http, HTTP_HEAD, uri));
829355b4669Sjacobs }
830355b4669Sjacobs 
831355b4669Sjacobs 
832355b4669Sjacobs /*
833355b4669Sjacobs  * 'httpOptions()' - Send an OPTIONS request to the server.
834355b4669Sjacobs  */
835355b4669Sjacobs 
836355b4669Sjacobs int					/* O - Status of call (0 = success) */
httpOptions(http_t * http,const char * uri)837355b4669Sjacobs httpOptions(http_t     *http,		/* I - HTTP data */
838355b4669Sjacobs             const char *uri)		/* I - URI for options */
839355b4669Sjacobs {
840355b4669Sjacobs   return (http_send(http, HTTP_OPTIONS, uri));
841355b4669Sjacobs }
842355b4669Sjacobs 
843355b4669Sjacobs 
844355b4669Sjacobs /*
845355b4669Sjacobs  * 'httpPost()' - Send a POST request to the server.
846355b4669Sjacobs  */
847355b4669Sjacobs 
848355b4669Sjacobs int					/* O - Status of call (0 = success) */
httpPost(http_t * http,const char * uri)849355b4669Sjacobs httpPost(http_t     *http,		/* I - HTTP data */
850355b4669Sjacobs          const char *uri)		/* I - URI for post */
851355b4669Sjacobs {
852355b4669Sjacobs   httpGetLength(http);
853355b4669Sjacobs 
854355b4669Sjacobs   return (http_send(http, HTTP_POST, uri));
855355b4669Sjacobs }
856355b4669Sjacobs 
857355b4669Sjacobs 
858355b4669Sjacobs /*
859355b4669Sjacobs  * 'httpPut()' - Send a PUT request to the server.
860355b4669Sjacobs  */
861355b4669Sjacobs 
862355b4669Sjacobs int					/* O - Status of call (0 = success) */
httpPut(http_t * http,const char * uri)863355b4669Sjacobs httpPut(http_t     *http,		/* I - HTTP data */
864355b4669Sjacobs         const char *uri)		/* I - URI to put */
865355b4669Sjacobs {
866355b4669Sjacobs   httpGetLength(http);
867355b4669Sjacobs 
868355b4669Sjacobs   return (http_send(http, HTTP_PUT, uri));
869355b4669Sjacobs }
870355b4669Sjacobs 
871355b4669Sjacobs 
872355b4669Sjacobs /*
873355b4669Sjacobs  * 'httpTrace()' - Send an TRACE request to the server.
874355b4669Sjacobs  */
875355b4669Sjacobs 
876355b4669Sjacobs int					/* O - Status of call (0 = success) */
httpTrace(http_t * http,const char * uri)877355b4669Sjacobs httpTrace(http_t     *http,		/* I - HTTP data */
878355b4669Sjacobs           const char *uri)		/* I - URI for trace */
879355b4669Sjacobs {
880355b4669Sjacobs   return (http_send(http, HTTP_TRACE, uri));
881355b4669Sjacobs }
882355b4669Sjacobs 
883355b4669Sjacobs 
884355b4669Sjacobs /*
885355b4669Sjacobs  * 'httpFlush()' - Flush data from a HTTP connection.
886355b4669Sjacobs  */
887355b4669Sjacobs 
888355b4669Sjacobs void
httpFlush(http_t * http)889355b4669Sjacobs httpFlush(http_t *http)			/* I - HTTP data */
890355b4669Sjacobs {
891355b4669Sjacobs   char	buffer[8192];			/* Junk buffer */
892355b4669Sjacobs 
893355b4669Sjacobs 
894355b4669Sjacobs   DEBUG_printf(("httpFlush(http=%p), state=%d\n", http, http->state));
895355b4669Sjacobs 
896355b4669Sjacobs   while (httpRead(http, buffer, sizeof(buffer)) > 0);
897355b4669Sjacobs }
898355b4669Sjacobs 
899355b4669Sjacobs 
900355b4669Sjacobs /*
901355b4669Sjacobs  * 'httpRead()' - Read data from a HTTP connection.
902355b4669Sjacobs  */
903355b4669Sjacobs 
904355b4669Sjacobs int					/* O - Number of bytes read */
httpRead(http_t * http,char * buffer,int length)905355b4669Sjacobs httpRead(http_t *http,			/* I - HTTP data */
906355b4669Sjacobs          char   *buffer,		/* I - Buffer for data */
907355b4669Sjacobs 	 int    length)			/* I - Maximum number of bytes */
908355b4669Sjacobs {
909355b4669Sjacobs   int		bytes;			/* Bytes read */
910355b4669Sjacobs   char		len[32];		/* Length string */
911355b4669Sjacobs 
912355b4669Sjacobs 
913355b4669Sjacobs   DEBUG_printf(("httpRead(http=%p, buffer=%p, length=%d)\n",
914355b4669Sjacobs                 http, buffer, length));
915355b4669Sjacobs 
916355b4669Sjacobs   if (http == NULL || buffer == NULL)
917355b4669Sjacobs     return (-1);
918355b4669Sjacobs 
919355b4669Sjacobs   http->activity = time(NULL);
920355b4669Sjacobs 
921355b4669Sjacobs   if (length <= 0)
922355b4669Sjacobs     return (0);
923355b4669Sjacobs 
924355b4669Sjacobs   if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
925355b4669Sjacobs       http->data_remaining <= 0)
926355b4669Sjacobs   {
927355b4669Sjacobs     DEBUG_puts("httpRead: Getting chunk length...");
928355b4669Sjacobs 
929355b4669Sjacobs     if (httpGets(len, sizeof(len), http) == NULL)
930355b4669Sjacobs     {
931355b4669Sjacobs       DEBUG_puts("httpRead: Could not get length!");
932355b4669Sjacobs       return (0);
933355b4669Sjacobs     }
934355b4669Sjacobs 
935355b4669Sjacobs     http->data_remaining = strtol(len, NULL, 16);
936355b4669Sjacobs     if (http->data_remaining < 0)
937355b4669Sjacobs     {
938355b4669Sjacobs       DEBUG_puts("httpRead: Negative chunk length!");
939355b4669Sjacobs       return (0);
940355b4669Sjacobs     }
941355b4669Sjacobs   }
942355b4669Sjacobs 
943355b4669Sjacobs   DEBUG_printf(("httpRead: data_remaining=%d\n", http->data_remaining));
944355b4669Sjacobs 
945355b4669Sjacobs   if (http->data_remaining <= 0)
946355b4669Sjacobs   {
947355b4669Sjacobs    /*
948355b4669Sjacobs     * A zero-length chunk ends a transfer; unless we are reading POST
949355b4669Sjacobs     * data, go idle...
950355b4669Sjacobs     */
951355b4669Sjacobs 
952355b4669Sjacobs     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
953355b4669Sjacobs       httpGets(len, sizeof(len), http);
954355b4669Sjacobs 
955355b4669Sjacobs     if (http->state == HTTP_POST_RECV)
956355b4669Sjacobs       http->state ++;
957355b4669Sjacobs     else
958355b4669Sjacobs       http->state = HTTP_WAITING;
959355b4669Sjacobs 
960355b4669Sjacobs    /*
961355b4669Sjacobs     * Prevent future reads for this request...
962355b4669Sjacobs     */
963355b4669Sjacobs 
964355b4669Sjacobs     http->data_encoding = HTTP_ENCODE_LENGTH;
965355b4669Sjacobs 
966355b4669Sjacobs     return (0);
967355b4669Sjacobs   }
968355b4669Sjacobs   else if (length > http->data_remaining)
969355b4669Sjacobs     length = http->data_remaining;
970355b4669Sjacobs 
971355b4669Sjacobs   if (http->used == 0 && length <= 256)
972355b4669Sjacobs   {
973355b4669Sjacobs    /*
974355b4669Sjacobs     * Buffer small reads for better performance...
975355b4669Sjacobs     */
976355b4669Sjacobs 
977355b4669Sjacobs     if (!http->blocking && !httpWait(http, 1000))
978355b4669Sjacobs       return (0);
979355b4669Sjacobs 
980355b4669Sjacobs     if (http->data_remaining > sizeof(http->buffer))
981355b4669Sjacobs       bytes = sizeof(http->buffer);
982355b4669Sjacobs     else
983355b4669Sjacobs       bytes = http->data_remaining;
984355b4669Sjacobs 
985355b4669Sjacobs #ifdef HAVE_SSL
986355b4669Sjacobs     if (http->tls)
987355b4669Sjacobs       bytes = http_read_ssl(http, http->buffer, bytes);
988355b4669Sjacobs     else
989355b4669Sjacobs #endif /* HAVE_SSL */
990355b4669Sjacobs     {
991355b4669Sjacobs       DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
992355b4669Sjacobs                     bytes));
993355b4669Sjacobs 
994355b4669Sjacobs       bytes = recv(http->fd, http->buffer, bytes, 0);
995355b4669Sjacobs 
996355b4669Sjacobs       DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
997355b4669Sjacobs                     bytes));
998355b4669Sjacobs #ifdef DEBUG_HTTP
999355b4669Sjacobs     httpDumpData(stdout, "httpRead:", http->buffer, bytes);
1000355b4669Sjacobs #endif
1001355b4669Sjacobs     }
1002355b4669Sjacobs 
1003355b4669Sjacobs     if (bytes > 0)
1004355b4669Sjacobs       http->used = bytes;
1005355b4669Sjacobs     else if (bytes < 0)
1006355b4669Sjacobs     {
1007355b4669Sjacobs #ifdef WIN32
1008355b4669Sjacobs       http->error = WSAGetLastError();
1009355b4669Sjacobs       return (-1);
1010355b4669Sjacobs #else
1011355b4669Sjacobs       if (errno != EINTR)
1012355b4669Sjacobs       {
1013355b4669Sjacobs         http->error = errno;
1014355b4669Sjacobs         return (-1);
1015355b4669Sjacobs       }
1016355b4669Sjacobs #endif /* WIN32 */
1017355b4669Sjacobs     }
1018355b4669Sjacobs     else
1019355b4669Sjacobs     {
1020355b4669Sjacobs       http->error = EPIPE;
1021355b4669Sjacobs       return (0);
1022355b4669Sjacobs     }
1023355b4669Sjacobs   }
1024355b4669Sjacobs 
1025355b4669Sjacobs   if (http->used > 0)
1026355b4669Sjacobs   {
1027355b4669Sjacobs     if (length > http->used)
1028355b4669Sjacobs       length = http->used;
1029355b4669Sjacobs 
1030355b4669Sjacobs     bytes = length;
1031355b4669Sjacobs 
1032355b4669Sjacobs     DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
1033355b4669Sjacobs 
1034355b4669Sjacobs     memcpy(buffer, http->buffer, length);
1035355b4669Sjacobs     http->used -= length;
1036355b4669Sjacobs 
1037355b4669Sjacobs     if (http->used > 0)
1038355b4669Sjacobs       memmove(http->buffer, http->buffer + length, http->used);
1039355b4669Sjacobs   }
1040355b4669Sjacobs #ifdef HAVE_SSL
1041355b4669Sjacobs   else if (http->tls)
1042355b4669Sjacobs   {
1043355b4669Sjacobs     if (!http->blocking && !httpWait(http, 1000))
1044355b4669Sjacobs       return (0);
1045355b4669Sjacobs 
1046355b4669Sjacobs     bytes = http_read_ssl(http, buffer, length);
1047355b4669Sjacobs   }
1048355b4669Sjacobs #endif /* HAVE_SSL */
1049355b4669Sjacobs   else
1050355b4669Sjacobs   {
1051355b4669Sjacobs     if (!http->blocking && !httpWait(http, 1000))
1052355b4669Sjacobs       return (0);
1053355b4669Sjacobs 
1054355b4669Sjacobs     DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
1055355b4669Sjacobs 
1056355b4669Sjacobs     while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
1057355b4669Sjacobs       if (errno != EINTR)
1058355b4669Sjacobs         break;
1059355b4669Sjacobs     DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
1060355b4669Sjacobs   }
1061355b4669Sjacobs #ifdef DEBUG_HTTP
1062355b4669Sjacobs     httpDumpData(stdout, "httpRead:", buffer, bytes);
1063355b4669Sjacobs #endif
1064355b4669Sjacobs 
1065355b4669Sjacobs   if (bytes > 0)
1066355b4669Sjacobs     http->data_remaining -= bytes;
1067355b4669Sjacobs   else if (bytes < 0)
1068355b4669Sjacobs   {
1069355b4669Sjacobs #ifdef WIN32
1070355b4669Sjacobs     http->error = WSAGetLastError();
1071355b4669Sjacobs #else
1072355b4669Sjacobs     if (errno == EINTR)
1073355b4669Sjacobs       bytes = 0;
1074355b4669Sjacobs     else
1075355b4669Sjacobs       http->error = errno;
1076355b4669Sjacobs #endif /* WIN32 */
1077355b4669Sjacobs   }
1078355b4669Sjacobs   else
1079355b4669Sjacobs   {
1080355b4669Sjacobs     http->error = EPIPE;
1081355b4669Sjacobs     return (0);
1082355b4669Sjacobs   }
1083355b4669Sjacobs 
1084355b4669Sjacobs   if (http->data_remaining == 0)
1085355b4669Sjacobs   {
1086355b4669Sjacobs     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1087355b4669Sjacobs       httpGets(len, sizeof(len), http);
1088355b4669Sjacobs 
1089355b4669Sjacobs     if (http->data_encoding != HTTP_ENCODE_CHUNKED)
1090355b4669Sjacobs     {
1091355b4669Sjacobs       if (http->state == HTTP_POST_RECV)
1092355b4669Sjacobs 	http->state ++;
1093355b4669Sjacobs       else
1094355b4669Sjacobs 	http->state = HTTP_WAITING;
1095355b4669Sjacobs     }
1096355b4669Sjacobs   }
1097355b4669Sjacobs 
1098355b4669Sjacobs   return (bytes);
1099355b4669Sjacobs }
1100355b4669Sjacobs 
1101355b4669Sjacobs 
1102355b4669Sjacobs /*
1103355b4669Sjacobs  * 'httpSetCookie()' - Set the cookie value(s)...
1104355b4669Sjacobs  */
1105355b4669Sjacobs 
1106355b4669Sjacobs void
httpSetCookie(http_t * http,const char * cookie)1107355b4669Sjacobs httpSetCookie(http_t     *http,		/* I - Connection */
1108355b4669Sjacobs               const char *cookie)	/* I - Cookie string */
1109355b4669Sjacobs {
1110355b4669Sjacobs   if (!http)
1111355b4669Sjacobs     return;
1112355b4669Sjacobs 
1113355b4669Sjacobs   if (http->cookie)
1114355b4669Sjacobs     free(http->cookie);
1115355b4669Sjacobs 
1116355b4669Sjacobs   if (cookie)
1117355b4669Sjacobs     http->cookie = strdup(cookie);
1118355b4669Sjacobs   else
1119355b4669Sjacobs     http->cookie = NULL;
1120355b4669Sjacobs }
1121355b4669Sjacobs 
1122355b4669Sjacobs 
1123355b4669Sjacobs /*
1124355b4669Sjacobs  * 'httpWait()' - Wait for data available on a connection.
1125355b4669Sjacobs  */
1126355b4669Sjacobs 
1127355b4669Sjacobs int					/* O - 1 if data is available, 0 otherwise */
httpWait(http_t * http,int msec)1128355b4669Sjacobs httpWait(http_t *http,			/* I - HTTP data */
1129355b4669Sjacobs          int    msec)			/* I - Milliseconds to wait */
1130355b4669Sjacobs {
1131355b4669Sjacobs  /*
1132355b4669Sjacobs   * First see if there is data in the buffer...
1133355b4669Sjacobs   */
1134355b4669Sjacobs 
1135355b4669Sjacobs   if (http == NULL)
1136355b4669Sjacobs     return (0);
1137355b4669Sjacobs 
1138355b4669Sjacobs   if (http->used)
1139355b4669Sjacobs     return (1);
1140355b4669Sjacobs 
1141355b4669Sjacobs  /*
1142355b4669Sjacobs   * If not, check the SSL/TLS buffers and do a select() on the connection...
1143355b4669Sjacobs   */
1144355b4669Sjacobs 
1145355b4669Sjacobs   return (http_wait(http, msec));
1146355b4669Sjacobs }
1147355b4669Sjacobs 
1148355b4669Sjacobs 
1149355b4669Sjacobs /*
1150355b4669Sjacobs  * 'httpWrite()' - Write data to a HTTP connection.
1151355b4669Sjacobs  */
1152*1da57d55SToomas Soome 
1153355b4669Sjacobs int					/* O - Number of bytes written */
httpWrite(http_t * http,const char * buffer,int length)1154355b4669Sjacobs httpWrite(http_t     *http,		/* I - HTTP data */
1155355b4669Sjacobs           const char *buffer,		/* I - Buffer for data */
1156355b4669Sjacobs 	  int        length)		/* I - Number of bytes to write */
1157355b4669Sjacobs {
1158355b4669Sjacobs   int	tbytes,				/* Total bytes sent */
1159355b4669Sjacobs 	bytes;				/* Bytes sent */
1160355b4669Sjacobs 
1161355b4669Sjacobs 
1162355b4669Sjacobs   if (http == NULL || buffer == NULL)
1163355b4669Sjacobs     return (-1);
1164355b4669Sjacobs 
1165355b4669Sjacobs   http->activity = time(NULL);
1166355b4669Sjacobs 
1167355b4669Sjacobs   if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1168355b4669Sjacobs   {
1169355b4669Sjacobs     if (httpPrintf(http, "%x\r\n", length) < 0)
1170355b4669Sjacobs       return (-1);
1171355b4669Sjacobs 
1172355b4669Sjacobs     if (length == 0)
1173355b4669Sjacobs     {
1174355b4669Sjacobs      /*
1175355b4669Sjacobs       * A zero-length chunk ends a transfer; unless we are sending POST
1176355b4669Sjacobs       * or PUT data, go idle...
1177355b4669Sjacobs       */
1178355b4669Sjacobs 
1179355b4669Sjacobs       DEBUG_printf(("httpWrite: changing states from %d", http->state));
1180355b4669Sjacobs 
1181355b4669Sjacobs       if (http->state == HTTP_POST_RECV)
1182355b4669Sjacobs 	http->state ++;
1183355b4669Sjacobs       else if (http->state == HTTP_PUT_RECV)
1184355b4669Sjacobs         http->state = HTTP_STATUS;
1185355b4669Sjacobs       else
1186355b4669Sjacobs 	http->state = HTTP_WAITING;
1187355b4669Sjacobs       DEBUG_printf((" to %d\n", http->state));
1188355b4669Sjacobs 
1189355b4669Sjacobs       if (httpPrintf(http, "\r\n") < 0)
1190355b4669Sjacobs 	return (-1);
1191355b4669Sjacobs 
1192355b4669Sjacobs       return (0);
1193355b4669Sjacobs     }
1194355b4669Sjacobs   }
1195355b4669Sjacobs 
1196355b4669Sjacobs   tbytes = 0;
1197355b4669Sjacobs 
1198355b4669Sjacobs   while (length > 0)
1199355b4669Sjacobs   {
1200355b4669Sjacobs #ifdef HAVE_SSL
1201355b4669Sjacobs     if (http->tls)
1202355b4669Sjacobs       bytes = http_write_ssl(http, buffer, length);
1203355b4669Sjacobs     else
1204355b4669Sjacobs #endif /* HAVE_SSL */
1205355b4669Sjacobs     bytes = send(http->fd, buffer, length, 0);
1206355b4669Sjacobs 
1207355b4669Sjacobs #ifdef DEBUG_HTTP
1208355b4669Sjacobs   if (bytes >= 0)
1209355b4669Sjacobs   	httpDumpData(stdout, "httpWrite:", buffer, bytes);
1210355b4669Sjacobs #endif /* DEBUG */
1211355b4669Sjacobs 
1212355b4669Sjacobs 
1213355b4669Sjacobs     if (bytes < 0)
1214355b4669Sjacobs     {
1215355b4669Sjacobs #ifdef WIN32
1216355b4669Sjacobs       if (WSAGetLastError() != http->error)
1217355b4669Sjacobs       {
1218355b4669Sjacobs         http->error = WSAGetLastError();
1219355b4669Sjacobs 	continue;
1220355b4669Sjacobs       }
1221355b4669Sjacobs #else
1222355b4669Sjacobs       if (errno == EINTR)
1223355b4669Sjacobs         continue;
1224355b4669Sjacobs       else if (errno != http->error && errno != ECONNRESET)
1225355b4669Sjacobs       {
1226355b4669Sjacobs         http->error = errno;
1227355b4669Sjacobs 	continue;
1228355b4669Sjacobs       }
1229355b4669Sjacobs #endif /* WIN32 */
1230355b4669Sjacobs 
1231355b4669Sjacobs       DEBUG_puts("httpWrite: error writing data...\n");
1232355b4669Sjacobs 
1233355b4669Sjacobs       return (-1);
1234355b4669Sjacobs     }
1235355b4669Sjacobs 
1236355b4669Sjacobs     buffer += bytes;
1237355b4669Sjacobs     tbytes += bytes;
1238355b4669Sjacobs     length -= bytes;
1239355b4669Sjacobs     if (http->data_encoding == HTTP_ENCODE_LENGTH)
1240355b4669Sjacobs       http->data_remaining -= bytes;
1241355b4669Sjacobs   }
1242355b4669Sjacobs 
1243355b4669Sjacobs   if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1244355b4669Sjacobs     if (httpPrintf(http, "\r\n") < 0)
1245355b4669Sjacobs       return (-1);
1246355b4669Sjacobs 
1247355b4669Sjacobs   if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
1248355b4669Sjacobs   {
1249355b4669Sjacobs    /*
1250355b4669Sjacobs     * Finished with the transfer; unless we are sending POST or PUT
1251355b4669Sjacobs     * data, go idle...
1252355b4669Sjacobs     */
1253355b4669Sjacobs 
1254355b4669Sjacobs     DEBUG_printf(("httpWrite: changing states from %d", http->state));
1255355b4669Sjacobs 
1256355b4669Sjacobs     if (http->state == HTTP_POST_RECV)
1257355b4669Sjacobs       http->state ++;
1258355b4669Sjacobs     else if (http->state == HTTP_PUT_RECV)
1259355b4669Sjacobs       http->state = HTTP_STATUS;
1260355b4669Sjacobs     else
1261355b4669Sjacobs       http->state = HTTP_WAITING;
1262355b4669Sjacobs 
1263355b4669Sjacobs     DEBUG_printf((" to %d\n", http->state));
1264355b4669Sjacobs   }
1265355b4669Sjacobs 
1266355b4669Sjacobs   return (tbytes);
1267355b4669Sjacobs }
1268355b4669Sjacobs 
1269355b4669Sjacobs 
1270355b4669Sjacobs /*
1271355b4669Sjacobs  * 'httpGets()' - Get a line of text from a HTTP connection.
1272355b4669Sjacobs  */
1273355b4669Sjacobs 
1274355b4669Sjacobs char *					/* O - Line or NULL */
httpGets(char * line,int length,http_t * http)1275355b4669Sjacobs httpGets(char   *line,			/* I - Line to read into */
1276355b4669Sjacobs          int    length,			/* I - Max length of buffer */
1277355b4669Sjacobs 	 http_t *http)			/* I - HTTP data */
1278355b4669Sjacobs {
1279355b4669Sjacobs   char	*lineptr,			/* Pointer into line */
1280355b4669Sjacobs 	*bufptr,			/* Pointer into input buffer */
1281355b4669Sjacobs 	*bufend;			/* Pointer to end of buffer */
1282355b4669Sjacobs   int	bytes;				/* Number of bytes read */
1283355b4669Sjacobs 
1284355b4669Sjacobs 
1285355b4669Sjacobs   DEBUG_printf(("httpGets(line=%p, length=%d, http=%p)\n", line, length, http));
1286355b4669Sjacobs 
1287355b4669Sjacobs   if (http == NULL || line == NULL)
1288355b4669Sjacobs     return (NULL);
1289355b4669Sjacobs 
1290355b4669Sjacobs  /*
1291355b4669Sjacobs   * Pre-scan the buffer and see if there is a newline in there...
1292355b4669Sjacobs   */
1293355b4669Sjacobs 
1294355b4669Sjacobs #ifdef WIN32
1295355b4669Sjacobs   WSASetLastError(0);
1296355b4669Sjacobs #else
1297355b4669Sjacobs   errno = 0;
1298355b4669Sjacobs #endif /* WIN32 */
1299355b4669Sjacobs 
1300355b4669Sjacobs   do
1301355b4669Sjacobs   {
1302355b4669Sjacobs     bufptr  = http->buffer;
1303355b4669Sjacobs     bufend  = http->buffer + http->used;
1304355b4669Sjacobs 
1305355b4669Sjacobs     while (bufptr < bufend)
1306355b4669Sjacobs       if (*bufptr == 0x0a)
1307355b4669Sjacobs 	break;
1308355b4669Sjacobs       else
1309355b4669Sjacobs 	bufptr ++;
1310355b4669Sjacobs 
1311355b4669Sjacobs     if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER)
1312355b4669Sjacobs     {
1313355b4669Sjacobs      /*
1314355b4669Sjacobs       * No newline; see if there is more data to be read...
1315355b4669Sjacobs       */
1316355b4669Sjacobs 
1317355b4669Sjacobs       if (!http->blocking && !http_wait(http, 1000))
1318355b4669Sjacobs         return (NULL);
1319355b4669Sjacobs 
1320355b4669Sjacobs #ifdef HAVE_SSL
1321355b4669Sjacobs       if (http->tls)
1322355b4669Sjacobs 	bytes = http_read_ssl(http, bufend, HTTP_MAX_BUFFER - http->used);
1323355b4669Sjacobs       else
1324355b4669Sjacobs #endif /* HAVE_SSL */
1325355b4669Sjacobs         bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0);
1326355b4669Sjacobs 
1327355b4669Sjacobs       DEBUG_printf(("httpGets: read %d bytes...\n", bytes));
1328355b4669Sjacobs #ifdef DEBUG_HTTP
1329355b4669Sjacobs       httpDumpData(stdout, "httpGets:", bufend, bytes);
1330355b4669Sjacobs #endif
1331355b4669Sjacobs 
1332355b4669Sjacobs       if (bytes < 0)
1333355b4669Sjacobs       {
1334355b4669Sjacobs        /*
1335355b4669Sjacobs 	* Nope, can't get a line this time...
1336355b4669Sjacobs 	*/
1337355b4669Sjacobs 
1338355b4669Sjacobs #ifdef WIN32
1339355b4669Sjacobs         if (WSAGetLastError() != http->error)
1340355b4669Sjacobs 	{
1341355b4669Sjacobs 	  http->error = WSAGetLastError();
1342355b4669Sjacobs 	  continue;
1343355b4669Sjacobs 	}
1344355b4669Sjacobs 
1345355b4669Sjacobs         DEBUG_printf(("httpGets: recv() error %d!\n", WSAGetLastError()));
1346355b4669Sjacobs #else
1347355b4669Sjacobs         DEBUG_printf(("httpGets: recv() error %d!\n", errno));
1348355b4669Sjacobs 
1349355b4669Sjacobs         if (errno == EINTR)
1350355b4669Sjacobs 	  continue;
1351355b4669Sjacobs 	else if (errno != http->error)
1352355b4669Sjacobs 	{
1353355b4669Sjacobs 	  http->error = errno;
1354355b4669Sjacobs 	  continue;
1355355b4669Sjacobs 	}
1356355b4669Sjacobs #endif /* WIN32 */
1357355b4669Sjacobs 
1358355b4669Sjacobs         return (NULL);
1359355b4669Sjacobs       }
1360355b4669Sjacobs       else if (bytes == 0)
1361355b4669Sjacobs       {
1362355b4669Sjacobs 	http->error = EPIPE;
1363355b4669Sjacobs 
1364355b4669Sjacobs         return (NULL);
1365355b4669Sjacobs       }
1366355b4669Sjacobs 
1367355b4669Sjacobs      /*
1368355b4669Sjacobs       * Yup, update the amount used and the end pointer...
1369355b4669Sjacobs       */
1370355b4669Sjacobs 
1371355b4669Sjacobs       http->used += bytes;
1372355b4669Sjacobs       bufend     += bytes;
1373355b4669Sjacobs       bufptr     = bufend;
1374355b4669Sjacobs     }
1375355b4669Sjacobs   }
1376355b4669Sjacobs   while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER);
1377355b4669Sjacobs 
1378355b4669Sjacobs   http->activity = time(NULL);
1379355b4669Sjacobs 
1380355b4669Sjacobs  /*
1381355b4669Sjacobs   * Read a line from the buffer...
1382355b4669Sjacobs   */
1383*1da57d55SToomas Soome 
1384355b4669Sjacobs   lineptr = line;
1385355b4669Sjacobs   bufptr  = http->buffer;
1386355b4669Sjacobs   bytes   = 0;
1387355b4669Sjacobs   length --;
1388355b4669Sjacobs 
1389355b4669Sjacobs   while (bufptr < bufend && bytes < length)
1390355b4669Sjacobs   {
1391355b4669Sjacobs     bytes ++;
1392355b4669Sjacobs 
1393355b4669Sjacobs     if (*bufptr == 0x0a)
1394355b4669Sjacobs     {
1395355b4669Sjacobs       bufptr ++;
1396355b4669Sjacobs       break;
1397355b4669Sjacobs     }
1398355b4669Sjacobs     else if (*bufptr == 0x0d)
1399355b4669Sjacobs       bufptr ++;
1400355b4669Sjacobs     else
1401355b4669Sjacobs       *lineptr++ = *bufptr++;
1402355b4669Sjacobs   }
1403355b4669Sjacobs 
1404355b4669Sjacobs   if (bytes > 0)
1405355b4669Sjacobs   {
1406355b4669Sjacobs     *lineptr = '\0';
1407355b4669Sjacobs 
1408355b4669Sjacobs     http->used -= bytes;
1409355b4669Sjacobs     if (http->used > 0)
1410355b4669Sjacobs       memmove(http->buffer, bufptr, http->used);
1411355b4669Sjacobs 
1412355b4669Sjacobs     DEBUG_printf(("httpGets: Returning \"%s\"\n", line));
1413355b4669Sjacobs     return (line);
1414355b4669Sjacobs   }
1415355b4669Sjacobs 
1416355b4669Sjacobs   DEBUG_puts("httpGets: No new line available!");
1417355b4669Sjacobs 
1418355b4669Sjacobs   return (NULL);
1419355b4669Sjacobs }
1420355b4669Sjacobs 
1421355b4669Sjacobs 
1422355b4669Sjacobs /*
1423355b4669Sjacobs  * 'httpPrintf()' - Print a formatted string to a HTTP connection.
1424355b4669Sjacobs  */
1425355b4669Sjacobs 
1426355b4669Sjacobs int					/* O - Number of bytes written */
httpPrintf(http_t * http,const char * format,...)1427355b4669Sjacobs httpPrintf(http_t     *http,		/* I - HTTP data */
1428355b4669Sjacobs            const char *format,		/* I - printf-style format string */
1429355b4669Sjacobs 	   ...)				/* I - Additional args as needed */
1430355b4669Sjacobs {
1431355b4669Sjacobs   int		bytes,			/* Number of bytes to write */
1432355b4669Sjacobs 		nbytes,			/* Number of bytes written */
1433355b4669Sjacobs 		tbytes;			/* Number of bytes all together */
1434355b4669Sjacobs   char		buf[HTTP_MAX_BUFFER],	/* Buffer for formatted string */
1435355b4669Sjacobs 		*bufptr;		/* Pointer into buffer */
1436355b4669Sjacobs   va_list	ap;			/* Variable argument pointer */
1437355b4669Sjacobs 
1438355b4669Sjacobs 
1439355b4669Sjacobs   DEBUG_printf(("httpPrintf: httpPrintf(http=%p, format=\"%s\", ...)\n", http, format));
1440355b4669Sjacobs 
1441355b4669Sjacobs   va_start(ap, format);
1442355b4669Sjacobs   bytes = vsnprintf(buf, sizeof(buf), format, ap);
1443355b4669Sjacobs   va_end(ap);
1444355b4669Sjacobs 
1445355b4669Sjacobs   DEBUG_printf(("httpPrintf: %s", buf));
1446355b4669Sjacobs 
1447355b4669Sjacobs   for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes)
1448355b4669Sjacobs   {
1449355b4669Sjacobs #ifdef HAVE_SSL
1450355b4669Sjacobs     if (http->tls)
1451355b4669Sjacobs       nbytes = http_write_ssl(http, bufptr, bytes - tbytes);
1452355b4669Sjacobs     else
1453355b4669Sjacobs #endif /* HAVE_SSL */
1454355b4669Sjacobs     nbytes = send(http->fd, bufptr, bytes - tbytes, 0);
1455355b4669Sjacobs 
1456355b4669Sjacobs #ifdef DEBUG_HTTP
1457355b4669Sjacobs     if (nbytes >= 0)
1458355b4669Sjacobs     	httpDumpData(stdout, "httpPrintf:", bufptr, nbytes);
1459355b4669Sjacobs #endif
1460355b4669Sjacobs 
1461355b4669Sjacobs     if (nbytes < 0)
1462355b4669Sjacobs     {
1463355b4669Sjacobs       nbytes = 0;
1464355b4669Sjacobs 
1465355b4669Sjacobs #ifdef WIN32
1466355b4669Sjacobs       if (WSAGetLastError() != http->error)
1467355b4669Sjacobs       {
1468355b4669Sjacobs         http->error = WSAGetLastError();
1469355b4669Sjacobs 	continue;
1470355b4669Sjacobs       }
1471355b4669Sjacobs #else
1472355b4669Sjacobs       if (errno == EINTR)
1473355b4669Sjacobs 	continue;
1474355b4669Sjacobs       else if (errno != http->error)
1475355b4669Sjacobs       {
1476355b4669Sjacobs         http->error = errno;
1477355b4669Sjacobs 	continue;
1478355b4669Sjacobs       }
1479355b4669Sjacobs #endif /* WIN32 */
1480355b4669Sjacobs 
1481355b4669Sjacobs       return (-1);
1482355b4669Sjacobs     }
1483355b4669Sjacobs   }
1484355b4669Sjacobs 
1485355b4669Sjacobs   return (bytes);
1486355b4669Sjacobs }
1487355b4669Sjacobs 
1488355b4669Sjacobs 
1489355b4669Sjacobs /*
1490355b4669Sjacobs  * 'httpGetDateString()' - Get a formatted date/time string from a time value.
1491355b4669Sjacobs  */
1492355b4669Sjacobs 
1493355b4669Sjacobs const char *				/* O - Date/time string */
httpGetDateString(time_t t)1494355b4669Sjacobs httpGetDateString(time_t t)		/* I - UNIX time */
1495355b4669Sjacobs {
1496355b4669Sjacobs   struct tm	*tdate;
1497355b4669Sjacobs   static char	datetime[256];
1498355b4669Sjacobs 
1499355b4669Sjacobs 
1500355b4669Sjacobs   tdate = gmtime(&t);
1501355b4669Sjacobs   snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT",
1502355b4669Sjacobs            days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon],
1503355b4669Sjacobs 	   tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
1504355b4669Sjacobs 
1505355b4669Sjacobs   return (datetime);
1506355b4669Sjacobs }
1507355b4669Sjacobs 
1508355b4669Sjacobs 
1509355b4669Sjacobs /*
1510355b4669Sjacobs  * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
1511355b4669Sjacobs  */
1512355b4669Sjacobs 
1513355b4669Sjacobs time_t					/* O - UNIX time */
httpGetDateTime(const char * s)1514355b4669Sjacobs httpGetDateTime(const char *s)		/* I - Date/time string */
1515355b4669Sjacobs {
1516355b4669Sjacobs   int		i;			/* Looping var */
1517355b4669Sjacobs   struct tm	tdate;			/* Time/date structure */
1518355b4669Sjacobs   char		mon[16];		/* Abbreviated month name */
1519355b4669Sjacobs   int		day, year;		/* Day of month and year */
1520355b4669Sjacobs   int		hour, min, sec;		/* Time */
1521355b4669Sjacobs 
1522355b4669Sjacobs 
1523355b4669Sjacobs   if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
1524355b4669Sjacobs     return (0);
1525355b4669Sjacobs 
1526355b4669Sjacobs   for (i = 0; i < 12; i ++)
1527355b4669Sjacobs     if (strcasecmp(mon, months[i]) == 0)
1528355b4669Sjacobs       break;
1529355b4669Sjacobs 
1530355b4669Sjacobs   if (i >= 12)
1531355b4669Sjacobs     return (0);
1532355b4669Sjacobs 
1533355b4669Sjacobs   tdate.tm_mon   = i;
1534355b4669Sjacobs   tdate.tm_mday  = day;
1535355b4669Sjacobs   tdate.tm_year  = year - 1900;
1536355b4669Sjacobs   tdate.tm_hour  = hour;
1537355b4669Sjacobs   tdate.tm_min   = min;
1538355b4669Sjacobs   tdate.tm_sec   = sec;
1539355b4669Sjacobs   tdate.tm_isdst = 0;
1540355b4669Sjacobs 
1541355b4669Sjacobs   return (mktime(&tdate));
1542355b4669Sjacobs }
1543355b4669Sjacobs 
1544355b4669Sjacobs 
1545355b4669Sjacobs /*
1546355b4669Sjacobs  * 'httpUpdate()' - Update the current HTTP state for incoming data.
1547355b4669Sjacobs  */
1548355b4669Sjacobs 
1549355b4669Sjacobs http_status_t				/* O - HTTP status */
httpUpdate(http_t * http)1550355b4669Sjacobs httpUpdate(http_t *http)		/* I - HTTP data */
1551355b4669Sjacobs {
1552355b4669Sjacobs   char		line[1024],		/* Line from connection... */
1553355b4669Sjacobs 		*value;			/* Pointer to value on line */
1554355b4669Sjacobs   http_field_t	field;			/* Field index */
1555355b4669Sjacobs   int		major, minor,		/* HTTP version numbers */
1556355b4669Sjacobs 		status;			/* Request status */
1557355b4669Sjacobs 
1558355b4669Sjacobs 
1559355b4669Sjacobs   DEBUG_printf(("httpUpdate(http=%p), state=%d\n", http, http->state));
1560355b4669Sjacobs 
1561355b4669Sjacobs  /*
1562355b4669Sjacobs   * If we haven't issued any commands, then there is nothing to "update"...
1563355b4669Sjacobs   */
1564355b4669Sjacobs 
1565355b4669Sjacobs   if (http->state == HTTP_WAITING)
1566355b4669Sjacobs     return (HTTP_CONTINUE);
1567355b4669Sjacobs 
1568355b4669Sjacobs  /*
1569355b4669Sjacobs   * Grab all of the lines we can from the connection...
1570355b4669Sjacobs   */
1571355b4669Sjacobs 
1572355b4669Sjacobs   line[0] = '\0';
1573355b4669Sjacobs   while (httpGets(line, sizeof(line), http) != NULL)
1574355b4669Sjacobs   {
1575355b4669Sjacobs     DEBUG_printf(("httpUpdate: Got \"%s\"\n", line));
1576355b4669Sjacobs 
1577355b4669Sjacobs     if (line[0] == '\0')
1578355b4669Sjacobs     {
1579355b4669Sjacobs      /*
1580355b4669Sjacobs       * Blank line means the start of the data section (if any).  Return
1581355b4669Sjacobs       * the result code, too...
1582355b4669Sjacobs       *
1583355b4669Sjacobs       * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
1584355b4669Sjacobs       * Instead, we just return HTTP_CONTINUE to the caller and keep on
1585355b4669Sjacobs       * tryin'...
1586355b4669Sjacobs       */
1587355b4669Sjacobs 
1588355b4669Sjacobs       if (http->status == HTTP_CONTINUE)
1589355b4669Sjacobs         return (http->status);
1590355b4669Sjacobs 
1591355b4669Sjacobs       if (http->status < HTTP_BAD_REQUEST)
1592355b4669Sjacobs         http->digest_tries = 0;
1593355b4669Sjacobs 
1594355b4669Sjacobs #ifdef HAVE_SSL
1595355b4669Sjacobs       if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
1596355b4669Sjacobs       {
1597355b4669Sjacobs 	if (http_setup_ssl(http) != 0)
1598355b4669Sjacobs 	{
1599355b4669Sjacobs #  ifdef WIN32
1600355b4669Sjacobs 	  closesocket(http->fd);
1601355b4669Sjacobs #  else
1602355b4669Sjacobs 	  close(http->fd);
1603355b4669Sjacobs #  endif /* WIN32 */
1604355b4669Sjacobs 
1605355b4669Sjacobs 	  return (HTTP_ERROR);
1606355b4669Sjacobs 	}
1607355b4669Sjacobs 
1608355b4669Sjacobs         return (HTTP_CONTINUE);
1609355b4669Sjacobs       }
1610355b4669Sjacobs #endif /* HAVE_SSL */
1611355b4669Sjacobs 
1612355b4669Sjacobs       httpGetLength(http);
1613355b4669Sjacobs 
1614355b4669Sjacobs       switch (http->state)
1615355b4669Sjacobs       {
1616355b4669Sjacobs         case HTTP_GET :
1617355b4669Sjacobs 	case HTTP_POST :
1618355b4669Sjacobs 	case HTTP_POST_RECV :
1619355b4669Sjacobs 	case HTTP_PUT :
1620355b4669Sjacobs 	    http->state ++;
1621355b4669Sjacobs 	case HTTP_POST_SEND :
1622355b4669Sjacobs 	    break;
1623355b4669Sjacobs 
1624355b4669Sjacobs 	default :
1625355b4669Sjacobs 	    http->state = HTTP_WAITING;
1626355b4669Sjacobs 	    break;
1627355b4669Sjacobs       }
1628355b4669Sjacobs 
1629355b4669Sjacobs       return (http->status);
1630355b4669Sjacobs     }
1631355b4669Sjacobs     else if (strncmp(line, "HTTP/", 5) == 0)
1632355b4669Sjacobs     {
1633355b4669Sjacobs      /*
1634355b4669Sjacobs       * Got the beginning of a response...
1635355b4669Sjacobs       */
1636355b4669Sjacobs 
1637355b4669Sjacobs       if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3)
1638355b4669Sjacobs         return (HTTP_ERROR);
1639355b4669Sjacobs 
1640355b4669Sjacobs       http->version = (http_version_t)(major * 100 + minor);
1641355b4669Sjacobs       http->status  = (http_status_t)status;
1642355b4669Sjacobs     }
1643355b4669Sjacobs     else if ((value = strchr(line, ':')) != NULL)
1644355b4669Sjacobs     {
1645355b4669Sjacobs      /*
1646355b4669Sjacobs       * Got a value...
1647355b4669Sjacobs       */
1648355b4669Sjacobs 
1649355b4669Sjacobs       *value++ = '\0';
1650355b4669Sjacobs       while (isspace(*value & 255))
1651355b4669Sjacobs         value ++;
1652355b4669Sjacobs 
1653355b4669Sjacobs      /*
1654355b4669Sjacobs       * Be tolerants of servers that send unknown attribute fields...
1655355b4669Sjacobs       */
1656355b4669Sjacobs 
1657355b4669Sjacobs       if (!strcasecmp(line, "expect"))
1658355b4669Sjacobs       {
1659355b4669Sjacobs        /*
1660355b4669Sjacobs         * "Expect: 100-continue" or similar...
1661355b4669Sjacobs 	*/
1662355b4669Sjacobs 
1663355b4669Sjacobs         http->expect = (http_status_t)atoi(value);
1664355b4669Sjacobs       }
1665355b4669Sjacobs       else if (!strcasecmp(line, "cookie"))
1666355b4669Sjacobs       {
1667355b4669Sjacobs        /*
1668355b4669Sjacobs         * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
1669355b4669Sjacobs 	*/
1670355b4669Sjacobs 
1671355b4669Sjacobs         httpSetCookie(http, value);
1672355b4669Sjacobs       }
1673355b4669Sjacobs       else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN)
1674355b4669Sjacobs       {
1675355b4669Sjacobs         DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line));
1676355b4669Sjacobs         continue;
1677355b4669Sjacobs       }
1678355b4669Sjacobs       else
1679355b4669Sjacobs         httpSetField(http, field, value);
1680355b4669Sjacobs     }
1681355b4669Sjacobs     else
1682355b4669Sjacobs     {
1683355b4669Sjacobs       http->status = HTTP_ERROR;
1684355b4669Sjacobs       return (HTTP_ERROR);
1685355b4669Sjacobs     }
1686355b4669Sjacobs   }
1687355b4669Sjacobs 
1688355b4669Sjacobs  /*
1689355b4669Sjacobs   * See if there was an error...
1690355b4669Sjacobs   */
1691355b4669Sjacobs 
1692355b4669Sjacobs   if (http->error == EPIPE && http->status > HTTP_CONTINUE)
1693355b4669Sjacobs     return (http->status);
1694355b4669Sjacobs 
1695355b4669Sjacobs   if (http->error)
1696355b4669Sjacobs   {
1697355b4669Sjacobs     DEBUG_printf(("httpUpdate: socket error %d - %s\n", http->error,
1698355b4669Sjacobs                   strerror(http->error)));
1699355b4669Sjacobs     http->status = HTTP_ERROR;
1700355b4669Sjacobs     return (HTTP_ERROR);
1701355b4669Sjacobs   }
1702355b4669Sjacobs 
1703355b4669Sjacobs  /*
1704355b4669Sjacobs   * If we haven't already returned, then there is nothing new...
1705355b4669Sjacobs   */
1706355b4669Sjacobs 
1707355b4669Sjacobs   return (HTTP_CONTINUE);
1708355b4669Sjacobs }
1709355b4669Sjacobs 
1710355b4669Sjacobs 
1711355b4669Sjacobs /*
1712355b4669Sjacobs  * 'httpDecode64()' - Base64-decode a string.
1713355b4669Sjacobs  */
1714355b4669Sjacobs 
1715355b4669Sjacobs char *					/* O - Decoded string */
httpDecode64(char * out,const char * in)1716355b4669Sjacobs httpDecode64(char       *out,		/* I - String to write to */
1717355b4669Sjacobs              const char *in)		/* I - String to read from */
1718355b4669Sjacobs {
1719355b4669Sjacobs   int	outlen;				/* Output buffer length */
1720355b4669Sjacobs 
1721355b4669Sjacobs 
1722355b4669Sjacobs  /*
1723355b4669Sjacobs   * Use the old maximum buffer size for binary compatibility...
1724355b4669Sjacobs   */
1725355b4669Sjacobs 
1726355b4669Sjacobs   outlen = 512;
1727355b4669Sjacobs 
1728355b4669Sjacobs   return (httpDecode64_2(out, &outlen, in));
1729355b4669Sjacobs }
1730355b4669Sjacobs 
1731355b4669Sjacobs 
1732355b4669Sjacobs /*
1733355b4669Sjacobs  * 'httpDecode64_2()' - Base64-decode a string.
1734355b4669Sjacobs  */
1735355b4669Sjacobs 
1736355b4669Sjacobs char *					/* O  - Decoded string */
httpDecode64_2(char * out,int * outlen,const char * in)1737355b4669Sjacobs httpDecode64_2(char       *out,		/* I  - String to write to */
1738355b4669Sjacobs 	       int        *outlen,	/* IO - Size of output string */
1739355b4669Sjacobs                const char *in)		/* I  - String to read from */
1740355b4669Sjacobs {
1741355b4669Sjacobs   int	pos,				/* Bit position */
1742355b4669Sjacobs 	base64;				/* Value of this character */
1743355b4669Sjacobs   char	*outptr,			/* Output pointer */
1744355b4669Sjacobs 	*outend;			/* End of output buffer */
1745355b4669Sjacobs 
1746355b4669Sjacobs 
1747355b4669Sjacobs  /*
1748355b4669Sjacobs   * Range check input...
1749355b4669Sjacobs   */
1750355b4669Sjacobs 
1751355b4669Sjacobs   if (!out || !outlen || *outlen < 1 || !in || !*in)
1752355b4669Sjacobs     return (NULL);
1753355b4669Sjacobs 
1754355b4669Sjacobs  /*
1755355b4669Sjacobs   * Convert from base-64 to bytes...
1756355b4669Sjacobs   */
1757355b4669Sjacobs 
1758355b4669Sjacobs   for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++)
1759355b4669Sjacobs   {
1760355b4669Sjacobs    /*
1761355b4669Sjacobs     * Decode this character into a number from 0 to 63...
1762355b4669Sjacobs     */
1763355b4669Sjacobs 
1764355b4669Sjacobs     if (*in >= 'A' && *in <= 'Z')
1765355b4669Sjacobs       base64 = *in - 'A';
1766355b4669Sjacobs     else if (*in >= 'a' && *in <= 'z')
1767355b4669Sjacobs       base64 = *in - 'a' + 26;
1768355b4669Sjacobs     else if (*in >= '0' && *in <= '9')
1769355b4669Sjacobs       base64 = *in - '0' + 52;
1770355b4669Sjacobs     else if (*in == '+')
1771355b4669Sjacobs       base64 = 62;
1772355b4669Sjacobs     else if (*in == '/')
1773355b4669Sjacobs       base64 = 63;
1774355b4669Sjacobs     else if (*in == '=')
1775355b4669Sjacobs       break;
1776355b4669Sjacobs     else
1777355b4669Sjacobs       continue;
1778355b4669Sjacobs 
1779355b4669Sjacobs    /*
1780355b4669Sjacobs     * Store the result in the appropriate chars...
1781355b4669Sjacobs     */
1782355b4669Sjacobs 
1783355b4669Sjacobs     switch (pos)
1784355b4669Sjacobs     {
1785355b4669Sjacobs       case 0 :
1786355b4669Sjacobs           if (outptr < outend)
1787355b4669Sjacobs             *outptr = base64 << 2;
1788355b4669Sjacobs 	  pos ++;
1789355b4669Sjacobs 	  break;
1790355b4669Sjacobs       case 1 :
1791355b4669Sjacobs           if (outptr < outend)
1792355b4669Sjacobs             *outptr++ |= (base64 >> 4) & 3;
1793355b4669Sjacobs           if (outptr < outend)
1794355b4669Sjacobs 	    *outptr = (base64 << 4) & 255;
1795355b4669Sjacobs 	  pos ++;
1796355b4669Sjacobs 	  break;
1797355b4669Sjacobs       case 2 :
1798355b4669Sjacobs           if (outptr < outend)
1799355b4669Sjacobs             *outptr++ |= (base64 >> 2) & 15;
1800355b4669Sjacobs           if (outptr < outend)
1801355b4669Sjacobs 	    *outptr = (base64 << 6) & 255;
1802355b4669Sjacobs 	  pos ++;
1803355b4669Sjacobs 	  break;
1804355b4669Sjacobs       case 3 :
1805355b4669Sjacobs           if (outptr < outend)
1806355b4669Sjacobs             *outptr++ |= base64;
1807355b4669Sjacobs 	  pos = 0;
1808355b4669Sjacobs 	  break;
1809355b4669Sjacobs     }
1810355b4669Sjacobs   }
1811355b4669Sjacobs 
1812355b4669Sjacobs   *outptr = '\0';
1813355b4669Sjacobs 
1814355b4669Sjacobs  /*
1815355b4669Sjacobs   * Return the decoded string and size...
1816355b4669Sjacobs   */
1817355b4669Sjacobs 
1818355b4669Sjacobs   *outlen = (int)(outptr - out);
1819355b4669Sjacobs 
1820355b4669Sjacobs   return (out);
1821355b4669Sjacobs }
1822355b4669Sjacobs 
1823355b4669Sjacobs 
1824355b4669Sjacobs /*
1825355b4669Sjacobs  * 'httpEncode64()' - Base64-encode a string.
1826355b4669Sjacobs  */
1827355b4669Sjacobs 
1828355b4669Sjacobs char *					/* O - Encoded string */
httpEncode64(char * out,const char * in)1829355b4669Sjacobs httpEncode64(char       *out,		/* I - String to write to */
1830355b4669Sjacobs              const char *in)		/* I - String to read from */
1831355b4669Sjacobs {
1832355b4669Sjacobs   return (httpEncode64_2(out, 512, in, strlen(in)));
1833355b4669Sjacobs }
1834355b4669Sjacobs 
1835355b4669Sjacobs 
1836355b4669Sjacobs /*
1837355b4669Sjacobs  * 'httpEncode64_2()' - Base64-encode a string.
1838355b4669Sjacobs  */
1839355b4669Sjacobs 
1840355b4669Sjacobs char *					/* O - Encoded string */
httpEncode64_2(char * out,int outlen,const char * in,int inlen)1841355b4669Sjacobs httpEncode64_2(char       *out,		/* I - String to write to */
1842355b4669Sjacobs 	       int        outlen,	/* I - Size of output string */
1843355b4669Sjacobs                const char *in,		/* I - String to read from */
1844355b4669Sjacobs 	       int        inlen)	/* I - Size of input string */
1845355b4669Sjacobs {
1846355b4669Sjacobs   char		*outptr,		/* Output pointer */
1847355b4669Sjacobs 		*outend;		/* End of output buffer */
1848355b4669Sjacobs   static const char base64[] =		/* Base64 characters... */
1849355b4669Sjacobs   		{
1850355b4669Sjacobs 		  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1851355b4669Sjacobs 		  "abcdefghijklmnopqrstuvwxyz"
1852355b4669Sjacobs 		  "0123456789"
1853355b4669Sjacobs 		  "+/"
1854355b4669Sjacobs   		};
1855355b4669Sjacobs 
1856355b4669Sjacobs 
1857355b4669Sjacobs  /*
1858355b4669Sjacobs   * Range check input...
1859355b4669Sjacobs   */
1860355b4669Sjacobs 
1861355b4669Sjacobs   if (!out || outlen < 1 || !in || inlen < 1)
1862355b4669Sjacobs     return (NULL);
1863355b4669Sjacobs 
1864355b4669Sjacobs  /*
1865355b4669Sjacobs   * Convert bytes to base-64...
1866355b4669Sjacobs   */
1867355b4669Sjacobs 
1868355b4669Sjacobs   for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --)
1869355b4669Sjacobs   {
1870355b4669Sjacobs    /*
1871355b4669Sjacobs     * Encode the up to 3 characters as 4 Base64 numbers...
1872355b4669Sjacobs     */
1873355b4669Sjacobs 
1874355b4669Sjacobs     if (outptr < outend)
1875355b4669Sjacobs       *outptr ++ = base64[(in[0] & 255) >> 2];
1876355b4669Sjacobs     if (outptr < outend)
1877355b4669Sjacobs       *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
1878355b4669Sjacobs 
1879355b4669Sjacobs     in ++;
1880355b4669Sjacobs     inlen --;
1881355b4669Sjacobs     if (inlen <= 0)
1882355b4669Sjacobs     {
1883355b4669Sjacobs       if (outptr < outend)
1884355b4669Sjacobs         *outptr ++ = '=';
1885355b4669Sjacobs       if (outptr < outend)
1886355b4669Sjacobs         *outptr ++ = '=';
1887355b4669Sjacobs       break;
1888355b4669Sjacobs     }
1889355b4669Sjacobs 
1890355b4669Sjacobs     if (outptr < outend)
1891355b4669Sjacobs       *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
1892355b4669Sjacobs 
1893355b4669Sjacobs     in ++;
1894355b4669Sjacobs     inlen --;
1895355b4669Sjacobs     if (inlen <= 0)
1896355b4669Sjacobs     {
1897355b4669Sjacobs       if (outptr < outend)
1898355b4669Sjacobs         *outptr ++ = '=';
1899355b4669Sjacobs       break;
1900355b4669Sjacobs     }
1901355b4669Sjacobs 
1902355b4669Sjacobs     if (outptr < outend)
1903355b4669Sjacobs       *outptr ++ = base64[in[0] & 63];
1904355b4669Sjacobs   }
1905355b4669Sjacobs 
1906355b4669Sjacobs   *outptr = '\0';
1907355b4669Sjacobs 
1908355b4669Sjacobs  /*
1909355b4669Sjacobs   * Return the encoded string...
1910355b4669Sjacobs   */
1911355b4669Sjacobs 
1912355b4669Sjacobs   return (out);
1913355b4669Sjacobs }
1914355b4669Sjacobs 
1915355b4669Sjacobs 
1916355b4669Sjacobs /*
1917355b4669Sjacobs  * 'httpGetLength()' - Get the amount of data remaining from the
1918355b4669Sjacobs  *                     content-length or transfer-encoding fields.
1919355b4669Sjacobs  */
1920355b4669Sjacobs 
1921355b4669Sjacobs int				/* O - Content length */
httpGetLength(http_t * http)1922355b4669Sjacobs httpGetLength(http_t *http)	/* I - HTTP data */
1923355b4669Sjacobs {
1924355b4669Sjacobs   DEBUG_printf(("httpGetLength(http=%p), state=%d\n", http, http->state));
1925355b4669Sjacobs 
1926355b4669Sjacobs   if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0)
1927355b4669Sjacobs   {
1928355b4669Sjacobs     DEBUG_puts("httpGetLength: chunked request!");
1929355b4669Sjacobs 
1930355b4669Sjacobs     http->data_encoding  = HTTP_ENCODE_CHUNKED;
1931355b4669Sjacobs     http->data_remaining = 0;
1932355b4669Sjacobs   }
1933355b4669Sjacobs   else
1934355b4669Sjacobs   {
1935355b4669Sjacobs     http->data_encoding = HTTP_ENCODE_LENGTH;
1936355b4669Sjacobs 
1937355b4669Sjacobs    /*
1938355b4669Sjacobs     * The following is a hack for HTTP servers that don't send a
1939355b4669Sjacobs     * content-length or transfer-encoding field...
1940355b4669Sjacobs     *
1941355b4669Sjacobs     * If there is no content-length then the connection must close
1942355b4669Sjacobs     * after the transfer is complete...
1943355b4669Sjacobs     */
1944355b4669Sjacobs 
1945355b4669Sjacobs     if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
1946355b4669Sjacobs       http->data_remaining = 2147483647;
1947355b4669Sjacobs     else
1948355b4669Sjacobs       http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]);
1949355b4669Sjacobs 
1950355b4669Sjacobs     DEBUG_printf(("httpGetLength: content_length=%d\n", http->data_remaining));
1951355b4669Sjacobs   }
1952355b4669Sjacobs 
1953355b4669Sjacobs   return (http->data_remaining);
1954355b4669Sjacobs }
1955355b4669Sjacobs 
1956355b4669Sjacobs 
1957355b4669Sjacobs /*
1958355b4669Sjacobs  * 'http_field()' - Return the field index for a field name.
1959355b4669Sjacobs  */
1960355b4669Sjacobs 
1961355b4669Sjacobs static http_field_t		/* O - Field index */
http_field(const char * name)1962355b4669Sjacobs http_field(const char *name)	/* I - String name */
1963355b4669Sjacobs {
1964355b4669Sjacobs   int	i;			/* Looping var */
1965355b4669Sjacobs 
1966355b4669Sjacobs 
1967355b4669Sjacobs   for (i = 0; i < HTTP_FIELD_MAX; i ++)
1968355b4669Sjacobs     if (strcasecmp(name, http_fields[i]) == 0)
1969355b4669Sjacobs       return ((http_field_t)i);
1970355b4669Sjacobs 
1971355b4669Sjacobs   return (HTTP_FIELD_UNKNOWN);
1972355b4669Sjacobs }
1973355b4669Sjacobs 
1974355b4669Sjacobs 
1975355b4669Sjacobs /*
1976355b4669Sjacobs  * 'http_send()' - Send a request with all fields and the trailing blank line.
1977355b4669Sjacobs  */
1978355b4669Sjacobs 
1979355b4669Sjacobs static int			/* O - 0 on success, non-zero on error */
http_send(http_t * http,http_state_t request,const char * uri)1980355b4669Sjacobs http_send(http_t       *http,	/* I - HTTP data */
1981355b4669Sjacobs           http_state_t request,	/* I - Request code */
1982355b4669Sjacobs 	  const char   *uri)	/* I - URI */
1983355b4669Sjacobs {
1984355b4669Sjacobs   int		i;		/* Looping var */
1985355b4669Sjacobs   char		*ptr,		/* Pointer in buffer */
1986355b4669Sjacobs 		buf[1024];	/* Encoded URI buffer */
1987355b4669Sjacobs   static const char * const codes[] =
1988355b4669Sjacobs 		{		/* Request code strings */
1989355b4669Sjacobs 		  NULL,
1990355b4669Sjacobs 		  "OPTIONS",
1991355b4669Sjacobs 		  "GET",
1992355b4669Sjacobs 		  NULL,
1993355b4669Sjacobs 		  "HEAD",
1994355b4669Sjacobs 		  "POST",
1995355b4669Sjacobs 		  NULL,
1996355b4669Sjacobs 		  NULL,
1997355b4669Sjacobs 		  "PUT",
1998355b4669Sjacobs 		  NULL,
1999355b4669Sjacobs 		  "DELETE",
2000355b4669Sjacobs 		  "TRACE",
2001355b4669Sjacobs 		  "CLOSE"
2002355b4669Sjacobs 		};
2003355b4669Sjacobs   static const char hex[] = "0123456789ABCDEF";
2004355b4669Sjacobs 				/* Hex digits */
2005355b4669Sjacobs 
2006355b4669Sjacobs 
2007355b4669Sjacobs   DEBUG_printf(("http_send(http=%p, request=HTTP_%s, uri=\"%s\")\n",
2008355b4669Sjacobs                 http, codes[request], uri));
2009355b4669Sjacobs 
2010355b4669Sjacobs   if (http == NULL || uri == NULL)
2011355b4669Sjacobs     return (-1);
2012355b4669Sjacobs 
2013355b4669Sjacobs  /*
2014355b4669Sjacobs   * Encode the URI as needed...
2015355b4669Sjacobs   */
2016355b4669Sjacobs 
2017355b4669Sjacobs   for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++)
2018355b4669Sjacobs     if (*uri <= ' ' || *uri >= 127)
2019355b4669Sjacobs     {
2020355b4669Sjacobs       if (ptr < (buf + sizeof(buf) - 1))
2021355b4669Sjacobs         *ptr ++ = '%';
2022355b4669Sjacobs       if (ptr < (buf + sizeof(buf) - 1))
2023355b4669Sjacobs         *ptr ++ = hex[(*uri >> 4) & 15];
2024355b4669Sjacobs       if (ptr < (buf + sizeof(buf) - 1))
2025355b4669Sjacobs         *ptr ++ = hex[*uri & 15];
2026355b4669Sjacobs     }
2027355b4669Sjacobs     else
2028355b4669Sjacobs       *ptr ++ = *uri;
2029355b4669Sjacobs 
2030355b4669Sjacobs   *ptr = '\0';
2031355b4669Sjacobs 
2032355b4669Sjacobs  /*
2033355b4669Sjacobs   * See if we had an error the last time around; if so, reconnect...
2034355b4669Sjacobs   */
2035355b4669Sjacobs 
2036355b4669Sjacobs   if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
2037355b4669Sjacobs     httpReconnect(http);
2038355b4669Sjacobs 
2039355b4669Sjacobs  /*
2040355b4669Sjacobs   * Send the request header...
2041355b4669Sjacobs   */
2042355b4669Sjacobs 
2043355b4669Sjacobs   http->state = request;
2044355b4669Sjacobs   if (request == HTTP_POST || request == HTTP_PUT)
2045355b4669Sjacobs     http->state ++;
2046355b4669Sjacobs 
2047355b4669Sjacobs   http->status = HTTP_CONTINUE;
2048355b4669Sjacobs 
2049355b4669Sjacobs #ifdef HAVE_SSL
2050355b4669Sjacobs   if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
2051355b4669Sjacobs   {
2052355b4669Sjacobs     httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
2053355b4669Sjacobs     httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
2054355b4669Sjacobs   }
2055355b4669Sjacobs #endif /* HAVE_SSL */
2056355b4669Sjacobs 
2057355b4669Sjacobs   if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
2058355b4669Sjacobs   {
2059355b4669Sjacobs     http->status = HTTP_ERROR;
2060355b4669Sjacobs     return (-1);
2061355b4669Sjacobs   }
2062355b4669Sjacobs 
2063355b4669Sjacobs   for (i = 0; i < HTTP_FIELD_MAX; i ++)
2064355b4669Sjacobs     if (http->fields[i][0] != '\0')
2065355b4669Sjacobs     {
2066355b4669Sjacobs       DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
2067355b4669Sjacobs 
2068355b4669Sjacobs       if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1)
2069355b4669Sjacobs       {
2070355b4669Sjacobs 	http->status = HTTP_ERROR;
2071355b4669Sjacobs 	return (-1);
2072355b4669Sjacobs       }
2073355b4669Sjacobs     }
2074355b4669Sjacobs 
2075355b4669Sjacobs   if (httpPrintf(http, "\r\n") < 1)
2076355b4669Sjacobs   {
2077355b4669Sjacobs     http->status = HTTP_ERROR;
2078355b4669Sjacobs     return (-1);
2079355b4669Sjacobs   }
2080355b4669Sjacobs 
2081355b4669Sjacobs   httpClearFields(http);
2082355b4669Sjacobs 
2083355b4669Sjacobs   return (0);
2084355b4669Sjacobs }
2085355b4669Sjacobs 
2086355b4669Sjacobs 
2087355b4669Sjacobs /*
2088355b4669Sjacobs  * 'http_wait()' - Wait for data available on a connection.
2089355b4669Sjacobs  */
2090355b4669Sjacobs 
2091355b4669Sjacobs static int				/* O - 1 if data is available, 0 otherwise */
http_wait(http_t * http,int msec)2092355b4669Sjacobs http_wait(http_t *http,			/* I - HTTP data */
2093355b4669Sjacobs           int    msec)			/* I - Milliseconds to wait */
2094355b4669Sjacobs {
2095355b4669Sjacobs #ifndef WIN32
2096355b4669Sjacobs   struct rlimit		limit;          /* Runtime limit */
2097355b4669Sjacobs #endif /* !WIN32 */
2098355b4669Sjacobs   struct timeval	timeout;	/* Timeout */
2099355b4669Sjacobs   int			nfds;		/* Result from select() */
2100355b4669Sjacobs   int			set_size;	/* Size of select set */
2101355b4669Sjacobs 
2102355b4669Sjacobs 
2103355b4669Sjacobs   DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec));
2104355b4669Sjacobs 
2105355b4669Sjacobs  /*
2106355b4669Sjacobs   * Check the SSL/TLS buffers for data first...
2107355b4669Sjacobs   */
2108355b4669Sjacobs 
2109355b4669Sjacobs #ifdef HAVE_SSL
2110355b4669Sjacobs   if (http->tls)
2111355b4669Sjacobs   {
2112355b4669Sjacobs #  ifdef HAVE_LIBSSL
2113355b4669Sjacobs     if (SSL_pending((SSL *)(http->tls)))
2114355b4669Sjacobs       return (1);
2115355b4669Sjacobs #  elif defined(HAVE_GNUTLS)
2116355b4669Sjacobs     if (gnutls_record_check_pending(((http_tls_t *)(http->tls))->session))
2117355b4669Sjacobs       return (1);
2118355b4669Sjacobs #  elif defined(HAVE_CDSASSL)
2119355b4669Sjacobs     size_t bytes;			/* Bytes that are available */
2120355b4669Sjacobs 
2121355b4669Sjacobs     if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0)
2122355b4669Sjacobs       return;
2123355b4669Sjacobs #  endif /* HAVE_LIBSSL */
2124355b4669Sjacobs   }
2125355b4669Sjacobs #endif /* HAVE_SSL */
2126355b4669Sjacobs 
2127355b4669Sjacobs  /*
2128355b4669Sjacobs   * Then try doing a select() to poll the socket...
2129355b4669Sjacobs   */
2130355b4669Sjacobs 
2131355b4669Sjacobs   if (!http->input_set)
2132355b4669Sjacobs   {
2133355b4669Sjacobs #ifdef WIN32
2134355b4669Sjacobs    /*
2135355b4669Sjacobs     * Windows has a fixed-size select() structure, different (surprise,
2136355b4669Sjacobs     * surprise!) from all UNIX implementations.  Just allocate this
2137355b4669Sjacobs     * fixed structure...
2138355b4669Sjacobs     */
2139355b4669Sjacobs 
2140355b4669Sjacobs     http->input_set = calloc(1, sizeof(fd_set));
2141355b4669Sjacobs #else
2142355b4669Sjacobs    /*
2143355b4669Sjacobs     * Allocate the select() input set based upon the max number of file
2144355b4669Sjacobs     * descriptors available for this process...
2145355b4669Sjacobs     */
2146355b4669Sjacobs 
2147355b4669Sjacobs     getrlimit(RLIMIT_NOFILE, &limit);
2148355b4669Sjacobs 
2149355b4669Sjacobs     set_size = (limit.rlim_cur + 31) / 8 + 4;
2150355b4669Sjacobs     if (set_size < sizeof(fd_set))
2151355b4669Sjacobs       set_size = sizeof(fd_set);
2152355b4669Sjacobs 
2153355b4669Sjacobs     http->input_set = calloc(1, set_size);
2154355b4669Sjacobs #endif /* WIN32 */
2155355b4669Sjacobs 
2156355b4669Sjacobs     if (!http->input_set)
2157355b4669Sjacobs       return (0);
2158355b4669Sjacobs   }
2159355b4669Sjacobs 
2160355b4669Sjacobs   do
2161355b4669Sjacobs   {
2162355b4669Sjacobs     FD_SET(http->fd, http->input_set);
2163355b4669Sjacobs 
2164355b4669Sjacobs     if (msec >= 0)
2165355b4669Sjacobs     {
2166355b4669Sjacobs       timeout.tv_sec  = msec / 1000;
2167355b4669Sjacobs       timeout.tv_usec = (msec % 1000) * 1000;
2168355b4669Sjacobs 
2169355b4669Sjacobs       nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout);
2170355b4669Sjacobs     }
2171355b4669Sjacobs     else
2172355b4669Sjacobs       nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
2173355b4669Sjacobs   }
2174355b4669Sjacobs #ifdef WIN32
2175355b4669Sjacobs   while (nfds < 0 && WSAGetLastError() == WSAEINTR);
2176355b4669Sjacobs #else
2177355b4669Sjacobs   while (nfds < 0 && errno == EINTR);
2178355b4669Sjacobs #endif /* WIN32 */
2179355b4669Sjacobs 
2180355b4669Sjacobs   FD_CLR(http->fd, http->input_set);
2181355b4669Sjacobs 
2182355b4669Sjacobs   return (nfds > 0);
2183355b4669Sjacobs }
2184355b4669Sjacobs 
2185355b4669Sjacobs 
2186355b4669Sjacobs #ifdef HAVE_SSL
2187355b4669Sjacobs /*
2188355b4669Sjacobs  * 'http_upgrade()' - Force upgrade to TLS encryption.
2189355b4669Sjacobs  */
2190355b4669Sjacobs 
2191355b4669Sjacobs static int			/* O - Status of connection */
http_upgrade(http_t * http)2192355b4669Sjacobs http_upgrade(http_t *http)	/* I - HTTP data */
2193355b4669Sjacobs {
2194355b4669Sjacobs   int		ret;		/* Return value */
2195355b4669Sjacobs   http_t	myhttp;		/* Local copy of HTTP data */
2196355b4669Sjacobs 
2197355b4669Sjacobs 
2198355b4669Sjacobs   DEBUG_printf(("http_upgrade(%p)\n", http));
2199355b4669Sjacobs 
2200355b4669Sjacobs  /*
2201355b4669Sjacobs   * Copy the HTTP data to a local variable so we can do the OPTIONS
2202355b4669Sjacobs   * request without interfering with the existing request data...
2203355b4669Sjacobs   */
2204355b4669Sjacobs 
2205355b4669Sjacobs   memcpy(&myhttp, http, sizeof(myhttp));
2206355b4669Sjacobs 
2207355b4669Sjacobs  /*
2208355b4669Sjacobs   * Send an OPTIONS request to the server, requiring SSL or TLS
2209355b4669Sjacobs   * encryption on the link...
2210355b4669Sjacobs   */
2211355b4669Sjacobs 
2212355b4669Sjacobs   httpClearFields(&myhttp);
2213355b4669Sjacobs   httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
2214355b4669Sjacobs   httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
2215355b4669Sjacobs 
2216355b4669Sjacobs   if ((ret = httpOptions(&myhttp, "*")) == 0)
2217355b4669Sjacobs   {
2218355b4669Sjacobs    /*
2219355b4669Sjacobs     * Wait for the secure connection...
2220355b4669Sjacobs     */
2221355b4669Sjacobs 
2222355b4669Sjacobs     while (httpUpdate(&myhttp) == HTTP_CONTINUE);
2223355b4669Sjacobs   }
2224355b4669Sjacobs 
2225355b4669Sjacobs   httpFlush(&myhttp);
2226355b4669Sjacobs 
2227355b4669Sjacobs  /*
2228355b4669Sjacobs   * Copy the HTTP data back over, if any...
2229355b4669Sjacobs   */
2230355b4669Sjacobs 
2231355b4669Sjacobs   http->fd         = myhttp.fd;
2232355b4669Sjacobs   http->error      = myhttp.error;
2233355b4669Sjacobs   http->activity   = myhttp.activity;
2234355b4669Sjacobs   http->status     = myhttp.status;
2235355b4669Sjacobs   http->version    = myhttp.version;
2236355b4669Sjacobs   http->keep_alive = myhttp.keep_alive;
2237355b4669Sjacobs   http->used       = myhttp.used;
2238355b4669Sjacobs 
2239355b4669Sjacobs   if (http->used)
2240355b4669Sjacobs     memcpy(http->buffer, myhttp.buffer, http->used);
2241355b4669Sjacobs 
2242355b4669Sjacobs   http->auth_type   = myhttp.auth_type;
2243355b4669Sjacobs   http->nonce_count = myhttp.nonce_count;
2244355b4669Sjacobs 
2245355b4669Sjacobs   memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
2246355b4669Sjacobs 
2247355b4669Sjacobs   http->tls        = myhttp.tls;
2248355b4669Sjacobs   http->encryption = myhttp.encryption;
2249355b4669Sjacobs 
2250355b4669Sjacobs  /*
2251355b4669Sjacobs   * See if we actually went secure...
2252355b4669Sjacobs   */
2253355b4669Sjacobs 
2254355b4669Sjacobs   if (!http->tls)
2255355b4669Sjacobs   {
2256355b4669Sjacobs    /*
2257355b4669Sjacobs     * Server does not support HTTP upgrade...
2258355b4669Sjacobs     */
2259355b4669Sjacobs 
2260355b4669Sjacobs     DEBUG_puts("Server does not support HTTP upgrade!");
2261355b4669Sjacobs 
2262355b4669Sjacobs #  ifdef WIN32
2263355b4669Sjacobs     closesocket(http->fd);
2264355b4669Sjacobs #  else
2265355b4669Sjacobs     close(http->fd);
2266355b4669Sjacobs #  endif
2267355b4669Sjacobs 
2268355b4669Sjacobs     http->fd = -1;
2269355b4669Sjacobs 
2270355b4669Sjacobs     return (-1);
2271355b4669Sjacobs   }
2272355b4669Sjacobs   else
2273355b4669Sjacobs     return (ret);
2274355b4669Sjacobs }
2275355b4669Sjacobs 
2276355b4669Sjacobs 
2277355b4669Sjacobs /*
2278355b4669Sjacobs  * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
2279355b4669Sjacobs  */
2280355b4669Sjacobs 
2281355b4669Sjacobs static int				/* O - Status of connection */
http_setup_ssl(http_t * http)2282355b4669Sjacobs http_setup_ssl(http_t *http)		/* I - HTTP data */
2283355b4669Sjacobs {
2284355b4669Sjacobs #  ifdef HAVE_LIBSSL
2285355b4669Sjacobs   SSL_CTX	*context;	/* Context for encryption */
2286355b4669Sjacobs   SSL		*conn;		/* Connection for encryption */
2287355b4669Sjacobs #  elif defined(HAVE_GNUTLS)
2288355b4669Sjacobs   http_tls_t	*conn;		/* TLS session object */
2289355b4669Sjacobs   gnutls_certificate_client_credentials *credentials;
2290355b4669Sjacobs 				/* TLS credentials */
2291355b4669Sjacobs #  elif defined(HAVE_CDSASSL)
2292355b4669Sjacobs   SSLContextRef	conn;		/* Context for encryption */
2293355b4669Sjacobs   OSStatus	error;		/* Error info */
2294355b4669Sjacobs #  endif /* HAVE_LIBSSL */
2295355b4669Sjacobs 
2296355b4669Sjacobs 
2297355b4669Sjacobs   DEBUG_printf(("http_setup_ssl(http=%p)\n", http));
2298355b4669Sjacobs 
2299355b4669Sjacobs #  ifdef HAVE_LIBSSL
2300355b4669Sjacobs   context = SSL_CTX_new(SSLv23_client_method());
2301355b4669Sjacobs 
2302355b4669Sjacobs   SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
2303355b4669Sjacobs 
2304355b4669Sjacobs   conn = SSL_new(context);
2305355b4669Sjacobs 
2306355b4669Sjacobs   SSL_set_fd(conn, http->fd);
2307355b4669Sjacobs   if (SSL_connect(conn) != 1)
2308355b4669Sjacobs   {
2309355b4669Sjacobs #    ifdef DEBUG
2310355b4669Sjacobs     unsigned long	error;	/* Error code */
2311355b4669Sjacobs 
2312355b4669Sjacobs     while ((error = ERR_get_error()) != 0)
2313355b4669Sjacobs       printf("http_setup_ssl: %s\n", ERR_error_string(error, NULL));
2314355b4669Sjacobs #    endif /* DEBUG */
2315355b4669Sjacobs 
2316355b4669Sjacobs     SSL_CTX_free(context);
2317355b4669Sjacobs     SSL_free(conn);
2318355b4669Sjacobs 
2319355b4669Sjacobs #    ifdef WIN32
2320355b4669Sjacobs     http->error  = WSAGetLastError();
2321355b4669Sjacobs #    else
2322355b4669Sjacobs     http->error  = errno;
2323355b4669Sjacobs #    endif /* WIN32 */
2324355b4669Sjacobs     http->status = HTTP_ERROR;
2325355b4669Sjacobs 
2326355b4669Sjacobs     return (HTTP_ERROR);
2327355b4669Sjacobs   }
2328355b4669Sjacobs 
2329355b4669Sjacobs #  elif defined(HAVE_GNUTLS)
2330355b4669Sjacobs   conn = (http_tls_t *)malloc(sizeof(http_tls_t));
2331355b4669Sjacobs 
2332355b4669Sjacobs   if (conn == NULL)
2333355b4669Sjacobs   {
2334355b4669Sjacobs     http->error  = errno;
2335355b4669Sjacobs     http->status = HTTP_ERROR;
2336355b4669Sjacobs 
2337355b4669Sjacobs     return (-1);
2338355b4669Sjacobs   }
2339355b4669Sjacobs 
2340355b4669Sjacobs   credentials = (gnutls_certificate_client_credentials *)
2341355b4669Sjacobs                     malloc(sizeof(gnutls_certificate_client_credentials));
2342355b4669Sjacobs   if (credentials == NULL)
2343355b4669Sjacobs   {
2344355b4669Sjacobs     free(conn);
2345355b4669Sjacobs 
2346355b4669Sjacobs     http->error = errno;
2347355b4669Sjacobs     http->status = HTTP_ERROR;
2348355b4669Sjacobs 
2349355b4669Sjacobs     return (-1);
2350355b4669Sjacobs   }
2351355b4669Sjacobs 
2352355b4669Sjacobs   gnutls_certificate_allocate_credentials(credentials);
2353355b4669Sjacobs 
2354355b4669Sjacobs   gnutls_init(&(conn->session), GNUTLS_CLIENT);
2355355b4669Sjacobs   gnutls_set_default_priority(conn->session);
2356355b4669Sjacobs   gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
2357355b4669Sjacobs   gnutls_transport_set_ptr(conn->session, http->fd);
2358355b4669Sjacobs 
2359355b4669Sjacobs   if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
2360355b4669Sjacobs   {
2361355b4669Sjacobs     http->error  = errno;
2362355b4669Sjacobs     http->status = HTTP_ERROR;
2363355b4669Sjacobs 
2364355b4669Sjacobs     return (-1);
2365355b4669Sjacobs   }
2366355b4669Sjacobs 
2367355b4669Sjacobs   conn->credentials = credentials;
2368355b4669Sjacobs 
2369355b4669Sjacobs #  elif defined(HAVE_CDSASSL)
2370355b4669Sjacobs   error = SSLNewContext(false, &conn);
2371355b4669Sjacobs 
2372355b4669Sjacobs   if (!error)
2373355b4669Sjacobs     error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc);
2374355b4669Sjacobs 
2375355b4669Sjacobs   if (!error)
2376355b4669Sjacobs     error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
2377355b4669Sjacobs 
2378355b4669Sjacobs   if (!error)
2379355b4669Sjacobs     error = SSLSetAllowsExpiredCerts(conn, true);
2380355b4669Sjacobs 
2381355b4669Sjacobs   if (!error)
2382355b4669Sjacobs     error = SSLSetAllowsAnyRoot(conn, true);
2383355b4669Sjacobs 
2384355b4669Sjacobs   if (!error)
2385355b4669Sjacobs     error = SSLHandshake(conn);
2386355b4669Sjacobs 
2387355b4669Sjacobs   if (error != 0)
2388355b4669Sjacobs   {
2389355b4669Sjacobs     http->error  = error;
2390355b4669Sjacobs     http->status = HTTP_ERROR;
2391355b4669Sjacobs 
2392355b4669Sjacobs     SSLDisposeContext(conn);
2393355b4669Sjacobs 
2394355b4669Sjacobs     close(http->fd);
2395355b4669Sjacobs 
2396355b4669Sjacobs     return (-1);
2397355b4669Sjacobs   }
2398355b4669Sjacobs #  endif /* HAVE_CDSASSL */
2399355b4669Sjacobs 
2400355b4669Sjacobs   http->tls = conn;
2401355b4669Sjacobs   return (0);
2402355b4669Sjacobs }
2403355b4669Sjacobs 
2404355b4669Sjacobs 
2405355b4669Sjacobs /*
2406355b4669Sjacobs  * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
2407355b4669Sjacobs  */
2408355b4669Sjacobs 
2409355b4669Sjacobs static void
http_shutdown_ssl(http_t * http)2410355b4669Sjacobs http_shutdown_ssl(http_t *http)	/* I - HTTP data */
2411355b4669Sjacobs {
2412355b4669Sjacobs #  ifdef HAVE_LIBSSL
2413355b4669Sjacobs   SSL_CTX	*context;	/* Context for encryption */
2414355b4669Sjacobs   SSL		*conn;		/* Connection for encryption */
2415355b4669Sjacobs 
2416355b4669Sjacobs 
2417355b4669Sjacobs   conn    = (SSL *)(http->tls);
2418355b4669Sjacobs   context = SSL_get_SSL_CTX(conn);
2419355b4669Sjacobs 
2420355b4669Sjacobs   SSL_shutdown(conn);
2421355b4669Sjacobs   SSL_CTX_free(context);
2422355b4669Sjacobs   SSL_free(conn);
2423355b4669Sjacobs 
2424355b4669Sjacobs #  elif defined(HAVE_GNUTLS)
2425355b4669Sjacobs   http_tls_t      *conn;	/* Encryption session */
2426355b4669Sjacobs   gnutls_certificate_client_credentials *credentials;
2427355b4669Sjacobs 				/* TLS credentials */
2428355b4669Sjacobs 
2429355b4669Sjacobs 
2430355b4669Sjacobs   conn = (http_tls_t *)(http->tls);
2431355b4669Sjacobs   credentials = (gnutls_certificate_client_credentials *)(conn->credentials);
2432355b4669Sjacobs 
2433355b4669Sjacobs   gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
2434355b4669Sjacobs   gnutls_deinit(conn->session);
2435355b4669Sjacobs   gnutls_certificate_free_credentials(*credentials);
2436355b4669Sjacobs   free(credentials);
2437355b4669Sjacobs   free(conn);
2438355b4669Sjacobs 
2439355b4669Sjacobs #  elif defined(HAVE_CDSASSL)
2440355b4669Sjacobs   SSLClose((SSLContextRef)http->tls);
2441355b4669Sjacobs   SSLDisposeContext((SSLContextRef)http->tls);
2442355b4669Sjacobs #  endif /* HAVE_LIBSSL */
2443355b4669Sjacobs 
2444355b4669Sjacobs   http->tls = NULL;
2445355b4669Sjacobs }
2446355b4669Sjacobs 
2447355b4669Sjacobs 
2448355b4669Sjacobs /*
2449355b4669Sjacobs  * 'http_read_ssl()' - Read from a SSL/TLS connection.
2450355b4669Sjacobs  */
2451355b4669Sjacobs 
2452355b4669Sjacobs static int				/* O - Bytes read */
http_read_ssl(http_t * http,char * buf,int len)2453355b4669Sjacobs http_read_ssl(http_t *http,		/* I - HTTP data */
2454355b4669Sjacobs 	      char   *buf,		/* I - Buffer to store data */
2455355b4669Sjacobs 	      int    len)		/* I - Length of buffer */
2456355b4669Sjacobs {
2457355b4669Sjacobs #  if defined(HAVE_LIBSSL)
2458355b4669Sjacobs   return (SSL_read((SSL *)(http->tls), buf, len));
2459355b4669Sjacobs 
2460355b4669Sjacobs #  elif defined(HAVE_GNUTLS)
2461355b4669Sjacobs   return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len));
2462355b4669Sjacobs 
2463355b4669Sjacobs #  elif defined(HAVE_CDSASSL)
2464355b4669Sjacobs   OSStatus	error;			/* Error info */
2465355b4669Sjacobs   size_t	processed;		/* Number of bytes processed */
2466355b4669Sjacobs 
2467355b4669Sjacobs 
2468355b4669Sjacobs   error = SSLRead((SSLContextRef)http->tls, buf, len, &processed);
2469355b4669Sjacobs 
2470355b4669Sjacobs   if (error == 0)
2471355b4669Sjacobs     return (processed);
2472355b4669Sjacobs   else
2473355b4669Sjacobs   {
2474355b4669Sjacobs     http->error = error;
2475355b4669Sjacobs 
2476355b4669Sjacobs     return (-1);
2477355b4669Sjacobs   }
2478355b4669Sjacobs #  endif /* HAVE_LIBSSL */
2479355b4669Sjacobs }
2480355b4669Sjacobs 
2481355b4669Sjacobs 
2482355b4669Sjacobs /*
2483355b4669Sjacobs  * 'http_write_ssl()' - Write to a SSL/TLS connection.
2484355b4669Sjacobs  */
2485355b4669Sjacobs 
2486355b4669Sjacobs static int				/* O - Bytes written */
http_write_ssl(http_t * http,const char * buf,int len)2487355b4669Sjacobs http_write_ssl(http_t     *http,	/* I - HTTP data */
2488355b4669Sjacobs 	       const char *buf,		/* I - Buffer holding data */
2489355b4669Sjacobs 	       int        len)		/* I - Length of buffer */
2490355b4669Sjacobs {
2491355b4669Sjacobs #  if defined(HAVE_LIBSSL)
2492355b4669Sjacobs   return (SSL_write((SSL *)(http->tls), buf, len));
2493355b4669Sjacobs 
2494355b4669Sjacobs #  elif defined(HAVE_GNUTLS)
2495355b4669Sjacobs   return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len));
2496355b4669Sjacobs #  elif defined(HAVE_CDSASSL)
2497355b4669Sjacobs   OSStatus	error;			/* Error info */
2498355b4669Sjacobs   size_t	processed;		/* Number of bytes processed */
2499355b4669Sjacobs 
2500355b4669Sjacobs 
2501355b4669Sjacobs   error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed);
2502355b4669Sjacobs 
2503355b4669Sjacobs   if (error == 0)
2504355b4669Sjacobs     return (processed);
2505355b4669Sjacobs   else
2506355b4669Sjacobs   {
2507355b4669Sjacobs     http->error = error;
2508355b4669Sjacobs     return (-1);
2509355b4669Sjacobs   }
2510355b4669Sjacobs #  endif /* HAVE_LIBSSL */
2511355b4669Sjacobs }
2512355b4669Sjacobs 
2513355b4669Sjacobs 
2514355b4669Sjacobs #  if defined(HAVE_CDSASSL)
2515355b4669Sjacobs /*
2516355b4669Sjacobs  * 'CDSAReadFunc()' - Read function for CDSA decryption code.
2517355b4669Sjacobs  */
2518355b4669Sjacobs 
2519355b4669Sjacobs static OSStatus					/* O  - -1 on error, 0 on success */
CDSAReadFunc(SSLConnectionRef connection,void * data,size_t * dataLength)2520355b4669Sjacobs CDSAReadFunc(SSLConnectionRef connection,	/* I  - SSL/TLS connection */
2521355b4669Sjacobs              void             *data,		/* I  - Data buffer */
2522355b4669Sjacobs 	     size_t           *dataLength)	/* IO - Number of bytes */
2523355b4669Sjacobs {
2524355b4669Sjacobs   ssize_t	bytes;				/* Number of bytes read */
2525355b4669Sjacobs 
2526355b4669Sjacobs #ifdef DEBUG_HTTP
2527355b4669Sjacobs   httpDumpData(stdout, "CDSAReadFunc:", data, *dataLength);
2528355b4669Sjacobs #endif
2529355b4669Sjacobs   bytes = recv((int)connection, data, *dataLength, 0);
2530355b4669Sjacobs   if (bytes >= 0)
2531355b4669Sjacobs   {
2532355b4669Sjacobs     *dataLength = bytes;
2533355b4669Sjacobs     return (0);
2534355b4669Sjacobs   }
2535355b4669Sjacobs   else
2536355b4669Sjacobs     return (-1);
2537355b4669Sjacobs }
2538355b4669Sjacobs 
2539355b4669Sjacobs 
2540355b4669Sjacobs /*
2541355b4669Sjacobs  * 'CDSAWriteFunc()' - Write function for CDSA encryption code.
2542355b4669Sjacobs  */
2543355b4669Sjacobs 
2544355b4669Sjacobs static OSStatus					/* O  - -1 on error, 0 on success */
CDSAWriteFunc(SSLConnectionRef connection,const void * data,size_t * dataLength)2545355b4669Sjacobs CDSAWriteFunc(SSLConnectionRef connection,	/* I  - SSL/TLS connection */
2546355b4669Sjacobs               const void       *data,		/* I  - Data buffer */
2547355b4669Sjacobs 	      size_t           *dataLength)	/* IO - Number of bytes */
2548355b4669Sjacobs {
2549355b4669Sjacobs   ssize_t bytes;
2550355b4669Sjacobs 
2551355b4669Sjacobs 
2552355b4669Sjacobs   bytes = write((int)connection, data, *dataLength);
2553355b4669Sjacobs   if (bytes >= 0)
2554355b4669Sjacobs   {
2555355b4669Sjacobs     *dataLength = bytes;
2556355b4669Sjacobs     return (0);
2557355b4669Sjacobs   }
2558355b4669Sjacobs   else
2559355b4669Sjacobs     return (-1);
2560355b4669Sjacobs }
2561355b4669Sjacobs #  endif /* HAVE_CDSASSL */
2562355b4669Sjacobs #endif /* HAVE_SSL */
2563355b4669Sjacobs 
2564355b4669Sjacobs 
2565355b4669Sjacobs /*
2566355b4669Sjacobs  * End of "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
2567355b4669Sjacobs  */
2568