From: "Shawn O. Pearce" <spearce@spearce.org>
To: git@vger.kernel.org
Cc: Daniel Barkalow <barkalow@iabervon.org>
Subject: [RFC PATCH v2 13/16] Discover refs via smart HTTP server when available
Date: Mon, 12 Oct 2009 19:25:12 -0700 [thread overview]
Message-ID: <1255400715-10508-14-git-send-email-spearce@spearce.org> (raw)
In-Reply-To: <1255400715-10508-1-git-send-email-spearce@spearce.org>
Instead of loading the cached info/refs, try to use the smart HTTP
version when the server supports it. Since the smart variant is
actually the pkt-line stream from the start of either upload-pack
or receive-pack we need to parse these through get_remote_heads,
which requires a background thread to feed its pipe.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
CC: Daniel Barkalow <barkalow@iabervon.org>
---
remote-curl.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 116 insertions(+), 19 deletions(-)
diff --git a/remote-curl.c b/remote-curl.c
index 000bb52..42fd06c 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -4,6 +4,7 @@
#include "strbuf.h"
#include "walker.h"
#include "http.h"
+#include "pkt-line.h"
#include "run-command.h"
@@ -17,24 +18,41 @@ static void init_walker(void)
walker = get_http_walker(url, remote);
}
-static struct ref *get_refs(void)
+struct discovery {
+ const char *service;
+ char *buf_alloc;
+ char *buf;
+ size_t len;
+ unsigned proto_git : 1;
+};
+static struct discovery *last_discovery;
+
+static void free_discovery(struct discovery *d)
{
- struct strbuf buffer = STRBUF_INIT;
- char *data, *start, *mid;
- char *ref_name;
+ if (d) {
+ if (d == last_discovery)
+ last_discovery = NULL;
+ free(d->buf_alloc);
+ free(d);
+ }
+}
+
+static struct discovery* discover_refs(const char *service)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct discovery *last = last_discovery;
char *refs_url;
- int i = 0;
int http_ret;
- struct ref *refs = NULL;
- struct ref *ref = NULL;
- struct ref *last_ref = NULL;
+ if (last && !strcmp(service, last->service))
+ return last;
+ free_discovery(last);
- refs_url = xmalloc(strlen(url) + 11);
- sprintf(refs_url, "%s/info/refs", url);
+ strbuf_addf(&buf, "%s/info/refs?service=%s", url, service);
+ refs_url = strbuf_detach(&buf, NULL);
init_walker();
- http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
+ http_ret = http_get_strbuf(refs_url, &buf, HTTP_NO_CACHE);
switch (http_ret) {
case HTTP_OK:
break;
@@ -46,10 +64,78 @@ static struct ref *get_refs(void)
die("HTTP request failed");
}
- data = buffer.buf;
+ last= xcalloc(1, sizeof(*last_discovery));
+ last->service = service;
+ last->buf_alloc = strbuf_detach(&buf, &last->len);
+ last->buf = last->buf_alloc;
+
+ if (5 <= last->len && last->buf[4] == '#') {
+ /* smart HTTP response; validate that the service
+ * pkt-line matches our request.
+ */
+ struct strbuf exp = STRBUF_INIT;
+
+ if (packet_get_line(&buf, &last->buf, &last->len) <= 0)
+ die("%s has invalid packet header", refs_url);
+ if (buf.len && buf.buf[buf.len - 1] == '\n')
+ strbuf_setlen(&buf, buf.len - 1);
+
+ strbuf_addf(&exp, "# service=%s", service);
+ if (strbuf_cmp(&exp, &buf))
+ die("invalid server response; got '%s'", buf.buf);
+ strbuf_release(&exp);
+
+ last->proto_git = 1;
+ }
+
+ free(refs_url);
+ strbuf_release(&buf);
+ last_discovery = last;
+ return last;
+}
+
+static int write_discovery(int fd, void *data)
+{
+ struct discovery *heads = data;
+ int err = 0;
+ if (write_in_full(fd, heads->buf, heads->len) != heads->len)
+ err = 1;
+ close(fd);
+ return err;
+}
+
+static struct ref *parse_git_refs(struct discovery *heads)
+{
+ struct ref *list = NULL;
+ struct async async;
+
+ memset(&async, 0, sizeof(async));
+ async.proc = write_discovery;
+ async.data = heads;
+
+ if (start_async(&async))
+ die("cannot start thread to parse advertised refs");
+ get_remote_heads(async.out, &list, 0, NULL, 0, NULL);
+ close(async.out);
+ if (finish_async(&async))
+ die("ref parsing thread failed");
+ return list;
+}
+
+static struct ref *parse_info_refs(struct discovery *heads)
+{
+ char *data, *start, *mid;
+ char *ref_name;
+ int i = 0;
+
+ struct ref *refs = NULL;
+ struct ref *ref = NULL;
+ struct ref *last_ref = NULL;
+
+ data = heads->buf;
start = NULL;
mid = data;
- while (i < buffer.len) {
+ while (i < heads->len) {
if (!start) {
start = &data[i];
}
@@ -73,8 +159,7 @@ static struct ref *get_refs(void)
i++;
}
- strbuf_release(&buffer);
-
+ init_walker();
ref = alloc_ref("HEAD");
if (!walker->fetch_ref(walker, ref) &&
!resolve_remote_symref(ref, refs)) {
@@ -84,11 +169,23 @@ static struct ref *get_refs(void)
free(ref);
}
- strbuf_release(&buffer);
- free(refs_url);
return refs;
}
+static struct ref *get_refs(int for_push)
+{
+ struct discovery *heads;
+
+ if (for_push)
+ heads = discover_refs("git-receive-pack");
+ else
+ heads = discover_refs("git-upload-pack");
+
+ if (heads->proto_git)
+ return parse_git_refs(heads);
+ return parse_info_refs(heads);
+}
+
static void output_refs(struct ref *refs)
{
struct ref *posn;
@@ -285,10 +382,10 @@ int main(int argc, const char **argv)
parse_fetch(&buf, 1);
} else if (!strcmp(buf.buf, "list")) {
- output_refs(get_refs());
+ output_refs(get_refs(0));
} else if (!strcmp(buf.buf, "list for-push")) {
- output_refs(get_refs());
+ output_refs(get_refs(1));
} else if (!prefixcmp(buf.buf, "push ")) {
parse_push(&buf);
--
1.6.5.52.g0ff2e
next prev parent reply other threads:[~2009-10-13 2:34 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-10-13 2:24 [RFC PATCH v2 00/16] Return of smart HTTP Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 01/16] pkt-line: Add strbuf based functions Shawn O. Pearce
2009-10-13 7:29 ` Johannes Sixt
2009-10-13 18:10 ` Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 02/16] pkt-line: Make packet_read_line easier to debug Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 03/16] fetch-pack: Use a strbuf to compose the want list Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 04/16] Move "get_ack()" back to fetch-pack Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 05/16] Add multi_ack_2 capability to fetch-pack/upload-pack Shawn O. Pearce
2009-10-13 21:35 ` Jakub Narebski
2009-10-13 21:36 ` Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 06/16] remote-curl: Refactor walker initialization Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 07/16] remote-helpers: Fetch more than one ref in a batch Shawn O. Pearce
2009-10-13 3:56 ` Daniel Barkalow
2009-10-13 18:05 ` Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 08/16] remote-helpers: Support custom transport options Shawn O. Pearce
2009-10-13 4:23 ` Daniel Barkalow
2009-10-13 18:45 ` Shawn O. Pearce
2009-10-13 20:39 ` Daniel Barkalow
2009-10-13 20:52 ` Shawn O. Pearce
2009-10-13 21:41 ` Daniel Barkalow
2009-10-13 21:51 ` Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 09/16] Move WebDAV HTTP push under remote-curl Shawn O. Pearce
2009-10-13 4:41 ` Mike Hommey
2009-10-13 18:04 ` Johannes Schindelin
2009-10-13 2:25 ` [RFC PATCH v2 10/16] Git-aware CGI to provide dumb HTTP transport Shawn O. Pearce
2009-10-13 10:56 ` Johannes Sixt
2009-10-13 2:25 ` [RFC PATCH v2 11/16] Add one shot RPC options to upload-pack, receive-pack Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 12/16] Smart fetch and push over HTTP: server side Shawn O. Pearce
2009-10-13 7:30 ` Johannes Sixt
2009-10-13 18:24 ` Shawn O. Pearce
2009-10-13 2:25 ` Shawn O. Pearce [this message]
2009-10-13 2:25 ` [RFC PATCH v2 14/16] Smart push over HTTP: client side Shawn O. Pearce
2009-10-13 11:02 ` Felipe Contreras
2009-10-13 2:25 ` [RFC PATCH v2 15/16] Smart fetch " Shawn O. Pearce
2009-10-13 2:25 ` [RFC PATCH v2 16/16] Smart HTTP fetch: gzip requests Shawn O. Pearce
2009-10-13 8:38 ` Junio C Hamano
2009-10-13 3:45 ` [RFC PATCH v2 00/16] Return of smart HTTP eduard stefan
2009-10-13 6:42 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1255400715-10508-14-git-send-email-spearce@spearce.org \
--to=spearce@spearce.org \
--cc=barkalow@iabervon.org \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).