1 /*
2  * "$Id: getputfile.c 8585 2009-04-30 22:15:05Z mike $"
3  *
4  *   Get/put file functions for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 2007-2009 by Apple Inc.
7  *   Copyright 1997-2006 by Easy Software Products.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Apple Inc. and are protected by Federal copyright
11  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  *   which should have been included with this file.  If this file is
13  *   file is missing or damaged, see the license at "http://www.cups.org/".
14  *
15  *   This file is subject to the Apple OS-Developed Software exception.
16  *
17  * Contents:
18  *
19  *   cupsGetFd()   - Get a file from the server.
20  *   cupsGetFile() - Get a file from the server.
21  *   cupsPutFd()   - Put a file on the server.
22  *   cupsPutFile() - Put a file on the server.
23  */
24 
25 /*
26  * Include necessary headers...
27  */
28 
29 #include "globals.h"
30 #include "cups.h"
31 #include "language.h"
32 #include "debug.h"
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <sys/stat.h>
38 #if defined(WIN32) || defined(__EMX__)
39 #  include <io.h>
40 #else
41 #  include <unistd.h>
42 #endif /* WIN32 || __EMX__ */
43 
44 
45 /*
46  * 'cupsGetFd()' - Get a file from the server.
47  *
48  * This function returns @code HTTP_OK@ when the file is successfully retrieved.
49  *
50  * @since CUPS 1.1.20/Mac OS X 10.4@
51  */
52 
53 http_status_t				/* O - HTTP status */
cupsGetFd(http_t * http,const char * resource,int fd)54 cupsGetFd(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
55 	  const char *resource,		/* I - Resource name */
56 	  int        fd)		/* I - File descriptor */
57 {
58   int		bytes;			/* Number of bytes read */
59   char		buffer[8192];		/* Buffer for file */
60   http_status_t	status;			/* HTTP status from server */
61   char		if_modified_since[HTTP_MAX_VALUE];
62 					/* If-Modified-Since header */
63 
64 
65  /*
66   * Range check input...
67   */
68 
69   DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", http,
70                 resource, fd));
71 
72   if (!resource || fd < 0)
73   {
74     if (http)
75       http->error = EINVAL;
76 
77     return (HTTP_ERROR);
78   }
79 
80   if (!http)
81     if ((http = _cupsConnect()) == NULL)
82       return (HTTP_SERVICE_UNAVAILABLE);
83 
84  /*
85   * Then send GET requests to the HTTP server...
86   */
87 
88   strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE),
89           sizeof(if_modified_since));
90 
91   do
92   {
93     httpClearFields(http);
94     httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
95     httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since);
96 
97     if (httpGet(http, resource))
98     {
99       if (httpReconnect(http))
100       {
101         status = HTTP_ERROR;
102 	break;
103       }
104       else
105       {
106         status = HTTP_UNAUTHORIZED;
107         continue;
108       }
109     }
110 
111     while ((status = httpUpdate(http)) == HTTP_CONTINUE);
112 
113     if (status == HTTP_UNAUTHORIZED)
114     {
115      /*
116       * Flush any error message...
117       */
118 
119       httpFlush(http);
120 
121      /*
122       * See if we can do authentication...
123       */
124 
125       if (cupsDoAuthentication(http, "GET", resource))
126       {
127         status = HTTP_AUTHORIZATION_CANCELED;
128         break;
129       }
130 
131       if (httpReconnect(http))
132       {
133         status = HTTP_ERROR;
134         break;
135       }
136 
137       continue;
138     }
139 #ifdef HAVE_SSL
140     else if (status == HTTP_UPGRADE_REQUIRED)
141     {
142       /* Flush any error message... */
143       httpFlush(http);
144 
145       /* Reconnect... */
146       if (httpReconnect(http))
147       {
148         status = HTTP_ERROR;
149         break;
150       }
151 
152       /* Upgrade with encryption... */
153       httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
154 
155       /* Try again, this time with encryption enabled... */
156       continue;
157     }
158 #endif /* HAVE_SSL */
159   }
160   while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED);
161 
162  /*
163   * See if we actually got the file or an error...
164   */
165 
166   if (status == HTTP_OK)
167   {
168    /*
169     * Yes, copy the file...
170     */
171 
172     while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
173       write(fd, buffer, bytes);
174   }
175   else
176   {
177     _cupsSetHTTPError(status);
178     httpFlush(http);
179   }
180 
181  /*
182   * Return the request status...
183   */
184 
185   DEBUG_printf(("1cupsGetFd: Returning %d...", status));
186 
187   return (status);
188 }
189 
190 
191 /*
192  * 'cupsGetFile()' - Get a file from the server.
193  *
194  * This function returns @code HTTP_OK@ when the file is successfully retrieved.
195  *
196  * @since CUPS 1.1.20/Mac OS X 10.4@
197  */
198 
199 http_status_t				/* O - HTTP status */
cupsGetFile(http_t * http,const char * resource,const char * filename)200 cupsGetFile(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
201 	    const char *resource,	/* I - Resource name */
202 	    const char *filename)	/* I - Filename */
203 {
204   int		fd;			/* File descriptor */
205   http_status_t	status;			/* Status */
206 
207 
208  /*
209   * Range check input...
210   */
211 
212   if (!http || !resource || !filename)
213   {
214     if (http)
215       http->error = EINVAL;
216 
217     return (HTTP_ERROR);
218   }
219 
220  /*
221   * Create the file...
222   */
223 
224   if ((fd = open(filename, O_WRONLY | O_EXCL | O_TRUNC)) < 0)
225   {
226    /*
227     * Couldn't open the file!
228     */
229 
230     http->error = errno;
231 
232     return (HTTP_ERROR);
233   }
234 
235  /*
236   * Get the file...
237   */
238 
239   status = cupsGetFd(http, resource, fd);
240 
241  /*
242   * If the file couldn't be gotten, then remove the file...
243   */
244 
245   close(fd);
246 
247   if (status != HTTP_OK)
248     unlink(filename);
249 
250  /*
251   * Return the HTTP status code...
252   */
253 
254   return (status);
255 }
256 
257 
258 /*
259  * 'cupsPutFd()' - Put a file on the server.
260  *
261  * This function returns @code HTTP_CREATED@ when the file is stored
262  * successfully.
263  *
264  * @since CUPS 1.1.20/Mac OS X 10.4@
265  */
266 
267 http_status_t				/* O - HTTP status */
cupsPutFd(http_t * http,const char * resource,int fd)268 cupsPutFd(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
269           const char *resource,		/* I - Resource name */
270 	  int        fd)		/* I - File descriptor */
271 {
272   int		bytes,			/* Number of bytes read */
273 		retries;		/* Number of retries */
274   char		buffer[8192];		/* Buffer for file */
275   http_status_t	status;			/* HTTP status from server */
276 
277 
278  /*
279   * Range check input...
280   */
281 
282   DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", http,
283                 resource, fd));
284 
285   if (!resource || fd < 0)
286   {
287     if (http)
288       http->error = EINVAL;
289 
290     return (HTTP_ERROR);
291   }
292 
293   if (!http)
294     if ((http = _cupsConnect()) == NULL)
295       return (HTTP_SERVICE_UNAVAILABLE);
296 
297  /*
298   * Then send PUT requests to the HTTP server...
299   */
300 
301   retries = 0;
302 
303   do
304   {
305     DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
306                   http->authstring));
307 
308     httpClearFields(http);
309     httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
310     httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
311     httpSetExpect(http, HTTP_CONTINUE);
312 
313     if (httpPut(http, resource))
314     {
315       if (httpReconnect(http))
316       {
317         status = HTTP_ERROR;
318 	break;
319       }
320       else
321       {
322         status = HTTP_UNAUTHORIZED;
323         continue;
324       }
325     }
326 
327    /*
328     * Wait up to 1 second for a 100-continue response...
329     */
330 
331     if (httpWait(http, 1000))
332       status = httpUpdate(http);
333     else
334       status = HTTP_CONTINUE;
335 
336     if (status == HTTP_CONTINUE)
337     {
338      /*
339       * Copy the file...
340       */
341 
342       lseek(fd, 0, SEEK_SET);
343 
344       while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
345 	if (httpCheck(http))
346 	{
347           if ((status = httpUpdate(http)) != HTTP_CONTINUE)
348             break;
349 	}
350 	else
351           httpWrite2(http, buffer, bytes);
352     }
353 
354     if (status == HTTP_CONTINUE)
355     {
356       httpWrite2(http, buffer, 0);
357 
358       while ((status = httpUpdate(http)) == HTTP_CONTINUE);
359     }
360 
361     if (status == HTTP_ERROR && !retries)
362     {
363       DEBUG_printf(("2cupsPutFd: retry on status %d", status));
364 
365       retries ++;
366 
367       /* Flush any error message... */
368       httpFlush(http);
369 
370       /* Reconnect... */
371       if (httpReconnect(http))
372       {
373         status = HTTP_ERROR;
374         break;
375       }
376 
377       /* Try again... */
378       continue;
379     }
380 
381     DEBUG_printf(("2cupsPutFd: status=%d", status));
382 
383     if (status == HTTP_UNAUTHORIZED)
384     {
385      /*
386       * Flush any error message...
387       */
388 
389       httpFlush(http);
390 
391      /*
392       * See if we can do authentication...
393       */
394 
395       if (cupsDoAuthentication(http, "PUT", resource))
396       {
397         status = HTTP_AUTHORIZATION_CANCELED;
398         break;
399       }
400 
401       if (httpReconnect(http))
402       {
403         status = HTTP_ERROR;
404         break;
405       }
406 
407       continue;
408     }
409 #ifdef HAVE_SSL
410     else if (status == HTTP_UPGRADE_REQUIRED)
411     {
412       /* Flush any error message... */
413       httpFlush(http);
414 
415       /* Reconnect... */
416       if (httpReconnect(http))
417       {
418         status = HTTP_ERROR;
419         break;
420       }
421 
422       /* Upgrade with encryption... */
423       httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
424 
425       /* Try again, this time with encryption enabled... */
426       continue;
427     }
428 #endif /* HAVE_SSL */
429   }
430   while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED ||
431          (status == HTTP_ERROR && retries < 2));
432 
433  /*
434   * See if we actually put the file or an error...
435   */
436 
437   if (status != HTTP_CREATED)
438   {
439     _cupsSetHTTPError(status);
440     httpFlush(http);
441   }
442 
443   DEBUG_printf(("1cupsPutFd: Returning %d...", status));
444 
445   return (status);
446 }
447 
448 
449 /*
450  * 'cupsPutFile()' - Put a file on the server.
451  *
452  * This function returns @code HTTP_CREATED@ when the file is stored
453  * successfully.
454  *
455  * @since CUPS 1.1.20/Mac OS X 10.4@
456  */
457 
458 http_status_t				/* O - HTTP status */
cupsPutFile(http_t * http,const char * resource,const char * filename)459 cupsPutFile(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
460             const char *resource,	/* I - Resource name */
461 	    const char *filename)	/* I - Filename */
462 {
463   int		fd;			/* File descriptor */
464   http_status_t	status;			/* Status */
465 
466 
467  /*
468   * Range check input...
469   */
470 
471   if (!http || !resource || !filename)
472   {
473     if (http)
474       http->error = EINVAL;
475 
476     return (HTTP_ERROR);
477   }
478 
479  /*
480   * Open the local file...
481   */
482 
483   if ((fd = open(filename, O_RDONLY)) < 0)
484   {
485    /*
486     * Couldn't open the file!
487     */
488 
489     http->error = errno;
490 
491     return (HTTP_ERROR);
492   }
493 
494  /*
495   * Put the file...
496   */
497 
498   status = cupsPutFd(http, resource, fd);
499 
500   close(fd);
501 
502   return (status);
503 }
504 
505 
506 /*
507  * End of "$Id: getputfile.c 8585 2009-04-30 22:15:05Z mike $".
508  */
509