]>
Commit | Line | Data |
---|---|---|
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 | 32 | http_status_t /* O - HTTP status */ |
568fa3fa | 33 | cupsGetFd(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 | 187 | http_status_t /* O - HTTP status */ |
568fa3fa | 188 | cupsGetFile(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 | 255 | http_status_t /* O - HTTP status */ |
568fa3fa | 256 | cupsPutFd(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 | 455 | http_status_t /* O - HTTP status */ |
568fa3fa | 456 | cupsPutFile(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 | } |