/*
- * "$Id: http.c 4914 2006-01-11 02:04:22Z mike $"
+ * "$Id: http.c 5630 2006-06-05 18:42:53Z mike $"
*
* HTTP routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* property of Easy Software Products and are protected by Federal
*
* Contents:
*
+ * httpBlocking() - Set blocking/non-blocking behavior on a connection.
* httpCheck() - Check to see if there is a pending response from
* the server.
* httpClearCookie() - Clear the cookie value(s).
+ * httpClearFields() - Clear HTTP request fields.
* httpClose() - Close an HTTP connection...
* httpConnect() - Connect to a HTTP server.
* httpConnectEncrypt() - Connect to a HTTP server using encryption.
* httpDelete() - Send a DELETE request to the server.
* httpEncryption() - Set the required encryption on the link.
+ * httpError() - Get the last error on a connection.
* httpFlush() - Flush data from a HTTP connection.
* httpFlushWrite() - Flush data in write buffer.
* httpGet() - Send a GET request to the server.
+ * httpGetBlocking() - Get the blocking/non-block state of a connection.
+ * httpGetCookie() - Get any cookie data from the response.
+ * httpGetFd() - Get the file descriptor associated with a
+ * connection.
+ * httpGetField() - Get a field value from a request/response.
* httpGetLength() - Get the amount of data remaining from the
* content-length or transfer-encoding fields.
* httpGetLength2() - Get the amount of data remaining from the
* content-length or transfer-encoding fields.
+ * httpGetStatus() - Get the status of the last HTTP request.
* httpGetSubField() - Get a sub-field value.
* httpGets() - Get a line of text from a HTTP connection.
* httpHead() - Send a HEAD request to the server.
* httpPrintf() - Print a formatted string to a HTTP connection.
* httpPut() - Send a PUT request to the server.
* httpRead() - Read data from a HTTP connection.
+ * httpRead2() - Read data from a HTTP connection.
* _httpReadCDSA() - Read function for CDSA decryption code.
* httpReconnect() - Reconnect to a HTTP server...
* httpSetCookie() - Set the cookie value(s)...
+ * httpSetExpect() - Set the Expect: header in a request.
* httpSetField() - Set the value of an HTTP header.
* httpSetLength() - Set the content-length and transfer-encoding.
* httpTrace() - Send an TRACE request to the server.
* httpUpdate() - Update the current HTTP state for incoming data.
* httpWait() - Wait for data available on a connection.
* httpWrite() - Write data to a HTTP connection.
+ * httpWrite2() - Write data to a HTTP connection.
* _httpWriteCDSA() - Write function for CDSA encryption code.
* http_field() - Return the field index for a field name.
* http_read_ssl() - Read from a SSL/TLS connection.
};
+/*
+ * 'httpBlocking()' - Set blocking/non-blocking behavior on a connection.
+ */
+
+void
+httpBlocking(http_t *http, /* I - HTTP connection */
+ int b) /* I - 1 = blocking, 0 = non-blocking */
+{
+ if (http)
+ http->blocking = b;
+}
+
+
/*
* 'httpCheck()' - Check to see if there is a pending response from the server.
*/
-int /* O - 0 = no data, 1 = data available */
-httpCheck(http_t *http) /* I - HTTP connection */
+int /* O - 0 = no data, 1 = data available */
+httpCheck(http_t *http) /* I - HTTP connection */
{
return (httpWait(http, 0));
}
*/
void
-httpClearCookie(http_t *http) /* I - Connection */
+httpClearCookie(http_t *http) /* I - HTTP connection */
{
if (!http)
return;
}
+/*
+ * 'httpClearFields()' - Clear HTTP request fields.
+ */
+
+void
+httpClearFields(http_t *http) /* I - HTTP connection */
+{
+ if (http)
+ {
+ memset(http->fields, 0, sizeof(http->fields));
+ httpSetField(http, HTTP_FIELD_HOST, http->hostname);
+
+ http->expect = (http_status_t)0;
+ }
+}
+
+
/*
* 'httpClose()' - Close an HTTP connection...
*/
void
-httpClose(http_t *http) /* I - Connection to close */
+httpClose(http_t *http) /* I - HTTP connection */
{
DEBUG_printf(("httpClose(http=%p)\n", http));
*/
int /* O - Status of call (0 = success) */
-httpDelete(http_t *http, /* I - HTTP data */
+httpDelete(http_t *http, /* I - HTTP connection */
const char *uri) /* I - URI to delete */
{
return (http_send(http, HTTP_DELETE, uri));
*/
int /* O - -1 on error, 0 on success */
-httpEncryption(http_t *http, /* I - HTTP data */
+httpEncryption(http_t *http, /* I - HTTP connection */
http_encryption_t e) /* I - New encryption preference */
{
DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e));
}
+/*
+ * 'httpError()' - Get the last error on a connection.
+ */
+
+int /* O - Error code (errno) value */
+httpError(http_t *http) /* I - HTTP connection */
+{
+ if (http)
+ return (http->error);
+ else
+ return (EINVAL);
+}
+
+
/*
* 'httpFlush()' - Flush data from a HTTP connection.
*/
void
-httpFlush(http_t *http) /* I - HTTP data */
+httpFlush(http_t *http) /* I - HTTP connection */
{
char buffer[8192]; /* Junk buffer */
+ int blocking; /* To block or not to block */
DEBUG_printf(("httpFlush(http=%p), state=%d\n", http, http->state));
- while (httpRead(http, buffer, sizeof(buffer)) > 0);
+ /*
+ * Temporarily set non-blocking mode so we don't get stuck in httpRead()...
+ */
+
+ blocking = http->blocking;
+ http->blocking = 0;
+
+ /*
+ * Read any data we can...
+ */
+
+ while (httpRead2(http, buffer, sizeof(buffer)) > 0);
+
+ /*
+ * Restore blocking and reset the connection if we didn't get all of
+ * the remaining data...
+ */
+
+ http->blocking = blocking;
+
+ if (http->state != HTTP_WAITING && http->fd >= 0)
+ {
+ /*
+ * Didn't get the data back, so close the current connection.
+ */
+
+ http->state = HTTP_WAITING;
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ http_shutdown_ssl(http);
+#endif /* HAVE_SSL */
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif /* WIN32 */
+
+ http->fd = -1;
+ }
}
*/
int /* O - Bytes written or -1 on error */
-httpFlushWrite(http_t *http) /* I - HTTP data */
+httpFlushWrite(http_t *http) /* I - HTTP connection */
{
int bytes; /* Bytes written */
*/
int /* O - Status of call (0 = success) */
-httpGet(http_t *http, /* I - HTTP data */
+httpGet(http_t *http, /* I - HTTP connection */
const char *uri) /* I - URI to get */
{
return (http_send(http, HTTP_GET, uri));
}
+/*
+ * 'httpGetBlocking()' - Get the blocking/non-block state of a connection.
+ *
+ * @since CUPS 1.2@
+ */
+
+int /* O - 1 if blocking, 0 if non-blocking */
+httpGetBlocking(http_t *http) /* I - HTTP connection */
+{
+ return (http ? http->blocking : 0);
+}
+
+
+/*
+ * 'httpGetCookie()' - Get any cookie data from the response.
+ *
+ * @since CUPS 1.1.19@
+ */
+
+const char * /* O - Cookie data or NULL */
+httpGetCookie(http_t *http) /* I - HTTP connecion */
+{
+ return (http ? http->cookie : NULL);
+}
+
+
+/*
+ * 'httpGetFd()' - Get the file descriptor associated with a connection.
+ *
+ * @since CUPS 1.2@
+ */
+
+int /* O - File descriptor or -1 if none */
+httpGetFd(http_t *http) /* I - HTTP connection */
+{
+ return (http ? http->fd : -1);
+}
+
+
+/*
+ * 'httpGetField()' - Get a field value from a request/response.
+ */
+
+const char * /* O - Field value */
+httpGetField(http_t *http, /* I - HTTP connection */
+ http_field_t field) /* I - Field to get */
+{
+ if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
+ return (NULL);
+ else
+ return (http->fields[field]);
+}
+
+
+/*
+ * 'httpGetLength()' - Get the amount of data remaining from the
+ * content-length or transfer-encoding fields.
+ *
+ * This function is deprecated and will not return lengths larger than
+ * 2^31 - 1; use httpGetLength2() instead.
+ *
+ * @deprecated@
+ */
+
+int /* O - Content length */
+httpGetLength(http_t *http) /* I - HTTP connection */
+{
+ /*
+ * Get the read content length and return the 32-bit value.
+ */
+
+ if (http)
+ {
+ httpGetLength2(http);
+
+ return (http->_data_remaining);
+ }
+ else
+ return (-1);
+}
+
+
+/*
+ * 'httpGetLength2()' - Get the amount of data remaining from the
+ * content-length or transfer-encoding fields.
+ *
+ * This function returns the complete content length, even for
+ * content larger than 2^31 - 1.
+ *
+ * @since CUPS 1.2@
+ */
+
+off_t /* O - Content length */
+httpGetLength2(http_t *http) /* I - HTTP connection */
+{
+ DEBUG_printf(("httpGetLength2(http=%p), state=%d\n", http, http->state));
+
+ if (!http)
+ return (-1);
+
+ if (!strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked"))
+ {
+ DEBUG_puts("httpGetLength2: chunked request!");
+
+ http->data_encoding = HTTP_ENCODE_CHUNKED;
+ http->data_remaining = 0;
+ }
+ else
+ {
+ http->data_encoding = HTTP_ENCODE_LENGTH;
+
+ /*
+ * The following is a hack for HTTP servers that don't send a
+ * content-length or transfer-encoding field...
+ *
+ * If there is no content-length then the connection must close
+ * after the transfer is complete...
+ */
+
+ if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
+ http->data_remaining = 2147483647;
+ else
+ http->data_remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
+ NULL, 10);
+
+ DEBUG_printf(("httpGetLength2: content_length=" CUPS_LLFMT "\n",
+ CUPS_LLCAST http->data_remaining));
+ }
+
+ if (http->data_remaining <= INT_MAX)
+ http->_data_remaining = (int)http->data_remaining;
+ else
+ http->_data_remaining = INT_MAX;
+
+ return (http->data_remaining);
+}
+
+
+/*
+ * 'httpGetStatus()' - Get the status of the last HTTP request.
+ *
+ * @since CUPS 1.2@
+ */
+
+http_status_t /* O - HTTP status */
+httpGetStatus(http_t *http) /* I - HTTP connection */
+{
+ return (http ? http->status : HTTP_ERROR);
+}
+
+
/*
* 'httpGetSubField()' - Get a sub-field value.
*
*/
char * /* O - Value or NULL */
-httpGetSubField(http_t *http, /* I - HTTP data */
+httpGetSubField(http_t *http, /* I - HTTP connection */
http_field_t field, /* I - Field index */
const char *name, /* I - Name of sub-field */
char *value) /* O - Value string */
*/
char * /* O - Value or NULL */
-httpGetSubField2(http_t *http, /* I - HTTP data */
+httpGetSubField2(http_t *http, /* I - HTTP connection */
http_field_t field, /* I - Field index */
const char *name, /* I - Name of sub-field */
char *value, /* O - Value string */
http, field, name, value, valuelen));
if (!http || !name || !value || valuelen < 2 ||
- field < HTTP_FIELD_ACCEPT_LANGUAGE ||
- field > HTTP_FIELD_WWW_AUTHENTICATE)
+ field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
return (NULL);
end = value + valuelen - 1;
}
-/*
- * 'httpGetLength()' - Get the amount of data remaining from the
- * content-length or transfer-encoding fields.
- *
- * This function is deprecated and will not return lengths larger than
- * 2^31 - 1; use httpGetLength2() instead.
- *
- * @since CUPS 1.2@
- */
-
-int /* O - Content length */
-httpGetLength(http_t *http) /* I - HTTP data */
-{
- /*
- * Get the read content length and return the 32-bit value.
- */
-
- httpGetLength2(http);
-
- return (http->_data_remaining);
-}
-
-
-/*
- * 'httpGetLength2()' - Get the amount of data remaining from the
- * content-length or transfer-encoding fields.
- *
- * This function returns the complete content length, even for
- * content larger than 2^31 - 1.
- */
-
-off_t /* O - Content length */
-httpGetLength2(http_t *http) /* I - HTTP data */
-{
- DEBUG_printf(("httpGetLength2(http=%p), state=%d\n", http, http->state));
-
- if (!strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked"))
- {
- DEBUG_puts("httpGetLength2: chunked request!");
-
- http->data_encoding = HTTP_ENCODE_CHUNKED;
- http->data_remaining = 0;
- }
- else
- {
- http->data_encoding = HTTP_ENCODE_LENGTH;
-
- /*
- * The following is a hack for HTTP servers that don't send a
- * content-length or transfer-encoding field...
- *
- * If there is no content-length then the connection must close
- * after the transfer is complete...
- */
-
- if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
- http->data_remaining = 2147483647;
- else
- http->data_remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
- NULL, 10);
-
- DEBUG_printf(("httpGetLength2: content_length=" CUPS_LLFMT "\n",
- CUPS_LLCAST http->data_remaining));
- }
-
- if (http->data_remaining <= INT_MAX)
- http->_data_remaining = (int)http->data_remaining;
- else
- http->_data_remaining = INT_MAX;
-
- return (http->data_remaining);
-}
-
-
/*
* 'httpGets()' - Get a line of text from a HTTP connection.
*/
char * /* O - Line or NULL */
httpGets(char *line, /* I - Line to read into */
int length, /* I - Max length of buffer */
- http_t *http) /* I - HTTP data */
+ http_t *http) /* I - HTTP connection */
{
char *lineptr, /* Pointer into line */
*lineend, /* End of line */
* No newline; see if there is more data to be read...
*/
- if (!http->blocking && !http_wait(http, 1000))
+ if (!http->blocking && !http_wait(http, 10000))
+ {
+ DEBUG_puts("httpGets: Timed out!");
+ http->error = ETIMEDOUT;
return (NULL);
+ }
#ifdef HAVE_SSL
if (http->tls)
*/
int /* O - Status of call (0 = success) */
-httpHead(http_t *http, /* I - HTTP data */
+httpHead(http_t *http, /* I - HTTP connection */
const char *uri) /* I - URI for head */
{
return (http_send(http, HTTP_HEAD, uri));
if (!initialized)
WSAStartup(MAKEWORD(1,1), &winsockdata);
-#elif defined(HAVE_SIGSET)
- sigset(SIGPIPE, SIG_IGN);
-#elif defined(HAVE_SIGACTION)
- struct sigaction action; /* POSIX sigaction data */
-
-
+#elif !defined(SO_NOSIGPIPE)
/*
* Ignore SIGPIPE signals...
*/
+# ifdef HAVE_SIGSET
+ sigset(SIGPIPE, SIG_IGN);
+# elif defined(HAVE_SIGACTION)
+ struct sigaction action; /* POSIX sigaction data */
+
+
memset(&action, 0, sizeof(action));
action.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &action, NULL);
-#else
+# else
signal(SIGPIPE, SIG_IGN);
+# endif /* !SO_NOSIGPIPE */
#endif /* WIN32 */
#ifdef HAVE_GNUTLS
*/
int /* O - Status of call (0 = success) */
-httpOptions(http_t *http, /* I - HTTP data */
+httpOptions(http_t *http, /* I - HTTP connection */
const char *uri) /* I - URI for options */
{
return (http_send(http, HTTP_OPTIONS, uri));
*/
int /* O - Status of call (0 = success) */
-httpPost(http_t *http, /* I - HTTP data */
+httpPost(http_t *http, /* I - HTTP connection */
const char *uri) /* I - URI for post */
{
return (http_send(http, HTTP_POST, uri));
/*
* 'httpPrintf()' - Print a formatted string to a HTTP connection.
+ *
+ * @private@
*/
int /* O - Number of bytes written */
-httpPrintf(http_t *http, /* I - HTTP data */
+httpPrintf(http_t *http, /* I - HTTP connection */
const char *format, /* I - printf-style format string */
...) /* I - Additional args as needed */
{
*/
int /* O - Status of call (0 = success) */
-httpPut(http_t *http, /* I - HTTP data */
+httpPut(http_t *http, /* I - HTTP connection */
const char *uri) /* I - URI to put */
{
return (http_send(http, HTTP_PUT, uri));
/*
* 'httpRead()' - Read data from a HTTP connection.
+ *
+ * This function is deprecated. Use the httpRead2() function which can
+ * read more than 2GB of data.
+ *
+ * @deprecated@
*/
int /* O - Number of bytes read */
-httpRead(http_t *http, /* I - HTTP data */
+httpRead(http_t *http, /* I - HTTP connection */
char *buffer, /* I - Buffer for data */
int length) /* I - Maximum number of bytes */
{
- int bytes; /* Bytes read */
+ return ((int)httpRead2(http, buffer, length));
+}
+
+
+/*
+ * 'httpRead2()' - Read data from a HTTP connection.
+ *
+ * @since CUPS 1.2@
+ */
+
+ssize_t /* O - Number of bytes read */
+httpRead2(http_t *http, /* I - HTTP connection */
+ char *buffer, /* I - Buffer for data */
+ size_t length) /* I - Maximum number of bytes */
+{
+ ssize_t bytes; /* Bytes read */
char len[32]; /* Length string */
if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
http->data_remaining <= 0)
{
- DEBUG_puts("httpRead: Getting chunk length...");
+ DEBUG_puts("httpRead2: Getting chunk length...");
if (httpGets(len, sizeof(len), http) == NULL)
{
- DEBUG_puts("httpRead: Could not get length!");
+ DEBUG_puts("httpRead2: Could not get length!");
return (0);
}
http->data_remaining = strtoll(len, NULL, 16);
if (http->data_remaining < 0)
{
- DEBUG_puts("httpRead: Negative chunk length!");
+ DEBUG_puts("httpRead2: Negative chunk length!");
return (0);
}
}
- DEBUG_printf(("httpRead: data_remaining=" CUPS_LLFMT "\n",
+ DEBUG_printf(("httpRead2: data_remaining=" CUPS_LLFMT "\n",
CUPS_LLCAST http->data_remaining));
if (http->data_remaining <= 0)
* Buffer small reads for better performance...
*/
- if (!http->blocking && !httpWait(http, 1000))
+ if (!http->blocking && !httpWait(http, 10000))
return (0);
if (http->data_remaining > sizeof(http->buffer))
else
#endif /* HAVE_SSL */
{
- DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
+ DEBUG_printf(("httpRead2: reading %d bytes from socket into buffer...\n",
bytes));
bytes = recv(http->fd, http->buffer, bytes, 0);
- DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
+ DEBUG_printf(("httpRead2: read %d bytes from socket into buffer...\n",
bytes));
}
bytes = length;
- DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
+ DEBUG_printf(("httpRead2: grabbing %d bytes from input buffer...\n", bytes));
memcpy(buffer, http->buffer, length);
http->used -= length;
#ifdef HAVE_SSL
else if (http->tls)
{
- if (!http->blocking && !httpWait(http, 1000))
+ if (!http->blocking && !httpWait(http, 10000))
return (0);
bytes = http_read_ssl(http, buffer, length);
#endif /* HAVE_SSL */
else
{
- if (!http->blocking && !httpWait(http, 1000))
+ if (!http->blocking && !httpWait(http, 10000))
return (0);
- DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
+ DEBUG_printf(("httpRead2: reading %d bytes from socket...\n", length));
while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
if (errno != EINTR)
break;
- DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
+ DEBUG_printf(("httpRead2: read %d bytes from socket...\n", bytes));
}
if (bytes > 0)
#ifdef DEBUG
{
int i, j, ch;
- printf("httpRead: Read %d bytes:\n", bytes);
+ printf("httpRead2: Read %d bytes:\n", bytes);
for (i = 0; i < bytes; i += 16)
{
printf(" ");
{
ch = buffer[i + j] & 255;
- if (ch < ' ' || ch == 127)
+ if (ch < ' ' || ch >= 127)
ch = '.';
putchar(ch);
void *data, /* I - Data buffer */
size_t *dataLength) /* IO - Number of bytes */
{
- ssize_t bytes; /* Number of bytes read */
+ OSStatus result; /* Return value */
+ ssize_t bytes; /* Number of bytes read */
+ cdsa_conn_ref_t u; /* Connection reference union */
+
+
+ u.connection = connection;
+ do
+ bytes = recv(u.sock, data, *dataLength, 0);
+ while (bytes == -1 && errno == EINTR);
- bytes = recv((int)connection, data, *dataLength, 0);
- if (bytes >= 0)
+ if (bytes == *dataLength)
+ result = 0;
+ else if (bytes > 0)
{
*dataLength = bytes;
- return (0);
+ result = errSSLWouldBlock;
}
else
- return (-1);
+ {
+ *dataLength = 0;
+
+ if (bytes == 0)
+ result = errSSLClosedGraceful;
+ else if (errno == EAGAIN)
+ result = errSSLWouldBlock;
+ else
+ result = errSSLClosedAbort;
+ }
+
+ return result;
}
#endif /* HAVE_SSL && HAVE_CDSASSL */
/*
- * 'httpReconnect()' - Reconnect to a HTTP server...
+ * 'httpReconnect()' - Reconnect to a HTTP server.
*/
int /* O - 0 on success, non-zero on failure */
-httpReconnect(http_t *http) /* I - HTTP data */
+httpReconnect(http_t *http) /* I - HTTP connection */
{
http_addrlist_t *addr; /* Connected address */
*/
if (http->fd >= 0)
+ {
#ifdef WIN32
closesocket(http->fd);
#else
close(http->fd);
#endif /* WIN32 */
+ http->fd = -1;
+ }
+
/*
* Connect to the server...
*/
}
+/*
+ * 'httpSetExpect()' - Set the Expect: header in a request.
+ *
+ * Currently only HTTP_CONTINUE is supported for the "expect" argument.
+ *
+ * @since CUPS 1.2@
+ */
+
+void
+httpSetExpect(http_t *http, /* I - HTTP connection */
+ http_status_t expect) /* I - HTTP status to expect (HTTP_CONTINUE) */
+{
+ if (http)
+ http->expect = expect;
+}
+
+
/*
* 'httpSetField()' - Set the value of an HTTP header.
*/
void
-httpSetField(http_t *http, /* I - HTTP data */
+httpSetField(http_t *http, /* I - HTTP connection */
http_field_t field, /* I - Field index */
const char *value) /* I - Value */
{
*/
void
-httpSetLength(http_t *http, /* I - HTTP data */
+httpSetLength(http_t *http, /* I - HTTP connection */
size_t length) /* I - Length (0 for chunked) */
{
if (!http)
*/
int /* O - Status of call (0 = success) */
-httpTrace(http_t *http, /* I - HTTP data */
+httpTrace(http_t *http, /* I - HTTP connection */
const char *uri) /* I - URI for trace */
{
return (http_send(http, HTTP_TRACE, uri));
*/
http_status_t /* O - HTTP status */
-httpUpdate(http_t *http) /* I - HTTP data */
+httpUpdate(http_t *http) /* I - HTTP connection */
{
char line[32768], /* Line from connection... */
*value; /* Pointer to value on line */
case HTTP_PUT :
http->state ++;
case HTTP_POST_SEND :
+ case HTTP_HEAD :
break;
default :
*/
int /* O - 1 if data is available, 0 otherwise */
-httpWait(http_t *http, /* I - HTTP data */
+httpWait(http_t *http, /* I - HTTP connection */
int msec) /* I - Milliseconds to wait */
{
/*
/*
* 'httpWrite()' - Write data to a HTTP connection.
+ *
+ * This function is deprecated. Use the httpWrite2() function which can
+ * write more than 2GB of data.
+ *
+ * @deprecated@
*/
int /* O - Number of bytes written */
-httpWrite(http_t *http, /* I - HTTP data */
+httpWrite(http_t *http, /* I - HTTP connection */
const char *buffer, /* I - Buffer for data */
int length) /* I - Number of bytes to write */
{
- int bytes; /* Bytes written */
+ return ((int)httpWrite2(http, buffer, length));
+}
+
+
+/*
+ * 'httpWrite2()' - Write data to a HTTP connection.
+ *
+ * @since CUPS 1.2@
+ */
+
+ssize_t /* O - Number of bytes written */
+httpWrite2(http_t *http, /* I - HTTP connection */
+ const char *buffer, /* I - Buffer for data */
+ size_t length) /* I - Number of bytes to write */
+{
+ ssize_t bytes; /* Bytes written */
DEBUG_printf(("httpWrite(http=%p, buffer=%p, length=%d)\n", http,
const void *data, /* I - Data buffer */
size_t *dataLength) /* IO - Number of bytes */
{
- ssize_t bytes; /* Number of write written */
+ OSStatus result; /* Return value */
+ ssize_t bytes; /* Number of bytes read */
+ cdsa_conn_ref_t u; /* Connection reference union */
- bytes = write((int)connection, data, *dataLength);
- if (bytes >= 0)
+ u.connection = connection;
+
+ do
+ bytes = write(u.sock, data, *dataLength);
+ while (bytes == -1 && errno == EINTR);
+
+ if (bytes == *dataLength)
+ result = 0;
+ else if (bytes >= 0)
{
*dataLength = bytes;
- return (0);
+ result = errSSLWouldBlock;
}
else
- return (-1);
+ {
+ *dataLength = 0;
+
+ if (errno == EAGAIN)
+ result = errSSLWouldBlock;
+ else
+ result = errSSLClosedAbort;
+ }
+
+ return result;
}
#endif /* HAVE_SSL && HAVE_CDSASSL */
*/
static int /* O - Bytes read */
-http_read_ssl(http_t *http, /* I - HTTP data */
+http_read_ssl(http_t *http, /* I - HTTP connection */
char *buf, /* I - Buffer to store data */
int len) /* I - Length of buffer */
{
return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len));
# elif defined(HAVE_CDSASSL)
+ int result; /* Return value */
OSStatus error; /* Error info */
size_t processed; /* Number of bytes processed */
- error = SSLRead((SSLContextRef)http->tls, buf, len, &processed);
+ error = SSLRead(((http_tls_t *)http->tls)->session, buf, len, &processed);
- if (error == 0)
- return (processed);
- else
+ switch (error)
{
- http->error = error;
-
- return (-1);
+ case 0 :
+ result = (int)processed;
+ break;
+ case errSSLClosedGraceful :
+ result = 0;
+ break;
+ case errSSLWouldBlock :
+ if (processed)
+ result = (int)processed;
+ else
+ {
+ result = -1;
+ errno = EINTR;
+ }
+ break;
+ default :
+ errno = EPIPE;
+ result = -1;
+ break;
}
+
+ return (result);
# endif /* HAVE_LIBSSL */
}
#endif /* HAVE_SSL */
*/
static int /* O - 0 on success, non-zero on error */
-http_send(http_t *http, /* I - HTTP data */
+http_send(http_t *http, /* I - HTTP connection */
http_state_t request, /* I - Request code */
const char *uri) /* I - URI */
{
*/
if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
- httpReconnect(http);
+ if (httpReconnect(http))
+ return (-1);
/*
* Send the request header...
return (-1);
}
+ if (http->expect == HTTP_CONTINUE &&
+ (http->state == HTTP_POST_RECV || http->state == HTTP_PUT_RECV))
+ if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+
if (httpPrintf(http, "\r\n") < 1)
{
http->status = HTTP_ERROR;
*/
static int /* O - Status of connection */
-http_setup_ssl(http_t *http) /* I - HTTP data */
+http_setup_ssl(http_t *http) /* I - HTTP connection */
{
# ifdef HAVE_LIBSSL
- SSL_CTX *context; /* Context for encryption */
- SSL *conn; /* Connection for encryption */
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
# elif defined(HAVE_GNUTLS)
- http_tls_t *conn; /* TLS session object */
+ http_tls_t *conn; /* TLS session object */
gnutls_certificate_client_credentials *credentials;
- /* TLS credentials */
+ /* TLS credentials */
# elif defined(HAVE_CDSASSL)
- SSLContextRef conn; /* Context for encryption */
- OSStatus error; /* Error info */
+ OSStatus error; /* Error code */
+ http_tls_t *conn; /* CDSA connection information */
+ cdsa_conn_ref_t u; /* Connection reference union */
# endif /* HAVE_LIBSSL */
}
# elif defined(HAVE_GNUTLS)
- conn = (http_tls_t *)malloc(sizeof(http_tls_t));
-
- if (conn == NULL)
+ if ((conn = (http_tls_t *)malloc(sizeof(http_tls_t))) == NULL)
{
http->error = errno;
http->status = HTTP_ERROR;
gnutls_init(&(conn->session), GNUTLS_CLIENT);
gnutls_set_default_priority(conn->session);
gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
- gnutls_transport_set_ptr(conn->session, http->fd);
+ gnutls_transport_set_ptr(conn->session,
+ (gnutls_transport_ptr)((long)http->fd));
if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
{
conn->credentials = credentials;
# elif defined(HAVE_CDSASSL)
- error = SSLNewContext(false, &conn);
+ conn = (http_tls_t *)calloc(1, sizeof(http_tls_t));
+
+ if (conn == NULL)
+ return (-1);
+
+ if ((error = SSLNewContext(false, &conn->session)))
+ {
+ http->error = error;
+ http->status = HTTP_ERROR;
+
+ free(conn);
+ return (-1);
+ }
+
+ /*
+ * Use a union to resolve warnings about int/pointer size mismatches...
+ */
+
+ u.connection = NULL;
+ u.sock = http->fd;
+ error = SSLSetConnection(conn->session, u.connection);
if (!error)
- error = SSLSetIOFuncs(conn, _httpReadCDSA, _httpWriteCDSA);
+ error = SSLSetIOFuncs(conn->session, _httpReadCDSA, _httpWriteCDSA);
if (!error)
- error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
+ error = SSLSetAllowsExpiredCerts(conn->session, true);
if (!error)
- error = SSLSetAllowsExpiredCerts(conn, true);
+ error = SSLSetAllowsAnyRoot(conn->session, true);
if (!error)
- error = SSLSetAllowsAnyRoot(conn, true);
+ error = SSLSetProtocolVersionEnabled(conn->session, kSSLProtocol2, false);
if (!error)
- error = SSLHandshake(conn);
+ {
+ while ((error = SSLHandshake(conn->session)) == errSSLWouldBlock)
+ usleep(1000);
+ }
- if (error != 0)
+ if (error)
{
http->error = error;
http->status = HTTP_ERROR;
- SSLDisposeContext(conn);
+ SSLDisposeContext(conn->session);
- close(http->fd);
+ free(conn);
return (-1);
}
*/
static void
-http_shutdown_ssl(http_t *http) /* I - HTTP data */
+http_shutdown_ssl(http_t *http) /* I - HTTP connection */
{
# ifdef HAVE_LIBSSL
- SSL_CTX *context; /* Context for encryption */
- SSL *conn; /* Connection for encryption */
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
conn = (SSL *)(http->tls);
SSL_free(conn);
# elif defined(HAVE_GNUTLS)
- http_tls_t *conn; /* Encryption session */
+ http_tls_t *conn; /* Encryption session */
gnutls_certificate_client_credentials *credentials;
- /* TLS credentials */
+ /* TLS credentials */
conn = (http_tls_t *)(http->tls);
free(conn);
# elif defined(HAVE_CDSASSL)
- SSLClose((SSLContextRef)http->tls);
- SSLDisposeContext((SSLContextRef)http->tls);
+ http_tls_t *conn; /* CDSA connection information */
+
+
+ conn = (http_tls_t *)(http->tls);
+
+ while (SSLClose(conn->session) == errSSLWouldBlock)
+ usleep(1000);
+
+ SSLDisposeContext(conn->session);
+
+ if (conn->certsArray)
+ CFRelease(conn->certsArray);
+
+ free(conn);
# endif /* HAVE_LIBSSL */
http->tls = NULL;
* 'http_upgrade()' - Force upgrade to TLS encryption.
*/
-static int /* O - Status of connection */
-http_upgrade(http_t *http) /* I - HTTP data */
+static int /* O - Status of connection */
+http_upgrade(http_t *http) /* I - HTTP connection */
{
- int ret; /* Return value */
- http_t myhttp; /* Local copy of HTTP data */
+ int ret; /* Return value */
+ http_t myhttp; /* Local copy of HTTP data */
DEBUG_printf(("http_upgrade(%p)\n", http));
*/
static int /* O - 1 if data is available, 0 otherwise */
-http_wait(http_t *http, /* I - HTTP data */
+http_wait(http_t *http, /* I - HTTP connection */
int msec) /* I - Milliseconds to wait */
{
#ifndef WIN32
DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec));
+ if (http->fd < 0)
+ return (0);
+
/*
* Check the SSL/TLS buffers for data first...
*/
# elif defined(HAVE_CDSASSL)
size_t bytes; /* Bytes that are available */
- if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0)
+ if (!SSLGetBufferedReadSize(((http_tls_t *)http->tls)->session, &bytes) && bytes > 0)
return (1);
# endif /* HAVE_LIBSSL */
}
{
FD_SET(http->fd, http->input_set);
+ DEBUG_printf(("http_wait: msec=%d, http->fd=%d\n", msec, http->fd));
+
if (msec >= 0)
{
timeout.tv_sec = msec / 1000;
}
else
nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
+
+ DEBUG_printf(("http_wait: select() returned %d...\n", nfds));
}
#ifdef WIN32
while (nfds < 0 && WSAGetLastError() == WSAEINTR);
FD_CLR(http->fd, http->input_set);
+ DEBUG_printf(("http_wait: returning with nfds=%d...\n", nfds));
+
return (nfds > 0);
}
*/
static int /* O - Number of bytes written */
-http_write(http_t *http, /* I - HTTP data */
+http_write(http_t *http, /* I - HTTP connection */
const char *buffer, /* I - Buffer for data */
int length) /* I - Number of bytes to write */
{
*/
static int /* O - Number bytes written */
-http_write_chunk(http_t *http, /* I - HTTP data */
+http_write_chunk(http_t *http, /* I - HTTP connection */
const char *buffer, /* I - Buffer to write */
int length) /* I - Length of buffer */
{
*/
static int /* O - Bytes written */
-http_write_ssl(http_t *http, /* I - HTTP data */
+http_write_ssl(http_t *http, /* I - HTTP connection */
const char *buf, /* I - Buffer holding data */
int len) /* I - Length of buffer */
{
# elif defined(HAVE_GNUTLS)
return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len));
# elif defined(HAVE_CDSASSL)
+ int result; /* Return value */
OSStatus error; /* Error info */
size_t processed; /* Number of bytes processed */
- error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed);
+ error = SSLWrite(((http_tls_t *)http->tls)->session, buf, len, &processed);
- if (error == 0)
- return (processed);
- else
+ switch (error)
{
- http->error = error;
- return (-1);
+ case 0 :
+ result = (int)processed;
+ break;
+ case errSSLClosedGraceful :
+ result = 0;
+ break;
+ case errSSLWouldBlock :
+ if (processed)
+ result = (int)processed;
+ else
+ {
+ result = -1;
+ errno = EINTR;
+ }
+ break;
+ default :
+ errno = EPIPE;
+ result = -1;
+ break;
}
+
+ return (result);
# endif /* HAVE_LIBSSL */
}
#endif /* HAVE_SSL */
/*
- * End of "$Id: http.c 4914 2006-01-11 02:04:22Z mike $".
+ * End of "$Id: http.c 5630 2006-06-05 18:42:53Z mike $".
*/