| 122 | | h.putheader('User-Agent', 'Trac/1.0') |
|---|
| 123 | | h.putheader('Connection', 'keep-alive') |
|---|
| 124 | | h.putheader('Transfer-Encoding', 'chunked') |
|---|
| 125 | | h.putheader('Expect', '100-continue') |
|---|
| 126 | | h.putheader('Accept', 'application/xml') |
|---|
| 127 | | h.putheader('Content-Type', 'text/xml') |
|---|
| 128 | | h.putheader('Content-Length', len(str(result))) |
|---|
| 129 | | if authorization: |
|---|
| 130 | | h.putheader('Authorization', authorization) |
|---|
| 131 | | h.endheaders() |
|---|
| | 120 | h.putheader('User-Agent', 'Trac/1.0') |
|---|
| | 121 | h.putheader('Accept', 'application/xml') |
|---|
| | 122 | h.putheader('Content-Type', 'text/xml') |
|---|
| | 123 | h.putheader('Authorization', authorization) |
|---|
| | 124 | h.putheader('Content-Length', len(data)) |
|---|
| | 125 | h.endheaders() |
|---|
| 151 | | # Got a response, now decide how to act upon it |
|---|
| 152 | | if status in redirect: |
|---|
| 153 | | location = resp.getheader('Location') |
|---|
| 154 | | uri = urlparse.urljoin(uri, location) |
|---|
| 155 | | host, port, path = parseuri(uri) |
|---|
| 156 | | |
|---|
| 157 | | # We may have to authenticate again |
|---|
| 158 | | if authorization: |
|---|
| 159 | | authorization = None |
|---|
| 160 | | |
|---|
| 161 | | elif status in authenticate: |
|---|
| 162 | | # If we've done this already, break |
|---|
| 163 | | if authorization: |
|---|
| 164 | | # barf("Going around in authentication circles") |
|---|
| 165 | | print "Authentication failed" |
|---|
| 166 | | return False |
|---|
| 167 | | |
|---|
| 168 | | if not (username and password): |
|---|
| 169 | | print "Need a username and password to authenticate with" |
|---|
| 170 | | return False |
|---|
| 171 | | |
|---|
| 172 | | # Get the scheme: Basic or Digest? |
|---|
| 173 | | wwwauth = resp.msg['www-authenticate'] # We may need this again |
|---|
| 174 | | wauth = wwwauth.lstrip(' \t') # Hence use wauth not wwwauth here |
|---|
| 175 | | wauth = wwwauth.replace('\t', ' ') |
|---|
| 176 | | i = wauth.index(' ') |
|---|
| 177 | | scheme = wauth[:i].lower() |
|---|
| 178 | | |
|---|
| 179 | | if scheme in set(['basic', 'digest']): |
|---|
| 180 | | if verbose: |
|---|
| 181 | | msg = "Performing %s Authentication..." % scheme.capitalize() |
|---|
| 182 | | print >> sys.stderr, msg |
|---|
| 183 | | else: |
|---|
| 184 | | print "Unknown authentication scheme: %s" % scheme |
|---|
| 185 | | return False |
|---|
| 186 | | |
|---|
| 187 | | if scheme == 'basic': |
|---|
| 188 | | import base64 |
|---|
| 189 | | userpass = username + ':' + password |
|---|
| 190 | | userpass = base64.encodestring(userpass).strip() |
|---|
| 191 | | authorized, authorization = True, 'Basic ' + userpass |
|---|
| 192 | | |
|---|
| 193 | | elif scheme == 'digest': |
|---|
| 194 | | if verbose: |
|---|
| 195 | | msg = "uses fragile, undocumented features in urllib2" |
|---|
| 196 | | print >> sys.stderr, "Warning! Digest Auth %s" % msg |
|---|
| 197 | | |
|---|
| 198 | | import urllib2 # See warning above |
|---|
| 199 | | |
|---|
| 200 | | passwd = type('Password', (object,), { |
|---|
| 201 | | 'find_user_password': lambda self, *args: (username, password), |
|---|
| 202 | | 'add_password': lambda self, *args: None |
|---|
| 203 | | })() |
|---|
| 204 | | |
|---|
| 205 | | xreq = type('Request', (object,), { |
|---|
| 206 | | 'get_full_url': lambda self: uri, |
|---|
| 207 | | 'has_data': lambda self: None, |
|---|
| 208 | | 'get_method': lambda self: 'PUT', |
|---|
| 209 | | 'get_selector': lambda self: path |
|---|
| 210 | | })() |
|---|
| 211 | | |
|---|
| 212 | | # Cf. urllib2.AbstractDigestAuthHandler.retry_http_digest_auth |
|---|
| 213 | | auth = urllib2.AbstractDigestAuthHandler(passwd) |
|---|
| 214 | | token, challenge = wwwauth.split(' ', 1) |
|---|
| 215 | | chal = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge)) |
|---|
| 216 | | userpass = auth.get_authorization(xreq, chal) |
|---|
| 217 | | authorized, authorization = True, 'Digest ' + userpass |
|---|
| 218 | | |
|---|
| 219 | | elif status in okay: |
|---|
| 220 | | if (username and password) and (not authorized): |
|---|
| 221 | | msg = "Warning! The supplied username and password went unused" |
|---|
| 222 | | print >> sys.stderr, msg |
|---|
| 223 | | |
|---|
| 224 | | if verbose: |
|---|
| 225 | | resultLine = "Success! Resource %s" |
|---|
| 226 | | statuses = {200: 'modified', 201: 'created', 204: 'modified'} |
|---|
| 227 | | print resultLine % statuses[status] |
|---|
| 228 | | |
|---|
| 229 | | statusLine = "Response-Status: %s %s" |
|---|
| 230 | | print statusLine % (status, resp.reason) |
|---|
| 231 | | |
|---|
| 232 | | body = resp.read(58) |
|---|
| 233 | | body = body.rstrip('\r\n') |
|---|
| 234 | | body = body.encode('string_escape') |
|---|
| 235 | | |
|---|
| 236 | | if len(body) >= 58: |
|---|
| 237 | | body = body[:57] + '[...]' |
|---|
| 238 | | |
|---|
| 239 | | bodyLine = 'Response-Body: "%s"' |
|---|
| 240 | | print bodyLine % body |
|---|
| 241 | | break |
|---|
| 242 | | |
|---|
| 243 | | # @@ raise PutError, do the catching in main? |
|---|
| 244 | | else: |
|---|
| 245 | | print 'Got "%s %s"' % (status, resp.reason) |
|---|
| 246 | | return False |
|---|
| 247 | | |
|---|
| 248 | | tries += 1 |
|---|
| 249 | | if tries >= 50: |
|---|
| 250 | | print "Too many redirects" |
|---|
| 251 | | return False |
|---|
| 252 | | |
|---|
| 253 | | print str(result) |
|---|