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