static aclList parsePermissions(xmlNode *node, aclList policyList) {
    xmlNode *cur_node = node;
    policyPtr accessNode = null;
    if (cur_node && cur_node->type == XML_ELEMENT_NODE && !strcmp(cur_node->name, permissionsTagName)) {
        for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
            if (cur_node->type == XML_ELEMENT_NODE) {
                if (!strcmp(cur_node->name, allowTagName)) {
                    accessNode = parsePermission(cur_node, 1);
                    if (accessNode) {
                        insertAtBack(policyList, accessNode);
                    } else {
                        return null;
                    }
                } else if (!strcmp(cur_node->name, denyTagName)) {
                    accessNode = parsePermission(cur_node, 0);
                    if (accessNode) {
                        insertAtStart(policyList, accessNode);
                    } else {
                        return null;
                    }
                } else {
                    fprintf(stderr, "\nInvalid Element:%s\n", cur_node->name);
                }

            }
        }
    } else {
        fprintf(stderr, "Expected element : %s, as root node but found:%s", permissionsTagName, cur_node->name);
    }
    return policyList;
}
ScriptPromise Permissions::revoke(ScriptState* scriptState, const Dictionary& rawPermission)
{
    WebPermissionClient* client = getClient(scriptState->getExecutionContext());
    if (!client)
        return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(InvalidStateError, "In its current state, the global scope can't revoke permissions."));

    ExceptionState exceptionState(ExceptionState::GetterContext,  "revoke", "Permissions", scriptState->context()->Global(), scriptState->isolate());
    Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermission, exceptionState);
    if (exceptionState.hadException())
        return exceptionState.reject(scriptState);

    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    client->revokePermission(type.get(), KURL(KURL(), scriptState->getExecutionContext()->getSecurityOrigin()->toString()), new PermissionCallback(resolver, type.get()));
    return promise;
}
ScriptPromise Permissions::query(ScriptState* scriptState, const Dictionary& rawPermission)
{
    WebPermissionClient* client = getClient(scriptState->getExecutionContext());
    if (!client)
        return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(InvalidStateError, "In its current state, the global scope can't query permissions."));

    ExceptionState exceptionState(ExceptionState::GetterContext,  "query", "Permissions", scriptState->context()->Global(), scriptState->isolate());
    Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermission, exceptionState);
    if (exceptionState.hadException())
        return exceptionState.reject(scriptState);

    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    // If the current origin is a file scheme, it will unlikely return a
    // meaningful value because most APIs are broken on file scheme and no
    // permission prompt will be shown even if the returned permission will most
    // likely be "prompt".
    client->queryPermission(type.get(), KURL(KURL(), scriptState->getExecutionContext()->getSecurityOrigin()->toString()), new PermissionCallback(resolver, type.get()));
    return promise;
}
ScriptPromise Permissions::requestAll(ScriptState* scriptState, const Vector<Dictionary>& rawPermissions)
{
    WebPermissionClient* client = getClient(scriptState->getExecutionContext());
    if (!client)
        return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(InvalidStateError, "In its current state, the global scope can't request permissions."));

    ExceptionState exceptionState(ExceptionState::GetterContext,  "request", "Permissions", scriptState->context()->Global(), scriptState->isolate());
    OwnPtr<Vector<WebPermissionType>> internalPermissions = adoptPtr(new Vector<WebPermissionType>());
    OwnPtr<Vector<int>> callerIndexToInternalIndex = adoptPtr(new Vector<int>(rawPermissions.size()));
    for (size_t i = 0; i < rawPermissions.size(); ++i) {
        const Dictionary& rawPermission = rawPermissions[i];

        Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermission, exceptionState);
        if (exceptionState.hadException())
            return exceptionState.reject(scriptState);

        // Only append permissions to the vector that is passed to the client if it is not already
        // in the vector (i.e. do not duplicate permisison types).
        int internalIndex;
        auto it = internalPermissions->find(type.get());
        if (it == kNotFound) {
            internalIndex = internalPermissions->size();
            internalPermissions->append(type.get());
        } else {
            internalIndex = it;
        }
        callerIndexToInternalIndex->operator[](i) = internalIndex;
    }

    ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    WebVector<WebPermissionType> internalWebPermissions = *internalPermissions;
    client->requestPermissions(internalWebPermissions, KURL(KURL(), scriptState->getExecutionContext()->getSecurityOrigin()->toString()),
        new PermissionsCallback(resolver, internalPermissions.release(), callerIndexToInternalIndex.release()));
    return promise;
}