tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pkix_pl_httpdefaultclient.c (57805B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5 * pkix_pl_httpdefaultclient.c
      6 *
      7 * HTTPDefaultClient Function Definitions
      8 *
      9 */
     10 
     11 #include "pkix_pl_httpdefaultclient.h"
     12 
     13 static void *plContext = NULL;
     14 
     15 /*
     16 * The interface specification for an http client requires that it register
     17 * a function table of type SEC_HttpClientFcn, which is defined as a union
     18 * of tables, of which only version 1 is defined at present.
     19 *
     20 * Note: these functions violate the PKIX calling conventions, in that they
     21 * return SECStatus rather than PKIX_Error*, and that they do not provide a
     22 * plContext argument. They are implemented here as calls to PKIX functions,
     23 * but the plContext value is circularly defined - a true kludge. Its value
     24 * is saved at the time of the call to pkix_pl_HttpDefaultClient_Create for
     25 * subsequent use, but since that initial call comes from the
     26 * pkix_pl_HttpDefaultClient_CreateSessionFcn, it's not really getting saved.
     27 */
     28 static SEC_HttpClientFcnV1 vtable = {
     29        pkix_pl_HttpDefaultClient_CreateSessionFcn,
     30        pkix_pl_HttpDefaultClient_KeepAliveSessionFcn,
     31        pkix_pl_HttpDefaultClient_FreeSessionFcn,
     32        pkix_pl_HttpDefaultClient_RequestCreateFcn,
     33        pkix_pl_HttpDefaultClient_SetPostDataFcn,
     34        pkix_pl_HttpDefaultClient_AddHeaderFcn,
     35        pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn,
     36        pkix_pl_HttpDefaultClient_CancelFcn,
     37        pkix_pl_HttpDefaultClient_FreeFcn
     38 };
     39 
     40 static SEC_HttpClientFcn httpClient;
     41 
     42 static const char *eohMarker = "\r\n\r\n";
     43 static const PKIX_UInt32 eohMarkLen = 4; /* strlen(eohMarker) */
     44 static const char *crlf = "\r\n";
     45 static const PKIX_UInt32 crlfLen = 2; /* strlen(crlf) */
     46 static const char *httpprotocol = "HTTP/";
     47 static const PKIX_UInt32 httpprotocolLen = 5; /* strlen(httpprotocol) */
     48 
     49 
     50 #define HTTP_UNKNOWN_CONTENT_LENGTH -1
     51 
     52 /* --Private-HttpDefaultClient-Functions------------------------- */
     53 
     54 /*
     55 * FUNCTION: pkix_pl_HttpDefaultClient_HdrCheckComplete
     56 * DESCRIPTION:
     57 *
     58 *  This function determines whether the headers in the current receive buffer
     59 *  in the HttpDefaultClient pointed to by "client" are complete. If so, the
     60 *  input data is checked for status code, content-type and content-length are
     61 *  extracted, and the client is set up to read the body of the response.
     62 *  Otherwise, the client is set up to continue reading header data.
     63 *
     64 * PARAMETERS:
     65 *  "client"
     66 *      The address of the HttpDefaultClient object. Must be non-NULL.
     67 *  "bytesRead"
     68 *      The UInt32 number of bytes received in the latest read.
     69 *  "pKeepGoing"
     70 *      The address at which the Boolean state machine flag is stored to
     71 *      indicate whether processing can continue without further input.
     72 *      Must be non-NULL.
     73 *  "plCtx"
     74 *      Platform-specific context pointer.
     75 * THREAD SAFETY:
     76 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
     77 * RETURNS:
     78 *  Returns NULL if the function succeeds.
     79 *  Returns a HttpDefaultClient Error if the function fails in a
     80 *      non-fatal way.
     81 *  Returns a Fatal Error if the function fails in an unrecoverable way.
     82 */
     83 static PKIX_Error *
     84 pkix_pl_HttpDefaultClient_HdrCheckComplete(
     85        PKIX_PL_HttpDefaultClient *client,
     86        PKIX_UInt32 bytesRead,
     87        PKIX_Boolean *pKeepGoing,
     88        void *plCtx)
     89 {
     90        PKIX_UInt32 alreadyScanned = 0;
     91        PKIX_UInt32 comp = 0;
     92        PKIX_UInt32 headerLength = 0;
     93        PKIX_Int32 contentLength = HTTP_UNKNOWN_CONTENT_LENGTH;
     94        char *eoh = NULL;
     95        char *statusLineEnd = NULL;
     96        char *space = NULL;
     97        char *nextHeader = NULL;
     98        const char *httpcode = NULL;
     99        char *thisHeaderEnd = NULL;
    100        char *value = NULL;
    101        char *colon = NULL;
    102 char *copy = NULL;
    103        char *body = NULL;
    104 
    105        PKIX_ENTER
    106                (HTTPDEFAULTCLIENT,
    107                "pkix_pl_HttpDefaultClient_HdrCheckComplete");
    108        PKIX_NULLCHECK_TWO(client, pKeepGoing);
    109 
    110        *pKeepGoing = PKIX_FALSE;
    111 
    112        /* Does buffer contain end-of-header marker? */
    113 
    114        /* Copy number of scanned bytes into a variable. */
    115        alreadyScanned = client->filledupBytes;
    116        /*
    117         * If this is the initial buffer, we have to scan from the beginning.
    118         * If we scanned, failed to find eohMarker, and read some more, we
    119         * only have to scan from where we left off.
    120         */
    121        if (alreadyScanned > eohMarkLen) {
    122            /* Back up and restart scanning over a few bytes that were
    123             * scanned before */
    124            PKIX_UInt32 searchStartPos = alreadyScanned - eohMarkLen;
    125            eoh = PL_strnstr(&(client->rcvBuf[searchStartPos]), eohMarker,
    126                             bytesRead + searchStartPos);
    127        } else {
    128            /* A search from the beginning of the buffer. */
    129            eoh = PL_strnstr(client->rcvBuf, eohMarker, bytesRead);
    130        }
    131 
    132        client->filledupBytes += bytesRead;
    133 
    134        if (eoh == NULL) { /* did we see end-of-header? */
    135                /* No. Continue to read header data */
    136                client->connectStatus = HTTP_RECV_HDR;
    137                *pKeepGoing = PKIX_TRUE;
    138                goto cleanup;
    139        }
    140 
    141        /* Yes. Calculate how many bytes in header (not counting eohMarker) */
    142        headerLength = (eoh - client->rcvBuf);
    143 
    144        /* allocate space to copy header (and for the NULL terminator) */
    145        PKIX_CHECK(PKIX_PL_Malloc(headerLength + 1, (void **)&copy, plCtx),
    146                PKIX_MALLOCFAILED);
    147 
    148        /* copy header data before we corrupt it (by storing NULLs) */
    149        PORT_Memcpy(copy, client->rcvBuf, headerLength);
    150 /* Store the NULL terminator */
    151 copy[headerLength] = '\0';
    152 client->rcvHeaders = copy;
    153 
    154        /* Did caller want a pointer to header? */
    155        if (client->rcv_http_headers != NULL) {
    156                /* store pointer for caller */
    157                *(client->rcv_http_headers) = copy;
    158        }
    159 
    160        /* Check that message status is okay. */
    161        statusLineEnd = PL_strnstr(client->rcvBuf, crlf, client->capacity);
    162        if (statusLineEnd == NULL) {
    163                client->connectStatus = HTTP_ERROR;
    164                PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
    165                goto cleanup;
    166        }
    167 
    168        *statusLineEnd = '\0';
    169 
    170        space = strchr((const char *)client->rcvBuf, ' ');
    171        if (space == NULL) {
    172                client->connectStatus = HTTP_ERROR;
    173                goto cleanup;
    174        }
    175 
    176        comp = PORT_Strncasecmp((const char *)client->rcvBuf, httpprotocol,
    177                                httpprotocolLen);
    178        if (comp != 0) {
    179                client->connectStatus = HTTP_ERROR;
    180                goto cleanup;
    181        }
    182 
    183        httpcode = space + 1;
    184        space = strchr(httpcode, ' ');
    185        if (space == NULL) {
    186                client->connectStatus = HTTP_ERROR;
    187                goto cleanup;
    188        }
    189        *space = '\0';
    190 
    191        client->responseCode = atoi(httpcode);
    192        if (client->responseCode != 200) {
    193                client->connectStatus = HTTP_ERROR;
    194                goto cleanup;
    195        }
    196 
    197        /* Find the content-type and content-length */
    198        nextHeader = statusLineEnd + crlfLen;
    199        *eoh = '\0';
    200        do {
    201                thisHeaderEnd = NULL;
    202                value = NULL;
    203 
    204                colon = strchr(nextHeader, ':');
    205                if (colon == NULL) {
    206                        client->connectStatus = HTTP_ERROR;
    207                        goto cleanup;
    208                }
    209                *colon = '\0';
    210                value = colon + 1;
    211                if (*value != ' ') {
    212                        client->connectStatus = HTTP_ERROR;
    213                        goto cleanup;
    214                }
    215                value++;
    216                thisHeaderEnd = strstr(value, crlf);
    217                if (thisHeaderEnd != NULL) {
    218                        *thisHeaderEnd = '\0';
    219                }
    220                comp = PORT_Strcasecmp(nextHeader, "content-type");
    221                if (comp == 0) {
    222                        client->rcvContentType = PORT_Strdup(value);
    223                } else {
    224                        comp = PORT_Strcasecmp(nextHeader, "content-length");
    225                        if (comp == 0) {
    226                                contentLength = atoi(value);
    227                        }
    228                }
    229                if (thisHeaderEnd != NULL) {
    230                        nextHeader = thisHeaderEnd + crlfLen;
    231                } else {
    232                        nextHeader = NULL;
    233                }
    234        } while ((nextHeader != NULL) && (nextHeader < (eoh + crlfLen)));
    235                
    236        /* Did caller provide a pointer to return content-type? */
    237        if (client->rcv_http_content_type != NULL) {
    238                *(client->rcv_http_content_type) = client->rcvContentType;
    239        }
    240 
    241        if (client->rcvContentType == NULL) {
    242                client->connectStatus = HTTP_ERROR;
    243                goto cleanup;
    244        }
    245 
    246         /* How many bytes remain in current buffer, beyond the header? */
    247         headerLength += eohMarkLen;
    248         client->filledupBytes -= headerLength;
    249 
    250         /*
    251          * The headers have passed validation. Now figure out whether the
    252          * message is within the caller's size limit (if one was specified).
    253          */
    254         switch (contentLength) {
    255         case 0:
    256             client->rcv_http_data_len = 0;
    257             client->connectStatus = HTTP_COMPLETE;
    258             *pKeepGoing = PKIX_FALSE;
    259             break;
    260 
    261         case HTTP_UNKNOWN_CONTENT_LENGTH:
    262             /* Unknown contentLength indicator.Will be set by
    263              * pkix_pl_HttpDefaultClient_RecvBody whey connection get closed */
    264             client->rcv_http_data_len = HTTP_UNKNOWN_CONTENT_LENGTH;
    265             contentLength =                 /* Try to reserve 4K+ buffer */
    266                 client->filledupBytes + HTTP_DATA_BUFSIZE;
    267             if (client->maxResponseLen > 0 &&
    268                 contentLength > (PKIX_Int32)client->maxResponseLen) {
    269                 if (client->filledupBytes < client->maxResponseLen) {
    270                     contentLength = client->maxResponseLen;
    271                 } else {
    272                     client->connectStatus = HTTP_ERROR;
    273                     goto cleanup;
    274                 }
    275             }
    276             /* set available number of bytes in the buffer */
    277             client->capacity = contentLength;
    278             client->connectStatus = HTTP_RECV_BODY;
    279             *pKeepGoing = PKIX_TRUE;
    280             break;
    281 
    282         default:
    283             client->rcv_http_data_len = contentLength;
    284             if (client->maxResponseLen > 0 &&
    285                 (PKIX_Int32)client->maxResponseLen < contentLength) {
    286                 client->connectStatus = HTTP_ERROR;
    287                 goto cleanup;
    288             }
    289             
    290             /*
    291              * Do we have all of the message body, or do we need to read some more?
    292              */
    293             if ((PKIX_Int32)client->filledupBytes < contentLength) {
    294                 client->connectStatus = HTTP_RECV_BODY;
    295                 *pKeepGoing = PKIX_TRUE;
    296             } else {
    297                 client->connectStatus = HTTP_COMPLETE;
    298                 *pKeepGoing = PKIX_FALSE;
    299             }
    300         }
    301 
    302         if (contentLength > 0) {
    303             /* allocate a buffer of size contentLength  for the content */
    304             PKIX_CHECK(PKIX_PL_Malloc(contentLength, (void **)&body, plCtx),
    305                        PKIX_MALLOCFAILED);
    306             
    307             /* copy any remaining bytes in current buffer into new buffer */
    308             if (client->filledupBytes > 0) {
    309                 PORT_Memcpy(body, &(client->rcvBuf[headerLength]),
    310                             client->filledupBytes);
    311             }
    312         }
    313 
    314         PKIX_CHECK(PKIX_PL_Free(client->rcvBuf, plCtx),
    315                    PKIX_FREEFAILED);
    316         client->rcvBuf = body;
    317 
    318 cleanup:
    319 
    320        PKIX_RETURN(HTTPDEFAULTCLIENT);
    321 }
    322 
    323 /*
    324 * FUNCTION: PKIX_PL_HttpDefaultClient_Create
    325 * DESCRIPTION:
    326 *
    327 *  This function creates a new HttpDefaultClient, and stores the result at
    328 *  "pClient".
    329 *
    330 *  The HttpClient API does not include a plContext argument in its
    331 *  function calls. Its value at the time of this Create call must be the
    332 *  same as when the client is invoked.
    333 *
    334 * PARAMETERS:
    335 *  "host"
    336 *      The name of the server with which we hope to exchange messages. Must
    337 *      be non-NULL.
    338 *  "portnum"
    339 *      The port number to be used for our connection to the server.
    340 *  "pClient"
    341 *      The address at which the created HttpDefaultClient is to be stored.
    342 *      Must be non-NULL.
    343 *  "plCtx"
    344 *      Platform-specific context pointer.
    345 * THREAD SAFETY:
    346 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    347 * RETURNS:
    348 *  Returns NULL if the function succeeds.
    349 *  Returns a HttpDefaultClient Error if the function fails in
    350 *      a non-fatal way.
    351 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    352 */
    353 static PKIX_Error *
    354 pkix_pl_HttpDefaultClient_Create(
    355        const char *host,
    356        PRUint16 portnum,
    357        PKIX_PL_HttpDefaultClient **pClient,
    358        void *plCtx)
    359 {
    360        PKIX_PL_HttpDefaultClient *client = NULL;
    361 
    362        PKIX_ENTER(HTTPDEFAULTCLIENT, "PKIX_PL_HttpDefaultClient_Create");
    363        PKIX_NULLCHECK_TWO(pClient, host);
    364 
    365        /* allocate an HttpDefaultClient */
    366        PKIX_CHECK(PKIX_PL_Object_Alloc
    367                (PKIX_HTTPDEFAULTCLIENT_TYPE,
    368                sizeof (PKIX_PL_HttpDefaultClient),
    369                (PKIX_PL_Object **)&client,
    370                plCtx),
    371                PKIX_COULDNOTCREATEHTTPDEFAULTCLIENTOBJECT);
    372 
    373        /* Client timeout is overwritten in HttpDefaultClient_RequestCreate
    374         * function. Default value will be ignored. */
    375        client->timeout = 0;
    376        client->connectStatus = HTTP_NOT_CONNECTED;
    377        client->portnum = portnum;
    378        client->bytesToWrite = 0;
    379        client->send_http_data_len = 0;
    380        client->rcv_http_data_len = 0;
    381        client->capacity = 0;
    382        client->filledupBytes = 0;
    383        client->responseCode = 0;
    384        client->maxResponseLen = 0;
    385        client->GETLen = 0;
    386        client->POSTLen = 0;
    387        client->pRcv_http_data_len = NULL;
    388        client->callbackList = NULL;
    389        client->GETBuf = NULL;
    390        client->POSTBuf = NULL;
    391        client->rcvBuf = NULL;
    392        /* "host" is a parsing result by CERT_GetURL function that adds
    393         * "end of line" to the value. OK to dup the string. */
    394        client->host = PORT_Strdup(host);
    395        if (!client->host) {
    396            PKIX_ERROR(PKIX_ALLOCERROR);
    397        }
    398        client->path = NULL;
    399        client->rcvContentType = NULL;
    400        client->rcvHeaders = NULL;
    401        client->send_http_method = HTTP_POST_METHOD;
    402        client->send_http_content_type = NULL;
    403        client->send_http_data = NULL;
    404        client->rcv_http_response_code = NULL;
    405        client->rcv_http_content_type = NULL;
    406        client->rcv_http_headers = NULL;
    407        client->rcv_http_data = NULL;
    408        client->socket = NULL;
    409 
    410        /*
    411         * The HttpClient API does not include a plCtx argument in its
    412         * function calls. Save it here.
    413         */
    414        client->plContext = plCtx;
    415 
    416        *pClient = client;
    417 
    418 cleanup:
    419        if (PKIX_ERROR_RECEIVED) {
    420                PKIX_DECREF(client);
    421        }
    422 
    423        PKIX_RETURN(HTTPDEFAULTCLIENT);
    424 }
    425 
    426 /*
    427 * FUNCTION: pkix_pl_HttpDefaultClient_Destroy
    428 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
    429 */
    430 static PKIX_Error *
    431 pkix_pl_HttpDefaultClient_Destroy(
    432        PKIX_PL_Object *object,
    433        void *plCtx)
    434 {
    435        PKIX_PL_HttpDefaultClient *client = NULL;
    436 
    437        PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Destroy");
    438        PKIX_NULLCHECK_ONE(object);
    439 
    440        PKIX_CHECK(pkix_CheckType
    441                    (object, PKIX_HTTPDEFAULTCLIENT_TYPE, plCtx),
    442                    PKIX_OBJECTNOTANHTTPDEFAULTCLIENT);
    443 
    444        client = (PKIX_PL_HttpDefaultClient *)object;
    445 
    446        if (client->rcvHeaders) {
    447            PKIX_PL_Free(client->rcvHeaders, plCtx);
    448            client->rcvHeaders = NULL;
    449        }
    450        if (client->rcvContentType) {
    451            PORT_Free(client->rcvContentType);
    452            client->rcvContentType = NULL;
    453        }
    454        if (client->GETBuf != NULL) {
    455                PR_smprintf_free(client->GETBuf);
    456                client->GETBuf = NULL;
    457        }
    458        if (client->POSTBuf != NULL) {
    459                PKIX_PL_Free(client->POSTBuf, plCtx);
    460                client->POSTBuf = NULL;
    461        }
    462        if (client->rcvBuf != NULL) {
    463                PKIX_PL_Free(client->rcvBuf, plCtx);
    464                client->rcvBuf = NULL;
    465        }
    466        if (client->host) {
    467                PORT_Free(client->host);
    468                client->host = NULL;
    469        }
    470        if (client->path) {
    471                PORT_Free(client->path);
    472                client->path = NULL;
    473        }
    474        PKIX_DECREF(client->socket);
    475 
    476 cleanup:
    477 
    478        PKIX_RETURN(HTTPDEFAULTCLIENT);
    479 }
    480 
    481 /*
    482 * FUNCTION: pkix_pl_HttpDefaultClient_RegisterSelf
    483 *
    484 * DESCRIPTION:
    485 *  Registers PKIX_PL_HTTPDEFAULTCLIENT_TYPE and its related
    486 *  functions with systemClasses[]
    487 *
    488 * THREAD SAFETY:
    489 *  Not Thread Safe - for performance and complexity reasons
    490 *
    491 *  Since this function is only called by PKIX_PL_Initialize, which should
    492 *  only be called once, it is acceptable that this function is not
    493 *  thread-safe.
    494 */
    495 PKIX_Error *
    496 pkix_pl_HttpDefaultClient_RegisterSelf(void *plCtx)
    497 {
    498        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
    499        pkix_ClassTable_Entry *entry =
    500            &systemClasses[PKIX_HTTPDEFAULTCLIENT_TYPE];
    501 
    502        PKIX_ENTER(HTTPDEFAULTCLIENT,
    503                "pkix_pl_HttpDefaultClient_RegisterSelf");
    504 
    505        entry->description = "HttpDefaultClient";
    506        entry->typeObjectSize = sizeof(PKIX_PL_HttpDefaultClient);
    507        entry->destructor = pkix_pl_HttpDefaultClient_Destroy;
    508 
    509        httpClient.version = 1;
    510        httpClient.fcnTable.ftable1 = vtable;
    511        (void)SEC_RegisterDefaultHttpClient(&httpClient);
    512 
    513        PKIX_RETURN(HTTPDEFAULTCLIENT);
    514 }
    515 
    516 /* --Private-HttpDefaultClient-I/O-Functions---------------------------- */
    517 /*
    518 * FUNCTION: pkix_pl_HttpDefaultClient_ConnectContinue
    519 * DESCRIPTION:
    520 *
    521 *  This function determines whether a socket Connect initiated earlier for the
    522 *  HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag
    523 *  indicating whether processing can continue without further input.
    524 *
    525 * PARAMETERS:
    526 *  "client"
    527 *      The address of the HttpDefaultClient object. Must be non-NULL.
    528 *  "pKeepGoing"
    529 *      The address at which the Boolean state machine flag is stored to
    530 *      indicate whether processing can continue without further input.
    531 *      Must be non-NULL.
    532 *  "plCtx"
    533 *      Platform-specific context pointer.
    534 * THREAD SAFETY:
    535 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    536 * RETURNS:
    537 *  Returns NULL if the function succeeds.
    538 *  Returns a HttpDefaultClient Error if the function fails in a
    539 *      non-fatal way.
    540 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    541 */
    542 static PKIX_Error *
    543 pkix_pl_HttpDefaultClient_ConnectContinue(
    544        PKIX_PL_HttpDefaultClient *client,
    545        PKIX_Boolean *pKeepGoing,
    546        void *plCtx)
    547 {
    548        PRErrorCode status;
    549        PKIX_Boolean keepGoing = PKIX_FALSE;
    550        PKIX_PL_Socket_Callback *callbackList = NULL;
    551 
    552        PKIX_ENTER
    553                (HTTPDEFAULTCLIENT,
    554                "pkix_pl_HttpDefaultClient_ConnectContinue");
    555        PKIX_NULLCHECK_ONE(client);
    556 
    557        callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
    558 
    559        PKIX_CHECK(callbackList->connectcontinueCallback
    560                (client->socket, &status, plCtx),
    561                PKIX_SOCKETCONNECTCONTINUEFAILED);
    562 
    563        if (status == 0) {
    564                client->connectStatus = HTTP_CONNECTED;
    565                keepGoing = PKIX_TRUE;
    566        } else if (status != PR_IN_PROGRESS_ERROR) {
    567                PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION);
    568        }
    569 
    570        *pKeepGoing = keepGoing;
    571 
    572 cleanup:
    573        PKIX_RETURN(HTTPDEFAULTCLIENT);
    574 }
    575 
    576 /*
    577 * FUNCTION: pkix_pl_HttpDefaultClient_Send
    578 * DESCRIPTION:
    579 *
    580 *  This function creates and sends HTTP-protocol headers and, if applicable,
    581 *  data, for the HttpDefaultClient "client", and stores in "pKeepGoing" a flag
    582 *  indicating whether processing can continue without further input, and at
    583 *  "pBytesTransferred" the number of bytes sent.
    584 *
    585 *  If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
    586 *  and that transmission has not completed.
    587 *
    588 * PARAMETERS:
    589 *  "client"
    590 *      The address of the HttpDefaultClient object. Must be non-NULL.
    591 *  "pKeepGoing"
    592 *      The address at which the Boolean state machine flag is stored to
    593 *      indicate whether processing can continue without further input.
    594 *      Must be non-NULL.
    595 *  "pBytesTransferred"
    596 *      The address at which the number of bytes sent is stored. Must be
    597 *      non-NULL.
    598 *  "plCtx"
    599 *      Platform-specific context pointer.
    600 * THREAD SAFETY:
    601 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    602 * RETURNS:
    603 *  Returns NULL if the function succeeds.
    604 *  Returns a HttpDefaultClient Error if the function fails in a
    605 *      non-fatal way.
    606 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    607 */
    608 static PKIX_Error *
    609 pkix_pl_HttpDefaultClient_Send(
    610        PKIX_PL_HttpDefaultClient *client,
    611        PKIX_Boolean *pKeepGoing,
    612        PKIX_UInt32 *pBytesTransferred,
    613        void *plCtx)
    614 {
    615        PKIX_Int32 bytesWritten = 0;
    616        PKIX_Int32 lenToWrite = 0;
    617        PKIX_PL_Socket_Callback *callbackList = NULL;
    618        char *dataToWrite = NULL;
    619 
    620        PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Send");
    621        PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
    622 
    623        *pKeepGoing = PKIX_FALSE;
    624 
    625        /* Do we have anything waiting to go? */
    626        if ((client->GETBuf) || (client->POSTBuf)) {
    627 
    628                if (client->GETBuf) {
    629                        dataToWrite = client->GETBuf;
    630                        lenToWrite = client->GETLen;
    631                } else {
    632                        dataToWrite = client->POSTBuf;
    633                        lenToWrite = client->POSTLen;
    634                }
    635 
    636                callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
    637 
    638                PKIX_CHECK(callbackList->sendCallback
    639                        (client->socket,
    640                        dataToWrite,
    641                        lenToWrite,
    642                        &bytesWritten,
    643                        plCtx),
    644                        PKIX_SOCKETSENDFAILED);
    645 
    646                client->rcvBuf = NULL;
    647                client->capacity = 0;
    648                client->filledupBytes = 0;
    649 
    650                /*
    651                 * If the send completed we can proceed to try for the
    652                 * response. If the send did not complete we will have
    653                 * to poll for completion later.
    654                 */
    655                if (bytesWritten >= 0) {
    656                        client->connectStatus = HTTP_RECV_HDR;
    657                        *pKeepGoing = PKIX_TRUE;
    658                } else {
    659                        client->connectStatus = HTTP_SEND_PENDING;
    660                        *pKeepGoing = PKIX_FALSE;
    661                }
    662 
    663        }
    664 
    665        *pBytesTransferred = bytesWritten;
    666 
    667 cleanup:
    668        PKIX_RETURN(HTTPDEFAULTCLIENT);
    669 }
    670 
    671 /*
    672 * FUNCTION: pkix_pl_HttpDefaultClient_SendContinue
    673 * DESCRIPTION:
    674 *
    675 *  This function determines whether the sending of the HTTP message for the
    676 *  HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a
    677 *  flag indicating whether processing can continue without further input, and
    678 *  at "pBytesTransferred" the number of bytes sent.
    679 *
    680 *  If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
    681 *  and that transmission has not completed.
    682 *
    683 * PARAMETERS:
    684 *  "client"
    685 *      The address of the HttpDefaultClient object. Must be non-NULL.
    686 *  "pKeepGoing"
    687 *      The address at which the Boolean state machine flag is stored to
    688 *      indicate whether processing can continue without further input.
    689 *      Must be non-NULL.
    690 *  "pBytesTransferred"
    691 *      The address at which the number of bytes sent is stored. Must be
    692 *      non-NULL.
    693 *  "plCtx"
    694 *      Platform-specific context pointer.
    695 * THREAD SAFETY:
    696 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    697 * RETURNS:
    698 *  Returns NULL if the function succeeds.
    699 *  Returns a HttpDefaultClient Error if the function fails in a
    700 *      non-fatal way.
    701 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    702 */
    703 static PKIX_Error *
    704 pkix_pl_HttpDefaultClient_SendContinue(
    705        PKIX_PL_HttpDefaultClient *client,
    706        PKIX_Boolean *pKeepGoing,
    707        PKIX_UInt32 *pBytesTransferred,
    708        void *plCtx)
    709 {
    710        PKIX_Int32 bytesWritten = 0;
    711        PKIX_PL_Socket_Callback *callbackList = NULL;
    712 
    713        PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_SendContinue");
    714        PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
    715 
    716        *pKeepGoing = PKIX_FALSE;
    717 
    718        callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
    719 
    720        PKIX_CHECK(callbackList->pollCallback
    721                (client->socket, &bytesWritten, NULL, plCtx),
    722                PKIX_SOCKETPOLLFAILED);
    723 
    724        /*
    725         * If the send completed we can proceed to try for the
    726         * response. If the send did not complete we will have
    727         * continue to poll.
    728         */
    729        if (bytesWritten >= 0) {
    730                       client->connectStatus = HTTP_RECV_HDR;
    731                *pKeepGoing = PKIX_TRUE;
    732        }
    733 
    734        *pBytesTransferred = bytesWritten;
    735 
    736 cleanup:
    737        PKIX_RETURN(HTTPDEFAULTCLIENT);
    738 }
    739 
    740 /*
    741 * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdr
    742 * DESCRIPTION:
    743 *
    744 *  This function receives HTTP headers for the HttpDefaultClient "client", and
    745 *  stores in "pKeepGoing" a flag indicating whether processing can continue
    746 *  without further input.
    747 *
    748 * PARAMETERS:
    749 *  "client"
    750 *      The address of the HttpDefaultClient object. Must be non-NULL.
    751 *  "pKeepGoing"
    752 *      The address at which the Boolean state machine flag is stored to
    753 *      indicate whether processing can continue without further input.
    754 *      Must be non-NULL.
    755 *  "plCtx"
    756 *      Platform-specific context pointer.
    757 * THREAD SAFETY:
    758 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    759 * RETURNS:
    760 *  Returns NULL if the function succeeds.
    761 *  Returns a HttpDefaultClient Error if the function fails in a
    762 *      non-fatal way.
    763 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    764 */
    765 static PKIX_Error *
    766 pkix_pl_HttpDefaultClient_RecvHdr(
    767        PKIX_PL_HttpDefaultClient *client,
    768        PKIX_Boolean *pKeepGoing,
    769        void *plCtx)
    770 {
    771        PKIX_UInt32 bytesToRead = 0;
    772        PKIX_Int32 bytesRead = 0;
    773        PKIX_PL_Socket_Callback *callbackList = NULL;
    774 
    775        PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvHdr");
    776        PKIX_NULLCHECK_TWO(client, pKeepGoing);
    777 
    778        /*
    779         * rcvbuf, capacity, and filledupBytes were
    780         * initialized when we wrote the headers. We begin by reading
    781         * HTTP_HEADER_BUFSIZE bytes, repeatedly increasing the buffersize and
    782         * reading again if necessary, until we have read the end-of-header
    783         * marker, "\r\n\r\n", or have reached our maximum.
    784         */
    785        client->capacity += HTTP_HEADER_BUFSIZE;
    786        PKIX_CHECK(PKIX_PL_Realloc
    787                (client->rcvBuf,
    788                client->capacity,
    789                (void **)&(client->rcvBuf),
    790                plCtx),
    791                PKIX_REALLOCFAILED);
    792 
    793        bytesToRead = client->capacity - client->filledupBytes;
    794 
    795        callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
    796 
    797        PKIX_CHECK(callbackList->recvCallback
    798                (client->socket,
    799                (void *)&(client->rcvBuf[client->filledupBytes]),
    800                bytesToRead,
    801                &bytesRead,
    802                plCtx),
    803                PKIX_SOCKETRECVFAILED);
    804 
    805        if (bytesRead > 0) {
    806            /* client->filledupBytes will be adjusted by
    807             * pkix_pl_HttpDefaultClient_HdrCheckComplete */
    808            PKIX_CHECK(
    809                pkix_pl_HttpDefaultClient_HdrCheckComplete(client, bytesRead,
    810                                                           pKeepGoing,
    811                                                           plCtx),
    812                       PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED);
    813        } else {
    814            client->connectStatus = HTTP_RECV_HDR_PENDING;
    815            *pKeepGoing = PKIX_FALSE;
    816        }
    817 
    818 cleanup:
    819        PKIX_RETURN(HTTPDEFAULTCLIENT);
    820 }
    821 
    822 /*
    823 * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdrContinue
    824 * DESCRIPTION:
    825 *
    826 *  This function determines whether the receiving of the HTTP headers for the
    827 *  HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag
    828 *  indicating whether processing can continue without further input.
    829 *
    830 * PARAMETERS:
    831 *  "client"
    832 *      The address of the HttpDefaultClient object. Must be non-NULL.
    833 *  "pKeepGoing"
    834 *      The address at which the Boolean state machine flag is stored to
    835 *      indicate whether processing can continue without further input.
    836 *      Must be non-NULL.
    837 *  "plCtx"
    838 *      Platform-specific context pointer.
    839 * THREAD SAFETY:
    840 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    841 * RETURNS:
    842 *  Returns NULL if the function succeeds.
    843 *  Returns a HttpDefaultClient Error if the function fails in a
    844 *      non-fatal way.
    845 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    846 */
    847 static PKIX_Error *
    848 pkix_pl_HttpDefaultClient_RecvHdrContinue(
    849        PKIX_PL_HttpDefaultClient *client,
    850        PKIX_Boolean *pKeepGoing,
    851        void *plCtx)
    852 {
    853        PKIX_Int32 bytesRead = 0;
    854        PKIX_PL_Socket_Callback *callbackList = NULL;
    855 
    856        PKIX_ENTER
    857                (HTTPDEFAULTCLIENT,
    858                "pkix_pl_HttpDefaultClient_RecvHdrContinue");
    859        PKIX_NULLCHECK_TWO(client, pKeepGoing);
    860 
    861        callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
    862 
    863        PKIX_CHECK(callbackList->pollCallback
    864                (client->socket, NULL, &bytesRead, plCtx),
    865                PKIX_SOCKETPOLLFAILED);
    866 
    867        if (bytesRead > 0) {
    868                client->filledupBytes += bytesRead;
    869 
    870                PKIX_CHECK(pkix_pl_HttpDefaultClient_HdrCheckComplete
    871                        (client, bytesRead, pKeepGoing, plCtx),
    872                        PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED);
    873 
    874        } else {
    875 
    876                *pKeepGoing = PKIX_FALSE;
    877 
    878        }
    879 
    880 cleanup:
    881        PKIX_RETURN(HTTPDEFAULTCLIENT);
    882 }
    883 
    884 /*
    885 * FUNCTION: pkix_pl_HttpDefaultClient_RecvBody
    886 * DESCRIPTION:
    887 *
    888 *  This function processes the contents of the first buffer of a received
    889 *  HTTP-protocol message for the HttpDefaultClient "client", and stores in
    890 *  "pKeepGoing" a flag indicating whether processing can continue without
    891 *  further input.
    892 *
    893 * PARAMETERS:
    894 *  "client"
    895 *      The address of the HttpDefaultClient object. Must be non-NULL.
    896 *  "pKeepGoing"
    897 *      The address at which the Boolean state machine flag is stored to
    898 *      indicate whether processing can continue without further input.
    899 *      Must be non-NULL.
    900 *  "plCtx"
    901 *      Platform-specific context pointer.
    902 * THREAD SAFETY:
    903 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    904 * RETURNS:
    905 *  Returns NULL if the function succeeds.
    906 *  Returns a HttpDefaultClient Error if the function fails in a
    907 *      non-fatal way.
    908 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    909 */
    910 static PKIX_Error *
    911 pkix_pl_HttpDefaultClient_RecvBody(
    912        PKIX_PL_HttpDefaultClient *client,
    913        PKIX_Boolean *pKeepGoing,
    914        void *plCtx)
    915 {
    916        PKIX_Int32 bytesRead = 0;
    917        PKIX_Int32 bytesToRead = 0;
    918        PKIX_PL_Socket_Callback *callbackList = NULL;
    919 
    920        PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvBody");
    921        PKIX_NULLCHECK_TWO(client, pKeepGoing);
    922 
    923        callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
    924 
    925        if (client->rcv_http_data_len != HTTP_UNKNOWN_CONTENT_LENGTH) {
    926            bytesToRead = client->rcv_http_data_len -
    927                client->filledupBytes;
    928        } else {
    929            /* Reading till the EOF. Context length is not known.*/
    930            /* Check the buffer capacity: increase and
    931             * reallocate if it is low. */
    932            int freeBuffSize = client->capacity - client->filledupBytes;
    933            if (freeBuffSize < HTTP_MIN_AVAILABLE_BUFFER_SIZE) {
    934                /* New length will be consist of available(downloaded) bytes,
    935                 * plus remaining capacity, plus new expansion. */
    936                int currBuffSize = client->capacity;
    937                /* Try to increase the buffer by 4K */
    938                unsigned int newLength = currBuffSize + HTTP_DATA_BUFSIZE;
    939                if (client->maxResponseLen > 0 &&
    940                    newLength > client->maxResponseLen) {
    941                        newLength = client->maxResponseLen;
    942                }
    943                /* Check if we can grow the buffer and report an error if
    944                 * new size is not larger than the current size of the buffer.*/
    945                if (newLength <= client->filledupBytes) {
    946                    client->rcv_http_data_len = client->filledupBytes;
    947                    client->connectStatus = HTTP_ERROR;
    948                    *pKeepGoing = PKIX_FALSE;
    949                    goto cleanup;
    950                }
    951                if (client->capacity < newLength) {
    952                    client->capacity = newLength;
    953                    PKIX_CHECK(
    954                        PKIX_PL_Realloc(client->rcvBuf, newLength,
    955                                        (void**)&client->rcvBuf, plCtx),
    956                        PKIX_REALLOCFAILED);
    957                    freeBuffSize = client->capacity -
    958                        client->filledupBytes;
    959                }
    960            }
    961            bytesToRead = freeBuffSize;
    962        }
    963 
    964        /* Use poll callback if waiting on non-blocking IO */
    965        if (client->connectStatus == HTTP_RECV_BODY_PENDING) {
    966            PKIX_CHECK(callbackList->pollCallback
    967                       (client->socket, NULL, &bytesRead, plCtx),
    968                       PKIX_SOCKETPOLLFAILED);
    969        } else {
    970            PKIX_CHECK(callbackList->recvCallback
    971                       (client->socket,
    972                        (void *)&(client->rcvBuf[client->filledupBytes]),
    973                        bytesToRead,
    974                        &bytesRead,
    975                        plCtx),
    976                       PKIX_SOCKETRECVFAILED);
    977        }
    978 
    979        /* If bytesRead < 0, an error will be thrown by recvCallback, so
    980         * need to handle >= 0 cases. */
    981 
    982        /* bytesRead == 0 - IO was blocked. */
    983        if (bytesRead == 0) {
    984            client->connectStatus = HTTP_RECV_BODY_PENDING;
    985            *pKeepGoing = PKIX_TRUE;
    986            goto cleanup;
    987        }
    988        
    989        /* We got something. Did we get it all? */
    990        client->filledupBytes += bytesRead;
    991 
    992        /* continue if not enough bytes read or if complete size of
    993         * transfer is unknown */
    994        if (bytesToRead > bytesRead ||
    995            client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) {
    996            *pKeepGoing = PKIX_TRUE;
    997            goto cleanup;
    998        }
    999        client->connectStatus = HTTP_COMPLETE;
   1000        *pKeepGoing = PKIX_FALSE;
   1001 
   1002 cleanup:
   1003        if (pkixErrorResult && pkixErrorResult->errCode ==
   1004            PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED) {
   1005            if (client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) {
   1006                client->rcv_http_data_len = client->filledupBytes;
   1007                client->connectStatus = HTTP_COMPLETE;
   1008                *pKeepGoing = PKIX_FALSE;
   1009                PKIX_DECREF(pkixErrorResult);
   1010            } else {
   1011                client->connectStatus = HTTP_ERROR;
   1012            }
   1013        }
   1014 
   1015        PKIX_RETURN(HTTPDEFAULTCLIENT);
   1016 }
   1017 
   1018 /*
   1019 * FUNCTION: pkix_pl_HttpDefaultClient_Dispatch
   1020 * DESCRIPTION:
   1021 *
   1022 *  This function is the state machine dispatcher for the HttpDefaultClient
   1023 *  pointed to by "client". Results are returned by changes to various fields
   1024 *  in the context.
   1025 *
   1026 * PARAMETERS:
   1027 *  "client"
   1028 *      The address of the HttpDefaultClient object. Must be non-NULL.
   1029 *  "plCtx"
   1030 *      Platform-specific context pointer.
   1031 * THREAD SAFETY:
   1032 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
   1033 * RETURNS:
   1034 *  Returns NULL if the function succeeds.
   1035 *  Returns a HttpDefaultClient Error if the function fails in a
   1036 *      non-fatal way.
   1037 *  Returns a Fatal Error if the function fails in an unrecoverable way.
   1038 */
   1039 static PKIX_Error *
   1040 pkix_pl_HttpDefaultClient_Dispatch(
   1041        PKIX_PL_HttpDefaultClient *client,
   1042        void *plCtx)
   1043 {
   1044        PKIX_UInt32 bytesTransferred = 0;
   1045        PKIX_Boolean keepGoing = PKIX_TRUE;
   1046 
   1047        PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Dispatch");
   1048        PKIX_NULLCHECK_ONE(client);
   1049 
   1050        while (keepGoing) {
   1051                switch (client->connectStatus) {
   1052                case HTTP_CONNECT_PENDING:
   1053                    PKIX_CHECK(pkix_pl_HttpDefaultClient_ConnectContinue
   1054                        (client, &keepGoing, plCtx),
   1055                        PKIX_HTTPDEFAULTCLIENTCONNECTCONTINUEFAILED);
   1056                    break;
   1057                case HTTP_CONNECTED:
   1058                    PKIX_CHECK(pkix_pl_HttpDefaultClient_Send
   1059                        (client, &keepGoing, &bytesTransferred, plCtx),
   1060                        PKIX_HTTPDEFAULTCLIENTSENDFAILED);
   1061                    break;
   1062                case HTTP_SEND_PENDING:
   1063                    PKIX_CHECK(pkix_pl_HttpDefaultClient_SendContinue
   1064                        (client, &keepGoing, &bytesTransferred, plCtx),
   1065                        PKIX_HTTPDEFAULTCLIENTSENDCONTINUEFAILED);
   1066                    break;
   1067                case HTTP_RECV_HDR:
   1068                    PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdr
   1069                        (client, &keepGoing, plCtx),
   1070                        PKIX_HTTPDEFAULTCLIENTRECVHDRFAILED);
   1071                    break;
   1072                case HTTP_RECV_HDR_PENDING:
   1073                    PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdrContinue
   1074                        (client, &keepGoing, plCtx),
   1075                        PKIX_HTTPDEFAULTCLIENTRECVHDRCONTINUEFAILED);
   1076                    break;
   1077                case HTTP_RECV_BODY:
   1078                case HTTP_RECV_BODY_PENDING:
   1079                    PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvBody
   1080                        (client, &keepGoing, plCtx),
   1081                        PKIX_HTTPDEFAULTCLIENTRECVBODYFAILED);
   1082                    break;
   1083                case HTTP_ERROR:
   1084                case HTTP_COMPLETE:
   1085                    keepGoing = PKIX_FALSE;
   1086                    break;
   1087                case HTTP_NOT_CONNECTED:
   1088                default:
   1089                    PKIX_ERROR(PKIX_HTTPDEFAULTCLIENTINILLEGALSTATE);
   1090                }
   1091        }
   1092 
   1093 cleanup:
   1094 
   1095        PKIX_RETURN(HTTPDEFAULTCLIENT);
   1096 }
   1097 
   1098 /*
   1099 * --HttpClient vtable functions
   1100 * See comments in ocspt.h for the function (wrappers) that return SECStatus.
   1101 * The functions that return PKIX_Error* are the libpkix implementations.
   1102 */
   1103 
   1104 PKIX_Error *
   1105 pkix_pl_HttpDefaultClient_CreateSession(
   1106        const char *host,
   1107        PRUint16 portnum,
   1108        SEC_HTTP_SERVER_SESSION *pSession,
   1109        void *plCtx)
   1110 {
   1111        PKIX_PL_HttpDefaultClient *client = NULL;
   1112 
   1113        PKIX_ENTER
   1114                (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_CreateSession");
   1115        PKIX_NULLCHECK_TWO(host, pSession);
   1116 
   1117        PKIX_CHECK(pkix_pl_HttpDefaultClient_Create
   1118                (host, portnum, &client, plCtx),
   1119                PKIX_HTTPDEFAULTCLIENTCREATEFAILED);
   1120 
   1121        *pSession = (SEC_HTTP_SERVER_SESSION)client;
   1122 
   1123 cleanup:
   1124 
   1125        PKIX_RETURN(HTTPDEFAULTCLIENT);
   1126 
   1127 }
   1128 
   1129 PKIX_Error *
   1130 pkix_pl_HttpDefaultClient_KeepAliveSession(
   1131        SEC_HTTP_SERVER_SESSION session,
   1132        PRPollDesc **pPollDesc,
   1133        void *plCtx)
   1134 {
   1135        PKIX_ENTER
   1136                (HTTPDEFAULTCLIENT,
   1137                "pkix_pl_HttpDefaultClient_KeepAliveSession");
   1138        PKIX_NULLCHECK_TWO(session, pPollDesc);
   1139 
   1140        PKIX_CHECK(pkix_CheckType
   1141                ((PKIX_PL_Object *)session,
   1142                PKIX_HTTPDEFAULTCLIENT_TYPE,
   1143                plCtx),
   1144                PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
   1145 
   1146        /* XXX Not implemented */
   1147 
   1148 cleanup:
   1149 
   1150        PKIX_RETURN(HTTPDEFAULTCLIENT);
   1151 
   1152 }
   1153 
   1154 PKIX_Error *
   1155 pkix_pl_HttpDefaultClient_RequestCreate(
   1156        SEC_HTTP_SERVER_SESSION session,
   1157        const char *http_protocol_variant, /* usually "http" */
   1158        const char *path_and_query_string,
   1159        const char *http_request_method, 
   1160        const PRIntervalTime timeout, 
   1161        SEC_HTTP_REQUEST_SESSION *pRequest,
   1162        void *plCtx)
   1163 {
   1164        PKIX_PL_HttpDefaultClient *client = NULL;
   1165        PKIX_PL_Socket *socket = NULL;
   1166        PKIX_PL_Socket_Callback *callbackList = NULL;
   1167        PRFileDesc *fileDesc = NULL;
   1168        PRErrorCode status = 0;
   1169 
   1170        PKIX_ENTER
   1171                (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RequestCreate");
   1172        PKIX_NULLCHECK_TWO(session, pRequest);
   1173 
   1174        PKIX_CHECK(pkix_CheckType
   1175                ((PKIX_PL_Object *)session,
   1176                PKIX_HTTPDEFAULTCLIENT_TYPE,
   1177                plCtx),
   1178                PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
   1179 
   1180        client = (PKIX_PL_HttpDefaultClient *)session;
   1181 
   1182        /* We only know how to do http */
   1183        if (PORT_Strncasecmp(http_protocol_variant, "http", 4) != 0) {
   1184                PKIX_ERROR(PKIX_UNRECOGNIZEDPROTOCOLREQUESTED);
   1185        }
   1186 
   1187        if (PORT_Strncasecmp(http_request_method, "POST", 4) == 0) {
   1188                client->send_http_method = HTTP_POST_METHOD;
   1189        } else if (PORT_Strncasecmp(http_request_method, "GET", 3) == 0) {
   1190                client->send_http_method = HTTP_GET_METHOD;
   1191        } else {
   1192                /* We only know how to do POST and GET */
   1193                PKIX_ERROR(PKIX_UNRECOGNIZEDREQUESTMETHOD);
   1194        }
   1195 
   1196        if (path_and_query_string) {
   1197            /* "path_and_query_string" is a parsing result by CERT_GetURL
   1198             * function that adds "end of line" to the value. OK to dup
   1199             * the string. */
   1200            client->path = PORT_Strdup(path_and_query_string);
   1201            if (!client->path) {
   1202                PKIX_ERROR(PKIX_ALLOCERROR);
   1203            }
   1204        }
   1205 
   1206        client->timeout = timeout;
   1207 
   1208 #if 0
   1209 PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
   1210                (timeout,
   1211                "variation.red.iplanet.com", /* (char *)client->host, */
   1212                2001,   /* client->portnum, */
   1213                &status,
   1214                &socket,
   1215                plCtx),
   1216 	PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
   1217 #else
   1218 PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
   1219                (timeout,
   1220                (char *)client->host,
   1221                client->portnum,
   1222                &status,
   1223                &socket,
   1224                plCtx),
   1225 	PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
   1226 #endif
   1227 
   1228        client->socket = socket;
   1229 
   1230        PKIX_CHECK(pkix_pl_Socket_GetCallbackList
   1231                (socket, &callbackList, plCtx),
   1232                PKIX_SOCKETGETCALLBACKLISTFAILED);
   1233 
   1234        client->callbackList = (void *)callbackList;
   1235 
   1236        PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc
   1237                (socket, &fileDesc, plCtx),
   1238                PKIX_SOCKETGETPRFILEDESCFAILED);
   1239 
   1240        client->pollDesc.fd = fileDesc;
   1241        client->pollDesc.in_flags = 0;
   1242        client->pollDesc.out_flags = 0;
   1243 
   1244        client->send_http_data = NULL;
   1245        client->send_http_data_len = 0;
   1246        client->send_http_content_type = NULL;
   1247 
   1248        client->connectStatus =
   1249                 ((status == 0) ? HTTP_CONNECTED : HTTP_CONNECT_PENDING);
   1250 
   1251        /* Request object is the same object as Session object */
   1252        PKIX_INCREF(client);
   1253        *pRequest = client;
   1254 
   1255 cleanup:
   1256 
   1257        PKIX_RETURN(HTTPDEFAULTCLIENT);
   1258 
   1259 }
   1260 
   1261 PKIX_Error *
   1262 pkix_pl_HttpDefaultClient_SetPostData(
   1263        SEC_HTTP_REQUEST_SESSION request,
   1264        const char *http_data, 
   1265        const PRUint32 http_data_len,
   1266        const char *http_content_type,
   1267        void *plCtx)
   1268 {
   1269        PKIX_PL_HttpDefaultClient *client = NULL;
   1270 
   1271        PKIX_ENTER
   1272                (HTTPDEFAULTCLIENT,
   1273                "pkix_pl_HttpDefaultClient_SetPostData");
   1274        PKIX_NULLCHECK_ONE(request);
   1275 
   1276        PKIX_CHECK(pkix_CheckType
   1277                ((PKIX_PL_Object *)request,
   1278                PKIX_HTTPDEFAULTCLIENT_TYPE,
   1279                plCtx),
   1280                PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
   1281 
   1282        client = (PKIX_PL_HttpDefaultClient *)request;
   1283 
   1284        client->send_http_data = http_data;
   1285        client->send_http_data_len = http_data_len;
   1286        client->send_http_content_type = http_content_type;
   1287 
   1288        /* Caller is allowed to give NULL or empty string for content_type */
   1289        if ((client->send_http_content_type == NULL) ||
   1290            (*(client->send_http_content_type) == '\0')) {
   1291                client->send_http_content_type = "application/ocsp-request";
   1292        }
   1293 
   1294 cleanup:
   1295 
   1296        PKIX_RETURN(HTTPDEFAULTCLIENT);
   1297 
   1298 }
   1299 
   1300 PKIX_Error *
   1301 pkix_pl_HttpDefaultClient_TrySendAndReceive(
   1302        SEC_HTTP_REQUEST_SESSION request,
   1303        PRUint16 *http_response_code, 
   1304        const char **http_response_content_type, 
   1305        const char **http_response_headers, 
   1306        const char **http_response_data, 
   1307        PRUint32 *http_response_data_len, 
   1308        PRPollDesc **pPollDesc,
   1309        SECStatus *pSECReturn,
   1310        void *plCtx)        
   1311 {
   1312        PKIX_PL_HttpDefaultClient *client = NULL;
   1313        PKIX_UInt32 postLen = 0;
   1314        PRPollDesc *pollDesc = NULL;
   1315        char *sendbuf = NULL;
   1316        char portstr[16];
   1317 
   1318        PKIX_ENTER
   1319                (HTTPDEFAULTCLIENT,
   1320                "pkix_pl_HttpDefaultClient_TrySendAndReceive");
   1321 
   1322        PKIX_NULLCHECK_ONE(request);
   1323 
   1324        PKIX_CHECK(pkix_CheckType
   1325                ((PKIX_PL_Object *)request,
   1326                PKIX_HTTPDEFAULTCLIENT_TYPE,
   1327                plCtx),
   1328                PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
   1329 
   1330        client = (PKIX_PL_HttpDefaultClient *)request;
   1331 
   1332        if (!pPollDesc && client->timeout == 0) {
   1333            PKIX_ERROR_FATAL(PKIX_NULLARGUMENT);
   1334        }
   1335 
   1336        if (pPollDesc) {
   1337            pollDesc = *pPollDesc;
   1338        }
   1339 
   1340        /* if not continuing from an earlier WOULDBLOCK return... */
   1341        if (pollDesc == NULL) {
   1342 
   1343                if (!((client->connectStatus == HTTP_CONNECTED) ||
   1344                     (client->connectStatus == HTTP_CONNECT_PENDING))) {
   1345                        PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
   1346                }
   1347 
   1348                /* Did caller provide a value for response length? */
   1349                if (http_response_data_len != NULL) {
   1350                        client->pRcv_http_data_len = http_response_data_len;
   1351                        client->maxResponseLen = *http_response_data_len;
   1352                }
   1353 
   1354                client->rcv_http_response_code = http_response_code;
   1355                client->rcv_http_content_type = http_response_content_type;
   1356                client->rcv_http_headers = http_response_headers;
   1357                client->rcv_http_data = http_response_data;
   1358 
   1359                /* prepare the message */
   1360                portstr[0] = '\0';
   1361                if (client->portnum != 80) {
   1362                        PR_snprintf(portstr, sizeof(portstr), ":%d", 
   1363                                    client->portnum);
   1364                }
   1365                
   1366                if (client->send_http_method == HTTP_POST_METHOD) {
   1367                        sendbuf = PR_smprintf
   1368                            ("POST %s HTTP/1.0\r\nHost: %s%s\r\n"
   1369                            "Content-Type: %s\r\nContent-Length: %u\r\n\r\n",
   1370                            client->path,
   1371                            client->host,
   1372                            portstr,
   1373                            client->send_http_content_type,
   1374                            client->send_http_data_len);
   1375                        postLen = PORT_Strlen(sendbuf);
   1376                            
   1377                        client->POSTLen = postLen + client->send_http_data_len;
   1378 
   1379                        /* allocate postBuffer big enough for header + data */
   1380                        PKIX_CHECK(PKIX_PL_Malloc
   1381                                (client->POSTLen,
   1382                                (void **)&(client->POSTBuf),
   1383                                plCtx),
   1384                                PKIX_MALLOCFAILED);
   1385 
   1386                        /* copy header into postBuffer */
   1387                        PORT_Memcpy(client->POSTBuf, sendbuf, postLen);
   1388 
   1389                        /* append data after header */
   1390                        PORT_Memcpy(&client->POSTBuf[postLen],
   1391                                    client->send_http_data,
   1392                                    client->send_http_data_len);
   1393 
   1394                        /* PR_smprintf_free original header buffer */
   1395                        PR_smprintf_free(sendbuf);
   1396                        sendbuf = NULL;
   1397                        
   1398                } else if (client->send_http_method == HTTP_GET_METHOD) {
   1399                        client->GETBuf = PR_smprintf
   1400                            ("GET %s HTTP/1.0\r\nHost: %s%s\r\n\r\n",
   1401                            client->path,
   1402                            client->host,
   1403                            portstr);
   1404                        client->GETLen = PORT_Strlen(client->GETBuf);
   1405                }
   1406 
   1407        }
   1408 
   1409        /* continue according to state */
   1410        PKIX_CHECK(pkix_pl_HttpDefaultClient_Dispatch(client, plCtx),
   1411                PKIX_HTTPDEFAULTCLIENTDISPATCHFAILED);
   1412 
   1413        switch (client->connectStatus) {
   1414                case HTTP_CONNECT_PENDING:
   1415                case HTTP_SEND_PENDING:
   1416                case HTTP_RECV_HDR_PENDING:
   1417                case HTTP_RECV_BODY_PENDING:
   1418                        pollDesc = &(client->pollDesc);
   1419                        *pSECReturn = SECWouldBlock;
   1420                        break;
   1421                case HTTP_ERROR:
   1422                        /* Did caller provide a pointer for length? */
   1423                        if (client->pRcv_http_data_len != NULL) {
   1424                                /* Was error "response too big?" */
   1425                                if (client->rcv_http_data_len !=
   1426                                            HTTP_UNKNOWN_CONTENT_LENGTH &&
   1427                                    client->maxResponseLen >=
   1428                                                client->rcv_http_data_len) {
   1429                                        /* Yes, report needed space */
   1430                                        *(client->pRcv_http_data_len) =
   1431                                                 client->rcv_http_data_len;
   1432                                } else {
   1433                                        /* No, report problem other than size */
   1434                                        *(client->pRcv_http_data_len) = 0;
   1435                                }
   1436                        }
   1437 
   1438                        pollDesc = NULL;
   1439                        *pSECReturn = SECFailure;
   1440                        break;
   1441                case HTTP_COMPLETE:
   1442                        *(client->rcv_http_response_code) =
   1443                                client->responseCode;
   1444                        if (client->pRcv_http_data_len != NULL) {
   1445                                *http_response_data_len =
   1446                                         client->rcv_http_data_len;
   1447                        }
   1448                        if (client->rcv_http_data != NULL) {
   1449                                *(client->rcv_http_data) = client->rcvBuf;
   1450                        }
   1451                        pollDesc = NULL;
   1452                        *pSECReturn = SECSuccess;
   1453                        break;
   1454                case HTTP_NOT_CONNECTED:
   1455                case HTTP_CONNECTED:
   1456                case HTTP_RECV_HDR:
   1457                case HTTP_RECV_BODY:
   1458                default:
   1459                        pollDesc = NULL;
   1460                        *pSECReturn = SECFailure;
   1461                        PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
   1462                        break;
   1463        }
   1464 
   1465        if (pPollDesc) {
   1466            *pPollDesc = pollDesc;
   1467        }
   1468 
   1469 cleanup:
   1470        if (sendbuf) {
   1471            PR_smprintf_free(sendbuf);
   1472        }
   1473 
   1474        PKIX_RETURN(HTTPDEFAULTCLIENT);
   1475 
   1476 }
   1477 
   1478 PKIX_Error *
   1479 pkix_pl_HttpDefaultClient_Cancel(
   1480        SEC_HTTP_REQUEST_SESSION request,
   1481        void *plCtx)
   1482 {
   1483        PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Cancel");
   1484        PKIX_NULLCHECK_ONE(request);
   1485 
   1486        PKIX_CHECK(pkix_CheckType
   1487                ((PKIX_PL_Object *)request,
   1488                PKIX_HTTPDEFAULTCLIENT_TYPE,
   1489                plCtx),
   1490                PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
   1491 
   1492        /* XXX Not implemented */
   1493 
   1494 cleanup:
   1495 
   1496        PKIX_RETURN(HTTPDEFAULTCLIENT);
   1497 
   1498 }
   1499 
   1500 SECStatus
   1501 pkix_pl_HttpDefaultClient_CreateSessionFcn(
   1502        const char *host,
   1503        PRUint16 portnum,
   1504        SEC_HTTP_SERVER_SESSION *pSession)
   1505 {
   1506        PKIX_Error *err = pkix_pl_HttpDefaultClient_CreateSession
   1507                (host, portnum, pSession, plContext);
   1508 
   1509        if (err) {
   1510                PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
   1511                return SECFailure;
   1512        }
   1513        return SECSuccess;
   1514 }
   1515 
   1516 SECStatus
   1517 pkix_pl_HttpDefaultClient_KeepAliveSessionFcn(
   1518        SEC_HTTP_SERVER_SESSION session,
   1519        PRPollDesc **pPollDesc)
   1520 {
   1521        PKIX_Error *err = pkix_pl_HttpDefaultClient_KeepAliveSession
   1522                (session, pPollDesc, plContext);
   1523 
   1524        if (err) {
   1525                PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
   1526                return SECFailure;
   1527        }
   1528        return SECSuccess;
   1529 }
   1530 
   1531 SECStatus
   1532 pkix_pl_HttpDefaultClient_FreeSessionFcn(
   1533        SEC_HTTP_SERVER_SESSION session)
   1534 {
   1535        PKIX_Error *err =
   1536            PKIX_PL_Object_DecRef((PKIX_PL_Object *)(session), plContext);
   1537 
   1538        if (err) {
   1539                PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
   1540                return SECFailure;
   1541        }
   1542        return SECSuccess;
   1543 }
   1544 
   1545 SECStatus
   1546 pkix_pl_HttpDefaultClient_RequestCreateFcn(
   1547        SEC_HTTP_SERVER_SESSION session,
   1548        const char *http_protocol_variant, /* usually "http" */
   1549        const char *path_and_query_string,
   1550        const char *http_request_method, 
   1551        const PRIntervalTime timeout, 
   1552        SEC_HTTP_REQUEST_SESSION *pRequest)
   1553 {
   1554        PKIX_Error *err = pkix_pl_HttpDefaultClient_RequestCreate
   1555                (session,
   1556                http_protocol_variant,
   1557                path_and_query_string,
   1558                http_request_method,
   1559                timeout,
   1560                pRequest,
   1561                plContext);
   1562 
   1563        if (err) {
   1564                PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
   1565                return SECFailure;
   1566        }
   1567        return SECSuccess;
   1568 }
   1569 
   1570 SECStatus
   1571 pkix_pl_HttpDefaultClient_SetPostDataFcn(
   1572        SEC_HTTP_REQUEST_SESSION request,
   1573        const char *http_data, 
   1574        const PRUint32 http_data_len,
   1575        const char *http_content_type)
   1576 {
   1577        PKIX_Error *err =
   1578            pkix_pl_HttpDefaultClient_SetPostData(request, http_data,
   1579                                                  http_data_len,
   1580                                                  http_content_type,
   1581                                                  plContext);
   1582        if (err) {
   1583                PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
   1584                return SECFailure;
   1585        }
   1586        return SECSuccess;
   1587 }
   1588 
   1589 SECStatus
   1590 pkix_pl_HttpDefaultClient_AddHeaderFcn(
   1591        SEC_HTTP_REQUEST_SESSION request,
   1592        const char *http_header_name, 
   1593        const char *http_header_value)
   1594 {
   1595        /* Not supported */
   1596        return SECFailure;
   1597 }
   1598 
   1599 SECStatus
   1600 pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn(
   1601        SEC_HTTP_REQUEST_SESSION request,
   1602        PRPollDesc **pPollDesc,
   1603        PRUint16 *http_response_code, 
   1604        const char **http_response_content_type, 
   1605        const char **http_response_headers, 
   1606        const char **http_response_data, 
   1607        PRUint32 *http_response_data_len) 
   1608 {
   1609        SECStatus rv = SECFailure;
   1610 
   1611        PKIX_Error *err = pkix_pl_HttpDefaultClient_TrySendAndReceive
   1612                (request,
   1613                http_response_code, 
   1614                http_response_content_type, 
   1615                http_response_headers, 
   1616                http_response_data, 
   1617                http_response_data_len,
   1618                pPollDesc,
   1619                &rv,
   1620                plContext);
   1621 
   1622        if (err) {
   1623                PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
   1624                return rv;
   1625        }
   1626        return SECSuccess;
   1627 }
   1628 
   1629 SECStatus
   1630 pkix_pl_HttpDefaultClient_CancelFcn(
   1631        SEC_HTTP_REQUEST_SESSION request)
   1632 {
   1633        PKIX_Error *err = pkix_pl_HttpDefaultClient_Cancel(request, plContext);
   1634 
   1635        if (err) {
   1636                PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
   1637                return SECFailure;
   1638        }
   1639        return SECSuccess;
   1640 }
   1641 
   1642 SECStatus
   1643 pkix_pl_HttpDefaultClient_FreeFcn(
   1644        SEC_HTTP_REQUEST_SESSION request)
   1645 {
   1646        PKIX_Error *err =
   1647            PKIX_PL_Object_DecRef((PKIX_PL_Object *)(request), plContext);
   1648 
   1649        if (err) {
   1650                PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
   1651                return SECFailure;
   1652        }
   1653        return SECSuccess;
   1654 }