common code, http chunked responses.

This commit is contained in:
Kelvin Sherlock 2012-09-10 20:50:51 -04:00
parent 9f570ffc82
commit f67e5f11a8
4 changed files with 151 additions and 69 deletions

View File

@ -12,19 +12,26 @@
#include <stdio.h>
#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)

View File

@ -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);

125
http.c
View File

@ -21,6 +21,7 @@
#include <MiscTool.h>
#include <Memory.h>
#include <IntMath.h>
#include <TimeTool.h>
#include <stdlib.h>
#include <stdio.h>
@ -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;
}

View File

@ -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);