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