]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/request.c
Merge changes from CUPS 1.6svn-r9939.
[thirdparty/cups.git] / cups / request.c
CommitLineData
ecdc0628 1/*
b19ccc9e 2 * "$Id: request.c 7946 2008-09-16 23:27:54Z mike $"
ecdc0628 3 *
71e16022 4 * IPP utilities for CUPS.
ecdc0628 5 *
e60ec91f 6 * Copyright 2007-2011 by Apple Inc.
b86bc4cf 7 * Copyright 1997-2007 by Easy Software Products.
ecdc0628 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ecdc0628 14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
3d052e43
MS
19 * cupsDoFileRequest() - Do an IPP request with a file.
20 * cupsDoIORequest() - Do an IPP request with file descriptors.
21 * cupsDoRequest() - Do an IPP request.
22 * cupsGetResponse() - Get a response to an IPP request.
6d2f911b
MS
23 * cupsLastError() - Return the last IPP status code.
24 * cupsLastErrorString() - Return the last IPP status-message.
f14324a7 25 * _cupsNextDelay() - Return the next retry delay value.
3d052e43
MS
26 * cupsReadResponseData() - Read additional data after the IPP response.
27 * cupsSendRequest() - Send an IPP request.
28 * cupsWriteRequestData() - Write additional data after an IPP request.
6d2f911b 29 * _cupsConnect() - Get the default server connection...
3d052e43
MS
30 * _cupsSetError() - Set the last IPP status code and status-message.
31 * _cupsSetHTTPError() - Set the last error using the HTTP status.
ecdc0628 32 */
33
34/*
35 * Include necessary headers...
36 */
37
71e16022 38#include "cups-private.h"
ecdc0628 39#include <fcntl.h>
40#include <sys/stat.h>
41#if defined(WIN32) || defined(__EMX__)
42# include <io.h>
43#else
44# include <unistd.h>
45#endif /* WIN32 || __EMX__ */
b94498cf 46#ifndef O_BINARY
47# define O_BINARY 0
48#endif /* O_BINARY */
ecdc0628 49
50
51/*
52 * 'cupsDoFileRequest()' - Do an IPP request with a file.
53 *
54 * This function sends the IPP request to the specified server, retrying
568fa3fa 55 * and authenticating as necessary. The request is freed with @link ippDelete@
ecdc0628 56 * after receiving a valid IPP response.
57 */
58
59ipp_t * /* O - Response data */
568fa3fa 60cupsDoFileRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
ecdc0628 61 ipp_t *request, /* I - IPP request */
62 const char *resource, /* I - HTTP resource for POST */
568fa3fa 63 const char *filename) /* I - File to send or @code NULL@ for none */
b94498cf 64{
65 ipp_t *response; /* IPP response data */
66 int infile; /* Input file */
67
68
a603edef 69 DEBUG_printf(("cupsDoFileRequest(http=%p, request=%p(%s), resource=\"%s\", "
e07d4801 70 "filename=\"%s\")", http, request,
a603edef 71 request ? ippOpString(request->request.op.operation_id) : "?",
e07d4801 72 resource, filename));
a603edef 73
b94498cf 74 if (filename)
75 {
76 if ((infile = open(filename, O_RDONLY | O_BINARY)) < 0)
77 {
78 /*
79 * Can't get file information!
80 */
81
82 _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
749b1e90 83 NULL, 0);
b94498cf 84
85 ippDelete(request);
86
87 return (NULL);
88 }
89 }
90 else
91 infile = -1;
92
93 response = cupsDoIORequest(http, request, resource, infile, -1);
94
95 if (infile >= 0)
96 close(infile);
97
98 return (response);
99}
100
101
102/*
103 * 'cupsDoIORequest()' - Do an IPP request with file descriptors.
104 *
105 * This function sends the IPP request to the specified server, retrying
106 * and authenticating as necessary. The request is freed with ippDelete()
107 * after receiving a valid IPP response.
108 *
109 * If "infile" is a valid file descriptor, cupsDoIORequest() copies
110 * all of the data from the file after the IPP request message.
111 *
112 * If "outfile" is a valid file descriptor, cupsDoIORequest() copies
113 * all of the data after the IPP response message to the file.
114 *
426c6a59 115 * @since CUPS 1.3/Mac OS X 10.5@
b94498cf 116 */
117
118ipp_t * /* O - Response data */
568fa3fa 119cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
b94498cf 120 ipp_t *request, /* I - IPP request */
121 const char *resource, /* I - HTTP resource for POST */
122 int infile, /* I - File to read from or -1 for none */
123 int outfile) /* I - File to write to or -1 for none */
ecdc0628 124{
3d052e43
MS
125 ipp_t *response = NULL; /* IPP response data */
126 size_t length = 0; /* Content-Length value */
ecdc0628 127 http_status_t status; /* Status of HTTP request */
ecdc0628 128 struct stat fileinfo; /* File information */
129 int bytes; /* Number of bytes read/written */
a74454a7 130 char buffer[32768]; /* Output buffer */
ecdc0628 131
132
a603edef 133 DEBUG_printf(("cupsDoIORequest(http=%p, request=%p(%s), resource=\"%s\", "
e07d4801 134 "infile=%d, outfile=%d)", http, request,
a603edef 135 request ? ippOpString(request->request.op.operation_id) : "?",
e07d4801 136 resource, infile, outfile));
3d052e43
MS
137
138 /*
139 * Range check input...
140 */
ecdc0628 141
3d052e43 142 if (!request || !resource)
ecdc0628 143 {
3d052e43 144 ippDelete(request);
ecdc0628 145
749b1e90 146 _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
ecdc0628 147
148 return (NULL);
149 }
150
3d052e43
MS
151 /*
152 * Get the default connection as needed...
153 */
154
155 if (!http)
a603edef 156 if ((http = _cupsConnect()) == NULL)
e60ec91f
MS
157 {
158 ippDelete(request);
159
a603edef 160 return (NULL);
e60ec91f 161 }
3d052e43 162
ecdc0628 163 /*
164 * See if we have a file to send...
165 */
166
b94498cf 167 if (infile >= 0)
ecdc0628 168 {
b94498cf 169 if (fstat(infile, &fileinfo))
ecdc0628 170 {
171 /*
172 * Can't get file information!
173 */
174
3d052e43 175 _cupsSetError(errno == EBADF ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
749b1e90 176 NULL, 0);
ecdc0628 177
178 ippDelete(request);
179
180 return (NULL);
181 }
182
183#ifdef WIN32
184 if (fileinfo.st_mode & _S_IFDIR)
185#else
186 if (S_ISDIR(fileinfo.st_mode))
187#endif /* WIN32 */
188 {
189 /*
190 * Can't send a directory...
191 */
192
193 ippDelete(request);
194
749b1e90 195 _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR), 0);
ecdc0628 196
197 return (NULL);
198 }
3d052e43
MS
199
200#ifndef WIN32
201 if (!S_ISREG(fileinfo.st_mode))
202 length = 0; /* Chunk when piping */
203 else
204#endif /* !WIN32 */
205 length = ippLength(request) + fileinfo.st_size;
206 }
207 else
208 length = ippLength(request);
209
e07d4801 210 DEBUG_printf(("2cupsDoIORequest: Request length=%ld, total length=%ld",
52f6f666
MS
211 (long)ippLength(request), (long)length));
212
b9faaae1
MS
213 /*
214 * Clear any "Local" authentication data since it is probably stale...
215 */
216
217 if (http->authstring && !strncmp(http->authstring, "Local ", 6))
218 httpSetAuthString(http, NULL, NULL);
219
3d052e43
MS
220 /*
221 * Loop until we can send the request without authorization problems.
222 */
223
224 while (response == NULL)
225 {
e07d4801 226 DEBUG_puts("2cupsDoIORequest: setup...");
3d052e43
MS
227
228 /*
229 * Send the request...
230 */
231
232 status = cupsSendRequest(http, request, resource, length);
233
e07d4801 234 DEBUG_printf(("2cupsDoIORequest: status=%d", status));
3d052e43
MS
235
236 if (status == HTTP_CONTINUE && request->state == IPP_DATA && infile >= 0)
237 {
e07d4801 238 DEBUG_puts("2cupsDoIORequest: file write...");
3d052e43
MS
239
240 /*
241 * Send the file with the request...
242 */
243
244#ifndef WIN32
245 if (S_ISREG(fileinfo.st_mode))
246#endif /* WIN32 */
247 lseek(infile, 0, SEEK_SET);
248
249 while ((bytes = (int)read(infile, buffer, sizeof(buffer))) > 0)
250 {
251 if (httpCheck(http))
252 {
e60ec91f
MS
253 _httpUpdate(http, &status);
254
255 if (status >= HTTP_MULTIPLE_CHOICES)
3d052e43
MS
256 break;
257 }
258
259 if (httpWrite2(http, buffer, bytes) < bytes)
260 break;
261 }
262 }
263
264 /*
265 * Get the server's response...
266 */
267
268 if (status == HTTP_CONTINUE || status == HTTP_OK)
269 {
270 response = cupsGetResponse(http, resource);
271 status = http->status;
272 }
5a6b583a
MS
273 else
274 httpFlush(http);
3d052e43 275
f11a948a
MS
276 DEBUG_printf(("2cupsDoIORequest: status=%d", status));
277
5a6b583a
MS
278 if (status == HTTP_ERROR ||
279 (status >= HTTP_BAD_REQUEST && status != HTTP_UNAUTHORIZED &&
280 status != HTTP_UPGRADE_REQUIRED))
ee571f26
MS
281 {
282 _cupsSetHTTPError(status);
568fa3fa 283 break;
ee571f26 284 }
568fa3fa 285
3d052e43
MS
286 if (response)
287 {
288 if (outfile >= 0)
289 {
290 /*
291 * Write trailing data to file...
292 */
293
294 while ((bytes = (int)httpRead2(http, buffer, sizeof(buffer))) > 0)
295 if (write(outfile, buffer, bytes) < bytes)
296 break;
297 }
298 else
299 {
300 /*
301 * Flush any remaining data...
302 */
303
304 httpFlush(http);
305 }
306 }
307 }
308
309 /*
310 * Delete the original request and return the response...
311 */
6d2f911b 312
3d052e43
MS
313 ippDelete(request);
314
315 return (response);
316}
317
318
319/*
320 * 'cupsDoRequest()' - Do an IPP request.
321 *
322 * This function sends the IPP request to the specified server, retrying
323 * and authenticating as necessary. The request is freed with ippDelete()
324 * after receiving a valid IPP response.
325 */
326
327ipp_t * /* O - Response data */
568fa3fa 328cupsDoRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
3d052e43
MS
329 ipp_t *request, /* I - IPP request */
330 const char *resource) /* I - HTTP resource for POST */
331{
e07d4801 332 DEBUG_printf(("cupsDoRequest(http=%p, request=%p(%s), resource=\"%s\")",
a603edef
MS
333 http, request,
334 request ? ippOpString(request->request.op.operation_id) : "?",
e07d4801 335 resource));
a603edef 336
b19ccc9e 337 return (cupsDoIORequest(http, request, resource, -1, -1));
3d052e43
MS
338}
339
340
341/*
342 * 'cupsGetResponse()' - Get a response to an IPP request.
343 *
344 * Use this function to get the response for an IPP request sent using
345 * cupsSendDocument() or cupsSendRequest(). For requests that return
a4845881
MS
346 * additional data, use httpRead() after getting a successful response,
347 * otherwise call httpFlush() to complete the response processing.
3d052e43 348 *
178cb736 349 * @since CUPS 1.4/Mac OS X 10.6@
3d052e43
MS
350 */
351
568fa3fa
MS
352ipp_t * /* O - Response or @code NULL@ on HTTP error */
353cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
3d052e43
MS
354 const char *resource) /* I - HTTP resource for POST */
355{
356 http_status_t status; /* HTTP status */
357 ipp_state_t state; /* IPP read state */
358 ipp_t *response = NULL; /* IPP response */
359
360
e07d4801 361 DEBUG_printf(("cupsGetResponse(http=%p, resource=\"%s\")", http, resource));
3d052e43
MS
362
363 /*
364 * Connect to the default server as needed...
365 */
366
367 if (!http)
368 http = _cupsConnect();
369
370 if (!http || (http->state != HTTP_POST_RECV && http->state != HTTP_POST_SEND))
371 return (NULL);
372
373 /*
374 * Check for an unfinished chunked request...
375 */
376
377 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
378 {
379 /*
380 * Send a 0-length chunk to finish off the request...
381 */
382
e07d4801 383 DEBUG_puts("2cupsGetResponse: Finishing chunked POST...");
3d052e43
MS
384
385 if (httpWrite2(http, "", 0) < 0)
386 return (NULL);
387 }
388
389 /*
390 * Wait for a response from the server...
391 */
392
e07d4801 393 DEBUG_printf(("2cupsGetResponse: Update loop, http->status=%d...",
1ff0402e 394 http->status));
3d052e43 395
e60ec91f
MS
396 do
397 {
1ff0402e 398 status = httpUpdate(http);
e60ec91f 399 }
22c9029b 400 while (status != HTTP_ERROR && http->state == HTTP_POST_RECV);
3d052e43 401
e07d4801 402 DEBUG_printf(("2cupsGetResponse: status=%d", status));
3d052e43
MS
403
404 if (status == HTTP_OK)
405 {
406 /*
407 * Get the IPP response...
408 */
409
410 response = ippNew();
411
412 while ((state = ippRead(http, response)) != IPP_DATA)
413 if (state == IPP_ERROR)
414 break;
415
416 if (state == IPP_ERROR)
417 {
418 /*
f14324a7 419 * Flush remaining data and delete the response...
3d052e43
MS
420 */
421
e07d4801 422 DEBUG_puts("1cupsGetResponse: IPP read error!");
3d052e43 423
f14324a7
MS
424 httpFlush(http);
425
3d052e43
MS
426 ippDelete(response);
427 response = NULL;
428
749b1e90 429 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
a4845881
MS
430 http->status = status = HTTP_ERROR;
431 http->error = EIO;
3d052e43
MS
432 }
433 }
434 else if (status != HTTP_ERROR)
435 {
436 /*
437 * Flush any error message...
438 */
439
440 httpFlush(http);
441
442 /*
443 * Then handle encryption and authentication...
444 */
445
446 if (status == HTTP_UNAUTHORIZED)
447 {
448 /*
449 * See if we can do authentication...
450 */
451
e07d4801 452 DEBUG_puts("2cupsGetResponse: Need authorization...");
568fa3fa 453
e07d4801 454 if (!cupsDoAuthentication(http, "POST", resource))
7cf5915e 455 httpReconnect(http);
f11a948a 456 else
a4845881 457 http->status = status = HTTP_AUTHORIZATION_CANCELED;
3d052e43
MS
458 }
459
460#ifdef HAVE_SSL
461 else if (status == HTTP_UPGRADE_REQUIRED)
462 {
463 /*
464 * Force a reconnect with encryption...
465 */
466
e07d4801 467 DEBUG_puts("2cupsGetResponse: Need encryption...");
3d052e43
MS
468
469 if (!httpReconnect(http))
470 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
471 }
472#endif /* HAVE_SSL */
473 }
474
475 if (response)
476 {
477 ipp_attribute_t *attr; /* status-message attribute */
478
479
480 attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
481
e07d4801 482 DEBUG_printf(("1cupsGetResponse: status-code=%s, status-message=\"%s\"",
a603edef
MS
483 ippErrorString(response->request.status.status_code),
484 attr ? attr->values[0].string.text : ""));
485
3d052e43 486 _cupsSetError(response->request.status.status_code,
749b1e90
MS
487 attr ? attr->values[0].string.text :
488 ippErrorString(response->request.status.status_code), 0);
3d052e43
MS
489 }
490 else if (status != HTTP_OK)
491 _cupsSetHTTPError(status);
492
493 return (response);
494}
495
496
6d2f911b
MS
497/*
498 * 'cupsLastError()' - Return the last IPP status code.
499 */
500
501ipp_status_t /* O - IPP status code from last request */
502cupsLastError(void)
503{
504 return (_cupsGlobals()->last_error);
505}
506
507
508/*
509 * 'cupsLastErrorString()' - Return the last IPP status-message.
510 *
511 * @since CUPS 1.2/Mac OS X 10.5@
512 */
513
514const char * /* O - status-message text from last request */
515cupsLastErrorString(void)
516{
517 return (_cupsGlobals()->last_status_message);
518}
519
520
f14324a7
MS
521/*
522 * '_cupsNextDelay()' - Return the next retry delay value.
523 *
524 * This function currently returns the Fibonacci sequence 1 1 2 3 5 8.
525 *
526 * Pass 0 for the current delay value to initialize the sequence.
527 */
528
529int /* O - Next delay value */
530_cupsNextDelay(int current, /* I - Current delay value or 0 */
531 int *previous) /* IO - Previous delay value */
532{
533 int next; /* Next delay value */
534
535
536 if (current > 0)
537 {
538 next = (current + *previous) % 12;
539 *previous = next < current ? 0 : current;
540 }
541 else
542 {
543 next = 1;
544 *previous = 0;
545 }
546
547 return (next);
548}
549
550
3d052e43
MS
551/*
552 * 'cupsReadResponseData()' - Read additional data after the IPP response.
553 *
554 * This function is used after cupsGetResponse() to read the PPD or document
555 * files for CUPS_GET_PPD and CUPS_GET_DOCUMENT requests, respectively.
556 *
178cb736 557 * @since CUPS 1.4/Mac OS X 10.6@
3d052e43
MS
558 */
559
560ssize_t /* O - Bytes read, 0 on EOF, -1 on error */
561cupsReadResponseData(
568fa3fa 562 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
3d052e43
MS
563 char *buffer, /* I - Buffer to use */
564 size_t length) /* I - Number of bytes to read */
565{
566 /*
567 * Get the default connection as needed...
568 */
569
a603edef 570 DEBUG_printf(("cupsReadResponseData(http=%p, buffer=%p, "
e07d4801 571 "length=" CUPS_LLFMT ")", http, buffer, CUPS_LLCAST length));
a603edef 572
3d052e43
MS
573 if (!http)
574 {
575 _cups_globals_t *cg = _cupsGlobals();
576 /* Pointer to library globals */
577
578 if ((http = cg->http) == NULL)
579 {
749b1e90 580 _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
3d052e43
MS
581 return (-1);
582 }
ecdc0628 583 }
ecdc0628 584
3d052e43
MS
585 /*
586 * Then read from the HTTP connection...
587 */
588
589 return (httpRead2(http, buffer, length));
590}
591
592
593/*
594 * 'cupsSendRequest()' - Send an IPP request.
595 *
596 * Use httpWrite() to write any additional data (document, PPD file, etc.)
597 * for the request, cupsGetResponse() to get the IPP response, and httpRead()
6d2f911b 598 * to read any additional data following the response. Only one request can be
3d052e43
MS
599 * sent/queued at a time.
600 *
601 * Unlike cupsDoFileRequest(), cupsDoIORequest(), and cupsDoRequest(), the
602 * request is not freed.
603 *
178cb736 604 * @since CUPS 1.4/Mac OS X 10.6@
3d052e43
MS
605 */
606
607http_status_t /* O - Initial HTTP status */
568fa3fa 608cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
3d052e43
MS
609 ipp_t *request, /* I - IPP request */
610 const char *resource, /* I - Resource path */
ae71f5de 611 size_t length) /* I - Length of data to follow or @code CUPS_LENGTH_VARIABLE@ */
3d052e43
MS
612{
613 http_status_t status; /* Status of HTTP request */
614 int got_status; /* Did we get the status? */
615 ipp_state_t state; /* State of IPP processing */
616 http_status_t expect; /* Expect: header to use */
617
618
a603edef 619 DEBUG_printf(("cupsSendRequest(http=%p, request=%p(%s), resource=\"%s\", "
e07d4801 620 "length=" CUPS_LLFMT ")", http, request,
a603edef 621 request ? ippOpString(request->request.op.operation_id) : "?",
e07d4801 622 resource, CUPS_LLCAST length));
3d052e43
MS
623
624 /*
625 * Range check input...
626 */
627
628 if (!request || !resource)
629 {
749b1e90 630 _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
3d052e43
MS
631
632 return (HTTP_ERROR);
633 }
634
635 /*
636 * Get the default connection as needed...
637 */
638
639 if (!http)
a603edef
MS
640 if ((http = _cupsConnect()) == NULL)
641 return (HTTP_SERVICE_UNAVAILABLE);
3d052e43 642
a4845881
MS
643 /*
644 * If the prior request was not flushed out, do so now...
645 */
646
647 if (http->state == HTTP_GET_SEND ||
648 http->state == HTTP_POST_SEND)
649 httpFlush(http);
650 else if (http->state != HTTP_WAITING)
651 {
652 _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
653
654 return (HTTP_ERROR);
655 }
656
7594b224 657#ifdef HAVE_SSL
658 /*
659 * See if we have an auth-info attribute and are communicating over
660 * a non-local link. If so, encrypt the link so that we can pass
661 * the authentication information securely...
662 */
663
664 if (ippFindAttribute(request, "auth-info", IPP_TAG_TEXT) &&
665 !httpAddrLocalhost(http->hostaddr) && !http->tls &&
666 httpEncryption(http, HTTP_ENCRYPT_REQUIRED))
b19ccc9e
MS
667 {
668 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
ee571f26 669 return (HTTP_SERVICE_UNAVAILABLE);
b19ccc9e 670 }
7594b224 671#endif /* HAVE_SSL */
672
1ff0402e
MS
673 /*
674 * Reconnect if the last response had a "Connection: close"...
675 */
676
88f9aafc 677 if (!_cups_strcasecmp(http->fields[HTTP_FIELD_CONNECTION], "close"))
1ff0402e 678 if (httpReconnect(http))
b19ccc9e
MS
679 {
680 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
1ff0402e 681 return (HTTP_SERVICE_UNAVAILABLE);
b19ccc9e 682 }
1ff0402e 683
ecdc0628 684 /*
685 * Loop until we can send the request without authorization problems.
686 */
687
3d052e43 688 expect = HTTP_CONTINUE;
ecdc0628 689
3d052e43 690 for (;;)
ecdc0628 691 {
e07d4801 692 DEBUG_puts("2cupsSendRequest: Setup...");
ecdc0628 693
694 /*
695 * Setup the HTTP variables needed...
696 */
697
ecdc0628 698 httpClearFields(http);
0268488e 699 httpSetExpect(http, expect);
ecdc0628 700 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
0268488e
MS
701 httpSetLength(http, length);
702
703#ifdef HAVE_GSSAPI
704 if (http->authstring && !strncmp(http->authstring, "Negotiate", 9))
705 {
706 /*
707 * Do not use cached Kerberos credentials since they will look like a
708 * "replay" attack...
709 */
710
eac3a0a0 711 _cupsSetNegotiateAuthString(http, "POST", resource);
0268488e 712 }
0268488e 713#endif /* HAVE_GSSAPI */
f14324a7 714
ecdc0628 715 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
716
e07d4801 717 DEBUG_printf(("2cupsSendRequest: authstring=\"%s\"", http->authstring));
ecdc0628 718
719 /*
720 * Try the request...
721 */
722
e07d4801 723 DEBUG_puts("2cupsSendRequest: Sending HTTP POST...");
ecdc0628 724
725 if (httpPost(http, resource))
726 {
727 if (httpReconnect(http))
b19ccc9e
MS
728 {
729 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
ee571f26 730 return (HTTP_SERVICE_UNAVAILABLE);
b19ccc9e 731 }
ecdc0628 732 else
733 continue;
734 }
735
736 /*
d6ae789d 737 * Send the IPP data...
ecdc0628 738 */
739
e07d4801 740 DEBUG_puts("2cupsSendRequest: Writing IPP request...");
b423cd4c 741
d6ae789d 742 request->state = IPP_IDLE;
743 status = HTTP_CONTINUE;
744 got_status = 0;
745
746 while ((state = ippWrite(http, request)) != IPP_DATA)
747 if (state == IPP_ERROR)
748 break;
749 else if (httpCheck(http))
750 {
751 got_status = 1;
752
e60ec91f
MS
753 _httpUpdate(http, &status);
754 if (status >= HTTP_MULTIPLE_CHOICES)
d6ae789d 755 break;
756 }
757
22c9029b
MS
758 if (state == IPP_ERROR)
759 {
760 http->status = HTTP_ERROR;
761 http->state = HTTP_WAITING;
762
763 return (HTTP_ERROR);
764 }
765
3d052e43
MS
766 /*
767 * Wait up to 1 second to get the 100-continue response as needed...
768 */
ecdc0628 769
e60ec91f 770 if (!got_status)
3d052e43 771 {
e60ec91f
MS
772 if (expect == HTTP_CONTINUE)
773 {
774 DEBUG_puts("2cupsSendRequest: Waiting for 100-continue...");
a603edef 775
e60ec91f
MS
776 if (httpWait(http, 1000))
777 _httpUpdate(http, &status);
778 }
779 else if (httpCheck(http))
780 _httpUpdate(http, &status);
d6ae789d 781 }
ecdc0628 782
e07d4801 783 DEBUG_printf(("2cupsSendRequest: status=%d", status));
a603edef 784
ecdc0628 785 /*
3d052e43 786 * Process the current HTTP status...
ecdc0628 787 */
788
e60ec91f 789 if (status >= HTTP_MULTIPLE_CHOICES)
ba55dc12
MS
790 httpFlush(http);
791
3d052e43 792 switch (status)
ecdc0628 793 {
3d052e43
MS
794 case HTTP_ERROR :
795 case HTTP_CONTINUE :
796 case HTTP_OK :
797 return (status);
ecdc0628 798
3d052e43 799 case HTTP_UNAUTHORIZED :
ba55dc12
MS
800 if (cupsDoAuthentication(http, "POST", resource))
801 return (HTTP_AUTHORIZATION_CANCELED);
802
803 if (httpReconnect(http))
f11a948a 804 {
ba55dc12
MS
805 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
806 return (HTTP_SERVICE_UNAVAILABLE);
f11a948a 807 }
ba55dc12 808 break;
89d46774 809
ecdc0628 810#ifdef HAVE_SSL
3d052e43
MS
811 case HTTP_UPGRADE_REQUIRED :
812 /*
813 * Flush any error message, reconnect, and then upgrade with
814 * encryption...
815 */
ecdc0628 816
3d052e43 817 if (httpReconnect(http))
b19ccc9e
MS
818 {
819 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
820 return (HTTP_SERVICE_UNAVAILABLE);
821 }
ecdc0628 822
ba55dc12
MS
823 if (httpEncryption(http, HTTP_ENCRYPT_REQUIRED))
824 {
825 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
826 return (HTTP_SERVICE_UNAVAILABLE);
827 }
828 break;
ecdc0628 829#endif /* HAVE_SSL */
f301802f 830
3d052e43
MS
831 case HTTP_EXPECTATION_FAILED :
832 /*
833 * Don't try using the Expect: header the next time around...
834 */
ecdc0628 835
3d052e43 836 expect = (http_status_t)0;
52f6f666
MS
837
838 if (httpReconnect(http))
839 {
840 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
841 return (HTTP_SERVICE_UNAVAILABLE);
842 }
a603edef 843 break;
ecdc0628 844
3d052e43
MS
845 default :
846 /*
847 * Some other error...
848 */
ecdc0628 849
3d052e43 850 return (status);
b94498cf 851 }
852 }
3d052e43
MS
853}
854
855
856/*
857 * 'cupsWriteRequestData()' - Write additional data after an IPP request.
858 *
568fa3fa
MS
859 * This function is used after @link cupsSendRequest@ to provide a PPD and
860 * after @link cupsStartDocument@ to provide a document file.
3d052e43 861 *
178cb736 862 * @since CUPS 1.4/Mac OS X 10.6@
3d052e43 863 */
ecdc0628 864
568fa3fa 865http_status_t /* O - @code HTTP_CONTINUE@ if OK or HTTP status on error */
3d052e43 866cupsWriteRequestData(
568fa3fa 867 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
3d052e43
MS
868 const char *buffer, /* I - Bytes to write */
869 size_t length) /* I - Number of bytes to write */
870{
38e73f87
MS
871 int wused; /* Previous bytes in buffer */
872
873
ecdc0628 874 /*
3d052e43 875 * Get the default connection as needed...
ecdc0628 876 */
ecdc0628 877
a603edef 878 DEBUG_printf(("cupsWriteRequestData(http=%p, buffer=%p, "
e07d4801 879 "length=" CUPS_LLFMT ")", http, buffer, CUPS_LLCAST length));
a603edef 880
3d052e43 881 if (!http)
ecdc0628 882 {
3d052e43
MS
883 _cups_globals_t *cg = _cupsGlobals();
884 /* Pointer to library globals */
ecdc0628 885
3d052e43
MS
886 if ((http = cg->http) == NULL)
887 {
749b1e90 888 _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
10d09e33 889 DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR.");
3d052e43
MS
890 return (HTTP_ERROR);
891 }
ecdc0628 892 }
ecdc0628 893
3d052e43
MS
894 /*
895 * Then write to the HTTP connection...
896 */
ecdc0628 897
38e73f87
MS
898 wused = http->wused;
899
3d052e43 900 if (httpWrite2(http, buffer, length) < 0)
10d09e33
MS
901 {
902 DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR.");
903 _cupsSetError(IPP_INTERNAL_ERROR, strerror(http->error), 0);
3d052e43 904 return (HTTP_ERROR);
10d09e33 905 }
ecdc0628 906
3d052e43
MS
907 /*
908 * Finally, check if we have any pending data from the server...
909 */
ecdc0628 910
f11a948a 911 if (length >= HTTP_MAX_BUFFER ||
38e73f87
MS
912 http->wused < wused ||
913 (wused > 0 && http->wused == length))
914 {
915 /*
916 * We've written something to the server, so check for response data...
917 */
918
919 if (_httpWait(http, 0, 1))
ba55dc12 920 {
e60ec91f 921 http_status_t status; /* Status from _httpUpdate */
ba55dc12 922
e60ec91f
MS
923 _httpUpdate(http, &status);
924 if (status >= HTTP_MULTIPLE_CHOICES)
10d09e33
MS
925 {
926 _cupsSetHTTPError(status);
ba55dc12 927 httpFlush(http);
10d09e33 928 }
ba55dc12 929
10d09e33 930 DEBUG_printf(("1cupsWriteRequestData: Returning %d.\n", status));
ba55dc12
MS
931 return (status);
932 }
38e73f87
MS
933 }
934
10d09e33 935 DEBUG_puts("1cupsWriteRequestData: Returning HTTP_CONTINUE.");
38e73f87 936 return (HTTP_CONTINUE);
ecdc0628 937}
938
939
6d2f911b
MS
940/*
941 * '_cupsConnect()' - Get the default server connection...
942 */
943
944http_t * /* O - HTTP connection */
945_cupsConnect(void)
946{
947 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
948
949
950 /*
951 * See if we are connected to the same server...
952 */
953
954 if (cg->http)
955 {
956 /*
957 * Compare the connection hostname, port, and encryption settings to
958 * the cached defaults; these were initialized the first time we
959 * connected...
960 */
961
962 if (strcmp(cg->http->hostname, cg->server) ||
963 cg->ipp_port != _httpAddrPort(cg->http->hostaddr) ||
964 (cg->http->encryption != cg->encryption &&
965 cg->http->encryption == HTTP_ENCRYPT_NEVER))
966 {
967 /*
968 * Need to close the current connection because something has changed...
969 */
970
971 httpClose(cg->http);
972 cg->http = NULL;
973 }
974 }
975
976 /*
977 * (Re)connect as needed...
978 */
979
980 if (!cg->http)
981 {
982 if ((cg->http = httpConnectEncrypt(cupsServer(), ippPort(),
983 cupsEncryption())) == NULL)
984 {
985 if (errno)
986 _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
987 else
988 _cupsSetError(IPP_SERVICE_UNAVAILABLE,
989 _("Unable to connect to host."), 1);
990 }
991 }
992
993 /*
994 * Return the cached connection...
995 */
996
997 return (cg->http);
998}
999
1000
ecdc0628 1001/*
1002 * '_cupsSetError()' - Set the last IPP status code and status-message.
1003 */
1004
1005void
1006_cupsSetError(ipp_status_t status, /* I - IPP status code */
749b1e90
MS
1007 const char *message, /* I - status-message value */
1008 int localize) /* I - Localize the message? */
ecdc0628 1009{
1010 _cups_globals_t *cg; /* Global data */
1011
1012
749b1e90
MS
1013 if (!message && errno)
1014 {
1015 message = strerror(errno);
1016 localize = 0;
1017 }
1018
ecdc0628 1019 cg = _cupsGlobals();
1020 cg->last_error = status;
1021
1022 if (cg->last_status_message)
1023 {
749b1e90 1024 _cupsStrFree(cg->last_status_message);
ecdc0628 1025
1026 cg->last_status_message = NULL;
1027 }
1028
1029 if (message)
749b1e90
MS
1030 {
1031 if (localize)
1032 {
1033 /*
1034 * Get the message catalog...
1035 */
1036
1037 if (!cg->lang_default)
1038 cg->lang_default = cupsLangDefault();
1039
1040 cg->last_status_message = _cupsStrAlloc(_cupsLangString(cg->lang_default,
1041 message));
1042 }
1043 else
1044 cg->last_status_message = _cupsStrAlloc(message);
1045 }
a603edef 1046
e07d4801
MS
1047 DEBUG_printf(("4_cupsSetError: last_error=%s, last_status_message=\"%s\"",
1048 ippErrorString(cg->last_error), cg->last_status_message));
ecdc0628 1049}
1050
1051
1052/*
355e94dc
MS
1053 * '_cupsSetHTTPError()' - Set the last error using the HTTP status.
1054 */
1055
1056void
1057_cupsSetHTTPError(http_status_t status) /* I - HTTP status code */
1058{
1059 switch (status)
1060 {
1061 case HTTP_NOT_FOUND :
749b1e90 1062 _cupsSetError(IPP_NOT_FOUND, httpStatus(status), 0);
355e94dc
MS
1063 break;
1064
1065 case HTTP_UNAUTHORIZED :
6c48a6ca 1066 _cupsSetError(IPP_NOT_AUTHENTICATED, httpStatus(status), 0);
355e94dc
MS
1067 break;
1068
7cf5915e 1069 case HTTP_AUTHORIZATION_CANCELED :
6c48a6ca 1070 _cupsSetError(IPP_AUTHENTICATION_CANCELED, httpStatus(status), 0);
7cf5915e
MS
1071 break;
1072
355e94dc 1073 case HTTP_FORBIDDEN :
749b1e90 1074 _cupsSetError(IPP_FORBIDDEN, httpStatus(status), 0);
355e94dc
MS
1075 break;
1076
1077 case HTTP_BAD_REQUEST :
749b1e90 1078 _cupsSetError(IPP_BAD_REQUEST, httpStatus(status), 0);
355e94dc
MS
1079 break;
1080
1081 case HTTP_REQUEST_TOO_LARGE :
749b1e90 1082 _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status), 0);
355e94dc
MS
1083 break;
1084
1085 case HTTP_NOT_IMPLEMENTED :
749b1e90 1086 _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status), 0);
355e94dc
MS
1087 break;
1088
1089 case HTTP_NOT_SUPPORTED :
749b1e90 1090 _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status), 0);
355e94dc
MS
1091 break;
1092
7cf5915e
MS
1093 case HTTP_UPGRADE_REQUIRED :
1094 _cupsSetError(IPP_UPGRADE_REQUIRED, httpStatus(status), 0);
1095 break;
1096
1097 case HTTP_PKI_ERROR :
1098 _cupsSetError(IPP_PKI_ERROR, httpStatus(status), 0);
1099 break;
1100
10d09e33
MS
1101 case HTTP_ERROR :
1102 _cupsSetError(IPP_INTERNAL_ERROR, httpStatus(status), 0);
1103 break;
1104
355e94dc 1105 default :
e07d4801
MS
1106 DEBUG_printf(("4_cupsSetHTTPError: HTTP error %d mapped to "
1107 "IPP_SERVICE_UNAVAILABLE!", status));
749b1e90 1108 _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status), 0);
355e94dc
MS
1109 break;
1110 }
1111}
1112
1113
1114/*
b19ccc9e 1115 * End of "$Id: request.c 7946 2008-09-16 23:27:54Z mike $".
ecdc0628 1116 */