Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(195)

Side by Side Diff: nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 * "plContext"
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 *plContext)
89 {
90 PKIX_UInt32 alreadyScanned = 0;
91 PKIX_UInt32 comp = 0;
92 PKIX_UInt32 headerLength = 0;
93 PKIX_Int32 contentLength = HTTP_UNKNOWN_CONTENT_LENGTH;
94 char *eoh = NULL;
95 char *statusLineEnd = NULL;
96 char *space = NULL;
97 char *nextHeader = NULL;
98 const char *httpcode = NULL;
99 char *thisHeaderEnd = NULL;
100 char *value = NULL;
101 char *colon = NULL;
102 char *copy = NULL;
103 char *body = NULL;
104
105 PKIX_ENTER
106 (HTTPDEFAULTCLIENT,
107 "pkix_pl_HttpDefaultClient_HdrCheckComplete");
108 PKIX_NULLCHECK_TWO(client, pKeepGoing);
109
110 *pKeepGoing = PKIX_FALSE;
111
112 /* Does buffer contain end-of-header marker? */
113
114 /* Copy number of scanned bytes into a variable. */
115 alreadyScanned = client->filledupBytes;
116 /*
117 * If this is the initial buffer, we have to scan from the beginning.
118 * If we scanned, failed to find eohMarker, and read some more, we
119 * only have to scan from where we left off.
120 */
121 if (alreadyScanned > eohMarkLen) {
122 /* Back up and restart scanning over a few bytes that were
123 * scanned before */
124 PKIX_UInt32 searchStartPos = alreadyScanned - eohMarkLen;
125 eoh = PL_strnstr(&(client->rcvBuf[searchStartPos]), eohMarker,
126 bytesRead + searchStartPos);
127 } else {
128 /* A search from the beginning of the buffer. */
129 eoh = PL_strnstr(client->rcvBuf, eohMarker, bytesRead);
130 }
131
132 client->filledupBytes += bytesRead;
133
134 if (eoh == NULL) { /* did we see end-of-header? */
135 /* No. Continue to read header data */
136 client->connectStatus = HTTP_RECV_HDR;
137 *pKeepGoing = PKIX_TRUE;
138 goto cleanup;
139 }
140
141 /* Yes. Calculate how many bytes in header (not counting eohMarker) */
142 headerLength = (eoh - client->rcvBuf);
143
144 /* allocate space to copy header (and for the NULL terminator) */
145 PKIX_CHECK(PKIX_PL_Malloc(headerLength + 1, (void **)&copy, plContext),
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 m ore?
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, plContext) ,
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, plContext),
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 * "plContext"
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 *plContext)
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 plContext),
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 plContext argument in its
412 * function calls. Save it here.
413 */
414 client->plContext = plContext;
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 *plContext)
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, plContext),
442 PKIX_OBJECTNOTANHTTPDEFAULTCLIENT);
443
444 client = (PKIX_PL_HttpDefaultClient *)object;
445
446 if (client->rcvHeaders) {
447 PKIX_PL_Free(client->rcvHeaders, plContext);
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, plContext);
460 client->POSTBuf = NULL;
461 }
462 if (client->rcvBuf != NULL) {
463 PKIX_PL_Free(client->rcvBuf, plContext);
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 *plContext)
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 * "plContext"
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 *plContext)
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, plContext),
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 * "plContext"
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 *plContext)
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 plContext),
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 * "plContext"
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 *plContext)
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, plContext),
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 * "plContext"
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 *plContext)
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 plContext),
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 plContext),
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 plContext),
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 * "plContext"
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 *plContext)
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, plContext),
865 PKIX_SOCKETPOLLFAILED);
866
867 if (bytesRead > 0) {
868 client->filledupBytes += bytesRead;
869
870 PKIX_CHECK(pkix_pl_HttpDefaultClient_HdrCheckComplete
871 (client, bytesRead, pKeepGoing, plContext),
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 * "plContext"
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 *plContext)
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, plContext),
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, plContext),
968 PKIX_SOCKETPOLLFAILED);
969 } else {
970 PKIX_CHECK(callbackList->recvCallback
971 (client->socket,
972 (void *)&(client->rcvBuf[client->filledupBytes]),
973 bytesToRead,
974 &bytesRead,
975 plContext),
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 * "plContext"
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 *plContext)
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, plContext),
1055 PKIX_HTTPDEFAULTCLIENTCONNECTCONTINUEFAILED);
1056 break;
1057 case HTTP_CONNECTED:
1058 PKIX_CHECK(pkix_pl_HttpDefaultClient_Send
1059 (client, &keepGoing, &bytesTransferred, plContext),
1060 PKIX_HTTPDEFAULTCLIENTSENDFAILED);
1061 break;
1062 case HTTP_SEND_PENDING:
1063 PKIX_CHECK(pkix_pl_HttpDefaultClient_SendContinue
1064 (client, &keepGoing, &bytesTransferred, plContext),
1065 PKIX_HTTPDEFAULTCLIENTSENDCONTINUEFAILED);
1066 break;
1067 case HTTP_RECV_HDR:
1068 PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdr
1069 (client, &keepGoing, plContext),
1070 PKIX_HTTPDEFAULTCLIENTRECVHDRFAILED);
1071 break;
1072 case HTTP_RECV_HDR_PENDING:
1073 PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdrContinue
1074 (client, &keepGoing, plContext),
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, plContext),
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 *plContext)
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, plContext),
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 *plContext)
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 plContext),
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 *plContext)
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 plContext),
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 plContext),
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 plContext),
1225 PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
1226 #endif
1227
1228 client->socket = socket;
1229
1230 PKIX_CHECK(pkix_pl_Socket_GetCallbackList
1231 (socket, &callbackList, plContext),
1232 PKIX_SOCKETGETCALLBACKLISTFAILED);
1233
1234 client->callbackList = (void *)callbackList;
1235
1236 PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc
1237 (socket, &fileDesc, plContext),
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 *plContext)
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 plContext),
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 *plContext)
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 plContext),
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 plContext),
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, plContext),
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 *plContext)
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 plContext),
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698