]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/request.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / request.c
CommitLineData
ecdc0628 1/*
f7deaa1a 2 * "$Id: request.c 6253 2007-02-10 18:48:40Z mike $"
ecdc0628 3 *
4 * IPP utilities for the Common UNIX Printing System (CUPS).
5 *
b86bc4cf 6 * Copyright 1997-2007 by Easy Software Products.
ecdc0628 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsDoFileRequest() - Do an IPP request with a file.
29 * cupsDoRequest() - Do an IPP request.
30 * _cupsSetError() - Set the last IPP status code and status-message.
31 */
32
33/*
34 * Include necessary headers...
35 */
36
37#include "globals.h"
38#include "debug.h"
39#include <stdlib.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <sys/stat.h>
43#if defined(WIN32) || defined(__EMX__)
44# include <io.h>
45#else
46# include <unistd.h>
47#endif /* WIN32 || __EMX__ */
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 ippDelete()
55 * after receiving a valid IPP response.
56 */
57
58ipp_t * /* O - Response data */
59cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */
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 NULL for none */
63{
64 ipp_t *response; /* IPP response data */
65 size_t length; /* Content-Length value */
66 http_status_t status; /* Status of HTTP request */
d6ae789d 67 int got_status; /* Did we get the status? */
b423cd4c 68 ipp_state_t state; /* State of IPP processing */
ecdc0628 69 FILE *file; /* File to send */
70 struct stat fileinfo; /* File information */
71 int bytes; /* Number of bytes read/written */
a74454a7 72 char buffer[32768]; /* Output buffer */
f301802f 73 http_status_t expect; /* Expect: header to use */
f7deaa1a 74#ifdef HAVE_AUTHORIZATION_H
75 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
76#endif /* HAVE_AUTHORIZATION_H */
ecdc0628 77
78
79 DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
80 http, request, resource ? resource : "(null)",
81 filename ? filename : "(null)"));
82
83 if (http == NULL || request == NULL || resource == NULL)
84 {
85 if (request != NULL)
86 ippDelete(request);
87
88 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
89
90 return (NULL);
91 }
92
93 /*
94 * See if we have a file to send...
95 */
96
97 if (filename != NULL)
98 {
99 if (stat(filename, &fileinfo))
100 {
101 /*
102 * Can't get file information!
103 */
104
105 _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
106 strerror(errno));
107
108 ippDelete(request);
109
110 return (NULL);
111 }
112
113#ifdef WIN32
114 if (fileinfo.st_mode & _S_IFDIR)
115#else
116 if (S_ISDIR(fileinfo.st_mode))
117#endif /* WIN32 */
118 {
119 /*
120 * Can't send a directory...
121 */
122
123 ippDelete(request);
124
89d46774 125 _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR));
ecdc0628 126
127 return (NULL);
128 }
129
130 if ((file = fopen(filename, "rb")) == NULL)
131 {
132 /*
133 * Can't open file!
134 */
135
136 _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
137 strerror(errno));
138
139 ippDelete(request);
140
141 return (NULL);
142 }
143 }
144 else
145 file = NULL;
146
147 /*
148 * Loop until we can send the request without authorization problems.
149 */
150
151 response = NULL;
152 status = HTTP_ERROR;
f301802f 153 expect = HTTP_CONTINUE;
ecdc0628 154
155 while (response == NULL)
156 {
157 DEBUG_puts("cupsDoFileRequest: setup...");
158
159 /*
160 * Setup the HTTP variables needed...
161 */
162
163 length = ippLength(request);
164 if (filename)
165 length += fileinfo.st_size;
166
167 httpClearFields(http);
168 httpSetLength(http, length);
169 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
170 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
f301802f 171 httpSetExpect(http, expect);
ecdc0628 172
173 DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http->authstring));
174
175 /*
176 * Try the request...
177 */
178
179 DEBUG_puts("cupsDoFileRequest: post...");
180
181 if (httpPost(http, resource))
182 {
183 if (httpReconnect(http))
184 {
185 status = HTTP_ERROR;
186 break;
187 }
188 else
189 continue;
190 }
191
192 /*
d6ae789d 193 * Send the IPP data...
ecdc0628 194 */
195
d6ae789d 196 DEBUG_puts("cupsDoFileRequest: ipp write...");
b423cd4c 197
d6ae789d 198 request->state = IPP_IDLE;
199 status = HTTP_CONTINUE;
200 got_status = 0;
201
202 while ((state = ippWrite(http, request)) != IPP_DATA)
203 if (state == IPP_ERROR)
204 break;
205 else if (httpCheck(http))
206 {
207 got_status = 1;
208
209 if ((status = httpUpdate(http)) != HTTP_CONTINUE)
210 break;
211 }
212
213 if (!got_status)
b423cd4c 214 {
215 /*
d6ae789d 216 * Wait up to 1 second to get the 100-continue response...
b423cd4c 217 */
ecdc0628 218
d6ae789d 219 if (httpWait(http, 1000))
220 status = httpUpdate(http);
221 }
222 else if (httpCheck(http))
223 status = httpUpdate(http);
ecdc0628 224
d6ae789d 225 if (status == HTTP_CONTINUE && state == IPP_DATA && filename)
226 {
227 DEBUG_puts("cupsDoFileRequest: file write...");
b423cd4c 228
d6ae789d 229 /*
230 * Send the file...
231 */
232
233 rewind(file);
234
235 while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0)
236 {
237 if (httpCheck(http))
b423cd4c 238 {
239 if ((status = httpUpdate(http)) != HTTP_CONTINUE)
240 break;
241 }
242
d6ae789d 243 if (httpWrite2(http, buffer, bytes) < bytes)
244 break;
ecdc0628 245 }
b423cd4c 246 }
ecdc0628 247
248 /*
249 * Get the server's return status...
250 */
251
252 DEBUG_puts("cupsDoFileRequest: update...");
253
254 while (status == HTTP_CONTINUE)
255 status = httpUpdate(http);
256
257 DEBUG_printf(("cupsDoFileRequest: status = %d\n", status));
258
259 if (status == HTTP_UNAUTHORIZED)
260 {
261 DEBUG_puts("cupsDoFileRequest: unauthorized...");
262
263 /*
264 * Flush any error message...
265 */
266
267 httpFlush(http);
268
269 /*
270 * See if we can do authentication...
271 */
272
273 if (cupsDoAuthentication(http, "POST", resource))
274 break;
275
276 if (httpReconnect(http))
277 {
278 status = HTTP_ERROR;
279 break;
280 }
281
282 continue;
283 }
284 else if (status == HTTP_ERROR)
285 {
89d46774 286 DEBUG_printf(("cupsDoFileRequest: http->error=%d (%s)\n", http->error,
287 strerror(http->error)));
288
ecdc0628 289#ifdef WIN32
89d46774 290 if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH &&
b86bc4cf 291 http->error != WSAETIMEDOUT)
ecdc0628 292#else
89d46774 293 if (http->error != ENETDOWN && http->error != ENETUNREACH &&
294 http->error != ETIMEDOUT)
ecdc0628 295#endif /* WIN32 */
296 continue;
297 else
298 break;
299 }
300#ifdef HAVE_SSL
301 else if (status == HTTP_UPGRADE_REQUIRED)
302 {
303 /* Flush any error message... */
304 httpFlush(http);
305
306 /* Reconnect... */
307 if (httpReconnect(http))
308 {
309 status = HTTP_ERROR;
310 break;
311 }
312
313 /* Upgrade with encryption... */
314 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
315
316 /* Try again, this time with encryption enabled... */
317 continue;
318 }
319#endif /* HAVE_SSL */
f301802f 320 else if (status == HTTP_EXPECTATION_FAILED)
321 {
322 /*
323 * Don't try using the Expect: header the next time around...
324 */
325
326 expect = (http_status_t)0;
327 }
ecdc0628 328 else if (status != HTTP_OK)
329 {
330 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status));
331
332 /*
333 * Flush any error message...
334 */
335
336 httpFlush(http);
337 break;
338 }
339 else
340 {
341 /*
342 * Read the response...
343 */
344
345 DEBUG_puts("cupsDoFileRequest: response...");
346
347 response = ippNew();
348
89d46774 349 while ((state = ippRead(http, response)) != IPP_DATA)
350 if (state == IPP_ERROR)
351 {
352 /*
353 * Delete the response...
354 */
ecdc0628 355
89d46774 356 DEBUG_puts("IPP read error!");
357 ippDelete(response);
358 response = NULL;
ecdc0628 359
89d46774 360 _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
ecdc0628 361
89d46774 362 break;
363 }
ecdc0628 364 }
365 }
366
367 /*
368 * Close the file if needed...
369 */
370
371 if (filename != NULL)
372 fclose(file);
373
374 /*
375 * Flush any remaining data...
376 */
377
378 httpFlush(http);
379
380 /*
381 * Delete the original request and return the response...
382 */
383
384 ippDelete(request);
385
386 if (response)
387 {
388 ipp_attribute_t *attr; /* status-message attribute */
389
390
391 attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
392
393 _cupsSetError(response->request.status.status_code,
394 attr ? attr->values[0].string.text :
395 ippErrorString(response->request.status.status_code));
396 }
397 else if (status != HTTP_OK)
398 {
399 switch (status)
400 {
401 case HTTP_NOT_FOUND :
402 _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
403 break;
404
405 case HTTP_UNAUTHORIZED :
406 _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
407 break;
408
409 case HTTP_FORBIDDEN :
410 _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
411 break;
412
413 case HTTP_BAD_REQUEST :
414 _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
415 break;
416
417 case HTTP_REQUEST_TOO_LARGE :
418 _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
419 break;
420
421 case HTTP_NOT_IMPLEMENTED :
422 _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
423 break;
424
425 case HTTP_NOT_SUPPORTED :
426 _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
427 break;
428
429 default :
430 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
431 status));
432 _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
433 break;
434 }
435 }
436
f7deaa1a 437#ifdef HAVE_AUTHORIZATION_H
438 /*
439 * Delete any authorization reference created for this request...
440 */
441
442 if (cg->auth_ref)
443 {
444 AuthorizationFree(cg->auth_ref, kAuthorizationFlagDefaults);
445 cg->auth_ref = NULL;
446 }
447#endif /* HAVE_AUTHORIZATION_H */
448
ecdc0628 449 return (response);
450}
451
452
453/*
454 * 'cupsDoRequest()' - Do an IPP request.
455 *
456 * This function sends the IPP request to the specified server, retrying
457 * and authenticating as necessary. The request is freed with ippDelete()
458 * after receiving a valid IPP response.
459 */
460
461ipp_t * /* O - Response data */
462cupsDoRequest(http_t *http, /* I - HTTP connection to server */
463 ipp_t *request, /* I - IPP request */
464 const char *resource) /* I - HTTP resource for POST */
465{
466 return (cupsDoFileRequest(http, request, resource, NULL));
467}
468
469
470/*
471 * '_cupsSetError()' - Set the last IPP status code and status-message.
472 */
473
474void
475_cupsSetError(ipp_status_t status, /* I - IPP status code */
476 const char *message) /* I - status-message value */
477{
478 _cups_globals_t *cg; /* Global data */
479
480
481 cg = _cupsGlobals();
482 cg->last_error = status;
483
484 if (cg->last_status_message)
485 {
486 free(cg->last_status_message);
487
488 cg->last_status_message = NULL;
489 }
490
491 if (message)
492 cg->last_status_message = strdup(message);
493}
494
495
496/*
f7deaa1a 497 * End of "$Id: request.c 6253 2007-02-10 18:48:40Z mike $".
ecdc0628 498 */