import repository from arizona
[raven.git] / lib / arizona-lib / transfer / arizonatransfer_http.py
1 #! /usr/bin/env python
2 """
3 Stork Project (http://www.cs.arizona.edu/stork/)
4 Module: arizonatransfer_http
5 Description:   Provides a general file transferring by HTTP
6
7 """
8
9 import urllib
10 import urllib2
11 import os
12 import time
13 import arizonareport
14 import arizonageneral
15
16 def log_transfer(function, pid, timestamp, timestampend):
17    try:
18       import storklog
19       storklog.log_transfer(function, pid, timestamp, timestampend)
20    except:
21       pass
22
23 def close_transfer_program():
24    """
25    <Purpose>
26       This closes a connection (dummy function for HTTP).
27
28    <Arguments>
29       None.
30    
31    <Exceptions>
32       None.
33
34    <Side Effects>
35       None.
36
37    <Returns>
38       True.
39    """
40  
41    return True
42
43
44
45 def init_transfer_program(ignore=None, ignore2=None, ignore3=None, ignore4=None):
46    """
47    <Purpose>
48       This initializes a connection (dummy function for HTTP).
49
50    <Arguments>
51       None.
52    
53    <Exceptions>
54       None.
55
56    <Side Effects>
57       None.
58
59    <Returns>
60       True.
61    """
62    return True
63
64
65
66
67 def retrieve_files(host, filelist, destdir='.', indicator=None, protocol="http", nestmode=False):
68    """
69    <Purpose>
70       This retrieves files from a host to a destdir.
71
72    <Arguments>
73       host:
74          'host' holds two things, a server name and target directory.
75          For example, if you want to retrieve files from '/tmp/' directory
76          in 'quadrus.cs.arizona.edu' server, the 'host' will be
77          'quadrus.cs.arizona.edu/tmp'.
78
79       filelist:
80          'filelist' is a list of files which need to be retrieved.
81
82       destdir:
83          'destdir' is a destination directory where retrieved files will
84          be placed. A user should have 'destdir' exist before retrieving 
85          files. 'destdir' should be a string. Default is a current dir.
86
87       indicator:
88          'indicator' is a module which has set_filename and 
89          download_indicator functions. 'indicator' will be passed in 
90          'urlretrieve' function so that progress bar will be shown 
91          while downloading files. Default is 'None'.
92
93       protocol:
94          either "http" or "https"
95
96       nestmode:
97          talk to a nestproxy on the local machine
98
99    <Exceptions>
100       None.
101
102    <Side Effects>
103       None.
104
105    <Returns>
106       (True, grabbed_list)
107       'grabbed_list' is a list of files which are retrieved
108    """
109    arizonareport.send_out(4, "[DEBUG] arizonatransfer_http.retrieve_files: started")
110
111    # set grabbed_list as a empty list. Later it will be appended with retrieved files
112    grabbed_list = []
113
114    # check if host is a string
115    if not isinstance(host, str):
116       arizonareport.send_syslog(arizonareport.ERR, "retrieve_files(): host should be a string")
117       # return false and empty list
118       return (False, grabbed_list)
119
120    # TODO - check for tuple list
121    #if not valid_sl(filelist):
122    #   arizonareport.send_syslog(arizonareport.ERR, "retrieve_files(): filelist should be a list of strings")
123    #   # return false and empty list
124    #   return (False, grabbed_list)
125
126    # check if destdir is a string
127    if not isinstance(destdir,str):
128       arizonareport.send_syslog(arizonareport.ERR, "retrieve_files(): destdir should be a string")
129       # return false and empty list
130       return (False, grabbed_list)
131
132    # check that the destination directory exists
133    if not os.path.isdir(destdir):
134       arizonareport.send_syslog(arizonareport.ERR, "\nretrieve_files(): The destination directory '" + destdir + "' for a requested does not exist")
135       # return false and empty list
136       return (False, grabbed_list)
137
138    # if destdir is a empty string, then make it as a current directory
139    if destdir == '':
140       destdir = '.'
141
142    # go through every file in the file list
143    for file in filelist:
144       filename = file['filename']
145       starttime = time.time()
146
147       # build url which specifies host and filename to be retrieved
148       thisurl = __build_url(host, filename, protocol)
149
150       if nestmode:
151          # nestproxy requires a hash
152          hash = file.get("hash", None)
153          if not hash:
154             arizonareport.send_out(1, "nestmode http does not support files without hashes")
155             continue
156
157          # nestproxy uses some query parameters to specify the hash, host, and filename
158          thisurl = "http://localhost:6648/" + \
159                    _strip_protocol(thisurl) + \
160                    "?hash=" + hash
161          # nestproxy will extract from the url: "&host=" + host + "&filename=" + filename
162
163       # open given url
164       try:
165          arizonareport.send_out(4, "[DEBUG] opening url " + thisurl)
166          aurl = urllib2.urlopen(thisurl)
167
168          blocknum = 0
169          blocksize = 8192
170
171          # get the size of the file from the HTTP headers
172          size = int(aurl.info().get("content-length", -1))
173
174          # tell the download indicator the filename and size
175          if indicator:
176             indicator.set_filename(os.path.basename(filename))
177             indicator.download_indicator(blocknum, blocksize, size)
178
179          # read from the aurl object and write to the destination file,
180          # updating the download indicator as necessary
181          outfile = open(os.path.join(destdir, filename), "w")
182          while True:
183             data = aurl.read(blocksize)
184             if not data:
185                break
186             outfile.write(data)
187             blocknum += 1
188             if indicator:
189                indicator.download_indicator(blocknum, blocksize, size)
190
191          # put a newline at the end of the indicator
192          if indicator:
193             arizonareport.send_out(0, "")
194
195          outfile.close()
196          aurl.close()
197
198          grabbed_list = grabbed_list + [file]
199          endtime = time.time()
200          arizonareport.send_out(4, "[DEBUG] completed url " + thisurl)
201          log_transfer("http", str(os.getpid()), str(starttime), str(endtime))
202
203       # if file is not permitted to be retrieved
204       except urllib2.HTTPError, (errstr):
205          # TODO: we may wish to catch errors that indicate the server is down
206          # and abort all remaining files rather than wasting time on them
207          arizonareport.send_syslog(arizonareport.ERR, 'retrieve_files(): "' + str(errstr) + '" on the file "' + filename + '"')
208
209    if (grabbed_list) :
210       return (True, grabbed_list)
211    # if nothing in grabbed_list
212    else:
213       return (False, grabbed_list)
214
215
216
217 def transfer_name():
218    """
219    <Purpose>
220       This gives the name of this transfer method.
221
222    <Arguments>
223       None.
224
225    <Exceptions>
226       None.
227
228    <Side Effects>
229       None.
230
231    <Returns>
232       'arizona_http' as an string
233    """
234
235    return 'arizona_http'
236
237
238
239
240
241
242 def __extract_hostname(host):
243    """
244    <Purpose>
245       Extracts the hostname from a host string
246
247    <Arguments>
248        host:
249          'host' holds two things, a server name and target directory.
250          For example, if you want to retrieve files from '/tmp/' directory
251          in 'quadrus.cs.arizona.edu' server, the 'host' will be
252          'quadrus.cs.arizona.edu/tmp'.
253
254    <Exceptions>
255       None.
256
257    <Side Effects>
258       None.
259
260    <Returns>
261       The hostname
262    """
263
264    # remove the protocol if there is one
265    host = arizonageneral.lcut(host, "http://")
266    host = arizonageneral.lcut(host, "https://")
267    host = arizonageneral.lcut(host, "ftp://")
268
269    index=host.find("/")
270
271    # set hostname to hold only a server name
272    if index != -1:
273       hostname = host[:index]
274    else :
275       hostname = host
276
277    return hostname
278
279
280
281
282
283 def __build_url(host, fname, protocol="http"):
284    """
285    <Purpose>
286       This builds a url string with Http address.
287
288    <Arguments>
289        host:
290          'host' holds two things, a server name and target directory.
291          For example, if you want to retrieve files from '/tmp/' directory
292          in 'quadrus.cs.arizona.edu' server, the 'host' will be
293          'quadrus.cs.arizona.edu/tmp'.
294       fname:
295          A file name to be retrieved
296
297    <Exceptions>
298       None.
299
300    <Side Effects>
301       None.
302
303    <Returns>
304       A whole url string created
305    """
306
307    host = _strip_protocol(host)
308
309    if (protocol != "http") and (protocol != "https"):
310       return TypeError, "unknown protocol"
311
312    # add '/' at the end of the host if there is not, so that file name is added properly
313    if not host.endswith("/"):
314       host = host + '/'
315
316    # return url which contains host and filename
317    return protocol + "://" + host + fname
318
319
320 def _strip_protocol(s):
321    s = arizonageneral.lcut(s, "http://")
322    s = arizonageneral.lcut(s, "https://")
323    s = arizonageneral.lcut(s, "ftp://")
324    return s