comparison nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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 > 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 client->maxResponseLen < contentLength) {
286 client->connectStatus = HTTP_ERROR;
287 goto cleanup;
288 }
289
290 /*
291 * Do we have all of the message body, or do we need to read some more?
292 */
293 if (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 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_PL_HttpDefaultClient *client = NULL;
1136
1137 PKIX_ENTER
1138 (HTTPDEFAULTCLIENT,
1139 "pkix_pl_HttpDefaultClient_KeepAliveSession");
1140 PKIX_NULLCHECK_TWO(session, pPollDesc);
1141
1142 PKIX_CHECK(pkix_CheckType
1143 ((PKIX_PL_Object *)session,
1144 PKIX_HTTPDEFAULTCLIENT_TYPE,
1145 plContext),
1146 PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
1147
1148 client = (PKIX_PL_HttpDefaultClient *)session;
1149
1150 /* XXX Not implemented */
1151
1152 cleanup:
1153
1154 PKIX_RETURN(HTTPDEFAULTCLIENT);
1155
1156 }
1157
1158 PKIX_Error *
1159 pkix_pl_HttpDefaultClient_RequestCreate(
1160 SEC_HTTP_SERVER_SESSION session,
1161 const char *http_protocol_variant, /* usually "http" */
1162 const char *path_and_query_string,
1163 const char *http_request_method,
1164 const PRIntervalTime timeout,
1165 SEC_HTTP_REQUEST_SESSION *pRequest,
1166 void *plContext)
1167 {
1168 PKIX_PL_HttpDefaultClient *client = NULL;
1169 PKIX_PL_Socket *socket = NULL;
1170 PKIX_PL_Socket_Callback *callbackList = NULL;
1171 PRFileDesc *fileDesc = NULL;
1172 PRErrorCode status = 0;
1173
1174 PKIX_ENTER
1175 (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RequestCreate");
1176 PKIX_NULLCHECK_TWO(session, pRequest);
1177
1178 PKIX_CHECK(pkix_CheckType
1179 ((PKIX_PL_Object *)session,
1180 PKIX_HTTPDEFAULTCLIENT_TYPE,
1181 plContext),
1182 PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
1183
1184 client = (PKIX_PL_HttpDefaultClient *)session;
1185
1186 /* We only know how to do http */
1187 if (PORT_Strncasecmp(http_protocol_variant, "http", 4) != 0) {
1188 PKIX_ERROR(PKIX_UNRECOGNIZEDPROTOCOLREQUESTED);
1189 }
1190
1191 if (PORT_Strncasecmp(http_request_method, "POST", 4) == 0) {
1192 client->send_http_method = HTTP_POST_METHOD;
1193 } else if (PORT_Strncasecmp(http_request_method, "GET", 3) == 0) {
1194 client->send_http_method = HTTP_GET_METHOD;
1195 } else {
1196 /* We only know how to do POST and GET */
1197 PKIX_ERROR(PKIX_UNRECOGNIZEDREQUESTMETHOD);
1198 }
1199
1200 if (path_and_query_string) {
1201 /* "path_and_query_string" is a parsing result by CERT_GetURL
1202 * function that adds "end of line" to the value. OK to dup
1203 * the string. */
1204 client->path = PORT_Strdup(path_and_query_string);
1205 if (!client->path) {
1206 PKIX_ERROR(PKIX_ALLOCERROR);
1207 }
1208 }
1209
1210 client->timeout = timeout;
1211
1212 #if 0
1213 PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
1214 (timeout,
1215 "variation.red.iplanet.com", /* (char *)client->host, */
1216 2001, /* client->portnum, */
1217 &status,
1218 &socket,
1219 plContext),
1220 PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
1221 #else
1222 PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
1223 (timeout,
1224 (char *)client->host,
1225 client->portnum,
1226 &status,
1227 &socket,
1228 plContext),
1229 PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
1230 #endif
1231
1232 client->socket = socket;
1233
1234 PKIX_CHECK(pkix_pl_Socket_GetCallbackList
1235 (socket, &callbackList, plContext),
1236 PKIX_SOCKETGETCALLBACKLISTFAILED);
1237
1238 client->callbackList = (void *)callbackList;
1239
1240 PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc
1241 (socket, &fileDesc, plContext),
1242 PKIX_SOCKETGETPRFILEDESCFAILED);
1243
1244 client->pollDesc.fd = fileDesc;
1245 client->pollDesc.in_flags = 0;
1246 client->pollDesc.out_flags = 0;
1247
1248 client->send_http_data = NULL;
1249 client->send_http_data_len = 0;
1250 client->send_http_content_type = NULL;
1251
1252 client->connectStatus =
1253 ((status == 0) ? HTTP_CONNECTED : HTTP_CONNECT_PENDING);
1254
1255 /* Request object is the same object as Session object */
1256 PKIX_INCREF(client);
1257 *pRequest = client;
1258
1259 cleanup:
1260
1261 PKIX_RETURN(HTTPDEFAULTCLIENT);
1262
1263 }
1264
1265 PKIX_Error *
1266 pkix_pl_HttpDefaultClient_SetPostData(
1267 SEC_HTTP_REQUEST_SESSION request,
1268 const char *http_data,
1269 const PRUint32 http_data_len,
1270 const char *http_content_type,
1271 void *plContext)
1272 {
1273 PKIX_PL_HttpDefaultClient *client = NULL;
1274
1275 PKIX_ENTER
1276 (HTTPDEFAULTCLIENT,
1277 "pkix_pl_HttpDefaultClient_SetPostData");
1278 PKIX_NULLCHECK_ONE(request);
1279
1280 PKIX_CHECK(pkix_CheckType
1281 ((PKIX_PL_Object *)request,
1282 PKIX_HTTPDEFAULTCLIENT_TYPE,
1283 plContext),
1284 PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
1285
1286 client = (PKIX_PL_HttpDefaultClient *)request;
1287
1288 client->send_http_data = http_data;
1289 client->send_http_data_len = http_data_len;
1290 client->send_http_content_type = http_content_type;
1291
1292 /* Caller is allowed to give NULL or empty string for content_type */
1293 if ((client->send_http_content_type == NULL) ||
1294 (*(client->send_http_content_type) == '\0')) {
1295 client->send_http_content_type = "application/ocsp-request";
1296 }
1297
1298 cleanup:
1299
1300 PKIX_RETURN(HTTPDEFAULTCLIENT);
1301
1302 }
1303
1304 PKIX_Error *
1305 pkix_pl_HttpDefaultClient_TrySendAndReceive(
1306 SEC_HTTP_REQUEST_SESSION request,
1307 PRUint16 *http_response_code,
1308 const char **http_response_content_type,
1309 const char **http_response_headers,
1310 const char **http_response_data,
1311 PRUint32 *http_response_data_len,
1312 PRPollDesc **pPollDesc,
1313 SECStatus *pSECReturn,
1314 void *plContext)
1315 {
1316 PKIX_PL_HttpDefaultClient *client = NULL;
1317 PKIX_UInt32 postLen = 0;
1318 PRPollDesc *pollDesc = NULL;
1319 char *sendbuf = NULL;
1320 char portstr[16];
1321
1322 PKIX_ENTER
1323 (HTTPDEFAULTCLIENT,
1324 "pkix_pl_HttpDefaultClient_TrySendAndReceive");
1325
1326 PKIX_NULLCHECK_ONE(request);
1327
1328 PKIX_CHECK(pkix_CheckType
1329 ((PKIX_PL_Object *)request,
1330 PKIX_HTTPDEFAULTCLIENT_TYPE,
1331 plContext),
1332 PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
1333
1334 client = (PKIX_PL_HttpDefaultClient *)request;
1335
1336 if (!pPollDesc && client->timeout == 0) {
1337 PKIX_ERROR_FATAL(PKIX_NULLARGUMENT);
1338 }
1339
1340 if (pPollDesc) {
1341 pollDesc = *pPollDesc;
1342 }
1343
1344 /* if not continuing from an earlier WOULDBLOCK return... */
1345 if (pollDesc == NULL) {
1346
1347 if (!((client->connectStatus == HTTP_CONNECTED) ||
1348 (client->connectStatus == HTTP_CONNECT_PENDING))) {
1349 PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
1350 }
1351
1352 /* Did caller provide a value for response length? */
1353 if (http_response_data_len != NULL) {
1354 client->pRcv_http_data_len = http_response_data_len;
1355 client->maxResponseLen = *http_response_data_len;
1356 }
1357
1358 client->rcv_http_response_code = http_response_code;
1359 client->rcv_http_content_type = http_response_content_type;
1360 client->rcv_http_headers = http_response_headers;
1361 client->rcv_http_data = http_response_data;
1362
1363 /* prepare the message */
1364 portstr[0] = '\0';
1365 if (client->portnum != 80) {
1366 PR_snprintf(portstr, sizeof(portstr), ":%d",
1367 client->portnum);
1368 }
1369
1370 if (client->send_http_method == HTTP_POST_METHOD) {
1371 sendbuf = PR_smprintf
1372 ("POST %s HTTP/1.0\r\nHost: %s%s\r\n"
1373 "Content-Type: %s\r\nContent-Length: %u\r\n\r\n",
1374 client->path,
1375 client->host,
1376 portstr,
1377 client->send_http_content_type,
1378 client->send_http_data_len);
1379 postLen = PORT_Strlen(sendbuf);
1380
1381 client->POSTLen = postLen + client->send_http_data_len;
1382
1383 /* allocate postBuffer big enough for header + data */
1384 PKIX_CHECK(PKIX_PL_Malloc
1385 (client->POSTLen,
1386 (void **)&(client->POSTBuf),
1387 plContext),
1388 PKIX_MALLOCFAILED);
1389
1390 /* copy header into postBuffer */
1391 PORT_Memcpy(client->POSTBuf, sendbuf, postLen);
1392
1393 /* append data after header */
1394 PORT_Memcpy(&client->POSTBuf[postLen],
1395 client->send_http_data,
1396 client->send_http_data_len);
1397
1398 /* PR_smprintf_free original header buffer */
1399 PR_smprintf_free(sendbuf);
1400 sendbuf = NULL;
1401
1402 } else if (client->send_http_method == HTTP_GET_METHOD) {
1403 client->GETBuf = PR_smprintf
1404 ("GET %s HTTP/1.0\r\nHost: %s%s\r\n\r\n",
1405 client->path,
1406 client->host,
1407 portstr);
1408 client->GETLen = PORT_Strlen(client->GETBuf);
1409 }
1410
1411 }
1412
1413 /* continue according to state */
1414 PKIX_CHECK(pkix_pl_HttpDefaultClient_Dispatch(client, plContext),
1415 PKIX_HTTPDEFAULTCLIENTDISPATCHFAILED);
1416
1417 switch (client->connectStatus) {
1418 case HTTP_CONNECT_PENDING:
1419 case HTTP_SEND_PENDING:
1420 case HTTP_RECV_HDR_PENDING:
1421 case HTTP_RECV_BODY_PENDING:
1422 pollDesc = &(client->pollDesc);
1423 *pSECReturn = SECWouldBlock;
1424 break;
1425 case HTTP_ERROR:
1426 /* Did caller provide a pointer for length? */
1427 if (client->pRcv_http_data_len != NULL) {
1428 /* Was error "response too big?" */
1429 if (client->rcv_http_data_len !=
1430 HTTP_UNKNOWN_CONTENT_LENGTH &&
1431 client->maxResponseLen >=
1432 client->rcv_http_data_len) {
1433 /* Yes, report needed space */
1434 *(client->pRcv_http_data_len) =
1435 client->rcv_http_data_len;
1436 } else {
1437 /* No, report problem other than size */
1438 *(client->pRcv_http_data_len) = 0;
1439 }
1440 }
1441
1442 pollDesc = NULL;
1443 *pSECReturn = SECFailure;
1444 break;
1445 case HTTP_COMPLETE:
1446 *(client->rcv_http_response_code) =
1447 client->responseCode;
1448 if (client->pRcv_http_data_len != NULL) {
1449 *http_response_data_len =
1450 client->rcv_http_data_len;
1451 }
1452 if (client->rcv_http_data != NULL) {
1453 *(client->rcv_http_data) = client->rcvBuf;
1454 }
1455 pollDesc = NULL;
1456 *pSECReturn = SECSuccess;
1457 break;
1458 case HTTP_NOT_CONNECTED:
1459 case HTTP_CONNECTED:
1460 case HTTP_RECV_HDR:
1461 case HTTP_RECV_BODY:
1462 default:
1463 pollDesc = NULL;
1464 *pSECReturn = SECFailure;
1465 PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
1466 break;
1467 }
1468
1469 if (pPollDesc) {
1470 *pPollDesc = pollDesc;
1471 }
1472
1473 cleanup:
1474 if (sendbuf) {
1475 PR_smprintf_free(sendbuf);
1476 }
1477
1478 PKIX_RETURN(HTTPDEFAULTCLIENT);
1479
1480 }
1481
1482 PKIX_Error *
1483 pkix_pl_HttpDefaultClient_Cancel(
1484 SEC_HTTP_REQUEST_SESSION request,
1485 void *plContext)
1486 {
1487 PKIX_PL_HttpDefaultClient *client = NULL;
1488
1489 PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Cancel");
1490 PKIX_NULLCHECK_ONE(request);
1491
1492 PKIX_CHECK(pkix_CheckType
1493 ((PKIX_PL_Object *)request,
1494 PKIX_HTTPDEFAULTCLIENT_TYPE,
1495 plContext),
1496 PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
1497
1498 client = (PKIX_PL_HttpDefaultClient *)request;
1499
1500 /* XXX Not implemented */
1501
1502 cleanup:
1503
1504 PKIX_RETURN(HTTPDEFAULTCLIENT);
1505
1506 }
1507
1508 SECStatus
1509 pkix_pl_HttpDefaultClient_CreateSessionFcn(
1510 const char *host,
1511 PRUint16 portnum,
1512 SEC_HTTP_SERVER_SESSION *pSession)
1513 {
1514 PKIX_Error *err = pkix_pl_HttpDefaultClient_CreateSession
1515 (host, portnum, pSession, plContext);
1516
1517 if (err) {
1518 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
1519 return SECFailure;
1520 }
1521 return SECSuccess;
1522 }
1523
1524 SECStatus
1525 pkix_pl_HttpDefaultClient_KeepAliveSessionFcn(
1526 SEC_HTTP_SERVER_SESSION session,
1527 PRPollDesc **pPollDesc)
1528 {
1529 PKIX_Error *err = pkix_pl_HttpDefaultClient_KeepAliveSession
1530 (session, pPollDesc, plContext);
1531
1532 if (err) {
1533 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
1534 return SECFailure;
1535 }
1536 return SECSuccess;
1537 }
1538
1539 SECStatus
1540 pkix_pl_HttpDefaultClient_FreeSessionFcn(
1541 SEC_HTTP_SERVER_SESSION session)
1542 {
1543 PKIX_Error *err =
1544 PKIX_PL_Object_DecRef((PKIX_PL_Object *)(session), plContext);
1545
1546 if (err) {
1547 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
1548 return SECFailure;
1549 }
1550 return SECSuccess;
1551 }
1552
1553 SECStatus
1554 pkix_pl_HttpDefaultClient_RequestCreateFcn(
1555 SEC_HTTP_SERVER_SESSION session,
1556 const char *http_protocol_variant, /* usually "http" */
1557 const char *path_and_query_string,
1558 const char *http_request_method,
1559 const PRIntervalTime timeout,
1560 SEC_HTTP_REQUEST_SESSION *pRequest)
1561 {
1562 PKIX_Error *err = pkix_pl_HttpDefaultClient_RequestCreate
1563 (session,
1564 http_protocol_variant,
1565 path_and_query_string,
1566 http_request_method,
1567 timeout,
1568 pRequest,
1569 plContext);
1570
1571 if (err) {
1572 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
1573 return SECFailure;
1574 }
1575 return SECSuccess;
1576 }
1577
1578 SECStatus
1579 pkix_pl_HttpDefaultClient_SetPostDataFcn(
1580 SEC_HTTP_REQUEST_SESSION request,
1581 const char *http_data,
1582 const PRUint32 http_data_len,
1583 const char *http_content_type)
1584 {
1585 PKIX_Error *err =
1586 pkix_pl_HttpDefaultClient_SetPostData(request, http_data,
1587 http_data_len,
1588 http_content_type,
1589 plContext);
1590 if (err) {
1591 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
1592 return SECFailure;
1593 }
1594 return SECSuccess;
1595 }
1596
1597 SECStatus
1598 pkix_pl_HttpDefaultClient_AddHeaderFcn(
1599 SEC_HTTP_REQUEST_SESSION request,
1600 const char *http_header_name,
1601 const char *http_header_value)
1602 {
1603 /* Not supported */
1604 return SECFailure;
1605 }
1606
1607 SECStatus
1608 pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn(
1609 SEC_HTTP_REQUEST_SESSION request,
1610 PRPollDesc **pPollDesc,
1611 PRUint16 *http_response_code,
1612 const char **http_response_content_type,
1613 const char **http_response_headers,
1614 const char **http_response_data,
1615 PRUint32 *http_response_data_len)
1616 {
1617 SECStatus rv = SECFailure;
1618
1619 PKIX_Error *err = pkix_pl_HttpDefaultClient_TrySendAndReceive
1620 (request,
1621 http_response_code,
1622 http_response_content_type,
1623 http_response_headers,
1624 http_response_data,
1625 http_response_data_len,
1626 pPollDesc,
1627 &rv,
1628 plContext);
1629
1630 if (err) {
1631 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
1632 return rv;
1633 }
1634 return SECSuccess;
1635 }
1636
1637 SECStatus
1638 pkix_pl_HttpDefaultClient_CancelFcn(
1639 SEC_HTTP_REQUEST_SESSION request)
1640 {
1641 PKIX_Error *err = pkix_pl_HttpDefaultClient_Cancel(request, plContext);
1642
1643 if (err) {
1644 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
1645 return SECFailure;
1646 }
1647 return SECSuccess;
1648 }
1649
1650 SECStatus
1651 pkix_pl_HttpDefaultClient_FreeFcn(
1652 SEC_HTTP_REQUEST_SESSION request)
1653 {
1654 PKIX_Error *err =
1655 PKIX_PL_Object_DecRef((PKIX_PL_Object *)(request), plContext);
1656
1657 if (err) {
1658 PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
1659 return SECFailure;
1660 }
1661 return SECSuccess;
1662 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)