rugged 0.28.5 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (411) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/rugged/extconf.rb +3 -1
  4. data/ext/rugged/rugged.c +35 -31
  5. data/ext/rugged/rugged.h +13 -0
  6. data/ext/rugged/rugged_blob.c +11 -9
  7. data/ext/rugged/rugged_commit.c +18 -16
  8. data/ext/rugged/rugged_config.c +1 -1
  9. data/ext/rugged/rugged_diff.c +4 -26
  10. data/ext/rugged/rugged_index.c +4 -2
  11. data/ext/rugged/rugged_note.c +5 -3
  12. data/ext/rugged/rugged_object.c +57 -10
  13. data/ext/rugged/rugged_rebase.c +3 -1
  14. data/ext/rugged/rugged_remote.c +32 -8
  15. data/ext/rugged/rugged_repo.c +232 -17
  16. data/ext/rugged/rugged_tag.c +8 -6
  17. data/ext/rugged/rugged_tree.c +18 -16
  18. data/lib/rugged/commit.rb +17 -4
  19. data/lib/rugged/repository.rb +5 -6
  20. data/lib/rugged/submodule_collection.rb +4 -4
  21. data/lib/rugged/version.rb +1 -1
  22. data/vendor/libgit2/CMakeLists.txt +57 -75
  23. data/vendor/libgit2/COPYING +28 -0
  24. data/vendor/libgit2/cmake/{Modules/AddCFlagIfSupported.cmake → AddCFlagIfSupported.cmake} +0 -0
  25. data/vendor/libgit2/cmake/{Modules/EnableWarnings.cmake → EnableWarnings.cmake} +5 -1
  26. data/vendor/libgit2/cmake/{Modules/FindCoreFoundation.cmake → FindCoreFoundation.cmake} +2 -2
  27. data/vendor/libgit2/cmake/{Modules/FindGSSAPI.cmake → FindGSSAPI.cmake} +1 -1
  28. data/vendor/libgit2/cmake/FindGSSFramework.cmake +28 -0
  29. data/vendor/libgit2/cmake/{Modules/FindHTTP_Parser.cmake → FindHTTP_Parser.cmake} +0 -0
  30. data/vendor/libgit2/cmake/{Modules/FindIconv.cmake → FindIconv.cmake} +0 -0
  31. data/vendor/libgit2/cmake/FindPCRE.cmake +38 -0
  32. data/vendor/libgit2/cmake/FindPCRE2.cmake +37 -0
  33. data/vendor/libgit2/cmake/{Modules/FindPkgLibraries.cmake → FindPkgLibraries.cmake} +0 -0
  34. data/vendor/libgit2/cmake/{Modules/FindSecurity.cmake → FindSecurity.cmake} +2 -2
  35. data/vendor/libgit2/cmake/{Modules/FindStatNsec.cmake → FindStatNsec.cmake} +6 -0
  36. data/vendor/libgit2/cmake/{Modules/FindmbedTLS.cmake → FindmbedTLS.cmake} +0 -0
  37. data/vendor/libgit2/cmake/{Modules/IdeSplitSources.cmake → IdeSplitSources.cmake} +0 -0
  38. data/vendor/libgit2/cmake/PkgBuildConfig.cmake +77 -0
  39. data/vendor/libgit2/cmake/SanitizeBool.cmake +20 -0
  40. data/vendor/libgit2/cmake/SelectGSSAPI.cmake +48 -0
  41. data/vendor/libgit2/cmake/SelectHTTPSBackend.cmake +120 -0
  42. data/vendor/libgit2/cmake/SelectHashes.cmake +61 -0
  43. data/vendor/libgit2/deps/http-parser/CMakeLists.txt +4 -3
  44. data/vendor/libgit2/deps/http-parser/http_parser.c +11 -6
  45. data/vendor/libgit2/deps/ntlmclient/CMakeLists.txt +25 -0
  46. data/vendor/libgit2/deps/ntlmclient/compat.h +28 -0
  47. data/vendor/libgit2/deps/ntlmclient/crypt.h +64 -0
  48. data/vendor/libgit2/deps/ntlmclient/crypt_commoncrypto.c +120 -0
  49. data/vendor/libgit2/deps/ntlmclient/crypt_commoncrypto.h +18 -0
  50. data/vendor/libgit2/deps/ntlmclient/crypt_mbedtls.c +145 -0
  51. data/vendor/libgit2/deps/ntlmclient/crypt_mbedtls.h +18 -0
  52. data/vendor/libgit2/deps/ntlmclient/crypt_openssl.c +130 -0
  53. data/vendor/libgit2/deps/ntlmclient/crypt_openssl.h +21 -0
  54. data/vendor/libgit2/deps/ntlmclient/ntlm.c +1419 -0
  55. data/vendor/libgit2/deps/ntlmclient/ntlm.h +174 -0
  56. data/vendor/libgit2/deps/ntlmclient/ntlmclient.h +320 -0
  57. data/vendor/libgit2/deps/ntlmclient/unicode.h +36 -0
  58. data/vendor/libgit2/deps/ntlmclient/unicode_builtin.c +445 -0
  59. data/vendor/libgit2/deps/ntlmclient/unicode_iconv.c +201 -0
  60. data/vendor/libgit2/deps/ntlmclient/utf8.h +1257 -0
  61. data/vendor/libgit2/deps/ntlmclient/util.c +35 -0
  62. data/vendor/libgit2/deps/ntlmclient/util.h +15 -0
  63. data/vendor/libgit2/deps/pcre/CMakeLists.txt +140 -0
  64. data/vendor/libgit2/deps/pcre/COPYING +5 -0
  65. data/vendor/libgit2/deps/pcre/LICENCE +93 -0
  66. data/vendor/libgit2/deps/pcre/cmake/COPYING-CMAKE-SCRIPTS +22 -0
  67. data/vendor/libgit2/deps/pcre/cmake/FindEditline.cmake +17 -0
  68. data/vendor/libgit2/deps/pcre/cmake/FindPackageHandleStandardArgs.cmake +58 -0
  69. data/vendor/libgit2/deps/pcre/cmake/FindReadline.cmake +29 -0
  70. data/vendor/libgit2/deps/pcre/config.h.in +57 -0
  71. data/vendor/libgit2/deps/pcre/pcre.h +641 -0
  72. data/vendor/libgit2/deps/pcre/pcre_byte_order.c +319 -0
  73. data/vendor/libgit2/deps/pcre/pcre_chartables.c +198 -0
  74. data/vendor/libgit2/deps/pcre/pcre_compile.c +9812 -0
  75. data/vendor/libgit2/deps/pcre/pcre_config.c +190 -0
  76. data/vendor/libgit2/deps/pcre/pcre_dfa_exec.c +3676 -0
  77. data/vendor/libgit2/deps/pcre/pcre_exec.c +7173 -0
  78. data/vendor/libgit2/deps/pcre/pcre_fullinfo.c +245 -0
  79. data/vendor/libgit2/deps/pcre/pcre_get.c +669 -0
  80. data/vendor/libgit2/deps/pcre/pcre_globals.c +86 -0
  81. data/vendor/libgit2/deps/pcre/pcre_internal.h +2787 -0
  82. data/vendor/libgit2/deps/pcre/pcre_jit_compile.c +11913 -0
  83. data/vendor/libgit2/deps/pcre/pcre_maketables.c +156 -0
  84. data/vendor/libgit2/deps/pcre/pcre_newline.c +210 -0
  85. data/vendor/libgit2/deps/pcre/pcre_ord2utf8.c +94 -0
  86. data/vendor/libgit2/deps/pcre/pcre_printint.c +834 -0
  87. data/vendor/libgit2/deps/pcre/pcre_refcount.c +92 -0
  88. data/vendor/libgit2/deps/pcre/pcre_string_utils.c +211 -0
  89. data/vendor/libgit2/deps/pcre/pcre_study.c +1686 -0
  90. data/vendor/libgit2/deps/pcre/pcre_tables.c +727 -0
  91. data/vendor/libgit2/deps/pcre/pcre_ucd.c +3644 -0
  92. data/vendor/libgit2/deps/pcre/pcre_valid_utf8.c +301 -0
  93. data/vendor/libgit2/deps/pcre/pcre_version.c +98 -0
  94. data/vendor/libgit2/deps/pcre/pcre_xclass.c +268 -0
  95. data/vendor/libgit2/deps/pcre/pcreposix.c +420 -0
  96. data/vendor/libgit2/deps/pcre/pcreposix.h +117 -0
  97. data/vendor/libgit2/deps/pcre/ucp.h +224 -0
  98. data/vendor/libgit2/deps/zlib/CMakeLists.txt +6 -5
  99. data/vendor/libgit2/deps/zlib/adler32.c +0 -7
  100. data/vendor/libgit2/deps/zlib/crc32.c +0 -7
  101. data/vendor/libgit2/deps/zlib/deflate.c +1 -0
  102. data/vendor/libgit2/include/git2.h +2 -0
  103. data/vendor/libgit2/include/git2/annotated_commit.h +1 -1
  104. data/vendor/libgit2/include/git2/apply.h +24 -2
  105. data/vendor/libgit2/include/git2/attr.h +23 -13
  106. data/vendor/libgit2/include/git2/blame.h +4 -2
  107. data/vendor/libgit2/include/git2/blob.h +61 -13
  108. data/vendor/libgit2/include/git2/branch.h +74 -57
  109. data/vendor/libgit2/include/git2/buffer.h +20 -14
  110. data/vendor/libgit2/include/git2/cert.h +135 -0
  111. data/vendor/libgit2/include/git2/checkout.h +46 -14
  112. data/vendor/libgit2/include/git2/cherrypick.h +3 -3
  113. data/vendor/libgit2/include/git2/clone.h +2 -2
  114. data/vendor/libgit2/include/git2/commit.h +23 -1
  115. data/vendor/libgit2/include/git2/common.h +34 -8
  116. data/vendor/libgit2/include/git2/config.h +13 -13
  117. data/vendor/libgit2/include/git2/cred_helpers.h +4 -42
  118. data/vendor/libgit2/include/git2/credential.h +314 -0
  119. data/vendor/libgit2/include/git2/credential_helpers.h +52 -0
  120. data/vendor/libgit2/include/git2/deprecated.h +362 -4
  121. data/vendor/libgit2/include/git2/describe.h +4 -4
  122. data/vendor/libgit2/include/git2/diff.h +17 -15
  123. data/vendor/libgit2/include/git2/errors.h +5 -2
  124. data/vendor/libgit2/include/git2/filter.h +8 -0
  125. data/vendor/libgit2/include/git2/index.h +5 -5
  126. data/vendor/libgit2/include/git2/indexer.h +49 -4
  127. data/vendor/libgit2/include/git2/merge.h +6 -10
  128. data/vendor/libgit2/include/git2/net.h +0 -5
  129. data/vendor/libgit2/include/git2/object.h +2 -14
  130. data/vendor/libgit2/include/git2/odb.h +18 -22
  131. data/vendor/libgit2/include/git2/odb_backend.h +5 -4
  132. data/vendor/libgit2/include/git2/oid.h +11 -6
  133. data/vendor/libgit2/include/git2/pack.h +13 -2
  134. data/vendor/libgit2/include/git2/proxy.h +6 -4
  135. data/vendor/libgit2/include/git2/rebase.h +46 -2
  136. data/vendor/libgit2/include/git2/refs.h +22 -3
  137. data/vendor/libgit2/include/git2/remote.h +40 -15
  138. data/vendor/libgit2/include/git2/repository.h +124 -58
  139. data/vendor/libgit2/include/git2/revert.h +1 -1
  140. data/vendor/libgit2/include/git2/revwalk.h +7 -3
  141. data/vendor/libgit2/include/git2/stash.h +4 -4
  142. data/vendor/libgit2/include/git2/status.h +25 -16
  143. data/vendor/libgit2/include/git2/strarray.h +6 -10
  144. data/vendor/libgit2/include/git2/submodule.h +20 -3
  145. data/vendor/libgit2/include/git2/sys/alloc.h +9 -9
  146. data/vendor/libgit2/include/git2/sys/cred.h +15 -0
  147. data/vendor/libgit2/include/git2/sys/credential.h +90 -0
  148. data/vendor/libgit2/include/git2/sys/index.h +4 -2
  149. data/vendor/libgit2/include/git2/sys/mempack.h +2 -1
  150. data/vendor/libgit2/include/git2/sys/merge.h +1 -1
  151. data/vendor/libgit2/include/git2/sys/odb_backend.h +48 -4
  152. data/vendor/libgit2/include/git2/sys/refdb_backend.h +164 -21
  153. data/vendor/libgit2/include/git2/sys/repository.h +17 -6
  154. data/vendor/libgit2/include/git2/sys/transport.h +4 -4
  155. data/vendor/libgit2/include/git2/tag.h +11 -2
  156. data/vendor/libgit2/include/git2/trace.h +2 -2
  157. data/vendor/libgit2/include/git2/transport.h +11 -340
  158. data/vendor/libgit2/include/git2/tree.h +7 -3
  159. data/vendor/libgit2/include/git2/types.h +4 -89
  160. data/vendor/libgit2/include/git2/version.h +5 -5
  161. data/vendor/libgit2/include/git2/worktree.h +5 -5
  162. data/vendor/libgit2/src/CMakeLists.txt +147 -272
  163. data/vendor/libgit2/src/alloc.c +2 -14
  164. data/vendor/libgit2/src/{stdalloc.c → allocators/stdalloc.c} +3 -4
  165. data/vendor/libgit2/src/{stdalloc.h → allocators/stdalloc.h} +4 -4
  166. data/vendor/libgit2/src/allocators/win32_crtdbg.c +118 -0
  167. data/vendor/libgit2/src/{transports/cred.h → allocators/win32_crtdbg.h} +5 -4
  168. data/vendor/libgit2/src/apply.c +36 -16
  169. data/vendor/libgit2/src/assert_safe.h +58 -0
  170. data/vendor/libgit2/src/attr.c +70 -64
  171. data/vendor/libgit2/src/attr_file.c +197 -99
  172. data/vendor/libgit2/src/attr_file.h +9 -9
  173. data/vendor/libgit2/src/attrcache.c +48 -49
  174. data/vendor/libgit2/src/attrcache.h +2 -1
  175. data/vendor/libgit2/src/blame.c +34 -15
  176. data/vendor/libgit2/src/blame.h +1 -1
  177. data/vendor/libgit2/src/blame_git.c +27 -10
  178. data/vendor/libgit2/src/blob.c +92 -17
  179. data/vendor/libgit2/src/blob.h +2 -2
  180. data/vendor/libgit2/src/branch.c +68 -42
  181. data/vendor/libgit2/src/buffer.c +11 -3
  182. data/vendor/libgit2/src/buffer.h +1 -0
  183. data/vendor/libgit2/src/cache.c +34 -58
  184. data/vendor/libgit2/src/cache.h +1 -1
  185. data/vendor/libgit2/src/cc-compat.h +5 -0
  186. data/vendor/libgit2/src/checkout.c +73 -86
  187. data/vendor/libgit2/src/cherrypick.c +9 -1
  188. data/vendor/libgit2/src/clone.c +130 -27
  189. data/vendor/libgit2/src/clone.h +4 -0
  190. data/vendor/libgit2/src/commit.c +70 -22
  191. data/vendor/libgit2/src/commit.h +6 -0
  192. data/vendor/libgit2/src/commit_list.c +28 -76
  193. data/vendor/libgit2/src/commit_list.h +2 -2
  194. data/vendor/libgit2/src/common.h +4 -75
  195. data/vendor/libgit2/src/config.c +34 -47
  196. data/vendor/libgit2/src/config.h +7 -6
  197. data/vendor/libgit2/src/config_backend.h +12 -0
  198. data/vendor/libgit2/src/config_cache.c +42 -39
  199. data/vendor/libgit2/src/config_entries.c +76 -98
  200. data/vendor/libgit2/src/config_entries.h +1 -0
  201. data/vendor/libgit2/src/config_file.c +346 -380
  202. data/vendor/libgit2/src/config_mem.c +12 -16
  203. data/vendor/libgit2/src/config_parse.c +50 -30
  204. data/vendor/libgit2/src/config_parse.h +13 -12
  205. data/vendor/libgit2/src/config_snapshot.c +207 -0
  206. data/vendor/libgit2/src/crlf.c +14 -14
  207. data/vendor/libgit2/src/describe.c +26 -21
  208. data/vendor/libgit2/src/diff.c +53 -75
  209. data/vendor/libgit2/src/diff.h +4 -3
  210. data/vendor/libgit2/src/diff_driver.c +37 -38
  211. data/vendor/libgit2/src/diff_file.c +15 -11
  212. data/vendor/libgit2/src/diff_file.h +2 -2
  213. data/vendor/libgit2/src/diff_generate.c +36 -37
  214. data/vendor/libgit2/src/diff_generate.h +2 -2
  215. data/vendor/libgit2/src/diff_parse.c +3 -4
  216. data/vendor/libgit2/src/diff_print.c +86 -71
  217. data/vendor/libgit2/src/diff_stats.c +13 -12
  218. data/vendor/libgit2/src/diff_tform.c +15 -16
  219. data/vendor/libgit2/src/errors.c +23 -25
  220. data/vendor/libgit2/src/errors.h +81 -0
  221. data/vendor/libgit2/src/features.h.in +9 -2
  222. data/vendor/libgit2/src/fetch.c +9 -2
  223. data/vendor/libgit2/src/fetchhead.c +9 -9
  224. data/vendor/libgit2/src/filebuf.c +1 -1
  225. data/vendor/libgit2/src/filebuf.h +1 -1
  226. data/vendor/libgit2/src/filter.c +19 -11
  227. data/vendor/libgit2/src/{fileops.c → futils.c} +23 -20
  228. data/vendor/libgit2/src/{fileops.h → futils.h} +8 -8
  229. data/vendor/libgit2/src/global.c +3 -1
  230. data/vendor/libgit2/src/hash.c +61 -0
  231. data/vendor/libgit2/src/hash.h +19 -21
  232. data/vendor/libgit2/src/hash/sha1.h +38 -0
  233. data/vendor/libgit2/src/hash/{hash_collisiondetect.h → sha1/collisiondetect.c} +14 -17
  234. data/vendor/libgit2/src/{sha1_lookup.h → hash/sha1/collisiondetect.h} +8 -8
  235. data/vendor/libgit2/src/hash/{hash_common_crypto.h → sha1/common_crypto.c} +15 -19
  236. data/vendor/libgit2/src/hash/sha1/common_crypto.h +19 -0
  237. data/vendor/libgit2/src/hash/{hash_generic.c → sha1/generic.c} +22 -10
  238. data/vendor/libgit2/src/hash/{hash_generic.h → sha1/generic.h} +4 -14
  239. data/vendor/libgit2/src/hash/{hash_mbedtls.c → sha1/mbedtls.c} +15 -7
  240. data/vendor/libgit2/src/hash/{hash_mbedtls.h → sha1/mbedtls.h} +6 -11
  241. data/vendor/libgit2/src/hash/{hash_openssl.h → sha1/openssl.c} +14 -18
  242. data/vendor/libgit2/src/{refdb_fs.h → hash/sha1/openssl.h} +8 -8
  243. data/vendor/libgit2/src/hash/{sha1dc → sha1/sha1dc}/sha1.c +14 -3
  244. data/vendor/libgit2/src/hash/{sha1dc → sha1/sha1dc}/sha1.h +0 -0
  245. data/vendor/libgit2/src/hash/{sha1dc → sha1/sha1dc}/ubc_check.c +0 -0
  246. data/vendor/libgit2/src/hash/{sha1dc → sha1/sha1dc}/ubc_check.h +0 -0
  247. data/vendor/libgit2/src/hash/{hash_win32.c → sha1/win32.c} +34 -24
  248. data/vendor/libgit2/src/hash/{hash_win32.h → sha1/win32.h} +6 -19
  249. data/vendor/libgit2/src/hashsig.c +1 -1
  250. data/vendor/libgit2/src/idxmap.c +73 -69
  251. data/vendor/libgit2/src/idxmap.h +151 -15
  252. data/vendor/libgit2/src/ignore.c +26 -35
  253. data/vendor/libgit2/src/index.c +123 -95
  254. data/vendor/libgit2/src/index.h +1 -1
  255. data/vendor/libgit2/src/indexer.c +99 -78
  256. data/vendor/libgit2/src/integer.h +26 -4
  257. data/vendor/libgit2/src/iterator.c +36 -32
  258. data/vendor/libgit2/src/iterator.h +8 -8
  259. data/vendor/libgit2/src/map.h +1 -1
  260. data/vendor/libgit2/src/merge.c +93 -57
  261. data/vendor/libgit2/src/merge.h +2 -2
  262. data/vendor/libgit2/src/merge_driver.c +5 -5
  263. data/vendor/libgit2/src/merge_file.c +5 -7
  264. data/vendor/libgit2/src/midx.c +418 -0
  265. data/vendor/libgit2/src/midx.h +83 -0
  266. data/vendor/libgit2/src/mwindow.c +144 -74
  267. data/vendor/libgit2/src/mwindow.h +4 -4
  268. data/vendor/libgit2/src/net.c +416 -0
  269. data/vendor/libgit2/src/net.h +57 -0
  270. data/vendor/libgit2/src/netops.c +6 -222
  271. data/vendor/libgit2/src/netops.h +1 -37
  272. data/vendor/libgit2/src/notes.c +8 -5
  273. data/vendor/libgit2/src/object.c +5 -4
  274. data/vendor/libgit2/src/object.h +2 -0
  275. data/vendor/libgit2/src/odb.c +54 -32
  276. data/vendor/libgit2/src/odb.h +3 -2
  277. data/vendor/libgit2/src/odb_loose.c +20 -13
  278. data/vendor/libgit2/src/odb_mempack.c +15 -24
  279. data/vendor/libgit2/src/odb_pack.c +4 -5
  280. data/vendor/libgit2/src/offmap.c +43 -55
  281. data/vendor/libgit2/src/offmap.h +102 -24
  282. data/vendor/libgit2/src/oid.c +21 -8
  283. data/vendor/libgit2/src/oidmap.c +39 -57
  284. data/vendor/libgit2/src/oidmap.h +99 -19
  285. data/vendor/libgit2/src/pack-objects.c +55 -52
  286. data/vendor/libgit2/src/pack-objects.h +1 -1
  287. data/vendor/libgit2/src/pack.c +160 -149
  288. data/vendor/libgit2/src/pack.h +32 -18
  289. data/vendor/libgit2/src/parse.c +10 -0
  290. data/vendor/libgit2/src/parse.h +3 -3
  291. data/vendor/libgit2/src/patch.c +1 -1
  292. data/vendor/libgit2/src/patch_generate.c +2 -4
  293. data/vendor/libgit2/src/patch_parse.c +34 -11
  294. data/vendor/libgit2/src/path.c +47 -10
  295. data/vendor/libgit2/src/path.h +2 -0
  296. data/vendor/libgit2/src/pathspec.c +18 -17
  297. data/vendor/libgit2/src/pool.c +42 -32
  298. data/vendor/libgit2/src/pool.h +15 -7
  299. data/vendor/libgit2/src/posix.c +39 -16
  300. data/vendor/libgit2/src/posix.h +21 -1
  301. data/vendor/libgit2/src/proxy.c +9 -2
  302. data/vendor/libgit2/src/push.c +15 -7
  303. data/vendor/libgit2/src/reader.c +2 -2
  304. data/vendor/libgit2/src/rebase.c +89 -28
  305. data/vendor/libgit2/src/refdb.c +147 -0
  306. data/vendor/libgit2/src/refdb.h +69 -0
  307. data/vendor/libgit2/src/refdb_fs.c +230 -241
  308. data/vendor/libgit2/src/reflog.c +13 -19
  309. data/vendor/libgit2/src/refs.c +113 -217
  310. data/vendor/libgit2/src/refs.h +10 -21
  311. data/vendor/libgit2/src/refspec.c +57 -48
  312. data/vendor/libgit2/src/regexp.c +221 -0
  313. data/vendor/libgit2/src/regexp.h +97 -0
  314. data/vendor/libgit2/src/remote.c +102 -79
  315. data/vendor/libgit2/src/remote.h +2 -2
  316. data/vendor/libgit2/src/repository.c +322 -203
  317. data/vendor/libgit2/src/repository.h +49 -57
  318. data/vendor/libgit2/src/revert.c +8 -1
  319. data/vendor/libgit2/src/revparse.c +23 -23
  320. data/vendor/libgit2/src/revwalk.c +73 -37
  321. data/vendor/libgit2/src/revwalk.h +20 -0
  322. data/vendor/libgit2/src/settings.c +22 -1
  323. data/vendor/libgit2/src/sortedcache.c +14 -29
  324. data/vendor/libgit2/src/sortedcache.h +1 -1
  325. data/vendor/libgit2/src/stash.c +49 -67
  326. data/vendor/libgit2/src/status.c +19 -11
  327. data/vendor/libgit2/src/strarray.c +63 -0
  328. data/vendor/libgit2/src/streams/openssl.c +66 -8
  329. data/vendor/libgit2/src/streams/registry.c +5 -3
  330. data/vendor/libgit2/src/streams/socket.c +2 -2
  331. data/vendor/libgit2/src/strmap.c +37 -84
  332. data/vendor/libgit2/src/strmap.h +105 -33
  333. data/vendor/libgit2/src/submodule.c +157 -130
  334. data/vendor/libgit2/src/submodule.h +1 -1
  335. data/vendor/libgit2/src/sysdir.c +4 -20
  336. data/vendor/libgit2/src/sysdir.h +0 -11
  337. data/vendor/libgit2/src/tag.c +12 -2
  338. data/vendor/libgit2/src/thread-utils.h +163 -40
  339. data/vendor/libgit2/src/trace.c +1 -1
  340. data/vendor/libgit2/src/trace.h +3 -3
  341. data/vendor/libgit2/src/trailer.c +46 -32
  342. data/vendor/libgit2/src/transaction.c +5 -9
  343. data/vendor/libgit2/src/transports/auth.c +16 -15
  344. data/vendor/libgit2/src/transports/auth.h +18 -11
  345. data/vendor/libgit2/src/transports/auth_negotiate.c +64 -33
  346. data/vendor/libgit2/src/transports/auth_negotiate.h +2 -2
  347. data/vendor/libgit2/src/transports/auth_ntlm.c +223 -0
  348. data/vendor/libgit2/src/transports/auth_ntlm.h +38 -0
  349. data/vendor/libgit2/src/transports/credential.c +478 -0
  350. data/vendor/libgit2/src/transports/{cred_helpers.c → credential_helpers.c} +23 -8
  351. data/vendor/libgit2/src/transports/git.c +11 -16
  352. data/vendor/libgit2/src/transports/http.c +488 -1248
  353. data/vendor/libgit2/src/transports/http.h +4 -1
  354. data/vendor/libgit2/src/transports/httpclient.c +1552 -0
  355. data/vendor/libgit2/src/transports/httpclient.h +190 -0
  356. data/vendor/libgit2/src/transports/local.c +12 -12
  357. data/vendor/libgit2/src/transports/smart.c +21 -21
  358. data/vendor/libgit2/src/transports/smart.h +3 -3
  359. data/vendor/libgit2/src/transports/smart_protocol.c +40 -64
  360. data/vendor/libgit2/src/transports/ssh.c +77 -59
  361. data/vendor/libgit2/src/transports/winhttp.c +368 -285
  362. data/vendor/libgit2/src/tree-cache.c +14 -7
  363. data/vendor/libgit2/src/tree.c +16 -26
  364. data/vendor/libgit2/src/unix/map.c +1 -1
  365. data/vendor/libgit2/src/unix/posix.h +16 -11
  366. data/vendor/libgit2/src/userdiff.h +3 -1
  367. data/vendor/libgit2/src/util.c +75 -110
  368. data/vendor/libgit2/src/util.h +18 -23
  369. data/vendor/libgit2/src/wildmatch.c +320 -0
  370. data/vendor/libgit2/src/wildmatch.h +23 -0
  371. data/vendor/libgit2/src/win32/git2.rc +18 -3
  372. data/vendor/libgit2/src/win32/map.c +3 -5
  373. data/vendor/libgit2/src/win32/path_w32.c +42 -5
  374. data/vendor/libgit2/src/win32/path_w32.h +15 -29
  375. data/vendor/libgit2/src/win32/posix.h +1 -4
  376. data/vendor/libgit2/src/win32/posix_w32.c +117 -5
  377. data/vendor/libgit2/src/win32/precompiled.h +0 -2
  378. data/vendor/libgit2/src/win32/thread.c +5 -5
  379. data/vendor/libgit2/src/win32/w32_buffer.c +7 -3
  380. data/vendor/libgit2/src/win32/w32_common.h +39 -0
  381. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +0 -93
  382. data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +0 -2
  383. data/vendor/libgit2/src/win32/w32_stack.c +4 -9
  384. data/vendor/libgit2/src/win32/w32_stack.h +3 -3
  385. data/vendor/libgit2/src/win32/w32_util.c +31 -0
  386. data/vendor/libgit2/src/win32/w32_util.h +6 -32
  387. data/vendor/libgit2/src/worktree.c +91 -50
  388. data/vendor/libgit2/src/xdiff/xdiffi.c +1 -1
  389. data/vendor/libgit2/src/xdiff/xmerge.c +12 -0
  390. data/vendor/libgit2/src/xdiff/xpatience.c +3 -0
  391. data/vendor/libgit2/src/zstream.c +5 -0
  392. data/vendor/libgit2/src/zstream.h +1 -0
  393. metadata +123 -53
  394. data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.c.in +0 -29
  395. data/vendor/libgit2/cmake/Modules/CheckPrototypeDefinition.cmake +0 -96
  396. data/vendor/libgit2/deps/regex/CMakeLists.txt +0 -2
  397. data/vendor/libgit2/deps/regex/COPYING +0 -502
  398. data/vendor/libgit2/deps/regex/config.h +0 -7
  399. data/vendor/libgit2/deps/regex/regcomp.c +0 -3857
  400. data/vendor/libgit2/deps/regex/regex.c +0 -92
  401. data/vendor/libgit2/deps/regex/regex.h +0 -582
  402. data/vendor/libgit2/deps/regex/regex_internal.c +0 -1744
  403. data/vendor/libgit2/deps/regex/regex_internal.h +0 -819
  404. data/vendor/libgit2/deps/regex/regexec.c +0 -4369
  405. data/vendor/libgit2/include/git2/inttypes.h +0 -309
  406. data/vendor/libgit2/include/git2/sys/time.h +0 -31
  407. data/vendor/libgit2/libgit2.pc.in +0 -13
  408. data/vendor/libgit2/src/fnmatch.c +0 -248
  409. data/vendor/libgit2/src/fnmatch.h +0 -48
  410. data/vendor/libgit2/src/sha1_lookup.c +0 -35
  411. data/vendor/libgit2/src/transports/cred.c +0 -390
@@ -9,8 +9,11 @@
9
9
  #define INCLUDE_transports_http_h__
10
10
 
11
11
  #include "buffer.h"
12
+ #include "httpclient.h"
12
13
 
13
- #define GIT_HTTP_REPLAY_MAX 7
14
+ #define GIT_HTTP_REPLAY_MAX 15
15
+
16
+ extern bool git_http__expect_continue;
14
17
 
15
18
  GIT_INLINE(int) git_http__user_agent(git_buf *buf)
16
19
  {
@@ -0,0 +1,1552 @@
1
+ /*
2
+ * Copyright (C) the libgit2 contributors. All rights reserved.
3
+ *
4
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
5
+ * a Linking Exception. For full terms see the included COPYING file.
6
+ */
7
+
8
+ #include "common.h"
9
+ #include "git2.h"
10
+ #include "http_parser.h"
11
+ #include "vector.h"
12
+ #include "trace.h"
13
+ #include "global.h"
14
+ #include "httpclient.h"
15
+ #include "http.h"
16
+ #include "auth.h"
17
+ #include "auth_negotiate.h"
18
+ #include "auth_ntlm.h"
19
+ #include "git2/sys/credential.h"
20
+ #include "net.h"
21
+ #include "stream.h"
22
+ #include "streams/socket.h"
23
+ #include "streams/tls.h"
24
+ #include "auth.h"
25
+
26
+ static git_http_auth_scheme auth_schemes[] = {
27
+ { GIT_HTTP_AUTH_NEGOTIATE, "Negotiate", GIT_CREDENTIAL_DEFAULT, git_http_auth_negotiate },
28
+ { GIT_HTTP_AUTH_NTLM, "NTLM", GIT_CREDENTIAL_USERPASS_PLAINTEXT, git_http_auth_ntlm },
29
+ { GIT_HTTP_AUTH_BASIC, "Basic", GIT_CREDENTIAL_USERPASS_PLAINTEXT, git_http_auth_basic },
30
+ };
31
+
32
+ /*
33
+ * Use a 16kb read buffer to match the maximum size of a TLS packet. This
34
+ * is critical for compatibility with SecureTransport, which will always do
35
+ * a network read on every call, even if it has data buffered to return to
36
+ * you. That buffered data may be the _end_ of a keep-alive response, so
37
+ * if SecureTransport performs another network read, it will wait until the
38
+ * server ultimately times out before it returns that buffered data to you.
39
+ * Since SecureTransport only reads a single TLS packet at a time, by
40
+ * calling it with a read buffer that is the maximum size of a TLS packet,
41
+ * we ensure that it will never buffer.
42
+ */
43
+ #define GIT_READ_BUFFER_SIZE (16 * 1024)
44
+
45
+ typedef struct {
46
+ git_net_url url;
47
+ git_stream *stream;
48
+
49
+ git_vector auth_challenges;
50
+ git_http_auth_context *auth_context;
51
+ } git_http_server;
52
+
53
+ typedef enum {
54
+ PROXY = 1,
55
+ SERVER
56
+ } git_http_server_t;
57
+
58
+ typedef enum {
59
+ NONE = 0,
60
+ SENDING_REQUEST,
61
+ SENDING_BODY,
62
+ SENT_REQUEST,
63
+ HAS_EARLY_RESPONSE,
64
+ READING_RESPONSE,
65
+ READING_BODY,
66
+ DONE
67
+ } http_client_state;
68
+
69
+ /* Parser state */
70
+ typedef enum {
71
+ PARSE_HEADER_NONE = 0,
72
+ PARSE_HEADER_NAME,
73
+ PARSE_HEADER_VALUE,
74
+ PARSE_HEADER_COMPLETE
75
+ } parse_header_state;
76
+
77
+ typedef enum {
78
+ PARSE_STATUS_OK,
79
+ PARSE_STATUS_NO_OUTPUT,
80
+ PARSE_STATUS_ERROR
81
+ } parse_status;
82
+
83
+ typedef struct {
84
+ git_http_client *client;
85
+ git_http_response *response;
86
+
87
+ /* Temporary buffers to avoid extra mallocs */
88
+ git_buf parse_header_name;
89
+ git_buf parse_header_value;
90
+
91
+ /* Parser state */
92
+ int error;
93
+ parse_status parse_status;
94
+
95
+ /* Headers parsing */
96
+ parse_header_state parse_header_state;
97
+
98
+ /* Body parsing */
99
+ char *output_buf; /* Caller's output buffer */
100
+ size_t output_size; /* Size of caller's output buffer */
101
+ size_t output_written; /* Bytes we've written to output buffer */
102
+ } http_parser_context;
103
+
104
+ /* HTTP client connection */
105
+ struct git_http_client {
106
+ git_http_client_options opts;
107
+
108
+ /* Are we writing to the proxy or server, and state of the client. */
109
+ git_http_server_t current_server;
110
+ http_client_state state;
111
+
112
+ http_parser parser;
113
+
114
+ git_http_server server;
115
+ git_http_server proxy;
116
+
117
+ unsigned request_count;
118
+ unsigned connected : 1,
119
+ proxy_connected : 1,
120
+ keepalive : 1,
121
+ request_chunked : 1;
122
+
123
+ /* Temporary buffers to avoid extra mallocs */
124
+ git_buf request_msg;
125
+ git_buf read_buf;
126
+
127
+ /* A subset of information from the request */
128
+ size_t request_body_len,
129
+ request_body_remain;
130
+
131
+ /*
132
+ * When state == HAS_EARLY_RESPONSE, the response of our proxy
133
+ * that we have buffered and will deliver during read_response.
134
+ */
135
+ git_http_response early_response;
136
+ };
137
+
138
+ bool git_http_response_is_redirect(git_http_response *response)
139
+ {
140
+ return (response->status == GIT_HTTP_MOVED_PERMANENTLY ||
141
+ response->status == GIT_HTTP_FOUND ||
142
+ response->status == GIT_HTTP_SEE_OTHER ||
143
+ response->status == GIT_HTTP_TEMPORARY_REDIRECT ||
144
+ response->status == GIT_HTTP_PERMANENT_REDIRECT);
145
+ }
146
+
147
+ void git_http_response_dispose(git_http_response *response)
148
+ {
149
+ assert(response);
150
+
151
+ git__free(response->content_type);
152
+ git__free(response->location);
153
+
154
+ memset(response, 0, sizeof(git_http_response));
155
+ }
156
+
157
+ static int on_header_complete(http_parser *parser)
158
+ {
159
+ http_parser_context *ctx = (http_parser_context *) parser->data;
160
+ git_http_client *client = ctx->client;
161
+ git_http_response *response = ctx->response;
162
+
163
+ git_buf *name = &ctx->parse_header_name;
164
+ git_buf *value = &ctx->parse_header_value;
165
+
166
+ if (!strcasecmp("Content-Type", name->ptr)) {
167
+ if (response->content_type) {
168
+ git_error_set(GIT_ERROR_HTTP,
169
+ "multiple content-type headers");
170
+ return -1;
171
+ }
172
+
173
+ response->content_type =
174
+ git__strndup(value->ptr, value->size);
175
+ GIT_ERROR_CHECK_ALLOC(ctx->response->content_type);
176
+ } else if (!strcasecmp("Content-Length", name->ptr)) {
177
+ int64_t len;
178
+
179
+ if (response->content_length) {
180
+ git_error_set(GIT_ERROR_HTTP,
181
+ "multiple content-length headers");
182
+ return -1;
183
+ }
184
+
185
+ if (git__strntol64(&len, value->ptr, value->size,
186
+ NULL, 10) < 0 || len < 0) {
187
+ git_error_set(GIT_ERROR_HTTP,
188
+ "invalid content-length");
189
+ return -1;
190
+ }
191
+
192
+ response->content_length = (size_t)len;
193
+ } else if (!strcasecmp("Transfer-Encoding", name->ptr) &&
194
+ !strcasecmp("chunked", value->ptr)) {
195
+ ctx->response->chunked = 1;
196
+ } else if (!strcasecmp("Proxy-Authenticate", git_buf_cstr(name))) {
197
+ char *dup = git__strndup(value->ptr, value->size);
198
+ GIT_ERROR_CHECK_ALLOC(dup);
199
+
200
+ if (git_vector_insert(&client->proxy.auth_challenges, dup) < 0)
201
+ return -1;
202
+ } else if (!strcasecmp("WWW-Authenticate", name->ptr)) {
203
+ char *dup = git__strndup(value->ptr, value->size);
204
+ GIT_ERROR_CHECK_ALLOC(dup);
205
+
206
+ if (git_vector_insert(&client->server.auth_challenges, dup) < 0)
207
+ return -1;
208
+ } else if (!strcasecmp("Location", name->ptr)) {
209
+ if (response->location) {
210
+ git_error_set(GIT_ERROR_HTTP,
211
+ "multiple location headers");
212
+ return -1;
213
+ }
214
+
215
+ response->location = git__strndup(value->ptr, value->size);
216
+ GIT_ERROR_CHECK_ALLOC(response->location);
217
+ }
218
+
219
+ return 0;
220
+ }
221
+
222
+ static int on_header_field(http_parser *parser, const char *str, size_t len)
223
+ {
224
+ http_parser_context *ctx = (http_parser_context *) parser->data;
225
+
226
+ switch (ctx->parse_header_state) {
227
+ /*
228
+ * We last saw a header value, process the name/value pair and
229
+ * get ready to handle this new name.
230
+ */
231
+ case PARSE_HEADER_VALUE:
232
+ if (on_header_complete(parser) < 0)
233
+ return ctx->parse_status = PARSE_STATUS_ERROR;
234
+
235
+ git_buf_clear(&ctx->parse_header_name);
236
+ git_buf_clear(&ctx->parse_header_value);
237
+ /* Fall through */
238
+
239
+ case PARSE_HEADER_NONE:
240
+ case PARSE_HEADER_NAME:
241
+ ctx->parse_header_state = PARSE_HEADER_NAME;
242
+
243
+ if (git_buf_put(&ctx->parse_header_name, str, len) < 0)
244
+ return ctx->parse_status = PARSE_STATUS_ERROR;
245
+
246
+ break;
247
+
248
+ default:
249
+ git_error_set(GIT_ERROR_HTTP,
250
+ "header name seen at unexpected time");
251
+ return ctx->parse_status = PARSE_STATUS_ERROR;
252
+ }
253
+
254
+ return 0;
255
+ }
256
+
257
+ static int on_header_value(http_parser *parser, const char *str, size_t len)
258
+ {
259
+ http_parser_context *ctx = (http_parser_context *) parser->data;
260
+
261
+ switch (ctx->parse_header_state) {
262
+ case PARSE_HEADER_NAME:
263
+ case PARSE_HEADER_VALUE:
264
+ ctx->parse_header_state = PARSE_HEADER_VALUE;
265
+
266
+ if (git_buf_put(&ctx->parse_header_value, str, len) < 0)
267
+ return ctx->parse_status = PARSE_STATUS_ERROR;
268
+
269
+ break;
270
+
271
+ default:
272
+ git_error_set(GIT_ERROR_HTTP,
273
+ "header value seen at unexpected time");
274
+ return ctx->parse_status = PARSE_STATUS_ERROR;
275
+ }
276
+
277
+ return 0;
278
+ }
279
+
280
+ GIT_INLINE(bool) challenge_matches_scheme(
281
+ const char *challenge,
282
+ git_http_auth_scheme *scheme)
283
+ {
284
+ const char *scheme_name = scheme->name;
285
+ size_t scheme_len = strlen(scheme_name);
286
+
287
+ if (!strncasecmp(challenge, scheme_name, scheme_len) &&
288
+ (challenge[scheme_len] == '\0' || challenge[scheme_len] == ' '))
289
+ return true;
290
+
291
+ return false;
292
+ }
293
+
294
+ static git_http_auth_scheme *scheme_for_challenge(const char *challenge)
295
+ {
296
+ size_t i;
297
+
298
+ for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
299
+ if (challenge_matches_scheme(challenge, &auth_schemes[i]))
300
+ return &auth_schemes[i];
301
+ }
302
+
303
+ return NULL;
304
+ }
305
+
306
+ GIT_INLINE(void) collect_authinfo(
307
+ unsigned int *schemetypes,
308
+ unsigned int *credtypes,
309
+ git_vector *challenges)
310
+ {
311
+ git_http_auth_scheme *scheme;
312
+ const char *challenge;
313
+ size_t i;
314
+
315
+ *schemetypes = 0;
316
+ *credtypes = 0;
317
+
318
+ git_vector_foreach(challenges, i, challenge) {
319
+ if ((scheme = scheme_for_challenge(challenge)) != NULL) {
320
+ *schemetypes |= scheme->type;
321
+ *credtypes |= scheme->credtypes;
322
+ }
323
+ }
324
+ }
325
+
326
+ static int resend_needed(git_http_client *client, git_http_response *response)
327
+ {
328
+ git_http_auth_context *auth_context;
329
+
330
+ if (response->status == GIT_HTTP_STATUS_UNAUTHORIZED &&
331
+ (auth_context = client->server.auth_context) &&
332
+ auth_context->is_complete &&
333
+ !auth_context->is_complete(auth_context))
334
+ return 1;
335
+
336
+ if (response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED &&
337
+ (auth_context = client->proxy.auth_context) &&
338
+ auth_context->is_complete &&
339
+ !auth_context->is_complete(auth_context))
340
+ return 1;
341
+
342
+ return 0;
343
+ }
344
+
345
+ static int on_headers_complete(http_parser *parser)
346
+ {
347
+ http_parser_context *ctx = (http_parser_context *) parser->data;
348
+
349
+ /* Finalize the last seen header */
350
+ switch (ctx->parse_header_state) {
351
+ case PARSE_HEADER_VALUE:
352
+ if (on_header_complete(parser) < 0)
353
+ return ctx->parse_status = PARSE_STATUS_ERROR;
354
+
355
+ /* Fall through */
356
+
357
+ case PARSE_HEADER_NONE:
358
+ ctx->parse_header_state = PARSE_HEADER_COMPLETE;
359
+ break;
360
+
361
+ default:
362
+ git_error_set(GIT_ERROR_HTTP,
363
+ "header completion at unexpected time");
364
+ return ctx->parse_status = PARSE_STATUS_ERROR;
365
+ }
366
+
367
+ ctx->response->status = parser->status_code;
368
+ ctx->client->keepalive = http_should_keep_alive(parser);
369
+
370
+ /* Prepare for authentication */
371
+ collect_authinfo(&ctx->response->server_auth_schemetypes,
372
+ &ctx->response->server_auth_credtypes,
373
+ &ctx->client->server.auth_challenges);
374
+ collect_authinfo(&ctx->response->proxy_auth_schemetypes,
375
+ &ctx->response->proxy_auth_credtypes,
376
+ &ctx->client->proxy.auth_challenges);
377
+
378
+ ctx->response->resend_credentials = resend_needed(ctx->client,
379
+ ctx->response);
380
+
381
+ /* Stop parsing. */
382
+ http_parser_pause(parser, 1);
383
+
384
+ if (ctx->response->content_type || ctx->response->chunked)
385
+ ctx->client->state = READING_BODY;
386
+ else
387
+ ctx->client->state = DONE;
388
+
389
+ return 0;
390
+ }
391
+
392
+ static int on_body(http_parser *parser, const char *buf, size_t len)
393
+ {
394
+ http_parser_context *ctx = (http_parser_context *) parser->data;
395
+ size_t max_len;
396
+
397
+ /* Saw data when we expected not to (eg, in consume_response_body) */
398
+ if (ctx->output_buf == NULL && ctx->output_size == 0) {
399
+ ctx->parse_status = PARSE_STATUS_NO_OUTPUT;
400
+ return 0;
401
+ }
402
+
403
+ assert(ctx->output_size >= ctx->output_written);
404
+
405
+ max_len = min(ctx->output_size - ctx->output_written, len);
406
+ max_len = min(max_len, INT_MAX);
407
+
408
+ memcpy(ctx->output_buf + ctx->output_written, buf, max_len);
409
+ ctx->output_written += max_len;
410
+
411
+ return 0;
412
+ }
413
+
414
+ static int on_message_complete(http_parser *parser)
415
+ {
416
+ http_parser_context *ctx = (http_parser_context *) parser->data;
417
+
418
+ ctx->client->state = DONE;
419
+ return 0;
420
+ }
421
+
422
+ GIT_INLINE(int) stream_write(
423
+ git_http_server *server,
424
+ const char *data,
425
+ size_t len)
426
+ {
427
+ git_trace(GIT_TRACE_TRACE,
428
+ "Sending request:\n%.*s", (int)len, data);
429
+
430
+ return git_stream__write_full(server->stream, data, len, 0);
431
+ }
432
+
433
+ GIT_INLINE(int) client_write_request(git_http_client *client)
434
+ {
435
+ git_stream *stream = client->current_server == PROXY ?
436
+ client->proxy.stream : client->server.stream;
437
+
438
+ git_trace(GIT_TRACE_TRACE,
439
+ "Sending request:\n%.*s",
440
+ (int)client->request_msg.size, client->request_msg.ptr);
441
+
442
+ return git_stream__write_full(stream,
443
+ client->request_msg.ptr,
444
+ client->request_msg.size,
445
+ 0);
446
+ }
447
+
448
+ static const char *name_for_method(git_http_method method)
449
+ {
450
+ switch (method) {
451
+ case GIT_HTTP_METHOD_GET:
452
+ return "GET";
453
+ case GIT_HTTP_METHOD_POST:
454
+ return "POST";
455
+ case GIT_HTTP_METHOD_CONNECT:
456
+ return "CONNECT";
457
+ }
458
+
459
+ return NULL;
460
+ }
461
+
462
+ /*
463
+ * Find the scheme that is suitable for the given credentials, based on the
464
+ * server's auth challenges.
465
+ */
466
+ static bool best_scheme_and_challenge(
467
+ git_http_auth_scheme **scheme_out,
468
+ const char **challenge_out,
469
+ git_vector *challenges,
470
+ git_credential *credentials)
471
+ {
472
+ const char *challenge;
473
+ size_t i, j;
474
+
475
+ for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
476
+ git_vector_foreach(challenges, j, challenge) {
477
+ git_http_auth_scheme *scheme = &auth_schemes[i];
478
+
479
+ if (challenge_matches_scheme(challenge, scheme) &&
480
+ (scheme->credtypes & credentials->credtype)) {
481
+ *scheme_out = scheme;
482
+ *challenge_out = challenge;
483
+ return true;
484
+ }
485
+ }
486
+ }
487
+
488
+ return false;
489
+ }
490
+
491
+ /*
492
+ * Find the challenge from the server for our current auth context.
493
+ */
494
+ static const char *challenge_for_context(
495
+ git_vector *challenges,
496
+ git_http_auth_context *auth_ctx)
497
+ {
498
+ const char *challenge;
499
+ size_t i, j;
500
+
501
+ for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) {
502
+ if (auth_schemes[i].type == auth_ctx->type) {
503
+ git_http_auth_scheme *scheme = &auth_schemes[i];
504
+
505
+ git_vector_foreach(challenges, j, challenge) {
506
+ if (challenge_matches_scheme(challenge, scheme))
507
+ return challenge;
508
+ }
509
+ }
510
+ }
511
+
512
+ return NULL;
513
+ }
514
+
515
+ static const char *init_auth_context(
516
+ git_http_server *server,
517
+ git_vector *challenges,
518
+ git_credential *credentials)
519
+ {
520
+ git_http_auth_scheme *scheme;
521
+ const char *challenge;
522
+ int error;
523
+
524
+ if (!best_scheme_and_challenge(&scheme, &challenge, challenges, credentials)) {
525
+ git_error_set(GIT_ERROR_HTTP, "could not find appropriate mechanism for credentials");
526
+ return NULL;
527
+ }
528
+
529
+ error = scheme->init_context(&server->auth_context, &server->url);
530
+
531
+ if (error == GIT_PASSTHROUGH) {
532
+ git_error_set(GIT_ERROR_HTTP, "'%s' authentication is not supported", scheme->name);
533
+ return NULL;
534
+ }
535
+
536
+ return challenge;
537
+ }
538
+
539
+ static void free_auth_context(git_http_server *server)
540
+ {
541
+ if (!server->auth_context)
542
+ return;
543
+
544
+ if (server->auth_context->free)
545
+ server->auth_context->free(server->auth_context);
546
+
547
+ server->auth_context = NULL;
548
+ }
549
+
550
+ static int apply_credentials(
551
+ git_buf *buf,
552
+ git_http_server *server,
553
+ const char *header_name,
554
+ git_credential *credentials)
555
+ {
556
+ git_http_auth_context *auth = server->auth_context;
557
+ git_vector *challenges = &server->auth_challenges;
558
+ const char *challenge;
559
+ git_buf token = GIT_BUF_INIT;
560
+ int error = 0;
561
+
562
+ /* We've started a new request without creds; free the context. */
563
+ if (auth && !credentials) {
564
+ free_auth_context(server);
565
+ return 0;
566
+ }
567
+
568
+ /* We haven't authenticated, nor were we asked to. Nothing to do. */
569
+ if (!auth && !git_vector_length(challenges))
570
+ return 0;
571
+
572
+ if (!auth) {
573
+ challenge = init_auth_context(server, challenges, credentials);
574
+ auth = server->auth_context;
575
+
576
+ if (!challenge || !auth) {
577
+ error = -1;
578
+ goto done;
579
+ }
580
+ } else if (auth->set_challenge) {
581
+ challenge = challenge_for_context(challenges, auth);
582
+ }
583
+
584
+ if (auth->set_challenge && challenge &&
585
+ (error = auth->set_challenge(auth, challenge)) < 0)
586
+ goto done;
587
+
588
+ if ((error = auth->next_token(&token, auth, credentials)) < 0)
589
+ goto done;
590
+
591
+ if (auth->is_complete && auth->is_complete(auth)) {
592
+ /*
593
+ * If we're done with an auth mechanism with connection affinity,
594
+ * we don't need to send any more headers and can dispose the context.
595
+ */
596
+ if (auth->connection_affinity)
597
+ free_auth_context(server);
598
+ } else if (!token.size) {
599
+ git_error_set(GIT_ERROR_HTTP, "failed to respond to authentication challenge");
600
+ error = -1;
601
+ goto done;
602
+ }
603
+
604
+ if (token.size > 0)
605
+ error = git_buf_printf(buf, "%s: %s\r\n", header_name, token.ptr);
606
+
607
+ done:
608
+ git_buf_dispose(&token);
609
+ return error;
610
+ }
611
+
612
+ GIT_INLINE(int) apply_server_credentials(
613
+ git_buf *buf,
614
+ git_http_client *client,
615
+ git_http_request *request)
616
+ {
617
+ return apply_credentials(buf,
618
+ &client->server,
619
+ "Authorization",
620
+ request->credentials);
621
+ }
622
+
623
+ GIT_INLINE(int) apply_proxy_credentials(
624
+ git_buf *buf,
625
+ git_http_client *client,
626
+ git_http_request *request)
627
+ {
628
+ return apply_credentials(buf,
629
+ &client->proxy,
630
+ "Proxy-Authorization",
631
+ request->proxy_credentials);
632
+ }
633
+
634
+ static int generate_connect_request(
635
+ git_http_client *client,
636
+ git_http_request *request)
637
+ {
638
+ git_buf *buf;
639
+ int error;
640
+
641
+ git_buf_clear(&client->request_msg);
642
+ buf = &client->request_msg;
643
+
644
+ git_buf_printf(buf, "CONNECT %s:%s HTTP/1.1\r\n",
645
+ client->server.url.host, client->server.url.port);
646
+
647
+ git_buf_puts(buf, "User-Agent: ");
648
+ git_http__user_agent(buf);
649
+ git_buf_puts(buf, "\r\n");
650
+
651
+ git_buf_printf(buf, "Host: %s\r\n", client->proxy.url.host);
652
+
653
+ if ((error = apply_proxy_credentials(buf, client, request) < 0))
654
+ return -1;
655
+
656
+ git_buf_puts(buf, "\r\n");
657
+
658
+ return git_buf_oom(buf) ? -1 : 0;
659
+ }
660
+
661
+ static bool use_connect_proxy(git_http_client *client)
662
+ {
663
+ return client->proxy.url.host && !strcmp(client->server.url.scheme, "https");
664
+ }
665
+
666
+ static int generate_request(
667
+ git_http_client *client,
668
+ git_http_request *request)
669
+ {
670
+ git_buf *buf;
671
+ size_t i;
672
+ int error;
673
+
674
+ assert(client && request);
675
+
676
+ git_buf_clear(&client->request_msg);
677
+ buf = &client->request_msg;
678
+
679
+ /* GET|POST path HTTP/1.1 */
680
+ git_buf_puts(buf, name_for_method(request->method));
681
+ git_buf_putc(buf, ' ');
682
+
683
+ if (request->proxy && strcmp(request->url->scheme, "https"))
684
+ git_net_url_fmt(buf, request->url);
685
+ else
686
+ git_net_url_fmt_path(buf, request->url);
687
+
688
+ git_buf_puts(buf, " HTTP/1.1\r\n");
689
+
690
+ git_buf_puts(buf, "User-Agent: ");
691
+ git_http__user_agent(buf);
692
+ git_buf_puts(buf, "\r\n");
693
+
694
+ git_buf_printf(buf, "Host: %s", request->url->host);
695
+
696
+ if (!git_net_url_is_default_port(request->url))
697
+ git_buf_printf(buf, ":%s", request->url->port);
698
+
699
+ git_buf_puts(buf, "\r\n");
700
+
701
+ if (request->accept)
702
+ git_buf_printf(buf, "Accept: %s\r\n", request->accept);
703
+ else
704
+ git_buf_puts(buf, "Accept: */*\r\n");
705
+
706
+ if (request->content_type)
707
+ git_buf_printf(buf, "Content-Type: %s\r\n",
708
+ request->content_type);
709
+
710
+ if (request->chunked)
711
+ git_buf_puts(buf, "Transfer-Encoding: chunked\r\n");
712
+
713
+ if (request->content_length > 0)
714
+ git_buf_printf(buf, "Content-Length: %"PRIuZ "\r\n",
715
+ request->content_length);
716
+
717
+ if (request->expect_continue)
718
+ git_buf_printf(buf, "Expect: 100-continue\r\n");
719
+
720
+ if ((error = apply_server_credentials(buf, client, request)) < 0 ||
721
+ (!use_connect_proxy(client) &&
722
+ (error = apply_proxy_credentials(buf, client, request)) < 0))
723
+ return error;
724
+
725
+ if (request->custom_headers) {
726
+ for (i = 0; i < request->custom_headers->count; i++) {
727
+ const char *hdr = request->custom_headers->strings[i];
728
+
729
+ if (hdr)
730
+ git_buf_printf(buf, "%s\r\n", hdr);
731
+ }
732
+ }
733
+
734
+ git_buf_puts(buf, "\r\n");
735
+
736
+ if (git_buf_oom(buf))
737
+ return -1;
738
+
739
+ return 0;
740
+ }
741
+
742
+ static int check_certificate(
743
+ git_stream *stream,
744
+ git_net_url *url,
745
+ int is_valid,
746
+ git_transport_certificate_check_cb cert_cb,
747
+ void *cert_cb_payload)
748
+ {
749
+ git_cert *cert;
750
+ git_error_state last_error = {0};
751
+ int error;
752
+
753
+ if ((error = git_stream_certificate(&cert, stream)) < 0)
754
+ return error;
755
+
756
+ git_error_state_capture(&last_error, GIT_ECERTIFICATE);
757
+
758
+ error = cert_cb(cert, is_valid, url->host, cert_cb_payload);
759
+
760
+ if (error == GIT_PASSTHROUGH && !is_valid)
761
+ return git_error_state_restore(&last_error);
762
+ else if (error == GIT_PASSTHROUGH)
763
+ error = 0;
764
+ else if (error && !git_error_last())
765
+ git_error_set(GIT_ERROR_HTTP,
766
+ "user rejected certificate for %s", url->host);
767
+
768
+ git_error_state_free(&last_error);
769
+ return error;
770
+ }
771
+
772
+ static int server_connect_stream(
773
+ git_http_server *server,
774
+ git_transport_certificate_check_cb cert_cb,
775
+ void *cb_payload)
776
+ {
777
+ int error;
778
+
779
+ GIT_ERROR_CHECK_VERSION(server->stream, GIT_STREAM_VERSION, "git_stream");
780
+
781
+ error = git_stream_connect(server->stream);
782
+
783
+ if (error && error != GIT_ECERTIFICATE)
784
+ return error;
785
+
786
+ if (git_stream_is_encrypted(server->stream) && cert_cb != NULL)
787
+ error = check_certificate(server->stream, &server->url, !error,
788
+ cert_cb, cb_payload);
789
+
790
+ return error;
791
+ }
792
+
793
+ static void reset_auth_connection(git_http_server *server)
794
+ {
795
+ /*
796
+ * If we've authenticated and we're doing "normal"
797
+ * authentication with a request affinity (Basic, Digest)
798
+ * then we want to _keep_ our context, since authentication
799
+ * survives even through non-keep-alive connections. If
800
+ * we've authenticated and we're doing connection-based
801
+ * authentication (NTLM, Negotiate) - indicated by the presence
802
+ * of an `is_complete` callback - then we need to restart
803
+ * authentication on a new connection.
804
+ */
805
+
806
+ if (server->auth_context &&
807
+ server->auth_context->connection_affinity)
808
+ free_auth_context(server);
809
+ }
810
+
811
+ /*
812
+ * Updates the server data structure with the new URL; returns 1 if the server
813
+ * has changed and we need to reconnect, returns 0 otherwise.
814
+ */
815
+ GIT_INLINE(int) server_setup_from_url(
816
+ git_http_server *server,
817
+ git_net_url *url)
818
+ {
819
+ if (!server->url.scheme || strcmp(server->url.scheme, url->scheme) ||
820
+ !server->url.host || strcmp(server->url.host, url->host) ||
821
+ !server->url.port || strcmp(server->url.port, url->port)) {
822
+ git__free(server->url.scheme);
823
+ git__free(server->url.host);
824
+ git__free(server->url.port);
825
+
826
+ server->url.scheme = git__strdup(url->scheme);
827
+ GIT_ERROR_CHECK_ALLOC(server->url.scheme);
828
+
829
+ server->url.host = git__strdup(url->host);
830
+ GIT_ERROR_CHECK_ALLOC(server->url.host);
831
+
832
+ server->url.port = git__strdup(url->port);
833
+ GIT_ERROR_CHECK_ALLOC(server->url.port);
834
+
835
+ return 1;
836
+ }
837
+
838
+ return 0;
839
+ }
840
+
841
+ static void reset_parser(git_http_client *client)
842
+ {
843
+ http_parser_init(&client->parser, HTTP_RESPONSE);
844
+ }
845
+
846
+ static int setup_hosts(
847
+ git_http_client *client,
848
+ git_http_request *request)
849
+ {
850
+ int ret, diff = 0;
851
+
852
+ assert(client && request && request->url);
853
+
854
+ if ((ret = server_setup_from_url(&client->server, request->url)) < 0)
855
+ return ret;
856
+
857
+ diff |= ret;
858
+
859
+ if (request->proxy &&
860
+ (ret = server_setup_from_url(&client->proxy, request->proxy)) < 0)
861
+ return ret;
862
+
863
+ diff |= ret;
864
+
865
+ if (diff) {
866
+ free_auth_context(&client->server);
867
+ free_auth_context(&client->proxy);
868
+
869
+ client->connected = 0;
870
+ }
871
+
872
+ return 0;
873
+ }
874
+
875
+ GIT_INLINE(int) server_create_stream(git_http_server *server)
876
+ {
877
+ git_net_url *url = &server->url;
878
+
879
+ if (strcasecmp(url->scheme, "https") == 0)
880
+ return git_tls_stream_new(&server->stream, url->host, url->port);
881
+ else if (strcasecmp(url->scheme, "http") == 0)
882
+ return git_socket_stream_new(&server->stream, url->host, url->port);
883
+
884
+ git_error_set(GIT_ERROR_HTTP, "unknown http scheme '%s'", url->scheme);
885
+ return -1;
886
+ }
887
+
888
+ GIT_INLINE(void) save_early_response(
889
+ git_http_client *client,
890
+ git_http_response *response)
891
+ {
892
+ /* Buffer the response so we can return it in read_response */
893
+ client->state = HAS_EARLY_RESPONSE;
894
+
895
+ memcpy(&client->early_response, response, sizeof(git_http_response));
896
+ memset(response, 0, sizeof(git_http_response));
897
+ }
898
+
899
+ static int proxy_connect(
900
+ git_http_client *client,
901
+ git_http_request *request)
902
+ {
903
+ git_http_response response = {0};
904
+ int error;
905
+
906
+ if (!client->proxy_connected || !client->keepalive) {
907
+ git_trace(GIT_TRACE_DEBUG, "Connecting to proxy %s:%s",
908
+ client->proxy.url.host, client->proxy.url.port);
909
+
910
+ if ((error = server_create_stream(&client->proxy)) < 0 ||
911
+ (error = server_connect_stream(&client->proxy,
912
+ client->opts.proxy_certificate_check_cb,
913
+ client->opts.proxy_certificate_check_payload)) < 0)
914
+ goto done;
915
+
916
+ client->proxy_connected = 1;
917
+ }
918
+
919
+ client->current_server = PROXY;
920
+ client->state = SENDING_REQUEST;
921
+
922
+ if ((error = generate_connect_request(client, request)) < 0 ||
923
+ (error = client_write_request(client)) < 0)
924
+ goto done;
925
+
926
+ client->state = SENT_REQUEST;
927
+
928
+ if ((error = git_http_client_read_response(&response, client)) < 0 ||
929
+ (error = git_http_client_skip_body(client)) < 0)
930
+ goto done;
931
+
932
+ assert(client->state == DONE);
933
+
934
+ if (response.status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
935
+ save_early_response(client, &response);
936
+
937
+ error = GIT_RETRY;
938
+ goto done;
939
+ } else if (response.status != GIT_HTTP_STATUS_OK) {
940
+ git_error_set(GIT_ERROR_HTTP, "proxy returned unexpected status: %d", response.status);
941
+ error = -1;
942
+ goto done;
943
+ }
944
+
945
+ reset_parser(client);
946
+ client->state = NONE;
947
+
948
+ done:
949
+ git_http_response_dispose(&response);
950
+ return error;
951
+ }
952
+
953
+ static int server_connect(git_http_client *client)
954
+ {
955
+ git_net_url *url = &client->server.url;
956
+ git_transport_certificate_check_cb cert_cb;
957
+ void *cert_payload;
958
+ int error;
959
+
960
+ client->current_server = SERVER;
961
+
962
+ if (client->proxy.stream)
963
+ error = git_tls_stream_wrap(&client->server.stream, client->proxy.stream, url->host);
964
+ else
965
+ error = server_create_stream(&client->server);
966
+
967
+ if (error < 0)
968
+ goto done;
969
+
970
+ cert_cb = client->opts.server_certificate_check_cb;
971
+ cert_payload = client->opts.server_certificate_check_payload;
972
+
973
+ error = server_connect_stream(&client->server, cert_cb, cert_payload);
974
+
975
+ done:
976
+ return error;
977
+ }
978
+
979
+ GIT_INLINE(void) close_stream(git_http_server *server)
980
+ {
981
+ if (server->stream) {
982
+ git_stream_close(server->stream);
983
+ git_stream_free(server->stream);
984
+ server->stream = NULL;
985
+ }
986
+ }
987
+
988
+ static int http_client_connect(
989
+ git_http_client *client,
990
+ git_http_request *request)
991
+ {
992
+ bool use_proxy = false;
993
+ int error;
994
+
995
+ if ((error = setup_hosts(client, request)) < 0)
996
+ goto on_error;
997
+
998
+ /* We're connected to our destination server; no need to reconnect */
999
+ if (client->connected && client->keepalive &&
1000
+ (client->state == NONE || client->state == DONE))
1001
+ return 0;
1002
+
1003
+ client->connected = 0;
1004
+ client->request_count = 0;
1005
+
1006
+ close_stream(&client->server);
1007
+ reset_auth_connection(&client->server);
1008
+
1009
+ reset_parser(client);
1010
+
1011
+ /* Reconnect to the proxy if necessary. */
1012
+ use_proxy = use_connect_proxy(client);
1013
+
1014
+ if (use_proxy) {
1015
+ if (!client->proxy_connected || !client->keepalive ||
1016
+ (client->state != NONE && client->state != DONE)) {
1017
+ close_stream(&client->proxy);
1018
+ reset_auth_connection(&client->proxy);
1019
+
1020
+ client->proxy_connected = 0;
1021
+ }
1022
+
1023
+ if ((error = proxy_connect(client, request)) < 0)
1024
+ goto on_error;
1025
+ }
1026
+
1027
+ git_trace(GIT_TRACE_DEBUG, "Connecting to remote %s:%s",
1028
+ client->server.url.host, client->server.url.port);
1029
+
1030
+ if ((error = server_connect(client)) < 0)
1031
+ goto on_error;
1032
+
1033
+ client->connected = 1;
1034
+ return error;
1035
+
1036
+ on_error:
1037
+ if (error != GIT_RETRY)
1038
+ close_stream(&client->proxy);
1039
+
1040
+ close_stream(&client->server);
1041
+ return error;
1042
+ }
1043
+
1044
+ GIT_INLINE(int) client_read(git_http_client *client)
1045
+ {
1046
+ http_parser_context *parser_context = client->parser.data;
1047
+ git_stream *stream;
1048
+ char *buf = client->read_buf.ptr + client->read_buf.size;
1049
+ size_t max_len;
1050
+ ssize_t read_len;
1051
+
1052
+ stream = client->current_server == PROXY ?
1053
+ client->proxy.stream : client->server.stream;
1054
+
1055
+ /*
1056
+ * We use a git_buf for convenience, but statically allocate it and
1057
+ * don't resize. Limit our consumption to INT_MAX since calling
1058
+ * functions use an int return type to return number of bytes read.
1059
+ */
1060
+ max_len = client->read_buf.asize - client->read_buf.size;
1061
+ max_len = min(max_len, INT_MAX);
1062
+
1063
+ if (parser_context->output_size)
1064
+ max_len = min(max_len, parser_context->output_size);
1065
+
1066
+ if (max_len == 0) {
1067
+ git_error_set(GIT_ERROR_HTTP, "no room in output buffer");
1068
+ return -1;
1069
+ }
1070
+
1071
+ read_len = git_stream_read(stream, buf, max_len);
1072
+
1073
+ if (read_len >= 0) {
1074
+ client->read_buf.size += read_len;
1075
+
1076
+ git_trace(GIT_TRACE_TRACE, "Received:\n%.*s",
1077
+ (int)read_len, buf);
1078
+ }
1079
+
1080
+ return (int)read_len;
1081
+ }
1082
+
1083
+ static bool parser_settings_initialized;
1084
+ static http_parser_settings parser_settings;
1085
+
1086
+ GIT_INLINE(http_parser_settings *) http_client_parser_settings(void)
1087
+ {
1088
+ if (!parser_settings_initialized) {
1089
+ parser_settings.on_header_field = on_header_field;
1090
+ parser_settings.on_header_value = on_header_value;
1091
+ parser_settings.on_headers_complete = on_headers_complete;
1092
+ parser_settings.on_body = on_body;
1093
+ parser_settings.on_message_complete = on_message_complete;
1094
+
1095
+ parser_settings_initialized = true;
1096
+ }
1097
+
1098
+ return &parser_settings;
1099
+ }
1100
+
1101
+ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
1102
+ {
1103
+ http_parser *parser = &client->parser;
1104
+ http_parser_context *ctx = (http_parser_context *) parser->data;
1105
+ unsigned char http_errno;
1106
+ int read_len;
1107
+ size_t parsed_len;
1108
+
1109
+ /*
1110
+ * If we have data in our read buffer, that means we stopped early
1111
+ * when parsing headers. Use the data in the read buffer instead of
1112
+ * reading more from the socket.
1113
+ */
1114
+ if (!client->read_buf.size && (read_len = client_read(client)) < 0)
1115
+ return read_len;
1116
+
1117
+ parsed_len = http_parser_execute(parser,
1118
+ http_client_parser_settings(),
1119
+ client->read_buf.ptr,
1120
+ client->read_buf.size);
1121
+ http_errno = client->parser.http_errno;
1122
+
1123
+ if (parsed_len > INT_MAX) {
1124
+ git_error_set(GIT_ERROR_HTTP, "unexpectedly large parse");
1125
+ return -1;
1126
+ }
1127
+
1128
+ if (ctx->parse_status == PARSE_STATUS_ERROR) {
1129
+ client->connected = 0;
1130
+ return ctx->error ? ctx->error : -1;
1131
+ }
1132
+
1133
+ /*
1134
+ * If we finished reading the headers or body, we paused parsing.
1135
+ * Otherwise the parser will start filling the body, or even parse
1136
+ * a new response if the server pipelined us multiple responses.
1137
+ * (This can happen in response to an expect/continue request,
1138
+ * where the server gives you a 100 and 200 simultaneously.)
1139
+ */
1140
+ if (http_errno == HPE_PAUSED) {
1141
+ /*
1142
+ * http-parser has a "feature" where it will not deliver the
1143
+ * final byte when paused in a callback. Consume that byte.
1144
+ * https://github.com/nodejs/http-parser/issues/97
1145
+ */
1146
+ assert(client->read_buf.size > parsed_len);
1147
+
1148
+ http_parser_pause(parser, 0);
1149
+
1150
+ parsed_len += http_parser_execute(parser,
1151
+ http_client_parser_settings(),
1152
+ client->read_buf.ptr + parsed_len,
1153
+ 1);
1154
+ }
1155
+
1156
+ /* Most failures will be reported in http_errno */
1157
+ else if (parser->http_errno != HPE_OK) {
1158
+ git_error_set(GIT_ERROR_HTTP, "http parser error: %s",
1159
+ http_errno_description(http_errno));
1160
+ return -1;
1161
+ }
1162
+
1163
+ /* Otherwise we should have consumed the entire buffer. */
1164
+ else if (parsed_len != client->read_buf.size) {
1165
+ git_error_set(GIT_ERROR_HTTP,
1166
+ "http parser did not consume entire buffer: %s",
1167
+ http_errno_description(http_errno));
1168
+ return -1;
1169
+ }
1170
+
1171
+ /* recv returned 0, the server hung up on us */
1172
+ else if (!parsed_len) {
1173
+ git_error_set(GIT_ERROR_HTTP, "unexpected EOF");
1174
+ return -1;
1175
+ }
1176
+
1177
+ git_buf_consume_bytes(&client->read_buf, parsed_len);
1178
+
1179
+ return (int)parsed_len;
1180
+ }
1181
+
1182
+ /*
1183
+ * See if we've consumed the entire response body. If the client was
1184
+ * reading the body but did not consume it entirely, it's possible that
1185
+ * they knew that the stream had finished (in a git response, seeing a
1186
+ * final flush) and stopped reading. But if the response was chunked,
1187
+ * we may have not consumed the final chunk marker. Consume it to
1188
+ * ensure that we don't have it waiting in our socket. If there's
1189
+ * more than just a chunk marker, close the connection.
1190
+ */
1191
+ static void complete_response_body(git_http_client *client)
1192
+ {
1193
+ http_parser_context parser_context = {0};
1194
+
1195
+ /* If we're not keeping alive, don't bother. */
1196
+ if (!client->keepalive) {
1197
+ client->connected = 0;
1198
+ goto done;
1199
+ }
1200
+
1201
+ parser_context.client = client;
1202
+ client->parser.data = &parser_context;
1203
+
1204
+ /* If there was an error, just close the connection. */
1205
+ if (client_read_and_parse(client) < 0 ||
1206
+ parser_context.error != HPE_OK ||
1207
+ (parser_context.parse_status != PARSE_STATUS_OK &&
1208
+ parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) {
1209
+ git_error_clear();
1210
+ client->connected = 0;
1211
+ }
1212
+
1213
+ done:
1214
+ git_buf_clear(&client->read_buf);
1215
+ }
1216
+
1217
+ int git_http_client_send_request(
1218
+ git_http_client *client,
1219
+ git_http_request *request)
1220
+ {
1221
+ git_http_response response = {0};
1222
+ int error = -1;
1223
+
1224
+ assert(client && request);
1225
+
1226
+ /* If the client did not finish reading, clean up the stream. */
1227
+ if (client->state == READING_BODY)
1228
+ complete_response_body(client);
1229
+
1230
+ /* If we're waiting for proxy auth, don't sending more requests. */
1231
+ if (client->state == HAS_EARLY_RESPONSE)
1232
+ return 0;
1233
+
1234
+ if (git_trace_level() >= GIT_TRACE_DEBUG) {
1235
+ git_buf url = GIT_BUF_INIT;
1236
+ git_net_url_fmt(&url, request->url);
1237
+ git_trace(GIT_TRACE_DEBUG, "Sending %s request to %s",
1238
+ name_for_method(request->method),
1239
+ url.ptr ? url.ptr : "<invalid>");
1240
+ git_buf_dispose(&url);
1241
+ }
1242
+
1243
+ if ((error = http_client_connect(client, request)) < 0 ||
1244
+ (error = generate_request(client, request)) < 0 ||
1245
+ (error = client_write_request(client)) < 0)
1246
+ goto done;
1247
+
1248
+ client->state = SENT_REQUEST;
1249
+
1250
+ if (request->expect_continue) {
1251
+ if ((error = git_http_client_read_response(&response, client)) < 0 ||
1252
+ (error = git_http_client_skip_body(client)) < 0)
1253
+ goto done;
1254
+
1255
+ error = 0;
1256
+
1257
+ if (response.status != GIT_HTTP_STATUS_CONTINUE) {
1258
+ save_early_response(client, &response);
1259
+ goto done;
1260
+ }
1261
+ }
1262
+
1263
+ if (request->content_length || request->chunked) {
1264
+ client->state = SENDING_BODY;
1265
+ client->request_body_len = request->content_length;
1266
+ client->request_body_remain = request->content_length;
1267
+ client->request_chunked = request->chunked;
1268
+ }
1269
+
1270
+ reset_parser(client);
1271
+
1272
+ done:
1273
+ if (error == GIT_RETRY)
1274
+ error = 0;
1275
+
1276
+ git_http_response_dispose(&response);
1277
+ return error;
1278
+ }
1279
+
1280
+ bool git_http_client_has_response(git_http_client *client)
1281
+ {
1282
+ return (client->state == HAS_EARLY_RESPONSE ||
1283
+ client->state > SENT_REQUEST);
1284
+ }
1285
+
1286
+ int git_http_client_send_body(
1287
+ git_http_client *client,
1288
+ const char *buffer,
1289
+ size_t buffer_len)
1290
+ {
1291
+ git_http_server *server;
1292
+ git_buf hdr = GIT_BUF_INIT;
1293
+ int error;
1294
+
1295
+ assert(client);
1296
+
1297
+ /* If we're waiting for proxy auth, don't sending more requests. */
1298
+ if (client->state == HAS_EARLY_RESPONSE)
1299
+ return 0;
1300
+
1301
+ if (client->state != SENDING_BODY) {
1302
+ git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
1303
+ return -1;
1304
+ }
1305
+
1306
+ if (!buffer_len)
1307
+ return 0;
1308
+
1309
+ server = &client->server;
1310
+
1311
+ if (client->request_body_len) {
1312
+ assert(buffer_len <= client->request_body_remain);
1313
+
1314
+ if ((error = stream_write(server, buffer, buffer_len)) < 0)
1315
+ goto done;
1316
+
1317
+ client->request_body_remain -= buffer_len;
1318
+ } else {
1319
+ if ((error = git_buf_printf(&hdr, "%" PRIxZ "\r\n", buffer_len)) < 0 ||
1320
+ (error = stream_write(server, hdr.ptr, hdr.size)) < 0 ||
1321
+ (error = stream_write(server, buffer, buffer_len)) < 0 ||
1322
+ (error = stream_write(server, "\r\n", 2)) < 0)
1323
+ goto done;
1324
+ }
1325
+
1326
+ done:
1327
+ git_buf_dispose(&hdr);
1328
+ return error;
1329
+ }
1330
+
1331
+ static int complete_request(git_http_client *client)
1332
+ {
1333
+ int error = 0;
1334
+
1335
+ assert(client && client->state == SENDING_BODY);
1336
+
1337
+ if (client->request_body_len && client->request_body_remain) {
1338
+ git_error_set(GIT_ERROR_HTTP, "truncated write");
1339
+ error = -1;
1340
+ } else if (client->request_chunked) {
1341
+ error = stream_write(&client->server, "0\r\n\r\n", 5);
1342
+ }
1343
+
1344
+ client->state = SENT_REQUEST;
1345
+ return error;
1346
+ }
1347
+
1348
+ int git_http_client_read_response(
1349
+ git_http_response *response,
1350
+ git_http_client *client)
1351
+ {
1352
+ http_parser_context parser_context = {0};
1353
+ int error;
1354
+
1355
+ assert(response && client);
1356
+
1357
+ if (client->state == SENDING_BODY) {
1358
+ if ((error = complete_request(client)) < 0)
1359
+ goto done;
1360
+ }
1361
+
1362
+ if (client->state == HAS_EARLY_RESPONSE) {
1363
+ memcpy(response, &client->early_response, sizeof(git_http_response));
1364
+ memset(&client->early_response, 0, sizeof(git_http_response));
1365
+ client->state = DONE;
1366
+ return 0;
1367
+ }
1368
+
1369
+ if (client->state != SENT_REQUEST) {
1370
+ git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
1371
+ error = -1;
1372
+ goto done;
1373
+ }
1374
+
1375
+ git_http_response_dispose(response);
1376
+
1377
+ if (client->current_server == PROXY) {
1378
+ git_vector_free_deep(&client->proxy.auth_challenges);
1379
+ } else if(client->current_server == SERVER) {
1380
+ git_vector_free_deep(&client->server.auth_challenges);
1381
+ }
1382
+
1383
+ client->state = READING_RESPONSE;
1384
+ client->keepalive = 0;
1385
+ client->parser.data = &parser_context;
1386
+
1387
+ parser_context.client = client;
1388
+ parser_context.response = response;
1389
+
1390
+ while (client->state == READING_RESPONSE) {
1391
+ if ((error = client_read_and_parse(client)) < 0)
1392
+ goto done;
1393
+ }
1394
+
1395
+ assert(client->state == READING_BODY || client->state == DONE);
1396
+
1397
+ done:
1398
+ git_buf_dispose(&parser_context.parse_header_name);
1399
+ git_buf_dispose(&parser_context.parse_header_value);
1400
+
1401
+ return error;
1402
+ }
1403
+
1404
+ int git_http_client_read_body(
1405
+ git_http_client *client,
1406
+ char *buffer,
1407
+ size_t buffer_size)
1408
+ {
1409
+ http_parser_context parser_context = {0};
1410
+ int error = 0;
1411
+
1412
+ if (client->state == DONE)
1413
+ return 0;
1414
+
1415
+ if (client->state != READING_BODY) {
1416
+ git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
1417
+ return -1;
1418
+ }
1419
+
1420
+ /*
1421
+ * Now we'll read from the socket and http_parser will pipeline the
1422
+ * data directly to the client.
1423
+ */
1424
+
1425
+ parser_context.client = client;
1426
+ parser_context.output_buf = buffer;
1427
+ parser_context.output_size = buffer_size;
1428
+
1429
+ client->parser.data = &parser_context;
1430
+
1431
+ /*
1432
+ * Clients expect to get a non-zero amount of data from us,
1433
+ * so we either block until we have data to return, until we
1434
+ * hit EOF or there's an error. Do this in a loop, since we
1435
+ * may end up reading only some stream metadata (like chunk
1436
+ * information).
1437
+ */
1438
+ while (!parser_context.output_written) {
1439
+ error = client_read_and_parse(client);
1440
+
1441
+ if (error <= 0)
1442
+ goto done;
1443
+
1444
+ if (client->state == DONE)
1445
+ break;
1446
+ }
1447
+
1448
+ assert(parser_context.output_written <= INT_MAX);
1449
+ error = (int)parser_context.output_written;
1450
+
1451
+ done:
1452
+ if (error < 0)
1453
+ client->connected = 0;
1454
+
1455
+ return error;
1456
+ }
1457
+
1458
+ int git_http_client_skip_body(git_http_client *client)
1459
+ {
1460
+ http_parser_context parser_context = {0};
1461
+ int error;
1462
+
1463
+ if (client->state == DONE)
1464
+ return 0;
1465
+
1466
+ if (client->state != READING_BODY) {
1467
+ git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
1468
+ return -1;
1469
+ }
1470
+
1471
+ parser_context.client = client;
1472
+ client->parser.data = &parser_context;
1473
+
1474
+ do {
1475
+ error = client_read_and_parse(client);
1476
+
1477
+ if (parser_context.error != HPE_OK ||
1478
+ (parser_context.parse_status != PARSE_STATUS_OK &&
1479
+ parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) {
1480
+ git_error_set(GIT_ERROR_HTTP,
1481
+ "unexpected data handled in callback");
1482
+ error = -1;
1483
+ }
1484
+ } while (error >= 0 && client->state != DONE);
1485
+
1486
+ if (error < 0)
1487
+ client->connected = 0;
1488
+
1489
+ return error;
1490
+ }
1491
+
1492
+ /*
1493
+ * Create an http_client capable of communicating with the given remote
1494
+ * host.
1495
+ */
1496
+ int git_http_client_new(
1497
+ git_http_client **out,
1498
+ git_http_client_options *opts)
1499
+ {
1500
+ git_http_client *client;
1501
+
1502
+ assert(out);
1503
+
1504
+ client = git__calloc(1, sizeof(git_http_client));
1505
+ GIT_ERROR_CHECK_ALLOC(client);
1506
+
1507
+ git_buf_init(&client->read_buf, GIT_READ_BUFFER_SIZE);
1508
+ GIT_ERROR_CHECK_ALLOC(client->read_buf.ptr);
1509
+
1510
+ if (opts)
1511
+ memcpy(&client->opts, opts, sizeof(git_http_client_options));
1512
+
1513
+ *out = client;
1514
+ return 0;
1515
+ }
1516
+
1517
+ GIT_INLINE(void) http_server_close(git_http_server *server)
1518
+ {
1519
+ if (server->stream) {
1520
+ git_stream_close(server->stream);
1521
+ git_stream_free(server->stream);
1522
+ server->stream = NULL;
1523
+ }
1524
+
1525
+ git_net_url_dispose(&server->url);
1526
+
1527
+ git_vector_free_deep(&server->auth_challenges);
1528
+ free_auth_context(server);
1529
+ }
1530
+
1531
+ static void http_client_close(git_http_client *client)
1532
+ {
1533
+ http_server_close(&client->server);
1534
+ http_server_close(&client->proxy);
1535
+
1536
+ git_buf_dispose(&client->request_msg);
1537
+
1538
+ client->state = 0;
1539
+ client->request_count = 0;
1540
+ client->connected = 0;
1541
+ client->keepalive = 0;
1542
+ }
1543
+
1544
+ void git_http_client_free(git_http_client *client)
1545
+ {
1546
+ if (!client)
1547
+ return;
1548
+
1549
+ http_client_close(client);
1550
+ git_buf_dispose(&client->read_buf);
1551
+ git__free(client);
1552
+ }