]> 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/*
f301802f 2 * "$Id: request.c 5556 2006-05-21 13:55:23Z mike $"
ecdc0628 3 *
4 * IPP utilities for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
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 */
ecdc0628 74
75
76 DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
77 http, request, resource ? resource : "(null)",
78 filename ? filename : "(null)"));
79
80 if (http == NULL || request == NULL || resource == NULL)
81 {
82 if (request != NULL)
83 ippDelete(request);
84
85 _cupsSetError(IPP_INTERNAL_ERROR, NULL);
86
87 return (NULL);
88 }
89
90 /*
91 * See if we have a file to send...
92 */
93
94 if (filename != NULL)
95 {
96 if (stat(filename, &fileinfo))
97 {
98 /*
99 * Can't get file information!
100 */
101
102 _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
103 strerror(errno));
104
105 ippDelete(request);
106
107 return (NULL);
108 }
109
110#ifdef WIN32
111 if (fileinfo.st_mode & _S_IFDIR)
112#else
113 if (S_ISDIR(fileinfo.st_mode))
114#endif /* WIN32 */
115 {
116 /*
117 * Can't send a directory...
118 */
119
120 ippDelete(request);
121
89d46774 122 _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR));
ecdc0628 123
124 return (NULL);
125 }
126
127 if ((file = fopen(filename, "rb")) == NULL)
128 {
129 /*
130 * Can't open file!
131 */
132
133 _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
134 strerror(errno));
135
136 ippDelete(request);
137
138 return (NULL);
139 }
140 }
141 else
142 file = NULL;
143
144 /*
145 * Loop until we can send the request without authorization problems.
146 */
147
148 response = NULL;
149 status = HTTP_ERROR;
f301802f 150 expect = HTTP_CONTINUE;
ecdc0628 151
152 while (response == NULL)
153 {
154 DEBUG_puts("cupsDoFileRequest: setup...");
155
156 /*
157 * Setup the HTTP variables needed...
158 */
159
160 length = ippLength(request);
161 if (filename)
162 length += fileinfo.st_size;
163
164 httpClearFields(http);
165 httpSetLength(http, length);
166 httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
167 httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
f301802f 168 httpSetExpect(http, expect);
ecdc0628 169
170 DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http->authstring));
171
172 /*
173 * Try the request...
174 */
175
176 DEBUG_puts("cupsDoFileRequest: post...");
177
178 if (httpPost(http, resource))
179 {
180 if (httpReconnect(http))
181 {
182 status = HTTP_ERROR;
183 break;
184 }
185 else
186 continue;
187 }
188
189 /*
d6ae789d 190 * Send the IPP data...
ecdc0628 191 */
192
d6ae789d 193 DEBUG_puts("cupsDoFileRequest: ipp write...");
b423cd4c 194
d6ae789d 195 request->state = IPP_IDLE;
196 status = HTTP_CONTINUE;
197 got_status = 0;
198
199 while ((state = ippWrite(http, request)) != IPP_DATA)
200 if (state == IPP_ERROR)
201 break;
202 else if (httpCheck(http))
203 {
204 got_status = 1;
205
206 if ((status = httpUpdate(http)) != HTTP_CONTINUE)
207 break;
208 }
209
210 if (!got_status)
b423cd4c 211 {
212 /*
d6ae789d 213 * Wait up to 1 second to get the 100-continue response...
b423cd4c 214 */
ecdc0628 215
d6ae789d 216 if (httpWait(http, 1000))
217 status = httpUpdate(http);
218 }
219 else if (httpCheck(http))
220 status = httpUpdate(http);
ecdc0628 221
d6ae789d 222 if (status == HTTP_CONTINUE && state == IPP_DATA && filename)
223 {
224 DEBUG_puts("cupsDoFileRequest: file write...");
b423cd4c 225
d6ae789d 226 /*
227 * Send the file...
228 */
229
230 rewind(file);
231
232 while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0)
233 {
234 if (httpCheck(http))
b423cd4c 235 {
236 if ((status = httpUpdate(http)) != HTTP_CONTINUE)
237 break;
238 }
239
d6ae789d 240 if (httpWrite2(http, buffer, bytes) < bytes)
241 break;
ecdc0628 242 }
b423cd4c 243 }
ecdc0628 244
245 /*
246 * Get the server's return status...
247 */
248
249 DEBUG_puts("cupsDoFileRequest: update...");
250
251 while (status == HTTP_CONTINUE)
252 status = httpUpdate(http);
253
254 DEBUG_printf(("cupsDoFileRequest: status = %d\n", status));
255
256 if (status == HTTP_UNAUTHORIZED)
257 {
258 DEBUG_puts("cupsDoFileRequest: unauthorized...");
259
260 /*
261 * Flush any error message...
262 */
263
264 httpFlush(http);
265
266 /*
267 * See if we can do authentication...
268 */
269
270 if (cupsDoAuthentication(http, "POST", resource))
271 break;
272
273 if (httpReconnect(http))
274 {
275 status = HTTP_ERROR;
276 break;
277 }
278
279 continue;
280 }
281 else if (status == HTTP_ERROR)
282 {
89d46774 283 DEBUG_printf(("cupsDoFileRequest: http->error=%d (%s)\n", http->error,
284 strerror(http->error)));
285
ecdc0628 286#ifdef WIN32
89d46774 287 if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH &&
288 http->error != ETIMEDOUT)
ecdc0628 289#else
89d46774 290 if (http->error != ENETDOWN && http->error != ENETUNREACH &&
291 http->error != ETIMEDOUT)
ecdc0628 292#endif /* WIN32 */
293 continue;
294 else
295 break;
296 }
297#ifdef HAVE_SSL
298 else if (status == HTTP_UPGRADE_REQUIRED)
299 {
300 /* Flush any error message... */
301 httpFlush(http);
302
303 /* Reconnect... */
304 if (httpReconnect(http))
305 {
306 status = HTTP_ERROR;
307 break;
308 }
309
310 /* Upgrade with encryption... */
311 httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
312
313 /* Try again, this time with encryption enabled... */
314 continue;
315 }
316#endif /* HAVE_SSL */
f301802f 317 else if (status == HTTP_EXPECTATION_FAILED)
318 {
319 /*
320 * Don't try using the Expect: header the next time around...
321 */
322
323 expect = (http_status_t)0;
324 }
ecdc0628 325 else if (status != HTTP_OK)
326 {
327 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status));
328
329 /*
330 * Flush any error message...
331 */
332
333 httpFlush(http);
334 break;
335 }
336 else
337 {
338 /*
339 * Read the response...
340 */
341
342 DEBUG_puts("cupsDoFileRequest: response...");
343
344 response = ippNew();
345
89d46774 346 while ((state = ippRead(http, response)) != IPP_DATA)
347 if (state == IPP_ERROR)
348 {
349 /*
350 * Delete the response...
351 */
ecdc0628 352
89d46774 353 DEBUG_puts("IPP read error!");
354 ippDelete(response);
355 response = NULL;
ecdc0628 356
89d46774 357 _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
ecdc0628 358
89d46774 359 break;
360 }
ecdc0628 361 }
362 }
363
364 /*
365 * Close the file if needed...
366 */
367
368 if (filename != NULL)
369 fclose(file);
370
371 /*
372 * Flush any remaining data...
373 */
374
375 httpFlush(http);
376
377 /*
378 * Delete the original request and return the response...
379 */
380
381 ippDelete(request);
382
383 if (response)
384 {
385 ipp_attribute_t *attr; /* status-message attribute */
386
387
388 attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
389
390 _cupsSetError(response->request.status.status_code,
391 attr ? attr->values[0].string.text :
392 ippErrorString(response->request.status.status_code));
393 }
394 else if (status != HTTP_OK)
395 {
396 switch (status)
397 {
398 case HTTP_NOT_FOUND :
399 _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
400 break;
401
402 case HTTP_UNAUTHORIZED :
403 _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
404 break;
405
406 case HTTP_FORBIDDEN :
407 _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
408 break;
409
410 case HTTP_BAD_REQUEST :
411 _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
412 break;
413
414 case HTTP_REQUEST_TOO_LARGE :
415 _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
416 break;
417
418 case HTTP_NOT_IMPLEMENTED :
419 _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
420 break;
421
422 case HTTP_NOT_SUPPORTED :
423 _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
424 break;
425
426 default :
427 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
428 status));
429 _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
430 break;
431 }
432 }
433
434 return (response);
435}
436
437
438/*
439 * 'cupsDoRequest()' - Do an IPP request.
440 *
441 * This function sends the IPP request to the specified server, retrying
442 * and authenticating as necessary. The request is freed with ippDelete()
443 * after receiving a valid IPP response.
444 */
445
446ipp_t * /* O - Response data */
447cupsDoRequest(http_t *http, /* I - HTTP connection to server */
448 ipp_t *request, /* I - IPP request */
449 const char *resource) /* I - HTTP resource for POST */
450{
451 return (cupsDoFileRequest(http, request, resource, NULL));
452}
453
454
455/*
456 * '_cupsSetError()' - Set the last IPP status code and status-message.
457 */
458
459void
460_cupsSetError(ipp_status_t status, /* I - IPP status code */
461 const char *message) /* I - status-message value */
462{
463 _cups_globals_t *cg; /* Global data */
464
465
466 cg = _cupsGlobals();
467 cg->last_error = status;
468
469 if (cg->last_status_message)
470 {
471 free(cg->last_status_message);
472
473 cg->last_status_message = NULL;
474 }
475
476 if (message)
477 cg->last_status_message = strdup(message);
478}
479
480
481/*
f301802f 482 * End of "$Id: request.c 5556 2006-05-21 13:55:23Z mike $".
ecdc0628 483 */