]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/getputfile.c
b4be78ae598647bb8555ef6e649d7871411fa454
[thirdparty/cups.git] / cups / getputfile.c
1 /*
2 * "$Id$"
3 *
4 * Get/put file functions for CUPS.
5 *
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
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/".
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
29 #include "cups-private.h"
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 *
42 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
43 *
44 * @since CUPS 1.1.20/OS X 10.4@
45 */
46
47 http_status_t /* O - HTTP status */
48 cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
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 */
55 char if_modified_since[HTTP_MAX_VALUE];
56 /* If-Modified-Since header */
57
58
59 /*
60 * Range check input...
61 */
62
63 DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", http,
64 resource, fd));
65
66 if (!resource || fd < 0)
67 {
68 if (http)
69 http->error = EINVAL;
70
71 return (HTTP_STATUS_ERROR);
72 }
73
74 if (!http)
75 if ((http = _cupsConnect()) == NULL)
76 return (HTTP_STATUS_SERVICE_UNAVAILABLE);
77
78 /*
79 * Then send GET requests to the HTTP server...
80 */
81
82 strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE),
83 sizeof(if_modified_since));
84
85 do
86 {
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
97 httpClearFields(http);
98 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
99 httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since);
100
101 if (httpGet(http, resource))
102 {
103 if (httpReconnect2(http, 30000, NULL))
104 {
105 status = HTTP_STATUS_ERROR;
106 break;
107 }
108 else
109 {
110 status = HTTP_STATUS_UNAUTHORIZED;
111 continue;
112 }
113 }
114
115 while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
116
117 if (status == HTTP_STATUS_UNAUTHORIZED)
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))
130 {
131 status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
132 break;
133 }
134
135 if (httpReconnect2(http, 30000, NULL))
136 {
137 status = HTTP_STATUS_ERROR;
138 break;
139 }
140
141 continue;
142 }
143 #ifdef HAVE_SSL
144 else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
145 {
146 /* Flush any error message... */
147 httpFlush(http);
148
149 /* Reconnect... */
150 if (httpReconnect2(http, 30000, NULL))
151 {
152 status = HTTP_STATUS_ERROR;
153 break;
154 }
155
156 /* Upgrade with encryption... */
157 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
158
159 /* Try again, this time with encryption enabled... */
160 continue;
161 }
162 #endif /* HAVE_SSL */
163 }
164 while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED);
165
166 /*
167 * See if we actually got the file or an error...
168 */
169
170 if (status == HTTP_STATUS_OK)
171 {
172 /*
173 * Yes, copy the file...
174 */
175
176 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
177 write(fd, buffer, bytes);
178 }
179 else
180 {
181 _cupsSetHTTPError(status);
182 httpFlush(http);
183 }
184
185 /*
186 * Return the request status...
187 */
188
189 DEBUG_printf(("1cupsGetFd: Returning %d...", status));
190
191 return (status);
192 }
193
194
195 /*
196 * 'cupsGetFile()' - Get a file from the server.
197 *
198 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
199 *
200 * @since CUPS 1.1.20/OS X 10.4@
201 */
202
203 http_status_t /* O - HTTP status */
204 cupsGetFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
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
221 return (HTTP_STATUS_ERROR);
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
236 return (HTTP_STATUS_ERROR);
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
251 if (status != HTTP_STATUS_OK)
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 *
265 * This function returns @code HTTP_STATUS_CREATED@ when the file is stored
266 * successfully.
267 *
268 * @since CUPS 1.1.20/OS X 10.4@
269 */
270
271 http_status_t /* O - HTTP status */
272 cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
273 const char *resource, /* I - Resource name */
274 int fd) /* I - File descriptor */
275 {
276 int bytes, /* Number of bytes read */
277 retries; /* Number of retries */
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
286 DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", http,
287 resource, fd));
288
289 if (!resource || fd < 0)
290 {
291 if (http)
292 http->error = EINVAL;
293
294 return (HTTP_STATUS_ERROR);
295 }
296
297 if (!http)
298 if ((http = _cupsConnect()) == NULL)
299 return (HTTP_STATUS_SERVICE_UNAVAILABLE);
300
301 /*
302 * Then send PUT requests to the HTTP server...
303 */
304
305 retries = 0;
306
307 do
308 {
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
319 DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
320 http->authstring));
321
322 httpClearFields(http);
323 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
324 httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
325 httpSetExpect(http, HTTP_STATUS_CONTINUE);
326
327 if (httpPut(http, resource))
328 {
329 if (httpReconnect2(http, 30000, NULL))
330 {
331 status = HTTP_STATUS_ERROR;
332 break;
333 }
334 else
335 {
336 status = HTTP_STATUS_UNAUTHORIZED;
337 continue;
338 }
339 }
340
341 /*
342 * Wait up to 1 second for a 100-continue response...
343 */
344
345 if (httpWait(http, 1000))
346 status = httpUpdate(http);
347 else
348 status = HTTP_STATUS_CONTINUE;
349
350 if (status == HTTP_STATUS_CONTINUE)
351 {
352 /*
353 * Copy the file...
354 */
355
356 lseek(fd, 0, SEEK_SET);
357
358 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
359 if (httpCheck(http))
360 {
361 if ((status = httpUpdate(http)) != HTTP_STATUS_CONTINUE)
362 break;
363 }
364 else
365 httpWrite2(http, buffer, bytes);
366 }
367
368 if (status == HTTP_STATUS_CONTINUE)
369 {
370 httpWrite2(http, buffer, 0);
371
372 while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
373 }
374
375 if (status == HTTP_STATUS_ERROR && !retries)
376 {
377 DEBUG_printf(("2cupsPutFd: retry on status %d", status));
378
379 retries ++;
380
381 /* Flush any error message... */
382 httpFlush(http);
383
384 /* Reconnect... */
385 if (httpReconnect2(http, 30000, NULL))
386 {
387 status = HTTP_STATUS_ERROR;
388 break;
389 }
390
391 /* Try again... */
392 continue;
393 }
394
395 DEBUG_printf(("2cupsPutFd: status=%d", status));
396
397 if (status == HTTP_STATUS_UNAUTHORIZED)
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))
410 {
411 status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
412 break;
413 }
414
415 if (httpReconnect2(http, 30000, NULL))
416 {
417 status = HTTP_STATUS_ERROR;
418 break;
419 }
420
421 continue;
422 }
423 #ifdef HAVE_SSL
424 else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
425 {
426 /* Flush any error message... */
427 httpFlush(http);
428
429 /* Reconnect... */
430 if (httpReconnect2(http, 30000, NULL))
431 {
432 status = HTTP_STATUS_ERROR;
433 break;
434 }
435
436 /* Upgrade with encryption... */
437 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
438
439 /* Try again, this time with encryption enabled... */
440 continue;
441 }
442 #endif /* HAVE_SSL */
443 }
444 while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED ||
445 (status == HTTP_STATUS_ERROR && retries < 2));
446
447 /*
448 * See if we actually put the file or an error...
449 */
450
451 if (status != HTTP_STATUS_CREATED)
452 {
453 _cupsSetHTTPError(status);
454 httpFlush(http);
455 }
456
457 DEBUG_printf(("1cupsPutFd: Returning %d...", status));
458
459 return (status);
460 }
461
462
463 /*
464 * 'cupsPutFile()' - Put a file on the server.
465 *
466 * This function returns @code HTTP_CREATED@ when the file is stored
467 * successfully.
468 *
469 * @since CUPS 1.1.20/OS X 10.4@
470 */
471
472 http_status_t /* O - HTTP status */
473 cupsPutFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
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
490 return (HTTP_STATUS_ERROR);
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
505 return (HTTP_STATUS_ERROR);
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 /*
521 * End of "$Id$".
522 */