[bug] allow ipc socket types
[leap_pycommon.git] / src / leap / common / http.py
1 # -*- coding: utf-8 -*-
2 # http.py
3 # Copyright (C) 2015 LEAP
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 """
18 Twisted HTTP/HTTPS client.
19 """
20
21 try:
22     import twisted
23 except ImportError:
24     print "*******"
25     print "Twisted is needed to use leap.common.http module"
26     print ""
27     print "Install the extra requirement of the package:"
28     print "$ pip install leap.common[Twisted]"
29     import sys
30     sys.exit(1)
31
32
33 from leap.common.certs import get_compatible_ssl_context_factory
34
35 from zope.interface import implements
36
37 from twisted.internet import reactor
38 from twisted.internet.defer import succeed
39
40 from twisted.web.client import Agent
41 from twisted.web.client import HTTPConnectionPool
42 from twisted.web.client import readBody
43 from twisted.web.http_headers import Headers
44 from twisted.web.iweb import IBodyProducer
45
46
47 def createPool(maxPersistentPerHost=10, persistent=True):
48     pool = HTTPConnectionPool(reactor, persistent)
49     pool.maxPersistentPerHost = maxPersistentPerHost
50     return pool
51
52 _pool = createPool()
53
54
55 class HTTPClient(object):
56     """
57     HTTP client done the twisted way, with a main focus on pinning the SSL
58     certificate.
59     """
60
61     def __init__(self, cert_file=None, pool=_pool):
62         """
63         Init the HTTP client
64
65         :param cert_file: The path to the certificate file, if None given the
66                           system's CAs will be used.
67         :type cert_file: str
68         """
69
70         policy = get_compatible_ssl_context_factory(cert_file)
71
72         self._agent = Agent(
73             reactor,
74             policy,
75             pool=pool)
76
77     def request(self, url, method='GET', body=None, headers={}):
78         """
79         Perform an HTTP request.
80
81         :param url: The URL for the request.
82         :type url: str
83         :param method: The HTTP method of the request.
84         :type method: str
85         :param body: The body of the request, if any.
86         :type body: str
87         :param headers: The headers of the request.
88         :type headers: dict
89
90         :return: A deferred that fires with the body of the request.
91         :rtype: twisted.internet.defer.Deferred
92         """
93         if body:
94             body = HTTPClient.StringBodyProducer(body)
95         d = self._agent.request(
96             method, url, headers=Headers(headers), bodyProducer=body)
97         d.addCallback(readBody)
98         return d
99
100     class StringBodyProducer(object):
101         """
102         A producer that writes the body of a request to a consumer.
103         """
104
105         implements(IBodyProducer)
106
107         def __init__(self, body):
108             """
109             Initialize the string produer.
110
111             :param body: The body of the request.
112             :type body: str
113             """
114             self.body = body
115             self.length = len(body)
116
117         def startProducing(self, consumer):
118             """
119             Write the body to the consumer.
120
121             :param consumer: Any IConsumer provider.
122             :type consumer: twisted.internet.interfaces.IConsumer
123
124             :return: A successful deferred.
125             :rtype: twisted.internet.defer.Deferred
126             """
127             consumer.write(self.body)
128             return succeed(None)
129
130         def pauseProducing(self):
131             pass
132
133         def stopProducing(self):
134             pass