Menu

#6 Attempt to read HTTP body when CIMError header is set

closed
None
5
2015-01-22
2011-10-07
No

I experienced a "hang" in a Python program that uses pywbem to perform an EnumerateClasses operation with no classname and deep inheritance turned on.

The version of pywbem is 0.7.0, with local changes that disable the local login processing which does not seem to work on Windows.
The OS platform is Windows XP Pro, the Python level is 2.7.0.

I first thought there is an issue with the large amount of response data (3.8MB in case of root/cimv2 of OpenPegasus), but debugging the problem revealed that the root cause seems to be that pywbem does not seem to properly handle HTTP response messages that contain a CIMError header but no HTTP body data.

Reproduction & analysis:

A scenario that triggers such a response with OpenPegasus is the EnumerateClasses operation with no classname, specified in Python as follows:

cliconn.EnumerateClasses(ClassName='',DeepInheritance=True,LocalOnly=True,IncludeQualifiers=True)

This leads to a HTTP request with the following body being sent to the CIMOM:

<?xml version="1.0" encoding="utf-8" ?>
<CIM CIMVERSION="2.0" DTDVERSION="2.0">
<MESSAGE ID="1001" PROTOCOLVERSION="1.0">
<SIMPLEREQ>
<IMETHODCALL NAME="EnumerateClasses">
<LOCALNAMESPACEPATH>
<NAMESPACE NAME="root"/>
<NAMESPACE NAME="PG_InterOp"/>
</LOCALNAMESPACEPATH>
<IPARAMVALUE NAME="ClassName"><CLASSNAME NAME=""/></IPARAMVALUE>
<IPARAMVALUE NAME="IncludeQualifiers"><VALUE>TRUE</VALUE></IPARAMVALUE>
<IPARAMVALUE NAME="DeepInheritance"><VALUE>TRUE</VALUE></IPARAMVALUE>
<IPARAMVALUE NAME="LocalOnly"><VALUE>TRUE</VALUE></IPARAMVALUE>
</IMETHODCALL>
</SIMPLEREQ>
</MESSAGE>
</CIM>

Note that the ClassName parameter is present, but specifies an empty string for the class name.

The HTTP response from OpenPegasus contains the following header fields (second one broken into two lines):

CIMError: request-not-valid
PGErrorDetail: PGS00616%3A%20Semantic%20error%20on%20line%202.%200PGS09610%3A%20
The%20CLASSNAME.NAME%20attribute%20value%20is%20not%20valid.

Using the CIMError header without an HTTP body is allowed (and even mandated) as per DSP0200 1.3.1, section 6.3.11 "CIMError":
"The CIMError header may be present in any HTTP response to a CIM message request that is not a CIM message response. It shall not be present in any CIM message response or in any CIM message request."

Just as a side discussion, this CIMError response is valid for this request, since:

a) DSP0201 2.3.1 states in section 5.1.1 "CIMName":

"The CIMName entity describes the name of a CIM element (class, instance, method, property, qualifier, or parameter). The value must be a legal CIM element name (DSP0004)."

This means an empty string for the class name is not allowed.

b) DSP0201 2.3.1 states in section 5.2.6.7 "IPARAMVALUE":

"The IPARAMVALUE element defines a single intrinsic method named parameter value. The absence of a subelement indicates that the parameter has the NULL value."

This means a NULL value for the ClassName operation parameter can be represented by an IPARAMVALUE element with no content.

c) DSP0200 1.3.1 sates in section 5.3.2.9 "EnumerateClasses":

Declaration of ClassName operation parameter:
[IN,OPTIONAL,NULL] <className> ClassName=NULL,

Description of what absence and NULL mean for the ClassName parameter:
"If the DeepInheritance input parameter is true, all subclasses of the specified class should be returned. If the ClassName input parameter is absent, this implies that all classes in the target namespace should be returned. If DeepInheritance is false, only immediate child subclasses are returned. If the ClassName input parameter is NULL, this implies that all base classes in the target namespace should be returned. This definition of DeepInheritance applies only to the EnumerateClasses and EnumerateClassName operations."

This description is a bit weird since it is not clear to me why it differentiates between absence and NULL. I'll bring that up in the DMTF CIM-XML WG.

Nevertheless, my interpretation is that the way to request the entire set of classes to be returned is with DeepInheritance=True and absence of ClassName, possibly with ClassName=NULL as an alternative.

The request shown above does not use any of these two alternatives, and is therefore invalid.

End of side discussion.

pywbem has the following code in wbem_request() in cim_http.py(223):

response = h.getresponse()
body = response.read()

As I see it, this attempts to do an unbounded read for HTTP body data (because of the missing content-length header field), which never arrives, so it waits forever in the socket receive.

Potential fix:

Test for presence of the CIMError header field in an HTTP response, before attempting to read HTTP body data.

Note that the EnumerateClasses() method caused the incorrect request to be sent by allowing its ClassName parameter to have a value of the empty string. I suggest that this does not get changed, since one might use pywbem also to drive such incorrect requests for testing purposes. Thus, the current very direct way of handling operation parameters is preferred and should not be "improved". With a fix to the "hang", raising the CIMError to the caller level would have revealed pretty much immediately that the ClassName parameter value was the culprit, so further improvement e.g. by testing and rejecting an empty value does not really make it better, it just removes the (useful) ability to drive incorrect requests for testing purposes.

Discussion

  • Andreas Maier

    Andreas Maier - 2014-07-29

    To fix this, I propose to move the reading of the HTTP body data (body = response.read())
    after the check for a successful response (if response.status != 200:).

    A patch for PyWBEM 0.7 is attached (not yet tested).

    -> All, please review.

     
  • Andreas Maier

    Andreas Maier - 2014-10-10
    • assigned_to: Andreas Maier
    • Group: --> v0.8.0
     
  • Andreas Maier

    Andreas Maier - 2015-01-16

    I have adjusted the patch listed above to the latest code level, and have committed it as r697.

     
  • Andreas Maier

    Andreas Maier - 2015-01-16
    • status: open --> open-fixed
     
  • Andreas Maier

    Andreas Maier - 2015-01-16
    • status: open-fixed --> closed
     
MongoDB Logo MongoDB