| Index: nss/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
|
| ===================================================================
|
| --- nss/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c (revision 0)
|
| +++ nss/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c (revision 0)
|
| @@ -0,0 +1,1688 @@
|
| +/* ***** BEGIN LICENSE BLOCK *****
|
| + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
| + *
|
| + * The contents of this file are subject to the Mozilla Public License Version
|
| + * 1.1 (the "License"); you may not use this file except in compliance with
|
| + * the License. You may obtain a copy of the License at
|
| + * http://www.mozilla.org/MPL/
|
| + *
|
| + * Software distributed under the License is distributed on an "AS IS" basis,
|
| + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
| + * for the specific language governing rights and limitations under the
|
| + * License.
|
| + *
|
| + * The Original Code is the PKIX-C library.
|
| + *
|
| + * The Initial Developer of the Original Code is
|
| + * Sun Microsystems, Inc.
|
| + * Portions created by the Initial Developer are
|
| + * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
|
| + *
|
| + * Contributor(s):
|
| + * Sun Microsystems, Inc.
|
| + *
|
| + * Alternatively, the contents of this file may be used under the terms of
|
| + * either the GNU General Public License Version 2 or later (the "GPL"), or
|
| + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
| + * in which case the provisions of the GPL or the LGPL are applicable instead
|
| + * of those above. If you wish to allow use of your version of this file only
|
| + * under the terms of either the GPL or the LGPL, and not to allow others to
|
| + * use your version of this file under the terms of the MPL, indicate your
|
| + * decision by deleting the provisions above and replace them with the notice
|
| + * and other provisions required by the GPL or the LGPL. If you do not delete
|
| + * the provisions above, a recipient may use your version of this file under
|
| + * the terms of any one of the MPL, the GPL or the LGPL.
|
| + *
|
| + * ***** END LICENSE BLOCK ***** */
|
| +/*
|
| + * pkix_pl_httpdefaultclient.c
|
| + *
|
| + * HTTPDefaultClient Function Definitions
|
| + *
|
| + */
|
| +
|
| +#include "pkix_pl_httpdefaultclient.h"
|
| +
|
| +static void *plContext = NULL;
|
| +
|
| +/*
|
| + * The interface specification for an http client requires that it register
|
| + * a function table of type SEC_HttpClientFcn, which is defined as a union
|
| + * of tables, of which only version 1 is defined at present.
|
| + *
|
| + * Note: these functions violate the PKIX calling conventions, in that they
|
| + * return SECStatus rather than PKIX_Error*, and that they do not provide a
|
| + * plContext argument. They are implemented here as calls to PKIX functions,
|
| + * but the plContext value is circularly defined - a true kludge. Its value
|
| + * is saved at the time of the call to pkix_pl_HttpDefaultClient_Create for
|
| + * subsequent use, but since that initial call comes from the
|
| + * pkix_pl_HttpDefaultClient_CreateSessionFcn, it's not really getting saved.
|
| + */
|
| +static SEC_HttpClientFcnV1 vtable = {
|
| + pkix_pl_HttpDefaultClient_CreateSessionFcn,
|
| + pkix_pl_HttpDefaultClient_KeepAliveSessionFcn,
|
| + pkix_pl_HttpDefaultClient_FreeSessionFcn,
|
| + pkix_pl_HttpDefaultClient_RequestCreateFcn,
|
| + pkix_pl_HttpDefaultClient_SetPostDataFcn,
|
| + pkix_pl_HttpDefaultClient_AddHeaderFcn,
|
| + pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn,
|
| + pkix_pl_HttpDefaultClient_CancelFcn,
|
| + pkix_pl_HttpDefaultClient_FreeFcn
|
| +};
|
| +
|
| +static SEC_HttpClientFcn httpClient;
|
| +
|
| +static const char *eohMarker = "\r\n\r\n";
|
| +static const PKIX_UInt32 eohMarkLen = 4; /* strlen(eohMarker) */
|
| +static const char *crlf = "\r\n";
|
| +static const PKIX_UInt32 crlfLen = 2; /* strlen(crlf) */
|
| +static const char *httpprotocol = "HTTP/";
|
| +static const PKIX_UInt32 httpprotocolLen = 5; /* strlen(httpprotocol) */
|
| +
|
| +
|
| +#define HTTP_UNKNOWN_CONTENT_LENGTH -1
|
| +
|
| +/* --Private-HttpDefaultClient-Functions------------------------- */
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_HdrCheckComplete
|
| + * DESCRIPTION:
|
| + *
|
| + * This function determines whether the headers in the current receive buffer
|
| + * in the HttpDefaultClient pointed to by "client" are complete. If so, the
|
| + * input data is checked for status code, content-type and content-length are
|
| + * extracted, and the client is set up to read the body of the response.
|
| + * Otherwise, the client is set up to continue reading header data.
|
| + *
|
| + * PARAMETERS:
|
| + * "client"
|
| + * The address of the HttpDefaultClient object. Must be non-NULL.
|
| + * "bytesRead"
|
| + * The UInt32 number of bytes received in the latest read.
|
| + * "pKeepGoing"
|
| + * The address at which the Boolean state machine flag is stored to
|
| + * indicate whether processing can continue without further input.
|
| + * Must be non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in a
|
| + * non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_HdrCheckComplete(
|
| + PKIX_PL_HttpDefaultClient *client,
|
| + PKIX_UInt32 bytesRead,
|
| + PKIX_Boolean *pKeepGoing,
|
| + void *plContext)
|
| +{
|
| + PKIX_UInt32 alreadyScanned = 0;
|
| + PKIX_UInt32 comp = 0;
|
| + PKIX_UInt32 headerLength = 0;
|
| + PKIX_Int32 contentLength = HTTP_UNKNOWN_CONTENT_LENGTH;
|
| + char *eoh = NULL;
|
| + char *statusLineEnd = NULL;
|
| + char *space = NULL;
|
| + char *nextHeader = NULL;
|
| + const char *httpcode = NULL;
|
| + char *thisHeaderEnd = NULL;
|
| + char *value = NULL;
|
| + char *colon = NULL;
|
| + char *copy = NULL;
|
| + char *body = NULL;
|
| +
|
| + PKIX_ENTER
|
| + (HTTPDEFAULTCLIENT,
|
| + "pkix_pl_HttpDefaultClient_HdrCheckComplete");
|
| + PKIX_NULLCHECK_TWO(client, pKeepGoing);
|
| +
|
| + *pKeepGoing = PKIX_FALSE;
|
| +
|
| + /* Does buffer contain end-of-header marker? */
|
| +
|
| + /* Copy number of scanned bytes into a variable. */
|
| + alreadyScanned = client->filledupBytes;
|
| + /*
|
| + * If this is the initial buffer, we have to scan from the beginning.
|
| + * If we scanned, failed to find eohMarker, and read some more, we
|
| + * only have to scan from where we left off.
|
| + */
|
| + if (alreadyScanned > eohMarkLen) {
|
| + /* Back up and restart scanning over a few bytes that were
|
| + * scanned before */
|
| + PKIX_UInt32 searchStartPos = alreadyScanned - eohMarkLen;
|
| + eoh = PL_strnstr(&(client->rcvBuf[searchStartPos]), eohMarker,
|
| + bytesRead + searchStartPos);
|
| + } else {
|
| + /* A search from the beginning of the buffer. */
|
| + eoh = PL_strnstr(client->rcvBuf, eohMarker, bytesRead);
|
| + }
|
| +
|
| + client->filledupBytes += bytesRead;
|
| +
|
| + if (eoh == NULL) { /* did we see end-of-header? */
|
| + /* No. Continue to read header data */
|
| + client->connectStatus = HTTP_RECV_HDR;
|
| + *pKeepGoing = PKIX_TRUE;
|
| + goto cleanup;
|
| + }
|
| +
|
| + /* Yes. Calculate how many bytes in header (not counting eohMarker) */
|
| + headerLength = (eoh - client->rcvBuf);
|
| +
|
| + /* allocate space to copy header (and for the NULL terminator) */
|
| + PKIX_CHECK(PKIX_PL_Malloc(headerLength + 1, (void **)©, plContext),
|
| + PKIX_MALLOCFAILED);
|
| +
|
| + /* copy header data before we corrupt it (by storing NULLs) */
|
| + PORT_Memcpy(copy, client->rcvBuf, headerLength);
|
| + /* Store the NULL terminator */
|
| + copy[headerLength] = '\0';
|
| + client->rcvHeaders = copy;
|
| +
|
| + /* Did caller want a pointer to header? */
|
| + if (client->rcv_http_headers != NULL) {
|
| + /* store pointer for caller */
|
| + *(client->rcv_http_headers) = copy;
|
| + }
|
| +
|
| + /* Check that message status is okay. */
|
| + statusLineEnd = PL_strnstr(client->rcvBuf, crlf, client->capacity);
|
| + if (statusLineEnd == NULL) {
|
| + client->connectStatus = HTTP_ERROR;
|
| + PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
|
| + goto cleanup;
|
| + }
|
| +
|
| + *statusLineEnd = '\0';
|
| +
|
| + space = strchr((const char *)client->rcvBuf, ' ');
|
| + if (space == NULL) {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| +
|
| + comp = PORT_Strncasecmp((const char *)client->rcvBuf, httpprotocol,
|
| + httpprotocolLen);
|
| + if (comp != 0) {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| +
|
| + httpcode = space + 1;
|
| + space = strchr(httpcode, ' ');
|
| + if (space == NULL) {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| + *space = '\0';
|
| +
|
| + client->responseCode = atoi(httpcode);
|
| + if (client->responseCode != 200) {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| +
|
| + /* Find the content-type and content-length */
|
| + nextHeader = statusLineEnd + crlfLen;
|
| + *eoh = '\0';
|
| + do {
|
| + thisHeaderEnd = NULL;
|
| + value = NULL;
|
| +
|
| + colon = strchr(nextHeader, ':');
|
| + if (colon == NULL) {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| + *colon = '\0';
|
| + value = colon + 1;
|
| + if (*value != ' ') {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| + value++;
|
| + thisHeaderEnd = strstr(value, crlf);
|
| + if (thisHeaderEnd != NULL) {
|
| + *thisHeaderEnd = '\0';
|
| + }
|
| + comp = PORT_Strcasecmp(nextHeader, "content-type");
|
| + if (comp == 0) {
|
| + client->rcvContentType = PORT_Strdup(value);
|
| + } else {
|
| + comp = PORT_Strcasecmp(nextHeader, "content-length");
|
| + if (comp == 0) {
|
| + contentLength = atoi(value);
|
| + }
|
| + }
|
| + if (thisHeaderEnd != NULL) {
|
| + nextHeader = thisHeaderEnd + crlfLen;
|
| + } else {
|
| + nextHeader = NULL;
|
| + }
|
| + } while ((nextHeader != NULL) && (nextHeader < (eoh + crlfLen)));
|
| +
|
| + /* Did caller provide a pointer to return content-type? */
|
| + if (client->rcv_http_content_type != NULL) {
|
| + *(client->rcv_http_content_type) = client->rcvContentType;
|
| + }
|
| +
|
| + if (client->rcvContentType == NULL) {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| +
|
| + /* How many bytes remain in current buffer, beyond the header? */
|
| + headerLength += eohMarkLen;
|
| + client->filledupBytes -= headerLength;
|
| +
|
| + /*
|
| + * The headers have passed validation. Now figure out whether the
|
| + * message is within the caller's size limit (if one was specified).
|
| + */
|
| + switch (contentLength) {
|
| + case 0:
|
| + client->rcv_http_data_len = 0;
|
| + client->connectStatus = HTTP_COMPLETE;
|
| + *pKeepGoing = PKIX_FALSE;
|
| + break;
|
| +
|
| + case HTTP_UNKNOWN_CONTENT_LENGTH:
|
| + /* Unknown contentLength indicator.Will be set by
|
| + * pkix_pl_HttpDefaultClient_RecvBody whey connection get closed */
|
| + client->rcv_http_data_len = HTTP_UNKNOWN_CONTENT_LENGTH;
|
| + contentLength = /* Try to reserve 4K+ buffer */
|
| + client->filledupBytes + HTTP_DATA_BUFSIZE;
|
| + if (client->maxResponseLen > 0 &&
|
| + contentLength > client->maxResponseLen) {
|
| + if (client->filledupBytes < client->maxResponseLen) {
|
| + contentLength = client->maxResponseLen;
|
| + } else {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| + }
|
| + /* set available number of bytes in the buffer */
|
| + client->capacity = contentLength;
|
| + client->connectStatus = HTTP_RECV_BODY;
|
| + *pKeepGoing = PKIX_TRUE;
|
| + break;
|
| +
|
| + default:
|
| + client->rcv_http_data_len = contentLength;
|
| + if (client->maxResponseLen > 0 &&
|
| + client->maxResponseLen < contentLength) {
|
| + client->connectStatus = HTTP_ERROR;
|
| + goto cleanup;
|
| + }
|
| +
|
| + /*
|
| + * Do we have all of the message body, or do we need to read some more?
|
| + */
|
| + if (client->filledupBytes < contentLength) {
|
| + client->connectStatus = HTTP_RECV_BODY;
|
| + *pKeepGoing = PKIX_TRUE;
|
| + } else {
|
| + client->connectStatus = HTTP_COMPLETE;
|
| + *pKeepGoing = PKIX_FALSE;
|
| + }
|
| + }
|
| +
|
| + if (contentLength > 0) {
|
| + /* allocate a buffer of size contentLength for the content */
|
| + PKIX_CHECK(PKIX_PL_Malloc(contentLength, (void **)&body, plContext),
|
| + PKIX_MALLOCFAILED);
|
| +
|
| + /* copy any remaining bytes in current buffer into new buffer */
|
| + if (client->filledupBytes > 0) {
|
| + PORT_Memcpy(body, &(client->rcvBuf[headerLength]),
|
| + client->filledupBytes);
|
| + }
|
| + }
|
| +
|
| + PKIX_CHECK(PKIX_PL_Free(client->rcvBuf, plContext),
|
| + PKIX_FREEFAILED);
|
| + client->rcvBuf = body;
|
| +
|
| +cleanup:
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: PKIX_PL_HttpDefaultClient_Create
|
| + * DESCRIPTION:
|
| + *
|
| + * This function creates a new HttpDefaultClient, and stores the result at
|
| + * "pClient".
|
| + *
|
| + * The HttpClient API does not include a plContext argument in its
|
| + * function calls. Its value at the time of this Create call must be the
|
| + * same as when the client is invoked.
|
| + *
|
| + * PARAMETERS:
|
| + * "host"
|
| + * The name of the server with which we hope to exchange messages. Must
|
| + * be non-NULL.
|
| + * "portnum"
|
| + * The port number to be used for our connection to the server.
|
| + * "pClient"
|
| + * The address at which the created HttpDefaultClient is to be stored.
|
| + * Must be non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in
|
| + * a non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_Create(
|
| + const char *host,
|
| + PRUint16 portnum,
|
| + PKIX_PL_HttpDefaultClient **pClient,
|
| + void *plContext)
|
| +{
|
| + PKIX_PL_HttpDefaultClient *client = NULL;
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT, "PKIX_PL_HttpDefaultClient_Create");
|
| + PKIX_NULLCHECK_TWO(pClient, host);
|
| +
|
| + /* allocate an HttpDefaultClient */
|
| + PKIX_CHECK(PKIX_PL_Object_Alloc
|
| + (PKIX_HTTPDEFAULTCLIENT_TYPE,
|
| + sizeof (PKIX_PL_HttpDefaultClient),
|
| + (PKIX_PL_Object **)&client,
|
| + plContext),
|
| + PKIX_COULDNOTCREATEHTTPDEFAULTCLIENTOBJECT);
|
| +
|
| + /* Client timeout is overwritten in HttpDefaultClient_RequestCreate
|
| + * function. Default value will be ignored. */
|
| + client->timeout = 0;
|
| + client->connectStatus = HTTP_NOT_CONNECTED;
|
| + client->portnum = portnum;
|
| + client->bytesToWrite = 0;
|
| + client->send_http_data_len = 0;
|
| + client->rcv_http_data_len = 0;
|
| + client->capacity = 0;
|
| + client->filledupBytes = 0;
|
| + client->responseCode = 0;
|
| + client->maxResponseLen = 0;
|
| + client->GETLen = 0;
|
| + client->POSTLen = 0;
|
| + client->pRcv_http_data_len = NULL;
|
| + client->callbackList = NULL;
|
| + client->GETBuf = NULL;
|
| + client->POSTBuf = NULL;
|
| + client->rcvBuf = NULL;
|
| + /* "host" is a parsing result by CERT_GetURL function that adds
|
| + * "end of line" to the value. OK to dup the string. */
|
| + client->host = PORT_Strdup(host);
|
| + if (!client->host) {
|
| + PKIX_ERROR(PKIX_ALLOCERROR);
|
| + }
|
| + client->path = NULL;
|
| + client->rcvContentType = NULL;
|
| + client->rcvHeaders = NULL;
|
| + client->send_http_method = HTTP_POST_METHOD;
|
| + client->send_http_content_type = NULL;
|
| + client->send_http_data = NULL;
|
| + client->rcv_http_response_code = NULL;
|
| + client->rcv_http_content_type = NULL;
|
| + client->rcv_http_headers = NULL;
|
| + client->rcv_http_data = NULL;
|
| + client->socket = NULL;
|
| +
|
| + /*
|
| + * The HttpClient API does not include a plContext argument in its
|
| + * function calls. Save it here.
|
| + */
|
| + client->plContext = plContext;
|
| +
|
| + *pClient = client;
|
| +
|
| +cleanup:
|
| + if (PKIX_ERROR_RECEIVED) {
|
| + PKIX_DECREF(client);
|
| + }
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_Destroy
|
| + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_Destroy(
|
| + PKIX_PL_Object *object,
|
| + void *plContext)
|
| +{
|
| + PKIX_PL_HttpDefaultClient *client = NULL;
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Destroy");
|
| + PKIX_NULLCHECK_ONE(object);
|
| +
|
| + PKIX_CHECK(pkix_CheckType
|
| + (object, PKIX_HTTPDEFAULTCLIENT_TYPE, plContext),
|
| + PKIX_OBJECTNOTANHTTPDEFAULTCLIENT);
|
| +
|
| + client = (PKIX_PL_HttpDefaultClient *)object;
|
| +
|
| + if (client->rcvHeaders) {
|
| + PKIX_PL_Free(client->rcvHeaders, plContext);
|
| + client->rcvHeaders = NULL;
|
| + }
|
| + if (client->rcvContentType) {
|
| + PORT_Free(client->rcvContentType);
|
| + client->rcvContentType = NULL;
|
| + }
|
| + if (client->GETBuf != NULL) {
|
| + PR_smprintf_free(client->GETBuf);
|
| + client->GETBuf = NULL;
|
| + }
|
| + if (client->POSTBuf != NULL) {
|
| + PKIX_PL_Free(client->POSTBuf, plContext);
|
| + client->POSTBuf = NULL;
|
| + }
|
| + if (client->rcvBuf != NULL) {
|
| + PKIX_PL_Free(client->rcvBuf, plContext);
|
| + client->rcvBuf = NULL;
|
| + }
|
| + if (client->host) {
|
| + PORT_Free(client->host);
|
| + client->host = NULL;
|
| + }
|
| + if (client->path) {
|
| + PORT_Free(client->path);
|
| + client->path = NULL;
|
| + }
|
| + PKIX_DECREF(client->socket);
|
| +
|
| +cleanup:
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_RegisterSelf
|
| + *
|
| + * DESCRIPTION:
|
| + * Registers PKIX_PL_HTTPDEFAULTCLIENT_TYPE and its related
|
| + * functions with systemClasses[]
|
| + *
|
| + * THREAD SAFETY:
|
| + * Not Thread Safe - for performance and complexity reasons
|
| + *
|
| + * Since this function is only called by PKIX_PL_Initialize, which should
|
| + * only be called once, it is acceptable that this function is not
|
| + * thread-safe.
|
| + */
|
| +PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_RegisterSelf(void *plContext)
|
| +{
|
| + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
|
| + pkix_ClassTable_Entry *entry =
|
| + &systemClasses[PKIX_HTTPDEFAULTCLIENT_TYPE];
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT,
|
| + "pkix_pl_HttpDefaultClient_RegisterSelf");
|
| +
|
| + entry->description = "HttpDefaultClient";
|
| + entry->typeObjectSize = sizeof(PKIX_PL_HttpDefaultClient);
|
| + entry->destructor = pkix_pl_HttpDefaultClient_Destroy;
|
| +
|
| + httpClient.version = 1;
|
| + httpClient.fcnTable.ftable1 = vtable;
|
| + (void)SEC_RegisterDefaultHttpClient(&httpClient);
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/* --Private-HttpDefaultClient-I/O-Functions---------------------------- */
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_ConnectContinue
|
| + * DESCRIPTION:
|
| + *
|
| + * This function determines whether a socket Connect initiated earlier for the
|
| + * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag
|
| + * indicating whether processing can continue without further input.
|
| + *
|
| + * PARAMETERS:
|
| + * "client"
|
| + * The address of the HttpDefaultClient object. Must be non-NULL.
|
| + * "pKeepGoing"
|
| + * The address at which the Boolean state machine flag is stored to
|
| + * indicate whether processing can continue without further input.
|
| + * Must be non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in a
|
| + * non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_ConnectContinue(
|
| + PKIX_PL_HttpDefaultClient *client,
|
| + PKIX_Boolean *pKeepGoing,
|
| + void *plContext)
|
| +{
|
| + PRErrorCode status;
|
| + PKIX_Boolean keepGoing = PKIX_FALSE;
|
| + PKIX_PL_Socket_Callback *callbackList = NULL;
|
| +
|
| + PKIX_ENTER
|
| + (HTTPDEFAULTCLIENT,
|
| + "pkix_pl_HttpDefaultClient_ConnectContinue");
|
| + PKIX_NULLCHECK_ONE(client);
|
| +
|
| + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
|
| +
|
| + PKIX_CHECK(callbackList->connectcontinueCallback
|
| + (client->socket, &status, plContext),
|
| + PKIX_SOCKETCONNECTCONTINUEFAILED);
|
| +
|
| + if (status == 0) {
|
| + client->connectStatus = HTTP_CONNECTED;
|
| + keepGoing = PKIX_TRUE;
|
| + } else if (status != PR_IN_PROGRESS_ERROR) {
|
| + PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION);
|
| + }
|
| +
|
| + *pKeepGoing = keepGoing;
|
| +
|
| +cleanup:
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_Send
|
| + * DESCRIPTION:
|
| + *
|
| + * This function creates and sends HTTP-protocol headers and, if applicable,
|
| + * data, for the HttpDefaultClient "client", and stores in "pKeepGoing" a flag
|
| + * indicating whether processing can continue without further input, and at
|
| + * "pBytesTransferred" the number of bytes sent.
|
| + *
|
| + * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
|
| + * and that transmission has not completed.
|
| + *
|
| + * PARAMETERS:
|
| + * "client"
|
| + * The address of the HttpDefaultClient object. Must be non-NULL.
|
| + * "pKeepGoing"
|
| + * The address at which the Boolean state machine flag is stored to
|
| + * indicate whether processing can continue without further input.
|
| + * Must be non-NULL.
|
| + * "pBytesTransferred"
|
| + * The address at which the number of bytes sent is stored. Must be
|
| + * non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in a
|
| + * non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_Send(
|
| + PKIX_PL_HttpDefaultClient *client,
|
| + PKIX_Boolean *pKeepGoing,
|
| + PKIX_UInt32 *pBytesTransferred,
|
| + void *plContext)
|
| +{
|
| + PKIX_Int32 bytesWritten = 0;
|
| + PKIX_Int32 lenToWrite = 0;
|
| + PKIX_PL_Socket_Callback *callbackList = NULL;
|
| + char *dataToWrite = NULL;
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Send");
|
| + PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
|
| +
|
| + *pKeepGoing = PKIX_FALSE;
|
| +
|
| + /* Do we have anything waiting to go? */
|
| + if ((client->GETBuf) || (client->POSTBuf)) {
|
| +
|
| + if (client->GETBuf) {
|
| + dataToWrite = client->GETBuf;
|
| + lenToWrite = client->GETLen;
|
| + } else {
|
| + dataToWrite = client->POSTBuf;
|
| + lenToWrite = client->POSTLen;
|
| + }
|
| +
|
| + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
|
| +
|
| + PKIX_CHECK(callbackList->sendCallback
|
| + (client->socket,
|
| + dataToWrite,
|
| + lenToWrite,
|
| + &bytesWritten,
|
| + plContext),
|
| + PKIX_SOCKETSENDFAILED);
|
| +
|
| + client->rcvBuf = NULL;
|
| + client->capacity = 0;
|
| + client->filledupBytes = 0;
|
| +
|
| + /*
|
| + * If the send completed we can proceed to try for the
|
| + * response. If the send did not complete we will have
|
| + * to poll for completion later.
|
| + */
|
| + if (bytesWritten >= 0) {
|
| + client->connectStatus = HTTP_RECV_HDR;
|
| + *pKeepGoing = PKIX_TRUE;
|
| + } else {
|
| + client->connectStatus = HTTP_SEND_PENDING;
|
| + *pKeepGoing = PKIX_FALSE;
|
| + }
|
| +
|
| + }
|
| +
|
| + *pBytesTransferred = bytesWritten;
|
| +
|
| +cleanup:
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_SendContinue
|
| + * DESCRIPTION:
|
| + *
|
| + * This function determines whether the sending of the HTTP message for the
|
| + * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a
|
| + * flag indicating whether processing can continue without further input, and
|
| + * at "pBytesTransferred" the number of bytes sent.
|
| + *
|
| + * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
|
| + * and that transmission has not completed.
|
| + *
|
| + * PARAMETERS:
|
| + * "client"
|
| + * The address of the HttpDefaultClient object. Must be non-NULL.
|
| + * "pKeepGoing"
|
| + * The address at which the Boolean state machine flag is stored to
|
| + * indicate whether processing can continue without further input.
|
| + * Must be non-NULL.
|
| + * "pBytesTransferred"
|
| + * The address at which the number of bytes sent is stored. Must be
|
| + * non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in a
|
| + * non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_SendContinue(
|
| + PKIX_PL_HttpDefaultClient *client,
|
| + PKIX_Boolean *pKeepGoing,
|
| + PKIX_UInt32 *pBytesTransferred,
|
| + void *plContext)
|
| +{
|
| + PKIX_Int32 bytesWritten = 0;
|
| + PKIX_PL_Socket_Callback *callbackList = NULL;
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_SendContinue");
|
| + PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
|
| +
|
| + *pKeepGoing = PKIX_FALSE;
|
| +
|
| + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
|
| +
|
| + PKIX_CHECK(callbackList->pollCallback
|
| + (client->socket, &bytesWritten, NULL, plContext),
|
| + PKIX_SOCKETPOLLFAILED);
|
| +
|
| + /*
|
| + * If the send completed we can proceed to try for the
|
| + * response. If the send did not complete we will have
|
| + * continue to poll.
|
| + */
|
| + if (bytesWritten >= 0) {
|
| + client->connectStatus = HTTP_RECV_HDR;
|
| + *pKeepGoing = PKIX_TRUE;
|
| + }
|
| +
|
| + *pBytesTransferred = bytesWritten;
|
| +
|
| +cleanup:
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdr
|
| + * DESCRIPTION:
|
| + *
|
| + * This function receives HTTP headers for the HttpDefaultClient "client", and
|
| + * stores in "pKeepGoing" a flag indicating whether processing can continue
|
| + * without further input.
|
| + *
|
| + * PARAMETERS:
|
| + * "client"
|
| + * The address of the HttpDefaultClient object. Must be non-NULL.
|
| + * "pKeepGoing"
|
| + * The address at which the Boolean state machine flag is stored to
|
| + * indicate whether processing can continue without further input.
|
| + * Must be non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in a
|
| + * non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_RecvHdr(
|
| + PKIX_PL_HttpDefaultClient *client,
|
| + PKIX_Boolean *pKeepGoing,
|
| + void *plContext)
|
| +{
|
| + PKIX_UInt32 bytesToRead = 0;
|
| + PKIX_Int32 bytesRead = 0;
|
| + PKIX_PL_Socket_Callback *callbackList = NULL;
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvHdr");
|
| + PKIX_NULLCHECK_TWO(client, pKeepGoing);
|
| +
|
| + /*
|
| + * rcvbuf, capacity, and filledupBytes were
|
| + * initialized when we wrote the headers. We begin by reading
|
| + * HTTP_HEADER_BUFSIZE bytes, repeatedly increasing the buffersize and
|
| + * reading again if necessary, until we have read the end-of-header
|
| + * marker, "\r\n\r\n", or have reached our maximum.
|
| + */
|
| + client->capacity += HTTP_HEADER_BUFSIZE;
|
| + PKIX_CHECK(PKIX_PL_Realloc
|
| + (client->rcvBuf,
|
| + client->capacity,
|
| + (void **)&(client->rcvBuf),
|
| + plContext),
|
| + PKIX_REALLOCFAILED);
|
| +
|
| + bytesToRead = client->capacity - client->filledupBytes;
|
| +
|
| + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
|
| +
|
| + PKIX_CHECK(callbackList->recvCallback
|
| + (client->socket,
|
| + (void *)&(client->rcvBuf[client->filledupBytes]),
|
| + bytesToRead,
|
| + &bytesRead,
|
| + plContext),
|
| + PKIX_SOCKETRECVFAILED);
|
| +
|
| + if (bytesRead > 0) {
|
| + /* client->filledupBytes will be adjusted by
|
| + * pkix_pl_HttpDefaultClient_HdrCheckComplete */
|
| + PKIX_CHECK(
|
| + pkix_pl_HttpDefaultClient_HdrCheckComplete(client, bytesRead,
|
| + pKeepGoing,
|
| + plContext),
|
| + PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED);
|
| + } else {
|
| + client->connectStatus = HTTP_RECV_HDR_PENDING;
|
| + *pKeepGoing = PKIX_FALSE;
|
| + }
|
| +
|
| +cleanup:
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdrContinue
|
| + * DESCRIPTION:
|
| + *
|
| + * This function determines whether the receiving of the HTTP headers for the
|
| + * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag
|
| + * indicating whether processing can continue without further input.
|
| + *
|
| + * PARAMETERS:
|
| + * "client"
|
| + * The address of the HttpDefaultClient object. Must be non-NULL.
|
| + * "pKeepGoing"
|
| + * The address at which the Boolean state machine flag is stored to
|
| + * indicate whether processing can continue without further input.
|
| + * Must be non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in a
|
| + * non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_RecvHdrContinue(
|
| + PKIX_PL_HttpDefaultClient *client,
|
| + PKIX_Boolean *pKeepGoing,
|
| + void *plContext)
|
| +{
|
| + PKIX_Int32 bytesRead = 0;
|
| + PKIX_PL_Socket_Callback *callbackList = NULL;
|
| +
|
| + PKIX_ENTER
|
| + (HTTPDEFAULTCLIENT,
|
| + "pkix_pl_HttpDefaultClient_RecvHdrContinue");
|
| + PKIX_NULLCHECK_TWO(client, pKeepGoing);
|
| +
|
| + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
|
| +
|
| + PKIX_CHECK(callbackList->pollCallback
|
| + (client->socket, NULL, &bytesRead, plContext),
|
| + PKIX_SOCKETPOLLFAILED);
|
| +
|
| + if (bytesRead > 0) {
|
| + client->filledupBytes += bytesRead;
|
| +
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_HdrCheckComplete
|
| + (client, bytesRead, pKeepGoing, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED);
|
| +
|
| + } else {
|
| +
|
| + *pKeepGoing = PKIX_FALSE;
|
| +
|
| + }
|
| +
|
| +cleanup:
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_RecvBody
|
| + * DESCRIPTION:
|
| + *
|
| + * This function processes the contents of the first buffer of a received
|
| + * HTTP-protocol message for the HttpDefaultClient "client", and stores in
|
| + * "pKeepGoing" a flag indicating whether processing can continue without
|
| + * further input.
|
| + *
|
| + * PARAMETERS:
|
| + * "client"
|
| + * The address of the HttpDefaultClient object. Must be non-NULL.
|
| + * "pKeepGoing"
|
| + * The address at which the Boolean state machine flag is stored to
|
| + * indicate whether processing can continue without further input.
|
| + * Must be non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in a
|
| + * non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_RecvBody(
|
| + PKIX_PL_HttpDefaultClient *client,
|
| + PKIX_Boolean *pKeepGoing,
|
| + void *plContext)
|
| +{
|
| + PKIX_Int32 bytesRead = 0;
|
| + PKIX_Int32 bytesToRead = 0;
|
| + PKIX_PL_Socket_Callback *callbackList = NULL;
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvBody");
|
| + PKIX_NULLCHECK_TWO(client, pKeepGoing);
|
| +
|
| + callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
|
| +
|
| + if (client->rcv_http_data_len != HTTP_UNKNOWN_CONTENT_LENGTH) {
|
| + bytesToRead = client->rcv_http_data_len -
|
| + client->filledupBytes;
|
| + } else {
|
| + /* Reading till the EOF. Context length is not known.*/
|
| + /* Check the buffer capacity: increase and
|
| + * reallocate if it is low. */
|
| + int freeBuffSize = client->capacity - client->filledupBytes;
|
| + if (freeBuffSize < HTTP_MIN_AVAILABLE_BUFFER_SIZE) {
|
| + /* New length will be consist of available(downloaded) bytes,
|
| + * plus remaining capacity, plus new expansion. */
|
| + int currBuffSize = client->capacity;
|
| + /* Try to increase the buffer by 4K */
|
| + int newLength = currBuffSize + HTTP_DATA_BUFSIZE;
|
| + if (client->maxResponseLen > 0 &&
|
| + newLength > client->maxResponseLen) {
|
| + newLength = client->maxResponseLen;
|
| + }
|
| + /* Check if we can grow the buffer and report an error if
|
| + * new size is not larger than the current size of the buffer.*/
|
| + if (newLength <= client->filledupBytes) {
|
| + client->rcv_http_data_len = client->filledupBytes;
|
| + client->connectStatus = HTTP_ERROR;
|
| + *pKeepGoing = PKIX_FALSE;
|
| + goto cleanup;
|
| + }
|
| + if (client->capacity < newLength) {
|
| + client->capacity = newLength;
|
| + PKIX_CHECK(
|
| + PKIX_PL_Realloc(client->rcvBuf, newLength,
|
| + (void**)&client->rcvBuf, plContext),
|
| + PKIX_REALLOCFAILED);
|
| + freeBuffSize = client->capacity -
|
| + client->filledupBytes;
|
| + }
|
| + }
|
| + bytesToRead = freeBuffSize;
|
| + }
|
| +
|
| + /* Use poll callback if waiting on non-blocking IO */
|
| + if (client->connectStatus == HTTP_RECV_BODY_PENDING) {
|
| + PKIX_CHECK(callbackList->pollCallback
|
| + (client->socket, NULL, &bytesRead, plContext),
|
| + PKIX_SOCKETPOLLFAILED);
|
| + } else {
|
| + PKIX_CHECK(callbackList->recvCallback
|
| + (client->socket,
|
| + (void *)&(client->rcvBuf[client->filledupBytes]),
|
| + bytesToRead,
|
| + &bytesRead,
|
| + plContext),
|
| + PKIX_SOCKETRECVFAILED);
|
| + }
|
| +
|
| + /* If bytesRead < 0, an error will be thrown by recvCallback, so
|
| + * need to handle >= 0 cases. */
|
| +
|
| + /* bytesRead == 0 - IO was blocked. */
|
| + if (bytesRead == 0) {
|
| + client->connectStatus = HTTP_RECV_BODY_PENDING;
|
| + *pKeepGoing = PKIX_TRUE;
|
| + goto cleanup;
|
| + }
|
| +
|
| + /* We got something. Did we get it all? */
|
| + client->filledupBytes += bytesRead;
|
| +
|
| + /* continue if not enough bytes read or if complete size of
|
| + * transfer is unknown */
|
| + if (bytesToRead > bytesRead ||
|
| + client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) {
|
| + *pKeepGoing = PKIX_TRUE;
|
| + goto cleanup;
|
| + }
|
| + client->connectStatus = HTTP_COMPLETE;
|
| + *pKeepGoing = PKIX_FALSE;
|
| +
|
| +cleanup:
|
| + if (pkixErrorResult && pkixErrorResult->errCode ==
|
| + PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED) {
|
| + if (client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) {
|
| + client->rcv_http_data_len = client->filledupBytes;
|
| + client->connectStatus = HTTP_COMPLETE;
|
| + *pKeepGoing = PKIX_FALSE;
|
| + PKIX_DECREF(pkixErrorResult);
|
| + } else {
|
| + client->connectStatus = HTTP_ERROR;
|
| + }
|
| + }
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * FUNCTION: pkix_pl_HttpDefaultClient_Dispatch
|
| + * DESCRIPTION:
|
| + *
|
| + * This function is the state machine dispatcher for the HttpDefaultClient
|
| + * pointed to by "client". Results are returned by changes to various fields
|
| + * in the context.
|
| + *
|
| + * PARAMETERS:
|
| + * "client"
|
| + * The address of the HttpDefaultClient object. Must be non-NULL.
|
| + * "plContext"
|
| + * Platform-specific context pointer.
|
| + * THREAD SAFETY:
|
| + * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
|
| + * RETURNS:
|
| + * Returns NULL if the function succeeds.
|
| + * Returns a HttpDefaultClient Error if the function fails in a
|
| + * non-fatal way.
|
| + * Returns a Fatal Error if the function fails in an unrecoverable way.
|
| + */
|
| +static PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_Dispatch(
|
| + PKIX_PL_HttpDefaultClient *client,
|
| + void *plContext)
|
| +{
|
| + PKIX_UInt32 bytesTransferred = 0;
|
| + PKIX_Boolean keepGoing = PKIX_TRUE;
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Dispatch");
|
| + PKIX_NULLCHECK_ONE(client);
|
| +
|
| + while (keepGoing) {
|
| + switch (client->connectStatus) {
|
| + case HTTP_CONNECT_PENDING:
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_ConnectContinue
|
| + (client, &keepGoing, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTCONNECTCONTINUEFAILED);
|
| + break;
|
| + case HTTP_CONNECTED:
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_Send
|
| + (client, &keepGoing, &bytesTransferred, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTSENDFAILED);
|
| + break;
|
| + case HTTP_SEND_PENDING:
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_SendContinue
|
| + (client, &keepGoing, &bytesTransferred, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTSENDCONTINUEFAILED);
|
| + break;
|
| + case HTTP_RECV_HDR:
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdr
|
| + (client, &keepGoing, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTRECVHDRFAILED);
|
| + break;
|
| + case HTTP_RECV_HDR_PENDING:
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdrContinue
|
| + (client, &keepGoing, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTRECVHDRCONTINUEFAILED);
|
| + break;
|
| + case HTTP_RECV_BODY:
|
| + case HTTP_RECV_BODY_PENDING:
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvBody
|
| + (client, &keepGoing, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTRECVBODYFAILED);
|
| + break;
|
| + case HTTP_ERROR:
|
| + case HTTP_COMPLETE:
|
| + keepGoing = PKIX_FALSE;
|
| + break;
|
| + case HTTP_NOT_CONNECTED:
|
| + default:
|
| + PKIX_ERROR(PKIX_HTTPDEFAULTCLIENTINILLEGALSTATE);
|
| + }
|
| + }
|
| +
|
| +cleanup:
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +}
|
| +
|
| +/*
|
| + * --HttpClient vtable functions
|
| + * See comments in ocspt.h for the function (wrappers) that return SECStatus.
|
| + * The functions that return PKIX_Error* are the libpkix implementations.
|
| + */
|
| +
|
| +PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_CreateSession(
|
| + const char *host,
|
| + PRUint16 portnum,
|
| + SEC_HTTP_SERVER_SESSION *pSession,
|
| + void *plContext)
|
| +{
|
| + PKIX_PL_HttpDefaultClient *client = NULL;
|
| +
|
| + PKIX_ENTER
|
| + (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_CreateSession");
|
| + PKIX_NULLCHECK_TWO(host, pSession);
|
| +
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_Create
|
| + (host, portnum, &client, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTCREATEFAILED);
|
| +
|
| + *pSession = (SEC_HTTP_SERVER_SESSION)client;
|
| +
|
| +cleanup:
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +
|
| +}
|
| +
|
| +PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_KeepAliveSession(
|
| + SEC_HTTP_SERVER_SESSION session,
|
| + PRPollDesc **pPollDesc,
|
| + void *plContext)
|
| +{
|
| + PKIX_PL_HttpDefaultClient *client = NULL;
|
| +
|
| + PKIX_ENTER
|
| + (HTTPDEFAULTCLIENT,
|
| + "pkix_pl_HttpDefaultClient_KeepAliveSession");
|
| + PKIX_NULLCHECK_TWO(session, pPollDesc);
|
| +
|
| + PKIX_CHECK(pkix_CheckType
|
| + ((PKIX_PL_Object *)session,
|
| + PKIX_HTTPDEFAULTCLIENT_TYPE,
|
| + plContext),
|
| + PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
|
| +
|
| + client = (PKIX_PL_HttpDefaultClient *)session;
|
| +
|
| + /* XXX Not implemented */
|
| +
|
| +cleanup:
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +
|
| +}
|
| +
|
| +PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_RequestCreate(
|
| + SEC_HTTP_SERVER_SESSION session,
|
| + const char *http_protocol_variant, /* usually "http" */
|
| + const char *path_and_query_string,
|
| + const char *http_request_method,
|
| + const PRIntervalTime timeout,
|
| + SEC_HTTP_REQUEST_SESSION *pRequest,
|
| + void *plContext)
|
| +{
|
| + PKIX_PL_HttpDefaultClient *client = NULL;
|
| + PKIX_PL_Socket *socket = NULL;
|
| + PKIX_PL_Socket_Callback *callbackList = NULL;
|
| + PRFileDesc *fileDesc = NULL;
|
| + PRErrorCode status = 0;
|
| +
|
| + PKIX_ENTER
|
| + (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RequestCreate");
|
| + PKIX_NULLCHECK_TWO(session, pRequest);
|
| +
|
| + PKIX_CHECK(pkix_CheckType
|
| + ((PKIX_PL_Object *)session,
|
| + PKIX_HTTPDEFAULTCLIENT_TYPE,
|
| + plContext),
|
| + PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
|
| +
|
| + client = (PKIX_PL_HttpDefaultClient *)session;
|
| +
|
| + /* We only know how to do http */
|
| + if (PORT_Strncasecmp(http_protocol_variant, "http", 4) != 0) {
|
| + PKIX_ERROR(PKIX_UNRECOGNIZEDPROTOCOLREQUESTED);
|
| + }
|
| +
|
| + if (PORT_Strncasecmp(http_request_method, "POST", 4) == 0) {
|
| + client->send_http_method = HTTP_POST_METHOD;
|
| + } else if (PORT_Strncasecmp(http_request_method, "GET", 3) == 0) {
|
| + client->send_http_method = HTTP_GET_METHOD;
|
| + } else {
|
| + /* We only know how to do POST and GET */
|
| + PKIX_ERROR(PKIX_UNRECOGNIZEDREQUESTMETHOD);
|
| + }
|
| +
|
| + if (path_and_query_string) {
|
| + /* "path_and_query_string" is a parsing result by CERT_GetURL
|
| + * function that adds "end of line" to the value. OK to dup
|
| + * the string. */
|
| + client->path = PORT_Strdup(path_and_query_string);
|
| + if (!client->path) {
|
| + PKIX_ERROR(PKIX_ALLOCERROR);
|
| + }
|
| + }
|
| +
|
| + client->timeout = timeout;
|
| +
|
| +#if 0
|
| + PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
|
| + (timeout,
|
| + "variation.red.iplanet.com", /* (char *)client->host, */
|
| + 2001, /* client->portnum, */
|
| + &status,
|
| + &socket,
|
| + plContext),
|
| + PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
|
| +#else
|
| + PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
|
| + (timeout,
|
| + (char *)client->host,
|
| + client->portnum,
|
| + &status,
|
| + &socket,
|
| + plContext),
|
| + PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
|
| +#endif
|
| +
|
| + client->socket = socket;
|
| +
|
| + PKIX_CHECK(pkix_pl_Socket_GetCallbackList
|
| + (socket, &callbackList, plContext),
|
| + PKIX_SOCKETGETCALLBACKLISTFAILED);
|
| +
|
| + client->callbackList = (void *)callbackList;
|
| +
|
| + PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc
|
| + (socket, &fileDesc, plContext),
|
| + PKIX_SOCKETGETPRFILEDESCFAILED);
|
| +
|
| + client->pollDesc.fd = fileDesc;
|
| + client->pollDesc.in_flags = 0;
|
| + client->pollDesc.out_flags = 0;
|
| +
|
| + client->send_http_data = NULL;
|
| + client->send_http_data_len = 0;
|
| + client->send_http_content_type = NULL;
|
| +
|
| + client->connectStatus =
|
| + ((status == 0) ? HTTP_CONNECTED : HTTP_CONNECT_PENDING);
|
| +
|
| + /* Request object is the same object as Session object */
|
| + PKIX_INCREF(client);
|
| + *pRequest = client;
|
| +
|
| +cleanup:
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +
|
| +}
|
| +
|
| +PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_SetPostData(
|
| + SEC_HTTP_REQUEST_SESSION request,
|
| + const char *http_data,
|
| + const PRUint32 http_data_len,
|
| + const char *http_content_type,
|
| + void *plContext)
|
| +{
|
| + PKIX_PL_HttpDefaultClient *client = NULL;
|
| +
|
| + PKIX_ENTER
|
| + (HTTPDEFAULTCLIENT,
|
| + "pkix_pl_HttpDefaultClient_SetPostData");
|
| + PKIX_NULLCHECK_ONE(request);
|
| +
|
| + PKIX_CHECK(pkix_CheckType
|
| + ((PKIX_PL_Object *)request,
|
| + PKIX_HTTPDEFAULTCLIENT_TYPE,
|
| + plContext),
|
| + PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
|
| +
|
| + client = (PKIX_PL_HttpDefaultClient *)request;
|
| +
|
| + client->send_http_data = http_data;
|
| + client->send_http_data_len = http_data_len;
|
| + client->send_http_content_type = http_content_type;
|
| +
|
| + /* Caller is allowed to give NULL or empty string for content_type */
|
| + if ((client->send_http_content_type == NULL) ||
|
| + (*(client->send_http_content_type) == '\0')) {
|
| + client->send_http_content_type = "application/ocsp-request";
|
| + }
|
| +
|
| +cleanup:
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +
|
| +}
|
| +
|
| +PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_TrySendAndReceive(
|
| + SEC_HTTP_REQUEST_SESSION request,
|
| + PRUint16 *http_response_code,
|
| + const char **http_response_content_type,
|
| + const char **http_response_headers,
|
| + const char **http_response_data,
|
| + PRUint32 *http_response_data_len,
|
| + PRPollDesc **pPollDesc,
|
| + SECStatus *pSECReturn,
|
| + void *plContext)
|
| +{
|
| + PKIX_PL_HttpDefaultClient *client = NULL;
|
| + PKIX_UInt32 postLen = 0;
|
| + PRPollDesc *pollDesc = NULL;
|
| + char *sendbuf = NULL;
|
| +
|
| + PKIX_ENTER
|
| + (HTTPDEFAULTCLIENT,
|
| + "pkix_pl_HttpDefaultClient_TrySendAndReceive");
|
| +
|
| + PKIX_NULLCHECK_ONE(request);
|
| +
|
| + PKIX_CHECK(pkix_CheckType
|
| + ((PKIX_PL_Object *)request,
|
| + PKIX_HTTPDEFAULTCLIENT_TYPE,
|
| + plContext),
|
| + PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
|
| +
|
| + client = (PKIX_PL_HttpDefaultClient *)request;
|
| +
|
| + if (!pPollDesc && client->timeout == 0) {
|
| + PKIX_ERROR_FATAL(PKIX_NULLARGUMENT);
|
| + }
|
| +
|
| + if (pPollDesc) {
|
| + pollDesc = *pPollDesc;
|
| + }
|
| +
|
| + /* if not continuing from an earlier WOULDBLOCK return... */
|
| + if (pollDesc == NULL) {
|
| +
|
| + if (!((client->connectStatus == HTTP_CONNECTED) ||
|
| + (client->connectStatus == HTTP_CONNECT_PENDING))) {
|
| + PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
|
| + }
|
| +
|
| + /* Did caller provide a value for response length? */
|
| + if (http_response_data_len != NULL) {
|
| + client->pRcv_http_data_len = http_response_data_len;
|
| + client->maxResponseLen = *http_response_data_len;
|
| + }
|
| +
|
| + client->rcv_http_response_code = http_response_code;
|
| + client->rcv_http_content_type = http_response_content_type;
|
| + client->rcv_http_headers = http_response_headers;
|
| + client->rcv_http_data = http_response_data;
|
| +
|
| + /* prepare the message */
|
| + if (client->send_http_method == HTTP_POST_METHOD) {
|
| + sendbuf = PR_smprintf
|
| + ("POST %s HTTP/1.0\r\nHost: %s:%d\r\n"
|
| + "Content-Type: %s\r\nContent-Length: %u\r\n\r\n",
|
| + client->path,
|
| + client->host,
|
| + client->portnum,
|
| + client->send_http_content_type,
|
| + client->send_http_data_len);
|
| + postLen = PORT_Strlen(sendbuf);
|
| +
|
| + client->POSTLen = postLen + client->send_http_data_len;
|
| +
|
| + /* allocate postBuffer big enough for header + data */
|
| + PKIX_CHECK(PKIX_PL_Malloc
|
| + (client->POSTLen,
|
| + (void **)&(client->POSTBuf),
|
| + plContext),
|
| + PKIX_MALLOCFAILED);
|
| +
|
| + /* copy header into postBuffer */
|
| + PORT_Memcpy(client->POSTBuf, sendbuf, postLen);
|
| +
|
| + /* append data after header */
|
| + PORT_Memcpy(&client->POSTBuf[postLen],
|
| + client->send_http_data,
|
| + client->send_http_data_len);
|
| +
|
| + /* PR_smprintf_free original header buffer */
|
| + PR_smprintf_free(sendbuf);
|
| + sendbuf = NULL;
|
| +
|
| + } else if (client->send_http_method == HTTP_GET_METHOD) {
|
| + client->GETBuf = PR_smprintf
|
| + ("GET %s HTTP/1.1\r\nHost: %s:%d\r\n\r\n",
|
| + client->path,
|
| + client->host,
|
| + client->portnum);
|
| + client->GETLen = PORT_Strlen(client->GETBuf);
|
| + }
|
| +
|
| + }
|
| +
|
| + /* continue according to state */
|
| + PKIX_CHECK(pkix_pl_HttpDefaultClient_Dispatch(client, plContext),
|
| + PKIX_HTTPDEFAULTCLIENTDISPATCHFAILED);
|
| +
|
| + switch (client->connectStatus) {
|
| + case HTTP_CONNECT_PENDING:
|
| + case HTTP_SEND_PENDING:
|
| + case HTTP_RECV_HDR_PENDING:
|
| + case HTTP_RECV_BODY_PENDING:
|
| + pollDesc = &(client->pollDesc);
|
| + *pSECReturn = SECWouldBlock;
|
| + break;
|
| + case HTTP_ERROR:
|
| + /* Did caller provide a pointer for length? */
|
| + if (client->pRcv_http_data_len != NULL) {
|
| + /* Was error "response too big?" */
|
| + if (client->rcv_http_data_len !=
|
| + HTTP_UNKNOWN_CONTENT_LENGTH &&
|
| + client->maxResponseLen >=
|
| + client->rcv_http_data_len) {
|
| + /* Yes, report needed space */
|
| + *(client->pRcv_http_data_len) =
|
| + client->rcv_http_data_len;
|
| + } else {
|
| + /* No, report problem other than size */
|
| + *(client->pRcv_http_data_len) = 0;
|
| + }
|
| + }
|
| +
|
| + pollDesc = NULL;
|
| + *pSECReturn = SECFailure;
|
| + break;
|
| + case HTTP_COMPLETE:
|
| + *(client->rcv_http_response_code) =
|
| + client->responseCode;
|
| + if (client->pRcv_http_data_len != NULL) {
|
| + *http_response_data_len =
|
| + client->rcv_http_data_len;
|
| + }
|
| + if (client->rcv_http_data != NULL) {
|
| + *(client->rcv_http_data) = client->rcvBuf;
|
| + }
|
| + pollDesc = NULL;
|
| + *pSECReturn = SECSuccess;
|
| + break;
|
| + case HTTP_NOT_CONNECTED:
|
| + case HTTP_CONNECTED:
|
| + case HTTP_RECV_HDR:
|
| + case HTTP_RECV_BODY:
|
| + default:
|
| + pollDesc = NULL;
|
| + *pSECReturn = SECFailure;
|
| + PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
|
| + break;
|
| + }
|
| +
|
| + if (pPollDesc) {
|
| + *pPollDesc = pollDesc;
|
| + }
|
| +
|
| +cleanup:
|
| + if (sendbuf) {
|
| + PR_smprintf_free(sendbuf);
|
| + }
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +
|
| +}
|
| +
|
| +PKIX_Error *
|
| +pkix_pl_HttpDefaultClient_Cancel(
|
| + SEC_HTTP_REQUEST_SESSION request,
|
| + void *plContext)
|
| +{
|
| + PKIX_PL_HttpDefaultClient *client = NULL;
|
| +
|
| + PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Cancel");
|
| + PKIX_NULLCHECK_ONE(request);
|
| +
|
| + PKIX_CHECK(pkix_CheckType
|
| + ((PKIX_PL_Object *)request,
|
| + PKIX_HTTPDEFAULTCLIENT_TYPE,
|
| + plContext),
|
| + PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
|
| +
|
| + client = (PKIX_PL_HttpDefaultClient *)request;
|
| +
|
| + /* XXX Not implemented */
|
| +
|
| +cleanup:
|
| +
|
| + PKIX_RETURN(HTTPDEFAULTCLIENT);
|
| +
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_CreateSessionFcn(
|
| + const char *host,
|
| + PRUint16 portnum,
|
| + SEC_HTTP_SERVER_SESSION *pSession)
|
| +{
|
| + PKIX_Error *err = pkix_pl_HttpDefaultClient_CreateSession
|
| + (host, portnum, pSession, plContext);
|
| +
|
| + if (err) {
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_KeepAliveSessionFcn(
|
| + SEC_HTTP_SERVER_SESSION session,
|
| + PRPollDesc **pPollDesc)
|
| +{
|
| + PKIX_Error *err = pkix_pl_HttpDefaultClient_KeepAliveSession
|
| + (session, pPollDesc, plContext);
|
| +
|
| + if (err) {
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_FreeSessionFcn(
|
| + SEC_HTTP_SERVER_SESSION session)
|
| +{
|
| + PKIX_Error *err =
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)(session), plContext);
|
| +
|
| + if (err) {
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_RequestCreateFcn(
|
| + SEC_HTTP_SERVER_SESSION session,
|
| + const char *http_protocol_variant, /* usually "http" */
|
| + const char *path_and_query_string,
|
| + const char *http_request_method,
|
| + const PRIntervalTime timeout,
|
| + SEC_HTTP_REQUEST_SESSION *pRequest)
|
| +{
|
| + PKIX_Error *err = pkix_pl_HttpDefaultClient_RequestCreate
|
| + (session,
|
| + http_protocol_variant,
|
| + path_and_query_string,
|
| + http_request_method,
|
| + timeout,
|
| + pRequest,
|
| + plContext);
|
| +
|
| + if (err) {
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_SetPostDataFcn(
|
| + SEC_HTTP_REQUEST_SESSION request,
|
| + const char *http_data,
|
| + const PRUint32 http_data_len,
|
| + const char *http_content_type)
|
| +{
|
| + PKIX_Error *err =
|
| + pkix_pl_HttpDefaultClient_SetPostData(request, http_data,
|
| + http_data_len,
|
| + http_content_type,
|
| + plContext);
|
| + if (err) {
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_AddHeaderFcn(
|
| + SEC_HTTP_REQUEST_SESSION request,
|
| + const char *http_header_name,
|
| + const char *http_header_value)
|
| +{
|
| + /* Not supported */
|
| + return SECFailure;
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn(
|
| + SEC_HTTP_REQUEST_SESSION request,
|
| + PRPollDesc **pPollDesc,
|
| + PRUint16 *http_response_code,
|
| + const char **http_response_content_type,
|
| + const char **http_response_headers,
|
| + const char **http_response_data,
|
| + PRUint32 *http_response_data_len)
|
| +{
|
| + SECStatus rv = SECFailure;
|
| +
|
| + PKIX_Error *err = pkix_pl_HttpDefaultClient_TrySendAndReceive
|
| + (request,
|
| + http_response_code,
|
| + http_response_content_type,
|
| + http_response_headers,
|
| + http_response_data,
|
| + http_response_data_len,
|
| + pPollDesc,
|
| + &rv,
|
| + plContext);
|
| +
|
| + if (err) {
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
|
| + return rv;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_CancelFcn(
|
| + SEC_HTTP_REQUEST_SESSION request)
|
| +{
|
| + PKIX_Error *err = pkix_pl_HttpDefaultClient_Cancel(request, plContext);
|
| +
|
| + if (err) {
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +SECStatus
|
| +pkix_pl_HttpDefaultClient_FreeFcn(
|
| + SEC_HTTP_REQUEST_SESSION request)
|
| +{
|
| + PKIX_Error *err =
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)(request), plContext);
|
| +
|
| + if (err) {
|
| + PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
|
|
| Property changes on: nss/mozilla/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|