rugged 0.17.0.b7 → 0.18.0.b1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.md +88 -32
- data/ext/rugged/extconf.rb +4 -2
- data/ext/rugged/rugged.c +72 -10
- data/ext/rugged/rugged.h +14 -10
- data/ext/rugged/rugged_blob.c +8 -10
- data/ext/rugged/rugged_branch.c +11 -14
- data/ext/rugged/rugged_commit.c +31 -24
- data/ext/rugged/rugged_config.c +2 -2
- data/ext/rugged/rugged_index.c +133 -198
- data/ext/rugged/rugged_note.c +372 -0
- data/ext/rugged/rugged_object.c +50 -22
- data/ext/rugged/rugged_reference.c +122 -130
- data/ext/rugged/rugged_remote.c +72 -29
- data/ext/rugged/rugged_repo.c +402 -20
- data/ext/rugged/rugged_revwalk.c +7 -3
- data/ext/rugged/rugged_settings.c +110 -0
- data/ext/rugged/rugged_signature.c +23 -7
- data/ext/rugged/rugged_tag.c +32 -16
- data/ext/rugged/rugged_tree.c +44 -15
- data/lib/rugged.rb +1 -0
- data/lib/rugged/index.rb +8 -0
- data/lib/rugged/remote.rb +13 -0
- data/lib/rugged/repository.rb +3 -3
- data/lib/rugged/version.rb +1 -1
- data/test/blob_test.rb +13 -15
- data/test/branch_test.rb +32 -67
- data/test/commit_test.rb +50 -12
- data/test/config_test.rb +12 -11
- data/test/coverage/HEAD.json +1 -1
- data/test/coverage/cover.rb +40 -21
- data/test/errors_test.rb +34 -0
- data/test/fixtures/alternate/objects/14/6ae76773c91e3b1d00cf7a338ec55ae58297e2 +0 -0
- data/test/fixtures/alternate/objects/14/9c32d47e99d0a3572ff1e70a2e0051bbf347a9 +0 -0
- data/test/fixtures/alternate/objects/14/fb3108588f9421bf764041e5e3ac305eb6277f +0 -0
- data/test/fixtures/testrepo.git/logs/refs/notes/commits +1 -0
- data/test/fixtures/testrepo.git/objects/44/1034f860c1d5d90e4188d11ae0d325176869a8 +1 -0
- data/test/fixtures/testrepo.git/objects/60/d415052a33de2150bf68757f6461df4f563ae4 +0 -0
- data/test/fixtures/testrepo.git/objects/68/8a8f4ef7496901d15322972f96e212a9e466cc +1 -0
- data/test/fixtures/testrepo.git/objects/94/eca2de348d5f672faf56b0decafa5937e3235e +0 -0
- data/test/fixtures/testrepo.git/objects/9b/7384fe1676186192842f5d3e129457b62db9e3 +0 -0
- data/test/fixtures/testrepo.git/objects/b7/4713326bc972cc15751ed504dca6f6f3b91f7a +3 -0
- data/test/fixtures/testrepo.git/refs/notes/commits +1 -0
- data/test/index_test.rb +65 -69
- data/test/lib_test.rb +76 -11
- data/test/note_test.rb +158 -0
- data/test/object_test.rb +8 -11
- data/test/reference_test.rb +77 -85
- data/test/remote_test.rb +86 -8
- data/test/repo_pack_test.rb +9 -7
- data/test/repo_reset_test.rb +80 -0
- data/test/repo_test.rb +176 -53
- data/test/tag_test.rb +44 -7
- data/test/test_helper.rb +63 -35
- data/test/tree_test.rb +34 -13
- data/test/walker_test.rb +14 -14
- data/vendor/libgit2/Makefile.embed +1 -1
- data/vendor/libgit2/deps/http-parser/http_parser.c +974 -578
- data/vendor/libgit2/deps/http-parser/http_parser.h +106 -70
- data/vendor/libgit2/deps/regex/regcomp.c +7 -6
- data/vendor/libgit2/deps/regex/regex_internal.c +1 -1
- data/vendor/libgit2/deps/regex/regex_internal.h +12 -3
- data/vendor/libgit2/deps/regex/regexec.c +5 -5
- data/vendor/libgit2/include/git2.h +5 -1
- data/vendor/libgit2/include/git2/attr.h +4 -2
- data/vendor/libgit2/include/git2/blob.h +39 -12
- data/vendor/libgit2/include/git2/branch.h +123 -35
- data/vendor/libgit2/include/git2/checkout.h +206 -48
- data/vendor/libgit2/include/git2/clone.h +72 -27
- data/vendor/libgit2/include/git2/commit.h +20 -17
- data/vendor/libgit2/include/git2/common.h +67 -1
- data/vendor/libgit2/include/git2/config.h +81 -60
- data/vendor/libgit2/include/git2/cred_helpers.h +53 -0
- data/vendor/libgit2/include/git2/diff.h +459 -150
- data/vendor/libgit2/include/git2/errors.h +9 -1
- data/vendor/libgit2/include/git2/graph.h +41 -0
- data/vendor/libgit2/include/git2/ignore.h +7 -6
- data/vendor/libgit2/include/git2/index.h +323 -97
- data/vendor/libgit2/include/git2/indexer.h +27 -59
- data/vendor/libgit2/include/git2/inttypes.h +4 -0
- data/vendor/libgit2/include/git2/merge.h +13 -3
- data/vendor/libgit2/include/git2/message.h +14 -8
- data/vendor/libgit2/include/git2/net.h +9 -7
- data/vendor/libgit2/include/git2/notes.h +88 -29
- data/vendor/libgit2/include/git2/object.h +16 -6
- data/vendor/libgit2/include/git2/odb.h +80 -17
- data/vendor/libgit2/include/git2/odb_backend.h +47 -11
- data/vendor/libgit2/include/git2/oid.h +26 -17
- data/vendor/libgit2/include/git2/pack.h +62 -8
- data/vendor/libgit2/include/git2/push.h +131 -0
- data/vendor/libgit2/include/git2/refdb.h +103 -0
- data/vendor/libgit2/include/git2/refdb_backend.h +109 -0
- data/vendor/libgit2/include/git2/reflog.h +30 -21
- data/vendor/libgit2/include/git2/refs.h +215 -193
- data/vendor/libgit2/include/git2/refspec.h +22 -2
- data/vendor/libgit2/include/git2/remote.h +158 -37
- data/vendor/libgit2/include/git2/repository.h +150 -31
- data/vendor/libgit2/include/git2/reset.h +43 -9
- data/vendor/libgit2/include/git2/revparse.h +48 -4
- data/vendor/libgit2/include/git2/revwalk.h +25 -10
- data/vendor/libgit2/include/git2/signature.h +20 -12
- data/vendor/libgit2/include/git2/stash.h +121 -0
- data/vendor/libgit2/include/git2/status.h +122 -53
- data/vendor/libgit2/include/git2/strarray.h +17 -11
- data/vendor/libgit2/include/git2/submodule.h +42 -7
- data/vendor/libgit2/include/git2/tag.h +72 -59
- data/vendor/libgit2/include/git2/threads.h +4 -2
- data/vendor/libgit2/include/git2/trace.h +68 -0
- data/vendor/libgit2/include/git2/transport.h +328 -0
- data/vendor/libgit2/include/git2/tree.h +149 -120
- data/vendor/libgit2/include/git2/types.h +13 -12
- data/vendor/libgit2/include/git2/version.h +3 -3
- data/vendor/libgit2/src/amiga/map.c +2 -2
- data/vendor/libgit2/src/attr.c +58 -48
- data/vendor/libgit2/src/attr.h +4 -18
- data/vendor/libgit2/src/attr_file.c +30 -6
- data/vendor/libgit2/src/attr_file.h +6 -8
- data/vendor/libgit2/src/attrcache.h +24 -0
- data/vendor/libgit2/src/blob.c +30 -7
- data/vendor/libgit2/src/blob.h +1 -1
- data/vendor/libgit2/src/branch.c +361 -68
- data/vendor/libgit2/src/branch.h +17 -0
- data/vendor/libgit2/src/bswap.h +1 -1
- data/vendor/libgit2/src/buf_text.c +291 -0
- data/vendor/libgit2/src/buf_text.h +122 -0
- data/vendor/libgit2/src/buffer.c +27 -101
- data/vendor/libgit2/src/buffer.h +54 -39
- data/vendor/libgit2/src/cache.c +15 -6
- data/vendor/libgit2/src/cache.h +1 -1
- data/vendor/libgit2/src/cc-compat.h +3 -1
- data/vendor/libgit2/src/checkout.c +1165 -222
- data/vendor/libgit2/src/checkout.h +24 -0
- data/vendor/libgit2/src/clone.c +171 -86
- data/vendor/libgit2/src/commit.c +44 -45
- data/vendor/libgit2/src/commit.h +3 -3
- data/vendor/libgit2/src/commit_list.c +194 -0
- data/vendor/libgit2/src/commit_list.h +49 -0
- data/vendor/libgit2/src/common.h +44 -10
- data/vendor/libgit2/src/compress.c +1 -1
- data/vendor/libgit2/src/compress.h +1 -1
- data/vendor/libgit2/src/config.c +211 -124
- data/vendor/libgit2/src/config.h +23 -4
- data/vendor/libgit2/src/config_cache.c +2 -2
- data/vendor/libgit2/src/config_file.c +129 -53
- data/vendor/libgit2/src/config_file.h +10 -8
- data/vendor/libgit2/src/crlf.c +66 -67
- data/vendor/libgit2/src/date.c +12 -12
- data/vendor/libgit2/src/delta-apply.c +14 -1
- data/vendor/libgit2/src/delta-apply.h +18 -1
- data/vendor/libgit2/src/delta.c +40 -107
- data/vendor/libgit2/src/delta.h +19 -17
- data/vendor/libgit2/src/diff.c +347 -496
- data/vendor/libgit2/src/diff.h +27 -1
- data/vendor/libgit2/src/diff_output.c +564 -249
- data/vendor/libgit2/src/diff_output.h +15 -8
- data/vendor/libgit2/src/diff_tform.c +687 -0
- data/vendor/libgit2/src/errors.c +27 -36
- data/vendor/libgit2/src/fetch.c +13 -351
- data/vendor/libgit2/src/fetch.h +13 -3
- data/vendor/libgit2/src/fetchhead.c +295 -0
- data/vendor/libgit2/src/fetchhead.h +34 -0
- data/vendor/libgit2/src/filebuf.c +42 -15
- data/vendor/libgit2/src/filebuf.h +4 -2
- data/vendor/libgit2/src/fileops.c +466 -113
- data/vendor/libgit2/src/fileops.h +154 -28
- data/vendor/libgit2/src/filter.c +3 -75
- data/vendor/libgit2/src/filter.h +1 -29
- data/vendor/libgit2/src/fnmatch.c +1 -1
- data/vendor/libgit2/src/fnmatch.h +1 -1
- data/vendor/libgit2/src/global.c +54 -10
- data/vendor/libgit2/src/global.h +10 -1
- data/vendor/libgit2/src/graph.c +178 -0
- data/vendor/libgit2/src/hash.c +25 -52
- data/vendor/libgit2/src/hash.h +21 -9
- data/vendor/libgit2/src/{sha1/sha1.c → hash/hash_generic.c} +20 -12
- data/vendor/libgit2/src/hash/hash_generic.h +24 -0
- data/vendor/libgit2/src/hash/hash_openssl.h +45 -0
- data/vendor/libgit2/src/hash/hash_win32.c +291 -0
- data/vendor/libgit2/src/hash/hash_win32.h +140 -0
- data/vendor/libgit2/src/hashsig.c +368 -0
- data/vendor/libgit2/src/hashsig.h +72 -0
- data/vendor/libgit2/src/ignore.c +22 -15
- data/vendor/libgit2/src/ignore.h +6 -1
- data/vendor/libgit2/src/index.c +770 -171
- data/vendor/libgit2/src/index.h +13 -5
- data/vendor/libgit2/src/indexer.c +286 -431
- data/vendor/libgit2/src/iterator.c +854 -466
- data/vendor/libgit2/src/iterator.h +134 -109
- data/vendor/libgit2/src/map.h +1 -1
- data/vendor/libgit2/src/merge.c +296 -0
- data/vendor/libgit2/src/merge.h +22 -0
- data/vendor/libgit2/src/message.c +1 -1
- data/vendor/libgit2/src/message.h +1 -1
- data/vendor/libgit2/src/mwindow.c +35 -30
- data/vendor/libgit2/src/mwindow.h +2 -2
- data/vendor/libgit2/src/netops.c +162 -98
- data/vendor/libgit2/src/netops.h +50 -15
- data/vendor/libgit2/src/notes.c +109 -58
- data/vendor/libgit2/src/notes.h +2 -1
- data/vendor/libgit2/src/object.c +46 -57
- data/vendor/libgit2/src/object.h +1 -8
- data/vendor/libgit2/src/odb.c +151 -40
- data/vendor/libgit2/src/odb.h +5 -1
- data/vendor/libgit2/src/odb_loose.c +4 -5
- data/vendor/libgit2/src/odb_pack.c +122 -80
- data/vendor/libgit2/src/offmap.h +65 -0
- data/vendor/libgit2/src/oid.c +12 -4
- data/vendor/libgit2/src/oidmap.h +1 -1
- data/vendor/libgit2/src/pack-objects.c +88 -61
- data/vendor/libgit2/src/pack-objects.h +8 -8
- data/vendor/libgit2/src/pack.c +293 -28
- data/vendor/libgit2/src/pack.h +49 -4
- data/vendor/libgit2/src/path.c +103 -14
- data/vendor/libgit2/src/path.h +23 -7
- data/vendor/libgit2/src/pathspec.c +168 -0
- data/vendor/libgit2/src/pathspec.h +40 -0
- data/vendor/libgit2/src/pool.c +29 -4
- data/vendor/libgit2/src/pool.h +8 -1
- data/vendor/libgit2/src/posix.c +26 -27
- data/vendor/libgit2/src/posix.h +2 -3
- data/vendor/libgit2/src/pqueue.c +23 -1
- data/vendor/libgit2/src/pqueue.h +23 -1
- data/vendor/libgit2/src/push.c +653 -0
- data/vendor/libgit2/src/push.h +51 -0
- data/vendor/libgit2/src/refdb.c +185 -0
- data/vendor/libgit2/src/refdb.h +46 -0
- data/vendor/libgit2/src/refdb_fs.c +1024 -0
- data/vendor/libgit2/src/refdb_fs.h +15 -0
- data/vendor/libgit2/src/reflog.c +77 -45
- data/vendor/libgit2/src/reflog.h +1 -3
- data/vendor/libgit2/src/refs.c +366 -1326
- data/vendor/libgit2/src/refs.h +22 -13
- data/vendor/libgit2/src/refspec.c +46 -7
- data/vendor/libgit2/src/refspec.h +11 -1
- data/vendor/libgit2/src/remote.c +758 -120
- data/vendor/libgit2/src/remote.h +10 -5
- data/vendor/libgit2/src/repo_template.h +6 -6
- data/vendor/libgit2/src/repository.c +315 -96
- data/vendor/libgit2/src/repository.h +5 -3
- data/vendor/libgit2/src/reset.c +99 -81
- data/vendor/libgit2/src/revparse.c +157 -84
- data/vendor/libgit2/src/revwalk.c +68 -470
- data/vendor/libgit2/src/revwalk.h +44 -0
- data/vendor/libgit2/src/sha1_lookup.c +1 -1
- data/vendor/libgit2/src/sha1_lookup.h +1 -1
- data/vendor/libgit2/src/signature.c +68 -200
- data/vendor/libgit2/src/signature.h +1 -1
- data/vendor/libgit2/src/stash.c +663 -0
- data/vendor/libgit2/src/status.c +101 -79
- data/vendor/libgit2/src/strmap.h +1 -1
- data/vendor/libgit2/src/submodule.c +67 -51
- data/vendor/libgit2/src/submodule.h +1 -1
- data/vendor/libgit2/src/tag.c +35 -29
- data/vendor/libgit2/src/tag.h +1 -1
- data/vendor/libgit2/src/thread-utils.c +1 -1
- data/vendor/libgit2/src/thread-utils.h +2 -2
- data/vendor/libgit2/src/trace.c +39 -0
- data/vendor/libgit2/src/trace.h +56 -0
- data/vendor/libgit2/src/transport.c +81 -34
- data/vendor/libgit2/src/transports/cred.c +60 -0
- data/vendor/libgit2/src/transports/cred_helpers.c +49 -0
- data/vendor/libgit2/src/transports/git.c +234 -127
- data/vendor/libgit2/src/transports/http.c +761 -433
- data/vendor/libgit2/src/transports/local.c +460 -64
- data/vendor/libgit2/src/transports/smart.c +345 -0
- data/vendor/libgit2/src/transports/smart.h +179 -0
- data/vendor/libgit2/src/{pkt.c → transports/smart_pkt.c} +131 -12
- data/vendor/libgit2/src/transports/smart_protocol.c +856 -0
- data/vendor/libgit2/src/transports/winhttp.c +1136 -0
- data/vendor/libgit2/src/tree-cache.c +2 -2
- data/vendor/libgit2/src/tree-cache.h +1 -1
- data/vendor/libgit2/src/tree.c +239 -166
- data/vendor/libgit2/src/tree.h +11 -2
- data/vendor/libgit2/src/tsort.c +39 -23
- data/vendor/libgit2/src/unix/map.c +1 -1
- data/vendor/libgit2/src/unix/posix.h +12 -2
- data/vendor/libgit2/src/unix/realpath.c +30 -0
- data/vendor/libgit2/src/util.c +250 -13
- data/vendor/libgit2/src/util.h +71 -14
- data/vendor/libgit2/src/vector.c +123 -60
- data/vendor/libgit2/src/vector.h +24 -22
- data/vendor/libgit2/src/win32/dir.c +1 -1
- data/vendor/libgit2/src/win32/dir.h +1 -1
- data/vendor/libgit2/src/win32/error.c +77 -0
- data/vendor/libgit2/src/win32/error.h +13 -0
- data/vendor/libgit2/src/win32/findfile.c +143 -54
- data/vendor/libgit2/src/win32/findfile.h +10 -6
- data/vendor/libgit2/src/win32/map.c +1 -1
- data/vendor/libgit2/src/win32/mingw-compat.h +1 -1
- data/vendor/libgit2/src/win32/msvc-compat.h +10 -1
- data/vendor/libgit2/src/win32/posix.h +10 -1
- data/vendor/libgit2/src/win32/posix_w32.c +132 -63
- data/vendor/libgit2/src/win32/precompiled.c +1 -1
- data/vendor/libgit2/src/win32/pthread.c +1 -1
- data/vendor/libgit2/src/win32/pthread.h +1 -1
- data/vendor/libgit2/src/win32/utf-conv.c +5 -5
- data/vendor/libgit2/src/win32/utf-conv.h +3 -3
- data/vendor/libgit2/src/win32/version.h +20 -0
- metadata +308 -252
- data/test/fixtures/testrepo.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 +0 -0
- data/test/fixtures/testrepo.git/objects/7f/043268ea43ce18e3540acaabf9e090c91965b0 +0 -0
- data/test/fixtures/testrepo.git/objects/a3/e05719b428a2d0ed7a55c4ce53dcc5768c6d5e +0 -0
- data/test/index_test.rb~ +0 -218
- data/vendor/libgit2/src/pkt.h +0 -91
- data/vendor/libgit2/src/ppc/sha1.c +0 -70
- data/vendor/libgit2/src/ppc/sha1.h +0 -26
- data/vendor/libgit2/src/protocol.c +0 -110
- data/vendor/libgit2/src/protocol.h +0 -21
- data/vendor/libgit2/src/sha1.h +0 -33
- data/vendor/libgit2/src/transport.h +0 -148
@@ -0,0 +1,1136 @@
|
|
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
|
+
#ifdef GIT_WINHTTP
|
9
|
+
|
10
|
+
#include "git2.h"
|
11
|
+
#include "git2/transport.h"
|
12
|
+
#include "buffer.h"
|
13
|
+
#include "posix.h"
|
14
|
+
#include "netops.h"
|
15
|
+
#include "smart.h"
|
16
|
+
#include "remote.h"
|
17
|
+
#include "repository.h"
|
18
|
+
|
19
|
+
#include <winhttp.h>
|
20
|
+
#pragma comment(lib, "winhttp")
|
21
|
+
|
22
|
+
/* For UuidCreate */
|
23
|
+
#pragma comment(lib, "rpcrt4")
|
24
|
+
|
25
|
+
#define WIDEN2(s) L ## s
|
26
|
+
#define WIDEN(s) WIDEN2(s)
|
27
|
+
|
28
|
+
#define MAX_CONTENT_TYPE_LEN 100
|
29
|
+
#define WINHTTP_OPTION_PEERDIST_EXTENSION_STATE 109
|
30
|
+
#define CACHED_POST_BODY_BUF_SIZE 4096
|
31
|
+
#define UUID_LENGTH_CCH 32
|
32
|
+
|
33
|
+
static const char *prefix_http = "http://";
|
34
|
+
static const char *prefix_https = "https://";
|
35
|
+
static const char *upload_pack_service = "upload-pack";
|
36
|
+
static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack";
|
37
|
+
static const char *upload_pack_service_url = "/git-upload-pack";
|
38
|
+
static const char *receive_pack_service = "receive-pack";
|
39
|
+
static const char *receive_pack_ls_service_url = "/info/refs?service=git-receive-pack";
|
40
|
+
static const char *receive_pack_service_url = "/git-receive-pack";
|
41
|
+
static const wchar_t *get_verb = L"GET";
|
42
|
+
static const wchar_t *post_verb = L"POST";
|
43
|
+
static const wchar_t *pragma_nocache = L"Pragma: no-cache";
|
44
|
+
static const wchar_t *transfer_encoding = L"Transfer-Encoding: chunked";
|
45
|
+
static const int no_check_cert_flags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
|
46
|
+
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
|
47
|
+
SECURITY_FLAG_IGNORE_UNKNOWN_CA;
|
48
|
+
|
49
|
+
#define OWNING_SUBTRANSPORT(s) ((winhttp_subtransport *)(s)->parent.subtransport)
|
50
|
+
|
51
|
+
typedef enum {
|
52
|
+
GIT_WINHTTP_AUTH_BASIC = 1,
|
53
|
+
} winhttp_authmechanism_t;
|
54
|
+
|
55
|
+
typedef struct {
|
56
|
+
git_smart_subtransport_stream parent;
|
57
|
+
const char *service;
|
58
|
+
const char *service_url;
|
59
|
+
const wchar_t *verb;
|
60
|
+
HINTERNET request;
|
61
|
+
wchar_t *request_uri;
|
62
|
+
char *chunk_buffer;
|
63
|
+
unsigned chunk_buffer_len;
|
64
|
+
HANDLE post_body;
|
65
|
+
DWORD post_body_len;
|
66
|
+
unsigned sent_request : 1,
|
67
|
+
received_response : 1,
|
68
|
+
chunked : 1;
|
69
|
+
} winhttp_stream;
|
70
|
+
|
71
|
+
typedef struct {
|
72
|
+
git_smart_subtransport parent;
|
73
|
+
transport_smart *owner;
|
74
|
+
const char *path;
|
75
|
+
char *host;
|
76
|
+
char *port;
|
77
|
+
char *user_from_url;
|
78
|
+
char *pass_from_url;
|
79
|
+
git_cred *cred;
|
80
|
+
git_cred *url_cred;
|
81
|
+
int auth_mechanism;
|
82
|
+
HINTERNET session;
|
83
|
+
HINTERNET connection;
|
84
|
+
unsigned use_ssl : 1;
|
85
|
+
} winhttp_subtransport;
|
86
|
+
|
87
|
+
static int apply_basic_credential(HINTERNET request, git_cred *cred)
|
88
|
+
{
|
89
|
+
git_cred_userpass_plaintext *c = (git_cred_userpass_plaintext *)cred;
|
90
|
+
git_buf buf = GIT_BUF_INIT, raw = GIT_BUF_INIT;
|
91
|
+
wchar_t *wide = NULL;
|
92
|
+
int error = -1, wide_len = 0;
|
93
|
+
|
94
|
+
git_buf_printf(&raw, "%s:%s", c->username, c->password);
|
95
|
+
|
96
|
+
if (git_buf_oom(&raw) ||
|
97
|
+
git_buf_puts(&buf, "Authorization: Basic ") < 0 ||
|
98
|
+
git_buf_put_base64(&buf, git_buf_cstr(&raw), raw.size) < 0)
|
99
|
+
goto on_error;
|
100
|
+
|
101
|
+
wide_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
102
|
+
git_buf_cstr(&buf), -1, NULL, 0);
|
103
|
+
|
104
|
+
if (!wide_len) {
|
105
|
+
giterr_set(GITERR_OS, "Failed to measure string for wide conversion");
|
106
|
+
goto on_error;
|
107
|
+
}
|
108
|
+
|
109
|
+
wide = git__malloc(wide_len * sizeof(wchar_t));
|
110
|
+
|
111
|
+
if (!wide)
|
112
|
+
goto on_error;
|
113
|
+
|
114
|
+
if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
115
|
+
git_buf_cstr(&buf), -1, wide, wide_len)) {
|
116
|
+
giterr_set(GITERR_OS, "Failed to convert string to wide form");
|
117
|
+
goto on_error;
|
118
|
+
}
|
119
|
+
|
120
|
+
if (!WinHttpAddRequestHeaders(request, wide, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) {
|
121
|
+
giterr_set(GITERR_OS, "Failed to add a header to the request");
|
122
|
+
goto on_error;
|
123
|
+
}
|
124
|
+
|
125
|
+
error = 0;
|
126
|
+
|
127
|
+
on_error:
|
128
|
+
/* We were dealing with plaintext passwords, so clean up after ourselves a bit. */
|
129
|
+
if (wide)
|
130
|
+
memset(wide, 0x0, wide_len * sizeof(wchar_t));
|
131
|
+
|
132
|
+
if (buf.size)
|
133
|
+
memset(buf.ptr, 0x0, buf.size);
|
134
|
+
|
135
|
+
if (raw.size)
|
136
|
+
memset(raw.ptr, 0x0, raw.size);
|
137
|
+
|
138
|
+
git__free(wide);
|
139
|
+
git_buf_free(&buf);
|
140
|
+
git_buf_free(&raw);
|
141
|
+
return error;
|
142
|
+
}
|
143
|
+
|
144
|
+
static int winhttp_stream_connect(winhttp_stream *s)
|
145
|
+
{
|
146
|
+
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
|
147
|
+
git_buf buf = GIT_BUF_INIT;
|
148
|
+
char *proxy_url = NULL;
|
149
|
+
wchar_t ct[MAX_CONTENT_TYPE_LEN];
|
150
|
+
wchar_t *types[] = { L"*/*", NULL };
|
151
|
+
BOOL peerdist = FALSE;
|
152
|
+
int error = -1, wide_len;
|
153
|
+
|
154
|
+
/* Prepare URL */
|
155
|
+
git_buf_printf(&buf, "%s%s", t->path, s->service_url);
|
156
|
+
|
157
|
+
if (git_buf_oom(&buf))
|
158
|
+
return -1;
|
159
|
+
|
160
|
+
/* Convert URL to wide characters */
|
161
|
+
wide_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
162
|
+
git_buf_cstr(&buf), -1, NULL, 0);
|
163
|
+
|
164
|
+
if (!wide_len) {
|
165
|
+
giterr_set(GITERR_OS, "Failed to measure string for wide conversion");
|
166
|
+
goto on_error;
|
167
|
+
}
|
168
|
+
|
169
|
+
s->request_uri = git__malloc(wide_len * sizeof(wchar_t));
|
170
|
+
|
171
|
+
if (!s->request_uri)
|
172
|
+
goto on_error;
|
173
|
+
|
174
|
+
if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
175
|
+
git_buf_cstr(&buf), -1, s->request_uri, wide_len)) {
|
176
|
+
giterr_set(GITERR_OS, "Failed to convert string to wide form");
|
177
|
+
goto on_error;
|
178
|
+
}
|
179
|
+
|
180
|
+
/* Establish request */
|
181
|
+
s->request = WinHttpOpenRequest(
|
182
|
+
t->connection,
|
183
|
+
s->verb,
|
184
|
+
s->request_uri,
|
185
|
+
NULL,
|
186
|
+
WINHTTP_NO_REFERER,
|
187
|
+
types,
|
188
|
+
t->use_ssl ? WINHTTP_FLAG_SECURE : 0);
|
189
|
+
|
190
|
+
if (!s->request) {
|
191
|
+
giterr_set(GITERR_OS, "Failed to open request");
|
192
|
+
goto on_error;
|
193
|
+
}
|
194
|
+
|
195
|
+
/* Set proxy if necessary */
|
196
|
+
if (git_remote__get_http_proxy(t->owner->owner, t->use_ssl, &proxy_url) < 0)
|
197
|
+
goto on_error;
|
198
|
+
|
199
|
+
if (proxy_url) {
|
200
|
+
WINHTTP_PROXY_INFO proxy_info;
|
201
|
+
wchar_t *proxy_wide;
|
202
|
+
|
203
|
+
/* Convert URL to wide characters */
|
204
|
+
wide_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
205
|
+
proxy_url, -1, NULL, 0);
|
206
|
+
|
207
|
+
if (!wide_len) {
|
208
|
+
giterr_set(GITERR_OS, "Failed to measure string for wide conversion");
|
209
|
+
goto on_error;
|
210
|
+
}
|
211
|
+
|
212
|
+
proxy_wide = git__malloc(wide_len * sizeof(wchar_t));
|
213
|
+
|
214
|
+
if (!proxy_wide)
|
215
|
+
goto on_error;
|
216
|
+
|
217
|
+
if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
|
218
|
+
proxy_url, -1, proxy_wide, wide_len)) {
|
219
|
+
giterr_set(GITERR_OS, "Failed to convert string to wide form");
|
220
|
+
git__free(proxy_wide);
|
221
|
+
goto on_error;
|
222
|
+
}
|
223
|
+
|
224
|
+
/* Strip any trailing forward slash on the proxy URL;
|
225
|
+
* WinHTTP doesn't like it if one is present */
|
226
|
+
if (wide_len > 1 && L'/' == proxy_wide[wide_len - 2])
|
227
|
+
proxy_wide[wide_len - 2] = L'\0';
|
228
|
+
|
229
|
+
proxy_info.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
|
230
|
+
proxy_info.lpszProxy = proxy_wide;
|
231
|
+
proxy_info.lpszProxyBypass = NULL;
|
232
|
+
|
233
|
+
if (!WinHttpSetOption(s->request,
|
234
|
+
WINHTTP_OPTION_PROXY,
|
235
|
+
&proxy_info,
|
236
|
+
sizeof(WINHTTP_PROXY_INFO))) {
|
237
|
+
giterr_set(GITERR_OS, "Failed to set proxy");
|
238
|
+
git__free(proxy_wide);
|
239
|
+
goto on_error;
|
240
|
+
}
|
241
|
+
|
242
|
+
git__free(proxy_wide);
|
243
|
+
}
|
244
|
+
|
245
|
+
/* Strip unwanted headers (X-P2P-PeerDist, X-P2P-PeerDistEx) that WinHTTP
|
246
|
+
* adds itself. This option may not be supported by the underlying
|
247
|
+
* platform, so we do not error-check it */
|
248
|
+
WinHttpSetOption(s->request,
|
249
|
+
WINHTTP_OPTION_PEERDIST_EXTENSION_STATE,
|
250
|
+
&peerdist,
|
251
|
+
sizeof(peerdist));
|
252
|
+
|
253
|
+
/* Send Pragma: no-cache header */
|
254
|
+
if (!WinHttpAddRequestHeaders(s->request, pragma_nocache, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) {
|
255
|
+
giterr_set(GITERR_OS, "Failed to add a header to the request");
|
256
|
+
goto on_error;
|
257
|
+
}
|
258
|
+
|
259
|
+
/* Send Content-Type header -- only necessary on a POST */
|
260
|
+
if (post_verb == s->verb) {
|
261
|
+
git_buf_clear(&buf);
|
262
|
+
if (git_buf_printf(&buf, "Content-Type: application/x-git-%s-request", s->service) < 0)
|
263
|
+
goto on_error;
|
264
|
+
|
265
|
+
git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf));
|
266
|
+
|
267
|
+
if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG) -1L, WINHTTP_ADDREQ_FLAG_ADD)) {
|
268
|
+
giterr_set(GITERR_OS, "Failed to add a header to the request");
|
269
|
+
goto on_error;
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
/* If requested, disable certificate validation */
|
274
|
+
if (t->use_ssl) {
|
275
|
+
int flags;
|
276
|
+
|
277
|
+
if (t->owner->parent.read_flags(&t->owner->parent, &flags) < 0)
|
278
|
+
goto on_error;
|
279
|
+
|
280
|
+
if ((GIT_TRANSPORTFLAGS_NO_CHECK_CERT & flags) &&
|
281
|
+
!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS,
|
282
|
+
(LPVOID)&no_check_cert_flags, sizeof(no_check_cert_flags))) {
|
283
|
+
giterr_set(GITERR_OS, "Failed to set options to ignore cert errors");
|
284
|
+
goto on_error;
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
/* If we have a credential on the subtransport, apply it to the request */
|
289
|
+
if (t->cred &&
|
290
|
+
t->cred->credtype == GIT_CREDTYPE_USERPASS_PLAINTEXT &&
|
291
|
+
t->auth_mechanism == GIT_WINHTTP_AUTH_BASIC &&
|
292
|
+
apply_basic_credential(s->request, t->cred) < 0)
|
293
|
+
goto on_error;
|
294
|
+
|
295
|
+
/* If no other credentials have been applied and the URL has username and
|
296
|
+
* password, use those */
|
297
|
+
if (!t->cred && t->user_from_url && t->pass_from_url) {
|
298
|
+
if (!t->url_cred &&
|
299
|
+
git_cred_userpass_plaintext_new(&t->url_cred, t->user_from_url, t->pass_from_url) < 0)
|
300
|
+
goto on_error;
|
301
|
+
if (apply_basic_credential(s->request, t->url_cred) < 0)
|
302
|
+
goto on_error;
|
303
|
+
}
|
304
|
+
|
305
|
+
/* We've done everything up to calling WinHttpSendRequest. */
|
306
|
+
|
307
|
+
error = 0;
|
308
|
+
|
309
|
+
on_error:
|
310
|
+
git__free(proxy_url);
|
311
|
+
git_buf_free(&buf);
|
312
|
+
return error;
|
313
|
+
}
|
314
|
+
|
315
|
+
static int parse_unauthorized_response(
|
316
|
+
HINTERNET request,
|
317
|
+
int *allowed_types,
|
318
|
+
int *auth_mechanism)
|
319
|
+
{
|
320
|
+
DWORD supported, first, target;
|
321
|
+
|
322
|
+
*allowed_types = 0;
|
323
|
+
*auth_mechanism = 0;
|
324
|
+
|
325
|
+
/* WinHttpQueryHeaders() must be called before WinHttpQueryAuthSchemes().
|
326
|
+
* We can assume this was already done, since we know we are unauthorized.
|
327
|
+
*/
|
328
|
+
if (!WinHttpQueryAuthSchemes(request, &supported, &first, &target)) {
|
329
|
+
giterr_set(GITERR_OS, "Failed to parse supported auth schemes");
|
330
|
+
return -1;
|
331
|
+
}
|
332
|
+
|
333
|
+
if (WINHTTP_AUTH_SCHEME_BASIC & supported) {
|
334
|
+
*allowed_types |= GIT_CREDTYPE_USERPASS_PLAINTEXT;
|
335
|
+
*auth_mechanism = GIT_WINHTTP_AUTH_BASIC;
|
336
|
+
}
|
337
|
+
|
338
|
+
return 0;
|
339
|
+
}
|
340
|
+
|
341
|
+
static int write_chunk(HINTERNET request, const char *buffer, size_t len)
|
342
|
+
{
|
343
|
+
DWORD bytes_written;
|
344
|
+
git_buf buf = GIT_BUF_INIT;
|
345
|
+
|
346
|
+
/* Chunk header */
|
347
|
+
git_buf_printf(&buf, "%X\r\n", len);
|
348
|
+
|
349
|
+
if (git_buf_oom(&buf))
|
350
|
+
return -1;
|
351
|
+
|
352
|
+
if (!WinHttpWriteData(request,
|
353
|
+
git_buf_cstr(&buf), (DWORD)git_buf_len(&buf),
|
354
|
+
&bytes_written)) {
|
355
|
+
git_buf_free(&buf);
|
356
|
+
giterr_set(GITERR_OS, "Failed to write chunk header");
|
357
|
+
return -1;
|
358
|
+
}
|
359
|
+
|
360
|
+
git_buf_free(&buf);
|
361
|
+
|
362
|
+
/* Chunk body */
|
363
|
+
if (!WinHttpWriteData(request,
|
364
|
+
buffer, (DWORD)len,
|
365
|
+
&bytes_written)) {
|
366
|
+
giterr_set(GITERR_OS, "Failed to write chunk");
|
367
|
+
return -1;
|
368
|
+
}
|
369
|
+
|
370
|
+
/* Chunk footer */
|
371
|
+
if (!WinHttpWriteData(request,
|
372
|
+
"\r\n", 2,
|
373
|
+
&bytes_written)) {
|
374
|
+
giterr_set(GITERR_OS, "Failed to write chunk footer");
|
375
|
+
return -1;
|
376
|
+
}
|
377
|
+
|
378
|
+
return 0;
|
379
|
+
}
|
380
|
+
|
381
|
+
static int winhttp_stream_read(
|
382
|
+
git_smart_subtransport_stream *stream,
|
383
|
+
char *buffer,
|
384
|
+
size_t buf_size,
|
385
|
+
size_t *bytes_read)
|
386
|
+
{
|
387
|
+
winhttp_stream *s = (winhttp_stream *)stream;
|
388
|
+
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
|
389
|
+
DWORD dw_bytes_read;
|
390
|
+
char replay_count = 0;
|
391
|
+
|
392
|
+
replay:
|
393
|
+
/* Enforce a reasonable cap on the number of replays */
|
394
|
+
if (++replay_count >= 7) {
|
395
|
+
giterr_set(GITERR_NET, "Too many redirects or authentication replays");
|
396
|
+
return -1;
|
397
|
+
}
|
398
|
+
|
399
|
+
/* Connect if necessary */
|
400
|
+
if (!s->request && winhttp_stream_connect(s) < 0)
|
401
|
+
return -1;
|
402
|
+
|
403
|
+
if (!s->received_response) {
|
404
|
+
DWORD status_code, status_code_length, content_type_length, bytes_written;
|
405
|
+
char expected_content_type_8[MAX_CONTENT_TYPE_LEN];
|
406
|
+
wchar_t expected_content_type[MAX_CONTENT_TYPE_LEN], content_type[MAX_CONTENT_TYPE_LEN];
|
407
|
+
|
408
|
+
if (!s->sent_request) {
|
409
|
+
if (!WinHttpSendRequest(s->request,
|
410
|
+
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
411
|
+
WINHTTP_NO_REQUEST_DATA, 0,
|
412
|
+
s->post_body_len, 0)) {
|
413
|
+
giterr_set(GITERR_OS, "Failed to send request");
|
414
|
+
return -1;
|
415
|
+
}
|
416
|
+
|
417
|
+
s->sent_request = 1;
|
418
|
+
}
|
419
|
+
|
420
|
+
if (s->chunked) {
|
421
|
+
assert(s->verb == post_verb);
|
422
|
+
|
423
|
+
/* Flush, if necessary */
|
424
|
+
if (s->chunk_buffer_len > 0 &&
|
425
|
+
write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0)
|
426
|
+
return -1;
|
427
|
+
|
428
|
+
s->chunk_buffer_len = 0;
|
429
|
+
|
430
|
+
/* Write the final chunk. */
|
431
|
+
if (!WinHttpWriteData(s->request,
|
432
|
+
"0\r\n\r\n", 5,
|
433
|
+
&bytes_written)) {
|
434
|
+
giterr_set(GITERR_OS, "Failed to write final chunk");
|
435
|
+
return -1;
|
436
|
+
}
|
437
|
+
}
|
438
|
+
else if (s->post_body) {
|
439
|
+
char *buffer;
|
440
|
+
DWORD len = s->post_body_len, bytes_read;
|
441
|
+
|
442
|
+
if (INVALID_SET_FILE_POINTER == SetFilePointer(s->post_body,
|
443
|
+
0, 0, FILE_BEGIN) &&
|
444
|
+
NO_ERROR != GetLastError()) {
|
445
|
+
giterr_set(GITERR_OS, "Failed to reset file pointer");
|
446
|
+
return -1;
|
447
|
+
}
|
448
|
+
|
449
|
+
buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE);
|
450
|
+
|
451
|
+
while (len > 0) {
|
452
|
+
DWORD bytes_written;
|
453
|
+
|
454
|
+
if (!ReadFile(s->post_body, buffer,
|
455
|
+
min(CACHED_POST_BODY_BUF_SIZE, len),
|
456
|
+
&bytes_read, NULL) ||
|
457
|
+
!bytes_read) {
|
458
|
+
git__free(buffer);
|
459
|
+
giterr_set(GITERR_OS, "Failed to read from temp file");
|
460
|
+
return -1;
|
461
|
+
}
|
462
|
+
|
463
|
+
if (!WinHttpWriteData(s->request, buffer,
|
464
|
+
bytes_read, &bytes_written)) {
|
465
|
+
git__free(buffer);
|
466
|
+
giterr_set(GITERR_OS, "Failed to write data");
|
467
|
+
return -1;
|
468
|
+
}
|
469
|
+
|
470
|
+
len -= bytes_read;
|
471
|
+
assert(bytes_read == bytes_written);
|
472
|
+
}
|
473
|
+
|
474
|
+
git__free(buffer);
|
475
|
+
|
476
|
+
/* Eagerly close the temp file */
|
477
|
+
CloseHandle(s->post_body);
|
478
|
+
s->post_body = NULL;
|
479
|
+
}
|
480
|
+
|
481
|
+
if (!WinHttpReceiveResponse(s->request, 0)) {
|
482
|
+
giterr_set(GITERR_OS, "Failed to receive response");
|
483
|
+
return -1;
|
484
|
+
}
|
485
|
+
|
486
|
+
/* Verify that we got a 200 back */
|
487
|
+
status_code_length = sizeof(status_code);
|
488
|
+
|
489
|
+
if (!WinHttpQueryHeaders(s->request,
|
490
|
+
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
|
491
|
+
WINHTTP_HEADER_NAME_BY_INDEX,
|
492
|
+
&status_code, &status_code_length,
|
493
|
+
WINHTTP_NO_HEADER_INDEX)) {
|
494
|
+
giterr_set(GITERR_OS, "Failed to retrieve status code");
|
495
|
+
return -1;
|
496
|
+
}
|
497
|
+
|
498
|
+
/* The implementation of WinHTTP prior to Windows 7 will not
|
499
|
+
* redirect to an identical URI. Some Git hosters use self-redirects
|
500
|
+
* as part of their DoS mitigation strategy. Check first to see if we
|
501
|
+
* have a redirect status code, and that we haven't already streamed
|
502
|
+
* a post body. (We can't replay a streamed POST.) */
|
503
|
+
if (!s->chunked &&
|
504
|
+
(HTTP_STATUS_MOVED == status_code ||
|
505
|
+
HTTP_STATUS_REDIRECT == status_code ||
|
506
|
+
(HTTP_STATUS_REDIRECT_METHOD == status_code &&
|
507
|
+
get_verb == s->verb) ||
|
508
|
+
HTTP_STATUS_REDIRECT_KEEP_VERB == status_code)) {
|
509
|
+
|
510
|
+
/* Check for Windows 7. This workaround is only necessary on
|
511
|
+
* Windows Vista and earlier. Windows 7 is version 6.1. */
|
512
|
+
if (!git_has_win32_version(6, 1)) {
|
513
|
+
wchar_t *location;
|
514
|
+
DWORD location_length;
|
515
|
+
int redirect_cmp;
|
516
|
+
|
517
|
+
/* OK, fetch the Location header from the redirect. */
|
518
|
+
if (WinHttpQueryHeaders(s->request,
|
519
|
+
WINHTTP_QUERY_LOCATION,
|
520
|
+
WINHTTP_HEADER_NAME_BY_INDEX,
|
521
|
+
WINHTTP_NO_OUTPUT_BUFFER,
|
522
|
+
&location_length,
|
523
|
+
WINHTTP_NO_HEADER_INDEX) ||
|
524
|
+
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
525
|
+
giterr_set(GITERR_OS, "Failed to read Location header");
|
526
|
+
return -1;
|
527
|
+
}
|
528
|
+
|
529
|
+
location = git__malloc(location_length);
|
530
|
+
GITERR_CHECK_ALLOC(location);
|
531
|
+
|
532
|
+
if (!WinHttpQueryHeaders(s->request,
|
533
|
+
WINHTTP_QUERY_LOCATION,
|
534
|
+
WINHTTP_HEADER_NAME_BY_INDEX,
|
535
|
+
location,
|
536
|
+
&location_length,
|
537
|
+
WINHTTP_NO_HEADER_INDEX)) {
|
538
|
+
giterr_set(GITERR_OS, "Failed to read Location header");
|
539
|
+
git__free(location);
|
540
|
+
return -1;
|
541
|
+
}
|
542
|
+
|
543
|
+
/* Compare the Location header with the request URI */
|
544
|
+
redirect_cmp = wcscmp(location, s->request_uri);
|
545
|
+
git__free(location);
|
546
|
+
|
547
|
+
if (!redirect_cmp) {
|
548
|
+
/* Replay the request */
|
549
|
+
WinHttpCloseHandle(s->request);
|
550
|
+
s->request = NULL;
|
551
|
+
s->sent_request = 0;
|
552
|
+
|
553
|
+
goto replay;
|
554
|
+
}
|
555
|
+
}
|
556
|
+
}
|
557
|
+
|
558
|
+
/* Handle authentication failures */
|
559
|
+
if (HTTP_STATUS_DENIED == status_code &&
|
560
|
+
get_verb == s->verb && t->owner->cred_acquire_cb) {
|
561
|
+
int allowed_types;
|
562
|
+
|
563
|
+
if (parse_unauthorized_response(s->request, &allowed_types, &t->auth_mechanism) < 0)
|
564
|
+
return -1;
|
565
|
+
|
566
|
+
if (allowed_types &&
|
567
|
+
(!t->cred || 0 == (t->cred->credtype & allowed_types))) {
|
568
|
+
|
569
|
+
if (t->owner->cred_acquire_cb(&t->cred, t->owner->url, t->user_from_url, allowed_types, t->owner->cred_acquire_payload) < 0)
|
570
|
+
return -1;
|
571
|
+
|
572
|
+
assert(t->cred);
|
573
|
+
|
574
|
+
WinHttpCloseHandle(s->request);
|
575
|
+
s->request = NULL;
|
576
|
+
s->sent_request = 0;
|
577
|
+
|
578
|
+
/* Successfully acquired a credential */
|
579
|
+
goto replay;
|
580
|
+
}
|
581
|
+
}
|
582
|
+
|
583
|
+
if (HTTP_STATUS_OK != status_code) {
|
584
|
+
giterr_set(GITERR_NET, "Request failed with status code: %d", status_code);
|
585
|
+
return -1;
|
586
|
+
}
|
587
|
+
|
588
|
+
/* Verify that we got the correct content-type back */
|
589
|
+
if (post_verb == s->verb)
|
590
|
+
snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-result", s->service);
|
591
|
+
else
|
592
|
+
snprintf(expected_content_type_8, MAX_CONTENT_TYPE_LEN, "application/x-git-%s-advertisement", s->service);
|
593
|
+
|
594
|
+
git__utf8_to_16(expected_content_type, MAX_CONTENT_TYPE_LEN, expected_content_type_8);
|
595
|
+
content_type_length = sizeof(content_type);
|
596
|
+
|
597
|
+
if (!WinHttpQueryHeaders(s->request,
|
598
|
+
WINHTTP_QUERY_CONTENT_TYPE,
|
599
|
+
WINHTTP_HEADER_NAME_BY_INDEX,
|
600
|
+
&content_type, &content_type_length,
|
601
|
+
WINHTTP_NO_HEADER_INDEX)) {
|
602
|
+
giterr_set(GITERR_OS, "Failed to retrieve response content-type");
|
603
|
+
return -1;
|
604
|
+
}
|
605
|
+
|
606
|
+
if (wcscmp(expected_content_type, content_type)) {
|
607
|
+
giterr_set(GITERR_NET, "Received unexpected content-type");
|
608
|
+
return -1;
|
609
|
+
}
|
610
|
+
|
611
|
+
s->received_response = 1;
|
612
|
+
}
|
613
|
+
|
614
|
+
if (!WinHttpReadData(s->request,
|
615
|
+
(LPVOID)buffer,
|
616
|
+
(DWORD)buf_size,
|
617
|
+
&dw_bytes_read))
|
618
|
+
{
|
619
|
+
giterr_set(GITERR_OS, "Failed to read data");
|
620
|
+
return -1;
|
621
|
+
}
|
622
|
+
|
623
|
+
*bytes_read = dw_bytes_read;
|
624
|
+
|
625
|
+
return 0;
|
626
|
+
}
|
627
|
+
|
628
|
+
static int winhttp_stream_write_single(
|
629
|
+
git_smart_subtransport_stream *stream,
|
630
|
+
const char *buffer,
|
631
|
+
size_t len)
|
632
|
+
{
|
633
|
+
winhttp_stream *s = (winhttp_stream *)stream;
|
634
|
+
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
|
635
|
+
DWORD bytes_written;
|
636
|
+
|
637
|
+
if (!s->request && winhttp_stream_connect(s) < 0)
|
638
|
+
return -1;
|
639
|
+
|
640
|
+
/* This implementation of write permits only a single call. */
|
641
|
+
if (s->sent_request) {
|
642
|
+
giterr_set(GITERR_NET, "Subtransport configured for only one write");
|
643
|
+
return -1;
|
644
|
+
}
|
645
|
+
|
646
|
+
if (!WinHttpSendRequest(s->request,
|
647
|
+
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
648
|
+
WINHTTP_NO_REQUEST_DATA, 0,
|
649
|
+
(DWORD)len, 0)) {
|
650
|
+
giterr_set(GITERR_OS, "Failed to send request");
|
651
|
+
return -1;
|
652
|
+
}
|
653
|
+
|
654
|
+
s->sent_request = 1;
|
655
|
+
|
656
|
+
if (!WinHttpWriteData(s->request,
|
657
|
+
(LPCVOID)buffer,
|
658
|
+
(DWORD)len,
|
659
|
+
&bytes_written)) {
|
660
|
+
giterr_set(GITERR_OS, "Failed to write data");
|
661
|
+
return -1;
|
662
|
+
}
|
663
|
+
|
664
|
+
assert((DWORD)len == bytes_written);
|
665
|
+
|
666
|
+
return 0;
|
667
|
+
}
|
668
|
+
|
669
|
+
static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch)
|
670
|
+
{
|
671
|
+
UUID uuid;
|
672
|
+
RPC_STATUS status = UuidCreate(&uuid);
|
673
|
+
HRESULT result;
|
674
|
+
|
675
|
+
if (RPC_S_OK != status &&
|
676
|
+
RPC_S_UUID_LOCAL_ONLY != status &&
|
677
|
+
RPC_S_UUID_NO_ADDRESS != status) {
|
678
|
+
giterr_set(GITERR_NET, "Unable to generate name for temp file");
|
679
|
+
return -1;
|
680
|
+
}
|
681
|
+
|
682
|
+
if (buffer_len_cch < UUID_LENGTH_CCH + 1) {
|
683
|
+
giterr_set(GITERR_NET, "Buffer too small for name of temp file");
|
684
|
+
return -1;
|
685
|
+
}
|
686
|
+
|
687
|
+
result = StringCbPrintfW(
|
688
|
+
buffer, buffer_len_cch,
|
689
|
+
L"%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x",
|
690
|
+
uuid.Data1, uuid.Data2, uuid.Data3,
|
691
|
+
uuid.Data4[0], uuid.Data4[1], uuid.Data4[2], uuid.Data4[3],
|
692
|
+
uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]);
|
693
|
+
|
694
|
+
if (FAILED(result)) {
|
695
|
+
giterr_set(GITERR_OS, "Unable to generate name for temp file");
|
696
|
+
return -1;
|
697
|
+
}
|
698
|
+
|
699
|
+
return 0;
|
700
|
+
}
|
701
|
+
|
702
|
+
static int get_temp_file(LPWSTR buffer, DWORD buffer_len_cch)
|
703
|
+
{
|
704
|
+
size_t len;
|
705
|
+
|
706
|
+
if (!GetTempPathW(buffer_len_cch, buffer)) {
|
707
|
+
giterr_set(GITERR_OS, "Failed to get temp path");
|
708
|
+
return -1;
|
709
|
+
}
|
710
|
+
|
711
|
+
len = wcslen(buffer);
|
712
|
+
|
713
|
+
if (buffer[len - 1] != '\\' && len < buffer_len_cch)
|
714
|
+
buffer[len++] = '\\';
|
715
|
+
|
716
|
+
if (put_uuid_string(&buffer[len], (size_t)buffer_len_cch - len) < 0)
|
717
|
+
return -1;
|
718
|
+
|
719
|
+
return 0;
|
720
|
+
}
|
721
|
+
|
722
|
+
static int winhttp_stream_write_buffered(
|
723
|
+
git_smart_subtransport_stream *stream,
|
724
|
+
const char *buffer,
|
725
|
+
size_t len)
|
726
|
+
{
|
727
|
+
winhttp_stream *s = (winhttp_stream *)stream;
|
728
|
+
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
|
729
|
+
DWORD bytes_written;
|
730
|
+
|
731
|
+
if (!s->request && winhttp_stream_connect(s) < 0)
|
732
|
+
return -1;
|
733
|
+
|
734
|
+
/* Buffer the payload, using a temporary file so we delegate
|
735
|
+
* memory management of the data to the operating system. */
|
736
|
+
if (!s->post_body) {
|
737
|
+
wchar_t temp_path[MAX_PATH + 1];
|
738
|
+
|
739
|
+
if (get_temp_file(temp_path, MAX_PATH + 1) < 0)
|
740
|
+
return -1;
|
741
|
+
|
742
|
+
s->post_body = CreateFileW(temp_path,
|
743
|
+
GENERIC_READ | GENERIC_WRITE,
|
744
|
+
FILE_SHARE_DELETE, NULL,
|
745
|
+
CREATE_NEW,
|
746
|
+
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_SEQUENTIAL_SCAN,
|
747
|
+
NULL);
|
748
|
+
|
749
|
+
if (INVALID_HANDLE_VALUE == s->post_body) {
|
750
|
+
s->post_body = NULL;
|
751
|
+
giterr_set(GITERR_OS, "Failed to create temporary file");
|
752
|
+
return -1;
|
753
|
+
}
|
754
|
+
}
|
755
|
+
|
756
|
+
if (!WriteFile(s->post_body, buffer, (DWORD)len, &bytes_written, NULL)) {
|
757
|
+
giterr_set(GITERR_OS, "Failed to write to temporary file");
|
758
|
+
return -1;
|
759
|
+
}
|
760
|
+
|
761
|
+
assert((DWORD)len == bytes_written);
|
762
|
+
|
763
|
+
s->post_body_len += bytes_written;
|
764
|
+
|
765
|
+
return 0;
|
766
|
+
}
|
767
|
+
|
768
|
+
static int winhttp_stream_write_chunked(
|
769
|
+
git_smart_subtransport_stream *stream,
|
770
|
+
const char *buffer,
|
771
|
+
size_t len)
|
772
|
+
{
|
773
|
+
winhttp_stream *s = (winhttp_stream *)stream;
|
774
|
+
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
|
775
|
+
|
776
|
+
if (!s->request && winhttp_stream_connect(s) < 0)
|
777
|
+
return -1;
|
778
|
+
|
779
|
+
if (!s->sent_request) {
|
780
|
+
/* Send Transfer-Encoding: chunked header */
|
781
|
+
if (!WinHttpAddRequestHeaders(s->request,
|
782
|
+
transfer_encoding, (ULONG) -1L,
|
783
|
+
WINHTTP_ADDREQ_FLAG_ADD)) {
|
784
|
+
giterr_set(GITERR_OS, "Failed to add a header to the request");
|
785
|
+
return -1;
|
786
|
+
}
|
787
|
+
|
788
|
+
if (!WinHttpSendRequest(s->request,
|
789
|
+
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
790
|
+
WINHTTP_NO_REQUEST_DATA, 0,
|
791
|
+
WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0)) {
|
792
|
+
giterr_set(GITERR_OS, "Failed to send request");
|
793
|
+
return -1;
|
794
|
+
}
|
795
|
+
|
796
|
+
s->sent_request = 1;
|
797
|
+
}
|
798
|
+
|
799
|
+
if (len > CACHED_POST_BODY_BUF_SIZE) {
|
800
|
+
/* Flush, if necessary */
|
801
|
+
if (s->chunk_buffer_len > 0) {
|
802
|
+
if (write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0)
|
803
|
+
return -1;
|
804
|
+
|
805
|
+
s->chunk_buffer_len = 0;
|
806
|
+
}
|
807
|
+
|
808
|
+
/* Write chunk directly */
|
809
|
+
if (write_chunk(s->request, buffer, len) < 0)
|
810
|
+
return -1;
|
811
|
+
}
|
812
|
+
else {
|
813
|
+
/* Append as much to the buffer as we can */
|
814
|
+
int count = min(CACHED_POST_BODY_BUF_SIZE - s->chunk_buffer_len, (int)len);
|
815
|
+
|
816
|
+
if (!s->chunk_buffer)
|
817
|
+
s->chunk_buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE);
|
818
|
+
|
819
|
+
memcpy(s->chunk_buffer + s->chunk_buffer_len, buffer, count);
|
820
|
+
s->chunk_buffer_len += count;
|
821
|
+
buffer += count;
|
822
|
+
len -= count;
|
823
|
+
|
824
|
+
/* Is the buffer full? If so, then flush */
|
825
|
+
if (CACHED_POST_BODY_BUF_SIZE == s->chunk_buffer_len) {
|
826
|
+
if (write_chunk(s->request, s->chunk_buffer, s->chunk_buffer_len) < 0)
|
827
|
+
return -1;
|
828
|
+
|
829
|
+
s->chunk_buffer_len = 0;
|
830
|
+
|
831
|
+
/* Is there any remaining data from the source? */
|
832
|
+
if (len > 0) {
|
833
|
+
memcpy(s->chunk_buffer, buffer, len);
|
834
|
+
s->chunk_buffer_len = (unsigned int)len;
|
835
|
+
}
|
836
|
+
}
|
837
|
+
}
|
838
|
+
|
839
|
+
return 0;
|
840
|
+
}
|
841
|
+
|
842
|
+
static void winhttp_stream_free(git_smart_subtransport_stream *stream)
|
843
|
+
{
|
844
|
+
winhttp_stream *s = (winhttp_stream *)stream;
|
845
|
+
|
846
|
+
if (s->chunk_buffer) {
|
847
|
+
git__free(s->chunk_buffer);
|
848
|
+
s->chunk_buffer = NULL;
|
849
|
+
}
|
850
|
+
|
851
|
+
if (s->post_body) {
|
852
|
+
CloseHandle(s->post_body);
|
853
|
+
s->post_body = NULL;
|
854
|
+
}
|
855
|
+
|
856
|
+
if (s->request_uri) {
|
857
|
+
git__free(s->request_uri);
|
858
|
+
s->request_uri = NULL;
|
859
|
+
}
|
860
|
+
|
861
|
+
if (s->request) {
|
862
|
+
WinHttpCloseHandle(s->request);
|
863
|
+
s->request = NULL;
|
864
|
+
}
|
865
|
+
|
866
|
+
git__free(s);
|
867
|
+
}
|
868
|
+
|
869
|
+
static int winhttp_stream_alloc(winhttp_subtransport *t, winhttp_stream **stream)
|
870
|
+
{
|
871
|
+
winhttp_stream *s;
|
872
|
+
|
873
|
+
if (!stream)
|
874
|
+
return -1;
|
875
|
+
|
876
|
+
s = git__calloc(sizeof(winhttp_stream), 1);
|
877
|
+
GITERR_CHECK_ALLOC(s);
|
878
|
+
|
879
|
+
s->parent.subtransport = &t->parent;
|
880
|
+
s->parent.read = winhttp_stream_read;
|
881
|
+
s->parent.write = winhttp_stream_write_single;
|
882
|
+
s->parent.free = winhttp_stream_free;
|
883
|
+
|
884
|
+
*stream = s;
|
885
|
+
|
886
|
+
return 0;
|
887
|
+
}
|
888
|
+
|
889
|
+
static int winhttp_connect(
|
890
|
+
winhttp_subtransport *t,
|
891
|
+
const char *url)
|
892
|
+
{
|
893
|
+
wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")";
|
894
|
+
wchar_t host[GIT_WIN_PATH];
|
895
|
+
int32_t port;
|
896
|
+
const char *default_port;
|
897
|
+
int ret;
|
898
|
+
|
899
|
+
if (!git__prefixcmp(url, prefix_http)) {
|
900
|
+
url = url + strlen(prefix_http);
|
901
|
+
default_port = "80";
|
902
|
+
}
|
903
|
+
|
904
|
+
if (!git__prefixcmp(url, prefix_https)) {
|
905
|
+
url += strlen(prefix_https);
|
906
|
+
default_port = "443";
|
907
|
+
t->use_ssl = 1;
|
908
|
+
}
|
909
|
+
|
910
|
+
if ((ret = gitno_extract_url_parts(&t->host, &t->port, &t->user_from_url,
|
911
|
+
&t->pass_from_url, url, default_port)) < 0)
|
912
|
+
return ret;
|
913
|
+
|
914
|
+
t->path = strchr(url, '/');
|
915
|
+
|
916
|
+
/* Prepare port */
|
917
|
+
if (git__strtol32(&port, t->port, NULL, 10) < 0)
|
918
|
+
return -1;
|
919
|
+
|
920
|
+
/* Prepare host */
|
921
|
+
git__utf8_to_16(host, GIT_WIN_PATH, t->host);
|
922
|
+
|
923
|
+
/* Establish session */
|
924
|
+
t->session = WinHttpOpen(
|
925
|
+
ua,
|
926
|
+
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
927
|
+
WINHTTP_NO_PROXY_NAME,
|
928
|
+
WINHTTP_NO_PROXY_BYPASS,
|
929
|
+
0);
|
930
|
+
|
931
|
+
if (!t->session) {
|
932
|
+
giterr_set(GITERR_OS, "Failed to init WinHTTP");
|
933
|
+
return -1;
|
934
|
+
}
|
935
|
+
|
936
|
+
/* Establish connection */
|
937
|
+
t->connection = WinHttpConnect(
|
938
|
+
t->session,
|
939
|
+
host,
|
940
|
+
port,
|
941
|
+
0);
|
942
|
+
|
943
|
+
if (!t->connection) {
|
944
|
+
giterr_set(GITERR_OS, "Failed to connect to host");
|
945
|
+
return -1;
|
946
|
+
}
|
947
|
+
|
948
|
+
return 0;
|
949
|
+
}
|
950
|
+
|
951
|
+
static int winhttp_uploadpack_ls(
|
952
|
+
winhttp_subtransport *t,
|
953
|
+
winhttp_stream *s)
|
954
|
+
{
|
955
|
+
s->service = upload_pack_service;
|
956
|
+
s->service_url = upload_pack_ls_service_url;
|
957
|
+
s->verb = get_verb;
|
958
|
+
|
959
|
+
return 0;
|
960
|
+
}
|
961
|
+
|
962
|
+
static int winhttp_uploadpack(
|
963
|
+
winhttp_subtransport *t,
|
964
|
+
winhttp_stream *s)
|
965
|
+
{
|
966
|
+
s->service = upload_pack_service;
|
967
|
+
s->service_url = upload_pack_service_url;
|
968
|
+
s->verb = post_verb;
|
969
|
+
|
970
|
+
return 0;
|
971
|
+
}
|
972
|
+
|
973
|
+
static int winhttp_receivepack_ls(
|
974
|
+
winhttp_subtransport *t,
|
975
|
+
winhttp_stream *s)
|
976
|
+
{
|
977
|
+
s->service = receive_pack_service;
|
978
|
+
s->service_url = receive_pack_ls_service_url;
|
979
|
+
s->verb = get_verb;
|
980
|
+
|
981
|
+
return 0;
|
982
|
+
}
|
983
|
+
|
984
|
+
static int winhttp_receivepack(
|
985
|
+
winhttp_subtransport *t,
|
986
|
+
winhttp_stream *s)
|
987
|
+
{
|
988
|
+
/* WinHTTP only supports Transfer-Encoding: chunked
|
989
|
+
* on Windows Vista (NT 6.0) and higher. */
|
990
|
+
s->chunked = git_has_win32_version(6, 0);
|
991
|
+
|
992
|
+
if (s->chunked)
|
993
|
+
s->parent.write = winhttp_stream_write_chunked;
|
994
|
+
else
|
995
|
+
s->parent.write = winhttp_stream_write_buffered;
|
996
|
+
|
997
|
+
s->service = receive_pack_service;
|
998
|
+
s->service_url = receive_pack_service_url;
|
999
|
+
s->verb = post_verb;
|
1000
|
+
|
1001
|
+
return 0;
|
1002
|
+
}
|
1003
|
+
|
1004
|
+
static int winhttp_action(
|
1005
|
+
git_smart_subtransport_stream **stream,
|
1006
|
+
git_smart_subtransport *subtransport,
|
1007
|
+
const char *url,
|
1008
|
+
git_smart_service_t action)
|
1009
|
+
{
|
1010
|
+
winhttp_subtransport *t = (winhttp_subtransport *)subtransport;
|
1011
|
+
winhttp_stream *s;
|
1012
|
+
int ret = -1;
|
1013
|
+
|
1014
|
+
if (!t->connection &&
|
1015
|
+
winhttp_connect(t, url) < 0)
|
1016
|
+
return -1;
|
1017
|
+
|
1018
|
+
if (winhttp_stream_alloc(t, &s) < 0)
|
1019
|
+
return -1;
|
1020
|
+
|
1021
|
+
if (!stream)
|
1022
|
+
return -1;
|
1023
|
+
|
1024
|
+
switch (action)
|
1025
|
+
{
|
1026
|
+
case GIT_SERVICE_UPLOADPACK_LS:
|
1027
|
+
ret = winhttp_uploadpack_ls(t, s);
|
1028
|
+
break;
|
1029
|
+
|
1030
|
+
case GIT_SERVICE_UPLOADPACK:
|
1031
|
+
ret = winhttp_uploadpack(t, s);
|
1032
|
+
break;
|
1033
|
+
|
1034
|
+
case GIT_SERVICE_RECEIVEPACK_LS:
|
1035
|
+
ret = winhttp_receivepack_ls(t, s);
|
1036
|
+
break;
|
1037
|
+
|
1038
|
+
case GIT_SERVICE_RECEIVEPACK:
|
1039
|
+
ret = winhttp_receivepack(t, s);
|
1040
|
+
break;
|
1041
|
+
|
1042
|
+
default:
|
1043
|
+
assert(0);
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
if (!ret)
|
1047
|
+
*stream = &s->parent;
|
1048
|
+
|
1049
|
+
return ret;
|
1050
|
+
}
|
1051
|
+
|
1052
|
+
static int winhttp_close(git_smart_subtransport *subtransport)
|
1053
|
+
{
|
1054
|
+
winhttp_subtransport *t = (winhttp_subtransport *)subtransport;
|
1055
|
+
int ret = 0;
|
1056
|
+
|
1057
|
+
if (t->host) {
|
1058
|
+
git__free(t->host);
|
1059
|
+
t->host = NULL;
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
if (t->port) {
|
1063
|
+
git__free(t->port);
|
1064
|
+
t->port = NULL;
|
1065
|
+
}
|
1066
|
+
|
1067
|
+
if (t->user_from_url) {
|
1068
|
+
git__free(t->user_from_url);
|
1069
|
+
t->user_from_url = NULL;
|
1070
|
+
}
|
1071
|
+
|
1072
|
+
if (t->pass_from_url) {
|
1073
|
+
git__free(t->pass_from_url);
|
1074
|
+
t->pass_from_url = NULL;
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
if (t->cred) {
|
1078
|
+
t->cred->free(t->cred);
|
1079
|
+
t->cred = NULL;
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
if (t->url_cred) {
|
1083
|
+
t->url_cred->free(t->url_cred);
|
1084
|
+
t->url_cred = NULL;
|
1085
|
+
}
|
1086
|
+
|
1087
|
+
if (t->connection) {
|
1088
|
+
if (!WinHttpCloseHandle(t->connection)) {
|
1089
|
+
giterr_set(GITERR_OS, "Unable to close connection");
|
1090
|
+
ret = -1;
|
1091
|
+
}
|
1092
|
+
|
1093
|
+
t->connection = NULL;
|
1094
|
+
}
|
1095
|
+
|
1096
|
+
if (t->session) {
|
1097
|
+
if (!WinHttpCloseHandle(t->session)) {
|
1098
|
+
giterr_set(GITERR_OS, "Unable to close session");
|
1099
|
+
ret = -1;
|
1100
|
+
}
|
1101
|
+
|
1102
|
+
t->session = NULL;
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
return ret;
|
1106
|
+
}
|
1107
|
+
|
1108
|
+
static void winhttp_free(git_smart_subtransport *subtransport)
|
1109
|
+
{
|
1110
|
+
winhttp_subtransport *t = (winhttp_subtransport *)subtransport;
|
1111
|
+
|
1112
|
+
winhttp_close(subtransport);
|
1113
|
+
|
1114
|
+
git__free(t);
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *owner)
|
1118
|
+
{
|
1119
|
+
winhttp_subtransport *t;
|
1120
|
+
|
1121
|
+
if (!out)
|
1122
|
+
return -1;
|
1123
|
+
|
1124
|
+
t = git__calloc(sizeof(winhttp_subtransport), 1);
|
1125
|
+
GITERR_CHECK_ALLOC(t);
|
1126
|
+
|
1127
|
+
t->owner = (transport_smart *)owner;
|
1128
|
+
t->parent.action = winhttp_action;
|
1129
|
+
t->parent.close = winhttp_close;
|
1130
|
+
t->parent.free = winhttp_free;
|
1131
|
+
|
1132
|
+
*out = (git_smart_subtransport *) t;
|
1133
|
+
return 0;
|
1134
|
+
}
|
1135
|
+
|
1136
|
+
#endif /* GIT_WINHTTP */
|