rugged 0.28.5 → 0.99.0

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