PKIX_Error *
pkix_pl_AIAMgr_GetHTTPCerts(
        PKIX_PL_AIAMgr *aiaMgr,
	PKIX_PL_InfoAccess *ia,
	void **pNBIOContext,
	PKIX_List **pCerts,
        void *plContext)
{
        PKIX_PL_GeneralName *location = NULL;
        PKIX_PL_String *locationString = NULL;
	PKIX_UInt32 len = 0;
	PRUint16 port = 0;
	const SEC_HttpClientFcn *httpClient = NULL;
	const SEC_HttpClientFcnV1 *hcv1 = NULL;
	SECStatus rv = SECFailure;
	SEC_HTTP_SERVER_SESSION serverSession = NULL;
	SEC_HTTP_REQUEST_SESSION requestSession = NULL;	
	char *path = NULL;
	char *hostname = NULL;
	char *locationAscii = NULL;
	void *nbio = NULL;
	PRUint16 responseCode = 0;
	const char *responseContentType = NULL;
	const char *responseData = NULL;

        PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetHTTPCerts");
        PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);

        nbio = *pNBIOContext;
        *pNBIOContext = NULL;
        *pCerts = NULL;

        if (nbio == NULL) { /* a new request */

                PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
                        (ia, &location, plContext),
                       PKIX_INFOACCESSGETLOCATIONFAILED);

                /* find or create httpClient = default client */
		httpClient = SEC_GetRegisteredHttpClient();
		aiaMgr->client.hdata.httpClient = httpClient;
		if (!httpClient)
		    PKIX_ERROR(PKIX_OUTOFMEMORY);

		if (httpClient->version == 1) {

                        PKIX_UInt32 timeout =
                             ((PKIX_PL_NssContext*)plContext)->timeoutSeconds;

			hcv1 = &(httpClient->fcnTable.ftable1);

			/* create server session */
			PKIX_TOSTRING(location, &locationString, plContext,
				PKIX_GENERALNAMETOSTRINGFAILED);

			PKIX_CHECK(PKIX_PL_String_GetEncoded
				(locationString,
				PKIX_ESCASCII,
				(void **)&locationAscii,
				&len,
				plContext),
				PKIX_STRINGGETENCODEDFAILED);

                        rv = CERT_ParseURL(locationAscii, &hostname, &port,
                                            &path);
			if ((rv != SECSuccess) ||
			    (hostname == NULL) ||
			    (path == NULL)) {
				PKIX_ERROR(PKIX_URLPARSINGFAILED);
			}

                        rv = (*hcv1->createSessionFcn)(hostname, port, 
                                                       &serverSession);
	                if (rv != SECSuccess) {
				PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED);
			}

			aiaMgr->client.hdata.serverSession = serverSession;

			/* create request session */
                        rv = (*hcv1->createFcn)(serverSession, "http", path,
                        	"GET", PR_SecondsToInterval(timeout),
                                 &requestSession);
                	if (rv != SECSuccess) {
                        	PKIX_ERROR(PKIX_HTTPSERVERERROR);
                	}

			aiaMgr->client.hdata.requestSession = requestSession;
		} else {
			PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
		}
	}

	httpClient = aiaMgr->client.hdata.httpClient;

	if (httpClient->version == 1) {
                PRUint32 responseDataLen = 
                   ((PKIX_PL_NssContext*)plContext)->maxResponseLength;

		hcv1 = &(httpClient->fcnTable.ftable1);
		requestSession = aiaMgr->client.hdata.requestSession;

		/* trySendAndReceive */
                rv = (*hcv1->trySendAndReceiveFcn)(requestSession,
                                 (PRPollDesc **)&nbio,
                                 &responseCode,
                                 (const char **)&responseContentType,
                                 NULL, /* &responseHeaders */
                                 (const char **)&responseData,
                                 &responseDataLen);

                if (rv != SECSuccess) {
                        PKIX_ERROR(PKIX_HTTPSERVERERROR);
                }

                if (nbio != 0) {
                        *pNBIOContext = nbio;
                        goto cleanup;
                }

		PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
	                (responseCode,
	                responseContentType,
	                responseData,
	                responseDataLen,
	                pCerts,
	                plContext),
	                PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED);
                
                /* Session and request cleanup in case of success */
                if (aiaMgr->client.hdata.requestSession != NULL) {
                    (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
                    aiaMgr->client.hdata.requestSession = NULL;
                }
                if (aiaMgr->client.hdata.serverSession != NULL) {
                    (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
                    aiaMgr->client.hdata.serverSession = NULL;
                }
                aiaMgr->client.hdata.httpClient = 0; /* callback fn */

        } else  {
		PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
	}

cleanup:
        /* Session and request cleanup in case of error. Passing through without cleanup
         * if interrupted by blocked IO. */
        if (PKIX_ERROR_RECEIVED && aiaMgr) {
            if (aiaMgr->client.hdata.requestSession != NULL) {
                (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
                aiaMgr->client.hdata.requestSession = NULL;
            }
            if (aiaMgr->client.hdata.serverSession != NULL) {
                (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
                aiaMgr->client.hdata.serverSession = NULL;
            }
            aiaMgr->client.hdata.httpClient = 0; /* callback fn */
        }

        PKIX_DECREF(location);
        PKIX_DECREF(locationString);

        if (locationAscii) {
            PORT_Free(locationAscii);
        }
        if (hostname) {
            PORT_Free(hostname);
        }
        if (path) {
            PORT_Free(path);
        }

        PKIX_RETURN(AIAMGR);
}
PKIX_Error *
pkix_pl_AIAMgr_GetLDAPCerts(
        PKIX_PL_AIAMgr *aiaMgr,
	PKIX_PL_InfoAccess *ia,
	void **pNBIOContext,
	PKIX_List **pCerts,
        void *plContext)
{
        PKIX_List *result = NULL;
        PKIX_PL_GeneralName *location = NULL;
        PKIX_PL_LdapClient *client = NULL;
        LDAPRequestParams request;
        PLArenaPool *arena = NULL;
        char *domainName = NULL;
	void *nbio = NULL;

        PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetLDAPCerts");
        PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);

        nbio = *pNBIOContext;
        *pNBIOContext = NULL;
        *pCerts = NULL;

        if (nbio == NULL) { /* a new request */

                /* Initiate an LDAP request */

                request.scope = WHOLE_SUBTREE;
                request.derefAliases = NEVER_DEREF;
                request.sizeLimit = 0;
                request.timeLimit = 0;

                PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
                        (ia, &location, plContext),
                        PKIX_INFOACCESSGETLOCATIONFAILED);

                /*
                 * Get a short-lived arena. We'll be done with
                 * this space once the request is encoded.
                 */
                arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
                if (!arena) {
                        PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
                }

                PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation
                        (location, arena, &request, &domainName, plContext),
                        PKIX_INFOACCESSPARSELOCATIONFAILED);

                PKIX_DECREF(location);

                /* Find or create a connection to LDAP server */
                PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient
                        (aiaMgr, domainName, &client, plContext),
                        PKIX_AIAMGRFINDLDAPCLIENTFAILED);

                aiaMgr->client.ldapClient = client;

                PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
                        (aiaMgr->client.ldapClient,
			&request,
			&nbio,
			&result,
			plContext),
                        PKIX_LDAPCLIENTINITIATEREQUESTFAILED);

                PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));

        } else {

                PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
                        (aiaMgr->client.ldapClient, &nbio, &result, plContext),
                        PKIX_LDAPCLIENTRESUMEREQUESTFAILED);

        }

        if (nbio != NULL) { /* WOULDBLOCK */
                *pNBIOContext = nbio;
                *pCerts = NULL;
                goto cleanup;
        }

	PKIX_DECREF(aiaMgr->client.ldapClient);

	if (result == NULL) {
		*pCerts = NULL;
	} else {
		PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
			(result, pCerts, plContext),
			PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
	}

	*pNBIOContext = nbio;

cleanup:

        if (arena && (PKIX_ERROR_RECEIVED)) {
                PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
        }

        if (PKIX_ERROR_RECEIVED) {
	        PKIX_DECREF(aiaMgr->client.ldapClient);
	}

        PKIX_DECREF(location);

        PKIX_RETURN(AIAMGR);
}
int test_subjectinfoaccess(int argc, char *argv[]) {

        PKIX_PL_Cert *cert = NULL;
        PKIX_PL_Cert *certDiff = NULL;
        PKIX_List *aiaList = NULL;
        PKIX_List *siaList = NULL;
        PKIX_PL_InfoAccess *sia = NULL;
        PKIX_PL_InfoAccess *siaDup = NULL;
        PKIX_PL_InfoAccess *siaDiff = NULL;
        PKIX_PL_GeneralName *location = NULL;
        char *certPathName = NULL;
        char *dirName = NULL;
        PKIX_UInt32 method = 0;
        PKIX_UInt32 actualMinorVersion;
        PKIX_UInt32 size, i;
        PKIX_UInt32 j = 0;
        char *expectedAscii = "[method:caRepository, "
                "location:http://betty.nist.gov/pathdiscoverytestsuite/"
                "p7cfiles/IssuedByTrustAnchor1.p7c]";

        PKIX_TEST_STD_VARS();

        startTests("SubjectInfoAccess");

        PKIX_TEST_EXPECT_NO_ERROR(
            PKIX_PL_NssContext_Create(0, PKIX_FALSE, NULL, &plContext));

        if (argc < 5+j) {
                printf("Usage: %s <test-purpose> <cert> <diff-cert>\n", argv[0]);
        }

        dirName = argv[2+j];
        certPathName = argv[3+j];

        subTest("Creating Cert with Subject Info Access");
        cert = createCert(dirName, certPathName, plContext);

        certPathName = argv[4+j];

        subTest("Creating Cert with Subject Info Access");
        certDiff = createCert(dirName, certPathName, plContext);

        subTest("Getting Subject Info Access");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetSubjectInfoAccess
                (cert, &siaList, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetLength
                (siaList, &size, plContext));

        if (size != 1) {
                pkixTestErrorMsg = "unexpected number of AIA";
                goto cleanup;
        }
 
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem
                (siaList, 0, (PKIX_PL_Object **) &sia, plContext));

        subTest("PKIX_PL_InfoAccess_GetMethod");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_InfoAccess_GetMethod
                (sia, &method, plContext));
        if (method != PKIX_INFOACCESS_CA_REPOSITORY) {
                pkixTestErrorMsg = "unexpected method of AIA";
                goto cleanup;
        }

        subTest("PKIX_PL_InfoAccess_GetLocation");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_InfoAccess_GetLocation
                (sia, &location, plContext));
        if (!location) {
                pkixTestErrorMsg = "Cannot get AIA location";
                goto cleanup;
        }

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem
                (siaList, 0, (PKIX_PL_Object **) &siaDup, plContext));

        subTest("Getting Authority Info Access as difference comparison");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetAuthorityInfoAccess
                (certDiff, &aiaList, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetLength
                (aiaList, &size, plContext));

        if (size != 1) {
                pkixTestErrorMsg = "unexpected number of AIA";
                goto cleanup;
        }
 
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem
                (aiaList, 0, (PKIX_PL_Object **) &siaDiff, plContext));

        subTest("Checking: Equal, Hash and ToString");
        PKIX_TEST_EQ_HASH_TOSTR_DUP
                (sia, siaDup, siaDiff, expectedAscii, InfoAccess, PKIX_FALSE);



cleanup:

        PKIX_TEST_DECREF_AC(location);
        PKIX_TEST_DECREF_AC(sia);
        PKIX_TEST_DECREF_AC(siaDup);
        PKIX_TEST_DECREF_AC(siaDiff);
        PKIX_TEST_DECREF_AC(aiaList);
        PKIX_TEST_DECREF_AC(siaList);
        PKIX_TEST_DECREF_AC(cert);
        PKIX_TEST_DECREF_AC(certDiff);
     
        PKIX_Shutdown(plContext);

        PKIX_TEST_RETURN();

        endTests("Subjectinfoaccess");

        return (0);
}