nsresult xptiInterfaceEntry::GetTypeForParam(uint16 methodIndex, const nsXPTParamInfo* param, uint16 dimension, nsXPTType* type) { if(!EnsureResolved()) return NS_ERROR_UNEXPECTED; if(methodIndex < mMethodBaseIndex) return mParent-> GetTypeForParam(methodIndex, param, dimension, type); if(methodIndex >= mMethodBaseIndex + mDescriptor->num_methods) { NS_ERROR("bad index"); return NS_ERROR_INVALID_ARG; } const XPTTypeDescriptor *td; if(dimension) { nsresult rv = GetTypeInArray(param, dimension, &td); if(NS_FAILED(rv)) return rv; } else td = ¶m->type; *type = nsXPTType(td->prefix); return NS_OK; }
// static JSBool XPCVariant::VariantDataToJS(XPCCallContext& ccx, nsIVariant* variant, JSObject* scope, nsresult* pErr, jsval* pJSVal) { // Get the type early because we might need to spoof it below. PRUint16 type; if(NS_FAILED(variant->GetDataType(&type))) return JS_FALSE; nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant); if(xpcvariant) { jsval realVal = xpcvariant->GetJSVal(); if(JSVAL_IS_PRIMITIVE(realVal) || type == nsIDataType::VTYPE_ARRAY || type == nsIDataType::VTYPE_ID) { // Not a JSObject (or is a JSArray or is a JSObject representing // an nsID),. // So, just pass through the underlying data. *pJSVal = realVal; return JS_TRUE; } // else, it's an object and we really need to double wrap it if we've // already decided that its 'natural' type is as some sort of interface. // We just fall through to the code below and let it do what it does. } // The nsIVariant is not a XPCVariant (or we act like it isn't). // So we extract the data and do the Right Thing. // We ASSUME that the variant implementation can do these conversions... nsXPTCVariant xpctvar; nsID iid; nsAutoString astring; nsCAutoString cString; nsUTF8String utf8String; PRUint32 size; xpctvar.flags = 0; JSBool success; switch(type) { case nsIDataType::VTYPE_INT8: case nsIDataType::VTYPE_INT16: case nsIDataType::VTYPE_INT32: case nsIDataType::VTYPE_INT64: case nsIDataType::VTYPE_UINT8: case nsIDataType::VTYPE_UINT16: case nsIDataType::VTYPE_UINT32: case nsIDataType::VTYPE_UINT64: case nsIDataType::VTYPE_FLOAT: case nsIDataType::VTYPE_DOUBLE: { // Easy. Handle inline. if(NS_FAILED(variant->GetAsDouble(&xpctvar.val.d))) return JS_FALSE; return JS_NewNumberValue(ccx, xpctvar.val.d, pJSVal); } case nsIDataType::VTYPE_BOOL: { // Easy. Handle inline. if(NS_FAILED(variant->GetAsBool(&xpctvar.val.b))) return JS_FALSE; *pJSVal = BOOLEAN_TO_JSVAL(xpctvar.val.b); return JS_TRUE; } case nsIDataType::VTYPE_CHAR: if(NS_FAILED(variant->GetAsChar(&xpctvar.val.c))) return JS_FALSE; xpctvar.type = (uint8)TD_CHAR; break; case nsIDataType::VTYPE_WCHAR: if(NS_FAILED(variant->GetAsWChar(&xpctvar.val.wc))) return JS_FALSE; xpctvar.type = (uint8)TD_WCHAR; break; case nsIDataType::VTYPE_ID: if(NS_FAILED(variant->GetAsID(&iid))) return JS_FALSE; xpctvar.type = (uint8)(TD_PNSIID | XPT_TDP_POINTER); xpctvar.val.p = &iid; break; case nsIDataType::VTYPE_ASTRING: if(NS_FAILED(variant->GetAsAString(astring))) return JS_FALSE; xpctvar.type = (uint8)(TD_ASTRING | XPT_TDP_POINTER); xpctvar.val.p = &astring; break; case nsIDataType::VTYPE_DOMSTRING: if(NS_FAILED(variant->GetAsAString(astring))) return JS_FALSE; xpctvar.type = (uint8)(TD_DOMSTRING | XPT_TDP_POINTER); xpctvar.val.p = &astring; break; case nsIDataType::VTYPE_CSTRING: if(NS_FAILED(variant->GetAsACString(cString))) return JS_FALSE; xpctvar.type = (uint8)(TD_CSTRING | XPT_TDP_POINTER); xpctvar.val.p = &cString; break; case nsIDataType::VTYPE_UTF8STRING: if(NS_FAILED(variant->GetAsAUTF8String(utf8String))) return JS_FALSE; xpctvar.type = (uint8)(TD_UTF8STRING | XPT_TDP_POINTER); xpctvar.val.p = &utf8String; break; case nsIDataType::VTYPE_CHAR_STR: if(NS_FAILED(variant->GetAsString((char**)&xpctvar.val.p))) return JS_FALSE; xpctvar.type = (uint8)(TD_PSTRING | XPT_TDP_POINTER); xpctvar.SetValIsAllocated(); break; case nsIDataType::VTYPE_STRING_SIZE_IS: if(NS_FAILED(variant->GetAsStringWithSize(&size, (char**)&xpctvar.val.p))) return JS_FALSE; xpctvar.type = (uint8)(TD_PSTRING_SIZE_IS | XPT_TDP_POINTER); break; case nsIDataType::VTYPE_WCHAR_STR: if(NS_FAILED(variant->GetAsWString((PRUnichar**)&xpctvar.val.p))) return JS_FALSE; xpctvar.type = (uint8)(TD_PWSTRING | XPT_TDP_POINTER); xpctvar.SetValIsAllocated(); break; case nsIDataType::VTYPE_WSTRING_SIZE_IS: if(NS_FAILED(variant->GetAsWStringWithSize(&size, (PRUnichar**)&xpctvar.val.p))) return JS_FALSE; xpctvar.type = (uint8)(TD_PWSTRING_SIZE_IS | XPT_TDP_POINTER); break; case nsIDataType::VTYPE_INTERFACE: case nsIDataType::VTYPE_INTERFACE_IS: { nsID* piid; if(NS_FAILED(variant->GetAsInterface(&piid, &xpctvar.val.p))) return JS_FALSE; iid = *piid; nsMemory::Free((char*)piid); xpctvar.type = (uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER); if(xpctvar.val.p) xpctvar.SetValIsInterface(); break; } case nsIDataType::VTYPE_ARRAY: { nsDiscriminatedUnion du; nsVariant::Initialize(&du); nsresult rv; rv = variant->GetAsArray(&du.u.array.mArrayType, &du.u.array.mArrayInterfaceID, &du.u.array.mArrayCount, &du.u.array.mArrayValue); if(NS_FAILED(rv)) return JS_FALSE; // must exit via VARIANT_DONE from here on... du.mType = nsIDataType::VTYPE_ARRAY; success = JS_FALSE; nsXPTType conversionType; PRUint16 elementType = du.u.array.mArrayType; const nsID* pid = nsnull; switch(elementType) { case nsIDataType::VTYPE_INT8: case nsIDataType::VTYPE_INT16: case nsIDataType::VTYPE_INT32: case nsIDataType::VTYPE_INT64: case nsIDataType::VTYPE_UINT8: case nsIDataType::VTYPE_UINT16: case nsIDataType::VTYPE_UINT32: case nsIDataType::VTYPE_UINT64: case nsIDataType::VTYPE_FLOAT: case nsIDataType::VTYPE_DOUBLE: case nsIDataType::VTYPE_BOOL: case nsIDataType::VTYPE_CHAR: case nsIDataType::VTYPE_WCHAR: conversionType = nsXPTType((uint8)elementType); break; case nsIDataType::VTYPE_ID: case nsIDataType::VTYPE_CHAR_STR: case nsIDataType::VTYPE_WCHAR_STR: conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER); break; case nsIDataType::VTYPE_INTERFACE: pid = &NS_GET_IID(nsISupports); conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER); break; case nsIDataType::VTYPE_INTERFACE_IS: pid = &du.u.array.mArrayInterfaceID; conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER); break; // The rest are illegal. case nsIDataType::VTYPE_VOID: case nsIDataType::VTYPE_ASTRING: case nsIDataType::VTYPE_DOMSTRING: case nsIDataType::VTYPE_CSTRING: case nsIDataType::VTYPE_UTF8STRING: case nsIDataType::VTYPE_WSTRING_SIZE_IS: case nsIDataType::VTYPE_STRING_SIZE_IS: case nsIDataType::VTYPE_ARRAY: case nsIDataType::VTYPE_EMPTY_ARRAY: case nsIDataType::VTYPE_EMPTY: default: NS_ERROR("bad type in array!"); goto VARIANT_DONE; } success = XPCConvert::NativeArray2JS(ccx, pJSVal, (const void**)&du.u.array.mArrayValue, conversionType, pid, du.u.array.mArrayCount, scope, pErr); VARIANT_DONE: nsVariant::Cleanup(&du); return success; } case nsIDataType::VTYPE_EMPTY_ARRAY: { JSObject* array = JS_NewArrayObject(ccx, 0, nsnull); if(!array) return JS_FALSE; *pJSVal = OBJECT_TO_JSVAL(array); return JS_TRUE; } case nsIDataType::VTYPE_VOID: case nsIDataType::VTYPE_EMPTY: *pJSVal = JSVAL_VOID; return JS_TRUE; default: NS_ERROR("bad type in variant!"); return JS_FALSE; } // If we are here then we need to convert the data in the xpctvar. if(xpctvar.type.TagPart() == TD_PSTRING_SIZE_IS || xpctvar.type.TagPart() == TD_PWSTRING_SIZE_IS) { success = XPCConvert::NativeStringWithSize2JS(ccx, pJSVal, (const void*)&xpctvar.val, xpctvar.type, size, pErr); } else { success = XPCConvert::NativeData2JS(ccx, pJSVal, (const void*)&xpctvar.val, xpctvar.type, &iid, scope, pErr); } if(xpctvar.IsValAllocated()) nsMemory::Free((char*)xpctvar.val.p); else if(xpctvar.IsValInterface()) ((nsISupports*)xpctvar.val.p)->Release(); return success; }
// static JSBool XPCArrayHomogenizer::GetTypeForArray(XPCCallContext& ccx, JSObject* array, jsuint length, nsXPTType* resultType, nsID* resultID) { Type state = tUnk; Type type; for(jsuint i = 0; i < length; i++) { jsval val; if(!JS_GetElement(ccx, array, i, &val)) return JS_FALSE; if(JSVAL_IS_INT(val)) type = tInt; else if(JSVAL_IS_DOUBLE(val)) type = tDbl; else if(JSVAL_IS_BOOLEAN(val)) type = tBool; else if(JSVAL_IS_VOID(val)) { state = tVar; break; } else if(JSVAL_IS_NULL(val)) type = tNull; else if(JSVAL_IS_STRING(val)) type = tStr; else { NS_ASSERTION(JSVAL_IS_OBJECT(val), "invalid type of jsval!"); JSObject* jsobj = JSVAL_TO_OBJECT(val); if(JS_IsArrayObject(ccx, jsobj)) type = tArr; else if(xpc_JSObjectIsID(ccx, jsobj)) type = tID; else type = tISup; } NS_ASSERTION(state != tErr, "bad state table!"); NS_ASSERTION(type != tErr, "bad type!"); NS_ASSERTION(type != tVar, "bad type!"); NS_ASSERTION(type != tUnk, "bad type!"); state = StateTable[state][type]; NS_ASSERTION(state != tErr, "bad state table!"); NS_ASSERTION(state != tUnk, "bad state table!"); if(state == tVar) break; } switch(state) { case tInt : *resultType = nsXPTType((uint8)TD_INT32); break; case tDbl : *resultType = nsXPTType((uint8)TD_DOUBLE); break; case tBool: *resultType = nsXPTType((uint8)TD_BOOL); break; case tStr : *resultType = nsXPTType((uint8)(TD_PWSTRING | XPT_TDP_POINTER)); break; case tID : *resultType = nsXPTType((uint8)(TD_PNSIID | XPT_TDP_POINTER)); break; case tISup: *resultType = nsXPTType((uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER)); *resultID = NS_GET_IID(nsISupports); break; case tNull: // FALL THROUGH case tVar : *resultType = nsXPTType((uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER)); *resultID = NS_GET_IID(nsIVariant); break; case tArr : // FALL THROUGH case tUnk : // FALL THROUGH case tErr : // FALL THROUGH default: NS_ERROR("bad state"); return JS_FALSE; } return JS_TRUE; }
/** * Asynchronous processing : * 1-> WSPProxy::CallMethod * 2 -> WSPCallContext::CallAsync * 3 -> nsSOAPCall::AsyncInvoke * 4 -> nsXXXSOAPTransport::AsyncCall * 5 -> nsIXMLHttpRequest::Send, nsXXXSOAPTransportCompletion::AddEventListener * ---- asynchronous ---- * 6 -> nsXXXSOAPTransportCompletion::HandleEvent * 7 -> WSPCallContext::HandleResponse, * WSPCallContext::CallCompletionListener * 8 -> nsSOAPBlock::SetSchemaType, nsSOAPBlock::GetValue * 9 -> nsSOAPEncoding::Decode, nsDefaultSOAPDecode::Decode * 10 -> WSPProxy::CallCompleted */ NS_IMETHODIMP WSPProxy::CallMethod(PRUint16 methodIndex, const XPTMethodDescriptor* info, nsXPTCMiniVariant* params) { nsresult rv; nsCOMPtr<nsIWebServiceCallContext> cc; nsCOMPtr<nsIWSDLBinding> binding; if (methodIndex < 3) { NS_ERROR("WSPProxy: bad method index"); return NS_ERROR_FAILURE; } // The first method in the interface for async callers is the // one to set the async listener if (mIsAsync && (methodIndex == 3)) { nsISupports* listener = static_cast<nsISupports*>(params[0].val.p); mAsyncListener = listener; return NS_OK; } PRUint32 methodOffset; if (mIsAsync) { methodOffset = 4; } else { methodOffset = 3; } nsCOMPtr<nsIWSDLOperation> operation; rv = mPort->GetOperation(methodIndex - methodOffset, getter_AddRefs(operation)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsIWSDLMessage> input; rv = operation->GetInput(getter_AddRefs(input)); if (NS_FAILED(rv)) { return rv; } // Create the call instance nsCOMPtr<nsISOAPCall> call = do_CreateInstance(NS_SOAPCALL_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsISOAPEncoding> encoding = do_CreateInstance(NS_SOAPENCODING_CONTRACTID, &rv); if (NS_FAILED(rv)) { return rv; } call->SetEncoding(encoding); // Get the method name and target object uri nsAutoString methodName, targetObjectURI; rv = operation->GetBinding(getter_AddRefs(binding)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsISOAPOperationBinding> operationBinding = do_QueryInterface(binding, &rv); if (NS_FAILED(rv)) { return rv; } nsAutoString soapAction; operationBinding->GetSoapAction(soapAction); call->SetActionURI(soapAction); PRUint16 style; operationBinding->GetStyle(&style); // If the style is RPC, find the method name and target object URI. // If it is document-style, these are both left blank. if (style == nsISOAPPortBinding::STYLE_RPC) { operation->GetName(methodName); rv = input->GetBinding(getter_AddRefs(binding)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsISOAPMessageBinding> messageBinding = do_QueryInterface(binding, &rv); if (NS_FAILED(rv)) { return rv; } messageBinding->GetNamespace(targetObjectURI); } // Set the transport URI rv = mPort->GetBinding(getter_AddRefs(binding)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsISOAPPortBinding> portBinding = do_QueryInterface(binding, &rv); if (NS_FAILED(rv)) { return rv; } nsAutoString address; portBinding->GetAddress(address); rv = call->SetTransportURI(address); if (NS_FAILED(rv)) { return rv; } PRUint16 version; portBinding->GetSoapVersion(&version); if (version == nsISOAPMessage::VERSION_UNKNOWN) { version = nsISOAPMessage::VERSION_1_1; } // Set up the parameters to the call PRUint32 i, partCount; input->GetPartCount(&partCount); PRUint32 maxParamIndex = info->num_args - 1; // Iterate through the parts to figure out how many are // body vs. header blocks nsCOMPtr<nsIWSDLPart> part; PRUint32 headerCount = 0, bodyCount = 0; for (i = 0; i < partCount; i++) { rv = input->GetPart(i, getter_AddRefs(part)); if (NS_FAILED(rv)) { return rv; } rv = part->GetBinding(getter_AddRefs(binding)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsISOAPPartBinding> partBinding = do_QueryInterface(binding, &rv); if (NS_FAILED(rv)) { return rv; } PRUint16 location; partBinding->GetLocation(&location); if (location == nsISOAPPartBinding::LOCATION_HEADER) { headerCount++; } else if (location == nsISOAPPartBinding::LOCATION_BODY) { bodyCount++; } } // Allocate parameter and header blocks nsISOAPParameter** bodyBlocks = nsnull; if (bodyCount) { bodyBlocks = static_cast<nsISOAPParameter**> (nsMemory::Alloc(bodyCount * sizeof(nsISOAPParameter*))); if (!bodyBlocks) { return NS_ERROR_OUT_OF_MEMORY; } for (i = 0; i < bodyCount; i++) { rv = CallCreateInstance(NS_SOAPPARAMETER_CONTRACTID, &bodyBlocks[i]); if (NS_FAILED(rv)) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, bodyBlocks); return rv; } } } nsISOAPHeaderBlock** headerBlocks = nsnull; if (headerCount) { headerBlocks = static_cast<nsISOAPHeaderBlock**> (nsMemory::Alloc(headerCount * sizeof(nsISOAPHeaderBlock*))); if (!headerBlocks) { if (bodyBlocks) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks); } return NS_ERROR_OUT_OF_MEMORY; } for (i = 0; i < headerCount; i++) { rv = CallCreateInstance(NS_SOAPHEADERBLOCK_CONTRACTID, &headerBlocks[i]); if (NS_FAILED(rv)) { if (bodyBlocks) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks); } NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(i, headerBlocks); return rv; } } } // Now iterate through the parameters and set up the parameter blocks PRUint32 bodyEntry = 0, headerEntry = 0, paramIndex = 0; for (i = 0; i < partCount; paramIndex++, i++) { input->GetPart(i, getter_AddRefs(part)); part->GetBinding(getter_AddRefs(binding)); nsCOMPtr<nsISOAPPartBinding> partBinding = do_QueryInterface(binding); PRUint16 location; partBinding->GetLocation(&location); nsCOMPtr<nsISOAPBlock> block; if (location == nsISOAPPartBinding::LOCATION_HEADER) { block = do_QueryInterface(headerBlocks[headerEntry++]); } else if (location == nsISOAPPartBinding::LOCATION_BODY) { block = do_QueryInterface(bodyBlocks[bodyEntry++]); } if (!block) { rv = NS_ERROR_FAILURE; goto call_method_end; } // Get the name, namespaceURI and type of the block based on // information from the WSDL part. If the schema component // associated with the part is an element, these values come // from the schema description of the element. If it is a // type, then the values are gathered from elsewhere. nsCOMPtr<nsISchemaComponent> schemaComponent; rv = part->GetSchemaComponent(getter_AddRefs(schemaComponent)); if (NS_FAILED(rv)) { goto call_method_end; } nsCOMPtr<nsISchemaType> type; nsAutoString blockName, blockNamespace; nsCOMPtr<nsISchemaElement> element = do_QueryInterface(schemaComponent); if (element) { rv = element->GetType(getter_AddRefs(type)); if (NS_FAILED(rv)) { goto call_method_end; } element->GetName(blockName); element->GetTargetNamespace(blockNamespace); } else { type = do_QueryInterface(schemaComponent); nsAutoString paramName; part->GetName(paramName); blockName.Assign(paramName); partBinding->GetNamespace(blockNamespace); } block->SetName(blockName); block->SetNamespaceURI(blockNamespace); block->SetSchemaType(type); nsAutoString encodingStyle; PRUint16 use; partBinding->GetUse(&use); // XXX Need a way to specify that a block should not be // encoded. if (use == nsISOAPPartBinding::USE_ENCODED) { partBinding->GetEncodingStyle(encodingStyle); if (!encodingStyle.IsEmpty()) { nsCOMPtr<nsISOAPEncoding> partEncoding; encoding->GetAssociatedEncoding(encodingStyle, PR_FALSE, getter_AddRefs(partEncoding)); block->SetEncoding(partEncoding); } } // Look ahead in the param info array to see if the current part has to be // treated as an array. If so then get the array length from the current // param and increment the param index. PRUint32 arrayLength; if (paramIndex < maxParamIndex && nsXPTType(info->params[paramIndex + 1].type.prefix).IsArray()) { arrayLength = params[paramIndex++].val.u32; } else { arrayLength = 0; } NS_ASSERTION(paramIndex <= maxParamIndex, "WSDL/IInfo param count mismatch"); const nsXPTParamInfo& paramInfo = info->params[paramIndex]; nsCOMPtr<nsIVariant> value; rv = ParameterToVariant(mPrimaryInterface, methodIndex, ¶mInfo, params[paramIndex], arrayLength, getter_AddRefs(value)); if (NS_FAILED(rv)) { goto call_method_end; } block->SetValue(value); } // Encode the parameters to the call rv = call->Encode(version, methodName, targetObjectURI, headerCount, headerBlocks, bodyCount, bodyBlocks); if (NS_FAILED(rv)) { goto call_method_end; } WSPCallContext* ccInst; ccInst = new WSPCallContext(this, call, methodName, operation); if (!ccInst) { rv = NS_ERROR_OUT_OF_MEMORY; goto call_method_end; } cc = ccInst; if (mIsAsync) { PRUint8 pcount; pcount = info->num_args; // There has to be at least one parameter - the retval. if (pcount == 0) { rv = NS_ERROR_FAILURE; goto call_method_end; } #ifdef DEBUG // The last one should be the retval. const nsXPTParamInfo& retParamInfo = info->params[pcount - 1]; if (!retParamInfo.IsRetval()) { rv = NS_ERROR_FAILURE; goto call_method_end; } // It should be an interface pointer const nsXPTType& retType = retParamInfo.GetType(); if (!retType.IsInterfacePointer()) { rv = NS_ERROR_FAILURE; goto call_method_end; } #endif nsIWebServiceCallContext** retval = static_cast<nsIWebServiceCallContext**>(params[pcount-1].val.p); if (!retval) { rv = NS_ERROR_FAILURE; goto call_method_end; } *retval = cc; NS_ADDREF(*retval); rv = ccInst->CallAsync(methodIndex, mAsyncListener); if (NS_FAILED(rv)) { goto call_method_end; } mPendingCalls.AppendObject(ccInst); } else { rv = ccInst->CallSync(methodIndex, params); } call_method_end: if (bodyBlocks) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(bodyCount, bodyBlocks); } if (headerBlocks) { NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(headerCount, headerBlocks); } return rv; }