From f67e5f11a81b31e79e201e39c7d4f5d8d9b24e25 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 10 Sep 2012 20:50:51 -0400 Subject: [PATCH] common code, http chunked responses. --- common.c | 72 +++++++++++++++++++++++++++-- gopher.c | 14 ++++-- http.c | 125 ++++++++++++++++++++++++++------------------------- prototypes.h | 9 +++- 4 files changed, 151 insertions(+), 69 deletions(-) diff --git a/common.c b/common.c index 03d9b31..9e6d11e 100644 --- a/common.c +++ b/common.c @@ -12,19 +12,26 @@ #include -#include "connection.h" +#include "prototypes.h" + #include "connection.h" -int read_binary(Word ipid, FILE *file) +int read_binary(Word ipid, FILE *file, ReadBlock *dcb) { Word rv = 0; + + if (dcb) dcb->transferCount = 0; + + IncBusy(); TCPIPPoll(); + DecBusy(); for(;;) { static char buffer[512]; rrBuff rb; Word count; + Word tcount; IncBusy(); rv = TCPIPReadTCP(ipid, 0, (Ref)buffer, 512, &rb); @@ -40,12 +47,69 @@ int read_binary(Word ipid, FILE *file) continue; } - fwrite(buffer, 1, count, file); + tcount = fwrite(buffer, 1, count, file); + if (dcb) dcb->transferCount += tcount; + + if (tcount != count) return -1; + } - return rv; + return 0; } +// ReadTCP will only return if the entire request is fulfilled or the connection closes, +// so it could just do that. For a large request, this is probably nicer. +int read_binary_size(Word ipid, FILE *file, ReadBlock *dcb) +{ + Word rv = 0; + LongWord size; + if (!dcb) return -1; + + dcb->transferCount = 0; + size = dcb->requestCount; + if (!size) return 0; + + IncBusy(); + TCPIPPoll(); + DecBusy(); + + for(;;) + { + static char buffer[512]; + rrBuff rb; + Word count; + Word tcount; + + count = 512; + if (count > size) count = size; + + IncBusy(); + rv = TCPIPReadTCP(ipid, 0, (Ref)buffer, count, &rb); + DecBusy(); + + count = rb.rrBuffCount; + if (!count) + { + if (rv) break; + IncBusy(); + TCPIPPoll(); + DecBusy(); + continue; + } + + tcount = fwrite(buffer, 1, count, file); + + dcb->transferCount += tcount; + size -= tcount; + + if (tcount != count) return -1; + + if (!size) return 0; + } + + return 0; + +} int ConnectLoop(char *host, Word port, Connection *connection) diff --git a/gopher.c b/gopher.c index 7e648b1..9be62d9 100644 --- a/gopher.c +++ b/gopher.c @@ -24,6 +24,16 @@ extern int setfiletype(const char *filename); +static int gopher_binary(Word ipid, FILE *file) +{ + ReadBlock dcb; + int ok; + + ok = read_binary(ipid, file, &dcb); + + return ok; +} + /* * connect gopher.floodgap.com:70 * send path @@ -32,8 +42,6 @@ extern int setfiletype(const char *filename); * bin -- ends when connection is closed. */ - - static int gopher_text(Word ipid, FILE *file) { // text \r\n @@ -397,7 +405,7 @@ int do_gopher(const char *url, URLComponents *components) case '5': case '9': fsetbinary(file); - ok = read_binary(connection.ipid, file); + ok = gopher_binary(connection.ipid, file); break; default: ok = gopher_text(connection.ipid, file); diff --git a/http.c b/http.c index 97244ef..f9ae284 100644 --- a/http.c +++ b/http.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ static int do_http_0_9( FILE *file, const char *filename) { + ReadBlock dcb; int ok; char *cp; @@ -67,8 +69,8 @@ static int do_http_0_9( TCPIPWriteTCP(ipid, "\r\n", 2, true, false); DecBusy(); - ok = read_binary(ipid, file); - return 0; + ok = read_binary(ipid, file, &dcb); + return ok; } @@ -212,9 +214,9 @@ enum { TE_chunked }; -int http_read_chunked(ipid, file) +int http_read_chunked(word ipid, FILE *file) { - + ReadBlock dcb; rlBuffer rb; LongWord chunkSize; LongWord count; @@ -225,7 +227,8 @@ int http_read_chunked(ipid, file) for (;;) { - + char *cp; + // get the chunk size. // 0 indicates end. for (;;) @@ -260,14 +263,20 @@ int http_read_chunked(ipid, file) // now read the data. if (chunkSize == 0) return 0; // eof. - ok = read_binary(ipid, file, chunkSize); + dcb.requestCount = chunkSize; + ok = read_binary_size(ipid, file, &dcb); if (ok < 0) return -1; - if (ok != chunkSize) return -1; - + if (dcb.requestCount != dcb.transferCount) + { + fprintf(stderr, "Read error - requested %ld, received %ld\n", + dcb.requestCount, dcb.transferCount); + return -1; + } + // read CRLF. for(;;) { - ok = ReadLine2(ipid, &rl); + ok = ReadLine2(ipid, &rb); if (ok == -1) return -1; if (ok == 0) { @@ -276,13 +285,17 @@ int http_read_chunked(ipid, file) } if (ok == 1) { - if (count) wtf + if (rb.bufferSize) + { + fprintf(stderr, "Unexpected data in chunked response.\n"); + return -1; + } break; } } } - + return 0; } int read_response(Word ipid, FILE *file, Handle dict) @@ -298,6 +311,9 @@ int read_response(Word ipid, FILE *file, Handle dict) int transferEncoding; LongWord contentSize; + + int haveTime = 0; + timeGSRec time; contentSize = 0; @@ -342,6 +358,30 @@ int read_response(Word ipid, FILE *file, Handle dict) return -1; } } + + value = DictionaryGet(dict, "Last-Modified", 13, &valueSize); + if (value && valueSize <= 255) + { + char *pstring; + + pstring = (char *)malloc(valueSize + 1); + if (pstring) + { + *pstring = valueSize; + memcpy(pstring + 1, value, valueSize); + + // parse the last-modified timestamp. + // 0x0e00 is rfc 822 format. + // (which is now obsoleted by rfc 2822 but close enough) + tiParseDateString(&time, pstring, 0x0e00); + if (!_toolErr) + { + haveTime = 1; + } + free(pstring); + } + } + // ? if (transferEncoding == -1) @@ -355,57 +395,20 @@ int read_response(Word ipid, FILE *file, Handle dict) { // identity. // just read contentLength bytes. - - static srBuff sr; - static rrBuff rr; - - int terr; - - // todo -- time out if no data for 30 seconds? - - while (contentSize) - { - LongWord count = 256; - - IncBusy(); - TCPIPPoll(); - TCPIPStatusTCP(ipid, &sr); - DecBusy(); - - count = sr.srRcvQueued; - if (count > contentSize) count = contentSize; - if (count == 0) - { - continue; - } - - IncBusy(); - terr = TCPIPReadTCP(ipid, 2, (Ref)0, count, &rr); - DecBusy(); - - if (_toolErr) break; - - if (rr.rrBuffCount) - { - Handle h = rr.rrBuffHandle; - HLock(h); - - fwrite(*(char **)h, 1, count, file); - contentSize -= rr.rrBuffCount; - - DisposeHandle(h); - - continue; - } - - if (terr && !rr.rrMoreFlag) - { - fprintf(stderr, "read error\n"); - return -1; - } + ReadBlock dcb; + int ok; + + dcb.requestCount = contentSize; + ok = read_binary_size(ipid, file, &dcb); + + if (!ok) return -1; + if (dcb.transferCount != dcb.requestCount) + { + fprintf(stderr, "Read error - requested %ld, received %ld\n", + dcb.requestCount, dcb.transferCount); + return -1; } - return 0; } @@ -514,6 +517,7 @@ static int do_http_1_1( #endif + if (ok == 200) { if (!flags._I) @@ -522,7 +526,6 @@ static int do_http_1_1( DisposeHandle(dict); - //ok = read_binary(ipid, file); return 0; } diff --git a/prototypes.h b/prototypes.h index 05a9f9d..7d1d21d 100644 --- a/prototypes.h +++ b/prototypes.h @@ -14,7 +14,14 @@ #define CLI() asm { cli } -int read_binary(unsigned ipid, FILE *file); +typedef struct ReadBlock +{ + LongWord requestCount; + LongWord transferCount; +} ReadBlock; + +int read_binary(unsigned ipid, FILE *file, ReadBlock *); +int read_binary_size(unsigned ipid, FILE *file, ReadBlock *); int setfiletype(const char *filename);