From: Bryan Turner Date: Sat, 01 Dec 2018 02:59:49 GMT Subject: Re: Parsing a git HTTP protocol response Message-ID: In-Reply-To: On Fri, Nov 30, 2018 at 6:58 PM Bryan Turner 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 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