]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/getputfile.c
ae33bc5993026fe781f8877e192d6945ce3f7de9
[thirdparty/cups.git] / cups / getputfile.c
1 /*
2 * Get/put file functions for CUPS.
3 *
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
6 *
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 * missing or damaged, see the license at "http://www.cups.org/".
12 *
13 * This file is subject to the Apple OS-Developed Software exception.
14 */
15
16 /*
17 * Include necessary headers...
18 */
19
20 #include "cups-private.h"
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #if defined(WIN32) || defined(__EMX__)
24 # include <io.h>
25 #else
26 # include <unistd.h>
27 #endif /* WIN32 || __EMX__ */
28
29
30 /*
31 * 'cupsGetFd()' - Get a file from the server.
32 *
33 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
34 *
35 * @since CUPS 1.1.20/macOS 10.4@
36 */
37
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 */
42 {
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 */
48
49
50 /*
51 * Range check input...
52 */
53
54 DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));
55
56 if (!resource || fd < 0)
57 {
58 if (http)
59 http->error = EINVAL;
60
61 return (HTTP_STATUS_ERROR);
62 }
63
64 if (!http)
65 if ((http = _cupsConnect()) == NULL)
66 return (HTTP_STATUS_SERVICE_UNAVAILABLE);
67
68 /*
69 * Then send GET requests to the HTTP server...
70 */
71
72 strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE),
73 sizeof(if_modified_since));
74
75 do
76 {
77 if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
78 {
79 httpClearFields(http);
80 if (httpReconnect2(http, 30000, NULL))
81 {
82 status = HTTP_STATUS_ERROR;
83 break;
84 }
85 }
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 (httpReconnect2(http, 30000, NULL))
94 {
95 status = HTTP_STATUS_ERROR;
96 break;
97 }
98 else
99 {
100 status = HTTP_STATUS_UNAUTHORIZED;
101 continue;
102 }
103 }
104
105 while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
106
107 if (status == HTTP_STATUS_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_STATUS_CUPS_AUTHORIZATION_CANCELED;
122 break;
123 }
124
125 if (httpReconnect2(http, 30000, NULL))
126 {
127 status = HTTP_STATUS_ERROR;
128 break;
129 }
130
131 continue;
132 }
133 #ifdef HAVE_SSL
134 else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
135 {
136 /* Flush any error message... */
137 httpFlush(http);
138
139 /* Reconnect... */
140 if (httpReconnect2(http, 30000, NULL))
141 {
142 status = HTTP_STATUS_ERROR;
143 break;
144 }
145
146 /* Upgrade with encryption... */
147 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
148
149 /* Try again, this time with encryption enabled... */
150 continue;
151 }
152 #endif /* HAVE_SSL */
153 }
154 while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED);
155
156 /*
157 * See if we actually got the file or an error...
158 */
159
160 if (status == HTTP_STATUS_OK)
161 {
162 /*
163 * Yes, copy the file...
164 */
165
166 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
167 write(fd, buffer, (size_t)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_STATUS_OK@ when the file is successfully retrieved.
189 *
190 * @since CUPS 1.1.20/macOS 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_STATUS_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_STATUS_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_STATUS_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_STATUS_CREATED@ when the file is stored
256 * successfully.
257 *
258 * @since CUPS 1.1.20/macOS 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 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 */
270
271
272 /*
273 * Range check input...
274 */
275
276 DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));
277
278 if (!resource || fd < 0)
279 {
280 if (http)
281 http->error = EINVAL;
282
283 return (HTTP_STATUS_ERROR);
284 }
285
286 if (!http)
287 if ((http = _cupsConnect()) == NULL)
288 return (HTTP_STATUS_SERVICE_UNAVAILABLE);
289
290 /*
291 * Then send PUT requests to the HTTP server...
292 */
293
294 retries = 0;
295
296 do
297 {
298 if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
299 {
300 httpClearFields(http);
301 if (httpReconnect2(http, 30000, NULL))
302 {
303 status = HTTP_STATUS_ERROR;
304 break;
305 }
306 }
307
308 DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
309 http->authstring));
310
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);
315
316 if (httpPut(http, resource))
317 {
318 if (httpReconnect2(http, 30000, NULL))
319 {
320 status = HTTP_STATUS_ERROR;
321 break;
322 }
323 else
324 {
325 status = HTTP_STATUS_UNAUTHORIZED;
326 continue;
327 }
328 }
329
330 /*
331 * Wait up to 1 second for a 100-continue response...
332 */
333
334 if (httpWait(http, 1000))
335 status = httpUpdate(http);
336 else
337 status = HTTP_STATUS_CONTINUE;
338
339 if (status == HTTP_STATUS_CONTINUE)
340 {
341 /*
342 * Copy the file...
343 */
344
345 lseek(fd, 0, SEEK_SET);
346
347 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
348 if (httpCheck(http))
349 {
350 if ((status = httpUpdate(http)) != HTTP_STATUS_CONTINUE)
351 break;
352 }
353 else
354 httpWrite2(http, buffer, (size_t)bytes);
355 }
356
357 if (status == HTTP_STATUS_CONTINUE)
358 {
359 httpWrite2(http, buffer, 0);
360
361 while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
362 }
363
364 if (status == HTTP_STATUS_ERROR && !retries)
365 {
366 DEBUG_printf(("2cupsPutFd: retry on status %d", status));
367
368 retries ++;
369
370 /* Flush any error message... */
371 httpFlush(http);
372
373 /* Reconnect... */
374 if (httpReconnect2(http, 30000, NULL))
375 {
376 status = HTTP_STATUS_ERROR;
377 break;
378 }
379
380 /* Try again... */
381 continue;
382 }
383
384 DEBUG_printf(("2cupsPutFd: status=%d", status));
385
386 if (status == HTTP_STATUS_UNAUTHORIZED)
387 {
388 /*
389 * Flush any error message...
390 */
391
392 httpFlush(http);
393
394 /*
395 * See if we can do authentication...
396 */
397
398 if (cupsDoAuthentication(http, "PUT", resource))
399 {
400 status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
401 break;
402 }
403
404 if (httpReconnect2(http, 30000, NULL))
405 {
406 status = HTTP_STATUS_ERROR;
407 break;
408 }
409
410 continue;
411 }
412 #ifdef HAVE_SSL
413 else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
414 {
415 /* Flush any error message... */
416 httpFlush(http);
417
418 /* Reconnect... */
419 if (httpReconnect2(http, 30000, NULL))
420 {
421 status = HTTP_STATUS_ERROR;
422 break;
423 }
424
425 /* Upgrade with encryption... */
426 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
427
428 /* Try again, this time with encryption enabled... */
429 continue;
430 }
431 #endif /* HAVE_SSL */
432 }
433 while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED ||
434 (status == HTTP_STATUS_ERROR && retries < 2));
435
436 /*
437 * See if we actually put the file or an error...
438 */
439
440 if (status != HTTP_STATUS_CREATED)
441 {
442 _cupsSetHTTPError(status);
443 httpFlush(http);
444 }
445
446 DEBUG_printf(("1cupsPutFd: Returning %d...", status));
447
448 return (status);
449 }
450
451
452 /*
453 * 'cupsPutFile()' - Put a file on the server.
454 *
455 * This function returns @code HTTP_CREATED@ when the file is stored
456 * successfully.
457 *
458 * @since CUPS 1.1.20/macOS 10.4@
459 */
460
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 */
465 {
466 int fd; /* File descriptor */
467 http_status_t status; /* Status */
468
469
470 /*
471 * Range check input...
472 */
473
474 if (!http || !resource || !filename)
475 {
476 if (http)
477 http->error = EINVAL;
478
479 return (HTTP_STATUS_ERROR);
480 }
481
482 /*
483 * Open the local file...
484 */
485
486 if ((fd = open(filename, O_RDONLY)) < 0)
487 {
488 /*
489 * Couldn't open the file!
490 */
491
492 http->error = errno;
493
494 return (HTTP_STATUS_ERROR);
495 }
496
497 /*
498 * Put the file...
499 */
500
501 status = cupsPutFd(http, resource, fd);
502
503 close(fd);
504
505 return (status);
506 }