add twisted-web
[enigma2-plugins.git] / lastfm / src / httpclient.py
1 from twisted.internet.protocol import ClientFactory
2 from twisted.web2.client.http import HTTPClientProtocol
3 from twisted.internet import reactor, error
4 from urlparse import urlsplit,urlparse as urlparse_urlparse,urlunparse as urlparse_urlunparse
5 from socket import gethostbyname
6 from urllib import urlencode as urllib_urlencode,unquote_plus as urllib_unquote_plus, quote_plus as urllib_quote_plus
7
8 global HTTPCLIENT_requestCount
9 HTTPCLIENT_requestCount = 0 # counts requests
10     
11 class Enigma2HTTPRequest:
12         
13     def __init__(self,hostname,path,port,method="GET",headerfields={}):
14         self.hostname=hostname
15         self.port=port
16         self.path=path
17         self.method=method
18         self.headerfields = headerfields
19         self.onRequestFinished = []
20         self.onRequestError = []
21         self.onHeaderLoaded = []
22         
23         self.data=""
24         self.readsize = 0
25         self.headers= {}
26         
27     def _DataRecived(self,data):
28         self.readsize += len(data)
29         self.data += data
30             
31     def getIPAdress(self):
32         """    
33             socket.gethostbyname() is syncron
34             Enigma2 is blocked while process is running    
35         """
36         try:
37             return gethostbyname(self.hostname)
38         except:
39             return False
40         
41     def HeaderLoaded(self,headers):
42         self.headers = headers
43         for i in self.onHeaderLoaded:
44             if i is not None:
45                 i(headers)
46         self.onHeaderLoaded=[]
47         
48     def RequestError(self,error):
49         for i in self.onRequestError:
50             if i is not None:
51                 i(error)
52         self.onRequestError = []
53         
54     def RequestFinished(self,data):
55         for i in self.onRequestFinished:
56             if i is not None:
57                 i(data)
58        
59 class Enigma2URLHTTPRequest(Enigma2HTTPRequest):
60     def __init__(self,url,method="GET",headerfields={}):
61         x= urlsplit(url)
62         if x[1].rfind(":")>0:
63             y = x[1].split(":")
64             hostname = y[0]
65             port = int(y[1])
66         else:
67             hostname = x[1]
68             port = 80
69         path=x[2]
70         Enigma2HTTPRequest.__init__(self,hostname,path,port,method=method,headerfields=headerfields)
71
72 class Enigma2FileHTTPRequest(Enigma2URLHTTPRequest):
73     def __init__(self,targetfile,url,method="GET",headerfields={}):
74         Enigma2URLHTTPRequest.__init__(self,url,method=method,headerfields=headerfields)
75         self.filehandle = open(targetfile,"w")
76         self.onRequestFinished.append(self.close)
77         self.onRequestError.append(self.close)
78     def close(self,dummy):
79         self.filehandle.close()
80     
81     def _DataRecived(self,data):
82         self.readsize += len(data)
83         self.filehandle.write(data)
84         
85             
86         
87         
88 class Enigma2HTTPProtocol(HTTPClientProtocol):
89     DEBUG = False
90     
91     def __init__(self,request,requestCount):
92         self.request = request
93         self.requestCount = requestCount
94         self.headers={}
95         self.headerread=False
96         self.responseFirstLine = True # to indikate, that first line of responseheader was read
97         HTTPClientProtocol.__init__(self)
98         self.setRawMode()
99         
100     def rawDataReceived(self,line):
101         for l in line.split(self.delimiter): 
102             if self.headerread:
103                 self.request._DataRecived(l)
104             else:
105                 if self.DEBUG:
106                     print "HTTP "+self.requestCount+" <<==",l
107                 if l == "":
108                     self.headerread = True
109                     self.request.HeaderLoaded(self.headers)
110                 else:
111                     self.parseHeaderLine(l)
112     
113     def parseHeaderLine(self,line):
114         if self.responseFirstLine is  True:
115             #print "parseHeaderLine",line.split(" ")
116             fields = line.split(" ")
117             protocoll = fields[0]
118             responsecode  = fields[1]
119             statuscode = " ".join(fields[2:])
120             self.headers["protocoll"] = protocoll
121             self.headers["responsecode"] = responsecode
122             self.headers["statuscode"] = statuscode
123             self.responseFirstLine = False
124         elif line.rfind(":"):
125             x = line.split(":")
126             key = x[0].lstrip().rstrip().lower()
127             var = ":".join(x[1:]).lstrip()
128             self.headers[key] = var        
129         else:
130             print "unknown headerline",line
131
132     def connectionMade(self):
133         if self.request.method == "POST":
134             (path,params ) = self.request.path.split("?")
135         elif self.request.method == "GET":
136             path = self.request.path
137         self.sendLine("%s %s HTTP/1.0"%(self.request.method,path))
138         self.sendLine("Host: %s"%self.request.hostname)
139         for i in self.request.headerfields:
140             self.sendLine(i+": "+self.request.headerfields[i])
141         if self.request.method == "POST":
142             self.sendLine("Content-Type: application/x-www-form-urlencoded")
143             self.sendLine("Content-Length: "+str(len(params)))
144         
145         self.sendLine("")
146         if self.request.method == "POST":
147             self.sendLine(params)
148     
149     def sendLine(self,data):
150         if self.DEBUG:
151             print "HTTP "+self.requestCount+" ==>>",data
152         HTTPClientProtocol.sendLine(self,data)
153         
154 class Enigma2HTTPClientFactory(ClientFactory):
155
156     initialDelay = 20
157     maxDelay = 500
158     def __init__(self,request):
159         self.hangup_ok = False
160         self.request = request
161        
162     def startedConnecting(self, connector):
163         pass
164     
165     def buildProtocol(self, addr):
166         global HTTPCLIENT_requestCount
167         HTTPCLIENT_requestCount = HTTPCLIENT_requestCount + 1
168         return Enigma2HTTPProtocol(self.request,str(HTTPCLIENT_requestCount))
169
170     def clientConnectionLost(self, connector, reason):
171         if not self.hangup_ok:
172             self.request.RequestFinished(self.request.data)
173         ClientFactory.clientConnectionLost(self, connector, reason)
174         
175     def clientConnectionFailed(self, connector, reason):
176         self.request.RequestError(reason.getErrorMessage())
177         ClientFactory.clientConnectionFailed(self, connector, reason)
178
179 def urlparse(url):
180     return urlparse_urlparse(url)
181 def urlunparse(url):
182     return urlparse_urlunparse(url)
183
184 def unquote_plus(string):
185     return urllib_unquote_plus(string)
186
187 def urlencode(dict):
188     return urllib_urlencode(dict)
189         
190 def quote_plus(data):
191         return urllib_quote_plus(data)
192
193 def getURL(url,callback=None,errorback=None,headercallback=None,method="GET",headers={}):
194     """ 
195         this will is called with a url
196         url = http://www.hostna.me/somewhere/on/the/server <string>
197     """
198     req = Enigma2URLHTTPRequest(url,method=method,headerfields=headers)
199     req.onRequestError.append(errorback)
200     req.onHeaderLoaded.append(headercallback)
201     req.onRequestFinished.append(callback)
202     ipadress = req.getIPAdress()
203     if ipadress is not False:
204         reactor.connectTCP(ipadress,req.port, Enigma2HTTPClientFactory(req))
205         return req
206     else:
207         if errorback is not None:
208             errorback("Error while resolve Hostname")
209
210 def getPage(hostname,port,path,method="GET",callback=None,errorback=None,headercallback=None,headers={}):
211     """ 
212         this will is called with separte hostname,port,path
213         hostname = www.hostna.me <string>
214         port = 80 <int>
215         path= /somewhere/on/the/server <string>
216     """
217     req = Enigma2HTTPRequest(hostname,path,port,method=method,headerfields=headers)
218     req.onRequestError.append(errorback)
219     req.onRequestFinished.append(callback)
220     ipadress = req.getIPAdress()
221     if ipadress is not False:
222         reactor.connectTCP(ipadress,req.port, Enigma2HTTPClientFactory(req))
223         return req
224     else:
225         if errorback is not None:
226             errorback("Error while resolve Hostname")
227
228 def getFile(filename,url,method="GET",callback=None,errorback=None,headercallback=None,headers={}):
229     """ 
230         this will is called with a url and a target file
231         fimename = /tmp/target.jpg 
232         url = http://www.hostna.me/somewhere/on/the/server.jpg <string>
233     """
234     req = Enigma2FileHTTPRequest(filename,url,method=method,headerfields=headers)
235     req.onRequestError.append(errorback)
236     req.onHeaderLoaded.append(headercallback)
237     req.onRequestFinished.append(callback)
238     ipadress = req.getIPAdress()
239     if ipadress is not False:
240         reactor.connectTCP(ipadress,req.port, Enigma2HTTPClientFactory(req))
241         return req
242     else:
243         if errorback is not None:
244             errorback("Error while resolve Hostname")
245