*
* IPP utilities for CUPS.
*
- * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2007-2011 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
* cupsGetResponse() - Get a response to an IPP request.
* cupsLastError() - Return the last IPP status code.
* cupsLastErrorString() - Return the last IPP status-message.
+ * _cupsNextDelay() - Return the next retry delay value.
* cupsReadResponseData() - Read additional data after the IPP response.
* cupsSendRequest() - Send an IPP request.
* cupsWriteRequestData() - Write additional data after an IPP request.
if (!http)
if ((http = _cupsConnect()) == NULL)
+ {
+ ippDelete(request);
+
return (NULL);
+ }
/*
* See if we have a file to send...
{
if (httpCheck(http))
{
- if ((status = httpUpdate(http)) != HTTP_CONTINUE)
+ _httpUpdate(http, &status);
+
+ if (status >= HTTP_MULTIPLE_CHOICES)
break;
}
DEBUG_printf(("2cupsGetResponse: Update loop, http->status=%d...",
http->status));
- status = http->status;
- while (status == HTTP_CONTINUE)
+ do
+ {
status = httpUpdate(http);
+ }
+ while (status != HTTP_ERROR && http->state == HTTP_POST_RECV);
DEBUG_printf(("2cupsGetResponse: status=%d", status));
if (state == IPP_ERROR)
{
/*
- * Delete the response...
+ * Flush remaining data and delete the response...
*/
DEBUG_puts("1cupsGetResponse: IPP read error!");
+ httpFlush(http);
+
ippDelete(response);
response = NULL;
}
+/*
+ * '_cupsNextDelay()' - Return the next retry delay value.
+ *
+ * This function currently returns the Fibonacci sequence 1 1 2 3 5 8.
+ *
+ * Pass 0 for the current delay value to initialize the sequence.
+ */
+
+int /* O - Next delay value */
+_cupsNextDelay(int current, /* I - Current delay value or 0 */
+ int *previous) /* IO - Previous delay value */
+{
+ int next; /* Next delay value */
+
+
+ if (current > 0)
+ {
+ next = (current + *previous) % 12;
+ *previous = next < current ? 0 : current;
+ }
+ else
+ {
+ next = 1;
+ *previous = 0;
+ }
+
+ return (next);
+}
+
+
/*
* 'cupsReadResponseData()' - Read additional data after the IPP response.
*
* Reconnect if the last response had a "Connection: close"...
*/
- if (!strcasecmp(http->fields[HTTP_FIELD_CONNECTION], "close"))
+ if (!_cups_strcasecmp(http->fields[HTTP_FIELD_CONNECTION], "close"))
if (httpReconnect(http))
{
_cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
*/
httpClearFields(http);
- httpSetLength(http, length);
+ httpSetExpect(http, expect);
httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
+ httpSetLength(http, length);
+
+#ifdef HAVE_GSSAPI
+ if (http->authstring && !strncmp(http->authstring, "Negotiate", 9))
+ {
+ /*
+ * Do not use cached Kerberos credentials since they will look like a
+ * "replay" attack...
+ */
+
+ _cupsSetNegotiateAuthString(http, "POST", resource);
+ }
+#endif /* HAVE_GSSAPI */
+
httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
- httpSetExpect(http, expect);
DEBUG_printf(("2cupsSendRequest: authstring=\"%s\"", http->authstring));
{
got_status = 1;
- if ((status = httpUpdate(http)) != HTTP_CONTINUE)
+ _httpUpdate(http, &status);
+ if (status >= HTTP_MULTIPLE_CHOICES)
break;
}
+ if (state == IPP_ERROR)
+ {
+ http->status = HTTP_ERROR;
+ http->state = HTTP_WAITING;
+
+ return (HTTP_ERROR);
+ }
+
/*
* Wait up to 1 second to get the 100-continue response as needed...
*/
- if (!got_status && expect == HTTP_CONTINUE)
+ if (!got_status)
{
- DEBUG_puts("2cupsSendRequest: Waiting for 100-continue...");
+ if (expect == HTTP_CONTINUE)
+ {
+ DEBUG_puts("2cupsSendRequest: Waiting for 100-continue...");
- if (httpWait(http, 1000))
- status = httpUpdate(http);
+ if (httpWait(http, 1000))
+ _httpUpdate(http, &status);
+ }
+ else if (httpCheck(http))
+ _httpUpdate(http, &status);
}
- else if (httpCheck(http))
- status = httpUpdate(http);
DEBUG_printf(("2cupsSendRequest: status=%d", status));
* Process the current HTTP status...
*/
- if (status >= HTTP_BAD_REQUEST)
+ if (status >= HTTP_MULTIPLE_CHOICES)
httpFlush(http);
switch (status)
if ((http = cg->http) == NULL)
{
_cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
+ DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR.");
return (HTTP_ERROR);
}
}
wused = http->wused;
if (httpWrite2(http, buffer, length) < 0)
+ {
+ DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR.");
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(http->error), 0);
return (HTTP_ERROR);
+ }
/*
* Finally, check if we have any pending data from the server...
if (_httpWait(http, 0, 1))
{
- http_status_t status; /* Status from httpUpdate */
+ http_status_t status; /* Status from _httpUpdate */
- if ((status = httpUpdate(http)) >= HTTP_BAD_REQUEST)
+ _httpUpdate(http, &status);
+ if (status >= HTTP_MULTIPLE_CHOICES)
+ {
+ _cupsSetHTTPError(status);
httpFlush(http);
+ }
+ DEBUG_printf(("1cupsWriteRequestData: Returning %d.\n", status));
return (status);
}
}
+ DEBUG_puts("1cupsWriteRequestData: Returning HTTP_CONTINUE.");
return (HTTP_CONTINUE);
}
break;
case HTTP_UNAUTHORIZED :
- _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status), 0);
+ _cupsSetError(IPP_NOT_AUTHENTICATED, httpStatus(status), 0);
break;
case HTTP_AUTHORIZATION_CANCELED :
- _cupsSetError(IPP_AUTHORIZATION_CANCELED, httpStatus(status), 0);
+ _cupsSetError(IPP_AUTHENTICATION_CANCELED, httpStatus(status), 0);
break;
case HTTP_FORBIDDEN :
_cupsSetError(IPP_PKI_ERROR, httpStatus(status), 0);
break;
+ case HTTP_ERROR :
+ _cupsSetError(IPP_INTERNAL_ERROR, httpStatus(status), 0);
+ break;
+
default :
DEBUG_printf(("4_cupsSetHTTPError: HTTP error %d mapped to "
"IPP_SERVICE_UNAVAILABLE!", status));