Skip to content

Commit

Permalink
http: Support sending custom HTTP headers
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dscho committed Apr 23, 2016
1 parent 51d4375 commit d8cef38
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 10 deletions.
6 changes: 6 additions & 0 deletions Documentation/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,12 @@ http.emptyAuth::
a username in the URL, as libcurl normally requires a username for
authentication.

http.extraHeader::
Pass an additional HTTP header when communicating with a server. If
more than one such entry exists, all of them are added as extra headers.
This feature is useful e.g. to increase security, or to allow
time-limited access based on expiring tokens.

http.cookieFile::
File containing previously stored cookie lines which should be used
in the Git http session, if they match the server. The file format
Expand Down
10 changes: 5 additions & 5 deletions http-push.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ static void curl_setup_http(CURL *curl, const char *url,
static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options)
{
struct strbuf buf = STRBUF_INIT;
struct curl_slist *dav_headers = NULL;
struct curl_slist *dav_headers = http_get_default_headers();

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

slot = get_active_slot();
slot->callback_func = process_response;
Expand Down Expand Up @@ -845,7 +845,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
char *ep;
char timeout_header[25];
struct remote_lock *lock = NULL;
struct curl_slist *dav_headers = NULL;
struct curl_slist *dav_headers = http_get_default_headers();
struct xml_ctx ctx;
char *escaped;

Expand Down Expand Up @@ -1126,7 +1126,7 @@ static void remote_ls(const char *path, int flags,
struct slot_results results;
struct strbuf in_buffer = STRBUF_INIT;
struct buffer out_buffer = { STRBUF_INIT, 0 };
struct curl_slist *dav_headers = NULL;
struct curl_slist *dav_headers = http_get_default_headers();
struct xml_ctx ctx;
struct remote_ls_ctx ls;

Expand Down Expand Up @@ -1204,7 +1204,7 @@ static int locking_available(void)
struct slot_results results;
struct strbuf in_buffer = STRBUF_INIT;
struct buffer out_buffer = { STRBUF_INIT, 0 };
struct curl_slist *dav_headers = NULL;
struct curl_slist *dav_headers = http_get_default_headers();
struct xml_ctx ctx;
int lock_flags = 0;
char *escaped;
Expand Down
28 changes: 25 additions & 3 deletions http.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ static unsigned long http_auth_methods = CURLAUTH_ANY;

static struct curl_slist *pragma_header;
static struct curl_slist *no_pragma_header;
static struct curl_slist *extra_http_headers;

static struct active_request_slot *active_queue_head;

Expand Down Expand Up @@ -323,6 +324,12 @@ static int http_options(const char *var, const char *value, void *cb)
#endif
}

if (!strcmp("http.extraheader", var)) {
extra_http_headers =
curl_slist_append(extra_http_headers, value);
return 0;
}

/* Fall back on the default ones */
return git_default_config(var, value, cb);
}
Expand Down Expand Up @@ -675,8 +682,10 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
if (remote)
var_override(&http_proxy_authmethod, remote->http_proxy_authmethod);

pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
pragma_header = curl_slist_append(http_get_default_headers(),
"Pragma: no-cache");
no_pragma_header = curl_slist_append(http_get_default_headers(),
"Pragma:");

#ifdef USE_CURL_MULTI
{
Expand Down Expand Up @@ -762,6 +771,9 @@ void http_cleanup(void)
#endif
curl_global_cleanup();

curl_slist_free_all(extra_http_headers);
extra_http_headers = NULL;

curl_slist_free_all(pragma_header);
pragma_header = NULL;

Expand Down Expand Up @@ -1160,6 +1172,16 @@ int run_one_slot(struct active_request_slot *slot,
return handle_curl_result(results);
}

struct curl_slist *http_get_default_headers()
{
struct curl_slist *headers = NULL, *h;

for (h = extra_http_headers; h; h = h->next)
headers = curl_slist_append(headers, h->data);

return headers;
}

static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
{
char *ptr;
Expand Down Expand Up @@ -1377,7 +1399,7 @@ static int http_request(const char *url,
{
struct active_request_slot *slot;
struct slot_results results;
struct curl_slist *headers = NULL;
struct curl_slist *headers = http_get_default_headers();
struct strbuf buf = STRBUF_INIT;
const char *accept_language;
int ret;
Expand Down
1 change: 1 addition & 0 deletions http.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ extern void step_active_slots(void);
extern void http_init(struct remote *remote, const char *url,
int proactive_auth);
extern void http_cleanup(void);
extern struct curl_slist *http_get_default_headers();

extern long int git_curl_ipresolve;
extern int active_requests;
Expand Down
4 changes: 2 additions & 2 deletions remote-curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ static int run_slot(struct active_request_slot *slot,
static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)
{
struct active_request_slot *slot;
struct curl_slist *headers = NULL;
struct curl_slist *headers = http_get_default_headers();
struct strbuf buf = STRBUF_INIT;
int err;

Expand Down Expand Up @@ -503,7 +503,7 @@ static int probe_rpc(struct rpc_state *rpc, struct slot_results *results)
static int post_rpc(struct rpc_state *rpc)
{
struct active_request_slot *slot;
struct curl_slist *headers = NULL;
struct curl_slist *headers = http_get_default_headers();
int use_gzip = rpc->gzip_request;
char *gzip_body = NULL;
size_t gzip_size = 0;
Expand Down

0 comments on commit d8cef38

Please sign in to comment.