Skip to content

Commit 5424bc5

Browse files
rctaygitster
authored andcommitted
http*: add helper methods for fetching objects (loose)
The code handling the fetching of loose objects in http-push.c and http-walker.c have been refactored into new methods and a new struct (object_http_request) in http.c. They are not meant to be invoked elsewhere. The new methods in http.c are - new_http_object_request - process_http_object_request - finish_http_object_request - abort_http_object_request - release_http_object_request and the new struct is http_object_request. RANGER_HEADER_SIZE and no_pragma_header is no longer made available outside of http.c, since after the above changes, there are no other instances of usage outside of http.c. Remove members of the transfer_request struct in http-push.c and http-walker.c, including filename, real_sha1 and zret, as they are used no longer used. Move the methods append_remote_object_url() and get_remote_object_url() from http-push.c to http.c. Additionally, get_remote_object_url() is no longer defined only when USE_CURL_MULTI is defined, since non-USE_CURL_MULTI code in http.c uses it (namely, in new_http_object_request()). Refactor code from http-push.c::start_fetch_loose() and http-walker.c::start_object_fetch_request() that deals with the details of coming up with the filename to store the retrieved object, resuming a previously aborted request, and making a new curl request, into a new function, new_http_object_request(). Refactor code from http-walker.c::process_object_request() into the function, process_http_object_request(). Refactor code from http-push.c::finish_request() and http-walker.c::finish_object_request() into a new function, finish_http_object_request(). It returns the result of the move_temp_to_file() invocation. Add a function, release_http_object_request(), which cleans up object request data. http-push.c and http-walker.c invoke this function separately; http-push.c::release_request() and http-walker.c::release_object_request() do not invoke this function. Add a function, abort_http_object_request(), which unlink()s the object file and invokes release_http_object_request(). Update http-walker.c::abort_object_request() to use this. Signed-off-by: Tay Ray Chuan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2264dfa commit 5424bc5

File tree

4 files changed

+336
-431
lines changed

4 files changed

+336
-431
lines changed

http-push.c

Lines changed: 15 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,10 @@ struct transfer_request
115115
struct remote_lock *lock;
116116
struct curl_slist *headers;
117117
struct buffer buffer;
118-
char filename[PATH_MAX];
119-
char tmpfile[PATH_MAX];
120-
int local_fileno;
121118
enum transfer_state state;
122119
CURLcode curl_result;
123120
char errorstr[CURL_ERROR_SIZE];
124121
long http_code;
125-
unsigned char real_sha1[20];
126-
git_SHA_CTX c;
127-
z_stream stream;
128-
int zret;
129-
int rename;
130122
void *userData;
131123
struct active_request_slot *slot;
132124
struct transfer_request *next;
@@ -232,15 +224,6 @@ static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum d
232224
return dav_headers;
233225
}
234226

235-
static void append_remote_object_url(struct strbuf *buf, const char *url,
236-
const char *hex,
237-
int only_two_digit_prefix)
238-
{
239-
strbuf_addf(buf, "%sobjects/%.*s/", url, 2, hex);
240-
if (!only_two_digit_prefix)
241-
strbuf_addf(buf, "%s", hex+2);
242-
}
243-
244227
static void finish_request(struct transfer_request *request);
245228
static void release_request(struct transfer_request *request);
246229

@@ -254,169 +237,29 @@ static void process_response(void *callback_data)
254237

255238
#ifdef USE_CURL_MULTI
256239

257-
static char *get_remote_object_url(const char *url, const char *hex,
258-
int only_two_digit_prefix)
259-
{
260-
struct strbuf buf = STRBUF_INIT;
261-
append_remote_object_url(&buf, url, hex, only_two_digit_prefix);
262-
return strbuf_detach(&buf, NULL);
263-
}
264-
265-
static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
266-
void *data)
267-
{
268-
unsigned char expn[4096];
269-
size_t size = eltsize * nmemb;
270-
int posn = 0;
271-
struct transfer_request *request = (struct transfer_request *)data;
272-
do {
273-
ssize_t retval = xwrite(request->local_fileno,
274-
(char *) ptr + posn, size - posn);
275-
if (retval < 0)
276-
return posn;
277-
posn += retval;
278-
} while (posn < size);
279-
280-
request->stream.avail_in = size;
281-
request->stream.next_in = ptr;
282-
do {
283-
request->stream.next_out = expn;
284-
request->stream.avail_out = sizeof(expn);
285-
request->zret = git_inflate(&request->stream, Z_SYNC_FLUSH);
286-
git_SHA1_Update(&request->c, expn,
287-
sizeof(expn) - request->stream.avail_out);
288-
} while (request->stream.avail_in && request->zret == Z_OK);
289-
data_received++;
290-
return size;
291-
}
292-
293240
static void start_fetch_loose(struct transfer_request *request)
294241
{
295-
char *hex = sha1_to_hex(request->obj->sha1);
296-
char *filename;
297-
char prevfile[PATH_MAX];
298-
char *url;
299-
int prevlocal;
300-
unsigned char prev_buf[PREV_BUF_SIZE];
301-
ssize_t prev_read = 0;
302-
long prev_posn = 0;
303-
char range[RANGE_HEADER_SIZE];
304-
struct curl_slist *range_header = NULL;
305242
struct active_request_slot *slot;
243+
struct http_object_request *obj_req;
306244

307-
filename = sha1_file_name(request->obj->sha1);
308-
snprintf(request->filename, sizeof(request->filename), "%s", filename);
309-
snprintf(request->tmpfile, sizeof(request->tmpfile),
310-
"%s.temp", filename);
311-
312-
snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename);
313-
unlink_or_warn(prevfile);
314-
rename(request->tmpfile, prevfile);
315-
unlink_or_warn(request->tmpfile);
316-
317-
if (request->local_fileno != -1)
318-
error("fd leakage in start: %d", request->local_fileno);
319-
request->local_fileno = open(request->tmpfile,
320-
O_WRONLY | O_CREAT | O_EXCL, 0666);
321-
/*
322-
* This could have failed due to the "lazy directory creation";
323-
* try to mkdir the last path component.
324-
*/
325-
if (request->local_fileno < 0 && errno == ENOENT) {
326-
char *dir = strrchr(request->tmpfile, '/');
327-
if (dir) {
328-
*dir = 0;
329-
mkdir(request->tmpfile, 0777);
330-
*dir = '/';
331-
}
332-
request->local_fileno = open(request->tmpfile,
333-
O_WRONLY | O_CREAT | O_EXCL, 0666);
334-
}
335-
336-
if (request->local_fileno < 0) {
245+
obj_req = new_http_object_request(repo->url, request->obj->sha1);
246+
if (obj_req == NULL) {
337247
request->state = ABORTED;
338-
error("Couldn't create temporary file %s for %s: %s",
339-
request->tmpfile, request->filename, strerror(errno));
340248
return;
341249
}
342250

343-
memset(&request->stream, 0, sizeof(request->stream));
344-
345-
git_inflate_init(&request->stream);
346-
347-
git_SHA1_Init(&request->c);
348-
349-
url = get_remote_object_url(repo->url, hex, 0);
350-
request->url = xstrdup(url);
351-
352-
/*
353-
* If a previous temp file is present, process what was already
354-
* fetched.
355-
*/
356-
prevlocal = open(prevfile, O_RDONLY);
357-
if (prevlocal != -1) {
358-
do {
359-
prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
360-
if (prev_read>0) {
361-
if (fwrite_sha1_file(prev_buf,
362-
1,
363-
prev_read,
364-
request) == prev_read)
365-
prev_posn += prev_read;
366-
else
367-
prev_read = -1;
368-
}
369-
} while (prev_read > 0);
370-
close(prevlocal);
371-
}
372-
unlink_or_warn(prevfile);
373-
374-
/*
375-
* Reset inflate/SHA1 if there was an error reading the previous temp
376-
* file; also rewind to the beginning of the local file.
377-
*/
378-
if (prev_read == -1) {
379-
memset(&request->stream, 0, sizeof(request->stream));
380-
git_inflate_init(&request->stream);
381-
git_SHA1_Init(&request->c);
382-
if (prev_posn>0) {
383-
prev_posn = 0;
384-
lseek(request->local_fileno, 0, SEEK_SET);
385-
ftruncate(request->local_fileno, 0);
386-
}
387-
}
388-
389-
slot = get_active_slot();
251+
slot = obj_req->slot;
390252
slot->callback_func = process_response;
391253
slot->callback_data = request;
392254
request->slot = slot;
393-
394-
curl_easy_setopt(slot->curl, CURLOPT_FILE, request);
395-
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
396-
curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
397-
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
398-
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
399-
400-
/*
401-
* If we have successfully processed data from a previous fetch
402-
* attempt, only fetch the data we don't already have.
403-
*/
404-
if (prev_posn>0) {
405-
if (push_verbosely)
406-
fprintf(stderr,
407-
"Resuming fetch of object %s at byte %ld\n",
408-
hex, prev_posn);
409-
sprintf(range, "Range: bytes=%ld-", prev_posn);
410-
range_header = curl_slist_append(range_header, range);
411-
curl_easy_setopt(slot->curl,
412-
CURLOPT_HTTPHEADER, range_header);
413-
}
255+
request->userData = obj_req;
414256

415257
/* Try to get the request started, abort the request on error */
416258
request->state = RUN_FETCH_LOOSE;
417259
if (!start_active_slot(slot)) {
418260
fprintf(stderr, "Unable to start GET request\n");
419261
repo->can_update_info_refs = 0;
262+
release_http_object_request(obj_req);
420263
release_request(request);
421264
}
422265
}
@@ -675,16 +518,14 @@ static void release_request(struct transfer_request *request)
675518
entry->next = entry->next->next;
676519
}
677520

678-
if (request->local_fileno != -1)
679-
close(request->local_fileno);
680521
free(request->url);
681522
free(request);
682523
}
683524

684525
static void finish_request(struct transfer_request *request)
685526
{
686-
struct stat st;
687527
struct http_pack_request *preq;
528+
struct http_object_request *obj_req;
688529

689530
request->curl_result = request->slot->curl_result;
690531
request->http_code = request->slot->http_code;
@@ -739,39 +580,17 @@ static void finish_request(struct transfer_request *request)
739580
aborted = 1;
740581
}
741582
} else if (request->state == RUN_FETCH_LOOSE) {
742-
close(request->local_fileno);
743-
request->local_fileno = -1;
744-
745-
if (request->curl_result != CURLE_OK &&
746-
request->http_code != 416) {
747-
if (stat(request->tmpfile, &st) == 0) {
748-
if (st.st_size == 0)
749-
unlink_or_warn(request->tmpfile);
750-
}
751-
} else {
752-
if (request->http_code == 416)
753-
warning("requested range invalid; we may already have all the data.");
754-
755-
git_inflate_end(&request->stream);
756-
git_SHA1_Final(request->real_sha1, &request->c);
757-
if (request->zret != Z_STREAM_END) {
758-
unlink_or_warn(request->tmpfile);
759-
} else if (hashcmp(request->obj->sha1, request->real_sha1)) {
760-
unlink_or_warn(request->tmpfile);
761-
} else {
762-
request->rename =
763-
move_temp_to_file(
764-
request->tmpfile,
765-
request->filename);
766-
if (request->rename == 0)
767-
request->obj->flags |= (LOCAL | REMOTE);
768-
}
769-
}
583+
obj_req = (struct http_object_request *)request->userData;
584+
585+
if (finish_http_object_request(obj_req) == 0)
586+
if (obj_req->rename == 0)
587+
request->obj->flags |= (LOCAL | REMOTE);
770588

771589
/* Try fetching packed if necessary */
772-
if (request->obj->flags & LOCAL)
590+
if (request->obj->flags & LOCAL) {
591+
release_http_object_request(obj_req);
773592
release_request(request);
774-
else
593+
} else
775594
start_fetch_packed(request);
776595

777596
} else if (request->state == RUN_FETCH_PACKED) {
@@ -843,7 +662,6 @@ static void add_fetch_request(struct object *obj)
843662
request->url = NULL;
844663
request->lock = NULL;
845664
request->headers = NULL;
846-
request->local_fileno = -1;
847665
request->state = NEED_FETCH;
848666
request->next = request_queue_head;
849667
request_queue_head = request;
@@ -882,7 +700,6 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)
882700
request->url = NULL;
883701
request->lock = lock;
884702
request->headers = NULL;
885-
request->local_fileno = -1;
886703
request->state = NEED_PUSH;
887704
request->next = request_queue_head;
888705
request_queue_head = request;

0 commit comments

Comments
 (0)