Skip to content

Commit d8cef38

Browse files
committed
http: Support sending custom HTTP headers
To make communication for `git fetch`, `git ls-remote` and friends extra secure, we introduce a way to send custom HTTP headers with all requests. This allows us, for example, to send an extra token that the server tests for. The server could use this token e.g. to ensure that only certain operations or refs are allowed, or allow the token to be used only once. This feature can be used like this: git -c http.extraheader='Secret: sssh!' fetch $URL $REF As `curl_easy_setopt(..., CURLOPT_HTTPHEADER, ...)` overrides previous calls' headers (instead of appending the headers, as this unsuspecting developer thought initially), we piggyback onto the `Pragma:` setting by default, and introduce the global helper `http_get_default_headers()` to help functions that want to specify HTTP headers themselves. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 51d4375 commit d8cef38

File tree

5 files changed

+39
-10
lines changed

5 files changed

+39
-10
lines changed

Documentation/config.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,12 @@ http.emptyAuth::
16751675
a username in the URL, as libcurl normally requires a username for
16761676
authentication.
16771677

1678+
http.extraHeader::
1679+
Pass an additional HTTP header when communicating with a server. If
1680+
more than one such entry exists, all of them are added as extra headers.
1681+
This feature is useful e.g. to increase security, or to allow
1682+
time-limited access based on expiring tokens.
1683+
16781684
http.cookieFile::
16791685
File containing previously stored cookie lines which should be used
16801686
in the Git http session, if they match the server. The file format

http-push.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ static void curl_setup_http(CURL *curl, const char *url,
211211
static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options)
212212
{
213213
struct strbuf buf = STRBUF_INIT;
214-
struct curl_slist *dav_headers = NULL;
214+
struct curl_slist *dav_headers = http_get_default_headers();
215215

216216
if (options & DAV_HEADER_IF) {
217217
strbuf_addf(&buf, "If: (<%s>)", lock->token);
@@ -417,7 +417,7 @@ static void start_put(struct transfer_request *request)
417417
static void start_move(struct transfer_request *request)
418418
{
419419
struct active_request_slot *slot;
420-
struct curl_slist *dav_headers = NULL;
420+
struct curl_slist *dav_headers = http_get_default_headers();
421421

422422
slot = get_active_slot();
423423
slot->callback_func = process_response;
@@ -845,7 +845,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
845845
char *ep;
846846
char timeout_header[25];
847847
struct remote_lock *lock = NULL;
848-
struct curl_slist *dav_headers = NULL;
848+
struct curl_slist *dav_headers = http_get_default_headers();
849849
struct xml_ctx ctx;
850850
char *escaped;
851851

@@ -1126,7 +1126,7 @@ static void remote_ls(const char *path, int flags,
11261126
struct slot_results results;
11271127
struct strbuf in_buffer = STRBUF_INIT;
11281128
struct buffer out_buffer = { STRBUF_INIT, 0 };
1129-
struct curl_slist *dav_headers = NULL;
1129+
struct curl_slist *dav_headers = http_get_default_headers();
11301130
struct xml_ctx ctx;
11311131
struct remote_ls_ctx ls;
11321132

@@ -1204,7 +1204,7 @@ static int locking_available(void)
12041204
struct slot_results results;
12051205
struct strbuf in_buffer = STRBUF_INIT;
12061206
struct buffer out_buffer = { STRBUF_INIT, 0 };
1207-
struct curl_slist *dav_headers = NULL;
1207+
struct curl_slist *dav_headers = http_get_default_headers();
12081208
struct xml_ctx ctx;
12091209
int lock_flags = 0;
12101210
char *escaped;

http.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ static unsigned long http_auth_methods = CURLAUTH_ANY;
114114

115115
static struct curl_slist *pragma_header;
116116
static struct curl_slist *no_pragma_header;
117+
static struct curl_slist *extra_http_headers;
117118

118119
static struct active_request_slot *active_queue_head;
119120

@@ -323,6 +324,12 @@ static int http_options(const char *var, const char *value, void *cb)
323324
#endif
324325
}
325326

327+
if (!strcmp("http.extraheader", var)) {
328+
extra_http_headers =
329+
curl_slist_append(extra_http_headers, value);
330+
return 0;
331+
}
332+
326333
/* Fall back on the default ones */
327334
return git_default_config(var, value, cb);
328335
}
@@ -675,8 +682,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
675682
if (remote)
676683
var_override(&http_proxy_authmethod, remote->http_proxy_authmethod);
677684

678-
pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
679-
no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
685+
pragma_header = curl_slist_append(http_get_default_headers(),
686+
"Pragma: no-cache");
687+
no_pragma_header = curl_slist_append(http_get_default_headers(),
688+
"Pragma:");
680689

681690
#ifdef USE_CURL_MULTI
682691
{
@@ -762,6 +771,9 @@ void http_cleanup(void)
762771
#endif
763772
curl_global_cleanup();
764773

774+
curl_slist_free_all(extra_http_headers);
775+
extra_http_headers = NULL;
776+
765777
curl_slist_free_all(pragma_header);
766778
pragma_header = NULL;
767779

@@ -1160,6 +1172,16 @@ int run_one_slot(struct active_request_slot *slot,
11601172
return handle_curl_result(results);
11611173
}
11621174

1175+
struct curl_slist *http_get_default_headers()
1176+
{
1177+
struct curl_slist *headers = NULL, *h;
1178+
1179+
for (h = extra_http_headers; h; h = h->next)
1180+
headers = curl_slist_append(headers, h->data);
1181+
1182+
return headers;
1183+
}
1184+
11631185
static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
11641186
{
11651187
char *ptr;
@@ -1377,7 +1399,7 @@ static int http_request(const char *url,
13771399
{
13781400
struct active_request_slot *slot;
13791401
struct slot_results results;
1380-
struct curl_slist *headers = NULL;
1402+
struct curl_slist *headers = http_get_default_headers();
13811403
struct strbuf buf = STRBUF_INIT;
13821404
const char *accept_language;
13831405
int ret;

http.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ extern void step_active_slots(void);
106106
extern void http_init(struct remote *remote, const char *url,
107107
int proactive_auth);
108108
extern void http_cleanup(void);
109+
extern struct curl_slist *http_get_default_headers();
109110

110111
extern long int git_curl_ipresolve;
111112
extern int active_requests;

remote-curl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ static int run_slot(struct active_request_slot *slot,
474474
static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)
475475
{
476476
struct active_request_slot *slot;
477-
struct curl_slist *headers = NULL;
477+
struct curl_slist *headers = http_get_default_headers();
478478
struct strbuf buf = STRBUF_INIT;
479479
int err;
480480

@@ -503,7 +503,7 @@ static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)
503503
static int post_rpc(struct rpc_state *rpc)
504504
{
505505
struct active_request_slot *slot;
506-
struct curl_slist *headers = NULL;
506+
struct curl_slist *headers = http_get_default_headers();
507507
int use_gzip = rpc->gzip_request;
508508
char *gzip_body = NULL;
509509
size_t gzip_size = 0;

0 commit comments

Comments
 (0)