Commits

Lynn Rees committed 3adc9e7

- cleanup

Comments (0)

Files changed (8)

 '''wire http errors'''
 
 
+class OffsetError(Exception):
+
+    '''invalide offset'''
+
+
 class HTTPHeaderException(Exception):
 
     '''Invalid HTTP header value'''
 # -*- coding: utf-8 -*-
 '''wire httplet'''
 
+from callchain.root.linked import chainlink
 from callchain.root.chainlet import chainlet
 
 
         '''
         super(httplet, self).__init__(root)
         self._cookies = root._cookies
-        self._data = root._data
+        self._data.extend(root._data)
         self._headers = root._headers
         self._params = root._params
+        self._files = root._files
+
+
+class httplink(chainlink):
+
+    def __init__(self, root):
+        '''
+        init
+
+        @param root: root object
+        '''
+        super(httplink, self).__init__(root)
+        self._cookies = root._cookies
+        self._data.extend(root._data)
+        self._headers = root._headers
+        self._params = root._params
+        self._files = root._files

wire/http/request/client.py

 # -*- coding: utf-8 -*-
 '''wire HTTP request core'''
 
+import hashlib
 from functools import partial
+from collections import deque
 
 from appspace.keys import appifies
 from callchain.internal import inside
-from stuf.utils import OrderedDict, exhaust, lazy_class
 from twoq.lazy.mixins import AutoResultMixin
 from callchain.assembly.chain import CallChainQ
 from callchain.mixin.reset import ResetTypeMixin
+from stuf.utils import OrderedDict, exhaust, lazy_class
 
+from wire.support import base64_encode
 from wire.http.request.apps import apps
 from wire.http.request.keys.client import KRequestClient
+from wire.http.errors import OffsetError
 
 
 class Request(ResetTypeMixin):
 
-    '''request wrapper'''
+    '''HTTP request wrapper'''
 
     def __init__(self, url, verify, allow_redirects, timeout, auth, proxy):
         super(Request, self).__init__()
         self._timeout = timeout
         self._auth = auth
         self._proxy = proxy
-        self._cookies = {}
+        self._cookies = None
         self._data = None
         self._file = None
-        self._headers = {}
+        self._headers = OrderedDict()
         self._params = None
 
     @property
     def cookies(self, cookies):
         self._cookies = cookies
 
-    def data(self, data):
+    def data(self, data, mime, charset=None):
+        '''
+        set HTTP *CONTENT-TYPE* header.
+
+        @param mime: MIME media type
+        @param charset: charset (default: None)
+        '''
         self._data = data
+        if charset is None:
+            self._headers.set('Content-Type', mime)
+        else:
+            self._headers.set(
+                'Content-Type', '{0}; charset={1}'.format(mime, charset),
+            )
 
     def file(self, data):
         self._file = data
 
     def headers(self, headers):
-        self._headers.update(headers)
+        self._headers.update(headers.dump())
 
     def params(self, params):
         self._params = params
 
+    def content_md5(self):
+        '''
+        take MD5 hash of data and set *CONTENT-MD5* HTTP header
+
+        @param value: HTTP response data
+        '''
+        self._headers.set('Content-MD5', base64_encode(
+            hashlib.md5.new(self._data).digest()
+        ))
+
 
 @appifies(KRequestClient)
 @inside(apps)
         _setdefault('_timeout', kw.get('timeout'), _defaults.timeout)
         # use random user agent
         _setdefault('_randomua', kw.pop('randomua'), _defaults.random_ua)
-        # authentication
+        # authentication config
         _setdefault('_auth', _defaults.authentication)
-        # proxy
+        # proxy config
         _setdefault('_proxy', _defaults.proxy)
         # headers
         self._headers = OrderedDict()
         # cookies
         self._cookies = None
+        # data
+        self._data = deque()
+        # files
+        self._files = deque()
+        # params
+        self._params = deque()
 
     def __getattr__(self, key):
         return partial(
 
     _hgetter = __getattr__
 
-    def __call__(self, *urls, **config):
+    ###########################################################################
+    ## internal management ####################################################
+    ###########################################################################
+
+    def clear(self):
+        '''clear all queues'''
+        self._resetdefaults()
+        self._qclear()
+        return self
+
+    _hclear = clear
+
+    def back(self, link):
         '''
-        load urls
+        handle chainlet end
 
-        @param *urls: Uniform Resource Locations (URLs)
+        @param link: linked chain
         '''
-        allow_redirects = self._allow_redirects
-        # verify certs
-        verify = self._verify
-        # default timeout
-        timeout = config.pop('timeout', self._timeout)
-        # authentication
-        auth = config.pop('auth', self._auth)
-        if auth:
-            self.auth(*auth)
-        randomua = config.get('randomua', self._randomua)
-        # proxy
-        proxy = config.pop('proxy', self._proxy)
-        if proxy:
-            self.proxy(*proxy)
-        # urls, if any
-        return self._dcall(*(Request(
-            u, verify, allow_redirects, timeout, auth, proxy, randomua
-        ) for u in urls))
+        self._headers = link._headers
+        self._cookies = link._cookies
+        self._data = link._data
+        self._files = link._files
+        self._params = link._params
+        return self._rback(link)
 
-    _hcall = __call__
+    _hback = back
 
     ###########################################################################
     ## http methods ###########################################################
 
         @param method: HTTP method
         '''
-        self.args(self._headers).invoke('headers').args(self._cookies).invoke(
-        'cookies').args(self._data).invoke('data')
+        (self.args(self._headers).invoke('headers')
+        .args(self._cookies).invoke('cookies')
+        .args(self._data).invoke('data')
+        .args(self._params).invoke('params')
+        .args(self._files).invoke('files'))
         pack = lambda x: self.chain(self._requester, method, x.url, **x.args)
         with self._sync as sync:
             exhaust(pack(i) for i in sync.interable)
 
     _hpack = _pack
 
+    def data(self, *data):
+        '''
+        `data` for urls (must equal number of previously passed urls)
+
+        param *data: data for request body
+        '''
+        if len(data) == len(self):
+            self._data.extend(data)
+        else:
+            raise OffsetError(
+                'number of data items does not match number of URLs'
+            )
+        return self
+
+    def files(self, *files):
+        '''
+        `files` for urls (must equal number of previously passed urls)
+
+        param *data: data for request body
+        '''
+        if len(files) == len(self):
+            # files demand multipart as default otherwise go with urlencode
+            self._value = 'multipart'
+            self._files.extend(files)
+        else:
+            raise OffsetError(
+                'number of file items does not match number of URLs'
+            )
+        return self
+
+    def params(self, *params):
+        '''
+        request parameters for all urls
+
+        param **params: parameters
+        '''
+        if len(params) == len(self):
+            self._params.extend(params)
+        else:
+            raise OffsetError(
+                'number of parameter items does not match number of URLs'
+            )
+        return self
+
+    def content_md5(self):
+        '''
+        take MD5 hash of data and set *CONTENT-MD5* HTTP header on items
+
+        @param value: HTTP response data
+        '''
+        self.args(self._headers).invoke('content_md5')
+        return self
+
     ###########################################################################
-    ## usage management #######################################################
+    ## http configuration #####################################################
     ###########################################################################
 
-    def clear(self):
-        '''clear all queues'''
-        self._resetdefaults()
-        self._qclear()
-        return self
+    def __call__(self, *urls, **config):
+        '''
+        load urls
 
-    _hclear = clear
+        @param *urls: Uniform Resource Locations (URLs)
+        '''
+        allow_redirects = self._allow_redirects
+        # verify certs
+        verify = self._verify
+        # default timeout
+        timeout = config.pop('timeout', self._timeout)
+        # authentication
+        auth = config.pop('auth', self._auth)
+        if auth:
+            self.auth(*auth)
+        randomua = config.get('randomua', self._randomua)
+        # proxy
+        proxy = config.pop('proxy', self._proxy)
+        if proxy:
+            self.proxy(*proxy)
+        # urls, if any
+        return self._dcall(*(Request(
+            u, verify, allow_redirects, timeout, auth, proxy, randomua,
+        ) for u in urls))
 
-    def back(self, link):
-        '''
-        handle chainlet end
-
-        @param link: linked chain
-        '''
-        self._headers = link._headers
-        self._cookies = link._cookies
-        self._data = link._data
-        self._params = link._params
-        return self._rback(link)
-
-    _hback = back
+    _hcall = __call__
 
     def auth(self, username, password):
         '''

wire/http/request/data.py

-# -*- coding: utf-8 -*-
-'''wire HTTP data manager'''
-
-import hashlib
-
-from appspace.keys import appifies
-from wire.support import base64_encode
-from callchain.root.linked import chainlink
-
-from wire.http.request.keys.data import KRequestData
-
-
-@appifies(KRequestData)
-class Data(chainlink):
-
-    def __init__(self, root):
-        super(Data, self).__init__(root)
-        self._data = ''
-
-    def content_type(self, mime, charset=None):
-        '''
-        set HTTP *Content-Type* header.
-
-        @param mime: MIME media type
-        @param charset: charset (default: None)
-        '''
-        if charset is None:
-            self._headers.set('Content-Type', mime)
-        else:
-            self._headers.set(
-                'Content-Type', '{0}; charset={1}'.format(mime, charset),
-            )
-        return self
-
-    def content_range(self, first, last, length='*'):
-        '''
-        set rangeset in HTTP header *Content-Range*
-
-        @param first: first byte position
-        @param last: last byte position
-        @param length: instance length
-        '''
-        if length == '*':
-            self._headers.set('Content-Range', 'bytes %d-%d/*' % (first, last))
-        else:
-            self._headers.set(
-                'Content-Range', 'bytes %d-%d/%d' % (first, last, length)
-            )
-        return self
-
-    def content_md5(self):
-        '''
-        take MD5 hash of data and set *CONTENT-MD5* HTTP header.
-
-        @param value: HTTP response data
-        '''
-        self._headers.set('Content-MD5', base64_encode(
-            hashlib.md5.new(self._data).digest()
-        ))
-        return self
-
-    def data(self, *data):
-        '''
-        `data` for urls (must equal number of previously passed urls)
-
-        param *data: data for request body
-        '''
-        self._data = data
-        return self
-
-    def files(self, *files):
-        '''
-        `files` for urls (must equal number of previously passed urls)
-
-        param *data: data for request body
-        '''
-        # files demand multipart as default otherwise go with urlencode
-        self._value = 'multipart'
-        self._files = files
-        return self
-
-    def params(self, **params):
-        '''
-        request parameters for all urls
-
-        param **params: parameters
-        '''
-        self._params = params
-        return self

wire/http/request/header.py

         '''python name -> header name mapping'''
         return dict((checkname(h), h) for h in self._headers.REQ_HEADERS)
 
+    def content_range(self, first, last, length='*'):
+        '''
+        set rangeset for HTTP header *CONTENT-RANGE*
+
+        @param first: first byte position
+        @param last: last byte position
+        @param length: instance length
+        '''
+        if length == '*':
+            self._headers.set('Content-Range', 'bytes %d-%d/*' % (first, last))
+        else:
+            self._headers.set(
+                'Content-Range', 'bytes %d-%d/%d' % (first, last, length)
+            )
+        return self
+
     def bheader(self, key, value):
         '''
         set HTTP request header with `bytes` (native string) value

wire/http/request/keys/client.py

         @param urls: Uniform Resource Locations (URLs)
         '''
 
+    def data(*data):
+        '''
+        `data` for urls (must equal number of previously passed urls)
+        
+        param *data: data for request body
+        '''
+    
+    def files(*files):
+        '''
+        `files` for urls (must equal number of previously passed urls)
+        
+        param *data: data for request body
+        '''
+        
+    def params(**params):
+        '''
+        request parameters for all urls
+        
+        param **params: parameters
+        '''
+
     def get():
         '''
         *GET* HTTP method
         @param host: proxy host
         '''
         
+    def content_md5():
+        '''
+        take MD5 hash of data and set *CONTENT-MD5* HTTP header.
+
+        @param value: HTTP response data
+        '''
 
 class KAPI(AppspaceKey):
     

wire/http/request/keys/data.py

-# -*- coding: utf-8 -*-
-#@PydevCodeAnalysisIgnore
-#pylint: disable-msg=e0211,e0213
-'''http request data keys'''
-
-from appspace.keys import AppspaceKey
-
-
-class KRequestData(AppspaceKey):
-    
-    '''HTTP request data key'''
-    
-    def content_range(first, last, length='*'):
-        '''
-        set rangeset in HTTP header *CONTENT-RANGE*
-
-        @param first: first byte position
-        @param last: last byte position
-        @param length: instance length
-        '''
-
-    def content_type(value, charset=None):
-        '''
-        *CONTENT-TYPE* HTTP header.
-
-        @param value: media type
-        @param charset: optional charset (default: None)
-        '''
-    
-    def content_md5():
-        '''
-        take MD5 hash of data and set *CONTENT-MD5* HTTP header.
-
-        @param value: HTTP response data
-        '''
-        
-    def data(*data):
-        '''
-        `data` for urls (must equal number of previously passed urls)
-        
-        param *data: data for request body
-        '''
-    
-    def files(*files):
-        '''
-        `files` for urls (must equal number of previously passed urls)
-        
-        param *data: data for request body
-        '''
-        
-    def params(**params):
-        '''
-        request parameters for all urls
-        
-        param **params: parameters
-        '''

wire/http/request/keys/header.py

         
         @param value: HTTP header value
         '''
-        
+
     def content_encoding(value):
         '''
         *CONTENT-ENCODING* HTTP header
         
         @param value: HTTP header value
         '''
+
+    def content_range(first, last, length='*'):
+        '''
+        set rangeset in HTTP header *CONTENT-RANGE*
+
+        @param first: first byte position
+        @param last: last byte position
+        @param length: instance length
+        '''
     
     def date(value):
         '''