diff options
Diffstat (limited to 'remote-curl.c')
-rw-r--r-- | remote-curl.c | 110 |
1 files changed, 66 insertions, 44 deletions
diff --git a/remote-curl.c b/remote-curl.c index 52c2d96ce6..f404faf0f4 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -11,6 +11,7 @@ #include "argv-array.h" #include "credential.h" #include "sha1-array.h" +#include "send-pack.h" static struct remote *remote; /* always ends with a trailing slash */ @@ -25,7 +26,9 @@ struct options { update_shallow : 1, followtags : 1, dry_run : 1, - thin : 1; + thin : 1, + /* One of the SEND_PACK_PUSH_CERT_* constants. */ + push_cert : 2; }; static struct options options; static struct string_list cas_options = STRING_LIST_INIT_DUP; @@ -106,6 +109,16 @@ static int set_option(const char *name, const char *value) else return -1; return 0; + } else if (!strcmp(name, "pushcert")) { + if (!strcmp(value, "true")) + options.push_cert = SEND_PACK_PUSH_CERT_ALWAYS; + else if (!strcmp(value, "false")) + options.push_cert = SEND_PACK_PUSH_CERT_NEVER; + else if (!strcmp(value, "if-asked")) + options.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED; + else + return -1; + return 0; } else { return 1 /* unsupported */; } @@ -155,11 +168,8 @@ static struct ref *parse_info_refs(struct discovery *heads) url.buf); data[i] = 0; ref_name = mid + 1; - ref = xmalloc(sizeof(struct ref) + - strlen(ref_name) + 1); - memset(ref, 0, sizeof(struct ref)); - strcpy(ref->name, ref_name); - get_sha1_hex(start, ref->old_sha1); + ref = alloc_ref(ref_name); + get_oid_hex(start, &ref->old_oid); if (!refs) refs = ref; if (last_ref) @@ -194,19 +204,19 @@ static void free_discovery(struct discovery *d) } } -static int show_http_message(struct strbuf *type, struct strbuf *msg) +static int show_http_message(struct strbuf *type, struct strbuf *charset, + struct strbuf *msg) { const char *p, *eol; /* * We only show text/plain parts, as other types are likely * to be ugly to look at on the user's terminal. - * - * TODO should handle "; charset=XXX", and re-encode into - * logoutputencoding */ - if (strcasecmp(type->buf, "text/plain")) + if (strcmp(type->buf, "text/plain")) return -1; + if (charset->len) + strbuf_reencode(msg, charset->buf, get_log_output_encoding()); strbuf_trim(msg); if (!msg->len) @@ -221,10 +231,11 @@ static int show_http_message(struct strbuf *type, struct strbuf *msg) return 0; } -static struct discovery* discover_refs(const char *service, int for_push) +static struct discovery *discover_refs(const char *service, int for_push) { struct strbuf exp = STRBUF_INIT; struct strbuf type = STRBUF_INIT; + struct strbuf charset = STRBUF_INIT; struct strbuf buffer = STRBUF_INIT; struct strbuf refs_url = STRBUF_INIT; struct strbuf effective_url = STRBUF_INIT; @@ -249,6 +260,7 @@ static struct discovery* discover_refs(const char *service, int for_push) memset(&options, 0, sizeof(options)); options.content_type = &type; + options.charset = &charset; options.effective_url = &effective_url; options.base_url = &url; options.no_cache = 1; @@ -259,13 +271,13 @@ static struct discovery* discover_refs(const char *service, int for_push) case HTTP_OK: break; case HTTP_MISSING_TARGET: - show_http_message(&type, &buffer); + show_http_message(&type, &charset, &buffer); die("repository '%s' not found", url.buf); case HTTP_NOAUTH: - show_http_message(&type, &buffer); + show_http_message(&type, &charset, &buffer); die("Authentication failed for '%s'", url.buf); default: - show_http_message(&type, &buffer); + show_http_message(&type, &charset, &buffer); die("unable to access '%s': %s", url.buf, curl_errorstr); } @@ -310,6 +322,7 @@ static struct discovery* discover_refs(const char *service, int for_push) strbuf_release(&refs_url); strbuf_release(&exp); strbuf_release(&type); + strbuf_release(&charset); strbuf_release(&effective_url); strbuf_release(&buffer); last_discovery = last; @@ -335,7 +348,7 @@ static void output_refs(struct ref *refs) if (posn->symref) printf("@%s %s\n", posn->symref, posn->name); else - printf("%s %s\n", sha1_to_hex(posn->old_sha1), posn->name); + printf("%s %s\n", oid_to_hex(&posn->old_oid), posn->name); } printf("\n"); fflush(stdout); @@ -396,7 +409,7 @@ static curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp) rpc->pos = 0; return CURLIOE_OK; } - fprintf(stderr, "Unable to rewind rpc post data - try increasing http.postBuffer\n"); + error("unable to rewind rpc post data - try increasing http.postBuffer"); return CURLIOE_FAILRESTART; default: @@ -555,7 +568,6 @@ retry: git_zstream stream; int ret; - memset(&stream, 0, sizeof(stream)); git_deflate_init_gzip(&stream, Z_BEST_COMPRESSION); gzip_size = git_deflate_bound(&stream, rpc->len); gzip_body = xmalloc(gzip_size); @@ -620,10 +632,9 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads) const char *svc = rpc->service_name; struct strbuf buf = STRBUF_INIT; struct strbuf *preamble = rpc->stdin_preamble; - struct child_process client; + struct child_process client = CHILD_PROCESS_INIT; int err = 0; - memset(&client, 0, sizeof(client)); client.in = -1; client.out = -1; client.git_cmd = 1; @@ -691,7 +702,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch) if (options.depth) die("dumb http transport does not support --depth"); for (i = 0; i < nr_heads; i++) - targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1)); + targets[i] = xstrdup(oid_to_hex(&to_fetch[i]->old_oid)); walker = get_http_walker(url.buf); walker->get_all = 1; @@ -706,7 +717,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch) free(targets[i]); free(targets); - return ret ? error("Fetch failed.") : 0; + return ret ? error("fetch failed.") : 0; } static int fetch_git(struct discovery *heads, @@ -749,10 +760,10 @@ static int fetch_git(struct discovery *heads, for (i = 0; i < nr_heads; i++) { struct ref *ref = to_fetch[i]; - if (!ref->name || !*ref->name) + if (!*ref->name) die("cannot fetch by sha1 over smart http"); packet_buf_write(&preamble, "%s %s\n", - sha1_to_hex(ref->old_sha1), ref->name); + oid_to_hex(&ref->old_oid), ref->name); } packet_buf_flush(&preamble); @@ -788,23 +799,23 @@ static void parse_fetch(struct strbuf *buf) int alloc_heads = 0, nr_heads = 0; do { - if (starts_with(buf->buf, "fetch ")) { - char *p = buf->buf + strlen("fetch "); - char *name; + const char *p; + if (skip_prefix(buf->buf, "fetch ", &p)) { + const char *name; struct ref *ref; - unsigned char old_sha1[20]; + struct object_id old_oid; - if (strlen(p) < 40 || get_sha1_hex(p, old_sha1)) + if (get_oid_hex(p, &old_oid)) die("protocol error: expected sha/ref, got %s'", p); - if (p[40] == ' ') - name = p + 41; - else if (!p[40]) + if (p[GIT_SHA1_HEXSZ] == ' ') + name = p + GIT_SHA1_HEXSZ + 1; + else if (!p[GIT_SHA1_HEXSZ]) name = ""; else die("protocol error: expected sha/ref, got %s'", p); ref = alloc_ref(name); - hashcpy(ref->old_sha1, old_sha1); + oidcpy(&ref->old_oid, &old_oid); *list = ref; list = &ref->next; @@ -860,6 +871,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) int i, err; struct argv_array args; struct string_list_item *cas_option; + struct strbuf preamble = STRBUF_INIT; argv_array_init(&args); argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status", @@ -869,6 +881,10 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) argv_array_push(&args, "--thin"); if (options.dry_run) argv_array_push(&args, "--dry-run"); + if (options.push_cert == SEND_PACK_PUSH_CERT_ALWAYS) + argv_array_push(&args, "--signed=yes"); + else if (options.push_cert == SEND_PACK_PUSH_CERT_IF_ASKED) + argv_array_push(&args, "--signed=if-asked"); if (options.verbosity == 0) argv_array_push(&args, "--quiet"); else if (options.verbosity > 1) @@ -877,17 +893,22 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) for_each_string_list_item(cas_option, &cas_options) argv_array_push(&args, cas_option->string); argv_array_push(&args, url.buf); + + argv_array_push(&args, "--stdin"); for (i = 0; i < nr_spec; i++) - argv_array_push(&args, specs[i]); + packet_buf_write(&preamble, "%s\n", specs[i]); + packet_buf_flush(&preamble); memset(&rpc, 0, sizeof(rpc)); rpc.service_name = "git-receive-pack", rpc.argv = args.argv; + rpc.stdin_preamble = &preamble; err = rpc_service(&rpc, heads); if (rpc.result.len) write_or_die(1, rpc.result.buf, rpc.result.len); strbuf_release(&rpc.result); + strbuf_release(&preamble); argv_array_clear(&args); return err; } @@ -943,10 +964,12 @@ int main(int argc, const char **argv) struct strbuf buf = STRBUF_INIT; int nongit; + git_setup_gettext(); + git_extract_argv0_path(argv[0]); setup_git_directory_gently(&nongit); if (argc < 2) { - fprintf(stderr, "Remote needed\n"); + error("remote-curl: usage: git remote-curl <remote> [<url>]"); return 1; } @@ -965,18 +988,18 @@ int main(int argc, const char **argv) http_init(remote, url.buf, 0); do { + const char *arg; + if (strbuf_getline(&buf, stdin, '\n') == EOF) { if (ferror(stdin)) - fprintf(stderr, "Error reading command stream\n"); - else - fprintf(stderr, "Unexpected end of command stream\n"); + error("remote-curl: error reading command stream from git"); return 1; } if (buf.len == 0) break; if (starts_with(buf.buf, "fetch ")) { if (nongit) - die("Fetch attempted without a local repo"); + die("remote-curl: fetch attempted without a local repo"); parse_fetch(&buf); } else if (!strcmp(buf.buf, "list") || starts_with(buf.buf, "list ")) { @@ -986,9 +1009,8 @@ int main(int argc, const char **argv) } else if (starts_with(buf.buf, "push ")) { parse_push(&buf); - } else if (starts_with(buf.buf, "option ")) { - char *name = buf.buf + strlen("option "); - char *value = strchr(name, ' '); + } else if (skip_prefix(buf.buf, "option ", &arg)) { + char *value = strchr(arg, ' '); int result; if (value) @@ -996,7 +1018,7 @@ int main(int argc, const char **argv) else value = "true"; - result = set_option(name, value); + result = set_option(arg, value); if (!result) printf("ok\n"); else if (result < 0) @@ -1013,7 +1035,7 @@ int main(int argc, const char **argv) printf("\n"); fflush(stdout); } else { - fprintf(stderr, "Unknown command '%s'\n", buf.buf); + error("remote-curl: unknown command '%s' from git", buf.buf); return 1; } strbuf_reset(&buf); |