1 # -*- coding: utf-8; -*-
4 # Part of ‘dput’, a Debian package upload toolkit.
6 # Copyright © 2015–2016 Ben Finney <ben+python@benfinney.id.au>
7 # Copyright © 2008–2012 Y Giridhar Appaji Nag <appaji@debian.org>
8 # Copyright © 2007–2008 Thomas Viehmann <tv@beamnet.de>
10 # This is free software: you may copy, modify, and/or distribute this work
11 # under the terms of the GNU General Public License as published by the
12 # Free Software Foundation; version 2 of that license or any later version.
13 # No warranty expressed or implied. See the file ‘LICENSE.GPL-2’ for details.
15 """ Implementation for HTTP upload method. """
17 from __future__
import absolute_import
25 from ..helper
import dputhelper
28 class PromptingPasswordMgr(urllib2
.HTTPPasswordMgr
):
29 """ Password manager that prompts at the terminal.
31 Custom HTTP password manager that prompts for a password using
32 getpass() if required, and mangles the saved URL so that only
33 one password is prompted for.
37 def __init__(self
, username
):
38 urllib2
.HTTPPasswordMgr
.__init
__(self
)
39 self
.username
= username
41 def find_user_password(self
, realm
, authuri
):
42 # Hack so that we only prompt for a password once
43 authuri
= self
.reduce_uri(authuri
)[0]
44 authinfo
= urllib2
.HTTPPasswordMgr
.find_user_password(
46 if authinfo
!= (None, None):
49 password
= getpass
.getpass(" Password for %s:" % realm
)
50 self
.add_password(realm
, authuri
, self
.username
, password
)
51 return (self
.username
, password
)
54 class AuthHandlerHackAround
:
55 """ Fake request and parent object. """
57 def __init__(self
, url
, resp_headers
, pwman
):
58 # fake request header dict
62 self
.resp_headers
= resp_headers
63 self
.authhandlers
= []
66 for authhandler_class
in [
67 urllib2
.HTTPBasicAuthHandler
, urllib2
.HTTPDigestAuthHandler
]:
68 ah
= authhandler_class(pwman
)
70 self
.authhandlers
.append(ah
)
72 # fake request methods
73 def add_header(self
, k
, v
):
76 def add_unredirected_header(self
, k
, v
):
79 def get_full_url(self
):
83 def open(self
, *args
, **keywords
):
86 # and what we really want
87 def get_auth_headers(self
):
88 for ah
in self
.authhandlers
:
90 ah
.http_error_401(self
, None, 401, None, self
.resp_headers
)
91 except ValueError as e
:
99 fqdn
, login
, incoming
, files_to_upload
, debug
, dummy
,
100 progress
=0, protocol
="http"):
101 """ Upload the files via WebDAV. """
103 # note: requires >= python 2.4 httplib
105 # EXCEPTION HANDLING!
106 if protocol
== 'https':
107 connclass
= httplib
.HTTPSConnection
108 elif protocol
== 'http':
109 connclass
= httplib
.HTTPConnection
111 sys
.stderr
.write("Wrong protocol for upload http[s].py method\n")
113 if not incoming
.startswith('/'):
114 incoming
= '/' + incoming
115 if not incoming
.endswith('/'):
117 unprocessed_files_to_upload
= files_to_upload
[:]
119 pwman
= PromptingPasswordMgr(login
)
120 while unprocessed_files_to_upload
:
121 afile
= unprocessed_files_to_upload
[0]
122 path_to_package
, package_name
= os
.path
.split(afile
)
123 sys
.stdout
.write(" Uploading %s: " % package_name
)
126 size
= os
.stat(afile
).st_size
128 sys
.stderr
.write("Determining size of file '%s' failed\n" % afile
)
130 f
= open(afile
, 'rb')
132 f
= dputhelper
.FileWithProgress(
134 progressf
=sys
.stderr
,
136 url_path
= incoming
+ package_name
137 url
= "%s://%s%s" % (protocol
, fqdn
, url_path
)
139 sys
.stdout
.write("D: HTTP-PUT to URL: %s\n" % url
)
140 conn
= connclass(fqdn
)
141 conn
.putrequest("PUT", url_path
, skip_accept_encoding
=True)
142 # Host: should be automatic
143 conn
.putheader('User-Agent', 'dput')
144 for k
, v
in auth_headers
.items():
146 conn
.putheader('Connection', 'close')
147 conn
.putheader('Content-Length', str(size
))
151 # sending in 64k steps (screws progress a bit)
157 res
= conn
.getresponse()
158 if res
.status
>= 200 and res
.status
< 300:
159 sys
.stdout
.write("done.\n")
160 del unprocessed_files_to_upload
[0]
161 elif res
.status
== 401 and not auth_headers
:
162 sys
.stdout
.write("need authentication.\n")
163 auth_headers
= AuthHandlerHackAround(
164 url
, res
.msg
, pwman
).get_auth_headers()
166 if res
.status
== 401:
168 "Upload failed as unauthorized: %s\n"
169 " Maybe wrong username or password?\n" % res
.reason
)
172 "Upload failed: %d %s\n" % (res
.status
, res
.reason
))
174 # must be done, but we're not interested
182 # vim: fileencoding=utf-8 filetype=python :