/*
- * $Id: HttpHdrRange.cc,v 1.17 1998/12/05 00:54:10 wessels Exp $
+ * $Id: HttpHdrRange.cc,v 1.18 1999/01/19 21:40:39 wessels Exp $
*
* DEBUG: section 64 HTTP Range Header
* AUTHOR: Alex Rousskov
return 0;
}
-/* hack: returns offset of first range spec */
+/* Returns lowest known offset in range spec(s), or range_spec_unknown */
+/* this is used for size limiting */
size_t
httpHdrRangeFirstOffset(const HttpHdrRange * range)
{
+ size_t offset = range_spec_unknown;
HttpHdrRangePos pos = HttpHdrRangeInitPos;
const HttpHdrRangeSpec *spec;
assert(range);
while ((spec = httpHdrRangeGetSpec(range, &pos))) {
- if (!known_spec(spec->offset)) /* ignore unknowns */
- continue;
- return spec->offset;
+ if (spec->offset < offset || !known_spec(offset))
+ offset = spec->offset;
}
- return 0;
+ return offset;
}
+/* Returns lowest offset in range spec(s), 0 if unknown */
+/* This is used for finding out where we need to start if all
+ * ranges are combined into one, for example FTP REST.
+ * Use 0 for size if unknown
+ */
+size_t
+httpHdrRangeLowestOffset(const HttpHdrRange * range, size_t size)
+{
+ size_t offset = range_spec_unknown;
+ size_t current;
+ HttpHdrRangePos pos = HttpHdrRangeInitPos;
+ const HttpHdrRangeSpec *spec;
+ assert(range);
+ while ((spec = httpHdrRangeGetSpec(range, &pos))) {
+ current = spec->offset;
+ if (!known_spec(current)) {
+ if (spec->length > size || !known_spec(spec->length))
+ return 0; /* Unknown. Assume start of file */
+ current = size - spec->length;
+ }
+ if (current < offset || !known_spec(offset))
+ offset = current;
+ }
+ return known_spec(offset) ? offset : 0;
+}
+
+
/* generates a "unique" boundary string for multipart responses
* the caller is responsible for cleaning the string */
String
/*
- * $Id: ftp.cc,v 1.267 1999/01/19 02:24:25 wessels Exp $
+ * $Id: ftp.cc,v 1.268 1999/01/19 21:40:40 wessels Exp $
*
* DEBUG: section 9 File Transfer Protocol (FTP)
* AUTHOR: Harvest Derived
SENT_CWD,
SENT_LIST,
SENT_NLST,
-#if RESTART_UNSUPPORTED
SENT_REST,
-#endif
SENT_RETR,
SENT_STOR,
SENT_QUIT,
int size;
wordlist *pathcomps;
char *filepath;
-#if RESTART_UNSUPPORTED
int restart_offset;
-#endif
+ int restarted_offset;
int rest_att;
char *proxy_host;
size_t list_width;
static CWCB ftpWriteCommandCallback;
static void ftpLoginParser(const char *, FtpStateData *, int escaped);
static wordlist *ftpParseControlReply(char *, size_t, int *, int *);
+static int ftpRestartable(FtpStateData * ftpState);
static void ftpAppendSuccessHeader(FtpStateData * ftpState);
static void ftpAuthRequired(HttpReply * reply, request_t * request, const char *realm);
static void ftpHackShortcut(FtpStateData * ftpState, FTPSM * nextState);
static FTPSM ftpSendList;
static FTPSM ftpSendNlst;
static FTPSM ftpReadList;
-#if RESTART_UNSUPPORTED
static FTPSM ftpSendRest;
static FTPSM ftpReadRest;
-#endif
static FTPSM ftpSendRetr;
static FTPSM ftpReadRetr;
static FTPSM ftpReadTransferDone;
ftpReadCwd,
ftpReadList, /* SENT_LIST */
ftpReadList, /* SENT_NLST */
-#if RESTART_UNSUPPORTED
ftpReadRest,
-#endif
ftpReadRetr,
ftpReadStor,
ftpReadQuit,
}
if (mode == 'I')
ftpState->flags.binary = 1;
+ else
+ ftpState->flags.binary = 0;
snprintf(cbuf, 1024, "TYPE %c\r\n", mode);
ftpWriteCommand(cbuf, ftpState);
ftpState->state = SENT_TYPE;
ftpState->flags.use_base = 1;
} else if (ftpState->flags.isdir)
ftpSendList(ftpState);
-#if RESTART_UNSUPPORTED
- else if (ftpState->restart_offset > 0)
+ else if (ftpRestartable(ftpState))
ftpSendRest(ftpState);
-#endif
else
ftpSendRetr(ftpState);
}
}
}
-#if RESTART_UNSUPPORTED
static void
ftpSendRest(FtpStateData * ftpState)
{
ftpState->state = SENT_REST;
}
+static int
+ftpRestartable(FtpStateData * ftpState)
+{
+ if (ftpState->restart_offset > 0)
+ return 1;
+ if (!ftpState->request->range)
+ return 0;
+ if (!ftpState->flags.binary)
+ return 0;
+ if (ftpState->size <= 0)
+ return 0;
+
+ ftpState->restart_offset = httpHdrRangeLowestOffset(ftpState->request->range, (size_t) ftpState->size);
+ if (ftpState->restart_offset <= 0)
+ return 0;
+ return 1;
+}
+
static void
ftpReadRest(FtpStateData * ftpState)
{
debug(9, 3) ("This is ftpReadRest\n");
assert(ftpState->restart_offset > 0);
if (code == 350) {
+ ftpState->restarted_offset = ftpState->restart_offset;
ftpSendRetr(ftpState);
} else if (code > 0) {
debug(9, 3) ("ftpReadRest: REST not supported\n");
ftpFail(ftpState);
}
}
-#endif
static void
ftpSendList(FtpStateData * ftpState)
storeBuffer(e);
httpReplyReset(reply);
/* set standard stuff */
- httpReplySetHeaders(reply, 1.0, HTTP_OK, "Gatewaying",
- mime_type, ftpState->size, ftpState->mdtm, -2);
+ if (ftpState->restarted_offset) {
+ /* Partial reply */
+ HttpHdrRangeSpec range_spec =
+ {
+ ftpState->restarted_offset,
+ ftpState->size - ftpState->restarted_offset
+ };
+ httpReplySetHeaders(reply, 1.0, HTTP_PARTIAL_CONTENT, "Gatewaying",
+ mime_type, ftpState->size - ftpState->restarted_offset, ftpState->mdtm, -2);
+ httpHeaderAddContRange(&reply->header, range_spec, ftpState->size);
+ } else {
+ /* Full reply */
+ httpReplySetHeaders(reply, 1.0, HTTP_OK, "Gatewaying",
+ mime_type, ftpState->size, ftpState->mdtm, -2);
+ }
/* additional info */
if (mime_enc)
httpHeaderPutStr(&reply->header, HDR_CONTENT_ENCODING, mime_enc);
if (pe)
storeRelease(pe);
storeRelease(e);
- } else if (EBIT_TEST(e->flags, ENTRY_CACHABLE)) {
+ } else if (EBIT_TEST(e->flags, ENTRY_CACHABLE) && !ftpState->restarted_offset) {
storeSetPublicKey(e);
} else {
storeRelease(e);