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