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