git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Bryan Turner <bturner@atlassian.com>
To: khanzf@gmail.com
Cc: Git Users <git@vger.kernel.org>
Subject: Re: Parsing a git HTTP protocol response
Date: Fri, 30 Nov 2018 18:59:49 -0800	[thread overview]
Message-ID: <CAGyf7-HvPTPS-N8vtEngkhw-J+Egfq=MzxL8swhD2h+ck87V6A@mail.gmail.com> (raw)
In-Reply-To: <CAGyf7-Eq6tQQocjXFzngX=vo3FWba=tvmAqGybcLxLXn6ZZkpA@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 219 bytes --]

On Fri, Nov 30, 2018 at 6:58 PM Bryan Turner <bturner@atlassian.com> wrote:
>
> Here's a (very ugly) patch I threw together on top of your code:
...snip

Gmail butchered my patch, so here it is as an attachment.

Bryan

[-- Attachment #2: short-size-reads.patch --]
[-- Type: application/octet-stream, Size: 5234 bytes --]

diff --git a/main.c b/main.c
index 956362b..8873fd5 100644
--- a/main.c
+++ b/main.c
@@ -71,7 +71,7 @@ int main(int argc, char *argv[]) {
 		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
 		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)content_length);
 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &parseread);
-		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, pack_protocol_line);
+		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &pack_protocol_line);
 
 		res = curl_easy_perform(curl);
 		if (curl != CURLE_OK)
diff --git a/post.c b/post.c
index cfffd5c..4f8512c 100644
--- a/post.c
+++ b/post.c
@@ -36,89 +36,83 @@ size_t pack_protocol_line(void *buffer, size_t size, size_t nmemb, void *userp)
 {
 	unsigned char *reply = buffer;
 	struct parseread *parseread = userp;
-	int offset = 0;
+	int offset = 0, pending = 0, remaining = 0;
 	char tmp[5];
-	int check;
-
-	int pool = size * nmemb;
 
 	printf("\n\n========Start=========\n");
-	printf("Current stats: Current state: %d Received: %ld\n", parseread->state, size*nmemb);
+	printf("Current stats: Current state: %d Received: %ld\n", parseread->state, nmemb);
 
-	while(offset + 1 < size + nmemb) {
+	while (offset + 3 < nmemb) {
 		if (parseread->state == STATE_NEWLINE) { 
 			printf("== New Object\n");
 			bzero(tmp, 5);
-			memcpy(tmp, buffer+offset, 4); tmp[4] = '\0';
-			check = sscanf(tmp, "%04x", &parseread->osize);
 
-			if (parseread->osize == 0) {
-				printf("Only happens if reached terminating 0000\n");
+			if (parseread->bsize > 0) {
+				// If there are buffered size bytes, consume them
+				memcpy(tmp, parseread->buffer, parseread->bsize);
+				memcpy(tmp + parseread->bsize, buffer + offset, 4 - parseread->bsize);
+				offset += 4 - parseread->bsize;
+				parseread->bsize = 0;
+			} else {
+				memcpy(tmp, buffer+offset, 4);
 				offset += 4;
-				break;
 			}
+			tmp[4] = '\0';
 
-			if (check == 0) {
-				printf("Error, unable to parse object size\n");
-				printf("Size bytes: %02x %02x %02x %02x\n",
-					reply[offset+0],
-					reply[offset+1],
-					reply[offset+2],
-					reply[offset+3]);
-				printf("Data: %02x %02x %02x %02x\n",
-					reply[offset+4],
-					reply[offset+5],
-					reply[offset+6],
-					reply[offset+7]);
-				exit(-1);
-			}
-			else {
-				printf("No Error, object is %d bytes\n", parseread->osize);
-				printf("Size bytes: %02x %02x %02x %02x\n",
-					reply[offset+0],
-					reply[offset+1],
-					reply[offset+2],
-					reply[offset+3]);
-				printf("%02x %02x %02x %02x\n",
-					reply[offset+4],
-					reply[offset+5],
-					reply[offset+6],
-					reply[offset+7]);
+			printf("Size bytes: %02x %02x %02x %02x\n", tmp[0], tmp[1], tmp[2], tmp[3]);
+			parseread->osize = (int) strtol(tmp, NULL, 16);
+			printf("Parsed size: %d\n", parseread->osize);
+
+			if (parseread->osize == 0) {
+				printf("Only happens if reached terminating 0000\n");
+				break;
 			}
 
-			printf("Size: %d\n", parseread->osize);
-			parseread->psize = 0;
+			parseread->psize = 4;
 
 			// This classifies the object
-			if ( strncmp(reply+offset+4, "NAK\n", 4)==0)
+			if ( strncmp(reply+offset, "NAK\n", 4)==0)
 				parseread->state = STATE_NAK;
-			else if (reply[offset+4] == 0x02)
+			else if (reply[offset] == 0x02)
 				parseread->state = STATE_REMOTE;
 			else
 				parseread->state = STATE_UNKNOWN;
 		}
 
-		if ( (pool - offset) > (parseread->osize - parseread->psize) ) {
-			printf("We have enough bytes, moving forward\n");
+		pending = parseread->osize - parseread->psize;
+		remaining = nmemb - offset;
+
+		if ( remaining > pending ) {
+			printf("Read complete; %d more bytes in buffer\n", remaining - pending);
 			process_objects(reply+offset, parseread);
 			offset += (parseread->osize - parseread->psize); 
 			parseread->state = STATE_NEWLINE;
 		}
-		else if ( (pool - offset) ==(parseread->osize - parseread->psize) ) {
-			printf("They are the same length\n");
+		else if ( remaining == pending ) {
+			printf("Read complete; buffer exhausted\n");
 			process_objects(reply+offset, parseread);
 			offset += (parseread->osize - parseread->psize);
 			parseread->state = STATE_NEWLINE;
 		}
-		else if ( (pool - offset) < (parseread->osize - parseread->psize)) {
-			printf("We do not have enough bytes\n");
+		else if ( remaining < pending ) {
+			printf("Read complete; still missing %d bytes (%d read of %d)\n",
+					pending - remaining, parseread->psize + remaining, parseread->osize);
 			process_objects(reply+offset, parseread);
-			parseread->psize += (pool - offset);
-			offset = pool;
+			parseread->psize += remaining;
+			offset = nmemb;
 		}
 	}
 
 	printf("Offset: %d\n", offset);
+	if (offset < nmemb) {
+		// We don't have enough bytes to read the next size, so buffer it
+		printf("Short read; %d bytes left", nmemb - offset);
+		bzero(parseread->buffer, 4);
+		parseread->bsize = nmemb - offset;
+		memcpy(parseread->buffer, buffer+offset, parseread->bsize);
+
+		offset = nmemb;
+	}
 
 	return offset;
 }
diff --git a/post.h b/post.h
index a229342..01a2669 100644
--- a/post.h
+++ b/post.h
@@ -5,6 +5,8 @@ struct parseread {
 	int state; // current state
 	int osize; // object size
 	int psize; // processed size
+	char buffer[4];
+	int bsize;
 };
 
 #define STATE_NEWLINE		0

      reply	other threads:[~2018-12-01  3:00 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-01  1:05 Parsing a git HTTP protocol response Farhan Khan
2018-12-01  2:58 ` Bryan Turner
2018-12-01  2:59   ` Bryan Turner [this message]

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

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAGyf7-HvPTPS-N8vtEngkhw-J+Egfq=MzxL8swhD2h+ck87V6A@mail.gmail.com' \
    --to=bturner@atlassian.com \
    --cc=git@vger.kernel.org \
    --cc=khanzf@gmail.com \
    /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.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).