2 * Get/put file functions for CUPS.
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
13 * This file is subject to the Apple OS-Developed Software exception.
17 * Include necessary headers...
20 #include "cups-private.h"
23 #if defined(WIN32) || defined(__EMX__)
27 #endif /* WIN32 || __EMX__ */
31 * 'cupsGetFd()' - Get a file from the server.
33 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
35 * @since CUPS 1.1.20/macOS 10.4@
38 http_status_t
/* O - HTTP status */
39 cupsGetFd(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
40 const char *resource
, /* I - Resource name */
41 int fd
) /* I - File descriptor */
43 ssize_t bytes
; /* Number of bytes read */
44 char buffer
[8192]; /* Buffer for file */
45 http_status_t status
; /* HTTP status from server */
46 char if_modified_since
[HTTP_MAX_VALUE
];
47 /* If-Modified-Since header */
51 * Range check input...
54 DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", (void *)http
, resource
, fd
));
56 if (!resource
|| fd
< 0)
61 return (HTTP_STATUS_ERROR
);
65 if ((http
= _cupsConnect()) == NULL
)
66 return (HTTP_STATUS_SERVICE_UNAVAILABLE
);
69 * Then send GET requests to the HTTP server...
72 strlcpy(if_modified_since
, httpGetField(http
, HTTP_FIELD_IF_MODIFIED_SINCE
),
73 sizeof(if_modified_since
));
77 if (!_cups_strcasecmp(httpGetField(http
, HTTP_FIELD_CONNECTION
), "close"))
79 httpClearFields(http
);
80 if (httpReconnect2(http
, 30000, NULL
))
82 status
= HTTP_STATUS_ERROR
;
87 httpClearFields(http
);
88 httpSetField(http
, HTTP_FIELD_AUTHORIZATION
, http
->authstring
);
89 httpSetField(http
, HTTP_FIELD_IF_MODIFIED_SINCE
, if_modified_since
);
91 if (httpGet(http
, resource
))
93 if (httpReconnect2(http
, 30000, NULL
))
95 status
= HTTP_STATUS_ERROR
;
100 status
= HTTP_STATUS_UNAUTHORIZED
;
105 while ((status
= httpUpdate(http
)) == HTTP_STATUS_CONTINUE
);
107 if (status
== HTTP_STATUS_UNAUTHORIZED
)
110 * Flush any error message...
116 * See if we can do authentication...
119 if (cupsDoAuthentication(http
, "GET", resource
))
121 status
= HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED
;
125 if (httpReconnect2(http
, 30000, NULL
))
127 status
= HTTP_STATUS_ERROR
;
134 else if (status
== HTTP_STATUS_UPGRADE_REQUIRED
)
136 /* Flush any error message... */
140 if (httpReconnect2(http
, 30000, NULL
))
142 status
= HTTP_STATUS_ERROR
;
146 /* Upgrade with encryption... */
147 httpEncryption(http
, HTTP_ENCRYPTION_REQUIRED
);
149 /* Try again, this time with encryption enabled... */
152 #endif /* HAVE_SSL */
154 while (status
== HTTP_STATUS_UNAUTHORIZED
|| status
== HTTP_STATUS_UPGRADE_REQUIRED
);
157 * See if we actually got the file or an error...
160 if (status
== HTTP_STATUS_OK
)
163 * Yes, copy the file...
166 while ((bytes
= httpRead2(http
, buffer
, sizeof(buffer
))) > 0)
167 write(fd
, buffer
, (size_t)bytes
);
171 _cupsSetHTTPError(status
);
176 * Return the request status...
179 DEBUG_printf(("1cupsGetFd: Returning %d...", status
));
186 * 'cupsGetFile()' - Get a file from the server.
188 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
190 * @since CUPS 1.1.20/macOS 10.4@
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 */
198 int fd
; /* File descriptor */
199 http_status_t status
; /* Status */
203 * Range check input...
206 if (!http
|| !resource
|| !filename
)
209 http
->error
= EINVAL
;
211 return (HTTP_STATUS_ERROR
);
218 if ((fd
= open(filename
, O_WRONLY
| O_EXCL
| O_TRUNC
)) < 0)
221 * Couldn't open the file!
226 return (HTTP_STATUS_ERROR
);
233 status
= cupsGetFd(http
, resource
, fd
);
236 * If the file couldn't be gotten, then remove the file...
241 if (status
!= HTTP_STATUS_OK
)
245 * Return the HTTP status code...
253 * 'cupsPutFd()' - Put a file on the server.
255 * This function returns @code HTTP_STATUS_CREATED@ when the file is stored
258 * @since CUPS 1.1.20/macOS 10.4@
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 */
266 ssize_t bytes
; /* Number of bytes read */
267 int retries
; /* Number of retries */
268 char buffer
[8192]; /* Buffer for file */
269 http_status_t status
; /* HTTP status from server */
273 * Range check input...
276 DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", (void *)http
, resource
, fd
));
278 if (!resource
|| fd
< 0)
281 http
->error
= EINVAL
;
283 return (HTTP_STATUS_ERROR
);
287 if ((http
= _cupsConnect()) == NULL
)
288 return (HTTP_STATUS_SERVICE_UNAVAILABLE
);
291 * Then send PUT requests to the HTTP server...
298 if (!_cups_strcasecmp(httpGetField(http
, HTTP_FIELD_CONNECTION
), "close"))
300 httpClearFields(http
);
301 if (httpReconnect2(http
, 30000, NULL
))
303 status
= HTTP_STATUS_ERROR
;
308 DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
311 httpClearFields(http
);
312 httpSetField(http
, HTTP_FIELD_AUTHORIZATION
, http
->authstring
);
313 httpSetField(http
, HTTP_FIELD_TRANSFER_ENCODING
, "chunked");
314 httpSetExpect(http
, HTTP_STATUS_CONTINUE
);
316 if (httpPut(http
, resource
))
318 if (httpReconnect2(http
, 30000, NULL
))
320 status
= HTTP_STATUS_ERROR
;
325 status
= HTTP_STATUS_UNAUTHORIZED
;
331 * Wait up to 1 second for a 100-continue response...
334 if (httpWait(http
, 1000))
335 status
= httpUpdate(http
);
337 status
= HTTP_STATUS_CONTINUE
;
339 if (status
== HTTP_STATUS_CONTINUE
)
345 lseek(fd
, 0, SEEK_SET
);
347 while ((bytes
= read(fd
, buffer
, sizeof(buffer
))) > 0)
350 if ((status
= httpUpdate(http
)) != HTTP_STATUS_CONTINUE
)
354 httpWrite2(http
, buffer
, (size_t)bytes
);
357 if (status
== HTTP_STATUS_CONTINUE
)
359 httpWrite2(http
, buffer
, 0);
361 while ((status
= httpUpdate(http
)) == HTTP_STATUS_CONTINUE
);
364 if (status
== HTTP_STATUS_ERROR
&& !retries
)
366 DEBUG_printf(("2cupsPutFd: retry on status %d", status
));
370 /* Flush any error message... */
374 if (httpReconnect2(http
, 30000, NULL
))
376 status
= HTTP_STATUS_ERROR
;
384 DEBUG_printf(("2cupsPutFd: status=%d", status
));
386 if (status
== HTTP_STATUS_UNAUTHORIZED
)
389 * Flush any error message...
395 * See if we can do authentication...
398 if (cupsDoAuthentication(http
, "PUT", resource
))
400 status
= HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED
;
404 if (httpReconnect2(http
, 30000, NULL
))
406 status
= HTTP_STATUS_ERROR
;
413 else if (status
== HTTP_STATUS_UPGRADE_REQUIRED
)
415 /* Flush any error message... */
419 if (httpReconnect2(http
, 30000, NULL
))
421 status
= HTTP_STATUS_ERROR
;
425 /* Upgrade with encryption... */
426 httpEncryption(http
, HTTP_ENCRYPTION_REQUIRED
);
428 /* Try again, this time with encryption enabled... */
431 #endif /* HAVE_SSL */
433 while (status
== HTTP_STATUS_UNAUTHORIZED
|| status
== HTTP_STATUS_UPGRADE_REQUIRED
||
434 (status
== HTTP_STATUS_ERROR
&& retries
< 2));
437 * See if we actually put the file or an error...
440 if (status
!= HTTP_STATUS_CREATED
)
442 _cupsSetHTTPError(status
);
446 DEBUG_printf(("1cupsPutFd: Returning %d...", status
));
453 * 'cupsPutFile()' - Put a file on the server.
455 * This function returns @code HTTP_CREATED@ when the file is stored
458 * @since CUPS 1.1.20/macOS 10.4@
461 http_status_t
/* O - HTTP status */
462 cupsPutFile(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
463 const char *resource
, /* I - Resource name */
464 const char *filename
) /* I - Filename */
466 int fd
; /* File descriptor */
467 http_status_t status
; /* Status */
471 * Range check input...
474 if (!http
|| !resource
|| !filename
)
477 http
->error
= EINVAL
;
479 return (HTTP_STATUS_ERROR
);
483 * Open the local file...
486 if ((fd
= open(filename
, O_RDONLY
)) < 0)
489 * Couldn't open the file!
494 return (HTTP_STATUS_ERROR
);
501 status
= cupsPutFd(http
, resource
, fd
);