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