rugged 0.17.0.b7 → 0.18.0.b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +88 -32
  3. data/ext/rugged/extconf.rb +4 -2
  4. data/ext/rugged/rugged.c +72 -10
  5. data/ext/rugged/rugged.h +14 -10
  6. data/ext/rugged/rugged_blob.c +8 -10
  7. data/ext/rugged/rugged_branch.c +11 -14
  8. data/ext/rugged/rugged_commit.c +31 -24
  9. data/ext/rugged/rugged_config.c +2 -2
  10. data/ext/rugged/rugged_index.c +133 -198
  11. data/ext/rugged/rugged_note.c +372 -0
  12. data/ext/rugged/rugged_object.c +50 -22
  13. data/ext/rugged/rugged_reference.c +122 -130
  14. data/ext/rugged/rugged_remote.c +72 -29
  15. data/ext/rugged/rugged_repo.c +402 -20
  16. data/ext/rugged/rugged_revwalk.c +7 -3
  17. data/ext/rugged/rugged_settings.c +110 -0
  18. data/ext/rugged/rugged_signature.c +23 -7
  19. data/ext/rugged/rugged_tag.c +32 -16
  20. data/ext/rugged/rugged_tree.c +44 -15
  21. data/lib/rugged.rb +1 -0
  22. data/lib/rugged/index.rb +8 -0
  23. data/lib/rugged/remote.rb +13 -0
  24. data/lib/rugged/repository.rb +3 -3
  25. data/lib/rugged/version.rb +1 -1
  26. data/test/blob_test.rb +13 -15
  27. data/test/branch_test.rb +32 -67
  28. data/test/commit_test.rb +50 -12
  29. data/test/config_test.rb +12 -11
  30. data/test/coverage/HEAD.json +1 -1
  31. data/test/coverage/cover.rb +40 -21
  32. data/test/errors_test.rb +34 -0
  33. data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
  34. data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
  35. data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
  36. data/test/fixtures/testrepo.git/logs/refs/notes/commits +1 -0
  37. data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +1 -0
  38. data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
  39. data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +1 -0
  40. data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
  41. data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
  42. data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +3 -0
  43. data/test/fixtures/testrepo.git/refs/notes/commits +1 -0
  44. data/test/index_test.rb +65 -69
  45. data/test/lib_test.rb +76 -11
  46. data/test/note_test.rb +158 -0
  47. data/test/object_test.rb +8 -11
  48. data/test/reference_test.rb +77 -85
  49. data/test/remote_test.rb +86 -8
  50. data/test/repo_pack_test.rb +9 -7
  51. data/test/repo_reset_test.rb +80 -0
  52. data/test/repo_test.rb +176 -53
  53. data/test/tag_test.rb +44 -7
  54. data/test/test_helper.rb +63 -35
  55. data/test/tree_test.rb +34 -13
  56. data/test/walker_test.rb +14 -14
  57. data/vendor/libgit2/Makefile.embed +1 -1
  58. data/vendor/libgit2/deps/http-parser/http_parser.c +974 -578
  59. data/vendor/libgit2/deps/http-parser/http_parser.h +106 -70
  60. data/vendor/libgit2/deps/regex/regcomp.c +7 -6
  61. data/vendor/libgit2/deps/regex/regex_internal.c +1 -1
  62. data/vendor/libgit2/deps/regex/regex_internal.h +12 -3
  63. data/vendor/libgit2/deps/regex/regexec.c +5 -5
  64. data/vendor/libgit2/include/git2.h +5 -1
  65. data/vendor/libgit2/include/git2/attr.h +4 -2
  66. data/vendor/libgit2/include/git2/blob.h +39 -12
  67. data/vendor/libgit2/include/git2/branch.h +123 -35
  68. data/vendor/libgit2/include/git2/checkout.h +206 -48
  69. data/vendor/libgit2/include/git2/clone.h +72 -27
  70. data/vendor/libgit2/include/git2/commit.h +20 -17
  71. data/vendor/libgit2/include/git2/common.h +67 -1
  72. data/vendor/libgit2/include/git2/config.h +81 -60
  73. data/vendor/libgit2/include/git2/cred_helpers.h +53 -0
  74. data/vendor/libgit2/include/git2/diff.h +459 -150
  75. data/vendor/libgit2/include/git2/errors.h +9 -1
  76. data/vendor/libgit2/include/git2/graph.h +41 -0
  77. data/vendor/libgit2/include/git2/ignore.h +7 -6
  78. data/vendor/libgit2/include/git2/index.h +323 -97
  79. data/vendor/libgit2/include/git2/indexer.h +27 -59
  80. data/vendor/libgit2/include/git2/inttypes.h +4 -0
  81. data/vendor/libgit2/include/git2/merge.h +13 -3
  82. data/vendor/libgit2/include/git2/message.h +14 -8
  83. data/vendor/libgit2/include/git2/net.h +9 -7
  84. data/vendor/libgit2/include/git2/notes.h +88 -29
  85. data/vendor/libgit2/include/git2/object.h +16 -6
  86. data/vendor/libgit2/include/git2/odb.h +80 -17
  87. data/vendor/libgit2/include/git2/odb_backend.h +47 -11
  88. data/vendor/libgit2/include/git2/oid.h +26 -17
  89. data/vendor/libgit2/include/git2/pack.h +62 -8
  90. data/vendor/libgit2/include/git2/push.h +131 -0
  91. data/vendor/libgit2/include/git2/refdb.h +103 -0
  92. data/vendor/libgit2/include/git2/refdb_backend.h +109 -0
  93. data/vendor/libgit2/include/git2/reflog.h +30 -21
  94. data/vendor/libgit2/include/git2/refs.h +215 -193
  95. data/vendor/libgit2/include/git2/refspec.h +22 -2
  96. data/vendor/libgit2/include/git2/remote.h +158 -37
  97. data/vendor/libgit2/include/git2/repository.h +150 -31
  98. data/vendor/libgit2/include/git2/reset.h +43 -9
  99. data/vendor/libgit2/include/git2/revparse.h +48 -4
  100. data/vendor/libgit2/include/git2/revwalk.h +25 -10
  101. data/vendor/libgit2/include/git2/signature.h +20 -12
  102. data/vendor/libgit2/include/git2/stash.h +121 -0
  103. data/vendor/libgit2/include/git2/status.h +122 -53
  104. data/vendor/libgit2/include/git2/strarray.h +17 -11
  105. data/vendor/libgit2/include/git2/submodule.h +42 -7
  106. data/vendor/libgit2/include/git2/tag.h +72 -59
  107. data/vendor/libgit2/include/git2/threads.h +4 -2
  108. data/vendor/libgit2/include/git2/trace.h +68 -0
  109. data/vendor/libgit2/include/git2/transport.h +328 -0
  110. data/vendor/libgit2/include/git2/tree.h +149 -120
  111. data/vendor/libgit2/include/git2/types.h +13 -12
  112. data/vendor/libgit2/include/git2/version.h +3 -3
  113. data/vendor/libgit2/src/amiga/map.c +2 -2
  114. data/vendor/libgit2/src/attr.c +58 -48
  115. data/vendor/libgit2/src/attr.h +4 -18
  116. data/vendor/libgit2/src/attr_file.c +30 -6
  117. data/vendor/libgit2/src/attr_file.h +6 -8
  118. data/vendor/libgit2/src/attrcache.h +24 -0
  119. data/vendor/libgit2/src/blob.c +30 -7
  120. data/vendor/libgit2/src/blob.h +1 -1
  121. data/vendor/libgit2/src/branch.c +361 -68
  122. data/vendor/libgit2/src/branch.h +17 -0
  123. data/vendor/libgit2/src/bswap.h +1 -1
  124. data/vendor/libgit2/src/buf_text.c +291 -0
  125. data/vendor/libgit2/src/buf_text.h +122 -0
  126. data/vendor/libgit2/src/buffer.c +27 -101
  127. data/vendor/libgit2/src/buffer.h +54 -39
  128. data/vendor/libgit2/src/cache.c +15 -6
  129. data/vendor/libgit2/src/cache.h +1 -1
  130. data/vendor/libgit2/src/cc-compat.h +3 -1
  131. data/vendor/libgit2/src/checkout.c +1165 -222
  132. data/vendor/libgit2/src/checkout.h +24 -0
  133. data/vendor/libgit2/src/clone.c +171 -86
  134. data/vendor/libgit2/src/commit.c +44 -45
  135. data/vendor/libgit2/src/commit.h +3 -3
  136. data/vendor/libgit2/src/commit_list.c +194 -0
  137. data/vendor/libgit2/src/commit_list.h +49 -0
  138. data/vendor/libgit2/src/common.h +44 -10
  139. data/vendor/libgit2/src/compress.c +1 -1
  140. data/vendor/libgit2/src/compress.h +1 -1
  141. data/vendor/libgit2/src/config.c +211 -124
  142. data/vendor/libgit2/src/config.h +23 -4
  143. data/vendor/libgit2/src/config_cache.c +2 -2
  144. data/vendor/libgit2/src/config_file.c +129 -53
  145. data/vendor/libgit2/src/config_file.h +10 -8
  146. data/vendor/libgit2/src/crlf.c +66 -67
  147. data/vendor/libgit2/src/date.c +12 -12
  148. data/vendor/libgit2/src/delta-apply.c +14 -1
  149. data/vendor/libgit2/src/delta-apply.h +18 -1
  150. data/vendor/libgit2/src/delta.c +40 -107
  151. data/vendor/libgit2/src/delta.h +19 -17
  152. data/vendor/libgit2/src/diff.c +347 -496
  153. data/vendor/libgit2/src/diff.h +27 -1
  154. data/vendor/libgit2/src/diff_output.c +564 -249
  155. data/vendor/libgit2/src/diff_output.h +15 -8
  156. data/vendor/libgit2/src/diff_tform.c +687 -0
  157. data/vendor/libgit2/src/errors.c +27 -36
  158. data/vendor/libgit2/src/fetch.c +13 -351
  159. data/vendor/libgit2/src/fetch.h +13 -3
  160. data/vendor/libgit2/src/fetchhead.c +295 -0
  161. data/vendor/libgit2/src/fetchhead.h +34 -0
  162. data/vendor/libgit2/src/filebuf.c +42 -15
  163. data/vendor/libgit2/src/filebuf.h +4 -2
  164. data/vendor/libgit2/src/fileops.c +466 -113
  165. data/vendor/libgit2/src/fileops.h +154 -28
  166. data/vendor/libgit2/src/filter.c +3 -75
  167. data/vendor/libgit2/src/filter.h +1 -29
  168. data/vendor/libgit2/src/fnmatch.c +1 -1
  169. data/vendor/libgit2/src/fnmatch.h +1 -1
  170. data/vendor/libgit2/src/global.c +54 -10
  171. data/vendor/libgit2/src/global.h +10 -1
  172. data/vendor/libgit2/src/graph.c +178 -0
  173. data/vendor/libgit2/src/hash.c +25 -52
  174. data/vendor/libgit2/src/hash.h +21 -9
  175. data/vendor/libgit2/src/{sha1/sha1.c → hash/hash_generic.c} +20 -12
  176. data/vendor/libgit2/src/hash/hash_generic.h +24 -0
  177. data/vendor/libgit2/src/hash/hash_openssl.h +45 -0
  178. data/vendor/libgit2/src/hash/hash_win32.c +291 -0
  179. data/vendor/libgit2/src/hash/hash_win32.h +140 -0
  180. data/vendor/libgit2/src/hashsig.c +368 -0
  181. data/vendor/libgit2/src/hashsig.h +72 -0
  182. data/vendor/libgit2/src/ignore.c +22 -15
  183. data/vendor/libgit2/src/ignore.h +6 -1
  184. data/vendor/libgit2/src/index.c +770 -171
  185. data/vendor/libgit2/src/index.h +13 -5
  186. data/vendor/libgit2/src/indexer.c +286 -431
  187. data/vendor/libgit2/src/iterator.c +854 -466
  188. data/vendor/libgit2/src/iterator.h +134 -109
  189. data/vendor/libgit2/src/map.h +1 -1
  190. data/vendor/libgit2/src/merge.c +296 -0
  191. data/vendor/libgit2/src/merge.h +22 -0
  192. data/vendor/libgit2/src/message.c +1 -1
  193. data/vendor/libgit2/src/message.h +1 -1
  194. data/vendor/libgit2/src/mwindow.c +35 -30
  195. data/vendor/libgit2/src/mwindow.h +2 -2
  196. data/vendor/libgit2/src/netops.c +162 -98
  197. data/vendor/libgit2/src/netops.h +50 -15
  198. data/vendor/libgit2/src/notes.c +109 -58
  199. data/vendor/libgit2/src/notes.h +2 -1
  200. data/vendor/libgit2/src/object.c +46 -57
  201. data/vendor/libgit2/src/object.h +1 -8
  202. data/vendor/libgit2/src/odb.c +151 -40
  203. data/vendor/libgit2/src/odb.h +5 -1
  204. data/vendor/libgit2/src/odb_loose.c +4 -5
  205. data/vendor/libgit2/src/odb_pack.c +122 -80
  206. data/vendor/libgit2/src/offmap.h +65 -0
  207. data/vendor/libgit2/src/oid.c +12 -4
  208. data/vendor/libgit2/src/oidmap.h +1 -1
  209. data/vendor/libgit2/src/pack-objects.c +88 -61
  210. data/vendor/libgit2/src/pack-objects.h +8 -8
  211. data/vendor/libgit2/src/pack.c +293 -28
  212. data/vendor/libgit2/src/pack.h +49 -4
  213. data/vendor/libgit2/src/path.c +103 -14
  214. data/vendor/libgit2/src/path.h +23 -7
  215. data/vendor/libgit2/src/pathspec.c +168 -0
  216. data/vendor/libgit2/src/pathspec.h +40 -0
  217. data/vendor/libgit2/src/pool.c +29 -4
  218. data/vendor/libgit2/src/pool.h +8 -1
  219. data/vendor/libgit2/src/posix.c +26 -27
  220. data/vendor/libgit2/src/posix.h +2 -3
  221. data/vendor/libgit2/src/pqueue.c +23 -1
  222. data/vendor/libgit2/src/pqueue.h +23 -1
  223. data/vendor/libgit2/src/push.c +653 -0
  224. data/vendor/libgit2/src/push.h +51 -0
  225. data/vendor/libgit2/src/refdb.c +185 -0
  226. data/vendor/libgit2/src/refdb.h +46 -0
  227. data/vendor/libgit2/src/refdb_fs.c +1024 -0
  228. data/vendor/libgit2/src/refdb_fs.h +15 -0
  229. data/vendor/libgit2/src/reflog.c +77 -45
  230. data/vendor/libgit2/src/reflog.h +1 -3
  231. data/vendor/libgit2/src/refs.c +366 -1326
  232. data/vendor/libgit2/src/refs.h +22 -13
  233. data/vendor/libgit2/src/refspec.c +46 -7
  234. data/vendor/libgit2/src/refspec.h +11 -1
  235. data/vendor/libgit2/src/remote.c +758 -120
  236. data/vendor/libgit2/src/remote.h +10 -5
  237. data/vendor/libgit2/src/repo_template.h +6 -6
  238. data/vendor/libgit2/src/repository.c +315 -96
  239. data/vendor/libgit2/src/repository.h +5 -3
  240. data/vendor/libgit2/src/reset.c +99 -81
  241. data/vendor/libgit2/src/revparse.c +157 -84
  242. data/vendor/libgit2/src/revwalk.c +68 -470
  243. data/vendor/libgit2/src/revwalk.h +44 -0
  244. data/vendor/libgit2/src/sha1_lookup.c +1 -1
  245. data/vendor/libgit2/src/sha1_lookup.h +1 -1
  246. data/vendor/libgit2/src/signature.c +68 -200
  247. data/vendor/libgit2/src/signature.h +1 -1
  248. data/vendor/libgit2/src/stash.c +663 -0
  249. data/vendor/libgit2/src/status.c +101 -79
  250. data/vendor/libgit2/src/strmap.h +1 -1
  251. data/vendor/libgit2/src/submodule.c +67 -51
  252. data/vendor/libgit2/src/submodule.h +1 -1
  253. data/vendor/libgit2/src/tag.c +35 -29
  254. data/vendor/libgit2/src/tag.h +1 -1
  255. data/vendor/libgit2/src/thread-utils.c +1 -1
  256. data/vendor/libgit2/src/thread-utils.h +2 -2
  257. data/vendor/libgit2/src/trace.c +39 -0
  258. data/vendor/libgit2/src/trace.h +56 -0
  259. data/vendor/libgit2/src/transport.c +81 -34
  260. data/vendor/libgit2/src/transports/cred.c +60 -0
  261. data/vendor/libgit2/src/transports/cred_helpers.c +49 -0
  262. data/vendor/libgit2/src/transports/git.c +234 -127
  263. data/vendor/libgit2/src/transports/http.c +761 -433
  264. data/vendor/libgit2/src/transports/local.c +460 -64
  265. data/vendor/libgit2/src/transports/smart.c +345 -0
  266. data/vendor/libgit2/src/transports/smart.h +179 -0
  267. data/vendor/libgit2/src/{pkt.c → transports/smart_pkt.c} +131 -12
  268. data/vendor/libgit2/src/transports/smart_protocol.c +856 -0
  269. data/vendor/libgit2/src/transports/winhttp.c +1136 -0
  270. data/vendor/libgit2/src/tree-cache.c +2 -2
  271. data/vendor/libgit2/src/tree-cache.h +1 -1
  272. data/vendor/libgit2/src/tree.c +239 -166
  273. data/vendor/libgit2/src/tree.h +11 -2
  274. data/vendor/libgit2/src/tsort.c +39 -23
  275. data/vendor/libgit2/src/unix/map.c +1 -1
  276. data/vendor/libgit2/src/unix/posix.h +12 -2
  277. data/vendor/libgit2/src/unix/realpath.c +30 -0
  278. data/vendor/libgit2/src/util.c +250 -13
  279. data/vendor/libgit2/src/util.h +71 -14
  280. data/vendor/libgit2/src/vector.c +123 -60
  281. data/vendor/libgit2/src/vector.h +24 -22
  282. data/vendor/libgit2/src/win32/dir.c +1 -1
  283. data/vendor/libgit2/src/win32/dir.h +1 -1
  284. data/vendor/libgit2/src/win32/error.c +77 -0
  285. data/vendor/libgit2/src/win32/error.h +13 -0
  286. data/vendor/libgit2/src/win32/findfile.c +143 -54
  287. data/vendor/libgit2/src/win32/findfile.h +10 -6
  288. data/vendor/libgit2/src/win32/map.c +1 -1
  289. data/vendor/libgit2/src/win32/mingw-compat.h +1 -1
  290. data/vendor/libgit2/src/win32/msvc-compat.h +10 -1
  291. data/vendor/libgit2/src/win32/posix.h +10 -1
  292. data/vendor/libgit2/src/win32/posix_w32.c +132 -63
  293. data/vendor/libgit2/src/win32/precompiled.c +1 -1
  294. data/vendor/libgit2/src/win32/pthread.c +1 -1
  295. data/vendor/libgit2/src/win32/pthread.h +1 -1
  296. data/vendor/libgit2/src/win32/utf-conv.c +5 -5
  297. data/vendor/libgit2/src/win32/utf-conv.h +3 -3
  298. data/vendor/libgit2/src/win32/version.h +20 -0
  299. metadata +308 -252
  300. data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
  301. data/test/fixtures/testrepo.git/objects/7f/043268ea43ce18e3540acaabf9e090c91965b0 +0 -0
  302. data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
  303. data/test/index_test.rb~ +0 -218
  304. data/vendor/libgit2/src/pkt.h +0 -91
  305. data/vendor/libgit2/src/ppc/sha1.c +0 -70
  306. data/vendor/libgit2/src/ppc/sha1.h +0 -26
  307. data/vendor/libgit2/src/protocol.c +0 -110
  308. data/vendor/libgit2/src/protocol.h +0 -21
  309. data/vendor/libgit2/src/sha1.h +0 -33
  310. data/vendor/libgit2/src/transport.h +0 -148
@@ -1,31 +1,35 @@
1
1
  /*
2
- * Copyright (C) 2009-2012 the libgit2 contributors
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
3
  *
4
4
  * This file is part of libgit2, distributed under the GNU GPL v2 with
5
5
  * a Linking Exception. For full terms see the included COPYING file.
6
6
  */
7
- #include <stdlib.h>
7
+ #ifndef GIT_WINHTTP
8
+
8
9
  #include "git2.h"
9
10
  #include "http_parser.h"
10
-
11
- #include "transport.h"
12
- #include "common.h"
13
- #include "netops.h"
14
11
  #include "buffer.h"
15
- #include "pkt.h"
16
- #include "refs.h"
17
- #include "pack.h"
18
- #include "fetch.h"
19
- #include "filebuf.h"
20
- #include "repository.h"
21
- #include "protocol.h"
22
- #if GIT_WINHTTP
23
- # include <winhttp.h>
24
- # pragma comment(lib, "winhttp.lib")
25
- #endif
26
-
27
- #define WIDEN2(s) L ## s
28
- #define WIDEN(s) WIDEN2(s)
12
+ #include "netops.h"
13
+ #include "smart.h"
14
+
15
+ static const char *prefix_http = "http://";
16
+ static const char *prefix_https = "https://";
17
+ static const char *upload_pack_service = "upload-pack";
18
+ static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack";
19
+ static const char *upload_pack_service_url = "/git-upload-pack";
20
+ static const char *receive_pack_service = "receive-pack";
21
+ static const char *receive_pack_ls_service_url = "/info/refs?service=git-receive-pack";
22
+ static const char *receive_pack_service_url = "/git-receive-pack";
23
+ static const char *get_verb = "GET";
24
+ static const char *post_verb = "POST";
25
+ static const char *basic_authtype = "Basic";
26
+
27
+ #define OWNING_SUBTRANSPORT(s) ((http_subtransport *)(s)->parent.subtransport)
28
+
29
+ #define PARSE_ERROR_GENERIC -1
30
+ #define PARSE_ERROR_REPLAY -2
31
+
32
+ #define CHUNK_SIZE 4096
29
33
 
30
34
  enum last_cb {
31
35
  NONE,
@@ -33,53 +37,132 @@ enum last_cb {
33
37
  VALUE
34
38
  };
35
39
 
40
+ typedef enum {
41
+ GIT_HTTP_AUTH_BASIC = 1,
42
+ } http_authmechanism_t;
43
+
36
44
  typedef struct {
37
- git_transport parent;
38
- http_parser_settings settings;
39
- git_buf buf;
40
- int error;
41
- int transfer_finished :1,
42
- ct_found :1,
43
- ct_finished :1,
44
- pack_ready :1;
45
- enum last_cb last_cb;
46
- http_parser parser;
47
- char *content_type;
48
- char *path;
45
+ git_smart_subtransport_stream parent;
46
+ const char *service;
47
+ const char *service_url;
48
+ char *redirect_url;
49
+ const char *verb;
50
+ char *chunk_buffer;
51
+ unsigned chunk_buffer_len;
52
+ unsigned sent_request : 1,
53
+ received_response : 1,
54
+ chunked : 1,
55
+ redirect_count : 3;
56
+ } http_stream;
57
+
58
+ typedef struct {
59
+ git_smart_subtransport parent;
60
+ transport_smart *owner;
61
+ gitno_socket socket;
62
+ const char *path;
49
63
  char *host;
50
64
  char *port;
51
- char *service;
52
- char buffer[65536];
53
- #ifdef GIT_WIN32
54
- WSADATA wsd;
55
- #endif
56
- #ifdef GIT_WINHTTP
57
- HINTERNET session;
58
- HINTERNET connection;
59
- HINTERNET request;
60
- #endif
61
- } transport_http;
62
-
63
- static int gen_request(git_buf *buf, const char *path, const char *host, const char *op,
64
- const char *service, ssize_t content_length, int ls)
65
+ char *user_from_url;
66
+ char *pass_from_url;
67
+ git_cred *cred;
68
+ git_cred *url_cred;
69
+ http_authmechanism_t auth_mechanism;
70
+ unsigned connected : 1,
71
+ use_ssl : 1;
72
+
73
+ /* Parser structures */
74
+ http_parser parser;
75
+ http_parser_settings settings;
76
+ gitno_buffer parse_buffer;
77
+ git_buf parse_header_name;
78
+ git_buf parse_header_value;
79
+ char parse_buffer_data[2048];
80
+ char *content_type;
81
+ char *location;
82
+ git_vector www_authenticate;
83
+ enum last_cb last_cb;
84
+ int parse_error;
85
+ unsigned parse_finished : 1;
86
+ } http_subtransport;
87
+
88
+ typedef struct {
89
+ http_stream *s;
90
+ http_subtransport *t;
91
+
92
+ /* Target buffer details from read() */
93
+ char *buffer;
94
+ size_t buf_size;
95
+ size_t *bytes_read;
96
+ } parser_context;
97
+
98
+ static int apply_basic_credential(git_buf *buf, git_cred *cred)
65
99
  {
66
- if (path == NULL) /* Is 'git fetch http://host.com/' valid? */
67
- path = "/";
100
+ git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
101
+ git_buf raw = GIT_BUF_INIT;
102
+ int error = -1;
103
+
104
+ git_buf_printf(&raw, "%s:%s", c->username, c->password);
105
+
106
+ if (git_buf_oom(&raw) ||
107
+ git_buf_puts(buf, "Authorization: Basic ") < 0 ||
108
+ git_buf_put_base64(buf, git_buf_cstr(&raw), raw.size) < 0 ||
109
+ git_buf_puts(buf, "\r\n") < 0)
110
+ goto on_error;
111
+
112
+ error = 0;
113
+
114
+ on_error:
115
+ if (raw.size)
116
+ memset(raw.ptr, 0x0, raw.size);
117
+
118
+ git_buf_free(&raw);
119
+ return error;
120
+ }
121
+
122
+ static int gen_request(
123
+ git_buf *buf,
124
+ http_stream *s,
125
+ size_t content_length)
126
+ {
127
+ http_subtransport *t = OWNING_SUBTRANSPORT(s);
128
+
129
+ if (!t->path)
130
+ t->path = "/";
131
+
132
+ /* If we were redirected, make sure to respect that here */
133
+ if (s->redirect_url)
134
+ git_buf_printf(buf, "%s %s HTTP/1.1\r\n", s->verb, s->redirect_url);
135
+ else
136
+ git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, t->path, s->service_url);
68
137
 
69
- if (ls) {
70
- git_buf_printf(buf, "%s %s/info/refs?service=git-%s HTTP/1.1\r\n", op, path, service);
71
- } else {
72
- git_buf_printf(buf, "%s %s/git-%s HTTP/1.1\r\n", op, path, service);
73
- }
74
138
  git_buf_puts(buf, "User-Agent: git/1.0 (libgit2 " LIBGIT2_VERSION ")\r\n");
75
- git_buf_printf(buf, "Host: %s\r\n", host);
76
- if (content_length > 0) {
77
- git_buf_printf(buf, "Accept: application/x-git-%s-result\r\n", service);
78
- git_buf_printf(buf, "Content-Type: application/x-git-%s-request\r\n", service);
79
- git_buf_printf(buf, "Content-Length: %"PRIuZ "\r\n", content_length);
80
- } else {
139
+ git_buf_printf(buf, "Host: %s\r\n", t->host);
140
+
141
+ if (s->chunked || content_length > 0) {
142
+ git_buf_printf(buf, "Accept: application/x-git-%s-result\r\n", s->service);
143
+ git_buf_printf(buf, "Content-Type: application/x-git-%s-request\r\n", s->service);
144
+
145
+ if (s->chunked)
146
+ git_buf_puts(buf, "Transfer-Encoding: chunked\r\n");
147
+ else
148
+ git_buf_printf(buf, "Content-Length: %"PRIuZ "\r\n", content_length);
149
+ } else
81
150
  git_buf_puts(buf, "Accept: */*\r\n");
151
+
152
+ /* Apply credentials to the request */
153
+ if (t->cred && t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT &&
154
+ t->auth_mechanism == GIT_HTTP_AUTH_BASIC &&
155
+ apply_basic_credential(buf, t->cred) < 0)
156
+ return -1;
157
+
158
+ /* Use url-parsed basic auth if username and password are both provided */
159
+ if (!t->cred && t->user_from_url && t->pass_from_url) {
160
+ if (!t->url_cred &&
161
+ git_cred_userpass_plaintext_new(&t->url_cred, t->user_from_url, t->pass_from_url) < 0)
162
+ return -1;
163
+ if (apply_basic_credential(buf, t->url_cred) < 0) return -1;
82
164
  }
165
+
83
166
  git_buf_puts(buf, "\r\n");
84
167
 
85
168
  if (git_buf_oom(buf))
@@ -88,538 +171,783 @@ static int gen_request(git_buf *buf, const char *path, const char *host, const c
88
171
  return 0;
89
172
  }
90
173
 
91
- static int send_request(transport_http *t, const char *service, void *data, ssize_t content_length, int ls)
174
+ static int parse_unauthorized_response(
175
+ git_vector *www_authenticate,
176
+ int *allowed_types,
177
+ http_authmechanism_t *auth_mechanism)
92
178
  {
93
- #ifndef GIT_WINHTTP
94
- git_buf request = GIT_BUF_INIT;
95
- const char *verb;
96
- int error = -1;
97
-
98
- verb = ls ? "GET" : "POST";
99
- /* Generate and send the HTTP request */
100
- if (gen_request(&request, t->path, t->host, verb, service, content_length, ls) < 0) {
101
- giterr_set(GITERR_NET, "Failed to generate request");
102
- return -1;
179
+ unsigned i;
180
+ char *entry;
181
+
182
+ git_vector_foreach(www_authenticate, i, entry) {
183
+ if (!strncmp(entry, basic_authtype, 5) &&
184
+ (entry[5] == '\0' || entry[5] == ' ')) {
185
+ *allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
186
+ *auth_mechanism = GIT_HTTP_AUTH_BASIC;
187
+ }
103
188
  }
104
189
 
190
+ return 0;
191
+ }
105
192
 
106
- if (gitno_send((git_transport *) t, request.ptr, request.size, 0) < 0)
107
- goto cleanup;
193
+ static int on_header_ready(http_subtransport *t)
194
+ {
195
+ git_buf *name = &t->parse_header_name;
196
+ git_buf *value = &t->parse_header_value;
108
197
 
109
- if (content_length) {
110
- if (gitno_send((git_transport *) t, data, content_length, 0) < 0)
111
- goto cleanup;
198
+ if (!strcasecmp("Content-Type", git_buf_cstr(name))) {
199
+ if (!t->content_type) {
200
+ t->content_type = git__strdup(git_buf_cstr(value));
201
+ GITERR_CHECK_ALLOC(t->content_type);
202
+ }
112
203
  }
204
+ else if (!strcmp("WWW-Authenticate", git_buf_cstr(name))) {
205
+ char *dup = git__strdup(git_buf_cstr(value));
206
+ GITERR_CHECK_ALLOC(dup);
113
207
 
114
- error = 0;
208
+ git_vector_insert(&t->www_authenticate, dup);
209
+ }
210
+ else if (!strcasecmp("Location", git_buf_cstr(name))) {
211
+ if (!t->location) {
212
+ t->location= git__strdup(git_buf_cstr(value));
213
+ GITERR_CHECK_ALLOC(t->location);
214
+ }
215
+ }
115
216
 
116
- cleanup:
117
- git_buf_free(&request);
118
- return error;
217
+ return 0;
218
+ }
219
+
220
+ static int on_header_field(http_parser *parser, const char *str, size_t len)
221
+ {
222
+ parser_context *ctx = (parser_context *) parser->data;
223
+ http_subtransport *t = ctx->t;
224
+
225
+ /* Both parse_header_name and parse_header_value are populated
226
+ * and ready for consumption */
227
+ if (VALUE == t->last_cb)
228
+ if (on_header_ready(t) < 0)
229
+ return t->parse_error = PARSE_ERROR_GENERIC;
230
+
231
+ if (NONE == t->last_cb || VALUE == t->last_cb)
232
+ git_buf_clear(&t->parse_header_name);
233
+
234
+ if (git_buf_put(&t->parse_header_name, str, len) < 0)
235
+ return t->parse_error = PARSE_ERROR_GENERIC;
236
+
237
+ t->last_cb = FIELD;
238
+ return 0;
239
+ }
240
+
241
+ static int on_header_value(http_parser *parser, const char *str, size_t len)
242
+ {
243
+ parser_context *ctx = (parser_context *) parser->data;
244
+ http_subtransport *t = ctx->t;
119
245
 
120
- #else
121
- wchar_t *verb;
122
- wchar_t url[GIT_WIN_PATH], ct[GIT_WIN_PATH];
246
+ assert(NONE != t->last_cb);
247
+
248
+ if (FIELD == t->last_cb)
249
+ git_buf_clear(&t->parse_header_value);
250
+
251
+ if (git_buf_put(&t->parse_header_value, str, len) < 0)
252
+ return t->parse_error = PARSE_ERROR_GENERIC;
253
+
254
+ t->last_cb = VALUE;
255
+ return 0;
256
+ }
257
+
258
+ static int on_headers_complete(http_parser *parser)
259
+ {
260
+ parser_context *ctx = (parser_context *) parser->data;
261
+ http_subtransport *t = ctx->t;
262
+ http_stream *s = ctx->s;
123
263
  git_buf buf = GIT_BUF_INIT;
124
- BOOL ret;
125
- DWORD flags;
126
- void *buffer;
127
- wchar_t *types[] = {
128
- L"*/*",
129
- NULL,
130
- };
131
-
132
- verb = ls ? L"GET" : L"POST";
133
- buffer = data ? data : WINHTTP_NO_REQUEST_DATA;
134
- flags = t->parent.use_ssl ? WINHTTP_FLAG_SECURE : 0;
135
-
136
- if (ls)
137
- git_buf_printf(&buf, "%s/info/refs?service=git-%s", t->path, service);
138
- else
139
- git_buf_printf(&buf, "%s/git-%s", t->path, service);
140
264
 
141
- if (git_buf_oom(&buf))
142
- return -1;
265
+ /* Both parse_header_name and parse_header_value are populated
266
+ * and ready for consumption. */
267
+ if (VALUE == t->last_cb)
268
+ if (on_header_ready(t) < 0)
269
+ return t->parse_error = PARSE_ERROR_GENERIC;
143
270
 
144
- git__utf8_to_16(url, GIT_WIN_PATH, git_buf_cstr(&buf));
271
+ /* Check for an authentication failure. */
272
+ if (parser->status_code == 401 &&
273
+ get_verb == s->verb &&
274
+ t->owner->cred_acquire_cb) {
275
+ int allowed_types = 0;
145
276
 
146
- t->request = WinHttpOpenRequest(t->connection, verb, url, NULL, WINHTTP_NO_REFERER, types, flags);
147
- if (t->request == NULL) {
148
- git_buf_free(&buf);
149
- giterr_set(GITERR_OS, "Failed to open request");
150
- return -1;
151
- }
277
+ if (parse_unauthorized_response(&t->www_authenticate,
278
+ &allowed_types, &t->auth_mechanism) < 0)
279
+ return t->parse_error = PARSE_ERROR_GENERIC;
152
280
 
153
- git_buf_clear(&buf);
154
- if (git_buf_printf(&buf, "Content-Type: application/x-git-%s-request", service) < 0)
155
- goto on_error;
281
+ if (allowed_types &&
282
+ (!t->cred || 0 == (t->cred->credtype & allowed_types))) {
156
283
 
157
- git__utf8_to_16(ct, GIT_WIN_PATH, git_buf_cstr(&buf));
284
+ if (t->owner->cred_acquire_cb(&t->cred,
285
+ t->owner->url,
286
+ t->user_from_url,
287
+ allowed_types,
288
+ t->owner->cred_acquire_payload) < 0)
289
+ return PARSE_ERROR_GENERIC;
158
290
 
159
- if (WinHttpAddRequestHeaders(t->request, ct, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD) == FALSE) {
160
- giterr_set(GITERR_OS, "Failed to add a header to the request");
161
- goto on_error;
291
+ assert(t->cred);
292
+
293
+ /* Successfully acquired a credential. */
294
+ return t->parse_error = PARSE_ERROR_REPLAY;
295
+ }
162
296
  }
163
297
 
164
- if (!t->parent.check_cert) {
165
- int flags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
166
- if (WinHttpSetOption(t->request, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags)) == FALSE) {
167
- giterr_set(GITERR_OS, "Failed to set options to ignore cert errors");
168
- goto on_error;
298
+ /* Check for a redirect.
299
+ * Right now we only permit a redirect to the same hostname. */
300
+ if ((parser->status_code == 301 ||
301
+ parser->status_code == 302 ||
302
+ (parser->status_code == 303 && get_verb == s->verb) ||
303
+ parser->status_code == 307) &&
304
+ t->location) {
305
+
306
+ if (s->redirect_count >= 7) {
307
+ giterr_set(GITERR_NET, "Too many redirects");
308
+ return t->parse_error = PARSE_ERROR_GENERIC;
309
+ }
310
+
311
+ if (t->location[0] != '/') {
312
+ giterr_set(GITERR_NET, "Only relative redirects are supported");
313
+ return t->parse_error = PARSE_ERROR_GENERIC;
169
314
  }
315
+
316
+ /* Set the redirect URL on the stream. This is a transfer of
317
+ * ownership of the memory. */
318
+ if (s->redirect_url)
319
+ git__free(s->redirect_url);
320
+
321
+ s->redirect_url = t->location;
322
+ t->location = NULL;
323
+
324
+ t->connected = 0;
325
+ s->redirect_count++;
326
+
327
+ return t->parse_error = PARSE_ERROR_REPLAY;
170
328
  }
171
329
 
172
- if (WinHttpSendRequest(t->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
173
- data, (DWORD)content_length, (DWORD)content_length, 0) == FALSE) {
174
- giterr_set(GITERR_OS, "Failed to send request");
175
- goto on_error;
330
+ /* Check for a 200 HTTP status code. */
331
+ if (parser->status_code != 200) {
332
+ giterr_set(GITERR_NET,
333
+ "Unexpected HTTP status code: %d",
334
+ parser->status_code);
335
+ return t->parse_error = PARSE_ERROR_GENERIC;
176
336
  }
177
337
 
178
- ret = WinHttpReceiveResponse(t->request, NULL);
179
- if (ret == FALSE) {
180
- giterr_set(GITERR_OS, "Failed to receive response");
181
- goto on_error;
338
+ /* The response must contain a Content-Type header. */
339
+ if (!t->content_type) {
340
+ giterr_set(GITERR_NET, "No Content-Type header in response");
341
+ return t->parse_error = PARSE_ERROR_GENERIC;
182
342
  }
183
343
 
184
- return 0;
344
+ /* The Content-Type header must match our expectation. */
345
+ if (get_verb == s->verb)
346
+ git_buf_printf(&buf,
347
+ "application/x-git-%s-advertisement",
348
+ ctx->s->service);
349
+ else
350
+ git_buf_printf(&buf,
351
+ "application/x-git-%s-result",
352
+ ctx->s->service);
353
+
354
+ if (git_buf_oom(&buf))
355
+ return t->parse_error = PARSE_ERROR_GENERIC;
356
+
357
+ if (strcmp(t->content_type, git_buf_cstr(&buf))) {
358
+ git_buf_free(&buf);
359
+ giterr_set(GITERR_NET,
360
+ "Invalid Content-Type: %s",
361
+ t->content_type);
362
+ return t->parse_error = PARSE_ERROR_GENERIC;
363
+ }
185
364
 
186
- on_error:
187
365
  git_buf_free(&buf);
188
- if (t->request)
189
- WinHttpCloseHandle(t->request);
190
- t->request = NULL;
191
- return -1;
192
- #endif
366
+
367
+ return 0;
193
368
  }
194
369
 
195
- static int do_connect(transport_http *t)
370
+ static int on_message_complete(http_parser *parser)
196
371
  {
197
- #ifndef GIT_WINHTTP
198
- if (t->parent.connected && http_should_keep_alive(&t->parser))
199
- return 0;
372
+ parser_context *ctx = (parser_context *) parser->data;
373
+ http_subtransport *t = ctx->t;
200
374
 
201
- if (gitno_connect((git_transport *) t, t->host, t->port) < 0)
202
- return -1;
203
-
204
- t->parent.connected = 1;
375
+ t->parse_finished = 1;
205
376
 
206
377
  return 0;
207
- #else
208
- wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")";
209
- wchar_t host[GIT_WIN_PATH];
210
- int32_t port;
378
+ }
211
379
 
212
- t->session = WinHttpOpen(ua, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
213
- WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
380
+ static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
381
+ {
382
+ parser_context *ctx = (parser_context *) parser->data;
383
+ http_subtransport *t = ctx->t;
214
384
 
215
- if (t->session == NULL) {
216
- giterr_set(GITERR_OS, "Failed to init WinHTTP");
217
- goto on_error;
385
+ if (ctx->buf_size < len) {
386
+ giterr_set(GITERR_NET, "Can't fit data in the buffer");
387
+ return t->parse_error = PARSE_ERROR_GENERIC;
218
388
  }
219
389
 
220
- git__utf8_to_16(host, GIT_WIN_PATH, t->host);
390
+ memcpy(ctx->buffer, str, len);
391
+ *(ctx->bytes_read) += len;
392
+ ctx->buffer += len;
393
+ ctx->buf_size -= len;
221
394
 
222
- if (git__strtol32(&port, t->port, NULL, 10) < 0)
223
- goto on_error;
395
+ return 0;
396
+ }
224
397
 
225
- t->connection = WinHttpConnect(t->session, host, port, 0);
226
- if (t->connection == NULL) {
227
- giterr_set(GITERR_OS, "Failed to connect to host");
228
- goto on_error;
229
- }
398
+ static void clear_parser_state(http_subtransport *t)
399
+ {
400
+ unsigned i;
401
+ char *entry;
230
402
 
231
- t->parent.connected = 1;
232
- return 0;
403
+ http_parser_init(&t->parser, HTTP_RESPONSE);
404
+ gitno_buffer_setup(&t->socket,
405
+ &t->parse_buffer,
406
+ t->parse_buffer_data,
407
+ sizeof(t->parse_buffer_data));
233
408
 
234
- on_error:
235
- if (t->session) {
236
- WinHttpCloseHandle(t->session);
237
- t->session = NULL;
238
- }
239
- return -1;
240
- #endif
241
- }
409
+ t->last_cb = NONE;
410
+ t->parse_error = 0;
411
+ t->parse_finished = 0;
242
412
 
243
- /*
244
- * The HTTP parser is streaming, so we need to wait until we're in the
245
- * field handler before we can be sure that we can store the previous
246
- * value. Right now, we only care about the
247
- * Content-Type. on_header_{field,value} should be kept generic enough
248
- * to work for any request.
249
- */
413
+ git_buf_free(&t->parse_header_name);
414
+ git_buf_init(&t->parse_header_name, 0);
250
415
 
251
- static const char *typestr = "Content-Type";
416
+ git_buf_free(&t->parse_header_value);
417
+ git_buf_init(&t->parse_header_value, 0);
252
418
 
253
- static int on_header_field(http_parser *parser, const char *str, size_t len)
419
+ git__free(t->content_type);
420
+ t->content_type = NULL;
421
+
422
+ git__free(t->location);
423
+ t->location = NULL;
424
+
425
+ git_vector_foreach(&t->www_authenticate, i, entry)
426
+ git__free(entry);
427
+
428
+ git_vector_free(&t->www_authenticate);
429
+ }
430
+
431
+ static int write_chunk(gitno_socket *socket, const char *buffer, size_t len)
254
432
  {
255
- transport_http *t = (transport_http *) parser->data;
256
- git_buf *buf = &t->buf;
257
-
258
- if (t->last_cb == VALUE && t->ct_found) {
259
- t->ct_finished = 1;
260
- t->ct_found = 0;
261
- t->content_type = git__strdup(git_buf_cstr(buf));
262
- GITERR_CHECK_ALLOC(t->content_type);
263
- git_buf_clear(buf);
264
- }
433
+ git_buf buf = GIT_BUF_INIT;
265
434
 
266
- if (t->ct_found) {
267
- t->last_cb = FIELD;
268
- return 0;
435
+ /* Chunk header */
436
+ git_buf_printf(&buf, "%X\r\n", (unsigned)len);
437
+
438
+ if (git_buf_oom(&buf))
439
+ return -1;
440
+
441
+ if (gitno_send(socket, buf.ptr, buf.size, 0) < 0) {
442
+ git_buf_free(&buf);
443
+ return -1;
269
444
  }
270
445
 
271
- if (t->last_cb != FIELD)
272
- git_buf_clear(buf);
446
+ git_buf_free(&buf);
273
447
 
274
- git_buf_put(buf, str, len);
275
- t->last_cb = FIELD;
448
+ /* Chunk body */
449
+ if (len > 0 && gitno_send(socket, buffer, len, 0) < 0)
450
+ return -1;
276
451
 
277
- return git_buf_oom(buf);
452
+ /* Chunk footer */
453
+ if (gitno_send(socket, "\r\n", 2, 0) < 0)
454
+ return -1;
455
+
456
+ return 0;
278
457
  }
279
458
 
280
- static int on_header_value(http_parser *parser, const char *str, size_t len)
459
+ static int http_connect(http_subtransport *t)
281
460
  {
282
- transport_http *t = (transport_http *) parser->data;
283
- git_buf *buf = &t->buf;
461
+ int flags = 0;
284
462
 
285
- if (t->ct_finished) {
286
- t->last_cb = VALUE;
463
+ if (t->connected &&
464
+ http_should_keep_alive(&t->parser) &&
465
+ http_body_is_final(&t->parser))
287
466
  return 0;
288
- }
289
467
 
290
- if (t->last_cb == VALUE)
291
- git_buf_put(buf, str, len);
468
+ if (t->socket.socket)
469
+ gitno_close(&t->socket);
470
+
471
+ if (t->use_ssl) {
472
+ int tflags;
292
473
 
293
- if (t->last_cb == FIELD && !strcmp(git_buf_cstr(buf), typestr)) {
294
- t->ct_found = 1;
295
- git_buf_clear(buf);
296
- git_buf_put(buf, str, len);
474
+ if (t->owner->parent.read_flags(&t->owner->parent, &tflags) < 0)
475
+ return -1;
476
+
477
+ flags |= GITNO_CONNECT_SSL;
478
+
479
+ if (GIT_TRANSPORTFLAGS_NO_CHECK_CERT & tflags)
480
+ flags |= GITNO_CONNECT_SSL_NO_CHECK_CERT;
297
481
  }
298
482
 
299
- t->last_cb = VALUE;
483
+ if (gitno_connect(&t->socket, t->host, t->port, flags) < 0)
484
+ return -1;
300
485
 
301
- return git_buf_oom(buf);
486
+ t->connected = 1;
487
+ return 0;
302
488
  }
303
489
 
304
- static int on_headers_complete(http_parser *parser)
490
+ static int http_stream_read(
491
+ git_smart_subtransport_stream *stream,
492
+ char *buffer,
493
+ size_t buf_size,
494
+ size_t *bytes_read)
305
495
  {
306
- transport_http *t = (transport_http *) parser->data;
307
- git_buf *buf = &t->buf;
496
+ http_stream *s = (http_stream *)stream;
497
+ http_subtransport *t = OWNING_SUBTRANSPORT(s);
498
+ parser_context ctx;
499
+ size_t bytes_parsed;
308
500
 
309
- /* The content-type is text/plain for 404, so don't validate */
310
- if (parser->status_code == 404) {
311
- git_buf_clear(buf);
312
- return 0;
501
+ replay:
502
+ *bytes_read = 0;
503
+
504
+ assert(t->connected);
505
+
506
+ if (!s->sent_request) {
507
+ git_buf request = GIT_BUF_INIT;
508
+
509
+ clear_parser_state(t);
510
+
511
+ if (gen_request(&request, s, 0) < 0) {
512
+ giterr_set(GITERR_NET, "Failed to generate request");
513
+ return -1;
514
+ }
515
+
516
+ if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) {
517
+ git_buf_free(&request);
518
+ return -1;
519
+ }
520
+
521
+ git_buf_free(&request);
522
+
523
+ s->sent_request = 1;
313
524
  }
314
525
 
315
- if (t->content_type == NULL) {
316
- t->content_type = git__strdup(git_buf_cstr(buf));
317
- if (t->content_type == NULL)
318
- return t->error = -1;
526
+ if (!s->received_response) {
527
+ if (s->chunked) {
528
+ assert(s->verb == post_verb);
529
+
530
+ /* Flush, if necessary */
531
+ if (s->chunk_buffer_len > 0 &&
532
+ write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0)
533
+ return -1;
534
+
535
+ s->chunk_buffer_len = 0;
536
+
537
+ /* Write the final chunk. */
538
+ if (gitno_send(&t->socket, "0\r\n\r\n", 5, 0) < 0)
539
+ return -1;
540
+ }
541
+
542
+ s->received_response = 1;
319
543
  }
320
544
 
321
- git_buf_clear(buf);
322
- git_buf_printf(buf, "application/x-git-%s-advertisement", t->service);
323
- if (git_buf_oom(buf))
324
- return t->error = -1;
545
+ while (!*bytes_read && !t->parse_finished) {
546
+ t->parse_buffer.offset = 0;
325
547
 
326
- if (strcmp(t->content_type, git_buf_cstr(buf)))
327
- return t->error = -1;
548
+ if (gitno_recv(&t->parse_buffer) < 0)
549
+ return -1;
328
550
 
329
- git_buf_clear(buf);
330
- return 0;
331
- }
551
+ /* This call to http_parser_execute will result in invocations of the
552
+ * on_* family of callbacks. The most interesting of these is
553
+ * on_body_fill_buffer, which is called when data is ready to be copied
554
+ * into the target buffer. We need to marshal the buffer, buf_size, and
555
+ * bytes_read parameters to this callback. */
556
+ ctx.t = t;
557
+ ctx.s = s;
558
+ ctx.buffer = buffer;
559
+ ctx.buf_size = buf_size;
560
+ ctx.bytes_read = bytes_read;
332
561
 
333
- static int on_message_complete(http_parser *parser)
334
- {
335
- transport_http *t = (transport_http *) parser->data;
562
+ /* Set the context, call the parser, then unset the context. */
563
+ t->parser.data = &ctx;
564
+
565
+ bytes_parsed = http_parser_execute(&t->parser,
566
+ &t->settings,
567
+ t->parse_buffer.data,
568
+ t->parse_buffer.offset);
569
+
570
+ t->parser.data = NULL;
571
+
572
+ /* If there was a handled authentication failure, then parse_error
573
+ * will have signaled us that we should replay the request. */
574
+ if (PARSE_ERROR_REPLAY == t->parse_error) {
575
+ s->sent_request = 0;
576
+
577
+ if (http_connect(t) < 0)
578
+ return -1;
336
579
 
337
- t->transfer_finished = 1;
580
+ goto replay;
581
+ }
582
+
583
+ if (t->parse_error < 0)
584
+ return -1;
338
585
 
339
- if (parser->status_code == 404) {
340
- giterr_set(GITERR_NET, "Remote error: %s", git_buf_cstr(&t->buf));
341
- t->error = -1;
586
+ if (bytes_parsed != t->parse_buffer.offset) {
587
+ giterr_set(GITERR_NET,
588
+ "HTTP parser error: %s",
589
+ http_errno_description((enum http_errno)t->parser.http_errno));
590
+ return -1;
591
+ }
342
592
  }
343
593
 
344
594
  return 0;
345
595
  }
346
596
 
347
- static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len)
597
+ static int http_stream_write_chunked(
598
+ git_smart_subtransport_stream *stream,
599
+ const char *buffer,
600
+ size_t len)
348
601
  {
349
- git_transport *transport = (git_transport *) parser->data;
350
- transport_http *t = (transport_http *) parser->data;
351
- gitno_buffer *buf = &transport->buffer;
602
+ http_stream *s = (http_stream *)stream;
603
+ http_subtransport *t = OWNING_SUBTRANSPORT(s);
352
604
 
353
- if (buf->len - buf->offset < len) {
354
- giterr_set(GITERR_NET, "Can't fit data in the buffer");
355
- return t->error = -1;
605
+ assert(t->connected);
606
+
607
+ /* Send the request, if necessary */
608
+ if (!s->sent_request) {
609
+ git_buf request = GIT_BUF_INIT;
610
+
611
+ clear_parser_state(t);
612
+
613
+ if (gen_request(&request, s, 0) < 0) {
614
+ giterr_set(GITERR_NET, "Failed to generate request");
615
+ return -1;
616
+ }
617
+
618
+ if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0) {
619
+ git_buf_free(&request);
620
+ return -1;
621
+ }
622
+
623
+ git_buf_free(&request);
624
+
625
+ s->sent_request = 1;
626
+ }
627
+
628
+ if (len > CHUNK_SIZE) {
629
+ /* Flush, if necessary */
630
+ if (s->chunk_buffer_len > 0) {
631
+ if (write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0)
632
+ return -1;
633
+
634
+ s->chunk_buffer_len = 0;
635
+ }
636
+
637
+ /* Write chunk directly */
638
+ if (write_chunk(&t->socket, buffer, len) < 0)
639
+ return -1;
356
640
  }
641
+ else {
642
+ /* Append as much to the buffer as we can */
643
+ int count = min(CHUNK_SIZE - s->chunk_buffer_len, len);
644
+
645
+ if (!s->chunk_buffer)
646
+ s->chunk_buffer = git__malloc(CHUNK_SIZE);
647
+
648
+ memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count);
649
+ s->chunk_buffer_len += count;
650
+ buffer += count;
651
+ len -= count;
357
652
 
358
- memcpy(buf->data + buf->offset, str, len);
359
- buf->offset += len;
653
+ /* Is the buffer full? If so, then flush */
654
+ if (CHUNK_SIZE == s->chunk_buffer_len) {
655
+ if (write_chunk(&t->socket, s->chunk_buffer, s->chunk_buffer_len) < 0)
656
+ return -1;
657
+
658
+ s->chunk_buffer_len = 0;
659
+
660
+ if (len > 0) {
661
+ memcpy(s->chunk_buffer, buffer, len);
662
+ s->chunk_buffer_len = len;
663
+ }
664
+ }
665
+ }
360
666
 
361
667
  return 0;
362
668
  }
363
669
 
364
- static int http_recv_cb(gitno_buffer *buf)
670
+ static int http_stream_write_single(
671
+ git_smart_subtransport_stream *stream,
672
+ const char *buffer,
673
+ size_t len)
365
674
  {
366
- git_transport *transport = (git_transport *) buf->cb_data;
367
- transport_http *t = (transport_http *) transport;
368
- size_t old_len;
369
- char buffer[2048];
370
- #ifdef GIT_WINHTTP
371
- DWORD recvd;
372
- #else
373
- gitno_buffer inner;
374
- int error;
375
- #endif
376
-
377
- if (t->transfer_finished)
378
- return 0;
675
+ http_stream *s = (http_stream *)stream;
676
+ http_subtransport *t = OWNING_SUBTRANSPORT(s);
677
+ git_buf request = GIT_BUF_INIT;
379
678
 
380
- #ifndef GIT_WINHTTP
381
- gitno_buffer_setup(transport, &inner, buffer, sizeof(buffer));
679
+ assert(t->connected);
382
680
 
383
- if ((error = gitno_recv(&inner)) < 0)
681
+ if (s->sent_request) {
682
+ giterr_set(GITERR_NET, "Subtransport configured for only one write");
384
683
  return -1;
385
-
386
- old_len = buf->offset;
387
- http_parser_execute(&t->parser, &t->settings, inner.data, inner.offset);
388
- if (t->error < 0)
389
- return t->error;
390
- #else
391
- old_len = buf->offset;
392
- if (WinHttpReadData(t->request, buffer, sizeof(buffer), &recvd) == FALSE) {
393
- giterr_set(GITERR_OS, "Failed to read data from the network");
394
- return t->error = -1;
395
684
  }
396
685
 
397
- if (buf->len - buf->offset < recvd) {
398
- giterr_set(GITERR_NET, "Can't fit data in the buffer");
399
- return t->error = -1;
686
+ clear_parser_state(t);
687
+
688
+ if (gen_request(&request, s, len) < 0) {
689
+ giterr_set(GITERR_NET, "Failed to generate request");
690
+ return -1;
400
691
  }
401
692
 
402
- memcpy(buf->data + buf->offset, buffer, recvd);
403
- buf->offset += recvd;
404
- #endif
693
+ if (gitno_send(&t->socket, request.ptr, request.size, 0) < 0)
694
+ goto on_error;
695
+
696
+ if (len && gitno_send(&t->socket, buffer, len, 0) < 0)
697
+ goto on_error;
698
+
699
+ git_buf_free(&request);
700
+ s->sent_request = 1;
405
701
 
406
- return (int)(buf->offset - old_len);
702
+ return 0;
703
+
704
+ on_error:
705
+ git_buf_free(&request);
706
+ return -1;
407
707
  }
408
708
 
409
- /* Set up the gitno_buffer so calling gitno_recv() grabs data from the HTTP response */
410
- static void setup_gitno_buffer(git_transport *transport)
709
+ static void http_stream_free(git_smart_subtransport_stream *stream)
411
710
  {
412
- transport_http *t = (transport_http *) transport;
711
+ http_stream *s = (http_stream *)stream;
413
712
 
414
- /* WinHTTP takes care of this for us */
415
- #ifndef GIT_WINHTTP
416
- http_parser_init(&t->parser, HTTP_RESPONSE);
417
- t->parser.data = t;
418
- t->transfer_finished = 0;
419
- memset(&t->settings, 0x0, sizeof(http_parser_settings));
420
- t->settings.on_header_field = on_header_field;
421
- t->settings.on_header_value = on_header_value;
422
- t->settings.on_headers_complete = on_headers_complete;
423
- t->settings.on_body = on_body_fill_buffer;
424
- t->settings.on_message_complete = on_message_complete;
425
- #endif
713
+ if (s->chunk_buffer)
714
+ git__free(s->chunk_buffer);
715
+
716
+ if (s->redirect_url)
717
+ git__free(s->redirect_url);
426
718
 
427
- gitno_buffer_setup_callback(transport, &transport->buffer, t->buffer, sizeof(t->buffer), http_recv_cb, t);
719
+ git__free(s);
428
720
  }
429
721
 
430
- static int http_connect(git_transport *transport, int direction)
722
+ static int http_stream_alloc(http_subtransport *t,
723
+ git_smart_subtransport_stream **stream)
431
724
  {
432
- transport_http *t = (transport_http *) transport;
433
- int ret;
434
- git_buf request = GIT_BUF_INIT;
435
- const char *service = "upload-pack";
436
- const char *url = t->parent.url, *prefix_http = "http://", *prefix_https = "https://";
437
- const char *default_port;
438
- git_pkt *pkt;
725
+ http_stream *s;
439
726
 
440
- if (direction == GIT_DIR_PUSH) {
441
- giterr_set(GITERR_NET, "Pushing over HTTP is not implemented");
727
+ if (!stream)
442
728
  return -1;
443
- }
444
729
 
445
- t->parent.direction = direction;
730
+ s = git__calloc(sizeof(http_stream), 1);
731
+ GITERR_CHECK_ALLOC(s);
446
732
 
447
- if (!git__prefixcmp(url, prefix_http)) {
448
- url = t->parent.url + strlen(prefix_http);
449
- default_port = "80";
450
- }
733
+ s->parent.subtransport = &t->parent;
734
+ s->parent.read = http_stream_read;
735
+ s->parent.write = http_stream_write_single;
736
+ s->parent.free = http_stream_free;
451
737
 
452
- if (!git__prefixcmp(url, prefix_https)) {
453
- url += strlen(prefix_https);
454
- default_port = "443";
455
- }
738
+ *stream = (git_smart_subtransport_stream *)s;
739
+ return 0;
740
+ }
456
741
 
457
- t->path = strchr(url, '/');
742
+ static int http_uploadpack_ls(
743
+ http_subtransport *t,
744
+ git_smart_subtransport_stream **stream)
745
+ {
746
+ http_stream *s;
458
747
 
459
- if ((ret = gitno_extract_host_and_port(&t->host, &t->port, url, default_port)) < 0)
460
- goto cleanup;
748
+ if (http_stream_alloc(t, stream) < 0)
749
+ return -1;
461
750
 
462
- t->service = git__strdup(service);
463
- GITERR_CHECK_ALLOC(t->service);
751
+ s = (http_stream *)*stream;
464
752
 
465
- if ((ret = do_connect(t)) < 0)
466
- goto cleanup;
753
+ s->service = upload_pack_service;
754
+ s->service_url = upload_pack_ls_service_url;
755
+ s->verb = get_verb;
467
756
 
468
- if ((ret = send_request(t, "upload-pack", NULL, 0, 1)) < 0)
469
- goto cleanup;
757
+ return 0;
758
+ }
470
759
 
471
- setup_gitno_buffer(transport);
472
- if ((ret = git_protocol_store_refs(transport, 2)) < 0)
473
- goto cleanup;
760
+ static int http_uploadpack(
761
+ http_subtransport *t,
762
+ git_smart_subtransport_stream **stream)
763
+ {
764
+ http_stream *s;
474
765
 
475
- pkt = git_vector_get(&transport->refs, 0);
476
- if (pkt == NULL || pkt->type != GIT_PKT_COMMENT) {
477
- giterr_set(GITERR_NET, "Invalid HTTP response");
478
- return t->error = -1;
479
- } else {
480
- /* Remove the comment pkt from the list */
481
- git_vector_remove(&transport->refs, 0);
482
- git__free(pkt);
483
- }
766
+ if (http_stream_alloc(t, stream) < 0)
767
+ return -1;
484
768
 
485
- if (git_protocol_detect_caps(git_vector_get(&transport->refs, 0), &transport->caps) < 0)
486
- return t->error = -1;
769
+ s = (http_stream *)*stream;
487
770
 
488
- cleanup:
489
- git_buf_free(&request);
490
- git_buf_clear(&t->buf);
771
+ s->service = upload_pack_service;
772
+ s->service_url = upload_pack_service_url;
773
+ s->verb = post_verb;
491
774
 
492
- return ret;
775
+ return 0;
493
776
  }
494
777
 
495
- static int http_negotiation_step(struct git_transport *transport, void *data, size_t len)
778
+ static int http_receivepack_ls(
779
+ http_subtransport *t,
780
+ git_smart_subtransport_stream **stream)
496
781
  {
497
- transport_http *t = (transport_http *) transport;
498
- int ret;
782
+ http_stream *s;
499
783
 
500
- /* First, send the data as a HTTP POST request */
501
- if ((ret = do_connect(t)) < 0)
784
+ if (http_stream_alloc(t, stream) < 0)
502
785
  return -1;
503
786
 
504
- if (send_request(t, "upload-pack", data, len, 0) < 0)
505
- return -1;
787
+ s = (http_stream *)*stream;
506
788
 
507
- /* Then we need to set up the buffer to grab data from the HTTP response */
508
- setup_gitno_buffer(transport);
789
+ s->service = receive_pack_service;
790
+ s->service_url = receive_pack_ls_service_url;
791
+ s->verb = get_verb;
509
792
 
510
793
  return 0;
511
794
  }
512
795
 
513
- static int http_close(git_transport *transport)
796
+ static int http_receivepack(
797
+ http_subtransport *t,
798
+ git_smart_subtransport_stream **stream)
514
799
  {
515
- #ifndef GIT_WINHTTP
516
- if (gitno_ssl_teardown(transport) < 0)
517
- return -1;
800
+ http_stream *s;
518
801
 
519
- if (gitno_close(transport->socket) < 0) {
520
- giterr_set(GITERR_OS, "Failed to close the socket: %s", strerror(errno));
802
+ if (http_stream_alloc(t, stream) < 0)
521
803
  return -1;
522
- }
523
- #else
524
- transport_http *t = (transport_http *) transport;
525
804
 
526
- if (t->request)
527
- WinHttpCloseHandle(t->request);
528
- if (t->connection)
529
- WinHttpCloseHandle(t->connection);
530
- if (t->session)
531
- WinHttpCloseHandle(t->session);
532
- #endif
805
+ s = (http_stream *)*stream;
533
806
 
534
- transport->connected = 0;
807
+ /* Use Transfer-Encoding: chunked for this request */
808
+ s->chunked = 1;
809
+ s->parent.write = http_stream_write_chunked;
810
+
811
+ s->service = receive_pack_service;
812
+ s->service_url = receive_pack_service_url;
813
+ s->verb = post_verb;
535
814
 
536
815
  return 0;
537
816
  }
538
817
 
539
-
540
- static void http_free(git_transport *transport)
818
+ static int http_action(
819
+ git_smart_subtransport_stream **stream,
820
+ git_smart_subtransport *subtransport,
821
+ const char *url,
822
+ git_smart_service_t action)
541
823
  {
542
- transport_http *t = (transport_http *) transport;
543
- git_vector *refs = &transport->refs;
544
- git_vector *common = &transport->common;
545
- unsigned int i;
546
- git_pkt *p;
547
-
548
- #ifdef GIT_WIN32
549
- /* cleanup the WSA context. note that this context
550
- * can be initialized more than once with WSAStartup(),
551
- * and needs to be cleaned one time for each init call
552
- */
553
- WSACleanup();
554
- #endif
555
-
556
- git_vector_foreach(refs, i, p) {
557
- git_pkt_free(p);
824
+ http_subtransport *t = (http_subtransport *)subtransport;
825
+ const char *default_port = NULL;
826
+ int ret;
827
+
828
+ if (!stream)
829
+ return -1;
830
+
831
+ if (!t->host || !t->port || !t->path) {
832
+ if (!git__prefixcmp(url, prefix_http)) {
833
+ url = url + strlen(prefix_http);
834
+ default_port = "80";
835
+ }
836
+
837
+ if (!git__prefixcmp(url, prefix_https)) {
838
+ url += strlen(prefix_https);
839
+ default_port = "443";
840
+ t->use_ssl = 1;
841
+ }
842
+
843
+ if (!default_port)
844
+ return -1;
845
+
846
+ if ((ret = gitno_extract_url_parts(&t->host, &t->port,
847
+ &t->user_from_url, &t->pass_from_url, url, default_port)) < 0)
848
+ return ret;
849
+
850
+ t->path = strchr(url, '/');
558
851
  }
559
- git_vector_free(refs);
560
- git_vector_foreach(common, i, p) {
561
- git_pkt_free(p);
852
+
853
+ if (http_connect(t) < 0)
854
+ return -1;
855
+
856
+ switch (action)
857
+ {
858
+ case GIT_SERVICE_UPLOADPACK_LS:
859
+ return http_uploadpack_ls(t, stream);
860
+
861
+ case GIT_SERVICE_UPLOADPACK:
862
+ return http_uploadpack(t, stream);
863
+
864
+ case GIT_SERVICE_RECEIVEPACK_LS:
865
+ return http_receivepack_ls(t, stream);
866
+
867
+ case GIT_SERVICE_RECEIVEPACK:
868
+ return http_receivepack(t, stream);
562
869
  }
563
- git_vector_free(common);
564
- git_buf_free(&t->buf);
565
- git__free(t->content_type);
566
- git__free(t->host);
567
- git__free(t->port);
568
- git__free(t->service);
569
- git__free(t->parent.url);
570
- git__free(t);
870
+
871
+ *stream = NULL;
872
+ return -1;
571
873
  }
572
874
 
573
- int git_transport_http(git_transport **out)
875
+ static int http_close(git_smart_subtransport *subtransport)
574
876
  {
575
- transport_http *t;
877
+ http_subtransport *t = (http_subtransport *) subtransport;
576
878
 
577
- t = git__malloc(sizeof(transport_http));
578
- GITERR_CHECK_ALLOC(t);
879
+ clear_parser_state(t);
579
880
 
580
- memset(t, 0x0, sizeof(transport_http));
881
+ if (t->socket.socket) {
882
+ gitno_close(&t->socket);
883
+ memset(&t->socket, 0x0, sizeof(gitno_socket));
884
+ }
581
885
 
582
- t->parent.connect = http_connect;
583
- t->parent.negotiation_step = http_negotiation_step;
584
- t->parent.close = http_close;
585
- t->parent.free = http_free;
586
- t->parent.rpc = 1;
886
+ if (t->cred) {
887
+ t->cred->free(t->cred);
888
+ t->cred = NULL;
889
+ }
587
890
 
588
- if (git_vector_init(&t->parent.refs, 16, NULL) < 0) {
589
- git__free(t);
590
- return -1;
891
+ if (t->url_cred) {
892
+ t->url_cred->free(t->url_cred);
893
+ t->url_cred = NULL;
591
894
  }
592
895
 
593
- #ifdef GIT_WIN32
594
- /* on win32, the WSA context needs to be initialized
595
- * before any socket calls can be performed */
596
- if (WSAStartup(MAKEWORD(2,2), &t->wsd) != 0) {
597
- http_free((git_transport *) t);
598
- giterr_set(GITERR_OS, "Winsock init failed");
599
- return -1;
896
+ if (t->host) {
897
+ git__free(t->host);
898
+ t->host = NULL;
899
+ }
900
+
901
+ if (t->port) {
902
+ git__free(t->port);
903
+ t->port = NULL;
904
+ }
905
+
906
+ if (t->user_from_url) {
907
+ git__free(t->user_from_url);
908
+ t->user_from_url = NULL;
909
+ }
910
+
911
+ if (t->pass_from_url) {
912
+ git__free(t->pass_from_url);
913
+ t->pass_from_url = NULL;
600
914
  }
601
- #endif
602
915
 
603
- *out = (git_transport *) t;
604
916
  return 0;
605
917
  }
606
918
 
607
- int git_transport_https(git_transport **out)
919
+ static void http_free(git_smart_subtransport *subtransport)
608
920
  {
609
- #if defined(GIT_SSL) || defined(GIT_WINHTTP)
610
- transport_http *t;
611
- if (git_transport_http((git_transport **)&t) < 0)
921
+ http_subtransport *t = (http_subtransport *) subtransport;
922
+
923
+ http_close(subtransport);
924
+
925
+ git__free(t);
926
+ }
927
+
928
+ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *owner)
929
+ {
930
+ http_subtransport *t;
931
+
932
+ if (!out)
612
933
  return -1;
613
934
 
614
- t->parent.use_ssl = 1;
615
- t->parent.check_cert = 1;
616
- *out = (git_transport *) t;
935
+ t = git__calloc(sizeof(http_subtransport), 1);
936
+ GITERR_CHECK_ALLOC(t);
617
937
 
618
- return 0;
619
- #else
620
- GIT_UNUSED(out);
938
+ t->owner = (transport_smart *)owner;
939
+ t->parent.action = http_action;
940
+ t->parent.close = http_close;
941
+ t->parent.free = http_free;
621
942
 
622
- giterr_set(GITERR_NET, "HTTPS support not available");
623
- return -1;
624
- #endif
943
+ t->settings.on_header_field = on_header_field;
944
+ t->settings.on_header_value = on_header_value;
945
+ t->settings.on_headers_complete = on_headers_complete;
946
+ t->settings.on_body = on_body_fill_buffer;
947
+ t->settings.on_message_complete = on_message_complete;
948
+
949
+ *out = (git_smart_subtransport *) t;
950
+ return 0;
625
951
  }
952
+
953
+ #endif /* !GIT_WINHTTP */