Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / http.py @ 176894c1

History | View | Annotate | Download (4.9 kB)

1
# Copyright 2011 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
import json
35
import logging
36

    
37
from httplib import HTTPConnection, HTTPSConnection
38
from urlparse import urlparse
39

    
40
from . import ClientError
41

    
42

    
43
log = logging.getLogger('kamaki.clients')
44

    
45

    
46
class HTTPClient(object):
47
    def __init__(self, config):
48
        self.config = config
49
    
50
    @property
51
    def url(self):
52
        url = self.config.get('url')
53
        if not url:
54
            raise ClientError('No URL was given')
55
        return url
56
    
57
    @property
58
    def token(self):
59
        token = self.config.get('token')
60
        if not token:
61
            raise ClientError('No token was given')
62
        return token
63
    
64
    def raw_http_cmd(self, method, path, body=None, headers=None, success=200,
65
                     json_reply=False, skip_read=False):
66
        p = urlparse(self.url)
67
        path = p.path + path
68
        if p.scheme == 'http':
69
            conn = HTTPConnection(p.netloc)
70
        elif p.scheme == 'https':
71
            conn = HTTPSConnection(p.netloc)
72
        else:
73
            raise ClientError('Unknown URL scheme')
74
        
75
        headers = headers or {}
76
        headers['X-Auth-Token'] = self.token
77
        if body:
78
            headers.setdefault('Content-Type', 'application/json')
79
            headers['Content-Length'] = len(body)
80
        
81
        log.debug('>' * 50)
82
        log.debug('%s %s', method, path)
83
        for key, val in headers.items():
84
            log.debug('%s: %s', key, val)
85
        if body:
86
            log.debug('')
87
            log.debug(body)
88
        
89
        conn.request(method, path, body, headers)
90
        
91
        resp = conn.getresponse()
92
        reply = '' if skip_read else resp.read()
93
        
94
        log.debug('<' * 50)
95
        log.info('%d %s', resp.status, resp.reason)
96
        for key, val in resp.getheaders():
97
            log.info('%s: %s', key.capitalize(), val)
98
        log.info('')
99
        log.debug(reply)
100
        log.debug('-' * 50)
101
        
102
        if json_reply:
103
            try:
104
                reply = json.loads(reply) if reply else {}
105
            except ValueError:
106
                raise ClientError('Did not receive valid JSON reply',
107
                                  resp.status, reply)
108
        
109
        if success and resp.status != success:
110
            if len(reply) == 1:
111
                if json_reply:
112
                    key = reply.keys()[0]
113
                    val = reply[key]
114
                    message = '%s: %s' % (key, val.get('message', ''))
115
                    details = val.get('details', '')
116
                else:
117
                    message = reply
118
                    details = ''
119
    
120
                raise ClientError(message, resp.status, details)
121
            else:
122
                raise ClientError('Invalid response from the server')
123
        
124
        return resp, reply
125
    
126
    def http_cmd(self, method, path, body=None, headers=None, success=200):
127
        resp, reply = self.raw_http_cmd(method, path, body, headers, success,
128
                                        json_reply=True)
129
        return reply
130
    
131
    def http_get(self, path, success=200):
132
        return self.http_cmd('GET', path, success=success)
133
    
134
    def http_post(self, path, body=None, headers=None, success=202):
135
        return self.http_cmd('POST', path, body, headers, success)
136
    
137
    def http_put(self, path, body=None, headers=None, success=204):
138
        return self.http_cmd('PUT', path, body, headers, success)
139
    
140
    def http_delete(self, path, success=204):
141
        return self.http_cmd('DELETE', path, success=success)