PageRenderTime 78ms CodeModel.GetById 15ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c

http://github.com/zpao/v8monkey
C | 1695 lines | 1054 code | 217 blank | 424 comment | 146 complexity | f975750bf320b03a51dc81b8405fc2ee MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file