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 **)©, 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 }