]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/getputfile.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / cups / getputfile.c
1 /*
2 * Get/put file functions for CUPS.
3 *
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8 */
9
10 /*
11 * Include necessary headers...
12 */
13
14 #include "cups-private.h"
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 *
27 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
28 *
29 * @since CUPS 1.1.20/macOS 10.4@
30 */
31
32 http_status_t /* O - HTTP status */
33 cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
34 const char *resource, /* I - Resource name */
35 int fd) /* I - File descriptor */
36 {
37 ssize_t bytes; /* Number of bytes read */
38 char buffer[8192]; /* Buffer for file */
39 http_status_t status; /* HTTP status from server */
40 char if_modified_since[HTTP_MAX_VALUE];
41 /* If-Modified-Since header */
42
43
44 /*
45 * Range check input...
46 */
47
48 DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));
49
50 if (!resource || fd < 0)
51 {
52 if (http)
53 http->error = EINVAL;
54
55 return (HTTP_STATUS_ERROR);
56 }
57
58 if (!http)
59 if ((http = _cupsConnect()) == NULL)
60 return (HTTP_STATUS_SERVICE_UNAVAILABLE);
61
62 /*
63 * Then send GET requests to the HTTP server...
64 */
65
66 strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE),
67 sizeof(if_modified_since));
68
69 do
70 {
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
81 httpClearFields(http);
82 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
83 httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since);
84
85 if (httpGet(http, resource))
86 {
87 if (httpReconnect2(http, 30000, NULL))
88 {
89 status = HTTP_STATUS_ERROR;
90 break;
91 }
92 else
93 {
94 status = HTTP_STATUS_UNAUTHORIZED;
95 continue;
96 }
97 }
98
99 while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
100
101 if (status == HTTP_STATUS_UNAUTHORIZED)
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))
114 {
115 status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
116 break;
117 }
118
119 if (httpReconnect2(http, 30000, NULL))
120 {
121 status = HTTP_STATUS_ERROR;
122 break;
123 }
124
125 continue;
126 }
127 #ifdef HAVE_SSL
128 else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
129 {
130 /* Flush any error message... */
131 httpFlush(http);
132
133 /* Reconnect... */
134 if (httpReconnect2(http, 30000, NULL))
135 {
136 status = HTTP_STATUS_ERROR;
137 break;
138 }
139
140 /* Upgrade with encryption... */
141 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
142
143 /* Try again, this time with encryption enabled... */
144 continue;
145 }
146 #endif /* HAVE_SSL */
147 }
148 while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED);
149
150 /*
151 * See if we actually got the file or an error...
152 */
153
154 if (status == HTTP_STATUS_OK)
155 {
156 /*
157 * Yes, copy the file...
158 */
159
160 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
161 write(fd, buffer, (size_t)bytes);
162 }
163 else
164 {
165 _cupsSetHTTPError(status);
166 httpFlush(http);
167 }
168
169 /*
170 * Return the request status...
171 */
172
173 DEBUG_printf(("1cupsGetFd: Returning %d...", status));
174
175 return (status);
176 }
177
178
179 /*
180 * 'cupsGetFile()' - Get a file from the server.
181 *
182 * This function returns @code HTTP_STATUS_OK@ when the file is successfully retrieved.
183 *
184 * @since CUPS 1.1.20/macOS 10.4@
185 */
186
187 http_status_t /* O - HTTP status */
188 cupsGetFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
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
205 return (HTTP_STATUS_ERROR);
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
220 return (HTTP_STATUS_ERROR);
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
235 if (status != HTTP_STATUS_OK)
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 *
249 * This function returns @code HTTP_STATUS_CREATED@ when the file is stored
250 * successfully.
251 *
252 * @since CUPS 1.1.20/macOS 10.4@
253 */
254
255 http_status_t /* O - HTTP status */
256 cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
257 const char *resource, /* I - Resource name */
258 int fd) /* I - File descriptor */
259 {
260 ssize_t bytes; /* Number of bytes read */
261 int retries; /* Number of retries */
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
270 DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd));
271
272 if (!resource || fd < 0)
273 {
274 if (http)
275 http->error = EINVAL;
276
277 return (HTTP_STATUS_ERROR);
278 }
279
280 if (!http)
281 if ((http = _cupsConnect()) == NULL)
282 return (HTTP_STATUS_SERVICE_UNAVAILABLE);
283
284 /*
285 * Then send PUT requests to the HTTP server...
286 */
287
288 retries = 0;
289
290 do
291 {
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
302 DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...",
303 http->authstring));
304
305 httpClearFields(http);
306 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
307 httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
308 httpSetExpect(http, HTTP_STATUS_CONTINUE);
309
310 if (httpPut(http, resource))
311 {
312 if (httpReconnect2(http, 30000, NULL))
313 {
314 status = HTTP_STATUS_ERROR;
315 break;
316 }
317 else
318 {
319 status = HTTP_STATUS_UNAUTHORIZED;
320 continue;
321 }
322 }
323
324 /*
325 * Wait up to 1 second for a 100-continue response...
326 */
327
328 if (httpWait(http, 1000))
329 status = httpUpdate(http);
330 else
331 status = HTTP_STATUS_CONTINUE;
332
333 if (status == HTTP_STATUS_CONTINUE)
334 {
335 /*
336 * Copy the file...
337 */
338
339 lseek(fd, 0, SEEK_SET);
340
341 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
342 if (httpCheck(http))
343 {
344 if ((status = httpUpdate(http)) != HTTP_STATUS_CONTINUE)
345 break;
346 }
347 else
348 httpWrite2(http, buffer, (size_t)bytes);
349 }
350
351 if (status == HTTP_STATUS_CONTINUE)
352 {
353 httpWrite2(http, buffer, 0);
354
355 while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
356 }
357
358 if (status == HTTP_STATUS_ERROR && !retries)
359 {
360 DEBUG_printf(("2cupsPutFd: retry on status %d", status));
361
362 retries ++;
363
364 /* Flush any error message... */
365 httpFlush(http);
366
367 /* Reconnect... */
368 if (httpReconnect2(http, 30000, NULL))
369 {
370 status = HTTP_STATUS_ERROR;
371 break;
372 }
373
374 /* Try again... */
375 continue;
376 }
377
378 DEBUG_printf(("2cupsPutFd: status=%d", status));
379
380 if (status == HTTP_STATUS_UNAUTHORIZED)
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))
393 {
394 status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
395 break;
396 }
397
398 if (httpReconnect2(http, 30000, NULL))
399 {
400 status = HTTP_STATUS_ERROR;
401 break;
402 }
403
404 continue;
405 }
406 #ifdef HAVE_SSL
407 else if (status == HTTP_STATUS_UPGRADE_REQUIRED)
408 {
409 /* Flush any error message... */
410 httpFlush(http);
411
412 /* Reconnect... */
413 if (httpReconnect2(http, 30000, NULL))
414 {
415 status = HTTP_STATUS_ERROR;
416 break;
417 }
418
419 /* Upgrade with encryption... */
420 httpEncryption(http, HTTP_ENCRYPTION_REQUIRED);
421
422 /* Try again, this time with encryption enabled... */
423 continue;
424 }
425 #endif /* HAVE_SSL */
426 }
427 while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED ||
428 (status == HTTP_STATUS_ERROR && retries < 2));
429
430 /*
431 * See if we actually put the file or an error...
432 */
433
434 if (status != HTTP_STATUS_CREATED)
435 {
436 _cupsSetHTTPError(status);
437 httpFlush(http);
438 }
439
440 DEBUG_printf(("1cupsPutFd: Returning %d...", status));
441
442 return (status);
443 }
444
445
446 /*
447 * 'cupsPutFile()' - Put a file on the server.
448 *
449 * This function returns @code HTTP_CREATED@ when the file is stored
450 * successfully.
451 *
452 * @since CUPS 1.1.20/macOS 10.4@
453 */
454
455 http_status_t /* O - HTTP status */
456 cupsPutFile(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
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
473 return (HTTP_STATUS_ERROR);
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
488 return (HTTP_STATUS_ERROR);
489 }
490
491 /*
492 * Put the file...
493 */
494
495 status = cupsPutFd(http, resource, fd);
496
497 close(fd);
498
499 return (status);
500 }