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