PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

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