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