##// END OF EJS Templates
url: more bytes/unicodes fussing in url.py around auth handling...
Augie Fackler -
r36670:8381126b default
parent child Browse files
Show More
@@ -1,352 +1,353 b''
1 test-abort-checkin.t
1 test-abort-checkin.t
2 test-add.t
2 test-add.t
3 test-addremove-similar.t
3 test-addremove-similar.t
4 test-addremove.t
4 test-addremove.t
5 test-amend-subrepo.t
5 test-amend-subrepo.t
6 test-ancestor.py
6 test-ancestor.py
7 test-annotate.py
7 test-annotate.py
8 test-annotate.t
8 test-annotate.t
9 test-audit-path.t
9 test-audit-path.t
10 test-audit-subrepo.t
10 test-audit-subrepo.t
11 test-automv.t
11 test-automv.t
12 test-backout.t
12 test-backout.t
13 test-backwards-remove.t
13 test-backwards-remove.t
14 test-basic.t
14 test-basic.t
15 test-bheads.t
15 test-bheads.t
16 test-bisect2.t
16 test-bisect2.t
17 test-bookmarks-current.t
17 test-bookmarks-current.t
18 test-bookmarks-merge.t
18 test-bookmarks-merge.t
19 test-bookmarks-rebase.t
19 test-bookmarks-rebase.t
20 test-bookmarks-strip.t
20 test-bookmarks-strip.t
21 test-bookmarks.t
21 test-bookmarks.t
22 test-branch-option.t
22 test-branch-option.t
23 test-branch-tag-confict.t
23 test-branch-tag-confict.t
24 test-branches.t
24 test-branches.t
25 test-bundle-phases.t
25 test-bundle-phases.t
26 test-bundle-vs-outgoing.t
26 test-bundle-vs-outgoing.t
27 test-bundle2-multiple-changegroups.t
27 test-bundle2-multiple-changegroups.t
28 test-cappedreader.py
28 test-cappedreader.py
29 test-casecollision.t
29 test-casecollision.t
30 test-cat.t
30 test-cat.t
31 test-censor.t
31 test-censor.t
32 test-changelog-exec.t
32 test-changelog-exec.t
33 test-check-commit.t
33 test-check-commit.t
34 test-check-execute.t
34 test-check-execute.t
35 test-check-module-imports.t
35 test-check-module-imports.t
36 test-check-pyflakes.t
36 test-check-pyflakes.t
37 test-check-pylint.t
37 test-check-pylint.t
38 test-check-shbang.t
38 test-check-shbang.t
39 test-children.t
39 test-children.t
40 test-clone-pull-corruption.t
40 test-clone-pull-corruption.t
41 test-clone-r.t
41 test-clone-r.t
42 test-clone-update-order.t
42 test-clone-update-order.t
43 test-command-template.t
43 test-command-template.t
44 test-commit-amend.t
44 test-commit-amend.t
45 test-commit-unresolved.t
45 test-commit-unresolved.t
46 test-commit.t
46 test-commit.t
47 test-completion.t
47 test-completion.t
48 test-conflict.t
48 test-conflict.t
49 test-confused-revert.t
49 test-confused-revert.t
50 test-contrib-check-code.t
50 test-contrib-check-code.t
51 test-contrib-check-commit.t
51 test-contrib-check-commit.t
52 test-convert-authormap.t
52 test-convert-authormap.t
53 test-convert-clonebranches.t
53 test-convert-clonebranches.t
54 test-convert-datesort.t
54 test-convert-datesort.t
55 test-convert-filemap.t
55 test-convert-filemap.t
56 test-convert-hg-sink.t
56 test-convert-hg-sink.t
57 test-convert-hg-source.t
57 test-convert-hg-source.t
58 test-convert-hg-startrev.t
58 test-convert-hg-startrev.t
59 test-copy-move-merge.t
59 test-copy-move-merge.t
60 test-copytrace-heuristics.t
60 test-copytrace-heuristics.t
61 test-debugbuilddag.t
61 test-debugbuilddag.t
62 test-debugbundle.t
62 test-debugbundle.t
63 test-debugextensions.t
63 test-debugextensions.t
64 test-debugindexdot.t
64 test-debugindexdot.t
65 test-debugrename.t
65 test-debugrename.t
66 test-diff-binary-file.t
66 test-diff-binary-file.t
67 test-diff-change.t
67 test-diff-change.t
68 test-diff-copy-depth.t
68 test-diff-copy-depth.t
69 test-diff-hashes.t
69 test-diff-hashes.t
70 test-diff-issue2761.t
70 test-diff-issue2761.t
71 test-diff-newlines.t
71 test-diff-newlines.t
72 test-diff-reverse.t
72 test-diff-reverse.t
73 test-diff-subdir.t
73 test-diff-subdir.t
74 test-diffdir.t
74 test-diffdir.t
75 test-directaccess.t
75 test-directaccess.t
76 test-dirstate-backup.t
76 test-dirstate-backup.t
77 test-dirstate-nonnormalset.t
77 test-dirstate-nonnormalset.t
78 test-doctest.py
78 test-doctest.py
79 test-double-merge.t
79 test-double-merge.t
80 test-drawdag.t
80 test-drawdag.t
81 test-duplicateoptions.py
81 test-duplicateoptions.py
82 test-empty-dir.t
82 test-empty-dir.t
83 test-empty-file.t
83 test-empty-file.t
84 test-empty-group.t
84 test-empty-group.t
85 test-empty.t
85 test-empty.t
86 test-encoding-func.py
86 test-encoding-func.py
87 test-encoding.t
87 test-encoding.t
88 test-eol-add.t
88 test-eol-add.t
89 test-eol-clone.t
89 test-eol-clone.t
90 test-eol-tag.t
90 test-eol-tag.t
91 test-eol-update.t
91 test-eol-update.t
92 test-excessive-merge.t
92 test-excessive-merge.t
93 test-exchange-obsmarkers-case-A1.t
93 test-exchange-obsmarkers-case-A1.t
94 test-exchange-obsmarkers-case-A2.t
94 test-exchange-obsmarkers-case-A2.t
95 test-exchange-obsmarkers-case-A3.t
95 test-exchange-obsmarkers-case-A3.t
96 test-exchange-obsmarkers-case-A4.t
96 test-exchange-obsmarkers-case-A4.t
97 test-exchange-obsmarkers-case-A5.t
97 test-exchange-obsmarkers-case-A5.t
98 test-exchange-obsmarkers-case-A6.t
98 test-exchange-obsmarkers-case-A6.t
99 test-exchange-obsmarkers-case-A7.t
99 test-exchange-obsmarkers-case-A7.t
100 test-exchange-obsmarkers-case-B1.t
100 test-exchange-obsmarkers-case-B1.t
101 test-exchange-obsmarkers-case-B2.t
101 test-exchange-obsmarkers-case-B2.t
102 test-exchange-obsmarkers-case-B3.t
102 test-exchange-obsmarkers-case-B3.t
103 test-exchange-obsmarkers-case-B4.t
103 test-exchange-obsmarkers-case-B4.t
104 test-exchange-obsmarkers-case-B5.t
104 test-exchange-obsmarkers-case-B5.t
105 test-exchange-obsmarkers-case-B6.t
105 test-exchange-obsmarkers-case-B6.t
106 test-exchange-obsmarkers-case-B7.t
106 test-exchange-obsmarkers-case-B7.t
107 test-exchange-obsmarkers-case-C1.t
107 test-exchange-obsmarkers-case-C1.t
108 test-exchange-obsmarkers-case-C2.t
108 test-exchange-obsmarkers-case-C2.t
109 test-exchange-obsmarkers-case-C3.t
109 test-exchange-obsmarkers-case-C3.t
110 test-exchange-obsmarkers-case-C4.t
110 test-exchange-obsmarkers-case-C4.t
111 test-exchange-obsmarkers-case-D1.t
111 test-exchange-obsmarkers-case-D1.t
112 test-exchange-obsmarkers-case-D2.t
112 test-exchange-obsmarkers-case-D2.t
113 test-exchange-obsmarkers-case-D3.t
113 test-exchange-obsmarkers-case-D3.t
114 test-exchange-obsmarkers-case-D4.t
114 test-exchange-obsmarkers-case-D4.t
115 test-execute-bit.t
115 test-execute-bit.t
116 test-extdiff.t
116 test-extdiff.t
117 test-extra-filelog-entry.t
117 test-extra-filelog-entry.t
118 test-filebranch.t
118 test-filebranch.t
119 test-fileset-generated.t
119 test-fileset-generated.t
120 test-flags.t
120 test-flags.t
121 test-generaldelta.t
121 test-generaldelta.t
122 test-getbundle.t
122 test-getbundle.t
123 test-git-export.t
123 test-git-export.t
124 test-glog-topological.t
124 test-glog-topological.t
125 test-gpg.t
125 test-gpg.t
126 test-graft.t
126 test-graft.t
127 test-hghave.t
127 test-hghave.t
128 test-hgignore.t
128 test-hgignore.t
129 test-hgk.t
129 test-hgk.t
130 test-hgweb-removed.t
130 test-hgweb-removed.t
131 test-histedit-arguments.t
131 test-histedit-arguments.t
132 test-histedit-base.t
132 test-histedit-base.t
133 test-histedit-bookmark-motion.t
133 test-histedit-bookmark-motion.t
134 test-histedit-commute.t
134 test-histedit-commute.t
135 test-histedit-drop.t
135 test-histedit-drop.t
136 test-histedit-edit.t
136 test-histedit-edit.t
137 test-histedit-fold-non-commute.t
137 test-histedit-fold-non-commute.t
138 test-histedit-fold.t
138 test-histedit-fold.t
139 test-histedit-no-change.t
139 test-histedit-no-change.t
140 test-histedit-non-commute-abort.t
140 test-histedit-non-commute-abort.t
141 test-histedit-non-commute.t
141 test-histedit-non-commute.t
142 test-histedit-obsolete.t
142 test-histedit-obsolete.t
143 test-histedit-outgoing.t
143 test-histedit-outgoing.t
144 test-histedit-templates.t
144 test-histedit-templates.t
145 test-http-branchmap.t
145 test-http-branchmap.t
146 test-http-bundle1.t
146 test-http-clone-r.t
147 test-http-clone-r.t
147 test-identify.t
148 test-identify.t
148 test-imports-checker.t
149 test-imports-checker.t
149 test-inherit-mode.t
150 test-inherit-mode.t
150 test-issue1089.t
151 test-issue1089.t
151 test-issue1102.t
152 test-issue1102.t
152 test-issue1175.t
153 test-issue1175.t
153 test-issue1306.t
154 test-issue1306.t
154 test-issue1438.t
155 test-issue1438.t
155 test-issue1502.t
156 test-issue1502.t
156 test-issue1802.t
157 test-issue1802.t
157 test-issue1877.t
158 test-issue1877.t
158 test-issue1993.t
159 test-issue1993.t
159 test-issue2137.t
160 test-issue2137.t
160 test-issue3084.t
161 test-issue3084.t
161 test-issue4074.t
162 test-issue4074.t
162 test-issue522.t
163 test-issue522.t
163 test-issue586.t
164 test-issue586.t
164 test-issue612.t
165 test-issue612.t
165 test-issue619.t
166 test-issue619.t
166 test-issue672.t
167 test-issue672.t
167 test-issue842.t
168 test-issue842.t
168 test-journal-exists.t
169 test-journal-exists.t
169 test-largefiles-small-disk.t
170 test-largefiles-small-disk.t
170 test-locate.t
171 test-locate.t
171 test-lock-badness.t
172 test-lock-badness.t
172 test-logexchange.t
173 test-logexchange.t
173 test-lrucachedict.py
174 test-lrucachedict.py
174 test-mactext.t
175 test-mactext.t
175 test-manifest-merging.t
176 test-manifest-merging.t
176 test-manifest.py
177 test-manifest.py
177 test-manifest.t
178 test-manifest.t
178 test-match.py
179 test-match.py
179 test-mdiff.py
180 test-mdiff.py
180 test-merge-closedheads.t
181 test-merge-closedheads.t
181 test-merge-commit.t
182 test-merge-commit.t
182 test-merge-criss-cross.t
183 test-merge-criss-cross.t
183 test-merge-default.t
184 test-merge-default.t
184 test-merge-internal-tools-pattern.t
185 test-merge-internal-tools-pattern.t
185 test-merge-local.t
186 test-merge-local.t
186 test-merge-remove.t
187 test-merge-remove.t
187 test-merge-revert.t
188 test-merge-revert.t
188 test-merge-revert2.t
189 test-merge-revert2.t
189 test-merge-subrepos.t
190 test-merge-subrepos.t
190 test-merge-symlinks.t
191 test-merge-symlinks.t
191 test-merge-types.t
192 test-merge-types.t
192 test-merge1.t
193 test-merge1.t
193 test-merge10.t
194 test-merge10.t
194 test-merge2.t
195 test-merge2.t
195 test-merge4.t
196 test-merge4.t
196 test-merge5.t
197 test-merge5.t
197 test-merge6.t
198 test-merge6.t
198 test-merge7.t
199 test-merge7.t
199 test-merge8.t
200 test-merge8.t
200 test-merge9.t
201 test-merge9.t
201 test-mq-git.t
202 test-mq-git.t
202 test-mq-pull-from-bundle.t
203 test-mq-pull-from-bundle.t
203 test-mq-qdiff.t
204 test-mq-qdiff.t
204 test-mq-qimport-fail-cleanup.t
205 test-mq-qimport-fail-cleanup.t
205 test-mq-qqueue.t
206 test-mq-qqueue.t
206 test-mq-qrefresh.t
207 test-mq-qrefresh.t
207 test-mq-qsave.t
208 test-mq-qsave.t
208 test-narrow-clone-no-ellipsis.t
209 test-narrow-clone-no-ellipsis.t
209 test-narrow-clone-nonlinear.t
210 test-narrow-clone-nonlinear.t
210 test-narrow-clone.t
211 test-narrow-clone.t
211 test-narrow-commit.t
212 test-narrow-commit.t
212 test-narrow-copies.t
213 test-narrow-copies.t
213 test-narrow-debugrebuilddirstate.t
214 test-narrow-debugrebuilddirstate.t
214 test-narrow-exchange-merges.t
215 test-narrow-exchange-merges.t
215 test-narrow-exchange.t
216 test-narrow-exchange.t
216 test-narrow-merge.t
217 test-narrow-merge.t
217 test-narrow-patch.t
218 test-narrow-patch.t
218 test-narrow-patterns.t
219 test-narrow-patterns.t
219 test-narrow-pull.t
220 test-narrow-pull.t
220 test-narrow-rebase.t
221 test-narrow-rebase.t
221 test-narrow-shallow-merges.t
222 test-narrow-shallow-merges.t
222 test-narrow-shallow.t
223 test-narrow-shallow.t
223 test-narrow-update.t
224 test-narrow-update.t
224 test-newbranch.t
225 test-newbranch.t
225 test-obshistory.t
226 test-obshistory.t
226 test-obsmarker-template.t
227 test-obsmarker-template.t
227 test-obsmarkers-effectflag.t
228 test-obsmarkers-effectflag.t
228 test-obsolete-bundle-strip.t
229 test-obsolete-bundle-strip.t
229 test-obsolete-changeset-exchange.t
230 test-obsolete-changeset-exchange.t
230 test-obsolete-checkheads.t
231 test-obsolete-checkheads.t
231 test-obsolete-distributed.t
232 test-obsolete-distributed.t
232 test-obsolete-tag-cache.t
233 test-obsolete-tag-cache.t
233 test-parents.t
234 test-parents.t
234 test-pathconflicts-merge.t
235 test-pathconflicts-merge.t
235 test-pathconflicts-update.t
236 test-pathconflicts-update.t
236 test-pending.t
237 test-pending.t
237 test-permissions.t
238 test-permissions.t
238 test-phases.t
239 test-phases.t
239 test-pull-branch.t
240 test-pull-branch.t
240 test-pull-http.t
241 test-pull-http.t
241 test-pull-permission.t
242 test-pull-permission.t
242 test-pull-pull-corruption.t
243 test-pull-pull-corruption.t
243 test-pull-r.t
244 test-pull-r.t
244 test-pull-update.t
245 test-pull-update.t
245 test-purge.t
246 test-purge.t
246 test-push-checkheads-partial-C1.t
247 test-push-checkheads-partial-C1.t
247 test-push-checkheads-partial-C2.t
248 test-push-checkheads-partial-C2.t
248 test-push-checkheads-partial-C3.t
249 test-push-checkheads-partial-C3.t
249 test-push-checkheads-partial-C4.t
250 test-push-checkheads-partial-C4.t
250 test-push-checkheads-pruned-B1.t
251 test-push-checkheads-pruned-B1.t
251 test-push-checkheads-pruned-B2.t
252 test-push-checkheads-pruned-B2.t
252 test-push-checkheads-pruned-B3.t
253 test-push-checkheads-pruned-B3.t
253 test-push-checkheads-pruned-B4.t
254 test-push-checkheads-pruned-B4.t
254 test-push-checkheads-pruned-B5.t
255 test-push-checkheads-pruned-B5.t
255 test-push-checkheads-pruned-B6.t
256 test-push-checkheads-pruned-B6.t
256 test-push-checkheads-pruned-B7.t
257 test-push-checkheads-pruned-B7.t
257 test-push-checkheads-pruned-B8.t
258 test-push-checkheads-pruned-B8.t
258 test-push-checkheads-superceed-A1.t
259 test-push-checkheads-superceed-A1.t
259 test-push-checkheads-superceed-A2.t
260 test-push-checkheads-superceed-A2.t
260 test-push-checkheads-superceed-A3.t
261 test-push-checkheads-superceed-A3.t
261 test-push-checkheads-superceed-A4.t
262 test-push-checkheads-superceed-A4.t
262 test-push-checkheads-superceed-A5.t
263 test-push-checkheads-superceed-A5.t
263 test-push-checkheads-superceed-A6.t
264 test-push-checkheads-superceed-A6.t
264 test-push-checkheads-superceed-A7.t
265 test-push-checkheads-superceed-A7.t
265 test-push-checkheads-superceed-A8.t
266 test-push-checkheads-superceed-A8.t
266 test-push-checkheads-unpushed-D1.t
267 test-push-checkheads-unpushed-D1.t
267 test-push-checkheads-unpushed-D2.t
268 test-push-checkheads-unpushed-D2.t
268 test-push-checkheads-unpushed-D3.t
269 test-push-checkheads-unpushed-D3.t
269 test-push-checkheads-unpushed-D4.t
270 test-push-checkheads-unpushed-D4.t
270 test-push-checkheads-unpushed-D5.t
271 test-push-checkheads-unpushed-D5.t
271 test-push-checkheads-unpushed-D6.t
272 test-push-checkheads-unpushed-D6.t
272 test-push-checkheads-unpushed-D7.t
273 test-push-checkheads-unpushed-D7.t
273 test-push-http.t
274 test-push-http.t
274 test-push-warn.t
275 test-push-warn.t
275 test-pushvars.t
276 test-pushvars.t
276 test-rebase-abort.t
277 test-rebase-abort.t
277 test-rebase-base-flag.t
278 test-rebase-base-flag.t
278 test-rebase-bookmarks.t
279 test-rebase-bookmarks.t
279 test-rebase-brute-force.t
280 test-rebase-brute-force.t
280 test-rebase-cache.t
281 test-rebase-cache.t
281 test-rebase-check-restore.t
282 test-rebase-check-restore.t
282 test-rebase-collapse.t
283 test-rebase-collapse.t
283 test-rebase-dest.t
284 test-rebase-dest.t
284 test-rebase-detach.t
285 test-rebase-detach.t
285 test-rebase-emptycommit.t
286 test-rebase-emptycommit.t
286 test-rebase-inmemory.t
287 test-rebase-inmemory.t
287 test-rebase-interruptions.t
288 test-rebase-interruptions.t
288 test-rebase-issue-noparam-single-rev.t
289 test-rebase-issue-noparam-single-rev.t
289 test-rebase-legacy.t
290 test-rebase-legacy.t
290 test-rebase-named-branches.t
291 test-rebase-named-branches.t
291 test-rebase-newancestor.t
292 test-rebase-newancestor.t
292 test-rebase-obsolete.t
293 test-rebase-obsolete.t
293 test-rebase-parameters.t
294 test-rebase-parameters.t
294 test-rebase-partial.t
295 test-rebase-partial.t
295 test-rebase-pull.t
296 test-rebase-pull.t
296 test-rebase-rename.t
297 test-rebase-rename.t
297 test-rebase-scenario-global.t
298 test-rebase-scenario-global.t
298 test-rebase-templates.t
299 test-rebase-templates.t
299 test-rebase-transaction.t
300 test-rebase-transaction.t
300 test-record.t
301 test-record.t
301 test-relink.t
302 test-relink.t
302 test-remove.t
303 test-remove.t
303 test-rename-after-merge.t
304 test-rename-after-merge.t
304 test-rename-dir-merge.t
305 test-rename-dir-merge.t
305 test-rename-merge1.t
306 test-rename-merge1.t
306 test-rename.t
307 test-rename.t
307 test-repair-strip.t
308 test-repair-strip.t
308 test-repo-compengines.t
309 test-repo-compengines.t
309 test-resolve.t
310 test-resolve.t
310 test-revert-flags.t
311 test-revert-flags.t
311 test-revert-unknown.t
312 test-revert-unknown.t
312 test-revlog-ancestry.py
313 test-revlog-ancestry.py
313 test-revlog-group-emptyiter.t
314 test-revlog-group-emptyiter.t
314 test-revlog-mmapindex.t
315 test-revlog-mmapindex.t
315 test-revlog-packentry.t
316 test-revlog-packentry.t
316 test-revset-dirstate-parents.t
317 test-revset-dirstate-parents.t
317 test-revset-outgoing.t
318 test-revset-outgoing.t
318 test-run-tests.py
319 test-run-tests.py
319 test-serve.t
320 test-serve.t
320 test-share.t
321 test-share.t
321 test-show-stack.t
322 test-show-stack.t
322 test-show-work.t
323 test-show-work.t
323 test-show.t
324 test-show.t
324 test-simple-update.t
325 test-simple-update.t
325 test-single-head.t
326 test-single-head.t
326 test-sparse-clear.t
327 test-sparse-clear.t
327 test-sparse-merges.t
328 test-sparse-merges.t
328 test-sparse-requirement.t
329 test-sparse-requirement.t
329 test-sparse-verbose-json.t
330 test-sparse-verbose-json.t
330 test-ssh-clone-r.t
331 test-ssh-clone-r.t
331 test-ssh-proto.t
332 test-ssh-proto.t
332 test-sshserver.py
333 test-sshserver.py
333 test-status-rev.t
334 test-status-rev.t
334 test-status-terse.t
335 test-status-terse.t
335 test-strip-cross.t
336 test-strip-cross.t
336 test-strip.t
337 test-strip.t
337 test-unamend.t
338 test-unamend.t
338 test-uncommit.t
339 test-uncommit.t
339 test-unified-test.t
340 test-unified-test.t
340 test-unrelated-pull.t
341 test-unrelated-pull.t
341 test-up-local-change.t
342 test-up-local-change.t
342 test-update-branches.t
343 test-update-branches.t
343 test-update-dest.t
344 test-update-dest.t
344 test-update-issue1456.t
345 test-update-issue1456.t
345 test-update-names.t
346 test-update-names.t
346 test-update-reverse.t
347 test-update-reverse.t
347 test-url-rev.t
348 test-url-rev.t
348 test-username-newline.t
349 test-username-newline.t
349 test-verify.t
350 test-verify.t
350 test-websub.t
351 test-websub.t
351 test-win32text.t
352 test-win32text.t
352 test-xdg.t
353 test-xdg.t
@@ -1,531 +1,531 b''
1 # url.py - HTTP handling for mercurial
1 # url.py - HTTP handling for mercurial
2 #
2 #
3 # Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
4 # Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12 import base64
12 import base64
13 import os
13 import os
14 import socket
14 import socket
15
15
16 from .i18n import _
16 from .i18n import _
17 from . import (
17 from . import (
18 encoding,
18 encoding,
19 error,
19 error,
20 httpconnection as httpconnectionmod,
20 httpconnection as httpconnectionmod,
21 keepalive,
21 keepalive,
22 pycompat,
22 pycompat,
23 sslutil,
23 sslutil,
24 urllibcompat,
24 urllibcompat,
25 util,
25 util,
26 )
26 )
27
27
28 httplib = util.httplib
28 httplib = util.httplib
29 stringio = util.stringio
29 stringio = util.stringio
30 urlerr = util.urlerr
30 urlerr = util.urlerr
31 urlreq = util.urlreq
31 urlreq = util.urlreq
32
32
33 def escape(s, quote=None):
33 def escape(s, quote=None):
34 '''Replace special characters "&", "<" and ">" to HTML-safe sequences.
34 '''Replace special characters "&", "<" and ">" to HTML-safe sequences.
35 If the optional flag quote is true, the quotation mark character (")
35 If the optional flag quote is true, the quotation mark character (")
36 is also translated.
36 is also translated.
37
37
38 This is the same as cgi.escape in Python, but always operates on
38 This is the same as cgi.escape in Python, but always operates on
39 bytes, whereas cgi.escape in Python 3 only works on unicodes.
39 bytes, whereas cgi.escape in Python 3 only works on unicodes.
40 '''
40 '''
41 s = s.replace(b"&", b"&amp;")
41 s = s.replace(b"&", b"&amp;")
42 s = s.replace(b"<", b"&lt;")
42 s = s.replace(b"<", b"&lt;")
43 s = s.replace(b">", b"&gt;")
43 s = s.replace(b">", b"&gt;")
44 if quote:
44 if quote:
45 s = s.replace(b'"', b"&quot;")
45 s = s.replace(b'"', b"&quot;")
46 return s
46 return s
47
47
48 class passwordmgr(object):
48 class passwordmgr(object):
49 def __init__(self, ui, passwddb):
49 def __init__(self, ui, passwddb):
50 self.ui = ui
50 self.ui = ui
51 self.passwddb = passwddb
51 self.passwddb = passwddb
52
52
53 def add_password(self, realm, uri, user, passwd):
53 def add_password(self, realm, uri, user, passwd):
54 return self.passwddb.add_password(realm, uri, user, passwd)
54 return self.passwddb.add_password(realm, uri, user, passwd)
55
55
56 def find_user_password(self, realm, authuri):
56 def find_user_password(self, realm, authuri):
57 authinfo = self.passwddb.find_user_password(realm, authuri)
57 authinfo = self.passwddb.find_user_password(realm, authuri)
58 user, passwd = authinfo
58 user, passwd = authinfo
59 if user and passwd:
59 if user and passwd:
60 self._writedebug(user, passwd)
60 self._writedebug(user, passwd)
61 return (user, passwd)
61 return (user, passwd)
62
62
63 if not user or not passwd:
63 if not user or not passwd:
64 res = httpconnectionmod.readauthforuri(self.ui, authuri, user)
64 res = httpconnectionmod.readauthforuri(self.ui, authuri, user)
65 if res:
65 if res:
66 group, auth = res
66 group, auth = res
67 user, passwd = auth.get('username'), auth.get('password')
67 user, passwd = auth.get('username'), auth.get('password')
68 self.ui.debug("using auth.%s.* for authentication\n" % group)
68 self.ui.debug("using auth.%s.* for authentication\n" % group)
69 if not user or not passwd:
69 if not user or not passwd:
70 u = util.url(authuri)
70 u = util.url(pycompat.bytesurl(authuri))
71 u.query = None
71 u.query = None
72 if not self.ui.interactive():
72 if not self.ui.interactive():
73 raise error.Abort(_('http authorization required for %s') %
73 raise error.Abort(_('http authorization required for %s') %
74 util.hidepassword(bytes(u)))
74 util.hidepassword(bytes(u)))
75
75
76 self.ui.write(_("http authorization required for %s\n") %
76 self.ui.write(_("http authorization required for %s\n") %
77 util.hidepassword(bytes(u)))
77 util.hidepassword(bytes(u)))
78 self.ui.write(_("realm: %s\n") % realm)
78 self.ui.write(_("realm: %s\n") % pycompat.bytesurl(realm))
79 if user:
79 if user:
80 self.ui.write(_("user: %s\n") % user)
80 self.ui.write(_("user: %s\n") % user)
81 else:
81 else:
82 user = self.ui.prompt(_("user:"), default=None)
82 user = self.ui.prompt(_("user:"), default=None)
83
83
84 if not passwd:
84 if not passwd:
85 passwd = self.ui.getpass()
85 passwd = self.ui.getpass()
86
86
87 self.passwddb.add_password(realm, authuri, user, passwd)
87 self.passwddb.add_password(realm, authuri, user, passwd)
88 self._writedebug(user, passwd)
88 self._writedebug(user, passwd)
89 return (user, passwd)
89 return (user, passwd)
90
90
91 def _writedebug(self, user, passwd):
91 def _writedebug(self, user, passwd):
92 msg = _('http auth: user %s, password %s\n')
92 msg = _('http auth: user %s, password %s\n')
93 self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
93 self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
94
94
95 def find_stored_password(self, authuri):
95 def find_stored_password(self, authuri):
96 return self.passwddb.find_user_password(None, authuri)
96 return self.passwddb.find_user_password(None, authuri)
97
97
98 class proxyhandler(urlreq.proxyhandler):
98 class proxyhandler(urlreq.proxyhandler):
99 def __init__(self, ui):
99 def __init__(self, ui):
100 proxyurl = (ui.config("http_proxy", "host") or
100 proxyurl = (ui.config("http_proxy", "host") or
101 encoding.environ.get('http_proxy'))
101 encoding.environ.get('http_proxy'))
102 # XXX proxyauthinfo = None
102 # XXX proxyauthinfo = None
103
103
104 if proxyurl:
104 if proxyurl:
105 # proxy can be proper url or host[:port]
105 # proxy can be proper url or host[:port]
106 if not (proxyurl.startswith('http:') or
106 if not (proxyurl.startswith('http:') or
107 proxyurl.startswith('https:')):
107 proxyurl.startswith('https:')):
108 proxyurl = 'http://' + proxyurl + '/'
108 proxyurl = 'http://' + proxyurl + '/'
109 proxy = util.url(proxyurl)
109 proxy = util.url(proxyurl)
110 if not proxy.user:
110 if not proxy.user:
111 proxy.user = ui.config("http_proxy", "user")
111 proxy.user = ui.config("http_proxy", "user")
112 proxy.passwd = ui.config("http_proxy", "passwd")
112 proxy.passwd = ui.config("http_proxy", "passwd")
113
113
114 # see if we should use a proxy for this url
114 # see if we should use a proxy for this url
115 no_list = ["localhost", "127.0.0.1"]
115 no_list = ["localhost", "127.0.0.1"]
116 no_list.extend([p.lower() for
116 no_list.extend([p.lower() for
117 p in ui.configlist("http_proxy", "no")])
117 p in ui.configlist("http_proxy", "no")])
118 no_list.extend([p.strip().lower() for
118 no_list.extend([p.strip().lower() for
119 p in encoding.environ.get("no_proxy", '').split(',')
119 p in encoding.environ.get("no_proxy", '').split(',')
120 if p.strip()])
120 if p.strip()])
121 # "http_proxy.always" config is for running tests on localhost
121 # "http_proxy.always" config is for running tests on localhost
122 if ui.configbool("http_proxy", "always"):
122 if ui.configbool("http_proxy", "always"):
123 self.no_list = []
123 self.no_list = []
124 else:
124 else:
125 self.no_list = no_list
125 self.no_list = no_list
126
126
127 proxyurl = bytes(proxy)
127 proxyurl = bytes(proxy)
128 proxies = {'http': proxyurl, 'https': proxyurl}
128 proxies = {'http': proxyurl, 'https': proxyurl}
129 ui.debug('proxying through %s\n' % util.hidepassword(proxyurl))
129 ui.debug('proxying through %s\n' % util.hidepassword(proxyurl))
130 else:
130 else:
131 proxies = {}
131 proxies = {}
132
132
133 urlreq.proxyhandler.__init__(self, proxies)
133 urlreq.proxyhandler.__init__(self, proxies)
134 self.ui = ui
134 self.ui = ui
135
135
136 def proxy_open(self, req, proxy, type_):
136 def proxy_open(self, req, proxy, type_):
137 host = urllibcompat.gethost(req).split(':')[0]
137 host = urllibcompat.gethost(req).split(':')[0]
138 for e in self.no_list:
138 for e in self.no_list:
139 if host == e:
139 if host == e:
140 return None
140 return None
141 if e.startswith('*.') and host.endswith(e[2:]):
141 if e.startswith('*.') and host.endswith(e[2:]):
142 return None
142 return None
143 if e.startswith('.') and host.endswith(e[1:]):
143 if e.startswith('.') and host.endswith(e[1:]):
144 return None
144 return None
145
145
146 return urlreq.proxyhandler.proxy_open(self, req, proxy, type_)
146 return urlreq.proxyhandler.proxy_open(self, req, proxy, type_)
147
147
148 def _gen_sendfile(orgsend):
148 def _gen_sendfile(orgsend):
149 def _sendfile(self, data):
149 def _sendfile(self, data):
150 # send a file
150 # send a file
151 if isinstance(data, httpconnectionmod.httpsendfile):
151 if isinstance(data, httpconnectionmod.httpsendfile):
152 # if auth required, some data sent twice, so rewind here
152 # if auth required, some data sent twice, so rewind here
153 data.seek(0)
153 data.seek(0)
154 for chunk in util.filechunkiter(data):
154 for chunk in util.filechunkiter(data):
155 orgsend(self, chunk)
155 orgsend(self, chunk)
156 else:
156 else:
157 orgsend(self, data)
157 orgsend(self, data)
158 return _sendfile
158 return _sendfile
159
159
160 has_https = util.safehasattr(urlreq, 'httpshandler')
160 has_https = util.safehasattr(urlreq, 'httpshandler')
161
161
162 class httpconnection(keepalive.HTTPConnection):
162 class httpconnection(keepalive.HTTPConnection):
163 # must be able to send big bundle as stream.
163 # must be able to send big bundle as stream.
164 send = _gen_sendfile(keepalive.HTTPConnection.send)
164 send = _gen_sendfile(keepalive.HTTPConnection.send)
165
165
166 def getresponse(self):
166 def getresponse(self):
167 proxyres = getattr(self, 'proxyres', None)
167 proxyres = getattr(self, 'proxyres', None)
168 if proxyres:
168 if proxyres:
169 if proxyres.will_close:
169 if proxyres.will_close:
170 self.close()
170 self.close()
171 self.proxyres = None
171 self.proxyres = None
172 return proxyres
172 return proxyres
173 return keepalive.HTTPConnection.getresponse(self)
173 return keepalive.HTTPConnection.getresponse(self)
174
174
175 # general transaction handler to support different ways to handle
175 # general transaction handler to support different ways to handle
176 # HTTPS proxying before and after Python 2.6.3.
176 # HTTPS proxying before and after Python 2.6.3.
177 def _generic_start_transaction(handler, h, req):
177 def _generic_start_transaction(handler, h, req):
178 tunnel_host = getattr(req, '_tunnel_host', None)
178 tunnel_host = getattr(req, '_tunnel_host', None)
179 if tunnel_host:
179 if tunnel_host:
180 if tunnel_host[:7] not in ['http://', 'https:/']:
180 if tunnel_host[:7] not in ['http://', 'https:/']:
181 tunnel_host = 'https://' + tunnel_host
181 tunnel_host = 'https://' + tunnel_host
182 new_tunnel = True
182 new_tunnel = True
183 else:
183 else:
184 tunnel_host = urllibcompat.getselector(req)
184 tunnel_host = urllibcompat.getselector(req)
185 new_tunnel = False
185 new_tunnel = False
186
186
187 if new_tunnel or tunnel_host == urllibcompat.getfullurl(req): # has proxy
187 if new_tunnel or tunnel_host == urllibcompat.getfullurl(req): # has proxy
188 u = util.url(tunnel_host)
188 u = util.url(tunnel_host)
189 if new_tunnel or u.scheme == 'https': # only use CONNECT for HTTPS
189 if new_tunnel or u.scheme == 'https': # only use CONNECT for HTTPS
190 h.realhostport = ':'.join([u.host, (u.port or '443')])
190 h.realhostport = ':'.join([u.host, (u.port or '443')])
191 h.headers = req.headers.copy()
191 h.headers = req.headers.copy()
192 h.headers.update(handler.parent.addheaders)
192 h.headers.update(handler.parent.addheaders)
193 return
193 return
194
194
195 h.realhostport = None
195 h.realhostport = None
196 h.headers = None
196 h.headers = None
197
197
198 def _generic_proxytunnel(self):
198 def _generic_proxytunnel(self):
199 proxyheaders = dict(
199 proxyheaders = dict(
200 [(x, self.headers[x]) for x in self.headers
200 [(x, self.headers[x]) for x in self.headers
201 if x.lower().startswith('proxy-')])
201 if x.lower().startswith('proxy-')])
202 self.send('CONNECT %s HTTP/1.0\r\n' % self.realhostport)
202 self.send('CONNECT %s HTTP/1.0\r\n' % self.realhostport)
203 for header in proxyheaders.iteritems():
203 for header in proxyheaders.iteritems():
204 self.send('%s: %s\r\n' % header)
204 self.send('%s: %s\r\n' % header)
205 self.send('\r\n')
205 self.send('\r\n')
206
206
207 # majority of the following code is duplicated from
207 # majority of the following code is duplicated from
208 # httplib.HTTPConnection as there are no adequate places to
208 # httplib.HTTPConnection as there are no adequate places to
209 # override functions to provide the needed functionality
209 # override functions to provide the needed functionality
210 res = self.response_class(self.sock,
210 res = self.response_class(self.sock,
211 strict=self.strict,
211 strict=self.strict,
212 method=self._method)
212 method=self._method)
213
213
214 while True:
214 while True:
215 version, status, reason = res._read_status()
215 version, status, reason = res._read_status()
216 if status != httplib.CONTINUE:
216 if status != httplib.CONTINUE:
217 break
217 break
218 # skip lines that are all whitespace
218 # skip lines that are all whitespace
219 list(iter(lambda: res.fp.readline().strip(), ''))
219 list(iter(lambda: res.fp.readline().strip(), ''))
220 res.status = status
220 res.status = status
221 res.reason = reason.strip()
221 res.reason = reason.strip()
222
222
223 if res.status == 200:
223 if res.status == 200:
224 # skip lines until we find a blank line
224 # skip lines until we find a blank line
225 list(iter(res.fp.readline, '\r\n'))
225 list(iter(res.fp.readline, '\r\n'))
226 return True
226 return True
227
227
228 if version == 'HTTP/1.0':
228 if version == 'HTTP/1.0':
229 res.version = 10
229 res.version = 10
230 elif version.startswith('HTTP/1.'):
230 elif version.startswith('HTTP/1.'):
231 res.version = 11
231 res.version = 11
232 elif version == 'HTTP/0.9':
232 elif version == 'HTTP/0.9':
233 res.version = 9
233 res.version = 9
234 else:
234 else:
235 raise httplib.UnknownProtocol(version)
235 raise httplib.UnknownProtocol(version)
236
236
237 if res.version == 9:
237 if res.version == 9:
238 res.length = None
238 res.length = None
239 res.chunked = 0
239 res.chunked = 0
240 res.will_close = 1
240 res.will_close = 1
241 res.msg = httplib.HTTPMessage(stringio())
241 res.msg = httplib.HTTPMessage(stringio())
242 return False
242 return False
243
243
244 res.msg = httplib.HTTPMessage(res.fp)
244 res.msg = httplib.HTTPMessage(res.fp)
245 res.msg.fp = None
245 res.msg.fp = None
246
246
247 # are we using the chunked-style of transfer encoding?
247 # are we using the chunked-style of transfer encoding?
248 trenc = res.msg.getheader('transfer-encoding')
248 trenc = res.msg.getheader('transfer-encoding')
249 if trenc and trenc.lower() == "chunked":
249 if trenc and trenc.lower() == "chunked":
250 res.chunked = 1
250 res.chunked = 1
251 res.chunk_left = None
251 res.chunk_left = None
252 else:
252 else:
253 res.chunked = 0
253 res.chunked = 0
254
254
255 # will the connection close at the end of the response?
255 # will the connection close at the end of the response?
256 res.will_close = res._check_close()
256 res.will_close = res._check_close()
257
257
258 # do we have a Content-Length?
258 # do we have a Content-Length?
259 # NOTE: RFC 2616, section 4.4, #3 says we ignore this if
259 # NOTE: RFC 2616, section 4.4, #3 says we ignore this if
260 # transfer-encoding is "chunked"
260 # transfer-encoding is "chunked"
261 length = res.msg.getheader('content-length')
261 length = res.msg.getheader('content-length')
262 if length and not res.chunked:
262 if length and not res.chunked:
263 try:
263 try:
264 res.length = int(length)
264 res.length = int(length)
265 except ValueError:
265 except ValueError:
266 res.length = None
266 res.length = None
267 else:
267 else:
268 if res.length < 0: # ignore nonsensical negative lengths
268 if res.length < 0: # ignore nonsensical negative lengths
269 res.length = None
269 res.length = None
270 else:
270 else:
271 res.length = None
271 res.length = None
272
272
273 # does the body have a fixed length? (of zero)
273 # does the body have a fixed length? (of zero)
274 if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or
274 if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or
275 100 <= status < 200 or # 1xx codes
275 100 <= status < 200 or # 1xx codes
276 res._method == 'HEAD'):
276 res._method == 'HEAD'):
277 res.length = 0
277 res.length = 0
278
278
279 # if the connection remains open, and we aren't using chunked, and
279 # if the connection remains open, and we aren't using chunked, and
280 # a content-length was not provided, then assume that the connection
280 # a content-length was not provided, then assume that the connection
281 # WILL close.
281 # WILL close.
282 if (not res.will_close and
282 if (not res.will_close and
283 not res.chunked and
283 not res.chunked and
284 res.length is None):
284 res.length is None):
285 res.will_close = 1
285 res.will_close = 1
286
286
287 self.proxyres = res
287 self.proxyres = res
288
288
289 return False
289 return False
290
290
291 class httphandler(keepalive.HTTPHandler):
291 class httphandler(keepalive.HTTPHandler):
292 def http_open(self, req):
292 def http_open(self, req):
293 return self.do_open(httpconnection, req)
293 return self.do_open(httpconnection, req)
294
294
295 def _start_transaction(self, h, req):
295 def _start_transaction(self, h, req):
296 _generic_start_transaction(self, h, req)
296 _generic_start_transaction(self, h, req)
297 return keepalive.HTTPHandler._start_transaction(self, h, req)
297 return keepalive.HTTPHandler._start_transaction(self, h, req)
298
298
299 if has_https:
299 if has_https:
300 class httpsconnection(httplib.HTTPConnection):
300 class httpsconnection(httplib.HTTPConnection):
301 response_class = keepalive.HTTPResponse
301 response_class = keepalive.HTTPResponse
302 default_port = httplib.HTTPS_PORT
302 default_port = httplib.HTTPS_PORT
303 # must be able to send big bundle as stream.
303 # must be able to send big bundle as stream.
304 send = _gen_sendfile(keepalive.safesend)
304 send = _gen_sendfile(keepalive.safesend)
305 getresponse = keepalive.wrapgetresponse(httplib.HTTPConnection)
305 getresponse = keepalive.wrapgetresponse(httplib.HTTPConnection)
306
306
307 def __init__(self, host, port=None, key_file=None, cert_file=None,
307 def __init__(self, host, port=None, key_file=None, cert_file=None,
308 *args, **kwargs):
308 *args, **kwargs):
309 httplib.HTTPConnection.__init__(self, host, port, *args, **kwargs)
309 httplib.HTTPConnection.__init__(self, host, port, *args, **kwargs)
310 self.key_file = key_file
310 self.key_file = key_file
311 self.cert_file = cert_file
311 self.cert_file = cert_file
312
312
313 def connect(self):
313 def connect(self):
314 self.sock = socket.create_connection((self.host, self.port))
314 self.sock = socket.create_connection((self.host, self.port))
315
315
316 host = self.host
316 host = self.host
317 if self.realhostport: # use CONNECT proxy
317 if self.realhostport: # use CONNECT proxy
318 _generic_proxytunnel(self)
318 _generic_proxytunnel(self)
319 host = self.realhostport.rsplit(':', 1)[0]
319 host = self.realhostport.rsplit(':', 1)[0]
320 self.sock = sslutil.wrapsocket(
320 self.sock = sslutil.wrapsocket(
321 self.sock, self.key_file, self.cert_file, ui=self.ui,
321 self.sock, self.key_file, self.cert_file, ui=self.ui,
322 serverhostname=host)
322 serverhostname=host)
323 sslutil.validatesocket(self.sock)
323 sslutil.validatesocket(self.sock)
324
324
325 class httpshandler(keepalive.KeepAliveHandler, urlreq.httpshandler):
325 class httpshandler(keepalive.KeepAliveHandler, urlreq.httpshandler):
326 def __init__(self, ui):
326 def __init__(self, ui):
327 keepalive.KeepAliveHandler.__init__(self)
327 keepalive.KeepAliveHandler.__init__(self)
328 urlreq.httpshandler.__init__(self)
328 urlreq.httpshandler.__init__(self)
329 self.ui = ui
329 self.ui = ui
330 self.pwmgr = passwordmgr(self.ui,
330 self.pwmgr = passwordmgr(self.ui,
331 self.ui.httppasswordmgrdb)
331 self.ui.httppasswordmgrdb)
332
332
333 def _start_transaction(self, h, req):
333 def _start_transaction(self, h, req):
334 _generic_start_transaction(self, h, req)
334 _generic_start_transaction(self, h, req)
335 return keepalive.KeepAliveHandler._start_transaction(self, h, req)
335 return keepalive.KeepAliveHandler._start_transaction(self, h, req)
336
336
337 def https_open(self, req):
337 def https_open(self, req):
338 # urllibcompat.getfullurl() does not contain credentials
338 # urllibcompat.getfullurl() does not contain credentials
339 # and we may need them to match the certificates.
339 # and we may need them to match the certificates.
340 url = urllibcompat.getfullurl(req)
340 url = urllibcompat.getfullurl(req)
341 user, password = self.pwmgr.find_stored_password(url)
341 user, password = self.pwmgr.find_stored_password(url)
342 res = httpconnectionmod.readauthforuri(self.ui, url, user)
342 res = httpconnectionmod.readauthforuri(self.ui, url, user)
343 if res:
343 if res:
344 group, auth = res
344 group, auth = res
345 self.auth = auth
345 self.auth = auth
346 self.ui.debug("using auth.%s.* for authentication\n" % group)
346 self.ui.debug("using auth.%s.* for authentication\n" % group)
347 else:
347 else:
348 self.auth = None
348 self.auth = None
349 return self.do_open(self._makeconnection, req)
349 return self.do_open(self._makeconnection, req)
350
350
351 def _makeconnection(self, host, port=None, *args, **kwargs):
351 def _makeconnection(self, host, port=None, *args, **kwargs):
352 keyfile = None
352 keyfile = None
353 certfile = None
353 certfile = None
354
354
355 if len(args) >= 1: # key_file
355 if len(args) >= 1: # key_file
356 keyfile = args[0]
356 keyfile = args[0]
357 if len(args) >= 2: # cert_file
357 if len(args) >= 2: # cert_file
358 certfile = args[1]
358 certfile = args[1]
359 args = args[2:]
359 args = args[2:]
360
360
361 # if the user has specified different key/cert files in
361 # if the user has specified different key/cert files in
362 # hgrc, we prefer these
362 # hgrc, we prefer these
363 if self.auth and 'key' in self.auth and 'cert' in self.auth:
363 if self.auth and 'key' in self.auth and 'cert' in self.auth:
364 keyfile = self.auth['key']
364 keyfile = self.auth['key']
365 certfile = self.auth['cert']
365 certfile = self.auth['cert']
366
366
367 conn = httpsconnection(host, port, keyfile, certfile, *args,
367 conn = httpsconnection(host, port, keyfile, certfile, *args,
368 **kwargs)
368 **kwargs)
369 conn.ui = self.ui
369 conn.ui = self.ui
370 return conn
370 return conn
371
371
372 class httpdigestauthhandler(urlreq.httpdigestauthhandler):
372 class httpdigestauthhandler(urlreq.httpdigestauthhandler):
373 def __init__(self, *args, **kwargs):
373 def __init__(self, *args, **kwargs):
374 urlreq.httpdigestauthhandler.__init__(self, *args, **kwargs)
374 urlreq.httpdigestauthhandler.__init__(self, *args, **kwargs)
375 self.retried_req = None
375 self.retried_req = None
376
376
377 def reset_retry_count(self):
377 def reset_retry_count(self):
378 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
378 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
379 # forever. We disable reset_retry_count completely and reset in
379 # forever. We disable reset_retry_count completely and reset in
380 # http_error_auth_reqed instead.
380 # http_error_auth_reqed instead.
381 pass
381 pass
382
382
383 def http_error_auth_reqed(self, auth_header, host, req, headers):
383 def http_error_auth_reqed(self, auth_header, host, req, headers):
384 # Reset the retry counter once for each request.
384 # Reset the retry counter once for each request.
385 if req is not self.retried_req:
385 if req is not self.retried_req:
386 self.retried_req = req
386 self.retried_req = req
387 self.retried = 0
387 self.retried = 0
388 return urlreq.httpdigestauthhandler.http_error_auth_reqed(
388 return urlreq.httpdigestauthhandler.http_error_auth_reqed(
389 self, auth_header, host, req, headers)
389 self, auth_header, host, req, headers)
390
390
391 class httpbasicauthhandler(urlreq.httpbasicauthhandler):
391 class httpbasicauthhandler(urlreq.httpbasicauthhandler):
392 def __init__(self, *args, **kwargs):
392 def __init__(self, *args, **kwargs):
393 self.auth = None
393 self.auth = None
394 urlreq.httpbasicauthhandler.__init__(self, *args, **kwargs)
394 urlreq.httpbasicauthhandler.__init__(self, *args, **kwargs)
395 self.retried_req = None
395 self.retried_req = None
396
396
397 def http_request(self, request):
397 def http_request(self, request):
398 if self.auth:
398 if self.auth:
399 request.add_unredirected_header(self.auth_header, self.auth)
399 request.add_unredirected_header(self.auth_header, self.auth)
400
400
401 return request
401 return request
402
402
403 def https_request(self, request):
403 def https_request(self, request):
404 if self.auth:
404 if self.auth:
405 request.add_unredirected_header(self.auth_header, self.auth)
405 request.add_unredirected_header(self.auth_header, self.auth)
406
406
407 return request
407 return request
408
408
409 def reset_retry_count(self):
409 def reset_retry_count(self):
410 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
410 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
411 # forever. We disable reset_retry_count completely and reset in
411 # forever. We disable reset_retry_count completely and reset in
412 # http_error_auth_reqed instead.
412 # http_error_auth_reqed instead.
413 pass
413 pass
414
414
415 def http_error_auth_reqed(self, auth_header, host, req, headers):
415 def http_error_auth_reqed(self, auth_header, host, req, headers):
416 # Reset the retry counter once for each request.
416 # Reset the retry counter once for each request.
417 if req is not self.retried_req:
417 if req is not self.retried_req:
418 self.retried_req = req
418 self.retried_req = req
419 self.retried = 0
419 self.retried = 0
420 return urlreq.httpbasicauthhandler.http_error_auth_reqed(
420 return urlreq.httpbasicauthhandler.http_error_auth_reqed(
421 self, auth_header, host, req, headers)
421 self, auth_header, host, req, headers)
422
422
423 def retry_http_basic_auth(self, host, req, realm):
423 def retry_http_basic_auth(self, host, req, realm):
424 user, pw = self.passwd.find_user_password(
424 user, pw = self.passwd.find_user_password(
425 realm, urllibcompat.getfullurl(req))
425 realm, urllibcompat.getfullurl(req))
426 if pw is not None:
426 if pw is not None:
427 raw = "%s:%s" % (user, pw)
427 raw = "%s:%s" % (pycompat.bytesurl(user), pycompat.bytesurl(pw))
428 auth = 'Basic %s' % base64.b64encode(raw).strip()
428 auth = r'Basic %s' % pycompat.strurl(base64.b64encode(raw).strip())
429 if req.get_header(self.auth_header, None) == auth:
429 if req.get_header(self.auth_header, None) == auth:
430 return None
430 return None
431 self.auth = auth
431 self.auth = auth
432 req.add_unredirected_header(self.auth_header, auth)
432 req.add_unredirected_header(self.auth_header, auth)
433 return self.parent.open(req)
433 return self.parent.open(req)
434 else:
434 else:
435 return None
435 return None
436
436
437 class cookiehandler(urlreq.basehandler):
437 class cookiehandler(urlreq.basehandler):
438 def __init__(self, ui):
438 def __init__(self, ui):
439 self.cookiejar = None
439 self.cookiejar = None
440
440
441 cookiefile = ui.config('auth', 'cookiefile')
441 cookiefile = ui.config('auth', 'cookiefile')
442 if not cookiefile:
442 if not cookiefile:
443 return
443 return
444
444
445 cookiefile = util.expandpath(cookiefile)
445 cookiefile = util.expandpath(cookiefile)
446 try:
446 try:
447 cookiejar = util.cookielib.MozillaCookieJar(cookiefile)
447 cookiejar = util.cookielib.MozillaCookieJar(cookiefile)
448 cookiejar.load()
448 cookiejar.load()
449 self.cookiejar = cookiejar
449 self.cookiejar = cookiejar
450 except util.cookielib.LoadError as e:
450 except util.cookielib.LoadError as e:
451 ui.warn(_('(error loading cookie file %s: %s; continuing without '
451 ui.warn(_('(error loading cookie file %s: %s; continuing without '
452 'cookies)\n') % (cookiefile, util.forcebytestr(e)))
452 'cookies)\n') % (cookiefile, util.forcebytestr(e)))
453
453
454 def http_request(self, request):
454 def http_request(self, request):
455 if self.cookiejar:
455 if self.cookiejar:
456 self.cookiejar.add_cookie_header(request)
456 self.cookiejar.add_cookie_header(request)
457
457
458 return request
458 return request
459
459
460 def https_request(self, request):
460 def https_request(self, request):
461 if self.cookiejar:
461 if self.cookiejar:
462 self.cookiejar.add_cookie_header(request)
462 self.cookiejar.add_cookie_header(request)
463
463
464 return request
464 return request
465
465
466 handlerfuncs = []
466 handlerfuncs = []
467
467
468 def opener(ui, authinfo=None, useragent=None):
468 def opener(ui, authinfo=None, useragent=None):
469 '''
469 '''
470 construct an opener suitable for urllib2
470 construct an opener suitable for urllib2
471 authinfo will be added to the password manager
471 authinfo will be added to the password manager
472 '''
472 '''
473 handlers = [httphandler()]
473 handlers = [httphandler()]
474 if has_https:
474 if has_https:
475 handlers.append(httpshandler(ui))
475 handlers.append(httpshandler(ui))
476
476
477 handlers.append(proxyhandler(ui))
477 handlers.append(proxyhandler(ui))
478
478
479 passmgr = passwordmgr(ui, ui.httppasswordmgrdb)
479 passmgr = passwordmgr(ui, ui.httppasswordmgrdb)
480 if authinfo is not None:
480 if authinfo is not None:
481 realm, uris, user, passwd = authinfo
481 realm, uris, user, passwd = authinfo
482 saveduser, savedpass = passmgr.find_stored_password(uris[0])
482 saveduser, savedpass = passmgr.find_stored_password(uris[0])
483 if user != saveduser or passwd:
483 if user != saveduser or passwd:
484 passmgr.add_password(realm, uris, user, passwd)
484 passmgr.add_password(realm, uris, user, passwd)
485 ui.debug('http auth: user %s, password %s\n' %
485 ui.debug('http auth: user %s, password %s\n' %
486 (user, passwd and '*' * len(passwd) or 'not set'))
486 (user, passwd and '*' * len(passwd) or 'not set'))
487
487
488 handlers.extend((httpbasicauthhandler(passmgr),
488 handlers.extend((httpbasicauthhandler(passmgr),
489 httpdigestauthhandler(passmgr)))
489 httpdigestauthhandler(passmgr)))
490 handlers.extend([h(ui, passmgr) for h in handlerfuncs])
490 handlers.extend([h(ui, passmgr) for h in handlerfuncs])
491 handlers.append(cookiehandler(ui))
491 handlers.append(cookiehandler(ui))
492 opener = urlreq.buildopener(*handlers)
492 opener = urlreq.buildopener(*handlers)
493
493
494 # The user agent should should *NOT* be used by servers for e.g.
494 # The user agent should should *NOT* be used by servers for e.g.
495 # protocol detection or feature negotiation: there are other
495 # protocol detection or feature negotiation: there are other
496 # facilities for that.
496 # facilities for that.
497 #
497 #
498 # "mercurial/proto-1.0" was the original user agent string and
498 # "mercurial/proto-1.0" was the original user agent string and
499 # exists for backwards compatibility reasons.
499 # exists for backwards compatibility reasons.
500 #
500 #
501 # The "(Mercurial %s)" string contains the distribution
501 # The "(Mercurial %s)" string contains the distribution
502 # name and version. Other client implementations should choose their
502 # name and version. Other client implementations should choose their
503 # own distribution name. Since servers should not be using the user
503 # own distribution name. Since servers should not be using the user
504 # agent string for anything, clients should be able to define whatever
504 # agent string for anything, clients should be able to define whatever
505 # user agent they deem appropriate.
505 # user agent they deem appropriate.
506 #
506 #
507 # The custom user agent is for lfs, because unfortunately some servers
507 # The custom user agent is for lfs, because unfortunately some servers
508 # do look at this value.
508 # do look at this value.
509 if not useragent:
509 if not useragent:
510 agent = 'mercurial/proto-1.0 (Mercurial %s)' % util.version()
510 agent = 'mercurial/proto-1.0 (Mercurial %s)' % util.version()
511 opener.addheaders = [(r'User-agent', pycompat.sysstr(agent))]
511 opener.addheaders = [(r'User-agent', pycompat.sysstr(agent))]
512 else:
512 else:
513 opener.addheaders = [(r'User-agent', pycompat.sysstr(useragent))]
513 opener.addheaders = [(r'User-agent', pycompat.sysstr(useragent))]
514
514
515 # This header should only be needed by wire protocol requests. But it has
515 # This header should only be needed by wire protocol requests. But it has
516 # been sent on all requests since forever. We keep sending it for backwards
516 # been sent on all requests since forever. We keep sending it for backwards
517 # compatibility reasons. Modern versions of the wire protocol use
517 # compatibility reasons. Modern versions of the wire protocol use
518 # X-HgProto-<N> for advertising client support.
518 # X-HgProto-<N> for advertising client support.
519 opener.addheaders.append((r'Accept', r'application/mercurial-0.1'))
519 opener.addheaders.append((r'Accept', r'application/mercurial-0.1'))
520 return opener
520 return opener
521
521
522 def open(ui, url_, data=None):
522 def open(ui, url_, data=None):
523 u = util.url(url_)
523 u = util.url(url_)
524 if u.scheme:
524 if u.scheme:
525 u.scheme = u.scheme.lower()
525 u.scheme = u.scheme.lower()
526 url_, authinfo = u.authinfo()
526 url_, authinfo = u.authinfo()
527 else:
527 else:
528 path = util.normpath(os.path.abspath(url_))
528 path = util.normpath(os.path.abspath(url_))
529 url_ = 'file://' + urlreq.pathname2url(path)
529 url_ = 'file://' + urlreq.pathname2url(path)
530 authinfo = None
530 authinfo = None
531 return opener(ui, authinfo).open(pycompat.strurl(url_), data)
531 return opener(ui, authinfo).open(pycompat.strurl(url_), data)
General Comments 0
You need to be logged in to leave comments. Login now