ó
þ›	Nc           @   s`  d  Z  e Z d d g Z d d l Z d d l Z d d l Z d d l Z d d l m	 Z	 d d l
 m Z m Z m Z m Z d d l Z d d l m Z d d l Z d d l m Z d d	 l m Z d d
 l m Z d d l m Z m Z d d l m Z d d l
 m Z m Z m  Z  d „  Z! d e f d „  ƒ  YZ" d e f d „  ƒ  YZ# d d d „  ƒ  YZ$ d S(   sï   Browser object to make requests of lazr.restful web services.

The `Browser` class does some massage of HTTP requests and responses,
and handles custom caches. It is not part of the public
lazr.restfulclient API. (But maybe it should be?)
t   Browsert   RestfulHttpiÿÿÿÿN(   t   sleep(   t   FailedToDecompressContentt	   FileCachet   Httpt   urlnorm(   t   StringIO(   t	   urlencode(   t   Application(   t   URI(   t	   error_fort	   HTTPError(   t   DatetimeJSONEncoder(   t   _md5t   re_url_schemet   re_slashc         C   s	  yU t  j |  ƒ rT t |  t ƒ rB |  j d ƒ }  |  j d ƒ }  qT |  j d ƒ }  n  Wn t k
 rh n Xt |  t ƒ rŠ |  j d ƒ }  n  t |  ƒ j	 ƒ  } t  j
 d |  ƒ }  t j
 d |  ƒ }  t j } | d d } t |  ƒ | k rö |  |  }  n  d j |  | f ƒ S(   s•   Return a filename suitable for the cache.

    Strips dangerous and common characters to create a filename we
    can use to store the cache in.
    s   utf-8t   idnat    t   ,i    i   (   R   t   matcht
   isinstancet   strt   decodet   encodet   UnicodeErrort   unicodeR   t	   hexdigestt   subR   R   t   maximum_cache_filename_lengtht   lent   join(   t   filenamet   filemd5t   maximum_filename_lengtht   maximum_length_before_md5_sum(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyt   safename6   s$    	c           B   s;   e  Z d  Z d Z d d d d d „ Z d „  Z d „  Z RS(   sú   An Http subclass with some custom behavior.

    This Http client uses the TE header instead of the Accept-Encoding
    header to ask for compressed representations. It also knows how to
    react when its cache is a MultipleRepresentationCache.
    i   c         C   sK   t  t |  ƒ j | | | ƒ | |  _ |  j d  k	 rG |  j j |  ƒ n  d  S(   N(   t   superR   t   __init__t
   authorizert   Nonet   authorizeSession(   t   selfR'   t   cachet   timeoutt
   proxy_info(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR&   k   s    	c
   
   
   C   sr   | j  d ƒ r | d =n  |  j d k	 rD |  j j | | | | ƒ n  t t |  ƒ j | | | | | | | | |	 ƒ	 S(   s4   Use the authorizer to authorize an outgoing request.t   authorizationN(   t   has_keyR'   R(   t   authorizeRequestR%   R   t   _request(
   R*   t   connt   hostt   absolute_urit   request_urit   methodt   bodyt   headerst   redirectionst   cachekey(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR1   r   s    
	c         C   s)   t  |  j t ƒ r% |  j j | | ƒ Sd S(   s+   Retrieve a cached value for an HTTP header.N(   R   R+   t   MultipleRepresentationCachet   _getCachedHeaderR(   (   R*   t   urit   header(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR<   „   s    N(   t   __name__t
   __module__t   __doc__R   R(   R&   R1   R<   (    (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR   a   s   		R;   c           B   s)   e  Z d  Z d „  Z d „  Z d „  Z RS(   s>  A cache that can hold different representations of the same resource.

    If a resource has two representations with two media types,
    FileCache will only store the most recently fetched
    representation. This cache can keep track of multiple
    representations of the same resource.

    This class works on the assumption that outside calling code sets
    an instance's request_media_type attribute to the value of the
    'Accept' header before initiating the request.

    This class is very much not thread-safe, but FileCache isn't
    thread-safe anyway.
    c         C   s)   t  t |  ƒ j | |  j ƒ d |  _ d S(   s>   Tell FileCache to call append_media_type when generating keys.N(   R%   R;   R&   t   append_media_typeR(   t   request_media_type(   R*   R+   (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR&   š   s    c         C   s-   |  j  d k	 r# | d |  j  } n  t | ƒ S(   s×   Append the request media type to the cache key.

        This ensures that representations of the same resource will be
        cached separately, so long as they're served as different
        media types.
        t   -N(   RC   R(   R$   (   R*   t   key(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyRB       s    c   
      C   s~   t  | ƒ \ } } } } |  j | ƒ } | d } | d k	 rz x: t | ƒ D]) }	 |	 j | ƒ rJ |	 t | ƒ j ƒ  SqJ Wn  d S(   s+   Retrieve a cached value for an HTTP header.t   :N(   R   t   getR(   R   t
   startswithR   t   strip(
   R*   R=   R>   t   schemet	   authorityR5   R:   t   cached_valuet   header_startt   line(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR<   ¬   s    
(   R?   R@   RA   R&   RB   R<   (    (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR;   ‹   s   		c           B   s•   e  Z d  Z e ƒ  Z d Z d d d d e d „ Z d „  Z d d d d d „ Z	 d e
 d „ Z d „  Z d	 „  Z d d
 „ Z d „  Z d d „ Z RS(   s6   A class for making calls to lazr.restful web services.i   c         C   s}   | d k r. t j ƒ  } t j t j | ƒ n  t | t ƒ rL t	 | ƒ } n  | j
 | | | | ƒ |  _ | |  _ | |  _ d S(   så   Initialize, possibly creating a cache.

        If no cache is provided, a temporary directory will be used as
        a cache. The temporary directory will be automatically removed
        when the Python process exits.
        N(   R(   t   tempfilet   mkdtempt   atexitt   registert   shutilt   rmtreeR   t
   basestringR;   t   httpFactoryt   _connectiont
   user_agentt   max_retries(   R*   t   service_roott   credentialsR+   R,   R-   RX   RY   (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR&   ¾   s    	c   	   	   C   s•   xˆ t  d |  j d ƒ D]p } |  j j | d | d | d | ƒ\ } } | j d	 k r† | |  j k  r† t d | d ƒ } t | ƒ q Pq W| | f S(
   Ni    i   R6   R7   R8   iö  i÷  i   (   iö  i÷  (   t   rangeRY   RW   t   requestt   statust   intR   (	   R*   t   urlR6   R7   R8   t   retry_countt   responset   contentt	   sleep_for(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyt   _request_and_retryÐ   s    	!t   GETs   application/jsonc   
      C   sJ  | d k r t  d ƒ ‚ n  i | d 6} |  j d k	 rG |  j | d <n  t |  j j t ƒ rn | |  j j _ n  | d k	 rŠ | j | ƒ n  |  j	 t
 | ƒ d | d | d | ƒ\ } } | j d k r| d	 k r	d
 | k sê d | k r÷ | |  j f St | | ƒ ‚ n	 d | _ | | f St | | ƒ }	 |	 d k	 r@|	 ‚ n  | | f S(   s'   Create an authenticated request object.s   tag:launchpad.net:2008:redactedsU   You tried to access a resource that you don't have the server-side permission to see.t   Accepts
   User-AgentR6   R7   R8   i0  R   s   If-None-Matchs   If-Modified-SinceiÈ   N(   t
   ValueErrorRX   R(   R   RW   R+   R;   RC   t   updateRe   R   R^   t   NOT_MODIFIEDR   R   (
   R*   R`   t   dataR6   t
   media_typet   extra_headersR8   Rb   Rc   t   error(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR1   ß   s.    '		
	c         C   sh   t  | t t f ƒ r | } n | j d ƒ } | j ƒ  } |  j | d | ƒ\ } } | rd | | f S| S(   s2   GET a representation of the given resource or URI.RG   Rm   (   R   RU   R
   t
   get_methodt   build_request_urlR1   (   R*   t   resource_or_uriR8   t   return_responseR`   R6   Rb   Rc   (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyRG     s    	
c         C   s4   d } |  j  | d | ƒ\ } } t t | ƒ | ƒ S(   s?   GET a WADL representation of the resource at the requested url.s   application/vnd.sun.wadl+xmlRl   (   R1   R	   R   (   R*   R`   t	   wadl_typeRb   Rc   (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyt   get_wadl_application(  s    c         K   s)   | | d <t  | ƒ } |  j | | d ƒ S(   s"   POST a request to the web service.s   ws.opt   POST(   R   R1   (   R*   R`   t   method_namet   kwsRk   (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyt   post.  s    
c         C   sB   i | d 6} | d k	 r) | j | ƒ n  |  j | | d d | ƒS(   s(   PUT the given representation to the URL.s   Content-Typet   PUTRm   N(   R(   Ri   R1   (   R*   R`   t   representationRl   R8   Rm   (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyt   put4  s
    c         C   s   |  j  | d d ƒd S(   s%   DELETE the resource at the given URL.R6   t   DELETEN(   R1   R(   (   R*   R`   (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyt   delete<  s    c         C   s’   i d d 6} | d k	 r) | j | ƒ n  |  j j t | ƒ d ƒ } | d k	 rj |  j j rj | | d <n  |  j | t j | d t	 ƒd d | ƒS(	   s8   PATCH the object at url with the updated representation.s   application/jsons   Content-Typet   etags   If-Matcht   clst   PATCHRm   N(
   R(   Ri   RW   R<   R   t   ignore_etagR1   t
   simplejsont   dumpsR   (   R*   R`   Rz   R8   Rm   t   cached_etag(    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyt   patchA  s    N(   R?   R@   RA   t   objectRj   t   MAX_RETRIESR(   R&   Re   R1   t   FalseRG   Rt   Rx   R{   R}   R…   (    (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyR    ¸   s   		<			(    (%   RA   t   typet   __metaclass__t   __all__RQ   t   gzipRS   RO   t   timeR   t   httplib2R   R   R   R   R‚   t	   cStringIOR   t   zlibt   urllibR   t   wadllib.applicationR	   t   lazr.uriR
   t   errorsR   R   t   _jsonR   R   R   R   R$   R   R;   R    (    (    (    s?   /usr/lib/python2.7/dist-packages/lazr/restfulclient/_browser.pyt   <module>   s,   	"	+*-