Beispiel #1
0
/*
 * Read from the socket and store the references in the vector
 */
static int store_refs(transport_git *t)
{
	gitno_buffer *buf = &t->buf;
	int ret = 0;

	while (1) {
		if ((ret = gitno_recv(buf)) < 0)
			return -1;
		if (ret == 0) /* Orderly shutdown, so exit */
			return 0;

		ret = git_protocol_store_refs(&t->proto, buf->data, buf->offset);
		if (ret == GIT_EBUFS) {
			gitno_consume_n(buf, buf->len);
			continue;
		}

		if (ret < 0)
			return ret;

		gitno_consume_n(buf, buf->offset);

		if (t->proto.flush) { /* No more refs */
			t->proto.flush = 0;
			return 0;
		}
	}
}
Beispiel #2
0
static int store_refs(transport_http *t)
{
	http_parser_settings settings;
	char buffer[1024];
	gitno_buffer buf;
	git_pkt *pkt;
	int ret;

	http_parser_init(&t->parser, HTTP_RESPONSE);
	t->parser.data = t;
	memset(&settings, 0x0, sizeof(http_parser_settings));
	settings.on_header_field = on_header_field;
	settings.on_header_value = on_header_value;
	settings.on_headers_complete = on_headers_complete;
	settings.on_body = on_body_store_refs;
	settings.on_message_complete = on_message_complete;

	gitno_buffer_setup((git_transport *)t, &buf, buffer, sizeof(buffer));

	while(1) {
		size_t parsed;

		if ((ret = gitno_recv(&buf)) < 0)
			return -1;

		parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset);
		/* Both should happen at the same time */
		if (parsed != buf.offset || t->error < 0)
			return t->error;

		gitno_consume_n(&buf, parsed);

		if (ret == 0 || t->transfer_finished)
			return 0;
	}

	pkt = git_vector_get(&t->refs, 0);
	if (pkt == NULL || pkt->type != GIT_PKT_COMMENT) {
		giterr_set(GITERR_NET, "Invalid HTTP response");
		return t->error = -1;
	} else {
		git_vector_remove(&t->refs, 0);
	}

	return 0;
}
Beispiel #3
0
static int parse_response(transport_http *t)
{
	int ret = 0;
	http_parser_settings settings;
	char buffer[1024];
	gitno_buffer buf;

	http_parser_init(&t->parser, HTTP_RESPONSE);
	t->parser.data = t;
	t->transfer_finished = 0;
	memset(&settings, 0x0, sizeof(http_parser_settings));
	settings.on_header_field = on_header_field;
	settings.on_header_value = on_header_value;
	settings.on_headers_complete = on_headers_complete;
	settings.on_body = on_body_parse_response;
	settings.on_message_complete = on_message_complete;

	gitno_buffer_setup((git_transport *)t, &buf, buffer, sizeof(buffer));

	while(1) {
		size_t parsed;

		if ((ret = gitno_recv(&buf)) < 0)
			return -1;

		parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset);
		/* Both should happen at the same time */
		if (parsed != buf.offset || t->error < 0)
			return t->error;

		gitno_consume_n(&buf, parsed);

		if (ret == 0 || t->transfer_finished || t->pack_ready) {
			return 0;
		}
	}

	return ret;
}
Beispiel #4
0
/*
 * As the server is probably using Transfer-Encoding: chunked, we have
 * to use the HTTP parser to download the pack instead of giving it to
 * the simple downloader. Furthermore, we're using keep-alive
 * connections, so the simple downloader would just hang.
 */
static int http_download_pack(git_transport *transport, git_repository *repo, git_off_t *bytes, git_indexer_stats *stats)
{
	transport_http *t = (transport_http *) transport;
	git_buf *oldbuf = &t->buf;
	int recvd;
	http_parser_settings settings;
	char buffer[1024];
	gitno_buffer buf;
	git_buf path = GIT_BUF_INIT;
	git_indexer_stream *idx = NULL;
	download_pack_cbdata data;

	gitno_buffer_setup(transport, &buf, buffer, sizeof(buffer));

	if (memcmp(oldbuf->ptr, "PACK", strlen("PACK"))) {
		giterr_set(GITERR_NET, "The pack doesn't start with a pack signature");
		return -1;
	}

	if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0)
		return -1;

	if (git_indexer_stream_new(&idx, git_buf_cstr(&path)) < 0)
		return -1;

	/*
	 * This is part of the previous response, so we don't want to
	 * re-init the parser, just set these two callbacks.
	 */
	memset(stats, 0, sizeof(git_indexer_stats));
	data.stats = stats;
	data.idx = idx;
	data.transport = t;
	t->parser.data = &data;
	t->transfer_finished = 0;
	memset(&settings, 0x0, sizeof(settings));
	settings.on_message_complete = on_message_complete_download_pack;
	settings.on_body = on_body_download_pack;
	*bytes = git_buf_len(oldbuf);

	if (git_indexer_stream_add(idx, git_buf_cstr(oldbuf), git_buf_len(oldbuf), stats) < 0)
		goto on_error;

	gitno_buffer_setup(transport, &buf, buffer, sizeof(buffer));

	do {
		size_t parsed;

		if ((recvd = gitno_recv(&buf)) < 0)
			goto on_error;

		parsed = http_parser_execute(&t->parser, &settings, buf.data, buf.offset);
		if (parsed != buf.offset || t->error < 0)
			goto on_error;

		*bytes += recvd;
		gitno_consume_n(&buf, parsed);
	} while (recvd > 0 && !t->transfer_finished);

	if (git_indexer_stream_finalize(idx, stats) < 0)
		goto on_error;

	git_indexer_stream_free(idx);
	return 0;

on_error:
	git_indexer_stream_free(idx);
	git_buf_free(&path);
	return -1;
}
Beispiel #5
0
/* Receiving data from a socket and storing it is pretty much the same for git and HTTP */
int git_fetch__download_pack(
	char **out,
	const char *buffered,
	size_t buffered_size,
	GIT_SOCKET fd,
	git_repository *repo)
{
	git_filebuf file = GIT_FILEBUF_INIT;
	int error;
	char buff[1024];
	git_buf path = GIT_BUF_INIT;
	static const char suff[] = "/objects/pack/pack-received";
	gitno_buffer buf;

	gitno_buffer_setup(&buf, buff, sizeof(buff), fd);

	if (memcmp(buffered, "PACK", strlen("PACK"))) {
		return git__throw(GIT_ERROR, "The pack doesn't start with the signature");
	}

	error = git_buf_joinpath(&path, repo->path_repository, suff);
	if (error < GIT_SUCCESS)
		goto cleanup;

	error = git_filebuf_open(&file, path.ptr, GIT_FILEBUF_TEMPORARY);
	if (error < GIT_SUCCESS)
		goto cleanup;

	/* Part of the packfile has been received, don't loose it */
	error = git_filebuf_write(&file, buffered, buffered_size);
	if (error < GIT_SUCCESS)
		goto cleanup;

	while (1) {
		error = git_filebuf_write(&file, buf.data, buf.offset);
		if (error < GIT_SUCCESS)
			goto cleanup;

		gitno_consume_n(&buf, buf.offset);
		error = gitno_recv(&buf);
		if (error < GIT_SUCCESS)
			goto cleanup;
		if (error == 0) /* Orderly shutdown */
			break;
	}

	*out = git__strdup(file.path_lock);
	if (*out == NULL) {
		error = GIT_ENOMEM;
		goto cleanup;
	}

	/* A bit dodgy, but we need to keep the pack at the temporary path */
	error = git_filebuf_commit_at(&file, file.path_lock, GIT_PACK_FILE_MODE);
cleanup:
	if (error < GIT_SUCCESS)
		git_filebuf_cleanup(&file);
    git_buf_free(&path);

	return error;
}