mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-01-27 17:59:09 +01:00
merge with branch issue-970
This commit is contained in:
76
docs/mercurial/clone-empty.md
Normal file
76
docs/mercurial/clone-empty.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Clone empty repository
|
||||
|
||||
```http
|
||||
GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1efk0qxy1dj5v133hev91zwsf4;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 05:57:18 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 130.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
.
|
||||
lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=bookmarks.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1rsxj8u1rq9wizawhyyxok2p5;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 05:57:18 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 0.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
GET /scm/hg/hgtest?cmd=batch HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: cmds=heads+%3Bknown+nodes%3D.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=ewyx4m53d8dajjsob6gxobne;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 05:57:18 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 42.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
0000000000000000000000000000000000000000
|
||||
;
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1o0hou15jtiywsywutf30qwm8;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 05:57:18 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 15.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
.
|
||||
publishing.True
|
||||
```
|
||||
117
docs/mercurial/push-bookmark.md
Normal file
117
docs/mercurial/push-bookmark.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Push bookmark
|
||||
|
||||
```http
|
||||
GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=7rq9vpp9svfm1sicq7h9vetmv;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 130.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
|
||||
|
||||
GET /scm/hg/hgtest?cmd=batch HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
T 172.17.0.2:8080 -> 172.17.0.1:36576 [AP]
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1553csz4sf7scyvw8mqnqfirn;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 43.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
ef5993bb4abb32a0565c347844c6d939fc4f4b98
|
||||
;1
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=11xa5u3nrmx8k1nar3sazg6jzh;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 15.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
publishing.True
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=bookmarks.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1p1uzcvfe1pvzh2buzo658rxw;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 0.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1mhlj3ucfzdp6ifmzoua4zwit;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 15.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
publishing.True
|
||||
|
||||
POST /scm/hg/hgtest?cmd=pushkey HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
content-type: application/mercurial-0.1.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: key=markone&namespace=bookmarks&new=ef5993bb4abb32a0565c347844c6d939fc4f4b98&old=.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
content-length: 0.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=s4vtagb303dv1xg809wnp7e8z;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 08:08:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 2.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
.
|
||||
1
|
||||
```
|
||||
167
docs/mercurial/push-multiple-branches-to-new.md
Normal file
167
docs/mercurial/push-multiple-branches-to-new.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# Push multiple branches to new repository
|
||||
|
||||
```http
|
||||
GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1wu06ykfd4bcv1uv731y4hss2m;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 130.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
|
||||
|
||||
GET /scm/hg/hgtest?cmd=batch HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1rajglvqx222g5nppcq3jdfk0;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 43.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
0000000000000000000000000000000000000000
|
||||
;0
|
||||
|
||||
GET /scm/hg/hgtest?cmd=known HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: nodes=c0ceccb3b2f0f5c977ff32b9337519e5f37942c2+187ddf37e237c370514487a0bb1a226f11a780b3+b5914611f84eae14543684b2721eec88b0edac12+8b63a323606f10c86b30465570c2574eb7a3a989.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=a5vykp1f0ga2186l8v3gu6lid;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 4.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
0000
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=s8lpwqm4c2nqs9kwcg2ca6vm;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 15.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
publishing.True
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=bookmarks.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1d2qj3kynxlhvk31oli4kk7vf;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 0.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
POST /scm/hg/hgtest?cmd=unbundle HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
content-type: application/mercurial-0.1.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: heads=686173686564+6768033e216468247bd031a0a2d9876d79818f8f.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
content-length: 913.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HG10GZx...oh.U......E.1.....2q.<...s.1.YK*e#..b..{....{..%A.....
|
||||
,\.....Y.XV....Q/J......`Q/.z.{...<.7....r.s.~?.?..<o....O.]....?.}..m?]z..I..u..}.a..rg..R[i.,D ...!.1..h.r.....G...M.\...J[.....+{.k...u..bL.!....F('..=Q.'......W.>5.~`..?..........O.j.0.....Ih.....!@.P... ..a
|
||||
;!y..cT...]q.8Zg=...<..,.tq.*.........l........';..w^...w...-......Co..Fs.HYg...
|
||||
9.F#.P......1..;......D.H.9$@.^....r:E..18...H....3..h...-.=.6l......=q .)."Yg..p\...s@.#.H.*....c8&96..2.GjJ.`.J....r...=Q1..@R.3.o{q...|.......yq.k..,cY..:[... ...S.2...VYp..c5..&.SFR.............V.d..o..........,.. A..M....k...0_.LO1..1"4.;...B....5.9.".U.m.e......]\../p..;?C..<vW.....|......F.8,....s....2.T
|
||||
N. .k..>W9.........n.~o..gW...Q;..$....S..X.CN.5I].H..!.@...U..J...L.lY.../.-...6.:.Q.'...>.e'..<#3........OL}.52ra[..g*Y:Y....w...=..Z\...S.......tz..;..mf...W......&yUN.r.......4...........`..F...nT..U9................_.~..?...BwzUN.r....B.
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=163487i0ayf9s1k2ng9e1azadj;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 102.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
1
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 5 changesets with 3 changes to 3 files
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=a3i712yjss6t1xsxltnssq0tl;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 58.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
c0ceccb3b2f0f5c977ff32b9337519e5f37942c2.1
|
||||
publishing.True
|
||||
|
||||
POST /scm/hg/hgtest?cmd=pushkey HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
content-type: application/mercurial-0.1.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: key=ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
content-length: 0.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=g8cavdze42d83knmuasrlg10;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 07:55:14 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 2.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
.
|
||||
1
|
||||
```
|
||||
183
docs/mercurial/push-multiple-branches.md
Normal file
183
docs/mercurial/push-multiple-branches.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Push multiple branches
|
||||
|
||||
```http
|
||||
GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1mvm1rxg8333iib7754ksusxc;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 130.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
|
||||
|
||||
GET /scm/hg/hgtest?cmd=batch HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=58p9y9vcnz5cjs22dtw8mpwk;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 43.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
c0ceccb3b2f0f5c977ff32b9337519e5f37942c2
|
||||
;0
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=v5wfwj8k4t261dp6808cdouoa;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 15.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
publishing.True
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=bookmarks.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=3pgqytfhm4za1dco9p41j9yz5;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 0.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
GET /scm/hg/hgtest?cmd=branchmap HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
.
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1tiz6zf7ui54e1j3d4vouxig5m;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 48.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
default c0ceccb3b2f0f5c977ff32b9337519e5f37942c2
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=bookmarks.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1augu4tc71xax1dit20dtxzkez;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 0.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
POST /scm/hg/hgtest?cmd=unbundle HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
content-type: application/mercurial-0.1.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: heads=686173686564+95373ca7cd5371cb6c49bb755ee451d9ec585845.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
content-length: 746.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HG10GZx...]H.Q...z..r.,.Y..Bw.~..c.Z&...hf.:......e.XK.X,...
|
||||
,2.E1.B+...(.B"."*..z1.*......M...........93..k|..I..<...h..J_.L.9>.h..@.....op..^.....#....;.*..W....T@....!..dY....jT..A0O6.}..S.2..JPU.O6...aa...rY.VOf9.....7Ukj.&..<...z...j......%}..Jc.8c....k.."9.&".I.P.\..$.At......0..1..g.2.)<..$.. E..dn#....#.Y$3...n...5....J.e.......SNHN.q.MD..4..."I..`PF..?GH1..F..uES..Rl$47.....a........D.1...87.k.t..D..O_.3..6'cN.w.M..|@E.).X!.h*....U.B.X.....h..$.`4...
|
||||
-..O.:./..oWN.....3...x.L......_[..../..k.R$.x.2..kkv.\2R....4...@.2...1Q..T
|
||||
..(..m....s.Uo.......{.d.....Y....TYO...S.Pl`a5. ."N$.@...b...qJ.l.).n...1..F.Zy.....&>v;.q.....Jy..X.?.;....>U..|.....d.Y.*.q...NR.3...h.T..x..,.]...p{.^S.S...~..`..q.\j{.oCI.............K.....l9n.s......
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1e4fnqpncil9z1f7a2pya26nt7;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 102.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
1
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 4 changesets with 2 changes to 2 files
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=f9hvrjssniym1qe33q0u8r2m8;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 101.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
b5914611f84eae14543684b2721eec88b0edac12.1
|
||||
187ddf37e237c370514487a0bb1a226f11a780b3.1
|
||||
publishing.True
|
||||
|
||||
POST /scm/hg/hgtest?cmd=pushkey HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
content-type: application/mercurial-0.1.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: key=ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
content-length: 0.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=z5lrut6940a650sw6x9bls8a;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:16:50 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 2.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
1
|
||||
```
|
||||
147
docs/mercurial/push-single-changeset.md
Normal file
147
docs/mercurial/push-single-changeset.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Push single changeset
|
||||
|
||||
```http
|
||||
GET /scm/hg/hgtest?cmd=capabilities HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=18r2i2jsba46d14ncsmcjdhaem;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 130.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
|
||||
|
||||
GET /scm/hg/hgtest?cmd=batch HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: cmds=heads+%3Bknown+nodes%3Dc0ceccb3b2f0f5c977ff32b9337519e5f37942c2.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=1fw0i0c5zpy281gfgha0f26git;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 43.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
0000000000000000000000000000000000000000
|
||||
;0
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=dfa46uaqgf39w3jhk857oymu;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 15.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
publishing.True
|
||||
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=bookmarks.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=2sk1llvrsagg33xgmwyirfpi;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 0.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
POST /scm/hg/hgtest?cmd=unbundle HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
content-type: application/mercurial-0.1.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: heads=686173686564+6768033e216468247bd031a0a2d9876d79818f8f.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
content-length: 261.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HG10GZx.c``8w.....>|=Y..h.q.....N.......%......Z....&&&.&...YZ.&.&[$.........$.%q..&%..d&.).....%*.....Y.....9z...v\..FF......
|
||||
..F..\.z%.%\\.)).)
|
||||
.P[....D..[un..L).nc..q.m*.H.l#C...eZJ..YJ.Q.qR...e.aJ.EjjJ.AZ..A.Q..E.1.T.'D..C....7s.}..4G........3.S.mL.0.....zk
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=hlucs5utn1ifnpehqmjpt593;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 102.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
1
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 1 changes to 1 files
|
||||
|
||||
T 172.17.0.1:33206 -> 172.17.0.2:8080 [AP]
|
||||
GET /scm/hg/hgtest?cmd=listkeys HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: namespace=phases.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=15xomlrxl8qja1cj47rjpqda0y;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 58.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
c0ceccb3b2f0f5c977ff32b9337519e5f37942c2.1
|
||||
publishing.True
|
||||
|
||||
POST /scm/hg/hgtest?cmd=pushkey HTTP/1.1.
|
||||
Accept-Encoding: identity.
|
||||
content-type: application/mercurial-0.1.
|
||||
vary: X-HgArg-1.
|
||||
x-hgarg-1: key=c0ceccb3b2f0f5c977ff32b9337519e5f37942c2&namespace=phases&new=0&old=1.
|
||||
accept: application/mercurial-0.1.
|
||||
authorization: Basic c2NtYWRtaW46c2NtYWRtaW4=.
|
||||
content-length: 0.
|
||||
host: localhost:8080.
|
||||
user-agent: mercurial/proto-1.0 (Mercurial 4.3.1).
|
||||
|
||||
HTTP/1.1 200 OK.
|
||||
Set-Cookie: JSESSIONID=5zrop5v8e661ipk12tvru525;Path=/scm.
|
||||
Expires: Thu, 01 Jan 1970 00:00:00 GMT.
|
||||
Set-Cookie: rememberMe=deleteMe; Path=/scm; Max-Age=0; Expires=Wed, 28-Mar-2018 06:03:35 GMT.
|
||||
Content-Type: application/mercurial-0.1.
|
||||
Content-Length: 2.
|
||||
Server: Jetty(7.6.21.v20160908).
|
||||
|
||||
1
|
||||
```
|
||||
@@ -127,6 +127,10 @@ public class HgConfig extends SimpleRepositoryConfig
|
||||
return disableHookSSLValidation;
|
||||
}
|
||||
|
||||
public boolean isEnableHttpPostArgs() {
|
||||
return enableHttpPostArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -197,6 +201,10 @@ public class HgConfig extends SimpleRepositoryConfig
|
||||
this.showRevisionInId = showRevisionInId;
|
||||
}
|
||||
|
||||
public void setEnableHttpPostArgs(boolean enableHttpPostArgs) {
|
||||
this.enableHttpPostArgs = enableHttpPostArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
@@ -232,6 +240,8 @@ public class HgConfig extends SimpleRepositoryConfig
|
||||
/** Field description */
|
||||
private boolean showRevisionInId = false;
|
||||
|
||||
private boolean enableHttpPostArgs = false;
|
||||
|
||||
/**
|
||||
* disable validation of ssl certificates for mercurial hook
|
||||
* @see <a href="https://goo.gl/zH5eY8">Issue 959</a>
|
||||
|
||||
@@ -87,6 +87,8 @@ public class HgCGIServlet extends HttpServlet
|
||||
/** Field description */
|
||||
public static final String ENV_REPOSITORY_PATH = "SCM_REPOSITORY_PATH";
|
||||
|
||||
private static final String ENV_HTTP_POST_ARGS = "SCM_HTTP_POST_ARGS";
|
||||
|
||||
/** Field description */
|
||||
public static final String ENV_SESSION_PREFIX = "SCM_";
|
||||
|
||||
@@ -278,11 +280,15 @@ public class HgCGIServlet extends HttpServlet
|
||||
environment.put(ENV_PYTHON_HTTPS_VERIFY, "0");
|
||||
}
|
||||
|
||||
// enable experimental httppostargs protocol of mercurial
|
||||
// Issue 970: https://goo.gl/poascp
|
||||
environment.put(ENV_HTTP_POST_ARGS, String.valueOf(handler.getConfig().isEnableHttpPostArgs()));
|
||||
|
||||
//J-
|
||||
HgEnvironment.prepareEnvironment(
|
||||
environment,
|
||||
handler,
|
||||
hookManager,
|
||||
hookManager,
|
||||
request
|
||||
);
|
||||
//J+
|
||||
|
||||
@@ -35,31 +35,35 @@ package sonia.scm.web;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.RepositoryProvider;
|
||||
import sonia.scm.web.filter.ProviderPermissionFilter;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Permission filter for mercurial repositories.
|
||||
*
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
public class HgPermissionFilter extends ProviderPermissionFilter
|
||||
{
|
||||
|
||||
|
||||
private static final Set<String> READ_METHODS = ImmutableSet.of("GET", "HEAD", "OPTIONS", "TRACE");
|
||||
|
||||
private final HgRepositoryHandler repositoryHandler;
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*
|
||||
@@ -67,17 +71,49 @@ public class HgPermissionFilter extends ProviderPermissionFilter
|
||||
* @param repositoryProvider repository provider
|
||||
*/
|
||||
@Inject
|
||||
public HgPermissionFilter(ScmConfiguration configuration,
|
||||
RepositoryProvider repositoryProvider)
|
||||
public HgPermissionFilter(ScmConfiguration configuration, RepositoryProvider repositoryProvider, HgRepositoryHandler repositoryHandler)
|
||||
{
|
||||
super(configuration, repositoryProvider);
|
||||
this.repositoryHandler = repositoryHandler;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
|
||||
@Override
|
||||
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
super.doFilter(wrapRequestIfRequired(request), response, chain);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
HttpServletRequest wrapRequestIfRequired(HttpServletRequest request) {
|
||||
if (isHttpPostArgsEnabled()) {
|
||||
return new HgServletRequest(request);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isWriteRequest(HttpServletRequest request)
|
||||
{
|
||||
return !READ_METHODS.contains(request.getMethod());
|
||||
if (isHttpPostArgsEnabled()) {
|
||||
return isHttpPostArgsWriteRequest(request);
|
||||
}
|
||||
return isDefaultWriteRequest(request);
|
||||
}
|
||||
|
||||
private boolean isHttpPostArgsEnabled() {
|
||||
return repositoryHandler.getConfig().isEnableHttpPostArgs();
|
||||
}
|
||||
|
||||
private boolean isHttpPostArgsWriteRequest(HttpServletRequest request) {
|
||||
return WireProtocol.isWriteRequest(request);
|
||||
}
|
||||
|
||||
private boolean isDefaultWriteRequest(HttpServletRequest request) {
|
||||
if (READ_METHODS.contains(request.getMethod())) {
|
||||
return WireProtocol.isWriteRequest(request);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package sonia.scm.web;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* HgServletInputStream is a wrapper around the original {@link ServletInputStream} and provides some extra
|
||||
* functionality to support the mercurial client.
|
||||
*/
|
||||
public class HgServletInputStream extends ServletInputStream {
|
||||
|
||||
private final ServletInputStream original;
|
||||
private ByteArrayInputStream captured;
|
||||
|
||||
HgServletInputStream(ServletInputStream original) {
|
||||
this.original = original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given amount of bytes from the stream and captures them, if the {@link #read()} methods is called the
|
||||
* captured bytes are returned before the rest of the stream.
|
||||
*
|
||||
* @param size amount of bytes to read
|
||||
*
|
||||
* @return byte array
|
||||
*
|
||||
* @throws IOException if the method is called twice
|
||||
*/
|
||||
public byte[] readAndCapture(int size) throws IOException {
|
||||
Preconditions.checkState(captured == null, "readAndCapture can only be called once per request");
|
||||
|
||||
// TODO should we enforce a limit? to prevent OOM?
|
||||
byte[] bytes = new byte[size];
|
||||
original.read(bytes);
|
||||
captured = new ByteArrayInputStream(bytes);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (captured != null && captured.available() > 0) {
|
||||
return captured.read();
|
||||
}
|
||||
return original.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
original.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package sonia.scm.web;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* {@link HttpServletRequestWrapper} which adds some functionality in order to support the mercurial client.
|
||||
*/
|
||||
public final class HgServletRequest extends HttpServletRequestWrapper {
|
||||
|
||||
private HgServletInputStream hgServletInputStream;
|
||||
|
||||
/**
|
||||
* Constructs a request object wrapping the given request.
|
||||
*
|
||||
* @param request
|
||||
* @throws IllegalArgumentException if the request is null
|
||||
*/
|
||||
public HgServletRequest(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HgServletInputStream getInputStream() throws IOException {
|
||||
if (hgServletInputStream == null) {
|
||||
hgServletInputStream = new HgServletInputStream(super.getInputStream());
|
||||
}
|
||||
return hgServletInputStream;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* Copyright (c) 2018, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.web;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* WireProtocol provides methods for handling the mercurial wire protocol.
|
||||
*
|
||||
* @see <a href="https://goo.gl/WaVJzw">Mercurial Wire Protocol</a>
|
||||
*/
|
||||
public final class WireProtocol {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WireProtocol.class);
|
||||
|
||||
private static final Set<String> READ_COMMANDS = ImmutableSet.of(
|
||||
"batch", "between", "branchmap", "branches", "capabilities", "changegroup", "changegroupsubset", "clonebundles",
|
||||
"getbundle", "heads", "hello", "listkeys", "lookup", "known", "stream_out",
|
||||
// could not find lheads in the wireprotocol description but mercurial 4.5.2 uses it for clone
|
||||
"lheads"
|
||||
);
|
||||
|
||||
private static final Set<String> WRITE_COMMANDS = ImmutableSet.of(
|
||||
"pushkey", "unbundle"
|
||||
);
|
||||
|
||||
private WireProtocol() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the request is a write request. The method will always return {@code true}, expect for the
|
||||
* following cases:
|
||||
*
|
||||
* - no command was specified with the request (is required for the hgweb ui)
|
||||
* - the command in the query string was found in the list of read request
|
||||
* - if query string contains the batch command, then all commands specified in X-HgArg headers must be
|
||||
* in the list of read requests
|
||||
* - in case of enabled HttpPostArgs protocol and query string container the batch command, the header X-HgArgs-Post
|
||||
* is read and the commands which are specified in the body from 0 to the value of X-HgArgs-Post must be in the list
|
||||
* of read requests
|
||||
*
|
||||
* @param request http request
|
||||
*
|
||||
* @return {@code true} for write requests.
|
||||
*/
|
||||
public static boolean isWriteRequest(HttpServletRequest request) {
|
||||
List<String> commands = commandsOf(request);
|
||||
boolean write = isWriteRequest(commands);
|
||||
LOG.trace("mercurial request {} is write: {}", commands, write);
|
||||
return write;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean isWriteRequest(List<String> commands) {
|
||||
return !READ_COMMANDS.containsAll(commands);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static List<String> commandsOf(HttpServletRequest request) {
|
||||
List<String> listOfCmds = Lists.newArrayList();
|
||||
|
||||
String cmd = getCommandFromQueryString(request);
|
||||
if (cmd != null) {
|
||||
listOfCmds.add(cmd);
|
||||
if (isBatchCommand(cmd)) {
|
||||
parseHgArgHeaders(request, listOfCmds);
|
||||
handleHttpPostArgs(request, listOfCmds);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(listOfCmds);
|
||||
}
|
||||
|
||||
private static void handleHttpPostArgs(HttpServletRequest request, List<String> listOfCmds) {
|
||||
int hgArgsPostSize = request.getIntHeader("X-HgArgs-Post");
|
||||
if (hgArgsPostSize > 0) {
|
||||
|
||||
if (request instanceof HgServletRequest) {
|
||||
HgServletRequest hgRequest = (HgServletRequest) request;
|
||||
|
||||
parseHttpPostArgs(listOfCmds, hgArgsPostSize, hgRequest);
|
||||
} else {
|
||||
throw new IllegalArgumentException("could not process the httppostargs protocol without HgServletRequest");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseHttpPostArgs(List<String> listOfCmds, int hgArgsPostSize, HgServletRequest hgRequest) {
|
||||
try {
|
||||
byte[] bytes = hgRequest.getInputStream().readAndCapture(hgArgsPostSize);
|
||||
// we use iso-8859-1 for encoding, because the post args are normally http headers which are using iso-8859-1
|
||||
// see https://tools.ietf.org/html/rfc7230#section-3.2.4
|
||||
String hgArgs = new String(bytes, Charsets.ISO_8859_1);
|
||||
String decoded = decodeValue(hgArgs);
|
||||
parseHgCommandHeader(listOfCmds, decoded);
|
||||
} catch (IOException ex) {
|
||||
throw Throwables.propagate(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseHgArgHeaders(HttpServletRequest request, List<String> listOfCmds) {
|
||||
Enumeration headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String header = (String) headerNames.nextElement();
|
||||
parseHgArgHeader(request, listOfCmds, header);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseHgArgHeader(HttpServletRequest request, List<String> listOfCmds, String header) {
|
||||
if (isHgArgHeader(header)) {
|
||||
String value = getHeaderDecoded(request, header);
|
||||
parseHgArgValue(listOfCmds, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseHgArgValue(List<String> listOfCmds, String value) {
|
||||
if (isHgArgCommandHeader(value)) {
|
||||
parseHgCommandHeader(listOfCmds, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseHgCommandHeader(List<String> listOfCmds, String value) {
|
||||
String[] cmds = value.substring(5).split(";");
|
||||
for (String cmd : cmds ) {
|
||||
String normalizedCmd = normalize(cmd);
|
||||
int index = normalizedCmd.indexOf(' ');
|
||||
if (index > 0) {
|
||||
listOfCmds.add(normalizedCmd.substring(0, index));
|
||||
} else {
|
||||
listOfCmds.add(normalizedCmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String normalize(String cmd) {
|
||||
return cmd.trim().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
private static boolean isHgArgCommandHeader(String value) {
|
||||
return value.startsWith("cmds=");
|
||||
}
|
||||
|
||||
private static String getHeaderDecoded(HttpServletRequest request, String header) {
|
||||
return decodeValue(request.getHeader(header));
|
||||
}
|
||||
|
||||
private static String decodeValue(String value) {
|
||||
return HttpUtil.decode(Strings.nullToEmpty(value));
|
||||
}
|
||||
|
||||
private static boolean isHgArgHeader(String header) {
|
||||
return header.toLowerCase(Locale.ENGLISH).startsWith("x-hgarg-");
|
||||
}
|
||||
|
||||
private static boolean isBatchCommand(String cmd) {
|
||||
return "batch".equalsIgnoreCase(cmd);
|
||||
}
|
||||
|
||||
private static String getCommandFromQueryString(HttpServletRequest request) {
|
||||
// we can't use getParameter, because this would inspect the body for form parameters as well
|
||||
Multimap<String, String> queryParameterMap = createQueryParameterMap(request);
|
||||
|
||||
Collection<String> cmd = queryParameterMap.get("cmd");
|
||||
Preconditions.checkArgument(cmd.size() <= 1, "found more than one cmd query parameter");
|
||||
Iterator<String> iterator = cmd.iterator();
|
||||
|
||||
String command = null;
|
||||
if (iterator.hasNext()) {
|
||||
command = iterator.next();
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Multimap<String,String> createQueryParameterMap(HttpServletRequest request) {
|
||||
Multimap<String,String> parameterMap = HashMultimap.create();
|
||||
|
||||
String queryString = request.getQueryString();
|
||||
if (!Strings.isNullOrEmpty(queryString)) {
|
||||
|
||||
String[] parameters = queryString.split("&");
|
||||
for (String parameter : parameters) {
|
||||
int index = parameter.indexOf('=');
|
||||
if (index > 0) {
|
||||
parameterMap.put(parameter.substring(0, index), parameter.substring(index + 1));
|
||||
} else {
|
||||
parameterMap.put(parameter, "true");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return parameterMap;
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,7 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, {
|
||||
showRevisionInIdText: 'Show Revision',
|
||||
// TODO: i18n
|
||||
disableHookSSLValidationText: 'Disable SSL Validation on Hooks',
|
||||
enableHttpPostArgsText: 'Enable HttpPostArgs Protocol',
|
||||
|
||||
// helpText
|
||||
hgBinaryHelpText: 'Location of Mercurial binary.',
|
||||
@@ -63,6 +64,10 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, {
|
||||
// TODO: i18n
|
||||
disableHookSSLValidationHelpText: 'Disables the validation of ssl certificates for the mercurial hook, which forwards the repository changes back to scm-manager. \n\
|
||||
This option should only be used, if SCM-Manager uses a self signed certificate.',
|
||||
// TODO explain it
|
||||
enableHttpPostArgsHelpText: 'Enables the experimental HttpPostArgs Protocol of mercurial.\n\
|
||||
The HttpPostArgs Protocol uses the body of post requests to send the meta information instead of http headers.\
|
||||
This helps to reduce the header size of mercurial requests. HttpPostArgs is supported since mercurial 3.8.',
|
||||
|
||||
initComponent: function(){
|
||||
|
||||
@@ -115,12 +120,18 @@ Sonia.hg.ConfigPanel = Ext.extend(Sonia.config.ConfigForm, {
|
||||
fieldLabel: this.disableHookSSLValidationText,
|
||||
inputValue: 'true',
|
||||
helpText: this.disableHookSSLValidationHelpText
|
||||
},{
|
||||
xtype: 'checkbox',
|
||||
name: 'enableHttpPostArgs',
|
||||
fieldLabel: this.enableHttpPostArgsText,
|
||||
inputValue: 'true',
|
||||
helpText: this.enableHttpPostArgsHelpText
|
||||
},{
|
||||
xtype: 'checkbox',
|
||||
name: 'disabled',
|
||||
fieldLabel: this.disabledText,
|
||||
inputValue: 'true',
|
||||
helpText: this.disabledHelpText
|
||||
helpText: this.disabledHelpText
|
||||
},{
|
||||
xtype: 'button',
|
||||
text: this.configWizardText,
|
||||
@@ -260,11 +271,11 @@ Sonia.repository.typeIcons['hg'] = 'resources/images/icons/16x16/mercurial.png';
|
||||
// override ChangesetViewerGrid to render changeset id's with revisions
|
||||
|
||||
Ext.override(Sonia.repository.ChangesetViewerGrid, {
|
||||
|
||||
|
||||
isMercurialRepository: function(){
|
||||
return this.repository.type === 'hg';
|
||||
},
|
||||
|
||||
|
||||
getChangesetId: function(id, record){
|
||||
if ( this.isMercurialRepository() ){
|
||||
var rev = Sonia.util.getProperty(record.get('properties'), 'hg.rev');
|
||||
@@ -274,7 +285,7 @@ Ext.override(Sonia.repository.ChangesetViewerGrid, {
|
||||
}
|
||||
return id;
|
||||
},
|
||||
|
||||
|
||||
getParentIds: function(id, record){
|
||||
var parents = record.get('parents');
|
||||
if ( this.isMercurialRepository() ){
|
||||
@@ -285,7 +296,7 @@ Ext.override(Sonia.repository.ChangesetViewerGrid, {
|
||||
parents[0] = rev + ':' + parents[0];
|
||||
}
|
||||
if ( parents.length > 1 ){
|
||||
rev = Sonia.util.getProperty(properties, 'hg.p2.rev');
|
||||
rev = Sonia.util.getProperty(properties, 'hg.p2.rev');
|
||||
if (rev){
|
||||
parents[1] = rev + ':' + parents[1];
|
||||
}
|
||||
@@ -294,5 +305,5 @@ Ext.override(Sonia.repository.ChangesetViewerGrid, {
|
||||
}
|
||||
return parents;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -31,12 +31,21 @@
|
||||
|
||||
|
||||
import os
|
||||
from mercurial import demandimport
|
||||
from mercurial import demandimport, ui as uimod, hg
|
||||
from mercurial.hgweb import hgweb, wsgicgi
|
||||
|
||||
repositoryPath = os.environ['SCM_REPOSITORY_PATH']
|
||||
|
||||
demandimport.enable()
|
||||
|
||||
application = hgweb(repositoryPath)
|
||||
u = uimod.ui.load()
|
||||
|
||||
# pass SCM_HTTP_POST_ARGS to enable experimental httppostargs protocol of mercurial
|
||||
# SCM_HTTP_POST_ARGS is set by HgCGIServlet
|
||||
# Issue 970: https://goo.gl/poascp
|
||||
u.setconfig('experimental', 'httppostargs', os.environ['SCM_HTTP_POST_ARGS'])
|
||||
|
||||
# open repository
|
||||
# SCM_REPOSITORY_PATH contains the repository path and is set by HgCGIServlet
|
||||
r = hg.repository(u, os.environ['SCM_REPOSITORY_PATH'])
|
||||
|
||||
application = hgweb(r)
|
||||
wsgicgi.launch(application)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
@@ -13,7 +13,7 @@
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -24,28 +24,38 @@
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package sonia.scm.web;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.*;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.repository.HgConfig;
|
||||
import sonia.scm.repository.HgRepositoryHandler;
|
||||
import sonia.scm.repository.RepositoryProvider;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static sonia.scm.web.WireProtocolRequestMockFactory.CMDS_HEADS_KNOWN_NODES;
|
||||
import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.BOOKMARKS;
|
||||
import static sonia.scm.web.WireProtocolRequestMockFactory.Namespace.PHASES;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link HgPermissionFilter}.
|
||||
*
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@@ -56,13 +66,37 @@ public class HgPermissionFilterTest {
|
||||
|
||||
@Mock
|
||||
private ScmConfiguration configuration;
|
||||
|
||||
|
||||
@Mock
|
||||
private RepositoryProvider repositoryProvider;
|
||||
|
||||
|
||||
@Mock
|
||||
private HgRepositoryHandler hgRepositoryHandler;
|
||||
|
||||
private WireProtocolRequestMockFactory wireProtocol = new WireProtocolRequestMockFactory("/scm/hg/repo");
|
||||
|
||||
@InjectMocks
|
||||
private HgPermissionFilter filter;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(hgRepositoryHandler.getConfig()).thenReturn(new HgConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#wrapRequestIfRequired(HttpServletRequest)}.
|
||||
*/
|
||||
@Test
|
||||
public void testWrapRequestIfRequired() {
|
||||
assertSame(request, filter.wrapRequestIfRequired(request));
|
||||
|
||||
HgConfig hgConfig = new HgConfig();
|
||||
hgConfig.setEnableHttpPostArgs(true);
|
||||
when(hgRepositoryHandler.getConfig()).thenReturn(hgConfig);
|
||||
|
||||
assertThat(filter.wrapRequestIfRequired(request), is(instanceOf(HgServletRequest.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)}.
|
||||
*/
|
||||
@@ -73,7 +107,7 @@ public class HgPermissionFilterTest {
|
||||
assertFalse(isWriteRequest("HEAD"));
|
||||
assertFalse(isWriteRequest("TRACE"));
|
||||
assertFalse(isWriteRequest("OPTIONS"));
|
||||
|
||||
|
||||
// write methods
|
||||
assertTrue(isWriteRequest("POST"));
|
||||
assertTrue(isWriteRequest("PUT"));
|
||||
@@ -81,8 +115,121 @@ public class HgPermissionFilterTest {
|
||||
assertTrue(isWriteRequest("KA"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with enabled httppostargs option.
|
||||
*/
|
||||
@Test
|
||||
public void testIsWriteRequestWithEnabledHttpPostArgs() {
|
||||
HgConfig config = new HgConfig();
|
||||
config.setEnableHttpPostArgs(true);
|
||||
when(hgRepositoryHandler.getConfig()).thenReturn(config);
|
||||
|
||||
assertFalse(isWriteRequest("POST"));
|
||||
assertFalse(isWriteRequest("POST", "heads"));
|
||||
assertTrue(isWriteRequest("POST", "unbundle"));
|
||||
}
|
||||
|
||||
private boolean isWriteRequest(String method) {
|
||||
return isWriteRequest(method, "capabilities");
|
||||
}
|
||||
|
||||
private boolean isWriteRequest(String method, String command) {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getQueryString()).thenReturn("cmd=" + command);
|
||||
when(request.getMethod()).thenReturn(method);
|
||||
return filter.isWriteRequest(request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a
|
||||
* fresh clone of a repository.
|
||||
*/
|
||||
@Test
|
||||
public void testIsWriteRequestWithClone() {
|
||||
assertIsReadRequest(wireProtocol.capabilities());
|
||||
assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS));
|
||||
assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a
|
||||
* push of a single changeset.
|
||||
*/
|
||||
@Test
|
||||
public void testIsWriteRequestWithSingleChangesetPush() {
|
||||
assertIsReadRequest(wireProtocol.capabilities());
|
||||
assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2")));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS));
|
||||
assertIsWriteRequest(wireProtocol.unbundle(261L, "686173686564+6768033e216468247bd031a0a2d9876d79818f8f"));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
assertIsWriteRequest(wireProtocol.pushkey("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2&namespace=phases&new=0&old=1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a
|
||||
* push to a single changeset.
|
||||
*/
|
||||
@Test
|
||||
public void testIsWriteRequestWithMultipleChangesetsPush() {
|
||||
assertIsReadRequest(wireProtocol.capabilities());
|
||||
assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98")));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS));
|
||||
assertIsReadRequest(wireProtocol.branchmap());
|
||||
assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS));
|
||||
assertIsWriteRequest(wireProtocol.unbundle(746L, "686173686564+95373ca7cd5371cb6c49bb755ee451d9ec585845"));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
assertIsWriteRequest(wireProtocol.pushkey("ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a
|
||||
* push of multiple branches to a new repository.
|
||||
*/
|
||||
@Test
|
||||
public void testIsWriteRequestWithMutlipleBranchesToNewRepositoryPush() {
|
||||
assertIsReadRequest(wireProtocol.capabilities());
|
||||
assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98")));
|
||||
assertIsReadRequest(wireProtocol.known("c0ceccb3b2f0f5c977ff32b9337519e5f37942c2+187ddf37e237c370514487a0bb1a226f11a780b3+b5914611f84eae14543684b2721eec88b0edac12+8b63a323606f10c86b30465570c2574eb7a3a989"));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS));
|
||||
assertIsWriteRequest(wireProtocol.unbundle(913L, "686173686564+6768033e216468247bd031a0a2d9876d79818f8f"));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
assertIsWriteRequest(wireProtocol.pushkey("ef5993bb4abb32a0565c347844c6d939fc4f4b98&namespace=phases&new=0&old=1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a set of requests, which are used for a
|
||||
* push of a bookmark.
|
||||
*/
|
||||
@Test
|
||||
public void testIsWriteRequestWithBookmarkPush() {
|
||||
assertIsReadRequest(wireProtocol.capabilities());
|
||||
assertIsReadRequest(wireProtocol.batch(CMDS_HEADS_KNOWN_NODES.concat("ef5993bb4abb32a0565c347844c6d939fc4f4b98")));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
assertIsReadRequest(wireProtocol.listkeys(BOOKMARKS));
|
||||
assertIsReadRequest(wireProtocol.listkeys(PHASES));
|
||||
assertIsWriteRequest(wireProtocol.pushkey("markone&namespace=bookmarks&new=ef5993bb4abb32a0565c347844c6d939fc4f4b98&old="));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HgPermissionFilter#isWriteRequest(HttpServletRequest)} with a write request hidden in a batch GET
|
||||
* request.
|
||||
*
|
||||
* @see <a href="https://goo.gl/poascp">Issue #970</a>
|
||||
*/
|
||||
@Test
|
||||
public void testIsWriteRequestWithBookmarkPushInABatch() {
|
||||
assertIsWriteRequest(wireProtocol.batch("pushkey key=markthree,namespace=bookmarks,new=187ddf37e237c370514487a0bb1a226f11a780b3,old="));
|
||||
}
|
||||
|
||||
private void assertIsReadRequest(HttpServletRequest request) {
|
||||
assertFalse(filter.isWriteRequest(request));
|
||||
}
|
||||
|
||||
private void assertIsWriteRequest(HttpServletRequest request) {
|
||||
assertTrue(filter.isWriteRequest(request));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package sonia.scm.web;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class HgServletInputStreamTest {
|
||||
|
||||
@Test
|
||||
public void testReadAndCapture() throws IOException {
|
||||
SampleServletInputStream original = new SampleServletInputStream("trillian.mcmillian@hitchhiker.com");
|
||||
HgServletInputStream hgServletInputStream = new HgServletInputStream(original);
|
||||
|
||||
byte[] prefix = hgServletInputStream.readAndCapture(8);
|
||||
assertEquals("trillian", new String(prefix, Charsets.US_ASCII));
|
||||
|
||||
byte[] wholeBytes = ByteStreams.toByteArray(hgServletInputStream);
|
||||
assertEquals("trillian.mcmillian@hitchhiker.com", new String(wholeBytes, Charsets.US_ASCII));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testReadAndCaptureCalledTwice() throws IOException {
|
||||
SampleServletInputStream original = new SampleServletInputStream("trillian.mcmillian@hitchhiker.com");
|
||||
HgServletInputStream hgServletInputStream = new HgServletInputStream(original);
|
||||
|
||||
hgServletInputStream.readAndCapture(1);
|
||||
hgServletInputStream.readAndCapture(1);
|
||||
}
|
||||
|
||||
private static class SampleServletInputStream extends ServletInputStream {
|
||||
|
||||
private ByteArrayInputStream input;
|
||||
|
||||
private SampleServletInputStream(String data) {
|
||||
input = new ByteArrayInputStream(data.getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return input.read();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package sonia.scm.web;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class WireProtocolRequestMockFactory {
|
||||
|
||||
public enum Namespace {
|
||||
PHASES, BOOKMARKS;
|
||||
}
|
||||
|
||||
public static final String CMDS_HEADS_KNOWN_NODES = "heads+%3Bknown+nodes%3D";
|
||||
|
||||
private String repositoryPath;
|
||||
|
||||
public WireProtocolRequestMockFactory(String repositoryPath) {
|
||||
this.repositoryPath = repositoryPath;
|
||||
}
|
||||
|
||||
public HttpServletRequest capabilities() {
|
||||
return base("GET", "cmd=capabilities");
|
||||
}
|
||||
|
||||
public HttpServletRequest listkeys(Namespace namespace) {
|
||||
HttpServletRequest request = base("GET", "cmd=capabilities");
|
||||
header(request, "vary", "X-HgArg-1");
|
||||
header(request, "x-hgarg-1", namespaceValue(namespace));
|
||||
return request;
|
||||
}
|
||||
|
||||
public HttpServletRequest branchmap() {
|
||||
return base("GET", "cmd=branchmap");
|
||||
}
|
||||
|
||||
public HttpServletRequest batch(String... args) {
|
||||
HttpServletRequest request = base("GET", "cmd=batch");
|
||||
args(request, "cmds", args);
|
||||
return request;
|
||||
}
|
||||
|
||||
public HttpServletRequest unbundle(long contentLength, String... heads) {
|
||||
HttpServletRequest request = base("POST", "cmd=unbundle");
|
||||
header(request, "Content-Length", String.valueOf(contentLength));
|
||||
args(request, "heads", heads);
|
||||
return request;
|
||||
}
|
||||
|
||||
public HttpServletRequest pushkey(String... keys) {
|
||||
HttpServletRequest request = base("POST", "cmd=pushkey");
|
||||
args(request, "key", keys);
|
||||
return request;
|
||||
}
|
||||
|
||||
public HttpServletRequest known(String... nodes) {
|
||||
HttpServletRequest request = base("GET", "cmd=known");
|
||||
args(request, "nodes", nodes);
|
||||
return request;
|
||||
}
|
||||
|
||||
private void args(HttpServletRequest request, String prefix, String[] values) {
|
||||
List<String> headers = Lists.newArrayList();
|
||||
|
||||
StringBuilder vary = new StringBuilder();
|
||||
for ( int i=0; i<values.length; i++ ) {
|
||||
String header = "X-HgArg-" + (i+1);
|
||||
|
||||
if (i>0) {
|
||||
vary.append(",");
|
||||
}
|
||||
|
||||
vary.append(header);
|
||||
headers.add(header);
|
||||
|
||||
header(request, header, prefix + "=" + values[i]);
|
||||
}
|
||||
header(request, "Vary", vary.toString());
|
||||
|
||||
when(request.getHeaderNames()).thenReturn(Collections.enumeration(headers));
|
||||
}
|
||||
|
||||
private HttpServletRequest base(String method, String queryStringValue) {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
|
||||
when(request.getRequestURI()).thenReturn(repositoryPath);
|
||||
when(request.getMethod()).thenReturn(method);
|
||||
|
||||
queryString(request, queryStringValue);
|
||||
|
||||
header(request, "Accept", "application/mercurial-0.1");
|
||||
header(request, "Accept-Encoding", "identity");
|
||||
header(request, "User-Agent", "mercurial/proto-1.0 (Mercurial 4.3.1)");
|
||||
return request;
|
||||
}
|
||||
|
||||
private void queryString(HttpServletRequest request, String queryString) {
|
||||
when(request.getQueryString()).thenReturn(queryString);
|
||||
}
|
||||
|
||||
private void header(HttpServletRequest request, String header, String value) {
|
||||
when(request.getHeader(header)).thenReturn(value);
|
||||
}
|
||||
|
||||
private String namespaceValue(Namespace namespace) {
|
||||
return "namespace=" + namespace.toString().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* Copyright (c) 2018, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.web;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link WireProtocol}.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WireProtocolTest {
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Test
|
||||
public void testIsWriteRequestOnPost() {
|
||||
assertIsWriteRequest("capabilities", "unbundle");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWriteRequest() {
|
||||
assertIsWriteRequest("unbundle");
|
||||
assertIsWriteRequest("capabilities", "unbundle");
|
||||
assertIsWriteRequest("capabilities", "postkeys");
|
||||
assertIsReadRequest();
|
||||
assertIsReadRequest("capabilities");
|
||||
assertIsReadRequest("capabilities", "branches", "branchmap");
|
||||
}
|
||||
|
||||
private void assertIsWriteRequest(String... commands) {
|
||||
List<String> cmdList = Lists.newArrayList(commands);
|
||||
assertTrue(WireProtocol.isWriteRequest(cmdList));
|
||||
}
|
||||
|
||||
private void assertIsReadRequest(String... commands) {
|
||||
List<String> cmdList = Lists.newArrayList(commands);
|
||||
assertFalse(WireProtocol.isWriteRequest(cmdList));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCommandsOf() {
|
||||
expectQueryCommand("capabilities", "cmd=capabilities");
|
||||
expectQueryCommand("unbundle", "cmd=unbundle");
|
||||
expectQueryCommand("unbundle", "prefix=stuff&cmd=unbundle");
|
||||
expectQueryCommand("unbundle", "cmd=unbundle&suffix=stuff");
|
||||
expectQueryCommand("unbundle", "prefix=stuff&cmd=unbundle&suffix=stuff");
|
||||
expectQueryCommand("unbundle", "bool=&cmd=unbundle");
|
||||
expectQueryCommand("unbundle", "bool&cmd=unbundle");
|
||||
expectQueryCommand("unbundle", "prefix=stu==ff&cmd=unbundle");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCommandsOfWithHgArgsPost() throws IOException {
|
||||
when(request.getMethod()).thenReturn("POST");
|
||||
when(request.getQueryString()).thenReturn("cmd=batch");
|
||||
when(request.getIntHeader("X-HgArgs-Post")).thenReturn(29);
|
||||
when(request.getHeaderNames()).thenReturn(Collections.enumeration(Lists.newArrayList("X-HgArgs-Post")));
|
||||
when(request.getInputStream()).thenReturn(new BufferedServletInputStream("cmds=lheads+%3Bknown+nodes%3D"));
|
||||
|
||||
List<String> commands = WireProtocol.commandsOf(new HgServletRequest(request));
|
||||
assertThat(commands, contains("batch", "lheads", "known"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCommandsOfWithBatch() {
|
||||
prepareBatch("cmds=heads ;known nodes,ef5993bb4abb32a0565c347844c6d939fc4f4b98");
|
||||
List<String> commands = WireProtocol.commandsOf(request);
|
||||
assertThat(commands, contains("batch", "heads", "known"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCommandsOfWithBatchEncoded() {
|
||||
prepareBatch("cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98");
|
||||
List<String> commands = WireProtocol.commandsOf(request);
|
||||
assertThat(commands, contains("batch", "heads", "known"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCommandsOfWithBatchAndMutlipleLines() {
|
||||
prepareBatch(
|
||||
"cmds=heads+%3Bknown+nodes%3Def5993bb4abb32a0565c347844c6d939fc4f4b98",
|
||||
"cmds=unbundle; postkeys",
|
||||
"cmds= branchmap p1=r2,p2=r4; listkeys"
|
||||
);
|
||||
List<String> commands = WireProtocol.commandsOf(request);
|
||||
assertThat(commands, contains("batch", "heads", "known", "unbundle", "postkeys", "branchmap", "listkeys"));
|
||||
}
|
||||
|
||||
private void prepareBatch(String... args) {
|
||||
when(request.getQueryString()).thenReturn("cmd=batch");
|
||||
List<String> headers = Lists.newArrayList();
|
||||
for (int i=0; i<args.length; i++) {
|
||||
String header = "X-HgArg-" + (i+1);
|
||||
headers.add(header);
|
||||
when(request.getHeader(header)).thenReturn(args[i]);
|
||||
}
|
||||
when(request.getHeaderNames()).thenReturn(Collections.enumeration(headers));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGetCommandsOfWithMultipleCommandsInQueryString() {
|
||||
when(request.getQueryString()).thenReturn("cmd=abc&cmd=def");
|
||||
WireProtocol.commandsOf(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCommandsOfWithoutCmdInQueryString() {
|
||||
when(request.getQueryString()).thenReturn("abc=def&123=456");
|
||||
assertTrue(WireProtocol.commandsOf(request).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCommandsOfWithEmptyQueryString() {
|
||||
when(request.getQueryString()).thenReturn("");
|
||||
assertTrue(WireProtocol.commandsOf(request).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCommandsOfWithNullQueryString() {
|
||||
assertTrue(WireProtocol.commandsOf(request).isEmpty());
|
||||
}
|
||||
|
||||
private void expectQueryCommand(String expected, String queryString) {
|
||||
when(request.getQueryString()).thenReturn(queryString);
|
||||
List<String> commands = WireProtocol.commandsOf(request);
|
||||
assertEquals(1, commands.size());
|
||||
assertTrue(commands.contains(expected));
|
||||
}
|
||||
|
||||
private static class BufferedServletInputStream extends ServletInputStream {
|
||||
|
||||
private ByteArrayInputStream input;
|
||||
|
||||
BufferedServletInputStream(String content) {
|
||||
this.input = new ByteArrayInputStream(content.getBytes(Charsets.US_ASCII));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return input.read();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user