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 <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; Word rv = 0;
if (dcb) dcb->transferCount = 0;
IncBusy();
TCPIPPoll(); TCPIPPoll();
DecBusy();
for(;;) for(;;)
{ {
static char buffer[512]; static char buffer[512];
rrBuff rb; rrBuff rb;
Word count; Word count;
Word tcount;
IncBusy(); IncBusy();
rv = TCPIPReadTCP(ipid, 0, (Ref)buffer, 512, &rb); rv = TCPIPReadTCP(ipid, 0, (Ref)buffer, 512, &rb);
@ -40,12 +47,69 @@ int read_binary(Word ipid, FILE *file)
continue; 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) int ConnectLoop(char *host, Word port, Connection *connection)

View File

@ -24,6 +24,16 @@
extern int setfiletype(const char *filename); 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 * connect gopher.floodgap.com:70
* send path * send path
@ -32,8 +42,6 @@ extern int setfiletype(const char *filename);
* bin -- ends when connection is closed. * bin -- ends when connection is closed.
*/ */
static int gopher_text(Word ipid, FILE *file) static int gopher_text(Word ipid, FILE *file)
{ {
// text \r\n // text \r\n
@ -397,7 +405,7 @@ int do_gopher(const char *url, URLComponents *components)
case '5': case '5':
case '9': case '9':
fsetbinary(file); fsetbinary(file);
ok = read_binary(connection.ipid, file); ok = gopher_binary(connection.ipid, file);
break; break;
default: default:
ok = gopher_text(connection.ipid, file); ok = gopher_text(connection.ipid, file);

125
http.c
View File

@ -21,6 +21,7 @@
#include <MiscTool.h> #include <MiscTool.h>
#include <Memory.h> #include <Memory.h>
#include <IntMath.h> #include <IntMath.h>
#include <TimeTool.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -44,6 +45,7 @@ static int do_http_0_9(
FILE *file, FILE *file,
const char *filename) const char *filename)
{ {
ReadBlock dcb;
int ok; int ok;
char *cp; char *cp;
@ -67,8 +69,8 @@ static int do_http_0_9(
TCPIPWriteTCP(ipid, "\r\n", 2, true, false); TCPIPWriteTCP(ipid, "\r\n", 2, true, false);
DecBusy(); DecBusy();
ok = read_binary(ipid, file); ok = read_binary(ipid, file, &dcb);
return 0; return ok;
} }
@ -212,9 +214,9 @@ enum {
TE_chunked TE_chunked
}; };
int http_read_chunked(ipid, file) int http_read_chunked(word ipid, FILE *file)
{ {
ReadBlock dcb;
rlBuffer rb; rlBuffer rb;
LongWord chunkSize; LongWord chunkSize;
LongWord count; LongWord count;
@ -225,7 +227,8 @@ int http_read_chunked(ipid, file)
for (;;) for (;;)
{ {
char *cp;
// get the chunk size. // get the chunk size.
// 0 indicates end. // 0 indicates end.
for (;;) for (;;)
@ -260,14 +263,20 @@ int http_read_chunked(ipid, file)
// now read the data. // now read the data.
if (chunkSize == 0) return 0; // eof. 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 < 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. // read CRLF.
for(;;) for(;;)
{ {
ok = ReadLine2(ipid, &rl); ok = ReadLine2(ipid, &rb);
if (ok == -1) return -1; if (ok == -1) return -1;
if (ok == 0) if (ok == 0)
{ {
@ -276,13 +285,17 @@ int http_read_chunked(ipid, file)
} }
if (ok == 1) if (ok == 1)
{ {
if (count) wtf if (rb.bufferSize)
{
fprintf(stderr, "Unexpected data in chunked response.\n");
return -1;
}
break; break;
} }
} }
} }
return 0;
} }
int read_response(Word ipid, FILE *file, Handle dict) int read_response(Word ipid, FILE *file, Handle dict)
@ -298,6 +311,9 @@ int read_response(Word ipid, FILE *file, Handle dict)
int transferEncoding; int transferEncoding;
LongWord contentSize; LongWord contentSize;
int haveTime = 0;
timeGSRec time;
contentSize = 0; contentSize = 0;
@ -342,6 +358,30 @@ int read_response(Word ipid, FILE *file, Handle dict)
return -1; 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) if (transferEncoding == -1)
@ -355,57 +395,20 @@ int read_response(Word ipid, FILE *file, Handle dict)
{ {
// identity. // identity.
// just read contentLength bytes. // 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) ReadBlock dcb;
{ int ok;
continue;
} dcb.requestCount = contentSize;
ok = read_binary_size(ipid, file, &dcb);
IncBusy();
terr = TCPIPReadTCP(ipid, 2, (Ref)0, count, &rr); if (!ok) return -1;
DecBusy(); if (dcb.transferCount != dcb.requestCount)
{
if (_toolErr) break; fprintf(stderr, "Read error - requested %ld, received %ld\n",
dcb.requestCount, dcb.transferCount);
if (rr.rrBuffCount) return -1;
{
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;
}
} }
return 0; return 0;
} }
@ -514,6 +517,7 @@ static int do_http_1_1(
#endif #endif
if (ok == 200) if (ok == 200)
{ {
if (!flags._I) if (!flags._I)
@ -522,7 +526,6 @@ static int do_http_1_1(
DisposeHandle(dict); DisposeHandle(dict);
//ok = read_binary(ipid, file);
return 0; return 0;
} }

View File

@ -14,7 +14,14 @@
#define CLI() asm { cli } #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); int setfiletype(const char *filename);