]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/getputfile.c
Update finishings support to use standard (or standard-inspired) PPD option
[thirdparty/cups.git] / cups / getputfile.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * Get/put file functions for CUPS.
ef416fc2 3 *
16f67389 4 * Copyright 2007-2018 by Apple Inc.
7e86f2f6 5 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 6 *
16f67389
MS
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
ef416fc2 9 */
10
11/*
12 * Include necessary headers...
13 */
14
71e16022 15#include "cups-private.h"
fb863569 16#include "debug-internal.h"
ef416fc2 17#include <fcntl.h>
18#include <sys/stat.h>
19dc16f7 19#if defined(_WIN32) || defined(__EMX__)
ef416fc2 20# include <io.h>
21#else
22# include <unistd.h>
19dc16f7 23#endif /* _WIN32 || __EMX__ */
ef416fc2 24
25
26/*
27 * 'cupsGetFd()' - Get a file from the server.
28 *
cb7f98ee 29 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
ef416fc2 30 *
8072030b 31 * @since CUPS 1.1.20/macOS 10.4@
ef416fc2 32 */
33
ecdc0628 34http_status_t /* O - HTTP status */
568fa3fa 35cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
ef416fc2 36 const char *resource, /* I - Resource name */
37 int fd) /* I - File descriptor */
38{
7e86f2f6 39 ssize_t bytes; /* Number of bytes read */
ef416fc2 40 char buffer[8192]; /* Buffer for file */
41 http_status_t status; /* HTTP status from server */
757d2cad 42 char if_modified_since[HTTP_MAX_VALUE];
43 /* If-Modified-Since header */
16f67389
MS
44 int new_auth = 0; /* Using new auth information? */
45 int digest; /* Are we using Digest authentication? */
ef416fc2 46
47
48 /*
49 * Range check input...
50 */
51
807315e6 52 DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));
ef416fc2 53
5a738aea 54 if (!resource || fd < 0)
ef416fc2 55 {
56 if (http)
57 http->error = EINVAL;
58
cb7f98ee 59 return (HTTP_STATUS_ERROR);
ef416fc2 60 }
61
5a738aea 62 if (!http)
a603edef 63 if ((http = _cupsConnect()) == NULL)
cb7f98ee 64 return (HTTP_STATUS_SERVICE_UNAVAILABLE);
5a738aea 65
ef416fc2 66 /*
67 * Then send GET requests to the HTTP server...
68 */
69
757d2cad 70 strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE),
71 sizeof(if_modified_since));
72
ef416fc2 73 do
74 {
0c4bedc4
MS
75 if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
76 {
77 httpClearFields(http);
78 if (httpReconnect2(http, 30000, NULL))
79 {
80 status = HTTP_STATUS_ERROR;
81 break;
82 }
83 }
84
ef416fc2 85 httpClearFields(http);
757d2cad 86 httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since);
ef416fc2 87
16f67389
MS
88 digest = http->authstring && !strncmp(http->authstring, "Digest ", 7);
89
90 if (digest && !new_auth)
91 {
92 /*
93 * Update the Digest authentication string...
94 */
95
5737d5eb 96 _httpSetDigestAuthString(http, http->nextnonce, "GET", resource);
16f67389
MS
97 }
98
99#ifdef HAVE_GSSAPI
100 if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth)
101 {
102 /*
103 * Do not use cached Kerberos credentials since they will look like a
104 * "replay" attack...
105 */
106
107 _cupsSetNegotiateAuthString(http, "GET", resource);
108 }
109#endif /* HAVE_GSSAPI */
110
111 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
112
ef416fc2 113 if (httpGet(http, resource))
114 {
cb7f98ee 115 if (httpReconnect2(http, 30000, NULL))
ef416fc2 116 {
cb7f98ee 117 status = HTTP_STATUS_ERROR;
ef416fc2 118 break;
119 }
120 else
121 {
cb7f98ee 122 status = HTTP_STATUS_UNAUTHORIZED;
ef416fc2 123 continue;
124 }
125 }
126
16f67389
MS
127 new_auth = 0;
128
cb7f98ee 129 while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
ef416fc2 130
cb7f98ee 131 if (status == HTTP_STATUS_UNAUTHORIZED)
ef416fc2 132 {
133 /*
134 * Flush any error message...
135 */
136
137 httpFlush(http);
138
139 /*
140 * See if we can do authentication...
141 */
142
16f67389
MS
143 new_auth = 1;
144
ef416fc2 145 if (cupsDoAuthentication(http, "GET", resource))
f11a948a 146 {
cb7f98ee 147 status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
ef416fc2 148 break;
f11a948a 149 }
ef416fc2 150
cb7f98ee 151 if (httpReconnect2(http, 30000, NULL))
fa73b229 152 {
cb7f98ee 153 status = HTTP_STATUS_ERROR;
fa73b229 154 break;
155 }
ef416fc2 156
157 continue;
158 }
159#ifdef HAVE_SSL
cb7f98ee 160 else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
ef416fc2 161 {
162 /* Flush any error message... */
163 httpFlush(http);
164
165 /* Reconnect... */
cb7f98ee 166 if (httpReconnect2(http, 30000, NULL))
fa73b229 167 {
cb7f98ee 168 status = HTTP_STATUS_ERROR;
fa73b229 169 break;
170 }
ef416fc2 171
172 /* Upgrade with encryption... */
cb7f98ee 173 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
ef416fc2 174
175 /* Try again, this time with encryption enabled... */
176 continue;
177 }
178#endif /* HAVE_SSL */
179 }
cb7f98ee 180 while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED);
ef416fc2 181
182 /*
183 * See if we actually got the file or an error...
184 */
185
cb7f98ee 186 if (status == HTTP_STATUS_OK)
ef416fc2 187 {
188 /*
189 * Yes, copy the file...
190 */
191
a4d04587 192 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
7e86f2f6 193 write(fd, buffer, (size_t)bytes);
ef416fc2 194 }
195 else
355e94dc
MS
196 {
197 _cupsSetHTTPError(status);
ef416fc2 198 httpFlush(http);
355e94dc 199 }
ef416fc2 200
201 /*
202 * Return the request status...
203 */
204
e07d4801
MS
205 DEBUG_printf(("1cupsGetFd: Returning %d...", status));
206
ef416fc2 207 return (status);
208}
209
210
211/*
212 * 'cupsGetFile()' - Get a file from the server.
213 *
cb7f98ee 214 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
ef416fc2 215 *
8072030b 216 * @since CUPS 1.1.20/macOS 10.4@
ef416fc2 217 */
218
ecdc0628 219http_status_t /* O - HTTP status */
568fa3fa 220cupsGetFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
ef416fc2 221 const char *resource, /* I - Resource name */
222 const char *filename) /* I - Filename */
223{
224 int fd; /* File descriptor */
225 http_status_t status; /* Status */
226
227
228 /*
229 * Range check input...
230 */
231
232 if (!http || !resource || !filename)
233 {
234 if (http)
235 http->error = EINVAL;
236
cb7f98ee 237 return (HTTP_STATUS_ERROR);
ef416fc2 238 }
239
240 /*
241 * Create the file...
242 */
243
244 if ((fd = open(filename, O_WRONLY | O_EXCL | O_TRUNC)) < 0)
245 {
246 /*
247 * Couldn't open the file!
248 */
249
250 http->error = errno;
251
cb7f98ee 252 return (HTTP_STATUS_ERROR);
ef416fc2 253 }
254
255 /*
256 * Get the file...
257 */
258
259 status = cupsGetFd(http, resource, fd);
260
261 /*
262 * If the file couldn't be gotten, then remove the file...
263 */
264
265 close(fd);
266
cb7f98ee 267 if (status != HTTP_STATUS_OK)
ef416fc2 268 unlink(filename);
269
270 /*
271 * Return the HTTP status code...
272 */
273
274 return (status);
275}
276
277
278/*
279 * 'cupsPutFd()' - Put a file on the server.
280 *
cb7f98ee 281 * This function returns @code HTTP_STATUS_CREATED@ when the file is stored
5a738aea 282 * successfully.
ef416fc2 283 *
8072030b 284 * @since CUPS 1.1.20/macOS 10.4@
ef416fc2 285 */
286
ecdc0628 287http_status_t /* O - HTTP status */
568fa3fa 288cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
ef416fc2 289 const char *resource, /* I - Resource name */
290 int fd) /* I - File descriptor */
291{
7e86f2f6
MS
292 ssize_t bytes; /* Number of bytes read */
293 int retries; /* Number of retries */
ef416fc2 294 char buffer[8192]; /* Buffer for file */
295 http_status_t status; /* HTTP status from server */
16f67389
MS
296 int new_auth = 0; /* Using new auth information? */
297 int digest; /* Are we using Digest authentication? */
ef416fc2 298
299
300 /*
301 * Range check input...
302 */
303
807315e6 304 DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));
ef416fc2 305
5a738aea 306 if (!resource || fd < 0)
ef416fc2 307 {
308 if (http)
309 http->error = EINVAL;
310
cb7f98ee 311 return (HTTP_STATUS_ERROR);
ef416fc2 312 }
313
5a738aea 314 if (!http)
a603edef 315 if ((http = _cupsConnect()) == NULL)
cb7f98ee 316 return (HTTP_STATUS_SERVICE_UNAVAILABLE);
5a738aea 317
ef416fc2 318 /*
319 * Then send PUT requests to the HTTP server...
320 */
321
bd7854cb 322 retries = 0;
323
ef416fc2 324 do
325 {
0c4bedc4
MS
326 if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
327 {
328 httpClearFields(http);
329 if (httpReconnect2(http, 30000, NULL))
330 {
331 status = HTTP_STATUS_ERROR;
332 break;
333 }
334 }
335
e07d4801 336 DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
ef416fc2 337 http->authstring));
338
339 httpClearFields(http);
ef416fc2 340 httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
cb7f98ee 341 httpSetExpect(http, HTTP_STATUS_CONTINUE);
ef416fc2 342
16f67389
MS
343 digest = http->authstring && !strncmp(http->authstring, "Digest ", 7);
344
345 if (digest && !new_auth)
346 {
347 /*
348 * Update the Digest authentication string...
349 */
350
5737d5eb 351 _httpSetDigestAuthString(http, http->nextnonce, "PUT", resource);
16f67389
MS
352 }
353
354#ifdef HAVE_GSSAPI
355 if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth)
356 {
357 /*
358 * Do not use cached Kerberos credentials since they will look like a
359 * "replay" attack...
360 */
361
362 _cupsSetNegotiateAuthString(http, "PUT", resource);
363 }
364#endif /* HAVE_GSSAPI */
365
366 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
367
ef416fc2 368 if (httpPut(http, resource))
369 {
cb7f98ee 370 if (httpReconnect2(http, 30000, NULL))
ef416fc2 371 {
cb7f98ee 372 status = HTTP_STATUS_ERROR;
ef416fc2 373 break;
374 }
375 else
376 {
cb7f98ee 377 status = HTTP_STATUS_UNAUTHORIZED;
ef416fc2 378 continue;
379 }
380 }
381
382 /*
b423cd4c 383 * Wait up to 1 second for a 100-continue response...
ef416fc2 384 */
385
b423cd4c 386 if (httpWait(http, 1000))
387 status = httpUpdate(http);
388 else
cb7f98ee 389 status = HTTP_STATUS_CONTINUE;
ef416fc2 390
cb7f98ee 391 if (status == HTTP_STATUS_CONTINUE)
b423cd4c 392 {
393 /*
394 * Copy the file...
395 */
ef416fc2 396
b423cd4c 397 lseek(fd, 0, SEEK_SET);
398
399 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
400 if (httpCheck(http))
401 {
cb7f98ee 402 if ((status = httpUpdate(http)) != HTTP_STATUS_CONTINUE)
b423cd4c 403 break;
404 }
405 else
7e86f2f6 406 httpWrite2(http, buffer, (size_t)bytes);
b423cd4c 407 }
ef416fc2 408
cb7f98ee 409 if (status == HTTP_STATUS_CONTINUE)
ef416fc2 410 {
a4d04587 411 httpWrite2(http, buffer, 0);
ef416fc2 412
cb7f98ee 413 while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
ef416fc2 414 }
415
cb7f98ee 416 if (status == HTTP_STATUS_ERROR && !retries)
bd7854cb 417 {
e07d4801 418 DEBUG_printf(("2cupsPutFd: retry on status %d", status));
bd7854cb 419
420 retries ++;
421
422 /* Flush any error message... */
423 httpFlush(http);
424
425 /* Reconnect... */
cb7f98ee 426 if (httpReconnect2(http, 30000, NULL))
bd7854cb 427 {
cb7f98ee 428 status = HTTP_STATUS_ERROR;
bd7854cb 429 break;
430 }
431
432 /* Try again... */
433 continue;
434 }
435
e07d4801 436 DEBUG_printf(("2cupsPutFd: status=%d", status));
ef416fc2 437
16f67389
MS
438 new_auth = 0;
439
cb7f98ee 440 if (status == HTTP_STATUS_UNAUTHORIZED)
ef416fc2 441 {
442 /*
443 * Flush any error message...
444 */
445
446 httpFlush(http);
447
448 /*
449 * See if we can do authentication...
450 */
451
16f67389
MS
452 new_auth = 1;
453
ef416fc2 454 if (cupsDoAuthentication(http, "PUT", resource))
f11a948a 455 {
cb7f98ee 456 status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
ef416fc2 457 break;
f11a948a 458 }
ef416fc2 459
cb7f98ee 460 if (httpReconnect2(http, 30000, NULL))
fa73b229 461 {
cb7f98ee 462 status = HTTP_STATUS_ERROR;
fa73b229 463 break;
464 }
ef416fc2 465
466 continue;
467 }
468#ifdef HAVE_SSL
cb7f98ee 469 else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
ef416fc2 470 {
471 /* Flush any error message... */
472 httpFlush(http);
473
474 /* Reconnect... */
cb7f98ee 475 if (httpReconnect2(http, 30000, NULL))
fa73b229 476 {
cb7f98ee 477 status = HTTP_STATUS_ERROR;
fa73b229 478 break;
479 }
ef416fc2 480
481 /* Upgrade with encryption... */
cb7f98ee 482 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
ef416fc2 483
484 /* Try again, this time with encryption enabled... */
485 continue;
486 }
487#endif /* HAVE_SSL */
488 }
cb7f98ee
MS
489 while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED ||
490 (status == HTTP_STATUS_ERROR && retries < 2));
ef416fc2 491
492 /*
493 * See if we actually put the file or an error...
494 */
495
cb7f98ee 496 if (status != HTTP_STATUS_CREATED)
355e94dc
MS
497 {
498 _cupsSetHTTPError(status);
ef416fc2 499 httpFlush(http);
355e94dc 500 }
ef416fc2 501
e07d4801
MS
502 DEBUG_printf(("1cupsPutFd: Returning %d...", status));
503
ef416fc2 504 return (status);
505}
506
507
508/*
509 * 'cupsPutFile()' - Put a file on the server.
510 *
5a738aea
MS
511 * This function returns @code HTTP_CREATED@ when the file is stored
512 * successfully.
ef416fc2 513 *
8072030b 514 * @since CUPS 1.1.20/macOS 10.4@
ef416fc2 515 */
516
ecdc0628 517http_status_t /* O - HTTP status */
568fa3fa 518cupsPutFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
ef416fc2 519 const char *resource, /* I - Resource name */
520 const char *filename) /* I - Filename */
521{
522 int fd; /* File descriptor */
523 http_status_t status; /* Status */
524
525
526 /*
527 * Range check input...
528 */
529
530 if (!http || !resource || !filename)
531 {
532 if (http)
533 http->error = EINVAL;
534
cb7f98ee 535 return (HTTP_STATUS_ERROR);
ef416fc2 536 }
537
538 /*
539 * Open the local file...
540 */
541
542 if ((fd = open(filename, O_RDONLY)) < 0)
543 {
544 /*
545 * Couldn't open the file!
546 */
547
548 http->error = errno;
549
cb7f98ee 550 return (HTTP_STATUS_ERROR);
ef416fc2 551 }
552
553 /*
554 * Put the file...
555 */
556
557 status = cupsPutFd(http, resource, fd);
558
559 close(fd);
560
561 return (status);
562}