t_c@sdZddlZddlZddlZddlZddlmZmZmZddl m Z m Z ddl m Z mZmZmZejeZe ZdefdYZdZd Zd efd YZd efd YZdefdYZdefdYZdefdYZdefdYZdefdYZ de efdYZ!de efdYZ"defdYZ#defdYZ$d e$efd!YZ%d"e$efd#YZ&ied$6ed%6e#d&6e%d'6e&d(6Z'dS()sResponse parsers for the various protocol types. The module contains classes that can take an HTTP response, and given an output shape, parse the response into a dict according to the rules in the output shape. There are many similarities amongst the different protocols with regard to response parsing, and the code is structured in a way to avoid code duplication when possible. The diagram below is a diagram showing the inheritance hierarchy of the response classes. :: +--------------+ |ResponseParser| +--------------+ ^ ^ ^ +--------------------+ | +-------------------+ | | | +----------+----------+ +------+-------+ +-------+------+ |BaseXMLResponseParser| |BaseRestParser| |BaseJSONParser| +---------------------+ +--------------+ +--------------+ ^ ^ ^ ^ ^ ^ | | | | | | | | | | | | | ++----------+-+ +-+-----------++ | | |RestXMLParser| |RestJSONParser| | +-----+-----+ +-------------+ +--------------+ +----+-----+ |QueryParser| |JSONParser| +-----------+ +----------+ The diagram above shows that there is a base class, ``ResponseParser`` that contains logic that is similar amongst all the different protocols (``query``, ``json``, ``rest-json``, ``rest-xml``). Amongst the various services there is shared logic that can be grouped several ways: * The ``query`` and ``rest-xml`` both have XML bodies that are parsed in the same way. * The ``json`` and ``rest-json`` protocols both have JSON bodies that are parsed in the same way. * The ``rest-json`` and ``rest-xml`` protocols have additional attributes besides body parameters that are parsed the same (headers, query string, status code). This is reflected in the class diagram above. The ``BaseXMLResponseParser`` and the BaseJSONParser contain logic for parsing the XML/JSON body, and the BaseRestParser contains logic for parsing out attributes that come from other parts of the HTTP response. Classes like the ``RestXMLParser`` inherit from the ``BaseXMLResponseParser`` to get the XML body parsing logic and the ``BaseRestParser`` to get the HTTP header/status code/query string parsing. Additionally, there are event stream parsers that are used by the other parsers to wrap streaming bodies that represent a stream of events. The BaseEventStreamParser extends from ResponseParser and defines the logic for parsing values from the headers and payload of a message from the underlying binary encoding protocol. Currently, event streams support parsing bodies encoded as JSON and XML through the following hierarchy. +--------------+ |ResponseParser| +--------------+ ^ ^ ^ +--------------------+ | +------------------+ | | | +----------+----------+ +----------+----------+ +-------+------+ |BaseXMLResponseParser| |BaseEventStreamParser| |BaseJSONParser| +---------------------+ +---------------------+ +--------------+ ^ ^ ^ ^ | | | | | | | | +-+----------------+-+ +-+-----------------+-+ |EventStreamXMLParser| |EventStreamJSONParser| +--------------------+ +---------------------+ Return Values ============= Each call to ``parse()`` returns a dict has this form:: Standard Response { "ResponseMetadata": {"RequestId": } } Error response { "ResponseMetadata": {"RequestId": } "Error": { "Code": , "Message": , "Type": , } } iN(tsixtETreet XMLParseError(t EventStreamtNoInitialResponseError(tparse_timestampt merge_dictstis_json_value_headertlowercase_dicttResponseParserFactorycBs#eZdZdZdZRS(cCs i|_dS(N(t _defaults(tself((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt__init__scKs|jj|dS(sOSet default arguments when a parser instance is created. You can specify any kwargs that are allowed by a ResponseParser class. There are currently two arguments: * timestamp_parser - A callable that can parse a timetsamp string * blob_parser - A callable that can parse a blob type N(R tupdate(R tkwargs((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pytset_parser_defaultss cCst|}||jS(N(tPROTOCOL_PARSERSR (R t protocol_namet parser_cls((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt create_parsers (t__name__t __module__R RR(((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR s  cCstj|S(N(R R(tprotocol((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyRscsfd}|S(NcsFt|dr0|j}|dkr6d}q6n|}|||S(Nttextt(thasattrRtNone(R tshapetnode_or_stringR(tfunc(s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt_get_text_contents    ((RR((Rs;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt _text_contents tResponseParserErrorcBseZRS((RR(((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR stResponseParsercBseZdZdZdZdddZdZdZdZ dZ dZ dZ d Z d Zd Zd Zd ZdZRS(soBase class for response parsing. This class represents the interface that all ResponseParsers for the various protocols must implement. This class will take an HTTP response and a model shape and parse the HTTP response into a dictionary. There is a single public method exposed: ``parse``. See the ``parse`` docstring for more info. sutf-8cCss|dkrt}n||_|dkr6|j}n||_d|_|jdk ro|j|||_ndS(N(RtDEFAULT_TIMESTAMP_PARSERt_timestamp_parsert_default_blob_parsert _blob_parsert_event_stream_parsertEVENT_STREAM_PARSER_CLS(R ttimestamp_parsert blob_parser((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR s       cCs tj|S(N(tbase64t b64decode(R tvalue((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR$scCstjd|dtjd|d|ddkr|j|rY|j|}q|j|r~|j||}|S|j||}n|j||}|r|jj dr|St |t r|j di}|d|d <|d}t ||d <||dParse the HTTP response given a shape. :param response: The HTTP response dictionary. This is a dictionary that represents the HTTP request. The dictionary must have the following keys, ``body``, ``headers``, and ``status_code``. :param shape: The model shape describing the expected output. :return: Returns a dictionary representing the parsed response described by the model. In addition to the shape described from the model, each response will also have a ``ResponseMetadata`` which contains metadata about the response, which contains at least two keys containing ``RequestId`` and ``HTTPStatusCode``. Some responses may populate additional keys, but ``RequestId`` will always be present. sResponse headers: %stheaderssResponse body: %stbodyt status_codei-t eventstreamtResponseMetadatatHTTPStatusCodet HTTPHeaders( tLOGtdebugt_is_generic_error_responset_do_generic_error_parset_is_modeled_error_shapet_do_modeled_error_parset_do_error_parset _do_parset serializationtgett isinstancetdictR(R tresponseRtparsedtresponse_metadataR-((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pytparses&  cCs|dk o|jjdtS(Nt exception(RtmetadataR=tFalse(R R((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR8scCsX|ddkrTd|ks,|ddkr0tS|dj}|jdpS| SdS(NR/iR.s(RtTruetstript startswith(R R@R.((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR6 s cCsPtjdiit|dd6tjjjj|ddd6d6id6S(NslReceived a non protocol specific error response from the service, unable to populate error code and message.R/tCodeRtMessagetErrorR1(R4R5tstrRtmovest http_clientt responsesR=(R R@((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR7s  cCstd|jjdS(Ns %s._do_parse(tNotImplementedErrort __class__R(R R@R((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR;*scCstd|jjdS(Ns%s._do_error_parse(RQRRR(R R@R((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR:-scCstd|jjdS(Ns%s._do_modeled_error_parse(RQRRR(R R@RRA((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR91scCs)t|d|j|j}|||S(Ns _handle_%s(tgetattrt type_namet_default_handle(R Rtnodethandler((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt _parse_shape5s cCs=g}|j}x'|D]}|j|j||qW|S(N(tmembertappendRX(R RRVRAt member_shapetitem((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt _handle_list:s   cCs|S(N((R RR,((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyRUCscCs3|j}|djd}t|d|||S(Ntcontexttoperation_nameR.(R&R=R(R R@Rtparsertname((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt_create_event_streamFs N(RRt__doc__tDEFAULT_ENCODINGRR'R R$RCR8R6R7R;R:R9RXR]RURb(((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR!s    0       tBaseXMLResponseParsercBseZdddZdZdZdZdZdZdZ dZ dZ d Z e d Ze d Ze d Ze d Ze dZe dZeZeZeZRS(cCs/tt|j||tjd|_dS(Ns{.*}(tsuperReR tretcompilet _namespace_re(R R(R)((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR Msc Csi}|j}|j}|jjdp-d}|jjdpEd}|jjdrvt|t rv|g}nx|D]}xo|D]g} |j| } | |kr|j|| } q| |kr|j|| } qtd| qW| || tlistt _node_tagRXR ( R RRVRAt key_shapet value_shapetkey_location_nametvalue_location_namet keyval_nodet single_pairttag_nametkey_nametval_name((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt _handle_mapRs"  "     cCs|jjd|jS(NR(Ritsubttag(R RV((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyRmgscCsG|jjdr.t|t r.|g}ntt|j||S(NRk(R<R=R>RlRfReR](R RRV((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyR]js" cCsfi}|j}|jjdtr6|j|}n|j|}x|D]}||}d|jksL|jjdrqLn|j||}|j|} | dk r|j || ||RlRRmRZ(R t parent_nodeRR\Rj((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyRs  cCsny>tjdtjd|j}|j||j}Wn)tk ri}td||fnX|S(NttargettencodingsTUnable to parse response (%s), invalid XML received. Further retries may succeed: %s(Rt XMLParsert TreeBuilderRdtfeedtcloseRR (R t xml_stringR`trootte((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyt_parse_xml_string_to_doms    cCs_xX|jD]J\}}t|rJ|j|}|j|||tbytesRRdRRXR ( R R@RRRtpayload_member_namet body_shapeR.RR((s;/opt/awscli/lib/python2.7/site-packages/botocore/parsers.pyRFs"     c Cs|d}x|D]}||}|jjd}|dkrEqq|dkrn|j||d||ts>    "  5%QN'kM